Class: Smpp::Server

Inherits:
Base
  • Object
show all
Defined in:
lib/smpp/server.rb

Overview

the opposite of a client-based receiver, the server transmitter waill send out MOs to the client when set up

Constant Summary collapse

BIND_STATUSES =

set of valid bind statuses

{:transmitter => :bound_tx, 
:receiver => :bound_rx, :transceiver => :bound_trx}

Instance Attribute Summary collapse

Attributes inherited from Base

#state

Instance Method Summary collapse

Methods inherited from Base

logger, #logger, logger=, #post_init, #receive_data, #send_unbind, #start_enquire_link_timer, #unbind

Constructor Details

#initialize(config, received_messages = [], sent_messages = []) ⇒ Server

Expects a config hash, a proc to invoke for incoming (MO) messages, a proc to invoke for delivery reports, and optionally a hash-like storage for pending delivery reports.



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/smpp/server.rb', line 11

def initialize(config, received_messages = [], sent_messages = [])
  super(config)
  @state = :unbound
  @received_messages = received_messages
  @sent_messages = sent_messages
  
  # Array of un-acked MT message IDs indexed by sequence number.
  # As soon as we receive SubmitSmResponse we will use this to find the 
  # associated message ID, and then create a pending delivery report.
  @ack_ids = Array.new(512)         
  
  ed = @config[:enquire_link_delay_secs] || 5
  comm_inactivity_timeout = [ed - 5, 3].max
rescue Exception => ex
  logger.error "Exception setting up server: #{ex}"
  raise
end

Instance Attribute Details

#bind_statusObject

what is the bind_status?



56
57
58
# File 'lib/smpp/server.rb', line 56

def bind_status
  @bind_status
end

Instance Method Details

#accept_deliver_sm_response(pdu) ⇒ Object

Acknowledge delivery of an outgoing MO message REVISIT = just a stub



186
187
188
189
190
191
192
193
194
195
196
# File 'lib/smpp/server.rb', line 186

def accept_deliver_sm_response(pdu)
  m_seq = pdu.sequence_number
  # add the id to the list of ids we're awaiting acknowledgement of
  # REVISIT - what id do we need to store?
  unless @sent_messages && @sent_messages.include?(m_seq)
    logger.error("Received deliver response for message for which we have no saved id: #{m_seq}")
  else
    @sent_messages.delete(m_seq)
    logger.info "Acknowledged receipt of SM delivery message id: #{m_seq}"
  end
end

#am_server?Boolean



74
75
76
# File 'lib/smpp/server.rb', line 74

def am_server?
  true
end

#bind_session(bind_pdu, bind_classname) ⇒ Object

actually perform the action of binding the session to the given session type

Raises:

  • (IOError)


99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/smpp/server.rb', line 99

def bind_session(bind_pdu, bind_classname)
  # TODO: probably should not "raise" here - what's better?
  raise IOError, "Session already bound." if bound?
  response_class = fetch_bind_response_class(bind_classname)

  # TODO: look inside the pdu for the password and check it

  send_bind_response(bind_pdu, response_class)

  @state = :bound
  set_bind_status(bind_classname)
end

#bound?Boolean

convenience methods is this session currently bound?



37
38
39
# File 'lib/smpp/server.rb', line 37

def bound?
  @state == :bound
end

#deliver_sm(from, to, message, config = {}) ⇒ Object

Message delivery (receiver) functions (used by receiver and transceiver-bound system)

When we get an incoming SMS to send on to the client, we need to initiate one of these PDUs. Note - data doesn’t have to be valid, as we’re not really doing much useful with it. Only the params that will be pulled out by the test system need to be valid.

Raises:

  • (IOError)


168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/smpp/server.rb', line 168

def deliver_sm(from, to, message, config = {})
  # TODO: probably should not "raise" here - what's better?
  raise IOError, "Connection not bound." if unbound?
  raise IOError, "Connection not set to receive" unless receiving?
  
  # submit the given message
  new_pdu = Pdu::DeliverSm.new(from, to, message, config)
  write_pdu(new_pdu)
  # add the id to the list of ids of which we're awaiting acknowledgement
  @sent_messages << m_seq

  logger.info "Delivered SM message id: #{m_seq}"

  new_pdu
end

#fetch_bind_response_class(bind_classname) ⇒ Object

REVISIT - not sure if these are using the correct data. Currently just pulls the data straight out of the given pdu and sends it right back.

Raises:

  • (IOError)


81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/smpp/server.rb', line 81

