NAME
Net::SMPP - pure Perl implementation of SMPP 3.4 over TCP
SYNOPSIS
use Net::SMPP;
$smpp = Net::SMPP->new_client($host, port=>$port,
system_id => 'yourusername',
password => 'secret',
) or die;
DESCRIPTION
Implements Short Message Peer to Peer protocol, which is frequently used to pass short messages between mobile operators implementing short message service (SMS). This is applicable to both european GSM and american CDMA/TDMA systems.
Despite its name, SMPP protocol defines a client (ESME) and a server (often called SMSC in the mobile operator world). Client usually initiates the TCP connection and does bind to log in. After binding, a series of request response pairs, called PDUs (protocol data units) is exchanged. Request can be initiated by either end (hence "peer-to-peer"?) and the other end reponds. Requests are numbered with a sequence number and each response has corresponding sequence number. This allows several requests to be pending at the same time. Conceptually this is similar to IMAP or LDAP.
Normally this module operates in synchronous mode, meaning that a method that sends a request will also block until it gets a response. Internal command used for waiting for response is
$resp_pdu = $smpp->wait_pdu($cmd_id, $seq);
If, while waiting for a particular response, other PDUs are received they are either handled by handlers (set up by constructor) or discarded. If caller wants to receive a command, he can call
$pdu = $smpp->read_pdu();
which will block until a command is received from the stream.
Module can also be used asynchronously by specifying async=>1 to the constructor. In this mode command methods return immediately and user should poll for any responses using
$pdu = $smpp->wait_pdu($cmd_id, $seq);
If wait_pdu returns a command, the caller should generate appropriate response.
If the caller does not want to block on wait_pdu(), he must use select() to determine if the socket is readable. (*** what if SSL layer gets inserted?)
CONSTRUCTORS
- new()
-
Do not call. Has special internal meaning during accepting connections from listening socket.
- new_client()
-
Create a new SMPP client object and open conncetion to SMSC host
$smpp = new Net::SMPP system_id => 'username', # usually needed (default '') password => 'secret', # usually needed (default '') system_type => '', # default ok, often not needed interface_version => 0x34, # default ok, almost never needed addr_ton => 0x00, # default ok, type of number unknwn addr_npi => 0x00, # default ok, number plan indicator address_range => '', # default ok, regex matching nmbrs or die;
- new_transceiver()
- new_transmitter()
- new_receiver()
-
These constructors first construct the object and then bind using given type of bind request. See bind family of methods, below.
- new_listen('localhost', port=>2251)
-
Create new SMPP server object and open socket to listen on given port.
- new_raw() ***
-
Create new SMPP object without creating any socket or cruft.
REQUEST PDU METHODS
Each request PDU method constructs a PDU from list of arguments supplied and sends it to the wire.
If async mode has been enabled (by specifying "async=>1" in the constructor or as an argument to the method), the methods return sequence number of the PDU just sent. This number can be later used to match up the response, like this:
$seq = $smpp->query_sm(message_id => $msg_id) or die;
...
$resp_pdu = $smpp->wait_pdu(Net::SMPP::CMD_query_sm_resp, $seq)
or die;
die "Response indicated error: " . $resp_pdu->explain_status()
if $resp_pdu->status;
If async mode is not enabled (i.e. "async=>1" was not specified neither in constructor nor the method), the method will wait for the corresponding response and return Net::SMPP::PDU object representing that response. The application should check the outcome of the operation from the status field of the response PDU, like this:
$resp_pdu = $smpp->query_sm(message_id => $msg_id) or die;
die "Response indicated error: " . $resp_pdu->explain_status()
if $resp_pdu->status;
All request PDU methods optionally take "seq=>123" argument that allows explicit specification of the sequence number. The default is to increment internally stored sequence number by one and use that.
Most PDUs have mandatory parameters and optional parameters. If mandatory parameter is not supplied, it is inherited from the smpp object. This means that the parameter can either be set as an argument to the constructor or it is inherited from built in defaults in the innards of Net::SMPP (see Default
table from line 217 onwards). Some mandatory parameters can not be defaulted - if they are missing a die results. In descriptions below, defaultable mandatory parameters are show with the default value and comment indicating that its defaultable.
Optional parameters can be supplied to all PDUs (although the SMPP spec does not allow optional parameters for some PDUs, the module does not check for this) by listing them in the order that they should be appended to the end of the PDU. Optional parameters can not be defaulted - if the parameter is not supplied, it simply is not included in the PDU. Optional parameters are not supported by previous versions of the SMPP protocol (up to and including 3.3). Applications wishing to be downwards compatible should not make use of optional parameters.
- alert_notification() (4.12.1, p.108)
-
Sent by SMSC to ESME when particular mobile subscriber has become available. source_addr specifies which mobile subscriber. esme_addr specifies which esme the message is destined to. Alert notifications can arise if delivery pending flag had been set for the subscriber from previous data_sm operation.
There is no response PDU.
$smpp->alert_notification( source_addr_ton => 0x00, # default ok source_addr_npi => 0x00, # default ok source_addr => '', # default ok esme_addr_ton => 0x00, # default ok esme_addr_npi => 0x00, # default ok esme_addr => $esme_addr, # mandatory ) or die;
- bind_transceiver() (4.1.5, p.51)
- bind_transmitter() (4.1.1, p.46)
- bind_receiver() (4.1.3, p.48)
-
Bind family of methods is used to authenticate the client (ESME) to the server (SMSC). Usually bind happens as part of corresponding constructor
new_transceiver()
,new_transmitter()
, ornew_receiver()
so these methods are rarely called directly. These methods take a plethora of options, which are largely the same as the options taken by the constructors and can safely be defaulted.$smpp->bind_transceiver( system_id => 'username', # usually needed (default '') password => 'secret', # usually needed (default '') system_type => '', # default ok, often not needed interface_version => 0x34, # default ok, almost never needed addr_ton => 0x00, # default ok, type of number unkwn addr_npi => 0x00, # default ok, number plan indic. address_range => '', # default ok, regex matching tels ) or die;
Typically it would be called like:
$resp_pdu = $smpp->bind_transceiver(system_id => 'username', password => 'secret') or die; die "Response indicated error: " . $resp_pdu->explain_status() if $resp_pdu->status;
or to inform SMSC that you can handle all Spanish numbers:
$resp_pdu = $smpp->bind_transceiver(system_id => 'username', password => 'secret', address_range => '^\+?34') or die; die "Response indicated error: " . $resp_pdu->explain_status() if $resp_pdu->status;
- cancel_sm() (4.9.1, p.98)
-
Issued by ESME to cancel one or more short messages. Two principal modes of operation are:
1. if message_id is supplied, other fields can be left at defaults. This mode deletes just one message.
2. if message_id is not supplied (or is empty string), then the other fields must be supplied and all messages matching the criteria reflected by the other fields are deleted.
$smpp->cancel_sm( service_type => '', # default ok message_id => '', # default ok, but often given source_addr_ton => 0x00, # default ok source_addr_npi => 0x00, # default ok source_addr => '', # default ok dest_addr_ton => 0x00, # default ok dest_addr_npi => 0x00, # default ok destination_addr => '', # default ok ) or die;
For example
$resp_pdu = $smpp->submit_sm(destination_addr => '+447799658372', short_message => 'test message') or die; die "Response indicated error: " . $resp_pdu->explain_status() if $resp_pdu->status; $msg_id = $resp_pdu->message_id; $resp_pdu = $smpp->query_sm(message_id => $msg_id) or die; die "Response indicated error: " . $resp_pdu->explain_status() if $resp_pdu->status; print "Message state is $resp_pdu->{message_state}\n"; $resp_pdu = $smpp->replace_sm(message_id => $msg_id, short_message => 'another test') or die; die "Response indicated error: " . $resp_pdu->explain_status() if $resp_pdu->status; $resp_pdu = $smpp->cancel_sm(message_id => $msg_id) or die; die "Response indicated error: " . $resp_pdu->explain_status() if $resp_pdu->status;
- data_sm() (4.7.1, p.87)
-
Newer alternative to submit_sm and deliver_sm. In addition to that data_sm can be used to pass special messages such as SMSC Delivery Receipt, SME Delivery Acknowledgement, SME Manual/User Acknowledgement, Intermediate notification.
Unlike submit_sm and deliver_sm, the short_message parameter is not mandatory. Never-the-less, the optional parameter message_payload must be supplied for things to work correctly.
$smpp->data_sm( service_type => '', # default ok source_addr_ton => 0x00, # default ok source_addr_npi => 0x00, # default ok source_addr => '', # default ok dest_addr_ton => 0x00, # default ok dest_addr_npi => 0x00, # default ok destination_addr => $tel, # mandatory esm_class => 0x00, # default ok registered_delivery => 0x00, #default ok data_coding => 0x00, # default ok message_payload => 'test msg', # opt, but needed ) or die;
For example
$resp_pdu = $smpp->data_sm(destination_addr => '+447799658372', message_payload => 'test message') or die; die "Response indicated error: " . $resp_pdu->explain_status() if $resp_pdu->status;
- deliver_sm() (4.6.1, p.79)
-
Issued by SMSC to send message to an ESME. Further more SMSC can transfer following special messages: 1. SMSC delivery receipt, 2. SME delivery acknowledgement, 3. SME Manual/User Acknowledgement, 4. Intermediate notification. These messages are sent in response to SMS message whose registered_delivery parameter requested them.
If message data is longer than 254 bytes, the optional parameter
message_payload
should be used to store the message andshort_message
should be set to empty string. N.B. although protocol has mechanism for sending fairly large messages, the underlying mobile network usually does not support very large messages. GSM supports only up to 160 characters, other systems 128 or even just 100 characters.$smpp->deliver_sm( service_type => '', # default ok source_addr_ton => 0x00, # default ok source_addr_npi => 0x00, # default ok source_addr => '', # default ok dest_addr_ton => 0x00, # default ok dest_addr_npi => 0x00, # default ok destination_addr => $t, # mandatory esm_class => 0x00, # default ok protocol_id => 0x00, # default ok on CDMA,TDMA # on GSM value needed priority_flag => 0x00, # default ok schedule_delivery_time => '', # default ok validity_period => '', # default ok registered_delivery => 0x00, # default ok replace_if_present_flag => 0x00, # default ok data_coding => 0x00, # default ok sm_default_msg_id => 0x00, # default ok short_message => '', # default ok, but # usually supplied ) or die;
For example
$resp_pdu = $smpp->deliver_sm(destination_addr => '+447799658372', short_message => 'test message') or die; die "Response indicated error: " . $resp_pdu->explain_status() if $resp_pdu->status;
- enquire_link() (4.11.1, p.106)
-
Used by either ESME or SMSC to "ping" the other side. Takes no parameters.
$smpp->enquire_link() or die;
- outbind() (4.1.7, p.54, 2.2.1, p.16)
-
Used by SMSC to signal ESME to originate a
bind_receiver
request to the SMSC.system_id
andpassword
authenticate the SMSC to the ESME. Theoutbind
is used when SMSC initiates the TCP session and needs to trigger ESME to perform abind_receiver
. It is not needed if the ESME initiates the TCP connection (e.g. sec 2.7.1, p.27).There is not response PDU for
outbind
, instead the ESME is expected to issuebind_receiver
.$smpp->outbind( system_id => '', # default ok, but usually given password => '', # default ok, but usually given ) or die;
- query_sm() (4.8.1, p.95)
-
Used by ESME to query status of a submitted short message. Both message_id and source_addr must match (if source_addr was defaulted to NULL during submit, it must be NULL here, too). See example near
cancel_sm
.$smpp->query_sm( message_id => $msg_id, # mandatory source_addr_ton => 0x00, # default ok source_addr_npi => 0x00, # default ok source_addr => '', # default ok ) or die;
- replace_sm() (4.10.1, p.102)
-
Used by ESME to replace a previously submitted short message, provided it is still pending delivery. Both message_id and source_addr must match (if source_addr was defaulted to NULL during submit, it must be NULL here, too). See example near
cancel_sm
.$smpp->replace_sm( message_id => $msg_id, # mandatory source_addr_ton => 0x00, # default ok source_addr_npi => 0x00, # default ok source_addr => '', # default ok schedule_delivery_time => '', # default ok validity_period => '', # default ok registered_delivery => 0x00, # default ok sm_default_msg_id => 0x00, # default ok short_message => '', # default ok, but # usually supplied ) or die;
- submit_sm() (4.4.1, p.59)
-
Used by ESME to submit short message to the SMSC for onward transmission to the specified short message entity (SME). The submit_sm does not support the transaction message mode.
If message data is longer than 254 bytes, the optional parameter
message_payload
should be used to store the message andshort_message
should be set to empty string. N.B. although protocol has mechanism for sending fairly large messages, the underlying mobile network usually does not support very large messages. GSM supports only up to 160 characters.$smpp->submit_sm( service_type => '', # default ok source_addr_ton => 0x00, # default ok source_addr_npi => 0x00, # default ok source_addr => '', # default ok dest_addr_ton => 0x00, # default ok dest_addr_npi => 0x00, # default ok destination_addr => $t, # mandatory esm_class => 0x00, # default ok protocol_id => 0x00, # default ok on CDMA,TDMA # on GSM value needed priority_flag => 0x00, # default ok schedule_delivery_time => '', # default ok validity_period => '', # default ok registered_delivery => 0x00, # default ok replace_if_present_flag => 0x00, # default ok data_coding => 0x00, # default ok sm_default_msg_id => 0x00, # default ok short_message => '', # default ok, but # usually supplied ) or die;
For example
$resp_pdu = $smpp->submit_sm(destination_addr => '+447799658372', short_message => 'test message') or die; die "Response indicated error: " . $resp_pdu->explain_status() if $resp_pdu->status;
Or
$resp_pdu = $smpp->submit_sm(destination_addr => '+447799658372', short_message => '', message_payload => 'a'x500) or die; die "Response indicated error: " . $resp_pdu->explain_status() if $resp_pdu->status;
- submit_multi() (4.5.1, p.69)
-
Used by ESME to submit short message to the SMSC for onward transmission to the specified short message entities (SMEs). This command is especially destined for multiple recepients.
If message data is longer than 254 bytes, the optional parameter
message_payload
should be used to store the message andshort_message
should be set to empty string. N.B. although protocol has mechanism for sending fairly large messages, the underlying mobile network usually does not support very large messages. GSM supports only up to 160 characters.$smpp->submit_multi( service_type => '', # default ok source_addr_ton => 0x00, # default ok source_addr_npi => 0x00, # default ok source_addr => '', # default ok dest_flag => # default ok [ MULTIDESTFLAG_SME_Address, MULTIDESTFLAG_dist_list, ... ], dest_addr_ton => # default ok [ 0x00, 0x00, ... ], dest_addr_npi => # default ok [ 0x00, 0x00, ... ], destination_addr => # mandatory [ $t1, $t2, ... ], esm_class => 0x00, # default ok protocol_id => 0x00, # default ok on CDMA,TDMA # on GSM value needed priority_flag => 0x00, # default ok schedule_delivery_time => '', # default ok validity_period => '', # default ok registered_delivery => 0x00, # default ok replace_if_present_flag => 0x00, # default ok data_coding => 0x00, # default ok sm_default_msg_id => 0x00, # default ok short_message => '', # default ok, but # usually supplied ) or die;
For example
$resp_pdu = $smpp->submit_multi(destination_addr => [ '+447799658372', '+447799658373' ], short_message => 'test message') or die; die "Response indicated error: " . $resp_pdu->explain_status() if $resp_pdu->status;
The destinations are specified as an array reference. dest_flag, dest_addr_ton, and dest_addr_npi must have same cardinality as destination_addr if they are present. Default for dest_flag is MULTIDESTFLAG_SME_Address, i.e. normal phone number.
- unbind() (4.2, p.56)
-
Used by ESME to unregisters ESME from SMSC. Does not take any parameters.
$smpp->unbind() or die;
RESPONSE PDU METHODS
Response PDU methods are used to indicate outcome of requested commands. Typically these methods would be used by someone implementing a server (SMSC).
Response PDUs do not have separate asynchronous behaviour pattern.
- bind_receiver_resp()
- bind_transmitter_resp()
- bind_transceiver_resp()
-
$smpp->bind_transceiver_resp( system_id => '', # default ok ) or die;
- cancel_sm_resp() (4.9.2, p.100)
-
$smpp->cancel_sm_resp() or die;
- data_sm_resp()
-
$smpp->data_sm_resp(message_id => $msg_id) or die;
- deliver_sm_resp()
-
$smpp->deliver_sm_resp(message_id => $msg_id) or die;
- enquire_link_resp() (4.11.2, p.106)
-
$smpp->enquire_link_resp() or die;
- generic_nack() (4.3.1, p.57)
-
$smpp->generic_nack() or die;
- query_sm_resp() (4.6.2, p.96)
-
$smpp->query_sm_resp( message_id => $msg_id, # mandatory final_date => '', # default ok message_state => $state, # mandatory error_code => 0x00, # default ok ) or die;
- replace_sm_resp() (4.10.2, p.104)
-
$smpp->replace_sm_resp() or die;
- submit_sm_resp() (4.4.2, p.67)
-
$smpp->submit_sm_resp(message_id => $msg_id) or die;
- submit_multi_resp() (4.5.2, p.76)
-
$smpp->submit_multi_resp(message_id => $msg_id dest_addr_ton => [], # default ok dest_addr_npi => [], # default ok destination_addr => [], # mandatory error_status_code => [], # mandatory ) or die;
- unbind_resp() (4.2.2, p.56)
-
$smpp->unbind_resp() or die;
OTHER METHODS
- read_pdu()
-
Reads a PDU from stream and analyzes it into Net::SMPP::PDU object (if PDU is of known type). Blocks until PDU is available. If you do not want it to block, do select on the socket to make sure some data is available (unfortunately some data may be available, but not enough, so it can still block).
read_pdu() is very useful for implementing main loop of SMSC where unknown PDUs must be received in random order and processed.
$pdu = $smpp->read_pdu() or die;
- wait_pdu()
-
Reads PDUs from stream and handles or discards them until matching PDU is found. Blocks until success. Typically wait_pdu() is used internally by request methods when operating in synchronous mode. The PDUs to handle are specified by
${*$me}{handlers}-
{$command_id}>. The handlers table is initially populated to handle enquiry_link PDUs automatically, but this can be altered usinghandlers
argument to constructor.$pdu = $smpp->wait_pdu($cmd_id_to_wait, $seq_to_wait) or die;
- set_version($vers)
-
Sets the protocol version of the object either to 0x40 or 0x34. Its important to use this method instead of altering $smpp->{smpp_version} field directly because there are several other fields that have to be set in tandem.
EXAMPLES
Typical client:
use Net:SMPP;
$smpp = Net::SMPP->new_transciever('smsc.foo.net', Port=>2552) or die;
$resp_pdu = $smpp->submit_sm(desination_addr => '447799658372',
data => 'test message') or die;
***
Typical server, run from inetd:
***
#4#cut =head1 VERSION 4.0 SUPPORT
Net::SMPP was originally written for version 3.4 of SMPP protocol. I have since then gotten specifications for an earlier protocol, the version 4.0 (Logical, eh? (pun intended)). In my understanding the relevant differences are as follows (n.b. (ok) marks difference that has already been implemented):
1. A reserved (always 0x00000000) field in message header (v4 p. 21) (ok)
2. Connection can not be opened in transciever mode (this module will not enforce this restriction) (ok)
3. Command versioning. Version 0x01 == V4 (v4 p. 22) (ok)
4. Support for extended facilities has to be requested during bind (ok)
5. bind_* PDUs have facilities_mask field (v4 p. 25) (ok)
6. bind_*_resp PDUs have facilities_mask field (v4 p. 27) (ok)
7. outbind lacks system ID field (v4 p.30, v3.4 p. 54) (ok)
8. submit_sm lacks service_type and adds message_class (v4 p. 34, v3.4 p. 59) (ok)
9. submit_sm: telematic_interworking == protocol_id (ok)
10. submit_sm: starting from number of destinations and destination address the message format is substantially different. Actually the message format is somewhat similar to v3.4 submit_multi. (ok)
11. submit_sm: validity period encoded as an integer relative offset (was absolute time as C string) (ok)
12. submit_sm: replace_if_present flag missing (ok)
13. submit_sm: sm_length field is 2 octets (was one) (ok)
14. submit_sm_resp is completely different, but actually equal to v3.4 submit_multi_resp (v4 p. 37, v3.4 pp. 67,75) (ok)
15. submit_sm vs submit_multi: lacks service_type, adds message_class (ok)
16. submit_sm vs submit_multi: number_of_dests increased from 1 byte to 4 (ok)
17. submit_sm vs submit_multi: esm_class lacking, adds messaging_mode and msg_reference (ok)
18. submit_sm vs submit_multi: telematic_interworking == protocol_id (ok)
19. submit_sm vs submit_multi: replace_if_present missing (ok)
20. submit_sm vs submit_multi: sm_length is 2 bytes (was one) (ok)
21. submit_sm vs submit_multi: lacks dest_flag and distribution_list_name (ok)
22. deliver_sm: lacks service_type (ok)
23. deliver_sm: lacks esm_class, adds msg_reference and message_class (ok)
24. deliver_sm: telematic_interworking == protocol_id (ok)
25. deliver_sm: priority_level == priority_flag (ok)
26. deliver_sm: submit_time_stamp == schedule_delivery_time (ok)
27. deliver_sm: lacks validity_period, registered_delivery, and replace_if_present_flag (ok)
28. deliver_sm: lacks sm_default_msg_id (ok)
29. deliver_sm: sm_length is now 2 bytes (was one) (ok)
30. deliver_sm_resp: lacks message_id (v3.4 has the field, but its unused) (ok)
31. New command: delivery_receipt (ok)
32. New response: delivery_receipt_resp (ok)
33. query_sm: dest_addr_* fields added (v4 p. 46, v3.4 p. 95) (ok)
34. query_sm_resp: error_code renamed to network_error_code and increased in size from one to 4 bytes (ok)
35. cancel_sm: service_type renamed to message_class, also type changed (ok)
36. replace_sm: added dest_addr_* fields (ok)
37. replace_sm: data type of validity_period changed (ok)
38. replace_sm: added data_coding field (ok)
39. replace_sm: sm_length field increased from one to two bytes (ok)
40. In v3.4 command code 0x0009 means bind_transciever, in v4.0 this very same code means delivery_receipt (bummer) (ok)
41. In v3.4 enquire_link is 0x0015 where as in v4 it is 0x000a (ok)
To create version 4 connection, you must specify smpp_version => 0x40 and you should not bind as transciever as that is not supported by the specification.
As v3.4 specifications seem more mature I recommend that where attributes have been renamed between v4 and v3.4 you stick to using v3.4 names. I have tried to provide compatibility code where ever possible.
#4#end
ERRORS
Please consult status_code
table in the beginning of the source code or SMPP specification section 5.1.3, table 5-2, pp.112-114.
EXPORT
None by default.
TESTS / WHAT IS KNOWN TO WORK
Interoperates with itself.
*** No real interoperability tests have been performed yet
TO DO AND BUGS
- read_pdu() can block even if socket selects for reading.
- The submit_multi command has not been implemented.
AUTHOR AND COPYRIGHT
Sampo Kellomaki <sampo@symlabs.com>
Net::SMPP is copyright (c) 2001 by Sampo Kellomaki, All rights reserved. Portions copyright (c) 2001 by Symlabs, All rights reserved. You may use and distribute Net::SMPP under same terms as perl itself.
NET::SMPP COMES WITH ABSOLUTELY NO WARRANTY.
PLUG
This work was sponsored by Symlabs, the LDAP and directory experts (www.symlabs.com).