Limit SMS Sending Retries/Handshake Error Patch
hisham malik <[email protected]>
| Newsgroups | gmane.comp.mobile.kannel.devel |
|---|---|
| Message-ID | <[email protected]> |
Attaching more patches for the kannel source. 1. Limit SMS Sending Retries: Limit SMS sending retries in split/long messages 2. Handshake Error and Garbage Character in Long Message: Added send_failed call to the message sending function when error is received during handshake. Fixed garbage characters in multi-part messages.
handshake_error_n_garbage_in_long_msg.patch
(application/octet-stream, 50.6 KB)
Index: smsc_at.c =================================================================== RCS file: /home/cvs/gateway/gw/smsc/smsc_at.c,v retrieving revision 1.58 diff -u -r1.58 smsc_at.c --- smsc_at.c 15 Apr 2009 11:54:11 -0000 1.58 +++ smsc_at.c 30 Apr 2009 09:17:31 -0000 @@ -1,67 +1,67 @@ -/* ==================================================================== - * The Kannel Software License, Version 1.0 - * - * Copyright (c) 2001-2009 Kannel Group - * Copyright (c) 1998-2001 WapIT Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Kannel Group (http://www.kannel.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Kannel" and "Kannel Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please - * contact [email protected]. - * - * 5. Products derived from this software may not be called "Kannel", - * nor may "Kannel" appear in their name, without prior written - * permission of the Kannel Group. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Kannel Group. For more information on - * the Kannel Group, please see <http://www.kannel.org/>. - * - * Portions of this software are based upon software originally written at - * WapIT Ltd., Helsinki, Finland for the Kannel project. - */ +/* ==================================================================== + * The Kannel Software License, Version 1.0 + * + * Copyright (c) 2001-2009 Kannel Group + * Copyright (c) 1998-2001 WapIT Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Kannel Group (http://www.kannel.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Kannel" and "Kannel Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please + * contact [email protected]. + * + * 5. Products derived from this software may not be called "Kannel", + * nor may "Kannel" appear in their name, without prior written + * permission of the Kannel Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Kannel Group. For more information on + * the Kannel Group, please see <http://www.kannel.org/>. + * + * Portions of this software are based upon software originally written at + * WapIT Ltd., Helsinki, Finland for the Kannel project. + */ /* * smsc_at.c - * + * * New driver for serial connected AT based * devices. * 4.9.2001 * Andreas Fink <[email protected]> - + * 23.6.2008, Andreas Fink, * added support for telnet connections * (for example Multi-Tech MTCBA-G-EN-F4) @@ -108,17 +108,17 @@ int b; int i; Octstr *hex; - + char answer[5]; - + if(!privdata->ilb) return; start = 0; len = octstr_len(privdata->ilb); hex = octstr_duplicate(privdata->ilb); octstr_binary_to_hex(hex,1); - + octstr_destroy(hex); while(start < len) @@ -157,7 +157,7 @@ } start = pos; } - + } static int at2_open_device1(PrivAT2data *privdata) @@ -176,12 +176,12 @@ if (octstr_str_compare(privdata->device, "rawtcp") == 0) { privdata->use_telnet = 0; privdata->fd = tcpip_connect_to_server(octstr_get_cstr(privdata->rawtcp_host), - privdata->rawtcp_port, NULL); + privdata->rawtcp_port, NULL); } else if (octstr_str_compare(privdata->device, "telnet") == 0) { privdata->use_telnet = 1; privdata->fd = tcpip_connect_to_server(octstr_get_cstr(privdata->rawtcp_host), - privdata->rawtcp_port, NULL); + privdata->rawtcp_port, NULL); } else { gw_assert(0); @@ -232,11 +232,11 @@ if (!privdata->is_serial) return 0; - + tcgetattr(privdata->fd, &tios); kannel_cfmakeraw(&tios); - + tios.c_iflag |= IGNBRK; /* ignore break & parity errors */ tios.c_iflag &= ~INPCK; /* INPCK: disable parity check */ tios.c_cflag |= HUPCL; /* hangup on close */ @@ -263,10 +263,10 @@ octstr_get_cstr(privdata->name)); } tcflush(privdata->fd, TCIOFLUSH); - - /* + + /* * Nokia 7110 and 6210 need some time between opening - * the connection and sending the first AT commands + * the connection and sending the first AT commands */ if (privdata->modem == NULL || privdata->modem->need_sleep) sleep(1); @@ -298,7 +298,7 @@ struct timeval tv; if (privdata->fd == -1) { - error(errno, "AT2[%s]: at2_read_buffer: fd = -1. Can not read", + error(errno, "AT2[%s]: at2_read_buffer: fd = -1. Can not read", octstr_get_cstr(privdata->name)); return; } @@ -326,7 +326,7 @@ s = read(privdata->fd, buf, count); if (s < 0) { - error(errno, "AT2[%s]: at2_read_buffer: Error during read", + error(errno, "AT2[%s]: at2_read_buffer: Error during read", octstr_get_cstr(privdata->name)); at2_close_device(privdata); } else { @@ -376,7 +376,7 @@ if (gt_flag==1) { /* looking for > if needed */ - gtloc = octstr_search_char(privdata->ilb, '>', 0); + gtloc = octstr_search_char(privdata->ilb, '>', 0); } else if((gt_flag == 2) && (privdata->username)) { /* looking for "Login" */ gtloc = -1; @@ -402,7 +402,7 @@ else gtloc = -1; - /* + /* if (gt_flag && (gtloc != -1)) debug("bb.smsc.at2", 0, "in at2_read_line with gt_flag=1, gtloc=%d, ilb=%s", gtloc, octstr_get_cstr(privdata->ilb)); @@ -429,16 +429,16 @@ octstr_strip_blanks(line); /* empty line, skipping */ - if ((strcmp(octstr_get_cstr(line), "") == 0) && ( gt_flag == 0)) + if ((strcmp(octstr_get_cstr(line), "") == 0) && ( gt_flag == 0)) { octstr_destroy(line); return NULL; } if ((gt_flag) && (gtloc != -1)) { /* got to re-add it again as the parser needs to see it */ - octstr_append_cstr(line, ">"); + octstr_append_cstr(line, ">"); } - debug("bb.smsc.at2", 0, "AT2[%s]: <-- %s", octstr_get_cstr(privdata->name), + debug("bb.smsc.at2", 0, "AT2[%s]: <-- %s", octstr_get_cstr(privdata->name), octstr_get_cstr(line)); return line; } @@ -458,7 +458,7 @@ count = octstr_len(linestr); while (count > data_written) { errno = 0; - s = write(privdata->fd, octstr_get_cstr(linestr) + data_written, + s = write(privdata->fd, octstr_get_cstr(linestr) + data_written, count - data_written); if (s < 0 && errno == EAGAIN && write_count < RETRY_WRITE) { gwthread_sleep(1); @@ -471,13 +471,13 @@ } O_DESTROY(linestr); if (s < 0) { - error(errno, "AT2[%s]: Couldnot write to device.", + error(errno, "AT2[%s]: Couldnot write to device.", octstr_get_cstr(privdata->name)); tcflush(privdata->fd, TCOFLUSH); return s; } tcdrain(privdata->fd); - gwthread_sleep((double) (privdata->modem == NULL ? + gwthread_sleep((double) (privdata->modem == NULL ? 100 : privdata->modem->sendline_sleep) / 1000); return s; } @@ -488,7 +488,7 @@ int s; char *ctrlz = "\032" ; int write_count = 0; - + debug("bb.smsc.at2", 0, "AT2[%s]: --> ^Z", octstr_get_cstr(privdata->name)); while (1) { errno = 0; @@ -500,7 +500,7 @@ break; } if (s < 0) { - error(errno, "AT2[%s]: Couldnot write to device.", + error(errno, "AT2[%s]: Couldnot write to device.", octstr_get_cstr(privdata->name)); tcflush(privdata->fd, TCOFLUSH); return s; @@ -510,7 +510,7 @@ 100 : privdata->modem->sendline_sleep) / 1000); return s; } - + static int at2_write(PrivAT2data *privdata, char *line) { @@ -609,15 +609,15 @@ /* enable hardware handshake */ if (octstr_len(privdata->modem->enable_hwhs)) { - if (at2_send_modem_command(privdata, + if (at2_send_modem_command(privdata, octstr_get_cstr(privdata->modem->enable_hwhs), 0, 0) == -1) - info(0, "AT2[%s]: cannot enable hardware handshake", + info(0, "AT2[%s]: cannot enable hardware handshake", octstr_get_cstr(privdata->name)); } /* * Check does the modem require a PIN and, if so, send it. - * This is not supported by the Nokia Premicell + * This is not supported by the Nokia Premicell */ if (!privdata->modem->no_pin) { ret = at2_send_modem_command(privdata, "AT+CPIN?", 10, 0); @@ -635,9 +635,9 @@ return -1; } - /* + /* * we have to wait until +CPIN: READY appears before issuing - * the next command. 10 sec should be suficient + * the next command. 10 sec should be suficient */ if (!privdata->pin_ready) { at2_wait_modem_command(privdata, 10, 0, NULL); @@ -649,8 +649,8 @@ } } } - /* - * Set the GSM SMS message center address if supplied + /* + * Set the GSM SMS message center address if supplied */ if (octstr_len(privdata->sms_center)) { Octstr *temp; @@ -658,7 +658,7 @@ octstr_append_char(temp, 34); octstr_append(temp, privdata->sms_center); octstr_append_char(temp, 34); - /* + /* * XXX If some modem don't process the +, remove it and add ",145" * and ",129" to national numbers */ @@ -667,7 +667,7 @@ if (ret == -1) return -1; if (ret > 0) { - info(0, "AT2[%s]: Cannot set SMS message center, continuing", + info(0, "AT2[%s]: Cannot set SMS message center, continuing", octstr_get_cstr(privdata->name)); } } @@ -681,7 +681,7 @@ ret = at2_send_modem_command(privdata, "AT+CSMS=?", 0, 0); if (ret != 0) { /* if it doesnt even understand the command, I'm sure it wont support it */ - privdata->phase2plus = 0; + privdata->phase2plus = 0; } else { /* we have to take a part a string like +CSMS: (0,1,128) */ Octstr *ts; @@ -736,7 +736,7 @@ } -static int at2_wait_modem_command(PrivAT2data *privdata, time_t timeout, int gt_flag, +static int at2_wait_modem_command(PrivAT2data *privdata, time_t timeout, int gt_flag, int *output) { Octstr *line = NULL; @@ -758,7 +758,7 @@ if (privdata->lines != NULL) octstr_destroy(privdata->lines); privdata->lines = octstr_create(""); - + smsc_number = octstr_create(""); while (privdata->fd != -1 && time(&cur_time) <= end_time) { O_DESTROY(line); @@ -788,21 +788,21 @@ } if (octstr_search(line, octstr_imm("+CMS ERROR"), 0) != -1) { int errcode; - error(0, "AT2[%s]: CMS ERROR: %s", octstr_get_cstr(privdata->name), + error(0, "AT2[%s]: CMS ERROR: %s", octstr_get_cstr(privdata->name), octstr_get_cstr(line)); if (sscanf(octstr_get_cstr(line), "+CMS ERROR: %d", &errcode) == 1) - error(0, "AT2[%s]: CMS ERROR: %s (%d)", octstr_get_cstr(privdata->name), + error(0, "AT2[%s]: CMS ERROR: %s (%d)", octstr_get_cstr(privdata->name), at2_error_string(errcode), errcode); ret = 1; goto end; } - if (octstr_search(line, octstr_imm("+CMTI:"), 0) != -1 || + if (octstr_search(line, octstr_imm("+CMTI:"), 0) != -1 || octstr_search(line, octstr_imm("+CDSI:"), 0) != -1) { - /* + /* * we received an incoming message indication - * put it in the pending_incoming_messages queue for later retrieval + * put it in the pending_incoming_messages queue for later retrieval */ - debug("bb.smsc.at2", 0, "AT2[%s]: +CMTI incoming SMS indication: %s", + debug("bb.smsc.at2", 0, "AT2[%s]: +CMTI incoming SMS indication: %s", octstr_get_cstr(privdata->name), octstr_get_cstr(line)); gwlist_append(privdata->pending_incoming_messages, line); line = NULL; @@ -814,7 +814,7 @@ line2 = at2_wait_line(privdata, 1, 0); if (line2 == NULL) { - error(0, "AT2[%s]: got +CMT but waiting for next line timed out", + error(0, "AT2[%s]: got +CMT but waiting for next line timed out", octstr_get_cstr(privdata->name)); } else { octstr_append_cstr(line, "\n"); @@ -822,7 +822,7 @@ O_DESTROY(line2); at2_pdu_extract(privdata, &pdu, line, smsc_number); if (pdu == NULL) { - error(0, "AT2[%s]: got +CMT but pdu_extract failed", + error(0, "AT2[%s]: got +CMT but pdu_extract failed", octstr_get_cstr(privdata->name)); } else { /* count message even if I can't decode it */ @@ -852,13 +852,13 @@ 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 + /* + * 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", + error(0, "AT2[%s]: Got +CMGS but failed to read message id", octstr_get_cstr(privdata->name)); else *output = temp; @@ -869,7 +869,7 @@ error(0, "AT2[%s]: Generic error: %s", octstr_get_cstr(privdata->name), octstr_get_cstr(line)); if (sscanf(octstr_get_cstr(line), "ERROR: %d", &errcode) == 1) - error(0, "AT2[%s]: Generic error: %s (%d)", octstr_get_cstr(privdata->name), + error(0, "AT2[%s]: Generic error: %s (%d)", octstr_get_cstr(privdata->name), at2_error_string(errcode), errcode); ret = -1; goto end; @@ -910,29 +910,29 @@ /* read one message from memory */ at2_write_line(privdata, cmd); if (at2_wait_modem_command(privdata, 0, 0, &message_count) != 0) { - debug("bb.smsc.at2", 0, "AT2[%s]: failed to get message %d.", + debug("bb.smsc.at2", 0, "AT2[%s]: failed to get message %d.", octstr_get_cstr(privdata->name), message_number); return 0; /* failed to read the message - skip to next message */ } /* no need to delete if no message collected */ - if (!message_count) { - debug("bb.smsc.at2", 0, "AT2[%s]: not deleted.", + if (!message_count) { + debug("bb.smsc.at2", 0, "AT2[%s]: not deleted.", octstr_get_cstr(privdata->name)); return 0; } sprintf(cmd, "AT+CMGD=%d", message_number); /* delete the message we just read */ - /* + /* * 3 seconds (default timeout of send_modem_command()) is not enough with some - * modems if the message is large, so we'll give it 7 seconds + * modems if the message is large, so we'll give it 7 seconds */ - if (at2_send_modem_command(privdata, cmd, 7, 0) != 0) { - /* - * failed to delete the message, we'll just ignore it for now, + if (at2_send_modem_command(privdata, cmd, 7, 0) != 0) { + /* + * failed to delete the message, we'll just ignore it for now, * this is bad, since if the message really didn't get deleted - * we'll see it next time around. - */ + * we'll see it next time around. + */ error(2, "AT2[%s]: failed to delete message %d.", octstr_get_cstr(privdata->name), message_number); } @@ -958,7 +958,7 @@ int pos; long location; Octstr *cmti_storage = NULL, *line = NULL; - + line = gwlist_extract_first(privdata->pending_incoming_messages); /* message memory starts after the first quote in the string */ if ((pos = octstr_search_char(line, '"', 0)) != -1) { @@ -974,10 +974,10 @@ } else /* reset pos for the next lookup which would start from the beginning if no memory * location was found */ - pos = 0; + pos = 0; /* if no message storage is set in configuration - set now */ - if (!privdata->modem->message_storage && cmti_storage) { + if (!privdata->modem->message_storage && cmti_storage) { info(2, "AT2[%s]: CMTI received, but no message-storage is set in confiuration." "setting now to <%s>", octstr_get_cstr(privdata->name), octstr_get_cstr(cmti_storage)); privdata->modem->message_storage = octstr_duplicate(cmti_storage); @@ -1009,18 +1009,18 @@ current_storage = octstr_duplicate(cmti_storage); at2_set_message_storage(privdata, cmti_storage); } - + if (!at2_read_delete_message(privdata, location)) { error(1, "AT2[%s]: CMTI notification received, but no message found in memory!", octstr_get_cstr(privdata->name)); } - + octstr_destroy(line); octstr_destroy(cmti_storage); } - + /* set prefered message storage back to what configured */ - if (current_storage && privdata->modem->message_storage + if (current_storage && privdata->modem->message_storage && (octstr_compare(privdata->modem->message_storage, current_storage) != 0)) at2_set_message_storage(privdata, privdata->modem->message_storage); @@ -1039,40 +1039,40 @@ if (privdata->sms_memory_usage) { /* * that is - greater then 0, meaning there are some messages to fetch - * now - I used to just loop over the first input_mem_sms_used locations, - * but it doesn't hold, since under load, messages may be received while - * we're in the loop, and get stored in locations towards the end of the list, - * thus creating 'holes' in the memory. - * - * There are two ways we can fix this : + * now - I used to just loop over the first input_mem_sms_used locations, + * but it doesn't hold, since under load, messages may be received while + * we're in the loop, and get stored in locations towards the end of the list, + * thus creating 'holes' in the memory. + * + * There are two ways we can fix this : * (a) Just read the last message location, delete it and return. - * It's not a complete solution since holes can still be created if messages - * are received between the memory check and the delete command, + * It's not a complete solution since holes can still be created if messages + * are received between the memory check and the delete command, * and anyway - it will slow us down and won't hold well under pressure - * (b) Just scan the entire memory each call, bottom to top. + * (b) Just scan the entire memory each call, bottom to top. * This will be slow too, but it'll be reliable. * * We can massivly improve performance by stopping after input_mem_sms_used messages - * have been read, but send_modem_command returns 0 for no message as well as for a - * message read, and the only other way to implement it is by doing memory_check - * after each read and stoping when input_mem_sms_used get to 0. This is slow - * (modem commands take time) so we improve speed only if there are less then 10 + * have been read, but send_modem_command returns 0 for no message as well as for a + * message read, and the only other way to implement it is by doing memory_check + * after each read and stoping when input_mem_sms_used get to 0. This is slow + * (modem commands take time) so we improve speed only if there are less then 10 * messages in memory. * - * I implemented the alternative - changed at2_wait_modem_command to return the + * I implemented the alternative - changed at2_wait_modem_command to return the * number of messages it collected. */ int i; int message_count = 0; /* cound number of messages collected */ - debug("bb.smsc.at2", 0, "AT2[%s]: %d messages waiting in memory", + debug("bb.smsc.at2", 0, "AT2[%s]: %d messages waiting in memory", octstr_get_cstr(privdata->name), privdata->sms_memory_usage); /* * loop till end of memory or collected enouch messages */ for (i = 1; i <= privdata->sms_memory_capacity && - message_count < privdata->sms_memory_usage; ++i) { + message_count < privdata->sms_memory_usage; ++i) { /* if (meanwhile) there are pending CMTI notifications, process these first * to not let CMTI and sim buffering sit in each others way */ @@ -1083,7 +1083,7 @@ message_count += at2_read_delete_message(privdata, i); } } - + /* at2_send_modem_command(privdata, ModemTypes[privdata->modemid].init1, 0, 0); */ @@ -1099,7 +1099,7 @@ Octstr *search_cpms = NULL; /* select memory type and get report */ - if ((ret = at2_send_modem_command(privdata, "AT+CPMS?", 0, 0)) != 0) { + if ((ret = at2_send_modem_command(privdata, "AT+CPMS?", 0, 0)) != 0) { debug("bb.smsc.at2.memory_check", 0, "failed to send mem select command to modem %d", ret); return -1; } @@ -1112,22 +1112,22 @@ pos += 6; /* position of parser in the stream - start after header */ /* skip memory indication */ - pos = octstr_search(privdata->lines, octstr_imm(","), pos) + 1; + pos = octstr_search(privdata->lines, octstr_imm(","), pos) + 1; /* find all the values */ while (index < 4 && pos < octstr_len(privdata->lines) && - (pos = octstr_parse_long(&values[index], privdata->lines, pos, 10)) != -1) { + (pos = octstr_parse_long(&values[index], privdata->lines, pos, 10)) != -1) { ++pos; /* skip number seperator */ ++index; /* increment array index */ if (index == 2) /* skip second memory indication */ - pos = octstr_search(privdata->lines, octstr_imm(","), pos) + 1; + pos = octstr_search(privdata->lines, octstr_imm(","), pos) + 1; } - if (index < 4) { + if (index < 4) { /* didn't get all memory data - I don't why, so I'll bail */ debug("bb.smsc.at2", 0, "AT2[%s]: couldn't parse all memory locations : %d:'%s'.", - octstr_get_cstr(privdata->name), index, + octstr_get_cstr(privdata->name), index, &(octstr_get_cstr(privdata->lines)[pos])); O_DESTROY(search_cpms); return -1; @@ -1141,17 +1141,17 @@ */ /* everything's cool */ - ret = 0; + ret = 0; /* clear the buffer */ O_DESTROY(privdata->lines); } else { - debug("bb.smsc.at2", 0, "AT2[%s]: no correct header for CPMS response.", + debug("bb.smsc.at2", 0, "AT2[%s]: no correct header for CPMS response.", octstr_get_cstr(privdata->name)); /* didn't get a +CPMS response - this is clearly an error */ - ret = -1; + ret = -1; } O_DESTROY(search_cpms); @@ -1234,7 +1234,7 @@ speed = B9600; #endif } - + cfsetospeed(&tios, speed); cfsetispeed(&tios, speed); ret = tcsetattr(privdata->fd, TCSANOW, &tios); /* apply changes now */ @@ -1280,12 +1280,12 @@ info(0, "AT2[%s]: trying to use speed <%ld> from modem definition", octstr_get_cstr(privdata->name), privdata->modem->speed); - if (at2_test_speed(privdata, privdata->modem->speed) == 0) { + if (at2_test_speed(privdata, privdata->modem->speed) == 0) { privdata->speed = privdata->modem->speed; - info(0, "AT2[%s]: speed is %ld", + info(0, "AT2[%s]: speed is %ld", octstr_get_cstr(privdata->name), privdata->speed); } else { - info(0, "AT2[%s]: speed in modem definition don't work, will autodetect", + info(0, "AT2[%s]: speed in modem definition don't work, will autodetect", octstr_get_cstr(privdata->name)); } } @@ -1301,20 +1301,20 @@ } if (at2_open_device(privdata)) { - error(errno, "AT2[%s]: at2_device_thread: open_at2_device failed.", + error(errno, "AT2[%s]: at2_device_thread: open_at2_device failed.", octstr_get_cstr(privdata->name)); reconnecting = 1; continue; } if (at2_login_device(privdata)) { - error(errno, "AT2[%s]: at2_device_thread: at2_login_device failed.", + error(errno, "AT2[%s]: at2_device_thread: at2_login_device failed.", octstr_get_cstr(privdata->name)); reconnecting = 1; continue; } - if (privdata->max_error_count > 0 && error_count > privdata->max_error_count + if (privdata->max_error_count > 0 && error_count > privdata->max_error_count && privdata->modem != NULL && privdata->modem->reset_string != NULL) { error_count = 0; if (at2_send_modem_command(privdata, @@ -1363,7 +1363,7 @@ if (privdata->keepalive && idle_timeout + privdata->keepalive < time(NULL)) { - if (at2_send_modem_command(privdata, + if (at2_send_modem_command(privdata, octstr_get_cstr(privdata->modem->keepalive_cmd), 5, 0) < 0) { at2_close_device(privdata); reconnecting = 1; @@ -1425,15 +1425,15 @@ octstr_get_cstr(privdata->name), finish_sending ? "slow" : "instant"); - /* + /* * Documentation claims this would have been done by smscconn.c, - * but isn't when this code is being written. + * but isn't when this code is being written. */ conn->why_killed = SMSCCONN_KILLED_SHUTDOWN; - privdata->shutdown = 1; - /* + privdata->shutdown = 1; + /* * Separate from why_killed to avoid locking, as - * why_killed may be changed from outside? + * why_killed may be changed from outside? */ if (finish_sending == 0) { Msg *msg; @@ -1469,7 +1469,7 @@ if (conn->status == SMSCCONN_DISCONNECTED) conn->status = SMSCCONN_ACTIVE; - + /* in case there are messages in the buffer already */ gwthread_wakeup(privdata->device_thread); debug("smsc.at2", 0, "AT2[%s]: start called", octstr_get_cstr(privdata->name)); @@ -1504,7 +1504,7 @@ error(0, "AT2[-]: 'device' missing in at2 configuration."); goto error; } - + if (octstr_str_compare(privdata->device, "rawtcp") == 0) { privdata->rawtcp_host = cfg_get(cfg, octstr_imm("host")); if (privdata->rawtcp_host == NULL) { @@ -1645,18 +1645,18 @@ int tmp; Octstr *numtmp; Octstr *tmp2; - + buffer = octstr_duplicate(line); /* find the beginning of a message from the modem*/ - if ((pos = octstr_search(buffer, octstr_imm("+CDS:"), 0)) != -1) + if ((pos = octstr_search(buffer, octstr_imm("+CDS:"), 0)) != -1) pos += 5; else { if ((pos = octstr_search(buffer, octstr_imm("+CMT:"), 0)) != -1) pos += 5; else if ((pos = octstr_search(buffer, octstr_imm("+CMGR:"), 0)) != -1) { /* skip status field in +CMGR response */ - if ((pos = octstr_search(buffer, octstr_imm(","), pos + 6)) != -1) + if ((pos = octstr_search(buffer, octstr_imm(","), pos + 6)) != -1) pos++; else goto nomsg; @@ -1688,7 +1688,7 @@ + at2_hexchar(octstr_get_char(buffer, pos + 1)); if (tmp < 0) goto nomsg; - + numtmp = octstr_create_from_data(octstr_get_cstr(buffer)+pos+2,tmp * 2); /* we now have the hexchars of the SMSC in GSM encoding */ octstr_hex_to_binary(numtmp); tmp2 = gsm2number(numtmp); @@ -1740,7 +1740,7 @@ len = octstr_len(pdu); if(len<= 0) return octstr_create(""); - + ton = octstr_get_char(pdu,pos++); npi = ton & 0x0F; ton = (ton >> 4) & 0x07; @@ -1766,7 +1766,7 @@ c = octstr_get_char(pdu,pos++); a = c & 0x0F; b = ((c & 0xF0) >> 4); - + if((b == 0x0F) && (len < 2)) { octstr_append_char(tmp, nibble2hex(a)); @@ -1824,9 +1824,9 @@ long stime; /* time in seconds */ int timezone; /* timezone in 15 minutes jumps from GMT */ - /* + /* * Note: some parts of the PDU are not decoded because they are - * not needed for the Msg type. + * not needed for the Msg type. */ /* convert the pdu to binary format for ease of processing */ @@ -1848,7 +1848,7 @@ tmpstr = octstr_copy(pdu, 3, len); at2_decode7bituncompressed(tmpstr, (((len - 1) * 4 - 3) / 7) + 1, origin, 0); octstr_destroy(tmpstr); - debug("bb.smsc.at2", 0, "AT2[%s]: Alphanumeric sender <%s>", + debug("bb.smsc.at2", 0, "AT2[%s]: Alphanumeric sender <%s>", octstr_get_cstr(privdata->name), octstr_get_cstr(origin)); pos += (len + 1) / 2; } else { @@ -1862,8 +1862,8 @@ if (i + 1 < len) octstr_append_char(origin, (octstr_get_char(pdu, pos) >> 4) + 48); } - debug("bb.smsc.at2", 0, "AT2[%s]: Numeric sender %s <%s>", - octstr_get_cstr(privdata->name), ((ntype & 0x90) == 0x90 ? "(international)" : ""), + debug("bb.smsc.at2", 0, "AT2[%s]: Numeric sender %s <%s>", + octstr_get_cstr(privdata->name), ((ntype & 0x90) == 0x90 ? "(international)" : ""), octstr_get_cstr(origin)); } @@ -1883,7 +1883,7 @@ pos++; mtime.year += (mtime.year < 70 ? 2000 : 1900); mtime.month = swap_nibbles(octstr_get_char(pdu, pos)); - mtime.month--; + mtime.month--; pos++; mtime.day = swap_nibbles(octstr_get_char(pdu, pos)); pos++; @@ -1894,24 +1894,24 @@ mtime.second = swap_nibbles(octstr_get_char(pdu, pos)); pos++; - /* - * time zone: + /* + * time zone: * - * time zone is "swapped nibble", with the MSB as the sign (1 is negative). + * time zone is "swapped nibble", with the MSB as the sign (1 is negative). */ timezone = swap_nibbles(octstr_get_char(pdu, pos)); pos++; timezone = ((timezone >> 7) ? -1 : 1) * (timezone & 127); - /* - * Ok, that was the time zone as read from the PDU. Now how to interpert it? - * All the handsets I tested send the timestamp of their local time and the - * timezone as GMT+0. I assume that the timestamp is the handset's local time, - * so we need to apply the timezone in reverse to get GM time: + /* + * Ok, that was the time zone as read from the PDU. Now how to interpert it? + * All the handsets I tested send the timestamp of their local time and the + * timezone as GMT+0. I assume that the timestamp is the handset's local time, + * so we need to apply the timezone in reverse to get GM time: */ - /* - * time in PDU is handset's local time and timezone is handset's time zone - * difference from GMT + /* + * time in PDU is handset's local time and timezone is handset's time zone + * difference from GMT */ mtime.hour -= timezone / 4; mtime.minute -= 15 * (timezone % 4); @@ -1924,7 +1924,7 @@ len = octstr_get_char(pdu, pos); pos++; - debug("bb.smsc.at2", 0, "AT2[%s]: User data length read as (%d)", + debug("bb.smsc.at2", 0, "AT2[%s]: User data length read as (%d)", octstr_get_cstr(privdata->name), len); /* if there is a UDH */ @@ -1972,11 +1972,12 @@ * Fix length because UDH data length is determined * in septets if we are in GSM coding, otherwise it's in octets. Adding 6 * will ensure that for an octet length of 0, we get septet length 0, - * and for octet length 1 we get septet length 2. + * and for octet length 1 we get septet length 2. */ len = len + udhlen + 1 - (8 * (udhlen + 1) + 6) / 7; } at2_decode7bituncompressed(tmpstr, len, text, offset); + if(udhi) octstr_truncate(text, len-1); //FIX: fixed garbage characters in multi-part messages. } message->sms.sender = origin; @@ -1997,7 +1998,7 @@ octstr_destroy(tmpstr); return message; - + msg_error: error(1, "AT2[%s]: Invalid DELIVER-SMS pdu!", octstr_get_cstr(privdata->name)); O_DESTROY(udh); @@ -2024,9 +2025,9 @@ /* 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>:", + 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); @@ -2095,10 +2096,10 @@ 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 + /* 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(privdata->conn->id, msg_id, receiver, type)) == NULL) { @@ -2109,7 +2110,7 @@ /* Beware DLR URL is now in msg->sms.dlr_url given by dlr_find() */ dlrmsg->sms.msgdata = octstr_duplicate(tmpstr); - + error: O_DESTROY(tmpstr); O_DESTROY(pdu); @@ -2184,7 +2185,7 @@ { Msg *msg; - if (privdata->modem->enable_mms && + if (privdata->modem->enable_mms && gw_prioqueue_len(privdata->outgoing_queue) > 1) at2_send_modem_command(privdata, "AT+CMMS=2", 0, 0); @@ -2204,11 +2205,11 @@ msg->sms.sender = octstr_duplicate(privdata->my_number); } - /* - * The standard says you should be prepending the PDU with 00 to indicate - * to use the default SC. Some older modems dont expect this so it can be - * disabled - * NB: This extra padding is not counted in the CMGS byte count + /* + * The standard says you should be prepending the PDU with 00 to indicate + * to use the default SC. Some older modems dont expect this so it can be + * disabled + * NB: This extra padding is not counted in the CMGS byte count */ sc[0] = '\0'; @@ -2224,8 +2225,8 @@ } int msg_id = -1; - /* - * send the initial command and then wait for > + /* + * send the initial command and then wait for > */ sprintf(command, "AT+CMGS=%ld", octstr_len(pdu) / 2); @@ -2235,10 +2236,10 @@ if (ret == 1) {/* > only! */ - /* - * Ok the > has been see now so we can send the PDU now and a - * control Z but no CR or LF - * + /* + * Ok the > has been see now so we can send the PDU now and a + * control Z but no CR or LF + * * We will handle the 'nokiaphone' types a bit differently, since * they have a generic error in accepting PDUs that are "too big". * Which means, PDU that are longer then 18 bytes get truncated by @@ -2246,7 +2247,7 @@ * All other types will get handled as used to be. */ - if (octstr_compare(privdata->modem->id, octstr_imm("nokiaphone")) != 0) { + if (octstr_compare(privdata->modem->id, octstr_imm("nokiaphone")) != 0) { sprintf(command, "%s%s", sc, octstr_get_cstr(pdu)); at2_write(privdata, command); @@ -2257,7 +2258,7 @@ /* include the CTRL-Z in the PDU string */ sprintf(command, "%s%s%c", sc, octstr_get_cstr(pdu), 0x1A); - /* chop PDU into 18-byte-at-a-time pieces to prevent choking + /* chop PDU into 18-byte-at-a-time pieces to prevent choking * of certain GSM Phones (e.g. Nokia 6310, 6230 etc.) */ if (strlen(command) > 18) { char chop[20]; @@ -2277,7 +2278,7 @@ } else { at2_write(privdata, command); } - } + } /* wait 20 secs for modem command */ ret = at2_wait_modem_command(privdata, 20, 0, &msg_id); @@ -2306,6 +2307,18 @@ bb_smscconn_sent(privdata->conn, msg, NULL); } } + //FIX: added send_failed call to the message sending function when error is received during handshake. + else { + //ret != 1 + error(0,"AT2[%s]: Error received, notifiying failure, " + "sender: %s receiver: %s msgdata: %s udhdata: %s", + octstr_get_cstr(privdata->name), + octstr_get_cstr(msg->sms.sender), octstr_get_cstr(msg->sms.receiver), + octstr_get_cstr(msg->sms.msgdata), octstr_get_cstr(msg->sms.udhdata)); + bb_smscconn_send_failed(privdata->conn, msg, + SMSCCONN_FAILED_TEMPORARILY, octstr_create("ERROR")); + } + //END of FIX O_DESTROY(pdu); } } @@ -2320,7 +2333,7 @@ Octstr *pdu = NULL, *temp = NULL, *buffer = octstr_create(""); int len, setvalidity = 0; - /* + /* * 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) @@ -2346,10 +2359,10 @@ octstr_append_char(buffer, fields_to_dcs(msg, /* data coding scheme */ (msg->sms.alt_dcs != -1 ? msg->sms.alt_dcs : privdata->conn->alt_dcs))); - /* + /* * Validity-Period (TP-VP) * see GSM 03.40 section 9.2.3.12 - * defaults to 24 hours = 167 if not set + * defaults to 24 hours = 167 if not set */ if (msg->sms.validity >= 0) { if (msg->sms.validity > 635040) @@ -2371,7 +2384,7 @@ if (msg->sms.validity < 5) setvalidity = 0; } else - setvalidity = (privdata->validityperiod != NULL ? + setvalidity = (privdata->validityperiod != NULL ? atoi(octstr_get_cstr(privdata->validityperiod)) : 167); if (setvalidity >= 0 && setvalidity <= 143) @@ -2403,7 +2416,7 @@ * The reason we branch here is because UDH data length is determined * in septets if we are in GSM coding, otherwise it's in octets. Adding 6 * will ensure that for an octet length of 0, we get septet length 0, - * and for octet length 1 we get septet length 2. + * and for octet length 1 we get septet length 2. */ int temp_len; len += (temp_len = (((8 * octstr_len(msg->sms.udhdata)) + 6) / 7)); @@ -2435,7 +2448,7 @@ } charset_utf8_to_gsm(msg->sms.msgdata); - + if ((temp = at2_encode7bituncompressed(msg->sms.msgdata, offset)) != NULL) octstr_append(buffer, temp); O_DESTROY(temp); @@ -2467,7 +2480,7 @@ /* start packing the septet stream into an octet stream */ for (posS = 0, posT = 0; (source_chr = octstr_get_char(source, posS++)) != -1;) { - /* grab least significant bits from current septet and + /* grab least significant bits from current septet and * store them packed to the right */ target_chr |= (source_chr & LSBmask[i]) << iStore; /* store current byte if last command filled it */ @@ -2476,14 +2489,14 @@ octstr_append_char(target, target_chr); target_chr = 0; } - /* grab most significant bits from current septet and + /* grab most significant bits from current septet and * store them packed to the left */ target_chr |= (source_chr & MSBmask[7 - i]) >> (8 - iStore) % 8; /* advance target bit index by 7 (modulo 8 addition ) */ iStore = (--iStore < 0 ? 7 : iStore); /* if just finished packing 8 septets (into 7 octets) don't advance mask index */ - if (iStore != 0) - i = (++i > 7 ? 1 : i); + if (iStore != 0) + i = (++i > 7 ? 1 : i); } /* don't forget to pack the leftovers ;-) */ @@ -2519,16 +2532,16 @@ static int at2_detect_speed(PrivAT2data *privdata) { int i; - int autospeeds[] = { + int autospeeds[] = { #ifdef B115200 115200, #endif #ifdef B57600 - 57600, + 57600, #endif 38400, 19200, 9600 }; - debug("bb.smsc.at2", 0, "AT2[%s]: detecting modem speed. ", + debug("bb.smsc.at2", 0, "AT2[%s]: detecting modem speed. ", octstr_get_cstr(privdata->name)); for (i = 0; i < (sizeof(autospeeds) / sizeof(int)); i++) { @@ -2546,7 +2559,7 @@ } -static int at2_test_speed(PrivAT2data *privdata, long speed) +static int at2_test_speed(PrivAT2data *privdata, long speed) { int res; @@ -2556,14 +2569,14 @@ at2_read_buffer(privdata); /* give telnet escape sequences a chance */ at2_set_speed(privdata, speed); /* send a return so the modem can detect the speed */ - res = at2_send_modem_command(privdata, "", 1, 0); + res = at2_send_modem_command(privdata, "", 1, 0); res = at2_send_modem_command(privdata, "AT", 0, 0); if (res != 0) res = at2_send_modem_command(privdata, "AT", 0, 0); if (res != 0) res = at2_send_modem_command(privdata, "AT", 0, 0); - + at2_close_device(privdata); return res; @@ -2583,7 +2596,7 @@ at2_set_speed(privdata, privdata->speed); /* send a return so the modem can detect the speed */ - res = at2_send_modem_command(privdata, "", 1, 0); + res = at2_send_modem_command(privdata, "", 1, 0); res = at2_send_modem_command(privdata, "AT", 0, 0); if (at2_send_modem_command(privdata, "AT&F", 0, 0) == -1) { @@ -2611,24 +2624,24 @@ continue; } - /* - debug("bb.smsc.at2",0,"AT2[%s]: searching for %s", octstr_get_cstr(privdata->name), - octstr_get_cstr(modem->name)); + /* + debug("bb.smsc.at2",0,"AT2[%s]: searching for %s", octstr_get_cstr(privdata->name), + octstr_get_cstr(modem->name)); */ if (octstr_search(privdata->lines, modem->detect_string, 0) != -1) { if (octstr_len(modem->detect_string2) == 0) { - debug("bb.smsc.at2", 0, "AT2[%s]: found string <%s>, using modem definition <%s>", - octstr_get_cstr(privdata->name), octstr_get_cstr(modem->detect_string), + debug("bb.smsc.at2", 0, "AT2[%s]: found string <%s>, using modem definition <%s>", + octstr_get_cstr(privdata->name), octstr_get_cstr(modem->detect_string), octstr_get_cstr(modem->name)); privdata->modem = modem; break; } else { if (octstr_search(privdata->lines, modem->detect_string2, 0) != -1) { debug("bb.smsc.at2", 0, "AT2[%s]: found string <%s> plus <%s>, using modem " - "definition <%s>", octstr_get_cstr(privdata->name), - octstr_get_cstr(modem->detect_string), - octstr_get_cstr(modem->detect_string2), + "definition <%s>", octstr_get_cstr(privdata->name), + octstr_get_cstr(modem->detect_string), + octstr_get_cstr(modem->detect_string2), octstr_get_cstr(modem->name)); privdata->modem = modem; break; @@ -2641,10 +2654,10 @@ } if (privdata->modem == NULL) { - debug("bb.smsc.at2", 0, "AT2[%s]: Cannot detect modem, using generic", + debug("bb.smsc.at2", 0, "AT2[%s]: Cannot detect modem, using generic", octstr_get_cstr(privdata->name)); if ((modem = at2_read_modems(privdata, privdata->configfile, octstr_imm("generic"), 0)) == NULL) { - panic(0, "AT2[%s]: Cannot detect modem and generic not found", + panic(0, "AT2[%s]: Cannot detect modem and generic not found", octstr_get_cstr(privdata->name)); } else { privdata->modem = modem; @@ -2655,7 +2668,7 @@ res = at2_send_modem_command(privdata, "AT+CSMS=?", 0, 0); if (res != 0) /* if it doesnt even understand the command, I'm sure it won't support it */ - privdata->phase2plus = 0; + privdata->phase2plus = 0; else { /* we have to take a part a string like +CSMS: (0,1,128) */ Octstr *ts; @@ -2696,14 +2709,14 @@ ModemDef *modem; int i = 1; - /* - * Use id and idnumber=0 or id=NULL and idnumber > 0 + /* + * Use id and idnumber=0 or id=NULL and idnumber > 0 */ if (octstr_len(id) == 0 && idnumber == 0) return NULL; if (idnumber == 0) - debug("bb.smsc.at2", 0, "AT2[%s]: Reading modem definitions from <%s>", + debug("bb.smsc.at2", 0, "AT2[%s]: Reading modem definitions from <%s>", octstr_get_cstr(privdata->name), octstr_get_cstr(file)); cfg = cfg_create(file); @@ -2712,7 +2725,7 @@ grplist = cfg_get_multi_group(cfg, octstr_imm("modems")); if (idnumber == 0) - debug("bb.smsc.at2", 0, "AT2[%s]: Found <%ld> modems in config", + debug("bb.smsc.at2", 0, "AT2[%s]: Found <%ld> modems in config", octstr_get_cstr(privdata->name), gwlist_len(grplist)); if (grplist == NULL) @@ -2784,7 +2797,7 @@ cfg_get_bool(&modem->enable_mms, grp, octstr_imm("enable-mms")); - /* + /* if (modem->message_storage == NULL) modem->message_storage = octstr_create("SM"); */ @@ -2872,7 +2885,7 @@ } O_DESTROY(temp); - return out; + return out; }
limit_sms_retry_in_long_msgs.patch
(application/octet-stream, 17.5 KB)
Index: bb_smscconn.c =================================================================== RCS file: /home/cvs/gateway/gw/bb_smscconn.c,v retrieving revision 1.100 diff -u -r1.100 bb_smscconn.c --- bb_smscconn.c 14 Jan 2009 11:11:46 -0000 1.100 +++ bb_smscconn.c 30 Apr 2009 09:32:37 -0000 @@ -1,58 +1,58 @@ -/* ==================================================================== - * The Kannel Software License, Version 1.0 - * - * Copyright (c) 2001-2009 Kannel Group - * Copyright (c) 1998-2001 WapIT Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Kannel Group (http://www.kannel.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Kannel" and "Kannel Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please - * contact [email protected]. - * - * 5. Products derived from this software may not be called "Kannel", - * nor may "Kannel" appear in their name, without prior written - * permission of the Kannel Group. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Kannel Group. For more information on - * the Kannel Group, please see <http://www.kannel.org/>. - * - * Portions of this software are based upon software originally written at - * WapIT Ltd., Helsinki, Finland for the Kannel project. - */ +/* ==================================================================== + * The Kannel Software License, Version 1.0 + * + * Copyright (c) 2001-2009 Kannel Group + * Copyright (c) 1998-2001 WapIT Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Kannel Group (http://www.kannel.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Kannel" and "Kannel Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please + * contact [email protected]. + * + * 5. Products derived from this software may not be called "Kannel", + * nor may "Kannel" appear in their name, without prior written + * permission of the Kannel Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Kannel Group. For more information on + * the Kannel Group, please see <http://www.kannel.org/>. + * + * Portions of this software are based upon software originally written at + * WapIT Ltd., Helsinki, Finland for the Kannel project. + */ /* * SMSC Connection interface for Bearerbox. @@ -65,7 +65,7 @@ * Kalle Marjola 2000 for project Kannel * Alexander Malysh <amalysh at kannel.org> 2003, 2004, 2005 */ - + #include "gw-config.h" #include <errno.h> @@ -193,7 +193,7 @@ static void handle_split(SMSCConn *conn, Msg *msg, long reason) { struct split_parts *split = msg->sms.split_parts; - + /* * If temporarely failed, try again immediately but only if connection active. * Because if connection is not active we will loop for ever here consuming 100% CPU @@ -205,7 +205,7 @@ msg_destroy(msg); return; } - + /* * if the reason is not a success and status is still success * then set status of a split to the reason. @@ -233,7 +233,7 @@ * we will split it again in smscconn_send(...). */ msg_destroy(msg); - + if (counter_decrease(split->parts_left) <= 1) { /* all splited parts were processed */ counter_destroy(split->parts_left); @@ -257,7 +257,7 @@ octstr_destroy(reply); return; } - + counter_increase(outgoing_sms_counter); load_increase(outgoing_sms_load); if (conn) counter_increase(conn->sent); @@ -289,12 +289,13 @@ void bb_smscconn_send_failed(SMSCConn *conn, Msg *sms, int reason, Octstr *reply) { - if (sms->sms.split_parts != NULL) { + //dded && reason != SMSCCONN_FAILED_TEMPORARILY, otherwise msg stays in queue forever and overloads smsc + if (sms->sms.split_parts != NULL && reason != SMSCCONN_FAILED_TEMPORARILY) { handle_split(conn, sms, reason); octstr_destroy(reply); return; } - + switch (reason) { case SMSCCONN_FAILED_TEMPORARILY: /* @@ -309,7 +310,7 @@ */ if (sms_resend_retry >= 0 && sms->sms.resend_try >= sms_resend_retry) { warning(0, "Maximum retries for message exceeded, discarding it!"); - bb_smscconn_send_failed(NULL, sms, SMSCCONN_FAILED_DISCARDED, + bb_smscconn_send_failed(NULL, sms, SMSCCONN_FAILED_DISCARDED, octstr_create("Retries Exceeded")); break; } @@ -318,7 +319,7 @@ } gwlist_produce(outgoing_sms, sms); break; - + case SMSCCONN_FAILED_SHUTDOWN: gwlist_produce(outgoing_sms, sms); break; @@ -388,7 +389,7 @@ msg_destroy(sms); return SMSCCONN_FAILED_REJECTED; } - + if (black_list && numhash_find_number(black_list, sms->sms.sender) == 1) { info(0, "Number <%s> is in black-list, message discarded", @@ -439,7 +440,7 @@ msg_destroy(sms); return SMSCCONN_SUCCESS; case concat_complete: - /* Combined sms received! save new one since it is now combined. */ + /* Combined sms received! save new one since it is now combined. */ msg_destroy(sms); /* Change the sms. */ sms = msg_duplicate(copy); @@ -463,7 +464,7 @@ */ rc = route_incoming_to_boxc(copy); } - + if (rc == -1 || (rc != SMSCCONN_SUCCESS && rc != SMSCCONN_QUEUED)) { warning(0, "incoming messages queue too long, dropping a message"); if (sms->sms.sms_type == report_mo) @@ -597,7 +598,7 @@ /* create split sms counter */ split_msg_counter = counter_create(); - + /* create smsc list and rwlock for it */ smsc_list = gwlist_create(); gw_rwlock_init_static(&smsc_list_lock); @@ -610,7 +611,7 @@ white_list_url = cfg_get(grp, octstr_imm("white-list")); if (white_list_url != NULL) { if ((white_list = numhash_create(octstr_get_cstr(white_list_url))) == NULL) - panic(0, "Could not get white-list at URL <%s>", + panic(0, "Could not get white-list at URL <%s>", octstr_get_cstr(white_list_url)); } if ((os = cfg_get(grp, octstr_imm("white-list-regex"))) != NULL) { @@ -618,11 +619,11 @@ panic(0, "Could not compile pattern '%s'", octstr_get_cstr(os)); octstr_destroy(os); } - + black_list_url = cfg_get(grp, octstr_imm("black-list")); if (black_list_url != NULL) { if ((black_list = numhash_create(octstr_get_cstr(black_list_url))) == NULL) - panic(0, "Could not get black-list at URL <%s>", + panic(0, "Could not get black-list at URL <%s>", octstr_get_cstr(black_list_url)); } if ((os = cfg_get(grp, octstr_imm("black-list-regex"))) != NULL) { @@ -636,7 +637,7 @@ sms_resend_frequency = 60; } info(0, "Set SMS resend frequency to %ld seconds.", sms_resend_frequency); - + if (cfg_get_integer(&sms_resend_retry, grp, octstr_imm("sms-resend-retry")) == -1) { sms_resend_retry = -1; info(0, "SMS resend retry set to unlimited."); @@ -659,18 +660,18 @@ smsc_groups = cfg_get_multi_group(cfg, octstr_imm("smsc")); gwlist_add_producer(smsc_list); - for (i = 0; i < gwlist_len(smsc_groups) && + for (i = 0; i < gwlist_len(smsc_groups) && (grp = gwlist_get(smsc_groups, i)) != NULL; i++) { - conn = smscconn_create(grp, 1); + conn = smscconn_create(grp, 1); if (conn == NULL) panic(0, "Cannot start with SMSC connection failing"); gwlist_append(smsc_list, conn); } gwlist_remove_producer(smsc_list); - + if ((router_thread = gwthread_create(sms_router, NULL)) == -1) panic(0, "Failed to start a new thread for SMS routing"); - + gwlist_add_producer(incoming_sms); smsc_running = 1; return 0; @@ -749,7 +750,7 @@ /* find the group with equal smsc id */ hit = 0; grp = NULL; - for (group_index = 0; group_index < gwlist_len(smsc_groups) && + for (group_index = 0; group_index < gwlist_len(smsc_groups) && (grp = gwlist_get(smsc_groups, group_index)) != NULL; group_index++) { smscid = cfg_get(grp, octstr_imm("smsc-id")); if (smscid != NULL && octstr_compare(smscid, id) == 0) { @@ -767,7 +768,7 @@ error(0, "HTTP: Could not find config for smsc-id `%s'", octstr_get_cstr(id)); break; } - + info(0,"HTTP: Re-starting smsc-id `%s'", octstr_get_cstr(id)); new_conn = smscconn_create(grp, 1); @@ -775,7 +776,7 @@ error(0, "Start of SMSC connection failed, smsc-id `%s'", octstr_get_cstr(id)); continue; /* keep old connection on the list */ } - + /* drop old connection from the active smsc list */ gwlist_delete(smsc_list, i, 1); /* destroy the connection */ @@ -785,11 +786,11 @@ num++; } gw_rwlock_unlock(&smsc_list_lock); - + /* wake-up the router */ if (router_thread >= 0) gwthread_wakeup(router_thread); - + return 0; } @@ -807,7 +808,7 @@ smscconn_start(conn); } gw_rwlock_unlock(&smsc_list_lock); - + if (router_thread >= 0) gwthread_wakeup(router_thread); } @@ -874,7 +875,7 @@ return; debug("smscconn", 0, "final clean-up for SMSCConn"); - + gw_rwlock_wrlock(&smsc_list_lock); for (i = 0; i < gwlist_len(smsc_list); i++) { conn = gwlist_get(smsc_list, i); @@ -884,7 +885,7 @@ smsc_list = NULL; gw_rwlock_unlock(&smsc_list_lock); gwlist_destroy(smsc_groups, NULL); - octstr_destroy(unified_prefix); + octstr_destroy(unified_prefix); numhash_destroy(white_list); numhash_destroy(black_list); octstr_destroy(white_list_url); @@ -940,8 +941,8 @@ conn = gwlist_get(smsc_list, i); if ((smscconn_info(conn, &info) == -1)) { - /* - * we do not delete SMSCs from the list + /* + * we do not delete SMSCs from the list * this way we can show in the status which links are dead */ continue; @@ -959,7 +960,7 @@ octstr_append_cstr(tmp, " "); octstr_append(tmp, conn_id); octstr_append_cstr(tmp, " "); - } + } if (status_type == BBSTATUS_XML) { octstr_append_cstr(tmp, "<smsc>\n\t\t<name>"); octstr_append(tmp, conn_name); @@ -990,7 +991,7 @@ default: sprintf(tmp3, "unknown"); } - + if (status_type == BBSTATUS_XML) octstr_format_append(tmp, "<status>%s</status>\n\t\t<received>%ld</received>" "\n\t\t<sent>%ld</sent>\n\t\t<failed>%ld</failed>\n\t\t" @@ -1165,11 +1166,11 @@ static long route_incoming_to_smsc(SMSCConn *conn, Msg *msg) { Octstr *smsc; - + /* sanity check */ if (!conn || !msg) return -1; - + /* check for dlr rerouting */ if (!conn->reroute_dlr && (msg->sms.sms_type == report_mo || msg->sms.sms_type == report_mt)) return -1; @@ -1186,7 +1187,7 @@ /* drop into outbound queue again for routing */ return smsc2_rout(msg, 0); } - + if (conn->reroute_to_smsc) { /* change message direction */ store_save_ack(msg, ack_success); @@ -1197,7 +1198,7 @@ msg->sms.smsc_id = octstr_duplicate(conn->reroute_to_smsc); return smsc2_rout(msg, 0); } - + if (conn->reroute_by_receiver && msg->sms.receiver && (smsc = dict_get(conn->reroute_by_receiver, msg->sms.receiver))) { /* change message direction */ @@ -1211,7 +1212,7 @@ return smsc2_rout(msg, 0); } - return -1; + return -1; } @@ -1254,7 +1255,7 @@ { if (incoming_concat_msgs != NULL) /* already initialised? */ return; - incoming_concat_msgs = dict_create(max_incoming_sms_qlength > 0 ? max_incoming_sms_qlength : 1024, + incoming_concat_msgs = dict_create(max_incoming_sms_qlength > 0 ? max_incoming_sms_qlength : 1024, destroy_concatMsg); concat_lock = mutex_create(); debug("bb.sms",0,"smsbox MO concatenated message handling enabled"); @@ -1397,9 +1398,9 @@ debug("bb.sms.splits", 0, "Got part %d [ref %d, total parts %d] of message from %s. Dump follows:", part, refnum,totalparts, octstr_get_cstr(msg->sms.sender)); - + msg_dump(msg,0); - + key = octstr_format("%S %S %S %d", msg->sms.sender, msg->sms.receiver, smscid, refnum); mutex_lock(concat_lock); if ((cmsg = dict_get(incoming_concat_msgs, key)) == NULL) { @@ -1429,11 +1430,11 @@ } /* check if we have seen message part before... */ - if (cmsg->parts[part - 1] != NULL) { + if (cmsg->parts[part - 1] != NULL) { warning(0, "Duplicate message part %d, ref %d, from %s, to %s. Discarded!", part, refnum, octstr_get_cstr(msg->sms.sender), octstr_get_cstr(msg->sms.receiver)); store_save_ack(msg, ack_success); - msg_destroy(msg); + msg_destroy(msg); *pmsg = msg = NULL; } else { cmsg->parts[part -1] = msg; @@ -1459,12 +1460,12 @@ octstr_append(msg->sms.msgdata, cmsg->parts[i]->sms.msgdata); /* Attempt to save the new one, if that fails, then reply with fail. */ - if (store_save(msg) == -1) { + if (store_save(msg) == -1) { mutex_unlock(concat_lock); msg_destroy(msg); *pmsg = msg = NULL; return concat_error; - } else + } else *pmsg = msg; /* return the message part. */ /* Delete it from the queue and from the Dict. */ @@ -1498,7 +1499,7 @@ { numhash_destroy(white_list); numhash_destroy(black_list); - + if (white_list_url != NULL) { white_list = numhash_create(octstr_get_cstr(white_list_url)); }