📄 wsp_session.c
字号:
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 = ¤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); 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 + -