Opwnsmppbox patch
Aarno Syvänen <[email protected]>
| Newsgroups | gmane.comp.mobile.kannel.devel |
|---|---|
| Message-ID | <[email protected]> |
Hi List, here are diffs again to Kannel, for documentation for gw for gwlib for opensmppbox, for documentation for code Aarno
doc.diff
(application/octet-stream, 2.1 KB)
--- /Users/syvanen/gateway/doc/userguide/userguide.xml 2011-12-15 16:09:28.000000000 +0100
+++ doc/userguide/userguide.xml 2011-12-19 11:32:49.000000000 +0100
@@ -5359,6 +5359,7 @@
field-mask = mask
field-status = status
field-boxc-id = boxc
+field-msg-id = id
</programlisting>
</para>
@@ -5490,6 +5491,7 @@
field-mask = mask
field-status = status
field-boxc-id = boxc
+field-msg-id = id
</programlisting>
</para>
@@ -5533,6 +5535,7 @@
field-mask = mask
field-status = status
field-boxc-id = boxc
+field-msg-id = id
</programlisting>
</para>
@@ -5573,6 +5576,7 @@
field-mask = mask
field-status = status
field-boxc-id = boxc
+field-msg-id = id
</programlisting>
</para>
@@ -5616,6 +5620,7 @@
field-mask = mask
field-status = status
field-boxc-id = boxc
+field-msg-id = id
</programlisting>
</para>
@@ -5653,6 +5658,7 @@
field-mask = mask
field-status = status
field-boxc-id = boxc
+field-msg-id = id
</programlisting>
</para>
@@ -5760,6 +5766,14 @@
database table and keep it empty.
</entry></row>
+ <row><entry><literal>field-msg-id (c)</literal></entry>
+ <entry>string</entry>
+ <entry valign="bottom">
+ The table field that is used to store the sms message id
+ that has passed the message for delivery. This is used by
+ opensmppbox to route DLR and SMPP responses the original client
+ </entry></row>
+
</tbody>
</tgroup>
</table>
@@ -5779,12 +5793,15 @@
field-mask = mask
field-status = status
field-boxc-id = boxc
+flied-msg-id = id
</programlisting>
</para>
- <para>Beware that all variables in this group are mandatory, so you
- have to specify all fields to enable bearerbox to know how to store
- and retrieve the DLR information from the external storage spaces.
+ <para>Beware that all variables in this group except field-msg-id
+ are mandatory, so you have to specify all fields expect field-msg-id
+ to enable bearerbox to know how to store and retrieve the DLR information
+ from the external storage spaces. If you use opensmppbox, you must set
+ field-msg-id to route DLRs and in the case of MOs, SMPP responses..
</para>
</sect2>
gw.diff
(application/octet-stream, 29.6 KB)
Common subdirectories: /Users/syvanen/gateway/gw/.svn and gw/.svn
Binary files /Users/syvanen/gateway/gw/bb_alog.o and gw/bb_alog.o differ
Binary files /Users/syvanen/gateway/gw/bb_boxc.o and gw/bb_boxc.o differ
Binary files /Users/syvanen/gateway/gw/bb_http.o and gw/bb_http.o differ
Binary files /Users/syvanen/gateway/gw/bb_smscconn.o and gw/bb_smscconn.o differ
Binary files /Users/syvanen/gateway/gw/bb_store.o and gw/bb_store.o differ
Binary files /Users/syvanen/gateway/gw/bb_store_file.o and gw/bb_store_file.o differ
Binary files /Users/syvanen/gateway/gw/bb_store_spool.o and gw/bb_store_spool.o differ
Binary files /Users/syvanen/gateway/gw/bb_udp.o and gw/bb_udp.o differ
Binary files /Users/syvanen/gateway/gw/bearerbox and gw/bearerbox differ
Binary files /Users/syvanen/gateway/gw/bearerbox.o and gw/bearerbox.o differ
diff -u -b -B -x '*conf' /Users/syvanen/gateway/gw/dlr.c gw/dlr.c
--- /Users/syvanen/gateway/gw/dlr.c 2011-12-15 16:11:04.000000000 +0100
+++ gw/dlr.c 2011-12-19 11:32:53.000000000 +0100
@@ -77,6 +77,8 @@
* connection a msg is passed. Now we can route the messages inside bearerbox.
* 2009-04-29: aguerrieri at kannel dot org:
* added support for ms-sql and sybase via freetds.
+ * 2011-11-27: aarno at alisanus dot com:
+ * added field-msg-id for mo and delivry report routing
*/
#include <ctype.h>
@@ -95,6 +97,8 @@
/* Our callback functions */
static struct dlr_storage *handles = NULL;
+static void add_true(const Octstr *smsc, const Octstr *ts, Msg *msg);
+
/*
* Function to allocate a new struct dlr_entry entry
* and intialize it to zero
@@ -131,10 +135,37 @@
ret->url = octstr_duplicate(dlr->url);
ret->boxc_id = octstr_duplicate(dlr->boxc_id);
ret->mask = dlr->mask;
+ ret->id = octstr_duplicate(dlr->id);
return ret;
}
+void dlr_entry_dump(const struct dlr_entry *dlr)
+{
+ if (dlr == NULL) {
+ debug("dlr.dlr", 0, "dlr entry points to NULL");
+ return;
+ }
+
+ if (dlr->smsc)
+ debug("dlr.dlr", 0, "dlr entry smsc id was %s", octstr_get_cstr(dlr->smsc));
+ if (dlr->timestamp)
+ debug("dlr.dlr", 0, "dlr entry timestamp was %s", octstr_get_cstr(dlr->timestamp));
+ if (dlr->source)
+ debug("dlr.dlr", 0, "dlr entry source was %s", octstr_get_cstr(dlr->source));
+ if (dlr->destination)
+ debug("dlr.dlr", 0, "dlr entry destination was %s", octstr_get_cstr(dlr->destination));
+ if (dlr->service)
+ debug("dlr.dlr", 0, "dlr entry service was %s", octstr_get_cstr(dlr->service));
+ if (dlr->url)
+ debug("dlr.dlr", 0, "dlr entry dlr URL was %s", octstr_get_cstr(dlr->url));
+ if (dlr->boxc_id)
+ debug("dlr.dlr", 0, "dlr entry box id was %s", octstr_get_cstr(dlr->boxc_id));
+ debug("dlr.dlr", 0, "dlr entry dlr mask was %d", dlr->mask);
+ if (dlr->id)
+ debug("dlr.dlr", 0, "dlr entry msg id was %s", octstr_get_cstr(dlr->id));
+}
+
/*
* Function to destroy the struct dlr_entry entry
*/
@@ -153,6 +184,7 @@
O_DELETE(dlr->service);
O_DELETE(dlr->url);
O_DELETE(dlr->boxc_id);
+ O_DELETE(dlr->id);
#undef O_DELETE
@@ -194,6 +226,8 @@
if (!(ret->field_boxc = cfg_get(grp, octstr_imm("field-boxc-id"))))
panic(0, "DLR: DB: directive 'field-boxc-id' is not specified!");
+ ret->field_id = cfg_get(grp, octstr_imm("field-msg-id"));
+
return ret;
}
@@ -215,6 +249,7 @@
O_DELETE(fields->field_mask);
O_DELETE(fields->field_status);
O_DELETE(fields->field_boxc);
+ O_DELETE(fields->field_id);
#undef O_DELETE
@@ -319,53 +354,16 @@
*/
void dlr_add(const Octstr *smsc, const Octstr *ts, Msg *msg)
{
- struct dlr_entry *dlr = NULL;
-
- /* Add the foreign_id so all SMSC modules can use it.
- * Obey also the original message in the split_parts list. */
- if (msg->sms.foreign_id != NULL)
- octstr_destroy(msg->sms.foreign_id);
- msg->sms.foreign_id = octstr_duplicate(ts);
- if (msg->sms.split_parts != NULL) {
- struct split_parts *split = msg->sms.split_parts;
- if (split->orig->sms.foreign_id != NULL)
- octstr_destroy(split->orig->sms.foreign_id);
- split->orig->sms.foreign_id = octstr_duplicate(ts);
- }
-
- if(octstr_len(smsc) == 0) {
- warning(0, "DLR[%s]: Can't add a dlr without smsc-id", dlr_type());
- return;
- }
-
- /* sanity check */
- if (handles == NULL || handles->dlr_add == NULL || msg == NULL)
- return;
-
/* check if delivery receipt requested */
if (!DLR_IS_ENABLED(msg->sms.dlr_mask))
return;
- /* allocate new struct dlr_entry struct */
- dlr = dlr_entry_create();
- gw_assert(dlr != NULL);
-
- /* now copy all values, we are interested in */
- dlr->smsc = (smsc ? octstr_duplicate(smsc) : octstr_create(""));
- dlr->timestamp = (ts ? octstr_duplicate(ts) : octstr_create(""));
- dlr->source = (msg->sms.sender ? octstr_duplicate(msg->sms.sender) : octstr_create(""));
- dlr->destination = (msg->sms.receiver ? octstr_duplicate(msg->sms.receiver) : octstr_create(""));
- dlr->service = (msg->sms.service ? octstr_duplicate(msg->sms.service) : octstr_create(""));
- dlr->url = (msg->sms.dlr_url ? octstr_duplicate(msg->sms.dlr_url) : octstr_create(""));
- dlr->boxc_id = (msg->sms.boxc_id ? octstr_duplicate(msg->sms.boxc_id) : octstr_create(""));
- dlr->mask = msg->sms.dlr_mask;
-
- debug("dlr.dlr", 0, "DLR[%s]: Adding DLR smsc=%s, ts=%s, src=%s, dst=%s, mask=%d, boxc=%s",
- dlr_type(), octstr_get_cstr(dlr->smsc), octstr_get_cstr(dlr->timestamp),
- octstr_get_cstr(dlr->source), octstr_get_cstr(dlr->destination), dlr->mask, octstr_get_cstr(dlr->boxc_id));
+ add_true(smsc, ts, msg);
+}
- /* call registered function */
- handles->dlr_add(dlr);
+void msg_add(const Octstr *smsc, const Octstr *ts, Msg *msg)
+{
+ add_true(smsc, ts, msg);
}
/*
@@ -395,12 +393,12 @@
if (len > MIN_DST_LEN)
octstr_delete(dst_min, 0, len - MIN_DST_LEN);
}
- debug("dlr.dlr", 0, "DLR[%s]: Looking for DLR smsc=%s, ts=%s, dst=%s, type=%d",
+ debug("dlr.dlr", 0, "dlr_find: DLR[%s]: Looking for DLR smsc=%s, ts=%s, dst=%s, type=%d",
dlr_type(), octstr_get_cstr(smsc), octstr_get_cstr(ts), octstr_get_cstr(dst), typ);
dlr = handles->dlr_get(smsc, ts, dst_min);
if (dlr == NULL) {
- warning(0, "DLR[%s]: DLR from SMSC<%s> for DST<%s> not found.",
+ warning(0, "DLR[%s]: dlr_find: DLR from SMSC<%s> for DST<%s> not found.",
dlr_type(), octstr_get_cstr(smsc), octstr_get_cstr(dst));
return NULL;
}
@@ -430,12 +428,11 @@
* route this msg back to originating smsbox
*/
O_SET(msg->sms.boxc_id, dlr->boxc_id);
-
time(&msg->sms.time);
- debug("dlr.dlr", 0, "DLR[%s]: created DLR message for URL <%s>",
+ debug("dlr.dlr", 0, "dlr_find: DLR[%s]: created DLR message for URL <%s>",
dlr_type(), (msg->sms.dlr_url?octstr_get_cstr(msg->sms.dlr_url):""));
} else {
- debug("dlr.dlr", 0, "DLR[%s]: Ignoring DLR message because of mask type=%d dlr->mask=%d", dlr_type(), typ, dlr->mask);
+ debug("dlr.dlr", 0, "dlr_find: DLR[%s]: Ignoring DLR message because of mask type=%d dlr->mask=%d", dlr_type(), typ, dlr->mask);
/* ok that was a status report but we where not interested in having it */
msg = NULL;
}
@@ -444,7 +441,7 @@
/* check for end status and if so remove from storage */
if ((typ & DLR_BUFFERED) && ((dlr->mask & DLR_SUCCESS) || (dlr->mask & DLR_FAIL))) {
- debug("dlr.dlr", 0, "DLR[%s]: DLR not destroyed, still waiting for other delivery report", dlr_type());
+ debug("dlr.dlr", 0, "dlr_find: DLR[%s]: DLR not destroyed, still waiting for other delivery report", dlr_type());
/* update dlr entry status if function defined */
if (handles != NULL && handles->dlr_update != NULL){
handles->dlr_update(smsc, ts, dst_min, typ);
@@ -454,7 +451,7 @@
/* it's not good for internal storage, but better for all others */
handles->dlr_remove(smsc, ts, dst_min);
} else {
- warning(0, "DLR[%s]: Storage don't have remove operation defined", dlr_type());
+ warning(0, "dlr_find: DLR[%s]: Storage don't have remove operation defined", dlr_type());
}
}
@@ -465,6 +462,77 @@
return msg;
}
+/*
+ * Return Msg* if dlr entry found in DB, otherwise NULL. If use_smpp_id is set, only 8
+ * first characters are used for matching. NOTE: msg is not removed. This funsction is
+ * used to fetch data from dlr table.
+ */
+Msg *dlr_find_by_id(const Octstr *id, int use_smpp_id)
+{
+ Msg *msg = NULL;
+ struct dlr_entry *dlr = NULL;
+ Octstr *used_id;
+
+ if (use_smpp_id)
+ used_id = octstr_copy(id, 0, 8);
+ else
+ used_id = octstr_duplicate(id);
+
+ /* check if we have handler registered */
+ if (handles == NULL || handles->dlr_peek_with_smppid == NULL ||
+ handles->dlr_peek == NULL) {
+ octstr_destroy(used_id);
+ return NULL;
+ }
+
+ debug("dlr.dlr", 0, "dlr_find_by_id: DLR[%s]:Looking for DLR id=%s (using %s)", dlr_type(), octstr_get_cstr(used_id),
+ use_smpp_id ? "first 8 characters" : "the whole UUID");
+
+ if (use_smpp_id)
+ dlr = handles->dlr_peek_with_smppid(id);
+ else
+ dlr = handles->dlr_peek(id);
+ if (dlr == NULL) {
+ warning(0, "dlr_find_by_id: DLR for ID <%s>not found.", octstr_get_cstr(id));
+ return NULL;
+ }
+
+#define O_SET(x, val) if (octstr_len(val) > 0) { x = val; val = NULL; }
+
+ msg = msg_create(sms);
+ msg->sms.sms_type = report_mo;
+ O_SET(msg->sms.service, dlr->service);
+ O_SET(msg->sms.smsc_id, dlr->smsc);
+ O_SET(msg->sms.receiver, dlr->destination);
+ O_SET(msg->sms.sender, dlr->source);
+ /* if dlr_url was present, recode it here again */
+ O_SET(msg->sms.dlr_url, dlr->url);
+ /*
+ * If id is available, use it to restore box id for smppbox
+ * usage
+ */
+ O_SET(msg->sms.foreign_id, dlr->id);
+ /*
+ * insert original message to the data segment
+ * later in the smsc module
+ */
+ msg->sms.msgdata = NULL;
+ /*
+ * If a boxc_id is available, then instruct smppbox to
+ * route this msg back to originating client
+ */
+ O_SET(msg->sms.boxc_id, dlr->boxc_id);
+ time(&msg->sms.time);
+ debug("dlr.dlr", 0, "dlr_find_by_id: created DLR message for ID <%s>",
+ (msg->sms.foreign_id ? octstr_get_cstr(msg->sms.foreign_id) : ""));
+
+#undef O_SET
+
+ /* destroy struct dlr_entry */
+ dlr_entry_destroy(dlr);
+ return msg;
+}
+
void dlr_flush(void)
{
info(0, "Flushing all %ld queued DLR messages in %s storage", dlr_messages(),
@@ -474,6 +542,11 @@
handles->dlr_flush();
}
+void dlr_remove_by_id(const Octstr *id)
+{
+ if (handles != NULL && handles->dlr_remove_by_id != NULL)
+ handles->dlr_remove_by_id(id);
+}
Msg* create_dlr_from_msg(const Octstr *smsc, const Msg *msg, const Octstr *reply, long stat)
{
@@ -507,3 +580,57 @@
return dlrmsg;
}
+
+static void add_true(const Octstr *smsc, const Octstr *ts, Msg *msg)
+{
+ struct dlr_entry *dlr = NULL;
+
+ /* Add the foreign_id so all SMSC modules can use it.
+ * Obey also the original message in the split_parts list. */
+ if (msg->sms.foreign_id != NULL)
+ octstr_destroy(msg->sms.foreign_id);
+ msg->sms.foreign_id = octstr_duplicate(ts);
+ if (msg->sms.split_parts != NULL) {
+ struct split_parts *split = msg->sms.split_parts;
+ if (split->orig->sms.foreign_id != NULL)
+ octstr_destroy(split->orig->sms.foreign_id);
+ split->orig->sms.foreign_id = octstr_duplicate(ts);
+ }
+
+ if(octstr_len(smsc) == 0) {
+ warning(0, "DLR[%s]: Can't add a dlr without smsc-id", dlr_type());
+ return;
+ }
+
+ /* sanity check */
+ if (handles == NULL || handles->dlr_add == NULL || msg == NULL)
+ return;
+
+ /* allocate new struct dlr_entry struct */
+ dlr = dlr_entry_create();
+ gw_assert(dlr != NULL);
+
+ /* now copy all values, we are interested in */
+ dlr->smsc = (smsc ? octstr_duplicate(smsc) : octstr_create(""));
+ dlr->timestamp = (ts ? octstr_duplicate(ts) : octstr_create(""));
+ dlr->source = (msg->sms.sender ? octstr_duplicate(msg->sms.sender) : octstr_create(""));
+ dlr->destination = (msg->sms.receiver ? octstr_duplicate(msg->sms.receiver) : octstr_create(""));
+ dlr->service = (msg->sms.service ? octstr_duplicate(msg->sms.service) : octstr_create(""));
+ dlr->url = (msg->sms.dlr_url ? octstr_duplicate(msg->sms.dlr_url) : octstr_create(""));
+ dlr->boxc_id = (msg->sms.boxc_id ? octstr_duplicate(msg->sms.boxc_id) : octstr_create(""));
+ dlr->mask = msg->sms.dlr_mask;
+
+ char uuidbuf[100];
+ Octstr *id;
+ uuid_unparse(msg->sms.id, uuidbuf);
+ id = octstr_create_from_data(uuidbuf, 36);
+ dlr->id = octstr_duplicate(id);
+
+ debug("dlr.dlr", 0, "DLR[%s]: Adding DLR smsc=%s, ts=%s, src=%s, dst=%s, mask=%d, boxc=%s, id=%s",
+ dlr_type(), octstr_get_cstr(dlr->smsc), octstr_get_cstr(dlr->timestamp),
+ octstr_get_cstr(dlr->source), octstr_get_cstr(dlr->destination), dlr->mask, octstr_get_cstr(dlr->boxc_id),
+ dlr->id ? octstr_get_cstr(dlr->id) : "nil");
+
+ /* call registered function */
+ handles->dlr_add(dlr);
+}
diff -u -b -B -x '*conf' /Users/syvanen/gateway/gw/dlr.h gw/dlr.h
--- /Users/syvanen/gateway/gw/dlr.h 2011-12-15 16:11:04.000000000 +0100
+++ gw/dlr.h 2011-12-19 11:32:53.000000000 +0100
@@ -95,16 +95,28 @@
void dlr_shutdown(void);
/*
- * Add a new entry to the list
+ * Add a new entry to the list, if delivery report is asked
*/
void dlr_add(const Octstr *smsc, const Octstr *ts, Msg *msg);
/*
+ * Add in all cases
+ */
+void msg_add(const Octstr *smsc, const Octstr *ts, Msg *msg);
+
+/*
* Find an entry in the list. If there is one a message is returned and
* the entry is removed from the list otherwhise the message returned is NULL
*/
Msg* dlr_find(const Octstr *smsc, const Octstr *ts, const Octstr *dst, int type, int use_dst);
+/*
+ * Find an entry in the list, using smpp smsc id as key. Message is not removed from
+ * the list. If use_smpp_id is set, only first 8 characters are used for matching.
+ * Return msg, if there are one eith id on the list, otherwise NULL.
+ */
+Msg* dlr_find_by_id(const Octstr *id, int use_smpp_id);
+
/* return the number of DLR messages in the current waiting queue */
long dlr_messages(void);
Binary files /Users/syvanen/gateway/gw/dlr.o and gw/dlr.o differ
diff -u -b -B -x '*conf' /Users/syvanen/gateway/gw/dlr_mem.c gw/dlr_mem.c
--- /Users/syvanen/gateway/gw/dlr_mem.c 2011-12-15 16:11:04.000000000 +0100
+++ gw/dlr_mem.c 2011-12-19 11:32:53.000000000 +0100
@@ -120,7 +120,7 @@
}
/*
- * Private compare function
+ * Private compare functions
* Return 0 if entry match and 1 if not.
*/
static int dlr_mem_entry_match(struct dlr_entry *dlr, const Octstr *smsc, const Octstr *ts, const Octstr *dst)
@@ -142,6 +142,23 @@
return 1;
}
+static int dlr_mem_entry_match_one(struct dlr_entry *dlr, const Octstr *id)
+{
+ if (octstr_compare(dlr->id, id) == 0)
+ return 0;
+
+ return 1;
+}
+
+static int dlr_mem_entry_match_first_eigth(struct dlr_entry *dlr, const Octstr *id)
+{
+ if (octstr_ncompare(dlr->id, id, 8) == 0) {
+ return 0;
+ }
+
+ return 1;
+}
+
/*
* Find matching entry and return copy of it, otherwise NULL
*/
@@ -167,6 +184,45 @@
return ret;
}
+static struct dlr_entry *dlr_mem_peek_true(const Octstr *id, int usesmppid)
+{
+ long i;
+ long len;
+ struct dlr_entry *dlr = NULL, *ret = NULL;
+
+ gw_rwlock_rdlock(&rwlock);
+ len = gwlist_len(dlr_waiting_list);
+ for (i=0; i < len; i++) {
+ dlr = gwlist_get(dlr_waiting_list, i);
+
+ if (!usesmppid) {
+ if (dlr_mem_entry_match_one(dlr, id) == 0) {
+ ret = dlr_entry_duplicate(dlr);
+ break;
+ }
+ } else {
+ if (dlr_mem_entry_match_first_eigth(dlr, id) == 0) {
+ ret = dlr_entry_duplicate(dlr);
+ break;
+ }
+ }
+ }
+ gw_rwlock_unlock(&rwlock);
+
+ /* we couldnt find a matching entry */
+ return ret;
+}
+
+static struct dlr_entry *dlr_mem_peek(const Octstr *id)
+{
+ dlr_mem_peek_true(id, 0);
+}
+
+static struct dlr_entry *dlr_mem_peek_with_smppid(const Octstr *id)
+{
+ dlr_mem_peek_true(id, 1);
+}
+
/*
* Remove matching entry
*/
@@ -190,11 +246,34 @@
gw_rwlock_unlock(&rwlock);
}
+static void dlr_mem_remove_by_id(const Octstr *id)
+{
+ long i;
+ long len;
+ struct dlr_entry *dlr = NULL;
+
+ gw_rwlock_wrlock(&rwlock);
+ len = gwlist_len(dlr_waiting_list);
+ for (i=0; i < len; i++) {
+ dlr = gwlist_get(dlr_waiting_list, i);
+
+ if (dlr_mem_entry_match_one(dlr, id) == 0) {
+ gwlist_delete(dlr_waiting_list, i, 1);
+ dlr_entry_destroy(dlr);
+ break;
+ }
+ }
+ gw_rwlock_unlock(&rwlock);
+}
+
static struct dlr_storage handles = {
.type = "internal",
.dlr_add = dlr_mem_add,
.dlr_get = dlr_mem_get,
+ .dlr_peek = dlr_mem_peek,
+ .dlr_peek_with_smppid = dlr_mem_peek_with_smppid,
.dlr_remove = dlr_mem_remove,
+ .dlr_remove_by_id = dlr_mem_remove_by_id,
.dlr_shutdown = dlr_mem_shutdown,
.dlr_messages = dlr_mem_messages,
.dlr_flush = dlr_mem_flush
Binary files /Users/syvanen/gateway/gw/dlr_mem.o and gw/dlr_mem.o differ
Binary files /Users/syvanen/gateway/gw/dlr_mssql.o and gw/dlr_mssql.o differ
diff -u -b -B -x '*conf' /Users/syvanen/gateway/gw/dlr_mysql.c gw/dlr_mysql.c
--- /Users/syvanen/gateway/gw/dlr_mysql.c 2011-12-15 16:11:04.000000000 +0100
+++ gw/dlr_mysql.c 2011-12-19 11:32:53.000000000 +0100
@@ -63,6 +63,7 @@
* Andreas Fink <[email protected]>, 18.08.2001
* Stipe Tolj <[email protected]>, 22.03.2002
* Alexander Malysh <[email protected]> 2003
+ * Aarno Syvanen <aarno at alisanus dot com> 2011
*/
#include "gwlib/gwlib.h"
@@ -105,12 +106,21 @@
return;
}
+ if (fields->field_id == NULL || octstr_len(fields->field_id) == 0)
sql = octstr_format("INSERT INTO `%S` (`%S`, `%S`, `%S`, `%S`, `%S`, `%S`, `%S`, `%S`, `%S`) VALUES "
"(?, ?, ?, ?, ?, ?, ?, ?, 0)",
fields->table, fields->field_smsc, fields->field_ts,
fields->field_src, fields->field_dst, fields->field_serv,
fields->field_url, fields->field_mask, fields->field_boxc,
fields->field_status);
+ else
+ sql = octstr_format("INSERT INTO `%S` (`%S`, `%S`, `%S`, `%S`, `%S`, `%S`, `%S`, `%S`, `%S`, `%S`) VALUES "
+ "(?, ?, ?, ?, ?, ?, ?, ?, ?, 0)",
+ fields->table, fields->field_smsc, fields->field_ts,
+ fields->field_src, fields->field_dst, fields->field_serv,
+ fields->field_url, fields->field_mask, fields->field_boxc,
+ fields->field_id, fields->field_status);
+
os_mask = octstr_format("%d", entry->mask);
gwlist_append(binds, entry->smsc);
gwlist_append(binds, entry->timestamp);
@@ -121,6 +131,9 @@
gwlist_append(binds, os_mask);
gwlist_append(binds, entry->boxc_id);
+ if (fields->field_id && octstr_len(fields->field_id) > 0)
+ gwlist_append(binds, entry->id);
+
#if defined(DLR_TRACE)
debug("dlr.mysql", 0, "sql: %s", octstr_get_cstr(sql));
#endif
@@ -202,6 +215,86 @@
return res;
}
+/* If use_smpp_id is on, only first eigth characters used for matching */
+static struct dlr_entry* dlr_mysql_peek_true(const Octstr *id, int use_smpp_id)
+{
+ Octstr *sql, *like, *smpp_id;
+ DBPoolConn *pconn;
+ List *result = NULL, *row;
+ struct dlr_entry *res = NULL;
+ List *binds = gwlist_create();
+
+ pconn = dbpool_conn_consume(pool);
+ if (pconn == NULL) /* should not happens, but sure is sure */
+ return NULL;
+
+ if (use_smpp_id) {
+ smpp_id = octstr_copy(id, 0, 8);
+ like = octstr_format("LIKE '%s%%'", octstr_get_cstr(smpp_id));
+ octstr_destroy(smpp_id);
+ sql = octstr_format("SELECT `%S`, `%S`, `%S`, `%S`, `%S`, `%S`, `%S`, `%S` FROM `%S` WHERE `%S` %S LIMIT 1",
+ fields->field_mask, fields->field_serv,
+ fields->field_url, fields->field_src,
+ fields->field_dst, fields->field_boxc,
+ fields->field_id, fields->field_smsc,
+ fields->table, fields->field_id, like);
+ } else
+ sql = octstr_format("SELECT `%S`, `%S`, `%S`, `%S`, `%S`, `%S`, `%S`, `%S` FROM `%S` WHERE `%S`=? LIMIT 1",
+ fields->field_mask, fields->field_serv,
+ fields->field_url, fields->field_src,
+ fields->field_dst, fields->field_boxc,
+ fields->field_id, fields->field_smsc,
+ fields->table, fields->field_id);
+
+ gwlist_append(binds, (Octstr *)id);
+
+#if defined(DLR_TRACE)
+ debug("dlr.mysql", 0, "sql: %s", octstr_get_cstr(sql));
+#endif
+
+ if (dbpool_conn_select(pconn, sql, binds, &result) != 0) {
+ octstr_destroy(sql);
+ octstr_destroy(like);
+ dbpool_conn_produce(pconn);
+ return NULL;
+ }
+ octstr_destroy(sql);
+
+ gwlist_destroy(binds, NULL);
+ dbpool_conn_produce(pconn);
+
+#define LO2CSTR(r, i) octstr_get_cstr(gwlist_get(r, i))
+
+ if (gwlist_len(result) > 0) {
+ row = gwlist_extract_first(result);
+ res = dlr_entry_create();
+ gw_assert(res != NULL);
+ res->mask = atoi(LO2CSTR(row,0));
+ res->service = octstr_create(LO2CSTR(row, 1));
+ res->url = octstr_create(LO2CSTR(row,2));
+ res->source = octstr_create(LO2CSTR(row, 3));
+ res->destination = octstr_create(LO2CSTR(row, 4));
+ res->boxc_id = octstr_create(LO2CSTR(row, 5));
+ res->id = octstr_create(LO2CSTR(row, 6));
+ res->smsc = octstr_create(LO2CSTR(row, 7));
+ }
+ gwlist_destroy(result, NULL);
+
+#undef LO2CSTR
+
+ return res;
+}
+
+static struct dlr_entry* dlr_mysql_peek_with_smppid(const Octstr *id)
+{
+ dlr_mysql_peek_true(id, 1);
+}
+
+static struct dlr_entry* dlr_mysql_peek(const Octstr *id)
+{
+ dlr_mysql_peek_true(id, 0);
+}
+
static void dlr_mysql_remove(const Octstr *smsc, const Octstr *ts, const Octstr *dst)
{
Octstr *sql, *like;
@@ -209,7 +302,7 @@
List *binds = gwlist_create();
int res;
- debug("dlr.mysql", 0, "removing DLR from database");
+ debug("dlr.mysql", 0, "dlr_mysql_remove: removing DLR from database");
pconn = dbpool_conn_consume(pool);
/* just for sure */
@@ -235,9 +328,9 @@
#endif
if ((res = dbpool_conn_update(pconn, sql, binds)) == -1)
- error(0, "DLR: MYSQL: Error while removing dlr entry for DST<%s>", octstr_get_cstr(dst));
+ error(0, "DLR: MYSQL: dlr_mysql_remove: Error while removing dlr entry for DST<%s>", octstr_get_cstr(dst));
else if (!res)
- warning(0, "DLR: MYSQL: No dlr deleted for DST<%s>", octstr_get_cstr(dst));
+ warning(0, "DLR: MYSQL: dl_mysql_remove: No dlr deleted for DST<%s>", octstr_get_cstr(dst));
dbpool_conn_produce(pconn);
gwlist_destroy(binds, NULL);
@@ -245,6 +338,39 @@
octstr_destroy(like);
}
+static void dlr_mysql_remove_by_id(const Octstr *id)
+{
+ Octstr *sql;
+ DBPoolConn *pconn;
+ List *binds = gwlist_create();
+ int res;
+
+ debug("dlr.mysql", 0, "dlr_mysql_remove_by_id: removing DLR from database");
+
+ pconn = dbpool_conn_consume(pool);
+ /* just for sure */
+ if (pconn == NULL)
+ return;
+
+ sql = octstr_format("DELETE FROM `%S` WHERE `%S`=? LIMIT 1",
+ fields->table, fields->field_id);
+
+ gwlist_append(binds, (Octstr *)id);
+
+#if defined(DLR_TRACE)
+ debug("dlr.mysql", 0, "sql: %s", octstr_get_cstr(sql));
+#endif
+
+ if ((res = dbpool_conn_update(pconn, sql, binds)) == -1)
+ error(0, "DLR: MYSQL: dlr_mysql_remove_by_id: Error while removing dlr entry for ID<%s>", octstr_get_cstr(id));
+ else if (!res)
+ warning(0, "DLR: MYSQL: dlr_nysql_remove_by_id: No dlr deleted for ID<%s>", octstr_get_cstr(id));
+
+ dbpool_conn_produce(pconn);
+ gwlist_destroy(binds, NULL);
+ octstr_destroy(sql);
+}
+
static void dlr_mysql_update(const Octstr *smsc, const Octstr *ts, const Octstr *dst, int status)
{
Octstr *sql, *os_status, *like;
@@ -353,8 +479,11 @@
.type = "mysql",
.dlr_add = dlr_mysql_add,
.dlr_get = dlr_mysql_get,
+ .dlr_peek_with_smppid = dlr_mysql_peek_with_smppid,
+ .dlr_peek = dlr_mysql_peek,
.dlr_update = dlr_mysql_update,
.dlr_remove = dlr_mysql_remove,
+ .dlr_remove_by_id = dlr_mysql_remove_by_id,
.dlr_shutdown = dlr_mysql_shutdown,
.dlr_messages = dlr_mysql_messages,
.dlr_flush = dlr_mysql_flush
@@ -397,6 +526,9 @@
octstr_replace(fields->field_status, octstr_imm("`"), octstr_imm("``"));
octstr_replace(fields->field_boxc, octstr_imm("`"), octstr_imm("``"));
+ if (fields->field_id && octstr_len(fields->field_id) > 0)
+ octstr_replace(fields->field_id, octstr_imm("`"), octstr_imm("``"));
+
/*
* now grap the required information from the 'mysql-connection' group
* with the mysql-id we just obtained
@@ -466,6 +598,7 @@
* Return NULL , so we point dlr-core that we were
* not compiled in.
*/
+
struct dlr_storage *dlr_init_mysql(Cfg* cfg)
{
return NULL;
Binary files /Users/syvanen/gateway/gw/dlr_mysql.o and gw/dlr_mysql.o differ
Binary files /Users/syvanen/gateway/gw/dlr_oracle.o and gw/dlr_oracle.o differ
diff -u -b -B -x '*conf' /Users/syvanen/gateway/gw/dlr_p.h gw/dlr_p.h
--- /Users/syvanen/gateway/gw/dlr_p.h 2011-12-15 16:11:04.000000000 +0100
+++ gw/dlr_p.h 2011-12-19 11:32:53.000000000 +0100
@@ -63,6 +63,7 @@
* Andreas Fink <[email protected]>, 18.08.2001
* Stipe Tolj <[email protected]>, 22.03.2002
* Alexander Malysh <[email protected]>
+ * Aarno Syvanen <[email protected]> 27.10.2011
*/
#ifndef DLR_P_H
@@ -84,6 +85,7 @@
Octstr *url;
Octstr *boxc_id;
int mask;
+ Octstr *id;
};
/*
@@ -120,9 +122,17 @@
*/
struct dlr_entry* (*dlr_get) (const Octstr *smsc, const Octstr *ts, const Octstr *dst);
/*
- * Remove matching dlr entry from storage
+ * Find and return struct dlr_entry. dlr_peek will use msg id as key,
+ * *smppid will match first 8 charaxters. If entry not found return NULL.
+ * NOTE: Caller will detroy struct dlr_entry
+ */
+ struct dlr_entry* (*dlr_peek) (const Octstr *id);
+ struct dlr_entry* (*dlr_peek_with_smppid) (const Octstr *id);
+ /*
+ * Remove matching dlr entry from storage 0
*/
void (*dlr_remove) (const Octstr *smsc, const Octstr *ts, const Octstr *dst);
+ void (*dlr_remove_by_id)(const Octstr *id);
/*
* Update dlr entry status field if any.
*/
@@ -156,6 +166,7 @@
Octstr *field_mask;
Octstr *field_status;
Octstr *field_boxc;
+ Octstr *field_id;
};
struct dlr_db_fields *dlr_db_fields_create(CfgGroup *grp);
Binary files /Users/syvanen/gateway/gw/dlr_pgsql.o and gw/dlr_pgsql.o differ
Binary files /Users/syvanen/gateway/gw/dlr_sdb.o and gw/dlr_sdb.o differ
Binary files /Users/syvanen/gateway/gw/dlr_sqlite3.o and gw/dlr_sqlite3.o differ
Binary files /Users/syvanen/gateway/gw/heartbeat.o and gw/heartbeat.o differ
Binary files /Users/syvanen/gateway/gw/html.o and gw/html.o differ
Binary files /Users/syvanen/gateway/gw/load.o and gw/load.o differ
Binary files /Users/syvanen/gateway/gw/meta_data.o and gw/meta_data.o differ
Binary files /Users/syvanen/gateway/gw/mime_decompiler.o and gw/mime_decompiler.o differ
Binary files /Users/syvanen/gateway/gw/msg.o and gw/msg.o differ
Binary files /Users/syvanen/gateway/gw/numhash.o and gw/numhash.o differ
Binary files /Users/syvanen/gateway/gw/ota_compiler.o and gw/ota_compiler.o differ
Binary files /Users/syvanen/gateway/gw/ota_prov.o and gw/ota_prov.o differ
Binary files /Users/syvanen/gateway/gw/shared.o and gw/shared.o differ
Binary files /Users/syvanen/gateway/gw/sms.o and gw/sms.o differ
Binary files /Users/syvanen/gateway/gw/smsbox and gw/smsbox differ
Binary files /Users/syvanen/gateway/gw/smsbox.o and gw/smsbox.o differ
Common subdirectories: /Users/syvanen/gateway/gw/smsc and gw/smsc
Binary files /Users/syvanen/gateway/gw/smscconn.o and gw/smscconn.o differ
Binary files /Users/syvanen/gateway/gw/urltrans.o and gw/urltrans.o differ
Binary files /Users/syvanen/gateway/gw/wap-appl.o and gw/wap-appl.o differ
Binary files /Users/syvanen/gateway/gw/wap-error.o and gw/wap-error.o differ
Binary files /Users/syvanen/gateway/gw/wap-maps.o and gw/wap-maps.o differ
Binary files /Users/syvanen/gateway/gw/wap_push_ota.o and gw/wap_push_ota.o differ
Binary files /Users/syvanen/gateway/gw/wap_push_pap_compiler.o and gw/wap_push_pap_compiler.o differ
Binary files /Users/syvanen/gateway/gw/wap_push_pap_mime.o and gw/wap_push_pap_mime.o differ
Binary files /Users/syvanen/gateway/gw/wap_push_ppg.o and gw/wap_push_ppg.o differ
Binary files /Users/syvanen/gateway/gw/wap_push_ppg_pushuser.o and gw/wap_push_ppg_pushuser.o differ
Binary files /Users/syvanen/gateway/gw/wap_push_si_compiler.o and gw/wap_push_si_compiler.o differ
Binary files /Users/syvanen/gateway/gw/wap_push_sl_compiler.o and gw/wap_push_sl_compiler.o differ
Binary files /Users/syvanen/gateway/gw/wapbox and gw/wapbox differ
Binary files /Users/syvanen/gateway/gw/wapbox.o and gw/wapbox.o differ
Binary files /Users/syvanen/gateway/gw/wml_compiler.o and gw/wml_compiler.o differ
Binary files /Users/syvanen/gateway/gw/xml_shared.o and gw/xml_shared.o differ
gwlib.diff
(application/octet-stream, 5.2 KB)
Common subdirectories: /Users/syvanen/gateway/gwlib/.svn and gwlib/.svn
Binary files /Users/syvanen/gateway/gwlib/accesslog.o and gwlib/accesslog.o differ
diff -u -b -B -x 'gw_uuid_types.*' /Users/syvanen/gateway/gwlib/cfg.def gwlib/cfg.def
--- /Users/syvanen/gateway/gwlib/cfg.def 2011-12-15 16:08:39.000000000 +0100
+++ gwlib/cfg.def 2011-12-19 11:32:57.000000000 +0100
@@ -622,6 +622,7 @@
OCTSTR(field-mask)
OCTSTR(field-status)
OCTSTR(field-boxc-id)
+ OCTSTR(field-msg-id)
)
Binary files /Users/syvanen/gateway/gwlib/cfg.o and gwlib/cfg.o differ
Binary files /Users/syvanen/gateway/gwlib/charset.o and gwlib/charset.o differ
diff -u -b -B -x 'gw_uuid_types.*' /Users/syvanen/gateway/gwlib/conn.c gwlib/conn.c
--- /Users/syvanen/gateway/gwlib/conn.c 2011-12-15 16:08:39.000000000 +0100
+++ gwlib/conn.c 2011-12-19 11:32:57.000000000 +0100
@@ -1474,3 +1474,24 @@
else
return conn->fd;
}
+
+void conn_dump_salient(Connection *conn)
+{
+ debug("gwlib.conn", 0, "connection dump starts");
+ debug("gwlib.conn", 0, "is connection claimed %d", conn->claimed);
+#ifndef NO_GWASSERT
+ debug("gwlib.conn", 0, "claiming thread was %ld", conn->claiming_thread);
+#endif
+
+ debug("gwlib.conn", 0, "conn is using socket %d", conn->fd);
+ debug("gwlib.conn", 0, "was conn connected ?", conn->connected);
+ debug("gwlib.conn", 0, "conn outbuf was %s", octstr_get_cstr(conn->outbuf));
+ debug("gwlib.conn", 0, "conn output pointer was at %ld", conn->outbufpos);
+ debug("gwlib.conn", 0, "conn buffers until %ld bytes", conn->output_buffering);
+ debug("gwlib.conn", 0, "conn inbuf was %s", octstr_get_cstr(conn->inbuf));
+ debug("gwlib.conn", 0, "conn intput pointer was at %ld", conn->inbufpos);
+
+ debug("gwlib.conn", 0, "conn eof flag was %d", conn->read_eof);
+ debug("gwlib.conn", 0, "conn error flag was %d", conn->io_error);
+ debug("gwlib.conn", 0, "connection dump ends");
+}
diff -u -b -B -x 'gw_uuid_types.*' /Users/syvanen/gateway/gwlib/conn.h gwlib/conn.h
--- /Users/syvanen/gateway/gwlib/conn.h 2011-12-15 16:08:39.000000000 +0100
+++ gwlib/conn.h 2011-12-19 11:32:57.000000000 +0100
@@ -346,3 +346,5 @@
#endif /* HAVE_LIBSSL */
int conn_get_id(Connection *conn);
+
+void conn_dump_salient(Connection *conn);
Binary files /Users/syvanen/gateway/gwlib/conn.o and gwlib/conn.o differ
Binary files /Users/syvanen/gateway/gwlib/counter.o and gwlib/counter.o differ
Binary files /Users/syvanen/gateway/gwlib/date.o and gwlib/date.o differ
Binary files /Users/syvanen/gateway/gwlib/dbpool.o and gwlib/dbpool.o differ
Binary files /Users/syvanen/gateway/gwlib/dbpool_mssql.o and gwlib/dbpool_mssql.o differ
Binary files /Users/syvanen/gateway/gwlib/dbpool_mysql.o and gwlib/dbpool_mysql.o differ
Binary files /Users/syvanen/gateway/gwlib/dbpool_oracle.o and gwlib/dbpool_oracle.o differ
Binary files /Users/syvanen/gateway/gwlib/dbpool_pgsql.o and gwlib/dbpool_pgsql.o differ
Binary files /Users/syvanen/gateway/gwlib/dbpool_sdb.o and gwlib/dbpool_sdb.o differ
Binary files /Users/syvanen/gateway/gwlib/dbpool_sqlite.o and gwlib/dbpool_sqlite.o differ
Binary files /Users/syvanen/gateway/gwlib/dbpool_sqlite3.o and gwlib/dbpool_sqlite3.o differ
Binary files /Users/syvanen/gateway/gwlib/dict.o and gwlib/dict.o differ
Binary files /Users/syvanen/gateway/gwlib/fdset.o and gwlib/fdset.o differ
Binary files /Users/syvanen/gateway/gwlib/gw-prioqueue.o and gwlib/gw-prioqueue.o differ
Binary files /Users/syvanen/gateway/gwlib/gw-rwlock.o and gwlib/gw-rwlock.o differ
Binary files /Users/syvanen/gateway/gwlib/gw_uuid.o and gwlib/gw_uuid.o differ
Binary files /Users/syvanen/gateway/gwlib/gwlib.o and gwlib/gwlib.o differ
Binary files /Users/syvanen/gateway/gwlib/gwmem-check.o and gwlib/gwmem-check.o differ
Binary files /Users/syvanen/gateway/gwlib/gwmem-native.o and gwlib/gwmem-native.o differ
Binary files /Users/syvanen/gateway/gwlib/gwpoll.o and gwlib/gwpoll.o differ
Binary files /Users/syvanen/gateway/gwlib/gwthread-pthread.o and gwlib/gwthread-pthread.o differ
Binary files /Users/syvanen/gateway/gwlib/http.o and gwlib/http.o differ
Binary files /Users/syvanen/gateway/gwlib/list.o and gwlib/list.o differ
Binary files /Users/syvanen/gateway/gwlib/log.o and gwlib/log.o differ
Binary files /Users/syvanen/gateway/gwlib/md5.o and gwlib/md5.o differ
Binary files /Users/syvanen/gateway/gwlib/mime.o and gwlib/mime.o differ
Binary files /Users/syvanen/gateway/gwlib/octstr.o and gwlib/octstr.o differ
Binary files /Users/syvanen/gateway/gwlib/parse.o and gwlib/parse.o differ
Binary files /Users/syvanen/gateway/gwlib/pcre.o and gwlib/pcre.o differ
Binary files /Users/syvanen/gateway/gwlib/pki.o and gwlib/pki.o differ
Binary files /Users/syvanen/gateway/gwlib/protected.o and gwlib/protected.o differ
Binary files /Users/syvanen/gateway/gwlib/regex.o and gwlib/regex.o differ
Binary files /Users/syvanen/gateway/gwlib/semaphore.o and gwlib/semaphore.o differ
Binary files /Users/syvanen/gateway/gwlib/socket.o and gwlib/socket.o differ
Binary files /Users/syvanen/gateway/gwlib/ssl.o and gwlib/ssl.o differ
Binary files /Users/syvanen/gateway/gwlib/thread.o and gwlib/thread.o differ
Binary files /Users/syvanen/gateway/gwlib/utils.o and gwlib/utils.o differ
Binary files /Users/syvanen/gateway/gwlib/xmlrpc.o and gwlib/xmlrpc.o differ
doc.diff
(application/octet-stream, 3.8 KB)
Common subdirectories: /Users/syvanen/gateway/addons/opensmppbox/doc/.svn and doc/.svn
Only in doc: SMPPBox.ps
Only in doc: userguide.html
Only in doc: userguide.pdf
Only in doc: userguide.ps
Only in doc: userguide.rtf
diff -u -b -B -x 'Makefile*' /Users/syvanen/gateway/addons/opensmppbox/doc/userguide.xml doc/userguide.xml
--- /Users/syvanen/gateway/addons/opensmppbox/doc/userguide.xml 2011-12-15 16:11:55.000000000 +0100
+++ doc/userguide.xml 2011-12-19 11:32:41.000000000 +0100
@@ -693,7 +693,22 @@
<literal>string</literal>
</entry>
<entry valign="bottom">
- Optional opensmppbox instance identifier. This is used for logging identification.
+ Optional opensmppbox instance identifier. This is used for logging identification,
+ and as opensmppbox box id, if usesmppboxid is set
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal> use-smppboxid (o) </literal>
+ </entry>
+ <entry>
+ <literal> Boolean </literal>
+ </entry>
+ <entry valign = "bottom">
+ If this flag is set, openamppbox will make only one connection to bearwrbox, and
+ use opensmppbox-id as its box id. If this flag is not set, every client will
+ have a separate connection instead. Not that if you use this flag, you must set
+ use-systemid-as-smsboxid flag, too.
</entry>
</row>
<row>
@@ -864,6 +879,58 @@
receive a valid pdu in this number of seconds.
(Defaults to 300).
</entry></row>
+ </table>
+
+ <para>
+ If usesmppbox-id variable is used, you probably want to configure
+ client-route group. It instructs opensmppbox to route MOs to a
+ specific client. If this group is missing, a random client is
+ picked instead. If both shortcode and and client-id variable is
+ supplied, this is interpreted as logical AND: only messages
+ addressed to the specifed shotcode and coming from specified
+ smsc are routed to client in question.
+ </para>
+
+ <table frame="none">
+ <title>client-route Group Variables</title>
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>Variable</entry>
+ <entry>Value</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row><entry><literal>group (o) </literal></entry>
+ <entry><literal>client-route</literal></entry>
+ <entry valign="bottom">
+ Optional. Configure this if you se use-smppboxid variable
+ and want MOs routed to a certain client
+ </entry></row>
+
+ <row><entry><literal>client-id</literal></entry>
+ <entry><literal>string</literal></entry>
+ <entry valign="bottom">
+ System id of the client the messages should be routed. Use
+ variable use-systemid-as-smsboxid to allow routing.
+ </entry></row>
+
+ <row><entry><literal>shortcode</literal></entry>
+ <entry><literal>list of numbers separated by semicolons</literal></entry>
+ <entry valign="bottom">
+ If set, specifies which receiver numbers for inbound messages
+ should be routed to this client. This rule may be used to pull
+ receiver number specific message streams to a client.
+ </entry></row>
+
+ <row><entry><literal>smsc-id</literal></entry>
+ <entry><literal>list of strings separated by semicolons</literal></entry>
+ <entry valign="bottom">
+ If set, specifies from which smsc-ids all inbound messages should be routed
+ to this client. This rule may be used to pull any smsc specific message
+ stream to a client.
+ </entry></row>
</tbody>
</tgroup>
</table>
box.diff
(application/octet-stream, 40.5 KB)
Only in gw: .deps
Only in gw: .libs
Common subdirectories: /Users/syvanen/gateway/addons/opensmppbox/gw/.svn and gw/.svn
Only in gw: opensmppbox
diff -u -b -B -x 'Makefile*' /Users/syvanen/gateway/addons/opensmppbox/gw/opensmppbox-cfg.def gw/opensmppbox-cfg.def
--- /Users/syvanen/gateway/addons/opensmppbox/gw/opensmppbox-cfg.def 2011-12-15 16:11:57.000000000 +0100
+++ gw/opensmppbox-cfg.def 2011-12-19 11:32:42.000000000 +0100
@@ -78,6 +78,13 @@
OCTSTR(dest-addr-npi)
OCTSTR(timeout)
OCTSTR(use-systemid-as-smsboxid)
+ OCTSTR(use-smppboxid)
OCTSTR(enable-pam)
OCTSTR(pam-acl)
)
+
+MULTI_GROUP(client-route,
+ OCTSTR(client-id)
+ OCTSTR(smsc-id)
+ OCTSTR(shortcode)
+)
diff -u -b -B -x 'Makefile*' /Users/syvanen/gateway/addons/opensmppbox/gw/opensmppbox.c gw/opensmppbox.c
--- /Users/syvanen/gateway/addons/opensmppbox/gw/opensmppbox.c 2011-12-15 16:11:57.000000000 +0100
+++ gw/opensmppbox.c 2011-12-19 11:32:42.000000000 +0100
@@ -118,18 +118,24 @@
static Octstr *smppbox_id;
static Octstr *our_system_id;
-static Octstr *route_to_smsc;
+static Octstr *route_to_smsc = NULL;
static time_t smpp_timeout;
static int systemidisboxcid;
static int enablepam;
static Octstr *pamacl;
+static int usesmppboxid;
+static Dict *client_by_smsc;
+static Dict *client_by_receiver;
+static Dict *client_by_smsc_receiver;
#define TIMEOUT_SECONDS 300
typedef enum { SMPP_LOGIN_NOTLOGGEDIN, SMPP_LOGIN_TRANSMITTER, SMPP_LOGIN_RECEIVER, SMPP_LOGIN_TRANSCEIVER } smpp_login;
+enum {USE_UUID = 0, USE_SMPP_ID = 1};
+
typedef struct _boxc {
Connection *smpp_connection;
Connection *bearerbox_connection;
@@ -150,6 +156,7 @@
Semaphore *pending;
volatile sig_atomic_t alive;
Octstr *boxc_id; /* identifies the connected opensmppbox instance */
+ Octstr *our_id; /* pir own id*/
Octstr *sms_service;
Octstr *route_to_smsc;
Dict *msg_acks;
@@ -173,11 +180,95 @@
} Boxc;
+typedef struct _bbboxc {
+ Connection *bearerbox_connection;
+ volatile sig_atomic_t alive;
+ Dict *msg_acks;
+ Dict *deliver_acks;
+ int mo_recode;
+} BBBoxc;
+
+static BBBoxc *bbbox;
+
+
+static void box_dump_salient(Boxc *boxc)
+{
+ if (!boxc) {
+ debug("opensmppbox", 0, "client pointer points to NULL");
+ return;
+ }
+
+ debug("opensmppbox", 0, "client dump starts");
+ if (boxc->client_ip)
+ debug("opensmppbox", 0, "client ip address was <%s>", octstr_get_cstr(boxc->client_ip));
+ if (boxc->boxc_id)
+ debug("opensmppbox", 0, "client box id (username) was <%s>", octstr_get_cstr(boxc->boxc_id));
+ if (boxc->our_id)
+ debug("opensmppbox", 0, "client id was <%s>", octstr_get_cstr(boxc->our_id));
+ if (boxc->bearerbox_connection) {
+ debug("opensmppbox", 0, "bearerboz connection was");
+ conn_dump_salient(boxc->bearerbox_connection);
+ }
+ if (boxc->smpp_connection) {
+ debug("opensmppbox", 0, "client connection was");
+ conn_dump_salient(boxc->smpp_connection);
+ }
+
+ debug("opensmppbox", 0, "client dump ends");
+}
+
+static void box_list_dump_salient(List *boxes)
+{
+ long i, len;
+ Boxc *box;
+
+ i = 0;
+ len = gwlist_len(boxes);
+ while (i < len) {
+ box = gwlist_get(boxes, i);
+ box_dump_salient(box);
+ ++i;
+ }
+}
+
+void box_id_dict_dump(Dict *box_id_by_msg_id)
+{
+ long i, count;
+ List *ids;
+ Octstr *key;
+ Octstr *box_id;
+
+ gwlib_assert_init();
+
+ debug("opensmppbox", 0, "Dumping box_id dict:");
+ if (!box_id_by_msg_id) {
+ debug("opensmppbox", 0, "box id dict point NULL");
+ return;
+ }
+
+ ids = dict_keys(box_id_by_msg_id);
+ count = dict_key_count(box_id_by_msg_id);
+ for (i = 0; i < count; ++i) {
+ key = gwlist_get(ids, i);
+ box_id = dict_get(box_id_by_msg_id, key);
+ debug("opensmppbox", 0, "Msg id %ld was: ", i);
+ octstr_dump(key, 0);
+ debug("opensmppbox", 0, "Box id %ld was: ", i);
+ octstr_dump(box_id, 0);
+ }
+ debug("opensmppbox", 0, "End of dump.");
+}
+
void smpp_pdu_destroy_item(void *pdu)
{
smpp_pdu_destroy(pdu);
}
+static void shutdown_connection(Connection *conn)
+{
+ conn_destroy(conn);
+}
+
/*
* Use PAM (Pluggable Authentication Module) to check sendsms authentication.
*/
@@ -309,16 +401,20 @@
valid_login:
for (box = 0; box < gwlist_len(all_boxes); box++) {
thisbox = (Boxc *)gwlist_get(all_boxes, box);
- if (octstr_compare(system_type, thisbox->boxc_id) == 0 && (thisbox->login_type == SMPP_LOGIN_TRANSCEIVER || (thisbox->login_type == login_type))) {
- debug("bb.sms.smpp", 0, "opensmppbox[%s]: Multiple login: disconnect.",
+ if (octstr_compare(system_type, thisbox->boxc_id) == 0 && (thisbox->login_type == SMPP_LOGIN_TRANSCEIVER
+ || (thisbox->login_type == login_type))) {
+ debug("opensmppbox", 0, "opensmppbox[%s]: Multiple login: disconnect.",
octstr_get_cstr(thisbox->boxc_id));
thisbox->alive = 0;
#ifdef HAVE_SHUTDOWN_CONNECTION
+ if (!use_smppboxid)
shutdown_connection(thisbox->bearerbox_connection);
shutdown_connection(thisbox->smpp_connection);
#endif
}
}
+ debug("opensmppbox", 0, "Accepted client with box id (username ?) <%s>",
+ octstr_get_cstr(boxc->boxc_id));
return 1;
}
@@ -342,6 +438,12 @@
} while(0)
#endif
+static void dump_pdu_debug(char *msg, Octstr *id, SMPP_PDU *pdu)
+{
+ debug("opensmppbox", 0, "SMPP[%s]: %s", \
+ octstr_get_cstr(id), msg); \
+ smpp_pdu_dump(pdu);
+}
/*
* Converting SMPP timestamp to minutes relative
@@ -396,7 +498,7 @@
localdiff = difftime(gw_mktime(&local), gw_mktime(&tm));
valutc += localdiff;
- debug("sms.smpp",0, "diff between utc and localtime (%d)", localdiff);
+ debug("opensmppbox",0, "diff between utc and localtime (%d)", localdiff);
diff = diff*15*60;
switch(relation) {
case '+':
@@ -421,10 +523,10 @@
return -1;
}
tm = gw_gmtime(valutc);
- debug("sms.smpp",0,"Requested UTC timestamp: %02d-%02d-%02d %02d:%02d:%02d",
+ debug("opensmppbox",0,"Requested UTC timestamp: %02d-%02d-%02d %02d:%02d:%02d",
tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
- debug("sms.smpp", 0, "requested timestamp in min. (%ld)", (valutc - utc)/60);
+ debug("opensmppbox", 0, "requested timestamp in min. (%ld)", (valutc - utc)/60);
return ceil ( difftime (valutc, utc) / 60 );
}
@@ -440,7 +542,7 @@
/* send to bearerbox */
-static int send_msg(Connection *conn, Boxc *boxconn, Msg *pmsg)
+static int send_msg(Connection *conn, Msg *pmsg)
{
/* Caution: implicit msg_destroy */
write_to_bearerbox_real(conn, pmsg);
@@ -456,7 +558,7 @@
for (pos = 0; pos < gwlist_len(all_boxes); pos++) {
box = (Boxc *)gwlist_get(all_boxes, pos);
- send_msg(box->bearerbox_connection, box, msg);
+ send_msg(box->bearerbox_connection, msg);
}
}
*/
@@ -474,25 +576,25 @@
* Do this even while no opensmppbox-id is given to unlock the sender thread in
* bearerbox.
*/
-static void identify_to_bearerbox(Boxc *conn)
+static void identify_to_bearerbox(Connection *conn, Octstr *our_id)
{
Msg *msg;
msg = msg_create(admin);
msg->admin.command = cmd_identify;
- msg->admin.boxc_id = octstr_duplicate(conn->boxc_id);
- send_msg(conn->bearerbox_connection, conn, msg);
+ msg->admin.boxc_id = octstr_duplicate(our_id);
+ send_msg(conn, msg);
}
/* read from bearerbox */
-static Msg *read_from_box(Connection *conn, Boxc *boxconn)
+static Msg *read_from_box(Connection *conn, int alive)
{
Octstr *pack;
Msg *msg;
pack = NULL;
- while (boxconn->alive) {
+ while (alive) {
switch (read_from_bearerbox_real(conn, &msg, 1.0)) {
case -1:
/* connection to bearerbox lost */
@@ -626,7 +728,7 @@
/* generate 8 character ID, taken from msgid */
static Octstr *generate_smppid(Msg *msg)
{
- char uuidbuf[100];
+ char uuidbuf[UUID_STR_LEN + 1];
Octstr *result;
// gw_assert(msg->type == sms); // we segfault on this
@@ -673,7 +775,7 @@
if (*pdu == NULL) {
error(0, "opensmppbox[%s]: PDU unpacking failed.",
octstr_get_cstr(box->boxc_id));
- debug("bb.sms.smpp", 0, "opensmppbox[%s]: Failed PDU omitted.",
+ debug("opensmppbox", 0, "opensmppbox[%s]: Failed PDU omitted.",
octstr_get_cstr(box->boxc_id));
/* octstr_dump(os, 0); */
octstr_destroy(os);
@@ -684,6 +786,35 @@
return 1;
}
+ /* To route to the original client, we restore the original
+ * box id (i.e., essentially the username). */
+static void restore_box_id(Msg *msg, Octstr *msgid)
+{
+ if (msg->sms.sms_type == report_mo) {
+ List *parts = octstr_split(msg->sms.dlr_url, octstr_imm(";"));
+ Octstr *msgid = gwlist_extract_first(parts);
+ Msg *dlr = dlr_find_by_id(msgid, USE_SMPP_ID);
+ Octstr *boxid = NULL;
+ if (dlr && dlr->sms.boxc_id)
+ boxid = octstr_duplicate(dlr->sms.boxc_id);
+
+ if (boxid) {
+ octstr_destroy(msg->sms.boxc_id);
+ msg->sms.boxc_id = octstr_duplicate(boxid);
+ }
+
+ octstr_destroy(boxid);
+ msg_destroy(dlr);
+ }
+ /* MOs are routed separately, using smsc_id */
+}
+
+static void change_box_id(Msg *msg)
+{
+ octstr_destroy(msg->sms.boxc_id);
+ msg->sms.boxc_id = octstr_duplicate(smppbox_id);
+}
+
static List *msg_to_pdu(Boxc *box, Msg *msg)
{
SMPP_PDU *pdu, *pdu2;
@@ -717,7 +848,7 @@
if(box->source_addr_ton > -1 && box->source_addr_npi > -1) {
pdu->u.deliver_sm.source_addr_ton = box->source_addr_ton;
pdu->u.deliver_sm.source_addr_npi = box->source_addr_npi;
- debug("bb.sms.smpp", 0, "SMPP[%s]: Manually forced source addr ton = %ld, source add npi = %ld",
+ debug("opensmppbox", 0, "SMPP[%s]: Manually forced source addr ton = %ld, source add npi = %ld",
octstr_get_cstr(box->boxc_id), box->source_addr_ton,
box->source_addr_npi);
} else {
@@ -749,7 +880,7 @@
if (box->dest_addr_ton > -1 && box->dest_addr_npi > -1) {
pdu->u.deliver_sm.dest_addr_ton = box->dest_addr_ton;
pdu->u.deliver_sm.dest_addr_npi = box->dest_addr_npi;
- debug("bb.sms.smpp", 0, "SMPP[%s]: Manually forced dest addr ton = %ld, dest add npi = %ld",
+ debug("opensmppbox", 0, "SMPP[%s]: Manually forced dest addr ton = %ld, dest add npi = %ld",
octstr_get_cstr(box->boxc_id), box->dest_addr_ton,
box->dest_addr_npi);
} else {
@@ -771,6 +902,7 @@
octstr_len(pdu->u.deliver_sm.source_addr) > 20) {
smpp_pdu_destroy(pdu);
gwlist_destroy(pdulist, NULL);
+ warning(0, "opensmppbox: msg_to_pdu: address too long, not acceptable");
return NULL;
}
@@ -819,6 +952,7 @@
gwlist_destroy(pdulist, NULL);
octstr_destroy(msgid);
gwlist_destroy(parts, octstr_destroy_item);
+ warning(0, "opensmppbox: msg_to_pdu: no msg corresponding dlr, ignoring");
return NULL;
}
dlvrd = octstr_imm("000");
@@ -901,7 +1035,6 @@
if (box->version > 0x33) {
pdu2->u.deliver_sm.receipted_message_id = octstr_duplicate(msgid2);
pdu2->u.deliver_sm.message_state = dlr_state;
- dict_destroy(pdu2->u.deliver_sm.tlv);
pdu2->u.deliver_sm.tlv = meta_data_get_values(msg->sms.meta_data, "smpp");
}
pdu2->u.deliver_sm.short_message = octstr_format("id:%S sub:001 dlvrd:%S submit date:%s done date:%s stat:%S err:%s text:%12s", msgid2, dlvrd, submit_date_c_str, done_date_c_str, dlr_status, err, text);
@@ -1028,7 +1161,7 @@
parts = NULL;
}
- debug("SMPP", 0, "message length %ld, sending %ld message%s",
+ debug("opensmppbox", 0, "message length %ld, sending %ld message%s",
octstr_len(msg->sms.msgdata), msg_count, msg_count == 1 ? "" : "s");
if (parts) {
@@ -1055,7 +1188,6 @@
}
if (box->version > 0x33) {
- dict_destroy(pdu2->u.deliver_sm.tlv);
pdu2->u.deliver_sm.tlv = meta_data_get_values(msg->sms.meta_data, "smpp");
}
@@ -1067,7 +1199,6 @@
}
else {
if (box->version > 0x33) {
- dict_destroy(pdu->u.deliver_sm.tlv);
pdu->u.deliver_sm.tlv = meta_data_get_values(msg->sms.meta_data, "smpp");
}
@@ -1162,7 +1292,7 @@
if (pdu->u.submit_sm.esm_class & ESM_CLASS_SUBMIT_UDH_INDICATOR) {
int udhl;
udhl = octstr_get_char(msg->sms.msgdata, 0) + 1;
- debug("bb.sms.smpp",0,"SMPP[%s]: UDH length read as %d",
+ debug("opensmppbox",0,"SMPP[%s]: UDH length read as %d",
octstr_get_cstr(box->boxc_id), udhl);
if (udhl > octstr_len(msg->sms.msgdata)) {
error(0, "SMPP[%s]: Mallformed UDH length indicator 0x%03x while message length "
@@ -1348,7 +1477,7 @@
if (pdu->u.data_sm.esm_class & ESM_CLASS_SUBMIT_UDH_INDICATOR) {
int udhl;
udhl = octstr_get_char(msg->sms.msgdata, 0) + 1;
- debug("bb.sms.smpp",0,"SMPP[%s]: UDH length read as %d",
+ debug("opensmppbox",0,"SMPP[%s]: UDH length read as %d",
octstr_get_cstr(box->boxc_id), udhl);
if (udhl > octstr_len(msg->sms.msgdata)) {
error(0, "SMPP[%s]: Mallformed UDH length indicator 0x%03x while message length "
@@ -1500,6 +1629,12 @@
int msg_to_send = 1;
List *parts_list = NULL;
char id[UUID_STR_LEN + 1];
+ Connection *bearerbox_connection;
+
+ if (usesmppboxid)
+ bearerbox_connection = bbbox->bearerbox_connection;
+ else
+ bearerbox_connection = box->bearerbox_connection;
dump_pdu("Got PDU:", box->boxc_id, pdu);
switch (pdu->type) {
@@ -1524,7 +1659,8 @@
box->login_type = SMPP_LOGIN_TRANSMITTER;
box->boxc_id = systemidisboxcid ? octstr_duplicate(pdu->u.bind_transmitter.system_id) : octstr_duplicate(system_type);
box->sms_service = octstr_duplicate(pdu->u.bind_transmitter.system_id);
- identify_to_bearerbox(box);
+ if (!usesmppboxid)
+ identify_to_bearerbox(box->bearerbox_connection, box->boxc_id);
resp = smpp_pdu_create(bind_transmitter_resp, pdu->u.bind_transmitter.sequence_number);
resp->u.bind_transmitter_resp.system_id = octstr_duplicate(our_system_id);
}
@@ -1541,7 +1677,8 @@
box->login_type = SMPP_LOGIN_RECEIVER;
box->boxc_id = systemidisboxcid ? octstr_duplicate(pdu->u.bind_transmitter.system_id) : octstr_duplicate(system_type);
box->sms_service = octstr_duplicate(pdu->u.bind_receiver.system_id);
- identify_to_bearerbox(box);
+ if (!usesmppboxid)
+ identify_to_bearerbox(box->bearerbox_connection, box->boxc_id);
resp = smpp_pdu_create(bind_receiver_resp, pdu->u.bind_receiver.sequence_number);
resp->u.bind_receiver_resp.system_id = octstr_duplicate(our_system_id);
}
@@ -1558,7 +1695,8 @@
box->login_type = SMPP_LOGIN_TRANSCEIVER;
box->boxc_id = systemidisboxcid ? octstr_duplicate(pdu->u.bind_transmitter.system_id) : octstr_duplicate(system_type);
box->sms_service = octstr_duplicate(pdu->u.bind_transceiver.system_id);
- identify_to_bearerbox(box);
+ if (!usesmppboxid)
+ identify_to_bearerbox(box->bearerbox_connection, box->boxc_id);
resp = smpp_pdu_create(bind_transceiver_resp, pdu->u.bind_transceiver.sequence_number);
resp->u.bind_transceiver_resp.system_id = octstr_duplicate(our_system_id);
}
@@ -1587,7 +1725,6 @@
check_multipart(box, msg, &msg_to_send, &msg2, &parts_list);
msg->sms.smsc_id = box->route_to_smsc ? octstr_duplicate(box->route_to_smsc) : NULL;
msg->sms.boxc_id = octstr_duplicate(box->boxc_id);
- msg_dump(msg, 0);
resp = smpp_pdu_create(data_sm_resp, pdu->u.data_sm.sequence_number);
msgid = generate_smppid(msg);
msg->sms.dlr_url = octstr_duplicate(msgid);
@@ -1601,15 +1738,23 @@
msg2->sms.dlr_url = concat_msgids(msgid, parts_list);
}
dlr_add(box->boxc_id, msgid, msg2);
+ if (usesmppboxid)
+ change_box_id(msg2);
octstr_destroy(msgid);
octstr_destroy(msg2->sms.service);
msg2->sms.service = hold_service;
}
uuid_unparse(msg2->sms.id, id);
msgid = octstr_create(id);
+ if (!usesmppboxid)
dict_put(box->msg_acks, msgid, resp);
+ else
+ dict_put(bbbox->msg_acks, msgid, resp);
resp = NULL;
- send_msg(box->bearerbox_connection, box, msg2);
+ if (usesmppboxid) {
+ send_msg(bearerbox_connection, msg2);
+ } else
+ send_msg(box->bearerbox_connection, msg2);
if (parts_list) {
/* destroy values */
gwlist_destroy(parts_list, msg_destroy_item);
@@ -1628,11 +1773,16 @@
check_multipart(box, msg, &msg_to_send, &msg2, &parts_list);
msg->sms.smsc_id = box->route_to_smsc ? octstr_duplicate(box->route_to_smsc) : NULL;
msg->sms.boxc_id = octstr_duplicate(box->boxc_id);
- msg_dump(msg, 0);
resp = smpp_pdu_create(submit_sm_resp, pdu->u.submit_sm.sequence_number);
msgid = generate_smppid(msg);
msg->sms.dlr_url = octstr_duplicate(msgid);
- resp->u.submit_sm_resp.message_id = msgid;
+ resp->u.submit_sm_resp.message_id = octstr_duplicate(msgid);
+ /* Note that we add msg to dlr tzble in all cases.
+ * In case of report_mo, need is obvious. In case
+ * of mo, it is needed to route resps. Report mo must be stored before
+ * we gahnge box id.*/
+ if (usesmppboxid)
+ msg_add(msg->sms.boxc_id, msgid, msg);
if (msg_to_send) {
if (DLR_IS_ENABLED(msg2->sms.dlr_mask)) {
hold_service = msg2->sms.service;
@@ -1641,17 +1791,26 @@
if (parts_list) {
msg2->sms.dlr_url = concat_msgids(msgid, parts_list);
}
- dlr_add(box->boxc_id, msgid, msg2);
+ //dlr_add(box->boxc_id, msgid, msg2);
+ if (usesmppboxid)
+ change_box_id(msg2);
octstr_destroy(msgid);
octstr_destroy(msg2->sms.service);
msg2->sms.service = hold_service;
}
uuid_unparse(msg2->sms.id, id);
msgid = octstr_create(id);
+ if (!usesmppboxid) {
dict_put(box->msg_acks, msgid, resp);
+ } else {
+ dict_put(bbbox->msg_acks, msgid, resp);
+ }
octstr_destroy(msgid);
resp = NULL;
- send_msg(box->bearerbox_connection, box, msg2);
+ if (usesmppboxid) {
+ send_msg(bearerbox_connection, msg2);
+ } else
+ send_msg(box->bearerbox_connection, msg2);
if (parts_list) {
/* destroy values */
gwlist_destroy(parts_list, msg_destroy_item);
@@ -1668,7 +1827,11 @@
if (pdu->u.deliver_sm_resp.command_status != 0) {
msg->ack.nack = ack_failed;
}
- send_msg(box->bearerbox_connection, box, msg);
+ if (usesmppboxid) {
+ send_msg(bearerbox_connection, msg);
+ } else {
+ send_msg(box->bearerbox_connection, msg);
+ }
dict_put(box->deliver_acks, msgid, NULL);
}
octstr_destroy(msgid);
@@ -1692,7 +1855,6 @@
smpp_pdu_destroy(pdu);
if (resp != NULL) {
send_pdu(conn, box->boxc_id, resp);
- smpp_pdu_destroy(resp);
}
}
@@ -1712,11 +1874,13 @@
boxc->is_wap = 0;
boxc->load = 0;
boxc->smpp_connection = conn_wrap_fd(fd, ssl);
+ boxc->bearerbox_connection = NULL;
boxc->id = counter_increase(boxid);
boxc->client_ip = octstr_duplicate(ip);
boxc->alive = 1;
boxc->connect_time = time(NULL);
- boxc->boxc_id = NULL;
+ boxc->boxc_id = octstr_duplicate(smppbox_id); /* Fix this one*/
+ boxc->our_id = octstr_duplicate(smppbox_id);
boxc->routable = 0;
boxc->smpp_pdu_counter = counter_create();
boxc->alt_charset = NULL; /* todo: get from config */
@@ -1754,6 +1918,8 @@
conn_destroy(boxc->bearerbox_connection);
if (boxc->boxc_id)
octstr_destroy(boxc->boxc_id);
+ if (boxc->our_id)
+ octstr_destroy(boxc->our_id);
if (boxc->alt_charset)
octstr_destroy(boxc->alt_charset);
counter_destroy(boxc->smpp_pdu_counter);
@@ -1767,6 +1933,31 @@
gw_free(boxc);
}
+static BBBoxc *bbboxc_create(void)
+{
+ BBBoxc *boxc;
+
+ boxc = gw_malloc(sizeof(BBBoxc));
+ boxc->bearerbox_connection = connect_to_bearerbox_real(bearerbox_host, bearerbox_port, bearerbox_port_ssl, NULL);
+ boxc->alive = 1;
+ boxc->mo_recode = 0;
+ boxc->msg_acks = dict_create(1024, smpp_pdu_destroy_item);
+
+ return boxc;
+}
+
+static void bbboxc_destroy(BBBoxc *boxc)
+{
+ if (boxc == NULL)
+ return;
+
+ /* do not do anyhting to dict, it stpres only refrences*/
+ if (boxc->bearerbox_connection)
+ conn_destroy(boxc->bearerbox_connection);
+
+ gw_free(boxc);
+}
+
/* ------------------------------------------------------------------
* SMPP thingies
* ------------------------------------------------------------------
@@ -1816,7 +2007,9 @@
SMPP_PDU *pdu;
long len;
+ error(0, "opensmppbox: smpp_to_bearerbox: thread starts");
box->last_pdu_received = time(NULL);
+
while (smppbox_status == SMPP_RUNNING && box->alive) {
len = 0;
switch (read_pdu(box, conn, &len, &pdu)) {
@@ -1838,16 +2031,117 @@
}
}
#ifdef HAVE_SHUTDOWN_CONNECTION
+ if (!usesmppboxid)
shutdown_connection(box->bearerbox_connection);
#endif
+ error(0, "opensmppbox: smpp_to_bearerbox: thread terminates");
+}
+
+/*
+ * Check do we have a specific route to pass this msg to client-id?
+ */
+static Octstr *find_configured_box_id(Msg *msg)
+{
+ Octstr *boxc_id = NULL;
+ Octstr *r, *s, *rs;
+ /*
+ * Check if we have a "client-route" for this msg.
+ * Where the shortcode route has a higher priority then the smsc-id rule.
+ * Highest priority has the combined <shortcode>:<smsc-id> route.
+ */
+ Octstr *os = octstr_format("%s:%s", octstr_get_cstr(msg->sms.receiver),
+ octstr_get_cstr(msg->sms.smsc_id));
+ s = (msg->sms.smsc_id ? dict_get(client_by_smsc, msg->sms.smsc_id) : NULL);
+ r = (msg->sms.receiver ? dict_get(client_by_receiver, msg->sms.receiver) : NULL);
+ rs = (os ? dict_get(client_by_smsc_receiver, os) : NULL);
+ octstr_destroy(os);
+ if (rs)
+ boxc_id = rs;
+ else if (r)
+ boxc_id = r;
+ else if (s)
+ boxc_id = s;
+
+ return boxc_id;
}
-/* if this login was made as a transmitter, then find the corresponding receiver connection */
-static Boxc *find_receiver_box(Boxc *box)
+static Boxc *find_box_by_id(Octstr *boxc_id)
+{
+ Boxc *thisbox;
+ long retry = 0;
+ long i = 0;
+ long cnt = gwlist_len(all_boxes);
+ while (i < cnt) {
+ thisbox = gwlist_get(all_boxes, i);
+ if (!thisbox || !(thisbox->boxc_id)) {
+ ++i;
+ continue;
+ }
+
+ /* Reject connection that is just sending*/
+ if (thisbox->login_type == SMPP_LOGIN_TRANSMITTER){
+ ++i;
+ continue;
+ }
+
+ /* If the client was not logged in, wait some time*/
+ if (thisbox->login_type == SMPP_LOGIN_NOTLOGGEDIN && retry < 30){
+ ++retry;
+ if (retry < 30)
+ gwthread_sleep(0.1);
+ else
+ ++i;
+ continue;
+ }
+
+ if (boxc_id && octstr_compare(thisbox->boxc_id, boxc_id) == 0) {
+ return thisbox;
+ }
+ ++i;
+ }
+
+ return NULL;
+}
+
+/*
+ * This function is used to route msg acks. Ack's msg id maps ack to original
+ * message. The box id of the original message is used for routing.
+ */
+static Boxc *find_receiver_box_by_msg_id(Octstr *msgid, Msg *msg)
+{
+ Msg *sack;
+ Octstr *boxid = NULL;
+ Boxc *thisbox;
+
+ sack = dlr_find_by_id(msgid, USE_UUID);
+ if (sack)
+ boxid = sack->sms.boxc_id;
+ else
+ return NULL;
+
+ if (boxid)
+ thisbox = find_box_by_id(boxid);
+ else
+ return NULL;
+
+ return thisbox;
+}
+
+/* if this login was made as a transmitter or receiver, then find the corresponding
+ * receiver connection */
+static Boxc *find_receiver_box(Boxc *box, Msg *msg)
{
Boxc *thisbox;
int cnt;
+ Octstr *boxc_id = NULL;
+ int report_mo = 0;
+ int retry = 0;
+ if (usesmppboxid && octstr_len(msg->sms.boxc_id) > 0) {
+ boxc_id = msg->sms.boxc_id;
+ }
+
+ if (!usesmppboxid) {
if (box->login_type == SMPP_LOGIN_RECEIVER || box->login_type == SMPP_LOGIN_TRANSCEIVER) {
return box;
}
@@ -1858,37 +2152,93 @@
}
}
return box;
+ }
+
+ else {
+ /* If we had no clients, wait a little, bearerbox may resend when they be connecting*/
+ report_mo = 1;
+ while (gwlist_len(all_boxes) == 0 && retry < 3) {
+ gwthread_sleep(1);
+ ++retry;
+ }
+
+ if (gwlist_len(all_boxes) == 0 && retry == 3)
+ return NULL;
+
+ if (msg->sms.sms_type == mo) {
+ report_mo = 0;
+ boxc_id = find_configured_box_id(msg);
+ }
+
+ /*
+ * Report_mos will be routed simply by they boxc-id, defined by smsbox-route.
+ * If there is none, a random box is picked.
+ */
+ thisbox = find_box_by_id(boxc_id);
+
+ /* If no box was found and we have MO, pick a random box. In case
+ * of DLR, this is an error. */
+ if (!thisbox && report_mo) {
+ thisbox = gwlist_get(all_boxes, gw_rand() % gwlist_len(all_boxes));
+ return thisbox;
+ }
+
+ return thisbox;
+ }
}
static void bearerbox_to_smpp(void *arg)
{
Msg *msg, *mack;
- Boxc *box = arg;
+ Boxc *box;
+ BBBoxc *bbbox;
SMPP_PDU *pdu;
- List *pdulist;
+ List *pdulist = NULL;
int dreport, errcode;
- Boxc *receiver_box;
+ Boxc *receiver_box = NULL;
char id[UUID_STR_LEN + 1];
Octstr *msgid;
- while (smppbox_status == SMPP_RUNNING && box->alive) {
+ error(0, "opensmppbox: bearerbox_to_smpp: thread starts");
- msg = read_from_box(box->bearerbox_connection, box);
+ if (!usesmppboxid) {
+ box = arg;
+ } else {
+ bbbox = arg;
+ }
+
+ while (smppbox_status == SMPP_RUNNING && (usesmppboxid ? bbbox->alive : box->alive)) {
+
+ if (usesmppboxid)
+ msg = read_from_box(bbbox->bearerbox_connection, bbbox->alive);
+ else
+ msg = read_from_box(box->bearerbox_connection, box->alive);
if (msg == NULL) {
- if ((!box->alive) || conn_eof(box->bearerbox_connection)) {
/* tell opensmppbox to die */
/* the client closes the connection, after that die in receiver */
+ if (usesmppboxid)
+ if (conn_eof(bbbox->bearerbox_connection))
+ bbbox->alive = 0;
+ else
+ if (conn_eof(box->bearerbox_connection))
box->alive = 0;
- }
continue;
}
+ debug("", 0, "we have msg from bearerbox");
+ msg_dump(msg, 0);
if (msg_type(msg) == admin) {
if (msg->admin.command == cmd_shutdown) {
info(0, "Bearerbox told us to die");
+ if (usesmppboxid)
+ bbbox->alive = 0;
+ else
box->alive = 0;
} else if (msg->admin.command == cmd_restart) {
info(0, "Bearerbox told us to restart");
restart = 1;
+ if (usesmppboxid)
+ bbbox->alive = 0;
+ else
box->alive = 0;
}
}
@@ -1901,7 +2251,11 @@
if (msg_type(msg) == ack) {
uuid_unparse(msg->ack.id, id);
msgid = octstr_create(id);
+ if (!usesmppboxid)
pdu = dict_get(box->msg_acks, msgid);
+ else
+ pdu = dict_get(bbbox->msg_acks, msgid);
+
errcode = SMPP_ESME_RMSGQFUL; /* in case we get ack_failed_tmp */
if (pdu) {
switch (msg->ack.nack) {
@@ -1933,26 +2287,38 @@
debug("opensmppbox", 0, "Unknown ack.nack type: %ld.", msg->ack.nack);
break;
}
+ if (!usesmppboxid) {
send_pdu(box->smpp_connection, box->boxc_id, pdu);
dict_put(box->msg_acks, msgid, NULL); /* also destroys item */
+ } else {
+ Boxc *receiver_box = find_receiver_box_by_msg_id(msgid, msg);
+ if (receiver_box) {
+ send_pdu(receiver_box->smpp_connection, receiver_box->boxc_id, pdu);
+ dict_put(receiver_box->msg_acks, msgid, NULL);
+ }
+ //dlr_remove_by_id(msg);
+ }
}
else {
debug("opensmppbox", 0, "Ack to unknown message: %s.", id);
}
octstr_destroy(msgid);
}
- if (!box->alive) {
+ if (usesmppboxid ? !bbbox->alive : !box->alive) {
msg_destroy(msg);
break;
}
if (msg_type(msg) == sms) {
info(0, "We received an SMS message.");
- if (msg->sms.sms_type == report_mo)
+ uuid_unparse(msg->sms.id, id);
+ msgid = octstr_create(id);
+ if (msg->sms.sms_type == report_mo) {
dreport = 1;
- else
+ } else {
dreport = 0;
+ }
/* Recode to iso-8859-1 the MO message if possible */
- if (box->mo_recode && msg->sms.coding == DC_UCS2) {
+ if ((usesmppboxid ? bbbox->mo_recode : box->mo_recode) && msg->sms.coding == DC_UCS2) {
int converted = 0;
Octstr *text;
@@ -2006,7 +2372,10 @@
mack->ack.nack = ack_failed;
mack->ack.time = msg->sms.time;
uuid_copy(mack->ack.id, msg->sms.id);
- send_msg(box->bearerbox_connection, box, mack);
+ if (usesmppboxid) {
+ send_msg(bbbox->bearerbox_connection, mack);
+ } else
+ send_msg(box->bearerbox_connection, mack);
msg_destroy(msg);
continue;
@@ -2017,8 +2386,12 @@
mack->ack.time = msg->sms.time;
uuid_copy(mack->ack.id, msg->sms.id);
- msgid = NULL;
- receiver_box = find_receiver_box(box);
+ if (usesmppboxid) {
+ restore_box_id(msg, msgid);
+ receiver_box = find_receiver_box(NULL, msg);
+ } else
+ receiver_box = find_receiver_box(box, msg);
+ if (receiver_box != NULL)
pdulist = msg_to_pdu(receiver_box, msg);
if (pdulist != NULL) {
while ((pdu = gwlist_extract_first(pdulist)) != NULL) {
@@ -2027,7 +2400,7 @@
msgid = octstr_format("%ld", pdu->u.deliver_sm.sequence_number);
dict_put(receiver_box->deliver_acks, msgid, mack);
}
- send_pdu(receiver_box->smpp_connection, box->boxc_id, pdu);
+ send_pdu(receiver_box->smpp_connection, receiver_box->boxc_id, pdu);
smpp_pdu_destroy(pdu);
}
if (msgid)
@@ -2038,11 +2411,17 @@
/* Send NACK to bearerbox, otherwise message remains in store file. */
warning(0, "msg_to_pdu failed, sending negative ack");
mack->ack.nack = ack_failed;
- send_msg(box->bearerbox_connection, box, mack);
+ if (usesmppboxid) {
+ send_msg(bbbox->bearerbox_connection, mack);
+ } else
+ send_msg(box->bearerbox_connection, mack);
}
}
msg_destroy(msg);
}
+
+ error(0, "opensmppbox: bearerbox_to_smpp: thread terminates");
+ smppbox_status = SMPP_SHUTDOWN;
}
static void run_smppbox(void *arg)
@@ -2057,7 +2436,8 @@
panic(0, "Socket accept failed");
return;
}
- newconn->boxc_id = octstr_duplicate(smppbox_id);
+
+ if (!usesmppboxid) {
newconn->bearerbox_connection = connect_to_bearerbox_real(bearerbox_host, bearerbox_port, bearerbox_port_ssl, NULL /* bb_our_host */);
/* XXX add our_host if required */
if (newconn->bearerbox_connection == NULL) {
@@ -2065,6 +2445,7 @@
boxc_destroy(newconn);
return;
}
+ }
gwlist_append(all_boxes, newconn);
@@ -2083,6 +2464,7 @@
boxc_destroy(newconn);
return;
}
+ if (!usesmppboxid)
bearerbox_to_smpp(newconn);
gwthread_join(sender);
gwlist_delete_equal(all_boxes, newconn);
@@ -2163,7 +2545,7 @@
switch (signum) {
case SIGINT:
-
+ case SIGTERM:
if (smppbox_status == SMPP_RUNNING) {
error(0, "SIGINT received, aborting program...");
smppbox_status = SMPP_SHUTDOWN;
@@ -2198,6 +2580,7 @@
sigaction(SIGQUIT, &act, NULL);
sigaction(SIGHUP, &act, NULL);
sigaction(SIGPIPE, &act, NULL);
+ sigaction(SIGTERM, &act, NULL);
}
@@ -2210,6 +2593,109 @@
{
}
+/*
+ * Populates the corresponding client_by_foobar dictionary hash tables
+ */
+static void init_client_routes(Cfg *cfg)
+{
+ CfgGroup *grp;
+ List *list, *items;
+ Octstr *client_id, *smsc_ids, *shortcuts;
+ int i, j;
+
+ client_id = smsc_ids = shortcuts = NULL;
+
+ list = cfg_get_multi_group(cfg, octstr_imm("client-route"));
+
+ /* loop multi-group "client-route" */
+ while (list && (grp = gwlist_extract_first(list)) != NULL) {
+ if ((client_id = cfg_get(grp, octstr_imm("client-id"))) == NULL) {
+ grp_dump(grp);
+ panic(0,"'client-route' group without valid 'client-id' directive!");
+ }
+
+ /*
+ * If smsc-id is given, then any message comming from the specified
+ * smsc-id in the list will be routed to this client.
+ * If shortcode is given, then any message with receiver number
+ * matching those will be routed to this client.
+ * If both are given, then only receiver within shortcode originating
+ * from smsc-id list will be routed to this cleint. So if both are
+ * present then this is a logical AND operation.
+ */
+ smsc_ids = cfg_get(grp, octstr_imm("smsc-id"));
+ shortcuts = cfg_get(grp, octstr_imm("shortcode"));
+
+ /* consider now the 3 possibilities: */
+ if (smsc_ids && !shortcuts) {
+ /* smsc-id only, so all MO traffic */
+ items = octstr_split(smsc_ids, octstr_imm(";"));
+ for (i = 0; i < gwlist_len(items); i++) {
+ Octstr *item = gwlist_get(items, i);
+ octstr_strip_blanks(item);
+
+ debug("opensmppbox",0,"Adding client routing to id <%s> for smsc id <%s>",
+ octstr_get_cstr(client_id), octstr_get_cstr(item));
+
+ if (!dict_put_once(client_by_smsc, item, octstr_duplicate(client_id)))
+ panic(0, "Routing for smsc-id <%s> already exists!",
+ octstr_get_cstr(item));
+ }
+ gwlist_destroy(items, octstr_destroy_item);
+ octstr_destroy(smsc_ids);
+ }
+ else if (!smsc_ids && shortcuts) {
+ /* shortcode only, so these MOs from all smscs */
+ items = octstr_split(shortcuts, octstr_imm(";"));
+ for (i = 0; i < gwlist_len(items); i++) {
+ Octstr *item = gwlist_get(items, i);
+ octstr_strip_blanks(item);
+
+ debug("opensmppbox",0,"Adding client routing to id <%s> for receiver no <%s>",
+ octstr_get_cstr(client_id), octstr_get_cstr(item));
+
+ if (!dict_put_once(client_by_receiver, item, octstr_duplicate(client_id)))
+ panic(0, "Routing for receiver no <%s> already exists!",
+ octstr_get_cstr(item));
+ }
+ gwlist_destroy(items, octstr_destroy_item);
+ octstr_destroy(shortcuts);
+ }
+ else if (smsc_ids && shortcuts) {
+ /* both, so only specified MOs from specified smscs */
+ items = octstr_split(shortcuts, octstr_imm(";"));
+ for (i = 0; i < gwlist_len(items); i++) {
+ List *subitems;
+ Octstr *item = gwlist_get(items, i);
+ octstr_strip_blanks(item);
+ subitems = octstr_split(smsc_ids, octstr_imm(";"));
+ for (j = 0; j < gwlist_len(subitems); j++) {
+ Octstr *subitem = gwlist_get(subitems, j);
+ octstr_strip_blanks(subitem);
+
+ debug("opensmppbox",0,"Adding client routing to id <%s> "
+ "for receiver no <%s> and smsc id <%s>",
+ octstr_get_cstr(client_id), octstr_get_cstr(item),
+ octstr_get_cstr(subitem));
+
+ /* construct the dict key '<shortcode>:<smsc-id>' */
+ octstr_insert(subitem, item, 0);
+ octstr_insert_char(subitem, octstr_len(item), ':');
+ if (!dict_put_once(client_by_smsc_receiver, subitem, octstr_duplicate(client_id)))
+ panic(0, "Routing for receiver:smsc <%s> already exists!",
+ octstr_get_cstr(subitem));
+ }
+ gwlist_destroy(subitems, octstr_destroy_item);
+ }
+ gwlist_destroy(items, octstr_destroy_item);
+ octstr_destroy(shortcuts);
+ }
+ octstr_destroy(client_id);
+ }
+
+ gwlist_destroy(list, NULL);
+}
+
static void init_smppbox(Cfg *cfg)
{
CfgGroup *grp;
@@ -2225,6 +2711,7 @@
lvl = 0;
systemidisboxcid = 0; /* default backward compatible */
enablepam = 0; /* also default false */
+ usesmppboxid = 0; /* Ditto */
/* init dlr storage */
dlr_init(cfg);
@@ -2298,6 +2784,7 @@
cfg_get_bool(&systemidisboxcid, grp, octstr_imm("use-systemid-as-smsboxid"));
cfg_get_bool(&enablepam, grp, octstr_imm("enable-pam"));
+ cfg_get_bool(&usesmppboxid, grp, octstr_imm("use-smppboxid"));
pamacl = cfg_get(grp, octstr_imm("pam-acl"));
if (NULL == pamacl) {
pamacl = octstr_create("kannel");
@@ -2318,6 +2805,12 @@
boxid = counter_create();
gw_smpp_enter(cfg);
+ /* the client routing specific inits */
+ client_by_smsc = dict_create(30, (void(*)(void *)) octstr_destroy);
+ client_by_receiver = dict_create(50, (void(*)(void *)) octstr_destroy);
+ client_by_smsc_receiver = dict_create(50, (void(*)(void *)) octstr_destroy);
+ init_client_routes(cfg);
+
smppbox_status = SMPP_RUNNING;
}
@@ -2414,15 +2907,30 @@
octstr_destroy(version);
init_smppbox(cfg);
-
+ if (usesmppboxid) {
+ bbbox = bbboxc_create();
+ identify_to_bearerbox(bbbox->bearerbox_connection, smppbox_id);
+ gwthread_create(bearerbox_to_smpp, bbbox);
+ }
smppboxc_run((void *)smppbox_port);
/* shutdown dlr storage */
heartbeat_stop(ALL_HEARTBEATS);
+ if (usesmppboxid) {
+ gwthread_join_every(bearerbox_to_smpp);
+ bbboxc_destroy(bbbox);
+ }
dlr_shutdown();
counter_destroy(catenated_sms_counter);
counter_destroy(boxid);
+ dict_destroy(client_by_smsc);
+ client_by_smsc = NULL;
+ dict_destroy(client_by_receiver);
+ client_by_receiver = NULL;
+ dict_destroy(client_by_smsc_receiver);
+ client_by_smsc_receiver = NULL;
+
if (restart_smppbox) {
gwthread_sleep(1.0);
}
Only in gw: opensmppbox.c.save
Only in gw: opensmppbox.c.save.1
Only in gw: opensmppbox.c.save.10
Only in gw: opensmppbox.c.save.11
Only in gw: opensmppbox.c.save.12
Only in gw: opensmppbox.c.save.2
Only in gw: opensmppbox.c.save.3
Only in gw: opensmppbox.c.save.4
Only in gw: opensmppbox.c.save.5
Only in gw: opensmppbox.c.save.6
Only in gw: opensmppbox.c.save.7
Only in gw: opensmppbox.c.save.8
Only in gw: opensmppbox.c.save.9
Only in gw: opensmppbox.o