ruby-smpp 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/CONTRIBUTORS.txt ADDED
@@ -0,0 +1,9 @@
1
+ Maintainer:
2
+ August Z. Flatby <august@apparat.no>
3
+
4
+ Contributors:
5
+ Abhishek Parolkar <abhishek@parolkar.com>
6
+ Taryn East <taryn@taryneast.org>
7
+ Josh Bryan <jbryan@cashnetusa.com>
8
+ Jon Wood <jonathan.wood@uk.clara.net>
9
+ Jacob Eiler <jacob.eiler@apide.com>
data/History.txt CHANGED
@@ -1,3 +1,8 @@
1
+ == 0.1.2 2008-12-11
2
+
3
+ * Contributions:
4
+ * See NEWS.txt
5
+
1
6
  == 0.1.1 2008-10-20
2
7
 
3
8
  * Contributions:
data/Manifest.txt CHANGED
@@ -1,15 +1,21 @@
1
+ CONTRIBUTORS.txt
1
2
  History.txt
2
3
  License.txt
3
4
  Manifest.txt
5
+ NEWS.txt
4
6
  README.txt
5
7
  Rakefile
6
- examples/sample_gateway.rb
7
8
  config/hoe.rb
8
9
  config/requirements.rb
10
+ examples/PDU1.example
11
+ examples/PDU2.example
12
+ examples/sample_gateway.rb
13
+ examples/sample_smsc.rb
9
14
  lib/smpp.rb
10
- lib/smpp/version.rb
11
15
  lib/smpp/base.rb
12
16
  lib/smpp/pdu/base.rb
17
+ lib/smpp/pdu/bind_base.rb
18
+ lib/smpp/pdu/bind_resp_base.rb
13
19
  lib/smpp/pdu/bind_transceiver.rb
14
20
  lib/smpp/pdu/bind_transceiver_response.rb
15
21
  lib/smpp/pdu/deliver_sm.rb
@@ -23,8 +29,11 @@ lib/smpp/pdu/submit_sm.rb
23
29
  lib/smpp/pdu/submit_sm_response.rb
24
30
  lib/smpp/pdu/unbind.rb
25
31
  lib/smpp/pdu/unbind_response.rb
32
+ lib/smpp/server.rb
26
33
  lib/smpp/transceiver.rb
34
+ lib/smpp/version.rb
27
35
  lib/sms.rb
36
+ ruby-smpp.gemspec
28
37
  script/console
29
38
  script/destroy
30
39
  script/generate
data/NEWS.txt ADDED
@@ -0,0 +1,44 @@
1
+ = 2009.01.22
2
+
3
+ == Delegate methods
4
+
5
+ - Some API breakage has been introduced in order to allow a delegate callback model from the transceiver. Also, the Receiver and Transmitter classes have been removed due to bad code reuse.
6
+
7
+ = 2008.12.11
8
+
9
+ == Updates from Jon Wood:
10
+
11
+ - Closes connections cleanly instead of stopping the event loop.
12
+ - Adds a send_concat_mt method to Transceivers (not implemented for Transmitter/Receiver), which does the neccesary encoding and message splitting to send messages > 160 characters by splitting them into multiple parts.
13
+
14
+ = 2008.10.20
15
+
16
+ == Patch from Josh Bryan:
17
+
18
+ Fixes smpp/base.rb so that it can handle partial pdu's and multiple pdu's available on the stream. Previously, base.rb assumed that all data available on the TCP stream constituted the next pdu. Though this often works in low load environments, moderately high traffic environments often see multiple pdu's back to back on the stream before event machine cycles through another turn of the reactor. Also, pdu's can be split over multiple TCP packets. Thus, incomplete or multiple pdu's may be delivered to Base#receive_data, and Base needs to be able buffer and split the pdu's.
19
+
20
+ = 2008.10.13
21
+
22
+ == Patch from Taryn East:
23
+
24
+ I added the receiver and transmitter equivalents of the transmitter class, and also hacked in some code that would support basic setup of an smpp server. Note: we were only using this to set up a test-harness for our own ruby-smpp code, so it's pretty basic and doesn't support all messages - or even do anything useful with an incoming deliver_sm. But it's better than nothing at all ;)
25
+
26
+ NOTE: Taryn's patch currently lives in a separate branch (taryn-patch), awaiting merge.
27
+
28
+ = 2008.06.25
29
+
30
+ == Check-ins from Abhishek Parolkar
31
+
32
+ I have implemented 4.5.1 section of SMPPv3.4: support for sending an MT message to multiple destination addresses.
33
+
34
+ - Added system_type paramenter to BindTransceiver.new
35
+ - Small change in submit_sm to discard '@' char in message push
36
+ - Made submit_sm more configurable with options
37
+ - Added PDU examples for submit_sm
38
+ - Added example to use submit_multi and submit_sm
39
+
40
+ = 2008.04.07
41
+
42
+ == Initial release (August Z. Flatby)
43
+
44
+ My first open source project after all these years! Ah.. it feels good.
data/README.txt CHANGED
@@ -37,13 +37,13 @@ You can also send MO messages from the simulator to the sample gateway by typing
37
37
 
