blob: ebf5a2bd33b94328209f7ca95b462a0161f34c96 [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $Id$ */
2/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include "test.h"
21
22#define THIS_FILE "stun_sock_test.c"
23
24enum {
25 RESPOND_STUN = 1,
26 WITH_MAPPED = 2,
27 WITH_XOR_MAPPED = 4,
28
29 ECHO = 8
30};
31
32/*
33 * Simple STUN server
34 */
35struct stun_srv
36{
37 pj_activesock_t *asock;
38 unsigned flag;
39 pj_sockaddr addr;
40 unsigned rx_cnt;
41 pj_ioqueue_op_key_t send_key;
42 pj_str_t ip_to_send;
43 pj_uint16_t port_to_send;
44};
45
46static pj_bool_t srv_on_data_recvfrom(pj_activesock_t *asock,
47 void *data,
48 pj_size_t size,
49 const pj_sockaddr_t *src_addr,
50 int addr_len,
51 pj_status_t status)
52{
53 struct stun_srv *srv;
54 pj_ssize_t sent;
55
56 srv = (struct stun_srv*) pj_activesock_get_user_data(asock);
57
58 /* Ignore error */
59 if (status != PJ_SUCCESS)
60 return PJ_TRUE;
61
62 ++srv->rx_cnt;
63
64 /* Ignore if we're not responding */
65 if (srv->flag & RESPOND_STUN) {
66 pj_pool_t *pool;
67 pj_stun_msg *req_msg, *res_msg;
68
69 pool = pj_pool_create(mem, "stunsrv", 512, 512, NULL);
70
71 /* Parse request */
72 status = pj_stun_msg_decode(pool, (pj_uint8_t*)data, size,
73 PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
74 &req_msg, NULL, NULL);
75 if (status != PJ_SUCCESS) {
76 app_perror(" pj_stun_msg_decode()", status);
77 pj_pool_release(pool);
78 return PJ_TRUE;
79 }
80
81 /* Create response */
82 status = pj_stun_msg_create(pool, PJ_STUN_BINDING_RESPONSE, PJ_STUN_MAGIC,
83 req_msg->hdr.tsx_id, &res_msg);
84 if (status != PJ_SUCCESS) {
85 app_perror(" pj_stun_msg_create()", status);
86 pj_pool_release(pool);
87 return PJ_TRUE;
88 }
89
90 /* Add MAPPED-ADDRESS or XOR-MAPPED-ADDRESS (or don't add) */
91 if (srv->flag & WITH_MAPPED) {
92 pj_sockaddr_in addr;
93
94 pj_sockaddr_in_init(&addr, &srv->ip_to_send, srv->port_to_send);
95 pj_stun_msg_add_sockaddr_attr(pool, res_msg, PJ_STUN_ATTR_MAPPED_ADDR,
96 PJ_FALSE, &addr, sizeof(addr));
97 } else if (srv->flag & WITH_XOR_MAPPED) {
98 pj_sockaddr_in addr;
99
100 pj_sockaddr_in_init(&addr, &srv->ip_to_send, srv->port_to_send);
101 pj_stun_msg_add_sockaddr_attr(pool, res_msg,
102 PJ_STUN_ATTR_XOR_MAPPED_ADDR,
103 PJ_TRUE, &addr, sizeof(addr));
104 }
105
106 /* Encode */
107 status = pj_stun_msg_encode(res_msg, (pj_uint8_t*)data, 100, 0,
108 NULL, &size);
109 if (status != PJ_SUCCESS) {
110 app_perror(" pj_stun_msg_encode()", status);
111 pj_pool_release(pool);
112 return PJ_TRUE;
113 }
114
115 /* Send back */
116 sent = size;
117 pj_activesock_sendto(asock, &srv->send_key, data, &sent, 0,
118 src_addr, addr_len);
119
120 pj_pool_release(pool);
121
122 } else if (srv->flag & ECHO) {
123 /* Send back */
124 sent = size;
125 pj_activesock_sendto(asock, &srv->send_key, data, &sent, 0,
126 src_addr, addr_len);
127
128 }
129
130 return PJ_TRUE;
131}
132
133static pj_status_t create_server(pj_pool_t *pool,
134 pj_ioqueue_t *ioqueue,
135 unsigned flag,
136 struct stun_srv **p_srv)
137{
138 struct stun_srv *srv;
139 pj_activesock_cb activesock_cb;
140 pj_status_t status;
141
142 srv = PJ_POOL_ZALLOC_T(pool, struct stun_srv);
143 srv->flag = flag;
144 srv->ip_to_send = pj_str("1.1.1.1");
145 srv->port_to_send = 1000;
146
147 status = pj_sockaddr_in_init(&srv->addr.ipv4, NULL, 0);
148 if (status != PJ_SUCCESS)
149 return status;
150
151 pj_bzero(&activesock_cb, sizeof(activesock_cb));
152 activesock_cb.on_data_recvfrom = &srv_on_data_recvfrom;
153 status = pj_activesock_create_udp(pool, &srv->addr, NULL, ioqueue,
154 &activesock_cb, srv, &srv->asock,
155 &srv->addr);
156 if (status != PJ_SUCCESS)
157 return status;
158
159 pj_ioqueue_op_key_init(&srv->send_key, sizeof(srv->send_key));
160
161 status = pj_activesock_start_recvfrom(srv->asock, pool, 512, 0);
162 if (status != PJ_SUCCESS) {
163 pj_activesock_close(srv->asock);
164 return status;
165 }
166
167 *p_srv = srv;
168 return PJ_SUCCESS;
169}
170
171static void destroy_server(struct stun_srv *srv)
172{
173 pj_activesock_close(srv->asock);
174}
175
176
177struct stun_client
178{
179 pj_pool_t *pool;
180 pj_stun_sock *sock;
181
182 pj_ioqueue_op_key_t send_key;
183 pj_bool_t destroy_on_err;
184
185 unsigned on_status_cnt;
186 pj_stun_sock_op last_op;
187 pj_status_t last_status;
188
189 unsigned on_rx_data_cnt;
190};
191
192static pj_bool_t stun_sock_on_status(pj_stun_sock *stun_sock,
193 pj_stun_sock_op op,
194 pj_status_t status)
195{
196 struct stun_client *client;
197
198 client = (struct stun_client*) pj_stun_sock_get_user_data(stun_sock);
199 client->on_status_cnt++;
200 client->last_op = op;
201 client->last_status = status;
202
203 if (status != PJ_SUCCESS && client->destroy_on_err) {
204 pj_stun_sock_destroy(client->sock);
205 client->sock = NULL;
206 return PJ_FALSE;
207 }
208
209 return PJ_TRUE;
210}
211
212static pj_bool_t stun_sock_on_rx_data(pj_stun_sock *stun_sock,
213 void *pkt,
214 unsigned pkt_len,
215 const pj_sockaddr_t *src_addr,
216 unsigned addr_len)
217{
218 struct stun_client *client;
219
220 PJ_UNUSED_ARG(pkt);
221 PJ_UNUSED_ARG(pkt_len);
222 PJ_UNUSED_ARG(src_addr);
223 PJ_UNUSED_ARG(addr_len);
224
225 client = (struct stun_client*) pj_stun_sock_get_user_data(stun_sock);
226 client->on_rx_data_cnt++;
227
228 return PJ_TRUE;
229}
230
231static pj_status_t create_client(pj_stun_config *cfg,
232 struct stun_client **p_client,
233 pj_bool_t destroy_on_err)
234{
235 pj_pool_t *pool;
236 struct stun_client *client;
237 pj_stun_sock_cfg sock_cfg;
238 pj_stun_sock_cb cb;
239 pj_status_t status;
240
241 pool = pj_pool_create(mem, "test", 512, 512, NULL);
242 client = PJ_POOL_ZALLOC_T(pool, struct stun_client);
243 client->pool = pool;
244
245 pj_stun_sock_cfg_default(&sock_cfg);
246
247 pj_bzero(&cb, sizeof(cb));
248 cb.on_status = &stun_sock_on_status;
249 cb.on_rx_data = &stun_sock_on_rx_data;
250 status = pj_stun_sock_create(cfg, NULL, pj_AF_INET(), &cb,
251 &sock_cfg, client, &client->sock);
252 if (status != PJ_SUCCESS) {
253 app_perror(" pj_stun_sock_create()", status);
254 pj_pool_release(pool);
255 return status;
256 }
257
258 pj_stun_sock_set_user_data(client->sock, client);
259
260 pj_ioqueue_op_key_init(&client->send_key, sizeof(client->send_key));
261
262 client->destroy_on_err = destroy_on_err;
263
264 *p_client = client;
265
266 return PJ_SUCCESS;
267}
268
269
270static void destroy_client(struct stun_client *client)
271{
272 if (client->sock) {
273 pj_stun_sock_destroy(client->sock);
274 client->sock = NULL;
275 }
276 pj_pool_release(client->pool);
277}
278
279static void handle_events(pj_stun_config *cfg, unsigned msec_delay)
280{
281 pj_time_val delay;
282
283 pj_timer_heap_poll(cfg->timer_heap, NULL);
284
285 delay.sec = 0;
286 delay.msec = msec_delay;
287 pj_time_val_normalize(&delay);
288
289 pj_ioqueue_poll(cfg->ioqueue, &delay);
290}
291
292/*
293 * Timeout test: scenario when no response is received from server
294 */
295static int timeout_test(pj_stun_config *cfg, pj_bool_t destroy_on_err)
296{
297 struct stun_srv *srv;
298 struct stun_client *client;
299 pj_str_t srv_addr;
300 pj_time_val timeout, t;
301 int i, ret = 0;
302 pj_status_t status;
303
304 PJ_LOG(3,(THIS_FILE, " timeout test [%d]", destroy_on_err));
305
306 status = create_client(cfg, &client, destroy_on_err);
307 if (status != PJ_SUCCESS)
308 return -10;
309
310 status = create_server(client->pool, cfg->ioqueue, 0, &srv);
311 if (status != PJ_SUCCESS) {
312 destroy_client(client);
313 return -20;
314 }
315
316 srv_addr = pj_str("127.0.0.1");
317 status = pj_stun_sock_start(client->sock, &srv_addr,
318 pj_ntohs(srv->addr.ipv4.sin_port), NULL);
319 if (status != PJ_SUCCESS) {
320 destroy_server(srv);
321 destroy_client(client);
322 return -30;
323 }
324
325 /* Wait until on_status() callback is called with the failure */
326 pj_gettimeofday(&timeout);
327 timeout.sec += 60;
328 do {
329 handle_events(cfg, 100);
330 pj_gettimeofday(&t);
331 } while (client->on_status_cnt==0 && PJ_TIME_VAL_LT(t, timeout));
332
333 /* Check that callback with correct operation is called */
334 if (client->last_op != PJ_STUN_SOCK_BINDING_OP) {
335 PJ_LOG(3,(THIS_FILE, " error: expecting Binding operation status"));
336 ret = -40;
337 goto on_return;
338 }
339 /* .. and with the correct status */
340 if (client->last_status != PJNATH_ESTUNTIMEDOUT) {
341 PJ_LOG(3,(THIS_FILE, " error: expecting PJNATH_ESTUNTIMEDOUT"));
342 ret = -50;
343 goto on_return;
344 }
345 /* Check that server received correct retransmissions */
346 if (srv->rx_cnt != PJ_STUN_MAX_TRANSMIT_COUNT) {
347 PJ_LOG(3,(THIS_FILE, " error: expecting %d retransmissions, got %d",
348 PJ_STUN_MAX_TRANSMIT_COUNT, srv->rx_cnt));
349 ret = -60;
350 goto on_return;
351 }
352 /* Check that client doesn't receive anything */
353 if (client->on_rx_data_cnt != 0) {
354 PJ_LOG(3,(THIS_FILE, " error: client shouldn't have received anything"));
355 ret = -70;
356 goto on_return;
357 }
358
359on_return:
360 destroy_server(srv);
361 destroy_client(client);
362 for (i=0; i<7; ++i)
363 handle_events(cfg, 50);
364 return ret;
365}
366
367
368/*
369 * Invalid response scenario: when server returns no MAPPED-ADDRESS or
370 * XOR-MAPPED-ADDRESS attribute.
371 */
372static int missing_attr_test(pj_stun_config *cfg, pj_bool_t destroy_on_err)
373{
374 struct stun_srv *srv;
375 struct stun_client *client;
376 pj_str_t srv_addr;
377 pj_time_val timeout, t;
378 int i, ret = 0;
379 pj_status_t status;
380
381 PJ_LOG(3,(THIS_FILE, " missing attribute test [%d]", destroy_on_err));
382
383 status = create_client(cfg, &client, destroy_on_err);
384 if (status != PJ_SUCCESS)
385 return -110;
386
387 status = create_server(client->pool, cfg->ioqueue, RESPOND_STUN, &srv);
388 if (status != PJ_SUCCESS) {
389 destroy_client(client);
390 return -120;
391 }
392
393 srv_addr = pj_str("127.0.0.1");
394 status = pj_stun_sock_start(client->sock, &srv_addr,
395 pj_ntohs(srv->addr.ipv4.sin_port), NULL);
396 if (status != PJ_SUCCESS) {
397 destroy_server(srv);
398 destroy_client(client);
399 return -130;
400 }
401
402 /* Wait until on_status() callback is called with the failure */
403 pj_gettimeofday(&timeout);
404 timeout.sec += 60;
405 do {
406 handle_events(cfg, 100);
407 pj_gettimeofday(&t);
408 } while (client->on_status_cnt==0 && PJ_TIME_VAL_LT(t, timeout));
409
410 /* Check that callback with correct operation is called */
411 if (client->last_op != PJ_STUN_SOCK_BINDING_OP) {
412 PJ_LOG(3,(THIS_FILE, " error: expecting Binding operation status"));
413 ret = -140;
414 goto on_return;
415 }
416 if (client->last_status != PJNATH_ESTUNNOMAPPEDADDR) {
417 PJ_LOG(3,(THIS_FILE, " error: expecting PJNATH_ESTUNNOMAPPEDADDR"));
418 ret = -150;
419 goto on_return;
420 }
421 /* Check that client doesn't receive anything */
422 if (client->on_rx_data_cnt != 0) {
423 PJ_LOG(3,(THIS_FILE, " error: client shouldn't have received anything"));
424 ret = -170;
425 goto on_return;
426 }
427
428on_return:
429 destroy_server(srv);
430 destroy_client(client);
431 for (i=0; i<7; ++i)
432 handle_events(cfg, 50);
433 return ret;
434}
435
436/*
437 * Keep-alive test.
438 */
439static int keep_alive_test(pj_stun_config *cfg)
440{
441 struct stun_srv *srv;
442 struct stun_client *client;
443 pj_sockaddr_in mapped_addr;
444 pj_stun_sock_info info;
445 pj_str_t srv_addr;
446 pj_time_val timeout, t;
447 int i, ret = 0;
448 pj_status_t status;
449
450 PJ_LOG(3,(THIS_FILE, " normal operation"));
451
452 status = create_client(cfg, &client, PJ_TRUE);
453 if (status != PJ_SUCCESS)
454 return -310;
455
456 status = create_server(client->pool, cfg->ioqueue, RESPOND_STUN|WITH_XOR_MAPPED, &srv);
457 if (status != PJ_SUCCESS) {
458 destroy_client(client);
459 return -320;
460 }
461
462 /*
463 * Part 1: initial Binding resolution.
464 */
465 PJ_LOG(3,(THIS_FILE, " initial Binding request"));
466 srv_addr = pj_str("127.0.0.1");
467 status = pj_stun_sock_start(client->sock, &srv_addr,
468 pj_ntohs(srv->addr.ipv4.sin_port), NULL);
469 if (status != PJ_SUCCESS) {
470 destroy_server(srv);
471 destroy_client(client);
472 return -330;
473 }
474
475 /* Wait until on_status() callback is called with success status */
476 pj_gettimeofday(&timeout);
477 timeout.sec += 60;
478 do {
479 handle_events(cfg, 100);
480 pj_gettimeofday(&t);
481 } while (client->on_status_cnt==0 && PJ_TIME_VAL_LT(t, timeout));
482
483 /* Check that callback with correct operation is called */
484 if (client->last_op != PJ_STUN_SOCK_BINDING_OP) {
485 PJ_LOG(3,(THIS_FILE, " error: expecting Binding operation status"));
486 ret = -340;
487 goto on_return;
488 }
489 if (client->last_status != PJ_SUCCESS) {
490 PJ_LOG(3,(THIS_FILE, " error: expecting PJ_SUCCESS status"));
491 ret = -350;
492 goto on_return;
493 }
494 /* Check that client doesn't receive anything */
495 if (client->on_rx_data_cnt != 0) {
496 PJ_LOG(3,(THIS_FILE, " error: client shouldn't have received anything"));
497 ret = -370;
498 goto on_return;
499 }
500
501 /* Get info */
502 pj_bzero(&info, sizeof(info));
503 pj_stun_sock_get_info(client->sock, &info);
504
505 /* Check that we have server address */
506 if (!pj_sockaddr_has_addr(&info.srv_addr)) {
507 PJ_LOG(3,(THIS_FILE, " error: missing server address"));
508 ret = -380;
509 goto on_return;
510 }
511 /* .. and bound address port must not be zero */
512 if (pj_sockaddr_get_port(&info.bound_addr)==0) {
513 PJ_LOG(3,(THIS_FILE, " error: bound address is zero"));
514 ret = -381;
515 goto on_return;
516 }
517 /* .. and mapped address */
518 if (!pj_sockaddr_has_addr(&info.mapped_addr)) {
519 PJ_LOG(3,(THIS_FILE, " error: missing mapped address"));
520 ret = -382;
521 goto on_return;
522 }
523 /* verify the mapped address */
524 pj_sockaddr_in_init(&mapped_addr, &srv->ip_to_send, srv->port_to_send);
525 if (pj_sockaddr_cmp(&info.mapped_addr, &mapped_addr) != 0) {
526 PJ_LOG(3,(THIS_FILE, " error: mapped address mismatched"));
527 ret = -383;
528 goto on_return;
529 }
530
531 /* .. and at least one alias */
532 if (info.alias_cnt == 0) {
533 PJ_LOG(3,(THIS_FILE, " error: must have at least one alias"));
534 ret = -384;
535 goto on_return;
536 }
537 if (!pj_sockaddr_has_addr(&info.aliases[0])) {
538 PJ_LOG(3,(THIS_FILE, " error: missing alias"));
539 ret = -386;
540 goto on_return;
541 }
542
543
544 /*
545 * Part 2: sending and receiving data
546 */
547 PJ_LOG(3,(THIS_FILE, " sending/receiving data"));
548
549 /* Change server operation mode to echo back data */
550 srv->flag = ECHO;
551
552 /* Reset server */
553 srv->rx_cnt = 0;
554
555 /* Client sending data to echo server */
556 {
557 char txt[100];
558 PJ_LOG(3,(THIS_FILE, " sending to %s", pj_sockaddr_print(&info.srv_addr, txt, sizeof(txt), 3)));
559 }
560 status = pj_stun_sock_sendto(client->sock, NULL, &ret, sizeof(ret),
561 0, &info.srv_addr,
562 pj_sockaddr_get_len(&info.srv_addr));
563 if (status != PJ_SUCCESS && status != PJ_EPENDING) {
564 app_perror(" error: server sending data", status);
565 ret = -390;
566 goto on_return;
567 }
568
569 /* Wait for a short period until client receives data. We can't wait for
570 * too long otherwise the keep-alive will kick in.
571 */
572 pj_gettimeofday(&timeout);
573 timeout.sec += 1;
574 do {
575 handle_events(cfg, 100);
576 pj_gettimeofday(&t);
577 } while (client->on_rx_data_cnt==0 && PJ_TIME_VAL_LT(t, timeout));
578
579 /* Check that data is received in server */
580 if (srv->rx_cnt == 0) {
581 PJ_LOG(3,(THIS_FILE, " error: server didn't receive data"));
582 ret = -395;
583 goto on_return;
584 }
585
586 /* Check that status is still OK */
587 if (client->last_status != PJ_SUCCESS) {
588 app_perror(" error: client has failed", client->last_status);
589 ret = -400;
590 goto on_return;
591 }
592 /* Check that data has been received */
593 if (client->on_rx_data_cnt == 0) {
594 PJ_LOG(3,(THIS_FILE, " error: client doesn't receive data"));
595 ret = -410;
596 goto on_return;
597 }
598
599 /*
600 * Part 3: Successful keep-alive,
601 */
602 PJ_LOG(3,(THIS_FILE, " successful keep-alive scenario"));
603
604 /* Change server operation mode to normal mode */
605 srv->flag = RESPOND_STUN | WITH_XOR_MAPPED;
606
607 /* Reset server */
608 srv->rx_cnt = 0;
609
610 /* Reset client */
611 client->on_status_cnt = 0;
612 client->last_status = PJ_SUCCESS;
613 client->on_rx_data_cnt = 0;
614
615 /* Wait for keep-alive duration to see if client actually sends the
616 * keep-alive.
617 */
618 pj_gettimeofday(&timeout);
619 timeout.sec += (PJ_STUN_KEEP_ALIVE_SEC + 1);
620 do {
621 handle_events(cfg, 100);
622 pj_gettimeofday(&t);
623 } while (PJ_TIME_VAL_LT(t, timeout));
624
625 /* Check that server receives some packets */
626 if (srv->rx_cnt == 0) {
627 PJ_LOG(3, (THIS_FILE, " error: no keep-alive was received"));
628 ret = -420;
629 goto on_return;
630 }
631 /* Check that client status is still okay and on_status() callback is NOT
632 * called
633 */
634 /* No longer valid due to this ticket:
635 * http://trac.pjsip.org/repos/ticket/742
636
637 if (client->on_status_cnt != 0) {
638 PJ_LOG(3, (THIS_FILE, " error: on_status() must not be called on successful"
639 "keep-alive when mapped-address does not change"));
640 ret = -430;
641 goto on_return;
642 }
643 */
644 /* Check that client doesn't receive anything */
645 if (client->on_rx_data_cnt != 0) {
646 PJ_LOG(3,(THIS_FILE, " error: client shouldn't have received anything"));
647 ret = -440;
648 goto on_return;
649 }
650
651
652 /*
653 * Part 4: Successful keep-alive with IP address change
654 */
655 PJ_LOG(3,(THIS_FILE, " mapped IP address change"));
656
657 /* Change server operation mode to normal mode */
658 srv->flag = RESPOND_STUN | WITH_XOR_MAPPED;
659
660 /* Change mapped address in the response */
661 srv->ip_to_send = pj_str("2.2.2.2");
662 srv->port_to_send++;
663
664 /* Reset server */
665 srv->rx_cnt = 0;
666
667 /* Reset client */
668 client->on_status_cnt = 0;
669 client->last_status = PJ_SUCCESS;
670 client->on_rx_data_cnt = 0;
671
672 /* Wait for keep-alive duration to see if client actually sends the
673 * keep-alive.
674 */
675 pj_gettimeofday(&timeout);
676 timeout.sec += (PJ_STUN_KEEP_ALIVE_SEC + 1);
677 do {
678 handle_events(cfg, 100);
679 pj_gettimeofday(&t);
680 } while (PJ_TIME_VAL_LT(t, timeout));
681
682 /* Check that server receives some packets */
683 if (srv->rx_cnt == 0) {
684 PJ_LOG(3, (THIS_FILE, " error: no keep-alive was received"));
685 ret = -450;
686 goto on_return;
687 }
688 /* Check that on_status() callback is called (because mapped address
689 * has changed)
690 */
691 if (client->on_status_cnt != 1) {
692 PJ_LOG(3, (THIS_FILE, " error: on_status() was not called"));
693 ret = -460;
694 goto on_return;
695 }
696 /* Check that callback was called with correct operation */
697 if (client->last_op != PJ_STUN_SOCK_MAPPED_ADDR_CHANGE) {
698 PJ_LOG(3,(THIS_FILE, " error: expecting keep-alive operation status"));
699 ret = -470;
700 goto on_return;
701 }
702 /* Check that last status is still success */
703 if (client->last_status != PJ_SUCCESS) {
704 PJ_LOG(3, (THIS_FILE, " error: expecting successful status"));
705 ret = -480;
706 goto on_return;
707 }
708 /* Check that client doesn't receive anything */
709 if (client->on_rx_data_cnt != 0) {
710 PJ_LOG(3,(THIS_FILE, " error: client shouldn't have received anything"));
711 ret = -490;
712 goto on_return;
713 }
714
715 /* Get info */
716 pj_bzero(&info, sizeof(info));
717 pj_stun_sock_get_info(client->sock, &info);
718
719 /* Check that we have server address */
720 if (!pj_sockaddr_has_addr(&info.srv_addr)) {
721 PJ_LOG(3,(THIS_FILE, " error: missing server address"));
722 ret = -500;
723 goto on_return;
724 }
725 /* .. and mapped address */
726 if (!pj_sockaddr_has_addr(&info.mapped_addr)) {
727 PJ_LOG(3,(THIS_FILE, " error: missing mapped address"));
728 ret = -510;
729 goto on_return;
730 }
731 /* verify the mapped address */
732 pj_sockaddr_in_init(&mapped_addr, &srv->ip_to_send, srv->port_to_send);
733 if (pj_sockaddr_cmp(&info.mapped_addr, &mapped_addr) != 0) {
734 PJ_LOG(3,(THIS_FILE, " error: mapped address mismatched"));
735 ret = -520;
736 goto on_return;
737 }
738
739 /* .. and at least one alias */
740 if (info.alias_cnt == 0) {
741 PJ_LOG(3,(THIS_FILE, " error: must have at least one alias"));
742 ret = -530;
743 goto on_return;
744 }
745 if (!pj_sockaddr_has_addr(&info.aliases[0])) {
746 PJ_LOG(3,(THIS_FILE, " error: missing alias"));
747 ret = -540;
748 goto on_return;
749 }
750
751
752 /*
753 * Part 5: Failed keep-alive
754 */
755 PJ_LOG(3,(THIS_FILE, " failed keep-alive scenario"));
756
757 /* Change server operation mode to respond without attribute */
758 srv->flag = RESPOND_STUN;
759
760 /* Reset server */
761 srv->rx_cnt = 0;
762
763 /* Reset client */
764 client->on_status_cnt = 0;
765 client->last_status = PJ_SUCCESS;
766 client->on_rx_data_cnt = 0;
767
768 /* Wait until on_status() is called with failure. */
769 pj_gettimeofday(&timeout);
770 timeout.sec += (PJ_STUN_KEEP_ALIVE_SEC + PJ_STUN_TIMEOUT_VALUE + 5);
771 do {
772 handle_events(cfg, 100);
773 pj_gettimeofday(&t);
774 } while (client->on_status_cnt==0 && PJ_TIME_VAL_LT(t, timeout));
775
776 /* Check that callback with correct operation is called */
777 if (client->last_op != PJ_STUN_SOCK_KEEP_ALIVE_OP) {
778 PJ_LOG(3,(THIS_FILE, " error: expecting keep-alive operation status"));
779 ret = -600;
780 goto on_return;
781 }
782 if (client->last_status == PJ_SUCCESS) {
783 PJ_LOG(3,(THIS_FILE, " error: expecting failed keep-alive"));
784 ret = -610;
785 goto on_return;
786 }
787 /* Check that client doesn't receive anything */
788 if (client->on_rx_data_cnt != 0) {
789 PJ_LOG(3,(THIS_FILE, " error: client shouldn't have received anything"));
790 ret = -620;
791 goto on_return;
792 }
793
794
795on_return:
796 destroy_server(srv);
797 destroy_client(client);
798 for (i=0; i<7; ++i)
799 handle_events(cfg, 50);
800 return ret;
801}
802
803
804#define DO_TEST(expr) \
805 capture_pjlib_state(&stun_cfg, &pjlib_state); \
806 ret = expr; \
807 if (ret != 0) goto on_return; \
808 ret = check_pjlib_state(&stun_cfg, &pjlib_state); \
809 if (ret != 0) goto on_return;
810
811
812int stun_sock_test(void)
813{
814 struct pjlib_state pjlib_state;
815 pj_stun_config stun_cfg;
816 pj_ioqueue_t *ioqueue = NULL;
817 pj_timer_heap_t *timer_heap = NULL;
818 pj_pool_t *pool = NULL;
819 pj_status_t status;
820 int ret = 0;
821
822 pool = pj_pool_create(mem, NULL, 512, 512, NULL);
823
824 status = pj_ioqueue_create(pool, 12, &ioqueue);
825 if (status != PJ_SUCCESS) {
826 app_perror(" pj_ioqueue_create()", status);
827 ret = -4;
828 goto on_return;
829 }
830
831 status = pj_timer_heap_create(pool, 100, &timer_heap);
832 if (status != PJ_SUCCESS) {
833 app_perror(" pj_timer_heap_create()", status);
834 ret = -8;
835 goto on_return;
836 }
837
838 pj_stun_config_init(&stun_cfg, mem, 0, ioqueue, timer_heap);
839
840 DO_TEST(timeout_test(&stun_cfg, PJ_FALSE));
841 DO_TEST(timeout_test(&stun_cfg, PJ_TRUE));
842
843 DO_TEST(missing_attr_test(&stun_cfg, PJ_FALSE));
844 DO_TEST(missing_attr_test(&stun_cfg, PJ_TRUE));
845
846 DO_TEST(keep_alive_test(&stun_cfg));
847
848on_return:
849 if (timer_heap) pj_timer_heap_destroy(timer_heap);
850 if (ioqueue) pj_ioqueue_destroy(ioqueue);
851 if (pool) pj_pool_release(pool);
852 return ret;
853}
854
855