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

📄 wsp_session.c

📁 The Kannel Open Source WAP and SMS gateway works as both an SMS gateway, for implementing keyword b
💻 C
📖 第 1 页 / 共 3 页
字号:
/* ====================================================================  * 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.   */ /* * wsp_session.c - Implement WSP session oriented service * * Lars Wirzenius * Stipe Tolj */#include <string.h>#include <limits.h>#include "gwlib/gwlib.h"#include "wsp.h"#include "wsp_pdu.h"#include "wsp_headers.h"#include "wsp_caps.h"#include "wsp_strings.h"#include "cookies.h"#include "wap.h"#include "wtp.h"typedef enum {	#define STATE_NAME(name) name,	#define ROW(state, event, condition, action, next_state)	#include "wsp_server_session_states.def"	#define STATE_NAME(name) name,	#define ROW(state, event, condition, action, next_state)	#include "wsp_server_method_states.def"        #define STATE_NAME(name) name,        #define ROW(state, event, condition, action, next_state)        #include "wsp_server_push_states.def"	WSPState_count} WSPState;/* * Give the status the module: * *	limbo *		not running at all *	running *		operating normally *	terminating *		waiting for operations to terminate, returning to limbo */static enum { limbo, running, terminating } run_status = limbo;static wap_dispatch_func_t *dispatch_to_wtp_resp;static wap_dispatch_func_t *dispatch_to_wtp_init;static wap_dispatch_func_t *dispatch_to_appl;static wap_dispatch_func_t *dispatch_to_ota;/* * True iff "Session resume facility" is enabled.  This means we are * willing to let sessions go to SUSPENDED state, and later resume them. * Currently we always support it, but this may become configurable * at some point. */static int resume_enabled = 1;static List *queue = NULL;static List *session_machines = NULL;static Counter *session_id_counter = NULL;static WSPMachine *find_session_machine(WAPEvent *event, WSP_PDU *pdu);static void handle_session_event(WSPMachine *machine, WAPEvent *event, 				 WSP_PDU *pdu);static WSPMachine *machine_create(void);static void machine_destroy(void *p);static void handle_method_event(WSPMachine *session, WSPMethodMachine *machine, WAPEvent *event, WSP_PDU *pdu);static void cant_handle_event(WSPMachine *sm, WAPEvent *event);static WSPMethodMachine *method_machine_create(WSPMachine *, long);static void method_machine_destroy(void *msm);static void handle_push_event(WSPMachine *session, WSPPushMachine *machine,                              WAPEvent *e);static WSPPushMachine *push_machine_create(WSPMachine *session, long id);static void push_machine_destroy(void *p);static char *state_name(WSPState state);static unsigned long next_wsp_session_id(void);static List *make_capabilities_reply(WSPMachine *m);static List *make_reply_headers(WSPMachine *m);static Octstr *make_connectreply_pdu(WSPMachine *m);static Octstr *make_resume_reply_pdu(WSPMachine *m, List *headers);static WSP_PDU *make_confirmedpush_pdu(WAPEvent *e);static WSP_PDU *make_push_pdu(WAPEvent *e);static int transaction_belongs_to_session(void *session, void *tuple);static int find_by_session_id(void *session, void *idp);static int same_client(void *sm1, void *sm2);static WSPMethodMachine *find_method_machine(WSPMachine *, long id);static WSPPushMachine *find_push_machine(WSPMachine *m, long id);static List *unpack_new_headers(WSPMachine *sm, Octstr *hdrs);static void disconnect_other_sessions(WSPMachine *sm);static void send_abort(long reason, long handle);static void indicate_disconnect(WSPMachine *sm, long reason);static void indicate_suspend(WSPMachine *sm, long reason);static void indicate_resume(WSPMachine *sm, WAPAddrTuple *tuple,                             List *client_headers);static void release_holding_methods(WSPMachine *sm);static void abort_methods(WSPMachine *sm, long reason);static void abort_pushes(WSPMachine *sm, long reason);static void method_abort(WSPMethodMachine *msm, long reason);static void indicate_method_abort(WSPMethodMachine *msm, long reason);static WAPEvent *make_abort(long reason, long handle);static void send_invoke(WSPMachine *session, WSP_PDU *pdu, WAPEvent *e,                        long class);static void send_abort_to_initiator(long reason, long handle);static void indicate_pushabort(WSPPushMachine *machine, long reason);static void confirm_push(WSPPushMachine *machine);static void main_thread(void *);static int id_belongs_to_session (void *, void *);static int wsp_encoding_string_to_version(Octstr *enc);static Octstr *wsp_encoding_version_to_string(int version);/*********************************************************************** * Public functions. */void wsp_session_init(wap_dispatch_func_t *responder_dispatch,                      wap_dispatch_func_t *initiator_dispatch,                      wap_dispatch_func_t *application_dispatch,                      wap_dispatch_func_t *push_ota_dispatch) {	queue = list_create();	list_add_producer(queue);	session_machines = list_create();	session_id_counter = counter_create();	dispatch_to_wtp_resp = responder_dispatch;	dispatch_to_wtp_init = initiator_dispatch;	dispatch_to_appl = application_dispatch;        dispatch_to_ota = push_ota_dispatch;        wsp_strings_init();	run_status = running;	gwthread_create(main_thread, NULL);}void wsp_session_shutdown(void) {	gw_assert(run_status == running);	run_status = terminating;	list_remove_producer(queue);	gwthread_join_every(main_thread);	list_destroy(queue, wap_event_destroy_item);	debug("wap.wsp", 0, "WSP: %ld session machines left.",		list_len(session_machines));	list_destroy(session_machines, machine_destroy);	counter_destroy(session_id_counter);        wsp_strings_shutdown();}void wsp_session_dispatch_event(WAPEvent *event) {	wap_event_assert(event);	list_produce(queue, event);}/*********************************************************************** * Local functions */static void main_thread(void *arg) {	WAPEvent *e;	WSPMachine *sm;	WSP_PDU *pdu;		while (run_status == running && (e = list_consume(queue)) != NULL) {		wap_event_assert(e);		switch (e->type) {		case TR_Invoke_Ind:			pdu = wsp_pdu_unpack(e->u.TR_Invoke_Ind.user_data);			if (pdu == NULL) {				warning(0, "WSP: Broken PDU ignored.");				wap_event_destroy(e);				continue;			}			break;			default:			pdu = NULL;			break;		}			sm = find_session_machine(e, pdu);		if (sm == NULL) {			wap_event_destroy(e);		} else {			handle_session_event(sm, e, pdu);		}				wsp_pdu_destroy(pdu);	}}static WSPMachine *find_session_machine(WAPEvent *event, WSP_PDU *pdu) {	WSPMachine *sm;	long session_id;	WAPAddrTuple *tuple;		tuple = NULL;	session_id = -1;		switch (event->type) {	case TR_Invoke_Ind:		tuple = wap_addr_tuple_duplicate(				event->u.TR_Invoke_Ind.addr_tuple);		break;        case TR_Invoke_Cnf:                tuple = wap_addr_tuple_duplicate(				event->u.TR_Invoke_Cnf.addr_tuple);	        break;	case TR_Result_Cnf:		tuple = wap_addr_tuple_duplicate(				event->u.TR_Result_Cnf.addr_tuple);		break;	case TR_Abort_Ind:		tuple = wap_addr_tuple_duplicate(				event->u.TR_Abort_Ind.addr_tuple);		break;	case S_Connect_Res:		session_id = event->u.S_Connect_Res.session_id;		break;	case S_Resume_Res:		session_id = event->u.S_Resume_Res.session_id;		break;	case Disconnect_Event:		session_id = event->u.Disconnect_Event.session_handle;		break;	case Suspend_Event:		session_id = event->u.Suspend_Event.session_handle;		break;	case S_MethodInvoke_Res:		session_id = event->u.S_MethodInvoke_Res.session_id;		break;	case S_MethodResult_Req:		session_id = event->u.S_MethodResult_Req.session_id;		break;	case S_ConfirmedPush_Req:                session_id = event->u.S_ConfirmedPush_Req.session_id;	        break;        case S_Push_Req:                session_id = event->u.S_Push_Req.session_id;	        break;	default:		error(0, "WSP: Cannot find machine for %s event",			wap_event_name(event->type));	}		gw_assert(tuple != NULL || session_id != -1);	/* Pre-state-machine tests, according to 7.1.5.  After the tests,	 * caller will pass the event to sm if sm is not NULL. */	sm = NULL;	/* First test is for MRUEXCEEDED, and we don't have a MRU */	/* Second test is for class 2 TR-Invoke.ind with Connect PDU */	if (event->type == TR_Invoke_Ind &&	    event->u.TR_Invoke_Ind.tcl == 2 &&	    pdu->type == Connect) {			/* Create a new session, even if there is already			 * a session open for this address.  The new session			 * will take care of killing the old ones. */			sm = machine_create();			gw_assert(tuple != NULL);			sm->addr_tuple = wap_addr_tuple_duplicate(tuple);			sm->connect_handle = event->u.TR_Invoke_Ind.handle;	/* Third test is for class 2 TR-Invoke.ind with Resume PDU */	} else if (event->type == TR_Invoke_Ind &&		   event->u.TR_Invoke_Ind.tcl == 2 &&	  	   pdu->type == Resume) {		/* Pass to session identified by session id, not		 * the address tuple. */		session_id = pdu->u.Resume.sessionid;		sm = list_search(session_machines, &session_id,				find_by_session_id);		if (sm == NULL) {			/* No session; TR-Abort.req(DISCONNECT) */			send_abort(WSP_ABORT_DISCONNECT,				event->u.TR_Invoke_Ind.handle);		}	/* Fourth test is for a class 1 or 2 TR-Invoke.Ind with no	 * session for that address tuple.  We also handle class 0	 * TR-Invoke.ind here by ignoring them; this seems to be	 * an omission in the spec table. */	} else if (event->type == TR_Invoke_Ind) {		sm = list_search(session_machines, tuple,				 transaction_belongs_to_session);		if (sm == NULL && (event->u.TR_Invoke_Ind.tcl == 1 ||				event->u.TR_Invoke_Ind.tcl == 2)) {			send_abort(WSP_ABORT_DISCONNECT,				event->u.TR_Invoke_Ind.handle);		}	/* Other tests are for events not handled by the state tables;	 * do those later, after we've tried to handle them. */	} else {		if (session_id != -1) {			sm = list_search(session_machines, &session_id,				find_by_session_id);		} else {			sm = list_search(session_machines, tuple,				transaction_belongs_to_session);		}		/* The table doesn't really say what we should do with		 * non-Invoke events for which there is no session.  But		 * such a situation means there is an error _somewhere_		 * in the gateway. */		if (sm == NULL) {			error(0, "WSP: Cannot find session machine for event.");			wap_event_dump(event);		}	}	wap_addr_tuple_destroy(tuple);	return sm;}static void handle_session_event(WSPMachine *sm, WAPEvent *current_event, WSP_PDU *pdu) {	debug("wap.wsp", 0, "WSP: machine %p, state %s, event %s",		(void *) sm,		state_name(sm->state), 		wap_event_name(current_event->type));	#define STATE_NAME(name)	#define ROW(state_name, event, condition, action, next_state) \		{ \			struct event *e; \			e = &current_event->u.event; \			if (sm->state == state_name && \			   current_event->type == event && \			   (condition)) { \				action \				sm->state = next_state; \				debug("wap.wsp", 0, "WSP %ld: New state %s", \					sm->session_id, #next_state); \				goto end; \			} \		}	#include "wsp_server_session_states.def"		cant_handle_event(sm, current_event);end:	wap_event_destroy(current_event);	if (sm->state == NULL_SESSION)		machine_destroy(sm);}static void cant_handle_event(WSPMachine *sm, WAPEvent *event) {	/* We do the rest of the pre-state-machine tests here.  The first	 * four were done in find_session_machine().  The fifth is a	 * class 1 or 2 TR-Invoke.ind not handled by the state tables. */	if (event->type == TR_Invoke_Ind &&	    (event->u.TR_Invoke_Ind.tcl == 1 ||	     event->u.TR_Invoke_Ind.tcl == 2)) {		warning(0, "WSP: Can't handle TR-Invoke.ind, aborting transaction.");		debug("wap.wsp", 0, "WSP: The unhandled event:");		wap_event_dump(event);		send_abort(WSP_ABORT_PROTOERR,			event->u.TR_Invoke_Ind.handle);	/* The sixth is a class 0 TR-Invoke.ind not handled by state tables. */	} else if (event->type == TR_Invoke_Ind) {		warning(0, "WSP: Can't handle TR-Invoke.ind, ignoring.");		debug("wap.wsp", 0, "WSP: The ignored event:");		wap_event_dump(event);	/* The seventh is any other event not handled by state tables. */	} else {		error(0, "WSP: Can't handle event. Aborting session.");		debug("wap.wsp", 0, "WSP: The unhandled event:");		wap_event_dump(event);		/* TR-Abort.req(PROTOERR) if it is some other transaction		 * event than abort. */		/* Currently that means TR-Result.cnf, because we already		 * tested for Invoke. */		/* FIXME We need a better way to get at event values than		 * by hardcoding the types. */		if (event->type == TR_Result_Cnf) {			send_abort(WSP_ABORT_PROTOERR,				event->u.TR_Result_Cnf.handle);		}		/* Abort(PROTOERR) all method and push transactions */		abort_methods(sm, WSP_ABORT_PROTOERR);                abort_pushes(sm, WSP_ABORT_PROTOERR);		/* S-Disconnect.ind(PROTOERR) */		indicate_disconnect(sm, WSP_ABORT_PROTOERR);	}}static WSPMachine *machine_create(void) {	WSPMachine *p;		p = gw_malloc(sizeof(WSPMachine));	debug("wap.wsp", 0, "WSP: Created WSPMachine %p", (void *) p);		#define INTEGER(name) p->name = 0;	#define OCTSTR(name) p->name = NULL;	#define HTTPHEADERS(name) p->name = NULL;	#define ADDRTUPLE(name) p->name = NULL;	#define MACHINESLIST(name) p->name = list_create();	#define CAPABILITIES(name) p->name = NULL;	#define COOKIES(name) p->name = NULL;	#define REFERER(name) p->name = NULL;	#define MACHINE(fields) fields	#include "wsp_server_session_machine.def"		p->state = NULL_SESSION;	/* set capabilities to default values (defined in 1.1) */

⌨️ 快捷键说明

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