38
38
  == FEATURES/PROBLEMS:
39
39
 
40
- * Implements only typical client subset of SMPP 3.4 with single-connection Transceiver as opposed to dual-connection Transmitter + Receiver (UPDATE: see NEWS re. patch from Taryn East)
40
+ * Implements only typical client subset of SMPP 3.4 with single-connection Transceiver.
41
41
  * Contributors are encouraged to add missing PDUs.
42
42
  * Need more test cases!
43
43
 
44
44
  == BASIC USAGE:
45
45
 
46
- Start the transceiver. Receive callbacks whenever incoming messages or delivery reports arrive. Send messages with Transceiver#send_mt.
46
+ Start the transceiver. Receive delegate callbacks whenever incoming messages or delivery reports arrive. Send messages with Transceiver#send_mt.
47
47
 
48
48
  <pre>
49
49
  # connect to SMSC
@@ -0,0 +1,26 @@
1
+
2
+ This is the PDU being sent when sender address is numeric
3
+
4
+ type_name: submit_sm
5
+ command_id: 4 = 0x00000004
6
+ command_status: 0 = 0x00000000
7
+ sequence_number: 3 = 0x00000003
8
+ service_type: "1"
9
+ source_addr_ton: 2 = 0x00000002
10
+ source_addr_npi: 1 = 0x00000001
11
+ source_addr: "919900000000" #number masked
12
+ dest_addr_ton: 2 = 0x00000002
13
+ dest_addr_npi: 1 = 0x00000001
14
+ destination_addr: "919900000000" #number masked
15
+ esm_class: 3 = 0x00000003
16
+ protocol_id: 0 = 0x00000000
17
+ priority_flag: 0 = 0x00000000
18
+ schedule_delivery_time: NULL
19
+ validity_period: NULL
20
+ registered_delivery: 1 = 0x00000001
21
+ replace_if_present_flag: 0 = 0x00000000
22
+ data_coding: 0 = 0x00000000
23
+ sm_default_msg_id: 0 = 0x00000000
24
+ sm_length: 9 = 0x00000009
25
+ short_message: "test smpp"
26
+
@@ -0,0 +1,26 @@
1
+
2
+ Example PDU when sender address is an alphanumeric keyword
3
+
4
+ type_name: submit_sm
5
+ command_id: 4 = 0x00000004
6
+ command_status: 0 = 0x00000000
7
+ sequence_number: 5 = 0x00000005
8
+ service_type: "1"
9
+ source_addr_ton: 5 = 0x00000005
10
+ source_addr_npi: 0 = 0x00000000
11
+ source_addr: "RUBYSMPP"
12
+ dest_addr_ton: 2 = 0x00000002
13
+ dest_addr_npi: 1 = 0x00000001
14
+ destination_addr: "919900000000" # number masked
15
+ esm_class: 3 = 0x00000003
16
+ protocol_id: 0 = 0x00000000
17
+ priority_flag: 0 = 0x00000000
18
+ schedule_delivery_time: NULL
19
+ validity_period: NULL
20
+ registered_delivery: 1 = 0x00000001
21
+ replace_if_present_flag: 0 = 0x00000000
22
+ data_coding: 0 = 0x00000000
23
+ sm_default_msg_id: 0 = 0x00000000
24
+ sm_length: 5 = 0x00000005
25
+ short_message: "hello"
26
+
@@ -1,24 +1,6 @@
1
- #!/usr/bin/env ruby
2
-
3
- # Sample SMPP SMS Gateway. A proper SMS gateway listens for MOs (incoming
4
- # messages) and DRs (delivery reports), and submit MTs (outgoing messages).
5
- #
6
- # An SMS gateway can be the endpoint for a shortcode. For example, the
7
- # shortcode 2210 in Norway is implemented as a number of gateways like this
8
- # (one for each mobile operator). Hence, it will receive MOs (deliver_sm) from
9
- # end users addressed to shortcode 2210 and send MTs (submit_sm) to end users
10
- # from shortcode 2210.
11
- #
12
- # This gateway logs activity (including incoming MO and DR) to log/sms_gateway.log
13
- # and accepts outgoing (MT) messages from the console. This may be useful for
14
- # testing your SMPP setup.
15
-
16
- require 'rubygems'
17
- gem 'ruby-smpp'
18
- require 'smpp'
19
-
20
- # set up logger
21
- Smpp::Base.logger = Logger.new('sms_gateway.log')
1
+ #!/usr/bin/env ruby0
2
+ LOGFILE = File.dirname(__FILE__) + "/sms_gateway.log"
3
+ Smpp::Base.logger = Logger.new(LOGFILE)
22
4
 
