Kannel: Open Source WAP and SMS gateway  svn-r5335
sqlbox.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2004 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  * sqlbox.c - main program of the sqlbox
59  */
60 
61 #include <errno.h>
62 #include <unistd.h>
63 #include <signal.h>
64 #include <string.h>
65 
66 #include "gwlib/gwlib.h"
67 #include "gwlib/dbpool.h"
68 #include "gw/msg.h"
69 #include "gw/sms.h"
70 #include "gw/shared.h"
71 #include "gw/bb.h"
72 #include "sqlbox_sql.h"
73 
74 /* our config */
75 static Cfg *cfg;
76 /* have we received restart cmd from bearerbox? */
77 static volatile sig_atomic_t restart_sqlbox = 0;
78 static volatile sig_atomic_t sqlbox_status;
79 #define SQL_DEAD 0
80 #define SQL_SHUTDOWN 1
81 #define SQL_RUNNING 2
82 static long sqlbox_port;
83 static int sqlbox_port_ssl = 0;
84 static long bearerbox_port;
86 static int bearerbox_port_ssl = 0;
88 static long limit_per_cycle;
89 static int save_mo, save_mt, save_dlr;
90 
91 #if !defined(HAVE_MSSQL) && !defined(HAVE_MYSQL) && !defined(HAVE_PGSQL) && !defined(HAVE_SDB) && \
92  !defined(HAVE_SQLITE) && !defined(HAVE_SQLITE3) && !defined(HAVE_ORACLE)
93 #error You need support for at least one DB engine. Please recompile Kannel.
94 #endif
96 
97 #define SLEEP_BETWEEN_EMPTY_SELECTS 1.0
98 #define DEFAULT_LIMIT_PER_CYCLE 10
99 
100 typedef struct _boxc {
103  time_t connect_time;
104  Octstr *client_ip;
105  volatile sig_atomic_t alive;
106  Octstr *boxc_id; /* identifies the connected smsbox instance */
107 } Boxc;
108 
109 /*
110  * Adding hooks to kannel check config
111  *
112  * Martin Conte.
113  */
114 
115 static int sqlbox_is_allowed_in_group(Octstr *group, Octstr *variable)
116 {
117  Octstr *groupstr;
118 
119  groupstr = octstr_imm("group");
120 
121  #define OCTSTR(name) \
122  if (octstr_compare(octstr_imm(#name), variable) == 0) \
123  return 1;
124  #define SINGLE_GROUP(name, fields) \
125  if (octstr_compare(octstr_imm(#name), group) == 0) { \
126  if (octstr_compare(groupstr, variable) == 0) \
127  return 1; \
128  fields \
129  return 0; \
130  }
131  #define MULTI_GROUP(name, fields) \
132  if (octstr_compare(octstr_imm(#name), group) == 0) { \
133  if (octstr_compare(groupstr, variable) == 0) \
134  return 1; \
135  fields \
136  return 0; \
137  }
138  #include "sqlbox-cfg.def"
139 
140  return 0;
141 }
142 
143 #undef OCTSTR
144 #undef SINGLE_GROUP
145 #undef MULTI_GROUP
146 
147 static int sqlbox_is_single_group(Octstr *query)
148 {
149  #define OCTSTR(name)
150  #define SINGLE_GROUP(name, fields) \
151  if (octstr_compare(octstr_imm(#name), query) == 0) \
152  return 1;
153  #define MULTI_GROUP(name, fields) \
154  if (octstr_compare(octstr_imm(#name), query) == 0) \
155  return 0;
156  #include "sqlbox-cfg.def"
157  return 0;
158 }
159 
160 
161 /****************************************************************************
162  * Character convertion.
163  *
164  * The 'msgdata' is read from the DB table as URL-encoded byte stream,
165  * which we need to URL-decode to get the orginal message. We use this
166  * approach to get rid of the table character dependancy of the DB systems.
167  * The URL-encoded chars as a subset of ASCII which is typicall no problem
168  * for any of the supported DB systems.
169  */
170 
172 {
173  gw_assert(msg->type == sms);
174 
175  /* URL-decode first */
176  if (octstr_url_decode(msg->sms.msgdata) == -1)
177  return -1;
178  if (octstr_url_decode(msg->sms.udhdata) == -1)
179  return -1;
180 
181  /* If a specific character encoding has been indicated by the
182  * user, then make sure we convert to our internal representations. */
183  if (octstr_len(msg->sms.charset)) {
184 
185  if (msg->sms.coding == DC_7BIT) {
186  /* For 7 bit, convert to UTF-8 */
187  if (charset_convert(msg->sms.msgdata, octstr_get_cstr(msg->sms.charset), "UTF-8") < 0)
188  return -1;
189  }
190  else if (msg->sms.coding == DC_UCS2) {
191  /* For UCS-2, convert to UTF-16BE */
192  if (charset_convert(msg->sms.msgdata, octstr_get_cstr(msg->sms.charset), "UTF-16BE") < 0)
193  return -1;
194  }
195  }
196 
197  return 0;
198 }
199 
200 
201 /*
202  *-------------------------------------------------
203  * receiver thingies
204  *-------------------------------------------------
205  *
206 */
207 
208 /* read from either smsbox or bearerbox */
209 
210 static Msg *read_from_box(Connection *conn, Boxc *boxconn)
211 {
212  Msg *msg;
213 
214  while (boxconn->alive) {
215  switch (read_from_bearerbox_real(conn, &msg, 1.0)) {
216  case -1:
217  /* connection to bearerbox lost */
218  return NULL;
219  break;
220  case 0:
221  /* all is well */
222  return msg;
223  break;
224  case 1:
225  /* timeout */
226  break;
227  }
228  }
229 
230  return NULL;
231 }
232 
233 /*
234  *-------------------------------------------------
235  * sender thingies
236  *-------------------------------------------------
237  *
238 */
239 
240 /* send to either smsbox or bearerbox */
241 
242 static int send_msg(Connection *conn, Boxc *boxconn, Msg *pmsg)
243 {
244  Octstr *pack;
245 
246  pack = msg_pack(pmsg);
247 
248  if (pack == NULL)
249  return -1;
250 
251  if (conn_write_withlen(conn, pack) == -1) {
252  error(0, "Couldn't write Msg to box <%s>, disconnecting",
253  octstr_get_cstr(boxconn->client_ip));
254  octstr_destroy(pack);
255  return -1;
256  }
257  octstr_destroy(pack);
258  return 0;
259 }
260 
261 static void smsbox_to_bearerbox(void *arg)
262 {
263  Boxc *conn = arg;
264  Msg *msg, *msg_escaped;
265 
266  /* remove messages from socket until it is closed */
267  while (sqlbox_status == SQL_RUNNING && conn->alive) {
268 
269  //list_consume(suspended); /* block here if suspended */
270 
271  msg = read_from_box(conn->smsbox_connection, conn);
272 
273  if (msg == NULL) { /* garbage/connection lost */
274  conn->alive = 0;
275  break;
276  }
277 
278  if (msg_type(msg) == sms) {
279  debug("sqlbox", 0, "smsbox_to_bearerbox: sms received");
280  if (save_mt) {
281  msg_escaped = msg_duplicate(msg);
282  /* convert validity & deferred to minutes */
283  if (msg_escaped->sms.validity != SMS_PARAM_UNDEFINED)
284  msg_escaped->sms.validity = (msg_escaped->sms.validity - time(NULL))/60;
285  if (msg_escaped->sms.deferred != SMS_PARAM_UNDEFINED)
286  msg_escaped->sms.deferred = (msg_escaped->sms.deferred - time(NULL))/60;
287  gw_sql_save_msg(msg_escaped, octstr_imm("MT"));
288  msg_destroy(msg_escaped);
289  }
290  }
291 
292  send_msg(conn->bearerbox_connection, conn, msg);
293 
294  /* if this is an identification message from an smsbox instance */
295  if (msg_type(msg) == admin && msg->admin.command == cmd_identify) {
296  /*
297  * any smsbox sends this command even if boxc_id is NULL,
298  * but we will only consider real identified boxes
299  */
300  if (msg->admin.boxc_id != NULL) {
301 
302  /* and add the boxc_id into conn for boxc_status() output */
303  conn->boxc_id = msg->admin.boxc_id;
304  msg->admin.boxc_id = NULL;
305 
306  debug("sqlbox", 0, "smsbox_to_bearerbox: got boxc_id <%s> from <%s>",
307  octstr_get_cstr(conn->boxc_id),
308  octstr_get_cstr(conn->client_ip));
309  }
310  }
311  msg_destroy(msg);
312  }
313  conn->alive = 0;
314 }
315 
316 static Boxc *boxc_create(int fd, Octstr *ip, int ssl)
317 {
318  Boxc *boxc;
319 
320  boxc = gw_malloc(sizeof(Boxc));
321  boxc->smsbox_connection = conn_wrap_fd(fd, ssl);
322  boxc->bearerbox_connection = NULL;
323  boxc->client_ip = ip;
324  boxc->alive = 1;
325  boxc->connect_time = time(NULL);
326  boxc->boxc_id = NULL;
327  return boxc;
328 }
329 
330 static void boxc_destroy(Boxc *boxc)
331 {
332  if (boxc == NULL)
333  return;
334 
335  /* do nothing to the lists, as they are only references */
336 
337  if (boxc->smsbox_connection)
339  if (boxc->bearerbox_connection)
341  octstr_destroy(boxc->client_ip);
342  octstr_destroy(boxc->boxc_id);
343  gw_free(boxc);
344 }
345 
346 
347 static Boxc *accept_boxc(int fd, int ssl)
348 {
349  Boxc *newconn;
350  Octstr *ip;
351 
352  int newfd;
353  struct sockaddr_in client_addr;
354  socklen_t client_addr_len;
355 
356  client_addr_len = sizeof(client_addr);
357 
358  newfd = accept(fd, (struct sockaddr *)&client_addr, &client_addr_len);
359  if (newfd < 0)
360  return NULL;
361 
362  ip = host_ip(client_addr);
363 
364  // if (is_allowed_ip(box_allow_ip, box_deny_ip, ip) == 0) {
365  // info(0, "Box connection tried from denied host <%s>, disconnected",
366  // octstr_get_cstr(ip));
367  // octstr_destroy(ip);
368  // close(newfd);
369  // return NULL;
370  // }
371  newconn = boxc_create(newfd, ip, ssl);
372 
373  /*
374  * check if the SSL handshake was successfull, otherwise
375  * this is no valid box connection any more
376  */
377 #ifdef HAVE_LIBSSL
378  if (ssl && !conn_get_ssl(newconn->smsbox_connection))
379  return NULL;
380 #endif
381 
382  if (ssl)
383  info(0, "Client connected from <%s> using SSL", octstr_get_cstr(ip));
384  else
385  info(0, "Client connected from <%s>", octstr_get_cstr(ip));
386 
387 
388  /* XXX TODO: do the hand-shake, baby, yeah-yeah! */
389 
390  return newconn;
391 }
392 
393 
394 static void bearerbox_to_smsbox(void *arg)
395 {
396  Msg *msg, *msg_escaped;
397  Boxc *conn = arg;
398 
399  while (sqlbox_status == SQL_RUNNING && conn->alive) {
400 
401  msg = read_from_box(conn->bearerbox_connection, conn);
402 
403  if (msg == NULL) {
404  /* tell sqlbox to die */
405  conn->alive = 0;
406  debug("sqlbox", 0, "bearerbox_to_smsbox: connection to bearerbox died.");
407  break;
408  }
409  if (msg_type(msg) == admin) {
410  if (msg->admin.command == cmd_shutdown || msg->admin.command == cmd_restart) {
411  /* tell sqlbox to die */
412  conn->alive = 0;
413  debug("sqlbox", 0, "bearerbox_to_smsbox: Bearerbox told us to shutdown.");
414  break;
415  }
416  }
417 
418  if (msg_type(msg) == heartbeat) {
419  // todo
420  debug("sqlbox", 0, "bearerbox_to_smsbox: catch an heartbeat - we are alive");
421  msg_destroy(msg);
422  continue;
423  }
424  if (!conn->alive) {
425  msg_destroy(msg);
426  break;
427  }
428  if (msg_type(msg) == sms) {
429  msg_escaped = msg_duplicate(msg);
430  if (msg->sms.sms_type != report_mo) {
431  if (save_mo) {
432  gw_sql_save_msg(msg_escaped, octstr_imm("MO"));
433  }
434  }
435  else {
436  if (save_dlr) {
437  gw_sql_save_msg(msg_escaped, octstr_imm("DLR"));
438  }
439  }
440  msg_destroy(msg_escaped);
441  }
442  send_msg(conn->smsbox_connection, conn, msg);
443  msg_destroy(msg);
444  }
445  /* the client closes the connection, after that die in receiver */
446  conn->alive = 0;
447 }
448 
449 static void run_sqlbox(void *arg)
450 {
451  int fd;
452  Boxc *newconn;
453  long sender;
454 
455  fd = (int)arg;
456  newconn = accept_boxc(fd, sqlbox_port_ssl);
457  if (newconn == NULL) {
458  panic(0, "Socket accept failed");
459  return;
460  }
462  /* XXX add our_host if required */
463 
464 
465  sender = gwthread_create(bearerbox_to_smsbox, newconn);
466  if (sender == -1) {
467  error(0, "Failed to start a new thread, disconnecting client <%s>",
468  octstr_get_cstr(newconn->client_ip));
469  //goto cleanup;
470  }
471  smsbox_to_bearerbox(newconn);
472  gwthread_join(sender);
473  boxc_destroy(newconn);
474 }
475 
476 static void wait_for_connections(int fd, void (*function) (void *arg),
477  List *waited)
478 {
479  int ret;
480  int timeout = 10; /* 10 sec. */
481 
482  gw_assert(function != NULL);
483 
484  while(sqlbox_status == SQL_RUNNING) {
485 
486  ret = gwthread_pollfd(fd, POLLIN, 1.0);
487  if (sqlbox_status == SQL_SHUTDOWN) {
488  if (ret == -1 || !timeout)
489  break;
490  else
491  timeout--;
492  }
493 
494  if (ret > 0) {
495  gwthread_create(function, (void *)fd);
496  gwthread_sleep(1.0);
497  } else if (ret < 0) {
498  if(errno==EINTR) continue;
499  if(errno==EAGAIN) continue;
500  error(errno, "wait_for_connections failed");
501  }
502  }
503 }
504 
505 /*
506  * Identify ourself to bearerbox for smsbox-specific routing inside bearerbox.
507  * Do this even while no smsbox-id is given to unlock the sender thread in
508  * bearerbox.
509  */
510 static void identify_to_bearerbox(Boxc *conn)
511 {
512  Msg *msg;
513 
514  msg = msg_create(admin);
515  msg->admin.command = cmd_identify;
516  msg->admin.boxc_id = octstr_duplicate(conn->boxc_id);
517  send_msg(conn->bearerbox_connection, conn, msg);
518  msg_destroy(msg);
519 }
520 
521 static void bearerbox_to_sql(void *arg)
522 {
523  Boxc *conn = (Boxc *)arg;
524  Msg *msg, *mack;
525 
526  while (sqlbox_status == SQL_RUNNING && conn->alive) {
527  msg = read_from_box(conn->bearerbox_connection, conn);
528 
529  if (msg == NULL) { /* garbage/connection lost */
530  /* tell sqlbox to die */
531  conn->alive = 0;
533  debug("sqlbox", 0, "bearerbox_to_sql: connection to bearerbox died.");
534  break;
535  }
536  if (msg_type(msg) == heartbeat) {
537  // todo
538  debug("sqlbox", 0, "bearerbox_to_sql: catch an heartbeat - we are alive");
539  msg_destroy(msg);
540  continue;
541  }
542  /* if this is an identification message from an smsbox instance */
543  if (msg_type(msg) == admin && msg->admin.command == cmd_shutdown) {
544  /* tell sqlbox to die */
545  conn->alive = 0;
547  debug("sqlbox", 0, "bearerbox_to_sql: Bearerbox told us to shutdown.");
548  break;
549  }
550  if (msg_type(msg) == sms) {
551  if (msg->sms.sms_type != report_mo) {
552  if (save_mo) {
554  }
555  }
556  else {
557  if (save_dlr) {
558  gw_sql_save_msg(msg, octstr_imm("DLR"));
559  }
560  }
561 
562  /* create ack message */
563  mack = msg_create(ack);
564  mack->ack.nack = ack_success;
565  mack->ack.time = msg->sms.time;
566  uuid_copy(mack->ack.id, msg->sms.id);
567  send_msg(conn->bearerbox_connection, conn, mack);
568  msg_destroy(mack);
569 
570  }
571 
572  msg_destroy(msg);
573  }
574 }
575 
576 static void sql_single(Boxc *boxc)
577 {
578  Msg *msg;
579 
580  while (sqlbox_status == SQL_RUNNING && boxc->alive) {
581  if ((msg = gw_sql_fetch_msg()) != NULL) {
582  if (charset_processing(msg) == -1) {
583  error(0, "Could not charset process message, dropping it!");
584  msg_destroy(msg);
585  continue;
586  }
587  if (global_sender != NULL && (msg->sms.sender == NULL || octstr_len(msg->sms.sender) == 0)) {
588  msg->sms.sender = octstr_duplicate(global_sender);
589  }
590  /* convert validity and deferred to unix timestamp */
591  if (msg->sms.validity != SMS_PARAM_UNDEFINED)
592  msg->sms.validity = time(NULL) + msg->sms.validity * 60;
593  if (msg->sms.deferred != SMS_PARAM_UNDEFINED)
594  msg->sms.deferred = time(NULL) + msg->sms.deferred * 60;
595  send_msg(boxc->bearerbox_connection, boxc, msg);
596 
597  if (save_mt) {
598  /* convert validity & deferred back to minutes
599  * TODO clarify why we fetched message from DB and then insert it back here???
600  */
601  if (msg->sms.validity != SMS_PARAM_UNDEFINED)
602  msg->sms.validity = (msg->sms.validity - time(NULL))/60;
603  if (msg->sms.deferred != SMS_PARAM_UNDEFINED)
604  msg->sms.deferred = (msg->sms.deferred - time(NULL))/60;
606  }
607  }
608  else {
610  }
611  msg_destroy(msg);
612  }
613 }
614 
615 static void sql_list(Boxc *boxc)
616 {
617  Msg *msg;
618  List *qlist, *save_list;
619 
620  qlist = gwlist_create();
621  gwlist_add_producer(qlist);
622  save_list = gwlist_create();
623  gwlist_add_producer(save_list);
624 
625  while (sqlbox_status == SQL_RUNNING && boxc->alive) {
626  if ( gw_sql_fetch_msg_list(qlist, limit_per_cycle) > 0 ) {
627  while((gwlist_len(qlist)>0) && ((msg = gwlist_consume(qlist)) != NULL )) {
628  if (charset_processing(msg) == -1) {
629  error(0, "Could not charset process message, dropping it!");
630  msg_destroy(msg);
631  continue;
632  }
633  if (global_sender != NULL && (msg->sms.sender == NULL || octstr_len(msg->sms.sender) == 0)) {
634  msg->sms.sender = octstr_duplicate(global_sender);
635  }
636  /* convert validity and deferred to unix timestamp */
637  if (msg->sms.validity != SMS_PARAM_UNDEFINED)
638  msg->sms.validity = time(NULL) + msg->sms.validity * 60;
639  if (msg->sms.deferred != SMS_PARAM_UNDEFINED)
640  msg->sms.deferred = time(NULL) + msg->sms.deferred * 60;
641  send_msg(boxc->bearerbox_connection, boxc, msg);
642 
643  /* convert validity & deferred back to minutes */
644  if (save_mt && msg->sms.validity != SMS_PARAM_UNDEFINED)
645  msg->sms.validity = (msg->sms.validity - time(NULL))/60;
646  if (save_mt && msg->sms.deferred != SMS_PARAM_UNDEFINED)
647  msg->sms.deferred = (msg->sms.deferred - time(NULL))/60;
648  gwlist_produce(save_list, msg);
649  }
650  /* save_list also deletes and destroys messages */
651  gw_sql_save_list(save_list, octstr_imm("MT"), save_mt);
652  }
653  else {
655  }
656  }
657 
658  gwlist_remove_producer(qlist);
659  gwlist_remove_producer(save_list);
661  gwlist_destroy(save_list, msg_destroy_item);
662 }
663 
664 static void sql_to_bearerbox(void *arg)
665 {
666  Boxc *boxc;
667 
668  boxc = gw_malloc(sizeof(Boxc));
670  boxc->smsbox_connection = NULL;
671  boxc->client_ip = NULL;
672  boxc->alive = 1;
673  boxc->connect_time = time(NULL);
675  if (boxc->bearerbox_connection == NULL) {
676  boxc_destroy(boxc);
677  return;
678  }
679 
681  identify_to_bearerbox(boxc);
682 
683  if (gw_sql_fetch_msg_list == NULL || gw_sql_save_list == NULL || limit_per_cycle <= 1) {
684  sql_single(boxc);
685  }
686  else {
687  sql_list(boxc);
688  }
689 
690  boxc_destroy(boxc);
691 }
692 
693 static void sqlboxc_run(void *arg)
694 {
695  int fd;
696  int port;
697 
698  /* we will use one thread for SQL sms injections */
700 
701  port = (int)arg;
702 
703  fd = make_server_socket(port, NULL);
704  /* XXX add interface_name if required */
705 
706  if (fd < 0) {
707  panic(0, "Could not open sqlbox port %d", port);
708  }
709 
710  /*
711  * infinitely wait for new connections;
712  * to shut down the system, SIGTERM is send and then
713  * select drops with error, so we can check the status
714  */
715 
716  wait_for_connections(fd, run_sqlbox, NULL);
717 
718  /* close listen socket */
719  close(fd);
720 }
721 
722 
723 
724 /***********************************************************************
725  * Main program. Configuration, signal handling, etc.
726  */
727 
728 static void signal_handler(int signum) {
729  /* On some implementations (i.e. linuxthreads), signals are delivered
730  * to all threads. We only want to handle each signal once for the
731  * entire box, and we let the gwthread wrapper take care of choosing
732  * one.
733  */
734  if (!gwthread_shouldhandlesignal(signum))
735  return;
736 
737  switch (signum) {
738  case SIGINT:
739  if (sqlbox_status == SQL_RUNNING) {
740  error(0, "SIGINT received, aborting program...");
742  }
743  break;
744 
745  case SIGHUP:
746  warning(0, "SIGHUP received, catching and re-opening logs");
747  log_reopen();
748  alog_reopen();
749  break;
750  /*
751  * It would be more proper to use SIGUSR1 for this, but on some
752  * platforms that's reserved by the pthread support.
753  */
754  case SIGQUIT:
755  warning(0, "SIGQUIT received, reporting memory usage.");
756  gw_check_leaks();
757  break;
758  }
759 }
760 
761 
762 static void setup_signal_handlers(void) {
763  struct sigaction act;
764 
765  act.sa_handler = signal_handler;
766  sigemptyset(&act.sa_mask);
767  act.sa_flags = 0;
768  sigaction(SIGINT, &act, NULL);
769  sigaction(SIGQUIT, &act, NULL);
770  sigaction(SIGHUP, &act, NULL);
771  sigaction(SIGPIPE, &act, NULL);
772 }
773 
774 
775 
776 static void init_sqlbox(Cfg *cfg)
777 {
778  CfgGroup *grp;
779  Octstr *logfile;
780  long lvl;
781 
782  /* some default values */
783  sqlbox_port_ssl = 0;
785  bearerbox_port_ssl = 0;
786  logfile = NULL;
787  lvl = 0;
788 
789  /*
790  * first we take the port number in bearerbox and other values from the
791  * core group in configuration file
792  */
793 
794  grp = cfg_get_single_group(cfg, octstr_imm("sqlbox"));
795  if (cfg_get_integer(&bearerbox_port, grp, octstr_imm("bearerbox-port")) == -1)
796  panic(0, "Missing or bad 'bearerbox-port' in sqlbox group");
797 #ifdef HAVE_LIBSSL
798  cfg_get_bool(&bearerbox_port_ssl, grp, octstr_imm("smsbox-port-ssl"));
799  conn_config_ssl(grp);
800 #endif
801 
802  grp = cfg_get_single_group(cfg, octstr_imm("sqlbox"));
803  if (grp == NULL)
804  panic(0, "No 'sqlbox' group in configuration");
805 
806  bearerbox_host = cfg_get( grp, octstr_imm("bearerbox-host"));
807  if (bearerbox_host == NULL)
809 
810  sqlbox_id = cfg_get(grp, octstr_imm("smsbox-id"));
811  global_sender = cfg_get(grp, octstr_imm("global-sender"));
812 
813  if (cfg_get_integer(&sqlbox_port, grp, octstr_imm("smsbox-port")) == -1)
814  sqlbox_port = 13005;
815 
816  /* setup limit per cycle */
817  if (cfg_get_integer(&limit_per_cycle, grp, octstr_imm("limit-per-cycle")) == -1)
819 
820  /* set up save parameters */
821  if (cfg_get_bool(&save_mo, grp, octstr_imm("save-mo")) == -1)
822  save_mo = 1;
823 
824  if (cfg_get_bool(&save_mt, grp, octstr_imm("save-mt")) == -1)
825  save_mt = 1;
826 
827  if (cfg_get_bool(&save_dlr, grp, octstr_imm("save-dlr")) == -1)
828  save_dlr = 1;
829 
830  /* setup logfile stuff */
831  logfile = cfg_get(grp, octstr_imm("log-file"));
832 
833  cfg_get_integer(&lvl, grp, octstr_imm("log-level"));
834 
835  if (logfile != NULL) {
836  info(0, "Starting to log to file %s level %ld",
837  octstr_get_cstr(logfile), lvl);
838  log_open(octstr_get_cstr(logfile), lvl, GW_NON_EXCL);
839  octstr_destroy(logfile);
840  }
841 
843  if (sql_type == NULL) {
844  panic(0, "No proper SQL server defined.");
845  }
846 
847  gw_sql_enter(cfg);
848 
850 }
851 
852 static int check_args(int i, int argc, char **argv) {
853  if (strcmp(argv[i], "-H")==0 || strcmp(argv[i], "--tryhttp")==0) {
854  //only_try_http = 1;
855  } else {
856  return -1;
857  }
858 
859  return 0;
860 }
861 
862 int main(int argc, char **argv)
863 {
864  int cf_index;
865  Octstr *filename;
866 
867  gwlib_init();
868 
869  cf_index = get_and_set_debugs(argc, argv, check_args);
871 
872  if (argv[cf_index] == NULL) {
873  filename = octstr_create("sqlbox.conf");
874  } else {
875  filename = octstr_create(argv[cf_index]);
876  }
877 
879 
880  /* Adding cfg-checks to core */
881 
883 
884  if (cfg_read(cfg) == -1)
885  panic(0, "Couldn't read configuration from `%s'.", octstr_get_cstr(filename));
886 
888 
889  report_versions("sqlbox");
890 
891  init_sqlbox(cfg);
892 
893  sqlboxc_run((void *)sqlbox_port);
894 
895  cfg_destroy(cfg);
896  if (restart_sqlbox) {
897  gwthread_sleep(1.0);
898  }
899 
900  gw_sql_leave();
901  gwlib_shutdown();
902 
903  if (restart_sqlbox)
904  execvp(argv[0], argv);
905  return 0;
906 }
void error(int err, const char *fmt,...)
Definition: log.c:648
#define gw_sql_leave
Definition: sqlbox_sql.h:52
static void sqlboxc_run(void *arg)
Definition: sqlbox.c:693
void info(int err, const char *fmt,...)
Definition: log.c:672
static long limit_per_cycle
Definition: sqlbox.c:88
Msg * msg_duplicate(Msg *msg)
Definition: msg.c:111
static int bearerbox_port_ssl
Definition: sqlbox.c:86
#define gw_sql_fetch_msg
Definition: sqlbox_sql.h:42
Definition: http.c:2014
#define gw_sql_save_list
Definition: sqlbox_sql.h:44
static Octstr * bearerbox_host
Definition: sqlbox.c:85
static void wait_for_connections(int fd, void(*function)(void *arg), List *waited)
Definition: sqlbox.c:476
Connection * connect_to_bearerbox_real(Octstr *host, int port, int ssl, Octstr *our_host)
Definition: shared.c:83
static void sql_to_bearerbox(void *arg)
Definition: sqlbox.c:664
gw_assert(wtls_machine->packet_to_send !=NULL)
int ssl
int read_from_bearerbox_real(Connection *conn, Msg **msg, double seconds)
Definition: shared.c:172
Octstr * client_ip
Definition: opensmppbox.c:153
static void setup_signal_handlers(void)
Definition: sqlbox.c:762
Definition: msg.h:109
void log_reopen(void)
Definition: log.c:297
static int send_msg(Connection *conn, Boxc *boxconn, Msg *pmsg)
Definition: sqlbox.c:242
void gwlist_produce(List *list, void *item)
Definition: list.c:411
#define SLEEP_BETWEEN_EMPTY_SELECTS
Definition: sqlbox.c:97
void gwthread_join(long thread)
long gwlist_len(List *list)
Definition: list.c:166
static Msg * read_from_box(Connection *conn, Boxc *boxconn)
Definition: sqlbox.c:210
static void smsbox_to_bearerbox(void *arg)
Definition: sqlbox.c:261
int octstr_url_decode(Octstr *ostr)
Definition: octstr.c:1746
#define BB_DEFAULT_HOST
Definition: bb.h:67
msg_type
Definition: msg.h:73
#define cfg_get(grp, varname)
Definition: cfg.h:86
static int sqlbox_is_allowed_in_group(Octstr *group, Octstr *variable)
Definition: sqlbox.c:115
static void signal_handler(int signum)
Definition: sqlbox.c:728
#define msg_create(type)
Definition: msg.h:136
int gwthread_shouldhandlesignal(int signal)
static int charset_processing(Msg *msg)
Definition: sqlbox.c:171
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
#define gw_sql_fetch_msg_list
Definition: sqlbox_sql.h:43
static volatile sig_atomic_t restart_sqlbox
Definition: sqlbox.c:77
Cfg * cfg_create(Octstr *filename)
Definition: cfg.c:318
static Boxc * boxc_create(int fd, Octstr *ip, int ssl)
Definition: sqlbox.c:316
Connection * bearerbox_connection
Definition: opensmppbox.c:143
volatile sig_atomic_t alive
Definition: opensmppbox.c:159
int cfg_read(Cfg *cfg)
Definition: cfg.c:452
static void sql_list(Boxc *boxc)
Definition: sqlbox.c:615
static int check_args(int i, int argc, char **argv)
Definition: sqlbox.c:852
static int port
Definition: fakesmsc.c:121
#define POLLIN
Definition: gwpoll.h:91
void msg_destroy_item(void *msg)
Definition: msg.c:147
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:283
void cfg_add_hooks(void *allowed, void *single)
Definition: cfg.c:253
Definition: msg.h:79
Definition: cfg.c:164
Octstr * boxc_id
Definition: opensmppbox.c:160
void cfg_destroy(Cfg *cfg)
Definition: cfg.c:331
void conn_config_ssl(CfgGroup *grp)
Definition: conn.c:1546
void gwlist_remove_producer(List *list)
Definition: list.c:401
void conn_destroy(Connection *conn)
Definition: conn.c:627
static long sqlbox_port
Definition: sqlbox.c:82
#define octstr_duplicate(ostr)
Definition: octstr.h:187
static Boxc * accept_boxc(int fd, int ssl)
Definition: sqlbox.c:347
struct _boxc Boxc
void uuid_copy(uuid_t dst, const uuid_t src)
Definition: gw_uuid.c:150
static void bearerbox_to_smsbox(void *arg)
Definition: sqlbox.c:394
void msg_destroy(Msg *msg)
Definition: msg.c:132
int make_server_socket(int port, const char *interface_name)
Definition: socket.c:93
time_t connect_time
Definition: opensmppbox.c:151
void warning(int err, const char *fmt,...)
Definition: log.c:660
#define DEFAULT_LIMIT_PER_CYCLE
Definition: sqlbox.c:98
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:324
#define SQL_RUNNING
Definition: sqlbox.c:81
char filename[FILENAME_MAX+1]
Definition: log.c:171
#define gwthread_create(func, arg)
Definition: gwthread.h:90
#define octstr_create(cstr)
Definition: octstr.h:125
#define gw_sql_save_msg(message, table)
Definition: sqlbox_sql.h:45
void gwthread_sleep(double seconds)
static volatile sig_atomic_t sqlbox_status
Definition: sqlbox.c:78
#define SMS_PARAM_UNDEFINED
Definition: sms.h:91
static int save_dlr
Definition: sqlbox.c:89
static void boxc_destroy(Boxc *boxc)
Definition: sqlbox.c:330
int main(int argc, char **argv)
Definition: sqlbox.c:862
int conn_write_withlen(Connection *conn, Octstr *data)
Definition: conn.c:1075
static void run_sqlbox(void *arg)
Definition: sqlbox.c:449
int gwthread_pollfd(int fd, int events, double timeout)
static void init_sqlbox(Cfg *cfg)
Definition: sqlbox.c:776
void alog_reopen(void)
Definition: accesslog.c:85
struct server_type * sqlbox_init_sql(Cfg *cfg)
Definition: sqlbox_sql.c:4
void report_versions(const char *boxname)
Definition: utils.c:539
int log_open(char *filename, int level, enum excl_state excl)
Definition: log.c:375
static int sqlbox_port_ssl
Definition: sqlbox.c:83
long octstr_len(const Octstr *ostr)
Definition: octstr.c:342
int cfg_get_bool(int *n, CfgGroup *grp, Octstr *varname)
Definition: cfg.c:759
Definition: octstr.c:118
void * gwlist_consume(List *list)
Definition: list.c:427
static void identify_to_bearerbox(Boxc *conn)
Definition: sqlbox.c:510
Octstr * host_ip(struct sockaddr_in addr)
Definition: socket.c:615
Connection * smsbox_connection
Definition: sqlbox.c:101
static void sql_single(Boxc *boxc)
Definition: sqlbox.c:576
static Cfg * cfg
Definition: sqlbox.c:75
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
static void bearerbox_to_sql(void *arg)
Definition: sqlbox.c:521
int cfg_get_integer(long *n, CfgGroup *grp, Octstr *varname)
Definition: cfg.c:742
#define panic
Definition: log.h:87
Definition: cfg.c:73
int socklen_t
Definition: socket.h:73
static int save_mo
Definition: sqlbox.c:89
void gwlib_shutdown(void)
Definition: gwlib.c:94
Octstr * msg_pack(Msg *msg)
Definition: msg.c:181
#define gwlist_create()
Definition: list.h:136
#define SQL_SHUTDOWN
Definition: sqlbox.c:80
#define gw_sql_enter
Definition: sqlbox_sql.h:51
static long bearerbox_port
Definition: sqlbox.c:84
void gwlib_init(void)
Definition: gwlib.c:78
CfgGroup * cfg_get_single_group(Cfg *cfg, Octstr *name)
Definition: cfg.c:639
void gwlist_add_producer(List *list)
Definition: list.c:383
Octstr * sqlbox_id
Definition: sqlbox.c:95
#define BB_DEFAULT_SMSBOX_PORT
Definition: bb.h:68
int get_and_set_debugs(int argc, char **argv, int(*find_own)(int index, int argc, char **argv))
Definition: utils.c:626
static Octstr * global_sender
Definition: sqlbox.c:87
struct server_type * sql_type
Definition: list.c:102
static XMLRPCDocument * msg
Definition: test_xmlrpc.c:86
static int sqlbox_is_single_group(Octstr *query)
Definition: sqlbox.c:147
static int save_mt
Definition: sqlbox.c:89
#define DC_UCS2
Definition: sms.h:112
Connection * conn_wrap_fd(int fd, int ssl)
Definition: conn.c:566
int charset_convert(Octstr *string, char *charset_from, char *charset_to)
Definition: charset.c:589
#define DC_7BIT
Definition: sms.h:110
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.