1 /* ====================================================================
2 * The Kannel Software License, Version 1.0
3 *
4 * Copyright (c) 2001-2014 Kannel Group
5 * Copyright (c) 1998-2001 WapIT Ltd.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. The end-user documentation included with the redistribution,
21 * if any, must include the following acknowledgment:
22 * "This product includes software developed by the
23 * Kannel Group (http://www.kannel.org/)."
24 * Alternately, this acknowledgment may appear in the software itself,
25 * if and wherever such third-party acknowledgments normally appear.
26 *
27 * 4. The names "Kannel" and "Kannel Group" must not be used to
28 * endorse or promote products derived from this software without
29 * prior written permission. For written permission, please
30 * contact org@kannel.org.
31 *
32 * 5. Products derived from this software may not be called "Kannel",
33 * nor may "Kannel" appear in their name, without prior written
34 * permission of the Kannel Group.
35 *
36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47 * ====================================================================
48 *
49 * This software consists of voluntary contributions made by many
50 * individuals on behalf of the Kannel Group. For more information on
51 * the Kannel Group, please see <http://www.kannel.org/>.
52 *
53 * Portions of this software are based upon software originally written at
54 * WapIT Ltd., Helsinki, Finland for the Kannel project.
55 */
56
57 /*
58 * smsc.oisd.c - Driver for Sema Group SMS Center G8.1 (OIS 5.8)
59 * using direct TCP/IP access interface
60 *
61 * Dariusz Markowicz <dm@tenbit.pl> 2002-2004
62 *
63 * This code is based on the CIMD2 module design.
64 *
65 * References:
66 *
67 * [1] Sema SMSC Version G8.1 Open Interface Specification
68 * document version 5.8, 18 January 2001, Sema Telecoms.
69 */
70
71 #include <ctype.h>
72 #include <time.h>
73 #include <errno.h>
74 #include <limits.h>
75 #include <string.h>
76
77 #include <unistd.h>
78
79 #include "gwlib/gwlib.h"
80 #include "smscconn.h"
81 #include "smscconn_p.h"
82 #include "bb_smscconn_cb.h"
83
84 #include "shared.h"
85 #include "sms.h"
86 #include "dlr.h"
87
88
89 typedef struct privdata {
90 Octstr *host;
91 long port;
92 long keepalive;
93 Octstr *my_number;
94 long validityperiod;
95 int no_dlr;
96
97 int socket;
98 unsigned long send_seq;
99
100 Octstr *inbuffer;
101 List *received;
102
103 time_t next_ping;
104
105 List *outgoing_queue;
106 SMSCConn *conn;
107 int io_thread;
108 int quitting;
109 List *stopped; /* list-trick for suspend/isolate */
110
111 } PrivData;
112
113
114
115 /* Microseconds before giving up on a request */
116 #define RESPONSE_TIMEOUT (10 * 1000000)
117 #define RESULT_SUCCESS 0
118
119 enum {
120 INVOKE = 0,
121 RESULT = 1
122 };
123
124 /* Textual names for the operation codes defined by the OISD spec. */
125 /* If you make changes here, also change the operation table. */
126 enum {
127 SUBMIT_SM = 0,
128 STATUS_REPORT = 4,
129 DELIVER_SM = 9,
130 RETRIEVE_REQUEST = 11,
131
132 /* Not a request; add to any request to make it a response */
133 RESPONSE = 50
134 };
135
isphonedigit(int c)136 static int isphonedigit(int c)
137 {
138 return isdigit(c) || c == '+' || c == '-';
139 }
140
parm_valid_address(Octstr * value)141 static int parm_valid_address(Octstr *value)
142 {
143 return octstr_check_range(value, 0, octstr_len(value), isphonedigit);
144 }
145
146 /***************************************************************************/
147 /* Some functions to look up information about operation codes */
148 /***************************************************************************/
149
150 static int operation_find(int operation);
151 static Octstr *operation_name(int operation);
152 static int operation_can_send(int operation);
153 static int operation_can_receive(int operation);
154
155 static const struct
156 {
157 char *name;
158 int code;
159 int can_send;
160 int can_receive;
161 }
162 operations[] = {
163 { "Submit SM", SUBMIT_SM, 1, 0 },
164 { "Status Report", STATUS_REPORT, 0, 1 },
165 { "Deliver SM", DELIVER_SM, 0, 1 },
166 { "Retrieve Request", RETRIEVE_REQUEST, 1, 0 },
167
168 { NULL, 0, 0, 0 }
169 };
170
operation_find(int operation)171 static int operation_find(int operation)
172 {
173 int i;
174
175 for (i = 0; operations[i].name != NULL; i++) {
176 if (operations[i].code == operation)
177 return i;
178 }
179
180 return -1;
181 }
182
183 /* Return a human-readable representation of this operation code */
operation_name(int operation)184 static Octstr *operation_name(int operation)
185 {
186 int i;
187
188 i = operation_find(operation);
189 if (i >= 0)
190 return octstr_create(operations[i].name);
191
192 if (operation >= RESPONSE) {
193 i = operation_find(operation - RESPONSE);
194 if (i >= 0) {
195 Octstr *name = octstr_create(operations[i].name);
196 octstr_append_cstr(name, " response");
197 return name;
198 }
199 }
200
201 /* Put the operation number here when we have octstr_format */
202 return octstr_create("(unknown)");
203 }
204
205 /* Return true if a OISD client may send this operation */
operation_can_send(int operation)206 static int operation_can_send(int operation)
207 {
208 int i = operation_find(operation);
209
210 if (i >= 0)
211 return operations[i].can_send;
212
213 /* If we can receive the request, then we can send the response. */
214 if (operation >= RESPONSE)
215 return operation_can_receive(operation - RESPONSE);
216
217 return 0;
218 }
219
220
221 /* Return true if a OISD server may send this operation */
operation_can_receive(int operation)222 static int operation_can_receive(int operation)
223 {
224 int i = operation_find(operation);
225
226 if (i >= 0)
227 return operations[i].can_receive;
228
229 /* If we can send the request, then we can receive the response. */
230 if (operation >= RESPONSE)
231 return operation_can_send(operation - RESPONSE);
232
233 return 0;
234 }
235
236 /***************************************************************************
237 * Packet encoding/decoding functions. They handle packets at the octet *
238 * level, and know nothing of the network. *
239 ***************************************************************************/
240
241 struct packet
242 {
243 unsigned long opref; /* operation reference */
244 int operation;
245 Octstr *data; /* Encoded packet */
246 };
247
248 /* A reminder that packets are created without a valid sequence number */
249 #define BOGUS_SEQUENCE 0
250
251 static Msg *oisd_accept_delivery_report_message(struct packet *request,
252 SMSCConn *conn);
253
packet_parse_header(struct packet * packet)254 static void packet_parse_header(struct packet *packet)
255 {
256 packet->opref = (octstr_get_char(packet->data, 3) << 24)
257 | (octstr_get_char(packet->data, 2) << 16)
258 | (octstr_get_char(packet->data, 1) << 8)
259 | (octstr_get_char(packet->data, 0));
260
261 packet->operation = octstr_get_char(packet->data, 5);
262 if (octstr_get_char(packet->data, 4) == 1)
263 packet->operation += RESPONSE;
264 }
265
266
267 /*
268 * Accept an Octstr containing one packet, build a struct packet around
269 * it, and return that struct. The Octstr is stored in the struct.
270 * No error checking is done here yet.
271 */
packet_parse(Octstr * packet_data)272 static struct packet *packet_parse(Octstr *packet_data)
273 {
274 struct packet *packet;
275
276 packet = gw_malloc(sizeof(*packet));
277 packet->data = packet_data;
278
279 /* Fill in packet->operation and packet->opref */
280 packet_parse_header(packet);
281
282 return packet;
283 }
284
285 /* Deallocate this packet */
packet_destroy(struct packet * packet)286 static void packet_destroy(struct packet *packet)
287 {
288 if (packet != NULL) {
289 octstr_destroy(packet->data);
290 gw_free(packet);
291 }
292 }
293
294 /*
295 * Find the first packet in "in", delete it from "in", and return it as
296 * a struct. Return NULL if "in" contains no packet. Always delete
297 * leading non-packet data from "in".
298 */
packet_extract(Octstr * in,SMSCConn * conn)299 static struct packet *packet_extract(Octstr *in, SMSCConn *conn)
300 {
301 Octstr *packet;
302 int size, i;
303 static char s[4][4] = {
304 { 0x01, 0x0b, 0x00, 0x00 },
305 { 0x01, 0x00, 0x00, 0x00 },
306 { 0x00, 0x04, 0x00, 0x00 },
307 { 0x00, 0x09, 0x00, 0x00 }
308 }; /* msgtype, oper, 0, 0 */
309 char known_bytes[4];
310
311 if (octstr_len(in) < 10)
312 return NULL;
313 octstr_get_many_chars(known_bytes, in, 4, 4);
314 /* Find s, and delete everything up to it. */
315 /* If packet starts with one of s, it should be good packet */
316 for (i = 0; i < 4; i++) {
317 if (memcmp(s[i], known_bytes, 4) == 0)
318 break;
319 }
320
321 if (i >= 4) {
322 error(0, "OISD[%s]: wrong packet",
323 octstr_get_cstr(conn->id));
324 octstr_dump(in, 0);
325 return NULL;
326 }
327
328 /* Find end of packet */
329 size = (octstr_get_char(in, 9) << 8) | octstr_get_char(in, 8);
330
331 if (size + 10 > octstr_len(in))
332 return NULL;
333
334 packet = octstr_copy(in, 0, size + 10);
335 octstr_delete(in, 0, size + 10);
336
337 return packet_parse(packet);
338 }
339
packet_check_can_receive(struct packet * packet,SMSCConn * conn)340 static void packet_check_can_receive(struct packet *packet, SMSCConn *conn)
341 {
342 gw_assert(packet != NULL);
343
344 if (!operation_can_receive(packet->operation)) {
345 Octstr *name = operation_name(packet->operation);
346 warning(0, "OISD[%s]: SMSC sent us %s request",
347 octstr_get_cstr(conn->id),
348 octstr_get_cstr(name));
349 octstr_destroy(name);
350 }
351 }
352
oisd_expand_gsm7_to_bits(char * bits,Octstr * raw7)353 static int oisd_expand_gsm7_to_bits(char *bits, Octstr *raw7)
354 {
355 int i, j, k;
356 int len;
357 char ch;
358
359 len = octstr_len(raw7) * 7; /* number of bits in the gsm 7-bit msg */
360
361 for (j = i = 0; j < len; ++i) {
362 ch = octstr_get_char(raw7, i);
363 for (k = 0; k < 8; ++k) {
364 bits[j++] = (char) (ch & 0x01);
365 ch >>= 1;
366 }
367 }
368
369 return j;
370 }
371
oisd_expand_gsm7_from_bits(const char * bits,int pos)372 static char oisd_expand_gsm7_from_bits(const char *bits, int pos)
373 {
374 int i;
375 char ch;
376
377 pos *= 7; /* septet position in bits */
378 ch = '\0';
379 for (i = 6; i >= 0; --i) {
380 ch <<= 1;
381 ch |= bits[pos + i];
382 }
383
384 return ch;
385 }
386
oisd_expand_gsm7(Octstr * raw7)387 static Octstr *oisd_expand_gsm7(Octstr *raw7)
388 {
389 Octstr *raw8;
390 int i, len;
391 char *bits;
392
393 raw8 = octstr_create("");
394 bits = gw_malloc(8 * octstr_len(raw7) + 1);
395
396 oisd_expand_gsm7_to_bits(bits, raw7);
397 len = octstr_len(raw7);
398
399 for (i = 0; i < len; ++i) {
400 octstr_append_char(raw8, oisd_expand_gsm7_from_bits(bits, i));
401 }
402
403 gw_free(bits);
404
405 return raw8;
406 }
407
oisd_shrink_gsm7(Octstr * str)408 static void oisd_shrink_gsm7(Octstr *str)
409 {
410 Octstr *result;
411 int len, i;
412 int numbits, value;
413
414 result = octstr_create("");
415 len = octstr_len(str);
416 value = 0;
417 numbits = 0;
418 for (i = 0; i < len; i++) {
419 value += octstr_get_char(str, i) << numbits;
420 numbits += 7;
421 if (numbits >= 8) {
422 octstr_append_char(result, value & 0xff);
423 value >>= 8;
424 numbits -= 8;
425 }
426 }
427 if (numbits > 0)
428 octstr_append_char(result, value);
429 octstr_delete(str, 0, LONG_MAX);
430 octstr_append(str, result);
431 octstr_destroy(result);
432 }
433
434 /****************************************************************************
435 * Packet encoding functions. They do not allow the creation of invalid
436 * OISD packets.
437 ***************************************************************************/
438
439 /* Build a new packet struct with this operation code and sequence number. */
packet_create(int operation,unsigned long opref)440 static struct packet *packet_create(int operation, unsigned long opref)
441 {
442 struct packet *packet;
443 unsigned char header[10];
444
445 packet = gw_malloc(sizeof(*packet));
446 packet->operation = operation;
447 packet->opref = opref;
448
449 /* Opref */
450 header[0] = opref & 0xff;
451 header[1] = (opref >> 8) & 0xff;
452 header[2] = (opref >> 16) & 0xff;
453 header[3] = (opref >> 24) & 0xff;
454
455 /* Message Type & Operation */
456 if (operation > RESPONSE) {
457 header[4] = RESULT;
458 header[5] = operation - RESPONSE;
459 } else {
460 header[4] = INVOKE;
461 header[5] = operation;
462 }
463
464 /* Unused */
465 header[6] = 0;
466 header[7] = 0;
467
468 /* Data Size */
469 header[8] = 0;
470 header[9] = 0;
471
472 packet->data = octstr_create_from_data((char *)header, 10);
473
474 return packet;
475 }
476
packet_set_data_size(struct packet * packet)477 static void packet_set_data_size(struct packet *packet)
478 {
479 int len;
480
481 gw_assert(packet != NULL);
482
483 len = octstr_len(packet->data) - 10;
484
485 octstr_set_char(packet->data, 8, len & 0xff); /* Data Size */
486 octstr_set_char(packet->data, 9, (len >> 8) & 0xff);
487 }
488
packet_set_sequence(struct packet * packet,unsigned long opref)489 static void packet_set_sequence(struct packet *packet, unsigned long opref)
490 {
491 gw_assert(packet != NULL);
492
493 octstr_set_char(packet->data, 0, opref & 0xff);
494 octstr_set_char(packet->data, 1, (opref >> 8) & 0xff);
495 octstr_set_char(packet->data, 2, (opref >> 16) & 0xff);
496 octstr_set_char(packet->data, 3, (opref >> 24) & 0xff);
497 packet->opref = opref;
498 }
499
packet_encode_message(Msg * msg,SMSCConn * conn)500 static struct packet *packet_encode_message(Msg *msg, SMSCConn *conn)
501 {
502 struct packet *packet;
503 PrivData *pdata = conn->data;
504 int DCS;
505 int setvalidity = SMS_PARAM_UNDEFINED;
506 int so = 0;
507 int udhlen7, udhlen8;
508 int msglen7, msglen8;
509 Octstr *udhdata = NULL;
510 Octstr *msgdata = NULL;
511
512 gw_assert(msg != NULL);
513 gw_assert(msg->type == sms);
514 gw_assert(msg->sms.receiver != NULL);
515
516 DCS = fields_to_dcs(msg, 0);
517 if (msg->sms.sender == NULL)
518 msg->sms.sender = octstr_create("");
519
520 if (!parm_valid_address(msg->sms.receiver)) {
521 warning(0, "OISD[%s]: non-digits in destination phone number '%s', discarded",
522 octstr_get_cstr(conn->id),
523 octstr_get_cstr(msg->sms.receiver));
524 return NULL;
525 }
526
527 if (!parm_valid_address(msg->sms.sender)) {
528 warning(0, "OISD[%s]: non-digits in originating phone number '%s', discarded",
529 octstr_get_cstr(conn->id),
530 octstr_get_cstr(msg->sms.sender));
531 return NULL;
532 }
533
534 packet = packet_create(SUBMIT_SM, BOGUS_SEQUENCE);
535
536 gw_assert(octstr_check_range(msg->sms.receiver, 0,
537 octstr_len(msg->sms.receiver), isphonedigit));
538 /* MSISDN length */
539 octstr_append_char(packet->data,
540 (unsigned char) octstr_len(msg->sms.receiver));
541
542 /* MSISDN */
543 octstr_append(packet->data, msg->sms.receiver);
544
545 /* Duplicate msg. behaviour */
546 /* 1=reject duplicates, 2=allow duplicates */
547 octstr_append_char(packet->data, 2);
548
549 /* SME ref. no. unused in this protocol implementation, but set */
550 octstr_append_char(packet->data, 0);
551 octstr_append_char(packet->data, 0);
552 octstr_append_char(packet->data, 0);
553 octstr_append_char(packet->data, 0);
554
555 /* Priority 0=high, 1=normal */
556 octstr_append_char(packet->data, 1);
557 gw_assert(octstr_check_range(msg->sms.sender, 0,
558 octstr_len(msg->sms.sender), isphonedigit));
559
560 /* Originating address length */
561 octstr_append_char(packet->data,
562 (unsigned char) (octstr_len(msg->sms.sender) + 2));
563
564 /* XXX: GSM operator dependent ? */
565 /* TON */
566 octstr_append_char(packet->data, 0x42);
567
568 /* NPI */
569 octstr_append_char(packet->data, 0x44);
570
571 /* Originating address */
572 octstr_append(packet->data, msg->sms.sender);
573
574 /* Validity period type 0=none, 1=absolute, 2=relative */
575
576 /*
577 * Validity-Period (TP-VP)
578 * see GSM 03.40 section 9.2.3.12
579 */
580 if (msg->sms.validity != SMS_PARAM_UNDEFINED)
581 setvalidity = (msg->sms.validity - time(NULL)) / 60;
582 else if (setvalidity != SMS_PARAM_UNDEFINED)
583 setvalidity = pdata->validityperiod;
584 if (setvalidity != SMS_PARAM_UNDEFINED) {
585 /* Validity period type 0=none, 1=absolute, 2=relative */
586 octstr_append_char(packet->data, 2);
587
588 if (setvalidity > 635040)
589 setvalidity = 255;
590 else if (setvalidity >= 50400 && setvalidity <= 635040)
591 setvalidity = (setvalidity - 1) / 7 / 24 / 60 + 192 + 1;
592 else if (setvalidity > 43200 && setvalidity < 50400)
593 setvalidity = 197;
594 else if (setvalidity >= 2880 && setvalidity <= 43200)
595 setvalidity = (setvalidity - 1) / 24 / 60 + 166 + 1;
596 else if (setvalidity > 1440 && setvalidity < 2880)
597 setvalidity = 168;
598 else if (setvalidity >= 750 && setvalidity <= 1440)
599 setvalidity = (setvalidity - 720 - 1) / 30 + 143 + 1;
600 else if (setvalidity > 720 && setvalidity < 750)
601 setvalidity = 144;
602 else if (setvalidity >= 5 && setvalidity <= 720)
603 setvalidity = (setvalidity - 1) / 5 - 1 + 1;
604 else if (setvalidity < 5)
605 setvalidity = 0;
606
607 octstr_append_char(packet->data, setvalidity);
608 } else {
609 /* Validity period type 0=none, 1=absolute, 2=relative */
610 octstr_append_char(packet->data, 0);
611 setvalidity = 0; /* reset */
612 }
613
614 if (setvalidity >= 0 && setvalidity <= 143)
615 debug("bb.smsc.oisd", 0, "OISD[%s]: Validity-Period: %d minutes",
616 octstr_get_cstr(conn->id), (setvalidity + 1)*5);
617 else if (setvalidity >= 144 && setvalidity <= 167)
618 debug("bb.smsc.oisd", 0, "OISD[%s]: Validity-Period: %3.1f hours",
619 octstr_get_cstr(conn->id), ((float)(setvalidity - 143) / 2) + 12);
620 else if (setvalidity >= 168 && setvalidity <= 196)
621 debug("bb.smsc.oisd", 0, "OISD[%s]: Validity-Period: %d days",
622 octstr_get_cstr(conn->id), (setvalidity - 166));
623 else
624 debug("bb.smsc.oisd", 0, "OISD[%s]: Validity-Period: %d weeks",
625 octstr_get_cstr(conn->id), (setvalidity - 192));
626
627 /* Data coding scheme */
628 octstr_append_char(packet->data, DCS);
629
630 /* Explicitly ask not to get status reports.
631 * If we do not do this, the server's default might be to
632 * send status reports in some cases, and we don't do anything
633 * with those reports anyway. */
634 /* ask for the delivery reports if needed*/
635
636 if (!pdata->no_dlr)
637 if (DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask))
638 octstr_append_char(packet->data, 7);
639 else
640 octstr_append_char(packet->data, 0);
641 else if (pdata->no_dlr && DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask))
642 warning(0, "OISD[%s]: dlr request make no sense while no-dlr set to true",
643 octstr_get_cstr(conn->id));
644
645 /* Protocol id 0=default */
646 octstr_append_char(packet->data, 0);
647
648 if (octstr_len(msg->sms.udhdata))
649 so |= 0x02;
650 if (msg->sms.coding == DC_8BIT)
651 so |= 0x10;
652
653 /* Submission options */
654 octstr_append_char(packet->data, so);
655
656 udhlen8 = octstr_len(msg->sms.udhdata);
657 msglen8 = octstr_len(msg->sms.msgdata);
658
659 udhdata = octstr_duplicate(msg->sms.udhdata);
660 msgdata = octstr_duplicate(msg->sms.msgdata);
661
662 if (msg->sms.coding == DC_7BIT || msg->sms.coding == DC_UNDEF) {
663 debug("bb.sms.oisd", 0, "OISD[%s]: sending UTF-8=%s",
664 octstr_get_cstr(conn->id),
665 octstr_get_cstr(msg->sms.msgdata));
666 charset_utf8_to_gsm(msgdata);
667 oisd_shrink_gsm7(msgdata);
668 }
669
670 /* calculate lengths */
671 udhlen7 = octstr_len(udhdata);
672 msglen7 = octstr_len(msgdata);
673
674 octstr_append_char(packet->data, (unsigned char) (udhlen8 + msglen8));
675 octstr_append_char(packet->data, (unsigned char) (udhlen7 + msglen7));
676
677 /*
678 * debug("bb.sms.oisd", 0, "OISD[%s]: packet_encode_message udhlen8=%d, msglen8=%d",
679 * octstr_get_cstr(conn->id), udhlen8, msglen8);
680 * debug("bb.sms.oisd", 0, "OISD[%s]: packet_encode_message udhlen7=%d, msglen7=%d",
681 * octstr_get_cstr(conn->id), udhlen7, msglen7);
682 */
683
684 /* copy text */
685 octstr_append(packet->data, udhdata);
686 octstr_append(packet->data, msgdata);
687
688 /* Sub-logical SME number */
689 octstr_append_char(packet->data, 0);
690 octstr_append_char(packet->data, 0);
691
692 octstr_destroy(udhdata);
693 octstr_destroy(msgdata);
694
695 return packet;
696 }
697
698 /***************************************************************************
699 * Protocol functions. These implement various transactions. *
700 ***************************************************************************/
701
702 /* Give this packet a proper sequence number for sending. */
packet_set_send_sequence(struct packet * packet,PrivData * pdata)703 static void packet_set_send_sequence(struct packet *packet, PrivData *pdata)
704 {
705 gw_assert(pdata != NULL);
706
707 packet_set_sequence(packet, pdata->send_seq);
708 pdata->send_seq++;
709 }
710
oisd_get_packet(PrivData * pdata,Octstr ** ts)711 static struct packet *oisd_get_packet(PrivData *pdata, Octstr **ts)
712 {
713 struct packet *packet = NULL;
714
715 gw_assert(pdata != NULL);
716
717 /* If packet is already available, don't try to read anything */
718 packet = packet_extract(pdata->inbuffer, pdata->conn);
719
720 while (packet == NULL) {
721 if (read_available(pdata->socket, RESPONSE_TIMEOUT) != 1) {
722 warning(0, "OISD[%s]: SMSC is not responding",
723 octstr_get_cstr(pdata->conn->id));
724 return NULL;
725 }
726
727 if (octstr_append_from_socket(pdata->inbuffer, pdata->socket) <= 0) {
728 error(0, "OISD[%s]: oisd_get_packet: read failed",
729 octstr_get_cstr(pdata->conn->id));
730 return NULL;
731 }
732
733 packet = packet_extract(pdata->inbuffer, pdata->conn);
734 }
735
736 packet_check_can_receive(packet, pdata->conn);
737 debug("bb.sms.oisd", 0, "OISD[%s]: received",
738 octstr_get_cstr(pdata->conn->id));
739 if (packet->operation != RETRIEVE_REQUEST + RESPONSE)
740 octstr_dump(packet->data, 0);
741 if (ts)
742 *ts = octstr_copy(packet->data, 15, 14);
743
744 if (pdata->keepalive > 0)
745 pdata->next_ping = time(NULL) + pdata->keepalive;
746
747 return packet;
748 }
749
750 /*
751 * Acknowledge a request.
752 */
oisd_send_response(struct packet * request,PrivData * pdata)753 static void oisd_send_response(struct packet *request, PrivData *pdata)
754 {
755 struct packet *response;
756
757 gw_assert(request != NULL);
758 gw_assert(request->operation < RESPONSE);
759
760 response = packet_create(request->operation + RESPONSE, request->opref);
761
762 octstr_append_char(response->data, (char) RESULT_SUCCESS);
763
764 packet_set_data_size(response);
765
766 debug("bb.sms.oisd", 0, "OISD[%s]: sending response",
767 octstr_get_cstr(pdata->conn->id));
768 octstr_dump(response->data, 0);
769
770 /* Don't check errors here because if there is something
771 * wrong with the socket, the main loop will detect it. */
772 octstr_write_to_socket(pdata->socket, response->data);
773
774 packet_destroy(response);
775 }
776
oisd_accept_message(struct packet * request,SMSCConn * conn)777 static Msg *oisd_accept_message(struct packet *request, SMSCConn *conn)
778 {
779 Msg *msg = NULL;
780 int DCS;
781 int dest_len;
782 int origin_len;
783 int add_info;
784 int msglen7, msglen8;
785 int udh_len;
786
787 msg = msg_create(sms);
788
789 /* See GSM 03.38. The bit patterns we can handle are:
790 * 000xyyxx Uncompressed text, yy indicates alphabet.
791 * yy = 00, default alphabet
792 * yy = 01, 8-bit data
793 * yy = 10, UCS-2
794 * yy = 11, reserved
795 * 1111xyxx Data, y indicates alphabet.
796 * y = 0, default alphabet
797 * y = 1, 8-bit data
798 */
799
800 /* Additional information
801 * xxxxxxyz This field conveys additional information to assist
802 * the recipient in interpreting the SM.
803 * z = reply path
804 * y = user data header indicator
805 * x = reserved
806 */
807
808 /*
809 * Destination addr. and Originating addr. w/o TOA
810 */
811
812 /* Destination addr. length */
813 dest_len = octstr_get_char(request->data, 10);
814
815 /* Destination addr. */
816 msg->sms.receiver = octstr_copy(request->data, 11+2, dest_len-2);
817
818 /* Originating addr. length */
819 origin_len = octstr_get_char(request->data, 11+dest_len+4);
820
821 /* Originating addr. */
822 msg->sms.sender = octstr_copy(request->data, 11+dest_len+5+2, origin_len-2);
823
824 DCS = octstr_get_char(request->data, 11+dest_len+5+origin_len);
825 if (!dcs_to_fields(&msg, DCS)) {
826 /* XXX: Should reject this message ? */
827 debug("bb.sms.oisd", 0, "OISD[%s]: Invalid DCS",
828 octstr_get_cstr(conn->id));
829 dcs_to_fields(&msg, 0);
830 }
831
832 add_info = octstr_get_char(request->data,11+dest_len+5+origin_len+2);
833
834 msglen7 = octstr_get_char(request->data, 11+dest_len+5+origin_len+3);
835 msglen8 = octstr_get_char(request->data, 11+dest_len+5+origin_len+4);
836
837 msg->sms.rpi = add_info & 0x01;
838
839 debug("bb.sms.oisd", 0,
840 "OISD[%s]: received DCS=%02X, add_info=%d, msglen7=%d, msglen8=%d, rpi=%ld",
841 octstr_get_cstr(conn->id),
842 DCS, add_info, msglen7, msglen8, msg->sms.rpi);
843
844 if (msg->sms.coding == DC_7BIT) {
845 msg->sms.msgdata =
846 oisd_expand_gsm7(octstr_copy(request->data,
847 11+dest_len+5+origin_len+5,
848 msglen7));
849 debug("bb.sms.oisd", 0, "OISD[%s]: received raw8=%s ",
850 octstr_get_cstr(conn->id),
851 octstr_get_cstr(msg->sms.msgdata));
852 if (add_info & 0x02) {
853 warning(0, "OISD[%s]: 7-bit UDH ?",
854 octstr_get_cstr(conn->id));
855 } else {
856 charset_gsm_to_utf8(msg->sms.msgdata);
857 debug("bb.sms.oisd", 0, "OISD[%s]: received UTF-8=%s",
858 octstr_get_cstr(conn->id),
859 octstr_get_cstr(msg->sms.msgdata));
860 }
861 } else {
862 /* 0xf4, 0xf5, 0xf6, 0xf7; 8bit to disp, mem, sim or term */
863 if (add_info & 0x02) {
864 udh_len = octstr_get_char(request->data,
865 11+dest_len+5+origin_len+5)+1;
866 msg->sms.msgdata =
867 octstr_copy(request->data,
868 11+dest_len+5+origin_len+5+udh_len,
869 msglen8);
870 msg->sms.udhdata =
871 octstr_copy(request->data,
872 11+dest_len+5+origin_len+5,
873 udh_len);
874 } else {
875 msg->sms.msgdata =
876 octstr_copy(request->data,
877 11+dest_len+5+origin_len+5,
878 msglen8);
879 }
880 }
881
882 /* Code elsewhere in the gateway always expects the sender and
883 * receiver fields to be filled, so we discard messages that
884 * lack them. If they should not be discarded, then the code
885 * handling sms messages should be reviewed. -- RB */
886 if (!(msg->sms.receiver) || octstr_len(msg->sms.receiver) == 0) {
887 info(0, "OISD[%s]: Got SMS without receiver, discarding.",
888 octstr_get_cstr(conn->id));
889 goto error;
890 }
891
892 if (!(msg->sms.sender) || octstr_len(msg->sms.sender) == 0) {
893 info(0, "OISD[%s]: Got SMS without sender, discarding.",
894 octstr_get_cstr(conn->id));
895 goto error;
896 }
897
898 if ((!(msg->sms.msgdata) || octstr_len(msg->sms.msgdata) == 0)
899 && (!(msg->sms.udhdata) || octstr_len(msg->sms.udhdata) == 0)) {
900 msg->sms.msgdata = octstr_create("");
901 }
902
903 return msg;
904
905 error:
906 msg_destroy(msg);
907 return NULL;
908 }
909
910 /* Deal with a request from the OISD server, and acknowledge it. */
oisd_handle_request(struct packet * request,SMSCConn * conn)911 static void oisd_handle_request(struct packet *request, SMSCConn *conn)
912 {
913 PrivData *pdata = conn->data;
914 Msg *msg = NULL;
915
916 if (request->operation == STATUS_REPORT) {
917 msg = oisd_accept_delivery_report_message(request, conn);
918 if (msg)
919 gwlist_append(pdata->received, msg);
920 } else if (request->operation == DELIVER_SM) {
921 msg = oisd_accept_message(request, conn);
922 if (msg)
923 gwlist_append(pdata->received, msg);
924 }
925
926 oisd_send_response(request, pdata);
927 }
928
929 /* Send a request and wait for the ack. If the other side responds with
930 * an error code, attempt to correct and retry.
931 * If other packets arrive while we wait for the ack, handle them.
932 *
933 * Return -1 if the SMSC refused the request. Return -2 for other
934 * errors, such as being unable to send the request at all. If the
935 * function returns -2, the caller would do well to try to reopen the
936 * connection.
937 *
938 * The SMSCenter must be already open.
939 */
oisd_request(struct packet * request,SMSCConn * conn,Octstr ** ts)940 static int oisd_request(struct packet *request, SMSCConn *conn, Octstr **ts)
941 {
942 PrivData *pdata = conn->data;
943 int ret;
944 struct packet *reply = NULL;
945 int errorcode;
946 int tries = 0;
947 Octstr *request_name;
948
949 gw_assert(pdata != NULL);
950 gw_assert(request != NULL);
951 gw_assert(operation_can_send(request->operation));
952
953 if (pdata->socket < 0) {
954 warning(0, "OISD[%s]: oisd_request: socket not open.",
955 octstr_get_cstr(conn->id));
956 return -2;
957 }
958
959 packet_set_data_size(request);
960
961 retransmit:
962 packet_set_send_sequence(request, pdata);
963
964 request_name = operation_name(request->operation);
965 debug("bb.sms.oisd", 0, "OISD[%s]: sending %s request",
966 octstr_get_cstr(conn->id),
967 octstr_get_cstr(request_name));
968 octstr_destroy(request_name);
969 if (request->operation != RETRIEVE_REQUEST)
970 octstr_dump(request->data, 0);
971
972 ret = octstr_write_to_socket(pdata->socket, request->data);
973 if (ret < 0)
974 goto io_error;
975
976 next_reply:
977 packet_destroy(reply); /* destroy old, if any */
978 reply = oisd_get_packet(pdata, ts);
979 if (!reply)
980 goto io_error;
981
982 /* The server sent us a request. Handle it, then wait for
983 * a new reply. */
984 if (reply->operation < RESPONSE) {
985 oisd_handle_request(reply, conn);
986 goto next_reply;
987 }
988
989 if (reply->opref != request->opref) {
990 /* We got a response to a different request number than
991 * what we send. Strange. */
992 warning(0, "OISD[%s]: response had unexpected sequence number; ignoring.",
993 octstr_get_cstr(conn->id));
994 goto next_reply;
995 }
996
997 if (reply->operation != request->operation + RESPONSE) {
998 /* We got a response that didn't match our request */
999 Octstr *request_name = operation_name(request->operation);
1000 Octstr *reply_name = operation_name(reply->operation);
1001 warning(0, "OISD[%s]: %s request got a %s",
1002 octstr_get_cstr(conn->id),
1003 octstr_get_cstr(request_name),
1004 octstr_get_cstr(reply_name));
1005
1006 octstr_destroy(request_name);
1007 octstr_destroy(reply_name);
1008 octstr_dump(reply->data, 0);
1009 goto retry;
1010 }
1011
1012 errorcode = octstr_get_char(reply->data, 10); /* Result */
1013
1014 if (errorcode > 0)
1015 goto error;
1016
1017 /* The reply passed all the checks... looks like the SMSC accepted
1018 * our request! */
1019 packet_destroy(reply);
1020 return 0;
1021
1022 io_error:
1023 packet_destroy(reply);
1024 return -2;
1025
1026 error:
1027 packet_destroy(reply);
1028 return -1;
1029
1030 retry:
1031 if (++tries < 3) {
1032 warning(0, "OISD[%s]: Retransmitting (take %d)",
1033 octstr_get_cstr(conn->id),
1034 tries);
1035 goto retransmit;
1036 }
1037 warning(0, "OISD[%s]: Giving up.",
1038 octstr_get_cstr(conn->id));
1039 goto io_error;
1040 }
1041
1042 /* Close the SMSC socket without fanfare. */
oisd_close_socket(PrivData * pdata)1043 static void oisd_close_socket(PrivData *pdata)
1044 {
1045 gw_assert(pdata != NULL);
1046
1047 if (pdata->socket < 0)
1048 return;
1049
1050 if (close(pdata->socket) < 0)
1051 warning(errno, "OISD[%s]: error closing socket",
1052 octstr_get_cstr(pdata->conn->id));
1053 pdata->socket = -1;
1054 }
1055
1056 /*
1057 * Open a socket to the SMSC, send a login packet, and wait for ack.
1058 * This may block. Return 0 for success, or -1 for failure.
1059 * Make sure the socket is closed before calling this function, otherwise
1060 * we will leak fd's.
1061 */
oisd_login(SMSCConn * conn)1062 static int oisd_login(SMSCConn *conn)
1063 {
1064 PrivData *pdata = conn->data;
1065 struct packet *packet = NULL;
1066
1067 gw_assert(pdata != NULL);
1068
1069 if (pdata->socket >= 0) {
1070 warning(0, "OISD[%s]: login: socket was already open; closing",
1071 octstr_get_cstr(conn->id));
1072 oisd_close_socket(pdata);
1073 }
1074
1075 pdata->socket = tcpip_connect_to_server(
1076 octstr_get_cstr(pdata->host),
1077 pdata->port,
1078 (conn->our_host ? octstr_get_cstr(conn->our_host) : NULL));
1079 if (pdata->socket != -1) {
1080 info(0, "OISD[%s] logged in.",
1081 octstr_get_cstr(conn->id));
1082 return 0;
1083 }
1084 error(0, "OISD[%s] login failed.",
1085 octstr_get_cstr(conn->id));
1086 oisd_close_socket(pdata);
1087 packet_destroy(packet);
1088 return -1;
1089 }
1090
oisd_send_delivery_request(SMSCConn * conn)1091 static int oisd_send_delivery_request(SMSCConn *conn)
1092 {
1093 PrivData *pdata = conn->data;
1094 struct packet *packet = NULL;
1095 int ret;
1096
1097 gw_assert(conn != NULL);
1098
1099 packet = packet_create(RETRIEVE_REQUEST, BOGUS_SEQUENCE);
1100
1101 gw_assert(octstr_check_range(pdata->my_number, 0,
1102 octstr_len(pdata->my_number),
1103 isphonedigit));
1104 /* Originating address length */
1105 octstr_append_char(packet->data,
1106 (char) (octstr_len(pdata->my_number) + 2));
1107 /* TON */
1108 octstr_append_char(packet->data, 0x42);
1109 /* NPI */
1110 octstr_append_char(packet->data, 0x44);
1111 /* Originating address */
1112 octstr_append(packet->data, pdata->my_number);
1113 /* Receive ready flag */
1114 octstr_append_char(packet->data, 1);
1115 /* Retrieve order */
1116 octstr_append_char(packet->data, 0);
1117
1118 ret = oisd_request(packet, conn, NULL);
1119 packet_destroy(packet);
1120
1121 if (ret < 0)
1122 warning(0, "OISD[%s]: Sending delivery request failed.\n",
1123 octstr_get_cstr(conn->id));
1124
1125 return ret;
1126 }
1127
oisd_destroy(PrivData * pdata)1128 static void oisd_destroy(PrivData *pdata)
1129 {
1130 int discarded;
1131
1132 if (pdata == NULL)
1133 return;
1134
1135 octstr_destroy(pdata->host);
1136 octstr_destroy(pdata->inbuffer);
1137 octstr_destroy(pdata->my_number);
1138
1139 discarded = gwlist_len(pdata->received);
1140 if (discarded > 0)
1141 warning(0, "OISD[%s]: discarded %d received messages",
1142 octstr_get_cstr(pdata->conn->id),
1143 discarded);
1144
1145 gwlist_destroy(pdata->received, msg_destroy_item);
1146 gwlist_destroy(pdata->outgoing_queue, NULL);
1147 gwlist_destroy(pdata->stopped, NULL);
1148
1149 gw_free(pdata);
1150 }
1151
oisd_submit_msg(SMSCConn * conn,Msg * msg)1152 static int oisd_submit_msg(SMSCConn *conn, Msg *msg)
1153 {
1154 PrivData *pdata = conn->data;
1155 struct packet *packet;
1156 Octstr *ts = NULL;
1157 int ret;
1158
1159 gw_assert(pdata != NULL);
1160 debug("bb.sms.oisd", 0, "OISD[%s]: sending message",
1161 octstr_get_cstr(conn->id));
1162
1163 packet = packet_encode_message(msg, conn);
1164 if (!packet) {
1165 /* This is a protocol error. Does this help? I doubt..
1166 * But nevermind that.
1167 */
1168 bb_smscconn_send_failed(conn, msg,
1169 SMSCCONN_FAILED_MALFORMED, octstr_create("MALFORMED"));
1170 return -1;
1171 }
1172
1173 ret = oisd_request(packet, conn, &ts);
1174 if((ret == 0) && (ts) && DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask) && !pdata->no_dlr) {
1175 dlr_add(conn->name, ts, msg, 0);
1176 }
1177 octstr_destroy(ts);
1178 packet_destroy(packet);
1179
1180 if (ret == -1) {
1181 bb_smscconn_send_failed(conn, msg,
1182 SMSCCONN_FAILED_REJECTED, octstr_create("REJECTED"));
1183 }
1184 else if (ret == -2) {
1185 oisd_close_socket(pdata);
1186 bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_TEMPORARILY, NULL);
1187 mutex_lock(conn->flow_mutex);
1188 conn->status = SMSCCONN_DISCONNECTED;
1189 mutex_unlock(conn->flow_mutex);
1190 }
1191 else {
1192 bb_smscconn_sent(conn, msg, NULL);
1193 }
1194
1195 return ret;
1196 }
1197
oisd_receive_msg(SMSCConn * conn,Msg ** msg)1198 static int oisd_receive_msg(SMSCConn *conn, Msg **msg)
1199 {
1200 PrivData *pdata = conn->data;
1201 long ret;
1202 struct packet *packet;
1203
1204 gw_assert(pdata != NULL);
1205
1206 if (gwlist_len(pdata->received) > 0) {
1207 *msg = gwlist_consume(pdata->received);
1208 return 1;
1209 }
1210
1211 if (pdata->socket < 0) {
1212 /* XXX We have to assume that smsc_send_message is
1213 * currently trying to reopen, so we have to make
1214 * this thread wait. It should be done in a nicer
1215 * way. */
1216 return 0;
1217 }
1218
1219 ret = read_available(pdata->socket, 0);
1220 if (ret == 0) {
1221 if (pdata->keepalive > 0 && pdata->next_ping < time(NULL)) {
1222 if (oisd_send_delivery_request(conn) < 0)
1223 return -1;
1224 }
1225 return 0;
1226 }
1227
1228 if (ret < 0) {
1229 warning(errno, "OISD[%s]: oisd_receive_msg: read_available failed",
1230 octstr_get_cstr(conn->id));
1231 return -1;
1232 }
1233
1234 /* We have some data waiting... see if it is an sms delivery. */
1235 ret = octstr_append_from_socket(pdata->inbuffer, pdata->socket);
1236
1237 if (ret == 0) {
1238 warning(0, "OISD[%s]: oisd_receive_msg: service center closed connection.",
1239 octstr_get_cstr(conn->id));
1240 return -1;
1241 }
1242 if (ret < 0) {
1243 warning(0, "OISD[%s]: oisd_receive_msg: read failed",
1244 octstr_get_cstr(conn->id));
1245 return -1;
1246 }
1247
1248
1249 for (;;) {
1250 packet = packet_extract(pdata->inbuffer, conn);
1251 if (!packet)
1252 break;
1253
1254 packet_check_can_receive(packet, conn);
1255 debug("bb.sms.oisd", 0, "OISD[%s]: received",
1256 octstr_get_cstr(pdata->conn->id));
1257 octstr_dump(packet->data, 0);
1258
1259 if (packet->operation < RESPONSE)
1260 oisd_handle_request(packet, conn);
1261 else {
1262 error(0, "OISD[%s]: oisd_receive_msg: unexpected response packet",
1263 octstr_get_cstr(conn->id));
1264 octstr_dump(packet->data, 0);
1265 }
1266
1267 packet_destroy(packet);
1268 }
1269
1270 if (gwlist_len(pdata->received) > 0) {
1271 *msg = gwlist_consume(pdata->received);
1272 return 1;
1273 }
1274 return 0;
1275 }
1276
oisd_accept_delivery_report_message(struct packet * request,SMSCConn * conn)1277 static Msg *oisd_accept_delivery_report_message(struct packet *request,
1278 SMSCConn *conn)
1279 {
1280 Msg *msg = NULL;
1281 Octstr *destination = NULL;
1282 Octstr *timestamp = NULL;
1283 int st_code;
1284 int code;
1285 int dest_len;
1286
1287 /* MSISDN length */
1288 dest_len = octstr_get_char(request->data, 10);
1289 /* MSISDN */
1290 destination = octstr_copy(request->data, 10+1, dest_len);
1291 /* Accept time */
1292 timestamp = octstr_copy(request->data, 10+1+dest_len+1+4+4, 14);
1293 /* SM status */
1294 st_code = octstr_get_char(request->data, 10+1+dest_len+1+4+4+14);
1295
1296 switch (st_code) {
1297 case 1:
1298 case 2:
1299 code = DLR_FAIL;
1300 break;
1301 case 3: /* success */
1302 code = DLR_SUCCESS;
1303 break;
1304 case 4:
1305 case 5:
1306 case 6:
1307 default:
1308 code = 0;
1309 }
1310
1311 if (code)
1312 msg = dlr_find(conn->name, timestamp, destination, code, 0);
1313
1314 octstr_destroy(destination);
1315 octstr_destroy(timestamp);
1316
1317 return msg;
1318 }
1319
sms_receive(SMSCConn * conn)1320 static Msg *sms_receive(SMSCConn *conn)
1321 {
1322 PrivData *pdata = conn->data;
1323 int ret;
1324 Msg *newmsg = NULL;
1325
1326 ret = oisd_receive_msg(conn, &newmsg);
1327 if (ret == 1) {
1328 /* if any smsc_id available, use it */
1329 newmsg->sms.smsc_id = octstr_duplicate(conn->id);
1330 return newmsg;
1331 }
1332 else if (ret == 0) { /* no message, just retry... */
1333 return NULL;
1334 }
1335 /* error. reconnect. */
1336 msg_destroy(newmsg);
1337 mutex_lock(conn->flow_mutex);
1338 oisd_close_socket(pdata);
1339 conn->status = SMSCCONN_DISCONNECTED;
1340 mutex_unlock(conn->flow_mutex);
1341 return NULL;
1342 }
1343
io_thread(void * arg)1344 static void io_thread (void *arg)
1345 {
1346 Msg *msg;
1347 SMSCConn *conn = arg;
1348 PrivData *pdata = conn->data;
1349 double sleep = 0.0001;
1350
1351 /* Make sure we log into our own log-file if defined */
1352 log_thread_to(conn->log_idx);
1353
1354 /* remove messages from SMSC until we are killed */
1355 while (!pdata->quitting) {
1356
1357 gwlist_consume(pdata->stopped); /* block here if suspended/isolated */
1358
1359 /* check that connection is active */
1360 if (conn->status != SMSCCONN_ACTIVE) {
1361 if (oisd_login(conn) != 0) {
1362 error(0, "OISD[%s]: Couldn't connect to SMSC (retrying in %ld seconds).",
1363 octstr_get_cstr(conn->id),
1364 conn->reconnect_delay);
1365 gwthread_sleep(conn->reconnect_delay);
1366 mutex_lock(conn->flow_mutex);
1367 conn->status = SMSCCONN_RECONNECTING;
1368 mutex_unlock(conn->flow_mutex);
1369 continue;
1370 }
1371 mutex_lock(conn->flow_mutex);
1372 conn->status = SMSCCONN_ACTIVE;
1373 conn->connect_time = time(NULL);
1374 bb_smscconn_connected(conn);
1375 mutex_unlock(conn->flow_mutex);
1376 }
1377
1378 /* receive messages */
1379 do {
1380 msg = sms_receive(conn);
1381 if (msg) {
1382 sleep = 0;
1383 debug("bb.sms.oisd", 0, "OISD[%s]: new message received",
1384 octstr_get_cstr(conn->id));
1385 bb_smscconn_receive(conn, msg);
1386 }
1387 } while (msg);
1388
1389 /* send messages */
1390 do {
1391 msg = gwlist_extract_first(pdata->outgoing_queue);
1392 if (msg) {
1393 sleep = 0;
1394 if (oisd_submit_msg(conn, msg) != 0) break;
1395 }
1396 } while (msg);
1397
1398 if (sleep > 0) {
1399
1400 /* note that this implementations means that we sleep even
1401 * when we fail connection.. but time is very short, anyway
1402 */
1403 gwthread_sleep(sleep);
1404 /* gradually sleep longer and longer times until something starts to
1405 * happen - this of course reduces response time, but that's better than
1406 * extensive CPU usage when it is not used
1407 */
1408 sleep *= 2;
1409 if (sleep >= 2.0)
1410 sleep = 1.999999;
1411 }
1412 else {
1413 sleep = 0.0001;
1414 }
1415 }
1416 }
1417
oisd_add_msg_cb(SMSCConn * conn,Msg * sms)1418 static int oisd_add_msg_cb (SMSCConn *conn, Msg *sms)
1419 {
1420 PrivData *pdata = conn->data;
1421 Msg *copy;
1422
1423 copy = msg_duplicate(sms);
1424 gwlist_produce(pdata->outgoing_queue, copy);
1425 gwthread_wakeup(pdata->io_thread);
1426
1427 return 0;
1428 }
1429
oisd_shutdown_cb(SMSCConn * conn,int finish_sending)1430 static int oisd_shutdown_cb (SMSCConn *conn, int finish_sending)
1431 {
1432 PrivData *pdata = conn->data;
1433
1434 debug("bb.sms", 0, "Shutting down SMSCConn OISD %s (%s)",
1435 octstr_get_cstr(conn->id),
1436 finish_sending ? "slow" : "instant");
1437
1438 /* Documentation claims this would have been done by smscconn.c,
1439 but isn't when this code is being written. */
1440 conn->why_killed = SMSCCONN_KILLED_SHUTDOWN;
1441 pdata->quitting = 1; /* Separate from why_killed to avoid locking, as
1442 * why_killed may be changed from outside? */
1443
1444 if (finish_sending == 0) {
1445 Msg *msg;
1446 while ((msg = gwlist_extract_first(pdata->outgoing_queue)) != NULL) {
1447 bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL);
1448 }
1449 }
1450
1451 if (conn->is_stopped) {
1452 gwlist_remove_producer(pdata->stopped);
1453 conn->is_stopped = 0;
1454 }
1455
1456 if (pdata->io_thread != -1) {
1457 gwthread_wakeup(pdata->io_thread);
1458 gwthread_join(pdata->io_thread);
1459 }
1460
1461 oisd_close_socket(pdata);
1462 oisd_destroy(pdata);
1463
1464 debug("bb.sms", 0, "SMSCConn OISD %s shut down.",
1465 octstr_get_cstr(conn->id));
1466 conn->status = SMSCCONN_DEAD;
1467 bb_smscconn_killed();
1468 return 0;
1469 }
1470
oisd_start_cb(SMSCConn * conn)1471 static void oisd_start_cb (SMSCConn *conn)
1472 {
1473 PrivData *pdata = conn->data;
1474
1475 gwlist_remove_producer(pdata->stopped);
1476 /* in case there are messages in the buffer already */
1477 gwthread_wakeup(pdata->io_thread);
1478 debug("bb.sms", 0, "SMSCConn OISD %s, start called",
1479 octstr_get_cstr(conn->id));
1480 }
1481
oisd_stop_cb(SMSCConn * conn)1482 static void oisd_stop_cb (SMSCConn *conn)
1483 {
1484 PrivData *pdata = conn->data;
1485 gwlist_add_producer(pdata->stopped);
1486 debug("bb.sms", 0, "SMSCConn OISD %s, stop called",
1487 octstr_get_cstr(conn->id));
1488 }
1489
oisd_queued_cb(SMSCConn * conn)1490 static long oisd_queued_cb (SMSCConn *conn)
1491 {
1492 PrivData *pdata = conn->data;
1493 conn->load = (pdata ? (conn->status != SMSCCONN_DEAD ?
1494 gwlist_len(pdata->outgoing_queue) : 0) : 0);
1495 return conn->load;
1496 }
1497
smsc_oisd_create(SMSCConn * conn,CfgGroup * grp)1498 int smsc_oisd_create(SMSCConn *conn, CfgGroup *grp)
1499 {
1500 PrivData *pdata;
1501 int ok;
1502
1503 pdata = gw_malloc(sizeof(PrivData));
1504 conn->data = pdata;
1505 pdata->conn = conn;
1506
1507 pdata->no_dlr = 0;
1508 pdata->quitting = 0;
1509 pdata->socket = -1;
1510 pdata->received = gwlist_create();
1511 pdata->inbuffer = octstr_create("");
1512 pdata->send_seq = 1;
1513 pdata->outgoing_queue = gwlist_create();
1514 pdata->stopped = gwlist_create();
1515 gwlist_add_producer(pdata->outgoing_queue);
1516
1517 if (conn->is_stopped)
1518 gwlist_add_producer(pdata->stopped);
1519
1520 pdata->host = cfg_get(grp, octstr_imm("host"));
1521 if (cfg_get_integer(&(pdata->port), grp, octstr_imm("port")) == -1)
1522 pdata->port = 0;
1523 pdata->my_number = cfg_get(grp, octstr_imm("my-number"));
1524 if (cfg_get_integer(&(pdata->keepalive), grp, octstr_imm("keepalive")) == -1)
1525 pdata->keepalive = 0;
1526 if (cfg_get_integer(&(pdata->validityperiod), grp, octstr_imm("validityperiod")) == -1)
1527 pdata->validityperiod = SMS_PARAM_UNDEFINED;
1528
1529 cfg_get_bool(&pdata->no_dlr, grp, octstr_imm("no-dlr"));
1530
1531 /* Check that config is OK */
1532 ok = 1;
1533 if (pdata->host == NULL) {
1534 error(0, "OISD[%s]: Configuration file doesn't specify host",
1535 octstr_get_cstr(conn->id));
1536 ok = 0;
1537 }
1538 if (pdata->port == 0) {
1539 error(0, "OISD[%s]: Configuration file doesn't specify port",
1540 octstr_get_cstr(conn->id));
1541 ok = 0;
1542 }
1543 if (pdata->my_number == NULL && pdata->keepalive > 0) {
1544 error(0, "OISD[%s]: Configuration file doesn't specify my-number.",
1545 octstr_get_cstr(conn->id));
1546 ok = 0;
1547 }
1548
1549 if (!ok) {
1550 oisd_destroy(pdata);
1551 return -1;
1552 }
1553
1554 conn->name = octstr_format("OISD:%s:%d",
1555 octstr_get_cstr(pdata->host),
1556 pdata->port);
1557
1558
1559 if (pdata->keepalive > 0) {
1560 debug("bb.sms.oisd", 0, "OISD[%s]: Keepalive set to %ld seconds",
1561 octstr_get_cstr(conn->id),
1562 pdata->keepalive);
1563 pdata->next_ping = time(NULL) + pdata->keepalive;
1564 }
1565
1566 if (pdata->validityperiod > 0) {
1567 debug("bb.sms.oisd", 0, "OISD[%s]: Validity-Period set to %ld",
1568 octstr_get_cstr(conn->id),
1569 pdata->validityperiod);
1570 }
1571
1572 pdata->io_thread = gwthread_create(io_thread, conn);
1573
1574 if (pdata->io_thread == -1) {
1575
1576 error(0, "OISD[%s]: Couldn't start I/O thread.",
1577 octstr_get_cstr(conn->id));
1578 pdata->quitting = 1;
1579 gwthread_wakeup(pdata->io_thread);
1580 gwthread_join(pdata->io_thread);
1581 oisd_destroy(pdata);
1582 return -1;
1583 }
1584
1585 conn->send_msg = oisd_add_msg_cb;
1586 conn->shutdown = oisd_shutdown_cb;
1587 conn->queued = oisd_queued_cb;
1588 conn->start_conn = oisd_start_cb;
1589 conn->stop_conn = oisd_stop_cb;
1590
1591 return 0;
1592 }
1593
1594