anjlab-ruby-smpp 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/CHANGELOG +52 -0
  2. data/CONTRIBUTORS.txt +11 -0
  3. data/Gemfile +8 -0
  4. data/Gemfile.lock +18 -0
  5. data/LICENSE +20 -0
  6. data/README.rdoc +89 -0
  7. data/Rakefile +53 -0
  8. data/VERSION +1 -0
  9. data/config/environment.rb +2 -0
  10. data/examples/PDU1.example +26 -0
  11. data/examples/PDU2.example +26 -0
  12. data/examples/sample_gateway.rb +137 -0
  13. data/examples/sample_smsc.rb +102 -0
  14. data/lib/smpp.rb +25 -0
  15. data/lib/smpp/base.rb +308 -0
  16. data/lib/smpp/encoding/utf8_encoder.rb +37 -0
  17. data/lib/smpp/optional_parameter.rb +35 -0
  18. data/lib/smpp/pdu/base.rb +183 -0
  19. data/lib/smpp/pdu/bind_base.rb +25 -0
  20. data/lib/smpp/pdu/bind_receiver.rb +4 -0
  21. data/lib/smpp/pdu/bind_receiver_response.rb +4 -0
  22. data/lib/smpp/pdu/bind_resp_base.rb +17 -0
  23. data/lib/smpp/pdu/bind_transceiver.rb +4 -0
  24. data/lib/smpp/pdu/bind_transceiver_response.rb +4 -0
  25. data/lib/smpp/pdu/deliver_sm.rb +142 -0
  26. data/lib/smpp/pdu/deliver_sm_response.rb +12 -0
  27. data/lib/smpp/pdu/enquire_link.rb +11 -0
  28. data/lib/smpp/pdu/enquire_link_response.rb +11 -0
  29. data/lib/smpp/pdu/generic_nack.rb +20 -0
  30. data/lib/smpp/pdu/submit_multi.rb +68 -0
  31. data/lib/smpp/pdu/submit_multi_response.rb +49 -0
  32. data/lib/smpp/pdu/submit_sm.rb +91 -0
  33. data/lib/smpp/pdu/submit_sm_response.rb +31 -0
  34. data/lib/smpp/pdu/unbind.rb +11 -0
  35. data/lib/smpp/pdu/unbind_response.rb +12 -0
  36. data/lib/smpp/receiver.rb +27 -0
  37. data/lib/smpp/server.rb +223 -0
  38. data/lib/smpp/transceiver.rb +109 -0
  39. data/lib/sms.rb +9 -0
  40. data/ruby-smpp.gemspec +96 -0
  41. data/test/delegate.rb +28 -0
  42. data/test/encoding_test.rb +231 -0
  43. data/test/optional_parameter_test.rb +30 -0
  44. data/test/pdu_parsing_test.rb +111 -0
  45. data/test/receiver_test.rb +232 -0
  46. data/test/responsive_delegate.rb +53 -0
  47. data/test/server.rb +56 -0
  48. data/test/smpp_test.rb +239 -0
  49. data/test/submit_sm_test.rb +40 -0
  50. data/test/transceiver_test.rb +35 -0
  51. metadata +133 -0
