def process_pdu(pdu)
      case pdu
      when Pdu::EnquireLinkResponse
        # nop
      when Pdu::EnquireLink
        write_pdu(Pdu::EnquireLinkResponse.new(pdu.sequence_number))
      when Pdu::Unbind
        @state = :unbound
        write_pdu(Pdu::UnbindResponse.new(pdu.sequence_number, Pdu::Base::ESME_ROK))
        close_connection
      when Pdu::UnbindResponse
        logger.info "Unbound OK. Closing connection."
        close_connection
      when Pdu::GenericNack
        logger.warn "Received NACK! (error code #{pdu.error_code})."
        # we don't take this lightly: close the connection
        close_connection
      when Pdu::DeliverSm
        begin
          logger.debug "ESM CLASS #{pdu.esm_class}"
          if pdu.esm_class != 4
            # MO message
            run_callback(:mo_received, self, pdu)
          else
            # Delivery report
            run_callback(:delivery_report_received, self, pdu)
          end
          write_pdu(Pdu::DeliverSmResponse.new(pdu.sequence_number))
        rescue => e
          logger.warn "Send Receiver Temporary App Error due to #{e.inspect} raised in delegate"
          write_pdu(Pdu::DeliverSmResponse.new(pdu.sequence_number, Pdu::Base::ESME_RX_T_APPN))
        end
      when Pdu::BindTransceiverResponse
        case pdu.command_status
        when Pdu::Base::ESME_ROK
          logger.debug "Bound OK."
          @state = :bound
          run_callback(:bound, self)
        when Pdu::Base::ESME_RINVPASWD
          logger.warn "Invalid password."
          # schedule the connection to close, which eventually will cause the unbound() delegate
          # method to be invoked.
          run_callback(:invalid_password, self)
          close_connection
        when Pdu::Base::ESME_RINVSYSID
          logger.warn "Invalid system id."
          run_callback(:invalid_system_id, self)
          close_connection
        else
          logger.warn "Unexpected BindTransceiverResponse. Command status: #{pdu.command_status}"
          run_callback(:unexpected_error, self)
          close_connection
        end
      when Pdu::SubmitSmResponse
        mt_message_id = @ack_ids.delete(pdu.sequence_number)
        if !mt_message_id
          raise "Got SubmitSmResponse for unknown sequence_number: #{pdu.sequence_number}"
        end
        if pdu.command_status != Pdu::Base::ESME_ROK
          logger.error "Error status in SubmitSmResponse: #{pdu.command_status}"
          run_callback(:message_rejected, self, mt_message_id, pdu)
        else
          logger.info "Got OK SubmitSmResponse (#{pdu.message_id} -> #{mt_message_id})"
          run_callback(:message_accepted, self, mt_message_id, pdu)
        end
      when Pdu::SubmitMultiResponse
        mt_message_id = @ack_ids[pdu.sequence_number]
        if !mt_message_id
          raise "Got SubmitMultiResponse for unknown sequence_number: #{pdu.sequence_number}"
        end
        if pdu.command_status != Pdu::Base::ESME_ROK
          logger.error "Error status in SubmitMultiResponse: #{pdu.command_status}"
          run_callback(:message_rejected, self, mt_message_id, pdu)
        else
          logger.info "Got OK SubmitMultiResponse (#{pdu.message_id} -> #{mt_message_id})"
          run_callback(:message_accepted, self, mt_message_id, pdu)
        end
      when Pdu::BindReceiverResponse
        case pdu.command_status
        when Pdu::Base::ESME_ROK
          logger.debug "Bound OK."
          @state = :bound
          run_callback(:bound, self)
        when Pdu::Base::ESME_RINVPASWD
          logger.warn "Invalid password."
          run_callback(:invalid_password, self)
          # scheduele the connection to close, which eventually will cause the unbound() delegate
          # method to be invoked.
          close_connection
        when Pdu::Base::ESME_RINVSYSID
          logger.warn "Invalid system id."
          run_callback(:invalid_system_id, self)
          close_connection
        else
          logger.warn "Unexpected BindReceiverResponse. Command status: #{pdu.command_status}"
          run_callback(:unexpected_error, self)
          close_connection
        end
      when Pdu::BindTransmitterResponse
        case pdu.command_status
        when Pdu::Base::ESME_ROK
          logger.debug "Bound OK."
          @state = :bound
          run_callback(:bound, self)
        when Pdu::Base::ESME_RINVPASWD
          logger.warn "Invalid password."
          run_callback(:invalid_password, self)
          # schedule the connection to close, which eventually will cause the unbound() delegate
          # method to be invoked.
          close_connection
        when Pdu::Base::ESME_RINVSYSID
          logger.warn "Invalid system id."
          run_callback(:invalid_system_id, self)
          close_connection
        else
          logger.warn "Unexpected BindReceiverResponse. Command status: #{pdu.command_status}"
          run_callback(:unexpected_error, self)
          close_connection
        end
      else
        logger.warn "(#{self.class.name}) Received unexpected PDU: #{pdu.to_human}."
        run_callback(:unexpected_pdu, self, pdu)
        close_connection
      end
    end
