⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smsc_cgw.c

📁 gnu的专业网关smpp协议支持源代码。
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * smsc_cgw.c - Implements an interface to the Sonera ContentGateway software * * Anders Lindh, FlyerOne Ltd <alindh@flyerone.com> * * * Changelog: * * 22/02/2002: Preliminary support for the Euro character (req. ProviderServer 2.5.2) * 25/01/2002: Caught a potentially nasty bug * 16/01/2002: Some code cleanup * 10/01/2002: Fixed a bug in trn handling * 16/11/2001: Some minor fixes (Thanks to Tuomas Luttinen) * 12/11/2001: Delivery reports, better acking and numerous other small fixes * 05/11/2001: Initial release. Based heavily on smsc_emi2 and smsc_at2.  * * * TO-DO: Do some real life testing *        Squash bugs * * Usage: add the following to kannel.conf: * * group = smsc * smsc = cgw * host = x.x.x.x      <- CGW server host * port = xxxx 	       <- CGW server otp port (if omitted, defaults to 21772) * receive-port = xxxx <- our port for incoming messages * appname = xxxx      <- Name of a "Send only" service. Defaults to "send". *	           	  All outgoing messages are routed through this service. * * Configure ContentGateway software to use the above port as text-port * (in provider.cnf). This is documented in their "Guide for Service * development 2.5", page 80. * * Add a new "Receive only" service (with the Remote Control tool), and set * the "Application for Incoming Message" to "text://kannelhost:receive-port". * * * Note: * * Do NOT define the service as a "Query/Reply" service, as it expects response * messages to have a matching session-id tag. Kannel does not store the * relation between a query and a reply, so the response message will not have * the session-id tag. Even though the messages are delivered successfully, * billing of premium priced services will fail. * * */#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"#define CGW_DEFPORT 	21772#define	CGW_EOL     	0x0A#define CGW_TRN_MAX 	500	/* Size of our internal message buffer. */#define CGWOP_MAXARGS	10     	/* max. number of name:value pairs in cgwop *//* Valid CGW operations */#define CGW_OP_NOP	0     	/* this doesn't really exist.. */#define CGW_OP_MSG	1#define CGW_OP_OK	2#define CGW_OP_ERR	3#define CGW_OP_DELIVERY	4#define CGW_OP_HELLO	5#define CGW_OP_STATUS	6struct cgwop{    int op;    			/* one of above */    int num_fields;    int trn;                    /* transaction number, used to ACK messages */    Octstr **name;    		/* for storing name/value pairs */    Octstr **value;};static char *cgw_ops[6] = {"nop", "msg", "ok", "err", "delivery", "hello"};typedef struct privdata{    List *outgoing_queue;    long receiver_thread;    long sender_thread;    int	shutdown;    	       	/* Internal signal to shut down */    int	listening_socket;     	/* File descriptor */    int	send_socket;    int	port;    	        /* SMSC port */    int	rport;    		/* port for receiving messages*/    int	our_port;    	  	/* Optional local port number in which to                	        	 * bind our end of send connection */    Octstr *host;    Octstr *allow_ip, *deny_ip;    Octstr *appname;    	/* Application name as defined in Sonera Remote manager */    Msg	*sendmsg[CGW_TRN_MAX];    time_t sendtime[CGW_TRN_MAX];    int	dlr[CGW_TRN_MAX];    	/* dlr = DLR_SMSC_SUCCESS || DLR_SMSC_FAIL */    int	unacked;    		/* Sent messages not acked */    int	waitack;        	/* Seconds to wait to ack */    int	nexttrn;    long check_time;     	/* last checked ack/nack status */}PrivData;static int cgw_add_msg_cb(SMSCConn *conn, Msg *sms);static int cgw_shutdown_cb(SMSCConn *conn, int finish_sending);static void cgw_start_cb(SMSCConn *conn);static long cgw_queued_cb(SMSCConn *conn);static void cgw_sender(void *arg);static Connection *cgw_open_send_connection(SMSCConn *conn);static int cgw_send_loop(SMSCConn *conn, Connection *server);void cgw_check_acks(PrivData *privdata);int cgw_wait_command(PrivData *privdata, SMSCConn *conn, Connection *server, int timeout);static int cgw_open_listening_socket(PrivData *privdata);static void cgw_listener(void *arg);static void cgw_receiver(SMSCConn *conn, Connection *server);static int cgw_handle_op(SMSCConn *conn, Connection *server, struct cgwop *cgwop);struct cgwop *cgw_read_op(PrivData *privdata, SMSCConn *conn, Connection *server, time_t timeout);/****************************************************************************** * Functions for handling cgwop -structures */static void cgwop_add(struct cgwop *cgwop, Octstr *name, Octstr *value){    if (cgwop->num_fields < CGWOP_MAXARGS)    {        cgwop->name[cgwop->num_fields] = octstr_duplicate(name);        cgwop->value[cgwop->num_fields] = octstr_duplicate(value);        cgwop->num_fields++;    } else    {        info(0, "cgw: CGWOP_MAXARGS exceeded.");    }}static struct cgwop *cgwop_create(int op, int trn){    struct cgwop *ret;    Octstr *trnstr;    ret = gw_malloc(sizeof(struct cgwop));    ret->op = op;    ret->num_fields = 0;    ret->trn = trn;    ret->name = gw_malloc(CGWOP_MAXARGS * sizeof(Octstr *));    ret->value = gw_malloc(CGWOP_MAXARGS * sizeof(Octstr *));    if (trn != -1)    {        trnstr = octstr_create("");        octstr_append_decimal(trnstr, trn);        cgwop_add(ret, octstr_imm("client-id"), trnstr);        octstr_destroy(trnstr);    }    return ret;}static void cgwop_destroy(struct cgwop *cgwop){    int len;    len = cgwop->num_fields;    while (--len >= 0)    {        octstr_destroy(cgwop->name[len]);      /* octstr_destroy(NULL) is ok */        octstr_destroy(cgwop->value[len]);    }    gw_free(cgwop->name);    gw_free(cgwop->value);    gw_free(cgwop);}static Octstr *cgwop_get(struct cgwop *cgwop, Octstr *name){    int len = cgwop->num_fields;    while (--len >= 0)        if (octstr_compare(name, cgwop->name[len]) == 0)            return cgwop->value[len];    return NULL;}static Octstr *cgwop_tostr(struct cgwop *cgwop){    int len = cgwop->num_fields;    Octstr *str;    if (cgw_ops[cgwop->op] == NULL) return NULL;     // invalid operation    str = octstr_create("");    octstr_append(str, octstr_imm("op:"));    octstr_append(str, octstr_imm(cgw_ops[cgwop->op]));    octstr_append_char(str, CGW_EOL);    while (--len >= 0)    {        octstr_append(str, cgwop->name[len]);        octstr_append_char(str, ':');        octstr_append(str, cgwop->value[len]);        octstr_append_char(str, CGW_EOL);    }    octstr_append(str, octstr_imm("end:"));    octstr_append(str, octstr_imm(cgw_ops[cgwop->op]));    octstr_append_char(str, CGW_EOL);    return str;}static int cgwop_send(Connection *conn, struct cgwop *cgwop){    Octstr *dta = cgwop_tostr(cgwop);    if (dta == NULL) return -1;     /* couldn't convert to string */    if (conn_write(conn, dta) == -1)    {        octstr_destroy(dta);        return -1;    }    octstr_destroy(dta);    return 1;}/****************************************************************************** * cgw_encode_msg - Encode a msg according to specifications */static Octstr *cgw_encode_msg(Octstr* str){    int i;    char esc = 27;    char e = 'e';    /* Euro char (0x80) -> ESC + e. We do this conversion as long as the message        length is under 160 chars (the checking could probably be done better) */    while ((i = octstr_search_char(str, 0x80, 0)) != -1) {            octstr_delete(str, i, 1);     // delete Euro char	if (octstr_len(str) < 160) {	    octstr_insert_data(str, i, &esc, 1);  // replace with ESC + e	    octstr_insert_data(str, i+1, &e, 1);  	} else {	    octstr_insert_data(str, i, &e, 1);  // no room for ESC + e, just replace with an e        }    }    /* Escape backslash characters */    while ((i = octstr_search_char(str, '\\', 0)) != -1) {        octstr_insert(str, octstr_imm("\\"), i);    }    /* Remove Line Feed characters */    while ((i = octstr_search_char(str, CGW_EOL, 0)) != -1) {        octstr_delete(str, i, 1);     // delete EOL char        octstr_insert(str, octstr_imm("\\n"), i);    }    /* Remove Carriage return characters */    while ((i = octstr_search_char(str, 13, 0)) != -1) {        octstr_delete(str, i, 1);     // delete EOL char        octstr_insert(str, octstr_imm("\\r"), i);    }    return str;}/****************************************************************************** * cgw_decode_msg - Decode an incoming msg */static Octstr *cgw_decode_msg(Octstr* str){    int i;    /* make \n -> linefeed */    while ((i = octstr_search(str, octstr_imm("\\n"), 0)) != -1) {        octstr_delete(str, i, 2);     // delete "\n" str        octstr_insert(str, octstr_imm("\n"), i);    }    /* make \r -> carriage return */    while ((i = octstr_search(str, octstr_imm("\\r"), 0)) != -1) {        octstr_delete(str, i, 2);     // delete EOL char        octstr_insert(str, octstr_imm("\r"), i);    }    /* remove double backslashes */    while ((i = octstr_search(str, octstr_imm("\\\\"), 0)) != -1) {        octstr_delete(str, i, 1);    }    return str;}/****************************************************************************** * msg_to_cgwop - Create a send cgwop from a message */static struct cgwop *msg_to_cgwop(PrivData *privdata, Msg *msg, int trn){    struct cgwop *cgwop;    Octstr *sender, *udh, *dta;    cgwop = cgwop_create(CGW_OP_MSG, trn);    if (cgwop == NULL) return NULL;    if (!octstr_check_range(msg->sms.sender, 0, octstr_len(msg->sms.sender), gw_isdigit))    {        /* If alphanumeric, simply prefix sender with '$' char */        sender = octstr_create("$");        octstr_append(sender, msg->sms.sender);    } else sender = octstr_duplicate(msg->sms.sender);    cgwop_add(cgwop, octstr_imm("app"), privdata->appname);    cgwop_add(cgwop, octstr_imm("from"), sender);    cgwop_add(cgwop, octstr_imm("to"), msg->sms.receiver);    /* If delivery reports are asked, ask for them by adding a nrq:anything field */    if (msg->sms.dlr_mask & 0x07)        cgwop_add(cgwop, octstr_imm("nrq"), octstr_imm("true"));    octstr_destroy(sender);    if (octstr_len(msg->sms.udhdata))    {        udh = octstr_duplicate(msg->sms.udhdata);        octstr_binary_to_hex(udh, 1);        cgwop_add(cgwop, octstr_imm("udh"), udh);        octstr_destroy(udh);        dta = octstr_duplicate(msg->sms.msgdata);        octstr_binary_to_hex(dta, 1);        cgwop_add(cgwop, octstr_imm("msg"), dta);        cgwop_add(cgwop, octstr_imm("type"), octstr_imm("bin"));        octstr_destroy(dta);    } else    {        cgwop_add(cgwop, octstr_imm("msg"), cgw_encode_msg(msg->sms.msgdata));    }    return cgwop;}/****************************************************************************** * Called to create the SMSC. This is our entry point. */int smsc_cgw_create(SMSCConn *conn, CfgGroup *cfg){    PrivData *privdata;    Octstr *allow_ip, *deny_ip, *host, *appname;    long portno, our_port, waitack;    int i;    privdata = gw_malloc(sizeof(PrivData));    privdata->outgoing_queue = list_create();    privdata->listening_socket = -1;    if (cfg_get_integer(&portno, cfg, octstr_imm("port")) == -1)        portno = 0;    privdata->port = portno;    if (cfg_get_integer(&portno, cfg, octstr_imm("receive-port")) < 0)        portno = 0;    privdata->rport = portno;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -