/src/pjsip/tests/fuzz/fuzz-sip.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) |
3 | | * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org> |
4 | | * |
5 | | * This program is free software; you can redistribute it and/or modify |
6 | | * it under the terms of the GNU General Public License as published by |
7 | | * the Free Software Foundation; either version 2 of the License, or |
8 | | * (at your option) any later version. |
9 | | * |
10 | | * This program is distributed in the hope that it will be useful, |
11 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | | * GNU General Public License for more details. |
14 | | * |
15 | | * You should have received a copy of the GNU General Public License |
16 | | * along with this program; if not, write to the Free Software |
17 | | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
18 | | */ |
19 | | #include <stdio.h> |
20 | | #include <stdint.h> |
21 | | #include <stdlib.h> |
22 | | |
23 | | #include <pjlib.h> |
24 | | #include <pjlib-util.h> |
25 | | #include <pjsip.h> |
26 | | #include <pjsip/sip_types.h> |
27 | | #include <pjsip/sip_multipart.h> |
28 | | #include <pjsip/sip_tel_uri.h> |
29 | | #include <pjsip/sip_auth.h> |
30 | | #include <pjsip/sip_transaction.h> |
31 | | #include <pjsip/sip_dialog.h> |
32 | | #include <pjsip-simple/evsub.h> |
33 | | #include <pjsip-ua/sip_replaces.h> |
34 | | #include <pjsip-ua/sip_timer.h> |
35 | | |
36 | | pjsip_endpoint *endpt; |
37 | | pj_caching_pool caching_pool; |
38 | | |
39 | 15.9k | #define POOL_SIZE 8000 |
40 | 1 | #define PJSIP_TEST_MEM_SIZE (2*1024*1024) |
41 | | |
42 | 15.9k | #define kMinInputLength 10 |
43 | 7.96k | #define kMaxInputLength 5120 |
44 | | |
45 | | /* Transaction user module */ |
46 | | static pjsip_module tsx_user_module; |
47 | | |
48 | | /* Transaction state callback */ |
49 | | static void on_tsx_state(pjsip_transaction *tsx, pjsip_event *event) |
50 | 0 | { |
51 | 0 | PJ_UNUSED_ARG(tsx); |
52 | 0 | PJ_UNUSED_ARG(event); |
53 | 0 | } |
54 | | |
55 | | /* Stub resolver. |
56 | | * |
57 | | * Message content can direct a response to an arbitrary host name (e.g. via |
58 | | * the Via "maddr" parameter, see RFC 3261 section 18.2.2), which would make |
59 | | * the endpoint perform a real DNS lookup with getaddrinfo(). Blocking network |
60 | | * I/O is not allowed in the fuzzing environment, so resolve every target to |
61 | | * the loopback address on the loop transport instead. |
62 | | */ |
63 | | static void fuzz_resolve(pjsip_resolver_t *resolver, pj_pool_t *pool, |
64 | | const pjsip_host_info *target, void *token, |
65 | | pjsip_resolver_callback *cb) |
66 | 1.55k | { |
67 | 1.55k | pjsip_server_addresses svr_addr; |
68 | 1.55k | pj_uint16_t port; |
69 | | |
70 | 1.55k | PJ_UNUSED_ARG(resolver); |
71 | 1.55k | PJ_UNUSED_ARG(pool); |
72 | | |
73 | 1.55k | port = (pj_uint16_t)(target->addr.port? target->addr.port : 5060); |
74 | | |
75 | 1.55k | pj_bzero(&svr_addr, sizeof(svr_addr)); |
76 | 1.55k | svr_addr.count = 1; |
77 | 1.55k | svr_addr.entry[0].name = target->addr.host; |
78 | 1.55k | svr_addr.entry[0].type = PJSIP_TRANSPORT_LOOP_DGRAM; |
79 | 1.55k | pj_sockaddr_in_init(&svr_addr.entry[0].addr.ipv4, NULL, port); |
80 | 1.55k | svr_addr.entry[0].addr.ipv4.sin_addr.s_addr = pj_htonl(0x7F000001); |
81 | 1.55k | svr_addr.entry[0].addr_len = sizeof(pj_sockaddr_in); |
82 | | |
83 | 1.55k | (*cb)(PJ_SUCCESS, token, &svr_addr); |
84 | 1.55k | } |
85 | | |
86 | | static pjsip_ext_resolver fuzz_ext_resolver = { &fuzz_resolve }; |
87 | | |
88 | | /* Standard header types to test */ |
89 | | static const pjsip_hdr_e hdr_types[] = { |
90 | | PJSIP_H_AUTHORIZATION, |
91 | | PJSIP_H_PROXY_AUTHORIZATION, |
92 | | PJSIP_H_WWW_AUTHENTICATE, |
93 | | PJSIP_H_PROXY_AUTHENTICATE, |
94 | | PJSIP_H_ROUTE, |
95 | | PJSIP_H_RECORD_ROUTE, |
96 | | PJSIP_H_CONTACT |
97 | | }; |
98 | | |
99 | | static pjsip_msg* parse_message(pj_pool_t *pool, char *data, size_t size) |
100 | 7.96k | { |
101 | 7.96k | pjsip_parser_err_report err_list; |
102 | 7.96k | pj_list_init(&err_list); |
103 | 7.96k | return pjsip_parse_msg(pool, data, size, &err_list); |
104 | 7.96k | } |
105 | | |
106 | | /* Multipart body parsing */ |
107 | | static void do_test_multipart(pj_pool_t *pool, pjsip_msg *msg) |
108 | 4.83k | { |
109 | 4.83k | if (!msg->body) |
110 | 4.66k | return; |
111 | | |
112 | 171 | pjsip_msg_body *body = msg->body; |
113 | | |
114 | 171 | if (body->content_type.type.slen > 0 && |
115 | 171 | pj_stricmp2(&body->content_type.type, "multipart") == 0) |
116 | 69 | { |
117 | 69 | pjsip_msg_body *multipart_body = NULL; |
118 | 69 | if (body->data && body->len > 0) { |
119 | 0 | multipart_body = pjsip_multipart_parse(pool, (char *)body->data, |
120 | 0 | body->len, &body->content_type, 0); |
121 | 0 | if (!multipart_body) |
122 | 0 | return; |
123 | 69 | } else { |
124 | 69 | multipart_body = body; |
125 | 69 | } |
126 | | |
127 | 69 | pjsip_multipart_part *part = pjsip_multipart_get_first_part(multipart_body); |
128 | | |
129 | 6.31k | while (part) { |
130 | 6.24k | pjsip_media_type ctype_app, ctype_text; |
131 | | |
132 | 6.24k | ctype_app.type = pj_str("application"); |
133 | 6.24k | ctype_app.subtype = pj_str("sdp"); |
134 | 6.24k | ctype_text.type = pj_str("text"); |
135 | 6.24k | ctype_text.subtype = pj_str("plain"); |
136 | | |
137 | 6.24k | pjsip_multipart_find_part(multipart_body, &ctype_app, NULL); |
138 | 6.24k | pjsip_multipart_find_part(multipart_body, &ctype_text, NULL); |
139 | | |
140 | 6.24k | part = pjsip_multipart_get_next_part(multipart_body, part); |
141 | 6.24k | } |
142 | | |
143 | 69 | pjsip_media_type search_type; |
144 | 69 | search_type.type = pj_str("application"); |
145 | 69 | search_type.subtype = pj_str("sdp"); |
146 | 69 | pjsip_multipart_find_part(multipart_body, &search_type, NULL); |
147 | 69 | } |
148 | 171 | } |
149 | | |
150 | | /* Tel URI parsing */ |
151 | | static void do_test_tel_uri(pj_pool_t *pool, char *data, size_t size) |
152 | 7.96k | { |
153 | 7.96k | pj_str_t uri_str; |
154 | 7.96k | pjsip_uri *uri; |
155 | | |
156 | 7.96k | if (size < 4 || size > 256) |
157 | 1.63k | return; |
158 | | |
159 | 6.32k | uri_str.ptr = data; |
160 | 6.32k | uri_str.slen = (pj_ssize_t)size; |
161 | | |
162 | 6.32k | uri = pjsip_parse_uri(pool, uri_str.ptr, uri_str.slen, 0); |
163 | | |
164 | 6.32k | if (uri && size > 20) { |
165 | 706 | pj_str_t uri2_str; |
166 | 706 | pjsip_uri *uri2; |
167 | | |
168 | 706 | uri2_str.ptr = data + 10; |
169 | 706 | uri2_str.slen = (pj_ssize_t)(size - 10); |
170 | | |
171 | 706 | uri2 = pjsip_parse_uri(pool, uri2_str.ptr, uri2_str.slen, 0); |
172 | 706 | if (uri2) { |
173 | 634 | pjsip_uri_cmp(PJSIP_URI_IN_FROMTO_HDR, uri, uri2); |
174 | 634 | pjsip_uri_cmp(PJSIP_URI_IN_REQ_URI, uri, uri2); |
175 | 634 | } |
176 | 706 | } |
177 | 6.32k | } |
178 | | |
179 | | /* Test UAS transaction creation and message feeding */ |
180 | | static void do_test_transaction_layer(pjsip_msg *msg, pjsip_rx_data *rdata) |
181 | 4.83k | { |
182 | 4.83k | pj_str_t tsx_key; |
183 | 4.83k | pjsip_via_hdr *via_hdr; |
184 | | |
185 | 4.83k | if (!msg || msg->type != PJSIP_REQUEST_MSG || !rdata) |
186 | 3.05k | return; |
187 | | |
188 | 1.78k | if (!rdata->msg_info.via || !rdata->msg_info.cseq || |
189 | 1.61k | !rdata->msg_info.from || !rdata->msg_info.cid) |
190 | 175 | return; |
191 | | |
192 | 1.60k | via_hdr = rdata->msg_info.via; |
193 | | |
194 | | /* Skip transaction creation if transport not available */ |
195 | 1.60k | if (!rdata->tp_info.transport) |
196 | 0 | return; |
197 | | |
198 | | /* Ensure From/To headers have tags */ |
199 | 1.60k | pjsip_from_hdr *from_hdr = (pjsip_from_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_FROM, NULL); |
200 | 1.60k | pjsip_to_hdr *to_hdr = (pjsip_to_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_TO, NULL); |
201 | | |
202 | 1.60k | if (from_hdr && pj_stricmp2(&from_hdr->tag, "") == 0) |
203 | 1.56k | from_hdr->tag = pj_str("from-tag-123"); |
204 | | |
205 | 1.60k | if (to_hdr && pj_stricmp2(&to_hdr->tag, "") == 0) |
206 | 1.58k | to_hdr->tag = pj_str("to-tag-456"); |
207 | | |
208 | | /* Ensure Via header has valid host/port for response addressing */ |
209 | 1.60k | if (via_hdr->sent_by.host.slen == 0) { |
210 | 0 | via_hdr->sent_by.host = pj_str("127.0.0.1"); |
211 | 0 | via_hdr->sent_by.port = 5060; |
212 | 0 | } |
213 | | |
214 | | /* Test transaction key generation */ |
215 | 1.60k | if (pjsip_tsx_create_key(rdata->tp_info.pool, &tsx_key, PJSIP_ROLE_UAS, |
216 | 1.60k | &msg->line.req.method, rdata) == PJ_SUCCESS) { |
217 | 1.60k | pjsip_tsx_layer_find_tsx(&tsx_key, PJ_FALSE); |
218 | 1.60k | } |
219 | 1.60k | } |
220 | | |
221 | | /* Test synthetic transaction creation */ |
222 | | static void do_test_transaction_synthetic(void) |
223 | 1 | { |
224 | 1 | pj_str_t target_uri_str = pj_str("sip:test@example.com"); |
225 | 1 | pj_str_t from_str = pj_str("sip:caller@example.com"); |
226 | 1 | pj_str_t to_str = pj_str("sip:callee@example.com"); |
227 | 1 | pj_str_t call_id_str = pj_str("call-id-fuzz-test@example.com"); |
228 | 1 | pjsip_tx_data *tdata; |
229 | | |
230 | 1 | if (pjsip_endpt_create_request(endpt, &pjsip_invite_method, |
231 | 1 | &target_uri_str, &from_str, &to_str, |
232 | 1 | NULL, &call_id_str, -1, NULL, &tdata) == PJ_SUCCESS) { |
233 | 1 | pjsip_tx_data_dec_ref(tdata); |
234 | 1 | } |
235 | 1 | } |
236 | | |
237 | | /* Test UAC transaction response handling */ |
238 | | static void do_test_transaction_uac(pjsip_msg *msg, pjsip_rx_data *rdata) |
239 | 3.05k | { |
240 | 3.05k | pj_str_t tsx_key; |
241 | | |
242 | 3.05k | if (!msg || msg->type != PJSIP_RESPONSE_MSG || !rdata) |
243 | 0 | return; |
244 | | |
245 | 3.05k | if (!rdata->msg_info.via || !rdata->msg_info.cseq || |
246 | 84 | !rdata->msg_info.from || !rdata->msg_info.cid) |
247 | 2.96k | return; |
248 | | |
249 | | /* Skip if no transport available */ |
250 | 81 | if (!rdata->tp_info.transport) |
251 | 0 | return; |
252 | | |
253 | | /* Test transaction key generation for responses */ |
254 | 81 | if (pjsip_tsx_create_key(rdata->tp_info.pool, &tsx_key, PJSIP_ROLE_UAC, |
255 | 81 | &rdata->msg_info.cseq->method, rdata) == PJ_SUCCESS) { |
256 | 81 | pjsip_tsx_layer_find_tsx(&tsx_key, PJ_FALSE); |
257 | 81 | } |
258 | 81 | } |
259 | | |
260 | | /* Test authentication client */ |
261 | | static void do_test_auth_client(pj_pool_t *pool, pjsip_msg *msg) |
262 | 4.83k | { |
263 | 4.83k | pjsip_auth_clt_sess auth_sess; |
264 | 4.83k | pjsip_hdr *hdr = NULL; |
265 | 4.83k | pj_status_t status; |
266 | | |
267 | | /* Only test with 401/407 responses */ |
268 | 4.83k | if (!msg || msg->type != PJSIP_RESPONSE_MSG) |
269 | 1.78k | return; |
270 | | |
271 | 3.05k | if (msg->line.status.code != 401 && msg->line.status.code != 407) |
272 | 2.29k | return; |
273 | | |
274 | | /* Initialize auth client session */ |
275 | 758 | if (pjsip_auth_clt_init(&auth_sess, endpt, pool, 0) != PJ_SUCCESS) |
276 | 0 | return; |
277 | | |
278 | | /* Set up credentials */ |
279 | 758 | pjsip_cred_info cred; |
280 | 758 | pj_bzero(&cred, sizeof(cred)); |
281 | 758 | cred.realm = pj_str("test"); |
282 | 758 | cred.username = pj_str("user"); |
283 | 758 | cred.data_type = PJSIP_CRED_DATA_PLAIN_PASSWD; |
284 | 758 | cred.data = pj_str("password"); |
285 | | |
286 | 758 | if (pjsip_auth_clt_set_credentials(&auth_sess, 1, &cred) != PJ_SUCCESS) |
287 | 0 | goto cleanup; |
288 | | |
289 | | /* Parse authentication headers */ |
290 | 758 | if (msg->line.status.code == 401) |
291 | 745 | hdr = pjsip_msg_find_hdr(msg, PJSIP_H_WWW_AUTHENTICATE, NULL); |
292 | 13 | else |
293 | 13 | hdr = pjsip_msg_find_hdr(msg, PJSIP_H_PROXY_AUTHENTICATE, NULL); |
294 | | |
295 | 758 | if (hdr) { |
296 | | /* Create a dummy request to test reinit */ |
297 | 592 | pjsip_tx_data *tdata = NULL; |
298 | 592 | pjsip_method method; |
299 | 592 | pj_str_t target_uri = pj_str("sip:server.com"); |
300 | 592 | pj_str_t from_uri = pj_str("sip:client@local"); |
301 | 592 | pj_str_t to_uri = pj_str("sip:server.com"); |
302 | 592 | pj_str_t contact = pj_str("sip:client@local"); |
303 | | |
304 | 592 | pjsip_method_set(&method, PJSIP_REGISTER_METHOD); |
305 | | |
306 | 592 | status = pjsip_endpt_create_request(endpt, &method, &target_uri, |
307 | 592 | &from_uri, &to_uri, &contact, |
308 | 592 | NULL, -1, NULL, &tdata); |
309 | 592 | if (status != PJ_SUCCESS || !tdata) |
310 | 0 | goto cleanup; |
311 | | |
312 | | /* Initialize request with auth */ |
313 | 592 | pjsip_auth_clt_init_req(&auth_sess, tdata); |
314 | | |
315 | | /* Create rx_data from the 401/407 message */ |
316 | 592 | pjsip_rx_data rdata; |
317 | 592 | pj_bzero(&rdata, sizeof(rdata)); |
318 | 592 | rdata.msg_info.msg = msg; |
319 | 592 | rdata.msg_info.info = NULL; |
320 | 592 | rdata.msg_info.len = 1024; |
321 | | |
322 | | /* Try to reinit with the challenge */ |
323 | 592 | pjsip_tx_data *new_tdata = NULL; |
324 | 592 | if (pjsip_auth_clt_reinit_req(&auth_sess, &rdata, tdata, &new_tdata) == PJ_SUCCESS && new_tdata) { |
325 | 263 | pjsip_tx_data_dec_ref(new_tdata); |
326 | 263 | } |
327 | | |
328 | 592 | pjsip_tx_data_dec_ref(tdata); |
329 | 592 | } |
330 | | |
331 | 758 | cleanup: |
332 | 758 | pjsip_auth_clt_deinit(&auth_sess); |
333 | 758 | } |
334 | | |
335 | | /* Test dialog creation */ |
336 | | static void do_test_dialog(pjsip_msg *msg) |
337 | 4.83k | { |
338 | 4.83k | pjsip_dialog *dlg = NULL; |
339 | 4.83k | pjsip_to_hdr *to; |
340 | 4.83k | pjsip_from_hdr *from; |
341 | 4.83k | pj_str_t local_uri = pj_str("sip:local@test.com"); |
342 | 4.83k | pj_str_t remote_uri = pj_str("sip:remote@test.com"); |
343 | 4.83k | pj_str_t target = pj_str("sip:remote@test.com"); |
344 | | |
345 | 4.83k | if (!msg || msg->type != PJSIP_REQUEST_MSG) |
346 | 3.05k | return; |
347 | | |
348 | 1.78k | if (msg->line.req.method.id != PJSIP_INVITE_METHOD) |
349 | 1.61k | return; |
350 | | |
351 | | /* Get To and From headers */ |
352 | 164 | to = (pjsip_to_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_TO, NULL); |
353 | 164 | from = (pjsip_from_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_FROM, NULL); |
354 | 164 | if (!to || !from) |
355 | 3 | return; |
356 | | |
357 | | /* Create UAC dialog */ |
358 | 161 | if (pjsip_dlg_create_uac(pjsip_ua_instance(), &local_uri, NULL, |
359 | 161 | &remote_uri, &target, &dlg) == PJ_SUCCESS && dlg) { |
360 | 161 | pjsip_dlg_inc_lock(dlg); |
361 | | |
362 | | /* Build route set from all Route headers */ |
363 | 161 | pjsip_route_hdr route_set; |
364 | 161 | pjsip_route_hdr *route; |
365 | 161 | pj_list_init(&route_set); |
366 | 161 | route = (pjsip_route_hdr*) |
367 | 161 | pjsip_msg_find_hdr(msg, PJSIP_H_ROUTE, NULL); |
368 | 2.69k | while (route) { |
369 | 2.53k | pjsip_route_hdr *route_clone = (pjsip_route_hdr*) |
370 | 2.53k | pjsip_hdr_clone(dlg->pool, route); |
371 | 2.53k | pj_list_push_back(&route_set, route_clone); |
372 | 2.53k | route = (pjsip_route_hdr*) |
373 | 2.53k | pjsip_msg_find_hdr(msg, PJSIP_H_ROUTE, |
374 | 2.53k | route->next); |
375 | 2.53k | } |
376 | 161 | if (!pj_list_empty(&route_set)) { |
377 | 88 | pjsip_dlg_set_route_set(dlg, &route_set); |
378 | 88 | } |
379 | | |
380 | 161 | pjsip_dlg_dec_lock(dlg); |
381 | 161 | } |
382 | 161 | } |
383 | | |
384 | | extern int |
385 | | LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) |
386 | 7.97k | { |
387 | 7.97k | char *DataFx; |
388 | 7.97k | pj_pool_t *pool; |
389 | 7.97k | pjsip_msg *msg; |
390 | 7.97k | static int initialized = 0; |
391 | | |
392 | 7.97k | if (Size < kMinInputLength || Size > kMaxInputLength) |
393 | 10 | return 1; |
394 | | |
395 | 7.96k | DataFx = (char *)calloc((Size+1), sizeof(char)); |
396 | 7.96k | if (DataFx == NULL) |
397 | 0 | return 0; |
398 | 7.96k | memcpy((void *)DataFx, (void *)Data, Size); |
399 | | |
400 | 7.96k | if (!initialized) { |
401 | 1 | pj_log_set_level(0); |
402 | | |
403 | 1 | if (pj_init() != PJ_SUCCESS || pjlib_util_init() != PJ_SUCCESS) { |
404 | 0 | free(DataFx); |
405 | 0 | return 0; |
406 | 0 | } |
407 | | |
408 | 1 | pj_caching_pool_init(&caching_pool, &pj_pool_factory_default_policy, |
409 | 1 | PJSIP_TEST_MEM_SIZE); |
410 | | |
411 | 1 | if (pjsip_endpt_create(&caching_pool.factory, "endpt", &endpt) != PJ_SUCCESS || !endpt) { |
412 | 0 | free(DataFx); |
413 | 0 | return 0; |
414 | 0 | } |
415 | | |
416 | 1 | if (pjsip_tsx_layer_init_module(endpt) != PJ_SUCCESS || |
417 | 1 | pjsip_loop_start(endpt, NULL) != PJ_SUCCESS) { |
418 | 0 | free(DataFx); |
419 | 0 | return 0; |
420 | 0 | } |
421 | | |
422 | 1 | if (pjsip_endpt_set_ext_resolver(endpt, &fuzz_ext_resolver) |
423 | 1 | != PJ_SUCCESS) |
424 | 0 | { |
425 | 0 | free(DataFx); |
426 | 0 | return 0; |
427 | 0 | } |
428 | | |
429 | 1 | pjsip_ua_init_module(endpt, NULL); |
430 | | |
431 | | /* Register the specialised SIP header parsers. The core SIP parser |
432 | | * only installs grammars for headers whose owning module has been |
433 | | * initialised; without these calls the headers below are parsed as |
434 | | * generic string headers and the hand-written grammars in |
435 | | * evsub_msg.c (Event/Subscription-State/Allow-Events), |
436 | | * sip_replaces.c (Replaces) and sip_timer.c (Session-Expires/Min-SE) |
437 | | * are never exercised even when present in the input message. */ |
438 | 1 | if (pjsip_evsub_init_module(endpt) != PJ_SUCCESS || |
439 | 1 | pjsip_replaces_init_module(endpt) != PJ_SUCCESS || |
440 | 1 | pjsip_timer_init_module(endpt) != PJ_SUCCESS) { |
441 | 0 | free(DataFx); |
442 | 0 | return 0; |
443 | 0 | } |
444 | | |
445 | | /* Initialize transaction user module */ |
446 | 1 | pj_bzero(&tsx_user_module, sizeof(tsx_user_module)); |
447 | 1 | tsx_user_module.name = pj_str("tsx-user"); |
448 | 1 | tsx_user_module.id = -1; |
449 | 1 | tsx_user_module.priority = PJSIP_MOD_PRIORITY_APPLICATION; |
450 | 1 | tsx_user_module.on_tsx_state = &on_tsx_state; |
451 | 1 | pjsip_endpt_register_module(endpt, &tsx_user_module); |
452 | | |
453 | 1 | do_test_transaction_synthetic(); |
454 | | |
455 | 1 | initialized = 1; |
456 | 1 | } |
457 | | |
458 | 7.96k | pool = pjsip_endpt_create_pool(endpt, NULL, POOL_SIZE, POOL_SIZE); |
459 | 7.96k | msg = parse_message(pool, DataFx, Size); |
460 | | |
461 | 7.96k | if (msg) { |
462 | 4.83k | pjsip_rx_data rdata; |
463 | 4.83k | pj_sockaddr remote_addr; |
464 | 4.83k | pjsip_transport *fake_transport = NULL; |
465 | 4.83k | int i; |
466 | | |
467 | 4.83k | do_test_multipart(pool, msg); |
468 | | |
469 | | /* Test named headers */ |
470 | 4.83k | const char *hdr_names[] = { |
471 | 4.83k | "Replaces", "Refer-To", "Refer-Sub", "Subscription-State", |
472 | 4.83k | "Session-Expires", "Min-SE", "RSeq", "RAck" |
473 | 4.83k | }; |
474 | 43.4k | for (i = 0; i < (int)(sizeof(hdr_names) / sizeof(hdr_names[0])); i++) { |
475 | 38.6k | pj_str_t hdr_name = pj_str((char *)hdr_names[i]); |
476 | 38.6k | pjsip_msg_find_hdr_by_name(msg, &hdr_name, NULL); |
477 | 38.6k | } |
478 | | |
479 | | /* Test standard header types */ |
480 | 38.6k | for (i = 0; i < (int)(sizeof(hdr_types) / sizeof(hdr_types[0])); i++) { |
481 | 33.8k | pjsip_msg_find_hdr(msg, hdr_types[i], NULL); |
482 | 33.8k | } |
483 | | |
484 | | /* Setup rx_data for transaction testing */ |
485 | 4.83k | pj_bzero(&rdata, sizeof(rdata)); |
486 | 4.83k | rdata.msg_info.msg = msg; |
487 | 4.83k | rdata.msg_info.len = Size; |
488 | 4.83k | rdata.msg_info.info = DataFx; |
489 | 4.83k | rdata.tp_info.pool = pool; |
490 | | |
491 | | /* Populate header shortcuts */ |
492 | 4.83k | rdata.msg_info.from = (pjsip_from_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_FROM, NULL); |
493 | 4.83k | rdata.msg_info.to = (pjsip_to_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_TO, NULL); |
494 | 4.83k | rdata.msg_info.via = (pjsip_via_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_VIA, NULL); |
495 | 4.83k | rdata.msg_info.cseq = (pjsip_cseq_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_CSEQ, NULL); |
496 | 4.83k | rdata.msg_info.cid = (pjsip_cid_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_CALL_ID, NULL); |
497 | 4.83k | rdata.msg_info.max_fwd = (pjsip_max_fwd_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_MAX_FORWARDS, NULL); |
498 | | |
499 | | /* Setup transport info */ |
500 | 4.83k | pj_sockaddr_init(pj_AF_INET(), &remote_addr, NULL, 5060); |
501 | 4.83k | remote_addr.ipv4.sin_addr.s_addr = pj_htonl(0x7F000001); |
502 | | |
503 | 4.83k | pj_memcpy(&rdata.pkt_info.src_addr, &remote_addr, |
504 | 4.83k | sizeof(remote_addr.ipv4)); |
505 | 4.83k | rdata.pkt_info.src_addr_len = sizeof(remote_addr.ipv4); |
506 | 4.83k | pj_ansi_snprintf(rdata.pkt_info.src_name, sizeof(rdata.pkt_info.src_name), |
507 | 4.83k | "127.0.0.1"); |
508 | 4.83k | rdata.pkt_info.src_port = 5060; |
509 | 4.83k | if (Size < sizeof(rdata.pkt_info.packet)) { |
510 | 4.74k | pj_memcpy(rdata.pkt_info.packet, DataFx, Size); |
511 | 4.74k | rdata.pkt_info.len = Size; |
512 | 4.74k | } else { |
513 | 86 | pj_memcpy(rdata.pkt_info.packet, DataFx, sizeof(rdata.pkt_info.packet)); |
514 | 86 | rdata.pkt_info.len = sizeof(rdata.pkt_info.packet); |
515 | 86 | } |
516 | | |
517 | | /* Acquire loop datagram transport */ |
518 | 4.83k | if (pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_LOOP_DGRAM, |
519 | 4.83k | &remote_addr, |
520 | 4.83k | sizeof(remote_addr.ipv4), |
521 | 4.83k | NULL, &fake_transport) == PJ_SUCCESS) { |
522 | 4.83k | rdata.tp_info.transport = fake_transport; |
523 | 4.83k | } |
524 | | |
525 | 4.83k | do_test_transaction_layer(msg, &rdata); |
526 | | |
527 | 4.83k | if (msg->type == PJSIP_RESPONSE_MSG) { |
528 | 3.05k | do_test_transaction_uac(msg, &rdata); |
529 | 3.05k | } |
530 | | |
531 | 4.83k | do_test_auth_client(pool, msg); |
532 | 4.83k | do_test_dialog(msg); |
533 | | |
534 | 4.83k | if (msg->type == PJSIP_REQUEST_MSG && rdata.msg_info.via) { |
535 | 1.63k | pj_strdup2(pool, &rdata.msg_info.via->recvd_param, |
536 | 1.63k | rdata.pkt_info.src_name); |
537 | 1.63k | if (rdata.msg_info.via->rport_param == 0) { |
538 | 29 | rdata.msg_info.via->rport_param = rdata.pkt_info.src_port; |
539 | 29 | } |
540 | 1.63k | } |
541 | | |
542 | | /* Route through the full endpoint module pipeline */ |
543 | 4.83k | if (rdata.tp_info.transport && |
544 | 4.83k | rdata.msg_info.from && rdata.msg_info.to && |
545 | 1.73k | rdata.msg_info.via && rdata.msg_info.cseq && |
546 | 1.62k | rdata.msg_info.cid && rdata.msg_info.cid->id.slen != 0) { |
547 | 1.62k | pjsip_transaction *tsx; |
548 | 1.62k | pj_time_val timeout = {0, 0}; |
549 | 1.62k | unsigned i; |
550 | | |
551 | 1.62k | pjsip_endpt_process_rx_data(endpt, &rdata, NULL, NULL); |
552 | | |
553 | 1.62k | tsx = pjsip_rdata_get_tsx(&rdata); |
554 | 1.62k | if (tsx) { |
555 | 0 | pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED); |
556 | 0 | } |
557 | | |
558 | | /* Pump events repeatedly */ |
559 | 14.6k | for (i = 0; i < 8; ++i) { |
560 | 13.0k | pjsip_endpt_handle_events(endpt, &timeout); |
561 | 13.0k | } |
562 | 1.62k | } |
563 | | |
564 | | /* Release transport */ |
565 | 4.83k | if (fake_transport) { |
566 | 4.83k | pjsip_transport_dec_ref(fake_transport); |
567 | 4.83k | } |
568 | 4.83k | } |
569 | | |
570 | 7.96k | do_test_tel_uri(pool, DataFx, Size); |
571 | | |
572 | 7.96k | pjsip_endpt_release_pool(endpt, pool); |
573 | 7.96k | free(DataFx); |
574 | | |
575 | 7.96k | return 0; |
576 | 7.96k | } |
577 | | |