wtls.c
资源名称:gateway-1.2.1 [点击查看]
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:19k
源码类别:
手机WAP编程
开发平台:
WINDOWS
- /*
- * wtls.c: WTLS server-side implementation
- *
- * Nick Clarey <nclarey@3glab.com>
- */
- #include "gwlib/gwlib.h"
- #if (HAVE_WTLS_OPENSSL)
- #include "wtls.h"
- #include "timers.h"
- #include "wap_events.h"
- #include "wtls_pdu.h"
- #include "wtls_statesupport.h"
- #include "gw/msg.h"
- #include "wtp.h"
- /***********************************************************************
- * Internal data structures.
- *
- * List of WTLS Server machines.
- */
- static List *wtls_machines = NULL;
- /*
- * Counter for WTLS Server machine id numbers, to make sure they are unique.
- */
- static Counter *wtls_machine_id_counter = NULL;
- /*
- * Give the status of wtls server layer:
- * limbo - not running at all
- * running - operating normally
- * terminating - waiting for operations to terminate, returning to limbo
- */
- static enum { limbo, running, terminating } wtls_run_status = limbo;
- /*
- * Queue of events to be handled by WTLS Server machines.
- */
- static List *wtls_queue = NULL;
- /*****************************************************************************
- *
- * Prototypes of internal functions:
- */
- /*
- * Create and destroy an uninitialized wtls server state machine.
- */
- static WTLSMachine* wtls_machine_create(WAPAddrTuple *tuple);
- static void wtls_machine_create_destroy(void *sm);
- static void wtls_machine_destroy(void * p);
- /*
- * Checks whether the list of wlts server machines includes a specific machine.
- *
- * The machine in question is identified with with source and destination
- * address and port. If the machine does not exist and the event is either;
- * - A SEC-Create-Request.req or
- * - A T-Unitdata.ind containing a ClientHello packet or
- * - A T-Unitdata.ind containing an Alert(no_renegotiation) packet
- * a new machine is created and added in the machines data structure.
- *
- * See WTLS 7.2 for details of this check.
- */
- static WTLSMachine *wtls_machine_find_or_create(WAPEvent *event);
- /*
- * Feed an event to a WTLS Server state machine. Handle all errors by
- * itself, do not report them to the caller.
- */
- static void wtls_event_handle(WTLSMachine *machine, WAPEvent *event);
- /*
- * Print a WTLS Server machine state as a string.
- */
- static unsigned char *name_wtlser_state(int name);
- /*
- * Find a WTLS Server machine from the global list of wtls server
- * structures that corresponds to the four-tuple of source and destination
- * addresses and ports. Return a pointer to the machine, or NULL if not found.
- */
- static WTLSMachine *wtls_machine_find(WAPAddrTuple *tuple, long mid);
- static void main_thread(void *);
- static WTLSMachine *find_wtls_machine_using_mid(long mid);
- static void add_wtls_address(Msg *msg, WTLSMachine *wtls_machine);
- /* The match* functions are used for searches through lists */
- static int match_handshake_type(void* item, void* pattern);
- static int match_pdu_type(void* item, void* pattern);
- /*static WAPEvent *create_tr_invoke_ind(WTPRespMachine *sm, Octstr *user_data);
- static WAPEvent *create_tr_abort_ind(WTPRespMachine *sm, long abort_reason);
- static WAPEvent *create_tr_result_cnf(WTPRespMachine *sm); */
- /******************************************************************************
- *
- * EXTERNAL FUNCTIONS:
- *
- */
- WAPEvent *wtls_unpack_wdp_datagram(Msg *msg)
- {
- WAPEvent* unitdataIndEvent;
- List* wtlsPayloadList;
- /* Dump the Msg */
- msg_dump(msg,0);
- /* Then, stuff it into a T_Unitdata_Ind Event */
- unitdataIndEvent = wap_event_create(T_Unitdata_Ind);
- info(0,"Event created");
- /* Firstly, the address */
- unitdataIndEvent->u.T_Unitdata_Ind.addr_tuple =
- wap_addr_tuple_create(msg->wdp_datagram.source_address,
- msg->wdp_datagram.source_port,
- msg->wdp_datagram.destination_address,
- msg->wdp_datagram.destination_port);
- info(0,"Set address and stuff");
- /* Attempt to stuff this baby into a list-of-WTLS-PDUs */
- wtlsPayloadList = wtls_unpack_payloadlist (msg->wdp_datagram.user_data);
- info(0,"Datagram unpacked!");
- /* Then, the pdu material */
- unitdataIndEvent->u.T_Unitdata_Ind.pdu_list = wtlsPayloadList;
- /* And return the event */
- return unitdataIndEvent;
- }
- void wtls_init(void) {
- /* Initialise our various lists and counters */
- wtls_machines = list_create();
- wtls_machine_id_counter = counter_create();
- wtls_queue = list_create();
- list_add_producer(wtls_queue);
- /* Idiot check - ensure that we are able to start running */
- gw_assert(wtls_run_status == limbo);
- wtls_run_status = running;
- gwthread_create(main_thread, NULL);
- }
- void wtls_shutdown(void) {
- /* Make sure that we're actually running; if so, then
- prepare for termination */
- gw_assert(wtls_run_status == running);
- wtls_run_status = terminating;
- list_remove_producer(wtls_queue);
- gwthread_join_every(main_thread);
- /* Print out a friendly message stating that we're going to die */
- debug("wap.wtls", 0, "wtls_shutdown: %ld wtls machines left",
- list_len(wtls_machines));
- /* And clean up nicely after ourselves */
- list_destroy(wtls_machines, wtls_machine_destroy);
- list_destroy(wtls_queue, wap_event_destroy_item);
- counter_destroy(wtls_machine_id_counter);
- }
- void wtls_dispatch_event(WAPEvent *event) {
- /* Stick the event on the incoming events queue */
- list_produce(wtls_queue, event);
- }
- int wtls_get_address_tuple(long mid, WAPAddrTuple **tuple) {
- WTLSMachine *sm;
- sm = find_wtls_machine_using_mid(mid);
- if (sm == NULL)
- return -1;
- *tuple = wap_addr_tuple_duplicate(sm->addr_tuple);
- return 0;
- }
- void send_alert(int alertLevel, int alertDescription, WTLSMachine* wtls_machine) {
- wtls_Payload* alertPayload;
- wtls_PDU* alertPDU;
- Octstr* packedAlert;
- Msg* msg = NULL;
- alertPDU = (wtls_PDU*) wtls_pdu_create(Alert_PDU);
- alertPDU->u.alert.level = alertLevel;
- alertPDU->u.alert.desc = alertDescription;
- /* Here's where we should get the current checksum from the wtls_machine */
- alertPDU->u.alert.chksum = 0;
- /* Pack the PDU */
- msg = msg_create(wdp_datagram);
- add_wtls_address(msg, wtls_machine);
- /* Pack the message */
- alertPayload = wtls_pdu_pack(alertPDU, wtls_machine);
- packedAlert = (Octstr*) wtls_payload_pack(alertPayload);
- msg->wdp_datagram.user_data = packedAlert;
- /* And destroy the structure */
- wtls_payload_destroy(alertPayload);
- alertPayload = NULL;
- /* Send it off */
- write_to_bearerbox(msg);
- }
- void clear_queuedpdus(WTLSMachine* wtls_machine)
- {
- }
- void add_pdu(WTLSMachine* wtls_machine, wtls_PDU* pduToAdd)
- {
- int currentLength;
- wtls_Payload* payloadToAdd;
- Octstr* packedPDU;
- /* Check to see if we've already allocated some memory for the list */
- if (wtls_machine->packet_to_send == NULL) {
- wtls_machine->packet_to_send = octstr_create("");
- }
- /* Pack and encrypt the pdu */
- payloadToAdd = wtls_pdu_pack(pduToAdd, wtls_machine);
- /* If the pdu is a Handshake pdu, append the Octstr to our wtls_machine's
- exchanged_handshakes Octstr */
- packedPDU = wtls_payload_pack(payloadToAdd);
- /* Add it to our list */
- currentLength = octstr_len(wtls_machine->packet_to_send);
- octstr_insert(wtls_machine->packet_to_send, packedPDU, currentLength);
- }
- /*
- * Send the pdu_to_send list to the destination specified by the address in the machine
- * structure. Don't return anything, handle all errors internally.
- */
- void send_queuedpdus(WTLSMachine* wtls_machine)
- {
- Msg* msg = NULL;
- gw_assert(wtls_machine->packet_to_send != NULL);
- /* Pack the PDU */
- msg = msg_create(wdp_datagram);
- add_wtls_address(msg, wtls_machine);
- msg->wdp_datagram.user_data = octstr_duplicate(wtls_machine->packet_to_send);
- /* Send it off */
- write_to_bearerbox(msg);
- /* Destroy our copy of the sent string */
- octstr_destroy(wtls_machine->packet_to_send);
- wtls_machine->packet_to_send = NULL;
- }
- /*
- * Add address from state machine.
- */
- void add_wtls_address(Msg *msg, WTLSMachine *wtls_machine){
- debug("wap.wtls", 0, "adding address");
- msg->wdp_datagram.source_address =
- octstr_duplicate(wtls_machine->addr_tuple->local->address);
- msg->wdp_datagram.source_port = wtls_machine->addr_tuple->local->port;
- msg->wdp_datagram.destination_address =
- octstr_duplicate(wtls_machine->addr_tuple->remote->address);
- msg->wdp_datagram.destination_port =
- wtls_machine->addr_tuple->remote->port;
- }
- /*****************************************************************************
- *
- * INTERNAL FUNCTIONS:
- *
- */
- static void main_thread(void *arg) {
- WTLSMachine *sm;
- WAPEvent *e;
- while (wtls_run_status == running &&
- (e = list_consume(wtls_queue)) != NULL) {
- sm = wtls_machine_find_or_create(e);
- if (sm == NULL)
- wap_event_destroy(e);
- else
- wtls_event_handle(sm, e);
- }
- }
- /*
- * Give the name of a WTLS Server state in a readable form.
- */
- static unsigned char *name_wtls_state(int s){
- switch (s){
- #define STATE_NAME(state) case state: return #state;
- #define ROW(state, event, condition, action, new_state)
- #include "wtls_state-decl.h"
- default:
- return "unknown state";
- }
- }
- /*
- * Feed an event to a WTP responder state machine. Handle all errors yourself,
- * do not report them to the caller. Note: Do not put {}s of the else block
- * inside the macro definition.
- */
- static void wtls_event_handle(WTLSMachine *wtls_machine, WAPEvent *event){
- debug("wap.wtls", 0, "WTLS: wtls_machine %ld, state %s, event %s.",
- wtls_machine->mid,
- name_wtls_state(wtls_machine->state),
- wap_event_name(event->type));
- /* for T_Unitdata_Ind PDUs */
- if(event->type == T_Unitdata_Ind) {
- /* if encryption: decrypt all pdus in the list */
- if( wtls_machine->encrypted ) {
- wtls_decrypt_pdu_list(wtls_machine, event->u.T_Unitdata_Ind.pdu_list);
- }
- /* add all handshake data to wtls_machine->handshake_data */
- //add_all_handshake_data(wtls_machine, event->u.T_Unitdata_Ind.pdu_list);
- }
- #define STATE_NAME(state)
- #define ROW(wtls_state, event_type, condition, action, next_state)
- if (wtls_machine->state == wtls_state &&
- event->type == event_type &&
- (condition)) {
- action
- wtls_machine->state = next_state;
- debug("wap.wtls", 0, "WTLS %ld: New state %s", wtls_machine->mid, #next_state);
- } else
- #include "wtls_state-decl.h"
- {
- error(0, "WTLS: handle_event: unhandled event!");
- debug("wap.wtls", 0, "WTLS: handle_event: Unhandled event was:");
- wap_event_destroy(event);
- return;
- }
- if (event != NULL) {
- wap_event_destroy(event);
- }
- if (wtls_machine->state == NULL_STATE)
- wtls_machine_destroy(wtls_machine);
- }
- /*
- * Checks whether wtls machines data structure includes a specific machine.
- * The machine in question is identified with with source and destination
- * address and port.
- */
- static WTLSMachine *wtls_machine_find_or_create(WAPEvent *event) {
- WTLSMachine *wtls_machine = NULL;
- long mid;
- WAPAddrTuple *tuple;
- tuple = NULL;
- mid = -1;
- debug("wap.wtls",0, "event->type = %d", event->type);
- /* Get the address that this PDU came in from */
- switch (event->type) {
- case T_Unitdata_Ind:
- case T_DUnitdata_Ind:
- tuple = event->u.T_Unitdata_Ind.addr_tuple;
- break;
- case SEC_Create_Request_Req:
- case SEC_Terminate_Req:
- case SEC_Exception_Req:
- case SEC_Create_Res:
- case SEC_Exchange_Req:
- case SEC_Commit_Req:
- case SEC_Unitdata_Req:
- tuple = event->u.T_Unitdata_Ind.addr_tuple;
- break;
- default:
- debug("wap.wtls", 0, "WTLS: wtls_machine_find_or_create:"
- "unhandled event (1)");
- wap_event_dump(event);
- return NULL;
- }
- /* Either the address or the machine id must be available at this point */
- gw_assert(tuple != NULL || mid != -1);
- /* Look for the machine owning this address */
- wtls_machine = wtls_machine_find(tuple, mid);
- /* Oh well, we didn't find one. We'll create one instead, provided
- it meets certain criteria */
- if (wtls_machine == NULL){
- switch (event->type){
- case SEC_Create_Request_Req:
- /* State NULL, case 1 */
- debug("wap.wtls",0,"WTLS: received a SEC_Create_Request_Req, and don't know what to do with it...");
- /* Create and dispatch a T_Unitdata_Req containing a HelloRequest */
- /* And there's no need to do anything else, 'cause we return to state NULL */
- break;
- case T_Unitdata_Ind:
- case T_DUnitdata_Ind:
- /* State NULL, case 3 */
- /* if (wtls_event_type(event) == Alert_No_Renegotiation) { */
- /* Create and dispatch a SEC_Exception_Ind event */
- /* debug("wap.wtls",0,"WTLS: received an Alert_no_Renegotiation; just dropped it."); */
- /* And there's no need to do anything else, 'cause we return to state NULL */
- /* break; */
- /* } else */
- /* if (event->u.T_Unitdata_Ind == ClientHello) { */
- /* State NULL, case 2 */
- wtls_machine = wtls_machine_create(tuple);
- /* And stick said event into machine, which should push us into state
- CREATING after a SEC_Create_Ind */
- /* } */
- break;
- default:
- error(0, "WTLS: wtls_machine_find_or_create:"
- " unhandled event (2)");
- wap_event_dump(event);
- break;
- }
- }
- return wtls_machine;
- }
- static int is_wanted_wtls_machine(void *a, void *b) {
- machine_pattern *pat;
- WTLSMachine *m;
- m = a;
- pat = b;
- if (m->mid == pat->mid)
- return 1;
- if (pat->mid != -1)
- return 0;
- return wap_addr_tuple_same(m->addr_tuple, pat->tuple);
- }
- static WTLSMachine *wtls_machine_find(WAPAddrTuple *tuple,
- long mid) {
- machine_pattern pat;
- WTLSMachine *m;
- pat.tuple = tuple;
- pat.mid = mid;
- m = list_search(wtls_machines, &pat, is_wanted_wtls_machine);
- return m;
- }
- static WTLSMachine *wtls_machine_create(WAPAddrTuple *tuple) {
- WTLSMachine *wtls_machine;
- wtls_machine = gw_malloc(sizeof(WTLSMachine));
- #define MACHINE(field) field
- #define ENUM(name) wtls_machine->name = NULL_STATE;
- #define ADDRTUPLE(name) wtls_machine->name = NULL;
- #define INTEGER(name) wtls_machine->name = 0;
- #define OCTSTR(name) wtls_machine->name = NULL;
- #define PDULIST(name) wtls_machine->name = NULL;
- #include "wtls_machine-decl.h"
- list_append(wtls_machines, wtls_machine);
- wtls_machine->mid = counter_increase(wtls_machine_id_counter);
- wtls_machine->addr_tuple = wap_addr_tuple_duplicate(tuple);
- wtls_machine->handshake_data = octstr_create("");
- debug("wap.wtls", 0, "WTLS: Created WTLSMachine %p (%ld)",
- (void *) wtls_machine, wtls_machine->mid);
- return wtls_machine;
- }
- /*
- * Destroys a WTLSMachine. Assumes it is safe to do so. Assumes it has
- * already been deleted from the machines list.
- */
- static void wtls_machine_destroy(void * p) {
- WTLSMachine *wtls_machine;
- wtls_machine = p;
- debug("wap.wtls", 0, "WTLS: Destroying WTLSMachine %p (%ld)",
- (void *) wtls_machine, wtls_machine->mid);
- list_delete_equal(wtls_machines, wtls_machine);
- #define MACHINE(field) field
- #define ENUM(name) wtls_machine->name = NULL_STATE;
- #define ADDRTUPLE(name) wap_addr_tuple_destroy(wtls_machine->name);
- #define INTEGER(name) wtls_machine->name = 0;
- #define OCTSTR(name) octstr_destroy(wtls_machine->name);
- #define PDULIST(name) wtls_machine->name = NULL;
- #include "wtls_machine-decl.h"
- gw_free(wtls_machine);
- }
- /*
- * Create a TR-Invoke.ind event.
- static WAPEvent *create_tr_invoke_ind(WTPRespMachine *sm, Octstr *user_data) {
- WAPEvent *event;
- event = wap_event_create(TR_Invoke_Ind);
- event->u.TR_Invoke_Ind.ack_type = sm->u_ack;
- event->u.TR_Invoke_Ind.user_data = octstr_duplicate(user_data);
- event->u.TR_Invoke_Ind.tcl = sm->tcl;
- event->u.TR_Invoke_Ind.addr_tuple =
- wap_addr_tuple_duplicate(sm->addr_tuple);
- event->u.TR_Invoke_Ind.handle = sm->mid;
- return event;
- }
- */
- /*
- * Create a TR-Result.cnf event.
- static WAPEvent *create_tr_result_cnf(WTPRespMachine *sm) {
- WAPEvent *event;
- event = wap_event_create(TR_Result_Cnf);
- event->u.TR_Result_Cnf.addr_tuple =
- wap_addr_tuple_duplicate(sm->addr_tuple);
- event->u.TR_Result_Cnf.handle = sm->mid;
- return event;
- }
- */
- /*
- * Creates TR-Abort.ind event from a responder state machine.
- static WAPEvent *create_tr_abort_ind(WTPRespMachine *sm, long abort_reason) {
- WAPEvent *event;
- event = wap_event_create(TR_Abort_Ind);
- event->u.TR_Abort_Ind.abort_code = abort_reason;
- event->u.TR_Abort_Ind.addr_tuple =
- wap_addr_tuple_duplicate(sm->addr_tuple);
- event->u.TR_Abort_Ind.handle = sm->mid;
- return event;
- }
- */
- static int wtls_machine_has_mid(void *a, void *b) {
- WTLSMachine *sm;
- long mid;
- sm = a;
- mid = *(long *) b;
- return sm->mid == mid;
- }
- static WTLSMachine *find_wtls_machine_using_mid(long mid) {
- return list_search(wtls_machines, &mid, wtls_machine_has_mid);
- }
- /* Used for list searches */
- static int match_handshake_type(void* item, void* pattern)
- {
- wtls_Payload* matchingPayload;
- int type;
- int retrievedType;
- matchingPayload = (wtls_Payload*) item;
- type = (int) pattern;
- retrievedType = octstr_get_char(matchingPayload->data, 0);
- if (matchingPayload->type == Handshake_PDU && retrievedType == type)
- {
- return 1;
- }
- else
- {
- return 0;
- }
- }
- static int match_pdu_type(void* item, void* pattern)
- {
- wtls_Payload* matchingPayload;
- int type;
- matchingPayload = (wtls_Payload*) item;
- type = (int) pattern;
- if (matchingPayload->type == type)
- {
- return 1;
- }
- else
- {
- return 0;
- }
- }
- #endif