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 +9 -0
- data/History.txt +5 -0
- data/Manifest.txt +11 -2
- data/NEWS.txt +44 -0
- data/README.txt +2 -2
- data/examples/PDU1.example +26 -0
- data/examples/PDU2.example +26 -0
- data/examples/sample_gateway.rb +113 -99
- data/examples/sample_smsc.rb +103 -0
- data/lib/smpp/base.rb +39 -16
- data/lib/smpp/pdu/base.rb +23 -24
- data/lib/smpp/pdu/bind_base.rb +25 -0
- data/lib/smpp/pdu/bind_resp_base.rb +17 -0
- data/lib/smpp/pdu/bind_transceiver.rb +3 -5
- data/lib/smpp/pdu/bind_transceiver_response.rb +3 -6
- data/lib/smpp/pdu/deliver_sm.rb +72 -29
- data/lib/smpp/pdu/deliver_sm_response.rb +7 -0
- data/lib/smpp/pdu/enquire_link.rb +6 -0
- data/lib/smpp/pdu/enquire_link_response.rb +7 -1
- data/lib/smpp/pdu/generic_nack.rb +14 -2
- data/lib/smpp/pdu/submit_multi.rb +13 -12
- data/lib/smpp/pdu/submit_multi_response.rb +43 -4
- data/lib/smpp/pdu/submit_sm.rb +61 -22
- data/lib/smpp/pdu/submit_sm_response.rb +11 -2
- data/lib/smpp/pdu/unbind.rb +6 -0
- data/lib/smpp/pdu/unbind_response.rb +7 -0
- data/lib/smpp/server.rb +224 -0
- data/lib/smpp/transceiver.rb +87 -30
- data/lib/smpp/version.rb +1 -1
- data/lib/smpp.rb +3 -1
- data/ruby-smpp.gemspec +36 -0
- data/test/smpp_test.rb +218 -12
- metadata +16 -5
data/CONTRIBUTORS.txt
ADDED
data/History.txt
CHANGED
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
|
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
|
+
|
data/examples/sample_gateway.rb
CHANGED
@@ -1,24 +1,6 @@
|
|
1
|
-
#!/usr/bin/env
|
2
|
-
|
3
|
-
|
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
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
# :
|
43
|
-
# :
|
44
|
-
# :
|
45
|
-
# :
|
46
|
-
# :
|
47
|
-
# :
|
48
|
-
# :
|
49
|
-
# :
|
50
|
-
# :
|
51
|
-
# :
|
52
|
-
# :
|
53
|
-
# :
|
54
|
-
# :
|
55
|
-
#
|
56
|
-
|
57
|
-
|
58
|
-
#
|
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
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
51
|
+
class SampleGateway
|
52
|
+
include KeyboardHandler
|
53
|
+
|
54
|
+
def logger
|
55
|
+
Smpp::Base.logger
|
56
|
+
end
|
67
57
|
|
68
|
-
def
|
69
|
-
|
70
|
-
|
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
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
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
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
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
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
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.
|
52
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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:
|
112
|
-
|
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
|
-
|
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}"
|