#include <ctype.h>#include <time.h>#include <errno.h>#include <limits.h>#include <string.h>#include <unistd.h>#include "gwlib/gwlib.h"#include "smscconn.h"#include "smscconn_p.h"#include "bb_smscconn_cb.h"#include "shared.h"#include "sms.h"#include "dlr.h"Include dependency graph for smsc_cimd2.c:

Go to the source code of this file.
|
|
Definition at line 471 of file smsc_cimd2.c. Referenced by cimd2_login(), cimd2_logout(), cimd2_send_alive(), oisd_send_delivery_request(), and packet_encode_message(). |
|
|
Definition at line 462 of file smsc_cimd2.c. Referenced by packet_extract(), parse_data(), pretty_print(), random_message(), and send_packet(). |
|
|
Definition at line 467 of file smsc_cimd2.c. Referenced by packet_create(), and packet_extract(). |
|
|
Definition at line 128 of file smsc_cimd2.c. Referenced by cimd2_get_packet(), and oisd_get_packet(). |
|
|
Definition at line 461 of file smsc_cimd2.c. Referenced by packet_extract(), parse_data(), pretty_print(), random_message(), and send_packet(). |
|
|
Definition at line 466 of file smsc_cimd2.c. Referenced by packet_create(). |
|
|
Definition at line 463 of file smsc_cimd2.c. Referenced by eat_string_parm(), packet_check(), packet_get_parm(), packet_set_checksum(), pretty_print(), and send_packet(). |
|
|
Definition at line 468 of file smsc_cimd2.c. Referenced by packet_add_parm(), and packet_create(). |
|
|
|
|
|
Definition at line 132 of file smsc_cimd2.c. 00132 {
00133 /* Requests from client */
00134 LOGIN = 1,
00135 LOGOUT = 2,
00136 SUBMIT_MESSAGE = 3,
00137 ENQUIRE_MESSAGE_STATUS = 4,
00138 DELIVERY_REQUEST = 5,
00139 CANCEL_MESSAGE = 6,
00140 SET_REQ = 8,
00141 GET_REQ = 9,
00142
00143 /* Requests from server */
00144 DELIVER_MESSAGE = 20,
00145 DELIVER_STATUS_REPORT = 23,
00146
00147 /* Requests from either */
00148 ALIVE = 40,
00149
00150 /* Not a request; add to any request to make it a response */
00151 RESPONSE = 50,
00152
00153 /* Responses not related to requests */
00154 GENERAL_ERROR_RESPONSE = 98,
00155 NACK = 99
00156 };
|
|
|
Definition at line 160 of file smsc_cimd2.c. 00160 {
00161 P_USER_IDENTITY = 10,
00162 P_PASSWORD = 11,
00163 P_DESTINATION_ADDRESS = 21,
00164 P_ORIGINATING_ADDRESS = 23,
00165 P_ORIGINATING_IMSI = 26,
00166 P_ALPHANUMERIC_ORIGINATING_ADDRESS = 27,
00167 P_ORIGINATED_VISITED_MSC = 28,
00168 P_DATA_CODING_SCHEME = 30,
00169 P_USER_DATA_HEADER = 32,
00170 P_USER_DATA = 33,
00171 P_USER_DATA_BINARY = 34,
00172 P_MORE_MESSAGES_TO_SEND = 44,
00173 P_VALIDITY_PERIOD_RELATIVE = 50,
00174 P_VALIDITY_PERIOD_ABSOLUTE = 51,
00175 P_PROTOCOL_IDENTIFIER = 52,
00176 P_FIRST_DELIVERY_TIME_RELATIVE = 53,
00177 P_FIRST_DELIVERY_TIME_ABSOLUTE = 54,
00178 P_REPLY_PATH = 55,
00179 P_STATUS_REPORT_REQUEST = 56,
00180 P_CANCEL_ENABLED = 58,
00181 P_CANCEL_MODE = 59,
00182 P_MC_TIMESTAMP = 60,
00183 P_STATUS_CODE = 61,
00184 P_STATUS_ERROR_CODE = 62,
00185 P_DISCHARGE_TIME = 63,
00186 P_TARIFF_CLASS = 64,
00187 P_SERVICE_DESCRIPTION = 65,
00188 P_MESSAGE_COUNT = 66,
00189 P_PRIORITY = 67,
00190 P_DELIVERY_REQUEST_MODE = 68,
00191 P_SERVICE_CENTER_ADDRESS = 69,
00192 P_GET_PARAMETER = 500,
00193 P_MC_TIME = 501,
00194 P_ERROR_CODE = 900,
00195 P_ERROR_TEXT = 901
00196 };
|
|
|
Definition at line 205 of file smsc_cimd2.c. 00205 { P_INT, P_STRING, P_ADDRESS, P_TIME, P_HEX, P_SMS };
|
|
||||||||||||
|
Definition at line 2084 of file smsc_cimd2.c. References code, dlr_find(), smscconn::name, octstr_destroy(), octstr_get_cstr, P_DESTINATION_ADDRESS, P_MC_TIMESTAMP, P_STATUS_CODE, P_USER_DATA, packet_get_parm(), and SMSCConn. Referenced by cimd2_handle_request(). 02086 {
02087 Msg *msg = NULL;
02088 Octstr *destination = NULL;
02089 Octstr *timestamp = NULL;
02090 Octstr *statuscode = NULL;
02091 int st_code;
02092 int code;
02093
02094 destination = packet_get_parm(request, P_DESTINATION_ADDRESS);
02095 timestamp = packet_get_parm(request, P_MC_TIMESTAMP);
02096 statuscode = packet_get_parm(request, P_STATUS_CODE);
02097
02098 st_code = atoi(octstr_get_cstr(statuscode));
02099
02100 switch(st_code)
02101 {
02102 case 2: /* validity period expired */
02103 case 3: /* delivery failed */
02104 case 6: /* last no response */
02105 case 7: /* message cancelled */
02106 case 8: /* message deleted */
02107 case 9: /* message deleted by cancel */
02108 code = DLR_FAIL;
02109 break;
02110 case 4: /* delivery successful */
02111 code = DLR_SUCCESS;
02112 break;
02113 default:
02114 code = 0;
02115 }
02116 if(code)
02117 msg = dlr_find(conn->name, timestamp, destination, code);
02118 else
02119 msg = NULL;
02120
02121 /* recode the body into msgdata */
02122 if (msg) {
02123 msg->sms.msgdata = packet_get_parm(request, P_USER_DATA);
02124 if (!msg->sms.msgdata) {
02125 msg->sms.msgdata = statuscode;
02126 statuscode = NULL;
02127 }
02128 }
02129
02130 octstr_destroy(statuscode);
02131 octstr_destroy(destination);
02132 octstr_destroy(timestamp);
02133
02134 return msg;
02135 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 1588 of file smsc_cimd2.c. References charset_gsm_to_utf8(), convert_cimd2_to_gsm(), dcs_to_fields(), debug(), error(), smscconn::id, info(), message, msg_create, msg_destroy(), octstr_destroy(), octstr_get_cstr, octstr_len(), P_DATA_CODING_SCHEME, P_DESTINATION_ADDRESS, P_ORIGINATING_ADDRESS, P_USER_DATA, P_USER_DATA_BINARY, P_USER_DATA_HEADER, packet_get_address_parm(), packet_get_hex_parm(), packet_get_int_parm(), packet_get_sms_parm(), sms, SMSCConn, and text. Referenced by cimd2_handle_request(). 01589 {
01590 Msg *message = NULL;
01591 Octstr *destination = NULL;
01592 Octstr *origin = NULL;
01593 Octstr *UDH = NULL;
01594 Octstr *text = NULL;
01595 int DCS;
01596
01597 /* See GSM 03.38. The bit patterns we can handle are:
01598 * 000xyyxx Uncompressed text, yy indicates alphabet.
01599 * yy = 00, default alphabet
01600 * yy = 01, 8-bit data
01601 * yy = 10, UCS-2
01602 * yy = 11, reserved
01603 * 1111xyxx Data, y indicates alphabet.
01604 * y = 0, default alphabet
01605 * y = 1, 8-bit data
01606 */
01607 DCS = packet_get_int_parm(request, P_DATA_CODING_SCHEME);
01608
01609 destination = packet_get_address_parm(request, P_DESTINATION_ADDRESS);
01610 origin = packet_get_address_parm(request, P_ORIGINATING_ADDRESS);
01611 UDH = packet_get_hex_parm(request, P_USER_DATA_HEADER);
01612 /* Text is either in User Data or User Data Binary field. */
01613 text = packet_get_sms_parm(request, P_USER_DATA);
01614 if (text != NULL) {
01615 convert_cimd2_to_gsm(text,conn);
01616 charset_gsm_to_utf8(text);
01617 } else {
01618 /*
01619 * FIXME: If DCS indicates GSM charset, and we get it in binary,
01620 * then it's probably bit-packed. We'll have to undo it because
01621 * our "charset_gsm" means one gsm character per octet. This is
01622 * not currently supported. -- RB
01623 */
01624 text = packet_get_hex_parm(request, P_USER_DATA_BINARY);
01625 }
01626
01627 /* Code elsewhere in the gateway always expects the sender and
01628 * receiver fields to be filled, so we discard messages that
01629 * lack them. If they should not be discarded, then the code
01630 * handling sms messages should be reviewed. -- RB */
01631 if (!destination || octstr_len(destination) == 0) {
01632 info(0, "CIMD2[%s]: Got SMS without receiver, discarding.",
01633 octstr_get_cstr(conn->id));
01634 goto error;
01635 }
01636 if (!origin || octstr_len(origin) == 0) {
01637 info(0, "CIMD2[%s]: Got SMS without sender, discarding.",
01638 octstr_get_cstr(conn->id));
01639 goto error;
01640 }
01641
01642 if (!text && (!UDH || octstr_len(UDH) == 0)) {
01643 info(0, "CIMD2[%s]: Got empty SMS, ignoring.",
01644 octstr_get_cstr(conn->id));
01645 goto error;
01646 }
01647
01648 message = msg_create(sms);
01649 if (! dcs_to_fields(&message, DCS)) {
01650 /* XXX Should reject this message ? */
01651 debug("bb.sms.cimd2", 0, "CIMD2[%s]: Invalid DCS",
01652 octstr_get_cstr(conn->id));
01653 dcs_to_fields(&message, 0);
01654 }
01655 time(&message->sms.time);
01656 message->sms.sender = origin;
01657 message->sms.receiver = destination;
01658 if (UDH) {
01659 message->sms.udhdata = UDH;
01660 }
01661 message->sms.msgdata = text;
01662 return message;
01663
01664 error:
01665 msg_destroy(message);
01666 octstr_destroy(destination);
01667 octstr_destroy(origin);
01668 octstr_destroy(UDH);
01669 octstr_destroy(text);
01670 return NULL;
01671 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 2237 of file smsc_cimd2.c. References smscconn::data, gwlist_produce(), gwthread_wakeup(), privdata::io_thread, msg_duplicate(), privdata::outgoing_queue, PrivData, sms, and SMSCConn. 02238 {
02239 PrivData *pdata = conn->data;
02240 Msg *copy;
02241
02242 copy = msg_duplicate(sms);
02243 gwlist_produce(pdata->outgoing_queue, copy);
02244 gwthread_wakeup(pdata->io_thread);
02245
02246 return 0;
02247 }
|
Here is the call graph for this function:

|
|
Definition at line 1837 of file smsc_cimd2.c. References privdata::conn, gw_assert, smscconn::id, octstr_get_cstr, PrivData, privdata::socket, and warning(). Referenced by cimd2_login(), cimd2_shutdown_cb(), cimd2_submit_msg(), and sms_receive(). 01838 {
01839 gw_assert(pdata != NULL);
01840
01841 if (pdata->socket < 0)
01842 return;
01843
01844 if (close(pdata->socket) < 0)
01845 warning(errno, "CIMD2[%s]: error closing socket",
01846 octstr_get_cstr(pdata->conn->id));
01847 pdata->socket = -1;
01848 }
|
Here is the call graph for this function:

|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 1526 of file smsc_cimd2.c. References privdata::conn, packet::data, debug(), error(), gw_assert, smscconn::id, privdata::inbuffer, privdata::keepalive, privdata::next_ping, octstr_append_from_socket(), octstr_get_cstr, P_MC_TIMESTAMP, packet_check(), packet_check_can_receive(), packet_extract(), packet_get_parm(), PrivData, read_available(), RESPONSE_TIMEOUT, privdata::socket, and warning(). Referenced by cimd2_request(). 01527 {
01528 struct packet *packet = NULL;
01529
01530 gw_assert(pdata != NULL);
01531
01532 /* If packet is already available, don't try to read anything */
01533 packet = packet_extract(pdata->inbuffer, pdata->conn);
01534
01535 while (packet == NULL) {
01536 if (read_available(pdata->socket, RESPONSE_TIMEOUT) != 1) {
01537 warning(0, "CIMD2[%s]: SMSC is not responding",
01538 octstr_get_cstr(pdata->conn->id));
01539 return NULL;
01540 }
01541
01542 if (octstr_append_from_socket(pdata->inbuffer, pdata->socket) <= 0) {
01543 error(0, "CIMD2[%s]: cimd2_get_packet: read failed",
01544 octstr_get_cstr(pdata->conn->id));
01545 return NULL;
01546 }
01547
01548 packet = packet_extract(pdata->inbuffer, pdata->conn);
01549 }
01550
01551 packet_check(packet,pdata->conn);
01552 packet_check_can_receive(packet,pdata->conn);
01553 debug("bb.sms.cimd2", 0, "CIMD2[%s]: received: <%s>",
01554 octstr_get_cstr(pdata->conn->id),
01555 octstr_get_cstr(packet->data));
01556 if (ts)
01557 *ts = packet_get_parm(packet,P_MC_TIMESTAMP);
01558
01559 if (pdata->keepalive > 0)
01560 pdata->next_ping = time(NULL) + pdata->keepalive;
01561
01562 return packet;
01563 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 1674 of file smsc_cimd2.c. References cimd2_accept_delivery_report_message(), cimd2_accept_message(), cimd2_send_response(), smscconn::data, gwlist_append(), smscconn::id, message, octstr_get_cstr, packet::operation, PrivData, privdata::receive_seq, privdata::received, packet::seq, SMSCConn, and warning(). Referenced by cimd2_receive_msg(), and cimd2_request(). 01675 {
01676 PrivData *pdata = conn->data;
01677 Msg *message = NULL;
01678
01679 if ((request->seq == 254 && pdata->receive_seq == 0) ||
01680 request->seq == pdata->receive_seq - 2) {
01681 warning(0, "CIMD2[%s]: request had same sequence number as previous.",
01682 octstr_get_cstr(conn->id));
01683 }
01684 else {
01685 pdata->receive_seq = request->seq + 2;
01686 if (pdata->receive_seq > 254)
01687 pdata->receive_seq = 0;
01688
01689 if (request->operation == DELIVER_STATUS_REPORT) {
01690 message = cimd2_accept_delivery_report_message(request, conn);
01691 if (message)
01692 gwlist_append(pdata->received, message);
01693 }
01694 else if (request->operation == DELIVER_MESSAGE) {
01695 message = cimd2_accept_message(request,conn);
01696 if (message)
01697 gwlist_append(pdata->received, message);
01698 }
01699 }
01700
01701 cimd2_send_response(request, pdata);
01702 }
|
Here is the call graph for this function:

|
|
Definition at line 1854 of file smsc_cimd2.c. References BOGUS_SEQUENCE, cimd2_close_socket(), cimd2_request(), smscconn::data, error(), gw_assert, privdata::host, smscconn::id, info(), LOGIN, octstr_get_cstr, smscconn::our_host, privdata::our_port, P_PASSWORD, P_USER_IDENTITY, packet_add_string_parm(), packet_create(), packet_destroy(), privdata::password, privdata::port, PrivData, SMSCConn, privdata::socket, tcpip_connect_to_server_with_port(), privdata::username, and warning(). Referenced by io_thread(). 01855 {
01856 PrivData *pdata = conn->data;
01857 int ret;
01858 struct packet *packet = NULL;
01859
01860 gw_assert(pdata != NULL);
01861
01862 if (pdata->socket >= 0) {
01863 warning(0, "CIMD2[%s]: login: socket was already open; closing",
01864 octstr_get_cstr(conn->id));
01865 cimd2_close_socket(pdata);
01866 }
01867
01868 pdata->socket = tcpip_connect_to_server_with_port(
01869 octstr_get_cstr(pdata->host),
01870 pdata->port,
01871 pdata->our_port,
01872 (conn->our_host ? octstr_get_cstr(conn->our_host) : NULL));
01873 if (pdata->socket != -1) {
01874
01875 packet = packet_create(LOGIN, BOGUS_SEQUENCE);
01876 packet_add_string_parm(packet, P_USER_IDENTITY, pdata->username, conn);
01877 packet_add_string_parm(packet, P_PASSWORD, pdata->password, conn);
01878
01879 ret = cimd2_request(packet, conn, NULL);
01880
01881 if (ret >= 0) {
01882 packet_destroy(packet);
01883 info(0, "CIMD2[%s] logged in.",
01884 octstr_get_cstr(conn->id));
01885 return 0;
01886 }
01887 }
01888 error(0, "CIMD2[%s] login failed.",
01889 octstr_get_cstr(conn->id));
01890 cimd2_close_socket(pdata);
01891 packet_destroy(packet);
01892 return -1;
01893 }
|
Here is the call graph for this function:

|
|
Definition at line 1895 of file smsc_cimd2.c. References BOGUS_SEQUENCE, cimd2_request(), smscconn::id, info(), LOGOUT, octstr_get_cstr, packet_create(), packet_destroy(), and SMSCConn. Referenced by cimd2_shutdown_cb(). 01896 {
01897 struct packet *packet = NULL;
01898 int ret;
01899
01900 packet = packet_create(LOGOUT, BOGUS_SEQUENCE);
01901
01902 /* TODO: Don't wait very long for a response in this case. */
01903 ret = cimd2_request(packet, conn, NULL);
01904
01905 if (ret == 0) {
01906 info(0, "CIMD2[%s] logged out.",
01907 octstr_get_cstr(conn->id));
01908 }
01909 packet_destroy(packet);
01910 }
|
Here is the call graph for this function:

|
|
Definition at line 2311 of file smsc_cimd2.c. References smscconn::data, gwlist_len(), smscconn::load, privdata::outgoing_queue, PrivData, SMSCConn, SMSCCONN_DEAD, and smscconn::status. 02312 {
02313 PrivData *pdata = conn->data;
02314 conn->load = (pdata ? (conn->status != SMSCCONN_DEAD ?
02315 gwlist_len(pdata->outgoing_queue) : 0) : 0);
02316 return conn->load;
02317 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 2002 of file smsc_cimd2.c. References cimd2_handle_request(), cimd2_send_alive(), privdata::conn, packet::data, smscconn::data, debug(), error(), gw_assert, gwlist_consume(), gwlist_len(), smscconn::id, privdata::inbuffer, privdata::keepalive, privdata::next_ping, octstr_append_from_socket(), octstr_dump, octstr_get_cstr, packet::operation, packet_check(), packet_check_can_receive(), packet_destroy(), packet_extract(), PrivData, read_available(), privdata::received, SMSCConn, privdata::socket, and warning(). Referenced by sms_receive(). 02003 {
02004 PrivData *pdata = conn->data;
02005 long ret;
02006 struct packet *packet;
02007
02008 gw_assert(pdata != NULL);
02009
02010 if (gwlist_len(pdata->received) > 0) {
02011 *msg = gwlist_consume(pdata->received);
02012 return 1;
02013 }
02014
02015 if (pdata->socket < 0) {
02016 /* XXX We have to assume that smsc_send_message is
02017 * currently trying to reopen, so we have to make
02018 * this thread wait. It should be done in a nicer
02019 * way. */
02020 return 0;
02021 }
02022
02023 ret = read_available(pdata->socket, 0);
02024 if (ret == 0) {
02025 if (pdata->keepalive > 0 && pdata->next_ping < time(NULL)) {
02026 if (cimd2_send_alive(conn) < 0)
02027 return -1;
02028 }
02029 return 0;
02030 }
02031
02032 if (ret < 0) {
02033 warning(errno, "CIMD2[%s]: cimd2_receive_msg: read_available failed",
02034 octstr_get_cstr(conn->id));
02035 return -1;
02036 }
02037
02038 /* We have some data waiting... see if it is an sms delivery. */
02039 ret = octstr_append_from_socket(pdata->inbuffer, pdata->socket);
02040
02041 if (ret == 0) {
02042 warning(0, "CIMD2[%s]: cimd2_receive_msg: service center closed connection.",
02043 octstr_get_cstr(conn->id));
02044 return -1;
02045 }
02046 if (ret < 0) {
02047 warning(0, "CIMD2[%s]: cimd2_receive_msg: read failed",
02048 octstr_get_cstr(conn->id));
02049 return -1;
02050 }
02051
02052
02053 for (;;) {
02054 packet = packet_extract(pdata->inbuffer,conn);
02055 if (!packet)
02056 break;
02057
02058 packet_check(packet,conn);
02059 packet_check_can_receive(packet,conn);
02060 debug("bb.sms.cimd2", 0, "CIMD2[%s]: received: <%s>",
02061 octstr_get_cstr(pdata->conn->id),
02062 octstr_get_cstr(packet->data));
02063
02064 if (packet->operation < RESPONSE)
02065 cimd2_handle_request(packet, conn);
02066 else {
02067 error(0, "CIMD2[%s]: cimd2_receive_msg: unexpected response packet",
02068 octstr_get_cstr(conn->id));
02069 octstr_dump(packet->data, 0);
02070 }
02071
02072 packet_destroy(packet);
02073 }
02074
02075 if (gwlist_len(pdata->received) > 0) {
02076 *msg = gwlist_consume(pdata->received);
02077 return 1;
02078 }
02079 return 0;
02080 }
|
Here is the call graph for this function:

|
||||||||||||||||
|
Definition at line 1718 of file smsc_cimd2.c. References cimd2_get_packet(), cimd2_handle_request(), packet::data, smscconn::data, debug(), error(), gw_assert, smscconn::id, octstr_destroy(), octstr_dump, octstr_get_cstr, octstr_write_to_socket(), packet::operation, operation_can_send(), operation_name(), packet_destroy(), packet_display_error(), packet_set_checksum(), packet_set_send_sequence(), PrivData, privdata::send_seq, packet::seq, SMSCConn, privdata::socket, and warning(). Referenced by cimd2_login(), cimd2_logout(), cimd2_send_alive(), and cimd2_submit_msg(). 01719 {
01720 PrivData *pdata = conn->data;
01721 int ret;
01722 struct packet *reply = NULL;
01723 int errorcode;
01724 int tries = 0;
01725
01726 gw_assert(pdata != NULL);
01727 gw_assert(request != NULL);
01728 gw_assert(operation_can_send(request->operation));
01729
01730 if (pdata->socket < 0) {
01731 warning(0, "CIMD2[%s]: cimd2_request: socket not open.",
01732 octstr_get_cstr(conn->id));
01733 return -2;
01734 }
01735
01736 retransmit:
01737 packet_set_send_sequence(request, pdata);
01738 packet_set_checksum(request);
01739
01740 debug("bb.sms.cimd2", 0, "CIMD2[%s]: sending <%s>",
01741 octstr_get_cstr(conn->id),
01742 octstr_get_cstr(request->data));
01743
01744 ret = octstr_write_to_socket(pdata->socket, request->data);
01745 if (ret < 0)
01746 goto io_error;
01747
01748 next_reply:
01749 packet_destroy(reply); /* destroy old, if any */
01750 reply = cimd2_get_packet(pdata, ts);
01751 if (!reply)
01752 goto io_error;
01753
01754 errorcode = packet_display_error(reply,conn);
01755
01756 if (reply->operation == NACK) {
01757 warning(0, "CIMD2[%s]: received NACK",
01758 octstr_get_cstr(conn->id));
01759 octstr_dump(reply->data, 0);
01760 /* Correct sequence number if server says it was wrong,
01761 * but only if server's number is sane. */
01762 if (reply->seq != request->seq && (reply->seq % 2) == 1) {
01763 warning(0, "CIMD2[%s]: correcting sequence number from %ld to %ld.",
01764 octstr_get_cstr(conn->id),
01765 (long) pdata->send_seq,
01766 (long) reply->seq);
01767 pdata->send_seq = reply->seq;
01768 }
01769 goto retry;
01770 }
01771
01772 if (reply->operation == GENERAL_ERROR_RESPONSE) {
01773 error(0, "CIMD2[%s]: received general error response",
01774 octstr_get_cstr(conn->id));
01775 goto io_error;
01776 }
01777
01778 /* The server sent us a request. Handle it, then wait for
01779 * a new reply. */
01780 if (reply->operation < RESPONSE) {
01781 cimd2_handle_request(reply, conn);
01782 goto next_reply;
01783 }
01784
01785 if (reply->seq != request->seq) {
01786 /* We got a response to a different request number than
01787 * what we send. Strange. */
01788 warning(0, "CIMD2[%s]: response had unexpected sequence number; ignoring.",
01789 octstr_get_cstr(conn->id));
01790 goto next_reply;
01791 }
01792
01793 if (reply->operation != request->operation + RESPONSE) {
01794 /* We got a response that didn't match our request */
01795 Octstr *request_name = operation_name(request->operation);
01796 Octstr *reply_name = operation_name(reply->operation);
01797 warning(0, "CIMD2[%s]: %s request got a %s",
01798 octstr_get_cstr(conn->id),
01799 octstr_get_cstr(request_name),
01800 octstr_get_cstr(reply_name));
01801
01802 octstr_destroy(request_name);
01803 octstr_destroy(reply_name);
01804 octstr_dump(reply->data, 0);
01805 goto retry;
01806 }
01807
01808 if (errorcode > 0)
01809 goto error;
01810
01811 /* The reply passed all the checks... looks like the SMSC accepted
01812 * our request! */
01813 packet_destroy(reply);
01814 return 0;
01815
01816 io_error:
01817 packet_destroy(reply);
01818 return -2;
01819
01820 error:
01821 packet_destroy(reply);
01822 return -1;
01823
01824 retry:
01825 if (++tries < 3) {
01826 warning(0, "CIMD2[%s]: Retransmitting (take %d)",
01827 octstr_get_cstr(conn->id),
01828 tries);
01829 goto retransmit;
01830 }
01831 warning(0, "CIMD2[%s]: Giving up.",
01832 octstr_get_cstr(conn->id));
01833 goto io_error;
01834 }
|
Here is the call graph for this function:

|
|
Definition at line 1912 of file smsc_cimd2.c. References ALIVE, BOGUS_SEQUENCE, cimd2_request(), smscconn::id, octstr_get_cstr, packet_create(), packet_destroy(), SMSCConn, and warning(). Referenced by cimd2_receive_msg(). 01913 {
01914 struct packet *packet = NULL;
01915 int ret;
01916
01917 packet = packet_create(ALIVE, BOGUS_SEQUENCE);
01918 ret = cimd2_request(packet, conn, NULL);
01919 packet_destroy(packet);
01920
01921 if (ret < 0)
01922 warning(0, "CIMD2[%s]: SMSC not alive.",
01923 octstr_get_cstr(conn->id));
01924
01925 return ret;
01926 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 1567 of file smsc_cimd2.c. References privdata::conn, packet::data, debug(), gw_assert, smscconn::id, octstr_get_cstr, octstr_write_to_socket(), packet::operation, packet_create(), packet_destroy(), packet_set_checksum(), PrivData, response, RESPONSE, packet::seq, and privdata::socket. Referenced by cimd2_handle_request(). 01568 {
01569 struct packet *response;
01570
01571 gw_assert(request != NULL);
01572 gw_assert(request->operation < RESPONSE);
01573
01574 response = packet_create(request->operation + RESPONSE, request->seq);
01575 packet_set_checksum(response);
01576
01577 debug("bb.sms.cimd2", 0, "CIMD2[%s]: sending <%s>",
01578 octstr_get_cstr(pdata->conn->id),
01579 octstr_get_cstr(response->data));
01580
01581 /* Don't check errors here because if there is something
01582 * wrong with the socket, the main loop will detect it. */
01583 octstr_write_to_socket(pdata->socket, response->data);
01584
01585 packet_destroy(response);
01586 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 2250 of file smsc_cimd2.c. References bb_smscconn_killed(), bb_smscconn_send_failed(), cimd2_close_socket(), cimd2_destroy(), cimd2_logout(), smscconn::data, debug(), gwlist_extract_first(), gwlist_remove_producer(), gwthread_join(), gwthread_wakeup(), smscconn::id, privdata::io_thread, smscconn::is_stopped, octstr_get_cstr, privdata::outgoing_queue, PrivData, privdata::quitting, SMSCConn, SMSCCONN_FAILED_SHUTDOWN, smscconn::status, privdata::stopped, and smscconn::why_killed. 02251 {
02252 PrivData *pdata = conn->data;
02253
02254 debug("bb.sms", 0, "Shutting down SMSCConn CIMD2 %s (%s)",
02255 octstr_get_cstr(conn->id),
02256 finish_sending ? "slow" : "instant");
02257
02258 /* Documentation claims this would have been done by smscconn.c,
02259 but isn't when this code is being written. */
02260 conn->why_killed = SMSCCONN_KILLED_SHUTDOWN;
02261 pdata->quitting = 1; /* Separate from why_killed to avoid locking, as
02262 * why_killed may be changed from outside? */
02263
02264 if (finish_sending == 0) {
02265 Msg *msg;
02266 while ((msg = gwlist_extract_first(pdata->outgoing_queue)) != NULL) {
02267 bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL);
02268 }
02269 }
02270
02271 cimd2_logout(conn);
02272 if (conn->is_stopped) {
02273 gwlist_remove_producer(pdata->stopped);
02274 conn->is_stopped = 0;
02275 }
02276
02277 if (pdata->io_thread != -1) {
02278 gwthread_wakeup(pdata->io_thread);
02279 gwthread_join(pdata->io_thread);
02280 }
02281
02282 cimd2_close_socket(pdata);
02283 cimd2_destroy(pdata);
02284
02285 debug("bb.sms", 0, "SMSCConn CIMD2 %s shut down.",
02286 octstr_get_cstr(conn->id));
02287 conn->status = SMSCCONN_DEAD;
02288 bb_smscconn_killed();
02289 return 0;
02290 }
|
Here is the call graph for this function:

|
|
Definition at line 2292 of file smsc_cimd2.c. References smscconn::data, debug(), gwlist_remove_producer(), gwthread_wakeup(), smscconn::id, privdata::io_thread, octstr_get_cstr, PrivData, SMSCConn, and privdata::stopped. 02293 {
02294 PrivData *pdata = conn->data;
02295
02296 gwlist_remove_producer(pdata->stopped);
02297 /* in case there are messages in the buffer already */
02298 gwthread_wakeup(pdata->io_thread);
02299 debug("bb.sms", 0, "SMSCConn CIMD2 %s, start called",
02300 octstr_get_cstr(conn->id));
02301 }
|
Here is the call graph for this function:

|
|
Definition at line 2303 of file smsc_cimd2.c. References smscconn::data, debug(), gwlist_add_producer(), smscconn::id, octstr_get_cstr, PrivData, SMSCConn, and privdata::stopped. 02304 {
02305 PrivData *pdata = conn->data;
02306 gwlist_add_producer(pdata->stopped);
02307 debug("bb.sms", 0, "SMSCConn CIMD2 %s, stop called",
02308 octstr_get_cstr(conn->id));
02309 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 1956 of file smsc_cimd2.c. References bb_smscconn_send_failed(), bb_smscconn_sent(), cimd2_close_socket(), cimd2_request(), smscconn::data, debug(), dlr_add(), DLR_IS_SUCCESS_OR_FAIL, smscconn::flow_mutex, gw_assert, smscconn::id, mutex_lock, mutex_unlock, privdata::my_number, smscconn::name, privdata::no_dlr, octstr_create, octstr_destroy(), octstr_get_cstr, packet_destroy(), packet_encode_message(), PrivData, SMSCConn, SMSCCONN_FAILED_MALFORMED, SMSCCONN_FAILED_REJECTED, SMSCCONN_FAILED_TEMPORARILY, and smscconn::status. Referenced by io_thread(). 01957 {
01958 PrivData *pdata = conn->data;
01959 struct packet *packet;
01960 Octstr *ts = NULL;
01961 int ret;
01962
01963 gw_assert(pdata != NULL);
01964 debug("bb.sms.cimd2", 0, "CIMD2[%s]: sending message",
01965 octstr_get_cstr(conn->id));
01966
01967 packet = packet_encode_message(msg, pdata->my_number,conn);
01968 if (!packet) {
01969 /* This is a protocol error. Does this help? I doubt..
01970 * But nevermind that.
01971 */
01972 bb_smscconn_send_failed(conn, msg,
01973 SMSCCONN_FAILED_MALFORMED, octstr_create("MALFORMED"));
01974 return -1;
01975 }
01976
01977 ret = cimd2_request(packet, conn, &ts);
01978 if((ret == 0) && (ts) && DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask) && !pdata->no_dlr) {
01979 dlr_add(conn->name, ts, msg);
01980 }
01981 octstr_destroy(ts);
01982 packet_destroy(packet);
01983
01984 if (ret == -1) {
01985 bb_smscconn_send_failed(conn, msg,
01986 SMSCCONN_FAILED_REJECTED, octstr_create("REJECTED"));
01987 }
01988 else if (ret == -2) {
01989 cimd2_close_socket(pdata);
01990 bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_TEMPORARILY, NULL);
01991 mutex_lock(conn->flow_mutex);
01992 conn->status = SMSCCONN_DISCONNECTED;
01993 mutex_unlock(conn->flow_mutex);
01994 }
01995 else {
01996 bb_smscconn_sent(conn,msg, NULL);
01997 }
01998
01999 return ret;
02000 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 1082 of file smsc_cimd2.c. References cimd1, cimd2, cimd_combinations, gsm, smscconn::id, octstr_delete(), octstr_get_char(), octstr_get_cstr, octstr_len(), octstr_set_char(), SMSCConn, text, and warning(). Referenced by cimd2_accept_message(). 01083 {
01084 long pos, len;
01085 int cimd1, cimd2;
01086 int c;
01087 int i;
01088
01089 /* CIMD2 uses four single-character mappings that do not map
01090 * to themselves:
01091 * '@' from 64 to 0, '$' from 36 to 2, ']' from 93 to 14 (A-ring),
01092 * and '}' from 125 to 15 (a-ring).
01093 * Other than those, we only have to worry about the escape
01094 * sequences introduced by _ (underscore).
01095 */
01096
01097 len = octstr_len(text);
01098 for (pos = 0; pos < len; pos++) {
01099 c = octstr_get_char(text, pos);
01100 if (c == '@')
01101 octstr_set_char(text, pos, 0);
01102 else if (c == '$')
01103 octstr_set_char(text, pos, 2);
01104 else if (c == ']')
01105 octstr_set_char(text, pos, 14);
01106 else if (c == '}')
01107 octstr_set_char(text, pos, 15);
01108 else if (c == '_' && pos + 2 < len) {
01109 cimd1 = octstr_get_char(text, pos + 1);
01110 cimd2 = octstr_get_char(text, pos + 2);
01111 for (i = 0; cimd_combinations[i].cimd1 != 0; i++) {
01112 if (cimd_combinations[i].cimd1 == cimd1 &&
01113 cimd_combinations[i].cimd2 == cimd2)
01114 break;
01115 }
01116 if (cimd_combinations[i].cimd1 == 0)
01117 warning(0, "CIMD2[%s]: Encountered unknown "
01118 "escape code _%c%c, ignoring.",
01119 octstr_get_cstr(conn->id),
01120 cimd1, cimd2);
01121 else {
01122 octstr_delete(text, pos, 2);
01123 octstr_set_char(text, pos, cimd_combinations[i].gsm);
01124 len = octstr_len(text);
01125 }
01126 }
01127 }
01128 }
|
Here is the call graph for this function:

|
|
Definition at line 1135 of file smsc_cimd2.c. References cimd1, cimd2, cimd_combinations, gw_assert, octstr_get_char(), octstr_insert_data(), octstr_len(), octstr_set_char(), and text. Referenced by packet_encode_message(). 01136 {
01137 long pos, len;
01138
01139 len = octstr_len(text);
01140 for (pos = 0; pos < len; pos++) {
01141 int c, i;
01142
01143 c = octstr_get_char(text, pos);
01144 /* If c is not in the GSM alphabet at this point,
01145 * the caller did something badly wrong. */
01146 gw_assert(c >= 0);
01147 gw_assert(c < 128);
01148
01149 for (i = 0; cimd_combinations[i].cimd1 != 0; i++) {
01150 if (cimd_combinations[i].gsm == c)
01151 break;
01152 }
01153
01154 if (cimd_combinations[i].gsm == c) {
01155 /* Escape sequence */
01156 octstr_insert_data(text, pos, "_ ", 2);
01157 pos += 2;
01158 len += 2;
01159 octstr_set_char(text, pos - 1, cimd_combinations[i].cimd1);
01160 octstr_set_char(text, pos, cimd_combinations[i].cimd2);
01161 } else if (c == 2) {
01162 /* The dollar sign is the only GSM character that
01163 * does not have a CIMD escape sequence and does not
01164 * map to itself. */
01165 octstr_set_char(text, pos, '$');
01166 }
01167 }
01168 }
|
Here is the call graph for this function:

|
|
Definition at line 2162 of file smsc_cimd2.c. References bb_smscconn_connected(), bb_smscconn_receive(), cimd2_login(), cimd2_submit_msg(), smscconn::connect_time, smscconn::data, debug(), error(), smscconn::flow_mutex, gwlist_consume(), gwlist_extract_first(), gwthread_sleep(), smscconn::id, smscconn::log_idx, log_thread_to(), mutex_lock, mutex_unlock, octstr_get_cstr, privdata::outgoing_queue, PrivData, privdata::quitting, smscconn::reconnect_delay, sms_receive(), SMSCConn, smscconn::status, and privdata::stopped. Referenced by smsc_cimd2_create(). 02163 {
02164 Msg *msg;
02165 SMSCConn *conn = arg;
02166 PrivData *pdata = conn->data;
02167 double sleep = 0.0001;
02168
02169 /* Make sure we log into our own log-file if defined */
02170 log_thread_to(conn->log_idx);
02171
02172 /* remove messages from SMSC until we are killed */
02173 while (!pdata->quitting) {
02174
02175 gwlist_consume(pdata->stopped); /* block here if suspended/isolated */
02176
02177 /* check that connection is active */
02178 if (conn->status != SMSCCONN_ACTIVE) {
02179 if (cimd2_login(conn) != 0) {
02180 error(0, "CIMD2[%s]: Couldn't connect to SMSC (retrying in %ld seconds).",
02181 octstr_get_cstr(conn->id),
02182 conn->reconnect_delay);
02183 gwthread_sleep(conn->reconnect_delay);
02184 mutex_lock(conn->flow_mutex);
02185 conn->status = SMSCCONN_RECONNECTING;
02186 mutex_unlock(conn->flow_mutex);
02187 continue;
02188 }
02189 mutex_lock(conn->flow_mutex);
02190 conn->status = SMSCCONN_ACTIVE;
02191 conn->connect_time = time(NULL);
02192 bb_smscconn_connected(conn);
02193 mutex_unlock(conn->flow_mutex);
02194 }
02195
02196 /* receive messages */
02197 do {
02198 msg = sms_receive(conn);
02199 if (msg) {
02200 sleep = 0;
02201 debug("bb.sms.cimd2", 0, "CIMD2[%s]: new message received",
02202 octstr_get_cstr(conn->id));
02203 bb_smscconn_receive(conn, msg);
02204 }
02205 } while (msg);
02206
02207 /* send messages */
02208 do {
02209 msg = gwlist_extract_first(pdata->outgoing_queue);
02210 if (msg) {
02211 sleep = 0;
02212 if (cimd2_submit_msg(conn,msg) != 0) break;
02213 }
02214 } while (msg);
02215
02216 if (sleep > 0) {
02217
02218 /* note that this implementations means that we sleep even
02219 * when we fail connection.. but time is very short, anyway
02220 */
02221 gwthread_sleep(sleep);
02222 /* gradually sleep longer and longer times until something starts to
02223 * happen - this of course reduces response time, but that's better than
02224 * extensive CPU usage when it is not used
02225 */
02226 sleep *= 2;
02227 if (sleep >= 2.0)
02228 sleep = 1.999999;
02229 }
02230 else {
02231 sleep = 0.0001;
02232 }
02233 }
02234 }
|
Here is the call graph for this function:

|
|
Definition at line 324 of file smsc_cimd2.c. Referenced by packet_add_address_parm(), packet_check_parameter(), and parm_valid_address(). 00325 {
00326 return isdigit(c) || c == '+' || c == '-';
00327 }
|
|
|
Definition at line 422 of file smsc_cimd2.c. References operation_can_send(), operation_find(), operations, and RESPONSE. 00423 {
00424 int i = operation_find(operation);
00425
00426 if (i >= 0)
00427 return operations[i].can_receive;
00428
00429 /* If we can send the request, then we can receive the response. */
00430 if (operation >= RESPONSE)
00431 return operation_can_send(operation - RESPONSE);
00432
00433 return 0;
00434 }
|
Here is the call graph for this function:

|
|
Definition at line 406 of file smsc_cimd2.c. References operation_can_receive(), operation_find(), operations, and RESPONSE. 00407 {
00408 int i = operation_find(operation);
00409
00410 if (i >= 0)
00411 return operations[i].can_send;
00412
00413 /* If we can receive the request, then we can send the response. */
00414 if (operation >= RESPONSE)
00415 return operation_can_receive(operation - RESPONSE);
00416
00417 return 0;
00418 }
|
Here is the call graph for this function:

|
|
Definition at line 371 of file smsc_cimd2.c. References operations. 00372 {
00373 int i;
00374
00375 for (i = 0; operations[i].name != NULL; i++) {
00376 if (operations[i].code == operation)
00377 return i;
00378 }
00379
00380 return -1;
00381 }
|
|
|
Definition at line 384 of file smsc_cimd2.c. References name, octstr_append_cstr(), octstr_create, operation_find(), operations, and RESPONSE. 00385 {
00386 int i;
00387
00388 i = operation_find(operation);
00389 if (i >= 0)
00390 return octstr_create(operations[i].name);
00391
00392 if (operation >= RESPONSE) {
00393 i = operation_find(operation - RESPONSE);
00394 if (i >= 0) {
00395 Octstr *name = octstr_create(operations[i].name);
00396 octstr_append_cstr(name, " response");
00397 return name;
00398 }
00399 }
00400
00401 /* Put the operation number here when we have octstr_format */
00402 return octstr_create("(unknown)");
00403 }
|
Here is the call graph for this function:

|
||||||||||||||||||||
|
Definition at line 1234 of file smsc_cimd2.c. References gw_assert, isphonedigit(), octstr_check_range(), octstr_len(), P_ADDRESS, packet_add_parm(), and SMSCConn. Referenced by packet_encode_message(). 01235 {
01236 gw_assert(octstr_check_range(value, 0, octstr_len(value), isphonedigit));
01237 packet_add_parm(packet, P_ADDRESS, parmno, value, conn);
01238 }
|
Here is the call graph for this function:

|
||||||||||||||||||||
|
Definition at line 1253 of file smsc_cimd2.c. References octstr_binary_to_hex(), octstr_destroy(), octstr_duplicate, P_HEX, packet_add_parm(), and SMSCConn. Referenced by packet_encode_message(). 01254 {
01255 value = octstr_duplicate(value);
01256 octstr_binary_to_hex(value, 1); /* 1 for uppercase hex, i.e. A .. F */
01257 packet_add_parm(packet, P_HEX, parmno, value, conn);
01258 octstr_destroy(value);
01259 }
|
Here is the call graph for this function:

|
||||||||||||||||||||
|
Definition at line 1262 of file smsc_cimd2.c. References gw_assert, octstr_create, octstr_destroy(), P_INT, packet_add_parm(), parm_in_range(), and SMSCConn. Referenced by packet_encode_message(). 01263 {
01264 char buf[128];
01265 Octstr *valuestr;
01266
01267 gw_assert(parm_in_range(parmno, value));
01268
01269 sprintf(buf, "%ld", value);
01270 valuestr = octstr_create(buf);
01271 packet_add_parm(packet, P_INT, parmno, valuestr, conn);
01272 octstr_destroy(valuestr);
01273 }
|
Here is the call graph for this function:

|
||||||||||||||||||||||||
|
Definition at line 1192 of file smsc_cimd2.c. References packet::data, gw_assert, smscconn::id, octstr_copy, octstr_destroy(), octstr_get_cstr, octstr_insert(), octstr_insert_data(), octstr_len(), parm_maxlen(), parm_name(), parm_type(), SMSCConn, TAB_str, and warning(). Referenced by packet_add_address_parm(), packet_add_hex_parm(), packet_add_int_parm(), packet_add_sms_parm(), packet_add_string_parm(), and packet_encode_message(). 01194 {
01195 char parmh[sizeof("tPPP:")];
01196 long position;
01197 long len;
01198 int copied = 0;
01199
01200 len = octstr_len(value);
01201
01202 gw_assert(packet != NULL);
01203 gw_assert(parm_type(parmno) == parmtype);
01204
01205 if (len > parm_maxlen(parmno)) {
01206 warning(0, "CIMD2[%s]: %s parameter too long, truncating from "
01207 "%ld to %ld characters",
01208 octstr_get_cstr(conn->id),
01209 parm_name(parmno),
01210 len,
01211 (long) parm_maxlen(parmno));
01212 value = octstr_copy(value, 0, parm_maxlen(parmno));
01213 copied = 1;
01214 }
01215
01216 /* There's a TAB and ETX at the end; insert it before those.
01217 * The new parameter will come with a new starting TAB. */
01218 position = octstr_len(packet->data) - 2;
01219
01220 sprintf(parmh, TAB_str "%03d:", parmno);
01221 octstr_insert_data(packet->data, position, parmh, strlen(parmh));
01222 octstr_insert(packet->data, value, position + strlen(parmh));
01223 if (copied)
01224 octstr_destroy(value);
01225 }
|
Here is the call graph for this function:

|
||||||||||||||||||||
|
Definition at line 1242 of file smsc_cimd2.c. References P_SMS, packet_add_parm(), and SMSCConn. Referenced by packet_encode_message(). 01243 {
01244 packet_add_parm(packet, P_SMS, parmno, value, conn);
01245 }
|
Here is the call graph for this function:

|
||||||||||||||||||||
|
Definition at line 1228 of file smsc_cimd2.c. References P_STRING, packet_add_parm(), and SMSCConn. Referenced by cimd2_login(), and packet_encode_message(). 01229 {
01230 packet_add_parm(packet, P_STRING, parmno, value, conn);
01231 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 846 of file smsc_cimd2.c. References packet::data, data, gw_assert, gw_isxdigit(), smscconn::id, octstr_check_range(), octstr_dump, octstr_get_cstr, octstr_len(), octstr_search_char(), packet_check_header(), packet_check_parameter(), SMSCConn, TAB, and warning(). Referenced by cimd2_get_packet(), and cimd2_receive_msg(). 00847 {
00848 int errors = 0;
00849 long pos, len, next;
00850 Octstr *data;
00851
00852 gw_assert(packet != NULL);
00853 data = packet->data;
00854
00855 if (octstr_search_char(data, 0, 0) >= 0) {
00856 /* CIMD2 spec does not allow NUL bytes in a packet */
00857 warning(0, "CIMD2[%s]: packet contains NULs",
00858 octstr_get_cstr(conn->id));
00859 errors++;
00860 }
00861
00862 /* Assume the packet starts with STX and ends with ETX,
00863 * because we parsed it that way in the first place. */
00864
00865 errors += (packet_check_header(packet,conn) < 0);
00866
00867 /* Parameters are separated by tabs. After the last parameter
00868 * there is a tab, an optional two-digit checksum, and the ETX.
00869 * Check each parameter in turn, by skipping from tab to tab.
00870 */
00871 len = octstr_len(data);
00872 /* Start at the first tab, wherever it is, so that we can still
00873 * check parameters if the header was weird. */
00874 pos = octstr_search_char(data, TAB, 0);
00875 for ( ; pos >= 0; pos = next) {
00876 next = octstr_search_char(data, TAB, pos + 1);
00877 if (next >= 0) {
00878 errors += (packet_check_parameter(packet, pos, next - pos, conn) < 0);
00879 } else {
00880 /* Check if the checksum has the right format. Don't
00881 * check the sum itself here, that will be done in a
00882 * separate call later. */
00883 /* There are two valid formats: TAB ETX (no checksum)
00884 * and TAB digit digit ETX. We already know the TAB
00885 * and the ETX are there. */
00886 if (!(octstr_len(data) - pos == 2 ||
00887 (octstr_len(data) - pos == 4 &&
00888 octstr_check_range(data, pos + 1, 2, gw_isxdigit)))) {
00889 warning(0, "CIMD2[%s]: packet checksum in wrong format",
00890 octstr_get_cstr(conn->id));
00891 errors++;
00892 }
00893 }
00894 }
00895
00896
00897 if (errors > 0) {
00898 octstr_dump(packet->data, 0);
00899 return -1;
00900 }
00901
00902 return 0;
00903 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 905 of file smsc_cimd2.c. References gw_assert, smscconn::id, name, octstr_destroy(), octstr_get_cstr, packet::operation, operation_can_receive(), operation_name(), SMSCConn, and warning(). 00906 {
00907 gw_assert(packet != NULL);
00908
00909 if (!operation_can_receive(packet->operation)) {
00910 Octstr *name = operation_name(packet->operation);
00911 warning(0, "CIMD2[%s]: SMSC sent us %s request",
00912 octstr_get_cstr(conn->id),
00913 octstr_get_cstr(name));
00914 octstr_destroy(name);
00915 }
00916 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 705 of file smsc_cimd2.c. References packet::data, data, gw_assert, gw_isdigit(), smscconn::id, octstr_check_range(), octstr_get_char(), octstr_get_cstr, octstr_len(), SMSCConn, and warning(). Referenced by packet_check(). 00706 {
00707 Octstr *data;
00708
00709 gw_assert(packet != NULL);
00710 data = packet->data;
00711
00712 /* The header must have a two-digit operation code, a colon,
00713 * and a three-digit sequence number, followed by a tab.
00714 * (CIMD2, 3.1) */
00715 if (octstr_len(data) < 8 ||
00716 !octstr_check_range(data, 1, 2, gw_isdigit) ||
00717 octstr_get_char(data, 3) != ':' ||
00718 !octstr_check_range(data, 4, 3, gw_isdigit) ||
00719 octstr_get_char(data, 7) != TAB) {
00720 warning(0, "CIMD2[%s]: packet header in wrong format",
00721 octstr_get_cstr(conn->id));
00722 return -1;
00723 }
00724
00725 return 0;
00726 }
|
Here is the call graph for this function:

|
||||||||||||||||||||
|
Definition at line 728 of file smsc_cimd2.c. References packet::data, data, gw_assert, gw_isdigit(), gw_isxdigit(), smscconn::id, isphonedigit(), octstr_check_range(), octstr_get_char(), octstr_get_cstr, octstr_parse_long(), P_ADDRESS, P_HEX, P_INT, P_SMS, P_STRING, P_TIME, parameters, parm_index(), SMSCConn, and warning(). Referenced by packet_check(). 00729 {
00730 Octstr *data;
00731 long parm;
00732 long dpos, dlen;
00733 int negative;
00734 long value;
00735 int i;
00736 int errors = 0;
00737
00738 gw_assert(packet != NULL);
00739 data = packet->data;
00740
00741 /* The parameter header should be TAB, followed by a three-digit
00742 * parameter number, a colon, and the data. We already know about
00743 * the tab. */
00744
00745 if (len < 5 ||
00746 !octstr_check_range(data, pos + 1, 3, gw_isdigit) ||
00747 octstr_get_char(data, pos + 4) != ':') {
00748 warning(0, "CIMD2[%s]: parameter at offset %ld in wrong format",
00749 octstr_get_cstr(conn->id),
00750 pos);
00751 errors++;
00752 }
00753
00754 /* If we can't parse a parameter number, there's nothing more
00755 * that we can check. */
00756 dpos = octstr_parse_long(&parm, data, pos + 1, 10);
00757 if (dpos < 0)
00758 return -1;
00759 if (octstr_get_char(data, dpos) == ':')
00760 dpos++;
00761 dlen = len - (dpos - pos);
00762 /* dlen can not go negative because octstr_parse_long must have
00763 * been stopped by the TAB at the end of the parameter data. */
00764 gw_assert(dlen >= 0);
00765
00766 i = parm_index(parm);
00767
00768 if (i < 0) {
00769 warning(0, "CIMD2[%s]: packet contains unknown parameter %ld",
00770 octstr_get_cstr(conn->id),
00771 parm);
00772 return -1;
00773 }
00774
00775 if (dlen > parameters[i].maxlen) {
00776 warning(0, "CIMD2[%s]: packet has '%s' parameter with length %ld, spec says max %d",
00777 octstr_get_cstr(conn->id),
00778 parameters[i].name, len, parameters[i].maxlen);
00779 errors++;
00780 }
00781
00782 switch (parameters[i].type) {
00783 case P_INT:
00784 /* Allow a leading - */
00785 negative = (octstr_get_char(data, dpos) == '-');
00786 if (!octstr_check_range(data, dpos + negative,
00787 dlen - negative, gw_isdigit)) {
00788 warning(0, "CIMD2[%s]: packet has '%s' parameter with non-integer contents",
00789 octstr_get_cstr(conn->id),
00790 parameters[i].name);
00791 errors++;
00792 }
00793 if (octstr_parse_long(&value, data, dpos, 10) >= 0 &&
00794 (value < parameters[i].minval || value > parameters[i].maxval)) {
00795 warning(0, "CIMD2[%s]: packet has '%s' parameter out of range (value %ld, min %d, max %d)",
00796 octstr_get_cstr(conn->id),
00797 parameters[i].name, value,
00798 parameters[i].minval, parameters[i].maxval);
00799 errors++;
00800 }
00801 break;
00802 case P_TIME:
00803 if (!octstr_check_range(data, dpos, dlen, gw_isdigit)) {
00804 warning(0, "CIMD2[%s]: packet has '%s' parameter with non-digit contents",
00805 octstr_get_cstr(conn->id),
00806 parameters[i].name);
00807 errors++;
00808 }
00809 break;
00810 case P_ADDRESS:
00811 if (!octstr_check_range(data, dpos, dlen, isphonedigit)) {
00812 warning(0, "CIMD2[%s]: packet has '%s' parameter with non phone number contents",
00813 octstr_get_cstr(conn->id),
00814 parameters[i].name);
00815 errors++;
00816 }
00817 break;
00818 case P_HEX:
00819 if (!octstr_check_range(data, dpos, dlen, gw_isxdigit)) {
00820 warning(0, "CIMD2[%s]: packet has '%s' parameter with non-hex contents",
00821 octstr_get_cstr(conn->id),
00822 parameters[i].name);
00823 errors++;
00824 }
00825 if (dlen % 2 != 0) {
00826 warning(0, "CIMD2[%s]: packet has odd-length '%s' parameter",
00827 octstr_get_cstr(conn->id),
00828 parameters[i].name);
00829 errors++;
00830 }
00831 break;
00832 case P_SMS:
00833 case P_STRING: /* nothing to check */
00834 break;
00835 }
00836
00837 if (errors > 0)
00838 return -1;
00839 return 0;
00840 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 1177 of file smsc_cimd2.c. References packet::data, ETX_str, octstr_create, packet::operation, packet::seq, STX_str, and TAB_str. 01178 {
01179 struct packet *packet;
01180 char minpacket[sizeof("sOO:SSSte")];
01181
01182 packet = gw_malloc(sizeof(*packet));
01183 packet->operation = operation;
01184 packet->seq = seq;
01185 sprintf(minpacket, STX_str "%02d:%03d" TAB_str ETX_str, operation, seq);
01186 packet->data = octstr_create(minpacket);
01187
01188 return packet;
01189 }
|
|
|
Definition at line 521 of file smsc_cimd2.c. References packet::data, and octstr_destroy(). 00522 {
00523 if (packet != NULL) {
00524 octstr_destroy(packet->data);
00525 gw_free(packet);
00526 }
00527 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 980 of file smsc_cimd2.c. References cimd2_errors, code, error(), smscconn::id, octstr_create, octstr_destroy(), octstr_get_cstr, packet::operation, operation_name(), P_ERROR_CODE, P_ERROR_TEXT, packet_get_int_parm(), packet_get_string_parm(), SMSCConn, and text. Referenced by cimd2_request(). 00981 {
00982 int code;
00983 Octstr *text = NULL;
00984 Octstr *opname = NULL;
00985
00986 code = packet_get_int_parm(packet, P_ERROR_CODE);
00987 text = packet_get_string_parm(packet, P_ERROR_TEXT);
00988
00989 if (code <= 0) {
00990 octstr_destroy(text);
00991 return 0;
00992 }
00993
00994 if (text == NULL) {
00995 /* No error text. Try to find it in the table. */
00996 int i;
00997 for (i = 0; cimd2_errors[i].text != NULL; i++) {
00998 if (cimd2_errors[i].code == code) {
00999 text = octstr_create(cimd2_errors[i].text);
01000 break;
01001 }
01002 }
01003 }
01004
01005 if (text == NULL) {
01006 /* Still no error text. Make one up. */
01007 text = octstr_create("Unknown error");
01008 }
01009
01010 opname = operation_name(packet->operation);
01011 error(0, "CIMD2[%s]: %s contained error message:",
01012 octstr_get_cstr(conn->id),
01013 octstr_get_cstr(opname));
01014 error(0, "code %03d: %s", code, octstr_get_cstr(text));
01015 octstr_destroy(opname);
01016 octstr_destroy(text);
01017 return code;
01018 }
|
Here is the call graph for this function:

|
||||||||||||||||
|
Definition at line 1320 of file smsc_cimd2.c. References smscconn::alt_dcs, BOGUS_SEQUENCE, charset_gsm_truncate(), charset_utf8_to_gsm(), convert_gsm_to_cimd2(), smscconn::data, DC_7BIT, DC_8BIT, DLR_IS_SUCCESS_OR_FAIL, fields_to_dcs(), gw_assert, smscconn::id, privdata::no_dlr, octstr_compare(), octstr_copy, octstr_create, octstr_destroy(), octstr_duplicate, octstr_get_cstr, octstr_imm(), octstr_len(), octstr_ncompare(), octstr_truncate(), P_ALPHANUMERIC_ORIGINATING_ADDRESS, P_DATA_CODING_SCHEME, P_DESTINATION_ADDRESS, P_INT, P_MORE_MESSAGES_TO_SEND, P_ORIGINATING_ADDRESS, P_PROTOCOL_IDENTIFIER, P_REPLY_PATH, P_STATUS_REPORT_REQUEST, P_TARIFF_CLASS, P_USER_DATA, P_USER_DATA_BINARY, P_USER_DATA_HEADER, P_VALIDITY_PERIOD_RELATIVE, packet_add_address_parm(), packet_add_hex_parm(), packet_add_int_parm(), packet_add_parm(), packet_add_sms_parm(), packet_add_string_parm(), packet_create(), parm_valid_address(), PrivData, sms, SMSCConn, SUBMIT_MESSAGE, text, and warning(). 01321 {
01322 struct packet *packet;
01323 PrivData *pdata = conn->data;
01324 Octstr *text;
01325 int spaceleft;
01326 long truncated;
01327 int dcs = 0;
01328 int setvalidity = 0;
01329
01330 gw_assert(msg != NULL);
01331 gw_assert(msg->type == sms);
01332 gw_assert(msg->sms.receiver != NULL);
01333
01334 dcs = fields_to_dcs(msg, (msg->sms.alt_dcs != -1 ?
01335 msg->sms.alt_dcs : conn->alt_dcs));
01336 if (msg->sms.sender == NULL)
01337 msg->sms.sender = octstr_create("");
01338
01339 if (!parm_valid_address(msg->sms.receiver)) {
01340 warning(0, "CIMD2[%s]: non-digits in destination phone number '%s', discarded",
01341 octstr_get_cstr(conn->id),
01342 octstr_get_cstr(msg->sms.receiver));
01343 return NULL;
01344 }
01345
01346 packet = packet_create(SUBMIT_MESSAGE, BOGUS_SEQUENCE);
01347
01348 packet_add_address_parm(packet, P_DESTINATION_ADDRESS, msg->sms.receiver, conn);
01349
01350 /* CIMD2 interprets the originating address as a sub-address to
01351 * our connection number (so if the connection is "400" and we
01352 * fill in "600" as the sender number, the user sees "400600").
01353 * Since we have no way to ask what this number is, it has to
01354 * be configured. */
01355
01356 /* Quick and dirty check to see if we are using alphanumeric sender */
01357 if (parm_valid_address(msg->sms.sender)) {
01358 /* We are not, so send in the usual way */
01359 /* Speed up the default case */
01360 if (octstr_len(sender_prefix) == 0) {
01361 packet_add_address_parm(packet, P_ORIGINATING_ADDRESS,msg->sms.sender, conn);
01362 }
01363 else if (octstr_compare(sender_prefix, octstr_imm("never")) != 0) {
01364 if (octstr_ncompare(sender_prefix, msg->sms.sender,
01365 octstr_len(sender_prefix)) == 0) {
01366 Octstr *sender;
01367 sender = octstr_copy(msg->sms.sender,
01368 octstr_len(sender_prefix), octstr_len(msg->sms.sender));
01369 packet_add_address_parm(packet, P_ORIGINATING_ADDRESS, sender, conn);
01370 octstr_destroy(sender);
01371 } else {
01372 warning(0, "CIMD2[%s]: Sending message with originating address <%s>, "
01373 "which does not start with the sender-prefix.",
01374 octstr_get_cstr(conn->id),
01375 octstr_get_cstr(msg->sms.sender));
01376 }
01377 }
01378 }
01379 else {
01380 /* The test above to check if sender was all digits failed, so assume we want alphanumeric sender */
01381 packet_add_string_parm(packet, P_ALPHANUMERIC_ORIGINATING_ADDRESS,msg->sms.sender, conn);
01382 }
01383
01384 /* Add the validity period if necessary. This sets the relative validity
01385 * period as this is the description of the "validity" parameter of the
01386 * sendsms interface.
01387 *
01388 * Convert from minutes to GSM 03.40 specification (section 9.2.3.12).
01389 * 0-143 = 0 to 12 hours in 5 minute increments.
01390 * 144-167 = 12hrs30min to 24hrs in 30 minute increments.
01391 * 168-196 = 2days to 30days in 1 day increments.
01392 * 197-255 = 5weeks to 63weeks in 1 week increments.
01393 *
01394 * This code was copied from smsc_at2.c.
01395 */
01396 if (msg->sms.validity >= 0) {
01397 if (msg->sms.validity > 635040)
01398 setvalidity = 255;
01399 if (msg->sms.validity >= 50400 && msg->sms.validity <= 635040)
01400 setvalidity = (msg->sms.validity - 1) / 7 / 24 / 60 + 192 + 1;
01401 if (msg->sms.validity > 43200 && msg->sms.validity < 50400)
01402 setvalidity = 197;
01403 if (msg->sms.validity >= 2880 && msg->sms.validity <= 43200)
01404 setvalidity = (msg->sms.validity - 1) / 24 / 60 + 166 + 1;
01405 if (msg->sms.validity > 1440 && msg->sms.validity < 2880)
01406 setvalidity = 168;
01407 if (msg->sms.validity >= 750 && msg->sms.validity <= 1440)
01408 setvalidity = (msg->sms.validity - 720 - 1) / 30 + 143 + 1;
01409 if (msg->sms.validity > 720 && msg->sms.validity < 750)
01410 setvalidity = 144;
01411 if (msg->sms.validity >= 5 && msg->sms.validity <= 720)
01412 setvalidity = (msg->sms.validity - 1) / 5 - 1 + 1;
01413 if (msg->sms.validity < 5)
01414 setvalidity = 0;
01415
01416 packet_add_int_parm(packet, P_VALIDITY_PERIOD_RELATIVE, setvalidity, conn);
01417 }
01418
01419 /* Explicitly ask not to get status reports.
01420 * If we do not do this, the server's default might be to
01421 * send status reports in some cases, and we don't do anything
01422 * with those reports anyway. */
01423 /* ask for the delivery reports if needed*/
01424
01425 if (!pdata->no_dlr)
01426 if (DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask))
01427 packet_add_int_parm(packet, P_STATUS_REPORT_REQUEST, 14, conn);
01428 else
01429 packet_add_int_parm(packet, P_STATUS_REPORT_REQUEST, 0, conn);
01430 else if( pdata->no_dlr && DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask))
01431 warning(0, "CIMD2[%s]: dlr request make no sense while no-dlr set to true",
01432 octstr_get_cstr(conn->id));
01433
01434 /* Turn off reply path as default.
01435 * This avoids phones automatically asking for a reply
01436 */
01437 if (msg->sms.rpi > 0)
01438 packet_add_int_parm(packet, P_REPLY_PATH, 1, conn);
01439 else
01440 packet_add_int_parm(packet, P_REPLY_PATH, 0, conn);
01441
01442 /* Use binfo to set the tariff class */
01443 if (octstr_len(msg->sms.binfo))
01444 packet_add_parm(packet, P_INT, P_TARIFF_CLASS, msg->sms.binfo, conn);
01445
01446 /* Set the protocol identifier if requested */
01447 if (msg->sms.pid > 0)
01448 packet_add_int_parm(packet, P_PROTOCOL_IDENTIFIER, msg->sms.pid, conn);
01449
01450 /* If there are more messages to the same destination, then set the
01451 * More Messages to Send flag. This allow faster delivery of many messages
01452 * to the same destination
01453 */
01454 if (msg->sms.msg_left > 0)
01455 packet_add_int_parm(packet, P_MORE_MESSAGES_TO_SEND, 1, conn);
01456 else
01457 packet_add_int_parm(packet, P_MORE_MESSAGES_TO_SEND, 0, conn);
01458
01459 truncated = 0;
01460
01461 spaceleft = 140;
01462 if (octstr_len(msg->sms.udhdata)) {
01463 /* udhdata will be truncated and warned about if
01464 * it does not fit. */
01465 packet_add_hex_parm(packet, P_USER_DATA_HEADER, msg->sms.udhdata, conn);
01466 }
01467 if (msg->sms.coding == DC_7BIT || msg->sms.coding == DC_UNDEF)
01468 spaceleft = spaceleft * 8 / 7;
01469 if (spaceleft < 0)
01470 spaceleft = 0;
01471
01472 text = octstr_duplicate(msg->sms.msgdata);
01473
01474 if (octstr_len(text) > 0 && spaceleft == 0) {
01475 warning(0, "CIMD2[%s]: message filled up with UDH, no room for message text",
01476 octstr_get_cstr(conn->id));
01477 } else if (msg->sms.coding == DC_8BIT || msg->sms.coding == DC_UCS2) {
01478 if (octstr_len(text) > spaceleft) {
01479 truncated = octstr_len(text) - spaceleft;
01480 octstr_truncate(text, spaceleft);
01481 }
01482 packet_add_hex_parm(packet, P_USER_DATA_BINARY, text, conn);
01483 } else {
01484 /* Going from latin1 to GSM to CIMD2 may seem like a
01485 * detour, but it's the only way to get all the escape
01486 * codes right. */
01487 charset_utf8_to_gsm(text);
01488 truncated = charset_gsm_truncate(text, spaceleft);
01489 convert_gsm_to_cimd2(text);
01490 packet_add_sms_parm(packet, P_USER_DATA, text, conn);
01491 }
01492
01493 if (dcs != 0)
01494 packet_add_int_parm(packet, P_DATA_CODING_SCHEME, dcs, conn);
01495
01496 if (truncated > 0) {
01497 warning(0, "CIMD2[%s]: truncating message text to fit in %d characters.",
01498 octstr_get_cstr(conn->id),
01499 spaceleft);
01500 }
01501
01502 octstr_destroy(text);
01503 return packet;
01504 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 533 of file smsc_cimd2.c. References ETX, ETX_str, smscconn::id, octstr_append_cstr(), octstr_copy, octstr_delete(), octstr_get_cstr, octstr_len(), octstr_search_char(), packet_parse(), SMSCConn, STX, and warning(). 00534 {
00535 int stx, etx;
00536 Octstr *packet;
00537
00538 /* Find STX, and delete everything up to it */
00539 stx = octstr_search_char(in, STX, 0);
00540 if (stx < 0) {
00541 octstr_delete(in, 0, octstr_len(in));
00542 return NULL;
00543 } else {
00544 octstr_delete(in, 0, stx);
00545 }
00546
00547 /* STX is now in position 0. Find ETX. */
00548 etx = octstr_search_char(in, ETX, 1);
00549 if (etx < 0)
00550 return NULL;
00551
00552 /* What shall we do with STX data... STX data... ETX?
00553 * Either skip to the second STX, or assume an ETX marker before
00554 * the STX. Doing the latter has a chance of succeeding, and
00555 * will at least allow good logging of the error. */
00556 stx = octstr_search_char(in, STX, 1);
00557 if (stx >= 0 && stx < etx) {
00558 warning(0, "CIMD2[%s]: packet without end marker",
00559 octstr_get_cstr(conn->id));
00560 packet = octstr_copy(in, 0, stx);
00561 octstr_delete(in, 0, stx);
00562 octstr_append_cstr(packet, ETX_str);
00563 } else {
00564 /* Normal case. Copy packet, and cut it from the source. */
00565 packet = octstr_copy(in, 0, etx + 1);
00566 octstr_delete(in, 0, etx + 1);
00567 }
00568
00569 return packet_parse(packet);
00570 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 653 of file smsc_cimd2.c. References gw_assert, P_ADDRESS, packet_get_parm(), and parm_type(). Referenced by cimd2_accept_message(). 00654 {
00655 /* Our code should never even try a bad parameter access. */
00656 gw_assert(parm_type(parmno) == P_ADDRESS);
00657
00658 return packet_get_parm(packet, parmno);
00659 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 681 of file smsc_cimd2.c. References error(), gw_assert, octstr_destroy(), octstr_hex_to_binary(), P_HEX, packet_get_parm(), and parm_type(). Referenced by cimd2_accept_message(). 00682 {
00683 Octstr *value = NULL;
00684
00685 /* Our code should never even try a bad parameter access. */
00686 gw_assert(parm_type(parmno) == P_HEX);
00687
00688 value = packet_get_parm(packet, parmno);
00689 if (!value)
00690 goto error;
00691
00692 if (octstr_hex_to_binary(value) < 0)
00693 goto error;
00694
00695 return value;
00696
00697 error:
00698 octstr_destroy(value);
00699 return NULL;
00700 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 616 of file smsc_cimd2.c. References error(), gw_assert, octstr_destroy(), octstr_parse_long(), P_INT, packet_get_parm(), and parm_type(). Referenced by cimd2_accept_message(), and packet_display_error(). 00617 {
00618 Octstr *valuestr = NULL;
00619 long value;
00620
00621 /* Our code should never even try a bad parameter access. */
00622 gw_assert(parm_type(parmno) == P_INT);
00623
00624 valuestr = packet_get_parm(packet, parmno);
00625 if (!valuestr)
00626 goto error;
00627
00628 if (octstr_parse_long(&value, valuestr, 0, 10) < 0)
00629 goto error;
00630
00631 octstr_destroy(valuestr);
00632 return value;
00633
00634 error:
00635 octstr_destroy(valuestr);
00636 return INT_MIN;
00637 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 579 of file smsc_cimd2.c. References packet::data, gw_assert, number, octstr_copy, octstr_parse_long(), octstr_search_char(), and TAB. Referenced by cimd2_accept_delivery_report_message(), cimd2_get_packet(), packet_get_address_parm(), packet_get_hex_parm(), packet_get_int_parm(), packet_get_sms_parm(), and packet_get_string_parm(). 00580 {
00581 long pos, next;
00582 long valuepos;
00583 long number;
00584
00585 gw_assert(packet != NULL);
00586 pos = octstr_search_char(packet->data, TAB, 0);
00587 if (pos < 0)
00588 return NULL; /* Bad packet, nothing we can do */
00589
00590 /* Parameters have a tab on each end. If we don't find the
00591 * closing tab, we're at the checksum, so we stop. */
00592 for ( ;
00593 (next = octstr_search_char(packet->data, TAB, pos + 1)) >= 0;
00594 pos = next) {
00595 if (octstr_parse_long(&number, packet->data, pos + 1, 10) < 0)
00596 continue;
00597 if (number != parmno)
00598 continue;
00599 valuepos = octstr_search_char(packet->data, ':', pos + 1);
00600 if (valuepos < 0)
00601 continue; /* badly formatted parm */
00602 valuepos++; /* skip the ':' */
00603
00604 /* Found the right parameter */
00605 return octstr_copy(packet->data, valuepos, next - valuepos);
00606 }
00607
00608 return NULL;
00609 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 665 of file smsc_cimd2.c. References gw_assert, P_SMS, packet_get_parm(), and parm_type(). Referenced by cimd2_accept_message(). 00666 {
00667 /* Our code should never even try a bad parameter access. */
00668 gw_assert(parm_type(parmno) == P_SMS);
00669
00670 return packet_get_parm(packet, parmno);
00671 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 642 of file smsc_cimd2.c. References gw_assert, P_STRING, packet_get_parm(), and parm_type(). Referenced by packet_display_error(). 00643 {
00644 /* Our code should never even try a bad parameter access. */
00645 gw_assert(parm_type(parmno) == P_STRING);
00646
00647 return packet_get_parm(packet, parmno);
00648 }
|
Here is the call graph for this function:

|
|
Definition at line 507 of file smsc_cimd2.c. References packet::data, and packet_parse_header(). 00508 {
00509 struct packet *packet;
00510
00511 packet = gw_malloc(sizeof(*packet));
00512 packet->data = packet_data;
00513
00514 /* Fill in packet->operation and packet->seq */
00515 packet_parse_header(packet);
00516
00517 return packet;
00518 }
|
Here is the call graph for this function:

|
|
Definition at line 480 of file smsc_cimd2.c. References packet::data, number, octstr_get_char(), octstr_parse_long(), packet::operation, and packet::seq. 00481 {
00482 int pos;
00483 long number;
00484
00485 /* Set default values, in case we can't parse the fields */
00486 packet->operation = -1;
00487 packet->seq = -1;
00488
00489 pos = octstr_parse_long(&number, packet->data, 1, 10);
00490 if (pos < 0)
00491 return;
00492 packet->operation = number;
00493
00494 if (octstr_get_char(packet->data, pos++) != ':')
00495 return;
00496
00497 pos = octstr_parse_long(&number, packet->data, pos, 10);
00498 if (pos < 0)
00499 return;
00500 packet->seq = number;
00501 }
|
Here is the call graph for this function:

|
|
Definition at line 1275 of file smsc_cimd2.c. References packet::data, data, gw_assert, octstr_delete(), octstr_get_char(), octstr_insert_data(), octstr_len(), and TAB. Referenced by cimd2_request(), and cimd2_send_response(). 01276 {
01277 Octstr *data;
01278 int checksum;
01279 long pos, len;
01280 char buf[16];
01281
01282 gw_assert(packet != NULL);
01283
01284 data = packet->data;
01285 if (octstr_get_char(data, octstr_len(data) - 2) != TAB) {
01286 /* Packet already has checksum; kill it. */
01287 octstr_delete(data, octstr_len(data) - 3, 2);
01288 }
01289
01290 gw_assert(octstr_get_char(data, octstr_len(data) - 2) == TAB);
01291
01292 /* Sum all the way up to the last TAB */
01293 checksum = 0;
01294 for (pos = 0, len = octstr_len(data); pos < len - 1; pos++) {
01295 checksum += octstr_get_char(data, pos);
01296 checksum &= 0xff;
01297 }
01298
01299 sprintf(buf, "%02X", checksum);
01300 octstr_insert_data(data, len - 1, buf, 2);
01301 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 1511 of file smsc_cimd2.c. References gw_assert, packet::operation, packet_set_sequence(), PrivData, and privdata::send_seq. 01512 {
01513 gw_assert(pdata != NULL);
01514 /* LOGIN packets always have sequence number 001 */
01515 if (packet->operation == LOGIN)
01516 pdata->send_seq = 1;
01517 /* Send sequence numbers are always odd, receiving are always even */
01518 gw_assert(pdata->send_seq % 2 == 1);
01519
01520 packet_set_sequence(packet, pdata->send_seq);
01521 pdata->send_seq += 2;
01522 if (pdata->send_seq > 256)
01523 pdata->send_seq = 1;
01524 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 1303 of file smsc_cimd2.c. References packet::data, gw_assert, octstr_set_char(), and packet::seq. 01304 {
01305 char buf[16];
01306
01307 gw_assert(packet != NULL);
01308 gw_assert(seq >= 0);
01309 gw_assert(seq < 256);
01310
01311 sprintf(buf, "%03d", seq);
01312
01313 /* Start at 4 to skip the <STX> ZZ: part of the header. */
01314 octstr_set_char(packet->data, 4, buf[0]);
01315 octstr_set_char(packet->data, 5, buf[1]);
01316 octstr_set_char(packet->data, 6, buf[2]);
01317 packet->seq = seq;
01318 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 310 of file smsc_cimd2.c. References parameters, and parm_index(). Referenced by packet_add_int_parm(). 00311 {
00312 int i;
00313
00314 i = parm_index(parmno);
00315
00316 if (i < 0)
00317 return -1;
00318
00319 return (value >= parameters[i].minval && value <= parameters[i].maxval);
00320 }
|
Here is the call graph for this function:

|
|
Definition at line 260 of file smsc_cimd2.c. References parameters. Referenced by packet_check_parameter(), parm_in_range(), parm_maxlen(), parm_name(), and parm_type(). 00261 {
00262 int i;
00263
00264 for (i = 0; parameters[i].name != NULL; i++) {
00265 if (parameters[i].number == parmno)
00266 return i;
00267 }
00268
00269 return -1;
00270 }
|
|
|
Definition at line 287 of file smsc_cimd2.c. References parameters, and parm_index(). Referenced by packet_add_parm(), and smsc_cimd2_create(). 00288 {
00289 int i = parm_index(parmno);
00290
00291 if (i < 0)
00292 return -1;
00293
00294 return parameters[i].maxlen;
00295 }
|
Here is the call graph for this function:

|
|
Definition at line 297 of file smsc_cimd2.c. References parameters, and parm_index(). Referenced by packet_add_parm(). 00298 {
00299 int i = parm_index(parmno);
00300
00301 if (i < 0)
00302 return NULL;
00303
00304 return parameters[i].name;
00305 }
|
Here is the call graph for this function:

|
|
Definition at line 274 of file smsc_cimd2.c. References parameters, and parm_index(). Referenced by packet_add_parm(), packet_get_address_parm(), packet_get_hex_parm(), packet_get_int_parm(), packet_get_sms_parm(), and packet_get_string_parm(). 00275 {
00276 int i = parm_index(parmno);
00277
00278 if (i < 0)
00279 return -1;
00280
00281 return parameters[i].type;
00282 }
|
Here is the call graph for this function:

|
|
Definition at line 329 of file smsc_cimd2.c. References isphonedigit(), octstr_check_range(), and octstr_len(). 00330 {
00331 return octstr_check_range(value, 0, octstr_len(value), isphonedigit);
00332 }
|
Here is the call graph for this function:

|
|
Definition at line 2137 of file smsc_cimd2.c. References cimd2_close_socket(), cimd2_receive_msg(), smscconn::data, smscconn::flow_mutex, smscconn::id, msg_destroy(), mutex_lock, mutex_unlock, octstr_duplicate, PrivData, SMSCConn, and smscconn::status. 02138 {
02139 PrivData *pdata = conn->data;
02140 int ret;
02141 Msg *newmsg = NULL;
02142
02143 ret = cimd2_receive_msg(conn, &newmsg);
02144 if (ret == 1) {
02145 /* if any smsc_id available, use it */
02146 newmsg->sms.smsc_id = octstr_duplicate(conn->id);
02147 return newmsg;
02148 }
02149 else if (ret == 0) { /* no message, just retry... */
02150 return NULL;
02151 }
02152 /* error. reconnect. */
02153 msg_destroy(newmsg);
02154 mutex_lock(conn->flow_mutex);
02155 cimd2_close_socket(pdata);
02156 conn->status = SMSCCONN_DISCONNECTED;
02157 mutex_unlock(conn->flow_mutex);
02158 return NULL;
02159 }
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 2319 of file smsc_cimd2.c. References cfg_get, cfg_get_bool(), cfg_get_integer(), cimd2_destroy(), privdata::conn, smscconn::data, debug(), error(), gwlist_add_producer(), gwlist_create, gwthread_create, gwthread_join(), gwthread_wakeup(), privdata::host, smscconn::id, privdata::inbuffer, privdata::io_thread, io_thread(), smscconn::is_stopped, privdata::keepalive, maxlen, privdata::my_number, smscconn::name, privdata::next_ping, privdata::no_dlr, octstr_create, octstr_format(), octstr_get_cstr, octstr_imm(), octstr_len(), octstr_truncate(), ok, privdata::our_port, privdata::outgoing_queue, P_PASSWORD, P_USER_IDENTITY, parm_maxlen(), privdata::password, privdata::port, PrivData, smscconn::queued, privdata::quitting, privdata::receive_seq, privdata::received, smscconn::send_msg, privdata::send_seq, smscconn::shutdown, SMSCConn, privdata::socket, smscconn::start_conn, smscconn::stop_conn, privdata::stopped, privdata::username, and warning(). Referenced by smscconn_create(). 02320 {
02321 PrivData *pdata;
02322 int ok;
02323 int maxlen;
02324
02325 pdata = gw_malloc(sizeof(PrivData));
02326 conn->data = pdata;
02327 pdata->conn = conn;
02328
02329 pdata->no_dlr = 0;
02330 pdata->quitting = 0;
02331 pdata->socket = -1;
02332 pdata->received = gwlist_create();
02333 pdata->inbuffer = octstr_create("");
02334 pdata->send_seq = 1;
02335 pdata->receive_seq = 0;
02336 pdata->outgoing_queue = gwlist_create();
02337 pdata->stopped = gwlist_create();
02338 gwlist_add_producer(pdata->outgoing_queue);
02339
02340 if (conn->is_stopped)
02341 gwlist_add_producer(pdata->stopped);
02342
02343 pdata->host = cfg_get(grp, octstr_imm("host"));
02344 if (cfg_get_integer(&(pdata->port), grp, octstr_imm("port")) == -1)
02345 pdata->port = 0;
02346 if (cfg_get_integer(&(pdata->our_port), grp, octstr_imm("our-port")) == -1)
02347 pdata->our_port = 0;
02348 pdata->username = cfg_get(grp, octstr_imm("smsc-username"));
02349 pdata->password = cfg_get(grp, octstr_imm("smsc-password"));
02350 pdata->my_number = cfg_get(grp, octstr_imm("my-number"));
02351 if (cfg_get_integer(&(pdata->keepalive), grp,octstr_imm("keepalive")) == -1)
02352 pdata->keepalive = 0;
02353
02354 cfg_get_bool(&pdata->no_dlr, grp, octstr_imm("no-dlr"));
02355
02356 /* Check that config is OK */
02357 ok = 1;
02358 if (pdata->host == NULL) {
02359 error(0,"CIMD2[%s]: Configuration file doesn't specify host",
02360 octstr_get_cstr(conn->id));
02361 ok = 0;
02362 }
02363 if (pdata->port == 0) {
02364 error(0,"CIMD2[%s]: Configuration file doesn't specify port",
02365 octstr_get_cstr(conn->id));
02366 ok = 0;
02367 }
02368 if (pdata->username == NULL) {
02369 error(0, "CIMD2[%s]: Configuration file doesn't specify username.",
02370 octstr_get_cstr(conn->id));
02371 ok = 0;
02372 }
02373 if (pdata->password == NULL) {
02374 error(0, "CIMD2[%s]: Configuration file doesn't specify password.",
02375 octstr_get_cstr(conn->id));
02376 ok = 0;
02377 }
02378
02379 if (!ok) {
02380 cimd2_destroy(pdata);
02381 return -1;
02382 }
02383
02384 conn->name = octstr_format("CIMD2:%s:%d:%s",
02385 octstr_get_cstr(pdata->host),
02386 pdata->port,
02387 octstr_get_cstr(pdata->username));
02388
02389
02390 if (pdata->keepalive > 0) {
02391 debug("bb.sms.cimd2", 0, "CIMD2[%s]: Keepalive set to %ld seconds",
02392 octstr_get_cstr(conn->id),
02393 pdata->keepalive);
02394 pdata->next_ping = time(NULL) + pdata->keepalive;
02395 }
02396
02397 maxlen = parm_maxlen(P_USER_IDENTITY);
02398 if (octstr_len(pdata->username) > maxlen) {
02399 octstr_truncate(pdata->username, maxlen);
02400 warning(0, "CIMD2[%s]: Truncating username to %d chars",
02401 octstr_get_cstr(conn->id),
02402 maxlen);
02403 }
02404
02405 maxlen = parm_maxlen(P_PASSWORD);
02406 if (octstr_len(pdata->password) > maxlen) {
02407 octstr_truncate(pdata->password, maxlen);
02408 warning(0, "CIMD2[%s]: Truncating password to %d chars",
02409 octstr_get_cstr(conn->id),
02410 maxlen);
02411 }
02412
02413 pdata->io_thread = gwthread_create(io_thread, conn);
02414
02415 if (pdata->io_thread == -1) {
02416
02417 error(0,"CIMD2[%s]: Couldn't start I/O thread.",
02418 octstr_get_cstr(conn->id));
02419 pdata->quitting = 1;
02420 gwthread_wakeup(pdata->io_thread);
02421 gwthread_join(pdata->io_thread);
02422 cimd2_destroy(pdata);
02423 return -1;
02424 }
02425
02426 conn->send_msg = cimd2_add_msg_cb;
02427 conn->shutdown = cimd2_shutdown_cb;
02428 conn->queued = cimd2_queued_cb;
02429 conn->start_conn = cimd2_start_cb;
02430 conn->stop_conn = cimd2_stop_cb;
02431
02432 return 0;
02433 }
|
Here is the call graph for this function:

|
|
Definition at line 348 of file smsc_cimd2.c. |
|
|
Definition at line 347 of file smsc_cimd2.c. |
|
|
Definition at line 1025 of file smsc_cimd2.c. Referenced by convert_cimd2_to_gsm(), and convert_gsm_to_cimd2(). |
|
|
Definition at line 1025 of file smsc_cimd2.c. Referenced by convert_cimd2_to_gsm(), and convert_gsm_to_cimd2(). |
|
|
Referenced by packet_display_error(). |
|
|
Referenced by convert_cimd2_to_gsm(), and convert_gsm_to_cimd2(). |
|
|
|
Definition at line 1026 of file smsc_cimd2.c. Referenced by charset_gsm_truncate(), and convert_cimd2_to_gsm(). |
|
|
Definition at line 214 of file smsc_cimd2.c. Referenced by eat_int_parm(), octstr_set_bits(), and smsc_cimd2_create(). |
|
|
Definition at line 216 of file smsc_cimd2.c. |
|
|
Definition at line 216 of file smsc_cimd2.c. |
|
|
|
|
Referenced by operation_can_receive(), operation_can_send(), operation_find(), and operation_name(). |
|
|
Referenced by packet_check_parameter(), parm_in_range(), parm_index(), parm_maxlen(), parm_name(), and parm_type(). |
|
|