nsprpub/pr/tests/prpoll.c

branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
equal deleted inserted replaced
-1:000000000000 0:8344250de1ab
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #ifdef WIN32
7 #include <windows.h>
8 #endif
9
10 #ifdef XP_UNIX
11 #include <unistd.h> /* for close() */
12 #endif
13
14 #include "prinit.h"
15 #include "prio.h"
16 #include "prlog.h"
17 #include "prprf.h"
18 #include "prnetdb.h"
19
20 #include "private/pprio.h"
21
22 #define CLIENT_LOOPS 5
23 #define BUF_SIZE 128
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28
29 #ifdef WINCE
30
31 int main(int argc, char **argv)
32 {
33 fprintf(stderr, "Invalid/Broken Test for WinCE/WinMobile\n");
34 exit(1);
35 }
36
37 #else
38
39 static void
40 clientThreadFunc(void *arg)
41 {
42 PRUint16 port = (PRUint16) arg;
43 PRFileDesc *sock;
44 PRNetAddr addr;
45 char buf[BUF_SIZE];
46 int i;
47
48 addr.inet.family = PR_AF_INET;
49 addr.inet.port = PR_htons(port);
50 addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
51 PR_snprintf(buf, sizeof(buf), "%hu", port);
52
53 for (i = 0; i < 5; i++) {
54 sock = PR_NewTCPSocket();
55 PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT);
56
57 PR_Write(sock, buf, sizeof(buf));
58 PR_Close(sock);
59 }
60 }
61
62 int main(int argc, char **argv)
63 {
64 PRFileDesc *listenSock1, *listenSock2;
65 PRFileDesc *badFD;
66 PRUint16 listenPort1, listenPort2;
67 PRNetAddr addr;
68 char buf[BUF_SIZE];
69 PRThread *clientThread;
70 PRPollDesc pds0[10], pds1[10], *pds, *other_pds;
71 PRIntn npds;
72 PRInt32 retVal;
73 PRInt32 rv;
74 PROsfd sd;
75 struct sockaddr_in saddr;
76 PRIntn saddr_len;
77 PRUint16 listenPort3;
78 PRFileDesc *socket_poll_fd;
79 PRIntn i, j;
80
81 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
82 PR_STDIO_INIT();
83
84 printf("This program tests PR_Poll with sockets.\n");
85 printf("Timeout, error reporting, and normal operation are tested.\n\n");
86
87 /* Create two listening sockets */
88 if ((listenSock1 = PR_NewTCPSocket()) == NULL) {
89 fprintf(stderr, "Can't create a new TCP socket\n");
90 exit(1);
91 }
92 addr.inet.family = PR_AF_INET;
93 addr.inet.ip = PR_htonl(PR_INADDR_ANY);
94 addr.inet.port = PR_htons(0);
95 if (PR_Bind(listenSock1, &addr) == PR_FAILURE) {
96 fprintf(stderr, "Can't bind socket\n");
97 exit(1);
98 }
99 if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) {
100 fprintf(stderr, "PR_GetSockName failed\n");
101 exit(1);
102 }
103 listenPort1 = PR_ntohs(addr.inet.port);
104 if (PR_Listen(listenSock1, 5) == PR_FAILURE) {
105 fprintf(stderr, "Can't listen on a socket\n");
106 exit(1);
107 }
108
109 if ((listenSock2 = PR_NewTCPSocket()) == NULL) {
110 fprintf(stderr, "Can't create a new TCP socket\n");
111 exit(1);
112 }
113 addr.inet.family = PR_AF_INET;
114 addr.inet.ip = PR_htonl(PR_INADDR_ANY);
115 addr.inet.port = PR_htons(0);
116 if (PR_Bind(listenSock2, &addr) == PR_FAILURE) {
117 fprintf(stderr, "Can't bind socket\n");
118 exit(1);
119 }
120 if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) {
121 fprintf(stderr, "PR_GetSockName failed\n");
122 exit(1);
123 }
124 listenPort2 = PR_ntohs(addr.inet.port);
125 if (PR_Listen(listenSock2, 5) == PR_FAILURE) {
126 fprintf(stderr, "Can't listen on a socket\n");
127 exit(1);
128 }
129 /* Set up the poll descriptor array */
130 pds = pds0;
131 other_pds = pds1;
132 memset(pds, 0, sizeof(pds));
133 npds = 0;
134 pds[npds].fd = listenSock1;
135 pds[npds].in_flags = PR_POLL_READ;
136 npds++;
137 pds[npds].fd = listenSock2;
138 pds[npds].in_flags = PR_POLL_READ;
139 npds++;
140
141 sd = socket(AF_INET, SOCK_STREAM, 0);
142 PR_ASSERT(sd >= 0);
143 memset((char *) &saddr, 0, sizeof(saddr));
144 saddr.sin_family = AF_INET;
145 saddr.sin_addr.s_addr = htonl(INADDR_ANY);
146 saddr.sin_port = htons(0);
147
148 rv = bind(sd, (struct sockaddr *)&saddr, sizeof(saddr));
149 PR_ASSERT(rv == 0);
150 saddr_len = sizeof(saddr);
151 rv = getsockname(sd, (struct sockaddr *) &saddr, &saddr_len);
152 PR_ASSERT(rv == 0);
153 listenPort3 = ntohs(saddr.sin_port);
154
155 rv = listen(sd, 5);
156 PR_ASSERT(rv == 0);
157 pds[npds].fd = socket_poll_fd = PR_CreateSocketPollFd(sd);
158 PR_ASSERT(pds[npds].fd);
159 pds[npds].in_flags = PR_POLL_READ;
160 npds++;
161 PR_snprintf(buf, sizeof(buf),
162 "The server thread is listening on ports %hu, %hu and %hu\n\n",
163 listenPort1, listenPort2, listenPort3);
164 printf("%s", buf);
165
166 /* Testing timeout */
167 printf("PR_Poll should time out in 5 seconds\n");
168 retVal = PR_Poll(pds, npds, PR_SecondsToInterval(5));
169 if (retVal != 0) {
170 PR_snprintf(buf, sizeof(buf),
171 "PR_Poll should time out and return 0, but it returns %ld\n",
172 retVal);
173 fprintf(stderr, "%s", buf);
174 exit(1);
175 }
176 printf("PR_Poll timed out. Test passed.\n\n");
177
178 /* Testing bad fd */
179 printf("PR_Poll should detect a bad file descriptor\n");
180 if ((badFD = PR_NewTCPSocket()) == NULL) {
181 fprintf(stderr, "Can't create a TCP socket\n");
182 exit(1);
183 }
184
185 pds[npds].fd = badFD;
186 pds[npds].in_flags = PR_POLL_READ;
187 npds++;
188 PR_Close(badFD); /* make the fd bad */
189 #if 0
190 retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT);
191 if (retVal != 1 || (unsigned short) pds[2].out_flags != PR_POLL_NVAL) {
192 fprintf(stderr, "Failed to detect the bad fd: "
193 "PR_Poll returns %d, out_flags is 0x%hx\n",
194 retVal, pds[npds - 1].out_flags);
195 exit(1);
196 }
197 printf("PR_Poll detected the bad fd. Test passed.\n\n");
198 #endif
199 npds--;
200
201 clientThread = PR_CreateThread(PR_USER_THREAD,
202 clientThreadFunc, (void *) listenPort1,
203 PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
204 PR_UNJOINABLE_THREAD, 0);
205 if (clientThread == NULL) {
206 fprintf(stderr, "can't create thread\n");
207 exit(1);
208 }
209
210 clientThread = PR_CreateThread(PR_USER_THREAD,
211 clientThreadFunc, (void *) listenPort2,
212 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
213 PR_UNJOINABLE_THREAD, 0);
214 if (clientThread == NULL) {
215 fprintf(stderr, "can't create thread\n");
216 exit(1);
217 }
218
219 clientThread = PR_CreateThread(PR_USER_THREAD,
220 clientThreadFunc, (void *) listenPort3,
221 PR_PRIORITY_NORMAL, PR_GLOBAL_BOUND_THREAD,
222 PR_UNJOINABLE_THREAD, 0);
223 if (clientThread == NULL) {
224 fprintf(stderr, "can't create thread\n");
225 exit(1);
226 }
227
228
229 printf("Three client threads are created. Each of them will\n");
230 printf("send data to one of the three ports the server is listening on.\n");
231 printf("The data they send is the port number. Each of them send\n");
232 printf("the data five times, so you should see ten lines below,\n");
233 printf("interleaved in an arbitrary order.\n");
234
235 /* 30 events total */
236 i = 0;
237 while (i < 30) {
238 PRPollDesc *tmp;
239 int nextIndex;
240 int nEvents = 0;
241
242 retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT);
243 PR_ASSERT(retVal != 0); /* no timeout */
244 if (retVal == -1) {
245 fprintf(stderr, "PR_Poll failed\n");
246 exit(1);
247 }
248
249 nextIndex = 3;
250 /* the three listening sockets */
251 for (j = 0; j < 3; j++) {
252 other_pds[j] = pds[j];
253 PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0
254 && (pds[j].out_flags & PR_POLL_EXCEPT) == 0);
255 if (pds[j].out_flags & PR_POLL_READ) {
256 PRFileDesc *sock;
257
258 nEvents++;
259 if (j == 2) {
260 PROsfd newsd;
261 newsd = accept(PR_FileDesc2NativeHandle(pds[j].fd), NULL, 0);
262 if (newsd == -1) {
263 fprintf(stderr, "accept() failed\n");
264 exit(1);
265 }
266 other_pds[nextIndex].fd = PR_CreateSocketPollFd(newsd);
267 PR_ASSERT(other_pds[nextIndex].fd);
268 other_pds[nextIndex].in_flags = PR_POLL_READ;
269 } else {
270 sock = PR_Accept(pds[j].fd, NULL, PR_INTERVAL_NO_TIMEOUT);
271 if (sock == NULL) {
272 fprintf(stderr, "PR_Accept() failed\n");
273 exit(1);
274 }
275 other_pds[nextIndex].fd = sock;
276 other_pds[nextIndex].in_flags = PR_POLL_READ;
277 }
278 nextIndex++;
279 } else if (pds[j].out_flags & PR_POLL_ERR) {
280 fprintf(stderr, "PR_Poll() indicates that an fd has error\n");
281 exit(1);
282 } else if (pds[j].out_flags & PR_POLL_NVAL) {
283 fprintf(stderr, "PR_Poll() indicates that fd %d is invalid\n",
284 PR_FileDesc2NativeHandle(pds[j].fd));
285 exit(1);
286 }
287 }
288
289 for (j = 3; j < npds; j++) {
290 PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0
291 && (pds[j].out_flags & PR_POLL_EXCEPT) == 0);
292 if (pds[j].out_flags & PR_POLL_READ) {
293 PRInt32 nBytes;
294
295 nEvents++;
296 /* XXX: This call is a hack and should be fixed */
297 if (PR_GetDescType(pds[j].fd) == (PRDescType) 0) {
298 nBytes = recv(PR_FileDesc2NativeHandle(pds[j].fd), buf,
299 sizeof(buf), 0);
300 if (nBytes == -1) {
301 fprintf(stderr, "recv() failed\n");
302 exit(1);
303 }
304 printf("Server read %d bytes from native fd %d\n",nBytes,
305 PR_FileDesc2NativeHandle(pds[j].fd));
306 #ifdef WIN32
307 closesocket((SOCKET)PR_FileDesc2NativeHandle(pds[j].fd));
308 #else
309 close(PR_FileDesc2NativeHandle(pds[j].fd));
310 #endif
311 PR_DestroySocketPollFd(pds[j].fd);
312 } else {
313 nBytes = PR_Read(pds[j].fd, buf, sizeof(buf));
314 if (nBytes == -1) {
315 fprintf(stderr, "PR_Read() failed\n");
316 exit(1);
317 }
318 PR_Close(pds[j].fd);
319 }
320 /* Just to be safe */
321 buf[BUF_SIZE - 1] = '\0';
322 printf("The server received \"%s\" from a client\n", buf);
323 } else if (pds[j].out_flags & PR_POLL_ERR) {
324 fprintf(stderr, "PR_Poll() indicates that an fd has error\n");
325 exit(1);
326 } else if (pds[j].out_flags & PR_POLL_NVAL) {
327 fprintf(stderr, "PR_Poll() indicates that an fd is invalid\n");
328 exit(1);
329 } else {
330 other_pds[nextIndex] = pds[j];
331 nextIndex++;
332 }
333 }
334
335 PR_ASSERT(retVal == nEvents);
336 /* swap */
337 tmp = pds;
338 pds = other_pds;
339 other_pds = tmp;
340 npds = nextIndex;
341 i += nEvents;
342 }
343 PR_DestroySocketPollFd(socket_poll_fd);
344
345 printf("All tests finished\n");
346 PR_Cleanup();
347 return 0;
348 }
349
350
351 #endif /* ifdef WINCE */

mercurial