ruby-smpp 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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}"
         |