static void wtp_event_dump(Msg *msg) { WAPEvent *dgram; List *events; long i, n; dgram = wdp_msg2event(msg); if (dgram == NULL) error(0, "dgram is null"); /* pdu = wtp_pdu_unpack(dgram->u.T_DUnitdata_Ind.user_data); if (pdu == NULL) { error(0, "WTP PDU unpacking failed, WAP event is:"); wap_event_dump(dgram); } else { wtp_pdu_dump(pdu, 0); wtp_pdu_destroy(pdu); } */ events = wtp_unpack_wdp_datagram(dgram); n = gwlist_len(events); debug("wap.proxy",0,"datagram contains %ld events", n); i = 1; while (gwlist_len(events) > 0) { WAPEvent *event; event = gwlist_extract_first(events); info(0, "WTP: %ld/%ld event %s.", i, n, wap_event_name(event->type)); if (wtp_event_is_for_responder(event)) /* wtp_resp_dispatch_event(event); */ debug("",0,"datagram is for WTP responder"); else /* wtp_initiator_dispatch_event(event); */ debug("",0,"datagram is for WTP initiator"); wap_event_dump(event); /* switch (event->type) { RcvInvoke: debug("",0,"XXX invoke"); break; RcvResult: debug("",0,"XXX result"); break; default: error(0,"unkown WTP event type while unpacking"); break; } */ i++; } wap_event_destroy(dgram); gwlist_destroy(events, NULL); }
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 = ¤t_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); }
/* * Feed an event to a WSP push client state machine. Do not report errors to * the caller. */ static void push_client_event_handle(WSPPushClientMachine *cpm, WAPEvent *e) { WAPEvent *wtp_event; WSP_PDU *pdu = NULL; wap_event_assert(e); gw_assert(cpm); if (e->type == TR_Invoke_Ind) { pdu = wsp_pdu_unpack(e->u.TR_Invoke_Ind.user_data); /* * Class 1 tests here * Case 4, no session matching address quadruplet, handled by the session mach- * ine. * Tests from table WSP, page 45. Case 5, a PDU state tables cannot handle. */ if (pdu == NULL || pdu->type != ConfirmedPush) { wap_event_destroy(e); wtp_event = send_abort_to_responder(cpm, PROTOERR); wtp_resp_dispatch_event(wtp_event); return; } } debug("wap.wsp", 0, "WSP_PUSH: WSPPushClientMachine %ld, state %s," " event %s", cpm->client_push_id, name_push_client_state(cpm->state), wap_event_name(e->type)); #define PUSH_CLIENT_STATE_NAME(state) #define ROW(push_state, event_type, condition, action, next_state) \ if (cpm->state == push_state && \ e->type == event_type && \ (condition)) { \ action \ cpm->state = next_state; \ debug("wap.wsp", 0, "WSP_PUSH %ld: new state %s", \ cpm->client_push_id, #next_state); \ } else #include "wsp_push_client_states.def" { error(0, "WSP_PUSH: handle_event: unhandled event!"); debug("wap.wsp", 0, "Unhandled event was:"); wap_event_dump(e); wap_event_destroy(e); return; } wsp_pdu_destroy(pdu); wap_event_destroy(e); if (cpm->state == PUSH_CLIENT_NULL_STATE) push_client_machine_destroy(cpm); }
/* * This timer has elapsed. Do the housekeeping. We have its set locked. */ static void elapse_timer(Timer *timer) { gw_assert(timer != NULL); gw_assert(timers != NULL); /* This must be true because abort_elapsed is always called * before a timer is activated. */ gw_assert(timer->elapsed_event == NULL); debug("timers", 0, "%s elapsed.", wap_event_name(timer->event->type)); timer->elapsed_event = wap_event_duplicate(timer->event); gwlist_produce(timer->output, timer->elapsed_event); timer->elapses = -1; }
/* * Go back and remove this timer's elapse event from the output list, * to pretend that it didn't elapse after all. This is necessary * to deal with some races between the timer thread and the caller's * start/stop actions. */ static void abort_elapsed(Timer *timer) { long count; if (timer->elapsed_event == NULL) return; count = gwlist_delete_equal(timer->output, timer->elapsed_event); if (count > 0) { debug("timers", 0, "Aborting %s timer.", wap_event_name(timer->elapsed_event->type)); wap_event_destroy(timer->elapsed_event); } timer->elapsed_event = NULL; }
/* * 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, stateName(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) wap_event_destroy(event); if (wtls_machine->state == NULL_STATE) { wtls_machine_destroy(wtls_machine); wtls_machine = NULL; } }
/* 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 = ¤t_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); gwlist_delete_equal(sm->methodmachines, msm); } }
/* * Feed an event to a WTP initiator state machine. Handle all errors by do not * report them to the caller. WSP indication or conformation is handled by an * included state table. Note: Do not put {}s of the else block inside the * macro definition . */ static void handle_init_event(WTPInitMachine *init_machine, WAPEvent *event) { WAPEvent *wsp_event = NULL; debug("wap.wtp", 0, "WTP_INIT: initiator machine %ld, state %s," " event %s.", init_machine->mid, name_init_state(init_machine->state), wap_event_name(event->type)); #define INIT_STATE_NAME(state) #define ROW(init_state, event_type, condition, action, next_state) \ if (init_machine->state == init_state && \ event->type == event_type && \ (condition)) { \ action \ init_machine->state = next_state; \ debug("wap.wtp", 0, "WTP_INIT %ld: New state %s", \ init_machine->mid, #next_state); \ } else #include "wtp_init_states.def" { error(1, "WTP_INIT: handle_init_event: unhandled event!"); debug("wap.wtp.init", 0, "WTP_INIT: handle_init_event:" "Unhandled event was:"); wap_event_dump(event); wap_event_destroy(event); return; } if (event != NULL) { wap_event_destroy(event); } if (init_machine->state == INITIATOR_NULL_STATE) init_machine_destroy(init_machine); }
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); gwlist_delete_equal(sm->pushmachines, pm); } }
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 = gwlist_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 = gwlist_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 = gwlist_search(session_machines, &session_id, find_by_session_id); } else { sm = gwlist_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; }
/* * Checks client push machines list for a specific machine. Creates it, if the * event is TR-Invoke.ind. * Client push machine is identified (when searching) by transcation identifi- * er. * Note that only WTP responder send its class 1 messages to client push state * machine. So, it is no need to specify WTP machine type. */ static WSPPushClientMachine *push_client_machine_find_or_create(WAPEvent *e) { WSPPushClientMachine *cpm; long transid; cpm = NULL; transid = -1; switch (e->type) { case TR_Invoke_Ind: transid = e->u.TR_Invoke_Ind.handle; break; case S_ConfirmedPush_Res: transid = e->u.S_ConfirmedPush_Res.client_push_id; break; case S_PushAbort_Req: transid = e->u.S_PushAbort_Req.push_id; break; case Abort_Event: break; case TR_Abort_Ind: transid = e->u.TR_Abort_Ind.handle; break; default: debug("wap.wsp", 0, "WSP PUSH: push_client_find_or_create: unhandled" " event"); wap_event_dump(e); wap_event_destroy(e); return NULL; } gw_assert(transid != -1); cpm = push_client_machine_find_using_transid(transid); if (cpm == NULL) { switch (e->type) { case TR_Invoke_Ind: cpm = push_client_machine_create(transid); break; case S_ConfirmedPush_Res: case S_PushAbort_Req: error(0, "WSP_PUSH_CLIENT: POT primitive to a nonexisting" " push client machine"); break; case Abort_Event: error(0, "WSP_PUSH_CLIENT: internal abort to a nonexisting" " push client machine"); break; case TR_Abort_Ind: error(0, "WSP_PUSH_CLIENT: WTP abort to a nonexisting push client" " machine"); break; default: error(0, "WSP_PUSH_CLIENT: Cannot handle event type %s", wap_event_name(e->type)); break; } } return cpm; }