RE: SMPP data_sm implementation for MT messages
Michael Zervakis <[email protected]>
| Newsgroups | gmane.comp.mobile.kannel.devel |
|---|---|
| Message-ID | <[email protected]> |
Hi , This is a proposed implementation for sending data_sm PDUs that also enforces SMPP requirement for having sm_length=0 when using message_payload TLV. To send a data_sm PDU the sendsms request should be like meta-data?smsc-type=smpp_data_sm?. *msg_to_pdu() was replaced by two functions *msg_to_sm_pdu() and *msg_to_datasm_pdu() for submit_sm and data_sm() PDUs respectively and handle_pdu() got a new case for incoming data_sm_resp PDU. BR, Michael Zervakis -----Original Message----- From: Alexander Malysh [mailto:[email protected]] On Behalf Of Alexander Malysh Sent: Friday, November 27, 2009 5:04 PM To: Michael Zervakis Cc: Kannel Devel; Alejandro Guerrieri Subject: Re: SMPP data_sm implementation for MT messages where do you have message_payload extracted to user? that is simple: MT(data_sm) -> sendsms?text=ABC&metadata=?smpp?pdu_type=data_sm... -> data_sm.message_payload=ABC MT(submit_sm) -> sendsms?text=ABC... -> submit_sm.short_message=ABC MO(data_sm) -> data_sm.message_payload=ABC -> receivesms?text=ABC&metadata=?smpp?pdu_type=data_sm MO(submit_sm) -> submit_sm.short_message=ABC -> receivesms?text=ABC If user set for MT text=ABC&metadata=?smpp?pdu_type=data_sm&message_payload=XXX then it's undefined and we are free to choose which one to use and I would prefer to use text as message_payload... Hope that's clear. Thanks, Alexander Malysh Am 27.11.2009 um 15:21 schrieb Michael Zervakis: > > Let's assume that we follow Alex's recommendation "meta-data=?smpp?operation=data_sm&..." and if operation is omitted we use submit_sm as default. > > > We should clarify what should happen to "text=xxxx" if set and this should affect both submit_sm and data_sm operations as SMPP specs state that short_message and message_payload cannot coexist in a PDU (sm_length should be zero if message_payload is used). I can think of three cases here: > > 1) When "text" has a value and "message_payload" is not set. For submit_sm no need to change anything. For data_sm we append meta-data with message_payload and set the value of "text" to it (example: "text=XXXX&meta-data=?smpp?operation=data_sm"). > 2) When both "text" and "message_payload" have values. For submit_sm operation "text" value is set to null (so "sm_length" is set to 0 and we don't break specs) and we use the provided "message_payload" value. For data_sm operation we simply ignore "text" value. > > 3) When "message_payload" has a value and "text" is not set. Normal case doesn't break specs. > > > > > >> -----Original Message----- >> From: Alexander Malysh [mailto:[email protected]] On Behalf Of > Alexander Malysh >> Sent: Friday, November 27, 2009 3:32 PM >> To: Michael Zervakis >> Cc: [email protected]; [email protected] >> Subject: Re: SMPP data_sm implementation for MT messages > > >> Hi, > > >> why not just use metadata=?smpp?operation=data_sm&... ? > >> then you can check in smsc_smpp whether submit_sm or data_sm should be used. > > >> Whether you have to use message_payload or short_message is > implementation details that > >> should not be exported to user interface. > > >> Thanks, > >> Alexander Malysh > > >> Am 27.11.2009 um 13:00 schrieb Michael Zervakis: > > >> > Data_sm PDU cannot contain a short_message field. Actually data_sm > contains only TLVs and instead of "short_message" field we should use TLV "message_payload" to send text. As a result text=xxxx is obsolete when sending data_sm PDU. If we use data=xxxx what would be the value of data since all necessary data will be included in "meta-data=?smpp?" ? > >> > > >> > > >> >> -----Original Message----- > >> >> From: Alejandro Guerrieri [mailto:[email protected]] > >> >> Sent: Friday, November 27, 2009 12:04 PM > >> >> To: Michael Zervakis > >> >> Cc: [email protected] > >> >> Subject: Re: SMPP data_sm implementation for MT messages > >> > > >> > > >> > >What about using "data=xxxx" instead of "text=xxxx" ? > >> > > >> > >-- > >> > > >> > >Alejandro Guerrieri > >> > > >> > >[email protected] > >> > > >> > > > >> > > > >> > > > >> > >On 27/11/2009, at 10:00, Michael Zervakis wrote: > >> > > >> > > > >> > >> Data_sm can be used as an alternate of submit_sm when transmitting > >> > >> optional parameters (meta-data) and some carriers require the use of > >> > >> data_sm for MT charging applications. > >> > > >> > >> Since Kannel is not implementing this feature it's a good idea to > >> > >> start a discussion on how this could be implemented. > >> > > >> > >> > >> > >> First of all it's obvious that "static int send_messages()" at gw > >> > > >> > >> \smsc\smsc_smpp.c must be able to differentiate msgs that need to be > >> > >> sent as data_sm. > >> > > >> > >> I can think of two ways to achieve this: > >> > > >> > >> 1) Alter MSG definition to inlcude a new parameter that defines type > >> > >> of message Data or normal SMS > >> > > >> > >> Possible ways to use the new parameter could be the following > >> > > >> > >> /cgi-bin/sendsms?from=1111&to=2222&<new parameter>=data&meta-data=? > >> > > >> > >> smpp?key=value > >> > > >> > >> /cgi-bin/senddata?from=1111&to=2222&meta-data=?smpp?key=value > >> > > >> > >> 2) Leave MSG definition untouched and use meta-data to mark msg as > >> > >> data > >> > > >> > >> /cgi-bin/sendsms?from=1111&to=2222&meta-data=?smpp?<new > >> > >> parameter>=data&key=value > >> > > >> > >> > >> > >> Finally a new function has to be defined at gw\smsc\smsc_smpp.c to > >> > >> build data_sm pdu from msg for example "static SMPP_PDU > >> > >> *dmsg_to_pdu(SMPP *smpp, Msg *msg)" > >> > > >> > >> and function "static int handle_pdu()" at gw\smsc\smsc_smpp.c has to > >> > >> be modified to include a case for data_sm_resp PDU. > >> > > >> > >> > >> > >> Any comments? > >> > > >> > >> > >> > >> > >> > > >
data_sm.patch
(text/plain, 19.6 KB)
Index: doc/userguide/userguide.xml
===================================================================
--- doc/userguide/userguide.xml (revision 4833)
+++ doc/userguide/userguide.xml (working copy)
@@ -9781,12 +9781,14 @@
</sect3>
</sect2>
<sect2>
- <title>MT Messages</title>
+ <title>MT Messages SUBMIT_SM or DATA_SM</title>
<para>To send into an MT messages the <literal>meta-data</literal> parameter should be used.</para>
<para>The format used to pass the data has 2 parts: The <literal>?smsc-type?</literal> (surrounded by question marks),
- which specify the kind of smsc receiving the data (at the moment only <literal>smpp</literal> is implemented) and then a set of key/value
- pairs with the data to be transmitted. Extra smsc-types can be added surrounded by question marks and followed by the key/value pairs.</para>
+ which specify the kind of smsc receiving the data and then a set of key/value pairs with the data to be transmitted.
+ Currently only SMPP is implemented with two possible values for <literal>?smsc-type?</literal>: <literal>smpp</literal>
+ for SUBMIT_SM PDUs and <literal>smpp_data_sm</literal>) for DATA_SM PDUs.
+ Extra smsc-types can be added surrounded by question marks and followed by the key/value pairs.</para>
<para>In other words, the data should be coded using the following format, where URLENCODE() implies that the data between parentheses should
be urlencoded:</para>
@@ -9800,14 +9802,26 @@
<sect3>
<title>Examples</title>
- <para>If we want to send the parameter "my-data" with value "Hello World" to an SMSC over SMPP, we'd use:</para>
+ <para>If we want to send the parameter "my-data" with value "Hello World" to an SMSC over SMPP using SUBMIT_SM PDU, we'd use:</para>
<para>sendsms get-url:</para>
<para><literal>http://localhost:13013/cgi-bin/sendsms?...&meta-data=%3Fsmpp%3Fmy-data%3DHello%2BWorld</literal></para>
+ <para>Similarly if we want to send the above using DATA_SM PDU, we'd use:</para>
+ <para>sendsms get-url:</para>
+ <para><literal>http://localhost:13013/cgi-bin/sendsms?...&meta-data=%3Fsmpp_data_sm%3Fmy-data%3DHello%2BWorld</literal></para>
<para>sendsms post:</para>
<para>Send <literal>?smpp?my-data=Hello+World</literal> on the <literal>X-Kannel-Meta-Data</literal> header</para>
- <para>XML:</para>
+ <para>XML: SUBMIT_SM</para>
<para><literal><meta-data>?smpp?my-data=Hello+World</meta-data></literal></para>
+ <para>XML: DATA_SM</para>
+ <para><literal><meta-data>?smpp_data_sm?my-data=Hello+World</meta-data></literal></para>
</sect3>
+
+ </sect3>
+ <title>SMPP TLV message_payload (0x0424)</title>
+ <para>SMPP message_payload TLV is an alternative to submit_sm short_message when sending messages longer than 255 octets.
+ When sending submit_sm PDU with message_payload then short_message should be null. Kannel enforces this restriction
+ by ignoring supplied values for <literal>text</literal> if <literal>message_payload</literal> TLV is present.</para>
+ </sect3>
</sect2>
</sect1>
</appendix>
Index: gw/smsc/smsc_smpp.c
===================================================================
--- gw/smsc/smsc_smpp.c (revision 4833)
+++ gw/smsc/smsc_smpp.c (working copy)
@@ -747,14 +747,12 @@
}
-static SMPP_PDU *msg_to_pdu(SMPP *smpp, Msg *msg)
+static SMPP_PDU *msg_to_sm_pdu(SMPP_PDU *pdu, Msg *msg, SMPP *smpp)
{
- SMPP_PDU *pdu;
+
int validity;
-
- pdu = smpp_pdu_create(submit_sm,
- counter_increase(smpp->message_id_counter));
-
+
+
pdu->u.submit_sm.source_addr = octstr_duplicate(msg->sms.sender);
pdu->u.submit_sm.destination_addr = octstr_duplicate(msg->sms.receiver);
@@ -876,9 +874,41 @@
/*
* set data segments and length
*/
-
- pdu->u.submit_sm.short_message = octstr_duplicate(msg->sms.msgdata);
-
+
+ /*
+ If a message contains both msg_data and meta_data and within meta_data is contained the tlv message_payload
+ then ignore smg_data field forward message's meta_data and print a warning message
+ */
+
+
+ if((octstr_len(msg->sms.msgdata)) && (octstr_len(msg->sms.meta_data)))
+ {
+ debug("bb.sms.smpp", 0, "msg->sms.msgdata = [%s] and msg->sms.meta_data !=[%s]", octstr_get_cstr(msg->sms.msgdata),octstr_get_cstr(msg->sms.meta_data));
+
+ if(octstr_search(msg->sms.meta_data, octstr_imm("message_payload"),0)!=-1)
+ {
+ pdu->u.submit_sm.short_message == NULL;
+ pdu->u.submit_sm.sm_length = 0;
+ warning(0, "SMPP[%s]: Ignoring msg->sms.msgdata = [%s] because msg->sms.meta_data(message_payload)= [%s] TLV message_payload was found ",
+ octstr_get_cstr(smpp->conn->id),octstr_get_cstr(msg->sms.msgdata),octstr_get_cstr(msg->sms.meta_data));
+
+ }
+ else
+ {
+ pdu->u.submit_sm.short_message = octstr_duplicate(msg->sms.msgdata);
+ pdu->u.submit_sm.sm_length = octstr_len(pdu->u.submit_sm.short_message);
+
+ }
+ }
+ else
+ {
+ pdu->u.submit_sm.short_message = octstr_duplicate(msg->sms.msgdata);
+ pdu->u.submit_sm.sm_length = octstr_len(pdu->u.submit_sm.short_message);
+
+ }
+
+ /*pdu->u.submit_sm.short_message = octstr_duplicate(msg->sms.msgdata);*/
+
/*
* only re-encoding if using default smsc charset that is defined via
* alt-charset in smsc group and if MT is not binary
@@ -908,9 +938,9 @@
if (octstr_len(msg->sms.udhdata)) {
octstr_insert(pdu->u.submit_sm.short_message, msg->sms.udhdata, 0);
}
-
- pdu->u.submit_sm.sm_length = octstr_len(pdu->u.submit_sm.short_message);
-
+
/*
* check for validity and defered settings
* were message value has higher priiority then smsc config group value
@@ -958,6 +988,228 @@
}
+/* Function to create a data_sm pdu
+
+ Pdu fields:
+
+ (common to both sumbit_sm and data_sm)
+ 1. command length
+ 2. command id
+ 3. command status
+ 4. sequence number
+ 5. service type
+ 6. source_addr_ton
+ 7. source_addr_npi
+ 8. source_addr
+ 9. dest_addr_ton
+ 10. dest_addr_npi
+ 11.destnation_addr
+ 12. esm_class
+ 13. registered_delivery
+ 14. data_coding
+ 15. Optional TLVs
+
+ */
+
+static SMPP_PDU *msg_to_datasm_pdu(SMPP_PDU *pdu, Msg *msg, SMPP *smpp)
+{
+
+
+ pdu->u.data_sm.source_addr = octstr_duplicate(msg->sms.sender);
+
+ pdu->u.data_sm.destination_addr = octstr_duplicate(msg->sms.receiver);
+
+
+ /* Set the service type of the outgoing message. We'll use the config
+ * directive as default and 'binfo' as specific parameter. */
+ pdu->u.data_sm.service_type = octstr_len(msg->sms.binfo) ?
+ octstr_duplicate(msg->sms.binfo) : octstr_duplicate(smpp->service_type);
+
+
+
+ /* Check for manual override of source ton and npi values */
+ if(smpp->source_addr_ton > -1 && smpp->source_addr_npi > -1) {
+ pdu->u.data_sm.source_addr_ton = smpp->source_addr_ton;
+ pdu->u.data_sm.source_addr_npi = smpp->source_addr_npi;
+ debug("bb.sms.smpp", 0, "SMPP[%s]: Manually forced source addr ton = %d, source add npi = %d",
+ octstr_get_cstr(smpp->conn->id), smpp->source_addr_ton,
+ smpp->source_addr_npi);
+ } else {
+ /* setup default values */
+ pdu->u.data_sm.source_addr_ton = GSM_ADDR_TON_NATIONAL; /* national */
+ pdu->u.data_sm.source_addr_npi = GSM_ADDR_NPI_E164; /* ISDN number plan */
+ }
+
+ if (pdu->u.data_sm.source_addr && smpp->autodetect_addr) {
+ /* lets see if its international or alphanumeric sender */
+ if (octstr_get_char(pdu->u.data_sm.source_addr, 0) == '+') {
+ if (!octstr_check_range(pdu->u.data_sm.source_addr, 1, 256, gw_isdigit)) {
+ pdu->u.data_sm.source_addr_ton = GSM_ADDR_TON_ALPHANUMERIC; /* alphanum */
+ pdu->u.data_sm.source_addr_npi = GSM_ADDR_NPI_UNKNOWN; /* short code */
+ if (smpp->alt_addr_charset) {
+ if (octstr_str_case_compare(smpp->alt_addr_charset, "gsm") == 0) {
+ /* @ would break PDU if converted into GSM*/
+ octstr_replace(pdu->u.data_sm.source_addr, octstr_imm("@"), octstr_imm("?"));
+ charset_utf8_to_gsm(pdu->u.data_sm.source_addr);
+ } else if (charset_convert(pdu->u.data_sm.source_addr, SMPP_DEFAULT_CHARSET, octstr_get_cstr(smpp->alt_addr_charset)) != 0)
+ error(0, "Failed to convert source_addr from charset <%s> to <%s>, will send as is.",
+ SMPP_DEFAULT_CHARSET, octstr_get_cstr(smpp->alt_addr_charset));
+ }
+ } else {
+ /* numeric sender address with + in front -> international (remove the +) */
+ octstr_delete(pdu->u.data_sm.source_addr, 0, 1);
+ pdu->u.data_sm.source_addr_ton = GSM_ADDR_TON_INTERNATIONAL;
+ }
+ } else {
+ if (!octstr_check_range(pdu->u.submit_sm.source_addr,0, 256, gw_isdigit)) {
+ pdu->u.data_sm.source_addr_ton = GSM_ADDR_TON_ALPHANUMERIC;
+ pdu->u.data_sm.source_addr_npi = GSM_ADDR_NPI_UNKNOWN;
+ if (smpp->alt_addr_charset) {
+ if (octstr_str_case_compare(smpp->alt_addr_charset, "gsm") == 0) {
+ /* @ would break PDU if converted into GSM */
+ octstr_replace(pdu->u.data_sm.source_addr, octstr_imm("@"), octstr_imm("?"));
+ charset_utf8_to_gsm(pdu->u.data_sm.source_addr);
+ } else if (charset_convert(pdu->u.data_sm.source_addr, SMPP_DEFAULT_CHARSET, octstr_get_cstr(smpp->alt_addr_charset)) != 0)
+ error(0, "Failed to convert source_addr from charset <%s> to <%s>, will send as is.",
+ SMPP_DEFAULT_CHARSET, octstr_get_cstr(smpp->alt_addr_charset));
+ }
+ }
+ }
+ }
+
+
+ /* Check for manual override of destination ton and npi values */
+ if (smpp->dest_addr_ton > -1 && smpp->dest_addr_npi > -1) {
+ pdu->u.data_sm.dest_addr_ton = smpp->dest_addr_ton;
+ pdu->u.data_sm.dest_addr_npi = smpp->dest_addr_npi;
+ debug("bb.sms.smpp", 0, "SMPP[%s]: Manually forced dest addr ton = %d, dest add npi = %d",
+ octstr_get_cstr(smpp->conn->id), smpp->dest_addr_ton,
+ smpp->dest_addr_npi);
+ } else {
+ pdu->u.data_sm.dest_addr_ton = GSM_ADDR_TON_NATIONAL; /* national */
+ pdu->u.data_sm.dest_addr_npi = GSM_ADDR_NPI_E164; /* ISDN number plan */
+ }
+
+ /*
+ * if its a international number starting with +, lets remove the
+ * '+' and set number type to international instead
+ */
+ if (octstr_get_char(pdu->u.data_sm.destination_addr,0) == '+') {
+ octstr_delete(pdu->u.data_sm.destination_addr, 0,1);
+ pdu->u.data_sm.dest_addr_ton = GSM_ADDR_TON_INTERNATIONAL;
+ }
+
+ /* check length of src/dst address */
+ if (octstr_len(pdu->u.data_sm.destination_addr) > 20 ||
+ octstr_len(pdu->u.data_sm.source_addr) > 20) {
+ smpp_pdu_destroy(pdu);
+ return NULL;
+ }
+
+ /*
+ * set the data coding scheme (DCS) field
+ * check if we have a forced value for this from the smsc-group.
+ * Note: if message class is set, then we _must_ force alt_dcs otherwise
+ * dcs has reserved values (e.g. mclass=2, dcs=0x11). We check MWI flag
+ * first here, because MWI and MCLASS can not be set at the same time and
+ * function fields_to_dcs check MWI first, so we have no need to force alt_dcs
+ * if MWI is set.
+ */
+ if (msg->sms.mwi == MWI_UNDEF && msg->sms.mclass != MC_UNDEF)
+ pdu->u.data_sm.data_coding = fields_to_dcs(msg, 1); /* force alt_dcs */
+ else
+ pdu->u.data_sm.data_coding = fields_to_dcs(msg,
+ (msg->sms.alt_dcs != SMS_PARAM_UNDEFINED ?
+ msg->sms.alt_dcs : smpp->conn->alt_dcs));
+
+
+ /*
+ * set the esm_class field
+ * default is store and forward, plus udh and rpi if requested
+ */
+ pdu->u.data_sm.esm_class = ESM_CLASS_SUBMIT_STORE_AND_FORWARD_MODE;
+ if (octstr_len(msg->sms.udhdata))
+ pdu->u.data_sm.esm_class = pdu->u.submit_sm.esm_class |
+ ESM_CLASS_SUBMIT_UDH_INDICATOR;
+ if (msg->sms.rpi > 0)
+ pdu->u.data_sm.esm_class = pdu->u.submit_sm.esm_class |
+ ESM_CLASS_SUBMIT_RPI;
+
+
+ /* ask for the delivery reports if needed */
+ if (DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask))
+ pdu->u.data_sm.registered_delivery = 1;
+ else if (DLR_IS_FAIL(msg->sms.dlr_mask) && !DLR_IS_SUCCESS(msg->sms.dlr_mask))
+ pdu->u.data_sm.registered_delivery = 2;
+
+ if (DLR_IS_INTERMEDIATE(msg->sms.dlr_mask))
+ pdu->u.data_sm.registered_delivery += 16;
+
+
+
+ /* set more messages to send */
+ if (smpp->version > 0x33 && msg->sms.msg_left > 0)
+ pdu->u.data_sm.more_messages_to_send = 1;
+
+ dict_destroy(pdu->u.data_sm.tlv);
+
+ /* search within meta_data group for smpp_data_sm */
+ pdu->u.data_sm.tlv = meta_data_get_values(msg->sms.meta_data, "smpp_data_sm");
+
+ /*pdu->u.data_sm.data_coding = 1;*/
+
+
+ return pdu;
+}
+
+
+
+/* Procedure for deternining the type of pdu to build :
+ 1. Submit_sm message will be build by the msg_to_pdu when the field meta_data is empty
+ or when within the meta_data mesage field there is not a string of the form "pdu_type=data_sm".
+ 2. Else when the meta_data is not empty and contains a string of the form "pdu_type=data_sm" the
+ pdu that is going to be build will be a data_sm pdu.
+ */
+
+static SMPP_PDU *msg_to_pdu(SMPP *smpp, Msg *msg)
+{
+ SMPP_PDU *pdu;
+ unsigned long pdu_type =0;
+
+ /* make sure we are not searching within a null string */
+ if(octstr_len(msg->sms.meta_data) == 0)
+ {
+ pdu_type = submit_sm;
+ debug("bb.sms.smpp", 0, "msg_to_pdu : pdu_type = submit_sm");
+ }
+ else if(octstr_search(msg->sms.meta_data, octstr_imm("?smpp_data_sm?"),0)==-1)
+ {
+ pdu_type = submit_sm;
+ debug("bb.sms.smpp", 0, "msg_to_pdu : pdu_type = submit_sm");
+ }
+ else
+ {
+ pdu_type = data_sm;
+ debug("bb.sms.smpp", 0, "msg_to_pdu : pdu_type = data_sm");
+ }
+
+
+ /* kltsa : 07/07/2010 : submit_sm will now passed as parameter pdu_type */
+ pdu = smpp_pdu_create(pdu_type,counter_increase(smpp->message_id_counter));
+
+ switch (pdu_type)
+ {
+ case data_sm : pdu = msg_to_datasm_pdu(pdu,msg,smpp);
+ break;/*add other cases here*/
+ default: pdu = msg_to_sm_pdu(pdu,msg,smpp);
+ break;
+ }
+
+ return pdu;
+}
+
+
+
static int send_enquire_link(SMPP *smpp, Connection *conn, long *last_sent)
{
SMPP_PDU *pdu;
@@ -1073,7 +1325,21 @@
/* check for write errors */
if (send_pdu(conn, smpp->conn->id, pdu) == 0) {
struct smpp_msg *smpp_msg = smpp_msg_create(msg);
- os = octstr_format("%ld", pdu->u.submit_sm.sequence_number);
+
+ /* Check for sequence number errors depending on pdu type */
+ if(pdu->type == submit_sm)
+ {
+ os = octstr_format("%ld", pdu->u.submit_sm.sequence_number);
+ debug("bb.sms.smpp", 0, "send_messages : pdu->type = submit_sm");
+ }
+ else if(pdu->type == data_sm)
+ {
+ os = octstr_format("%ld", pdu->u.data_sm.sequence_number);
+ debug("bb.sms.smpp", 0, "send_messages : pdu->type = data_sm");
+ }
+ else
+ error(0, "send_messages : :unknown pdu type = [%lu]!\n",pdu->type);
+
dict_put(smpp->sent_msgs, os, smpp_msg);
smpp_pdu_destroy(pdu);
octstr_destroy(os);
@@ -1504,9 +1770,72 @@
msg->sms.smsc_id = octstr_duplicate(smpp->conn->id);
reason = bb_smscconn_receive(smpp->conn, msg);
resp->u.data_sm_resp.command_status = smscconn_failure_reason_to_smpp_status(reason);
- }
- break;
-
+ }
+ break;
+ case data_sm_resp:
+ os = octstr_format("%ld", pdu->u.data_sm_resp.sequence_number);
+ smpp_msg = dict_remove(smpp->sent_msgs, os);
+ octstr_destroy(os);
+ if (smpp_msg == NULL) {
+ warning(0, "SMPP[%s]: SMSC sent data_sm_resp "
+ "with wrong sequence number 0x%08lx",
+ octstr_get_cstr(smpp->conn->id),
+ pdu->u.data_sm_resp.sequence_number);
+ break;
+ }
+ msg = smpp_msg->msg;
+ smpp_msg_destroy(smpp_msg, 0);
+ if (pdu->u.data_sm_resp.command_status != 0) {
+ error(0, "SMPP[%s]: SMSC returned error code 0x%08lx (%s) "
+ "in response to data_sm.",
+ octstr_get_cstr(smpp->conn->id),
+ pdu->u.data_sm_resp.command_status,
+ smpp_error_to_string(pdu->u.data_sm_resp.command_status));
+ reason = smpp_status_to_smscconn_failure_reason(
+ pdu->u.data_sm_resp.command_status);
+
+ /*
+ * check to see if we got a "throttling error", in which case we'll just
+ * sleep for a while
+ */
+ if (pdu->u.data_sm_resp.command_status == SMPP_ESME_RTHROTTLED)
+ time(&(smpp->throttling_err_time));
+ else
+ smpp->throttling_err_time = 0;
+
+ bb_smscconn_send_failed(smpp->conn, msg, reason, octstr_format("0x%08lx/%s", pdu->u.data_sm_resp.command_status,
+ smpp_error_to_string(pdu->u.data_sm_resp.command_status)));
+ --(*pending_submits);
+ } else {
+ Octstr *tmp;
+
+ /* check if msg_id is C string, decimal or hex for this SMSC */
+ if (smpp->smpp_msg_id_type == -1) {
+ /* the default, C string */
+ tmp = octstr_duplicate(pdu->u.data_sm_resp.message_id);
+ } else {
+ if ((smpp->smpp_msg_id_type & 0x01) ||
+ (!octstr_check_range(pdu->u.data_sm_resp.message_id, 0,
+ octstr_len(pdu->u.data_sm_resp.message_id), gw_isdigit))) {
+ tmp = octstr_format("%llu", strtoll( /* hex */
+ octstr_get_cstr(pdu->u.data_sm_resp.message_id), NULL, 16));
+ } else {
+ tmp = octstr_format("%llu", strtoll( /* decimal */
+ octstr_get_cstr(pdu->u.data_sm_resp.message_id), NULL, 10));
+ }
+ }
+
+ /* SMSC ACK.. now we have the message id. */
+ if (DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask))
+ dlr_add(smpp->conn->id, tmp, msg);
+
+ octstr_destroy(tmp);
+ bb_smscconn_sent(smpp->conn, msg, NULL);
+ --(*pending_submits);
+ } /* end if for SMSC ACK */
+ break;
+
case deliver_sm:
/*
* If SMSCConn stopped then send temp. error code