blob: d867a6bbef613cfa162bf8d9e9b752f7bfebf8b5 [file] [log] [blame]
Benny Prijonoff1df042008-06-06 14:47:10 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijonoff1df042008-06-06 14:47:10 +00005 *
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
Benny Prijono89ac2b42008-06-13 12:52:56 +000056 srv = (struct stun_srv*) pj_activesock_get_user_data(asock);
Benny Prijonoff1df042008-06-06 14:47:10 +000057
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
Benny Prijono89ac2b42008-06-13 12:52:56 +0000198 client = (struct stun_client*) pj_stun_sock_get_user_data(stun_sock);
Benny Prijonoff1df042008-06-06 14:47:10 +0000199 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
Benny Prijono89ac2b42008-06-13 12:52:56 +0000225 client = (struct stun_client*) pj_stun_sock_get_user_data(stun_sock);
Benny Prijonoff1df042008-06-06 14:47:10 +0000226 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 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 return ret;
363}
364
365
366/*
367 * Invalid response scenario: when server returns no MAPPED-ADDRESS or
368 * XOR-MAPPED-ADDRESS attribute.
369 */
370static int missing_attr_test(pj_stun_config *cfg, pj_bool_t destroy_on_err)
371{
372 struct stun_srv *srv;
373 struct stun_client *client;
374 pj_str_t srv_addr;
375 pj_time_val timeout, t;
376 int ret = 0;
377 pj_status_t status;
378
379 PJ_LOG(3,(THIS_FILE, " missing attribute test [%d]", destroy_on_err));
380
381 status = create_client(cfg, &client, destroy_on_err);
382 if (status != PJ_SUCCESS)
383 return -110;
384
385 status = create_server(client->pool, cfg->ioqueue, RESPOND_STUN, &srv);
386 if (status != PJ_SUCCESS) {
387 destroy_client(client);
388 return -120;
389 }
390
391 srv_addr = pj_str("127.0.0.1");
392 status = pj_stun_sock_start(client->sock, &srv_addr,
393 pj_ntohs(srv->addr.ipv4.sin_port), NULL);
394 if (status != PJ_SUCCESS) {
395 destroy_server(srv);
396 destroy_client(client);
397 return -130;
398 }
399
400 /* Wait until on_status() callback is called with the failure */
401 pj_gettimeofday(&timeout);
402 timeout.sec += 60;
403 do {
404 handle_events(cfg, 100);
405 pj_gettimeofday(&t);
406 } while (client->on_status_cnt==0 && PJ_TIME_VAL_LT(t, timeout));
407
408 /* Check that callback with correct operation is called */
409 if (client->last_op != PJ_STUN_SOCK_BINDING_OP) {
410 PJ_LOG(3,(THIS_FILE, " error: expecting Binding operation status"));
411 ret = -140;
412 goto on_return;
413 }
414 if (client->last_status != PJNATH_ESTUNNOMAPPEDADDR) {
415 PJ_LOG(3,(THIS_FILE, " error: expecting PJNATH_ESTUNNOMAPPEDADDR"));
416 ret = -150;
417 goto on_return;
418 }
419 /* Check that client doesn't receive anything */
420 if (client->on_rx_data_cnt != 0) {
421 PJ_LOG(3,(THIS_FILE, " error: client shouldn't have received anything"));
422 ret = -170;
423 goto on_return;
424 }
425
426on_return:
427 destroy_server(srv);
428 destroy_client(client);
429 return ret;
430}
431
432/*
433 * Keep-alive test.
434 */
435static int keep_alive_test(pj_stun_config *cfg)
436{
437 struct stun_srv *srv;
438 struct stun_client *client;
439 pj_sockaddr_in mapped_addr;
440 pj_stun_sock_info info;
441 pj_str_t srv_addr;
442 pj_time_val timeout, t;
443 int ret = 0;
444 pj_status_t status;
445
446 PJ_LOG(3,(THIS_FILE, " normal operation"));
447
448 status = create_client(cfg, &client, PJ_TRUE);
449 if (status != PJ_SUCCESS)
450 return -310;
451
452 status = create_server(client->pool, cfg->ioqueue, RESPOND_STUN|WITH_XOR_MAPPED, &srv);
453 if (status != PJ_SUCCESS) {
454 destroy_client(client);
455 return -320;
456 }
457
458 /*
459 * Part 1: initial Binding resolution.
460 */
461 PJ_LOG(3,(THIS_FILE, " initial Binding request"));
462 srv_addr = pj_str("127.0.0.1");
463 status = pj_stun_sock_start(client->sock, &srv_addr,
464 pj_ntohs(srv->addr.ipv4.sin_port), NULL);
465 if (status != PJ_SUCCESS) {
466 destroy_server(srv);
467 destroy_client(client);
468 return -330;
469 }
470
471 /* Wait until on_status() callback is called with success status */
472 pj_gettimeofday(&timeout);
473 timeout.sec += 60;
474 do {
475 handle_events(cfg, 100);
476 pj_gettimeofday(&t);
477 } while (client->on_status_cnt==0 && PJ_TIME_VAL_LT(t, timeout));
478
479 /* Check that callback with correct operation is called */
480 if (client->last_op != PJ_STUN_SOCK_BINDING_OP) {
481 PJ_LOG(3,(THIS_FILE, " error: expecting Binding operation status"));
482 ret = -340;
483 goto on_return;
484 }
485 if (client->last_status != PJ_SUCCESS) {
486 PJ_LOG(3,(THIS_FILE, " error: expecting PJ_SUCCESS status"));
487 ret = -350;
488 goto on_return;
489 }
490 /* Check that client doesn't receive anything */
491 if (client->on_rx_data_cnt != 0) {
492 PJ_LOG(3,(THIS_FILE, " error: client shouldn't have received anything"));
493 ret = -370;
494 goto on_return;
495 }
496
497 /* Get info */
498 pj_bzero(&info, sizeof(info));
499 pj_stun_sock_get_info(client->sock, &info);
500
501 /* Check that we have server address */
502 if (!pj_sockaddr_has_addr(&info.srv_addr)) {
503 PJ_LOG(3,(THIS_FILE, " error: missing server address"));
504 ret = -380;
505 goto on_return;
506 }
507 /* .. and bound address port must not be zero */
508 if (pj_sockaddr_get_port(&info.bound_addr)==0) {
509 PJ_LOG(3,(THIS_FILE, " error: bound address is zero"));
510 ret = -381;
511 goto on_return;
512 }
513 /* .. and mapped address */
514 if (!pj_sockaddr_has_addr(&info.mapped_addr)) {
515 PJ_LOG(3,(THIS_FILE, " error: missing mapped address"));
516 ret = -382;
517 goto on_return;
518 }
519 /* verify the mapped address */
520 pj_sockaddr_in_init(&mapped_addr, &srv->ip_to_send, srv->port_to_send);
521 if (pj_sockaddr_cmp(&info.mapped_addr, &mapped_addr) != 0) {
522 PJ_LOG(3,(THIS_FILE, " error: mapped address mismatched"));
523 ret = -383;
524 goto on_return;
525 }
526
527 /* .. and at least one alias */
528 if (info.alias_cnt == 0) {
529 PJ_LOG(3,(THIS_FILE, " error: must have at least one alias"));
530 ret = -384;
531 goto on_return;
532 }
533 if (!pj_sockaddr_has_addr(&info.aliases[0])) {
534 PJ_LOG(3,(THIS_FILE, " error: missing alias"));
535 ret = -386;
536 goto on_return;
537 }
538
539
540 /*
541 * Part 2: sending and receiving data
542 */
543 PJ_LOG(3,(THIS_FILE, " sending/receiving data"));
544
545 /* Change server operation mode to echo back data */
546 srv->flag = ECHO;
547
548 /* Reset server */
549 srv->rx_cnt = 0;
550
551 /* Client sending data to echo server */
552 {
553 char txt[100];
554 PJ_LOG(3,(THIS_FILE, " sending to %s", pj_sockaddr_print(&info.srv_addr, txt, sizeof(txt), 3)));
555 }
556 status = pj_stun_sock_sendto(client->sock, NULL, &ret, sizeof(ret),
557 0, &info.srv_addr,
558 pj_sockaddr_get_len(&info.srv_addr));
559 if (status != PJ_SUCCESS && status != PJ_EPENDING) {
560 app_perror(" error: server sending data", status);
561 ret = -390;
562 goto on_return;
563 }
564
565 /* Wait for a short period until client receives data. We can't wait for
566 * too long otherwise the keep-alive will kick in.
567 */
568 pj_gettimeofday(&timeout);
569 timeout.sec += 1;
570 do {
571 handle_events(cfg, 100);
572 pj_gettimeofday(&t);
573 } while (client->on_rx_data_cnt==0 && PJ_TIME_VAL_LT(t, timeout));
574
575 /* Check that data is received in server */
576 if (srv->rx_cnt == 0) {
577 PJ_LOG(3,(THIS_FILE, " error: server didn't receive data"));
578 ret = -395;
579 goto on_return;
580 }
581
582 /* Check that status is still OK */
583 if (client->last_status != PJ_SUCCESS) {
584 app_perror(" error: client has failed", client->last_status);
585 ret = -400;
586 goto on_return;
587 }
588 /* Check that data has been received */
589 if (client->on_rx_data_cnt == 0) {
590 PJ_LOG(3,(THIS_FILE, " error: client doesn't receive data"));
591 ret = -410;
592 goto on_return;
593 }
594
595 /*
596 * Part 3: Successful keep-alive,
597 */
598 PJ_LOG(3,(THIS_FILE, " successful keep-alive scenario"));
599
600 /* Change server operation mode to normal mode */
601 srv->flag = RESPOND_STUN | WITH_XOR_MAPPED;
602
603 /* Reset server */
604 srv->rx_cnt = 0;
605
606 /* Reset client */
607 client->on_status_cnt = 0;
608 client->last_status = PJ_SUCCESS;
609 client->on_rx_data_cnt = 0;
610
611 /* Wait for keep-alive duration to see if client actually sends the
612 * keep-alive.
613 */
614 pj_gettimeofday(&timeout);
615 timeout.sec += (PJ_STUN_KEEP_ALIVE_SEC + 1);
616 do {
617 handle_events(cfg, 100);
618 pj_gettimeofday(&t);
619 } while (PJ_TIME_VAL_LT(t, timeout));
620
621 /* Check that server receives some packets */
622 if (srv->rx_cnt == 0) {
623 PJ_LOG(3, (THIS_FILE, " error: no keep-alive was received"));
624 ret = -420;
625 goto on_return;
626 }
627 /* Check that client status is still okay and on_status() callback is NOT
628 * called
629 */
Benny Prijonof6945dd2009-03-18 18:56:25 +0000630 /* No longer valid due to this ticket:
631 * http://trac.pjsip.org/repos/ticket/742
632
Benny Prijonoff1df042008-06-06 14:47:10 +0000633 if (client->on_status_cnt != 0) {
634 PJ_LOG(3, (THIS_FILE, " error: on_status() must not be called on successful"
635 "keep-alive when mapped-address does not change"));
636 ret = -430;
637 goto on_return;
638 }
Benny Prijonof6945dd2009-03-18 18:56:25 +0000639 */
Benny Prijonoff1df042008-06-06 14:47:10 +0000640 /* Check that client doesn't receive anything */
641 if (client->on_rx_data_cnt != 0) {
642 PJ_LOG(3,(THIS_FILE, " error: client shouldn't have received anything"));
643 ret = -440;
644 goto on_return;
645 }
646
647
648 /*
649 * Part 4: Successful keep-alive with IP address change
650 */
651 PJ_LOG(3,(THIS_FILE, " mapped IP address change"));
652
653 /* Change server operation mode to normal mode */
654 srv->flag = RESPOND_STUN | WITH_XOR_MAPPED;
655
656 /* Change mapped address in the response */
657 srv->ip_to_send = pj_str("2.2.2.2");
658 srv->port_to_send++;
659
660 /* Reset server */
661 srv->rx_cnt = 0;
662
663 /* Reset client */
664 client->on_status_cnt = 0;
665 client->last_status = PJ_SUCCESS;
666 client->on_rx_data_cnt = 0;
667
668 /* Wait for keep-alive duration to see if client actually sends the
669 * keep-alive.
670 */
671 pj_gettimeofday(&timeout);
672 timeout.sec += (PJ_STUN_KEEP_ALIVE_SEC + 1);
673 do {
674 handle_events(cfg, 100);
675 pj_gettimeofday(&t);
676 } while (PJ_TIME_VAL_LT(t, timeout));
677
678 /* Check that server receives some packets */
679 if (srv->rx_cnt == 0) {
680 PJ_LOG(3, (THIS_FILE, " error: no keep-alive was received"));
681 ret = -450;
682 goto on_return;
683 }
684 /* Check that on_status() callback is called (because mapped address
685 * has changed)
686 */
687 if (client->on_status_cnt != 1) {
688 PJ_LOG(3, (THIS_FILE, " error: on_status() was not called"));
689 ret = -460;
690 goto on_return;
691 }
692 /* Check that callback was called with correct operation */
Benny Prijonof6945dd2009-03-18 18:56:25 +0000693 if (client->last_op != PJ_STUN_SOCK_MAPPED_ADDR_CHANGE) {
Benny Prijonoff1df042008-06-06 14:47:10 +0000694 PJ_LOG(3,(THIS_FILE, " error: expecting keep-alive operation status"));
695 ret = -470;
696 goto on_return;
697 }
698 /* Check that last status is still success */
699 if (client->last_status != PJ_SUCCESS) {
700 PJ_LOG(3, (THIS_FILE, " error: expecting successful status"));
701 ret = -480;
702 goto on_return;
703 }
704 /* Check that client doesn't receive anything */
705 if (client->on_rx_data_cnt != 0) {
706 PJ_LOG(3,(THIS_FILE, " error: client shouldn't have received anything"));
707 ret = -490;
708 goto on_return;
709 }
710
711 /* Get info */
712 pj_bzero(&info, sizeof(info));
713 pj_stun_sock_get_info(client->sock, &info);
714
715 /* Check that we have server address */
716 if (!pj_sockaddr_has_addr(&info.srv_addr)) {
717 PJ_LOG(3,(THIS_FILE, " error: missing server address"));
718 ret = -500;
719 goto on_return;
720 }
721 /* .. and mapped address */
722 if (!pj_sockaddr_has_addr(&info.mapped_addr)) {
723 PJ_LOG(3,(THIS_FILE, " error: missing mapped address"));
724 ret = -510;
725 goto on_return;
726 }
727 /* verify the mapped address */
728 pj_sockaddr_in_init(&mapped_addr, &srv->ip_to_send, srv->port_to_send);
729 if (pj_sockaddr_cmp(&info.mapped_addr, &mapped_addr) != 0) {
730 PJ_LOG(3,(THIS_FILE, " error: mapped address mismatched"));
731 ret = -520;
732 goto on_return;
733 }
734
735 /* .. and at least one alias */
736 if (info.alias_cnt == 0) {
737 PJ_LOG(3,(THIS_FILE, " error: must have at least one alias"));
738 ret = -530;
739 goto on_return;
740 }
741 if (!pj_sockaddr_has_addr(&info.aliases[0])) {
742 PJ_LOG(3,(THIS_FILE, " error: missing alias"));
743 ret = -540;
744 goto on_return;
745 }
746
747
748 /*
749 * Part 5: Failed keep-alive
750 */
751 PJ_LOG(3,(THIS_FILE, " failed keep-alive scenario"));
752
753 /* Change server operation mode to respond without attribute */
754 srv->flag = RESPOND_STUN;
755
756 /* Reset server */
757 srv->rx_cnt = 0;
758
759 /* Reset client */
760 client->on_status_cnt = 0;
761 client->last_status = PJ_SUCCESS;
762 client->on_rx_data_cnt = 0;
763
764 /* Wait until on_status() is called with failure. */
765 pj_gettimeofday(&timeout);
766 timeout.sec += (PJ_STUN_KEEP_ALIVE_SEC + PJ_STUN_TIMEOUT_VALUE + 5);
767 do {
768 handle_events(cfg, 100);
769 pj_gettimeofday(&t);
770 } while (client->on_status_cnt==0 && PJ_TIME_VAL_LT(t, timeout));
771
772 /* Check that callback with correct operation is called */
773 if (client->last_op != PJ_STUN_SOCK_KEEP_ALIVE_OP) {
774 PJ_LOG(3,(THIS_FILE, " error: expecting keep-alive operation status"));
775 ret = -600;
776 goto on_return;
777 }
778 if (client->last_status == PJ_SUCCESS) {
779 PJ_LOG(3,(THIS_FILE, " error: expecting failed keep-alive"));
780 ret = -610;
781 goto on_return;
782 }
783 /* Check that client doesn't receive anything */
784 if (client->on_rx_data_cnt != 0) {
785 PJ_LOG(3,(THIS_FILE, " error: client shouldn't have received anything"));
786 ret = -620;
787 goto on_return;
788 }
789
790
791on_return:
792 destroy_server(srv);
793 destroy_client(client);
794 return ret;
795}
796
797
798#define DO_TEST(expr) \
799 capture_pjlib_state(&stun_cfg, &pjlib_state); \
800 ret = expr; \
801 if (ret != 0) goto on_return; \
802 ret = check_pjlib_state(&stun_cfg, &pjlib_state); \
803 if (ret != 0) goto on_return;
804
805
806int stun_sock_test(void)
807{
808 struct pjlib_state pjlib_state;
809 pj_stun_config stun_cfg;
810 pj_ioqueue_t *ioqueue = NULL;
811 pj_timer_heap_t *timer_heap = NULL;
812 pj_pool_t *pool = NULL;
813 pj_status_t status;
814 int ret = 0;
815
816 pool = pj_pool_create(mem, NULL, 512, 512, NULL);
817
818 status = pj_ioqueue_create(pool, 12, &ioqueue);
819 if (status != PJ_SUCCESS) {
820 app_perror(" pj_ioqueue_create()", status);
821 ret = -4;
822 goto on_return;
823 }
824
825 status = pj_timer_heap_create(pool, 100, &timer_heap);
826 if (status != PJ_SUCCESS) {
827 app_perror(" pj_timer_heap_create()", status);
828 ret = -8;
829 goto on_return;
830 }
831
832 pj_stun_config_init(&stun_cfg, mem, 0, ioqueue, timer_heap);
833
834 DO_TEST(timeout_test(&stun_cfg, PJ_FALSE));
835 DO_TEST(timeout_test(&stun_cfg, PJ_TRUE));
836
837 DO_TEST(missing_attr_test(&stun_cfg, PJ_FALSE));
838 DO_TEST(missing_attr_test(&stun_cfg, PJ_TRUE));
839
840 DO_TEST(keep_alive_test(&stun_cfg));
841
842on_return:
843 if (timer_heap) pj_timer_heap_destroy(timer_heap);
844 if (ioqueue) pj_ioqueue_destroy(ioqueue);
845 if (pool) pj_pool_release(pool);
846 return ret;
847}
848
849