Add support for ICE/STUN/TURN in res_rtp_asterisk and chan_sip.
[asterisk/asterisk.git] / res / pjproject / pjlib / src / pjlib-test / select.c
1 /* $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 /**
23  * \page page_pjlib_select_test Test: Socket Select()
24  *
25  * This file provides implementation of \b select_test(). It tests the
26  * functionality of the pj_sock_select() API.
27  *
28  *
29  * This file is <b>pjlib-test/select.c</b>
30  *
31  * \include pjlib-test/select.c
32  */
33
34
35 #if INCLUDE_SELECT_TEST
36
37 #include <pj/sock.h>
38 #include <pj/sock_select.h>
39 #include <pj/log.h>
40 #include <pj/string.h>
41 #include <pj/assert.h>
42 #include <pj/os.h>
43 #include <pj/errno.h>
44
45 enum
46 {
47     READ_FDS,
48     WRITE_FDS,
49     EXCEPT_FDS
50 };
51
52 #define UDP_PORT    51232
53 #define THIS_FILE   "select_test"
54
55 /*
56  * do_select()
57  *
58  * Perform pj_sock_select() and find out which sockets
59  * are signalled.
60  */    
61 static int do_select( pj_sock_t sock1, pj_sock_t sock2,
62                       int setcount[])
63 {
64     pj_fd_set_t fds[3];
65     pj_time_val timeout;
66     int i, n;
67     
68     for (i=0; i<3; ++i) {
69         PJ_FD_ZERO(&fds[i]);
70         PJ_FD_SET(sock1, &fds[i]);
71         PJ_FD_SET(sock2, &fds[i]);
72         setcount[i] = 0;
73     }
74
75     timeout.sec = 1;
76     timeout.msec = 0;
77
78     n = pj_sock_select(PJ_IOQUEUE_MAX_HANDLES, &fds[0], &fds[1], &fds[2],
79                        &timeout);
80     if (n < 0)
81         return n;
82     if (n == 0)
83         return 0;
84
85     for (i=0; i<3; ++i) {
86         if (PJ_FD_ISSET(sock1, &fds[i]))
87             setcount[i]++;
88         if (PJ_FD_ISSET(sock2, &fds[i]))
89             setcount[i]++;
90     }
91
92     return n;
93 }
94
95 /*
96  * select_test()
97  *
98  * Test main entry.
99  */
100 int select_test()
101 {
102     pj_sock_t udp1=PJ_INVALID_SOCKET, udp2=PJ_INVALID_SOCKET;
103     pj_sockaddr_in udp_addr;
104     int status;
105     int setcount[3];
106     pj_str_t s;
107     const char data[] = "hello";
108     const int datalen = 5;
109     pj_ssize_t sent, received;
110     char buf[10];
111     pj_status_t rc;
112
113     PJ_LOG(3, (THIS_FILE, "...Testing simple UDP select()"));
114     
115     // Create two UDP sockets.
116     rc = pj_sock_socket( pj_AF_INET(), pj_SOCK_DGRAM(), 0, &udp1);
117     if (rc != PJ_SUCCESS) {
118         app_perror("...error: unable to create socket", rc);
119         status=-10; goto on_return;
120     }
121     rc = pj_sock_socket( pj_AF_INET(), pj_SOCK_DGRAM(), 0, &udp2);
122     if (udp2 == PJ_INVALID_SOCKET) {
123         app_perror("...error: unable to create socket", rc);
124         status=-20; goto on_return;
125     }
126
127     // Bind one of the UDP socket.
128     pj_bzero(&udp_addr, sizeof(udp_addr));
129     udp_addr.sin_family = pj_AF_INET();
130     udp_addr.sin_port = UDP_PORT;
131     udp_addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
132
133     if (pj_sock_bind(udp2, &udp_addr, sizeof(udp_addr))) {
134         status=-30; goto on_return;
135     }
136
137     // Send data.
138     sent = datalen;
139     rc = pj_sock_sendto(udp1, data, &sent, 0, &udp_addr, sizeof(udp_addr));
140     if (rc != PJ_SUCCESS || sent != datalen) {
141         app_perror("...error: sendto() error", rc);
142         status=-40; goto on_return;
143     }
144
145     // Sleep a bit. See http://trac.pjsip.org/repos/ticket/890
146     pj_thread_sleep(10);
147
148     // Check that socket is marked as reable.
149     // Note that select() may also report that sockets are writable.
150     status = do_select(udp1, udp2, setcount);
151     if (status < 0) {
152         char errbuf[128];
153         pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf));
154         PJ_LOG(1,(THIS_FILE, "...error: %s", errbuf));
155         status=-50; goto on_return;
156     }
157     if (status == 0) {
158         status=-60; goto on_return;
159     }
160
161     if (setcount[READ_FDS] != 1) {
162         status=-70; goto on_return;
163     }
164     if (setcount[WRITE_FDS] != 0) {
165         if (setcount[WRITE_FDS] == 2) {
166             PJ_LOG(3,(THIS_FILE, "...info: system reports writable sockets"));
167         } else {
168             status=-80; goto on_return;
169         }
170     } else {
171         PJ_LOG(3,(THIS_FILE, 
172                   "...info: system doesn't report writable sockets"));
173     }
174     if (setcount[EXCEPT_FDS] != 0) {
175         status=-90; goto on_return;
176     }
177
178     // Read the socket to clear readable sockets.
179     received = sizeof(buf);
180     rc = pj_sock_recv(udp2, buf, &received, 0);
181     if (rc != PJ_SUCCESS || received != 5) {
182         status=-100; goto on_return;
183     }
184     
185     status = 0;
186
187     // Test timeout on the read part.
188     // This won't necessarily return zero, as select() may report that
189     // sockets are writable.
190     setcount[0] = setcount[1] = setcount[2] = 0;
191     status = do_select(udp1, udp2, setcount);
192     if (status != 0 && status != setcount[WRITE_FDS]) {
193         PJ_LOG(3,(THIS_FILE, "...error: expecting timeout but got %d sks set",
194                              status));
195         PJ_LOG(3,(THIS_FILE, "          rdset: %d, wrset: %d, exset: %d",
196                              setcount[0], setcount[1], setcount[2]));
197         status = -110; goto on_return;
198     }
199     if (setcount[READ_FDS] != 0) {
200         PJ_LOG(3,(THIS_FILE, "...error: readable socket not expected"));
201         status = -120; goto on_return;
202     }
203
204     status = 0;
205
206 on_return:
207     if (udp1 != PJ_INVALID_SOCKET)
208         pj_sock_close(udp1);
209     if (udp2 != PJ_INVALID_SOCKET)
210         pj_sock_close(udp2);
211     return status;
212 }
213
214 #else
215 /* To prevent warning about "translation unit is empty"
216  * when this test is disabled. 
217  */
218 int dummy_select_test;
219 #endif  /* INCLUDE_SELECT_TEST */
220
221