smsc_http.c
资源名称:gateway-1.2.1 [点击查看]
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:14k
源码类别:
手机WAP编程
开发平台:
WINDOWS
- /*
- * smsc_http.c - interface to various HTTP based content/SMS gateways
- *
- * HTTP based "SMSC Connection" is meant for gateway connections,
- * and has following features:
- *
- * o Kannel listens to certain (HTTP server) port for MO SMS messages.
- * The exact format of these HTTP calls are defined by type of HTTP based
- * connection. Kannel replies to these messages as ACK, but does not
- * support immediate reply. Thus, if Kannel is linked to another Kannel,
- * only 'max-messages = 0' services are practically supported - any
- * replies must be done with SMS PUSH (sendsms)
- *
- * o For MT messages, Kannel does HTTP GET or POST to given address, in format
- * defined by type of HTTP based protocol
- *
- *
- * The 'type' of requests and replies are defined by 'system-type' variable.
- * The only type of HTTP requests currently supported are basic Kannel.
- * If new support is added, smsc_http_create is modified accordingly and new
- * functions added.
- *
- *
- *
- * KANNEL->KANNEL linking: (UDH not supported in MO messages)
- *
- *****
- * FOR CLIENT/END-POINT KANNEL:
- *
- * group = smsc
- * smsc = http
- * system-type = kannel
- * port = NNN
- * smsc-username = XXX
- * smsc-password = YYY
- * send-url = "server.host:PORT"
- *
- *****
- * FOR SERVER/RELAY KANNEL:
- *
- * group = smsbox
- * sendsms-port = PORT
- * ...
- *
- * group = sms-service
- * keyword = ...
- * url = "client.host:NNN/sms?user=XXX&pass=YYY&from=%p&to=%P&text=%a"
- * max-messages = 0
- *
- * group = send-sms
- * username = XXX
- * password = YYY
- *
- *
- *
- * Kalle Marjola for Project Kannel 2001
- */
- #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"
- typedef struct conndata {
- HTTPCaller *http_ref;
- long receive_thread;
- long send_cb_thread;
- int shutdown;
- int port; /* port for receiving SMS'es */
- Octstr *allow_ip;
- Octstr *send_url;
- long open_sends;
- Octstr *username; /* if needed */
- Octstr *password; /* as said */
- int no_sender; /* ditto */
- int no_coding; /* this, too */
- int no_sep; /* not to mention this */
- /* callback functions set by HTTP-SMSC type */
- void (*send_sms) (SMSCConn *conn, Msg *msg);
- void (*parse_reply) (SMSCConn *conn, Msg *msg, int status,
- List *headers, Octstr *body);
- void (*receive_sms) (SMSCConn *conn, HTTPClient *client,
- List *headers, Octstr *body, List *cgivars);
- } ConnData;
- static void conndata_destroy(ConnData *conndata)
- {
- if (conndata == NULL)
- return;
- if (conndata->http_ref)
- http_caller_destroy(conndata->http_ref);
- octstr_destroy(conndata->allow_ip);
- octstr_destroy(conndata->send_url);
- octstr_destroy(conndata->username);
- octstr_destroy(conndata->password);
- gw_free(conndata);
- }
- /*
- * thread to listen to HTTP requests from other end
- */
- static void httpsmsc_receiver(void *arg)
- {
- SMSCConn *conn = arg;
- ConnData *conndata = conn->data;
- HTTPClient *client;
- Octstr *ip, *url, *body;
- List *headers, *cgivars;
- while(conndata->shutdown == 0) {
- /* XXX if conn->is_stopped, do not receive new messages.. */
- client = http_accept_request(conndata->port, &ip, &url,
- &headers, &body, &cgivars);
- if (client == NULL)
- break;
- debug("smsc.http", 0, "Got request '%s'", octstr_get_cstr(url));
- if (connect_denied(conndata->allow_ip, ip)) {
- info(0, "httpsmsc: connection '%s' tried from denied "
- "host %s, ignored", octstr_get_cstr(url),
- octstr_get_cstr(ip));
- http_close_client(client);
- } else
- conndata->receive_sms(conn, client, headers, body, cgivars);
- debug("smsc.http", 0, "destroying client information");
- octstr_destroy(url);
- octstr_destroy(ip);
- octstr_destroy(body);
- http_destroy_headers(headers);
- http_destroy_cgiargs(cgivars);
- }
- debug("http_smsc", 0, "httpsmsc_receiver dying");
- conndata->shutdown = 1;
- http_close_port(conndata->port);
- http_caller_signal_shutdown(conndata->http_ref);
- }
- /*
- * thread to handle finished sendings
- */
- static void httpsmsc_send_cb(void *arg)
- {
- SMSCConn *conn = arg;
- ConnData *conndata = conn->data;
- Msg *msg;
- int status;
- List *headers;
- Octstr *final_url, *body;
- while(conndata->shutdown == 0 || conndata->open_sends) {
- msg = http_receive_result(conndata->http_ref, &status,
- &final_url, &headers, &body);
- if (msg == NULL)
- break; /* they told us to die */
- conndata->open_sends--;
- conndata->parse_reply(conn, msg, status, headers, body);
- http_destroy_headers(headers);
- octstr_destroy(final_url);
- octstr_destroy(body);
- }
- debug("http-smsc", 0, "httpsmsc_send_cb dying");
- conndata->shutdown = 1;
- gwthread_join(conndata->receive_thread);
- conn->data = NULL;
- conndata_destroy(conndata);
- conn->status = SMSCCONN_DEAD;
- bb_smscconn_killed();
- }
- /*----------------------------------------------------------------
- * SMSC-type specific functions
- *
- * 3 functions are needed for each:
- *
- * 1) send SMS
- * 2) parse send SMS result
- * 3) receive SMS (and send reply)
- *
- * These functions do not return anything and do not destroy
- * arguments. They must handle everything that happens therein
- * and must call appropriate bb_smscconn functions
- */
- /*xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
- * Kannel
- */
- enum {HEX_NOT_UPPERCASE = 0};
- static void kannel_send_sms(SMSCConn *conn, Msg *sms)
- {
- ConnData *conndata = conn->data;
- Octstr *url;
- List *headers;
- if (!conndata->no_sep) {
- url = octstr_format("%S?"
- "user=%E&pass=%E&to=%E&text=%E",
- conndata->send_url,
- conndata->username, conndata->password,
- sms->sms.receiver, sms->sms.msgdata);
- } else {
- octstr_binary_to_hex(sms->sms.msgdata, HEX_NOT_UPPERCASE);
- url = octstr_format("%S?"
- "user=%E&pass=%E&to=%E&text=%S",
- conndata->send_url,
- conndata->username, conndata->password,
- sms->sms.receiver,
- sms->sms.msgdata);
- }
- if (octstr_len(sms->sms.udhdata)) {
- if (!conndata->no_sep) {
- octstr_format_append(url, "&udh=%E", sms->sms.udhdata);
- } else {
- octstr_binary_to_hex(sms->sms.udhdata, HEX_NOT_UPPERCASE);
- octstr_format_append(url, "&udh=%S", sms->sms.udhdata);
- }
- }
- if (!conndata->no_sender)
- octstr_format_append(url, "&from=%E", sms->sms.sender);
- if (sms->sms.mclass)
- octstr_format_append(url, "&mclass=%d", sms->sms.mclass);
- if (!conndata->no_coding && sms->sms.coding)
- octstr_format_append(url, "&coding=%d", sms->sms.coding);
- if (sms->sms.mwi)
- octstr_format_append(url, "&mwi=%d", sms->sms.mwi);
- if (sms->sms.account) /* prepend account with local username */
- octstr_format_append(url, "&account=%E:%E", sms->sms.service, sms->sms.account);
- headers = list_create();
- debug("smsc.http.kannel", 0, "start request");
- http_start_request(conndata->http_ref, HTTP_METHOD_GET, url, headers,
- NULL, 0, sms, NULL);
- octstr_destroy(url);
- http_destroy_headers(headers);
- }
- static void kannel_parse_reply(SMSCConn *conn, Msg *msg, int status,
- List *headers, Octstr *body)
- {
- if ((status == HTTP_OK || status == HTTP_ACCEPTED)
- && octstr_case_compare(body, octstr_imm("Sent."))==0)
- bb_smscconn_sent(conn, msg);
- else if ((status == HTTP_OK || status == HTTP_ACCEPTED)
- && octstr_ncompare(body, octstr_imm("Result: OK"),10) == 0)
- bb_smscconn_sent(conn, msg);
- else
- bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_MALFORMED);
- }
- static void kannel_receive_sms(SMSCConn *conn, HTTPClient *client,
- List *headers, Octstr *body, List *cgivars)
- {
- ConnData *conndata = conn->data;
- Octstr *user, *pass, *from, *to, *text, *udh, *account, *tmp_string;
- Octstr *retmsg;
- int mclass, mwi, coding, validity, deferred;
- List *reply_headers;
- int ret;
- mclass = mwi = coding = validity = deferred = 0;
- user = http_cgi_variable(cgivars, "user");
- pass = http_cgi_variable(cgivars, "pass");
- from = http_cgi_variable(cgivars, "from");
- to = http_cgi_variable(cgivars, "to");
- text = http_cgi_variable(cgivars, "text");
- udh = http_cgi_variable(cgivars, "udh");
- account = http_cgi_variable(cgivars, "account");
- tmp_string = http_cgi_variable(cgivars, "flash");
- if(tmp_string) {
- sscanf(octstr_get_cstr(tmp_string),"%d", &mclass);
- }
- tmp_string = http_cgi_variable(cgivars, "mclass");
- if(tmp_string) {
- sscanf(octstr_get_cstr(tmp_string),"%d", &mclass);
- }
- tmp_string = http_cgi_variable(cgivars, "mwi");
- if(tmp_string) {
- sscanf(octstr_get_cstr(tmp_string),"%d", &mwi);
- }
- tmp_string = http_cgi_variable(cgivars, "coding");
- if(tmp_string) {
- sscanf(octstr_get_cstr(tmp_string),"%d", &coding);
- }
- tmp_string = http_cgi_variable(cgivars, "validity");
- if(tmp_string) {
- sscanf(octstr_get_cstr(tmp_string),"%d", &validity);
- }
- tmp_string = http_cgi_variable(cgivars, "deferred");
- if(tmp_string) {
- sscanf(octstr_get_cstr(tmp_string),"%d", &deferred);
- }
- debug("smsc.http.kannel", 0, "Received an HTTP request");
- if ( user == NULL || pass == NULL
- || octstr_compare(user, conndata->username)!= 0
- || octstr_compare(pass, conndata->password)!= 0) {
- debug("smsc.http.kannel", 0, "Authorization failure");
- retmsg = octstr_create("Authorization failed for sendsms");
- }
- else if (from == NULL || to == NULL || text == NULL) {
- debug("smsc.http.kannel", 0, "Insufficient args");
- retmsg = octstr_create("Insufficient args, rejected");
- }
- else {
- Msg *msg;
- msg = msg_create(sms);
- debug("smsc.http.kannel", 0, "Constructing new SMS");
- msg->sms.sender = octstr_duplicate(from);
- msg->sms.receiver = octstr_duplicate(to);
- msg->sms.msgdata = octstr_duplicate(text);
- msg->sms.udhdata = octstr_duplicate(udh);
- msg->sms.smsc_id = octstr_duplicate(conn->id);
- msg->sms.time = time(NULL);
- msg->sms.mclass = mclass;
- msg->sms.mwi = mwi;
- msg->sms.coding = coding;
- msg->sms.validity = validity;
- msg->sms.deferred = deferred;
- msg->sms.account = account;
- ret = bb_smscconn_receive(conn, msg);
- if (ret == -1)
- retmsg = octstr_create("Not accepted");
- else
- retmsg = octstr_create("Ok.");
- }
- reply_headers = list_create();
- http_header_add(reply_headers, "Content-Type", "text/plain");
- debug("smsc.http.kannel", 0, "sending reply");
- http_send_reply(client, HTTP_OK, reply_headers, retmsg);
- octstr_destroy(retmsg);
- http_destroy_headers(reply_headers);
- }
- /*xxxxxxxxxxxxxxxxxxxxxxx
- *
- * ADD NEW CONTENT GATEWAY/HTTP SMSC CALLBACKS HERE
- */
- /*-----------------------------------------------------------------
- * functions to implement various smscconn operations
- */
- static int httpsmsc_send(SMSCConn *conn, Msg *msg)
- {
- ConnData *conndata = conn->data;
- Msg *sms = msg_duplicate(msg);
- conndata->open_sends++;
- conndata->send_sms(conn, sms);
- return 0;
- }
- static long httpsmsc_queued(SMSCConn *conn)
- {
- ConnData *conndata = conn->data;
- return conndata->open_sends;
- }
- static int httpsmsc_shutdown(SMSCConn *conn, int finish_sending)
- {
- ConnData *conndata = conn->data;
- debug("httpsmsc_shutdown", 0, "httpsmsc: shutting down");
- conn->why_killed = SMSCCONN_KILLED_SHUTDOWN;
- conndata->shutdown = 1;
- http_close_port(conndata->port);
- return 0;
- }
- int smsc_http_create(SMSCConn *conn, CfgGroup *cfg)
- {
- ConnData *conndata = NULL;
- Octstr *type;
- long portno; /* has to be long because of cfg_get_integer */
- int ssl = 0; /* indicate if SSL-enabled server should be used */
- if (cfg_get_integer(&portno, cfg, octstr_imm("port")) == -1) {
- error(0, "'port' invalid in smsc 'http' record.");
- return -1;
- }
- if ((type = cfg_get(cfg, octstr_imm("system-type")))==NULL) {
- error(0, "'type' missing in smsc 'http' record.");
- octstr_destroy(type);
- return -1;
- }
- conndata = gw_malloc(sizeof(ConnData));
- conndata->http_ref = NULL;
- conndata->allow_ip = cfg_get(cfg, octstr_imm("connect-allow-ip"));
- conndata->send_url = cfg_get(cfg, octstr_imm("send-url"));
- conndata->username = cfg_get(cfg, octstr_imm("smsc-username"));
- conndata->password = cfg_get(cfg, octstr_imm("smsc-password"));
- cfg_get_bool(&conndata->no_sender, cfg, octstr_imm("no-sender"));
- cfg_get_bool(&conndata->no_coding, cfg, octstr_imm("no-coding"));
- cfg_get_bool(&conndata->no_sep, cfg, octstr_imm("no-sep"));
- if (conndata->send_url == NULL)
- panic(0, "Sending not allowed");
- if (octstr_case_compare(type, octstr_imm("kannel"))==0) {
- if (conndata->username == NULL || conndata->password == NULL) {
- error(0, "username and password required for Kannel http smsc");
- goto error;
- }
- conndata->receive_sms = kannel_receive_sms;
- conndata->send_sms = kannel_send_sms;
- conndata->parse_reply = kannel_parse_reply;
- }
- /*
- * ADD NEW HTTP SMSC TYPES HERE
- */
- else {
- error(0, "system-type '%s' unknown smsc 'http' record.",
- octstr_get_cstr(type));
- goto error;
- }
- conndata->open_sends = 0;
- conndata->http_ref = http_caller_create();
- conn->data = conndata;
- conn->name = octstr_format("HTTP:%S", type);
- conn->status = SMSCCONN_ACTIVE;
- conn->connect_time = time(NULL);
- conn->shutdown = httpsmsc_shutdown;
- conn->queued = httpsmsc_queued;
- conn->send_msg = httpsmsc_send;
- if (http_open_port(portno, ssl)==-1)
- goto error;
- conndata->port = portno;
- conndata->shutdown = 0;
- if ((conndata->receive_thread =
- gwthread_create(httpsmsc_receiver, conn)) == -1)
- goto error;
- if ((conndata->send_cb_thread =
- gwthread_create(httpsmsc_send_cb, conn)) == -1)
- goto error;
- info(0, "httpsmsc '%s' initiated and ready", octstr_get_cstr(conn->name));
- octstr_destroy(type);
- return 0;
- error:
- error(0, "Failed to create http smsc connection");
- conn->data = NULL;
- conndata_destroy(conndata);
- conn->why_killed = SMSCCONN_KILLED_CANNOT_CONNECT;
- conn->status = SMSCCONN_DEAD;
- octstr_destroy(type);
- return -1;
- }