Kannel: Open Source WAP and SMS gateway  $Revision: 5037 $
smsc_cgw.c File Reference
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <limits.h>
#include "gwlib/gwlib.h"
#include "smscconn.h"
#include "smscconn_p.h"
#include "bb_smscconn_cb.h"
#include "msg.h"
#include "sms.h"
#include "dlr.h"

Go to the source code of this file.

Data Structures

struct  cgwop
 
struct  privdata
 

Macros

#define CGW_DEFPORT   21772
 
#define CGW_EOL   0x0A
 
#define CGW_TRN_MAX   500 /* Size of our internal message buffer. */
 
#define CGWOP_MAXARGS   10 /* max. number of name:value pairs in cgwop */
 
#define CGW_OP_NOP   0 /* this doesn't really exist.. */
 
#define CGW_OP_MSG   1
 
#define CGW_OP_OK   2
 
#define CGW_OP_ERR   3
 
#define CGW_OP_DELIVERY   4
 
#define CGW_OP_HELLO   5
 
#define CGW_OP_STATUS   6
 

Typedefs

typedef struct privdata PrivData
 

Functions

static int cgw_add_msg_cb (SMSCConn *conn, Msg *sms)
 
static int cgw_shutdown_cb (SMSCConn *conn, int finish_sending)
 
static void cgw_start_cb (SMSCConn *conn)
 
static long cgw_queued_cb (SMSCConn *conn)
 
static void cgw_sender (void *arg)
 
static Connectioncgw_open_send_connection (SMSCConn *conn)
 
static int cgw_send_loop (SMSCConn *conn, Connection *server)
 
void cgw_check_acks (PrivData *privdata)
 
int cgw_wait_command (PrivData *privdata, SMSCConn *conn, Connection *server, int timeout)
 
static int cgw_open_listening_socket (SMSCConn *conn, PrivData *privdata)
 
static void cgw_listener (void *arg)
 
static void cgw_receiver (SMSCConn *conn, Connection *server)
 
static int cgw_handle_op (SMSCConn *conn, Connection *server, struct cgwop *cgwop)
 
struct cgwopcgw_read_op (PrivData *privdata, SMSCConn *conn, Connection *server, time_t timeout)
 
static void cgwop_add (struct cgwop *cgwop, Octstr *name, Octstr *value)
 
static struct cgwopcgwop_create (int op, int trn)
 
static void cgwop_destroy (struct cgwop *cgwop)
 
static Octstrcgwop_get (struct cgwop *cgwop, Octstr *name)
 
static Octstrcgwop_tostr (struct cgwop *cgwop)
 
static int cgwop_send (Connection *conn, struct cgwop *cgwop)
 
static Octstrcgw_encode_msg (Octstr *str)
 
static Octstrcgw_decode_msg (Octstr *str)
 
static struct cgwopmsg_to_cgwop (PrivData *privdata, Msg *msg, int trn)
 
int smsc_cgw_create (SMSCConn *conn, CfgGroup *cfg)
 

Variables

static char * cgw_ops [6] = {"nop", "msg", "ok", "err", "delivery", "hello"}
 

Macro Definition Documentation

#define CGW_DEFPORT   21772

Definition at line 123 of file smsc_cgw.c.

Referenced by smsc_cgw_create().

#define CGW_EOL   0x0A

Definition at line 124 of file smsc_cgw.c.

Referenced by cgw_encode_msg(), and cgwop_tostr().

#define CGW_OP_DELIVERY   4

Definition at line 135 of file smsc_cgw.c.

Referenced by cgw_handle_op(), and cgw_read_op().

#define CGW_OP_ERR   3

Definition at line 134 of file smsc_cgw.c.

Referenced by cgw_handle_op(), and cgw_read_op().

#define CGW_OP_HELLO   5

Definition at line 136 of file smsc_cgw.c.

Referenced by cgw_handle_op(), and cgw_read_op().

#define CGW_OP_MSG   1

Definition at line 132 of file smsc_cgw.c.

Referenced by cgw_handle_op(), cgw_read_op(), and msg_to_cgwop().

#define CGW_OP_NOP   0 /* this doesn't really exist.. */

Definition at line 131 of file smsc_cgw.c.

Referenced by cgw_read_op().

#define CGW_OP_OK   2

Definition at line 133 of file smsc_cgw.c.

Referenced by cgw_handle_op(), and cgw_read_op().

#define CGW_OP_STATUS   6

Definition at line 137 of file smsc_cgw.c.

Referenced by cgw_handle_op(), and cgw_read_op().

#define CGW_TRN_MAX   500 /* Size of our internal message buffer. */

Definition at line 125 of file smsc_cgw.c.

Referenced by cgw_check_acks(), cgw_handle_op(), cgw_send_loop(), and smsc_cgw_create().

#define CGWOP_MAXARGS   10 /* max. number of name:value pairs in cgwop */

Definition at line 127 of file smsc_cgw.c.

Referenced by cgwop_add(), and cgwop_create().

Typedef Documentation

typedef struct privdata PrivData

Function Documentation

static int cgw_add_msg_cb ( SMSCConn conn,
Msg sms 
)
static

Definition at line 549 of file smsc_cgw.c.

References smscconn::data, gwlist_produce(), gwthread_wakeup(), msg_duplicate(), privdata::outgoing_queue, and privdata::sender_thread.

Referenced by smsc_cgw_create().

550 {
551  PrivData *privdata = conn->data;
552  Msg *copy;
553 
554  copy = msg_duplicate(sms);
555  gwlist_produce(privdata->outgoing_queue, copy);
556  gwthread_wakeup(privdata->sender_thread);
557 
558  return 0;
559 }
Msg * msg_duplicate(Msg *msg)
Definition: msg.c:111
void gwlist_produce(List *list, void *item)
Definition: list.c:411
void * data
Definition: smscconn_p.h:249
List * outgoing_queue
Definition: smsc_cgw.c:153
Definition: msg.h:79
long sender_thread
Definition: smsc_cgw.c:155
void gwthread_wakeup(long thread)
void cgw_check_acks ( PrivData privdata)

Definition at line 787 of file smsc_cgw.c.

References CGW_TRN_MAX, privdata::check_time, gwlist_produce(), privdata::outgoing_queue, privdata::sendmsg, privdata::sendtime, privdata::unacked, privdata::waitack, and warning().

Referenced by cgw_sender().

788 {
789  time_t current_time;
790  int i;
791 
792  current_time = time(NULL);
793  if (privdata->unacked && (current_time > privdata->check_time + 30)) {
794  privdata->check_time = current_time;
795  for (i = 0; i < CGW_TRN_MAX; i++)
796  if (privdata->sendtime[i] && privdata->sendtime[i] < (current_time - privdata->waitack)) {
797  privdata->sendtime[i] = 0;
798  privdata->unacked--;
799  warning(0, "smsc_cgw: received neither OK nor ERR for message %d "
800  "in %d seconds, resending message", i, privdata->waitack);
801  gwlist_produce(privdata->outgoing_queue, privdata->sendmsg[i]);
802  }
803  }
804 }
Msg * sendmsg[CGW_TRN_MAX]
Definition: smsc_cgw.c:167
void gwlist_produce(List *list, void *item)
Definition: list.c:411
int waitack
Definition: smsc_cgw.c:171
List * outgoing_queue
Definition: smsc_cgw.c:153
void warning(int err, const char *fmt,...)
Definition: log.c:624
long check_time
Definition: smsc_cgw.c:173
#define CGW_TRN_MAX
Definition: smsc_cgw.c:125
int unacked
Definition: smsc_cgw.c:170
time_t sendtime[CGW_TRN_MAX]
Definition: smsc_cgw.c:168
static Octstr* cgw_decode_msg ( Octstr str)
static

Definition at line 354 of file smsc_cgw.c.

References octstr_delete(), octstr_imm(), octstr_insert(), and octstr_search().

Referenced by cgw_handle_op().

355 {
356  int i;
357 
358  /* make \n -> linefeed */
359  while ((i = octstr_search(str, octstr_imm("\\n"), 0)) != -1) {
360  octstr_delete(str, i, 2); /* delete "\n" str */
361  octstr_insert(str, octstr_imm("\n"), i);
362  }
363  /* make \r -> carriage return */
364  while ((i = octstr_search(str, octstr_imm("\\r"), 0)) != -1) {
365  octstr_delete(str, i, 2); /* delete EOL char */
366  octstr_insert(str, octstr_imm("\r"), i);
367  }
368  /* remove double backslashes */
369  while ((i = octstr_search(str, octstr_imm("\\\\"), 0)) != -1) {
370  octstr_delete(str, i, 1);
371  }
372 
373  return str;
374 }
long octstr_search(const Octstr *haystack, const Octstr *needle, long pos)
Definition: octstr.c:1068
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:281
void octstr_insert(Octstr *ostr1, const Octstr *ostr2, long pos)
Definition: octstr.c:1301
void octstr_delete(Octstr *ostr1, long pos, long len)
Definition: octstr.c:1525
static Octstr* cgw_encode_msg ( Octstr str)
static

