00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065 #include <string.h>
00066 #include <limits.h>
00067
00068 #include "gwlib/gwlib.h"
00069 #include "wsp.h"
00070 #include "wsp_pdu.h"
00071 #include "wsp_headers.h"
00072 #include "wsp_caps.h"
00073 #include "wsp_strings.h"
00074 #include "cookies.h"
00075 #include "wap.h"
00076 #include "wtp.h"
00077
00078
00079 typedef enum {
00080 #define STATE_NAME(name) name,
00081 #define ROW(state, event, condition, action, next_state)
00082 #include "wsp_server_session_states.def"
00083
00084 #define STATE_NAME(name) name,
00085 #define ROW(state, event, condition, action, next_state)
00086 #include "wsp_server_method_states.def"
00087
00088 #define STATE_NAME(name) name,
00089 #define ROW(state, event, condition, action, next_state)
00090 #include "wsp_server_push_states.def"
00091
00092 WSPState_count
00093 } WSPState;
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106 static enum { limbo, running, terminating } run_status = limbo;
00107
00108 static wap_dispatch_func_t *dispatch_to_wtp_resp;
00109 static wap_dispatch_func_t *dispatch_to_wtp_init;
00110 static wap_dispatch_func_t *dispatch_to_appl;
00111 static wap_dispatch_func_t *dispatch_to_ota;
00112
00113
00114
00115
00116
00117
00118
00119
00120 static int resume_enabled = 1;
00121
00122 static List *queue = NULL;
00123 static List *session_machines = NULL;
00124 static Counter *session_id_counter = NULL;
00125
00126
00127 static WSPMachine *find_session_machine(WAPEvent *event, WSP_PDU *pdu);
00128 static void handle_session_event(WSPMachine *machine, WAPEvent *event,
00129 WSP_PDU *pdu);
00130 static WSPMachine *machine_create(void);
00131 static void machine_destroy(void *p);
00132
00133 static void handle_method_event(WSPMachine *session, WSPMethodMachine *machine, WAPEvent *event, WSP_PDU *pdu);
00134 static void cant_handle_event(WSPMachine *sm, WAPEvent *event);
00135 static WSPMethodMachine *method_machine_create(WSPMachine *, long);
00136 static void method_machine_destroy(void *msm);
00137
00138 static void handle_push_event(WSPMachine *session, WSPPushMachine *machine,
00139 WAPEvent *e);
00140 static WSPPushMachine *push_machine_create(WSPMachine *session, long id);
00141 static void push_machine_destroy(void *p);
00142
00143 static char *state_name(WSPState state);
00144 static unsigned long next_wsp_session_id(void);
00145
00146 static List *make_capabilities_reply(WSPMachine *m);
00147 static List *make_reply_headers(WSPMachine *m);
00148 static Octstr *make_connectreply_pdu(WSPMachine *m);
00149 static Octstr *make_resume_reply_pdu(WSPMachine *m, List *headers);
00150 static WSP_PDU *make_confirmedpush_pdu(WAPEvent *e);
00151 static WSP_PDU *make_push_pdu(WAPEvent *e);
00152
00153 static int transaction_belongs_to_session(void *session, void *tuple);
00154 static int find_by_session_id(void *session, void *idp);
00155 static int same_client(void *sm1, void *sm2);
00156 static WSPMethodMachine *find_method_machine(WSPMachine *, long id);
00157 static WSPPushMachine *find_push_machine(WSPMachine *m, long id);
00158
00159 static List *unpack_new_headers(WSPMachine *sm, Octstr *hdrs);
00160
00161 static void disconnect_other_sessions(WSPMachine *sm);
00162 static void send_abort(long reason, long handle);
00163 static void indicate_disconnect(WSPMachine *sm, long reason);
00164 static void indicate_suspend(WSPMachine *sm, long reason);
00165 static void indicate_resume(WSPMachine *sm, WAPAddrTuple *tuple,
00166 List *client_headers);
00167
00168 static void release_holding_methods(WSPMachine *sm);
00169 static void abort_methods(WSPMachine *sm, long reason);
00170 static void abort_pushes(WSPMachine *sm, long reason);
00171
00172 static void method_abort(WSPMethodMachine *msm, long reason);
00173 static void indicate_method_abort(WSPMethodMachine *msm, long reason);
00174
00175 static WAPEvent *make_abort(long reason, long handle);
00176 static void send_invoke(WSPMachine *session, WSP_PDU *pdu, WAPEvent *e,
00177 long class);
00178 static void send_abort_to_initiator(long reason, long handle);
00179 static void indicate_pushabort(WSPPushMachine *machine, long reason);
00180 static void confirm_push(WSPPushMachine *machine);
00181
00182 static void main_thread(void *);
00183 static int id_belongs_to_session (void *, void *);
00184 static int wsp_encoding_string_to_version(Octstr *enc);
00185 static Octstr *wsp_encoding_version_to_string(int version);
00186
00187
00188
00189
00190
00191
00192
00193 void wsp_session_init(wap_dispatch_func_t *responder_dispatch,
00194 wap_dispatch_func_t *initiator_dispatch,
00195 wap_dispatch_func_t *application_dispatch,
00196 wap_dispatch_func_t *push_ota_dispatch) {
00197 queue = gwlist_create();
00198 gwlist_add_producer(queue);
00199 session_machines = gwlist_create();
00200 session_id_counter = counter_create();
00201 dispatch_to_wtp_resp = responder_dispatch;
00202 dispatch_to_wtp_init = initiator_dispatch;
00203 dispatch_to_appl = application_dispatch;
00204 dispatch_to_ota = push_ota_dispatch;
00205 wsp_strings_init();
00206 run_status = running;
00207 gwthread_create(main_thread, NULL);
00208 }
00209
00210
00211 void wsp_session_shutdown(void) {
00212 gw_assert(run_status == running);
00213 run_status = terminating;
00214 gwlist_remove_producer(queue);
00215 gwthread_join_every(main_thread);
00216
00217 gwlist_destroy(queue, wap_event_destroy_item);
00218
00219 debug("wap.wsp", 0, "WSP: %ld session machines left.",
00220 gwlist_len(session_machines));
00221 gwlist_destroy(session_machines, machine_destroy);
00222
00223 counter_destroy(session_id_counter);
00224 wsp_strings_shutdown();
00225 }
00226
00227
00228 void wsp_session_dispatch_event(WAPEvent *event) {
00229 wap_event_assert(event);
00230 gwlist_produce(queue, event);
00231 }
00232
00233
00234
00235
00236
00237
00238
00239 static void main_thread(void *arg) {
00240 WAPEvent *e;
00241 WSPMachine *sm;
00242 WSP_PDU *pdu;
00243
00244 while (run_status == running && (e = gwlist_consume(queue)) != NULL) {
00245 wap_event_assert(e);
00246 switch (e->type) {
00247 case TR_Invoke_Ind:
00248 pdu = wsp_pdu_unpack(e->u.TR_Invoke_Ind.user_data);
00249 if (pdu == NULL) {
00250 warning(0, "WSP: Broken PDU ignored.");
00251 wap_event_destroy(e);
00252 continue;
00253 }
00254 break;
00255
00256 default:
00257 pdu = NULL;
00258 break;
00259 }
00260
00261 sm = find_session_machine(e, pdu);
00262 if (sm == NULL) {
00263 wap_event_destroy(e);
00264 } else {
00265 handle_session_event(sm, e, pdu);
00266 }
00267
00268 wsp_pdu_destroy(pdu);
00269 }
00270 }
00271
00272
00273 static WSPMachine *find_session_machine(WAPEvent *event, WSP_PDU *pdu) {
00274 WSPMachine *sm;
00275 long session_id;
00276 WAPAddrTuple *tuple;
00277
00278 tuple = NULL;
00279 session_id = -1;
00280
00281 switch (event->type) {
00282 case TR_Invoke_Ind:
00283 tuple = wap_addr_tuple_duplicate(
00284 event->u.TR_Invoke_Ind.addr_tuple);
00285 break;
00286
00287 case TR_Invoke_Cnf:
00288 tuple = wap_addr_tuple_duplicate(
00289 event->u.TR_Invoke_Cnf.addr_tuple);
00290 break;
00291
00292 case TR_Result_Cnf:
00293 tuple = wap_addr_tuple_duplicate(
00294 event->u.TR_Result_Cnf.addr_tuple);
00295 break;
00296
00297 case TR_Abort_Ind:
00298 tuple = wap_addr_tuple_duplicate(
00299 event->u.TR_Abort_Ind.addr_tuple);
00300 break;
00301
00302 case S_Connect_Res:
00303 session_id = event->u.S_Connect_Res.session_id;
00304 break;
00305
00306 case S_Resume_Res:
00307 session_id = event->u.S_Resume_Res.session_id;
00308 break;
00309
00310 case Disconnect_Event:
00311 session_id = event->u.Disconnect_Event.session_handle;
00312 break;
00313
00314 case Suspend_Event:
00315 session_id = event->u.Suspend_Event.session_handle;
00316 break;
00317
00318 case S_MethodInvoke_Res:
00319 session_id = event->u.S_MethodInvoke_Res.session_id;
00320 break;
00321
00322 case S_MethodResult_Req:
00323 session_id = event->u.S_MethodResult_Req.session_id;
00324 break;
00325
00326 case S_ConfirmedPush_Req:
00327 session_id = event->u.S_ConfirmedPush_Req.session_id;
00328 break;
00329
00330 case S_Push_Req:
00331 session_id = event->u.S_Push_Req.session_id;
00332 break;
00333
00334 default:
00335 error(0, "WSP: Cannot find machine for %s event",
00336 wap_event_name(event->type));
00337 }
00338
00339 gw_assert(tuple != NULL || session_id != -1);
00340
00341
00342
00343 sm = NULL;
00344
00345
00346
00347 if (event->type == TR_Invoke_Ind &&
00348 event->u.TR_Invoke_Ind.tcl == 2 &&
00349 pdu->type == Connect) {
00350
00351
00352
00353 sm = machine_create();
00354 gw_assert(tuple != NULL);
00355 sm->addr_tuple = wap_addr_tuple_duplicate(tuple);
00356 sm->connect_handle = event->u.TR_Invoke_Ind.handle;
00357
00358 } else if (event->type == TR_Invoke_Ind &&
00359 event->u.TR_Invoke_Ind.tcl == 2 &&
00360 pdu->type == Resume) {
00361
00362
00363 session_id = pdu->u.Resume.sessionid;
00364 sm = gwlist_search(session_machines, &session_id,
00365 find_by_session_id);
00366 if (sm == NULL) {
00367
00368 send_abort(WSP_ABORT_DISCONNECT,
00369 event->u.TR_Invoke_Ind.handle);
00370 }
00371
00372
00373
00374
00375 } else if (event->type == TR_Invoke_Ind) {
00376 sm = gwlist_search(session_machines, tuple,
00377 transaction_belongs_to_session);
00378 if (sm == NULL && (event->u.TR_Invoke_Ind.tcl == 1 ||
00379 event->u.TR_Invoke_Ind.tcl == 2)) {
00380 send_abort(WSP_ABORT_DISCONNECT,
00381 event->u.TR_Invoke_Ind.handle);
00382 }
00383
00384
00385 } else {
00386 if (session_id != -1) {
00387 sm = gwlist_search(session_machines, &session_id,
00388 find_by_session_id);
00389 } else {
00390 sm = gwlist_search(session_machines, tuple,
00391 transaction_belongs_to_session);
00392 }
00393
00394
00395
00396
00397 if (sm == NULL) {
00398 error(0, "WSP: Cannot find session machine for event.");
00399 wap_event_dump(event);
00400 }
00401 }
00402
00403 wap_addr_tuple_destroy(tuple);
00404 return sm;
00405 }
00406
00407
00408 static void handle_session_event(WSPMachine *sm, WAPEvent *current_event,
00409 WSP_PDU *pdu) {
00410 debug("wap.wsp", 0, "WSP: machine %p, state %s, event %s",
00411 (void *) sm,
00412 state_name(sm->state),
00413 wap_event_name(current_event->type));
00414
00415 #define STATE_NAME(name)
00416 #define ROW(state_name, event, condition, action, next_state) \
00417 { \
00418 struct event *e; \
00419 e = ¤t_event->u.event; \
00420 if (sm->state == state_name && \
00421 current_event->type == event && \
00422 (condition)) { \
00423 action \
00424 sm->state = next_state; \
00425 debug("wap.wsp", 0, "WSP %ld: New state %s", \
00426 sm->session_id, #next_state); \
00427 goto end; \
00428 } \
00429 }
00430 #include "wsp_server_session_states.def"
00431
00432 cant_handle_event(sm, current_event);
00433
00434 end:
00435 wap_event_destroy(current_event);
00436
00437 if (sm->state == NULL_SESSION)
00438 machine_destroy(sm);
00439 }
00440
00441
00442 static void cant_handle_event(WSPMachine *sm, WAPEvent *event) {
00443
00444
00445
00446 if (event->type == TR_Invoke_Ind &&
00447 (event->u.TR_Invoke_Ind.tcl == 1 ||
00448 event->u.TR_Invoke_Ind.tcl == 2)) {
00449 warning(0, "WSP: Can't handle TR-Invoke.ind, aborting transaction.");
00450 debug("wap.wsp", 0, "WSP: The unhandled event:");
00451 wap_event_dump(event);
00452 send_abort(WSP_ABORT_PROTOERR,
00453 event->u.TR_Invoke_Ind.handle);
00454
00455 } else if (event->type == TR_Invoke_Ind) {
00456 warning(0, "WSP: Can't handle TR-Invoke.ind, ignoring.");
00457 debug("wap.wsp", 0, "WSP: The ignored event:");
00458 wap_event_dump(event);
00459
00460 } else {
00461 error(0, "WSP: Can't handle event. Aborting session.");
00462 debug("wap.wsp", 0, "WSP: The unhandled event:");
00463 wap_event_dump(event);
00464
00465
00466
00467
00468
00469
00470 if (event->type == TR_Result_Cnf) {
00471 send_abort(WSP_ABORT_PROTOERR,
00472 event->u.TR_Result_Cnf.handle);
00473 }
00474
00475 abort_methods(sm, WSP_ABORT_PROTOERR);
00476 abort_pushes(sm, WSP_ABORT_PROTOERR);
00477
00478 indicate_disconnect(sm, WSP_ABORT_PROTOERR);
00479 }
00480 }
00481
00482
00483 static WSPMachine *machine_create(void) {
00484 WSPMachine *p;
00485
00486 p = gw_malloc(sizeof(WSPMachine));
00487 debug("wap.wsp", 0, "WSP: Created WSPMachine %p", (void *) p);
00488
00489 #define INTEGER(name) p->name = 0;
00490 #define OCTSTR(name) p->name = NULL;
00491 #define HTTPHEADERS(name) p->name = NULL;
00492 #define ADDRTUPLE(name) p->name = NULL;
00493 #define MACHINESLIST(name) p->name = gwlist_create();
00494 #define CAPABILITIES(name) p->name = NULL;
00495 #define COOKIES(name) p->name = gwlist_create();
00496 #define REFERER(name) p->name = NULL;
00497 #define MACHINE(fields) fields
00498 #include "wsp_server_session_machine.def"
00499
00500 p->state = NULL_SESSION;
00501
00502
00503
00504 p->client_SDU_size = 1400;
00505 p->MOR_push = 1;
00506
00507
00508
00509
00510
00511 gwlist_insert(session_machines, 0, p);
00512
00513 return p;
00514 }
00515
00516
00517 static void destroy_methodmachines(List *machines) {
00518 if (gwlist_len(machines) > 0) {
00519 warning(0, "Destroying WSP session with %ld active methods\n",
00520 gwlist_len(machines));
00521 }
00522
00523 gwlist_destroy(machines, method_machine_destroy);
00524 }
00525
00526 static void destroy_pushmachines(List *machines) {
00527 if (gwlist_len(machines) > 0) {
00528 warning(0, "Destroying WSP session with %ld active pushes\n",
00529 gwlist_len(machines));
00530 }
00531
00532 gwlist_destroy(machines, push_machine_destroy);
00533 }
00534
00535 static void machine_destroy(void *pp) {
00536 WSPMachine *p;
00537
00538 p = pp;
00539 debug("wap.wsp", 0, "Destroying WSPMachine %p", pp);
00540 gwlist_delete_equal(session_machines, p);
00541
00542 #define INTEGER(name) p->name = 0;
00543 #define OCTSTR(name) octstr_destroy(p->name);
00544 #define HTTPHEADERS(name) http_destroy_headers(p->name);
00545 #define ADDRTUPLE(name) wap_addr_tuple_destroy(p->name);
00546 #define MACHINESLIST(name) destroy_##name(p->name);
00547 #define CAPABILITIES(name) wsp_cap_destroy_list(p->name);
00548 #define COOKIES(name) cookies_destroy(p->name);
00549 #define REFERER(name) octstr_destroy(p->name);
00550 #define MACHINE(fields) fields
00551 #include "wsp_server_session_machine.def"
00552 gw_free(p);
00553 }
00554
00555
00556 struct msm_pattern {
00557 WAPAddrTuple *addr_tuple;
00558 long msmid, tid;
00559 };
00560
00561
00562
00563
00564 static void handle_method_event(WSPMachine *sm, WSPMethodMachine *msm,
00565 WAPEvent *current_event, WSP_PDU *pdu) {
00566
00567 if (msm == NULL) {
00568 warning(0, "No method machine for event.");
00569 wap_event_dump(current_event);
00570 return;
00571 }
00572
00573 debug("wap.wsp", 0, "WSP: method %ld, state %s, event %s",
00574 msm->transaction_id, state_name(msm->state),
00575 wap_event_name(current_event->type));
00576
00577 gw_assert(sm->session_id == msm->session_id);
00578
00579 #define STATE_NAME(name)
00580 #define ROW(state_name, event, condition, action, next_state) \
00581 { \
00582 struct event *e; \
00583 e = ¤t_event->u.event; \
00584 if (msm->state == state_name && \
00585 current_event->type == event && \
00586 (condition)) { \
00587 action \
00588 msm->state = next_state; \
00589 debug("wap.wsp", 0, "WSP %ld/%ld: New method state %s", \
00590 msm->session_id, msm->transaction_id, #next_state); \
00591 goto end; \
00592 } \
00593 }
00594 #include "wsp_server_method_states.def"
00595
00596 cant_handle_event(sm, current_event);
00597
00598 end:
00599 if (msm->state == NULL_METHOD) {
00600 method_machine_destroy(msm);
00601 gwlist_delete_equal(sm->methodmachines, msm);
00602 }
00603 }
00604
00605
00606 static WSPMethodMachine *method_machine_create(WSPMachine *sm,
00607 long wtp_handle) {
00608 WSPMethodMachine *msm;
00609
00610 msm = gw_malloc(sizeof(*msm));
00611
00612 #define INTEGER(name) msm->name = 0;
00613 #define ADDRTUPLE(name) msm->name = NULL;
00614 #define EVENT(name) msm->name = NULL;
00615 #define MACHINE(fields) fields
00616 #include "wsp_server_method_machine.def"
00617
00618 msm->transaction_id = wtp_handle;
00619 msm->state = NULL_METHOD;
00620 msm->addr_tuple = wap_addr_tuple_duplicate(sm->addr_tuple);
00621 msm->session_id = sm->session_id;
00622
00623 gwlist_append(sm->methodmachines, msm);
00624
00625 return msm;
00626 }
00627
00628
00629
00630 static void method_machine_destroy(void *p) {
00631 WSPMethodMachine *msm;
00632
00633 if (p == NULL)
00634 return;
00635
00636 msm = p;
00637
00638 debug("wap.wsp", 0, "Destroying WSPMethodMachine %ld",
00639 msm->transaction_id);
00640
00641 #define INTEGER(name)
00642 #define ADDRTUPLE(name) wap_addr_tuple_destroy(msm->name);
00643 #define EVENT(name) wap_event_destroy(msm->name);
00644 #define MACHINE(fields) fields
00645 #include "wsp_server_method_machine.def"
00646
00647 gw_free(msm);
00648 }
00649
00650 static void handle_push_event(WSPMachine *sm, WSPPushMachine *pm,
00651 WAPEvent *current_event)
00652 {
00653 if (pm == NULL) {
00654 warning(0, "No push machine for event.");
00655 wap_event_dump(current_event);
00656 return;
00657 }
00658
00659 debug("wap.wsp", 0, "WSP(tid/pid): push %ld/%ld, state %s, event %s",
00660 pm->transaction_id, pm->server_push_id, state_name(pm->state),
00661 wap_event_name(current_event->type));
00662 gw_assert(sm->session_id == pm->session_id);
00663
00664 #define STATE_NAME(name)
00665 #define ROW(state_name, event, condition, action, next_state) \
00666 { \
00667 if (pm->state == state_name && \
00668 current_event->type == event && \
00669 (condition)) { \
00670 action \
00671 pm->state = next_state; \
00672 debug("wap.wsp", 0, "WSP %ld/%ld: New push state %s", \
00673 pm->session_id, pm->transaction_id, #next_state); \
00674 goto end; \
00675 } \
00676 }
00677 #include "wsp_server_push_states.def"
00678
00679 cant_handle_event(sm, current_event);
00680 end:
00681 if (pm->state == SERVER_PUSH_NULL_STATE) {
00682 push_machine_destroy(pm);
00683 gwlist_delete_equal(sm->pushmachines, pm);
00684 }
00685 }
00686
00687 static WSPPushMachine *push_machine_create(WSPMachine *sm,
00688 long pid)
00689 {
00690 WSPPushMachine *m;
00691
00692 m = gw_malloc(sizeof(WSPPushMachine));
00693
00694 #define INTEGER(name) m->name = 0;
00695 #define ADDRTUPLE(name) m->name = NULL;
00696 #define HTTPHEADER(name) m->name = http_create_empty_headers();
00697 #define MACHINE(fields) fields
00698 #include "wsp_server_push_machine.def"
00699
00700 m->server_push_id = pid;
00701 m->transaction_id = pid;
00702 m->state = SERVER_PUSH_NULL_STATE;
00703 m->addr_tuple = wap_addr_tuple_duplicate(sm->addr_tuple);
00704 m->session_id = sm->session_id;
00705
00706 gwlist_append(sm->pushmachines, m);
00707
00708 return m;
00709 }
00710
00711 static void push_machine_destroy(void *p)
00712 {
00713 WSPPushMachine *m = NULL;
00714
00715 if (p == NULL)
00716 return;
00717 m = p;
00718 debug("wap.wsp", 0, "Destroying WSPPushMachine %ld",
00719 m->transaction_id);
00720 #define INTEGER(name)
00721 #define ADDRTUPLE(name) wap_addr_tuple_destroy(m->name);
00722 #define HTTPHEADER(name) http_destroy_headers(m->name);
00723 #define MACHINE(fields) fields
00724 #include "wsp_server_push_machine.def"
00725
00726 gw_free(m);
00727 }
00728
00729 static char *state_name(WSPState state) {
00730 switch (state) {
00731 #define STATE_NAME(name) case name: return #name;
00732 #define ROW(state, event, cond, stmt, next_state)
00733 #include "wsp_server_session_states.def"
00734
00735 #define STATE_NAME(name) case name: return #name;
00736 #define ROW(state, event, cond, stmt, next_state)
00737 #include "wsp_server_method_states.def"
00738
00739 #define STATE_NAME(name) case name: return #name;
00740 #define ROW(state, event, cond, stmt, next_state)
00741 #include "wsp_server_push_states.def"
00742
00743 default:
00744 return "unknown wsp state";
00745 }
00746 }
00747
00748
00749 static unsigned long next_wsp_session_id(void) {
00750 return counter_increase(session_id_counter);
00751 }
00752
00753
00754 static void sanitize_capabilities(List *caps, WSPMachine *m) {
00755 long i;
00756 Capability *cap;
00757 unsigned long ui;
00758
00759 for (i = 0; i < gwlist_len(caps); i++) {
00760 cap = gwlist_get(caps, i);
00761
00762
00763
00764 if (cap->name != NULL)
00765 continue;
00766
00767 switch (cap->id) {
00768 case WSP_CAPS_CLIENT_SDU_SIZE:
00769
00770
00771
00772 if (cap->data != NULL &&
00773 octstr_extract_uintvar(cap->data, &ui, 0) < 0)
00774 goto bad_cap;
00775 else
00776 m->client_SDU_size = ui;
00777 break;
00778
00779 case WSP_CAPS_SERVER_SDU_SIZE:
00780
00781 if (cap->data != NULL &&
00782 (octstr_extract_uintvar(cap->data, &ui, 0) < 0))
00783 goto bad_cap;
00784
00785
00786
00787
00788 break;
00789
00790 case WSP_CAPS_PROTOCOL_OPTIONS:
00791
00792
00793
00794 if (cap->data != NULL && octstr_len(cap->data) > 0
00795 && (octstr_get_char(cap->data, 0) & 0xf0) != 0) {
00796 warning(0, "WSP: Application layer tried to "
00797 "negotiate protocol options.");
00798 octstr_set_bits(cap->data, 0, 4, 0);
00799 }
00800 break;
00801
00802 case WSP_CAPS_EXTENDED_METHODS:
00803
00804 break;
00805
00806
00807 case WSP_CAPS_HEADER_CODE_PAGES:
00808
00809
00810 if (cap->data)
00811 goto bad_cap;
00812 break;
00813 }
00814 continue;
00815
00816 bad_cap:
00817 error(0, "WSP: Found illegal value in capabilities reply.");
00818 wsp_cap_dump(cap);
00819 gwlist_delete(caps, i, 1);
00820 i--;
00821 wsp_cap_destroy(cap);
00822 continue;
00823 }
00824 }
00825
00826
00827 static void reply_known_capabilities(List *caps, List *req, WSPMachine *m) {
00828 unsigned long ui;
00829 Capability *cap;
00830 Octstr *data;
00831
00832 if (wsp_cap_count(caps, WSP_CAPS_CLIENT_SDU_SIZE, NULL) == 0) {
00833 if (wsp_cap_get_client_sdu(req, &ui) > 0) {
00834
00835 if ((ui >= 256 && ui < LONG_MAX) || ui == 0) {
00836 m->client_SDU_size = ui;
00837 }
00838 }
00839
00840 data = octstr_create("");
00841 octstr_append_uintvar(data, m->client_SDU_size);
00842 cap = wsp_cap_create(WSP_CAPS_CLIENT_SDU_SIZE,
00843 NULL, data);
00844 gwlist_append(caps, cap);
00845 }
00846
00847 if (wsp_cap_count(caps, WSP_CAPS_SERVER_SDU_SIZE, NULL) == 0) {
00848
00849
00850
00851 if (wsp_cap_get_server_sdu(req, &ui) <= 0) {
00852 ui = 1400;
00853 }
00854 data = octstr_create("");
00855 octstr_append_uintvar(data, ui);
00856 cap = wsp_cap_create(WSP_CAPS_SERVER_SDU_SIZE, NULL, data);
00857 gwlist_append(caps, cap);
00858 }
00859
00860
00861 if (wsp_cap_count(caps, WSP_CAPS_PROTOCOL_OPTIONS, NULL) == 0) {
00862 data = octstr_create("");
00863 octstr_append_char(data, 0);
00864 cap = wsp_cap_create(WSP_CAPS_PROTOCOL_OPTIONS, NULL, data);
00865 gwlist_append(caps, cap);
00866 }
00867
00868
00869
00870 if (wsp_cap_count(caps, WSP_CAPS_METHOD_MOR, NULL) == 0) {
00871 if (wsp_cap_get_method_mor(req, &ui) <= 0) {
00872 ui = 1;
00873 }
00874 data = octstr_create("");
00875 octstr_append_char(data, ui);
00876 cap = wsp_cap_create(WSP_CAPS_METHOD_MOR, NULL, data);
00877 gwlist_append(caps, cap);
00878 }
00879
00880
00881
00882
00883 if (wsp_cap_count(caps, WSP_CAPS_PUSH_MOR, NULL) == 0) {
00884 if (wsp_cap_get_push_mor(req, &ui) > 0) {
00885 m->MOR_push = ui;
00886 }
00887 data = octstr_create("");
00888 octstr_append_char(data, m->MOR_push);
00889 cap = wsp_cap_create(WSP_CAPS_PUSH_MOR, NULL, data);
00890 gwlist_append(caps, cap);
00891 }
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904 }
00905
00906
00907
00908
00909 static void refuse_unreplied_capabilities(List *caps, List *req) {
00910 long i, len;
00911 Capability *cap;
00912
00913 len = gwlist_len(req);
00914 for (i = 0; i < len; i++) {
00915 cap = gwlist_get(req, i);
00916 if (wsp_cap_count(caps, cap->id, cap->name) == 0) {
00917 cap = wsp_cap_create(cap->id, cap->name, NULL);
00918 gwlist_append(caps, cap);
00919 }
00920 }
00921 }
00922
00923
00924 static int is_default_cap(Capability *cap) {
00925 unsigned long ui;
00926
00927
00928 if (cap->name != NULL || cap->id < 0 || cap->id >= WSP_NUM_CAPS)
00929 return cap->data == NULL || octstr_len(cap->data) == 0;
00930
00931 switch (cap->id) {
00932 case WSP_CAPS_CLIENT_SDU_SIZE:
00933 case WSP_CAPS_SERVER_SDU_SIZE:
00934 return (cap->data != NULL &&
00935 octstr_extract_uintvar(cap->data, &ui, 0) >= 0 &&
00936 ui == 1400);
00937 case WSP_CAPS_PROTOCOL_OPTIONS:
00938 return cap->data != NULL && octstr_get_char(cap->data, 0) == 0;
00939 case WSP_CAPS_METHOD_MOR:
00940 case WSP_CAPS_PUSH_MOR:
00941 return cap->data != NULL && octstr_get_char(cap->data, 0) == 1;
00942 case WSP_CAPS_EXTENDED_METHODS:
00943 case WSP_CAPS_HEADER_CODE_PAGES:
00944 case WSP_CAPS_ALIASES:
00945 return cap->data == NULL || octstr_len(cap->data) == 0;
00946 default:
00947 return 0;
00948 }
00949 }
00950
00951
00952
00953
00954 static void strip_default_capabilities(List *caps, List *req) {
00955 long i;
00956 Capability *cap;
00957 int count;
00958
00959
00960
00961 i = 0;
00962 while (i < gwlist_len(caps)) {
00963 cap = gwlist_get(caps, i);
00964
00965 count = wsp_cap_count(req, cap->id, cap->name);
00966 if (count == 0 && is_default_cap(cap)) {
00967 gwlist_delete(caps, i, 1);
00968 wsp_cap_destroy(cap);
00969 } else {
00970 i++;
00971 }
00972 }
00973 }
00974
00975
00976 static List *make_capabilities_reply(WSPMachine *m) {
00977 List *caps;
00978
00979
00980
00981
00982
00983
00984
00985 caps = wsp_cap_duplicate_list(m->reply_caps);
00986
00987
00988
00989
00990 sanitize_capabilities(caps, m);
00991
00992
00993
00994 reply_known_capabilities(caps, m->request_caps, m);
00995
00996
00997
00998
00999 refuse_unreplied_capabilities(caps, m->request_caps);
01000
01001
01002
01003 strip_default_capabilities(caps, m->request_caps);
01004
01005 return caps;
01006 }
01007
01008
01009 static List *make_reply_headers(WSPMachine *m)
01010 {
01011 List *headers;
01012 Octstr *encoding_version;
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026 headers = http_create_empty_headers();
01027 encoding_version = wsp_encoding_version_to_string(m->encoding_version);
01028 http_header_add(headers, "Encoding-Version", octstr_get_cstr(encoding_version));
01029 octstr_destroy(encoding_version);
01030
01031 return headers;
01032 }
01033
01034 static Octstr *make_connectreply_pdu(WSPMachine *m)
01035 {
01036 WSP_PDU *pdu;
01037 Octstr *os;
01038 List *caps;
01039 List *reply_headers;
01040
01041 pdu = wsp_pdu_create(ConnectReply);
01042
01043 pdu->u.ConnectReply.sessionid = m->session_id;
01044
01045 caps = make_capabilities_reply(m);
01046 pdu->u.ConnectReply.capabilities = wsp_cap_pack_list(caps);
01047 wsp_cap_destroy_list(caps);
01048
01049 reply_headers = make_reply_headers(m);
01050 pdu->u.ConnectReply.headers =
01051 wsp_headers_pack(reply_headers, 0, m->encoding_version);
01052 http_destroy_headers(reply_headers);
01053
01054 os = wsp_pdu_pack(pdu);
01055 wsp_pdu_destroy(pdu);
01056
01057 return os;
01058 }
01059
01060
01061 static Octstr *make_resume_reply_pdu(WSPMachine *m, List *headers)
01062 {
01063 WSP_PDU *pdu;
01064 Octstr *os;
01065
01066 pdu = wsp_pdu_create(Reply);
01067
01068
01069 pdu->u.Reply.status = wsp_convert_http_status_to_wsp_status(HTTP_OK);
01070 if (headers == NULL) {
01071 headers = http_create_empty_headers();
01072 pdu->u.Reply.headers = wsp_headers_pack(headers, 1, m->encoding_version);
01073 http_destroy_headers(headers);
01074 } else {
01075 pdu->u.Reply.headers = wsp_headers_pack(headers, 1, m->encoding_version);
01076 }
01077 pdu->u.Reply.data = octstr_create("");
01078
01079 os = wsp_pdu_pack(pdu);
01080 wsp_pdu_destroy(pdu);
01081
01082 return os;
01083 }
01084
01085 static WSP_PDU *make_confirmedpush_pdu(WAPEvent *e)
01086 {
01087 WSP_PDU *pdu;
01088 List *headers;
01089
01090 pdu = wsp_pdu_create(ConfirmedPush);
01091
01092
01093
01094 if (e->u.S_ConfirmedPush_Req.push_headers == NULL) {
01095 headers = http_create_empty_headers();
01096 pdu->u.ConfirmedPush.headers = wsp_headers_pack(headers, 1, WSP_1_2);
01097 http_destroy_headers(headers);
01098 } else
01099 pdu->u.ConfirmedPush.headers =
01100 wsp_headers_pack(e->u.S_ConfirmedPush_Req.push_headers, 1, WSP_1_2);
01101
01102 if (e->u.S_ConfirmedPush_Req.push_body == NULL)
01103 pdu->u.ConfirmedPush.data = octstr_create("");
01104 else
01105 pdu->u.ConfirmedPush.data =
01106 octstr_duplicate(e->u.S_ConfirmedPush_Req.push_body);
01107
01108 return pdu;
01109 }
01110
01111 static WSP_PDU *make_push_pdu(WAPEvent *e)
01112 {
01113 WSP_PDU *pdu;
01114 List *headers;
01115
01116 pdu = wsp_pdu_create(Push);
01117
01118
01119
01120 if (e->u.S_Push_Req.push_headers == NULL) {
01121 headers = http_create_empty_headers();
01122 pdu->u.Push.headers = wsp_headers_pack(headers, 1, WSP_1_2);
01123 http_destroy_headers(headers);
01124 } else
01125 pdu->u.Push.headers =
01126 wsp_headers_pack(e->u.S_Push_Req.push_headers, 1, WSP_1_2);
01127
01128 if (e->u.S_Push_Req.push_body == NULL)
01129 pdu->u.Push.data = octstr_create("");
01130 else
01131 pdu->u.Push.data =
01132 octstr_duplicate(e->u.S_Push_Req.push_body);
01133
01134 return pdu;
01135 }
01136
01137 static int transaction_belongs_to_session(void *wsp_ptr, void *tuple_ptr) {
01138 WSPMachine *wsp;
01139 WAPAddrTuple *tuple;
01140
01141 wsp = wsp_ptr;
01142 tuple = tuple_ptr;
01143
01144 return wap_addr_tuple_same(wsp->addr_tuple, tuple);
01145 }
01146
01147
01148 static int find_by_session_id(void *wsp_ptr, void *id_ptr) {
01149 WSPMachine *wsp = wsp_ptr;
01150 long *idp = id_ptr;
01151
01152 return wsp->session_id == *idp;
01153 }
01154
01155
01156 static int find_by_method_id(void *wspm_ptr, void *id_ptr) {
01157 WSPMethodMachine *msm = wspm_ptr;
01158 long *idp = id_ptr;
01159
01160 return msm->transaction_id == *idp;
01161 }
01162
01163 static int find_by_push_id(void *m_ptr, void *id_ptr) {
01164 WSPPushMachine *m = m_ptr;
01165 long *idp = id_ptr;
01166
01167 return m->transaction_id == *idp;
01168 }
01169
01170 static WSPMethodMachine *find_method_machine(WSPMachine *sm, long id) {
01171 return gwlist_search(sm->methodmachines, &id, find_by_method_id);
01172 }
01173
01174 static WSPPushMachine *find_push_machine(WSPMachine *m, long id)
01175 {
01176 return gwlist_search(m->pushmachines, &id, find_by_push_id);
01177 }
01178
01179 static int same_client(void *a, void *b) {
01180 WSPMachine *sm1, *sm2;
01181
01182 sm1 = a;
01183 sm2 = b;
01184 return wap_addr_tuple_same(sm1->addr_tuple, sm2->addr_tuple);
01185 }
01186
01187
01188 static void disconnect_other_sessions(WSPMachine *sm) {
01189 List *old_sessions;
01190 WAPEvent *disconnect;
01191 WSPMachine *sm2;
01192 long i;
01193
01194 old_sessions = gwlist_search_all(session_machines, sm, same_client);
01195 if (old_sessions == NULL)
01196 return;
01197
01198 for (i = 0; i < gwlist_len(old_sessions); i++) {
01199 sm2 = gwlist_get(old_sessions, i);
01200 if (sm2 != sm) {
01201 disconnect = wap_event_create(Disconnect_Event);
01202 handle_session_event(sm2, disconnect, NULL);
01203 }
01204 }
01205
01206 gwlist_destroy(old_sessions, NULL);
01207 }
01208
01209
01210 static List *unpack_new_headers(WSPMachine *sm, Octstr *hdrs) {
01211 List *new_headers;
01212
01213 if (hdrs && octstr_len(hdrs) > 0) {
01214 new_headers = wsp_headers_unpack(hdrs, 0);
01215 if (sm->http_headers == NULL)
01216 sm->http_headers = http_create_empty_headers();
01217 http_header_combine(sm->http_headers, new_headers);
01218 return new_headers;
01219 }
01220 return NULL;
01221 }
01222
01223 static WAPEvent *make_abort(long reason, long handle)
01224 {
01225 WAPEvent *wtp_event;
01226
01227 wtp_event = wap_event_create(TR_Abort_Req);
01228 wtp_event->u.TR_Abort_Req.abort_type = 0x01;
01229 wtp_event->u.TR_Abort_Req.abort_reason = reason;
01230 wtp_event->u.TR_Abort_Req.handle = handle;
01231
01232 return wtp_event;
01233 }
01234
01235 static void send_abort(long reason, long handle) {
01236 WAPEvent *wtp_event;
01237
01238 wtp_event = make_abort(reason, handle);
01239 dispatch_to_wtp_resp(wtp_event);
01240 }
01241
01242 static void send_abort_to_initiator(long reason, long handle)
01243 {
01244 WAPEvent *wtp_event;
01245
01246 wtp_event = make_abort(reason, handle);
01247 dispatch_to_wtp_init(wtp_event);
01248 }
01249
01250
01251
01252
01253
01254 static void send_invoke(WSPMachine *m, WSP_PDU *pdu, WAPEvent *e, long class)
01255 {
01256 WAPEvent *wtp_event;
01257
01258 wtp_event = wap_event_create(TR_Invoke_Req);
01259 wtp_event->u.TR_Invoke_Req.addr_tuple =
01260 wap_addr_tuple_duplicate(m->addr_tuple);
01261
01262
01263
01264
01265
01266 wtp_event->u.TR_Invoke_Req.up_flag = USER_ACKNOWLEDGEMENT;
01267 wtp_event->u.TR_Invoke_Req.tcl = class;
01268 if (e->type == S_ConfirmedPush_Req)
01269 wtp_event->u.TR_Invoke_Req.handle =
01270 e->u.S_ConfirmedPush_Req.server_push_id;
01271 wtp_event->u.TR_Invoke_Req.user_data = wsp_pdu_pack(pdu);
01272
01273 wsp_pdu_destroy(pdu);
01274 dispatch_to_wtp_init(wtp_event);
01275 }
01276
01277 static void indicate_disconnect(WSPMachine *sm, long reason) {
01278 WAPEvent *new_event;
01279
01280 new_event = wap_event_create(S_Disconnect_Ind);
01281 new_event->u.S_Disconnect_Ind.reason_code = reason;
01282 new_event->u.S_Disconnect_Ind.redirect_security = 0;
01283 new_event->u.S_Disconnect_Ind.redirect_addresses = 0;
01284 new_event->u.S_Disconnect_Ind.error_headers = NULL;
01285 new_event->u.S_Disconnect_Ind.error_body = NULL;
01286 new_event->u.S_Disconnect_Ind.session_handle = sm->session_id;
01287 dispatch_to_appl(new_event);
01288 }
01289
01290
01291 static void indicate_suspend(WSPMachine *sm, long reason) {
01292 WAPEvent *new_event;
01293
01294 new_event = wap_event_create(S_Suspend_Ind);
01295 new_event->u.S_Suspend_Ind.reason = reason;
01296 new_event->u.S_Suspend_Ind.session_id = sm->session_id;
01297 dispatch_to_appl(new_event);
01298 }
01299
01300
01301 static void indicate_resume(WSPMachine *sm,
01302 WAPAddrTuple *tuple, List *headers) {
01303 WAPEvent *new_event;
01304
01305 new_event = wap_event_create(S_Resume_Ind);
01306 new_event->u.S_Resume_Ind.addr_tuple = wap_addr_tuple_duplicate(tuple);
01307 new_event->u.S_Resume_Ind.client_headers = http_header_duplicate(headers);
01308 new_event->u.S_Resume_Ind.session_id = sm->session_id;
01309 dispatch_to_appl(new_event);
01310 }
01311
01312 static void indicate_pushabort(WSPPushMachine *spm, long reason)
01313 {
01314 WAPEvent *ota_event;
01315
01316 ota_event = wap_event_create(S_PushAbort_Ind);
01317 ota_event->u.S_PushAbort_Ind.push_id = spm->server_push_id;
01318 ota_event->u.S_PushAbort_Ind.reason = reason;
01319 ota_event->u.S_PushAbort_Ind.session_id = spm->session_id;
01320 dispatch_to_appl(ota_event);
01321 }
01322
01323 static void confirm_push(WSPPushMachine *m)
01324 {
01325 WAPEvent *ota_event;
01326
01327 ota_event = wap_event_create(S_ConfirmedPush_Cnf);
01328 ota_event->u.S_ConfirmedPush_Cnf.server_push_id = m->server_push_id;
01329 ota_event->u.S_ConfirmedPush_Cnf.session_id = m->session_id;
01330 dispatch_to_appl(ota_event);
01331 }
01332
01333 static void method_abort(WSPMethodMachine *msm, long reason) {
01334 WAPEvent *wtp_event;
01335
01336
01337 wtp_event = wap_event_create(TR_Abort_Req);
01338
01339
01340 if (reason < WSP_ABORT_PROTOERR) {
01341 wtp_event->u.TR_Abort_Req.abort_type = 0x00;
01342 } else {
01343 wtp_event->u.TR_Abort_Req.abort_type = 0x01;
01344 }
01345 wtp_event->u.TR_Abort_Req.abort_reason = reason;
01346 wtp_event->u.TR_Abort_Req.handle = msm->transaction_id;
01347
01348 dispatch_to_wtp_resp(wtp_event);
01349 }
01350
01351
01352 static void indicate_method_abort(WSPMethodMachine *msm, long reason) {
01353 WAPEvent *new_event;
01354
01355
01356 new_event = wap_event_create(S_MethodAbort_Ind);
01357 new_event->u.S_MethodAbort_Ind.transaction_id = msm->transaction_id;
01358 new_event->u.S_MethodAbort_Ind.reason = reason;
01359 new_event->u.S_MethodAbort_Ind.session_handle = msm->session_id;
01360 dispatch_to_appl(new_event);
01361 }
01362
01363
01364 static int method_is_holding(void *item, void *pattern) {
01365 WSPMethodMachine *msm = item;
01366
01367 return msm->state == HOLDING;
01368 }
01369
01370
01371 static void release_holding_methods(WSPMachine *sm) {
01372 WAPEvent *release;
01373 WSPMethodMachine *msm;
01374 List *holding;
01375 long i, len;
01376
01377 holding = gwlist_search_all(sm->methodmachines, NULL, method_is_holding);
01378 if (holding == NULL)
01379 return;
01380
01381
01382
01383 release = wap_event_create(Release_Event);
01384
01385 len = gwlist_len(holding);
01386 for (i = 0; i < len; i++) {
01387 msm = gwlist_get(holding, i);
01388 handle_method_event(sm, msm, release, NULL);
01389 }
01390 gwlist_destroy(holding, NULL);
01391 wap_event_destroy(release);
01392 }
01393
01394
01395 static void abort_methods(WSPMachine *sm, long reason) {
01396 WAPEvent *ab;
01397 WSPMethodMachine *msm;
01398 long i, len;
01399
01400 ab = wap_event_create(Abort_Event);
01401 ab->u.Abort_Event.reason = reason;
01402
01403
01404
01405 len = gwlist_len(sm->methodmachines);
01406 for (i = len - 1; i >= 0; i--) {
01407 msm = gwlist_get(sm->methodmachines, i);
01408 handle_method_event(sm, msm, ab, NULL);
01409 }
01410
01411 wap_event_destroy(ab);
01412 }
01413
01414
01415 static void abort_pushes(WSPMachine *sm, long reason)
01416 {
01417 WAPEvent *ab;
01418 WSPPushMachine *psm;
01419 long i, len;
01420
01421 ab = wap_event_create(Abort_Event);
01422 ab->u.Abort_Event.reason = reason;
01423
01424 len = gwlist_len(sm->pushmachines);
01425 for (i = len - 1; i >= 0; i--) {
01426 psm = gwlist_get(sm->pushmachines, i);
01427 handle_push_event(sm, psm, ab);
01428 }
01429
01430 wap_event_destroy(ab);
01431 }
01432
01433
01434 WSPMachine *find_session_machine_by_id (int id) {
01435
01436 return gwlist_search(session_machines, &id, id_belongs_to_session);
01437 }
01438
01439
01440 static int id_belongs_to_session (void *wsp_ptr, void *pid) {
01441 WSPMachine *wsp;
01442 int *id;
01443
01444 wsp = wsp_ptr;
01445 id = (int *) pid;
01446
01447 if (*id == wsp->session_id) return 1;
01448 return 0;
01449 }
01450
01451
01452 static int wsp_encoding_string_to_version(Octstr *enc)
01453 {
01454 int v;
01455
01456
01457 v = WSP_1_2;
01458
01459 if (octstr_compare(enc, octstr_imm("1.1")) == 0) {
01460 v = WSP_1_1;
01461 }
01462 else if (octstr_compare(enc, octstr_imm("1.2")) == 0) {
01463 v = WSP_1_2;
01464 }
01465 else if (octstr_compare(enc, octstr_imm("1.3")) == 0) {
01466 v = WSP_1_3;
01467 }
01468 else if (octstr_compare(enc, octstr_imm("1.4")) == 0) {
01469 v = WSP_1_4;
01470 }
01471 else if (octstr_compare(enc, octstr_imm("1.5")) == 0) {
01472 v = WSP_1_5;
01473 }
01474
01475 return v;
01476 }
01477
01478 static Octstr *wsp_encoding_version_to_string(int version)
01479 {
01480 Octstr *os;
01481
01482 switch (version) {
01483 case WSP_1_1:
01484 os = octstr_create("1.1");
01485 break;
01486 case WSP_1_2:
01487 os = octstr_create("1.2");
01488 break;
01489 case WSP_1_3:
01490 os = octstr_create("1.3");
01491 break;
01492 case WSP_1_4:
01493 os = octstr_create("1.4");
01494 break;
01495 case WSP_1_5:
01496 os = octstr_create("1.5");
01497 break;
01498 default:
01499 os = octstr_create("1.2");
01500 break;
01501 }
01502
01503 return os;
01504 }
01505
See file LICENSE for details about the license agreement for using,
modifying, copying or deriving work from this software.