00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080 #include <ctype.h>
00081 #include <time.h>
00082 #include <errno.h>
00083 #include <limits.h>
00084 #include <string.h>
00085
00086 #include <unistd.h>
00087
00088 #include "gwlib/gwlib.h"
00089 #include "smscconn.h"
00090 #include "smscconn_p.h"
00091 #include "bb_smscconn_cb.h"
00092
00093 #include "shared.h"
00094 #include "sms.h"
00095 #include "dlr.h"
00096
00097
00098 typedef struct privdata {
00099 Octstr *username;
00100 Octstr *password;
00101 Octstr *host;
00102 long port;
00103 long our_port;
00104 long keepalive;
00105 Octstr *my_number;
00106 int no_dlr;
00107
00108 int socket;
00109 int send_seq;
00110 int receive_seq;
00111
00112 Octstr *inbuffer;
00113 List *received;
00114
00115 time_t next_ping;
00116
00117 List *outgoing_queue;
00118 SMSCConn *conn;
00119 int io_thread;
00120 int quitting;
00121 List *stopped;
00122
00123 } PrivData;
00124
00125
00126
00127
00128 #define RESPONSE_TIMEOUT (60 * 1000000)
00129
00130
00131
00132 enum {
00133
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
00144 DELIVER_MESSAGE = 20,
00145 DELIVER_STATUS_REPORT = 23,
00146
00147
00148 ALIVE = 40,
00149
00150
00151 RESPONSE = 50,
00152
00153
00154 GENERAL_ERROR_RESPONSE = 98,
00155 NACK = 99
00156 };
00157
00158
00159
00160 enum {
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 };
00197
00198
00199
00200
00201
00202
00203
00204
00205 enum { P_INT, P_STRING, P_ADDRESS, P_TIME, P_HEX, P_SMS };
00206
00207
00208
00209
00210 static const struct
00211 {
00212 char *name;
00213 int number;
00214 int maxlen;
00215 int type;
00216 int minval, maxval;
00217 }
00218 parameters[] = {
00219 { "user identity", P_USER_IDENTITY, 32, P_STRING },
00220 { "password", P_PASSWORD, 32, P_STRING },
00221 { "destination address", P_DESTINATION_ADDRESS, 20, P_ADDRESS },
00222 { "originating address", P_ORIGINATING_ADDRESS, 20, P_ADDRESS },
00223
00224 { "originating IMSI", P_ORIGINATING_IMSI, 20, P_ADDRESS },
00225 { "alphanumeric originating address", P_ALPHANUMERIC_ORIGINATING_ADDRESS, 11, P_STRING },
00226 { "originated visited MSC", P_ORIGINATED_VISITED_MSC, 20, P_ADDRESS },
00227 { "data coding scheme", P_DATA_CODING_SCHEME, 3, P_INT, 0, 255 },
00228 { "user data header", P_USER_DATA_HEADER, 280, P_HEX },
00229 { "user data", P_USER_DATA, 480, P_SMS },
00230 { "user data binary", P_USER_DATA_BINARY, 280, P_HEX },
00231 { "more messages to send", P_MORE_MESSAGES_TO_SEND, 1, P_INT, 0, 1 },
00232 { "validity period relative", P_VALIDITY_PERIOD_RELATIVE, 3, P_INT, -1, 255 },
00233 { "validity period absolute", P_VALIDITY_PERIOD_ABSOLUTE, 12, P_TIME },
00234 { "protocol identifier", P_PROTOCOL_IDENTIFIER, 3, P_INT, 0, 255 },
00235 { "first delivery time relative", P_FIRST_DELIVERY_TIME_RELATIVE, 3, P_INT, -1, 255 },
00236 { "first delivery time absolute", P_FIRST_DELIVERY_TIME_ABSOLUTE, 12, P_TIME },
00237 { "reply path", P_REPLY_PATH, 1, P_INT, 0, 1 },
00238 { "status report request", P_STATUS_REPORT_REQUEST, 2, P_INT, 0, 63 },
00239 { "cancel enabled", P_CANCEL_ENABLED, 1, P_INT, 0, 1 },
00240 { "cancel mode", P_CANCEL_MODE, 1, P_INT, 0, 2 },
00241 { "service centre timestamp", P_MC_TIMESTAMP, 12, P_TIME },
00242 { "status code", P_STATUS_CODE, 2, P_INT, 0, 9 },
00243 { "status error code", P_STATUS_ERROR_CODE, 3, P_INT, 0, 999 },
00244 { "discharge time", P_DISCHARGE_TIME, 12, P_TIME },
00245 { "tariff class", P_TARIFF_CLASS, 2, P_INT, 0, 99 },
00246 { "service description", P_SERVICE_DESCRIPTION, 2, P_INT, 0, 9 },
00247 { "message count", P_MESSAGE_COUNT, 3, P_INT, 0, 999 },
00248 { "priority", P_PRIORITY, 1, P_INT, 1, 9 },
00249 { "delivery request mode", P_DELIVERY_REQUEST_MODE, 1, P_INT, 0, 2 },
00250 { "service center address", P_SERVICE_CENTER_ADDRESS, 20, P_ADDRESS },
00251 { "get parameter", P_GET_PARAMETER, 3, P_INT, 501, 999 },
00252 { "MC time", P_MC_TIME, 12, P_TIME },
00253 { "error code", P_ERROR_CODE, 3, P_INT, 0, 999 },
00254 { "error text", P_ERROR_TEXT, 64, P_STRING },
00255 { NULL }
00256 };
00257
00258
00259
00260 static int parm_index(int parmno)
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 }
00271
00272 #ifndef NO_GWASSERT
00273
00274 static int parm_type(int parmno)
00275 {
00276 int i = parm_index(parmno);
00277
00278 if (i < 0)
00279 return -1;
00280
00281 return parameters[i].type;
00282 }
00283 #endif
00284
00285
00286
00287 static int parm_maxlen(int parmno)
00288 {
00289 int i = parm_index(parmno);
00290
00291 if (i < 0)
00292 return -1;
00293
00294 return parameters[i].maxlen;
00295 }
00296
00297 static const char *parm_name(int parmno)
00298 {
00299 int i = parm_index(parmno);
00300
00301 if (i < 0)
00302 return NULL;
00303
00304 return parameters[i].name;
00305 }
00306
00307 #ifndef NO_GWASSERT
00308
00309
00310 static int parm_in_range(int parmno, long value)
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 }
00321 #endif
00322
00323
00324 static int isphonedigit(int c)
00325 {
00326 return isdigit(c) || c == '+' || c == '-';
00327 }
00328
00329 static int parm_valid_address(Octstr *value)
00330 {
00331 return octstr_check_range(value, 0, octstr_len(value), isphonedigit);
00332 }
00333
00334
00335
00336
00337
00338 static int operation_find(int operation);
00339 static Octstr *operation_name(int operation);
00340 static int operation_can_send(int operation);
00341 static int operation_can_receive(int operation);
00342
00343 static const struct
00344 {
00345 char *name;
00346 int code;
00347 int can_send;
00348 int can_receive;
00349 }
00350 operations[] = {
00351 { "Login", LOGIN, 1, 0 },
00352 { "Logout", LOGOUT, 1, 0 },
00353 { "Submit message", SUBMIT_MESSAGE, 1, 0 },
00354 { "Enquire message status", ENQUIRE_MESSAGE_STATUS, 1, 0 },
00355 { "Delivery request", DELIVERY_REQUEST, 1, 0 },
00356 { "Cancel message", CANCEL_MESSAGE, 1, 0 },
00357 { "Set parameter", SET_REQ, 1, 0 },
00358 { "Get parameter", GET_REQ, 1, 0 },
00359
00360 { "Deliver message", DELIVER_MESSAGE, 0, 1 },
00361 { "Deliver status report", DELIVER_STATUS_REPORT, 0, 1 },
00362
00363 { "Alive", ALIVE, 1, 1 },
00364
00365 { "NACK", NACK, 1, 1 },
00366 { "General error response", GENERAL_ERROR_RESPONSE, 0, 1 },
00367
00368 { NULL, 0, 0, 0 }
00369 };
00370
00371 static int operation_find(int operation)
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 }
00382
00383
00384 static Octstr *operation_name(int operation)
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
00402 return octstr_create("(unknown)");
00403 }
00404
00405
00406 static int operation_can_send(int operation)
00407 {
00408 int i = operation_find(operation);
00409
00410 if (i >= 0)
00411 return operations[i].can_send;
00412
00413
00414 if (operation >= RESPONSE)
00415 return operation_can_receive(operation - RESPONSE);
00416
00417 return 0;
00418 }
00419
00420
00421
00422 static int operation_can_receive(int operation)
00423 {
00424 int i = operation_find(operation);
00425
00426 if (i >= 0)
00427 return operations[i].can_receive;
00428
00429
00430 if (operation >= RESPONSE)
00431 return operation_can_send(operation - RESPONSE);
00432
00433 return 0;
00434 }
00435
00436
00437
00438
00439
00440
00441 struct packet
00442 {
00443
00444 int operation;
00445 int seq;
00446 Octstr *data;
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458 };
00459
00460
00461 #define STX 2
00462 #define ETX 3
00463 #define TAB 9
00464
00465
00466 #define STX_str "\02"
00467 #define ETX_str "\03"
00468 #define TAB_str "\011"
00469
00470
00471 #define BOGUS_SEQUENCE 0
00472
00473 static Msg *cimd2_accept_delivery_report_message(struct packet *request,
00474 SMSCConn *conn);
00475
00476
00477
00478
00479
00480 static void packet_parse_header(struct packet *packet)
00481 {
00482 int pos;
00483 long number;
00484
00485
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 }
00502
00503
00504
00505
00506
00507 static struct packet *packet_parse(Octstr *packet_data)
00508 {
00509 struct packet *packet;
00510
00511 packet = gw_malloc(sizeof(*packet));
00512 packet->data = packet_data;
00513
00514
00515 packet_parse_header(packet);
00516
00517 return packet;
00518 }
00519
00520
00521 static void packet_destroy(struct packet *packet)
00522 {
00523 if (packet != NULL) {
00524 octstr_destroy(packet->data);
00525 gw_free(packet);
00526 }
00527 }
00528
00529
00530
00531
00532
00533 static struct packet *packet_extract(Octstr *in, SMSCConn *conn)
00534 {
00535 int stx, etx;
00536 Octstr *packet;
00537
00538
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
00548 etx = octstr_search_char(in, ETX, 1);
00549 if (etx < 0)
00550 return NULL;
00551
00552
00553
00554
00555
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
00565 packet = octstr_copy(in, 0, etx + 1);
00566 octstr_delete(in, 0, etx + 1);
00567 }
00568
00569 return packet_parse(packet);
00570 }
00571
00572
00573
00574
00575
00576
00577
00578
00579 static Octstr *packet_get_parm(struct packet *packet, int parmno)
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;
00589
00590
00591
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;
00602 valuepos++;
00603
00604
00605 return octstr_copy(packet->data, valuepos, next - valuepos);
00606 }
00607
00608 return NULL;
00609 }
00610
00611
00612
00613
00614
00615
00616 static long packet_get_int_parm(struct packet *packet, int parmno)
00617 {
00618 Octstr *valuestr = NULL;
00619 long value;
00620
00621
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 }
00638
00639
00640
00641
00642 static Octstr *packet_get_string_parm(struct packet *packet, int parmno)
00643 {
00644
00645 gw_assert(parm_type(parmno) == P_STRING);
00646
00647 return packet_get_parm(packet, parmno);
00648 }
00649
00650
00651
00652
00653 static Octstr *packet_get_address_parm(struct packet *packet, int parmno)
00654 {
00655
00656 gw_assert(parm_type(parmno) == P_ADDRESS);
00657
00658 return packet_get_parm(packet, parmno);
00659 }
00660
00661
00662
00663
00664
00665 static Octstr *packet_get_sms_parm(struct packet *packet, int parmno)
00666 {
00667
00668 gw_assert(parm_type(parmno) == P_SMS);
00669
00670 return packet_get_parm(packet, parmno);
00671 }
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681 static Octstr *packet_get_hex_parm(struct packet *packet, int parmno)
00682 {
00683 Octstr *value = NULL;
00684
00685
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 }
00701
00702
00703
00704
00705 static int packet_check_header(struct packet *packet, SMSCConn *conn)
00706 {
00707 Octstr *data;
00708
00709 gw_assert(packet != NULL);
00710 data = packet->data;
00711
00712
00713
00714
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 }
00727
00728 static int packet_check_parameter(struct packet *packet, long pos, long len, SMSCConn *conn)
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
00742
00743
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
00755
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
00763
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
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:
00834 break;
00835 }
00836
00837 if (errors > 0)
00838 return -1;
00839 return 0;
00840 }
00841
00842
00843
00844
00845
00846 static int packet_check(struct packet *packet, SMSCConn *conn)
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
00857 warning(0, "CIMD2[%s]: packet contains NULs",
00858 octstr_get_cstr(conn->id));
00859 errors++;
00860 }
00861
00862
00863
00864
00865 errors += (packet_check_header(packet,conn) < 0);
00866
00867
00868
00869
00870
00871 len = octstr_len(data);
00872
00873
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
00881
00882
00883
00884
00885
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 }
00904
00905 static void packet_check_can_receive(struct packet *packet, SMSCConn *conn)
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 }
00917
00918
00919 static struct
00920 {
00921 int code;
00922 char *text;
00923 }
00924 cimd2_errors[] = {
00925 { 0, "No error" },
00926 { 1, "Unexpected operation" },
00927 { 2, "Syntax error" },
00928 { 3, "Unsupported parameter error" },
00929 { 4, "Connection to message center lost" },
00930 { 5, "No response from message center" },
00931 { 6, "General system error" },
00932 { 7, "Cannot find information" },
00933 { 8, "Parameter formatting error" },
00934 { 9, "Requested operation failed" },
00935
00936 { 100, "Invalid login" },
00937 { 101, "Incorrect access type" },
00938 { 102, "Too many users with this login id" },
00939 { 103, "Login refused by message center" },
00940
00941 { 300, "Incorrect destination address" },
00942 { 301, "Incorrect number of destination addresses" },
00943 { 302, "Syntax error in user data parameter" },
00944 { 303, "Incorrect bin/head/normal user data parameter combination" },
00945 { 304, "Incorrect data coding scheme parameter usage" },
00946 { 305, "Incorrect validity period parameters usage" },
00947 { 306, "Incorrect originator address usage" },
00948 { 307, "Incorrect pid paramterer usage" },
00949 { 308, "Incorrect first delivery parameter usage" },
00950 { 309, "Incorrect reply path usage" },
00951 { 310, "Incorrect status report request parameter usage" },
00952 { 311, "Incorrect cancel enabled parameter usage" },
00953 { 312, "Incorrect priority parameter usage" },
00954 { 313, "Incorrect tariff class parameter usage" },
00955 { 314, "Incorrect service description parameter usage" },
00956 { 315, "Incorrect transport type parameter usage" },
00957 { 316, "Incorrect message type parameter usage" },
00958 { 318, "Incorrect mms parameter usage" },
00959 { 319, "Incorrect operation timer parameter usage" },
00960
00961 { 400, "Incorrect address parameter usage" },
00962 { 401, "Incorrect scts parameter usage" },
00963
00964 { 500, "Incorrect scts parameter usage" },
00965 { 501, "Incorrect mode parameter usage" },
00966 { 502, "Incorrect parameter combination" },
00967
00968 { 600, "Incorrect scts parameter usage" },
00969 { 601, "Incorrect address parameter usage" },
00970 { 602, "Incorrect mode parameter usage" },
00971 { 603, "Incorrect parameter combination" },
00972
00973 { 800, "Changing password failed" },
00974 { 801, "Changing password not allowed" },
00975
00976 { 900, "Unsupported item requested" },
00977 { -1, NULL }
00978 };
00979
00980 static int packet_display_error(struct packet *packet, SMSCConn *conn)
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
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
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 }
01019
01020
01021
01022
01023 static const struct
01024 {
01025 unsigned char cimd1, cimd2;
01026 unsigned char gsm;
01027 }
01028 cimd_combinations[] = {
01029 { 'O', 'a', 0 },
01030 { 'L', '-', 1 },
01031 { 'Y', '-', 3 },
01032 { 'e', '`', 4 },
01033 { 'e', '\'', 5 },
01034 { 'u', '`', 6 },
01035 { 'i', '`', 7 },
01036 { 'o', '`', 8 },
01037 { 'C', ',', 9 },
01038 { 'O', '/', 11 },
01039 { 'o', '/', 12 },
01040 { 'A', '*', 14 },
01041 { 'a', '*', 15 },
01042 { 'g', 'd', 16 },
01043 { '-', '-', 17 },
01044 { 'g', 'f', 18 },
01045 { 'g', 'g', 19 },
01046 { 'g', 'l', 20 },
01047 { 'g', 'o', 21 },
01048 { 'g', 'p', 22 },
01049 { 'g', 'i', 23 },
01050 { 'g', 's', 24 },
01051 { 'g', 't', 25 },
01052 { 'g', 'x', 26 },
01053 { 'X', 'X', 27 },
01054 { 'A', 'E', 28 },
01055 { 'a', 'e', 29 },
01056 { 's', 's', 30 },
01057 { 'E', '\'', 31 },
01058 { 'q', 'q', '"' },
01059 { 'o', 'x', 36 },
01060 { '!', '!', 64 },
01061 { 'A', '"', 91 },
01062 { 'O', '"', 92 },
01063 { 'N', '~', 93 },
01064 { 'U', '"', 94 },
01065 { 's', 'o', 95 },
01066 { '?', '?', 96 },
01067 { 'a', '"', 123 },
01068 { 'o', '"', 124 },
01069 { 'n', '~', 125 },
01070 { 'u', '"', 126 },
01071 { 'a', '`', 127 },
01072 { 0, 0, 0 }
01073 };
01074
01075
01076
01077
01078
01079
01080
01081
01082 static void convert_cimd2_to_gsm(Octstr *text, SMSCConn *conn)
01083 {
01084 long pos, len;
01085 int cimd1, cimd2;
01086 int c;
01087 int i;
01088
01089
01090
01091
01092
01093
01094
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 }
01129
01130
01131
01132
01133
01134
01135 static void convert_gsm_to_cimd2(Octstr *text)
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
01145
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
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
01163
01164
01165 octstr_set_char(text, pos, '$');
01166 }
01167 }
01168 }
01169
01170
01171
01172
01173
01174
01175
01176
01177 static struct packet *packet_create(int operation, int seq)
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 }
01190
01191
01192 static void packet_add_parm(struct packet *packet, int parmtype,
01193 int parmno, Octstr *value, SMSCConn *conn)
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
01217
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 }
01226
01227
01228 static void packet_add_string_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
01229 {
01230 packet_add_parm(packet, P_STRING, parmno, value, conn);
01231 }
01232
01233
01234 static void packet_add_address_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
01235 {
01236 gw_assert(octstr_check_range(value, 0, octstr_len(value), isphonedigit));
01237 packet_add_parm(packet, P_ADDRESS, parmno, value, conn);
01238 }
01239
01240
01241
01242 static void packet_add_sms_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
01243 {
01244 packet_add_parm(packet, P_SMS, parmno, value, conn);
01245 }
01246
01247
01248
01249
01250
01251
01252
01253 static void packet_add_hex_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
01254 {
01255 value = octstr_duplicate(value);
01256 octstr_binary_to_hex(value, 1);
01257 packet_add_parm(packet, P_HEX, parmno, value, conn);
01258 octstr_destroy(value);
01259 }
01260
01261
01262 static void packet_add_int_parm(struct packet *packet, int parmno, long value, SMSCConn *conn)
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 }
01274
01275 static void packet_set_checksum(struct packet *packet)
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
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
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 }
01302
01303 static void packet_set_sequence(struct packet *packet, int 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
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 }
01319
01320 static struct packet *packet_encode_message(Msg *msg, Octstr *sender_prefix, SMSCConn *conn)
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
01351
01352
01353
01354
01355
01356
01357 if (parm_valid_address(msg->sms.sender)) {
01358
01359
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
01381 packet_add_string_parm(packet, P_ALPHANUMERIC_ORIGINATING_ADDRESS,msg->sms.sender, conn);
01382 }
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
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
01420
01421
01422
01423
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
01435
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
01443 if (octstr_len(msg->sms.binfo))
01444 packet_add_parm(packet, P_INT, P_TARIFF_CLASS, msg->sms.binfo, conn);
01445
01446
01447 if (msg->sms.pid > 0)
01448 packet_add_int_parm(packet, P_PROTOCOL_IDENTIFIER, msg->sms.pid, conn);
01449
01450
01451
01452
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
01464
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
01485
01486
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 }
01505
01506
01507
01508
01509
01510
01511 static void packet_set_send_sequence(struct packet *packet, PrivData *pdata)
01512 {
01513 gw_assert(pdata != NULL);
01514
01515 if (packet->operation == LOGIN)
01516 pdata->send_seq = 1;
01517
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 }
01525
01526 static struct packet *cimd2_get_packet(PrivData *pdata, Octstr **ts)
01527 {
01528 struct packet *packet = NULL;
01529
01530 gw_assert(pdata != NULL);
01531
01532
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 }
01564
01565
01566
01567 static void cimd2_send_response(struct packet *request, PrivData *pdata)
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
01582
01583 octstr_write_to_socket(pdata->socket, response->data);
01584
01585 packet_destroy(response);
01586 }
01587
01588 static Msg *cimd2_accept_message(struct packet *request, SMSCConn *conn)
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
01598
01599
01600
01601
01602
01603
01604
01605
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
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
01620
01621
01622
01623
01624 text = packet_get_hex_parm(request, P_USER_DATA_BINARY);
01625 }
01626
01627
01628
01629
01630
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
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 }
01672
01673
01674 static void cimd2_handle_request(struct packet *request, SMSCConn *conn)
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 }
01703
01704
01705
01706
01707
01708
01709
01710
01711
01712
01713
01714
01715
01716
01717
01718 static int cimd2_request(struct packet *request, SMSCConn *conn, Octstr **ts)
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);
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
01761
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
01779
01780 if (reply->operation < RESPONSE) {
01781 cimd2_handle_request(reply, conn);
01782 goto next_reply;
01783 }
01784
01785 if (reply->seq != request->seq) {
01786
01787
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
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
01812
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 }
01835
01836
01837 static void cimd2_close_socket(PrivData *pdata)
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 }
01849
01850
01851
01852
01853
01854 static int cimd2_login(SMSCConn *conn)
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 }
01894
01895 static void cimd2_logout(SMSCConn *conn)
01896 {
01897 struct packet *packet = NULL;
01898 int ret;
01899
01900 packet = packet_create(LOGOUT, BOGUS_SEQUENCE);
01901
01902
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 }
01911
01912 static int cimd2_send_alive(SMSCConn *conn)
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 }
01927
01928
01929 static void cimd2_destroy(PrivData *pdata)
01930 {
01931 int discarded;
01932
01933 if (pdata == NULL)
01934 return;
01935
01936 octstr_destroy(pdata->host);
01937 octstr_destroy(pdata->username);
01938 octstr_destroy(pdata->password);
01939 octstr_destroy(pdata->inbuffer);
01940 octstr_destroy(pdata->my_number);
01941
01942 discarded = gwlist_len(pdata->received);
01943 if (discarded > 0)
01944 warning(0, "CIMD2[%s]: discarded %d received messages",
01945 octstr_get_cstr(pdata->conn->id),
01946 discarded);
01947
01948 gwlist_destroy(pdata->received, msg_destroy_item);
01949 gwlist_destroy(pdata->outgoing_queue, NULL);
01950 gwlist_destroy(pdata->stopped, NULL);
01951
01952 gw_free(pdata);
01953 }
01954
01955
01956 static int cimd2_submit_msg(SMSCConn *conn, Msg *msg)
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
01970
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 }
02001
02002 static int cimd2_receive_msg(SMSCConn *conn, Msg **msg)
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
02017
02018
02019
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
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 }
02081
02082
02083
02084 static Msg *cimd2_accept_delivery_report_message(struct packet *request,
02085 SMSCConn *conn)
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:
02103 case 3:
02104 case 6:
02105 case 7:
02106 case 8:
02107 case 9:
02108 code = DLR_FAIL;
02109 break;
02110 case 4:
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
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 }
02136
02137 static Msg *sms_receive(SMSCConn *conn)
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
02146 newmsg->sms.smsc_id = octstr_duplicate(conn->id);
02147 return newmsg;
02148 }
02149 else if (ret == 0) {
02150 return NULL;
02151 }
02152
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 }
02160
02161
02162 static void io_thread (void *arg)
02163 {
02164 Msg *msg;
02165 SMSCConn *conn = arg;
02166 PrivData *pdata = conn->data;
02167 double sleep = 0.0001;
02168
02169
02170 log_thread_to(conn->log_idx);
02171
02172
02173 while (!pdata->quitting) {
02174
02175 gwlist_consume(pdata->stopped);
02176
02177
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
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
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
02219
02220
02221 gwthread_sleep(sleep);
02222
02223
02224
02225
02226 sleep *= 2;
02227 if (sleep >= 2.0)
02228 sleep = 1.999999;
02229 }
02230 else {
02231 sleep = 0.0001;
02232 }
02233 }
02234 }
02235
02236
02237 static int cimd2_add_msg_cb (SMSCConn *conn, Msg *sms)
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 }
02248
02249
02250 static int cimd2_shutdown_cb (SMSCConn *conn, int finish_sending)
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
02259
02260 conn->why_killed = SMSCCONN_KILLED_SHUTDOWN;
02261 pdata->quitting = 1;
02262
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 }
02291
02292 static void cimd2_start_cb (SMSCConn *conn)
02293 {
02294 PrivData *pdata = conn->data;
02295
02296 gwlist_remove_producer(pdata->stopped);
02297
02298 gwthread_wakeup(pdata->io_thread);
02299 debug("bb.sms", 0, "SMSCConn CIMD2 %s, start called",
02300 octstr_get_cstr(conn->id));
02301 }
02302
02303 static void cimd2_stop_cb (SMSCConn *conn)
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 }
02310
02311 static long cimd2_queued_cb (SMSCConn *conn)
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 }
02318
02319 int smsc_cimd2_create(SMSCConn *conn, CfgGroup *grp)
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
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 }
02434
See file LICENSE for details about the license agreement for using,
modifying, copying or deriving work from this software.