Kannel: Open Source WAP and SMS gateway  $Revision: 5037 $
wsp_unit.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2016 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_unit.c - Implement WSP Connectionless mode
59  *
60  * Lars Wirzenius
61  */
62 
63 #include <string.h>
64 
65 #include "gwlib/gwlib.h"
66 #include "wsp.h"
67 #include "wsp_pdu.h"
68 #include "wsp_headers.h"
69 #include "wap_events.h"
70 #include "wsp_strings.h"
71 #include "wap.h"
72 
73 
74 /*
75  * Give the status the module:
76  *
77  * limbo
78  * not running at all
79  * running
80  * operating normally
81  * terminating
82  * waiting for operations to terminate, returning to limbo
83  */
85 
88 
89 static List *queue = NULL;
90 
91 
92 static void main_thread(void *);
95 
96 /***********************************************************************
97  * Public functions
98  */
99 
100 void wsp_unit_init(wap_dispatch_func_t *datagram_dispatch,
101  wap_dispatch_func_t *application_dispatch)
102 {
103  queue = gwlist_create();
104  gwlist_add_producer(queue);
105  dispatch_to_wdp = datagram_dispatch;
106  dispatch_to_appl = application_dispatch;
110 }
111 
112 
114 {
117  gwlist_remove_producer(queue);
121 }
122 
123 
125 {
126  wap_event_assert(event);
127  gwlist_produce(queue, event);
128 }
129 
130 
132 {
133  WAPEvent *event;
134  Octstr *os;
135  WSP_PDU *pdu;
136  long tid_byte;
137  int method;
139 
140  gw_assert(datagram->type == T_DUnitdata_Ind);
141 
142  os = NULL;
143  pdu = NULL;
144  event = NULL;
145 
146  os = octstr_duplicate(datagram->u.T_DUnitdata_Ind.user_data);
147  if (os && octstr_len(os) == 0) {
148  warning(0, "WSP UNIT: Empty datagram.");
149  goto error;
150  }
151 
152  tid_byte = octstr_get_char(os, 0);
153  octstr_delete(os, 0, 1);
154 
155  pdu = wsp_pdu_unpack(os);
156  if (pdu == NULL)
157  goto error;
158 
159  if (pdu->type != Get && pdu->type != Post) {
160  warning(0, "WSP UNIT: Unsupported PDU type %d", pdu->type);
161  goto error;
162  }
163 
164  event = wap_event_create(S_Unit_MethodInvoke_Ind);
165  event->u.S_Unit_MethodInvoke_Ind.addr_tuple = wap_addr_tuple_duplicate(
166  datagram->u.T_DUnitdata_Ind.addr_tuple);
167  event->u.S_Unit_MethodInvoke_Ind.transaction_id = tid_byte;
168 
169  switch (pdu->type) {
170  case Get:
171  debug("wap.wsp", 0, "Connectionless Get request received.");
172  method = GET_METHODS + pdu->u.Get.subtype;
173  event->u.S_Unit_MethodInvoke_Ind.request_uri =
174  octstr_duplicate(pdu->u.Get.uri);
175  event->u.S_Unit_MethodInvoke_Ind.request_headers =
176  wsp_headers_unpack(pdu->u.Get.headers, 0);
177  event->u.S_Unit_MethodInvoke_Ind.request_body = NULL;
178  break;
179 
180  case Post:
181  debug("wap.wsp", 0, "Connectionless Post request received.");
182  method = POST_METHODS + pdu->u.Post.subtype;
183  event->u.S_Unit_MethodInvoke_Ind.request_uri =
184  octstr_duplicate(pdu->u.Post.uri);
185  event->u.S_Unit_MethodInvoke_Ind.request_headers =
186  wsp_headers_unpack(pdu->u.Post.headers, 1);
187  event->u.S_Unit_MethodInvoke_Ind.request_body =
188  octstr_duplicate(pdu->u.Post.data);
189  break;
190 
191  default:
192  warning(0, "WSP UNIT: Unsupported PDU type %d", pdu->type);
193  goto error;
194  }
195 
196  method_name = wsp_method_to_string(method);
197  if (method_name == NULL)
198  method_name = octstr_format("UNKNOWN%02X", method);
199  event->u.S_Unit_MethodInvoke_Ind.method = method_name;
200 
201  octstr_destroy(os);
202  wsp_pdu_destroy(pdu);
203  return event;
204 
205 error:
206  octstr_destroy(os);
207  wsp_pdu_destroy(pdu);
208  wap_event_destroy(event);
209  return NULL;
210 }
211 
212 
213 /***********************************************************************
214  * Local functions
215  */
216 
217 static void main_thread(void *arg)
218 {
219  WAPEvent *e;
220  WAPEvent *newevent;
221 
222  while (run_status == running && (e = gwlist_consume(queue)) != NULL) {
223  debug("wap.wsp.unit", 0, "WSP (UNIT): event arrived");
224  wap_event_assert(e);
225  switch (e->type) {
226  case T_DUnitdata_Ind:
227  newevent = unpack_datagram(e);
228  if (newevent != NULL)
229  dispatch_to_appl(newevent);
230  break;
231 
232  case S_Unit_MethodResult_Req:
233  newevent = pack_into_result_datagram(e);
234  if (newevent != NULL)
235  dispatch_to_wdp(newevent);
236  break;
237 
238  case S_Unit_Push_Req:
239  newevent = pack_into_push_datagram(e);
240  if (newevent != NULL)
241  dispatch_to_wdp(newevent);
242  debug("wsp.unit", 0, "WSP (UNIT): delivering to wdp");
243  break;
244 
245  default:
246  warning(0, "WSP UNIT: Unknown event type %d", e->type);
247  break;
248  }
250  }
251 }
252 
253 
254 /*
255  * We do not set TUnitData.ind's SMS-specific fields here, because we do not
256  * support sending results to the phone over SMS. Wsp, chapter 8.4.1 states
257  * that "that each peer entity is always associated with an encoding version.".
258  * So we add Encoding-Version when we are sending something to the client.
259  * (This includes push, which is not directly mentioned in chapter 8.4.2.70).
260  */
262 {
263  WAPEvent *datagram;
264  struct S_Unit_MethodResult_Req *p;
265  WSP_PDU *pdu;
266  Octstr *ospdu;
267  unsigned char tid;
268 
269  gw_assert(event->type == S_Unit_MethodResult_Req);
270  p = &event->u.S_Unit_MethodResult_Req;
271 
272  http_header_add(p->response_headers, "Encoding-Version", "1.3");
273 
274  pdu = wsp_pdu_create(Reply);
275  pdu->u.Reply.status = wsp_convert_http_status_to_wsp_status(p->status);
276  pdu->u.Reply.headers = wsp_headers_pack(p->response_headers, 1, WSP_1_3);
277  pdu->u.Reply.data = octstr_duplicate(p->response_body);
278  ospdu = wsp_pdu_pack(pdu);
279  wsp_pdu_destroy(pdu);
280  if (ospdu == NULL)
281  return NULL;
282 
283  tid = p->transaction_id;
284  octstr_insert_data(ospdu, 0, (char *)&tid, 1);
285 
286  datagram = wap_event_create(T_DUnitdata_Req);
287  datagram->u.T_DUnitdata_Req.addr_tuple =
288  wap_addr_tuple_duplicate(p->addr_tuple);
289  datagram->u.T_DUnitdata_Req.user_data = ospdu;
290 
291  return datagram;
292 }
293 
294 /*
295  * According to WSP table 12, p. 63, push id and transaction id are stored
296  * into same field. T-UnitData.ind is different for IP and SMS bearer.
297  */
299 {
300  WAPEvent *datagram;
301  WSP_PDU *pdu;
302  Octstr *ospdu;
303  unsigned char push_id;
304 
305  gw_assert(event->type == S_Unit_Push_Req);
306  debug("wap.wsp.unit", 0, "WSP_UNIT: Connectionless push accepted");
307 
308  http_header_add(event->u.S_Unit_Push_Req.push_headers,
309  "Encoding-Version", "1.3");
310 
311  pdu = wsp_pdu_create(Push);
312  pdu->u.Push.headers = wsp_headers_pack(
313  event->u.S_Unit_Push_Req.push_headers, 1, WSP_1_3);
314  pdu->u.Push.data = octstr_duplicate(
315  event->u.S_Unit_Push_Req.push_body);
316  wsp_pdu_dump(pdu, 0);
317  ospdu = wsp_pdu_pack(pdu);
318  wsp_pdu_destroy(pdu);
319  if (ospdu == NULL)
320  return NULL;
321 
322  push_id = event->u.S_Unit_Push_Req.push_id;
323  octstr_insert_data(ospdu, 0, (char *)&push_id, 1);
324 
325  datagram = wap_event_create(T_DUnitdata_Req);
326 
327  datagram->u.T_DUnitdata_Req.addr_tuple =
328  wap_addr_tuple_duplicate(event->u.S_Unit_Push_Req.addr_tuple);
329  datagram->u.T_DUnitdata_Req.address_type =
330  event->u.S_Unit_Push_Req.address_type;
331  if (event->u.S_Unit_Push_Req.smsc_id != NULL)
332  datagram->u.T_DUnitdata_Req.smsc_id =
333  octstr_duplicate(event->u.S_Unit_Push_Req.smsc_id);
334  else
335  datagram->u.T_DUnitdata_Req.smsc_id = NULL;
336  if (event->u.S_Unit_Push_Req.dlr_url != NULL)
337  datagram->u.T_DUnitdata_Req.dlr_url =
338  octstr_duplicate(event->u.S_Unit_Push_Req.dlr_url);
339  else
340  datagram->u.T_DUnitdata_Req.dlr_url = NULL;
341  datagram->u.T_DUnitdata_Req.dlr_mask = event->u.S_Unit_Push_Req.dlr_mask;
342  if (event->u.S_Unit_Push_Req.smsbox_id != NULL)
343  datagram->u.T_DUnitdata_Req.smsbox_id =
344  octstr_duplicate(event->u.S_Unit_Push_Req.smsbox_id);
345  else
346  datagram->u.T_DUnitdata_Req.smsbox_id = NULL;
347  datagram->u.T_DUnitdata_Req.service_name =
348  octstr_duplicate(event->u.S_Unit_Push_Req.service_name);
349 
350  datagram->u.T_DUnitdata_Req.user_data = ospdu;
351 
352  return datagram;
353 }
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:612
union wsp_pdu::@89 u
Definition: wsp.h:73
void http_header_add(List *headers, char *name, char *contents)
Definition: http.c:2863
static Octstr * method_name
Definition: test_http.c:86
Definition: wsp_unit.c:84
Octstr * wsp_headers_pack(List *headers, int separate_content_type, int wsp_version)
Definition: wsp_headers.c:2963
void gwlist_produce(List *list, void *item)
Definition: list.c:411
Octstr * wsp_pdu_pack(WSP_PDU *pdu)
Definition: wsp_pdu.c:271
void octstr_insert_data(Octstr *ostr, long pos, const char *data, long len)
Definition: octstr.c:1459
static void main_thread(void *)
Definition: wsp_unit.c:217
void gwthread_join_every(gwthread_func_t *func)
WAPAddrTuple * wap_addr_tuple_duplicate(WAPAddrTuple *tuple)
Definition: wap_addr.c:125
WSP_PDU * wsp_pdu_create(int type)
Definition: wsp_pdu.c:68
void wap_event_assert(WAPEvent *event)
Definition: wap_events.c:220
void octstr_delete(Octstr *ostr1, long pos, long len)
Definition: octstr.c:1525
void gwlist_remove_producer(List *list)
Definition: list.c:401
void wap_event_destroy_item(void *event)
Definition: wap_events.c:130
#define octstr_duplicate(ostr)
Definition: octstr.h:187
static WAPEvent * unpack_datagram(WAPEvent *datagram)
Definition: wsp_unit.c:131
static wap_dispatch_func_t * dispatch_to_appl
Definition: wsp_unit.c:87
#define wap_event_create(type)
Definition: wap_events.h:107
void warning(int err, const char *fmt,...)
Definition: log.c:624
Octstr * octstr_format(const char *fmt,...)
Definition: octstr.c:2462
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
#define gwthread_create(func, arg)
Definition: gwthread.h:90
static int method
Definition: test_http.c:76
gw_assert(wtls_machine->packet_to_send!=NULL)
void wsp_pdu_destroy(WSP_PDU *pdu)
Definition: wsp_pdu.c:102
static wap_dispatch_func_t * dispatch_to_wdp
Definition: wsp_unit.c:86
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
Definition: octstr.c:118
void wsp_strings_shutdown(void)
Definition: wsp_strings.c:286
void wsp_unit_init(wap_dispatch_func_t *datagram_dispatch, wap_dispatch_func_t *application_dispatch)
Definition: wsp_unit.c:100
void * gwlist_consume(List *list)
Definition: list.c:427
void wsp_strings_init(void)
Definition: wsp_strings.c:269
List * wsp_headers_unpack(Octstr *headers, int content_type_present)
Definition: wsp_headers.c:1331
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
int type
Definition: wsp_pdu.h:87
WAPEventName type
Definition: wap_events.h:88
#define gwlist_create()
Definition: list.h:136
static WAPEvent * pack_into_push_datagram(WAPEvent *event)
Definition: wsp_unit.c:298
void wsp_pdu_dump(WSP_PDU *pdu, int level)
Definition: wsp_pdu.c:324
static enum @92 run_status
static WAPEvent * pack_into_result_datagram(WAPEvent *event)
Definition: wsp_unit.c:261
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:404
static List * queue
Definition: wsp_unit.c:89
void wsp_unit_dispatch_event(WAPEvent *event)
Definition: wsp_unit.c:124
Definition: list.c:102
WSP_PDU * wsp_pdu_unpack(Octstr *data)
Definition: wsp_pdu.c:178
void wsp_unit_shutdown(void)
Definition: wsp_unit.c:113
void wap_event_destroy(WAPEvent *event)
Definition: wap_events.c:102
void wap_dispatch_func_t(WAPEvent *event)
Definition: wap.h:85
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.