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

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  * smsc_fake.c - interface to fakesmsc.c
  3.  *
  4.  * Uoti Urpala 2001
  5.  */
  6. /* Doesn't support multi-send
  7.  * Doesn't warn about unrecognized configuration variables */
  8. #include <sys/types.h>
  9. #include <sys/socket.h>
  10. #include <unistd.h>
  11. #include <errno.h>
  12. #include <time.h>
  13. #include <limits.h>
  14. #include "gwlib/gwlib.h"
  15. #include "smscconn.h"
  16. #include "smscconn_p.h"
  17. #include "bb_smscconn_cb.h"
  18. #include "msg.h"
  19. #include "sms.h"
  20. typedef struct privdata {
  21.     List *outgoing_queue;
  22.     long connection_thread;
  23.     int shutdown; /* Signal to the connection thread to shut down */
  24.     int listening_socket; /* File descriptor */
  25.     int port;   /* Port number to listen */
  26.     Octstr *allow_ip, *deny_ip;
  27. } PrivData;
  28. static int fake_open_connection(PrivData *privdata)
  29. {
  30.     int s;
  31.     if ((s = make_server_socket(privdata->port, NULL)) == -1) {
  32.     /* XXX add interface_name if required */
  33.         error(0, "smsc_fake: could not create listening socket in port %d",
  34.           privdata->port);
  35.         return -1;
  36.     }
  37.     if (socket_set_blocking(s, 0) == -1) {
  38.         error(0, "smsc_fake: couldn't make listening socket port %d non-blocking",
  39.           privdata->port);
  40.         return -1;
  41.     }
  42.     privdata->listening_socket = s;
  43.     return 0;
  44. }
  45. static int sms_to_client(Connection *client, Msg *msg)
  46. {
  47.     Octstr *line;
  48.     Octstr *msgdata = NULL; /* NULL to allow octstr_destroy */
  49.     char *contents;
  50.     int len;
  51.     debug("bb.sms", 0, "smsc_fake: sending message to client");
  52.     line = octstr_duplicate(msg->sms.sender);
  53.     octstr_append_char(line, ' ');
  54.     octstr_append(line, msg->sms.receiver);
  55.     if (octstr_len(msg->sms.udhdata)) {
  56.         octstr_append(line, octstr_imm(" udh "));
  57.         msgdata = octstr_duplicate(msg->sms.udhdata);
  58.         octstr_url_encode(msgdata);
  59.         octstr_append(line, msgdata);
  60.         octstr_destroy(msgdata);
  61.         octstr_append_char(line, ' ');
  62.         msgdata = octstr_duplicate(msg->sms.msgdata);
  63.         octstr_url_encode(msgdata);
  64.         octstr_append(line, msgdata);
  65.     } else {
  66.         contents = octstr_get_cstr(msg->sms.msgdata);
  67.         len = octstr_len(msg->sms.msgdata);
  68.         while (len > 0) {
  69.             len--;
  70.             if (contents[len] < 32 || contents[len] > 126) {
  71.                 octstr_append(line, octstr_imm(" data "));
  72.                 msgdata = octstr_duplicate(msg->sms.msgdata);
  73.                 octstr_url_encode(msgdata);
  74.                 octstr_append(line, msgdata);
  75.                 goto notelse; /* C lacks "else" clause for while loops */
  76.             }
  77.         }
  78.         octstr_append(line, octstr_imm(" text "));
  79.         octstr_append(line, msg->sms.msgdata);
  80.     }
  81. notelse:
  82.     octstr_append_char(line, 10);
  83.     if (conn_write(client, line) == -1) {
  84.         octstr_destroy(msgdata);
  85.         octstr_destroy(line);
  86.         return -1;
  87.     }
  88.     octstr_destroy(msgdata);
  89.     octstr_destroy(line);
  90.     return 1;
  91. }
  92. static void msg_to_bb(SMSCConn *conn, Octstr *line)
  93. {
  94.     long p, p2;
  95.     Msg *msg;
  96.     Octstr *type = NULL; /* might be destroyed after error before created */
  97.     msg = msg_create(sms);
  98.     p = octstr_search_char(line, ' ', 0);
  99.     if (p == -1)
  100.         goto error;
  101.     msg->sms.sender = octstr_copy(line, 0, p);
  102.     p2 = octstr_search_char(line, ' ', p + 1);
  103.     if (p2 == -1)
  104.         goto error;
  105.     msg->sms.receiver = octstr_copy(line, p + 1, p2 - p - 1);
  106.     p = octstr_search_char(line, ' ', p2 + 1);
  107.     if (p == -1)
  108.         goto error;
  109.     type = octstr_copy(line, p2 + 1, p - p2 - 1);
  110.     if (!octstr_compare(type, octstr_imm("text")))
  111.         msg->sms.msgdata = octstr_copy(line, p + 1, LONG_MAX);
  112.     else if (!octstr_compare(type, octstr_imm("data"))) {
  113.         msg->sms.msgdata = octstr_copy(line, p + 1, LONG_MAX);
  114.         if (octstr_url_decode(msg->sms.msgdata) == -1)
  115.             warning(0, "smsc_fake: urlcoded data from client looks malformed");
  116.     }
  117.     else if (!octstr_compare(type, octstr_imm("udh"))) {
  118.         p2 = octstr_search_char(line, ' ', p + 1);
  119.         if (p2 == -1)
  120.             goto error;
  121.         msg->sms.udhdata = octstr_copy(line, p + 1, p2 - p - 1);
  122.         msg->sms.msgdata = octstr_copy(line, p2 + 1, LONG_MAX);
  123.         if (msg->sms.coding == DC_UNDEF)
  124.             msg->sms.coding = DC_8BIT;;
  125.         if (octstr_url_decode(msg->sms.msgdata) == -1 ||
  126.             octstr_url_decode(msg->sms.udhdata) == -1)
  127.             warning(0, "smsc_fake: urlcoded data from client looks malformed");
  128.     } else
  129.         goto error;
  130.     octstr_destroy(line);
  131.     octstr_destroy(type);
  132.     time(&msg->sms.time);
  133.     msg->sms.smsc_id = octstr_duplicate(conn->id);
  134.     debug("bb.sms", 0, "smsc_fake: new message received");
  135.     bb_smscconn_receive(conn, msg);
  136.     return;
  137. error:
  138.     warning(0, "smsc_fake: invalid message syntax from client, ignored");
  139.     msg_destroy(msg);
  140.     octstr_destroy(line);
  141.     octstr_destroy(type);
  142.     return;
  143. }
  144. static void main_connection_loop(SMSCConn *conn, Connection *client)
  145. {
  146.     PrivData *privdata = conn->data;
  147.     Octstr *line;
  148.     Msg *msg;
  149.     while (1) {
  150.         while (!conn->is_stopped && !privdata->shutdown &&
  151.                 (line = conn_read_line(client)))
  152.             msg_to_bb(conn, line);
  153.         if (conn_read_error(client))
  154.             goto error;
  155.         if (conn_eof(client))
  156.             goto eof;
  157.         while ((msg = list_extract_first(privdata->outgoing_queue)) != NULL) {
  158.             if (sms_to_client(client, msg) == 1) {
  159.                 /* 
  160.                  * Actually no quarantee of it having been really sent,
  161.                  * but I suppose that doesn't matter since this interface
  162.                  * is just for debugging anyway 
  163.                  */
  164.                 bb_smscconn_sent(conn, msg);
  165.             } else {
  166.                 bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_REJECTED);
  167.                 goto error;
  168.             }
  169.         }
  170.         if (privdata->shutdown) {
  171.             debug("bb.sms", 0, "smsc_fake shutting down, closing client socket");
  172.             conn_destroy(client);
  173.             return;
  174.         }
  175.         conn_wait(client, -1);
  176.         if (conn_read_error(client))
  177.             goto error;
  178.         if (conn_eof(client))
  179.             goto eof;
  180.     }
  181. error:
  182.     info(0, "IO error to fakesmsc client. Closing connection.");
  183.     conn_destroy(client);
  184.     return;
  185. eof:
  186.     info(0, "EOF from fakesmsc client. Closing connection.");
  187.     conn_destroy(client);
  188.     return;
  189. }
  190. static void fake_listener(void *arg)
  191. {
  192.     SMSCConn *conn = arg;
  193.     PrivData *privdata = conn->data;
  194.     struct sockaddr_in client_addr;
  195.     socklen_t client_addr_len;
  196.     Octstr *ip;
  197.     Connection *client;
  198.     int s, ret;
  199.     Msg *msg;
  200.     while (1) {
  201.         client_addr_len = sizeof(client_addr);
  202.         ret = gwthread_pollfd(privdata->listening_socket, POLLIN, -1);
  203.         if (ret == -1) {
  204.             if (errno == EINTR)
  205.                 continue;
  206.             error(0, "Poll for fakesmsc connections failed, shutting down");
  207.             break;
  208.         }
  209.         if (privdata->shutdown)
  210.             break;
  211.         if (ret == 0) 
  212.             /* 
  213.              * This thread was woken up from elsewhere, but
  214.              * if we're not shutting down nothing to do here. 
  215.              */
  216.             continue;
  217.         s = accept(privdata->listening_socket, (struct sockaddr *)&client_addr,
  218.                    &client_addr_len);
  219.         if (s == -1) {
  220.             warning(errno, "fake_listener: accept() failed, retrying...");
  221.             continue;
  222.         }
  223.         ip = host_ip(client_addr);
  224.         if (!is_allowed_ip(privdata->allow_ip, privdata->deny_ip, ip)) {
  225.             info(0, "Fakesmsc connection tried from denied host <%s>,"
  226.                  " disconnected", octstr_get_cstr(ip));
  227.             octstr_destroy(ip);
  228.             close(s);
  229.             continue;
  230.         }
  231.         client = conn_wrap_fd(s, 0);
  232.         if (client == NULL) {
  233.             error(0, "fake_listener: conn_wrap_fd failed on accept()ed fd");
  234.             octstr_destroy(ip);
  235.             close(s);
  236.             continue;
  237.         }
  238.         conn_claim(client);
  239.         info(0, "Fakesmsc client connected from %s", octstr_get_cstr(ip));
  240.         octstr_destroy(ip);
  241.         mutex_lock(conn->flow_mutex);
  242.         conn->status = SMSCCONN_ACTIVE;
  243.         conn->connect_time = time(NULL);
  244.         mutex_unlock(conn->flow_mutex);
  245.         bb_smscconn_connected(conn);
  246.         main_connection_loop(conn, client);
  247.         if (privdata->shutdown)
  248.             break;
  249.         mutex_lock(conn->flow_mutex);
  250.         conn->status = SMSCCONN_RECONNECTING;
  251.         mutex_unlock(conn->flow_mutex);
  252.         while ((msg = list_extract_first(privdata->outgoing_queue)) != NULL) {
  253.             bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_TEMPORARILY);
  254.         }
  255.     }
  256.     if (close(privdata->listening_socket) == -1)
  257.         warning(errno, "smsc_fake: couldn't close listening socket at shutdown");
  258.     mutex_lock(conn->flow_mutex);
  259.     conn->status = SMSCCONN_DEAD;
  260.     while ((msg = list_extract_first(privdata->outgoing_queue)) != NULL) {
  261.         bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN);
  262.     }
  263.     list_destroy(privdata->outgoing_queue, NULL);
  264.     octstr_destroy(privdata->allow_ip);
  265.     octstr_destroy(privdata->deny_ip);
  266.     gw_free(privdata);
  267.     conn->data = NULL;
  268.     mutex_unlock(conn->flow_mutex);
  269.     debug("bb.sms", 0, "smsc_fake connection has completed shutdown.");
  270.     bb_smscconn_killed();
  271. }
  272. static int add_msg_cb(SMSCConn *conn, Msg *sms)
  273. {
  274.     PrivData *privdata = conn->data;
  275.     Msg *copy;
  276.     copy = msg_duplicate(sms);
  277.     list_produce(privdata->outgoing_queue, copy);
  278.     gwthread_wakeup(privdata->connection_thread);
  279.     return 0;
  280. }
  281. static int shutdown_cb(SMSCConn *conn, int finish_sending)
  282. {
  283.     PrivData *privdata = conn->data;
  284.     debug("bb.sms", 0, "Shutting down SMSCConn FAKE, %s",
  285.           finish_sending ? "slow" : "instant");
  286.     /* 
  287.      * Documentation claims this would have been done by smscconn.c,
  288.      * but isn't when this code is being written. 
  289.      */
  290.     conn->why_killed = SMSCCONN_KILLED_SHUTDOWN;
  291.     privdata->shutdown = 1; 
  292.     /*
  293.      * Separate from why_killed to avoid locking, as
  294.      * why_killed may be changed from outside? 
  295.      */
  296.     if (finish_sending == 0) {
  297.         Msg *msg;
  298.         while((msg = list_extract_first(privdata->outgoing_queue)) != NULL) {
  299.             bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN);
  300.         }
  301.     }
  302.     gwthread_wakeup(privdata->connection_thread);
  303.     return 0;
  304. }
  305. static void start_cb(SMSCConn *conn)
  306. {
  307.     PrivData *privdata = conn->data;
  308.     /* in case there are messages in the buffer already */
  309.     gwthread_wakeup(privdata->connection_thread);
  310.     debug("bb.sms", 0, "smsc_fake: start called");
  311. }
  312. static long queued_cb(SMSCConn *conn)
  313. {
  314.     PrivData *privdata = conn->data;
  315.     long ret;
  316.     
  317.     ret = (privdata ? list_len(privdata->outgoing_queue) : 0);
  318.     /* use internal queue as load, maybe something else later */
  319.     conn->load = ret;
  320.     return ret;
  321. }
  322. int smsc_fake_create(SMSCConn *conn, CfgGroup *cfg)
  323. {
  324.     PrivData *privdata = NULL;
  325.     Octstr *allow_ip, *deny_ip;
  326.     long portno;   /* has to be long because of cfg_get_integer */
  327.     if (cfg_get_integer(&portno, cfg, octstr_imm("port")) == -1)
  328.         portno = 0;
  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 (portno == 0) {
  335.         error(0, "'port' invalid in 'fake' record.");
  336.         goto error;
  337.     }
  338.     privdata = gw_malloc(sizeof(PrivData));
  339.     privdata->listening_socket = -1;
  340.     privdata->port = portno;
  341.     privdata->allow_ip = allow_ip;
  342.     privdata->deny_ip = deny_ip;
  343.     if (fake_open_connection(privdata) < 0) {
  344.         gw_free(privdata);
  345.         privdata = NULL;
  346.         goto error;
  347.     }
  348.     conn->data = privdata;
  349.     conn->name = octstr_format("FAKE:%d", privdata->port);
  350.     privdata->outgoing_queue = list_create();
  351.     privdata->shutdown = 0;
  352.     conn->status = SMSCCONN_CONNECTING;
  353.     conn->connect_time = time(NULL);
  354.     if ((privdata->connection_thread = gwthread_create(fake_listener, conn)) == -1)
  355.         goto error;
  356.     conn->shutdown = shutdown_cb;
  357.     conn->queued = queued_cb;
  358.     conn->start_conn = start_cb;
  359.     conn->send_msg = add_msg_cb;
  360.     return 0;
  361. error:
  362.     error(0, "Failed to create fake smsc connection");
  363.     if (privdata != NULL) {
  364.         list_destroy(privdata->outgoing_queue, NULL);
  365.         if (close(privdata->listening_socket == -1)) {
  366.             error(errno, "smsc_fake: closing listening socket port %d failed",
  367.                   privdata->listening_socket);
  368.         }
  369.     }
  370.     gw_free(privdata);
  371.     octstr_destroy(allow_ip);
  372.     octstr_destroy(deny_ip);
  373.     conn->why_killed = SMSCCONN_KILLED_CANNOT_CONNECT;
  374.     conn->status = SMSCCONN_DEAD;
  375.     return -1;
  376. }