def process_pdu(pdu)
      case pdu
      when Pdu::EnquireLinkResponse
        # nop
      when Pdu::EnquireLink
        write_pdu(Pdu::EnquireLinkResponse.new(pdu.sequence_number))
      when Pdu::Unbind
        @state = :unbound
        write_pdu(Pdu::UnbindResponse.new(pdu.sequence_number, Pdu::Base::ESME_ROK))
        close_connection
      when Pdu::UnbindResponse
        logger.info "Unbound OK. Closing connection."
        close_connection
      when Pdu::GenericNack
        logger.warn "Received NACK! (error code #{pdu.error_code})."
        # we don't take this lightly: close the connection
        close_connection
      when Pdu::DeliverSm
        begin
          logger.debug "ESM CLASS #{pdu.esm_class}"
          if pdu.esm_class != 4
            # MO message
            run_callback(:mo_received, self, pdu)
          else
            # Delivery report
            run_callback(:delivery_report_received, self, pdu)
          end
          write_pdu(Pdu::DeliverSmResponse.new(pdu.sequence_number))
        rescue => e
          logger.warn "Send Receiver Temporary App Error due to #{e.inspect} raised in delegate"
          write_pdu(Pdu::DeliverSmResponse.new(pdu.sequence_number, Pdu::Base::ESME_RX_T_APPN))
        end
      when Pdu::BindTransceiverResponse
        case pdu.command_status
        when Pdu::Base::ESME_ROK
          logger.debug "Bound OK."
          @state = :bound
          run_callback(:bound, self)
        when Pdu::Base::ESME_RINVPASWD
          logger.warn "Invalid password."
          # schedule the connection to close, which eventually will cause the unbound() delegate
          # method to be invoked.
          run_callback(:invalid_password, self)
          close_connection
        when Pdu::Base::ESME_RINVSYSID
          logger.warn "Invalid system id."
          run_callback(:invalid_system_id, self)
          close_connection
        else
          logger.warn "Unexpected BindTransceiverResponse. Command status: #{pdu.command_status}"
          run_callback(:unexpected_error, self)
          close_connection
        end
      when Pdu::SubmitSmResponse
        mt_message_id = @ack_ids.delete(pdu.sequence_number)
        if !mt_message_id
          raise "Got SubmitSmResponse for unknown sequence_number: #{pdu.sequence_number}"
        end
        if pdu.command_status != Pdu::Base::ESME_ROK
          logger.error "Error status in SubmitSmResponse: #{pdu.command_status}"
          run_callback(:message_rejected, self, mt_message_id, pdu)
        else
          logger.info "Got OK SubmitSmResponse (#{pdu.message_id} -> #{mt_message_id})"
          run_callback(:message_accepted, self, mt_message_id, pdu)
        end
      when Pdu::SubmitMultiResponse
        mt_message_id = @ack_ids[pdu.sequence_number]
        if !mt_message_id
          raise "Got SubmitMultiResponse for unknown sequence_number: #{pdu.sequence_number}"
        end
        if pdu.command_status != Pdu::Base::ESME_ROK
          logger.error "Error status in SubmitMultiResponse: #{pdu.command_status}"
          run_callback(:message_rejected, self, mt_message_id, pdu)
        else
          logger.info "Got OK SubmitMultiResponse (#{pdu.message_id} -> #{mt_message_id})"
          run_callback(:message_accepted, self, mt_message_id, pdu)
        end
      when Pdu::BindReceiverResponse
        case pdu.command_status
        when Pdu::Base::ESME_ROK
          logger.debug "Bound OK."
          @state = :bound
          run_callback(:bound, self)
        when Pdu::Base::ESME_RINVPASWD
          logger.warn "Invalid password."
          run_callback(:invalid_password, self)
          # scheduele the connection to close, which eventually will cause the unbound() delegate
          # method to be invoked.
          close_connection
        when Pdu::Base::ESME_RINVSYSID
          logger.warn "Invalid system id."
          run_callback(:invalid_system_id, self)
          close_connection
        else
          logger.warn "Unexpected BindReceiverResponse. Command status: #{pdu.command_status}"
          run_callback(:unexpected_error, self)
          close_connection
        end
      when Pdu::BindTransmitterResponse
        case pdu.command_status
        when Pdu::Base::ESME_ROK
          logger.debug "Bound OK."
          @state = :bound
          run_callback(:bound, self)
        when Pdu::Base::ESME_RINVPASWD
          logger.warn "Invalid password."
          run_callback(:invalid_password, self)
          # schedule the connection to close, which eventually will cause the unbound() delegate
          # method to be invoked.
          close_connection
        when Pdu::Base::ESME_RINVSYSID
          logger.warn "Invalid system id."
          run_callback(:invalid_system_id, self)
          close_connection
        else
          logger.warn "Unexpected BindReceiverResponse. Command status: #{pdu.command_status}"
          run_callback(:unexpected_error, self)
          close_connection
        end
      else
        logger.warn "(#{self.class.name}) Received unexpected PDU: #{pdu.to_human}."
        run_callback(:unexpected_pdu, self, pdu)
        close_connection
      end
    end
process common PDUs
 returns true if no further processing necessary