📄 wap-appl.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. */ /* * gw/wap-appl.c - wapbox application layer and push ota indication, response * and confirmation primitive implementation. * * This module implements indication and confirmation primitives of WAP-189- * PushOTA-20000217-a (hereafter called ota). * In addition, WAP-200-WDP-20001212-a (wdp) is referred. * Wapbox application layer is not a Wapforum protocol. * * The application layer is reads events from its event queue, fetches the * corresponding URLs and feeds back events to the WSP layer (pull). * * In addition, the layer forwards WSP events related to push to the module * wap_push_ppg and wsp, implementing indications, responses and confirma- * tions of ota. * * Note that push header encoding and decoding are divided two parts: * first decoding and encoding numeric values and then packing these values * into WSP format and unpacking them from WSP format. This module contains * encoding part. * * Lars Wirzenius */#include <string.h>#include "gwlib/gwlib.h"#include "wmlscript/ws.h"#include "xml_shared.h"#include "wml_compiler.h"#include "mime_decompiler.h"#include "wap/wap.h"#include "wap-appl.h"#include "wap_push_ppg.h"#include "wap/wsp_strings.h"#include "wap/wsp_caps.h"#include "wap/wsp.h"#ifdef ENABLE_COOKIES#include "wap/cookies.h"#endif#include "radius/radius_acct.h"#include "wap-error.h"#include "wap-maps.h"#define ENABLE_NOT_ACCEPTED /* * 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;/* * The queue of incoming events. */static List *queue = NULL;/* * HTTP caller identifier for application layer. */static HTTPCaller *caller = NULL;/* * Number of currently running HTTP fetching threads. */static Counter *fetches = NULL;/* * Charsets supported by WML compiler, queried from wml_compiler. */static List *charsets = NULL;struct content { Octstr *body; Octstr *type; Octstr *charset; Octstr *url; Octstr *version;};/* * A mapping from HTTP request identifiers to information about the request. */struct request_data { long client_SDU_size; WAPEvent *event; long session_id; Octstr *method; Octstr *url; long x_wap_tod; List *request_headers;};/* * WSP smart error messaging */extern int wsp_smart_errors;extern Octstr *device_home;/* * Defines if PPG is running in wapbox instance */static int have_ppg = 0;/* * Private functions. */static void main_thread(void *);static void start_fetch(WAPEvent *);static void return_replies_thread(void *);static void dev_null(const char *data, size_t len, void *context);static Octstr *convert_wml_to_wmlc(struct content *content);static Octstr *convert_wmlscript_to_wmlscriptc(struct content *content);/* DAVI: To-Do static Octstr *convert_multipart_mixed(struct content *content); */static Octstr *deconvert_multipart_formdata(struct content *content);/* DAVI: To-Do static Octstr *deconvert_mms_message(struct content *content); */static List *negotiate_capabilities(List *req_caps);static struct { char *type; char *result_type; Octstr *(*convert)(struct content *);} converters[] = { { "text/vnd.wap.wml", "application/vnd.wap.wmlc", convert_wml_to_wmlc }, { "text/vnd.wap.wmlscript", "application/vnd.wap.wmlscriptc", convert_wmlscript_to_wmlscriptc },/* DAVI: To-Do { "multipart/mixed", "application/vnd.wap.multipart.mixed", convert_multipart_mixed }, */};#define NUM_CONVERTERS ((long)(sizeof(converters) / sizeof(converters[0])))static struct { char *type; char *result_type; Octstr *(*deconvert)(struct content *);} deconverters[] = { { "application/vnd.wap.multipart.form-data", "multipart/form-data; boundary=kannel_boundary", deconvert_multipart_formdata },/* DAVI: To-Do { "application/vnd.wap.mms-message", "multipart/related; type=application/smil; boundary=kannel_boundary; start=<t0>", deconvert_mms_message },*/};#define NUM_DECONVERTERS ((long)(sizeof(deconverters) / sizeof(deconverters[0])))/* * Following functions implement indications and conformations part of Push * OTA protocol. */static void indicate_push_connection(WAPEvent *e);static void indicate_push_disconnect(WAPEvent *e);static void indicate_push_suspend(WAPEvent *e);static void indicate_push_resume(WAPEvent *e);static void confirm_push(WAPEvent *e);static void indicate_push_abort(WAPEvent *e);static void split_header_list(List **headers, List **new_headers, char *name);static void check_application_headers(List **headers, List **app_headers);static void decode_bearer_indication(List **headers, List **bearer_headers);static void response_push_connection(WAPEvent *e);/*********************************************************************** * The public interface to the application layer. */void wap_appl_init(Cfg *cfg) { gw_assert(run_status == limbo); queue = list_create(); fetches = counter_create(); list_add_producer(queue); run_status = running; charsets = wml_charsets(); caller = http_caller_create(); gwthread_create(main_thread, NULL); gwthread_create(return_replies_thread, NULL); if (cfg != NULL) have_ppg = 1; else have_ppg = 0;}void wap_appl_shutdown(void) { gw_assert(run_status == running); run_status = terminating; list_remove_producer(queue); gwthread_join_every(main_thread); http_caller_signal_shutdown(caller); gwthread_join_every(return_replies_thread); wap_map_destroy(); wap_map_user_destroy(); http_caller_destroy(caller); list_destroy(queue, wap_event_destroy_item); list_destroy(charsets, octstr_destroy_item); counter_destroy(fetches);}void wap_appl_dispatch(WAPEvent *event) { gw_assert(run_status == running); list_produce(queue, event);}long wap_appl_get_load(void) { gw_assert(run_status == running); return counter_value(fetches) + list_len(queue);}/*********************************************************************** * Private functions. *//* * When we have a push event, create ota indication or confirmation and send * it to ppg module. * Because Accept-Application and Bearer-Indication are optional, we cannot * rely on them. We must ask ppg main module do we have an open push session * for this initiator. Push is identified by push id. * If there is no ppg configured, do not refer to ppg's sessions' list. */static void main_thread(void *arg) { WAPEvent *ind, *res; long sid; WAPAddrTuple *tuple; while (run_status == running && (ind = list_consume(queue)) != NULL) { switch (ind->type) { case S_MethodInvoke_Ind: res = wap_event_create(S_MethodInvoke_Res); res->u.S_MethodInvoke_Res.server_transaction_id = ind->u.S_MethodInvoke_Ind.server_transaction_id; res->u.S_MethodInvoke_Res.session_id = ind->u.S_MethodInvoke_Ind.session_id; wsp_session_dispatch_event(res); start_fetch(ind); break; case S_Unit_MethodInvoke_Ind: start_fetch(ind); break; case S_Connect_Ind: tuple = ind->u.S_Connect_Ind.addr_tuple; if (have_ppg && wap_push_ppg_have_push_session_for(tuple)) { indicate_push_connection(ind); } else { res = wap_event_create(S_Connect_Res); /* FIXME: Not yet used by WSP layer */ res->u.S_Connect_Res.server_headers = NULL; res->u.S_Connect_Res.negotiated_capabilities = negotiate_capabilities(ind->u.S_Connect_Ind.requested_capabilities); res->u.S_Connect_Res.session_id = ind->u.S_Connect_Ind.session_id; wsp_session_dispatch_event(res); } wap_event_destroy(ind); break; case S_Disconnect_Ind: sid = ind->u.S_Disconnect_Ind.session_handle; if (have_ppg && wap_push_ppg_have_push_session_for_sid(sid)) indicate_push_disconnect(ind); wap_event_destroy(ind); break; case S_Suspend_Ind: sid = ind->u.S_Suspend_Ind.session_id; if (wap_push_ppg_have_push_session_for_sid(sid)) indicate_push_suspend(ind); wap_event_destroy(ind); break; case S_Resume_Ind: sid = ind->u.S_Resume_Ind.session_id; if (have_ppg && wap_push_ppg_have_push_session_for_sid(sid)) { indicate_push_resume(ind); } else { res = wap_event_create(S_Resume_Res); res->u.S_Resume_Res.server_headers = NULL; res->u.S_Resume_Res.session_id = ind->u.S_Resume_Ind.session_id; wsp_session_dispatch_event(res); } wap_event_destroy(ind); break; case S_MethodResult_Cnf: wap_event_destroy(ind); break; case S_ConfirmedPush_Cnf: confirm_push(ind); wap_event_destroy(ind); break; case S_MethodAbort_Ind: /* XXX Interrupt the fetch thread somehow */ wap_event_destroy(ind); break; case S_PushAbort_Ind: indicate_push_abort(ind); wap_event_destroy(ind); break; case Pom_Connect_Res: response_push_connection(ind); wap_event_destroy(ind); break; default: panic(0, "WAP-APPL: Can't handle %s event", wap_event_name(ind->type)); break; } /* switch */ } /* while */}/* * Tries to convert or compile a specific content-type to * it's complementing one. It does not convert if the client has explicitely * told us via Accept: header that a specific type is supported. * Returns 1 if an convertion has been successfull, * -1 if an convertion failed and 0 if no convertion routine * was maching this content-type */static int convert_content(struct content *content, List *request_headers, int allow_empty) { Octstr *new_body; int failed = 0; int i; for (i = 0; i < NUM_CONVERTERS; i++) { if (octstr_str_compare(content->type, converters[i].type) == 0 && !http_type_accepted(request_headers, octstr_get_cstr(content->type))) { debug("wap.convert",0,"WSP: Converting from <%s> to <%s>", octstr_get_cstr(content->type), converters[i].result_type); /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -