RE: Oded AT2 DLR patch
"Oded Arbel" <[email protected]>
| Newsgroups | gmane.comp.mobile.kannel.devel |
|---|---|
| Message-ID | <[email protected]> |
> -----Original Message----- > From: Andrea Viscovich [mailto:[email protected]] > > There is a problem. > In at2_send_one message here is the code: <snip> > So if one has dlrmask = 3 will never get dlr, as there is dlr only > if in the mask is set DLR_SMSC_SUCCESS bit ahmm.. oops ? :-\ > Oded, think I found my problem :-), Yes you did. updated patch attached. > by the way you should tell me which dlrmask you were using! 31. > P.S. in smsc_at2.c in your patch you have some debug("bb.at2...... So ? -- Oded Arbel m-Wise mobile solutions [email protected] +972-9-9581711 (116) +972-67-340014 ::.. Diplomacy is the art of saying "nice doggy" until you can find a rock.
smsc_at2.patch
(application/octet-stream, 12.7 KB)
--- gateway/gw/smsc/smsc_at2.c 2002-08-08 20:44:38.000000000 +0300
+++ gateway/gw/smsc/smsc_at2.c 2002-08-11 14:18:19.000000000 +0300
@@ -241,6 +241,7 @@
{
int count;
int s = 0;
+ int write_count = 0;
Octstr *linestr = NULL;
linestr = octstr_format("%s\r", line);
@@ -248,7 +249,15 @@
debug("bb.smsc.at2", 0, "AT2[%s]: --> %s^M", octstr_get_cstr(privdata->name), line);
count = octstr_len(linestr);
- s = write(privdata->fd, octstr_get_cstr(linestr), count);
+ while (1) {
+ errno = 0;
+ s = write(privdata->fd, octstr_get_cstr(linestr), count);
+ if (s < 0 && errno == EAGAIN && write_count < RETRY_SEND) {
+ gwthread_sleep(1);
+ ++write_count;
+ } else
+ break;
+ };
O_DESTROY(linestr);
if (s < 0) {
debug("bb.smsc.at2", 0, "AT2[%s]: write failed with errno %d",
@@ -266,9 +275,18 @@
{
int s;
char *ctrlz = "\032" ;
-
+ int write_count = 0;
+
debug("bb.smsc.at2", 0, "AT2[%s]: --> ^Z", octstr_get_cstr(privdata->name));
- s = write(privdata->fd, ctrlz, 1);
+ while (1) {
+ errno = 0;
+ s = write(privdata->fd, ctrlz, 1);
+ if (s < 0 && errno == EAGAIN && write_count < RETRY_SEND) {
+ gwthread_sleep(1);
+ ++write_count;
+ } else
+ break;
+ };
if (s < 0) {
debug("bb.smsc.at2", 0, "AT2[%s]: write failed with errno %d",
octstr_get_cstr(privdata->name), errno);
@@ -470,7 +488,7 @@
int at2_wait_modem_command(PrivAT2data *privdata, time_t timeout, int gt_flag,
- int *messages_collected)
+ int *output)
{
Octstr *line = NULL;
Octstr *line2 = NULL;
@@ -541,8 +559,8 @@
octstr_get_cstr(privdata->name));
} else {
/* count message even if I can't decode it */
- if (messages_collected)
- ++(*messages_collected);
+ if (output)
+ ++(*output);
msg = at2_pdu_decode(pdu, privdata);
if (msg != NULL) {
msg->sms.smsc_id = octstr_duplicate(privdata->conn->id);
@@ -559,6 +577,14 @@
}
continue;
}
+ if ((octstr_search(line, octstr_imm("+CMGS:"),0) != -1) && (output)) {
+ /* found response to a +CMGS command, read the message id and return it in output */
+ long temp;
+ if (octstr_parse_long(&temp, line, octstr_search(line, octstr_imm("+CMGS:"),0)+6,10) == -1)
+ error(0,"AT2[%s]: got +CMGS but failed to read message id", octstr_get_cstr(privdata->name));
+ else
+ *output = temp;
+ }
if ( -1 != octstr_search(line, octstr_imm("ERROR"), 0)) {
ret = -1;
@@ -1183,6 +1222,9 @@
case AT_DELIVER_SM:
msg = at2_pdu_decode_deliver_sm(data, privdata);
break;
+ case AT_STATUS_REPORT_SM:
+ msg = at2_pdu_decode_report_sm(data, privdata);
+ break;
/* Add other message types here: */
@@ -1354,6 +1396,119 @@
return message;
}
+Msg *at2_pdu_decode_report_sm(Octstr *data, PrivAT2data *privdata)
+{
+/* example : 06 D2 0B 91 79 62 37 04 10 F4 20 80 80 81 52 05 00 20 80 80 81 52 45 00 00
+ MR 0B 91 97267340014-sender 02080818255000 ts 02080818255400 ts 00
+
+ buffered : 06DC0B917962370410F4208080027075002080800270850030
+ received : 06DC0B917962370410F4208080027075002080800211740000
+
+*/
+ Msg* dlrmsg = NULL;
+ Octstr *pdu, *msg_id, *tmpstr = NULL, *receiver = NULL;
+ int type, tp_mr, len, ntype, pos;
+
+ /*
+ * parse the PDU.
+ */
+
+ /* convert the pdu to binary format for ease of processing */
+ pdu = at2_convertpdu(data);
+
+ /* Message reference */
+ tp_mr = octstr_get_char(pdu,1);
+ msg_id = octstr_format("%d",tp_mr);
+ debug("bb.smsc.at2",0,"AT2[%s]: got STATUS-REPORT for message <%d>:", octstr_get_cstr(privdata->name), tp_mr);
+
+ /* reciver address */
+ len = octstr_get_char(pdu, 2);
+ ntype = octstr_get_char(pdu, 3);
+
+ pos = 4;
+ if ((ntype & 0xD0) == 0xD0) {
+ /* Alphanumeric sender */
+ receiver = octstr_create("");
+ tmpstr = octstr_copy(pdu, pos, (len+1)/2);
+ at2_decode7bituncompressed(tmpstr, (((len - 1) * 4 - 3) / 7) + 1, receiver, 0);
+ octstr_destroy(tmpstr);
+ debug("bb.smsc.at2", 0, "AT2[%s]: Alphanumeric receiver <%s>",
+ octstr_get_cstr(privdata->name), octstr_get_cstr(receiver));
+ pos += (len + 1) / 2;
+ } else {
+ int i;
+ receiver = octstr_create("");
+ if ((ntype & 0x90) == 0x90) {
+ /* International number */
+ octstr_append_char(receiver, '+');
+ }
+ for (i = 0; i < len; i += 2, pos++) {
+ octstr_append_char(receiver, (octstr_get_char(pdu, pos) & 15) + 48);
+ if (i + 1 < len)
+ octstr_append_char(receiver, (octstr_get_char(pdu, pos) >> 4) + 48);
+ }
+ debug("bb.smsc.at2", 0, "AT2[%s]: Numeric receiver %s <%s>",
+ octstr_get_cstr(privdata->name), ((ntype & 0x90) == 0x90 ? "(international)" : ""),
+ octstr_get_cstr(receiver));
+ }
+
+ pos += 14; /* skip time stamps for now */
+
+ if ((type = octstr_get_char(pdu, pos)) == -1 ) {
+ error(1,"AT2[%s]: STATUS-REPORT pdu too short to have TP-Status field !",
+ octstr_get_cstr(privdata->name));
+ goto error;
+ }
+
+ /* check DLR type:
+ * 3GPP TS 23.040 defines this a bit mapped field with lots of options
+ * most of which are not really intersting to us, as we are only interested
+ * in one of three conditions : failed, held in SC for delivery later, or delivered successfuly
+ * and here's how I suggest to test it (read the 3GPP reference for further detailes) -
+ * we'll test the 6th and 5th bits (7th bit when set making all other values 'reseved' so I want to test it).
+ */
+ type = type & 0xE0; /* filter out everything but the 7th, 6th and 5th bits */
+ switch (type) {
+ case 0x00:
+ /* 0 0 : success class */
+ type = DLR_SUCCESS;
+ tmpstr = octstr_create("Success/");
+ break;
+ case 0x20:
+ /* 0 1 : buffered class (temporary error) */
+ type = DLR_BUFFERED;
+ tmpstr = octstr_create("Buffered/");
+ break;
+ case 0x40:
+ case 0x60:
+ default:
+ /* 1 0 : failed class */
+ /* 1 1 : failed class (actually, temporary error but timed out) */
+ /* and any other value (can't think of any) is considered failure */
+ type = DLR_FAIL;
+ tmpstr = octstr_create("Failed/");
+ break;
+ }
+ /* Actually, the above implementation is not correct, as the reference says that implementations should consider
+ * any "reserved" values to be "failure", but most reserved values fall into one of the three categories. it will catch
+ * "reserved" values where the first 3 MSBits are not set as "Success" which may not be correct. */
+
+ if ((dlrmsg = dlr_find(octstr_get_cstr(privdata->conn->id),
+ octstr_get_cstr(msg_id), octstr_get_cstr(receiver), type)) == NULL) {
+ debug("bb.at2",1,"AT2[%s]: Received delivery notification but can't find that ID in the DLR storage",
+ octstr_get_cstr(privdata->name));
+ goto error;
+ }
+
+ octstr_insert(dlrmsg->sms.msgdata, tmpstr, 0);
+
+error:
+ O_DESTROY(tmpstr);
+ O_DESTROY(pdu);
+ O_DESTROY(receiver);
+ O_DESTROY(msg_id);
+ return dlrmsg;
+}
Octstr *at2_convertpdu(Octstr *pdutext)
{
@@ -1461,6 +1616,7 @@
ret = -99;
retries = RETRY_SEND;
while ((ret != 0) && (retries-- > 0)) {
+ int msg_id = -1;
/*
* send the initial command and then wait for >
*/
@@ -1481,17 +1637,76 @@
at2_write_ctrlz(privdata);
/* wait 20 secs for modem command */
- ret = at2_wait_modem_command(privdata, 20, 0, NULL);
+ ret = at2_wait_modem_command(privdata, 20, 0, &msg_id);
debug("bb.at", 0, "AT2[%s]: send command status: %d",
octstr_get_cstr(privdata->name), ret);
if (ret != 0) /* OK only */
continue;
+
+ /* gen DLR_SMSC_SUCCESS */
+ if (msg->sms.dlr_mask & DLR_SMSC_SUCCESS)
+ {
+ Msg* dlrmsg;
+
+ dlrmsg = msg_create(sms);
+ dlrmsg->sms.id = msg->sms.id;
+ dlrmsg->sms.service = octstr_duplicate(msg->sms.service);
+ dlrmsg->sms.dlr_mask = DLR_SMSC_SUCCESS;
+ dlrmsg->sms.sms_type = report;
+ dlrmsg->sms.smsc_id = octstr_duplicate(privdata->conn->id);
+ dlrmsg->sms.sender = octstr_duplicate(msg->sms.receiver);
+ dlrmsg->sms.receiver = octstr_duplicate(msg->sms.sender);
+ dlrmsg->sms.msgdata = octstr_create("ACK/");
+ octstr_append(dlrmsg->sms.msgdata,msg->sms.dlr_url);
+ time(&dlrmsg->sms.time);
+
+ debug("bb.at2",0,"AT2[%s]: sending DLR type ACK", octstr_get_cstr(privdata->name));
+ bb_smscconn_receive(privdata->conn, dlrmsg);
+
+ }
+ /* store DLR message if needed for SMSC generated delivery reports */
+ if (msg->sms.dlr_mask & (DLR_SUCCESS | DLR_FAIL | DLR_BUFFERED)) {
+ if (msg_id == -1)
+ error(0,"AT2[%s]: delivery notification requested, but I have no message ID!",
+ octstr_get_cstr(privdata->name));
+ else {
+ Octstr* dlrmsgid = octstr_format("%d", msg_id);
+
+ dlr_add(octstr_get_cstr(privdata->conn->id),
+ octstr_get_cstr(dlrmsgid),
+ octstr_get_cstr(msg->sms.receiver),
+ octstr_get_cstr(msg->sms.service),
+ octstr_get_cstr(msg->sms.dlr_url),
+ msg->sms.dlr_mask);
+
+ O_DESTROY(dlrmsgid);
+ }
+ }
counter_increase(privdata->conn->sent);
bb_smscconn_sent(privdata->conn, msg);
}
if (ret != 0) {
+ /* gen DLR_SMSC_FAIL */
+ if (msg->sms.dlr_mask & DLR_SMSC_FAIL)
+ {
+ Msg* dlrmsg;
+
+ dlrmsg = msg_create(sms);
+ dlrmsg->sms.service = octstr_duplicate(msg->sms.service);
+ dlrmsg->sms.dlr_mask = DLR_SMSC_FAIL;
+ dlrmsg->sms.sms_type = report;
+ dlrmsg->sms.smsc_id = octstr_duplicate(privdata->conn->id);
+ dlrmsg->sms.sender = octstr_duplicate(msg->sms.receiver);
+ dlrmsg->sms.receiver = octstr_duplicate(msg->sms.sender);
+ dlrmsg->sms.msgdata = octstr_create("NACK/");
+ octstr_append(dlrmsg->sms.msgdata,msg->sms.dlr_url);
+ time(&dlrmsg->sms.time);
+
+ debug("bb.at2",0,"AT2[%s]: sending DLR type NACK", octstr_get_cstr(privdata->name));
+ bb_smscconn_receive(privdata->conn, dlrmsg);
+ }
/*
* no need to do counter_increase(privdata->conn->failed) here,
* since bb_smscconn_send_failed() will inc the counter on
@@ -1517,14 +1732,18 @@
*/
/*
- * message type SUBMIT
- * 01010001 = 0x51 indicating add. UDH, TP-VP(Rel) & MSG_SUBMIT
- * or 00010001 = 0x11 for just TP-VP(Rel) & MSG_SUBMIT
+ * message type SUBMIT , bit mapped :
+ * bit7 .. bit0
+ * TP-RP , TP-UDHI, TP-SRR, TP-VPF(4), TP-VPF(3), TP-RD, TP-MTI(1), TP-MTI(0)
*/
-
- pdu[pos] = octstr_len(msg->sms.udhdata) ? at2_numtext(5) : at2_numtext(1);
+ i = (msg->sms.rpi ? 1 : 0) << 7 /* TP-RP */
+ | (octstr_len(msg->sms.udhdata) ? 1 : 0) << 6 /* TP-UDHI */
+ | ((msg->sms.dlr_mask & (DLR_SUCCESS | DLR_FAIL | DLR_BUFFERED)) ? 1 : 0) << 5 /* TP-SRR */
+ | 16 /* TP-VP(Rel)*/
+ | 1; /* TP-MTI: SUBMIT_SM */
+ pdu[pos] = at2_numtext(i >> 4);
pos++;
- pdu[pos] = at2_numtext(AT_SUBMIT_SM);
+ pdu[pos] = at2_numtext(i & 15);
pos++;
/* message reference (0 for now) */
--- gateway/gw/smsc/smsc_at2.h 2002-08-08 20:44:38.000000000 +0300
+++ gateway/gw/smsc/smsc_at2.h 2002-08-08 21:18:38.000000000 +0300
@@ -19,6 +19,7 @@
/* Message types defines */
#define AT_DELIVER_SM 0
#define AT_SUBMIT_SM 1
+#define AT_STATUS_REPORT_SM 2
/* type of phone number defines */
#define PNT_UNKNOWN 0
@@ -164,7 +165,7 @@
* Waits for the modem to send us something.
*/
int at2_wait_modem_command(PrivAT2data *privdata, time_t timeout,
- int greaterflag, int* messages_collected);
+ int greaterflag, int* output);
/*
* Sets the serial port speed on the device
@@ -209,6 +211,11 @@
Msg *at2_pdu_decode_deliver_sm(Octstr *data, PrivAT2data *privdata);
/*
+ * Decode a SUBMIT-REPORT PDU
+ */
+Msg *at2_pdu_decode_report_sm(Octstr *data, PrivAT2data *privdata);
+
+/*
* Converts the text representation of hexa to binary
*/
Octstr *at2_convertpdu(Octstr *pdutext);