def fetch_bind_response_class(bind_classname)
  # check we have a valid classname - probably overkill as only our code
  # will send the classnames through
  raise IOError, "bind class name missing" if bind_classname.nil?
  raise IOError, "bind class name: #{bind_classname} unknown" unless BIND_STATUSES.has_key?(bind_classname)

  case bind_classname
  when :transceiver
    return Smpp::Pdu::BindTransceiverResponse
  when :transmitter
    return Smpp::Pdu::BindTransmitterResponse
  when :receiver
    return Smpp::Pdu::BindReceiverResponse
  end
end

#process_pdu(pdu) ⇒ Object

a PDU is received these pdus are all responses to a message sent by the client and require their own special response



202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/smpp/server.rb', line 202

def process_pdu(pdu)
  case pdu
  # client has asked to set up a connection
  when Pdu::BindTransmitter
    bind_session(pdu, :transmitter)
  when Pdu::BindReceiver
    bind_session(pdu, :receiver)
  when Pdu::BindTransceiver
    bind_session(pdu, :transceiver)
  # client has acknowledged receipt of a message we sent to them
  when Pdu::DeliverSmResponse
    accept_deliver_sm_response(pdu) # acknowledge its sending

  # client has asked for a message to be sent
  when Pdu::SubmitSm
    receive_sm(pdu)
  else
    # for generic functions or default fallback
    super(pdu)
  end 
end

#receive_sm(pdu) ⇒ Object

Message submission (transmitter) functions (used by transmitter and transceiver-bound system) Note - we only support submit_sm message type, not submit_multi or data_sm message types

Receive an incoming message to send to the network and respond REVISIT = just a stub

Raises:

  • (IOError)


133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/smpp/server.rb', line 133

def receive_sm(pdu)
  # TODO: probably should not "raise" here - what's better?
  raise IOError, "Connection not bound." if unbound?
  # Doesn't matter if it's a TX/RX/TRX, have to send a SubmitSmResponse:
  # raise IOError, "Connection not set to receive" unless receiving?

  # Must respond to SubmitSm requests with the same sequence number
  m_seq = pdu.sequence_number
  # add the id to the list of ids of which we're awaiting acknowledgement
  @received_messages << m_seq

  # In theory this is where the MC would actually do something useful with
  # the PDU - eg send it on to the network. We'd check if it worked and
  # send a failure PDU if it failed.
  #
  # Given this is a dummy MC, that's not necessary, so all our responses
  # will be OK.

  # so respond with a successful response
  pdu = Pdu::SubmitSmResponse.new(m_seq, Pdu::Base::ESME_ROK, message_id = '' )
  write_pdu pdu
  @received_messages.delete m_seq
  
  logger.info "Received submit sm message: #{m_seq}"
end

#receiving?Boolean

convenience function - are we able to receive in this bind-Status?



67
68
69
70
71
72
# File 'lib/smpp/server.rb', line 67

def receiving?
  # not receiving if not bound
  return false if unbound? || bind_status.nil?
  # transmitters can't receive
  bind_status != :bound_tx
end

#send_bind_response(bind_pdu, bind_class) ⇒ Object

Send BindReceiverResponse PDU - used in response to a “bind_receiver” pdu.



114
115
116
117
118
119
120
121
122
123
# File 'lib/smpp/server.rb', line 114

def send_bind_response(bind_pdu, bind_class)
  resp_pdu = bind_class.new(
                bind_pdu.sequence_number, 
                # currently assume that it binds ok
                Pdu::Base::ESME_ROK, 
                # TODO: not sure where we get the system ID
                # is this the session id?
                bind_pdu.system_id)
  write_pdu(resp_pdu)
end

#set_bind_status(bind_classname) ⇒ Object

set the bind status based on the common-name for the bind class



48
49
50
# File 'lib/smpp/server.rb', line 48

def set_bind_status(bind_classname)
  @bind_status = BIND_STATUSES[bind_classname]
end

#transmitting?Boolean

convenience function - are we able to transmit in this bind-Status?



60
61
62
63
64
65
# File 'lib/smpp/server.rb', line 60

def transmitting?
  # not transmitting if not bound
  return false if unbound? || bind_status.nil?
  # receivers can't transmit
  bind_status != :bound_rx
end

#unbound?Boolean

is this session currently unbound?



41
42
43
# File 'lib/smpp/server.rb', line 41

def unbound?
  @state == :unbound
end

#unset_bind_statusObject

and kill the bind status when done



52
53
54
# File 'lib/smpp/server.rb', line 52

def unset_bind_status
  @bind_status = nil
end