📄 smsc_http.c
字号:
/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2004 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see <http://www.kannel.org/>. * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * 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 * Stipe Tolj <stolj@wapme.de> * Alexander Malysh <amalysh at kannel.org> * Tobias Weber <weber@wapme.de> */#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"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 */ Octstr *proxy; /* proxy a constant string */ /* 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); octstr_destroy(conndata->proxy); gw_free(conndata);}/* * Thread to listen to HTTP requests from SMSC entity */static void httpsmsc_receiver(void *arg){ SMSCConn *conn = arg; ConnData *conndata = conn->data; HTTPClient *client; Octstr *ip, *url, *body; List *headers, *cgivars; ip = url = body = NULL; headers = cgivars = NULL; /* Make sure we log into our own log-file if defined */ log_thread_to(conn->log_idx); 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, "HTTP[%s]: Got request `%s'", octstr_get_cstr(conn->id), octstr_get_cstr(url)); if (connect_denied(conndata->allow_ip, ip)) { info(0, "HTTP[%s]: Connection `%s' tried from denied " "host %s, ignored", octstr_get_cstr(conn->id), 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, "HTTP[%s]: Destroying client information", octstr_get_cstr(conn->id)); octstr_destroy(url); octstr_destroy(ip); octstr_destroy(body); http_destroy_headers(headers); http_destroy_cgiargs(cgivars); } debug("smsc.http", 0, "HTTP[%s]: httpsmsc_receiver dying", octstr_get_cstr(conn->id)); conndata->shutdown = 1; http_close_port(conndata->port); /* unblock http_receive_result() if there are no open sends */ if (conndata->open_sends == 0) 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; /* Make sure we log into our own log-file if defined */ log_thread_to(conn->log_idx); 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, by unlocking */ /* Handle various states here. */ /* request failed and we are not in shutdown mode */ if (status == -1 && conndata->shutdown == 0) { error(0, "HTTP[%s]: Couldn't connect to SMS center " "(retrying in %ld seconds).", octstr_get_cstr(conn->id), conn->reconnect_delay); conn->status = SMSCCONN_RECONNECTING; gwthread_sleep(conn->reconnect_delay); debug("smsc.http.kannel", 0, "HTTP[%s]: Re-sending request", octstr_get_cstr(conn->id)); conndata->send_sms(conn, msg); continue; } /* request failed and we *are* in shutdown mode, drop the message */ else if (status == -1 && conndata->shutdown == 1) { } /* request succeeded */ else { /* we received a response, so this link is considered online again */ if (status && conn->status != SMSCCONN_ACTIVE) { conn->status = SMSCCONN_ACTIVE; } conndata->parse_reply(conn, msg, status, headers, body); } conndata->open_sends--; http_destroy_headers(headers); octstr_destroy(final_url); octstr_destroy(body); } debug("smsc.http", 0, "HTTP[%s]: httpsmsc_send_cb dying", octstr_get_cstr(conn->id)); conndata->shutdown = 1; if (conndata->open_sends) { warning(0, "HTTP[%s]: Shutdown while <%ld> requests are pending.", octstr_get_cstr(conn->id), conndata->open_sends); } 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 *//*---------------------------------------------------------------- * 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?" "username=%E&password=%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?" "username=%E&password=%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 != MC_UNDEF) octstr_format_append(url, "&mclass=%d", sms->sms.mclass); if (!conndata->no_coding && sms->sms.coding != DC_UNDEF) octstr_format_append(url, "&coding=%d", sms->sms.coding); if (sms->sms.mwi != MWI_UNDEF) 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); if (sms->sms.binfo) /* prepend billing info */ octstr_format_append(url, "&binfo=%S", sms->sms.binfo); if (sms->sms.smsc_id) /* proxy the smsc-id to the next instance */ octstr_format_append(url, "&smsc=%S", sms->sms.smsc_id); if (sms->sms.dlr_url) { octstr_format_append(url, "&dlr-url=%E", sms->sms.dlr_url); } if (sms->sms.dlr_mask != DLR_UNDEFINED && sms->sms.dlr_mask != DLR_NOTHING) octstr_format_append(url, "&dlr-mask=%d", sms->sms.dlr_mask); headers = list_create(); debug("smsc.http.kannel", 0, "HTTP[%s]: Start request", octstr_get_cstr(conn->id)); 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){ /* Test on three cases: * 1. an smsbox reply of an remote kannel instance * 2. an smsc_http response (if used for MT to MO looping) * 3. an smsbox reply of partly successful sendings */ if ((status == HTTP_OK || status == HTTP_ACCEPTED) && (octstr_case_compare(body, octstr_imm("Sent.")) == 0 || octstr_case_compare(body, octstr_imm("Ok.")) == 0 || octstr_ncompare(body, octstr_imm("Result: OK"),10) == 0)) { bb_smscconn_sent(conn, msg, NULL); } else { bb_smscconn_send_failed(conn, msg,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -