nsprpub/pr/tests/poll_nm.c

branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
equal deleted inserted replaced
-1:000000000000 0:4b044a5cde85
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 /***********************************************************************
7 **
8 ** Name: prpoll_norm.c
9 **
10 ** Description: This program tests PR_Poll with sockets.
11 ** Normal operation are tested
12 **
13 ** Modification History:
14 ** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
15 ** The debug mode will print all of the printfs associated with this test.
16 ** The regress mode will be the default mode. Since the regress tool limits
17 ** the output to a one line status:PASS or FAIL,all of the printf statements
18 ** have been handled with an if (debug_mode) statement.
19 ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
20 ** recognize the return code from tha main program.
21 ***********************************************************************/
22
23 /***********************************************************************
24 ** Includes
25 ***********************************************************************/
26 /* Used to get the command line option */
27 #include "plgetopt.h"
28
29 #include "prinit.h"
30 #include "prio.h"
31 #include "prlog.h"
32 #include "prprf.h"
33 #include "prnetdb.h"
34 #include "obsolete/probslet.h"
35
36 #include "private/pprio.h"
37
38 #include <stdio.h>
39 #include <string.h>
40 #include <stdlib.h>
41
42 PRIntn failed_already=0;
43 PRIntn debug_mode;
44
45 #define NUM_ITERATIONS 5
46
47 static void PR_CALLBACK
48 clientThreadFunc(void *arg)
49 {
50 PRUintn port = (PRUintn) arg;
51 PRFileDesc *sock;
52 PRNetAddr addr;
53 char buf[128];
54 int i;
55 PRStatus sts;
56 PRInt32 n;
57
58 addr.inet.family = PR_AF_INET;
59 addr.inet.port = PR_htons((PRUint16)port);
60 addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
61 memset(buf, 0, sizeof(buf));
62 PR_snprintf(buf, sizeof(buf), "%hu", port);
63
64 for (i = 0; i < NUM_ITERATIONS; i++) {
65 sock = PR_NewTCPSocket();
66 PR_ASSERT(sock != NULL);
67
68 sts = PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT);
69 PR_ASSERT(sts == PR_SUCCESS);
70
71 n = PR_Write(sock, buf, sizeof(buf));
72 PR_ASSERT(n >= 0);
73
74 sts = PR_Close(sock);
75 PR_ASSERT(sts == PR_SUCCESS);
76 }
77 }
78
79 int main(int argc, char **argv)
80 {
81 PRFileDesc *listenSock1 = NULL, *listenSock2 = NULL;
82 PRUint16 listenPort1, listenPort2;
83 PRNetAddr addr;
84 char buf[128];
85 PRThread *clientThread;
86 PRPollDesc pds0[20], pds1[20], *pds, *other_pds;
87 PRIntn npds;
88 PRInt32 retVal;
89 PRIntn i, j;
90 PRSocketOptionData optval;
91
92 /* The command line argument: -d is used to determine if the test is being run
93 in debug mode. The regress tool requires only one line output:PASS or FAIL.
94 All of the printfs associated with this test has been handled with a if (debug_mode)
95 test.
96 Usage: test_name -d
97 */
98 PLOptStatus os;
99 PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
100 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
101 {
102 if (PL_OPT_BAD == os) continue;
103 switch (opt->option)
104 {
105 case 'd': /* debug mode */
106 debug_mode = 1;
107 break;
108 default:
109 break;
110 }
111 }
112 PL_DestroyOptState(opt);
113
114 /* main test */
115
116 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
117 PR_STDIO_INIT();
118
119 if (debug_mode) {
120 printf("This program tests PR_Poll with sockets.\n");
121 printf("Normal operation are tested.\n\n");
122 }
123
124 /* Create two listening sockets */
125 if ((listenSock1 = PR_NewTCPSocket()) == NULL) {
126 fprintf(stderr, "Can't create a new TCP socket\n");
127 failed_already=1;
128 goto exit_now;
129 }
130 memset(&addr, 0, sizeof(addr));
131 addr.inet.family = PR_AF_INET;
132 addr.inet.ip = PR_htonl(PR_INADDR_ANY);
133 addr.inet.port = PR_htons(0);
134 if (PR_Bind(listenSock1, &addr) == PR_FAILURE) {
135 fprintf(stderr, "Can't bind socket\n");
136 failed_already=1;
137 goto exit_now;
138 }
139 if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) {
140 fprintf(stderr, "PR_GetSockName failed\n");
141 failed_already=1;
142 goto exit_now;
143 }
144 listenPort1 = PR_ntohs(addr.inet.port);
145 optval.option = PR_SockOpt_Nonblocking;
146 optval.value.non_blocking = PR_TRUE;
147 PR_SetSocketOption(listenSock1, &optval);
148 if (PR_Listen(listenSock1, 5) == PR_FAILURE) {
149 fprintf(stderr, "Can't listen on a socket\n");
150 failed_already=1;
151 goto exit_now;
152 }
153
154 if ((listenSock2 = PR_NewTCPSocket()) == NULL) {
155 fprintf(stderr, "Can't create a new TCP socket\n");
156 failed_already=1;
157 goto exit_now;
158 }
159 addr.inet.family = PR_AF_INET;
160 addr.inet.ip = PR_htonl(PR_INADDR_ANY);
161 addr.inet.port = PR_htons(0);
162 if (PR_Bind(listenSock2, &addr) == PR_FAILURE) {
163 fprintf(stderr, "Can't bind socket\n");
164 failed_already=1;
165 goto exit_now;
166 }
167 if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) {
168 fprintf(stderr, "PR_GetSockName failed\n");
169 failed_already=1;
170 goto exit_now;
171 }
172 listenPort2 = PR_ntohs(addr.inet.port);
173 PR_SetSocketOption(listenSock2, &optval);
174 if (PR_Listen(listenSock2, 5) == PR_FAILURE) {
175 fprintf(stderr, "Can't listen on a socket\n");
176 failed_already=1;
177 goto exit_now;
178 }
179 PR_snprintf(buf, sizeof(buf),
180 "The server thread is listening on ports %hu and %hu\n\n",
181 listenPort1, listenPort2);
182 if (debug_mode) printf("%s", buf);
183
184 /* Set up the poll descriptor array */
185 pds = pds0;
186 other_pds = pds1;
187 memset(pds, 0, sizeof(pds));
188 pds[0].fd = listenSock1;
189 pds[0].in_flags = PR_POLL_READ;
190 pds[1].fd = listenSock2;
191 pds[1].in_flags = PR_POLL_READ;
192 /* Add some unused entries to test if they are ignored by PR_Poll() */
193 memset(&pds[2], 0, sizeof(pds[2]));
194 memset(&pds[3], 0, sizeof(pds[3]));
195 memset(&pds[4], 0, sizeof(pds[4]));
196 npds = 5;
197
198 clientThread = PR_CreateThread(PR_USER_THREAD,
199 clientThreadFunc, (void *) listenPort1,
200 PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
201 PR_UNJOINABLE_THREAD, 0);
202 if (clientThread == NULL) {
203 fprintf(stderr, "can't create thread\n");
204 failed_already=1;
205 goto exit_now;
206 }
207
208 clientThread = PR_CreateThread(PR_USER_THREAD,
209 clientThreadFunc, (void *) listenPort2,
210 PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
211 PR_UNJOINABLE_THREAD, 0);
212 if (clientThread == NULL) {
213 fprintf(stderr, "can't create thread\n");
214 failed_already=1;
215 goto exit_now;
216 }
217
218 if (debug_mode) {
219 printf("Two client threads are created. Each of them will\n");
220 printf("send data to one of the two ports the server is listening on.\n");
221 printf("The data they send is the port number. Each of them send\n");
222 printf("the data five times, so you should see ten lines below,\n");
223 printf("interleaved in an arbitrary order.\n");
224 }
225
226 /* two clients, three events per iteration: accept, read, close */
227 i = 0;
228 while (i < 2 * 3 * NUM_ITERATIONS) {
229 PRPollDesc *tmp;
230 int nextIndex;
231 int nEvents = 0;
232
233 retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT);
234 PR_ASSERT(retVal != 0); /* no timeout */
235 if (retVal == -1) {
236 fprintf(stderr, "PR_Poll failed\n");
237 failed_already=1;
238 goto exit_now;
239 }
240
241 nextIndex = 2;
242 /* the two listening sockets */
243 for (j = 0; j < 2; j++) {
244 other_pds[j] = pds[j];
245 PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0
246 && (pds[j].out_flags & PR_POLL_EXCEPT) == 0);
247 if (pds[j].out_flags & PR_POLL_READ) {
248 PRFileDesc *sock;
249
250 nEvents++;
251 sock = PR_Accept(pds[j].fd, NULL, PR_INTERVAL_NO_TIMEOUT);
252 if (sock == NULL) {
253 fprintf(stderr, "PR_Accept() failed\n");
254 failed_already=1;
255 goto exit_now;
256 }
257 other_pds[nextIndex].fd = sock;
258 other_pds[nextIndex].in_flags = PR_POLL_READ;
259 nextIndex++;
260 } else if (pds[j].out_flags & PR_POLL_ERR) {
261 fprintf(stderr, "PR_Poll() indicates that an fd has error\n");
262 failed_already=1;
263 goto exit_now;
264 } else if (pds[j].out_flags & PR_POLL_NVAL) {
265 fprintf(stderr, "PR_Poll() indicates that fd %d is invalid\n",
266 PR_FileDesc2NativeHandle(pds[j].fd));
267 failed_already=1;
268 goto exit_now;
269 }
270 }
271
272 for (j = 2; j < npds; j++) {
273 if (NULL == pds[j].fd) {
274 /*
275 * Keep the unused entries in the poll descriptor array
276 * for testing purposes.
277 */
278 other_pds[nextIndex] = pds[j];
279 nextIndex++;
280 continue;
281 }
282
283 PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0
284 && (pds[j].out_flags & PR_POLL_EXCEPT) == 0);
285 if (pds[j].out_flags & PR_POLL_READ) {
286 PRInt32 nAvail;
287 PRInt32 nRead;
288
289 nEvents++;
290 nAvail = PR_Available(pds[j].fd);
291 nRead = PR_Read(pds[j].fd, buf, sizeof(buf));
292 PR_ASSERT(nAvail == nRead);
293 if (nRead == -1) {
294 fprintf(stderr, "PR_Read() failed\n");
295 failed_already=1;
296 goto exit_now;
297 } else if (nRead == 0) {
298 PR_Close(pds[j].fd);
299 continue;
300 } else {
301 /* Just to be safe */
302 buf[127] = '\0';
303 if (debug_mode) printf("The server received \"%s\" from a client\n", buf);
304 }
305 } else if (pds[j].out_flags & PR_POLL_ERR) {
306 fprintf(stderr, "PR_Poll() indicates that an fd has error\n");
307 failed_already=1;
308 goto exit_now;
309 } else if (pds[j].out_flags & PR_POLL_NVAL) {
310 fprintf(stderr, "PR_Poll() indicates that an fd is invalid\n");
311 failed_already=1;
312 goto exit_now;
313 }
314 other_pds[nextIndex] = pds[j];
315 nextIndex++;
316 }
317
318 PR_ASSERT(retVal == nEvents);
319 /* swap */
320 tmp = pds;
321 pds = other_pds;
322 other_pds = tmp;
323 npds = nextIndex;
324 i += nEvents;
325 }
326
327 if (debug_mode) printf("Tests passed\n");
328
329 exit_now:
330
331 if (listenSock1) {
332 PR_Close(listenSock1);
333 }
334 if (listenSock2) {
335 PR_Close(listenSock2);
336 }
337
338 PR_Cleanup();
339
340 if(failed_already)
341 return 1;
342 else
343 return 0;
344
345 }

mercurial