23
5
  # the transceiver
24
6
  $tx = nil
@@ -31,95 +13,127 @@ module KeyboardHandler
31
13
  def receive_line(data)
32
14
  puts "Sending MT: #{data}"
33
15
  from = '2210'
34
- to = '4790000000'
35
- $tx.send_mt(123, from, to, data)
36
-
37
-
38
- # if you want to send messages with custom options, uncomment below code, this configuration allows the sender ID to be alpha numeric
39
- # $tx.send_mt(123, "RubySmpp", to, "Testing RubySmpp as sender id",{
40
- # :source_addr_ton=> 5,
41
- # :service_type => 1,
42
- # :source_addr_ton => 5,
43
- # :source_addr_npi => 0 ,
44
- # :dest_addr_ton => 2,
45
- # :dest_addr_npi => 1,
46
- # :esm_class => 3 ,
47
- # :protocol_id => 0,
48
- # :priority_flag => 0,
49
- # :schedule_delivery_time => nil,
50
- # :validity_period => nil,
51
- # :registered_delivery=> 1,
52
- # :replace_if_present_flag => 0,
53
- # :data_coding => 0,
54
- # :sm_default_msg_id => 0
55
- # })
56
-
57
- # if you want to send message to multiple destinations , uncomment below code
58
- # $tx.send_multi_mt(123, from, ["919900000001","919900000002","919900000003"], "I am echoing that ruby-smpp is great")
16
+ to = '4790000000'
17
+ msg_id = 123
18
+ $tx.send_mt(msg_id, from, to, data)
19
+
20
+
21
+ # if you want to send messages with custom options, uncomment below code, this configuration allows the sender ID to be alpha numeric
22
+ # $tx.send_mt(123, "RubySmpp", to, "Testing RubySmpp as sender id",{
23
+ # :source_addr_ton=> 5,
24
+ # :service_type => 1,
25
+ # :source_addr_ton => 5,
26
+ # :source_addr_npi => 0 ,
27
+ # :dest_addr_ton => 2,
28
+ # :dest_addr_npi => 1,
29
+ # :esm_class => 3 ,
30
+ # :protocol_id => 0,
31
+ # :priority_flag => 0,
32
+ # :schedule_delivery_time => nil,
33
+ # :validity_period => nil,
34
+ # :registered_delivery=> 1,
35
+ # :replace_if_present_flag => 0,
36
+ # :data_coding => 0,
37
+ # :sm_default_msg_id => 0
38
+ # })
39
+
40
+ # if you want to send message to multiple destinations , uncomment below code
41
+ # $tx.send_multi_mt(123, from, ["919900000001","919900000002","919900000003"], "I am echoing that ruby-smpp is great")
59
42
  prompt