Definition at line 312 of file smsc_cgw.c.

References CGW_EOL, octstr_delete(), octstr_imm(), octstr_insert(), octstr_insert_data(), octstr_len(), and octstr_search_char().

Referenced by msg_to_cgwop().

313 {
314  int i;
315  char esc = 27;
316  char e = 'e';
317 
318  /* Euro char (0x80) -> ESC + e. We do this conversion as long as the message
319  length is under 160 chars (the checking could probably be done better) */
320 
321  while ((i = octstr_search_char(str, 0x80, 0)) != -1) {
322  octstr_delete(str, i, 1); /* delete Euro char */
323  if (octstr_len(str) < 160) {
324  octstr_insert_data(str, i, &esc, 1); /* replace with ESC + e */
325  octstr_insert_data(str, i+1, &e, 1);
326  } else {
327  octstr_insert_data(str, i, &e, 1); /* no room for ESC + e, just replace with an e */
328  }
329  }
330 
331 
332  /* Escape backslash characters */
333  while ((i = octstr_search_char(str, '\\', 0)) != -1) {
334  octstr_insert(str, octstr_imm("\\"), i);
335  }
336  /* Remove Line Feed characters */
337  while ((i = octstr_search_char(str, CGW_EOL, 0)) != -1) {
338  octstr_delete(str, i, 1); /* delete EOL char */
339  octstr_insert(str, octstr_imm("\\n"), i);
340  }
341  /* Remove Carriage return characters */
342  while ((i = octstr_search_char(str, 13, 0)) != -1) {
343  octstr_delete(str, i, 1); /* delete EOL char */
344  octstr_insert(str, octstr_imm("\\r"), i);
345  }
346 
347  return str;
348 }
void octstr_insert_data(Octstr *ostr, long pos, const char *data, long len)
Definition: octstr.c:1459
long octstr_search_char(const Octstr *ostr, int ch, long pos)
Definition: octstr.c:1010
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:281
void octstr_insert(Octstr *ostr1, const Octstr *ostr2, long pos)
Definition: octstr.c:1301
void octstr_delete(Octstr *ostr1, long pos, long len)
Definition: octstr.c:1525
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
#define CGW_EOL
Definition: smsc_cgw.c:124
static int cgw_handle_op ( SMSCConn conn,
Connection server,
struct cgwop cgwop 
)
static

Definition at line 1064 of file smsc_cgw.c.

References bb_smscconn_receive(), bb_smscconn_send_failed(), bb_smscconn_sent(), cgw_decode_msg(), CGW_OP_DELIVERY, CGW_OP_ERR, CGW_OP_HELLO, CGW_OP_MSG, CGW_OP_OK, CGW_OP_STATUS, CGW_TRN_MAX, cgwop_add(), cgwop_create(), cgwop_destroy(), cgwop_get(), cgwop_send(), smscconn::data, privdata::dlr, dlr_add(), DLR_BUFFERED, DLR_FAIL, dlr_find(), DLR_IS_ENABLED_DEVICE, DLR_SUCCESS, from, smscconn::id, info(), msg, msg_create, octstr_append(), octstr_append_char(), octstr_append_decimal(), octstr_create, octstr_destroy(), octstr_duplicate, octstr_get_cstr, octstr_imm(), octstr_parse_long(), cgwop::op, reply(), privdata::sendmsg, privdata::sendtime, SMSCCONN_FAILED_REJECTED, cgwop::trn, and privdata::unacked.

Referenced by cgw_receiver(), and cgw_wait_command().

