blob: f9bd9f79fcde1e7910f926cb7bbb8aaa433a338b [file] [log] [blame]
Benny Prijono5dcb38d2005-11-21 01:55:47 +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 Prijono5dcb38d2005-11-21 01:55:47 +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/**
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
45enum
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 */
61static 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
Benny Prijonob1cf8902008-02-08 09:43:30 +000078 n = pj_sock_select(PJ_IOQUEUE_MAX_HANDLES, &fds[0], &fds[1], &fds[2],
Benny Prijono5dcb38d2005-11-21 01:55:47 +000079 &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 */
100int 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.
Benny Prijono8ab968f2007-07-20 08:08:30 +0000116 rc = pj_sock_socket( pj_AF_INET(), pj_SOCK_DGRAM(), 0, &udp1);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000117 if (rc != PJ_SUCCESS) {
118 app_perror("...error: unable to create socket", rc);
119 status=-10; goto on_return;
120 }
Benny Prijono8ab968f2007-07-20 08:08:30 +0000121 rc = pj_sock_socket( pj_AF_INET(), pj_SOCK_DGRAM(), 0, &udp2);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000122 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.
Benny Prijonoac623b32006-07-03 15:19:31 +0000128 pj_bzero(&udp_addr, sizeof(udp_addr));
Benny Prijono8ab968f2007-07-20 08:08:30 +0000129 udp_addr.sin_family = pj_AF_INET();
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000130 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
Benny Prijono6a65a7d2009-06-19 09:38:40 +0000145 // Sleep a bit. See http://trac.pjsip.org/repos/ticket/890
146 pj_thread_sleep(10);
147
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000148 // 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
206on_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 */
218int dummy_select_test;
219#endif /* INCLUDE_SELECT_TEST */
220
221