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

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  * smsc_http.c - interface to various HTTP based content/SMS gateways
  3.  *
  4.  * HTTP based "SMSC Connection" is meant for gateway connections,
  5.  * and has following features:
  6.  *
  7.  * o Kannel listens to certain (HTTP server) port for MO SMS messages.
  8.  *   The exact format of these HTTP calls are defined by type of HTTP based
  9.  *   connection. Kannel replies to these messages as ACK, but does not
  10.  *   support immediate reply. Thus, if Kannel is linked to another Kannel,
  11.  *   only 'max-messages = 0' services are practically supported - any
  12.  *   replies must be done with SMS PUSH (sendsms)
  13.  *
  14.  * o For MT messages, Kannel does HTTP GET or POST to given address, in format
  15.  *   defined by type of HTTP based protocol
  16.  *
  17.  *
  18.  * The 'type' of requests and replies are defined by 'system-type' variable.
  19.  * The only type of HTTP requests currently supported are basic Kannel.
  20.  * If new support is added, smsc_http_create is modified accordingly and new
  21.  * functions added.
  22.  *
  23.  *
  24.  *
  25.  * KANNEL->KANNEL linking: (UDH not supported in MO messages)
  26.  *
  27.  *****
  28.  * FOR CLIENT/END-POINT KANNEL:
  29.  *
  30.  *  group = smsc
  31.  *  smsc = http
  32.  *  system-type = kannel
  33.  *  port = NNN
  34.  *  smsc-username = XXX
  35.  *  smsc-password = YYY
  36.  *  send-url = "server.host:PORT"
  37.  *
  38.  *****
  39.  * FOR SERVER/RELAY KANNEL:
  40.  *
  41.  *  group = smsbox
  42.  *  sendsms-port = PORT
  43.  *  ...
  44.  * 
  45.  *  group = sms-service
  46.  *  keyword = ...
  47.  *  url = "client.host:NNN/sms?user=XXX&pass=YYY&from=%p&to=%P&text=%a"
  48.  *  max-messages = 0
  49.  *
  50.  *  group = send-sms
  51.  *  username = XXX
  52.  *  password = YYY
  53.  *  
  54.  *
  55.  *
  56.  * Kalle Marjola for Project Kannel 2001
  57.  */
  58. #include <sys/types.h>
  59. #include <sys/socket.h>
  60. #include <unistd.h>
  61. #include <errno.h>
  62. #include <time.h>
  63. #include <limits.h>
  64. #include "gwlib/gwlib.h"
  65. #include "smscconn.h"
  66. #include "smscconn_p.h"
  67. #include "bb_smscconn_cb.h"
  68. #include "msg.h"
  69. typedef struct conndata {
  70.     HTTPCaller  *http_ref;
  71.     long receive_thread;
  72.     long send_cb_thread;
  73.     int shutdown;
  74.     int port;        /* port for receiving SMS'es */
  75.     Octstr *allow_ip;
  76.     Octstr *send_url;
  77.     long open_sends;
  78.     Octstr *username; /* if needed */
  79.     Octstr *password; /* as said */
  80.     int         no_sender;      /* ditto */
  81.     int         no_coding;      /* this, too */
  82.     int         no_sep;         /* not to mention this */
  83.     /* callback functions set by HTTP-SMSC type */
  84.     void (*send_sms) (SMSCConn *conn, Msg *msg);
  85.     void (*parse_reply) (SMSCConn *conn, Msg *msg, int status,
  86.  List *headers, Octstr *body);
  87.     void (*receive_sms) (SMSCConn *conn, HTTPClient *client,
  88.  List *headers, Octstr *body, List *cgivars);
  89. } ConnData;
  90. static void conndata_destroy(ConnData *conndata)
  91. {
  92.     if (conndata == NULL)
  93. return;
  94.     if (conndata->http_ref)
  95. http_caller_destroy(conndata->http_ref);
  96.     octstr_destroy(conndata->allow_ip);
  97.     octstr_destroy(conndata->send_url);
  98.     octstr_destroy(conndata->username);
  99.     octstr_destroy(conndata->password);
  100.     gw_free(conndata);
  101. }
  102. /*
  103.  * thread to listen to HTTP requests from other end
  104.  */
  105. static void httpsmsc_receiver(void *arg)
  106. {
  107.     SMSCConn *conn = arg;
  108.     ConnData *conndata = conn->data;
  109.     HTTPClient *client;
  110.     Octstr *ip, *url, *body;
  111.     List *headers, *cgivars;
  112.     
  113.     while(conndata->shutdown == 0) {
  114. /* XXX if conn->is_stopped, do not receive new messages.. */
  115. client = http_accept_request(conndata->port, &ip, &url,
  116.      &headers, &body, &cgivars);
  117. if (client == NULL)
  118.     break;
  119. debug("smsc.http", 0, "Got request '%s'", octstr_get_cstr(url));
  120. if (connect_denied(conndata->allow_ip, ip)) {
  121.     info(0, "httpsmsc: connection '%s' tried from denied "
  122.  "host %s, ignored", octstr_get_cstr(url),
  123.  octstr_get_cstr(ip));
  124.     http_close_client(client);
  125. } else
  126.     conndata->receive_sms(conn, client, headers, body, cgivars);
  127. debug("smsc.http", 0, "destroying client information");
  128. octstr_destroy(url);
  129. octstr_destroy(ip);
  130. octstr_destroy(body);
  131. http_destroy_headers(headers);
  132. http_destroy_cgiargs(cgivars);
  133.     }
  134.     debug("http_smsc", 0, "httpsmsc_receiver dying");
  135.     conndata->shutdown = 1;
  136.     http_close_port(conndata->port);
  137.     http_caller_signal_shutdown(conndata->http_ref);
  138. }
  139. /*
  140.  *   thread to handle finished sendings
  141.  */
  142. static void httpsmsc_send_cb(void *arg)
  143. {
  144.     SMSCConn *conn = arg;
  145.     ConnData *conndata = conn->data;
  146.     Msg *msg;
  147.     int status;
  148.     List *headers;
  149.     Octstr *final_url, *body;
  150.     while(conndata->shutdown == 0 || conndata->open_sends) {
  151. msg = http_receive_result(conndata->http_ref, &status,
  152.  &final_url, &headers, &body);
  153. if (msg == NULL)
  154.     break; /* they told us to die */
  155. conndata->open_sends--;
  156. conndata->parse_reply(conn, msg, status, headers, body);
  157. http_destroy_headers(headers);
  158. octstr_destroy(final_url);
  159. octstr_destroy(body);
  160.     }
  161.     debug("http-smsc", 0, "httpsmsc_send_cb dying");
  162.     conndata->shutdown = 1;
  163.     gwthread_join(conndata->receive_thread);
  164.     conn->data = NULL;
  165.     conndata_destroy(conndata);
  166.     conn->status = SMSCCONN_DEAD;
  167.     bb_smscconn_killed();
  168. }
  169. /*----------------------------------------------------------------
  170.  * SMSC-type specific functions
  171.  *
  172.  * 3 functions are needed for each:
  173.  *
  174.  *   1) send SMS
  175.  *   2) parse send SMS result
  176.  *   3) receive SMS (and send reply)
  177.  *
  178.  *   These functions do not return anything and do not destroy
  179.  *   arguments. They must handle everything that happens therein
  180.  *   and must call appropriate bb_smscconn functions
  181.  */
  182. /*xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  183.  * Kannel
  184.  */
  185. enum {HEX_NOT_UPPERCASE = 0};
  186. static void kannel_send_sms(SMSCConn *conn, Msg *sms)
  187. {
  188.     ConnData *conndata = conn->data;
  189.     Octstr *url;
  190.     List *headers;
  191.     if (!conndata->no_sep) {
  192.         url = octstr_format("%S?"
  193.     "user=%E&pass=%E&to=%E&text=%E",
  194.      conndata->send_url,
  195.      conndata->username, conndata->password,
  196.      sms->sms.receiver, sms->sms.msgdata);
  197.     } else {
  198.         octstr_binary_to_hex(sms->sms.msgdata, HEX_NOT_UPPERCASE);
  199.         url = octstr_format("%S?"
  200.     "user=%E&pass=%E&to=%E&text=%S",
  201.      conndata->send_url,
  202.      conndata->username, conndata->password,
  203.      sms->sms.receiver, 
  204.                              sms->sms.msgdata); 
  205.     }   
  206.     if (octstr_len(sms->sms.udhdata)) {
  207.         if (!conndata->no_sep) {
  208.     octstr_format_append(url, "&udh=%E", sms->sms.udhdata);
  209.         } else {
  210.     octstr_binary_to_hex(sms->sms.udhdata, HEX_NOT_UPPERCASE);
  211.             octstr_format_append(url, "&udh=%S", sms->sms.udhdata);
  212. }
  213.     }
  214.     if (!conndata->no_sender)
  215.         octstr_format_append(url, "&from=%E", sms->sms.sender);
  216.     if (sms->sms.mclass)
  217. octstr_format_append(url, "&mclass=%d", sms->sms.mclass);
  218.     if (!conndata->no_coding && sms->sms.coding)
  219. octstr_format_append(url, "&coding=%d", sms->sms.coding);
  220.     if (sms->sms.mwi)
  221. octstr_format_append(url, "&mwi=%d", sms->sms.mwi);
  222.     if (sms->sms.account) /* prepend account with local username */
  223. octstr_format_append(url, "&account=%E:%E", sms->sms.service, sms->sms.account);
  224.     headers = list_create();
  225.     debug("smsc.http.kannel", 0, "start request");
  226.     http_start_request(conndata->http_ref, HTTP_METHOD_GET, url, headers, 
  227.                        NULL, 0, sms, NULL);
  228.     octstr_destroy(url);
  229.     http_destroy_headers(headers);
  230.     
  231. }
  232. static void kannel_parse_reply(SMSCConn *conn, Msg *msg, int status,
  233.        List *headers, Octstr *body)
  234. {
  235.     if ((status == HTTP_OK || status == HTTP_ACCEPTED) 
  236.         && octstr_case_compare(body, octstr_imm("Sent."))==0)
  237.         bb_smscconn_sent(conn, msg);
  238.     else if ((status == HTTP_OK || status == HTTP_ACCEPTED) 
  239.         && octstr_ncompare(body, octstr_imm("Result: OK"),10) == 0)
  240.         bb_smscconn_sent(conn, msg);
  241.     else
  242. bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_MALFORMED);
  243. }
  244. static void kannel_receive_sms(SMSCConn *conn, HTTPClient *client,
  245.        List *headers, Octstr *body, List *cgivars)
  246. {
  247.     ConnData *conndata = conn->data;
  248.     Octstr *user, *pass, *from, *to, *text, *udh, *account, *tmp_string;
  249.     Octstr *retmsg;
  250.     int mclass, mwi, coding, validity, deferred; 
  251.     List *reply_headers;
  252.     int ret;
  253.     mclass = mwi = coding = validity = deferred = 0;
  254.     user = http_cgi_variable(cgivars, "user");
  255.     pass = http_cgi_variable(cgivars, "pass");
  256.     from = http_cgi_variable(cgivars, "from");
  257.     to = http_cgi_variable(cgivars, "to");
  258.     text = http_cgi_variable(cgivars, "text");
  259.     udh = http_cgi_variable(cgivars, "udh");
  260.     account = http_cgi_variable(cgivars, "account");
  261.     tmp_string = http_cgi_variable(cgivars, "flash");
  262.     if(tmp_string) {
  263. sscanf(octstr_get_cstr(tmp_string),"%d", &mclass);
  264.     }
  265.     tmp_string = http_cgi_variable(cgivars, "mclass");
  266.     if(tmp_string) {
  267. sscanf(octstr_get_cstr(tmp_string),"%d", &mclass);
  268.     }
  269.     tmp_string = http_cgi_variable(cgivars, "mwi");
  270.     if(tmp_string) {
  271. sscanf(octstr_get_cstr(tmp_string),"%d", &mwi);
  272.     }
  273.     tmp_string = http_cgi_variable(cgivars, "coding");
  274.     if(tmp_string) {
  275. sscanf(octstr_get_cstr(tmp_string),"%d", &coding);
  276.     }
  277.     tmp_string = http_cgi_variable(cgivars, "validity");
  278.     if(tmp_string) {
  279. sscanf(octstr_get_cstr(tmp_string),"%d", &validity);
  280.     }
  281.     tmp_string = http_cgi_variable(cgivars, "deferred");
  282.     if(tmp_string) {
  283. sscanf(octstr_get_cstr(tmp_string),"%d", &deferred);
  284.     }
  285.     debug("smsc.http.kannel", 0, "Received an HTTP request");
  286.     
  287.     if (   user == NULL || pass == NULL
  288.    || octstr_compare(user, conndata->username)!= 0
  289.    || octstr_compare(pass, conndata->password)!= 0) {
  290. debug("smsc.http.kannel", 0, "Authorization failure");
  291. retmsg = octstr_create("Authorization failed for sendsms");
  292.     }
  293.     else if (from == NULL || to == NULL || text == NULL) {
  294. debug("smsc.http.kannel", 0, "Insufficient args");
  295. retmsg = octstr_create("Insufficient args, rejected");
  296.     }
  297.     else {
  298. Msg *msg;
  299. msg = msg_create(sms);
  300. debug("smsc.http.kannel", 0, "Constructing new SMS");
  301. msg->sms.sender = octstr_duplicate(from);
  302. msg->sms.receiver = octstr_duplicate(to);
  303. msg->sms.msgdata = octstr_duplicate(text);
  304. msg->sms.udhdata = octstr_duplicate(udh);
  305. msg->sms.smsc_id = octstr_duplicate(conn->id);
  306. msg->sms.time = time(NULL);
  307. msg->sms.mclass = mclass;
  308. msg->sms.mwi = mwi;
  309. msg->sms.coding = coding;
  310. msg->sms.validity = validity;
  311. msg->sms.deferred = deferred;
  312.         msg->sms.account = account;
  313. ret = bb_smscconn_receive(conn, msg);
  314. if (ret == -1)
  315.     retmsg = octstr_create("Not accepted");
  316. else
  317.     retmsg = octstr_create("Ok.");
  318.     }
  319.     reply_headers = list_create();
  320.     http_header_add(reply_headers, "Content-Type", "text/plain");
  321.     debug("smsc.http.kannel", 0, "sending reply");
  322.     http_send_reply(client, HTTP_OK, reply_headers, retmsg);
  323.     octstr_destroy(retmsg);
  324.     http_destroy_headers(reply_headers);
  325. }
  326. /*xxxxxxxxxxxxxxxxxxxxxxx
  327.  *
  328.  * ADD NEW CONTENT GATEWAY/HTTP SMSC CALLBACKS HERE
  329.  */
  330. /*-----------------------------------------------------------------
  331.  * functions to implement various smscconn operations
  332.  */
  333. static int httpsmsc_send(SMSCConn *conn, Msg *msg)
  334. {
  335.     ConnData *conndata = conn->data;
  336.     Msg *sms = msg_duplicate(msg);
  337.     conndata->open_sends++;
  338.     conndata->send_sms(conn, sms);
  339.     return 0;
  340. }
  341. static long httpsmsc_queued(SMSCConn *conn)
  342. {
  343.     ConnData *conndata = conn->data;
  344.     return conndata->open_sends;
  345. }
  346. static int httpsmsc_shutdown(SMSCConn *conn, int finish_sending)
  347. {
  348.     ConnData *conndata = conn->data;
  349.     debug("httpsmsc_shutdown", 0, "httpsmsc: shutting down");
  350.     conn->why_killed = SMSCCONN_KILLED_SHUTDOWN;
  351.     conndata->shutdown = 1;
  352.     http_close_port(conndata->port);
  353.     return 0;
  354. }
  355. int smsc_http_create(SMSCConn *conn, CfgGroup *cfg)
  356. {
  357.     ConnData *conndata = NULL;
  358.     Octstr *type;
  359.     long portno;   /* has to be long because of cfg_get_integer */
  360.     int ssl = 0;   /* indicate if SSL-enabled server should be used */
  361.     if (cfg_get_integer(&portno, cfg, octstr_imm("port")) == -1) {
  362. error(0, "'port' invalid in smsc 'http' record.");
  363. return -1;
  364.     }
  365.     if ((type = cfg_get(cfg, octstr_imm("system-type")))==NULL) {
  366. error(0, "'type' missing in smsc 'http' record.");
  367. octstr_destroy(type);
  368. return -1;
  369.     }
  370.     conndata = gw_malloc(sizeof(ConnData));
  371.     conndata->http_ref = NULL;
  372.     conndata->allow_ip = cfg_get(cfg, octstr_imm("connect-allow-ip"));
  373.     conndata->send_url = cfg_get(cfg, octstr_imm("send-url"));
  374.     conndata->username = cfg_get(cfg, octstr_imm("smsc-username"));
  375.     conndata->password = cfg_get(cfg, octstr_imm("smsc-password"));
  376.     cfg_get_bool(&conndata->no_sender, cfg, octstr_imm("no-sender"));
  377.     cfg_get_bool(&conndata->no_coding, cfg, octstr_imm("no-coding"));
  378.     cfg_get_bool(&conndata->no_sep, cfg, octstr_imm("no-sep"));
  379.     if (conndata->send_url == NULL)
  380. panic(0, "Sending not allowed");
  381.     if (octstr_case_compare(type, octstr_imm("kannel"))==0) {
  382. if (conndata->username == NULL || conndata->password == NULL) {
  383.     error(0, "username and password required for Kannel http smsc");
  384.     goto error;
  385. }
  386. conndata->receive_sms = kannel_receive_sms;
  387. conndata->send_sms = kannel_send_sms;
  388. conndata->parse_reply = kannel_parse_reply;
  389.     }
  390.     /*
  391.      * ADD NEW HTTP SMSC TYPES HERE
  392.      */
  393.     else {
  394. error(0, "system-type '%s' unknown smsc 'http' record.",
  395.       octstr_get_cstr(type));
  396. goto error;
  397.     }
  398.     conndata->open_sends = 0;
  399.     conndata->http_ref = http_caller_create();
  400.     
  401.     conn->data = conndata;
  402.     conn->name = octstr_format("HTTP:%S", type);
  403.     conn->status = SMSCCONN_ACTIVE;
  404.     conn->connect_time = time(NULL);
  405.     conn->shutdown = httpsmsc_shutdown;
  406.     conn->queued = httpsmsc_queued;
  407.     conn->send_msg = httpsmsc_send;
  408.     if (http_open_port(portno, ssl)==-1)
  409. goto error;
  410.     conndata->port = portno;
  411.     conndata->shutdown = 0;
  412.     
  413.     if ((conndata->receive_thread =
  414.  gwthread_create(httpsmsc_receiver, conn)) == -1)
  415. goto error;
  416.     if ((conndata->send_cb_thread =
  417.  gwthread_create(httpsmsc_send_cb, conn)) == -1)
  418. goto error;
  419.     info(0, "httpsmsc '%s' initiated and ready", octstr_get_cstr(conn->name));
  420.     
  421.     octstr_destroy(type);
  422.     return 0;
  423. error:
  424.     error(0, "Failed to create http smsc connection");
  425.     conn->data = NULL;
  426.     conndata_destroy(conndata);
  427.     conn->why_killed = SMSCCONN_KILLED_CANNOT_CONNECT;
  428.     conn->status = SMSCCONN_DEAD;
  429.     octstr_destroy(type);
  430.     return -1;
  431. }