smsc_cgw.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:35k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  * smsc_cgw.c - Implements an interface to the Sonera ContentGateway software
  3.  *
  4.  * Anders Lindh, FlyerOne Ltd <alindh@flyerone.com>
  5.  *
  6.  *
  7.  * Changelog:
  8.  *
  9.  * 22/02/2002: Preliminary support for the Euro character (req. ProviderServer 2.5.2)
  10.  * 25/01/2002: Caught a potentially nasty bug
  11.  * 16/01/2002: Some code cleanup
  12.  * 10/01/2002: Fixed a bug in trn handling
  13.  * 16/11/2001: Some minor fixes (Thanks to Tuomas Luttinen)
  14.  * 12/11/2001: Delivery reports, better acking and numerous other small fixes
  15.  * 05/11/2001: Initial release. Based heavily on smsc_emi2 and smsc_at2. 
  16.  *
  17.  *
  18.  * TO-DO: Do some real life testing
  19.  *        Squash bugs
  20.  *
  21.  * Usage: add the following to kannel.conf:
  22.  *
  23.  * group = smsc
  24.  * smsc = cgw
  25.  * host = x.x.x.x      <- CGW server host
  26.  * port = xxxx         <- CGW server otp port (if omitted, defaults to 21772)
  27.  * receive-port = xxxx <- our port for incoming messages
  28.  * appname = xxxx      <- Name of a "Send only" service. Defaults to "send".
  29.  *               All outgoing messages are routed through this service.
  30.  *
  31.  * Configure ContentGateway software to use the above port as text-port
  32.  * (in provider.cnf). This is documented in their "Guide for Service
  33.  * development 2.5", page 80.
  34.  *
  35.  * Add a new "Receive only" service (with the Remote Control tool), and set
  36.  * the "Application for Incoming Message" to "text://kannelhost:receive-port".
  37.  *
  38.  *
  39.  * Note:
  40.  *
  41.  * Do NOT define the service as a "Query/Reply" service, as it expects response
  42.  * messages to have a matching session-id tag. Kannel does not store the
  43.  * relation between a query and a reply, so the response message will not have
  44.  * the session-id tag. Even though the messages are delivered successfully,
  45.  * billing of premium priced services will fail.
  46.  *
  47.  *
  48.  */
  49. #include <sys/types.h>
  50. #include <sys/socket.h>
  51. #include <unistd.h>
  52. #include <errno.h>
  53. #include <time.h>
  54. #include <limits.h>
  55. #include "gwlib/gwlib.h"
  56. #include "smscconn.h"
  57. #include "smscconn_p.h"
  58. #include "bb_smscconn_cb.h"
  59. #include "msg.h"
  60. #include "sms.h"
  61. #include "dlr.h"
  62. #define CGW_DEFPORT  21772
  63. #define CGW_EOL      0x0A
  64. #define CGW_TRN_MAX  500 /* Size of our internal message buffer. */
  65. #define CGWOP_MAXARGS 10      /* max. number of name:value pairs in cgwop */
  66. /* Valid CGW operations */
  67. #define CGW_OP_NOP 0      /* this doesn't really exist.. */
  68. #define CGW_OP_MSG 1
  69. #define CGW_OP_OK 2
  70. #define CGW_OP_ERR 3
  71. #define CGW_OP_DELIVERY 4
  72. #define CGW_OP_HELLO 5
  73. #define CGW_OP_STATUS 6
  74. struct cgwop
  75. {
  76.     int op;     /* one of above */
  77.     int num_fields;
  78.     int trn;                    /* transaction number, used to ACK messages */
  79.     Octstr **name;     /* for storing name/value pairs */
  80.     Octstr **value;
  81. };
  82. static char *cgw_ops[6] = {"nop", "msg", "ok", "err", "delivery", "hello"};
  83. typedef struct privdata
  84. {
  85.     List *outgoing_queue;
  86.     long receiver_thread;
  87.     long sender_thread;
  88.     int shutdown;             /* Internal signal to shut down */
  89.     int listening_socket;      /* File descriptor */
  90.     int send_socket;
  91.     int port;             /* SMSC port */
  92.     int rport;     /* port for receiving messages*/
  93.     int our_port;        /* Optional local port number in which to
  94.                            * bind our end of send connection */
  95.     Octstr *host;
  96.     Octstr *allow_ip, *deny_ip;
  97.     Octstr *appname;     /* Application name as defined in Sonera Remote manager */
  98.     Msg *sendmsg[CGW_TRN_MAX];
  99.     time_t sendtime[CGW_TRN_MAX];
  100.     int dlr[CGW_TRN_MAX];     /* dlr = DLR_SMSC_SUCCESS || DLR_SMSC_FAIL */
  101.     int unacked;     /* Sent messages not acked */
  102.     int waitack;         /* Seconds to wait to ack */
  103.     int nexttrn;
  104.     long check_time;      /* last checked ack/nack status */
  105. }
  106. PrivData;
  107. static int cgw_add_msg_cb(SMSCConn *conn, Msg *sms);
  108. static int cgw_shutdown_cb(SMSCConn *conn, int finish_sending);
  109. static void cgw_start_cb(SMSCConn *conn);
  110. static long cgw_queued_cb(SMSCConn *conn);
  111. static void cgw_sender(void *arg);
  112. static Connection *cgw_open_send_connection(SMSCConn *conn);
  113. static int cgw_send_loop(SMSCConn *conn, Connection *server);
  114. void cgw_check_acks(PrivData *privdata);
  115. int cgw_wait_command(PrivData *privdata, SMSCConn *conn, Connection *server, int timeout);
  116. static int cgw_open_listening_socket(PrivData *privdata);
  117. static void cgw_listener(void *arg);
  118. static void cgw_receiver(SMSCConn *conn, Connection *server);
  119. static int cgw_handle_op(SMSCConn *conn, Connection *server, struct cgwop *cgwop);
  120. struct cgwop *cgw_read_op(PrivData *privdata, SMSCConn *conn, Connection *server, time_t timeout);
  121. /******************************************************************************
  122.  * Functions for handling cgwop -structures
  123.  */
  124. static void cgwop_add(struct cgwop *cgwop, Octstr *name, Octstr *value)
  125. {
  126.     if (cgwop->num_fields < CGWOP_MAXARGS)
  127.     {
  128.         cgwop->name[cgwop->num_fields] = octstr_duplicate(name);
  129.         cgwop->value[cgwop->num_fields] = octstr_duplicate(value);
  130.         cgwop->num_fields++;
  131.     } else
  132.     {
  133.         info(0, "cgw: CGWOP_MAXARGS exceeded.");
  134.     }
  135. }
  136. static struct cgwop *cgwop_create(int op, int trn)
  137. {
  138.     struct cgwop *ret;
  139.     Octstr *trnstr;
  140.     ret = gw_malloc(sizeof(struct cgwop));
  141.     ret->op = op;
  142.     ret->num_fields = 0;
  143.     ret->trn = trn;
  144.     ret->name = gw_malloc(CGWOP_MAXARGS * sizeof(Octstr *));
  145.     ret->value = gw_malloc(CGWOP_MAXARGS * sizeof(Octstr *));
  146.     if (trn != -1)
  147.     {
  148.         trnstr = octstr_create("");
  149.         octstr_append_decimal(trnstr, trn);
  150.         cgwop_add(ret, octstr_imm("client-id"), trnstr);
  151.         octstr_destroy(trnstr);
  152.     }
  153.     return ret;
  154. }
  155. static void cgwop_destroy(struct cgwop *cgwop)
  156. {
  157.     int len;
  158.     len = cgwop->num_fields;
  159.     while (--len >= 0)
  160.     {
  161.         octstr_destroy(cgwop->name[len]);      /* octstr_destroy(NULL) is ok */
  162.         octstr_destroy(cgwop->value[len]);
  163.     }
  164.     gw_free(cgwop->name);
  165.     gw_free(cgwop->value);
  166.     gw_free(cgwop);
  167. }
  168. static Octstr *cgwop_get(struct cgwop *cgwop, Octstr *name)
  169. {
  170.     int len = cgwop->num_fields;
  171.     while (--len >= 0)
  172.         if (octstr_compare(name, cgwop->name[len]) == 0)
  173.             return cgwop->value[len];
  174.     return NULL;
  175. }
  176. static Octstr *cgwop_tostr(struct cgwop *cgwop)
  177. {
  178.     int len = cgwop->num_fields;
  179.     Octstr *str;
  180.     if (cgw_ops[cgwop->op] == NULL) return NULL;     // invalid operation
  181.     str = octstr_create("");
  182.     octstr_append(str, octstr_imm("op:"));
  183.     octstr_append(str, octstr_imm(cgw_ops[cgwop->op]));
  184.     octstr_append_char(str, CGW_EOL);
  185.     while (--len >= 0)
  186.     {
  187.         octstr_append(str, cgwop->name[len]);
  188.         octstr_append_char(str, ':');
  189.         octstr_append(str, cgwop->value[len]);
  190.         octstr_append_char(str, CGW_EOL);
  191.     }
  192.     octstr_append(str, octstr_imm("end:"));
  193.     octstr_append(str, octstr_imm(cgw_ops[cgwop->op]));
  194.     octstr_append_char(str, CGW_EOL);
  195.     return str;
  196. }
  197. static int cgwop_send(Connection *conn, struct cgwop *cgwop)
  198. {
  199.     Octstr *dta = cgwop_tostr(cgwop);
  200.     if (dta == NULL) return -1;     /* couldn't convert to string */
  201.     if (conn_write(conn, dta) == -1)
  202.     {
  203.         octstr_destroy(dta);
  204.         return -1;
  205.     }
  206.     octstr_destroy(dta);
  207.     return 1;
  208. }
  209. /******************************************************************************
  210.  * cgw_encode_msg - Encode a msg according to specifications
  211.  */
  212. static Octstr *cgw_encode_msg(Octstr* str)
  213. {
  214.     int i;
  215.     char esc = 27;
  216.     char e = 'e';
  217.     /* Euro char (0x80) -> ESC + e. We do this conversion as long as the message 
  218.        length is under 160 chars (the checking could probably be done better) */
  219.     while ((i = octstr_search_char(str, 0x80, 0)) != -1) {    
  220.         octstr_delete(str, i, 1);     // delete Euro char
  221. if (octstr_len(str) < 160) {
  222.     octstr_insert_data(str, i, &esc, 1);  // replace with ESC + e
  223.     octstr_insert_data(str, i+1, &e, 1);  
  224. } else {
  225.     octstr_insert_data(str, i, &e, 1);  // no room for ESC + e, just replace with an e
  226.         }
  227.     }
  228.     /* Escape backslash characters */
  229.     while ((i = octstr_search_char(str, '\', 0)) != -1) {
  230.         octstr_insert(str, octstr_imm("\"), i);
  231.     }
  232.     /* Remove Line Feed characters */
  233.     while ((i = octstr_search_char(str, CGW_EOL, 0)) != -1) {
  234.         octstr_delete(str, i, 1);     // delete EOL char
  235.         octstr_insert(str, octstr_imm("\n"), i);
  236.     }
  237.     /* Remove Carriage return characters */
  238.     while ((i = octstr_search_char(str, 13, 0)) != -1) {
  239.         octstr_delete(str, i, 1);     // delete EOL char
  240.         octstr_insert(str, octstr_imm("\r"), i);
  241.     }
  242.     return str;
  243. }
  244. /******************************************************************************
  245.  * cgw_decode_msg - Decode an incoming msg
  246.  */
  247. static Octstr *cgw_decode_msg(Octstr* str)
  248. {
  249.     int i;
  250.     /* make n -> linefeed */
  251.     while ((i = octstr_search(str, octstr_imm("\n"), 0)) != -1) {
  252.         octstr_delete(str, i, 2);     // delete "n" str
  253.         octstr_insert(str, octstr_imm("n"), i);
  254.     }
  255.     /* make r -> carriage return */
  256.     while ((i = octstr_search(str, octstr_imm("\r"), 0)) != -1) {
  257.         octstr_delete(str, i, 2);     // delete EOL char
  258.         octstr_insert(str, octstr_imm("r"), i);
  259.     }
  260.     /* remove double backslashes */
  261.     while ((i = octstr_search(str, octstr_imm("\\"), 0)) != -1) {
  262.         octstr_delete(str, i, 1);
  263.     }
  264.     return str;
  265. }
  266. /******************************************************************************
  267.  * msg_to_cgwop - Create a send cgwop from a message
  268.  */
  269. static struct cgwop *msg_to_cgwop(PrivData *privdata, Msg *msg, int trn)
  270. {
  271.     struct cgwop *cgwop;
  272.     Octstr *sender, *udh, *dta;
  273.     cgwop = cgwop_create(CGW_OP_MSG, trn);
  274.     if (cgwop == NULL) return NULL;
  275.     if (!octstr_check_range(msg->sms.sender, 0, octstr_len(msg->sms.sender), gw_isdigit))
  276.     {
  277.         /* If alphanumeric, simply prefix sender with '$' char */
  278.         sender = octstr_create("$");
  279.         octstr_append(sender, msg->sms.sender);
  280.     } else sender = octstr_duplicate(msg->sms.sender);
  281.     cgwop_add(cgwop, octstr_imm("app"), privdata->appname);
  282.     cgwop_add(cgwop, octstr_imm("from"), sender);
  283.     cgwop_add(cgwop, octstr_imm("to"), msg->sms.receiver);
  284.     /* If delivery reports are asked, ask for them by adding a nrq:anything field */
  285.     if (msg->sms.dlr_mask & 0x07)
  286.         cgwop_add(cgwop, octstr_imm("nrq"), octstr_imm("true"));
  287.     octstr_destroy(sender);
  288.     if (octstr_len(msg->sms.udhdata))
  289.     {
  290.         udh = octstr_duplicate(msg->sms.udhdata);
  291.         octstr_binary_to_hex(udh, 1);
  292.         cgwop_add(cgwop, octstr_imm("udh"), udh);
  293.         octstr_destroy(udh);
  294.         dta = octstr_duplicate(msg->sms.msgdata);
  295.         octstr_binary_to_hex(dta, 1);
  296.         cgwop_add(cgwop, octstr_imm("msg"), dta);
  297.         cgwop_add(cgwop, octstr_imm("type"), octstr_imm("bin"));
  298.         octstr_destroy(dta);
  299.     } else
  300.     {
  301.         cgwop_add(cgwop, octstr_imm("msg"), cgw_encode_msg(msg->sms.msgdata));
  302.     }
  303.     return cgwop;
  304. }
  305. /******************************************************************************
  306.  * Called to create the SMSC. This is our entry point.
  307.  */
  308. int smsc_cgw_create(SMSCConn *conn, CfgGroup *cfg)
  309. {
  310.     PrivData *privdata;
  311.     Octstr *allow_ip, *deny_ip, *host, *appname;
  312.     long portno, our_port, waitack;
  313.     int i;
  314.     privdata = gw_malloc(sizeof(PrivData));
  315.     privdata->outgoing_queue = list_create();
  316.     privdata->listening_socket = -1;
  317.     if (cfg_get_integer(&portno, cfg, octstr_imm("port")) == -1)
  318.         portno = 0;
  319.     privdata->port = portno;
  320.     if (cfg_get_integer(&portno, cfg, octstr_imm("receive-port")) < 0)
  321.         portno = 0;
  322.     privdata->rport = portno;
  323.     host = cfg_get(cfg, octstr_imm("host"));
  324.     appname = cfg_get(cfg, octstr_imm("appname"));
  325.     if (cfg_get_integer(&our_port, cfg, octstr_imm("our-port")) == -1)
  326.         privdata->our_port = 0;     /* 0 means use any port */
  327.     else
  328.         privdata->our_port = our_port;
  329.     allow_ip = cfg_get(cfg, octstr_imm("connect-allow-ip"));
  330.     if (allow_ip)
  331.         deny_ip = octstr_create("*.*.*.*");
  332.     else
  333.         deny_ip = NULL;
  334.     if (cfg_get_integer(&waitack, cfg, octstr_imm("wait-ack")) < 0)
  335.         privdata->waitack = 60;
  336.     else
  337.         privdata->waitack = waitack;
  338.     if (privdata->port <= 0 || privdata->port > 65535) {
  339.         info(1, "No port defined for cgw -> using default (%d)", CGW_DEFPORT);
  340.         privdata->port = CGW_DEFPORT;
  341.     }
  342.     if (host == NULL) {
  343.         error(0, "'host' missing in cgw configuration.");
  344.         goto error;
  345.     }
  346.     if (appname == NULL)
  347.         appname = octstr_create("send");
  348.     privdata->allow_ip = allow_ip;
  349.     privdata->deny_ip = deny_ip;
  350.     privdata->host = host;
  351.     privdata->appname = appname;
  352.     privdata->nexttrn = 0;
  353.     privdata->check_time = 0;
  354.     for (i = 0; i < CGW_TRN_MAX; i++) {
  355.         privdata->sendtime[i] = 0;
  356.         privdata->dlr[i] = 0;
  357.     }
  358.     if (privdata->rport > 0 && cgw_open_listening_socket(privdata) < 0) {
  359.         gw_free(privdata);
  360.         privdata = NULL;
  361.         goto error;
  362.     }
  363.     conn->data = privdata;
  364.     conn->name = octstr_format("CGW:%d", privdata->port);
  365.     privdata->shutdown = 0;
  366.     conn->status = SMSCCONN_CONNECTING;
  367.     conn->connect_time = time(NULL);
  368.     if (privdata->rport > 0 && (privdata->receiver_thread = gwthread_create(cgw_listener, conn)) == -1)
  369.         goto error;
  370.     if ((privdata->sender_thread = gwthread_create(cgw_sender, conn)) == -1) {
  371.         privdata->shutdown = 1;
  372.         goto error;
  373.     }
  374.     conn->shutdown = cgw_shutdown_cb;
  375.     conn->queued = cgw_queued_cb;
  376.     conn->start_conn = cgw_start_cb;
  377.     conn->send_msg = cgw_add_msg_cb;
  378.     return 0;
  379. error:
  380.     error(0, "Failed to create CGW smsc connection");
  381.     if (privdata != NULL)
  382.         list_destroy(privdata->outgoing_queue, NULL);
  383.     gw_free(privdata);
  384.     octstr_destroy(host);
  385.     octstr_destroy(allow_ip);
  386.     octstr_destroy(deny_ip);
  387.     octstr_destroy(appname);
  388.     conn->why_killed = SMSCCONN_KILLED_CANNOT_CONNECT;
  389.     conn->status = SMSCCONN_DEAD;
  390.     info(0, "exiting");
  391.     return -1;
  392. }
  393. /******************************************************************************
  394.  * Callbacks for startup, shutdown, incoming and outgoing messages
  395.  */
  396. static int cgw_add_msg_cb(SMSCConn *conn, Msg *sms)
  397. {
  398.     PrivData *privdata = conn->data;
  399.     Msg *copy;
  400.     copy = msg_duplicate(sms);
  401.     list_produce(privdata->outgoing_queue, copy);
  402.     gwthread_wakeup(privdata->sender_thread);
  403.     return 0;
  404. }
  405. static int cgw_shutdown_cb(SMSCConn *conn, int finish_sending)
  406. {
  407.     PrivData *privdata = conn->data;
  408.     debug("bb.sms", 0, "Shutting down SMSCConn CGW, %s",
  409.           finish_sending ? "slow" : "instant");
  410.     /* Documentation claims this would have been done by smscconn.c,
  411.        but isn't when this code is being written. */
  412.     conn->why_killed = SMSCCONN_KILLED_SHUTDOWN;
  413.     privdata->shutdown = 1;     /* Separate from why_killed to avoid locking, as
  414.                   * why_killed may be changed from outside? */
  415.     if (finish_sending == 0) {
  416.         Msg *msg;
  417.         while ((msg = list_extract_first(privdata->outgoing_queue)) != NULL) {
  418.             bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN);
  419.         }
  420.     }
  421.     if (privdata->rport > 0)
  422.         gwthread_wakeup(privdata->receiver_thread);
  423.     return 0;
  424. }
  425. static void cgw_start_cb(SMSCConn *conn)
  426. {
  427.     PrivData *privdata = conn->data;
  428.     /* in case there are messages in the buffer already */
  429.     if (privdata->rport > 0)
  430.         gwthread_wakeup(privdata->receiver_thread);
  431.     debug("smsc.cgw", 0, "smsc_cgw: start called");
  432. }
  433. static long cgw_queued_cb(SMSCConn *conn)
  434. {
  435.     PrivData *privdata = conn->data;
  436.     long ret = list_len(privdata->outgoing_queue);
  437.     /* use internal queue as load, maybe something else later */
  438.     conn->load = ret;
  439.     return ret;
  440. }
  441. /******************************************************************************
  442.  * This is the entry point for out sender thread. This function is responsible
  443.  * for sending and acking messages in queue
  444.  */
  445. static void cgw_sender(void *arg)
  446. {
  447.     SMSCConn *conn = arg;
  448.     PrivData *privdata = conn->data;
  449.     Msg *msg = NULL;
  450.     Connection *server = NULL;
  451.     int l = 0;
  452.     int ret = 0;
  453.     conn->status = SMSCCONN_CONNECTING;
  454.     while (!privdata->shutdown) {
  455.         // check that connection is active
  456.         if (conn->status != SMSCCONN_ACTIVE) {
  457.             if ((server = cgw_open_send_connection(conn)) == NULL) {
  458.                 privdata->shutdown = 1;
  459.                 error(0, "Unable to connect to CGW server");
  460.                 return ;
  461.             }
  462.             conn->status = SMSCCONN_ACTIVE;
  463.             bb_smscconn_connected(conn);
  464.         } else {
  465.     ret = 0;
  466.             l = list_len(privdata->outgoing_queue);
  467.             if (l > 0)
  468.                ret = cgw_send_loop(conn, server);     /* send any messages in queue */
  469.             if (ret != -1) ret = cgw_wait_command(privdata, conn, server, 1);     /* read ack's and delivery reports */
  470.             if (ret != -1) cgw_check_acks(privdata);     /* check un-acked messages */
  471.  
  472.             if (ret == -1) {
  473.                 mutex_lock(conn->flow_mutex);
  474.                 conn->status = SMSCCONN_RECONNECTING;
  475.                 mutex_unlock(conn->flow_mutex);
  476.     }
  477.         }
  478.     }
  479.     conn_destroy(server);
  480.     while ((msg = list_extract_first(privdata->outgoing_queue)) != NULL)
  481.         bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN);
  482.     mutex_lock(conn->flow_mutex);
  483.     conn->status = SMSCCONN_DEAD;
  484.     list_destroy(privdata->outgoing_queue, NULL);
  485.     octstr_destroy(privdata->host);
  486.     octstr_destroy(privdata->allow_ip);
  487.     octstr_destroy(privdata->deny_ip);
  488.     gw_free(privdata);
  489.     conn->data = NULL;
  490.     mutex_unlock(conn->flow_mutex);
  491.     debug("bb.sms", 0, "smsc_cgw connection has completed shutdown.");
  492.     bb_smscconn_killed();
  493. }
  494. static Connection *cgw_open_send_connection(SMSCConn *conn)
  495. {
  496.     PrivData *privdata = conn->data;
  497.     int wait;
  498.     Connection *server;
  499.     Msg *msg;
  500.     wait = 0;
  501.     while (!privdata->shutdown) {
  502.         /* Change status only if the first attempt to form a
  503.  * connection fails, as it's possible that the SMSC closed the
  504.  * connection because of idle timeout and a new one will be
  505.  * created quickly. */
  506.         if (wait) {
  507.             if (conn->status == SMSCCONN_ACTIVE) {
  508.                 mutex_lock(conn->flow_mutex);
  509.                 conn->status = SMSCCONN_RECONNECTING;
  510.                 mutex_unlock(conn->flow_mutex);
  511.             }
  512.             while ((msg = list_extract_first(privdata->outgoing_queue)))
  513.                 bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_TEMPORARILY);
  514.             info(0, "smsc_cgw: waiting for %d minutes before trying to connect again", wait);
  515.             gwthread_sleep(wait * 60);
  516.             wait = wait > 5 ? 10 : wait * 2;
  517.         } else
  518.             wait = 1;
  519.         server = conn_open_tcp_with_port(privdata->host, privdata->port,
  520.                                          privdata->our_port, NULL /* privdata->our_host */);
  521.         if (privdata->shutdown) {
  522.             conn_destroy(server);
  523.             return NULL;
  524.         }
  525.         if (server == NULL) {
  526.             error(0, "smsc_cgw: opening TCP connection to %s failed", octstr_get_cstr(privdata->host));
  527.             continue;
  528.         }
  529.         if (conn->status != SMSCCONN_ACTIVE) {
  530.             mutex_lock(conn->flow_mutex);
  531.             conn->status = SMSCCONN_ACTIVE;
  532.             conn->connect_time = time(NULL);
  533.             mutex_unlock(conn->flow_mutex);
  534.             bb_smscconn_connected(conn);
  535.         }
  536.         return server;
  537.     }
  538.     return NULL;
  539. }
  540. /******************************************************************************
  541.  * Send messages in queue.
  542.  */
  543. static int cgw_send_loop(SMSCConn *conn, Connection *server)
  544. {
  545.     PrivData *privdata = conn->data;
  546.     struct cgwop *cgwop;
  547.     Msg *msg;
  548.     int firsttrn;
  549.     /* Send messages in queue */
  550.     while ((msg = list_extract_first(privdata->outgoing_queue)) != NULL) {
  551.         firsttrn = privdata->nexttrn;
  552.         while (privdata->sendtime[privdata->nexttrn] != 0) { 
  553.             if (++privdata->nexttrn >= CGW_TRN_MAX) privdata->nexttrn = 0;    
  554.             if (privdata->nexttrn == firsttrn) { /* no available trn */
  555.         /* this happens too many messages are sent, and old messages
  556.  * haven't been acked. In this case, increase size of 
  557.                  * CGW_TRN_MAX */
  558.                 info(0, "cgw: Saturated, increase size of CGW_TRN_MAX!");
  559.                 list_produce(privdata->outgoing_queue, msg);
  560.                 return 1;     /* re-insert, and go check for acks */
  561.             }
  562.         }
  563.         cgwop = msg_to_cgwop(privdata, msg, privdata->nexttrn);
  564.         if (cgwop == NULL) {
  565.             info(0, "cgw: cgwop == NULL");
  566.             return 0;
  567.         }
  568.         privdata->sendmsg[privdata->nexttrn] = msg;
  569.         privdata->sendtime[privdata->nexttrn] = time(NULL);
  570.         if (cgwop_send(server, cgwop) == -1) {
  571.             cgwop_destroy(cgwop);
  572.             info(0, "cgw: Unable to send (cgwop_send() == -1)");
  573.             return -1;
  574.         }
  575.         privdata->unacked++;
  576.         cgwop_destroy(cgwop);
  577.     }
  578.     return 0;
  579. }
  580. /* Check whether there are messages the server hasn't acked in a
  581.  * reasonable time */
  582. void cgw_check_acks(PrivData *privdata)
  583. {
  584.     time_t current_time;
  585.     int i;
  586.     current_time = time(NULL);
  587.     if (privdata->unacked && (current_time > privdata->check_time + 30)) {
  588.         privdata->check_time = current_time;
  589.         for (i = 0; i < CGW_TRN_MAX; i++)
  590.             if (privdata->sendtime[i] && privdata->sendtime[i] < (current_time - privdata->waitack)) {
  591.                 privdata->sendtime[i] = 0;
  592.                 privdata->unacked--;
  593.                 warning(0, "smsc_cgw: received neither OK nor ERR for message %d "
  594.                         "in %d seconds, resending message", i, privdata->waitack);
  595.                 list_produce(privdata->outgoing_queue, privdata->sendmsg[i]);
  596.             }
  597.     }
  598. }
  599. /******************************************************************************
  600.  * cgw_wait_command - Used by cgw_sender thread to read delivery reports
  601.  */
  602. int cgw_wait_command(PrivData *privdata, SMSCConn *conn, Connection *server, int timeout)
  603. {
  604.     int ret;
  605.     struct cgwop *cgwop;
  606.     /* is there data to be read? */
  607.     ret = gwthread_pollfd(privdata->send_socket, POLLIN, 0.2); 
  608.     
  609.     if (ret != -1) {
  610.         /* read all waiting ops */
  611. cgwop = cgw_read_op(privdata, conn, server, timeout);
  612.         if (cgwop != NULL) {
  613.     do {
  614. if (conn_eof(server)) {
  615.     info(0, "cgw: Connection closed by SMSC");
  616.     conn->status = SMSCCONN_DISCONNECTED;
  617.     if (cgwop != NULL) cgwop_destroy(cgwop);
  618.     return -1;
  619. }
  620. if (conn_read_error(server)) {
  621.     error(0, "cgw: Error trying to read ACKs from SMSC");
  622.     if (cgwop != NULL) cgwop_destroy(cgwop);
  623.     return -1;
  624. }
  625. cgw_handle_op(conn, server, cgwop);
  626. cgwop_destroy(cgwop);
  627.     } while ((cgwop = cgw_read_op(privdata, conn, server, timeout)) != NULL);
  628. } else 
  629.     conn_wait(server, 1); /* added because gwthread_pollfd
  630.      seems to always return 1. This will keep
  631.      the load on a reasonable level */
  632.     }
  633.     return 0;
  634. }
  635. /******************************************************************************
  636.  * cgw_read_op - read an operation, and return it as a *cgwop structure
  637.  *
  638.  * This function will not lock and wait for data if none is available. It will
  639.  * however lock until a whole op has been read. Timeout not implemented yet.
  640.  */
  641. struct cgwop *cgw_read_op(PrivData *privdata, SMSCConn *conn, Connection *server, time_t timeout)
  642. {
  643.     Octstr *line, *name, *value;
  644.     int finished = 0;
  645.     int c = 0;
  646.     struct cgwop *cgwop = NULL;
  647.     int op = CGW_OP_NOP;
  648.     if ((line = conn_read_line(server)) == NULL) 
  649.         return NULL;     /* don't block */
  650.     do
  651.     {
  652.         while (line == NULL)
  653.             line = conn_read_line(server);     /* wait for more data */
  654.         c = octstr_search_char(line, ':', 0);
  655.         if (c != -1) {
  656.             name = octstr_copy(line, 0, c);
  657.             value = octstr_copy(line, c + 1, octstr_len(line) - (c + 1));
  658.             if (octstr_compare(name, octstr_imm("hello")) == 0) {
  659.                 /* A connection is started by CGW by sending a 
  660.  * "hello: Provider Server..." line. */
  661.                 cgwop = cgwop_create(CGW_OP_HELLO, 0);
  662.                 cgwop_add(cgwop, octstr_imm("hello"), value);
  663.                 octstr_destroy(name);
  664.                 octstr_destroy(value);
  665.                 octstr_destroy(line);
  666.                 return cgwop;
  667.             }
  668.             if (octstr_compare(name, octstr_imm("op")) == 0) {
  669.                 /* check different ops */
  670.                 if (octstr_compare(value, octstr_imm("msg")) == 0)
  671.                     op = CGW_OP_MSG;
  672.                 else
  673.                     if (octstr_compare(value, octstr_imm("ok")) == 0)
  674.                         op = CGW_OP_OK;
  675.                     else
  676.                         if (octstr_compare(value, octstr_imm("delivery")) == 0)
  677.                             op = CGW_OP_DELIVERY;
  678.                         else
  679.                             if (octstr_compare(value, octstr_imm("err")) == 0)
  680.                                 op = CGW_OP_ERR;
  681.                             else
  682.                                 if (octstr_compare(value, octstr_imm("status")) == 0)
  683.                                     op = CGW_OP_STATUS;
  684.                                 else
  685.                                     info(0, "CGW: Received unknown op: %s", octstr_get_cstr(value));
  686.                 if (cgwop == NULL)
  687.                     cgwop = cgwop_create(op, 0);
  688.                 else
  689.                     info(0, "cgw: cgwop != null");
  690.             }
  691.             if (op != CGW_OP_NOP) {
  692.                 /* All commands have to be inside an op:xx ... end:xx statement */
  693.                 if (octstr_compare(name, octstr_imm("end")) == 0) { // found end of op
  694.                     finished = 1;
  695.                 } else {
  696.                     // store in name/value fields in cgwop
  697.                     if (cgwop != NULL) {
  698.                         cgwop_add(cgwop, name, value);
  699.                     }
  700.                 }
  701.             }
  702.             octstr_destroy(name);
  703.             octstr_destroy(value);
  704.             octstr_destroy(line);
  705.             if (!finished) line = conn_read_line(server);
  706.         } else {
  707.             info(0, "cgw: Received invalid input: %s", octstr_get_cstr(line));
  708.             octstr_destroy(line);
  709.             finished = 1;
  710.         }
  711.     } while (!finished);
  712.     return cgwop;
  713. }
  714. static int cgw_open_listening_socket(PrivData *privdata)
  715. {
  716.     int s;
  717.     if ((s = make_server_socket(privdata->rport, NULL)) == -1) {
  718.         /* XXX add interface_name if required */
  719.         error(0, "smsc_cgw: could not create listening socket in port %d", privdata->rport);
  720.         return -1;
  721.     }
  722.     if (socket_set_blocking(s, 0) == -1) {
  723.         error(0, "smsc_cgw: couldn't make listening socket port %d non-blocking", privdata->rport);
  724.         close(s);
  725.         return -1;
  726.     }
  727.     privdata->listening_socket = s;
  728.     return 0;
  729. }
  730. /******************************************************************************
  731.  * This is the entry point for our receiver thread. Listens for incoming 
  732.  * connections and handles operations.
  733.  */
  734. static void cgw_listener(void *arg)
  735. {
  736.     SMSCConn *conn = arg;
  737.     PrivData *privdata = conn->data;
  738.     struct sockaddr_in server_addr;
  739.     socklen_t server_addr_len;
  740.     Octstr *ip;
  741.     Connection *server;
  742.     int s, ret;
  743.     while (!privdata->shutdown) {
  744.         server_addr_len = sizeof(server_addr);
  745.         ret = gwthread_pollfd(privdata->listening_socket, POLLIN, -1);
  746.         if (ret == -1) {
  747.             if (errno == EINTR)
  748.                 continue;
  749.             error(0, "Poll for cgw smsc connections failed, shutting down");
  750.             break;
  751.         }
  752.         if (privdata->shutdown)
  753.             break;
  754.         if (ret == 0) /* This thread was woken up from elsewhere, but
  755.                        * if we're not shutting down nothing to do here. */
  756.             continue;
  757.         s = accept(privdata->listening_socket, (struct sockaddr *) & server_addr,
  758.                    &server_addr_len);
  759.         if (s == -1) {
  760.             warning(errno, "cgw_listener: accept() failed, retrying...");
  761.             continue;
  762.         }
  763.         ip = host_ip(server_addr);
  764.         if (!is_allowed_ip(privdata->allow_ip, privdata->deny_ip, ip)) {
  765.             info(0, "CGW smsc connection tried from denied host <%s>, disconnected", octstr_get_cstr(ip));
  766.             octstr_destroy(ip);
  767.             close(s);
  768.             continue;
  769.         }
  770.         server = conn_wrap_fd(s, 0);
  771.         if (server == NULL) {
  772.             error(0, "cgw_listener: conn_wrap_fd failed on accept()ed fd");
  773.             octstr_destroy(ip);
  774.             close(s);
  775.             continue;
  776.         }
  777.         conn_claim(server);
  778.         info(0, "cgw: smsc connected from %s", octstr_get_cstr(ip));
  779.         octstr_destroy(ip);
  780.         cgw_receiver(conn, server);
  781.         conn_destroy(server);
  782.     }
  783.     if (close(privdata->listening_socket) == -1)
  784.         warning(errno, "smsc_cgw: couldn't close listening socket at shutdown");
  785.     gwthread_wakeup(privdata->sender_thread);
  786. }
  787. static void cgw_receiver(SMSCConn *conn, Connection *server)
  788. {
  789.     PrivData *privdata = conn->data;
  790.     Octstr *str = NULL;
  791.     struct cgwop *cgwop;
  792.     while (1) {
  793.         if (conn_eof(server)) {
  794.             info(0, "cgw: receive connection closed by SMSC");
  795.             return ;
  796.         }
  797.         if (conn_read_error(server)) {
  798.             error(0, "cgw: receive connection broken");
  799.             return ;
  800.         }
  801.         if (conn->is_stopped)
  802.     str = NULL;
  803.         cgwop = cgw_read_op(conn->data, conn, server, 0);
  804.         if (cgwop != NULL) {
  805.             cgw_handle_op(conn, server, cgwop);
  806.             cgwop_destroy(cgwop);
  807.         } else
  808.             conn_wait(server, -1);
  809.         if (privdata->shutdown)
  810.             break;
  811.     }
  812.     return ;
  813. }
  814. /******************************************************************************
  815.  * This function handles incoming operations. Used by both receiver and sender
  816.  * threads (i.e. sender thread uses this function for delivery and ack
  817.  * operations).
  818.  * Returns 1 if successfull, otherwise 0
  819.  */
  820. static int cgw_handle_op(SMSCConn *conn, Connection *server, struct cgwop *cgwop)
  821. {
  822.     PrivData *privdata = conn->data;
  823.     Msg *msg = NULL;
  824.     Octstr *from, *app, *sid, *to, *msgtype, *msgdata; /* for messages */
  825.     Octstr *msid, *status, *txt;            /* delivery reports */
  826.     Octstr *clid;                    /* for acks */
  827.     struct cgwop *reply = NULL;
  828.     long trn, stat;                          /* transaction number for ack */
  829.     Msg *dlrmsg = NULL, *origmsg = NULL;
  830.     Octstr *ts;
  831.     if (cgwop == NULL) return 0;
  832.     from = cgwop_get(cgwop, octstr_imm("from"));
  833.     app = cgwop_get(cgwop, octstr_imm("app"));
  834.     sid = cgwop_get(cgwop, octstr_imm("session-id"));
  835.     to = cgwop_get(cgwop, octstr_imm("to"));
  836.     msgtype = cgwop_get(cgwop, octstr_imm("type"));
  837.     msgdata = cgwop_get(cgwop, octstr_imm("msg"));
  838.     txt = cgwop_get(cgwop, octstr_imm("txt"));
  839.     msid = cgwop_get(cgwop, octstr_imm("msid"));
  840.     status = cgwop_get(cgwop, octstr_imm("status"));
  841.     clid = cgwop_get(cgwop, octstr_imm("client-id"));
  842.     if (clid != NULL)
  843.     {
  844.         octstr_parse_long(&trn, clid, 0, 10);
  845.         if ((trn < 0) || (trn >= CGW_TRN_MAX)) { /* invalid transaction number */
  846.     info(0, "cgw: Invalid transaction number: %d", (int) trn);
  847.             trn = -1;            
  848.     return 0;
  849.         }
  850.     }
  851.     switch (cgwop->op)
  852.     {
  853.     case CGW_OP_MSG:
  854.         msg = msg_create(sms);
  855.         time(&msg->sms.time);
  856.         msg->sms.msgdata = cgw_decode_msg(octstr_duplicate(msgdata));
  857.         msg->sms.sender = octstr_duplicate(from);
  858.         msg->sms.receiver = octstr_duplicate(to);
  859.         msg->sms.smsc_id = octstr_duplicate(conn->id);
  860.         bb_smscconn_receive(conn, msg);
  861.         reply = cgwop_create(CGW_OP_OK, -1);
  862.         cgwop_add(reply, octstr_imm("session-id"), sid);
  863.         cgwop_send(server, reply);     // send reply
  864.         cgwop_destroy(reply);
  865.         break;
  866.     case CGW_OP_DELIVERY:
  867.         if (privdata->dlr[trn]) {
  868.             octstr_parse_long(&stat, status, 0, 10);
  869.             origmsg = privdata->sendmsg[trn];
  870.             if (origmsg == NULL) break;
  871.             ts = octstr_create("");
  872.             octstr_append(ts, conn->id);
  873.             octstr_append_char(ts, '-');
  874.             octstr_append_decimal(ts, trn);
  875.             switch (stat) {
  876.             case 0:     /* delivered */
  877.                 dlrmsg = dlr_find(octstr_get_cstr(conn->id),
  878.                                   octstr_get_cstr(ts),     /* timestamp */
  879.                                   octstr_get_cstr(msid),   /* destination */
  880.                                   DLR_SUCCESS);
  881.                 break;
  882.             case 1:     /* buffered */
  883.                 dlrmsg = dlr_find(octstr_get_cstr(conn->id),
  884.                                   octstr_get_cstr(ts),     /* timestamp */
  885.                                   octstr_get_cstr(msid),   /* destination */
  886.                                   DLR_BUFFERED);
  887.                 break;
  888.             case 2:     /* not delivered */
  889.                 dlrmsg = dlr_find(octstr_get_cstr(conn->id),
  890.                                   octstr_get_cstr(ts),     /* timestamp */
  891.                                   octstr_get_cstr(msid),   /* destination */
  892.                                   DLR_FAIL);
  893.                 break;
  894.             }
  895.             octstr_destroy(ts);
  896.             if (dlrmsg != NULL) {
  897.                 dlrmsg->sms.msgdata = octstr_duplicate(txt);
  898.                 bb_smscconn_receive(conn, dlrmsg);
  899.             }
  900.         }
  901.         break;
  902.     case CGW_OP_OK:
  903.         if (trn == -1) break;     /* invalid transaction number */
  904.         /* info(0, "cgw: Got ACK: %s", octstr_get_cstr(clid)); */
  905.         privdata->sendtime[trn] = 0;
  906.         privdata->unacked--;
  907.         /* add delivery notification request if wanted */
  908.         msg = privdata->sendmsg[trn];
  909.         if (msg && msg->sms.dlr_url && (msg->sms.dlr_mask & 0x07)) {
  910.             Octstr *ts;
  911.             ts = octstr_create("");
  912.             octstr_append(ts, conn->id);
  913.             octstr_append_char(ts, '-');
  914.             octstr_append_decimal(ts, trn);
  915.             dlr_add(octstr_get_cstr(conn->id),
  916.                     octstr_get_cstr(ts),
  917.                     octstr_get_cstr(msg->sms.sender),
  918.                     octstr_get_cstr(msg->sms.receiver),
  919.                     octstr_get_cstr(msg->sms.service),
  920.                     octstr_get_cstr(msg->sms.dlr_url),
  921.                     msg->sms.dlr_mask);
  922.             octstr_destroy(ts);
  923.             privdata->dlr[trn] = 1;
  924.         } else {
  925.             privdata->dlr[trn] = 0;
  926.         }
  927.         bb_smscconn_sent(conn, msg);     /* mark as successfully sent */
  928.         break;
  929.     case CGW_OP_STATUS:
  930.         info(0, "CGW: Warning: Got session status");
  931.         /* op:status messages are sent by ProviderServer to tell if there are problems with
  932.            the session status. These are not wanted, and should never occur, as the delivery is
  933.            cancelled, and no end-user billing is done. */
  934.         break;
  935.     case CGW_OP_HELLO:
  936.         info(0, "CGW: Server said: %s", octstr_get_cstr(cgwop_get(cgwop, octstr_imm("hello"))));
  937.         break;
  938.     case CGW_OP_ERR:
  939.         if (trn == -1) break;     /* invalid transaction number */
  940.         info(0, "CGW: Received error: %s", octstr_get_cstr(txt));
  941.         privdata->sendtime[trn] = 0;
  942.         privdata->unacked--;
  943.         bb_smscconn_send_failed(conn, privdata->sendmsg[trn],
  944.                                 SMSCCONN_FAILED_REJECTED);
  945.         break;
  946.     default:
  947.         info(0, "cgw: Unknown operation: %d", cgwop->op);
  948.         return 0;
  949.     }
  950.     return 1;
  951. }