60
43
  end
44
+
45
+ def prompt
46
+ print "Enter MT body: "
47
+ $stdout.flush
48
+ end
61
49
  end
62
50
 
63
- def prompt
64
- print "Enter MT body: "
65
- $stdout.flush
66
- end
51
+ class SampleGateway
52
+ include KeyboardHandler
53
+
54
+ def logger
55
+ Smpp::Base.logger
56
+ end
67
57
 
68
- def logger
69
- Smpp::Base.logger
70
- end
58
+ def start(config)
59
+ # The transceiver sends MT messages to the SMSC. It needs a storage with Hash-like
60
+ # semantics to map SMSC message IDs to your own message IDs.
61
+ pdr_storage = {}
62
+
63
+ # The block invoked when we receive an MO message from the SMSC
64
+ mo_proc = Proc.new do |sender, receiver, msg|
65
+ begin
66
+ # This is where you'd enqueue or store the MO message for further processing.
67
+ logger.info "Received MO from <#{sender}> to <#{receiver}>: <#{msg}>"
68
+ rescue Exception => ex
69
+ logger.error "Exception processing MO: #{ex}"
70
+ end
71
+ end
71
72
 
72
- def start(config)
73
- # The transceiver sends MT messages to the SMSC. It needs a storage with Hash-like
74
- # semantics to map SMSC message IDs to your own message IDs.
75
- pdr_storage = {}
76
-
77
- # The block invoked when we receive an MO message from the SMSC
78
- mo_proc = Proc.new do |sender, receiver, msg|
79
- begin
80
- # This is where you'd enqueue or store the MO message for further processing.
81
- logger.info "Received MO from <#{sender}> to <#{receiver}>: <#{msg}>"
82
- rescue Exception => ex
83
- logger.error "Exception processing MO: #{ex}"
73
+ # Invoked on delivery reports
74
+ dr_proc = Proc.new do |msg_reference, stat, dr_pdu|
75
+ begin
76
+ # The SMSC returns its own message reference. Look up (and delete) our stored objects
77
+ # based on this reference.
78
+ #
79
+ # The short_message attribute contains details on the current delivery status of the
80
+ # message.
81
+ pending_message = pdr_storage.delete(msg_reference)
82
+ logger.info "Received DR for #{pending_message}. Stat: #{stat} SM: #{dr_pdu.short_message}"
83
+ rescue Exception => ex
84
+ logger.error "Error processing DR: #{ex}"
85
+ end
84
86
  end
85
- end
86
87
 
87
- # Invoked on delivery reports
88
- dr_proc = Proc.new do |msg_reference, operator_status_code|
89
- begin
90
- # The SMSC returns its own message reference. Look up (and delete) our stored objects
91
- # based on this reference.
92
- pending_message = pdr_storage.delete(msg_reference)
93
- logger.info "Received DR for #{pending_message}: #{operator_status_code}"
94
- rescue Exception => ex
95
- logger.error "Error processing DR: #{ex}"
88
+ # Run EventMachine in loop so we can reconnect when the SMSC drops our connection.
89
+ prompt
90
+ loop do
91
+ EventMachine::run do
92
+ $tx = EventMachine::connect(
93
+ config[:host],
94
+ config[:port],
95
+ Smpp::Transceiver,
96
+ config,
97
+ self # self is delegate
98
+ )
99
+
100
+ # Start consuming MT messages (in this case, from the console)
101
+ # Normally, you'd hook this up to a message queue such as Starling
102
+ # or ActiveMQ via STOMP.
103
+ EventMachine::open_keyboard(KeyboardHandler)
104
+ end
105
+ logger.warn "Event loop stopped. Restarting in 5 seconds.."
106
+ sleep 5
96
107
  end