data/CHANGELOG ADDED
@@ -0,0 +1,52 @@
1
+ = 0.3.0
2
+ * Added begin/rescue handling in receive_data to keep the connection alive. Delegates can implement data_error(Exception) and re-raise the error if they wish to break the connection.
3
+
4
+ = 0.1.3
5
+ * Transition maintenance from August to Ray Krueger
6
+ * Changed the expected signature of transceiver delegates to use the full PDU instead of picking off attributes one by one
7
+ * Added support for parsing optional parameters from delivery receipts in deliver_sm PDUs (this is also the fix for trailing bytes from MOs)
8
+
9
+ = 0.1.2 2009.01.22
10
+
11
+ == Delegate methods
12
+
13
+ - 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.
14
+
15
+ = 2008.12.11
16
+
17
+ == Updates from Jon Wood:
18
+
19
+ - Closes connections cleanly instead of stopping the event loop.
20
+ - 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.
21
+
22
+ = 2008.10.20
23
+
24
+ == Patch from Josh Bryan:
25
+
26
+ 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.
27
+
28
+ = 2008.10.13
29
+
30
+ == Patch from Taryn East:
31
+
32
+ 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 ;)
33
+
34
+ NOTE: Taryn's patch currently lives in a separate branch (taryn-patch), awaiting merge.
35
+
36
+ = 2008.06.25
37
+
38
+ == Check-ins from Abhishek Parolkar
39
+
40
+ I have implemented 4.5.1 section of SMPPv3.4: support for sending an MT message to multiple destination addresses.
41
+
42
+ - Added system_type paramenter to BindTransceiver.new
43
+ - Small change in submit_sm to discard '@' char in message push
44
+ - Made submit_sm more configurable with options
45
+ - Added PDU examples for submit_sm
46
+ - Added example to use submit_multi and submit_sm
47
+
48
+ = 2008.04.07
49
+
50
+ == Initial release (August Z. Flatby)
51
+
52
+ My first open source project after all these years! Ah.. it feels good.
data/CONTRIBUTORS.txt ADDED
@@ -0,0 +1,11 @@
1
+ Maintainer:
2
+ Ray Krueger <raykrueger@gmail.com>
3
+ August Z. Flatby <august@apparat.no>
4
+
5
+ Contributors:
6
+ Abhishek Parolkar <abhishek@parolkar.com>
7
+ Taryn East <taryn@taryneast.org>
8
+ Josh Bryan <jbryan@cashnetusa.com>
9
+ Jon Wood <jonathan.wood@uk.clara.net>
10
+ Jacob Eiler <jacob.eiler@apide.com>
11
+ Valdis Pornieks <valdis@ithouse.lv>
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem "eventmachine", ">= 0.10.0"
4
+
5
+ group :development do
6
+ gem "jeweler"
7
+ gem "rake"
8
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,18 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ eventmachine (0.12.10)
5
+ git (1.2.5)
6
+ jeweler (1.6.4)
7
+ bundler (~> 1.0)
8
+ git (>= 1.2.5)
9
+ rake
10
+ rake (0.9.2)
11
+
12
+ PLATFORMS
13
+ ruby
14
+
15
+ DEPENDENCIES
16
+ eventmachine (>= 0.10.0)
17
+ jeweler
18
+ rake
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Apparat AS
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,89 @@
1
+ = Ruby-SMPP
2
+
3
+ == DESCRIPTION:
4
+
5
+ Ruby-SMPP is a Ruby implementation of the SMPP v3.4 protocol. It is suitable for writing gateway daemons that communicate with SMSCs for sending and receiving SMS messages.
6
+
7
+ The implementation is based on the Ruby/EventMachine library.
8
+
9
+ <b>NOTE: Breaking change from 0.1.2 to 0.1.3</b>. See below.
10
+
11
+ For help please use the Google group here: http://groups.google.com/group/ruby-smpp/topics
12
+ === Glossary
13
+
14
+
15
+ * SMSC: SMS Center. Mobile operators normally operate an SMSC in their network. The SMSC stores and forwards SMS messages.
16
+ * MO: Mobile Originated SMS: originated in a mobile phone, ie. sent by an end user.
17
+ * MT: Mobile Terminated SMS: terminated in a mobile phone, ie. received by an end user.
18
+ * DR: Delivery Report, or delivery notification. When you send an MT message, you should receive a DR after a while.
19
+ * PDU: Protcol Base Unit, the data units that SMPP is comprised of. This implementation does _not_ implement all SMPP PDUs.
20
+
21
+ === Protocol
22
+
23
+ The SMPP 3.4 protocol spec can be downloaded here: http://smsforum.net/SMPP_v3_4_Issue1_2.zip
24
+
25
+ === Testing/Sample Code
26
+
27
+ Logica provides an SMPP simulator that you can download from http://opensmpp.logica.com. You can
28
+ also sign up for a demo SMPP account at one of the many bulk-SMS providers out there.
29
+
30
+ For a quick test, download smscsim.jar and smpp.jar from the Logica site, and start the simulator by typing:
31
+
32
+ java -cp smscsim.jar:smpp.jar com.logica.smscsim.Simulator
33
+
34
+ Then type 1 (start simulation), and enter 6000 for port number. The simulator then starts a server socket on a background thread. In another terminal window, start the sample sms gateway from the ruby-smpp/examples directory by typing:
35
+
36
+ ruby sample_gateway.rb
37
+
38
+ You will be able to send MT messages from the sample gateway terminal window by typing the message body. In the simulator terminal window you should see SMPP PDUs being sent from the sample gateway.
39
+
40
+ You can also send MO messages from the simulator to the sample gateway by typing 7 (log to screen off) and then 4 (send message). MO messages received by the sample gateway will be logged to ./sms_gateway.log.
41
+
42
+ == FEATURES/PROBLEMS:
43
+
44
+
45
+ * Implements only typical client subset of SMPP 3.4 with single-connection Transceiver.
46
+ * Contributors are encouraged to add missing PDUs.
47
+
48
+ == BASIC USAGE:
49
+
50
+ Start the transceiver. Receive delegate callbacks whenever incoming messages or delivery reports arrive. Send messages with Transceiver#send_mt.
51
+
52
+ # connect to SMSC
53
+ tx = EventMachine::run do
54
+ $tx = EventMachine::connect(
55
+ host,
56
+ port,
57
+ Smpp::Transceiver,
58
+ config, # a property hash
59
+ delegate # delegate class that will receive callbacks on MOs and DRs and other events
60
+ end
61
+
62
+ # send a message
63
+ tx.send_mt(id, from, to, body)
64
+
65
+ As of 0.1.3 the delegate method signatures are as follows:
66
+ * mo_received(transceiver, deliver_sm_pdu)
67
+ * delivery_report_received(transceiver, deliver_sm_pdu)
68
+ * message_accepted(transceiver, mt_message_id, submit_sm_response_pdu)
69
+ * message_rejected(transceiver, mt_message_id, submit_sm_response_pdu)
70
+ * bound(transceiver)
71
+ * unbound(transceiver)
72
+
73
+ Where 'pdu' above is the actual actual instance of the Smpp:Pdu:: class created.
74
+
75
+ For a more complete example, see examples/sample_gateway.rb
76
+
77
+ == REQUIREMENTS:
78
+
79
+
80
+ * Eventmachine >= 0.10.0
81
+
82
+ == INSTALL:
83
+
84
+ sudo gem install ruby-smpp
85
+
86
+ == LICENSE:
87
+
88
+ Copyright (c) 2008 Apparat AS
89
+ Released under the MIT license.
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ require File.expand_path('../config/environment', __FILE__)
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
8
+ gem.name = "ruby-smpp"
9
+ gem.summary = %Q{Ruby implementation of the SMPP protocol, based on EventMachine.}
10
+ gem.description = gem.summary + " SMPP is a protocol that allows ordinary people outside the mobile network to exchange SMS messages directly with mobile operators."
11
+ gem.email = "raykrueger@gmail.com"
12
+ gem.homepage = "http://github.com/raykrueger/ruby-smpp"
13
+ gem.authors = ["Ray Krueger", "August Z. Flatby"]
14
+ gem.rubyforge_project = gem.name
15
+
16
+ gem.extra_rdoc_files = ["README.rdoc", "CHANGELOG", "CONTRIBUTORS.txt"]
17
+ end
18
+ Jeweler::GemcutterTasks.new
19
+ rescue LoadError
20
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
21
+ end
22
+
23
+ require 'rake/testtask'
24
+ Rake::TestTask.new(:test) do |test|
25
+ test.libs << 'lib' << 'test'
26
+ test.pattern = 'test/**/*_test.rb'
27
+ test.verbose = true
28
+ end
29
+
30
+ begin
31
+ require 'rcov/rcovtask'
32
+ Rcov::RcovTask.new do |test|
33
+ test.libs << 'test'
34
+ test.pattern = 'test/**/*_test.rb'
35
+ test.verbose = true
36
+ end
37
+ rescue LoadError
38
+ task :rcov do
39
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
40
+ end
41
+ end
42
+
43
+ task :default => :test
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "ruby-smpp #{version}"
51
+ rdoc.rdoc_files.include('README*', "CHANGELOG", "CONTRIBUTORS.txt", "LICENSE")
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.6.0
@@ -0,0 +1,2 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
@@ -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
+
@@ -0,0 +1,137 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Sample SMS gateway that can receive MOs (mobile originated messages) and
4
+ # DRs (delivery reports), and send MTs (mobile terminated messages).
5
+ # MTs are, in the name of simplicity, entered on the command line in the format
6
+ # <sender> <receiver> <message body>
7
+ # MOs and DRs will be dumped to standard out.
8
+
9
+ require 'rubygems'
10
+ require File.dirname(__FILE__) + '/../lib/smpp'
11
+
12
+ LOGFILE = File.dirname(__FILE__) + "/sms_gateway.log"
13
+ Smpp::Base.logger = Logger.new(LOGFILE)
14
+
15
+ # We use EventMachine to receive keyboard input (which we send as MT messages).
16
+ # A "real" gateway would probably get its MTs from a message queue instead.
17
+ module KeyboardHandler
18
+ include EventMachine::Protocols::LineText2
19
+
20
+ def receive_line(data)
21
+ sender, receiver, *body_parts = data.split
22
+ unless sender && receiver && body_parts.size > 0
23
+ puts "Syntax: <sender> <receiver> <message body>"
24
+ else
25
+ body = body_parts.join(' ')
26
+ puts "Sending MT from #{sender} to #{receiver}: #{body}"
27
+ SampleGateway.send_mt(sender, receiver, body)
28
+ end
29
+ prompt
30
+ end
31
+
32
+ def prompt
33
+ print "MT: "
34
+ $stdout.flush
35
+ end
36
+ end
37
+
38
+ class SampleGateway
39
+
40
+ # MT id counter.
41
+ @@mt_id = 0
42
+
43
+ # expose SMPP transceiver's send_mt method
44
+ def self.send_mt(*args)
45
+ @@mt_id += 1
46
+ @@tx.send_mt(@@mt_id, *args)
47
+ end
48
+
49
+ def logger
50
+ Smpp::Base.logger
51
+ end
52
+
53
+ def start(config)
54
+ # The transceiver sends MT messages to the SMSC. It needs a storage with Hash-like
55
+ # semantics to map SMSC message IDs to your own message IDs.
56
+ pdr_storage = {}
57
+
58
+ # Run EventMachine in loop so we can reconnect when the SMSC drops our connection.
59
+ puts "Connecting to SMSC..."
60
+ loop do
61
+ EventMachine::run do
62
+ @@tx = EventMachine::connect(
63
+ config[:host],
64
+ config[:port],
65
+ Smpp::Transceiver,
66
+ config,
67
+ self # delegate that will receive callbacks on MOs and DRs and other events
68
+ )
69
+ print "MT: "
70
+ $stdout.flush
71
+
72
+ # Start consuming MT messages (in this case, from the console)
73
+ # Normally, you'd hook this up to a message queue such as Starling
74
+ # or ActiveMQ via STOMP.
75
+ EventMachine::open_keyboard(KeyboardHandler)
76
+ end
77
+ puts "Disconnected. Reconnecting in 5 seconds.."
78
+ sleep 5
79
+ end
80
+ end
81
+
82
+ # ruby-smpp delegate methods
83
+
84
+ def mo_received(transceiver, pdu)
85
+ logger.info "Delegate: mo_received: from #{pdu.source_addr} to #{pdu.destination_addr}: #{pdu.short_message}"
86
+ end
87
+
88
+ def delivery_report_received(transceiver, pdu)
89
+ logger.info "Delegate: delivery_report_received: ref #{pdu.msg_reference} stat #{pdu.stat}"
90
+ end
91
+
92
+ def message_accepted(transceiver, mt_message_id, pdu)
93
+ logger.info "Delegate: message_accepted: id #{mt_message_id} smsc ref id: #{pdu.message_id}"
94
+ end
95
+
96
+ def message_rejected(transceiver, mt_message_id, pdu)
97
+ logger.info "Delegate: message_rejected: id #{mt_message_id} smsc ref id: #{pdu.message_id}"
98
+ end
99
+
100
+ def bound(transceiver)
101
+ logger.info "Delegate: transceiver bound"
102
+ end
103
+
104
+ def unbound(transceiver)
105
+ logger.info "Delegate: transceiver unbound"
106
+ EventMachine::stop_event_loop
107
+ end
108
+
109
+ end
110
+
111
+ # Start the Gateway
112
+ begin
113
+ puts "Starting SMS Gateway. Please check the log at #{LOGFILE}"
114
+
115
+ # SMPP properties. These parameters work well with the Logica SMPP simulator.
116
+ # Consult the SMPP spec or your mobile operator for the correct settings of
117
+ # the other properties.
118
+ config = {
119
+ :host => '127.0.0.1',
120
+ :port => 6000,
121
+ :system_id => 'hugo',
122
+ :password => 'ggoohu',
123
+ :system_type => '', # default given according to SMPP 3.4 Spec
124
+ :interface_version => 52,
125
+ :source_ton => 0,
126
+ :source_npi => 1,
127
+ :destination_ton => 1,
128
+ :destination_npi => 1,
129
+ :source_address_range => '',
130
+ :destination_address_range => '',
131
+ :enquire_link_delay_secs => 10
132
+ }
133
+ gw = SampleGateway.new
134
+ gw.start(config)
135
+ rescue Exception => ex
136
+ puts "Exception in SMS Gateway: #{ex} at #{ex.backtrace.join("\n")}"
137
+ end