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

📄 wsp_session.c

📁 The Kannel Open Source WAP and SMS gateway works as both an SMS gateway, for implementing keyword b
💻 C
📖 第 1 页 / 共 3 页
字号:
	p->client_SDU_size = 1400;	p->MOR_push = 1;		/* Insert new machine at the _front_, because 1) it's more likely	 * to get events than old machines are, so this speeds up the linear	 * search, and 2) we want the newest machine to get any method	 * invokes that come through before the Connect is established. */	list_insert(session_machines, 0, p);	return p;}static void destroy_methodmachines(List *machines) {	if (list_len(machines) > 0) {		warning(0, "Destroying WSP session with %ld active methods\n",			list_len(machines));	}	list_destroy(machines, method_machine_destroy);}static void destroy_pushmachines(List *machines) {	if (list_len(machines) > 0) {		warning(0, "Destroying WSP session with %ld active pushes\n",			list_len(machines));	}	list_destroy(machines, push_machine_destroy);}static void machine_destroy(void *pp) {	WSPMachine *p;		p = pp;	debug("wap.wsp", 0, "Destroying WSPMachine %p", pp);	list_delete_equal(session_machines, p);	#define INTEGER(name) p->name = 0;	#define OCTSTR(name) octstr_destroy(p->name);	#define HTTPHEADERS(name) http_destroy_headers(p->name);	#define ADDRTUPLE(name) wap_addr_tuple_destroy(p->name);	#define MACHINESLIST(name) destroy_##name(p->name);	#define CAPABILITIES(name) wsp_cap_destroy_list(p->name);	#define COOKIES(name) cookies_destroy(p->name);	#define REFERER(name) octstr_destroy(p->name);	#define MACHINE(fields) fields	#include "wsp_server_session_machine.def"	gw_free(p);}struct msm_pattern {	WAPAddrTuple *addr_tuple;	long msmid, tid;};/* This function does NOT consume its event; it leaves that task up * to the parent session */static void handle_method_event(WSPMachine *sm, WSPMethodMachine *msm, WAPEvent *current_event, WSP_PDU *pdu) {	if (msm == NULL) {		warning(0, "No method machine for event.");		wap_event_dump(current_event);		return;	}			debug("wap.wsp", 0, "WSP: method %ld, state %s, event %s",		msm->transaction_id, state_name(msm->state), 		wap_event_name(current_event->type));	gw_assert(sm->session_id == msm->session_id);	#define STATE_NAME(name)	#define ROW(state_name, event, condition, action, next_state) \		{ \			struct event *e; \			e = &current_event->u.event; \			if (msm->state == state_name && \			   current_event->type == event && \			   (condition)) { \				action \				msm->state = next_state; \				debug("wap.wsp", 0, "WSP %ld/%ld: New method state %s", \					msm->session_id, msm->transaction_id, #next_state); \				goto end; \			} \		}	#include "wsp_server_method_states.def"		cant_handle_event(sm, current_event);end:	if (msm->state == NULL_METHOD) {		method_machine_destroy(msm);		list_delete_equal(sm->methodmachines, msm);	}}static WSPMethodMachine *method_machine_create(WSPMachine *sm,			long wtp_handle) {	WSPMethodMachine *msm;		msm = gw_malloc(sizeof(*msm));		#define INTEGER(name) msm->name = 0;	#define ADDRTUPLE(name) msm->name = NULL;	#define EVENT(name) msm->name = NULL;	#define MACHINE(fields) fields	#include "wsp_server_method_machine.def"		msm->transaction_id = wtp_handle;	msm->state = NULL_METHOD;	msm->addr_tuple = wap_addr_tuple_duplicate(sm->addr_tuple);	msm->session_id = sm->session_id;	list_append(sm->methodmachines, msm);	return msm;}static void method_machine_destroy(void *p) {	WSPMethodMachine *msm;	if (p == NULL)		return;	msm = p;	debug("wap.wsp", 0, "Destroying WSPMethodMachine %ld",			msm->transaction_id);	#define INTEGER(name)	#define ADDRTUPLE(name) wap_addr_tuple_destroy(msm->name);	#define EVENT(name) wap_event_destroy(msm->name);	#define MACHINE(fields) fields	#include "wsp_server_method_machine.def"	gw_free(msm);}static void handle_push_event(WSPMachine *sm, WSPPushMachine *pm,                               WAPEvent *current_event){        if (pm == NULL) {		warning(0, "No push machine for event.");		wap_event_dump(current_event);		return;	}        debug("wap.wsp", 0, "WSP(tid/pid): push %ld/%ld, state %s, event %s",		pm->transaction_id, pm->server_push_id, state_name(pm->state), 		wap_event_name(current_event->type));	gw_assert(sm->session_id == pm->session_id);        #define STATE_NAME(name)	#define ROW(state_name, event, condition, action, next_state) \		{ \		    if (pm->state == state_name && \			current_event->type == event && \			(condition)) { \			     action \			     pm->state = next_state; \			     debug("wap.wsp", 0, "WSP %ld/%ld: New push state %s", \			           pm->session_id, pm->transaction_id, #next_state); \				goto end; \			} \		}	#include "wsp_server_push_states.def"        cant_handle_event(sm, current_event);end:        if (pm->state == SERVER_PUSH_NULL_STATE) {		push_machine_destroy(pm);		list_delete_equal(sm->pushmachines, pm);	}}static WSPPushMachine *push_machine_create(WSPMachine *sm,         long pid){        WSPPushMachine *m;        m = gw_malloc(sizeof(WSPPushMachine));        #define INTEGER(name) m->name = 0;        #define ADDRTUPLE(name) m->name = NULL;        #define HTTPHEADER(name) m->name = http_create_empty_headers();        #define MACHINE(fields) fields        #include "wsp_server_push_machine.def"        m->server_push_id = pid;        m->transaction_id = pid;	m->state = SERVER_PUSH_NULL_STATE;	m->addr_tuple = wap_addr_tuple_duplicate(sm->addr_tuple);	m->session_id = sm->session_id;	list_append(sm->pushmachines, m);	return m;      }static void push_machine_destroy(void *p){        WSPPushMachine *m = NULL;   	if (p == NULL)	       return;          m = p;        debug("wap.wsp", 0, "Destroying WSPPushMachine %ld",			m->transaction_id);        #define INTEGER(name)         #define ADDRTUPLE(name) wap_addr_tuple_destroy(m->name);        #define HTTPHEADER(name) http_destroy_headers(m->name);        #define MACHINE(fields) fields        #include "wsp_server_push_machine.def"        gw_free(m);}static char *state_name(WSPState state) {	switch (state) {	#define STATE_NAME(name) case name: return #name;	#define ROW(state, event, cond, stmt, next_state)	#include "wsp_server_session_states.def"	#define STATE_NAME(name) case name: return #name;	#define ROW(state, event, cond, stmt, next_state)	#include "wsp_server_method_states.def"        #define STATE_NAME(name) case name: return #name;        #define ROW(state, event, cond, stmt, next_state)        #include "wsp_server_push_states.def"	default:		return "unknown wsp state";	}}static unsigned long next_wsp_session_id(void) {	return counter_increase(session_id_counter);}static void sanitize_capabilities(List *caps, WSPMachine *m) {	long i;	Capability *cap;	unsigned long ui;	for (i = 0; i < list_len(caps); i++) {		cap = list_get(caps, i);		/* We only know numbered capabilities.  Let the application		 * layer negotiate whatever it wants for unknown ones. */		if (cap->name != NULL)			continue;		switch (cap->id) {		case WSP_CAPS_CLIENT_SDU_SIZE:			/* Check if it's a valid uintvar.  The value is the			 * max SDU size we will send, and there's no			 * internal limit to that, so accept any value. */			if (cap->data != NULL &&			    octstr_extract_uintvar(cap->data, &ui, 0) < 0)				goto bad_cap;			else				m->client_SDU_size = ui;			break;		case WSP_CAPS_SERVER_SDU_SIZE:			/* Check if it's a valid uintvar */			if (cap->data != NULL &&			    (octstr_extract_uintvar(cap->data, &ui, 0) < 0))				goto bad_cap;			/* XXX Our MRU is not quite unlimited, since we			 * use signed longs in the library functions --			 * should we make sure we limit the reply value			 * to LONG_MAX?  (That's already a 2GB packet) */			break;		case WSP_CAPS_PROTOCOL_OPTIONS:			/* Currently we don't support any Push, nor			 * session resume, nor acknowledgement headers,			 * so make sure those bits are not set. */			if (cap->data != NULL && octstr_len(cap->data) > 0			   && (octstr_get_char(cap->data, 0) & 0xf0) != 0) {				warning(0, "WSP: Application layer tried to "					"negotiate protocol options.");				octstr_set_bits(cap->data, 0, 4, 0);			}			break;		case WSP_CAPS_EXTENDED_METHODS:			/* XXX Check format here */			break;				case WSP_CAPS_HEADER_CODE_PAGES:			/* We don't support any yet, so don't let this			 * be negotiated. */			if (cap->data)				goto bad_cap;			break;		}		continue;	bad_cap:		error(0, "WSP: Found illegal value in capabilities reply.");		wsp_cap_dump(cap);		list_delete(caps, i, 1);		i--;		wsp_cap_destroy(cap);		continue;	}}static void reply_known_capabilities(List *caps, List *req, WSPMachine *m) {	unsigned long ui;	Capability *cap;	Octstr *data;	if (wsp_cap_count(caps, WSP_CAPS_CLIENT_SDU_SIZE, NULL) == 0) {		if (wsp_cap_get_client_sdu(req, &ui) > 0) {			/* Accept value if it is not silly. */			if ((ui >= 256 && ui < LONG_MAX) || ui == 0) {				m->client_SDU_size = ui;			}		}		/* Reply with the client SDU we decided on */		data = octstr_create("");		octstr_append_uintvar(data, m->client_SDU_size);		cap = wsp_cap_create(WSP_CAPS_CLIENT_SDU_SIZE,			NULL, data);		list_append(caps, cap);	}	if (wsp_cap_count(caps, WSP_CAPS_SERVER_SDU_SIZE, NULL) == 0) {		/* Accept whatever size the client is willing		 * to send.  If the client did not specify anything,		 * then use the default. */		if (wsp_cap_get_server_sdu(req, &ui) <= 0) {			ui = 1400;		}		data = octstr_create("");		octstr_append_uintvar(data, ui);		cap = wsp_cap_create(WSP_CAPS_SERVER_SDU_SIZE, NULL, data);		list_append(caps, cap);	}	/* Currently we cannot handle any protocol options */	if (wsp_cap_count(caps, WSP_CAPS_PROTOCOL_OPTIONS, NULL) == 0) {		data = octstr_create("");		octstr_append_char(data, 0);		cap = wsp_cap_create(WSP_CAPS_PROTOCOL_OPTIONS, NULL, data);		list_append(caps, cap);	}	/* Accept any Method-MOR the client sent; if it sent none,	 * use the default. */	if (wsp_cap_count(caps, WSP_CAPS_METHOD_MOR, NULL) == 0) {		if (wsp_cap_get_method_mor(req, &ui) <= 0) {			ui = 1;		}		data = octstr_create("");		octstr_append_char(data, ui);		cap = wsp_cap_create(WSP_CAPS_METHOD_MOR, NULL, data);		list_append(caps, cap);	}	/* We will never send any Push requests because we don't support	 * that yet.  But we already specified that in protocol options;	 * so, pretend we do, and handle the value that way. */	if (wsp_cap_count(caps, WSP_CAPS_PUSH_MOR, NULL) == 0) {		if (wsp_cap_get_push_mor(req, &ui) > 0) {			m->MOR_push = ui;		}		data = octstr_create("");		octstr_append_char(data, m->MOR_push);		cap = wsp_cap_create(WSP_CAPS_PUSH_MOR, NULL, data);		list_append(caps, cap);	}	/* Supporting extended methods is up to the application layer,	 * not up to us.  If the application layer didn't specify any,	 * then we refuse whatever the client requested.  The default	 * is to support none, so we don't really have to add anything here. */	/* We do not support any header code pages.  sanitize_capabilities	 * must have already deleted any reply that indicates otherwise.	 * Again, not adding anything here is the same as refusing support. */	/* Listing aliases is something the application layer can do if	 * it wants to.  We don't care. */}/* Generate a refusal for all requested capabilities that are not * replied to. */static void refuse_unreplied_capabilities(List *caps, List *req) {	long i, len;	Capability *cap;	len = list_len(req);	for (i = 0; i < len; i++) {		cap = list_get(req, i);		if (wsp_cap_count(caps, cap->id, cap->name) == 0) {			cap = wsp_cap_create(cap->id, cap->name, NULL);			list_append(caps, cap);		}	}}static int is_default_cap(Capability *cap) {	unsigned long ui;	/* All unknown values are empty by default */	if (cap->name != NULL || cap->id < 0 || cap->id >= WSP_NUM_CAPS)		return cap->data == NULL || octstr_len(cap->data) == 0;	switch (cap->id) {	case WSP_CAPS_CLIENT_SDU_SIZE:	case WSP_CAPS_SERVER_SDU_SIZE:		return (cap->data != NULL &&		    octstr_extract_uintvar(cap->data, &ui, 0) >= 0 &&		    ui == 1400);	case WSP_CAPS_PROTOCOL_OPTIONS:		return cap->data != NULL && octstr_get_char(cap->data, 0) == 0;	case WSP_CAPS_METHOD_MOR:	case WSP_CAPS_PUSH_MOR:		return cap->data != NULL && octstr_get_char(cap->data, 0) == 1;	case WSP_CAPS_EXTENDED_METHODS:	case WSP_CAPS_HEADER_CODE_PAGES:	case WSP_CAPS_ALIASES:		return cap->data == NULL || octstr_len(cap->data) == 0;	default:		return 0;	}}/* Remove any replies that have no corresponding request and that * are equal to the default. */static void strip_default_capabilities(List *caps, List *req) {	long i;	Capability *cap;	int count;	/* Hmm, this is an O(N*N) operation, which may be bad. */	i = 0;	while (i < list_len(caps)) {		cap = list_get(caps, i);		count = wsp_cap_count(req, cap->id, cap->name);		if (count == 0 && is_default_cap(cap)) {			list_delete(caps, i, 1);			wsp_cap_destroy(cap);		} else {			i++;		}	}}static List *make_capabilities_reply(WSPMachine *m) {	List *caps;	/* In principle, copy the application layer's capabilities	 * response, add refusals for all unknown requested capabilities,	 * and add responses for all known capabilities that are	 * not already responded to.  Then eliminate any replies that 	 * would have no effect because they are equal to the default. */	caps = wsp_cap_duplicate_list(m->reply_caps);	/* Don't let the application layer negotiate anything we	 * cannot handle.  Also parse the values it set if we're	 * interested. */	sanitize_capabilities(caps, m);	/* Add capability records for all capabilities we know about	 * that are not already in the reply list. */	reply_known_capabilities(caps, m->request_caps, m);	/* All remaining capabilities in the request list that are	 * not in the reply list at this point must be unknown ones	 * that we want to refuse. */	refuse_unreplied_capabilities(caps, m->request_caps);	/* Now eliminate replies that would be equal to the requested	 * value, or (if there was none) to the default value. */	strip_default_capabilities(caps, m->request_caps);

⌨️ 快捷键说明

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