108
+
97
109
  end
110
+ # Delegate methods that will receive callbacks on various events
98
111
 
99
- # Run EventMachine in loop so we can reconnect when the SMSC drops our connection.
100
- loop do
101
- EventMachine::run do
102
- $tx = EventMachine::connect(
103
- config[:host],
104
- config[:port],
105
- Smpp::Transceiver,
106
- config,
107
- mo_proc,
108
- dr_proc,
109
- pdr_storage)
110
- # Start consuming MT messages (in this case, from the console)
111
- # Normally, you'd hook this up to a message queue such as Starling
112
- # or ActiveMQ via STOMP.
113
- EventMachine::open_keyboard(KeyboardHandler)
114
- end
115
- logger.warn "Event loop stopped. Restarting in 5 seconds.."
116
- sleep 5
112
+ def mo_received(transceiver, source_addr, destination_addr, short_message)
113
+ logger.info "Delegate: mo_received: from #{source_addr} to #{destination_addr}: #{short_message}"
114
+ end
115
+
116
+ def delivery_report_received(transceiver, msg_reference, stat, pdu)
117
+ logger.info "Delegate: delivery_report_received: ref #{msg_reference} stat #{stat} pdu #{pdu}"
118
+ end
119
+
120
+ def message_accepted(transceiver, mt_message_id, smsc_message_id)
121
+ logger.info "Delegate: message_sent: id #{mt_message_id} smsc ref id: #{smsc_message_id}"
122
+ end
123
+
124
+ def bound(transceiver)
125
+ logger.info "Delegate: transceiver bound"
126
+ end
127
+
128
+ def unbound(transceiver)
129
+ logger.info "Delegate: transceiver unbound"
130
+ EventMachine::stop_event_loop
117
131
  end
118
132
  end
119
133
 
120
134
  # Start the Gateway
121
135
  begin
122
- puts "Starting SMS Gateway"
136
+ puts "Starting SMS Gateway. Check the log at #{LOGFILE}"
123
137
 
124
138
  # SMPP properties. These parameters work well with the Logica SMPP simulator.
125
139
  # Consult the SMPP spec or your mobile operator for the correct settings of
@@ -129,7 +143,7 @@ begin
129
143
  :port => 6000,
130
144
  :system_id => 'hugo',
131
145
  :password => 'ggoohu',
132
- :system_type => 'vma', # default given according to SMPP 3.4 Spec
146
+ :system_type => 'vma', # default given according to SMPP 3.4 Spec
133
147
  :interface_version => 52,
134
148
  :source_ton => 0,
135
149
  :source_npi => 1,
@@ -138,9 +152,9 @@ begin
138
152
  :source_address_range => '',
139
153
  :destination_address_range => '',
140
154
  :enquire_link_delay_secs => 10
141
- }
142
- prompt
143
- start(config)
155
+ }
156
+ gw = SampleGateway.new
157
+ gw.start(config)
144
158
  rescue Exception => ex
