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 #include <ctype.h>
00072 #include <time.h>
00073 #include <errno.h>
00074 #include <limits.h>
00075 #include <string.h>
00076
00077 #include <unistd.h>
00078
00079 #include "gwlib/gwlib.h"
00080 #include "smscconn.h"
00081 #include "smscconn_p.h"
00082 #include "bb_smscconn_cb.h"
00083
00084 #include "shared.h"
00085 #include "sms.h"
00086 #include "dlr.h"
00087
00088
00089 typedef struct privdata {
00090 Octstr *host;
00091 long port;
00092 long keepalive;
00093 Octstr *my_number;
00094 long validityperiod;
00095 int no_dlr;
00096
00097 int socket;
00098 unsigned long send_seq;
00099
00100 Octstr *inbuffer;
00101 List *received;
00102
00103 time_t next_ping;
00104
00105 List *outgoing_queue;
00106 SMSCConn *conn;
00107 int io_thread;
00108 int quitting;
00109 List *stopped;
00110
00111 } PrivData;
00112
00113
00114
00115
00116 #define RESPONSE_TIMEOUT (10 * 1000000)
00117 #define RESULT_SUCCESS 0
00118
00119 enum {
00120 INVOKE = 0,
00121 RESULT = 1
00122 };
00123
00124
00125
00126 enum {
00127 SUBMIT_SM = 0,
00128 STATUS_REPORT = 4,
00129 DELIVER_SM = 9,
00130 RETRIEVE_REQUEST = 11,
00131
00132
00133 RESPONSE = 50
00134 };
00135
00136 static int isphonedigit(int c)
00137 {
00138 return isdigit(c) || c == '+' || c == '-';
00139 }
00140
00141 static int parm_valid_address(Octstr *value)
00142 {
00143 return octstr_check_range(value, 0, octstr_len(value), isphonedigit);
00144 }
00145
00146
00147
00148
00149
00150 static int operation_find(int operation);
00151 static Octstr *operation_name(int operation);
00152 static int operation_can_send(int operation);
00153 static int operation_can_receive(int operation);
00154
00155 static const struct
00156 {
00157 char *name;
00158 int code;
00159 int can_send;
00160 int can_receive;
00161 }
00162 operations[] = {
00163 { "Submit SM", SUBMIT_SM, 1, 0 },
00164 { "Status Report", STATUS_REPORT, 0, 1 },
00165 { "Deliver SM", DELIVER_SM, 0, 1 },
00166 { "Retrieve Request", RETRIEVE_REQUEST, 1, 0 },
00167
00168 { NULL, 0, 0, 0 }
00169 };
00170
00171 static int operation_find(int operation)
00172 {
00173 int i;
00174
00175 for (i = 0; operations[i].name != NULL; i++) {
00176 if (operations[i].code == operation)
00177 return i;
00178 }
00179
00180 return -1;
00181 }
00182
00183
00184 static Octstr *operation_name(int operation)
00185 {
00186 int i;
00187
00188 i = operation_find(operation);
00189 if (i >= 0)
00190 return octstr_create(operations[i].name);
00191
00192 if (operation >= RESPONSE) {
00193 i = operation_find(operation - RESPONSE);
00194 if (i >= 0) {
00195 Octstr *name = octstr_create(operations[i].name);
00196 octstr_append_cstr(name, " response");
00197 return name;
00198 }
00199 }
00200
00201
00202 return octstr_create("(unknown)");
00203 }
00204
00205
00206 static int operation_can_send(int operation)
00207 {
00208 int i = operation_find(operation);
00209
00210 if (i >= 0)
00211 return operations[i].can_send;
00212
00213
00214 if (operation >= RESPONSE)
00215 return operation_can_receive(operation - RESPONSE);
00216
00217 return 0;
00218 }
00219
00220
00221
00222 static int operation_can_receive(int operation)
00223 {
00224 int i = operation_find(operation);
00225
00226 if (i >= 0)
00227 return operations[i].can_receive;
00228
00229
00230 if (operation >= RESPONSE)
00231 return operation_can_send(operation - RESPONSE);
00232
00233 return 0;
00234 }
00235
00236
00237
00238
00239
00240
00241 struct packet
00242 {
00243 unsigned long opref;
00244 int operation;
00245 Octstr *data;
00246 };
00247
00248
00249 #define BOGUS_SEQUENCE 0
00250
00251 static Msg *oisd_accept_delivery_report_message(struct packet *request,
00252 SMSCConn *conn);
00253
00254 static void packet_parse_header(struct packet *packet)
00255 {
00256 packet->opref = (octstr_get_char(packet->data, 3) << 24)
00257 | (octstr_get_char(packet->data, 2) << 16)
00258 | (octstr_get_char(packet->data, 1) << 8)
00259 | (octstr_get_char(packet->data, 0));
00260
00261 packet->operation = octstr_get_char(packet->data, 5);
00262 if (octstr_get_char(packet->data, 4) == 1)
00263 packet->operation += RESPONSE;
00264 }
00265
00266
00267
00268
00269
00270
00271
00272 static struct packet *packet_parse(Octstr *packet_data)
00273 {
00274 struct packet *packet;
00275
00276 packet = gw_malloc(sizeof(*packet));
00277 packet->data = packet_data;
00278
00279
00280 packet_parse_header(packet);
00281
00282 return packet;
00283 }
00284
00285
00286 static void packet_destroy(struct packet *packet)
00287 {
00288 if (packet != NULL) {
00289 octstr_destroy(packet->data);
00290 gw_free(packet);
00291 }
00292 }
00293
00294
00295
00296
00297
00298
00299 static struct packet *packet_extract(Octstr *in, SMSCConn *conn)
00300 {
00301 Octstr *packet;
00302 int size, i;
00303 static char s[4][4] = {
00304 { 0x01, 0x0b, 0x00, 0x00 },
00305 { 0x01, 0x00, 0x00, 0x00 },
00306 { 0x00, 0x04, 0x00, 0x00 },
00307 { 0x00, 0x09, 0x00, 0x00 }
00308 };
00309 char known_bytes[4];
00310
00311 if (octstr_len(in) < 10)
00312 return NULL;
00313 octstr_get_many_chars(known_bytes, in, 4, 4);
00314
00315
00316 for (i = 0; i < 4; i++) {
00317 if (memcmp(s[i], known_bytes, 4) == 0)
00318 break;
00319 }
00320
00321 if (i >= 4) {
00322 error(0, "OISD[%s]: wrong packet",
00323 octstr_get_cstr(conn->id));
00324 octstr_dump(in, 0);
00325 return NULL;
00326 }
00327
00328
00329 size = (octstr_get_char(in, 9) << 8) | octstr_get_char(in, 8);
00330
00331 if (size + 10 > octstr_len(in))
00332 return NULL;
00333
00334 packet = octstr_copy(in, 0, size + 10);
00335 octstr_delete(in, 0, size + 10);
00336
00337 return packet_parse(packet);
00338 }
00339
00340 static void packet_check_can_receive(struct packet *packet, SMSCConn *conn)
00341 {
00342 gw_assert(packet != NULL);
00343
00344 if (!operation_can_receive(packet->operation)) {
00345 Octstr *name = operation_name(packet->operation);
00346 warning(0, "OISD[%s]: SMSC sent us %s request",
00347 octstr_get_cstr(conn->id),
00348 octstr_get_cstr(name));
00349 octstr_destroy(name);
00350 }
00351 }
00352
00353 static int oisd_expand_gsm7_to_bits(char *bits, Octstr *raw7)
00354 {
00355 int i, j, k;
00356 int len;
00357 char ch;
00358
00359 len = octstr_len(raw7) * 7;
00360
00361 for (j = i = 0; j < len; ++i) {
00362 ch = octstr_get_char(raw7, i);
00363 for (k = 0; k < 8; ++k) {
00364 bits[j++] = (char) (ch & 0x01);
00365 ch >>= 1;
00366 }
00367 }
00368
00369 return j;
00370 }
00371
00372 static char oisd_expand_gsm7_from_bits(const char *bits, int pos)
00373 {
00374 int i;
00375 char ch;
00376
00377 pos *= 7;
00378 ch = '\0';
00379 for (i = 6; i >= 0; --i) {
00380 ch <<= 1;
00381 ch |= bits[pos + i];
00382 }
00383
00384 return ch;
00385 }
00386
00387 static Octstr *oisd_expand_gsm7(Octstr *raw7)
00388 {
00389 Octstr *raw8;
00390 int i, len;
00391 char *bits;
00392
00393 raw8 = octstr_create("");
00394 bits = gw_malloc(8 * octstr_len(raw7) + 1);
00395
00396 oisd_expand_gsm7_to_bits(bits, raw7);
00397 len = octstr_len(raw7);
00398
00399 for (i = 0; i < len; ++i) {
00400 octstr_append_char(raw8, oisd_expand_gsm7_from_bits(bits, i));
00401 }
00402
00403 gw_free(bits);
00404
00405 return raw8;
00406 }
00407
00408 static void oisd_shrink_gsm7(Octstr *str)
00409 {
00410 Octstr *result;
00411 int len, i;
00412 int numbits, value;
00413
00414 result = octstr_create("");
00415 len = octstr_len(str);
00416 value = 0;
00417 numbits = 0;
00418 for (i = 0; i < len; i++) {
00419 value += octstr_get_char(str, i) << numbits;
00420 numbits += 7;
00421 if (numbits >= 8) {
00422 octstr_append_char(result, value & 0xff);
00423 value >>= 8;
00424 numbits -= 8;
00425 }
00426 }
00427 if (numbits > 0)
00428 octstr_append_char(result, value);
00429 octstr_delete(str, 0, LONG_MAX);
00430 octstr_append(str, result);
00431 octstr_destroy(result);
00432 }
00433
00434
00435
00436
00437
00438
00439
00440 static struct packet *packet_create(int operation, unsigned long opref)
00441 {
00442 struct packet *packet;
00443 unsigned char header[10];
00444
00445 packet = gw_malloc(sizeof(*packet));
00446 packet->operation = operation;
00447 packet->opref = opref;
00448
00449
00450 header[0] = opref & 0xff;
00451 header[1] = (opref >> 8) & 0xff;
00452 header[2] = (opref >> 16) & 0xff;
00453 header[3] = (opref >> 24) & 0xff;
00454
00455
00456 if (operation > RESPONSE) {
00457 header[4] = RESULT;
00458 header[5] = operation - RESPONSE;
00459 } else {
00460 header[4] = INVOKE;
00461 header[5] = operation;
00462 }
00463
00464
00465 header[6] = 0;
00466 header[7] = 0;
00467
00468
00469 header[8] = 0;
00470 header[9] = 0;
00471
00472 packet->data = octstr_create_from_data((char *)header, 10);
00473
00474 return packet;
00475 }
00476
00477 static void packet_set_data_size(struct packet *packet)
00478 {
00479 int len;
00480
00481 gw_assert(packet != NULL);
00482
00483 len = octstr_len(packet->data) - 10;
00484
00485 octstr_set_char(packet->data, 8, len & 0xff);
00486 octstr_set_char(packet->data, 9, (len >> 8) & 0xff);
00487 }
00488
00489 static void packet_set_sequence(struct packet *packet, unsigned long opref)
00490 {
00491 gw_assert(packet != NULL);
00492
00493 octstr_set_char(packet->data, 0, opref & 0xff);
00494 octstr_set_char(packet->data, 1, (opref >> 8) & 0xff);
00495 octstr_set_char(packet->data, 2, (opref >> 16) & 0xff);
00496 octstr_set_char(packet->data, 3, (opref >> 24) & 0xff);
00497 packet->opref = opref;
00498 }
00499
00500 static struct packet *packet_encode_message(Msg *msg, SMSCConn *conn)
00501 {
00502 struct packet *packet;
00503 PrivData *pdata = conn->data;
00504 int DCS;
00505 int setvalidity = 0;
00506 int so = 0;
00507 int udhlen7, udhlen8;
00508 int msglen7, msglen8;
00509 Octstr *udhdata = NULL;
00510 Octstr *msgdata = NULL;
00511
00512 gw_assert(msg != NULL);
00513 gw_assert(msg->type == sms);
00514 gw_assert(msg->sms.receiver != NULL);
00515
00516 DCS = fields_to_dcs(msg, 0);
00517 if (msg->sms.sender == NULL)
00518 msg->sms.sender = octstr_create("");
00519
00520 if (!parm_valid_address(msg->sms.receiver)) {
00521 warning(0, "OISD[%s]: non-digits in destination phone number '%s', discarded",
00522 octstr_get_cstr(conn->id),
00523 octstr_get_cstr(msg->sms.receiver));
00524 return NULL;
00525 }
00526
00527 if (!parm_valid_address(msg->sms.sender)) {
00528 warning(0, "OISD[%s]: non-digits in originating phone number '%s', discarded",
00529 octstr_get_cstr(conn->id),
00530 octstr_get_cstr(msg->sms.sender));
00531 return NULL;
00532 }
00533
00534 packet = packet_create(SUBMIT_SM, BOGUS_SEQUENCE);
00535
00536 gw_assert(octstr_check_range(msg->sms.receiver, 0,
00537 octstr_len(msg->sms.receiver), isphonedigit));
00538
00539 octstr_append_char(packet->data,
00540 (unsigned char) octstr_len(msg->sms.receiver));
00541
00542
00543 octstr_append(packet->data, msg->sms.receiver);
00544
00545
00546
00547 octstr_append_char(packet->data, 2);
00548
00549
00550 octstr_append_char(packet->data, 0);
00551 octstr_append_char(packet->data, 0);
00552 octstr_append_char(packet->data, 0);
00553 octstr_append_char(packet->data, 0);
00554
00555
00556 octstr_append_char(packet->data, 1);
00557 gw_assert(octstr_check_range(msg->sms.sender, 0,
00558 octstr_len(msg->sms.sender), isphonedigit));
00559
00560
00561 octstr_append_char(packet->data,
00562 (unsigned char) (octstr_len(msg->sms.sender) + 2));
00563
00564
00565
00566 octstr_append_char(packet->data, 0x42);
00567
00568
00569 octstr_append_char(packet->data, 0x44);
00570
00571
00572 octstr_append(packet->data, msg->sms.sender);
00573
00574
00575
00576
00577
00578
00579
00580 if ((setvalidity = msg->sms.validity) != SMS_PARAM_UNDEFINED ||
00581 (setvalidity = pdata->validityperiod) != SMS_PARAM_UNDEFINED) {
00582
00583 octstr_append_char(packet->data, 2);
00584
00585 if (setvalidity > 635040)
00586 setvalidity = 255;
00587 else if (setvalidity >= 50400 && setvalidity <= 635040)
00588 setvalidity = (setvalidity - 1) / 7 / 24 / 60 + 192 + 1;
00589 else if (setvalidity > 43200 && setvalidity < 50400)
00590 setvalidity = 197;
00591 else if (setvalidity >= 2880 && setvalidity <= 43200)
00592 setvalidity = (setvalidity - 1) / 24 / 60 + 166 + 1;
00593 else if (setvalidity > 1440 && setvalidity < 2880)
00594 setvalidity = 168;
00595 else if (setvalidity >= 750 && setvalidity <= 1440)
00596 setvalidity = (setvalidity - 720 - 1) / 30 + 143 + 1;
00597 else if (setvalidity > 720 && setvalidity < 750)
00598 setvalidity = 144;
00599 else if (setvalidity >= 5 && setvalidity <= 720)
00600 setvalidity = (setvalidity - 1) / 5 - 1 + 1;
00601 else if (setvalidity < 5)
00602 setvalidity = 0;
00603
00604 octstr_append_char(packet->data, setvalidity);
00605 } else {
00606
00607 octstr_append_char(packet->data, 0);
00608 setvalidity = 0;
00609 }
00610
00611 if (setvalidity >= 0 && setvalidity <= 143)
00612 debug("bb.smsc.oisd", 0, "OISD[%s]: Validity-Period: %d minutes",
00613 octstr_get_cstr(conn->id), (setvalidity + 1)*5);
00614 else if (setvalidity >= 144 && setvalidity <= 167)
00615 debug("bb.smsc.oisd", 0, "OISD[%s]: Validity-Period: %3.1f hours",
00616 octstr_get_cstr(conn->id), ((float)(setvalidity - 143) / 2) + 12);
00617 else if (setvalidity >= 168 && setvalidity <= 196)
00618 debug("bb.smsc.oisd", 0, "OISD[%s]: Validity-Period: %d days",
00619 octstr_get_cstr(conn->id), (setvalidity - 166));
00620 else
00621 debug("bb.smsc.oisd", 0, "OISD[%s]: Validity-Period: %d weeks",
00622 octstr_get_cstr(conn->id), (setvalidity - 192));
00623
00624
00625 octstr_append_char(packet->data, DCS);
00626
00627
00628
00629
00630
00631
00632
00633 if (!pdata->no_dlr)
00634 if (DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask))
00635 octstr_append_char(packet->data, 7);
00636 else
00637 octstr_append_char(packet->data, 0);
00638 else if (pdata->no_dlr && DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask))
00639 warning(0, "OISD[%s]: dlr request make no sense while no-dlr set to true",
00640 octstr_get_cstr(conn->id));
00641
00642
00643 octstr_append_char(packet->data, 0);
00644
00645 if (octstr_len(msg->sms.udhdata))
00646 so |= 0x02;
00647 if (msg->sms.coding == DC_8BIT)
00648 so |= 0x10;
00649
00650
00651 octstr_append_char(packet->data, so);
00652
00653 udhlen8 = octstr_len(msg->sms.udhdata);
00654 msglen8 = octstr_len(msg->sms.msgdata);
00655
00656 udhdata = octstr_duplicate(msg->sms.udhdata);
00657 msgdata = octstr_duplicate(msg->sms.msgdata);
00658
00659 if (msg->sms.coding == DC_7BIT || msg->sms.coding == DC_UNDEF) {
00660 debug("bb.sms.oisd", 0, "OISD[%s]: sending UTF-8=%s",
00661 octstr_get_cstr(conn->id),
00662 octstr_get_cstr(msg->sms.msgdata));
00663 charset_utf8_to_gsm(msgdata);
00664 oisd_shrink_gsm7(msgdata);
00665 }
00666
00667
00668 udhlen7 = octstr_len(udhdata);
00669 msglen7 = octstr_len(msgdata);
00670
00671 octstr_append_char(packet->data, (unsigned char) (udhlen8 + msglen8));
00672 octstr_append_char(packet->data, (unsigned char) (udhlen7 + msglen7));
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682 octstr_append(packet->data, udhdata);
00683 octstr_append(packet->data, msgdata);
00684
00685
00686 octstr_append_char(packet->data, 0);
00687 octstr_append_char(packet->data, 0);
00688
00689 octstr_destroy(udhdata);
00690 octstr_destroy(msgdata);
00691
00692 return packet;
00693 }
00694
00695
00696
00697
00698
00699
00700 static void packet_set_send_sequence(struct packet *packet, PrivData *pdata)
00701 {
00702 gw_assert(pdata != NULL);
00703
00704 packet_set_sequence(packet, pdata->send_seq);
00705 pdata->send_seq++;
00706 }
00707
00708 static struct packet *oisd_get_packet(PrivData *pdata, Octstr **ts)
00709 {
00710 struct packet *packet = NULL;
00711
00712 gw_assert(pdata != NULL);
00713
00714
00715 packet = packet_extract(pdata->inbuffer, pdata->conn);
00716
00717 while (packet == NULL) {
00718 if (read_available(pdata->socket, RESPONSE_TIMEOUT) != 1) {
00719 warning(0, "OISD[%s]: SMSC is not responding",
00720 octstr_get_cstr(pdata->conn->id));
00721 return NULL;
00722 }
00723
00724 if (octstr_append_from_socket(pdata->inbuffer, pdata->socket) <= 0) {
00725 error(0, "OISD[%s]: oisd_get_packet: read failed",
00726 octstr_get_cstr(pdata->conn->id));
00727 return NULL;
00728 }
00729
00730 packet = packet_extract(pdata->inbuffer, pdata->conn);
00731 }
00732
00733 packet_check_can_receive(packet, pdata->conn);
00734 debug("bb.sms.oisd", 0, "OISD[%s]: received",
00735 octstr_get_cstr(pdata->conn->id));
00736 if (packet->operation != RETRIEVE_REQUEST + RESPONSE)
00737 octstr_dump(packet->data, 0);
00738 if (ts)
00739 *ts = octstr_copy(packet->data, 15, 14);
00740
00741 if (pdata->keepalive > 0)
00742 pdata->next_ping = time(NULL) + pdata->keepalive;
00743
00744 return packet;
00745 }
00746
00747
00748
00749
00750 static void oisd_send_response(struct packet *request, PrivData *pdata)
00751 {
00752 struct packet *response;
00753
00754 gw_assert(request != NULL);
00755 gw_assert(request->operation < RESPONSE);
00756
00757 response = packet_create(request->operation + RESPONSE, request->opref);
00758
00759 octstr_append_char(response->data, (char) RESULT_SUCCESS);
00760
00761 packet_set_data_size(response);
00762
00763 debug("bb.sms.oisd", 0, "OISD[%s]: sending response",
00764 octstr_get_cstr(pdata->conn->id));
00765 octstr_dump(response->data, 0);
00766
00767
00768
00769 octstr_write_to_socket(pdata->socket, response->data);
00770
00771 packet_destroy(response);
00772 }
00773
00774 static Msg *oisd_accept_message(struct packet *request, SMSCConn *conn)
00775 {
00776 Msg *msg = NULL;
00777 int DCS;
00778 int dest_len;
00779 int origin_len;
00780 int add_info;
00781 int msglen7, msglen8;
00782 int udh_len;
00783
00784 msg = msg_create(sms);
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810 dest_len = octstr_get_char(request->data, 10);
00811
00812
00813 msg->sms.receiver = octstr_copy(request->data, 11+2, dest_len-2);
00814
00815
00816 origin_len = octstr_get_char(request->data, 11+dest_len+4);
00817
00818
00819 msg->sms.sender = octstr_copy(request->data, 11+dest_len+5+2, origin_len-2);
00820
00821 DCS = octstr_get_char(request->data, 11+dest_len+5+origin_len);
00822 if (!dcs_to_fields(&msg, DCS)) {
00823
00824 debug("bb.sms.oisd", 0, "OISD[%s]: Invalid DCS",
00825 octstr_get_cstr(conn->id));
00826 dcs_to_fields(&msg, 0);
00827 }
00828
00829 add_info = octstr_get_char(request->data,11+dest_len+5+origin_len+2);
00830
00831 msglen7 = octstr_get_char(request->data, 11+dest_len+5+origin_len+3);
00832 msglen8 = octstr_get_char(request->data, 11+dest_len+5+origin_len+4);
00833
00834 msg->sms.rpi = add_info & 0x01;
00835
00836 debug("bb.sms.oisd", 0,
00837 "OISD[%s]: received DCS=%02X, add_info=%d, msglen7=%d, msglen8=%d, rpi=%ld",
00838 octstr_get_cstr(conn->id),
00839 DCS, add_info, msglen7, msglen8, msg->sms.rpi);
00840
00841 if (msg->sms.coding == DC_7BIT) {
00842 msg->sms.msgdata =
00843 oisd_expand_gsm7(octstr_copy(request->data,
00844 11+dest_len+5+origin_len+5,
00845 msglen7));
00846 debug("bb.sms.oisd", 0, "OISD[%s]: received raw8=%s ",
00847 octstr_get_cstr(conn->id),
00848 octstr_get_cstr(msg->sms.msgdata));
00849 if (add_info & 0x02) {
00850 warning(0, "OISD[%s]: 7-bit UDH ?",
00851 octstr_get_cstr(conn->id));
00852 } else {
00853 charset_gsm_to_utf8(msg->sms.msgdata);
00854 debug("bb.sms.oisd", 0, "OISD[%s]: received UTF-8=%s",
00855 octstr_get_cstr(conn->id),
00856 octstr_get_cstr(msg->sms.msgdata));
00857 }
00858 } else {
00859
00860 if (add_info & 0x02) {
00861 udh_len = octstr_get_char(request->data,
00862 11+dest_len+5+origin_len+5)+1;
00863 msg->sms.msgdata =
00864 octstr_copy(request->data,
00865 11+dest_len+5+origin_len+5+udh_len,
00866 msglen8);
00867 msg->sms.udhdata =
00868 octstr_copy(request->data,
00869 11+dest_len+5+origin_len+5,
00870 udh_len);
00871 } else {
00872 msg->sms.msgdata =
00873 octstr_copy(request->data,
00874 11+dest_len+5+origin_len+5,
00875 msglen8);
00876 }
00877 }
00878
00879
00880
00881
00882
00883 if (!(msg->sms.receiver) || octstr_len(msg->sms.receiver) == 0) {
00884 info(0, "OISD[%s]: Got SMS without receiver, discarding.",
00885 octstr_get_cstr(conn->id));
00886 goto error;
00887 }
00888
00889 if (!(msg->sms.sender) || octstr_len(msg->sms.sender) == 0) {
00890 info(0, "OISD[%s]: Got SMS without sender, discarding.",
00891 octstr_get_cstr(conn->id));
00892 goto error;
00893 }
00894
00895 if ((!(msg->sms.msgdata) || octstr_len(msg->sms.msgdata) == 0)
00896 && (!(msg->sms.udhdata) || octstr_len(msg->sms.udhdata) == 0)) {
00897 info(0, "OISD[%s]: Got empty SMS, ignoring.",
00898 octstr_get_cstr(conn->id));
00899 goto error;
00900 }
00901
00902 return msg;
00903
00904 error:
00905 msg_destroy(msg);
00906 return NULL;
00907 }
00908
00909
00910 static void oisd_handle_request(struct packet *request, SMSCConn *conn)
00911 {
00912 PrivData *pdata = conn->data;
00913 Msg *msg = NULL;
00914
00915 if (request->operation == STATUS_REPORT) {
00916 msg = oisd_accept_delivery_report_message(request, conn);
00917 if (msg)
00918 gwlist_append(pdata->received, msg);
00919 } else if (request->operation == DELIVER_SM) {
00920 msg = oisd_accept_message(request, conn);
00921 if (msg)
00922 gwlist_append(pdata->received, msg);
00923 }
00924
00925 oisd_send_response(request, pdata);
00926 }
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939 static int oisd_request(struct packet *request, SMSCConn *conn, Octstr **ts)
00940 {
00941 PrivData *pdata = conn->data;
00942 int ret;
00943 struct packet *reply = NULL;
00944 int errorcode;
00945 int tries = 0;
00946 Octstr *request_name;
00947
00948 gw_assert(pdata != NULL);
00949 gw_assert(request != NULL);
00950 gw_assert(operation_can_send(request->operation));
00951
00952 if (pdata->socket < 0) {
00953 warning(0, "OISD[%s]: oisd_request: socket not open.",
00954 octstr_get_cstr(conn->id));
00955 return -2;
00956 }
00957
00958 packet_set_data_size(request);
00959
00960 retransmit:
00961 packet_set_send_sequence(request, pdata);
00962
00963 request_name = operation_name(request->operation);
00964 debug("bb.sms.oisd", 0, "OISD[%s]: sending %s request",
00965 octstr_get_cstr(conn->id),
00966 octstr_get_cstr(request_name));
00967 octstr_destroy(request_name);
00968 if (request->operation != RETRIEVE_REQUEST)
00969 octstr_dump(request->data, 0);
00970
00971 ret = octstr_write_to_socket(pdata->socket, request->data);
00972 if (ret < 0)
00973 goto io_error;
00974
00975 next_reply:
00976 packet_destroy(reply);
00977 reply = oisd_get_packet(pdata, ts);
00978 if (!reply)
00979 goto io_error;
00980
00981
00982
00983 if (reply->operation < RESPONSE) {
00984 oisd_handle_request(reply, conn);
00985 goto next_reply;
00986 }
00987
00988 if (reply->opref != request->opref) {
00989
00990
00991 warning(0, "OISD[%s]: response had unexpected sequence number; ignoring.",
00992 octstr_get_cstr(conn->id));
00993 goto next_reply;
00994 }
00995
00996 if (reply->operation != request->operation + RESPONSE) {
00997
00998 Octstr *request_name = operation_name(request->operation);
00999 Octstr *reply_name = operation_name(reply->operation);
01000 warning(0, "OISD[%s]: %s request got a %s",
01001 octstr_get_cstr(conn->id),
01002 octstr_get_cstr(request_name),
01003 octstr_get_cstr(reply_name));
01004
01005 octstr_destroy(request_name);
01006 octstr_destroy(reply_name);
01007 octstr_dump(reply->data, 0);
01008 goto retry;
01009 }
01010
01011 errorcode = octstr_get_char(reply->data, 10);
01012
01013 if (errorcode > 0)
01014 goto error;
01015
01016
01017
01018 packet_destroy(reply);
01019 return 0;
01020
01021 io_error:
01022 packet_destroy(reply);
01023 return -2;
01024
01025 error:
01026 packet_destroy(reply);
01027 return -1;
01028
01029 retry:
01030 if (++tries < 3) {
01031 warning(0, "OISD[%s]: Retransmitting (take %d)",
01032 octstr_get_cstr(conn->id),
01033 tries);
01034 goto retransmit;
01035 }
01036 warning(0, "OISD[%s]: Giving up.",
01037 octstr_get_cstr(conn->id));
01038 goto io_error;
01039 }
01040
01041
01042 static void oisd_close_socket(PrivData *pdata)
01043 {
01044 gw_assert(pdata != NULL);
01045
01046 if (pdata->socket < 0)
01047 return;
01048
01049 if (close(pdata->socket) < 0)
01050 warning(errno, "OISD[%s]: error closing socket",
01051 octstr_get_cstr(pdata->conn->id));
01052 pdata->socket = -1;
01053 }
01054
01055
01056
01057
01058
01059
01060
01061 static int oisd_login(SMSCConn *conn)
01062 {
01063 PrivData *pdata = conn->data;
01064 struct packet *packet = NULL;
01065
01066 gw_assert(pdata != NULL);
01067
01068 if (pdata->socket >= 0) {
01069 warning(0, "OISD[%s]: login: socket was already open; closing",
01070 octstr_get_cstr(conn->id));
01071 oisd_close_socket(pdata);
01072 }
01073
01074 pdata->socket = tcpip_connect_to_server(
01075 octstr_get_cstr(pdata->host),
01076 pdata->port,
01077 (conn->our_host ? octstr_get_cstr(conn->our_host) : NULL));
01078 if (pdata->socket != -1) {
01079 info(0, "OISD[%s] logged in.",
01080 octstr_get_cstr(conn->id));
01081 return 0;
01082 }
01083 error(0, "OISD[%s] login failed.",
01084 octstr_get_cstr(conn->id));
01085 oisd_close_socket(pdata);
01086 packet_destroy(packet);
01087 return -1;
01088 }
01089
01090 static int oisd_send_delivery_request(SMSCConn *conn)
01091 {
01092 PrivData *pdata = conn->data;
01093 struct packet *packet = NULL;
01094 int ret;
01095
01096 gw_assert(conn != NULL);
01097
01098 packet = packet_create(RETRIEVE_REQUEST, BOGUS_SEQUENCE);
01099
01100 gw_assert(octstr_check_range(pdata->my_number, 0,
01101 octstr_len(pdata->my_number),
01102 isphonedigit));
01103
01104 octstr_append_char(packet->data,
01105 (char) (octstr_len(pdata->my_number) + 2));
01106
01107 octstr_append_char(packet->data, 0x42);
01108
01109 octstr_append_char(packet->data, 0x44);
01110
01111 octstr_append(packet->data, pdata->my_number);
01112
01113 octstr_append_char(packet->data, 1);
01114
01115 octstr_append_char(packet->data, 0);
01116
01117 ret = oisd_request(packet, conn, NULL);
01118 packet_destroy(packet);
01119
01120 if (ret < 0)
01121 warning(0, "OISD[%s]: Sending delivery request failed.\n",
01122 octstr_get_cstr(conn->id));
01123
01124 return ret;
01125 }
01126
01127 static void oisd_destroy(PrivData *pdata)
01128 {
01129 int discarded;
01130
01131 if (pdata == NULL)
01132 return;
01133
01134 octstr_destroy(pdata->host);
01135 octstr_destroy(pdata->inbuffer);
01136 octstr_destroy(pdata->my_number);
01137
01138 discarded = gwlist_len(pdata->received);
01139 if (discarded > 0)
01140 warning(0, "OISD[%s]: discarded %d received messages",
01141 octstr_get_cstr(pdata->conn->id),
01142 discarded);
01143
01144 gwlist_destroy(pdata->received, msg_destroy_item);
01145 gwlist_destroy(pdata->outgoing_queue, NULL);
01146 gwlist_destroy(pdata->stopped, NULL);
01147
01148 gw_free(pdata);
01149 }
01150
01151 static int oisd_submit_msg(SMSCConn *conn, Msg *msg)
01152 {
01153 PrivData *pdata = conn->data;
01154 struct packet *packet;
01155 Octstr *ts = NULL;
01156 int ret;
01157
01158 gw_assert(pdata != NULL);
01159 debug("bb.sms.oisd", 0, "OISD[%s]: sending message",
01160 octstr_get_cstr(conn->id));
01161
01162 packet = packet_encode_message(msg, conn);
01163 if (!packet) {
01164
01165
01166
01167 bb_smscconn_send_failed(conn, msg,
01168 SMSCCONN_FAILED_MALFORMED, octstr_create("MALFORMED"));
01169 return -1;
01170 }
01171
01172 ret = oisd_request(packet, conn, &ts);
01173 if((ret == 0) && (ts) && DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask) && !pdata->no_dlr) {
01174 dlr_add(conn->name, ts, msg);
01175 }
01176 octstr_destroy(ts);
01177 packet_destroy(packet);
01178
01179 if (ret == -1) {
01180 bb_smscconn_send_failed(conn, msg,
01181 SMSCCONN_FAILED_REJECTED, octstr_create("REJECTED"));
01182 }
01183 else if (ret == -2) {
01184 oisd_close_socket(pdata);
01185 bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_TEMPORARILY, NULL);
01186 mutex_lock(conn->flow_mutex);
01187 conn->status = SMSCCONN_DISCONNECTED;
01188 mutex_unlock(conn->flow_mutex);
01189 }
01190 else {
01191 bb_smscconn_sent(conn, msg, NULL);
01192 }
01193
01194 return ret;
01195 }
01196
01197 static int oisd_receive_msg(SMSCConn *conn, Msg **msg)
01198 {
01199 PrivData *pdata = conn->data;
01200 long ret;
01201 struct packet *packet;
01202
01203 gw_assert(pdata != NULL);
01204
01205 if (gwlist_len(pdata->received) > 0) {
01206 *msg = gwlist_consume(pdata->received);
01207 return 1;
01208 }
01209
01210 if (pdata->socket < 0) {
01211
01212
01213
01214
01215 return 0;
01216 }
01217
01218 ret = read_available(pdata->socket, 0);
01219 if (ret == 0) {
01220 if (pdata->keepalive > 0 && pdata->next_ping < time(NULL)) {
01221 if (oisd_send_delivery_request(conn) < 0)
01222 return -1;
01223 }
01224 return 0;
01225 }
01226
01227 if (ret < 0) {
01228 warning(errno, "OISD[%s]: oisd_receive_msg: read_available failed",
01229 octstr_get_cstr(conn->id));
01230 return -1;
01231 }
01232
01233
01234 ret = octstr_append_from_socket(pdata->inbuffer, pdata->socket);
01235
01236 if (ret == 0) {
01237 warning(0, "OISD[%s]: oisd_receive_msg: service center closed connection.",
01238 octstr_get_cstr(conn->id));
01239 return -1;
01240 }
01241 if (ret < 0) {
01242 warning(0, "OISD[%s]: oisd_receive_msg: read failed",
01243 octstr_get_cstr(conn->id));
01244 return -1;
01245 }
01246
01247
01248 for (;;) {
01249 packet = packet_extract(pdata->inbuffer, conn);
01250 if (!packet)
01251 break;
01252
01253 packet_check_can_receive(packet, conn);
01254 debug("bb.sms.oisd", 0, "OISD[%s]: received",
01255 octstr_get_cstr(pdata->conn->id));
01256 octstr_dump(packet->data, 0);
01257
01258 if (packet->operation < RESPONSE)
01259 oisd_handle_request(packet, conn);
01260 else {
01261 error(0, "OISD[%s]: oisd_receive_msg: unexpected response packet",
01262 octstr_get_cstr(conn->id));
01263 octstr_dump(packet->data, 0);
01264 }
01265
01266 packet_destroy(packet);
01267 }
01268
01269 if (gwlist_len(pdata->received) > 0) {
01270 *msg = gwlist_consume(pdata->received);
01271 return 1;
01272 }
01273 return 0;
01274 }
01275
01276 static Msg *oisd_accept_delivery_report_message(struct packet *request,
01277 SMSCConn *conn)
01278 {
01279 Msg *msg = NULL;
01280 Octstr *destination = NULL;
01281 Octstr *timestamp = NULL;
01282 int st_code;
01283 int code;
01284 int dest_len;
01285
01286
01287 dest_len = octstr_get_char(request->data, 10);
01288
01289 destination = octstr_copy(request->data, 10+1, dest_len);
01290
01291 timestamp = octstr_copy(request->data, 10+1+dest_len+1+4+4, 14);
01292
01293 st_code = octstr_get_char(request->data, 10+1+dest_len+1+4+4+14);
01294
01295 switch (st_code) {
01296 case 1:
01297 case 2:
01298 code = DLR_FAIL;
01299 break;
01300 case 3:
01301 code = DLR_SUCCESS;
01302 break;
01303 case 4:
01304 case 5:
01305 case 6:
01306 default:
01307 code = 0;
01308 }
01309
01310 if (code)
01311 msg = dlr_find(conn->name, timestamp, destination, code);
01312
01313 octstr_destroy(destination);
01314 octstr_destroy(timestamp);
01315
01316 return msg;
01317 }
01318
01319 static Msg *sms_receive(SMSCConn *conn)
01320 {
01321 PrivData *pdata = conn->data;
01322 int ret;
01323 Msg *newmsg = NULL;
01324
01325 ret = oisd_receive_msg(conn, &newmsg);
01326 if (ret == 1) {
01327
01328 newmsg->sms.smsc_id = octstr_duplicate(conn->id);
01329 return newmsg;
01330 }
01331 else if (ret == 0) {
01332 return NULL;
01333 }
01334
01335 msg_destroy(newmsg);
01336 mutex_lock(conn->flow_mutex);
01337 oisd_close_socket(pdata);
01338 conn->status = SMSCCONN_DISCONNECTED;
01339 mutex_unlock(conn->flow_mutex);
01340 return NULL;
01341 }
01342
01343 static void io_thread (void *arg)
01344 {
01345 Msg *msg;
01346 SMSCConn *conn = arg;
01347 PrivData *pdata = conn->data;
01348 double sleep = 0.0001;
01349
01350
01351 log_thread_to(conn->log_idx);
01352
01353
01354 while (!pdata->quitting) {
01355
01356 gwlist_consume(pdata->stopped);
01357
01358
01359 if (conn->status != SMSCCONN_ACTIVE) {
01360 if (oisd_login(conn) != 0) {
01361 error(0, "OISD[%s]: Couldn't connect to SMSC (retrying in %ld seconds).",
01362 octstr_get_cstr(conn->id),
01363 conn->reconnect_delay);
01364 gwthread_sleep(conn->reconnect_delay);
01365 mutex_lock(conn->flow_mutex);
01366 conn->status = SMSCCONN_RECONNECTING;
01367 mutex_unlock(conn->flow_mutex);
01368 continue;
01369 }
01370 mutex_lock(conn->flow_mutex);
01371 conn->status = SMSCCONN_ACTIVE;
01372 conn->connect_time = time(NULL);
01373 bb_smscconn_connected(conn);
01374 mutex_unlock(conn->flow_mutex);
01375 }
01376
01377
01378 do {
01379 msg = sms_receive(conn);
01380 if (msg) {
01381 sleep = 0;
01382 debug("bb.sms.oisd", 0, "OISD[%s]: new message received",
01383 octstr_get_cstr(conn->id));
01384 bb_smscconn_receive(conn, msg);
01385 }
01386 } while (msg);
01387
01388
01389 do {
01390 msg = gwlist_extract_first(pdata->outgoing_queue);
01391 if (msg) {
01392 sleep = 0;
01393 if (oisd_submit_msg(conn, msg) != 0) break;
01394 }
01395 } while (msg);
01396
01397 if (sleep > 0) {
01398
01399
01400
01401
01402 gwthread_sleep(sleep);
01403
01404
01405
01406
01407 sleep *= 2;
01408 if (sleep >= 2.0)
01409 sleep = 1.999999;
01410 }
01411 else {
01412 sleep = 0.0001;
01413 }
01414 }
01415 }
01416
01417 static int oisd_add_msg_cb (SMSCConn *conn, Msg *sms)
01418 {
01419 PrivData *pdata = conn->data;
01420 Msg *copy;
01421
01422 copy = msg_duplicate(sms);
01423 gwlist_produce(pdata->outgoing_queue, copy);
01424 gwthread_wakeup(pdata->io_thread);
01425
01426 return 0;
01427 }
01428
01429 static int oisd_shutdown_cb (SMSCConn *conn, int finish_sending)
01430 {
01431 PrivData *pdata = conn->data;
01432
01433 debug("bb.sms", 0, "Shutting down SMSCConn OISD %s (%s)",
01434 octstr_get_cstr(conn->id),
01435 finish_sending ? "slow" : "instant");
01436
01437
01438
01439 conn->why_killed = SMSCCONN_KILLED_SHUTDOWN;
01440 pdata->quitting = 1;
01441
01442
01443 if (finish_sending == 0) {
01444 Msg *msg;
01445 while ((msg = gwlist_extract_first(pdata->outgoing_queue)) != NULL) {
01446 bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL);
01447 }
01448 }
01449
01450 if (conn->is_stopped) {
01451 gwlist_remove_producer(pdata->stopped);
01452 conn->is_stopped = 0;
01453 }
01454
01455 if (pdata->io_thread != -1) {
01456 gwthread_wakeup(pdata->io_thread);
01457 gwthread_join(pdata->io_thread);
01458 }
01459
01460 oisd_close_socket(pdata);
01461 oisd_destroy(pdata);
01462
01463 debug("bb.sms", 0, "SMSCConn OISD %s shut down.",
01464 octstr_get_cstr(conn->id));
01465 conn->status = SMSCCONN_DEAD;
01466 bb_smscconn_killed();
01467 return 0;
01468 }
01469
01470 static void oisd_start_cb (SMSCConn *conn)
01471 {
01472 PrivData *pdata = conn->data;
01473
01474 gwlist_remove_producer(pdata->stopped);
01475
01476 gwthread_wakeup(pdata->io_thread);
01477 debug("bb.sms", 0, "SMSCConn OISD %s, start called",
01478 octstr_get_cstr(conn->id));
01479 }
01480
01481 static void oisd_stop_cb (SMSCConn *conn)
01482 {
01483 PrivData *pdata = conn->data;
01484 gwlist_add_producer(pdata->stopped);
01485 debug("bb.sms", 0, "SMSCConn OISD %s, stop called",
01486 octstr_get_cstr(conn->id));
01487 }
01488
01489 static long oisd_queued_cb (SMSCConn *conn)
01490 {
01491 PrivData *pdata = conn->data;
01492 conn->load = (pdata ? (conn->status != SMSCCONN_DEAD ?
01493 gwlist_len(pdata->outgoing_queue) : 0) : 0);
01494 return conn->load;
01495 }
01496
01497 int smsc_oisd_create(SMSCConn *conn, CfgGroup *grp)
01498 {
01499 PrivData *pdata;
01500 int ok;
01501
01502 pdata = gw_malloc(sizeof(PrivData));
01503 conn->data = pdata;
01504 pdata->conn = conn;
01505
01506 pdata->no_dlr = 0;
01507 pdata->quitting = 0;
01508 pdata->socket = -1;
01509 pdata->received = gwlist_create();
01510 pdata->inbuffer = octstr_create("");
01511 pdata->send_seq = 1;
01512 pdata->outgoing_queue = gwlist_create();
01513 pdata->stopped = gwlist_create();
01514 gwlist_add_producer(pdata->outgoing_queue);
01515
01516 if (conn->is_stopped)
01517 gwlist_add_producer(pdata->stopped);
01518
01519 pdata->host = cfg_get(grp, octstr_imm("host"));
01520 if (cfg_get_integer(&(pdata->port), grp, octstr_imm("port")) == -1)
01521 pdata->port = 0;
01522 pdata->my_number = cfg_get(grp, octstr_imm("my-number"));
01523 if (cfg_get_integer(&(pdata->keepalive), grp, octstr_imm("keepalive")) == -1)
01524 pdata->keepalive = 0;
01525 if (cfg_get_integer(&(pdata->validityperiod), grp, octstr_imm("validityperiod")) == -1)
01526 pdata->validityperiod = 0;
01527
01528 cfg_get_bool(&pdata->no_dlr, grp, octstr_imm("no-dlr"));
01529
01530
01531 ok = 1;
01532 if (pdata->host == NULL) {
01533 error(0, "OISD[%s]: Configuration file doesn't specify host",
01534 octstr_get_cstr(conn->id));
01535 ok = 0;
01536 }
01537 if (pdata->port == 0) {
01538 error(0, "OISD[%s]: Configuration file doesn't specify port",
01539 octstr_get_cstr(conn->id));
01540 ok = 0;
01541 }
01542 if (pdata->my_number == NULL && pdata->keepalive > 0) {
01543 error(0, "OISD[%s]: Configuration file doesn't specify my-number.",
01544 octstr_get_cstr(conn->id));
01545 ok = 0;
01546 }
01547
01548 if (!ok) {
01549 oisd_destroy(pdata);
01550 return -1;
01551 }
01552
01553 conn->name = octstr_format("OISD:%s:%d",
01554 octstr_get_cstr(pdata->host),
01555 pdata->port);
01556
01557
01558 if (pdata->keepalive > 0) {
01559 debug("bb.sms.oisd", 0, "OISD[%s]: Keepalive set to %ld seconds",
01560 octstr_get_cstr(conn->id),
01561 pdata->keepalive);
01562 pdata->next_ping = time(NULL) + pdata->keepalive;
01563 }
01564
01565 if (pdata->validityperiod > 0) {
01566 debug("bb.sms.oisd", 0, "OISD[%s]: Validity-Period set to %ld",
01567 octstr_get_cstr(conn->id),
01568 pdata->validityperiod);
01569 }
01570
01571 pdata->io_thread = gwthread_create(io_thread, conn);
01572
01573 if (pdata->io_thread == -1) {
01574
01575 error(0, "OISD[%s]: Couldn't start I/O thread.",
01576 octstr_get_cstr(conn->id));
01577 pdata->quitting = 1;
01578 gwthread_wakeup(pdata->io_thread);
01579 gwthread_join(pdata->io_thread);
01580 oisd_destroy(pdata);
01581 return -1;
01582 }
01583
01584 conn->send_msg = oisd_add_msg_cb;
01585 conn->shutdown = oisd_shutdown_cb;
01586 conn->queued = oisd_queued_cb;
01587 conn->start_conn = oisd_start_cb;
01588 conn->stop_conn = oisd_stop_cb;
01589
01590 return 0;
01591 }
01592
See file LICENSE for details about the license agreement for using,
modifying, copying or deriving work from this software.