Kannel: Open Source WAP and SMS gateway  svn-r5335
wsp_session.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2018 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Kannel Group (http://www.kannel.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  * endorse or promote products derived from this software without
29  * prior written permission. For written permission, please
30  * contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  * nor may "Kannel" appear in their name, without prior written
34  * permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group. For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57 /*
58  * wsp_session.c - Implement WSP session oriented service
59  *
60  * Lars Wirzenius
61  * Stipe Tolj
62  */
63 
64 
65 #include <string.h>
66 #include <limits.h>
67 
68 #include "gwlib/gwlib.h"
69 #include "wsp.h"
70 #include "wsp_pdu.h"
71 #include "wsp_headers.h"
72 #include "wsp_caps.h"
73 #include "wsp_strings.h"
74 #include "cookies.h"
75 #include "wap.h"
76 #include "wtp.h"
77 
78 
79 typedef enum {
80  #define STATE_NAME(name) name,
81  #define ROW(state, event, condition, action, next_state)
83 
84  #define STATE_NAME(name) name,
85  #define ROW(state, event, condition, action, next_state)
87 
88  #define STATE_NAME(name) name,
89  #define ROW(state, event, condition, action, next_state)
91 
92  WSPState_count
93 } WSPState;
94 
95 
96 /*
97  * Give the status the module:
98  *
99  * limbo
100  * not running at all
101  * running
102  * operating normally
103  * terminating
104  * waiting for operations to terminate, returning to limbo
105  */
107 
112 
113 /*
114  * True iff "Session resume facility" is enabled. This means we are
115  * willing to let sessions go to SUSPENDED state, and later resume them.
116  * Currently we always support it, but this may become configurable
117  * at some point.
118  */
119 
120 static int resume_enabled = 1;
121 
122 static List *queue = NULL;
123 static List *session_machines = NULL;
125 
126 
127 static WSPMachine *find_session_machine(WAPEvent *event, WSP_PDU *pdu);
128 static void handle_session_event(WSPMachine *machine, WAPEvent *event,
129  WSP_PDU *pdu);
130 static WSPMachine *machine_create(void);
131 static void machine_destroy(void *p);
132 
133 static void handle_method_event(WSPMachine *session, WSPMethodMachine *machine, WAPEvent *event, WSP_PDU *pdu);
134 static void cant_handle_event(WSPMachine *sm, WAPEvent *event);
136 static void method_machine_destroy(void *msm);
137 
138 static void handle_push_event(WSPMachine *session, WSPPushMachine *machine,
139  WAPEvent *e);
140 static WSPPushMachine *push_machine_create(WSPMachine *session, long id);
141 static void push_machine_destroy(void *p);
142 
143 static char *state_name(WSPState state);
144 static unsigned long next_wsp_session_id(void);
145 
149 static Octstr *make_resume_reply_pdu(WSPMachine *m, List *headers);
151 static WSP_PDU *make_push_pdu(WAPEvent *e);
152 
153 static int transaction_belongs_to_session(void *session, void *tuple);
154 static int find_by_session_id(void *session, void *idp);
155 static int same_client(void *sm1, void *sm2);
157 static WSPPushMachine *find_push_machine(WSPMachine *m, long id);
158 
159 static List *unpack_new_headers(WSPMachine *sm, Octstr *hdrs);
161 static void disconnect_other_sessions(WSPMachine *sm);
162 static void send_abort(long reason, long handle);
163 static void indicate_disconnect(WSPMachine *sm, long reason);
164 static void indicate_suspend(WSPMachine *sm, long reason);
165 static void indicate_resume(WSPMachine *sm, WAPAddrTuple *tuple,
166  List *client_headers);
167 
168 static void release_holding_methods(WSPMachine *sm);
169 static void abort_methods(WSPMachine *sm, long reason);
170 static void abort_pushes(WSPMachine *sm, long reason);
171 
172 static void method_abort(WSPMethodMachine *msm, long reason);
173 static void indicate_method_abort(WSPMethodMachine *msm, long reason);
174 
175 static WAPEvent *make_abort(long reason, long handle);
176 static void send_invoke(WSPMachine *session, WSP_PDU *pdu, WAPEvent *e,
177  long class);
178 static void send_abort_to_initiator(long reason, long handle);
179 static void indicate_pushabort(WSPPushMachine *machine, long reason);
180 static void confirm_push(WSPPushMachine *machine);
181 
182 static void main_thread(void *);
183 static int id_belongs_to_session (void *, void *);
184 static int wsp_encoding_string_to_version(Octstr *enc);
185 static Octstr *wsp_encoding_version_to_string(int version);
186 
187 
188 /***********************************************************************
189  * Public functions.
190  */
191 
192 
193 void wsp_session_init(wap_dispatch_func_t *responder_dispatch,
194  wap_dispatch_func_t *initiator_dispatch,
195  wap_dispatch_func_t *application_dispatch,
196  wap_dispatch_func_t *push_ota_dispatch) {
197  queue = gwlist_create();
201  dispatch_to_wtp_resp = responder_dispatch;
202  dispatch_to_wtp_init = initiator_dispatch;
203  dispatch_to_appl = application_dispatch;
204  dispatch_to_ota = push_ota_dispatch;
208 }
209 
210 
216 
218 
219  debug("wap.wsp", 0, "WSP: %ld session machines left.",
222 
225 }
226 
227 
229  wap_event_assert(event);
230  gwlist_produce(queue, event);
231 }
232 
233 
234 /***********************************************************************
235  * Local functions
236  */
237 
238 
239 static void main_thread(void *arg) {
240  WAPEvent *e;
241  WSPMachine *sm;
242  WSP_PDU *pdu;
243 
244  while (run_status == running && (e = gwlist_consume(queue)) != NULL) {
245  wap_event_assert(e);
246  switch (e->type) {
247  case TR_Invoke_Ind:
248  pdu = wsp_pdu_unpack(e->u.TR_Invoke_Ind.user_data);
249  if (pdu == NULL) {
250  warning(0, "WSP: Broken PDU ignored.");
252  continue;
253  }
254  break;
255 
256  default:
257  pdu = NULL;
258  break;
259  }
260 
261  sm = find_session_machine(e, pdu);
262  if (sm == NULL) {
264  } else {
265  handle_session_event(sm, e, pdu);
266  }
267 
268  wsp_pdu_destroy(pdu);
269  }
270 }
271 
272 
274  WSPMachine *sm;
275  long session_id;
276  WAPAddrTuple *tuple;
277 
278  tuple = NULL;
279  session_id = -1;
280 
281  switch (event->type) {
282  case TR_Invoke_Ind:
283  tuple = wap_addr_tuple_duplicate(
284  event->u.TR_Invoke_Ind.addr_tuple);
285  break;
286 
287  case TR_Invoke_Cnf:
288  tuple = wap_addr_tuple_duplicate(
289  event->u.TR_Invoke_Cnf.addr_tuple);
290  break;
291 
292  case TR_Result_Cnf:
293  tuple = wap_addr_tuple_duplicate(
294  event->u.TR_Result_Cnf.addr_tuple);
295  break;
296 
297  case TR_Abort_Ind:
298  tuple = wap_addr_tuple_duplicate(
299  event->u.TR_Abort_Ind.addr_tuple);
300  break;
301 
302  case S_Connect_Res:
303  session_id = event->u.S_Connect_Res.session_id;
304  break;
305 
306  case S_Resume_Res:
307  session_id = event->u.S_Resume_Res.session_id;
308  break;
309 
310  case Disconnect_Event:
311  session_id = event->u.Disconnect_Event.session_handle;
312  break;
313 
314  case Suspend_Event:
315  session_id = event->u.Suspend_Event.session_handle;
316  break;
317 
318  case S_MethodInvoke_Res:
319  session_id = event->u.S_MethodInvoke_Res.session_id;
320  break;
321 
322  case S_MethodResult_Req:
323  session_id = event->u.S_MethodResult_Req.session_id;
324  break;
325 
326  case S_ConfirmedPush_Req:
327  session_id = event->u.S_ConfirmedPush_Req.session_id;
328  break;
329 
330  case S_Push_Req:
331  session_id = event->u.S_Push_Req.session_id;
332  break;
333 
334  default:
335  error(0, "WSP: Cannot find machine for %s event",
336  wap_event_name(event->type));
337  }
338 
339  gw_assert(tuple != NULL || session_id != -1);
340 
341  /* Pre-state-machine tests, according to 7.1.5. After the tests,
342  * caller will pass the event to sm if sm is not NULL. */
343  sm = NULL;
344  /* First test is for MRUEXCEEDED, and we don't have a MRU */
345 
346  /* Second test is for class 2 TR-Invoke.ind with Connect PDU */
347  if (event->type == TR_Invoke_Ind &&
348  event->u.TR_Invoke_Ind.tcl == 2 &&
349  pdu->type == Connect) {
350  /* Create a new session, even if there is already
351  * a session open for this address. The new session
352  * will take care of killing the old ones. */
353  sm = machine_create();
354  gw_assert(tuple != NULL);
355  sm->addr_tuple = wap_addr_tuple_duplicate(tuple);
356  sm->connect_handle = event->u.TR_Invoke_Ind.handle;
357  /* Third test is for class 2 TR-Invoke.ind with Resume PDU */
358  } else if (event->type == TR_Invoke_Ind &&
359  event->u.TR_Invoke_Ind.tcl == 2 &&
360  pdu->type == Resume) {
361  /* Pass to session identified by session id, not
362  * the address tuple. */
363  session_id = pdu->u.Resume.sessionid;
364  sm = gwlist_search(session_machines, &session_id,
366  if (sm == NULL) {
367  /* No session; TR-Abort.req(DISCONNECT) */
369  event->u.TR_Invoke_Ind.handle);
370  }
371  /* Fourth test is for a class 1 or 2 TR-Invoke.Ind with no
372  * session for that address tuple. We also handle class 0
373  * TR-Invoke.ind here by ignoring them; this seems to be
374  * an omission in the spec table. */
375  } else if (event->type == TR_Invoke_Ind) {
376  sm = gwlist_search(session_machines, tuple,
378  if (sm == NULL && (event->u.TR_Invoke_Ind.tcl == 1 ||
379  event->u.TR_Invoke_Ind.tcl == 2)) {
381  event->u.TR_Invoke_Ind.handle);
382  }
383  /* Other tests are for events not handled by the state tables;
384  * do those later, after we've tried to handle them. */
385  } else {
386  if (session_id != -1) {
387  sm = gwlist_search(session_machines, &session_id,
389  } else {
390  sm = gwlist_search(session_machines, tuple,
392  }
393  /* The table doesn't really say what we should do with
394  * non-Invoke events for which there is no session. But
395  * such a situation means there is an error _somewhere_
396  * in the gateway. */
397  if (sm == NULL) {
398  error(0, "WSP: Cannot find session machine for event.");
399  wap_event_dump(event);
400  }
401  }
402 
403  wap_addr_tuple_destroy(tuple);
404  return sm;
405 }
406 
407 
408 static void handle_session_event(WSPMachine *sm, WAPEvent *current_event,
409 WSP_PDU *pdu) {
410  debug("wap.wsp", 0, "WSP: machine %p, state %s, event %s",
411  (void *) sm,
412  state_name(sm->state),
413  wap_event_name(current_event->type));
414 
415  #define STATE_NAME(name)
416  #define ROW(state_name, event, condition, action, next_state) \
417  { \
418  struct event *e; \
419  e = &current_event->u.event; \
420  if (sm->state == state_name && \
421  current_event->type == event && \
422  (condition)) { \
423  action \
424  sm->state = next_state; \
425  debug("wap.wsp", 0, "WSP %ld: New state %s", \
426  sm->session_id, #next_state); \
427  goto end; \
428  } \
429  }
431 
432  cant_handle_event(sm, current_event);
433 
434 end:
435  wap_event_destroy(current_event);
436 
437  if (sm->state == NULL_SESSION)
438  machine_destroy(sm);
439 }
440 
441 
442 static void cant_handle_event(WSPMachine *sm, WAPEvent *event) {
443  /* We do the rest of the pre-state-machine tests here. The first
444  * four were done in find_session_machine(). The fifth is a
445  * class 1 or 2 TR-Invoke.ind not handled by the state tables. */
446  if (event->type == TR_Invoke_Ind &&
447  (event->u.TR_Invoke_Ind.tcl == 1 ||
448  event->u.TR_Invoke_Ind.tcl == 2)) {
449  warning(0, "WSP: Can't handle TR-Invoke.ind, aborting transaction.");
450  debug("wap.wsp", 0, "WSP: The unhandled event:");
451  wap_event_dump(event);
453  event->u.TR_Invoke_Ind.handle);
454  /* The sixth is a class 0 TR-Invoke.ind not handled by state tables. */
455  } else if (event->type == TR_Invoke_Ind) {
456  warning(0, "WSP: Can't handle TR-Invoke.ind, ignoring.");
457  debug("wap.wsp", 0, "WSP: The ignored event:");
458  wap_event_dump(event);
459  /* The seventh is any other event not handled by state tables. */
460  } else {
461  error(0, "WSP: Can't handle event. Aborting session.");
462  debug("wap.wsp", 0, "WSP: The unhandled event:");
463  wap_event_dump(event);
464  /* TR-Abort.req(PROTOERR) if it is some other transaction
465  * event than abort. */
466  /* Currently that means TR-Result.cnf, because we already
467  * tested for Invoke. */
468  /* FIXME We need a better way to get at event values than
469  * by hardcoding the types. */
470  if (event->type == TR_Result_Cnf) {
472  event->u.TR_Result_Cnf.handle);
473  }
474  /* Abort(PROTOERR) all method and push transactions */
477  /* S-Disconnect.ind(PROTOERR) */
479  }
480 }
481 
482 
483 static WSPMachine *machine_create(void) {
484  WSPMachine *p;
485 
486  p = gw_malloc(sizeof(WSPMachine));
487  debug("wap.wsp", 0, "WSP: Created WSPMachine %p", (void *) p);
488 
489  #define INTEGER(name) p->name = 0;
490  #define OCTSTR(name) p->name = NULL;
491  #define HTTPHEADERS(name) p->name = NULL;
492  #define ADDRTUPLE(name) p->name = NULL;
493  #define MACHINESLIST(name) p->name = gwlist_create();
494  #define CAPABILITIES(name) p->name = NULL;
495  #define COOKIES(name) p->name = gwlist_create();
496  #define REFERER(name) p->name = NULL;
497  #define MACHINE(fields) fields
499 
500  p->state = NULL_SESSION;
501 
502  /* set capabilities to default values (defined in 1.1) */
503 
504  p->client_SDU_size = 1400;
505  p->MOR_push = 1;
506 
507  /* Insert new machine at the _front_, because 1) it's more likely
508  * to get events than old machines are, so this speeds up the linear
509  * search, and 2) we want the newest machine to get any method
510  * invokes that come through before the Connect is established. */
512 
513  return p;
514 }
515 
516 
517 static void destroy_methodmachines(List *machines) {
518  if (gwlist_len(machines) > 0) {
519  warning(0, "Destroying WSP session with %ld active methods\n",
520  gwlist_len(machines));
521  }
522 
524 }
525 
526 static void destroy_pushmachines(List *machines) {
527  if (gwlist_len(machines) > 0) {
528  warning(0, "Destroying WSP session with %ld active pushes\n",
529  gwlist_len(machines));
530  }
531 
533 }
534 
535 static void machine_destroy(void *pp) {
536  WSPMachine *p;
537 
538  p = pp;
539  debug("wap.wsp", 0, "Destroying WSPMachine %p", pp);
541 
542  #define INTEGER(name) p->name = 0;
543  #define OCTSTR(name) octstr_destroy(p->name);
544  #define HTTPHEADERS(name) http_destroy_headers(p->name);
545  #define ADDRTUPLE(name) wap_addr_tuple_destroy(p->name);
546  #define MACHINESLIST(name) destroy_##name(p->name);
547  #define CAPABILITIES(name) wsp_cap_destroy_list(p->name);
548  #define COOKIES(name) cookies_destroy(p->name);
549  #define REFERER(name) octstr_destroy(p->name);
550  #define MACHINE(fields) fields
552  gw_free(p);
553 }
554 
555 
556 struct msm_pattern {
558  long msmid, tid;
559 };
560 
561 
562 /* This function does NOT consume its event; it leaves that task up
563  * to the parent session */
565 WAPEvent *current_event, WSP_PDU *pdu) {
566 
567  if (msm == NULL) {
568  warning(0, "No method machine for event.");
569  wap_event_dump(current_event);
570  return;
571  }
572 
573  debug("wap.wsp", 0, "WSP: method %ld, state %s, event %s",
574  msm->transaction_id, state_name(msm->state),
575  wap_event_name(current_event->type));
576 
577  gw_assert(sm->session_id == msm->session_id);
578 
579  #define STATE_NAME(name)
580  #define ROW(state_name, event, condition, action, next_state) \
581  { \
582  struct event *e; \
583  e = &current_event->u.event; \
584  if (msm->state == state_name && \
585  current_event->type == event && \
586  (condition)) { \
587  action \
588  msm->state = next_state; \
589  debug("wap.wsp", 0, "WSP %ld/%ld: New method state %s", \
590  msm->session_id, msm->transaction_id, #next_state); \
591  goto end; \
592  } \
593  }
595 
596  cant_handle_event(sm, current_event);
597 
598 end:
599  if (msm->state == NULL_METHOD) {
601  gwlist_delete_equal(sm->methodmachines, msm);
602  }
603 }
604 
605 
607  long wtp_handle) {
608  WSPMethodMachine *msm;
609 
610  msm = gw_malloc(sizeof(*msm));
611 
612  #define INTEGER(name) msm->name = 0;
613  #define ADDRTUPLE(name) msm->name = NULL;
614  #define EVENT(name) msm->name = NULL;
615  #define MACHINE(fields) fields
617 
618  msm->transaction_id = wtp_handle;
619  msm->state = NULL_METHOD;
620  msm->addr_tuple = wap_addr_tuple_duplicate(sm->addr_tuple);
621  msm->session_id = sm->session_id;
622 
623  gwlist_append(sm->methodmachines, msm);
624 
625  return msm;
626 }
627 
628 
629 
630 static void method_machine_destroy(void *p) {
631  WSPMethodMachine *msm;
632 
633  if (p == NULL)
634  return;
635 
636  msm = p;
637 
638  debug("wap.wsp", 0, "Destroying WSPMethodMachine %ld",
639  msm->transaction_id);
640 
641  #define INTEGER(name)
642  #define ADDRTUPLE(name) wap_addr_tuple_destroy(msm->name);
643  #define EVENT(name) wap_event_destroy(msm->name);
644  #define MACHINE(fields) fields
646 
647  gw_free(msm);
648 }
649 
651  WAPEvent *current_event)
652 {
653  if (pm == NULL) {
654  warning(0, "No push machine for event.");
655  wap_event_dump(current_event);
656  return;
657  }
658 
659  debug("wap.wsp", 0, "WSP(tid/pid): push %ld/%ld, state %s, event %s",
660  pm->transaction_id, pm->server_push_id, state_name(pm->state),
661  wap_event_name(current_event->type));
662  gw_assert(sm->session_id == pm->session_id);
663 
664  #define STATE_NAME(name)
665  #define ROW(state_name, event, condition, action, next_state) \
666  { \
667  if (pm->state == state_name && \
668  current_event->type == event && \
669  (condition)) { \
670  action \
671  pm->state = next_state; \
672  debug("wap.wsp", 0, "WSP %ld/%ld: New push state %s", \
673  pm->session_id, pm->transaction_id, #next_state); \
674  goto end; \
675  } \
676  }
677  #include "wsp_server_push_states.def"
678 
679  cant_handle_event(sm, current_event);
680 end:
681  if (pm->state == SERVER_PUSH_NULL_STATE) {
683  gwlist_delete_equal(sm->pushmachines, pm);
684  }
685 }
686 
688  long pid)
689 {
690  WSPPushMachine *m;
691 
692  m = gw_malloc(sizeof(WSPPushMachine));
693 
694  #define INTEGER(name) m->name = 0;
695  #define ADDRTUPLE(name) m->name = NULL;
696  #define HTTPHEADER(name) m->name = http_create_empty_headers();
697  #define MACHINE(fields) fields
698  #include "wsp_server_push_machine.def"
699 
700  m->server_push_id = pid;
701  m->transaction_id = pid;
702  m->state = SERVER_PUSH_NULL_STATE;
703  m->addr_tuple = wap_addr_tuple_duplicate(sm->addr_tuple);
704  m->session_id = sm->session_id;
705 
706  gwlist_append(sm->pushmachines, m);
707 
708  return m;
709 }
710 
711 static void push_machine_destroy(void *p)
712 {
713  WSPPushMachine *m = NULL;
714 
715  if (p == NULL)
716  return;
717  m = p;
718  debug("wap.wsp", 0, "Destroying WSPPushMachine %ld",
719  m->transaction_id);
720  #define INTEGER(name)
721  #define ADDRTUPLE(name) wap_addr_tuple_destroy(m->name);
722  #define HTTPHEADER(name) http_destroy_headers(m->name);
723  #define MACHINE(fields) fields
724  #include "wsp_server_push_machine.def"
725 
726  gw_free(m);
727 }
728 
729 static char *state_name(WSPState state) {
730  switch (state) {
731  #define STATE_NAME(name) case name: return #name;
732  #define ROW(state, event, cond, stmt, next_state)
734 
735  #define STATE_NAME(name) case name: return #name;
736  #define ROW(state, event, cond, stmt, next_state)
738 
739  #define STATE_NAME(name) case name: return #name;
740  #define ROW(state, event, cond, stmt, next_state)
741  #include "wsp_server_push_states.def"
742 
743  default:
744  return "unknown wsp state";
745  }
746 }
747 
748 
749 static unsigned long next_wsp_session_id(void) {
751 }
752 
753 
754 static void sanitize_capabilities(List *caps, WSPMachine *m) {
755  long i;
756  Capability *cap;
757  unsigned long ui;
758 
759  for (i = 0; i < gwlist_len(caps); i++) {
760  cap = gwlist_get(caps, i);
761 
762  /* We only know numbered capabilities. Let the application
763  * layer negotiate whatever it wants for unknown ones. */
764  if (cap->name != NULL)
765  continue;
766 
767  switch (cap->id) {
769  /* Check if it's a valid uintvar. The value is the
770  * max SDU size we will send, and there's no
771  * internal limit to that, so accept any value. */
772  if (cap->data != NULL &&
773  octstr_extract_uintvar(cap->data, &ui, 0) < 0)
774  goto bad_cap;
775  else
776  m->client_SDU_size = ui;
777  break;
778 
780  /* Check if it's a valid uintvar */
781  if (cap->data != NULL &&
782  (octstr_extract_uintvar(cap->data, &ui, 0) < 0))
783  goto bad_cap;
784  /* XXX Our MRU is not quite unlimited, since we
785  * use signed longs in the library functions --
786  * should we make sure we limit the reply value
787  * to LONG_MAX? (That's already a 2GB packet) */
788  break;
789 
791  /* Currently we don't support any Push, nor
792  * session resume, nor acknowledgement headers,
793  * so make sure those bits are not set. */
794  if (cap->data != NULL && octstr_len(cap->data) > 0
795  && (octstr_get_char(cap->data, 0) & 0xf0) != 0) {
796  warning(0, "WSP: Application layer tried to "
797  "negotiate protocol options.");
798  octstr_set_bits(cap->data, 0, 4, 0);
799  }
800  break;
801 
803  /* XXX Check format here */
804  break;
805 
806 
808  /* We don't support any yet, so don't let this
809  * be negotiated. */
810  if (cap->data)
811  goto bad_cap;
812  break;
813  }
814  continue;
815 
816  bad_cap:
817  error(0, "WSP: Found illegal value in capabilities reply.");
818  wsp_cap_dump(cap);
819  gwlist_delete(caps, i, 1);
820  i--;
821  wsp_cap_destroy(cap);
822  continue;
823  }
824 }
825 
826 
827 static void reply_known_capabilities(List *caps, List *req, WSPMachine *m) {
828  unsigned long ui;
829  Capability *cap;
830  Octstr *data;
831 
832  if (wsp_cap_count(caps, WSP_CAPS_CLIENT_SDU_SIZE, NULL) == 0) {
833  if (wsp_cap_get_client_sdu(req, &ui) > 0) {
834  /* Accept value if it is not silly. */
835  if ((ui >= 256 && ui < LONG_MAX) || ui == 0) {
836  m->client_SDU_size = ui;
837  }
838  }
839  /* Reply with the client SDU we decided on */
840  data = octstr_create("");
841  octstr_append_uintvar(data, m->client_SDU_size);
843  NULL, data);
844  gwlist_append(caps, cap);
845  }
846 
847  if (wsp_cap_count(caps, WSP_CAPS_SERVER_SDU_SIZE, NULL) == 0) {
848  /* Accept whatever size the client is willing
849  * to send. If the client did not specify anything,
850  * then use the default. */
851  if (wsp_cap_get_server_sdu(req, &ui) <= 0) {
852  ui = 1400;
853  }
854  data = octstr_create("");
855  octstr_append_uintvar(data, ui);
856  cap = wsp_cap_create(WSP_CAPS_SERVER_SDU_SIZE, NULL, data);
857  gwlist_append(caps, cap);
858  }
859 
860  /* Currently we cannot handle any protocol options */
861  if (wsp_cap_count(caps, WSP_CAPS_PROTOCOL_OPTIONS, NULL) == 0) {
862  data = octstr_create("");
863  octstr_append_char(data, 0);
864  cap = wsp_cap_create(WSP_CAPS_PROTOCOL_OPTIONS, NULL, data);
865  gwlist_append(caps, cap);
866  }
867 
868  /* Accept any Method-MOR the client sent; if it sent none,
869  * use the default. */
870  if (wsp_cap_count(caps, WSP_CAPS_METHOD_MOR, NULL) == 0) {
871  if (wsp_cap_get_method_mor(req, &ui) <= 0) {
872  ui = 1;
873  }
874  data = octstr_create("");
875  octstr_append_char(data, ui);
876  cap = wsp_cap_create(WSP_CAPS_METHOD_MOR, NULL, data);
877  gwlist_append(caps, cap);
878  }
879 
880  /* We will never send any Push requests because we don't support
881  * that yet. But we already specified that in protocol options;
882  * so, pretend we do, and handle the value that way. */
883  if (wsp_cap_count(caps, WSP_CAPS_PUSH_MOR, NULL) == 0) {
884  if (wsp_cap_get_push_mor(req, &ui) > 0) {
885  m->MOR_push = ui;
886  }
887  data = octstr_create("");
888  octstr_append_char(data, m->MOR_push);
889  cap = wsp_cap_create(WSP_CAPS_PUSH_MOR, NULL, data);
890  gwlist_append(caps, cap);
891  }
892 
893  /* Supporting extended methods is up to the application layer,
894  * not up to us. If the application layer didn't specify any,
895  * then we refuse whatever the client requested. The default
896  * is to support none, so we don't really have to add anything here. */
897 
898  /* We do not support any header code pages. sanitize_capabilities
899  * must have already deleted any reply that indicates otherwise.
900  * Again, not adding anything here is the same as refusing support. */
901 
902  /* Listing aliases is something the application layer can do if
903  * it wants to. We don't care. */
904 }
905 
906 
907 /* Generate a refusal for all requested capabilities that are not
908  * replied to. */
909 static void refuse_unreplied_capabilities(List *caps, List *req) {
910  long i, len;
911  Capability *cap;
912 
913  len = gwlist_len(req);
914  for (i = 0; i < len; i++) {
915  cap = gwlist_get(req, i);
916  if (wsp_cap_count(caps, cap->id, cap->name) == 0) {
917  cap = wsp_cap_create(cap->id, cap->name, NULL);
918  gwlist_append(caps, cap);
919  }
920  }
921 }
922 
923 
924 static int is_default_cap(Capability *cap) {
925  unsigned long ui;
926 
927  /* All unknown values are empty by default */
928  if (cap->name != NULL || cap->id < 0 || cap->id >= WSP_NUM_CAPS)
929  return cap->data == NULL || octstr_len(cap->data) == 0;
930 
931  switch (cap->id) {
934  return (cap->data != NULL &&
935  octstr_extract_uintvar(cap->data, &ui, 0) >= 0 &&
936  ui == 1400);
938  return cap->data != NULL && octstr_get_char(cap->data, 0) == 0;
939  case WSP_CAPS_METHOD_MOR:
940  case WSP_CAPS_PUSH_MOR:
941  return cap->data != NULL && octstr_get_char(cap->data, 0) == 1;
944  case WSP_CAPS_ALIASES:
945  return cap->data == NULL || octstr_len(cap->data) == 0;
946  default:
947  return 0;
948  }
949 }
950 
951 
952 /* Remove any replies that have no corresponding request and that
953  * are equal to the default. */
954 static void strip_default_capabilities(List *caps, List *req) {
955  long i;
956  Capability *cap;
957  int count;
958 
959  /* Hmm, this is an O(N*N) operation, which may be bad. */
960 
961  i = 0;
962  while (i < gwlist_len(caps)) {
963  cap = gwlist_get(caps, i);
964 
965  count = wsp_cap_count(req, cap->id, cap->name);
966  if (count == 0 && is_default_cap(cap)) {
967  gwlist_delete(caps, i, 1);
968  wsp_cap_destroy(cap);
969  } else {
970  i++;
971  }
972  }
973 }
974 
975 
977  List *caps;
978 
979  /* In principle, copy the application layer's capabilities
980  * response, add refusals for all unknown requested capabilities,
981  * and add responses for all known capabilities that are
982  * not already responded to. Then eliminate any replies that
983  * would have no effect because they are equal to the default. */
984 
985  caps = wsp_cap_duplicate_list(m->reply_caps);
986 
987  /* Don't let the application layer negotiate anything we
988  * cannot handle. Also parse the values it set if we're
989  * interested. */
990  sanitize_capabilities(caps, m);
991 
992  /* Add capability records for all capabilities we know about
993  * that are not already in the reply list. */
994  reply_known_capabilities(caps, m->request_caps, m);
995 
996  /* All remaining capabilities in the request list that are
997  * not in the reply list at this point must be unknown ones
998  * that we want to refuse. */
999  refuse_unreplied_capabilities(caps, m->request_caps);
1000 
1001  /* Now eliminate replies that would be equal to the requested
1002  * value, or (if there was none) to the default value. */
1003  strip_default_capabilities(caps, m->request_caps);
1004 
1005  return caps;
1006 }
1007 
1008 
1010 {
1011  List *headers;
1012  Octstr *encoding_version;
1013 
1014  /* Add all server wsp level hop-by-hop headers. Currently only
1015  * Encoding-Version, as defined by wsp, chapter 8.4.2.70.
1016  * What headers belong to which version is defined in appendix A,
1017  * table 39..
1018  encoding_version = request_version = NULL;
1019  * Essentially, if the client sends us an Encoding-Version
1020  * higher than ours (1.3) we send our version number to it,
1021  * if it is lower, we left version number intact. */
1022  /* First the case that we have no Encoding-Version header at all.
1023  * This case we must assume that the client supports version 1.2
1024  * or lower. */
1025 
1026  headers = http_create_empty_headers();
1027  encoding_version = wsp_encoding_version_to_string(m->encoding_version);
1028  http_header_add(headers, "Encoding-Version", octstr_get_cstr(encoding_version));
1029  octstr_destroy(encoding_version);
1030 
1031  return headers;
1032 }
1033 
1035 {
1036  WSP_PDU *pdu;
1037  Octstr *os;
1038  List *caps;
1039  List *reply_headers;
1040 
1041  pdu = wsp_pdu_create(ConnectReply);
1042 
1043  pdu->u.ConnectReply.sessionid = m->session_id;
1044 
1045  caps = make_capabilities_reply(m);
1046  pdu->u.ConnectReply.capabilities = wsp_cap_pack_list(caps);
1047  wsp_cap_destroy_list(caps);
1048 
1049  reply_headers = make_reply_headers(m);
1050  pdu->u.ConnectReply.headers =
1051  wsp_headers_pack(reply_headers, 0, m->encoding_version);
1052  http_destroy_headers(reply_headers);
1053 
1054  os = wsp_pdu_pack(pdu);
1055  wsp_pdu_destroy(pdu);
1056 
1057  return os;
1058 }
1059 
1060 
1062 {
1063  WSP_PDU *pdu;
1064  Octstr *os;
1065 
1066  pdu = wsp_pdu_create(Reply);
1067 
1068  /* Not specified for Resume replies */
1069  pdu->u.Reply.status = wsp_convert_http_status_to_wsp_status(HTTP_OK);
1070  if (headers == NULL) {
1071  headers = http_create_empty_headers();
1072  pdu->u.Reply.headers = wsp_headers_pack(headers, 1, m->encoding_version);
1073  http_destroy_headers(headers);
1074  } else {
1075  pdu->u.Reply.headers = wsp_headers_pack(headers, 1, m->encoding_version);
1076  }
1077  pdu->u.Reply.data = octstr_create("");
1078 
1079  os = wsp_pdu_pack(pdu);
1080  wsp_pdu_destroy(pdu);
1081 
1082  return os;
1083 }
1084 
1086 {
1087  WSP_PDU *pdu;
1088  List *headers;
1089 
1090  pdu = wsp_pdu_create(ConfirmedPush);
1091 /*
1092  * Both push headers and push body are optional.
1093  */
1094  if (e->u.S_ConfirmedPush_Req.push_headers == NULL) {
1095  headers = http_create_empty_headers();
1096  pdu->u.ConfirmedPush.headers = wsp_headers_pack(headers, 1, WSP_1_2);
1097  http_destroy_headers(headers);
1098  } else
1099  pdu->u.ConfirmedPush.headers =
1100  wsp_headers_pack(e->u.S_ConfirmedPush_Req.push_headers, 1, WSP_1_2);
1101 
1102  if (e->u.S_ConfirmedPush_Req.push_body == NULL)
1103  pdu->u.ConfirmedPush.data = octstr_create("");
1104  else
1105  pdu->u.ConfirmedPush.data =
1106  octstr_duplicate(e->u.S_ConfirmedPush_Req.push_body);
1107 
1108  return pdu;
1109 }
1110 
1112 {
1113  WSP_PDU *pdu;
1114  List *headers;
1115 
1116  pdu = wsp_pdu_create(Push);
1117 /*
1118  * Both push headers and push body are optional
1119  */
1120  if (e->u.S_Push_Req.push_headers == NULL) {
1121  headers = http_create_empty_headers();
1122  pdu->u.Push.headers = wsp_headers_pack(headers, 1, WSP_1_2);
1123  http_destroy_headers(headers);
1124  } else
1125  pdu->u.Push.headers =
1126  wsp_headers_pack(e->u.S_Push_Req.push_headers, 1, WSP_1_2);
1127 
1128  if (e->u.S_Push_Req.push_body == NULL)
1129  pdu->u.Push.data = octstr_create("");
1130  else
1131  pdu->u.Push.data =
1132  octstr_duplicate(e->u.S_Push_Req.push_body);
1133 
1134  return pdu;
1135 }
1136 
1137 static int transaction_belongs_to_session(void *wsp_ptr, void *tuple_ptr) {
1138  WSPMachine *wsp;
1139  WAPAddrTuple *tuple;
1140 
1141  wsp = wsp_ptr;
1142  tuple = tuple_ptr;
1143 
1144  return wap_addr_tuple_same(wsp->addr_tuple, tuple);
1145 }
1146 
1147 
1148 static int find_by_session_id(void *wsp_ptr, void *id_ptr) {
1149  WSPMachine *wsp = wsp_ptr;
1150  long *idp = id_ptr;
1151 
1152  return wsp->session_id == *idp;
1153 }
1154 
1155 
1156 static int find_by_method_id(void *wspm_ptr, void *id_ptr) {
1157  WSPMethodMachine *msm = wspm_ptr;
1158  long *idp = id_ptr;
1159 
1160  return msm->transaction_id == *idp;
1161 }
1162 
1163 static int find_by_push_id(void *m_ptr, void *id_ptr) {
1164  WSPPushMachine *m = m_ptr;
1165  long *idp = id_ptr;
1166 
1167  return m->transaction_id == *idp;
1168 }
1169 
1171  return gwlist_search(sm->methodmachines, &id, find_by_method_id);
1172 }
1173 
1175 {
1176  return gwlist_search(m->pushmachines, &id, find_by_push_id);
1177 }
1178 
1179 static int same_client(void *a, void *b) {
1180  WSPMachine *sm1, *sm2;
1181 
1182  sm1 = a;
1183  sm2 = b;
1184  return wap_addr_tuple_same(sm1->addr_tuple, sm2->addr_tuple);
1185 }
1186 
1187 
1189  List *old_sessions;
1190  WAPEvent *disconnect;
1191  WSPMachine *sm2;
1192  long i;
1193 
1194  old_sessions = gwlist_search_all(session_machines, sm, same_client);
1195  if (old_sessions == NULL)
1196  return;
1197 
1198  for (i = 0; i < gwlist_len(old_sessions); i++) {
1199  sm2 = gwlist_get(old_sessions, i);
1200  if (sm2 != sm) {
1201  disconnect = wap_event_create(Disconnect_Event);
1202  handle_session_event(sm2, disconnect, NULL);
1203  }
1204  }
1205 
1206  gwlist_destroy(old_sessions, NULL);
1207 }
1208 
1209 
1211  List *new_headers;
1212 
1213  if (hdrs && octstr_len(hdrs) > 0) {
1214  new_headers = wsp_headers_unpack(hdrs, 0);
1215  if (sm->http_headers == NULL)
1216  sm->http_headers = http_create_empty_headers();
1217  http_header_combine(sm->http_headers, new_headers);
1218  return new_headers;
1219  }
1220  return NULL;
1221 }
1222 
1223 static WAPEvent *make_abort(long reason, long handle)
1224 {
1225  WAPEvent *wtp_event;
1226 
1227  wtp_event = wap_event_create(TR_Abort_Req);
1228  wtp_event->u.TR_Abort_Req.abort_type = 0x01;
1229  wtp_event->u.TR_Abort_Req.abort_reason = reason;
1230  wtp_event->u.TR_Abort_Req.handle = handle;
1231 
1232  return wtp_event;
1233 }
1234 
1235 static void send_abort(long reason, long handle) {
1236  WAPEvent *wtp_event;
1237 
1238  wtp_event = make_abort(reason, handle);
1239  dispatch_to_wtp_resp(wtp_event);
1240 }
1241 
1242 static void send_abort_to_initiator(long reason, long handle)
1243 {
1244  WAPEvent *wtp_event;
1245 
1246  wtp_event = make_abort(reason, handle);
1247  dispatch_to_wtp_init(wtp_event);
1248 }
1249 
1250 /*
1251  * The server sends invoke (to be exact, makes TR-Invoke.req) only when it is
1252  * pushing. (Only the client disconnects sessions.)
1253  */
1254 static void send_invoke(WSPMachine *m, WSP_PDU *pdu, WAPEvent *e, long class)
1255 {
1256  WAPEvent *wtp_event;
1257 
1258  wtp_event = wap_event_create(TR_Invoke_Req);
1259  wtp_event->u.TR_Invoke_Req.addr_tuple =
1260  wap_addr_tuple_duplicate(m->addr_tuple);
1261 /*
1262  * There is no mention of acknowledgement type in the specs. But because
1263  * confirmed push is confirmed after response from OTA, provider acknowledge-
1264  * ments seem redundant.
1265  */
1266  wtp_event->u.TR_Invoke_Req.up_flag = USER_ACKNOWLEDGEMENT;
1267  wtp_event->u.TR_Invoke_Req.tcl = class;
1268  if (e->type == S_ConfirmedPush_Req)
1269  wtp_event->u.TR_Invoke_Req.handle =
1270  e->u.S_ConfirmedPush_Req.server_push_id;
1271  wtp_event->u.TR_Invoke_Req.user_data = wsp_pdu_pack(pdu);
1272 
1273  wsp_pdu_destroy(pdu);
1274  dispatch_to_wtp_init(wtp_event);
1275 }
1276 
1277 static void indicate_disconnect(WSPMachine *sm, long reason) {
1278  WAPEvent *new_event;
1279 
1280  new_event = wap_event_create(S_Disconnect_Ind);
1281  new_event->u.S_Disconnect_Ind.reason_code = reason;
1282  new_event->u.S_Disconnect_Ind.redirect_security = 0;
1283  new_event->u.S_Disconnect_Ind.redirect_addresses = 0;
1284  new_event->u.S_Disconnect_Ind.error_headers = NULL;
1285  new_event->u.S_Disconnect_Ind.error_body = NULL;
1286  new_event->u.S_Disconnect_Ind.session_handle = sm->session_id;
1287  dispatch_to_appl(new_event);
1288 }
1289 
1290 
1291 static void indicate_suspend(WSPMachine *sm, long reason) {
1292  WAPEvent *new_event;
1293 
1294  new_event = wap_event_create(S_Suspend_Ind);
1295  new_event->u.S_Suspend_Ind.reason = reason;
1296  new_event->u.S_Suspend_Ind.session_id = sm->session_id;
1297  dispatch_to_appl(new_event);
1298 }
1299 
1300 
1301 static void indicate_resume(WSPMachine *sm,
1302  WAPAddrTuple *tuple, List *headers) {
1303  WAPEvent *new_event;
1304 
1305  new_event = wap_event_create(S_Resume_Ind);
1306  new_event->u.S_Resume_Ind.addr_tuple = wap_addr_tuple_duplicate(tuple);
1307  new_event->u.S_Resume_Ind.client_headers = http_header_duplicate(headers);
1308  new_event->u.S_Resume_Ind.session_id = sm->session_id;
1309  dispatch_to_appl(new_event);
1310 }
1311 
1312 static void indicate_pushabort(WSPPushMachine *spm, long reason)
1313 {
1314  WAPEvent *ota_event;
1315 
1316  ota_event = wap_event_create(S_PushAbort_Ind);
1317  ota_event->u.S_PushAbort_Ind.push_id = spm->server_push_id;
1318  ota_event->u.S_PushAbort_Ind.reason = reason;
1319  ota_event->u.S_PushAbort_Ind.session_id = spm->session_id;
1320  dispatch_to_appl(ota_event);
1321 }
1322 
1324 {
1325  WAPEvent *ota_event;
1326 
1327  ota_event = wap_event_create(S_ConfirmedPush_Cnf);
1328  ota_event->u.S_ConfirmedPush_Cnf.server_push_id = m->server_push_id;
1329  ota_event->u.S_ConfirmedPush_Cnf.session_id = m->session_id;
1330  dispatch_to_appl(ota_event);
1331 }
1332 
1333 static void method_abort(WSPMethodMachine *msm, long reason) {
1334  WAPEvent *wtp_event;
1335 
1336  /* Send TR-Abort.req(reason) */
1337  wtp_event = wap_event_create(TR_Abort_Req);
1338  /* FIXME: Specs are unclear about this; we may indeed have to
1339  * guess abort whether this is a WSP or WTP level abort code */
1340  if (reason < WSP_ABORT_PROTOERR) {
1341  wtp_event->u.TR_Abort_Req.abort_type = 0x00;
1342  } else {
1343  wtp_event->u.TR_Abort_Req.abort_type = 0x01;
1344  }
1345  wtp_event->u.TR_Abort_Req.abort_reason = reason;
1346  wtp_event->u.TR_Abort_Req.handle = msm->transaction_id;
1347 
1348  dispatch_to_wtp_resp(wtp_event);
1349 }
1350 
1351 
1352 static void indicate_method_abort(WSPMethodMachine *msm, long reason) {
1353  WAPEvent *new_event;
1354 
1355  /* Send S-MethodAbort.ind(reason) */
1356  new_event = wap_event_create(S_MethodAbort_Ind);
1357  new_event->u.S_MethodAbort_Ind.transaction_id = msm->transaction_id;
1358  new_event->u.S_MethodAbort_Ind.reason = reason;
1359  new_event->u.S_MethodAbort_Ind.session_handle = msm->session_id;
1360  dispatch_to_appl(new_event);
1361 }
1362 
1363 
1364 static int method_is_holding(void *item, void *pattern) {
1365  WSPMethodMachine *msm = item;
1366 
1367  return msm->state == HOLDING;
1368 }
1369 
1370 
1372  WAPEvent *release;
1373  WSPMethodMachine *msm;
1374  List *holding;
1375  long i, len;
1376 
1377  holding = gwlist_search_all(sm->methodmachines, NULL, method_is_holding);
1378  if (holding == NULL)
1379  return;
1380 
1381  /* We can re-use this because wsp_handle_method_event does not
1382  * destroy its event */
1383  release = wap_event_create(Release_Event);
1384 
1385  len = gwlist_len(holding);
1386  for (i = 0; i < len; i++) {
1387  msm = gwlist_get(holding, i);
1388  handle_method_event(sm, msm, release, NULL);
1389  }
1390  gwlist_destroy(holding, NULL);
1391  wap_event_destroy(release);
1392 }
1393 
1394 
1395 static void abort_methods(WSPMachine *sm, long reason) {
1396  WAPEvent *ab;
1397  WSPMethodMachine *msm;
1398  long i, len;
1399 
1400  ab = wap_event_create(Abort_Event);
1401  ab->u.Abort_Event.reason = reason;
1402 
1403  /* This loop goes backward because it has to deal with the
1404  * possibility of method machines disappearing after their event. */
1405  len = gwlist_len(sm->methodmachines);
1406  for (i = len - 1; i >= 0; i--) {
1407  msm = gwlist_get(sm->methodmachines, i);
1408  handle_method_event(sm, msm, ab, NULL);
1409  }
1410 
1411  wap_event_destroy(ab);
1412 }
1413 
1414 
1415 static void abort_pushes(WSPMachine *sm, long reason)
1416 {
1417  WAPEvent *ab;
1418  WSPPushMachine *psm;
1419  long i, len;
1420 
1421  ab = wap_event_create(Abort_Event);
1422  ab->u.Abort_Event.reason = reason;
1423 
1424  len = gwlist_len(sm->pushmachines);
1425  for (i = len - 1; i >= 0; i--) {
1426  psm = gwlist_get(sm->pushmachines, i);
1427  handle_push_event(sm, psm, ab);
1428  }
1429 
1430  wap_event_destroy(ab);
1431 }
1432 
1433 
1435 
1437 }
1438 
1439 
1440 static int id_belongs_to_session (void *wsp_ptr, void *pid) {
1441  WSPMachine *wsp;
1442  int *id;
1443 
1444  wsp = wsp_ptr;
1445  id = (int *) pid;
1446 
1447  if (*id == wsp->session_id) return 1;
1448  return 0;
1449 }
1450 
1451 
1453 {
1454  int v;
1455 
1456  /* default will be WSP 1.2, as defined by WAPWSP */
1457  v = WSP_1_2;
1458 
1459  if (octstr_compare(enc, octstr_imm("1.1")) == 0) {
1460  v = WSP_1_1;
1461  }
1462  else if (octstr_compare(enc, octstr_imm("1.2")) == 0) {
1463  v = WSP_1_2;
1464  }
1465  else if (octstr_compare(enc, octstr_imm("1.3")) == 0) {
1466  v = WSP_1_3;
1467  }
1468  else if (octstr_compare(enc, octstr_imm("1.4")) == 0) {
1469  v = WSP_1_4;
1470  }
1471  else if (octstr_compare(enc, octstr_imm("1.5")) == 0) {
1472  v = WSP_1_5;
1473  }
1474 
1475  return v;
1476 }
1477 
1479 {
1480  Octstr *os;
1481 
1482  switch (version) {
1483  case WSP_1_1:
1484  os = octstr_create("1.1");
1485  break;
1486  case WSP_1_2:
1487  os = octstr_create("1.2");
1488  break;
1489  case WSP_1_3:
1490  os = octstr_create("1.3");
1491  break;
1492  case WSP_1_4:
1493  os = octstr_create("1.4");
1494  break;
1495  case WSP_1_5:
1496  os = octstr_create("1.5");
1497  break;
1498  default:
1499  os = octstr_create("1.2");
1500  break;
1501  }
1502 
1503  return os;
1504 }
1505 
static List * queue
Definition: wsp_session.c:122
long wsp_convert_http_status_to_wsp_status(long http_status)
Definition: wsp.c:77
void error(int err, const char *fmt,...)
Definition: log.c:648
int wsp_cap_get_push_mor(List *caps_list, unsigned long *mor)
Definition: wsp_caps.c:328
void wsp_session_shutdown(void)
Definition: wsp_session.c:211
union wsp_pdu::@89 u
Definition: wsp.h:73
void * gwlist_search(List *list, void *pattern, int(*cmp)(void *, void *))
Definition: list.c:486
static void release_holding_methods(WSPMachine *sm)
Definition: wsp_session.c:1371
static int find_by_session_id(void *session, void *idp)
Definition: wsp_session.c:1148
void wsp_cap_destroy_list(List *caps_list)
Definition: wsp_caps.c:121
void http_header_add(List *headers, char *name, char *contents)
Definition: http.c:2886
gw_assert(wtls_machine->packet_to_send !=NULL)
int wsp_cap_get_server_sdu(List *caps_list, unsigned long *sdu)
Definition: wsp_caps.c:300
void counter_destroy(Counter *counter)
Definition: counter.c:110
static void handle_push_event(WSPMachine *session, WSPPushMachine *machine, WAPEvent *e)
Definition: wsp_session.c:650
void gwlist_append(List *list, void *item)
Definition: list.c:179
static void indicate_resume(WSPMachine *sm, WAPAddrTuple *tuple, List *client_headers)
Definition: wsp_session.c:1301
static void indicate_disconnect(WSPMachine *sm, long reason)
Definition: wsp_session.c:1277
Octstr * wsp_headers_pack(List *headers, int separate_content_type, int wsp_version)
Definition: wsp_headers.c:2963
static void abort_methods(WSPMachine *sm, long reason)
Definition: wsp_session.c:1395
static void handle_session_event(WSPMachine *machine, WAPEvent *event, WSP_PDU *pdu)
Definition: wsp_session.c:408
static unsigned long next_wsp_session_id(void)
Definition: wsp_session.c:749
void gwlist_produce(List *list, void *item)
Definition: list.c:411
int id
Definition: wsp_caps.h:72
long gwlist_len(List *list)
Definition: list.c:166
static WSP_PDU * make_confirmedpush_pdu(WAPEvent *e)
Definition: wsp_session.c:1085
void * gwlist_get(List *list, long pos)
Definition: list.c:292
void octstr_set_bits(Octstr *ostr, long bitpos, int numbits, unsigned long value)
Definition: octstr.c:1849
void http_header_combine(List *old_headers, List *new_headers)
Definition: http.c:3068
static void sanitize_capabilities(List *caps, WSPMachine *m)
Definition: wsp_session.c:754
void octstr_append_char(Octstr *ostr, int ch)
Definition: octstr.c:1517
Capability * wsp_cap_create(int id, Octstr *name, Octstr *data)
Definition: wsp_caps.c:71
Definition: wsp.h:75
static void strip_default_capabilities(List *caps, List *req)
Definition: wsp_session.c:954
static void push_machine_destroy(void *p)
Definition: wsp_session.c:711
void wsp_cap_dump(Capability *cap)
Definition: wsp_caps.c:92
static WSPPushMachine * push_machine_create(WSPMachine *session, long id)
Definition: wsp_session.c:687
Octstr * wsp_pdu_pack(WSP_PDU *pdu)
Definition: wsp_pdu.c:271
WAPAddrTuple * addr_tuple
Definition: wsp_session.c:557
static WSP_PDU * make_push_pdu(WAPEvent *e)
Definition: wsp_session.c:1111
static void abort_pushes(WSPMachine *sm, long reason)
Definition: wsp_session.c:1415
List * wsp_cap_duplicate_list(List *caps_list)
Definition: wsp_caps.c:125
static WSPMachine * machine_create(void)
Definition: wsp_session.c:483
static void confirm_push(WSPPushMachine *machine)
Definition: wsp_session.c:1323
static int is_default_cap(Capability *cap)
Definition: wsp_session.c:924
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
static int find_by_method_id(void *wspm_ptr, void *id_ptr)
Definition: wsp_session.c:1156
void wap_event_dump(WAPEvent *event)
Definition: wap_events.c:181
void gwthread_join_every(gwthread_func_t *func)
unsigned long counter_increase(Counter *counter)
Definition: counter.c:123
WAPAddrTuple * wap_addr_tuple_duplicate(WAPAddrTuple *tuple)
Definition: wap_addr.c:125
void wsp_session_init(wap_dispatch_func_t *responder_dispatch, wap_dispatch_func_t *initiator_dispatch, wap_dispatch_func_t *application_dispatch, wap_dispatch_func_t *push_ota_dispatch)
Definition: wsp_session.c:193
Octstr * data
Definition: wsp_caps.h:76
static List * session_machines
Definition: wsp_session.c:123
List * gwlist_search_all(List *list, void *pattern, int(*cmp)(void *, void *))
Definition: list.c:508
static WSPPushMachine * find_push_machine(WSPMachine *m, long id)
Definition: wsp_session.c:1174
void http_destroy_headers(List *headers)
Definition: http.c:2879
WSP_PDU * wsp_pdu_create(int type)
Definition: wsp_pdu.c:68
int wsp_cap_get_client_sdu(List *caps_list, unsigned long *sdu)
Definition: wsp_caps.c:288
static void method_abort(WSPMethodMachine *msm, long reason)
Definition: wsp_session.c:1333
static int same_client(void *sm1, void *sm2)
Definition: wsp_session.c:1179
static void send_invoke(WSPMachine *session, WSP_PDU *pdu, WAPEvent *e, long class)
Definition: wsp_session.c:1254
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:283
Definition: http.h:142
WSPState
Definition: wsp_session.c:79
Counter * counter_create(void)
Definition: counter.c:94
static WSPMachine * find_session_machine(WAPEvent *event, WSP_PDU *pdu)
Definition: wsp_session.c:273
static Octstr * make_resume_reply_pdu(WSPMachine *m, List *headers)
Definition: wsp_session.c:1061
void gwlist_delete(List *list, long pos, long count)
Definition: list.c:232
void wap_event_assert(WAPEvent *event)
Definition: wap_events.c:220
void gwlist_remove_producer(List *list)
Definition: list.c:401
static void destroy_pushmachines(List *machines)
Definition: wsp_session.c:526
List * http_create_empty_headers(void)
Definition: http.c:2872
void wap_event_destroy_item(void *event)
Definition: wap_events.c:130
static WSPMethodMachine * find_method_machine(WSPMachine *, long id)
Definition: wsp_session.c:1170
static void machine_destroy(void *p)
Definition: wsp_session.c:535
#define octstr_duplicate(ostr)
Definition: octstr.h:187
const char * wap_event_name(WAPEventName type)
Definition: wap_events.c:169
int wsp_cap_get_method_mor(List *caps_list, unsigned long *mor)
Definition: wsp_caps.c:312
static void main_thread(void *)
Definition: wsp_session.c:239
long gwlist_delete_equal(List *list, void *item)
Definition: list.c:266
static wap_dispatch_func_t * dispatch_to_appl
Definition: wsp_session.c:110
#define wap_event_create(type)
Definition: wap_events.h:107
int wsp_cap_count(List *caps_list, int id, Octstr *name)
Definition: wsp_caps.c:282
void warning(int err, const char *fmt,...)
Definition: log.c:660
static void refuse_unreplied_capabilities(List *caps, List *req)
Definition: wsp_session.c:909
static Octstr * make_connectreply_pdu(WSPMachine *m)
Definition: wsp_session.c:1034
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:324
void wap_addr_tuple_destroy(WAPAddrTuple *tuple)
Definition: wap_addr.c:108
static void destroy_methodmachines(List *machines)
Definition: wsp_session.c:517
#define gwthread_create(func, arg)
Definition: gwthread.h:90
#define octstr_create(cstr)
Definition: octstr.h:125
static int find_by_push_id(void *m_ptr, void *id_ptr)
Definition: wsp_session.c:1163
static WSPMethodMachine * method_machine_create(WSPMachine *, long)
Definition: wsp_session.c:606
void wsp_pdu_destroy(WSP_PDU *pdu)
Definition: wsp_pdu.c:102
static enum @91 run_status
static int wsp_encoding_string_to_version(Octstr *enc)
Definition: wsp_session.c:1452
static void reply_known_capabilities(List *caps, List *req, WSPMachine *m)
Definition: wsp_session.c:827
void gwlist_insert(List *list, long pos, void *item)
Definition: list.c:214
static void indicate_method_abort(WSPMethodMachine *msm, long reason)
Definition: wsp_session.c:1352
static void indicate_suspend(WSPMachine *sm, long reason)
Definition: wsp_session.c:1291
static int id_belongs_to_session(void *, void *)
Definition: wsp_session.c:1440
static void handle_method_event(WSPMachine *session, WSPMethodMachine *machine, WAPEvent *event, WSP_PDU *pdu)
Definition: wsp_session.c:564
static int transaction_belongs_to_session(void *session, void *tuple)
Definition: wsp_session.c:1137
long octstr_len(const Octstr *ostr)
Definition: octstr.c:342
int wap_addr_tuple_same(WAPAddrTuple *a, WAPAddrTuple *b)
Definition: wap_addr.c:118
static Octstr * wsp_encoding_version_to_string(int version)
Definition: wsp_session.c:1478
void octstr_append_uintvar(Octstr *ostr, unsigned long value)
Definition: octstr.c:1931
WSPMachine * find_session_machine_by_id(int id)
Definition: wsp_session.c:1434
static List * unpack_new_headers(WSPMachine *sm, Octstr *hdrs)
Definition: wsp_session.c:1210
Definition: octstr.c:118
void wsp_strings_shutdown(void)
Definition: wsp_strings.c:286
void * gwlist_consume(List *list)
Definition: list.c:427
void wsp_strings_init(void)
Definition: wsp_strings.c:269
static wap_dispatch_func_t * dispatch_to_wtp_resp
Definition: wsp_session.c:108
List * wsp_headers_unpack(Octstr *headers, int content_type_present)
Definition: wsp_headers.c:1331
Definition: wsp.h:74
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
int type
Definition: wsp_pdu.h:87
static void method_machine_destroy(void *msm)
Definition: wsp_session.c:630
static void send_abort_to_initiator(long reason, long handle)
Definition: wsp_session.c:1242
static WAPEvent * make_abort(long reason, long handle)
Definition: wsp_session.c:1223
static int resume_enabled
Definition: wsp_session.c:120
WAPEventName type
Definition: wap_events.h:88
static List * make_reply_headers(WSPMachine *m)
Definition: wsp_session.c:1009
static wap_dispatch_func_t * dispatch_to_wtp_init
Definition: wsp_session.c:109
static void cant_handle_event(WSPMachine *sm, WAPEvent *event)
Definition: wsp_session.c:442
List * http_header_duplicate(List *headers)
Definition: http.c:2969
Octstr * name
Definition: wsp_caps.h:73
Octstr * wsp_cap_pack_list(List *caps_list)
Definition: wsp_caps.c:207
#define gwlist_create()
Definition: list.h:136
void wsp_session_dispatch_event(WAPEvent *event)
Definition: wsp_session.c:228
static void indicate_pushabort(WSPPushMachine *machine, long reason)
Definition: wsp_session.c:1312
static void disconnect_other_sessions(WSPMachine *sm)
Definition: wsp_session.c:1188
Definition: wsp.h:71
long octstr_extract_uintvar(Octstr *ostr, unsigned long *value, long pos)
Definition: octstr.c:1954
static List * make_capabilities_reply(WSPMachine *m)
Definition: wsp_session.c:976
static int method_is_holding(void *item, void *pattern)
Definition: wsp_session.c:1364
void gwlist_add_producer(List *list)
Definition: list.c:383
union WAPEvent::@87 u
int octstr_get_char(const Octstr *ostr, long pos)
Definition: octstr.c:406
static void send_abort(long reason, long handle)
Definition: wsp_session.c:1235
static Counter * session_id_counter
Definition: wsp_session.c:124
Definition: wsp.h:72
void wsp_cap_destroy(Capability *cap)
Definition: wsp_caps.c:83
Definition: list.c:102
WSP_PDU * wsp_pdu_unpack(Octstr *data)
Definition: wsp_pdu.c:178
static wap_dispatch_func_t * dispatch_to_ota
Definition: wsp_session.c:111
void wap_event_destroy(WAPEvent *event)
Definition: wap_events.c:102
void wap_dispatch_func_t(WAPEvent *event)
Definition: wap.h:85
static char * state_name(WSPState state)
Definition: wsp_session.c:729
int octstr_compare(const Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:871
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.