145
- puts "Exception in SMS Gateway: #{ex} at #{ex.backtrace[0]}"
159
+ puts "Exception in SMS Gateway: #{ex} at #{ex.backtrace.join("\n")}"
146
160
  end
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Sample SMPP SMS Gateway.
4
+
5
+ require 'rubygems'
6
+ gem 'ruby-smpp'
7
+ require 'smpp'
8
+ require 'smpp/server'
9
+
10
+ # set up logger
11
+ Smpp::Base.logger = Logger.new('smsc.log')
12
+
13
+ # the transceiver
14
+ $tx = nil
15
+
16
+ # We use EventMachine to receive keyboard input (which we send as MT messages).
17
+ # A "real" gateway would probably get its MTs from a message queue instead.
18
+ module KeyboardHandler
19
+ include EventMachine::Protocols::LineText2
20
+
21
+ def receive_line(data)
22
+ puts "Sending MO: #{data}"
23
+ from = '1111111111'
24
+ to = '1111111112'
25
+ $tx.send_mo(from, to, data)
26
+
27
+
28
+ # if you want to send messages with custom options, uncomment below code, this configuration allows the sender ID to be alpha numeric
29
+ # $tx.send_mt(123, "RubySmpp", to, "Testing RubySmpp as sender id",{
30
+ # :source_addr_ton=> 5,
31
+ # :service_type => 1,
32
+ # :source_addr_ton => 5,
33
+ # :source_addr_npi => 0 ,
34
+ # :dest_addr_ton => 2,
35
+ # :dest_addr_npi => 1,
36
+ # :esm_class => 3 ,
37
+ # :protocol_id => 0,
38
+ # :priority_flag => 0,
39
+ # :schedule_delivery_time => nil,
40
+ # :validity_period => nil,
41
+ # :registered_delivery=> 1,
42
+ # :replace_if_present_flag => 0,
43
+ # :data_coding => 0,
44
+ # :sm_default_msg_id => 0
45
+ # })
46
+
47
+ # if you want to send message to multiple destinations , uncomment below code
48
+ # $tx.send_multi_mt(123, from, ["919900000001","919900000002","919900000003"], "I am echoing that ruby-smpp is great")
49
+ prompt
50
+ end
51
+ end
52
+
53
+ def prompt
54
+ print "Enter MO body: "
55
+ $stdout.flush
56
+ end
57
+
58
+ def logger
59
+ Smpp::Base.logger
60
+ end
61
+
62
+ def start(config)
63
+
64
+ # Run EventMachine in loop so we can reconnect when the SMSC drops our connection.
65
+ loop do
66
+ EventMachine::run do
67
+ $tx = EventMachine::start_server(
68
+ config[:host],
69
+ config[:port],
70
+ Smpp::Server,
71
+ config
72
+ )
73
+ end
74
+ logger.warn "Event loop stopped. Restarting in 5 seconds.."
75
+ sleep 5
76
+ end
77
+ end
78
+
79
+ # Start the Gateway
80
+ begin
81
+ puts "Starting SMS Gateway"
82
+
83
+ # SMPP properties. These parameters the ones provided sample_gateway.rb and
84
+ # will work with it.
85
+ config = {
86
+ :host => 'localhost',
87
+ :port => 6000,
88
+ :system_id => 'hugo',
89
+ :password => 'ggoohu',
90
+ :system_type => 'vma', # default given according to SMPP 3.4 Spec
91
+ :interface_version => 52,
92
+ :source_ton => 0,
93
+ :source_npi => 1,
94
+ :destination_ton => 1,
95
+ :destination_npi => 1,
96
+ :source_address_range => '',
97
+ :destination_address_range => '',
98
+ :enquire_link_delay_secs => 10
99
+ }
100
+ start(config)
101
+ rescue Exception => ex
102
+ puts "Exception in SMS Gateway: #{ex} at #{ex.backtrace[0]}"
103
+ end
data/lib/smpp/base.rb CHANGED
@@ -1,6 +1,3 @@
1
- require 'rubygems'
2
- gem 'eventmachine'
3
-
4
1
  require 'timeout'
5
2
  require 'iconv'
6
3
  require 'scanf'
@@ -16,6 +13,15 @@ module Smpp
16
13
  # :bound or :unbound
17
14
  attr_accessor :state
18
15
 
16
+ # queries the state of the transmitter - is it bound?
17
+ def unbound?
18
+ @state == :unbound
19
+ end
20
+
21
+ def bound?
22
+ @state == :bound
23
+ end
24
+
19
25
  def Base.logger
20
26
  @@logger
21
27
  end
@@ -29,14 +35,16 @@ module Smpp
29
35
  end
30
36
 
31
37
  def initialize(config)
38
+ @state = :unbound
32
39
  @config = config
