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

📄 smsc_emi.c

📁 The Kannel Open Source WAP and SMS gateway works as both an SMS gateway, for implementing keyword b
💻 C
📖 第 1 页 / 共 4 页
字号:
/* ====================================================================  * 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_emi.c - interface to EMI/UCP SMS centers * * Uoti Urpala 2001 * Alexander Malysh and Stipe Tolj 2002-2003 * * References: * *   [1] Short Message Sergice Centre 4.0 EMI - UCP Interface Specification *       document version 4.2, May 2001, CMG Wireless Data Solutions. *//* Doesn't warn about unrecognized configuration variables *//* The EMI specification doesn't document how connections should be * opened/used. The way they currently work might need to be changed. */#include <sys/types.h>#include <sys/socket.h>#include <unistd.h>#include <errno.h>#include <time.h>#include <limits.h>#include <float.h>#include "gwlib/gwlib.h"#include "smscconn.h"#include "smscconn_p.h"#include "bb_smscconn_cb.h"#include "msg.h"#include "sms.h"#include "emimsg.h"#include "dlr.h"#include "alt_charsets.h"#define EMI2_MAX_TRN 100typedef struct privdata {    Octstr	*name;    gw_prioqueue_t *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, alt_port;		  /* SMSC port */    int		our_port;	  /* Optional local port number in which to				   * bind our end of send connection */    int		rport;		  /* Receive-port to listen */    Octstr	*allow_ip, *deny_ip;    Octstr	*host, *alt_host, *username, *password;    Octstr	*my_number;	/* My number if we want to force one */    int		unacked;	/* Sent messages not acked */    struct {	time_t	sendtime;	/* When we sent out a message with a given				 * TRN. Is 0 if the TRN slot is currently free. */	int     sendtype;	/* OT of message, undefined if time == 0 */	Msg     *sendmsg; 	/* Corresponding message for OT == 51 */    } slots[EMI2_MAX_TRN];    int		keepalive; 	/* Seconds to send a Keepalive Command (OT=31) */    int		flowcontrol;	/* 0=Windowing, 1=Stop-and-Wait */    int		waitack;	/* Seconds to wait to ack */    int		waitack_expire;	/* What to do on waitack expire */    int		window;		/* In windowed flow-control, the window size */    int         can_write;      /* write = 1, read = 0, for stop-and-wait flow control */    int         priv_nexttrn;   /* next TRN, this should never be accessed directly.				 * use int emi2_next_trn (SMSCConn *conn) instead.				 */    time_t	last_activity_time; /* the last time something was sent over the main				     * SMSC connection				     */    time_t      check_time;    int         idle_timeout;   /* Seconds a Main connection to the SMSC is allowed to be idle.				   If 0, no idle timeout is in effect */    Octstr   *npid; /* Notification PID value */    Octstr   *nadc; /* Notification Address */    int alt_charset; /* Alternative GSM charset, defined via values in gwlib/alt_charsets.h */} PrivData;typedef enum {    EMI2_SENDREQ,  /* somebody asked this driver to send a SMS message */    EMI2_SMSCREQ,  /* the SMSC wants something from us */    EMI2_CONNERR,  /* an error condition in the SMSC main connection */    EMI2_TIMEOUT,  /* timeout on the SMSC main connection */} EMI2Event;#define PRIVDATA(conn) ((PrivData *)((conn)->data))#define SLOTBUSY(conn,i) (PRIVDATA(conn)->slots[(i)].sendtime != 0)#define CONNECTIONIDLE(conn)								\((PRIVDATA(conn)->unacked == 0) &&							\ (PRIVDATA(conn)->idle_timeout ?							\  (PRIVDATA(conn)->last_activity_time + PRIVDATA(conn)->idle_timeout) <= time(0):0))#define emi2_can_send(conn)					\((PRIVDATA(conn)->can_write || !PRIVDATA(conn)->flowcontrol) &&	\ (PRIVDATA(conn)->unacked < PRIVDATA(conn)->window) &&		\ (!PRIVDATA(conn)->shutdown))#define emi2_needs_keepalive(conn)							\(emi2_can_send(conn) &&									\ (PRIVDATA(conn)->keepalive > 0) &&							\ (time(NULL) > (PRIVDATA(conn)->last_activity_time + PRIVDATA(conn)->keepalive)))/* * Send an EMI message and update the last_activity_time field. */static int emi2_emimsg_send(SMSCConn *conn, Connection *server, struct emimsg *emimsg){    int result = emimsg_send(server, emimsg, PRIVDATA(conn)->name);    if (result >= 0 && emimsg->or == 'O' && ( emimsg->ot == 31 || emimsg->ot == 51)) {	PRIVDATA(conn)->last_activity_time = time (NULL);    }    return result;}/* Wait for a message of type 'ot', sent with TRN 0, to be acked. * Timeout after 't' seconds. Any other packets received are ignored. * This function is meant for initial login packet(s) and testing. * Return 1 for positive ACK, 0 for timeout, -1 for broken/closed connection, * -2 for negative NACK. */static int wait_for_ack(PrivData *privdata, Connection *server, int ot, int t){    time_t timeout_time;    int time_left;    Octstr *str;    struct emimsg *emimsg;    timeout_time = time(NULL) + t;    while (1) {	str = conn_read_packet(server, 2, 3);	if (conn_eof(server)) {	    error(0, "EMI2[%s]: connection closed in wait_for_ack",		  octstr_get_cstr(privdata->name));	    return -1;	}	if (conn_error(server)) {	    error(0, "EMI2[%s]: connection error in wait_for_ack",		  octstr_get_cstr(privdata->name));	    return -1;	}	if (str) {	    emimsg = get_fields(str, privdata->name);	    if (emimsg == NULL) {		octstr_destroy(str);		continue;	    }	    if (emimsg->ot == ot && emimsg->trn == 0 && emimsg->or == 'R') {		octstr_destroy(str);		break;	    }	    warning(0, "EMI2[%s]: ignoring message %s while waiting for ack to"			"ot:%d trn:%d", octstr_get_cstr(privdata->name),			octstr_get_cstr(str), ot, 0);	    emimsg_destroy(emimsg);	    octstr_destroy(str);	}	time_left = timeout_time - time(NULL);	if (time_left < 0 || privdata->shutdown)	    return 0;	conn_wait(server, time_left);    }    if (octstr_get_char(emimsg->fields[0], 0) == 'N') {	emimsg_destroy(emimsg);	return -2;    }    emimsg_destroy(emimsg);    return 1;}static struct emimsg *make_emi31(PrivData *privdata, int trn){    struct emimsg *emimsg;    if(octstr_len(privdata->username) || octstr_len(privdata->my_number)) {        emimsg = emimsg_create_op(31, trn, privdata->name);        if(octstr_len(privdata->username)) {            emimsg->fields[0] = octstr_duplicate(privdata->username);	} else {            emimsg->fields[0] = octstr_duplicate(privdata->my_number);	}        emimsg->fields[1] = octstr_create("0539");        return emimsg;    } else {        return NULL;    }}static struct emimsg *make_emi60(PrivData *privdata){    struct emimsg *emimsg;    emimsg = emimsg_create_op(60, 0, privdata->name);    emimsg->fields[E60_OADC] = octstr_duplicate(privdata->username);    emimsg->fields[E60_OTON] = octstr_create("6");    emimsg->fields[E60_ONPI] = octstr_create("5");    emimsg->fields[E60_STYP] = octstr_create("1");    emimsg->fields[E60_PWD] = octstr_duplicate(privdata->password);    octstr_binary_to_hex(emimsg->fields[E60_PWD], 1);    emimsg->fields[E60_VERS] = octstr_create("0100");    return emimsg;}static Connection *open_send_connection(SMSCConn *conn){    PrivData *privdata = conn->data;    int result, alt_host, do_alt_host;    struct emimsg *emimsg;    Connection *server;    Msg *msg;    int connect_error = 0;    int wait_ack = 0;    do_alt_host = octstr_len(privdata->alt_host) != 0 || 	    privdata->alt_port != 0;    alt_host = 0;    mutex_lock(conn->flow_mutex);    conn->status = SMSCCONN_RECONNECTING;    mutex_unlock(conn->flow_mutex);    while (!privdata->shutdown) {    while ((msg = gw_prioqueue_remove(privdata->outgoing_queue))) {        bb_smscconn_send_failed(conn, msg,                         SMSCCONN_FAILED_TEMPORARILY, NULL);    }    /* if there is no alternative host, sleep and try to re-connect */    if (alt_host == 0 && connect_error) {        error(0, "EMI2[%s]: Couldn't connect to SMS center (retrying in %ld seconds).",              octstr_get_cstr(privdata->name), conn->reconnect_delay);        gwthread_sleep(conn->reconnect_delay);    }	if (alt_host != 1) {	    info(0, "EMI2[%s]: connecting to Primary SMSC",			    octstr_get_cstr(privdata->name));	    server = conn_open_tcp_with_port(privdata->host, privdata->port,					     privdata->our_port,					     conn->our_host);	    if(do_alt_host)		alt_host=1;	    else		alt_host=0;	} else {	    info(0, "EMI2[%s]: connecting to Alternate SMSC",			    octstr_get_cstr(privdata->name));	    /* use alt_host or/and alt_port if defined */	    server = conn_open_tcp_with_port(		(octstr_len(privdata->alt_host) ? privdata->alt_host : privdata->host),		(privdata->alt_port ? privdata->alt_port : privdata->port),		privdata->our_port, conn->our_host);	    alt_host=0;	}	if (privdata->shutdown) {	    conn_destroy(server);	    return NULL;	}	if (server == NULL) {	    error(0, "EMI2[%s]: opening TCP connection to %s failed",		  octstr_get_cstr(privdata->name),		  octstr_get_cstr(privdata->host));        connect_error = 1;  	    continue;	}    if (privdata->username && privdata->password) {        emimsg = make_emi60(privdata);        emi2_emimsg_send(conn, server, emimsg);	    emimsg_destroy(emimsg);        wait_ack = privdata->waitack > 30 ? privdata->waitack : 30;        result = wait_for_ack(privdata, server, 60, wait_ack);        if (result == -2) {            /*              * Are SMSCs going to return any temporary errors? If so,             * testing for those error codes should be added here.              */            error(0, "EMI2[%s]: Server rejected our login",                  octstr_get_cstr(privdata->name));            conn_destroy(server);            connect_error = 1;            continue;        } else if (result == 0) {            error(0, "EMI2[%s]: Got no reply to login attempt "                     "within %d seconds", octstr_get_cstr(privdata->name),                     wait_ack);            conn_destroy(server);            connect_error = 1;            continue;        } else if (result == -1) { /* Broken connection, already logged */            conn_destroy(server);            connect_error = 1;            continue;        }        privdata->last_activity_time = 0; /* to force keepalive after login */        privdata->can_write = 1;    }	mutex_lock(conn->flow_mutex);	conn->status = SMSCCONN_ACTIVE;	conn->connect_time = time(NULL);	mutex_unlock(conn->flow_mutex);	bb_smscconn_connected(conn);	return server;    }    return NULL;}static void pack_7bit(Octstr *str){    Octstr *result;    int len, i;    int numbits, value;    result = octstr_create("0");    len = octstr_len(str);    value = 0;    numbits = 0;    for (i = 0; i < len; i++) {	value += octstr_get_char(str, i) << numbits;	numbits += 7;	if (numbits >= 8) {	    octstr_append_char(result, value & 0xff);	    value >>= 8;	    numbits -= 8;	}    }    if (numbits > 0)	octstr_append_char(result, value);    octstr_set_char(result, 0, (len * 7 + 3) / 4);    octstr_delete(str, 0, LONG_MAX);    octstr_append(str, result);    octstr_binary_to_hex(str, 1);    octstr_destroy(result);}static struct emimsg *msg_to_emimsg(Msg *msg, int trn, PrivData *privdata){    Octstr *str;    struct emimsg *emimsg;    int dcs;    struct tm tm;    char p[20];    emimsg = emimsg_create_op(51, trn, privdata->name);    str = octstr_duplicate(msg->sms.sender);    if(octstr_get_char(str,0) == '+') {    	/* either alphanum or international */    	if (!octstr_check_range(str, 1, 256, gw_isdigit)) {	    /* alphanumeric sender address with + in front*/	    charset_latin1_to_gsm(str);	    octstr_truncate(str, 11); /* max length of alphanumeric OaDC */	    emimsg->fields[E50_OTOA] = octstr_create("5039");	    pack_7bit(str);	}	else {	    /* international number. Set format and remove + */	    emimsg->fields[E50_OTOA] = octstr_create("1139");	    octstr_delete(str, 0, 1);	    octstr_truncate(str, 22);  /* max length of numeric OaDC */	}    }    else {	if (!octstr_check_range(str, 0, 256, gw_isdigit)) {	    /* alphanumeric sender address */            charset_latin1_to_gsm(str);	    octstr_truncate(str, 11); /* max length of alphanumeric OaDC */	    emimsg->fields[E50_OTOA] = octstr_create("5039");	    pack_7bit(str);	}    }     emimsg->fields[E50_OADC] = str;    /* set protocol id */    if (msg->sms.pid >= 0) {        emimsg->fields[E50_RPID] = octstr_format("%04d", msg->sms.pid);    }    /* set reply path indicator */    if (msg->sms.rpi == 2)        emimsg->fields[E50_RPI] = octstr_create("2");    else if (msg->sms.rpi > 0)        emimsg->fields[E50_RPI] = octstr_create("1");    str = octstr_duplicate(msg->sms.receiver);    if(octstr_get_char(str,0) == '+') {    	 /* international number format */

⌨️ 快捷键说明

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