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