1065 {
1066  PrivData *privdata = conn->data;
1067  Msg *msg = NULL;
1068  Octstr *from, *sid, *to, *msgdata; /* for messages */
1069  Octstr *msid, *status, *txt; /* delivery reports */
1070  Octstr *clid; /* for acks */
1071  struct cgwop *reply = NULL;
1072  long trn, stat; /* transaction number for ack */
1073  Msg *dlrmsg = NULL, *origmsg = NULL;
1074  Octstr *ts;
1075 
1076  if (cgwop == NULL) return 0;
1077 
1078  from = cgwop_get(cgwop, octstr_imm("from"));
1079  sid = cgwop_get(cgwop, octstr_imm("session-id"));
1080  to = cgwop_get(cgwop, octstr_imm("to"));
1081  msgdata = cgwop_get(cgwop, octstr_imm("msg"));
1082  txt = cgwop_get(cgwop, octstr_imm("txt"));
1083 
1084  msid = cgwop_get(cgwop, octstr_imm("msid"));
1085  status = cgwop_get(cgwop, octstr_imm("status"));
1086  clid = cgwop_get(cgwop, octstr_imm("client-id"));
1087 
1088  if (clid != NULL)
1089  {
1090  octstr_parse_long(&trn, clid, 0, 10);
1091  if ((trn < 0) || (trn >= CGW_TRN_MAX)) { /* invalid transaction number */
1092  info(0, "cgw: Invalid transaction number: %d", (int) trn);
1093  trn = -1;
1094  return 0;
1095  }
1096  }
1097 
1098  switch (cgwop->op)
1099  {
1100  case CGW_OP_MSG:
1101  msg = msg_create(sms);
1102  time(&msg->sms.time);
1103  msg->sms.msgdata = cgw_decode_msg(octstr_duplicate(msgdata));
1104  msg->sms.sender = octstr_duplicate(from);
1105  msg->sms.receiver = octstr_duplicate(to);
1106  msg->sms.smsc_id = octstr_duplicate(conn->id);
1107  bb_smscconn_receive(conn, msg);
1108 
1109  reply = cgwop_create(CGW_OP_OK, -1);
1110  cgwop_add(reply, octstr_imm("session-id"), sid);
1111  cgwop_send(server, reply); /* send reply */
1112 
1113  cgwop_destroy(reply);
1114 
1115  break;
1116 
1117  case CGW_OP_DELIVERY:
1118  if (privdata->dlr[trn]) {
1119 
1120  octstr_parse_long(&stat, status, 0, 10);
1121  origmsg = privdata->sendmsg[trn];
1122 
1123  if (origmsg == NULL) break;
1124 
1125  ts = octstr_create("");
1126  octstr_append(ts, conn->id);
1127  octstr_append_char(ts, '-');
1128  octstr_append_decimal(ts, trn);
1129 
1130  switch (stat) {
1131  case 0: /* delivered */
1132  dlrmsg = dlr_find(conn->id,
1133  ts, /* timestamp */
1134  msid, /* destination */
1135  DLR_SUCCESS, 0);
1136  break;
1137  case 1: /* buffered */
1138  dlrmsg = dlr_find(conn->id,
1139  ts, /* timestamp */
1140  msid, /* destination */
1141  DLR_BUFFERED, 0);
1142  break;
1143  case 2: /* not delivered */
1144  dlrmsg = dlr_find(conn->id,
1145  ts, /* timestamp */
1146  msid, /* destination */
1147  DLR_FAIL, 0);
1148  break;
1149  }
1150 
1151  octstr_destroy(ts);
1152  if (dlrmsg != NULL) {
1153  dlrmsg->sms.msgdata = octstr_duplicate(txt);
1154  bb_smscconn_receive(conn, dlrmsg);
1155  }
1156  }
1157 
1158  break;
1159 
1160  case CGW_OP_OK:
1161  if (trn == -1) break; /* invalid transaction number */
1162  /* info(0, "cgw: Got ACK: %s", octstr_get_cstr(clid)); */
1163 
1164  privdata->sendtime[trn] = 0;
1165  privdata->unacked--;
1166 
1167  /* add delivery notification request if wanted */
1168 
1169  msg = privdata->sendmsg[trn];
1170 
1171  if (msg && msg->sms.dlr_url && DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask)) {
1172  Octstr *ts;
1173 
1174  ts = octstr_create("");
1175  octstr_append(ts, conn->id);
1176  octstr_append_char(ts, '-');
1177  octstr_append_decimal(ts, trn);
1178 
1179  dlr_add(conn->id, ts, msg, 0);
1180 
1181  octstr_destroy(ts);
1182  privdata->dlr[trn] = 1;
1183  } else {
1184  privdata->dlr[trn] = 0;
1185  }
1186 
1187  /* mark as successfully sent */
1188  bb_smscconn_sent(conn, msg, NULL);
1189 
1190  break;
1191 
1192  case CGW_OP_STATUS:
1193  info(0, "CGW: Warning: Got session status");
1194  /* op:status messages are sent by ProviderServer to tell if there are problems with
1195  the session status. These are not wanted, and should never occur, as the delivery is
1196  cancelled, and no end-user billing is done. */
1197 
1198  break;
1199 
1200 
1201  case CGW_OP_HELLO:
1202  info(0, "CGW: Server said: %s", octstr_get_cstr(cgwop_get(cgwop, octstr_imm("hello"))));
1203  break;
1204 
1205  case CGW_OP_ERR:
1206  if (trn == -1) break; /* invalid transaction number */
1207 
1208  info(0, "CGW: Received error: %s", octstr_get_cstr(txt));
1209 
1210  privdata->sendtime[trn] = 0;
1211  privdata->unacked--;
1212 
1213  bb_smscconn_send_failed(conn, privdata->sendmsg[trn],
1215 
1216  break;
1217 
1218  default:
1219  info(0, "cgw: Unknown operation: %d", cgwop->op);
1220  return 0;
1221  }
1222 
1223  return 1;
1224 }
void info(int err, const char *fmt,...)
Definition: log.c:636
Msg * sendmsg[CGW_TRN_MAX]
Definition: smsc_cgw.c:167
void octstr_append(Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:1502
Octstr * id
Definition: smscconn_p.h:174
void * data
Definition: smscconn_p.h:249
static void cgwop_add(struct cgwop *cgwop, Octstr *name, Octstr *value)
Definition: smsc_cgw.c:199
void octstr_append_char(Octstr *ostr, int ch)
Definition: octstr.c:1515
#define DLR_IS_ENABLED_DEVICE(dlr)
Definition: dlr.h:82
int op
Definition: smsc_cgw.c:141
#define msg_create(type)
Definition: msg.h:136
static Octstr * cgwop_get(struct cgwop *cgwop, Octstr *name)
Definition: smsc_cgw.c:255
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 CGW_OP_HELLO
Definition: smsc_cgw.c:136
static void cgwop_destroy(struct cgwop *cgwop)
Definition: smsc_cgw.c:239
#define DLR_SUCCESS
Definition: dlr.h:72
static Octstr * from
Definition: mtbatch.c:95
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:281
Definition: msg.h:79
static struct cgwop * cgwop_create(int op, int trn)
Definition: smsc_cgw.c:214
long bb_smscconn_receive(SMSCConn *conn, Msg *sms)
Definition: bb_smscconn.c:478
#define octstr_duplicate(ostr)
Definition: octstr.h:187
#define CGW_OP_MSG
Definition: smsc_cgw.c:132
static int cgwop_send(Connection *conn, struct cgwop *cgwop)
Definition: smsc_cgw.c:292
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
#define CGW_OP_OK
Definition: smsc_cgw.c:133
#define CGW_OP_DELIVERY
Definition: smsc_cgw.c:135
#define octstr_create(cstr)
Definition: octstr.h:125
#define CGW_TRN_MAX
Definition: smsc_cgw.c:125
void octstr_append_decimal(Octstr *ostr, long value)
Definition: octstr.c:1974
int trn
Definition: smsc_cgw.c:143
Definition: octstr.c:118
void bb_smscconn_sent(SMSCConn *conn, Msg *sms, Octstr *reply)
Definition: bb_smscconn.c:279
#define CGW_OP_STATUS
Definition: smsc_cgw.c:137
long octstr_parse_long(long *nump, Octstr *ostr, long pos, int base)
Definition: octstr.c:747
#define DLR_BUFFERED
Definition: dlr.h:74
void bb_smscconn_send_failed(SMSCConn *conn, Msg *sms, int reason, Octstr *reply)
Definition: bb_smscconn.c:328
int unacked
Definition: smsc_cgw.c:170
static Octstr * cgw_decode_msg(Octstr *str)
Definition: smsc_cgw.c:354
time_t sendtime[CGW_TRN_MAX]
Definition: smsc_cgw.c:168
static XMLRPCDocument * msg
Definition: test_xmlrpc.c:86
#define DLR_FAIL
Definition: dlr.h:73
#define CGW_OP_ERR
Definition: smsc_cgw.c:134
int dlr[CGW_TRN_MAX]
Definition: smsc_cgw.c:169
static void reply(HTTPClient *c, List *push_headers)
static void cgw_listener ( void *  arg)
static

Definition at line 967 of file smsc_cgw.c.

References privdata::allow_ip, cgw_receiver(), conn_claim(), conn_destroy(), conn_wrap_fd(), smscconn::data, privdata::deny_ip, error(), gwthread_pollfd(), gwthread_wakeup(), host_ip(), info(), is_allowed_ip(), privdata::listening_socket, smscconn::log_idx, log_thread_to(), octstr_destroy(), octstr_get_cstr, POLLIN, privdata::sender_thread, server(), privdata::shutdown, and warning().

Referenced by smsc_cgw_create().

968 {
969  SMSCConn *conn = arg;
970  PrivData *privdata = conn->data;
971  struct sockaddr_in server_addr;
972  socklen_t server_addr_len;
973  Octstr *ip;
975  int s, ret;
976 
977  /* Make sure we log into our own log-file if defined */
978  log_thread_to(conn->log_idx);
979 
980  while (!privdata->shutdown) {
981  server_addr_len = sizeof(server_addr);
982 
983  ret = gwthread_pollfd(privdata->listening_socket, POLLIN, -1);
984  if (ret == -1) {
985  if (errno == EINTR)
986  continue;
987  error(0, "Poll for cgw smsc connections failed, shutting down");
988  break;
989  }
990 
991  if (privdata->shutdown)
992  break;
993  if (ret == 0) /* This thread was woken up from elsewhere, but
994  * if we're not shutting down nothing to do here. */
995  continue;
996  s = accept(privdata->listening_socket, (struct sockaddr *) & server_addr,
997  &server_addr_len);
998  if (s == -1) {
999  warning(errno, "cgw_listener: accept() failed, retrying...");
1000  continue;
1001  }
1002 
1003  ip = host_ip(server_addr);
1004  if (!is_allowed_ip(privdata->allow_ip, privdata->deny_ip, ip)) {
1005  info(0, "CGW smsc connection tried from denied host <%s>, disconnected", octstr_get_cstr(ip));
1006  octstr_destroy(ip);
1007  close(s);
1008  continue;
1009  }
1010  server = conn_wrap_fd(s, 0);
1011  if (server == NULL) {
1012  error(0, "cgw_listener: conn_wrap_fd failed on accept()ed fd");
1013  octstr_destroy(ip);
1014  close(s);
1015  continue;
1016  }
1017  conn_claim(server);
1018  info(0, "cgw: smsc connected from %s", octstr_get_cstr(ip));
1019  octstr_destroy(ip);
1020 
1021  cgw_receiver(conn, server);
1022  conn_destroy(server);
1023  }
1024  if (close(privdata->listening_socket) == -1)
1025  warning(errno, "smsc_cgw: couldn't close listening socket at shutdown");
1026  gwthread_wakeup(privdata->sender_thread);
1027 }
void error(int err, const char *fmt,...)
Definition: log.c:612
void info(int err, const char *fmt,...)
Definition: log.c:636
void * data
Definition: smscconn_p.h:249
int log_idx
Definition: smscconn_p.h:197
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
void log_thread_to(int idx)
Definition: log.c:723
static void cgw_receiver(SMSCConn *conn, Connection *server)
Definition: smsc_cgw.c:1029
int is_allowed_ip(Octstr *allow_ip, Octstr *deny_ip, Octstr *ip)
Definition: utils.c:815
void conn_claim(Connection *conn)
Definition: conn.c:663
#define POLLIN
Definition: gwpoll.h:91
void conn_destroy(Connection *conn)
Definition: conn.c:619
Octstr * allow_ip
Definition: smsc_cgw.c:164
void warning(int err, const char *fmt,...)
Definition: log.c:624
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
int gwthread_pollfd(int fd, int events, double timeout)
int shutdown
Definition: smsc_cgw.c:156
long sender_thread
Definition: smsc_cgw.c:155
Definition: octstr.c:118
Octstr * host_ip(struct sockaddr_in addr)
Definition: socket.c:615
void gwthread_wakeup(long thread)
int socklen_t
Definition: socket.h:73
static void server(int lport, int pport)
int listening_socket
Definition: smsc_cgw.c:157
Octstr * deny_ip
Definition: smsc_cgw.c:164
Connection * conn_wrap_fd(int fd, int ssl)
Definition: conn.c:558
static int cgw_open_listening_socket ( SMSCConn conn,
PrivData privdata 
)
static

Definition at line 945 of file smsc_cgw.c.

References error(), privdata::listening_socket, make_server_socket(), octstr_get_cstr, smscconn::our_host, privdata::rport, and socket_set_blocking().

Referenced by smsc_cgw_create().

946 {
947  int s;
948 
949  if ((s = make_server_socket(privdata->rport, (conn->our_host ? octstr_get_cstr(conn->our_host) : NULL))) == -1) {
950  error(0, "smsc_cgw: could not create listening socket in port %d", privdata->rport);
951  return -1;
952  }
953  if (socket_set_blocking(s, 0) == -1) {
954  error(0, "smsc_cgw: couldn't make listening socket port %d non-blocking", privdata->rport);
955  close(s);
956  return -1;
957  }
958  privdata->listening_socket = s;
959  return 0;
960 }
void error(int err, const char *fmt,...)
Definition: log.c:612
int socket_set_blocking(int fd, int blocking)
Definition: socket.c:368
Octstr * our_host
Definition: smscconn_p.h:192
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
int make_server_socket(int port, const char *interface_name)
Definition: socket.c:93
int rport
Definition: smsc_cgw.c:160
int listening_socket
Definition: smsc_cgw.c:157
static Connection * cgw_open_send_connection ( SMSCConn conn)
static

Definition at line 681 of file smsc_cgw.c.

References bb_smscconn_connected(), bb_smscconn_send_failed(), conn_destroy(), conn_open_tcp_with_port(), smscconn::connect_time, smscconn::data, error(), smscconn::flow_mutex, gwlist_extract_first(), gwthread_sleep(), privdata::host, info(), msg, mutex_lock, mutex_unlock, octstr_get_cstr, smscconn::our_host, privdata::our_port, privdata::outgoing_queue, privdata::port, server(), privdata::shutdown, SMSCCONN_ACTIVE, SMSCCONN_FAILED_TEMPORARILY, SMSCCONN_RECONNECTING, and smscconn::status.

Referenced by cgw_sender().

682 {
683  PrivData *privdata = conn->data;
684  int wait;
686  Msg *msg;
687 
688  wait = 0;
689  while (!privdata->shutdown) {
690 
691  /* Change status only if the first attempt to form a
692  * connection fails, as it's possible that the SMSC closed the
693  * connection because of idle timeout and a new one will be
694  * created quickly. */
695  if (wait) {
696  if (conn->status == SMSCCONN_ACTIVE) {
697  mutex_lock(conn->flow_mutex);
699  mutex_unlock(conn->flow_mutex);
700  }
701  while ((msg = gwlist_extract_first(privdata->outgoing_queue)))
703  info(0, "smsc_cgw: waiting for %d minutes before trying to connect again", wait);
704  gwthread_sleep(wait * 60);
705  wait = wait > 5 ? 10 : wait * 2;
706  } else
707  wait = 1;
708 
709  server = conn_open_tcp_with_port(privdata->host, privdata->port,
710  privdata->our_port, conn->our_host);
711 
712  if (privdata->shutdown) {
713  conn_destroy(server);
714  return NULL;
715  }
716 
717  if (server == NULL) {
718  error(0, "smsc_cgw: opening TCP connection to %s failed", octstr_get_cstr(privdata->host));
719  continue;
720  }
721 
722  if (conn->status != SMSCCONN_ACTIVE) {
723  mutex_lock(conn->flow_mutex);
724  conn->status = SMSCCONN_ACTIVE;
725  conn->connect_time = time(NULL);
726  mutex_unlock(conn->flow_mutex);
727  bb_smscconn_connected(conn);
728  }
729  return server;
730  }
731  return NULL;
732 }
int port
Definition: smsc_cgw.c:159
void error(int err, const char *fmt,...)
Definition: log.c:612
void info(int err, const char *fmt,...)
Definition: log.c:636
void bb_smscconn_connected(SMSCConn *conn)
Definition: bb_smscconn.c:192
#define mutex_unlock(m)
Definition: thread.h:136
void * data
Definition: smscconn_p.h:249
List * outgoing_queue
Definition: smsc_cgw.c:153
Octstr * our_host
Definition: smscconn_p.h:192
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
Definition: msg.h:79
void * gwlist_extract_first(List *list)
Definition: list.c:305
void conn_destroy(Connection *conn)
Definition: conn.c:619
time_t connect_time
Definition: smscconn_p.h:155
Mutex * flow_mutex
Definition: smscconn_p.h:157
Connection * conn_open_tcp_with_port(Octstr *host, int port, int our_port, Octstr *our_host)
Definition: conn.c:540
Octstr * host
Definition: smsc_cgw.c:163
void gwthread_sleep(double seconds)
int shutdown
Definition: smsc_cgw.c:156
smscconn_status_t status
Definition: smscconn_p.h:151
static void server(int lport, int pport)
void bb_smscconn_send_failed(SMSCConn *conn, Msg *sms, int reason, Octstr *reply)
Definition: bb_smscconn.c:328
int our_port
Definition: smsc_cgw.c:161
#define mutex_lock(m)
Definition: thread.h:130
static XMLRPCDocument * msg
Definition: test_xmlrpc.c:86
static long cgw_queued_cb ( SMSCConn conn)
static

Definition at line 599 of file smsc_cgw.c.

References smscconn::data, gwlist_len(), smscconn::load, and privdata::outgoing_queue.

Referenced by smsc_cgw_create().

600 {
601  PrivData *privdata = conn->data;
602  long ret = gwlist_len(privdata->outgoing_queue);
603 
604  /* use internal queue as load, maybe something else later */
605 
606  conn->load = ret;
607  return ret;
608 }
long gwlist_len(List *list)
Definition: list.c:166
void * data
Definition: smscconn_p.h:249
List * outgoing_queue
Definition: smsc_cgw.c:153
int load
Definition: smscconn_p.h:152
struct cgwop * cgw_read_op ( PrivData privdata,
SMSCConn conn,
Connection server,
time_t  timeout 
)

Definition at line 856 of file smsc_cgw.c.

References CGW_OP_DELIVERY, CGW_OP_ERR, CGW_OP_HELLO, CGW_OP_MSG, CGW_OP_NOP, CGW_OP_OK, CGW_OP_STATUS, cgwop_add(), cgwop_create(), conn_read_line(), info(), name, octstr_compare(), octstr_copy, octstr_destroy(), octstr_get_cstr, octstr_imm(), octstr_len(), octstr_search_char(), cgwop::op, and cgwop::value.

Referenced by cgw_receiver(), and cgw_wait_command().

857 {
858  Octstr *line, *name, *value;
859  int finished = 0;
860  int c = 0;
861  struct cgwop *cgwop = NULL;
862 
863  int op = CGW_OP_NOP;
864 
865  if ((line = conn_read_line(server)) == NULL)
866  return NULL; /* don't block */
867 
868  do
869  {
870  while (line == NULL)
871  line = conn_read_line(server); /* wait for more data */
872 
873  c = octstr_search_char(line, ':', 0);
874  if (c != -1) {
875  name = octstr_copy(line, 0, c);
876  value = octstr_copy(line, c + 1, octstr_len(line) - (c + 1));
877 
878  if (octstr_compare(name, octstr_imm("hello")) == 0) {
879  /* A connection is started by CGW by sending a
880  * "hello: Provider Server..." line. */
881 
882  cgwop = cgwop_create(CGW_OP_HELLO, 0);
883  cgwop_add(cgwop, octstr_imm("hello"), value);
884 
885  octstr_destroy(name);
886  octstr_destroy(value);
887  octstr_destroy(line);
888 
889  return cgwop;
890  }
891 
892  if (octstr_compare(name, octstr_imm("op")) == 0) {
893  /* check different ops */
894  if (octstr_compare(value, octstr_imm("msg")) == 0)
895  op = CGW_OP_MSG;
896  else
897  if (octstr_compare(value, octstr_imm("ok")) == 0)
898  op = CGW_OP_OK;
899  else
900  if (octstr_compare(value, octstr_imm("delivery")) == 0)
901  op = CGW_OP_DELIVERY;
902  else
903  if (octstr_compare(value, octstr_imm("err")) == 0)
904  op = CGW_OP_ERR;
905  else
906  if (octstr_compare(value, octstr_imm("status")) == 0)
907  op = CGW_OP_STATUS;
908  else
909  info(0, "CGW: Received unknown op: %s", octstr_get_cstr(value));
910 
911  if (cgwop == NULL)
912  cgwop = cgwop_create(op, 0);
913  else
914  info(0, "cgw: cgwop != null");
915  }
916 
917  if (op != CGW_OP_NOP) {
918  /* All commands have to be inside an op:xx ... end:xx statement */
919 
920  if (octstr_compare(name, octstr_imm("end")) == 0) { /* found end of op */
921  finished = 1;
922  } else {
923  /* store in name/value fields in cgwop */
924  if (cgwop != NULL) {
925  cgwop_add(cgwop, name, value);
926  }
927  }
928  }
929  octstr_destroy(name);
930  octstr_destroy(value);
931  octstr_destroy(line);
932 
933  if (!finished) line = conn_read_line(server);
934  } else {
935  info(0, "cgw: Received invalid input: %s", octstr_get_cstr(line));
936  octstr_destroy(line);
937  finished = 1;
938  }
939 
940  } while (!finished);
941 
942  return cgwop;
943 }
Octstr * conn_read_line(Connection *conn)
Definition: conn.c:1126
void info(int err, const char *fmt,...)
Definition: log.c:636
static void cgwop_add(struct cgwop *cgwop, Octstr *name, Octstr *value)
Definition: smsc_cgw.c:199
int op
Definition: smsc_cgw.c:141
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
#define octstr_copy(ostr, from, len)
Definition: octstr.h:178
long octstr_search_char(const Octstr *ostr, int ch, long pos)
Definition: octstr.c:1010
#define CGW_OP_HELLO
Definition: smsc_cgw.c:136
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:281
static struct cgwop * cgwop_create(int op, int trn)
Definition: smsc_cgw.c:214
#define CGW_OP_MSG
Definition: smsc_cgw.c:132
char * name
Definition: smsc_cimd2.c:212
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
#define CGW_OP_OK
Definition: smsc_cgw.c:133
#define CGW_OP_DELIVERY
Definition: smsc_cgw.c:135
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
#define CGW_OP_NOP
Definition: smsc_cgw.c:131
Definition: octstr.c:118
#define CGW_OP_STATUS
Definition: smsc_cgw.c:137
#define CGW_OP_ERR
Definition: smsc_cgw.c:134
int octstr_compare(const Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:869
static void cgw_receiver ( SMSCConn conn,
Connection server 
)
static

Definition at line 1029 of file smsc_cgw.c.

References cgw_handle_op(), cgw_read_op(), cgwop_destroy(), conn_eof(), conn_error(), conn_wait(), smscconn::data, error(), info(), and privdata::shutdown.

Referenced by cgw_listener().

1030 {
1031  PrivData *privdata = conn->data;
1032  struct cgwop *cgwop;
1033 
1034  while (1) {
1035  if (conn_eof(server)) {
1036  info(0, "cgw: receive connection closed by SMSC");
1037  return ;
1038  }
1039  if (conn_error(server)) {
1040  error(0, "cgw: receive connection broken");
1041  return ;
1042  }
1043 
1044  cgwop = cgw_read_op(conn->data, conn, server, 0);
1045 
1046  if (cgwop != NULL) {
1047  cgw_handle_op(conn, server, cgwop);
1048  cgwop_destroy(cgwop);
1049  } else
1050  conn_wait(server, -1);
1051 
1052  if (privdata->shutdown)
1053  break;
1054  }
1055  return ;
1056 }
void error(int err, const char *fmt,...)
Definition: log.c:612
void info(int err, const char *fmt,...)
Definition: log.c:636
void * data
Definition: smscconn_p.h:249
static int cgw_handle_op(SMSCConn *conn, Connection *server, struct cgwop *cgwop)
Definition: smsc_cgw.c:1064
int conn_eof(Connection *conn)
Definition: conn.c:697
static void cgwop_destroy(struct cgwop *cgwop)
Definition: smsc_cgw.c:239
int shutdown
Definition: smsc_cgw.c:156
int conn_wait(Connection *conn, double seconds)
Definition: conn.c:896
struct cgwop * cgw_read_op(PrivData *privdata, SMSCConn *conn, Connection *server, time_t timeout)
Definition: smsc_cgw.c:856
int conn_error(Connection *conn)
Definition: conn.c:708
static int cgw_send_loop ( SMSCConn conn,
Connection server 
)
static

Definition at line 739 of file smsc_cgw.c.

References CGW_TRN_MAX, cgwop_destroy(), cgwop_send(), smscconn::data, gwlist_extract_first(), gwlist_produce(), info(), msg, msg_to_cgwop(), privdata::nexttrn, privdata::outgoing_queue, privdata::sendmsg, privdata::sendtime, and privdata::unacked.

Referenced by cgw_sender().

740 {
741  PrivData *privdata = conn->data;
742  struct cgwop *cgwop;
743  Msg *msg;
744  int firsttrn;
745 
746  /* Send messages in queue */
747  while ((msg = gwlist_extract_first(privdata->outgoing_queue)) != NULL) {
748  firsttrn = privdata->nexttrn;
749  while (privdata->sendtime[privdata->nexttrn] != 0) {
750  if (++privdata->nexttrn >= CGW_TRN_MAX) privdata->nexttrn = 0;
751  if (privdata->nexttrn == firsttrn) { /* no available trn */
752  /* this happens too many messages are sent, and old messages
753  * haven't been acked. In this case, increase size of
754  * CGW_TRN_MAX */
755  info(0, "cgw: Saturated, increase size of CGW_TRN_MAX!");
756  gwlist_produce(privdata->outgoing_queue, msg);
757  return 1; /* re-insert, and go check for acks */
758  }
759  }
760 
761  cgwop = msg_to_cgwop(privdata, msg, privdata->nexttrn);
762 
763  if (cgwop == NULL) {
764  info(0, "cgw: cgwop == NULL");
765  return 0;
766  }
767 
768  privdata->sendmsg[privdata->nexttrn] = msg;
769  privdata->sendtime[privdata->nexttrn] = time(NULL);
770 
771  if (cgwop_send(server, cgwop) == -1) {
772  cgwop_destroy(cgwop);
773  info(0, "cgw: Unable to send (cgwop_send() == -1)");
774  return -1;
775  }
776 
777  privdata->unacked++;
778 
779  cgwop_destroy(cgwop);
780  }
781  return 0;
782 }
void info(int err, const char *fmt,...)
Definition: log.c:636
Msg * sendmsg[CGW_TRN_MAX]
Definition: smsc_cgw.c:167
void gwlist_produce(List *list, void *item)
Definition: list.c:411
void * data
Definition: smscconn_p.h:249
List * outgoing_queue
Definition: smsc_cgw.c:153
static void cgwop_destroy(struct cgwop *cgwop)
Definition: smsc_cgw.c:239
Definition: msg.h:79
void * gwlist_extract_first(List *list)
Definition: list.c:305
static struct cgwop * msg_to_cgwop(PrivData *privdata, Msg *msg, int trn)
Definition: smsc_cgw.c:380
static int cgwop_send(Connection *conn, struct cgwop *cgwop)
Definition: smsc_cgw.c:292
#define CGW_TRN_MAX
Definition: smsc_cgw.c:125
int unacked
Definition: smsc_cgw.c:170
time_t sendtime[CGW_TRN_MAX]
Definition: smsc_cgw.c:168
static XMLRPCDocument * msg
Definition: test_xmlrpc.c:86
int nexttrn
Definition: smsc_cgw.c:172
static void cgw_sender ( void *  arg)
static

Definition at line 616 of file smsc_cgw.c.

References privdata::allow_ip, bb_smscconn_connected(), bb_smscconn_killed(), bb_smscconn_send_failed(), cgw_check_acks(), cgw_open_send_connection(), cgw_send_loop(), cgw_wait_command(), conn_destroy(), smscconn::data, debug(), privdata::deny_ip, error(), smscconn::flow_mutex, gwlist_destroy(), gwlist_extract_first(), gwlist_len(), privdata::host, smscconn::log_idx, log_thread_to(), msg, mutex_lock, mutex_unlock, octstr_destroy(), privdata::outgoing_queue, server(), privdata::shutdown, SMSCCONN_ACTIVE, SMSCCONN_CONNECTING, SMSCCONN_DEAD, SMSCCONN_FAILED_SHUTDOWN, SMSCCONN_RECONNECTING, and smscconn::status.

Referenced by smsc_cgw_create().

617 {
618  SMSCConn *conn = arg;
619  PrivData *privdata = conn->data;
620  Msg *msg = NULL;
621  Connection *server = NULL;
622  int l = 0;
623  int ret = 0;
624 
625  conn->status = SMSCCONN_CONNECTING;
626 
627  /* Make sure we log into our own log-file if defined */
628  log_thread_to(conn->log_idx);
629 
630  while (!privdata->shutdown) {
631 
632  /* check that connection is active */
633  if (conn->status != SMSCCONN_ACTIVE) {
634  if ((server = cgw_open_send_connection(conn)) == NULL) {
635  privdata->shutdown = 1;
636  error(0, "Unable to connect to CGW server");
637  return ;
638  }
639 
640  conn->status = SMSCCONN_ACTIVE;
641  bb_smscconn_connected(conn);
642  } else {
643  ret = 0;
644  l = gwlist_len(privdata->outgoing_queue);
645  if (l > 0)
646  ret = cgw_send_loop(conn, server); /* send any messages in queue */
647 
648  if (ret != -1) ret = cgw_wait_command(privdata, conn, server, 1); /* read ack's and delivery reports */
649  if (ret != -1) cgw_check_acks(privdata); /* check un-acked messages */
650 
651  if (ret == -1) {
652  mutex_lock(conn->flow_mutex);
654  mutex_unlock(conn->flow_mutex);
655  }
656  }
657  }
658 
659  conn_destroy(server);
660 
661  while ((msg = gwlist_extract_first(privdata->outgoing_queue)) != NULL)
663  mutex_lock(conn->flow_mutex);
664 
665  conn->status = SMSCCONN_DEAD;
666 
667  gwlist_destroy(privdata->outgoing_queue, NULL);
668  octstr_destroy(privdata->host);
669  octstr_destroy(privdata->allow_ip);
670  octstr_destroy(privdata->deny_ip);
671 
672  gw_free(privdata);
673  conn->data = NULL;
674 
675  mutex_unlock(conn->flow_mutex);
676  debug("bb.sms", 0, "smsc_cgw connection has completed shutdown.");
678 }
void error(int err, const char *fmt,...)
Definition: log.c:612
void bb_smscconn_connected(SMSCConn *conn)
Definition: bb_smscconn.c:192
static Connection * cgw_open_send_connection(SMSCConn *conn)
Definition: smsc_cgw.c:681
#define mutex_unlock(m)
Definition: thread.h:136
void bb_smscconn_killed(void)
Definition: bb_smscconn.c:199
long gwlist_len(List *list)
Definition: list.c:166
void * data
Definition: smscconn_p.h:249
List * outgoing_queue
Definition: smsc_cgw.c:153
int log_idx
Definition: smscconn_p.h:197
int cgw_wait_command(PrivData *privdata, SMSCConn *conn, Connection *server, int timeout)
Definition: smsc_cgw.c:811
static int cgw_send_loop(SMSCConn *conn, Connection *server)
Definition: smsc_cgw.c:739
void log_thread_to(int idx)
Definition: log.c:723
Definition: msg.h:79
void * gwlist_extract_first(List *list)
Definition: list.c:305
void conn_destroy(Connection *conn)
Definition: conn.c:619
void cgw_check_acks(PrivData *privdata)
Definition: smsc_cgw.c:787
Mutex * flow_mutex
Definition: smscconn_p.h:157
Octstr * allow_ip
Definition: smsc_cgw.c:164
Octstr * host
Definition: smsc_cgw.c:163
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
int shutdown
Definition: smsc_cgw.c:156
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
smscconn_status_t status
Definition: smscconn_p.h:151
static void server(int lport, int pport)
void bb_smscconn_send_failed(SMSCConn *conn, Msg *sms, int reason, Octstr *reply)
Definition: bb_smscconn.c:328
#define mutex_lock(m)
Definition: thread.h:130
Octstr * deny_ip
Definition: smsc_cgw.c:164
static XMLRPCDocument * msg
Definition: test_xmlrpc.c:86
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145
static int cgw_shutdown_cb ( SMSCConn conn,
int  finish_sending 
)
static

Definition at line 562 of file smsc_cgw.c.

References bb_smscconn_send_failed(), smscconn::data, debug(), gwlist_extract_first(), gwthread_wakeup(), msg, privdata::outgoing_queue, privdata::receiver_thread, privdata::rport, privdata::shutdown, SMSCCONN_FAILED_SHUTDOWN, SMSCCONN_KILLED_SHUTDOWN, and smscconn::why_killed.

Referenced by smsc_cgw_create().

563 {
564  PrivData *privdata = conn->data;
565 
566  debug("bb.sms", 0, "Shutting down SMSCConn CGW, %s",
567  finish_sending ? "slow" : "instant");
568 
569  /* Documentation claims this would have been done by smscconn.c,
570  but isn't when this code is being written. */
572  privdata->shutdown = 1; /* Separate from why_killed to avoid locking, as
573  * why_killed may be changed from outside? */
574 
575  if (finish_sending == 0) {
576  Msg *msg;
577  while ((msg = gwlist_extract_first(privdata->outgoing_queue)) != NULL) {
579  }
580  }
581 
582  if (privdata->rport > 0)
583  gwthread_wakeup(privdata->receiver_thread);
584  return 0;
585 }
void * data
Definition: smscconn_p.h:249
List * outgoing_queue
Definition: smsc_cgw.c:153
smscconn_killed_t why_killed
Definition: smscconn_p.h:153
Definition: msg.h:79
void * gwlist_extract_first(List *list)
Definition: list.c:305
int rport
Definition: smsc_cgw.c:160
int shutdown
Definition: smsc_cgw.c:156
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
void gwthread_wakeup(long thread)
long receiver_thread
Definition: smsc_cgw.c:154
void bb_smscconn_send_failed(SMSCConn *conn, Msg *sms, int reason, Octstr *reply)
Definition: bb_smscconn.c:328
static XMLRPCDocument * msg
Definition: test_xmlrpc.c:86
static void cgw_start_cb ( SMSCConn conn)
static

Definition at line 588 of file smsc_cgw.c.

References smscconn::data, debug(), gwthread_wakeup(), privdata::receiver_thread, and privdata::rport.

Referenced by smsc_cgw_create().

589 {
590  PrivData *privdata = conn->data;
591 
592  /* in case there are messages in the buffer already */
593  if (privdata->rport > 0)
594  gwthread_wakeup(privdata->receiver_thread);
595  debug("smsc.cgw", 0, "smsc_cgw: start called");
596 }
void * data
Definition: smscconn_p.h:249
int rport
Definition: smsc_cgw.c:160
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
void gwthread_wakeup(long thread)
long receiver_thread
Definition: smsc_cgw.c:154
int cgw_wait_command ( PrivData privdata,
SMSCConn conn,
Connection server,
int  timeout 
)

Definition at line 811 of file smsc_cgw.c.

References cgw_handle_op(), cgw_read_op(), cgwop_destroy(), conn_eof(), conn_error(), conn_wait(), error(), gwthread_pollfd(), info(), POLLIN, privdata::send_socket, SMSCCONN_DISCONNECTED, and smscconn::status.

Referenced by cgw_sender().

812 {
813  int ret;
814  struct cgwop *cgwop;
815 
816  /* is there data to be read? */
817  ret = gwthread_pollfd(privdata->send_socket, POLLIN, 0.2);
818 
819  if (ret != -1) {
820  /* read all waiting ops */
821  cgwop = cgw_read_op(privdata, conn, server, timeout);
822  if (cgwop != NULL) {
823  do {
824  if (conn_eof(server)) {
825  info(0, "cgw: Connection closed by SMSC");
827  if (cgwop != NULL) cgwop_destroy(cgwop);
828  return -1;
829  }
830  if (conn_error(server)) {
831  error(0, "cgw: Error trying to read ACKs from SMSC");
832  if (cgwop != NULL) cgwop_destroy(cgwop);
833  return -1;
834  }
835 
836  cgw_handle_op(conn, server, cgwop);
837  cgwop_destroy(cgwop);
838  } while ((cgwop = cgw_read_op(privdata, conn, server, timeout)) != NULL);
839  } else
840  conn_wait(server, 1); /* added because gwthread_pollfd
841  seems to always return 1. This will keep
842  the load on a reasonable level */
843  }
844 
845  return 0;
846 }
void error(int err, const char *fmt,...)
Definition: log.c:612
void info(int err, const char *fmt,...)
Definition: log.c:636
int send_socket
Definition: smsc_cgw.c:158
static int cgw_handle_op(SMSCConn *conn, Connection *server, struct cgwop *cgwop)
Definition: smsc_cgw.c:1064
int conn_eof(Connection *conn)
Definition: conn.c:697
static void cgwop_destroy(struct cgwop *cgwop)
Definition: smsc_cgw.c:239
#define POLLIN
Definition: gwpoll.h:91
int gwthread_pollfd(int fd, int events, double timeout)
int conn_wait(Connection *conn, double seconds)
Definition: conn.c:896
struct cgwop * cgw_read_op(PrivData *privdata, SMSCConn *conn, Connection *server, time_t timeout)
Definition: smsc_cgw.c:856
smscconn_status_t status
Definition: smscconn_p.h:151
int conn_error(Connection *conn)
Definition: conn.c:708
static void cgwop_add ( struct cgwop cgwop,
Octstr name,
Octstr value 
)
static

Definition at line 199 of file smsc_cgw.c.

References CGWOP_MAXARGS, info(), cgwop::name, cgwop::num_fields, octstr_duplicate, and cgwop::value.

Referenced by cgw_handle_op(), cgw_read_op(), cgwop_create(), and msg_to_cgwop().

200 {
201  if (cgwop->num_fields < CGWOP_MAXARGS)
202  {
203  cgwop->name[cgwop->num_fields] = octstr_duplicate(name);
204  cgwop->value[cgwop->num_fields] = octstr_duplicate(value);
205 
206  cgwop->num_fields++;
207  } else
208  {
209  info(0, "cgw: CGWOP_MAXARGS exceeded.");
210  }
211 }
void info(int err, const char *fmt,...)
Definition: log.c:636
Octstr ** value
Definition: smsc_cgw.c:145
Octstr ** name
Definition: smsc_cgw.c:144
#define octstr_duplicate(ostr)
Definition: octstr.h:187
int num_fields
Definition: smsc_cgw.c:142
#define CGWOP_MAXARGS
Definition: smsc_cgw.c:127
static struct cgwop* cgwop_create ( int  op,
int  trn 
)
static

Definition at line 214 of file smsc_cgw.c.

References cgwop_add(), CGWOP_MAXARGS, cgwop::name, cgwop::num_fields, octstr_append_decimal(), octstr_create, octstr_destroy(), octstr_imm(), cgwop::op, cgwop::trn, and cgwop::value.

Referenced by cgw_handle_op(), cgw_read_op(), and msg_to_cgwop().

215 {
216  struct cgwop *ret;
217  Octstr *trnstr;
218 
219  ret = gw_malloc(sizeof(struct cgwop));
220 
221  ret->op = op;
222  ret->num_fields = 0;
223  ret->trn = trn;
224 
225  ret->name = gw_malloc(CGWOP_MAXARGS * sizeof(Octstr *));
226  ret->value = gw_malloc(CGWOP_MAXARGS * sizeof(Octstr *));
227 
228  if (trn != -1)
229  {
230  trnstr = octstr_create("");
231  octstr_append_decimal(trnstr, trn);
232  cgwop_add(ret, octstr_imm("client-id"), trnstr);
233  octstr_destroy(trnstr);
234  }
235 
236  return ret;
237 }
Octstr ** value
Definition: smsc_cgw.c:145
Octstr ** name
Definition: smsc_cgw.c:144
static void cgwop_add(struct cgwop *cgwop, Octstr *name, Octstr *value)
Definition: smsc_cgw.c:199
int op
Definition: smsc_cgw.c:141
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:281
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
#define octstr_create(cstr)
Definition: octstr.h:125
int num_fields
Definition: smsc_cgw.c:142
void octstr_append_decimal(Octstr *ostr, long value)
Definition: octstr.c:1974
int trn
Definition: smsc_cgw.c:143
Definition: octstr.c:118
#define CGWOP_MAXARGS
Definition: smsc_cgw.c:127
static void cgwop_destroy ( struct cgwop cgwop)
static

Definition at line 239 of file smsc_cgw.c.

References cgwop::name, cgwop::num_fields, octstr_destroy(), and cgwop::value.

Referenced by cgw_handle_op(), cgw_receiver(), cgw_send_loop(), and cgw_wait_command().

240 {
241  int len;
242 
243  len = cgwop->num_fields;
244  while (--len >= 0)
245  {
246  octstr_destroy(cgwop->name[len]); /* octstr_destroy(NULL) is ok */
247  octstr_destroy(cgwop->value[len]);
248  }
249 
250  gw_free(cgwop->name);
251  gw_free(cgwop->value);
252  gw_free(cgwop);
253 }
Octstr ** value
Definition: smsc_cgw.c:145
Octstr ** name
Definition: smsc_cgw.c:144
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
int num_fields
Definition: smsc_cgw.c:142
static Octstr* cgwop_get ( struct cgwop cgwop,
Octstr name 
)
static

Definition at line 255 of file smsc_cgw.c.

References cgwop::name, cgwop::num_fields, octstr_compare(), and cgwop::value.

Referenced by cgw_handle_op().

256 {
257  int len = cgwop->num_fields;
258 
259  while (--len >= 0)
260  if (octstr_compare(name, cgwop->name[len]) == 0)
261  return cgwop->value[len];
262  return NULL;
263 }
Octstr ** value
Definition: smsc_cgw.c:145
Octstr ** name
Definition: smsc_cgw.c:144
int num_fields
Definition: smsc_cgw.c:142
int octstr_compare(const Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:869
static int cgwop_send ( Connection conn,
struct cgwop cgwop 
)
static

Definition at line 292 of file smsc_cgw.c.

References cgwop_tostr(), conn_write(), and octstr_destroy().

Referenced by cgw_handle_op(), and cgw_send_loop().

293 {
294  Octstr *dta = cgwop_tostr(cgwop);
295 
296  if (dta == NULL) return -1; /* couldn't convert to string */
297 
298  if (conn_write(conn, dta) == -1)
299  {
300  octstr_destroy(dta);
301  return -1;
302  }
303 
304  octstr_destroy(dta);
305  return 1;
306 }
int conn_write(Connection *conn, Octstr *data)
Definition: conn.c:1043
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
static Octstr * cgwop_tostr(struct cgwop *cgwop)
Definition: smsc_cgw.c:265
Definition: octstr.c:118
static Octstr* cgwop_tostr ( struct cgwop cgwop)
static

Definition at line 265 of file smsc_cgw.c.

References CGW_EOL, cgw_ops, cgwop::name, cgwop::num_fields, octstr_append(), octstr_append_char(), octstr_create, octstr_imm(), cgwop::op, and cgwop::value.

Referenced by cgwop_send().

266 {
267  int len = cgwop->num_fields;
268  Octstr *str;
269 
270  if (cgw_ops[cgwop->op] == NULL) return NULL; /* invalid operation */
271 
272  str = octstr_create("");
273 
274  octstr_append(str, octstr_imm("op:"));
275  octstr_append(str, octstr_imm(cgw_ops[cgwop->op]));
277 
278  while (--len >= 0)
279  {
280  octstr_append(str, cgwop->name[len]);
281  octstr_append_char(str, ':');
282  octstr_append(str, cgwop->value[len]);
284  }
285  octstr_append(str, octstr_imm("end:"));
286  octstr_append(str, octstr_imm(cgw_ops[cgwop->op]));
288 
289  return str;
290 }
Octstr ** value
Definition: smsc_cgw.c:145
Octstr ** name
Definition: smsc_cgw.c:144
void octstr_append(Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:1502
void octstr_append_char(Octstr *ostr, int ch)
Definition: octstr.c:1515
int op
Definition: smsc_cgw.c:141
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:281
#define octstr_create(cstr)
Definition: octstr.h:125
int num_fields
Definition: smsc_cgw.c:142
static char * cgw_ops[6]
Definition: smsc_cgw.c:148
Definition: octstr.c:118
#define CGW_EOL
Definition: smsc_cgw.c:124
static struct cgwop* msg_to_cgwop ( PrivData privdata,
Msg msg,
int  trn 
)
static

Definition at line 380 of file smsc_cgw.c.

References privdata::appname, cgw_encode_msg(), CGW_OP_MSG, cgwop_add(), cgwop_create(), DLR_IS_ENABLED_DEVICE, gw_isdigit(), octstr_append(), octstr_binary_to_hex(), octstr_check_range(), octstr_create, octstr_destroy(), octstr_duplicate, octstr_imm(), and octstr_len().

Referenced by cgw_send_loop().

381 {
382  struct cgwop *cgwop;
383  Octstr *sender, *udh, *dta;
384 
385  cgwop = cgwop_create(CGW_OP_MSG, trn);
386 
387  if (cgwop == NULL) return NULL;
388 
389  if (!octstr_check_range(msg->sms.sender, 0, octstr_len(msg->sms.sender), gw_isdigit))
390  {
391  /* If alphanumeric, simply prefix sender with '$' char */
392  sender = octstr_create("$");
393  octstr_append(sender, msg->sms.sender);
394  } else sender = octstr_duplicate(msg->sms.sender);
395 
396  cgwop_add(cgwop, octstr_imm("app"), privdata->appname);
397  cgwop_add(cgwop, octstr_imm("from"), sender);
398  cgwop_add(cgwop, octstr_imm("to"), msg->sms.receiver);
399 
400  /* If delivery reports are asked, ask for them by adding a nrq:anything field */
401  if (DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask))
402  cgwop_add(cgwop, octstr_imm("nrq"), octstr_imm("true"));
403 
404  octstr_destroy(sender);
405 
406  if (octstr_len(msg->sms.udhdata))
407  {
408  udh = octstr_duplicate(msg->sms.udhdata);
409  octstr_binary_to_hex(udh, 1);
410  cgwop_add(cgwop, octstr_imm("udh"), udh);
411  octstr_destroy(udh);
412 
413  dta = octstr_duplicate(msg->sms.msgdata);
414  octstr_binary_to_hex(dta, 1);
415  cgwop_add(cgwop, octstr_imm("msg"), dta);
416  cgwop_add(cgwop, octstr_imm("type"), octstr_imm("bin"));
417  octstr_destroy(dta);
418  } else
419  {
420  cgwop_add(cgwop, octstr_imm("msg"), cgw_encode_msg(msg->sms.msgdata));
421  }
422 
423  return cgwop;
424 }
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
static void cgwop_add(struct cgwop *cgwop, Octstr *name, Octstr *value)
Definition: smsc_cgw.c:199
#define DLR_IS_ENABLED_DEVICE(dlr)
Definition: dlr.h:82
void octstr_binary_to_hex(Octstr *ostr, int uppercase)
Definition: octstr.c:463
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:281
static struct cgwop * cgwop_create(int op, int trn)
Definition: smsc_cgw.c:214
#define octstr_duplicate(ostr)
Definition: octstr.h:187
#define CGW_OP_MSG
Definition: smsc_cgw.c:132
int gw_isdigit(int c)
Definition: utils.c:988
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
#define octstr_create(cstr)
Definition: octstr.h:125
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
int trn
Definition: smsc_cgw.c:143
Definition: octstr.c:118
Octstr * appname
Definition: smsc_cgw.c:165
static Octstr * cgw_encode_msg(Octstr *str)
Definition: smsc_cgw.c:312
int smsc_cgw_create ( SMSCConn conn,
CfgGroup cfg 
)

Definition at line 431 of file smsc_cgw.c.

References allow_ip, privdata::allow_ip, privdata::appname, cfg_get, cfg_get_integer(), cgw_add_msg_cb(), CGW_DEFPORT, cgw_listener(), cgw_open_listening_socket(), cgw_queued_cb(), cgw_sender(), cgw_shutdown_cb(), cgw_start_cb(), CGW_TRN_MAX, privdata::check_time, smscconn::connect_time, smscconn::data, deny_ip, privdata::deny_ip, privdata::dlr, error(), gwlist_create, gwlist_destroy(), gwthread_create, host, privdata::host, info(), privdata::listening_socket, smscconn::name, privdata::nexttrn, octstr_create, octstr_destroy(), octstr_format(), octstr_imm(), our_port, privdata::our_port, privdata::outgoing_queue, privdata::port, smscconn::queued, privdata::receiver_thread, privdata::rport, smscconn::send_msg, privdata::sender_thread, privdata::sendtime, privdata::shutdown, smscconn::shutdown, SMSCCONN_CONNECTING, SMSCCONN_DEAD, SMSCCONN_KILLED_CANNOT_CONNECT, smscconn::start_conn, smscconn::status, privdata::waitack, and smscconn::why_killed.

Referenced by smscconn_create().

432 {
434  Octstr *allow_ip, *deny_ip, *host, *appname;
435  long portno, our_port, waitack;
436  int i;
437 
438  privdata = gw_malloc(sizeof(PrivData));
439  privdata->outgoing_queue = gwlist_create();
440  privdata->listening_socket = -1;
441 
442  if (cfg_get_integer(&portno, cfg, octstr_imm("port")) == -1)
443  portno = 0;
444  privdata->port = portno;
445 
446  if (cfg_get_integer(&portno, cfg, octstr_imm("receive-port")) < 0)
447  portno = 0;
448  privdata->rport = portno;
449 
450  host = cfg_get(cfg, octstr_imm("host"));
451  appname = cfg_get(cfg, octstr_imm("appname"));
452 
453  if (cfg_get_integer(&our_port, cfg, octstr_imm("our-port")) == -1)
454  privdata->our_port = 0; /* 0 means use any port */
455  else
456  privdata->our_port = our_port;
457 
458  allow_ip = cfg_get(cfg, octstr_imm("connect-allow-ip"));
459  if (allow_ip)
460  deny_ip = octstr_create("*.*.*.*");
461  else
462  deny_ip = NULL;
463 
464  if (cfg_get_integer(&waitack, cfg, octstr_imm("wait-ack")) < 0)
465  privdata->waitack = 60;
466  else
467  privdata->waitack = waitack;
468 
469  if (privdata->port <= 0 || privdata->port > 65535) {
470  info(1, "No port defined for cgw -> using default (%d)", CGW_DEFPORT);
471  privdata->port = CGW_DEFPORT;
472  }
473 
474 
475  if (host == NULL) {
476  error(0, "'host' missing in cgw configuration.");
477  goto error;
478  }
479 
480  if (appname == NULL)
481  appname = octstr_create("send");
482 
483  privdata->allow_ip = allow_ip;
484  privdata->deny_ip = deny_ip;
485  privdata->host = host;
486  privdata->appname = appname;
487  privdata->nexttrn = 0;
488  privdata->check_time = 0;
489 
490  for (i = 0; i < CGW_TRN_MAX; i++) {
491  privdata->sendtime[i] = 0;
492  privdata->dlr[i] = 0;
493  }
494 
495  if (privdata->rport > 0 && cgw_open_listening_socket(conn,privdata) < 0) {
496  gw_free(privdata);
497  privdata = NULL;
498  goto error;
499  }
500 
501 
502  conn->data = privdata;
503 
504  conn->name = octstr_format("CGW:%d", privdata->port);
505 
506  privdata->shutdown = 0;
507 
508  conn->status = SMSCCONN_CONNECTING;
509  conn->connect_time = time(NULL);
510 
511  if (privdata->rport > 0 && (privdata->receiver_thread = gwthread_create(cgw_listener, conn)) == -1)
512  goto error;
513 
514  if ((privdata->sender_thread = gwthread_create(cgw_sender, conn)) == -1) {
515  privdata->shutdown = 1;
516  goto error;
517  }
518 
519  conn->shutdown = cgw_shutdown_cb;
520  conn->queued = cgw_queued_cb;
521  conn->start_conn = cgw_start_cb;
522  conn->send_msg = cgw_add_msg_cb;
523 
524  return 0;
525 
526 error:
527  error(0, "Failed to create CGW smsc connection");
528  if (privdata != NULL)
529  gwlist_destroy(privdata->outgoing_queue, NULL);
530 
531  gw_free(privdata);
532  octstr_destroy(host);
533  octstr_destroy(allow_ip);
534  octstr_destroy(deny_ip);
535  octstr_destroy(appname);
536 
538  conn->status = SMSCCONN_DEAD;
539  info(0, "exiting");
540  return -1;
541 }
#define CGW_DEFPORT
Definition: smsc_cgw.c:123
int port
Definition: smsc_cgw.c:159
Octstr * name
Definition: smscconn_p.h:173
void error(int err, const char *fmt,...)
Definition: log.c:612
void info(int err, const char *fmt,...)
Definition: log.c:636
static long our_port
Definition: radius_acct.c:87
static void cgw_start_cb(SMSCConn *conn)
Definition: smsc_cgw.c:588
void * data
Definition: smscconn_p.h:249
int waitack
Definition: smsc_cgw.c:171
List * outgoing_queue
Definition: smsc_cgw.c:153
static Octstr * host
Definition: fakesmsc.c:121
#define cfg_get(grp, varname)
Definition: cfg.h:86
static int cgw_add_msg_cb(SMSCConn *conn, Msg *sms)
Definition: smsc_cgw.c:549
void(* start_conn)(SMSCConn *conn)
Definition: smscconn_p.h:245
smscconn_killed_t why_killed
Definition: smscconn_p.h:153
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:281
static int cgw_shutdown_cb(SMSCConn *conn, int finish_sending)
Definition: smsc_cgw.c:562
time_t connect_time
Definition: smscconn_p.h:155
static Octstr * deny_ip
Definition: bb_udp.c:112
Octstr * allow_ip
Definition: smsc_cgw.c:164
Octstr * host
Definition: smsc_cgw.c:163
Octstr * octstr_format(const char *fmt,...)
Definition: octstr.c:2462
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
int rport
Definition: smsc_cgw.c:160
#define gwthread_create(func, arg)
Definition: gwthread.h:90
#define octstr_create(cstr)
Definition: octstr.h:125
long check_time
Definition: smsc_cgw.c:173
#define CGW_TRN_MAX
Definition: smsc_cgw.c:125
static void cgw_sender(void *arg)
Definition: smsc_cgw.c:616
static Octstr * allow_ip
Definition: bb_udp.c:111
int shutdown
Definition: smsc_cgw.c:156
long sender_thread
Definition: smsc_cgw.c:155
static long cgw_queued_cb(SMSCConn *conn)
Definition: smsc_cgw.c:599
Definition: octstr.c:118
int(* shutdown)(SMSCConn *conn, int finish_sending)
Definition: smscconn_p.h:229
int cfg_get_integer(long *n, CfgGroup *grp, Octstr *varname)
Definition: cfg.c:739
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
int(* send_msg)(SMSCConn *conn, Msg *msg)
Definition: smscconn_p.h:235
long receiver_thread
Definition: smsc_cgw.c:154
int listening_socket
Definition: smsc_cgw.c:157
Octstr * appname
Definition: smsc_cgw.c:165
time_t sendtime[CGW_TRN_MAX]
Definition: smsc_cgw.c:168
int our_port
Definition: smsc_cgw.c:161
static void cgw_listener(void *arg)
Definition: smsc_cgw.c:967
Octstr * deny_ip
Definition: smsc_cgw.c:164
static int cgw_open_listening_socket(SMSCConn *conn, PrivData *privdata)
Definition: smsc_cgw.c:945
int dlr[CGW_TRN_MAX]
Definition: smsc_cgw.c:169
int nexttrn
Definition: smsc_cgw.c:172
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145

Variable Documentation

char* cgw_ops[6] = {"nop", "msg", "ok", "err", "delivery", "hello"}
static

Definition at line 148 of file smsc_cgw.c.

Referenced by cgwop_tostr().

See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.