[PATCH] (quasi) non-persistent SMPP - Non solicited feature
"Josh McAllister" <[email protected]>
| Newsgroups | gmane.comp.mobile.kannel.devel |
|---|---|
| Message-ID | <[email protected]> |
This patch adds the ability to set smpp connection idle limits, and max submits per connection. This is a requirement for Sprint's SMSC. Adds 2 smsc group config directives: sms-max-submits and sms-max-idle The patch does not change existing behavior if these are not set, or set to 0. If sms-max-submits is set, it will shutdown the connection (unbind / wait for unbind_resp / etc) once we've submitted sms-max-submits messages, and immediately re-connect. Likewise, sms-max-idle will shutdown and immediately reconnect if we have submitted no messages in > sms-max-idle seconds. Note: the test for max-idle will not be executed while we're sitting around doing nothing, so make sure that enquire-link-interval is set to some number < max seconds you can be late disconnecting. In other words, if sms-max-idle is 30 seconds, and enquire-link-interval is 30 seconds, it could be 1 minute before we disconnect. This is my first patch submission so please be gentle... but of course feedback is appreciated. Thanks, Josh McAllister
non-persistent.patch
(application/octet-stream, 12.7 KB)
Index: gw/smsc/smsc_smpp.c
===================================================================
RCS file: /home/cvs/gateway/gw/smsc/smsc_smpp.c,v
retrieving revision 1.94
diff -u -r1.94 smsc_smpp.c
--- gw/smsc/smsc_smpp.c 1 Jun 2006 21:39:19 -0000 1.94
+++ gw/smsc/smsc_smpp.c 6 Jun 2006 21:43:07 -0000
@@ -157,6 +157,8 @@
int priority; /* set default priority for messages */
int validityperiod;
time_t throttling_err_time;
+ time_t last_msg_time; /*when the last message was sent for this thread*/
+ int msg_count; /*message count for this thread*/
int smpp_msg_id_type; /* msg id in C string, hex or decimal */
int autodetect_addr;
Octstr *alt_charset;
@@ -1014,6 +1016,34 @@
smpp_pdu_destroy(pdu);
octstr_destroy(os);
++(*pending_submits);
+ /*______________________________________
+ This section manages the SMSC
+ connection limits. Two limits are
+ enforced here. The first is an idle
+ time limit. This portion of code
+ merely performs a timestamp. The
+ check will be done by the code that
+ calls this function. If no timeout
+ was specified, no timestamp will be
+ performed. A NULL value for the
+ current time inicates that no timeout
+ was specified.
+
+ The second limitation is on the
+ number of messages that can be sent
+ during a connection session. For this
+ limitation, the code below will
+ perform a "count-down". The initial
+ value to count down from is provided
+ by the caller of this function. If
+ that value is 0, no count down will
+ be performed. The message count has
+ been exceeded if the count gets to
+ "1".
+ ______________________________________*/
+ smpp->last_msg_time = (smpp->last_msg_time)?time(NULL):(time_t)0;
+ smpp->msg_count -= (smpp->msg_count)? 1:0;
+ if(smpp->msg_count == 1) break;
/*
* obey throughput speed limit, if any.
*/
@@ -1265,9 +1295,9 @@
tmp = octstr_duplicate(msgid);
} else {
if (smpp->smpp_msg_id_type & 0x02) {
- tmp = octstr_format("%lu", strtoll(octstr_get_cstr(msgid), NULL, 16));
+ tmp = octstr_format("%ld", strtol(octstr_get_cstr(msgid), NULL, 16));
} else {
- tmp = octstr_format("%lu", strtoll(octstr_get_cstr(msgid), NULL, 10));
+ tmp = octstr_format("%ld", strtol(octstr_get_cstr(msgid), NULL, 10));
}
}
@@ -1481,10 +1511,10 @@
tmp = octstr_duplicate(pdu->u.submit_sm_resp.message_id);
} else {
if (smpp->smpp_msg_id_type & 0x01) {
- tmp = octstr_format("%lu", strtoll( /* hex */
+ tmp = octstr_format("%ld", strtol( /* hex */
octstr_get_cstr(pdu->u.submit_sm_resp.message_id), NULL, 16));
} else {
- tmp = octstr_format("%lu", strtoll( /* decimal */
+ tmp = octstr_format("%ld", strtol( /* decimal */
octstr_get_cstr(pdu->u.submit_sm_resp.message_id), NULL, 10));
}
}
@@ -1723,6 +1753,26 @@
struct io_arg *io_arg;
int transmitter;
Connection *conn;
+ /*______________________________________
+ This variable is used for 2 purposes.
+ Initially, it is the return value
+ obtained from the "read_pdu()"
+ function. A value of "1" indicates a
+ successful read, and causes the read
+ loop to continue. A value of "0" is
+ the normal loop exit condition. A
+ value of "-1" is an error loop exit
+ condition.
+
+ The second use for this variable is
+ to specify that a message timeout or
+ message count limit has been
+ exceeded. This will be the case if
+ (ret == 1). This will be the
+ meaning of the variable as it is
+ evaluated OUTSIDE of the
+ "read_pdu()" loop.
+ ______________________________________*/
int ret;
long last_enquire_sent;
long pending_submits;
@@ -1730,9 +1780,31 @@
SMPP_PDU *pdu;
double timeout;
time_t last_response, last_cleanup;
+ int max_msg_count;
+ int reconnect;
+ time_t max_msg_time;
io_arg = arg;
smpp = io_arg->smpp;
+ /*______________________________________
+ These lines retrive the SMSC
+ connection limits that were packaged
+ up by the caller. For a description
+ of the use of these, see the
+ send_messages() function.
+
+ The values originate in a
+ configuration file. The function that
+ retrieves this information from the
+ configuration file is not easily
+ called from this context. Thus, the
+ values come via the caller of this
+ function and are carried in the smpp
+ structure.
+ ______________________________________*/
+ max_msg_time = smpp->last_msg_time;
+ max_msg_count = smpp->msg_count;
+
transmitter = io_arg->transmitter;
gw_free(io_arg);
@@ -1752,7 +1824,20 @@
pending_submits = -1;
len = 0;
smpp->throttling_err_time = 0;
+
+ /*______________________________________
+ These lines initialize the SMSC
+ limit management variables. The idea
+ is to reset these each time a
+ connection is made.
+ ______________________________________*/
+ if(max_msg_count) smpp->msg_count = max_msg_count + 1;
+ smpp->last_msg_time = (max_msg_time)?time(NULL):(time_t)0;
+ reconnect = 0;
+
+
for (;conn != NULL;) {
+
timeout = last_enquire_sent + smpp->enquire_link_interval
- date_universal_now();
@@ -1763,7 +1848,7 @@
* Read so long as unbind_resp received or timeout passed. Otherwise we have
* double delivered messages.
*/
- if (smpp->quitting) {
+ if (smpp->quitting || reconnect) {
send_unbind(smpp, conn);
last_response = time(NULL);
while(conn_wait(conn, 1.00) != -1 &&
@@ -1783,6 +1868,12 @@
send_enquire_link(smpp, conn, &last_enquire_sent);
+ /*______________________________________
+ To see a description of the use of
+ the "ret" variable, look at the
+ variable's definition at the start of
+ this function.
+ ______________________________________*/
while ((ret = read_pdu(smpp, conn, &len, &pdu)) == 1) {
last_response = time(NULL);
/* Deal with the PDU we just got */
@@ -1807,8 +1898,30 @@
if (transmitter && difftime(time(NULL), smpp->throttling_err_time) > SMPP_THROTTLING_SLEEP_TIME) {
smpp->throttling_err_time = 0;
send_messages(smpp, conn, &pending_submits);
- }
- }
+ }
+ /*______________________________________
+ This test breaks the connection with
+ the server if the message count was
+ exceeded.
+ ______________________________________*/
+ if(smpp->msg_count == 1) {
+ debug("bb.smpp",0, "SMPP %s reached max submits during read_pdu. Reconnecting momentarily.", octstr_get_cstr(smpp->conn->id));
+ ret = 1;
+ reconnect = 1;
+ break;
+ }
+ /*______________________________________
+ This test breaks the connection with
+ the server if the idle time was
+ exceeded.
+ ______________________________________*/
+ if ( max_msg_time && (max_msg_time < (time(NULL) - smpp->last_msg_time)) ) {
+ debug("bb.smpp",0, "SMPP %s reached max idle time during read_pdu. Reconnecting momentarily.", octstr_get_cstr(smpp->conn->id));
+ ret = 1;
+ reconnect = 1;
+ break;
+ }
+ } /*while(read_pdu)*/
if (ret == -1) {
error(0, "SMPP[%s]: I/O error or other error. Re-connecting.",
@@ -1824,7 +1937,6 @@
break;
}
-
/* cleanup sent queue */
if (transmitter && difftime(time(NULL), last_cleanup) > smpp->wait_ack) {
if (do_queue_cleanup(smpp, &pending_submits, smpp->wait_ack_action))
@@ -1835,8 +1947,29 @@
if (transmitter && difftime(time(NULL), smpp->throttling_err_time) > SMPP_THROTTLING_SLEEP_TIME) {
smpp->throttling_err_time = 0;
send_messages(smpp, conn, &pending_submits);
- }
- }
+ }
+ /*______________________________________
+ This test breaks the connection with
+ the server if the message count was
+ exceeded.
+ ______________________________________*/
+ if(smpp->msg_count == 1) {
+ debug("bb.smpp",0, "SMPP %s reached max submitts. Reconnecting momentarily.", octstr_get_cstr(smpp->conn->id));
+ ret = 1;
+ reconnect = 1;
+ }
+ /*______________________________________
+ This test breaks the connection with
+ the server if the idle time was
+ exceeded.
+ ______________________________________*/
+ if ( max_msg_time && (max_msg_time < (time(NULL) - smpp->last_msg_time)) ) {
+ debug("bb.smpp",0, "SMPP %s reached max idle time. Reconnecting momentarily.", octstr_get_cstr(smpp->conn->id));
+ ret = 1;
+ reconnect = 1;
+ }
+
+ } /*for ... SMS I/O */
if (conn != NULL) {
conn_destroy(conn);
@@ -1877,9 +2010,21 @@
* Reconnect if that was a connection problem.
*/
if (!smpp->quitting) {
- error(0, "SMPP[%s]: Couldn't connect to SMS center (retrying in %ld seconds).",
- octstr_get_cstr(smpp->conn->id), smpp->conn->reconnect_delay);
- gwthread_sleep(smpp->conn->reconnect_delay);
+
+ /*______________________________________
+ This section inserts a delay in the
+ event that connection to the SMS
+ server was a problem. Otherwise, no
+ delay is imposed on the reconnect.
+
+ The default for the delay imposed
+ here is 10.0 seconds.
+ ______________________________________*/
+ if(ret != 1) {
+ error(0, "SMPP[%s]: Couldn't connect to SMS center (retrying in %ld seconds).",
+ octstr_get_cstr(smpp->conn->id), smpp->conn->reconnect_delay);
+ gwthread_sleep(smpp->conn->reconnect_delay);
+ }
}
}
mutex_lock(smpp->conn->flow_mutex);
@@ -1983,6 +2128,28 @@
Octstr *alt_charset;
Octstr *alt_addr_charset;
long connection_timeout, wait_ack, wait_ack_action;
+ long max_msg_count;
+ long max_msg_time;
+
+ /*______________________________________
+ These lines retrieve the SMSC
+ connection limits from the config
+ file. These are limitations for max
+ idle time and max message count per
+ connection.
+
+ These values are used in the
+ 'io_thread' function. They are
+ extracted here because the
+ cfg_get_integer() function requires
+ the 'grp' resource, which is not
+ available from within the io_thread
+ function.
+ ______________________________________*/
+ if (cfg_get_integer(&max_msg_count, grp, octstr_imm("sms-max-submits")) == -1)
+ max_msg_count = 0;
+ if (cfg_get_integer(&max_msg_time, grp, octstr_imm("sms-max-idle")) == -1)
+ max_msg_time = 0;
my_number = alt_addr_charset = alt_charset = NULL;
transceiver_mode = 0;
@@ -2150,11 +2317,19 @@
conn->status = SMSCCONN_CONNECTING;
+ /*______________________________________
+ These lines package up the SMSC
+ connection limits so that the
+ io_thread will be aware of them.
+ ______________________________________*/
+ smpp->last_msg_time = (time_t)max_msg_time;
+ smpp->msg_count = max_msg_count;
/*
* I/O threads are only started if the corresponding ports
* have been configured with positive numbers. Use 0 to
* disable the creation of the corresponding thread.
*/
+
if (port != 0)
smpp->transmitter = gwthread_create(io_thread, io_arg_create(smpp,
(transceiver_mode ? 2 : 1)));
Index: gwlib/cfg.def
===================================================================
RCS file: /home/cvs/gateway/gwlib/cfg.def,v
retrieving revision 1.118
diff -u -r1.118 cfg.def
--- gwlib/cfg.def 9 May 2006 14:32:31 -0000 1.118
+++ gwlib/cfg.def 6 Jun 2006 21:43:08 -0000
@@ -368,6 +368,8 @@
OCTSTR(preferred-prefix-regex)
OCTSTR(max-error-count)
OCTSTR(alt-addr-charset)
+ OCTSTR(sms-max-idle)
+ OCTSTR(sms-max-submits)
)