Kannel: Open Source WAP and SMS gateway  $Revision: 5037 $
smsc_oisd.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2016 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;
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 
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 {
131 
132  /* Not a request; add to any request to make it a response */
133  RESPONSE = 50
134 };
135 
136 static int isphonedigit(int c)
137 {
138  return isdigit(c) || c == '+' || c == '-';
139 }
140 
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;
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 
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 */
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 */
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 */
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 
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  */
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 */
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  */
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 
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 
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 
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 
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) {
401  }
402 
403  gw_free(bits);
404 
405  return raw8;
406 }
407 
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. */
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 
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 
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 
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 
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. */
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 
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  */
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 
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 =
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. */
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  */
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);
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. */
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  */
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 
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 
1092 {
1093  PrivData *pdata = conn->data;
1094  struct packet *packet = NULL;
1095  int ret;
1096 
1097  gw_assert(conn != NULL);
1098 
1100 
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 
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 
1146  gwlist_destroy(pdata->outgoing_queue, NULL);
1147  gwlist_destroy(pdata->stopped, NULL);
1148 
1149  gw_free(pdata);
1150 }
1151 
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,
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,
1183  }
1184  else if (ret == -2) {
1185  oisd_close_socket(pdata);
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 
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 
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 
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 
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);
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 
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 
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. */
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) {
1448  }
1449  }
1450 
1451  if (conn->is_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;
1468  return 0;
1469 }
1470 
1471 static void oisd_start_cb (SMSCConn *conn)
1472 {
1473  PrivData *pdata = conn->data;
1474 
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 
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 
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 
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();
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)
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 
int port
Definition: smsc_cgw.c:159
Octstr * name
Definition: smscconn_p.h:173
static struct packet * packet_extract(Octstr *in, SMSCConn *conn)
Definition: smsc_oisd.c:299
void error(int err, const char *fmt,...)
Definition: log.c:612
int smsc_oisd_create(SMSCConn *conn, CfgGroup *grp)
Definition: smsc_oisd.c:1498
static char oisd_expand_gsm7_from_bits(const char *bits, int pos)
Definition: smsc_oisd.c:372
int operation
Definition: smsc_cimd2.c:444
void info(int err, const char *fmt,...)
Definition: log.c:636
int octstr_write_to_socket(int socket, Octstr *ostr)
Definition: octstr.c:1225
Msg * msg_duplicate(Msg *msg)
Definition: msg.c:111
static Msg * oisd_accept_message(struct packet *request, SMSCConn *conn)
Definition: smsc_oisd.c:777
void bb_smscconn_connected(SMSCConn *conn)
Definition: bb_smscconn.c:192
int size
Definition: wsasm.c:84
#define BOGUS_SEQUENCE
Definition: smsc_oisd.c:249
int code
Definition: smsc_oisd.c:158
static int oisd_receive_msg(SMSCConn *conn, Msg **msg)
Definition: smsc_oisd.c:1198
Octstr * inbuffer
Definition: smsc_cimd2.c:112
#define RESULT_SUCCESS
Definition: smsc_oisd.c:117
static void io_thread(void *arg)
Definition: smsc_oisd.c:1344
#define mutex_unlock(m)
Definition: thread.h:136
void gwlist_append(List *list, void *item)
Definition: list.c:179
int tcpip_connect_to_server(char *hostname, int port, const char *source_addr)
Definition: socket.c:149
void bb_smscconn_killed(void)
Definition: bb_smscconn.c:199
static void oisd_stop_cb(SMSCConn *conn)
Definition: smsc_oisd.c:1482
int octstr_check_range(Octstr *ostr, long pos, long len, octstr_func_t filter)
Definition: octstr.c:812
void octstr_append(Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:1502
void gwlist_produce(List *list, void *item)
Definition: list.c:411
Octstr * id
Definition: smscconn_p.h:174
void gwthread_join(long thread)
int can_receive
Definition: smsc_oisd.c:160
long gwlist_len(List *list)
Definition: list.c:166
long validityperiod
Definition: smsc_oisd.c:94
void * data
Definition: smscconn_p.h:249
int octstr_append_from_socket(Octstr *ostr, int socket)
Definition: octstr.c:1278
static void packet_parse_header(struct packet *packet)
Definition: smsc_oisd.c:254
static void packet_set_sequence(struct packet *packet, unsigned long opref)
Definition: smsc_oisd.c:489
List * outgoing_queue
Definition: smsc_cgw.c:153
void(* stop_conn)(SMSCConn *conn)
Definition: smscconn_p.h:246
void octstr_append_char(Octstr *ostr, int ch)
Definition: octstr.c:1515
void charset_utf8_to_gsm(Octstr *ostr)
Definition: charset.c:288
int socket
Definition: smsc_cimd2.c:108
static Msg * oisd_accept_delivery_report_message(struct packet *request, SMSCConn *conn)
Definition: smsc_oisd.c:1277
int log_idx
Definition: smscconn_p.h:197
#define cfg_get(grp, varname)
Definition: cfg.h:86
#define DC_8BIT
Definition: sms.h:111
static int oisd_request(struct packet *request, SMSCConn *conn, Octstr **ts)
Definition: smsc_oisd.c:940
static void packet_check_can_receive(struct packet *packet, SMSCConn *conn)
Definition: smsc_oisd.c:340
#define msg_create(type)
Definition: msg.h:136
static void oisd_shrink_gsm7(Octstr *str)
Definition: smsc_oisd.c:408
int io_thread
Definition: smsc_cimd2.c:119
static int isphonedigit(int c)
Definition: smsc_oisd.c:136
Octstr * our_host
Definition: smscconn_p.h:192
void octstr_append_cstr(Octstr *ostr, const char *cstr)
Definition: octstr.c:1509
Msg * dlr_find(const Octstr *smsc, const Octstr *ts, const Octstr *dst, int typ, int use_dst)
Definition: dlr.c:387
void dlr_add(const Octstr *smsc, const Octstr *ts, Msg *msg, int use_dst)
Definition: dlr.c:330
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
#define octstr_copy(ostr, from, len)
Definition: octstr.h:178
void(* start_conn)(SMSCConn *conn)
Definition: smscconn_p.h:245
long reconnect_delay
Definition: smscconn_p.h:199
void log_thread_to(int idx)
Definition: log.c:723
List * stopped
Definition: smsc_cimd2.c:121
int can_send
Definition: smsc_oisd.c:159
time_t next_ping
Definition: smsc_cimd2.c:115
static int oisd_add_msg_cb(SMSCConn *conn, Msg *sms)
Definition: smsc_oisd.c:1418
static struct packet * packet_parse(Octstr *packet_data)
Definition: smsc_oisd.c:272
smscconn_killed_t why_killed
Definition: smscconn_p.h:153
static void oisd_start_cb(SMSCConn *conn)
Definition: smsc_oisd.c:1471
#define DLR_SUCCESS
Definition: dlr.h:72
static void oisd_close_socket(PrivData *pdata)
Definition: smsc_oisd.c:1043
void msg_destroy_item(void *msg)
Definition: msg.c:147
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:281
Definition: msg.h:79
Octstr * my_number
Definition: smsc_cimd2.c:105
void * gwlist_extract_first(List *list)
Definition: list.c:305
void octstr_delete(Octstr *ostr1, long pos, long len)
Definition: octstr.c:1525
void gwlist_remove_producer(List *list)
Definition: list.c:401
Octstr * data
Definition: smsc_cimd2.c:446
long bb_smscconn_receive(SMSCConn *conn, Msg *sms)
Definition: bb_smscconn.c:478
static void packet_destroy(struct packet *packet)
Definition: smsc_oisd.c:286
time_t connect_time
Definition: smscconn_p.h:155
#define octstr_duplicate(ostr)
Definition: octstr.h:187
#define octstr_dump(ostr, level,...)
Definition: octstr.h:564
Mutex * flow_mutex
Definition: smscconn_p.h:157
static struct packet * packet_create(int operation, unsigned long opref)
Definition: smsc_oisd.c:440
void msg_destroy(Msg *msg)
Definition: msg.c:132
static void oisd_destroy(PrivData *pdata)
Definition: smsc_oisd.c:1128
void warning(int err, const char *fmt,...)
Definition: log.c:624
Octstr * host
Definition: smsc_cgw.c:163
int quitting
Definition: smsc_cimd2.c:120
Octstr * octstr_format(const char *fmt,...)
Definition: octstr.c:2462
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
static int oisd_expand_gsm7_to_bits(char *bits, Octstr *raw7)
Definition: smsc_oisd.c:353
#define gwthread_create(func, arg)
Definition: gwthread.h:90
#define octstr_create(cstr)
Definition: octstr.h:125
int fields_to_dcs(Msg *msg, int mode)
Definition: sms.c:73
gw_assert(wtls_machine->packet_to_send!=NULL)
void gwthread_sleep(double seconds)
static void packet_set_data_size(struct packet *packet)
Definition: smsc_oisd.c:477
#define SMS_PARAM_UNDEFINED
Definition: sms.h:91
static int oisd_submit_msg(SMSCConn *conn, Msg *msg)
Definition: smsc_oisd.c:1152
static int operation_can_receive(int operation)
Definition: smsc_oisd.c:222
static Octstr * operation_name(int operation)
Definition: smsc_oisd.c:184
volatile sig_atomic_t is_stopped
Definition: smscconn_p.h:169
static void packet_set_send_sequence(struct packet *packet, PrivData *pdata)
Definition: smsc_oisd.c:703
static int operation_can_send(int operation)
Definition: smsc_oisd.c:206
static long oisd_queued_cb(SMSCConn *conn)
Definition: smsc_oisd.c:1490
static struct packet * packet_encode_message(Msg *msg, SMSCConn *conn)
Definition: smsc_oisd.c:500
int send_seq
Definition: smsc_cimd2.c:109
static int oisd_send_delivery_request(SMSCConn *conn)
Definition: smsc_oisd.c:1091
int no_dlr
Definition: smsc_cimd2.c:106
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
unsigned long send_seq
Definition: smsc_oisd.c:98
int cfg_get_bool(int *n, CfgGroup *grp, Octstr *varname)
Definition: cfg.c:756
Definition: octstr.c:118
void bb_smscconn_sent(SMSCConn *conn, Msg *sms, Octstr *reply)
Definition: bb_smscconn.c:279
void * gwlist_consume(List *list)
Definition: list.c:427
int read_available(int fd, long wait_usec)
Definition: socket.c:406
static void oisd_send_response(struct packet *request, PrivData *pdata)
Definition: smsc_oisd.c:753
int(* shutdown)(SMSCConn *conn, int finish_sending)
Definition: smscconn_p.h:229
static const struct @26 operations[]
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
int cfg_get_integer(long *n, CfgGroup *grp, Octstr *varname)
Definition: cfg.c:739
Definition: wtp_tid.h:82
struct privdata PrivData
void gwthread_wakeup(long thread)
Definition: cfg.c:73
List * received
Definition: smsc_cimd2.c:113
smscconn_status_t status
Definition: smscconn_p.h:151
#define gwlist_create()
Definition: list.h:136
long(* queued)(SMSCConn *conn)
Definition: smscconn_p.h:240
enum msg_type type
Definition: msg.h:80
int(* send_msg)(SMSCConn *conn, Msg *msg)
Definition: smscconn_p.h:235
unsigned long opref
Definition: smsc_oisd.c:243
void bb_smscconn_send_failed(SMSCConn *conn, Msg *sms, int reason, Octstr *reply)
Definition: bb_smscconn.c:328
#define RESPONSE_TIMEOUT
Definition: smsc_oisd.c:116
int dcs_to_fields(Msg **msg, int dcs)
Definition: sms.c:139
static struct packet * oisd_get_packet(PrivData *pdata, Octstr **ts)
Definition: smsc_oisd.c:711
#define DC_UNDEF
Definition: sms.h:109
static Octstr * oisd_expand_gsm7(Octstr *raw7)
Definition: smsc_oisd.c:387
void gwlist_add_producer(List *list)
Definition: list.c:383
static Msg * sms_receive(SMSCConn *conn)
Definition: smsc_oisd.c:1320
static int response(List *push_headers, Octstr **username, Octstr **password)
void octstr_get_many_chars(char *buf, Octstr *ostr, long pos, long len)
Definition: octstr.c:423
int octstr_get_char(const Octstr *ostr, long pos)
Definition: octstr.c:404
#define mutex_lock(m)
Definition: thread.h:130
static int parm_valid_address(Octstr *value)
Definition: smsc_oisd.c:141
void octstr_set_char(Octstr *ostr, long pos, int ch)
Definition: octstr.c:413
#define octstr_create_from_data(data, len)
Definition: octstr.h:134
static void oisd_handle_request(struct packet *request, SMSCConn *conn)
Definition: smsc_oisd.c:911
long keepalive
Definition: smsc_cimd2.c:104
Definition: list.c:102
static int oisd_shutdown_cb(SMSCConn *conn, int finish_sending)
Definition: smsc_oisd.c:1430
char * name
Definition: smsc_oisd.c:157
static int oisd_login(SMSCConn *conn)
Definition: smsc_oisd.c:1062
#define DLR_IS_SUCCESS_OR_FAIL(dlr)
Definition: dlr.h:85
static XMLRPCDocument * msg
Definition: test_xmlrpc.c:86
#define DLR_FAIL
Definition: dlr.h:73
static int operation_find(int operation)
Definition: smsc_oisd.c:171
static void reply(HTTPClient *c, List *push_headers)
#define DC_7BIT
Definition: sms.h:110
SMSCConn * conn
Definition: smsc_cimd2.c:118
int load
Definition: smscconn_p.h:152
void charset_gsm_to_utf8(Octstr *ostr)
Definition: charset.c:220
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.