33
40
  @data = ""
34
41
  end
35
42
 
36
43
  # invoked by EventMachine when connected
37
44
  def post_init
38
- # send Bind PDU
39
- send_bind
45
+ # send Bind PDU if we are a binder (eg
46
+ # Receiver/Transmitter/Transceiver
47
+ send_bind unless defined?(am_server?) && am_server?
40
48
 
41
49
  # start timer that will periodically send enquire link PDUs
42
50
  start_enquire_link_timer(@config[:enquire_link_delay_secs]) if @config[:enquire_link_delay_secs]
@@ -44,14 +52,27 @@ module Smpp
44
52
  logger.error "Error starting RX: #{ex.message} at #{ex.backtrace[0]}"
45
53
  end
46
54
 
55
+ # sets up a periodic timer that will periodically enquire as to the
56
+ # state of the connection
57
+ # Note: to add in custom executable code (that only runs on an open
58
+ # connection), derive from the appropriate Smpp class and overload the
59
+ # method named: periodic_call_method
47
60
  def start_enquire_link_timer(delay_secs)
48
61
  logger.info "Starting enquire link timer (with #{delay_secs}s interval)"
49
62
  EventMachine::PeriodicTimer.new(delay_secs) do
50
63
  if error?
51
- logger.warn "Link timer: Connection is in error state. Terminating loop."
52
- EventMachine::stop_event_loop
64
+ logger.warn "Link timer: Connection is in error state. Disconnecting."
65
+ close_connection
66
+ elsif unbound?
67
+ logger.warn "Link is unbound, waiting until next #{delay_secs} interval before querying again"
53
68
  else
54
- write_pdu Pdu::EnquireLink.new
69
+
70
+ # if the user has defined a method to be called periodically, do
71
+ # it now - and continue if it indicates to do so
72
+ rval = defined?(periodic_call_method) ? periodic_call_method : true
73
+
74
+ # only send an OK if this worked
75
+ write_pdu Pdu::EnquireLink.new if rval
55
76
  end
56
77
  end
57
78
  end
@@ -80,14 +101,16 @@ module Smpp
80
101
  end
81
102
 
82
103
  # EventMachine::Connection#unbind
104
+ # Invoked by EM when connection is closed. Delegates should consider
105
+ # breaking the event loop and reconnect when they receive this callback.
83
106
  def unbind
84
- logger.warn "EventMachine: unbind invoked in bound state" if @state == :bound
107
+ if @delegate.respond_to?(:unbound)
108
+ @delegate.unbound(self)
109
+ end
85
110
  end
86
111
 
87
112
  def send_unbind
88
- #raise rescue logger.debug "Unbinding, now?? #{$!.backtrace[1..5].join("\n")}"
89
113
  write_pdu Pdu::Unbind.new
90
- # leave it to the subclass to process the UnbindResponse
91
114
  @state = :unbound
92
115
  end
93
116
 
@@ -102,20 +125,20 @@ module Smpp
102
125
  when Pdu::Unbind
103
126
  @state = :unbound
104
127
  write_pdu(Pdu::UnbindResponse.new(pdu.sequence_number, Pdu::Base::ESME_ROK))
105
- EventMachine::stop_event_loop
128
+ close_connection
106
129
  when Pdu::UnbindResponse
107
130
  logger.info "Unbound OK. Closing connection."
108
131
  close_connection
109
132
  when Pdu::GenericNack
110
133
  logger.warn "Received NACK! (error code #{pdu.error_code})."
111
- # we don't take this lightly: stop the event loop
112
- EventMachine::stop_event_loop
134
+ # we don't take this lightly: close the connection
135
+ close_connection
113
136
  else
114
137
  logger.warn "(#{self.class.name}) Received unexpected PDU: #{pdu.to_human}."
115
- EventMachine::stop_event_loop
138
+ close_connection
116
139
  end
117
140
  end
118
-
141
+
119
142
  private
120
143
  def write_pdu(pdu)
121
144
  logger.debug "<- #{pdu.to_human}"