Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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/. */
6 /***********************************************************************
7 ** 1997 - Netscape Communications Corporation
8 **
9 ** Name: prselect_err.c
10 **
11 ** Description: tests PR_Select with sockets Error condition functions.
12 **
13 ** Modification History:
14 ** 14-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 ***********************************************************************/
21 /***********************************************************************
22 ** Includes
23 ***********************************************************************/
24 /* Used to get the command line option */
25 #include "plgetopt.h"
26 #include "prttools.h"
29 #include "prinit.h"
30 #include "prio.h"
31 #include "prlog.h"
32 #include "prprf.h"
33 #include "prerror.h"
34 #include "prnetdb.h"
36 #include <stdio.h>
37 #include <string.h>
38 #include <stdlib.h>
40 /***********************************************************************
41 ** PRIVATE FUNCTION: Test_Result
42 ** DESCRIPTION: Used in conjunction with the regress tool, prints out the
43 ** status of the test case.
44 ** INPUTS: PASS/FAIL
45 ** OUTPUTS: None
46 ** RETURN: None
47 ** SIDE EFFECTS:
48 **
49 ** RESTRICTIONS:
50 ** None
51 ** MEMORY: NA
52 ** ALGORITHM: Determine what the status is and print accordingly.
53 **
54 ***********************************************************************/
57 static Test_Result (int result)
58 {
59 if (result == PASS)
60 printf ("PASS\n");
61 else
62 printf ("FAIL\n");
63 }
65 static void
66 clientThreadFunc(void *arg)
67 {
68 PRUint16 port = (PRUint16) arg;
69 PRFileDesc *sock;
70 PRNetAddr addr;
71 char buf[128];
72 int i;
74 addr.inet.family = AF_INET;
75 addr.inet.port = PR_htons(port);
76 addr.inet.ip = PR_htonl(INADDR_LOOPBACK);
77 PR_snprintf(buf, sizeof(buf), "%hu", port);
79 for (i = 0; i < 5; i++) {
80 sock = PR_NewTCPSocket();
81 PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT);
82 PR_Write(sock, buf, sizeof(buf));
83 PR_Close(sock);
84 }
85 }
87 int main(int argc, char **argv)
88 {
89 PRFileDesc *listenSock1, *listenSock2;
90 PRFileDesc *badFD;
91 PRFileDesc *fds0[10], *fds1[10], **fds, **other_fds;
92 PRIntn nfds;
93 PRUint16 listenPort1, listenPort2;
94 PRNetAddr addr;
95 PR_fd_set readFdSet;
96 char buf[128];
97 PRThread *clientThread;
98 PRInt32 retVal;
99 PRIntn i, j;
101 /* The command line argument: -d is used to determine if the test is being run
102 in debug mode. The regress tool requires only one line output:PASS or FAIL.
103 All of the printfs associated with this test has been handled with a if (debug_mode)
104 test.
105 Usage: test_name -d
106 */
107 PLOptStatus os;
108 PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
109 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
110 {
111 if (PL_OPT_BAD == os) continue;
112 switch (opt->option)
113 {
114 case 'd': /* debug mode */
115 debug_mode = 1;
116 break;
117 default:
118 break;
119 }
120 }
121 PL_DestroyOptState(opt);
123 /* main test */
125 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
126 PR_STDIO_INIT();
128 if (debug_mode) {
129 printf("This program tests PR_Select with sockets. Timeout, error\n");
130 printf("reporting, and normal operation are tested.\n\n");
131 }
133 /* Create two listening sockets */
134 if ((listenSock1 = PR_NewTCPSocket()) == NULL) {
135 fprintf(stderr, "Can't create a new TCP socket\n");
136 if (!debug_mode) Test_Result(FAIL);
137 exit(1);
138 }
139 addr.inet.family = AF_INET;
140 addr.inet.ip = PR_htonl(INADDR_ANY);
141 addr.inet.port = PR_htons(0);
142 if (PR_Bind(listenSock1, &addr) == PR_FAILURE) {
143 fprintf(stderr, "Can't bind socket\n");
144 if (!debug_mode) Test_Result(FAIL);
145 exit(1);
146 }
147 if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) {
148 fprintf(stderr, "PR_GetSockName failed\n");
149 if (!debug_mode) Test_Result(FAIL);
150 exit(1);
151 }
152 listenPort1 = PR_ntohs(addr.inet.port);
153 if (PR_Listen(listenSock1, 5) == PR_FAILURE) {
154 fprintf(stderr, "Can't listen on a socket\n");
155 if (!debug_mode) Test_Result(FAIL);
156 exit(1);
157 }
159 if ((listenSock2 = PR_NewTCPSocket()) == NULL) {
160 fprintf(stderr, "Can't create a new TCP socket\n");
161 if (!debug_mode) Test_Result(FAIL);
162 exit(1);
163 }
164 addr.inet.family = AF_INET;
165 addr.inet.ip = PR_htonl(INADDR_ANY);
166 addr.inet.port = PR_htons(0);
167 if (PR_Bind(listenSock2, &addr) == PR_FAILURE) {
168 fprintf(stderr, "Can't bind socket\n");
169 if (!debug_mode) Test_Result(FAIL);
170 exit(1);
171 }
172 if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) {
173 fprintf(stderr, "PR_GetSockName failed\n");
174 if (!debug_mode) Test_Result(FAIL);
175 exit(1);
176 }
177 listenPort2 = PR_ntohs(addr.inet.port);
178 if (PR_Listen(listenSock2, 5) == PR_FAILURE) {
179 fprintf(stderr, "Can't listen on a socket\n");
180 if (!debug_mode) Test_Result(FAIL);
181 exit(1);
182 }
183 PR_snprintf(buf, sizeof(buf),
184 "The server thread is listening on ports %hu and %hu\n\n",
185 listenPort1, listenPort2);
186 printf("%s", buf);
188 /* Set up the fd set */
189 PR_FD_ZERO(&readFdSet);
190 PR_FD_SET(listenSock1, &readFdSet);
191 PR_FD_SET(listenSock2, &readFdSet);
193 /* Testing timeout */
194 if (debug_mode) printf("PR_Select should time out in 5 seconds\n");
195 retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL,
196 PR_SecondsToInterval(5));
197 if (retVal != 0) {
198 PR_snprintf(buf, sizeof(buf),
199 "PR_Select should time out and return 0, but it returns %ld\n",
200 retVal);
201 fprintf(stderr, "%s", buf);
202 if (retVal == -1) {
203 fprintf(stderr, "Error %d, oserror %d\n", PR_GetError(),
204 PR_GetOSError());
205 if (!debug_mode) Test_Result(FAIL);
206 }
207 exit(1);
208 }
209 if (debug_mode) printf("PR_Select timed out. Test passed.\n\n");
210 else Test_Result(PASS);
212 /* Testing bad fd */
213 printf("PR_Select should detect a bad file descriptor\n");
214 if ((badFD = PR_NewTCPSocket()) == NULL) {
215 fprintf(stderr, "Can't create a TCP socket\n");
216 exit(1);
217 }
219 PR_FD_SET(listenSock1, &readFdSet);
220 PR_FD_SET(listenSock2, &readFdSet);
221 PR_FD_SET(badFD, &readFdSet);
222 PR_Close(badFD); /* make the fd bad */
223 retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL,
224 PR_INTERVAL_NO_TIMEOUT);
225 if (retVal != -1 || PR_GetError() != PR_BAD_DESCRIPTOR_ERROR) {
226 fprintf(stderr, "Failed to detect the bad fd: "
227 "PR_Select returns %d\n", retVal);
228 if (retVal == -1) {
229 fprintf(stderr, "Error %d, oserror %d\n", PR_GetError(),
230 PR_GetOSError());
231 }
232 exit(1);
233 }
234 printf("PR_Select detected a bad fd. Test passed.\n\n");
235 PR_FD_CLR(badFD, &readFdSet);
237 clientThread = PR_CreateThread(PR_USER_THREAD,
238 clientThreadFunc, (void *) listenPort1,
239 PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
240 PR_UNJOINABLE_THREAD, 0);
241 if (clientThread == NULL) {
242 fprintf(stderr, "can't create thread\n");
243 exit(1);
244 }
246 clientThread = PR_CreateThread(PR_USER_THREAD,
247 clientThreadFunc, (void *) listenPort2,
248 PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
249 PR_UNJOINABLE_THREAD, 0);
250 if (clientThread == NULL) {
251 fprintf(stderr, "can't create thread\n");
252 exit(1);
253 }
255 printf("Two client threads are created. Each of them will\n");
256 printf("send data to one of the two ports the server is listening on.\n");
257 printf("The data they send is the port number. Each of them send\n");
258 printf("the data five times, so you should see ten lines below,\n");
259 printf("interleaved in an arbitrary order.\n");
261 /* set up the fd array */
262 fds = fds0;
263 other_fds = fds1;
264 fds[0] = listenSock1;
265 fds[1] = listenSock2;
266 nfds = 2;
267 PR_FD_SET(listenSock1, &readFdSet);
268 PR_FD_SET(listenSock2, &readFdSet);
270 /* 20 events total */
271 i = 0;
272 while (i < 20) {
273 PRFileDesc **tmp;
274 int nextIndex;
275 int nEvents = 0;
277 retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL,
278 PR_INTERVAL_NO_TIMEOUT);
279 PR_ASSERT(retVal != 0); /* no timeout */
280 if (retVal == -1) {
281 fprintf(stderr, "PR_Select failed (%d, %d)\n", PR_GetError(),
282 PR_GetOSError());
283 exit(1);
284 }
286 nextIndex = 2;
287 /* the two listening sockets */
288 for (j = 0; j < 2; j++) {
289 other_fds[j] = fds[j];
290 if (PR_FD_ISSET(fds[j], &readFdSet)) {
291 PRFileDesc *sock;
293 nEvents++;
294 sock = PR_Accept(fds[j], NULL, PR_INTERVAL_NO_TIMEOUT);
295 if (sock == NULL) {
296 fprintf(stderr, "PR_Accept() failed\n");
297 exit(1);
298 }
299 other_fds[nextIndex] = sock;
300 PR_FD_SET(sock, &readFdSet);
301 nextIndex++;
302 }
303 PR_FD_SET(fds[j], &readFdSet);
304 }
306 for (j = 2; j < nfds; j++) {
307 if (PR_FD_ISSET(fds[j], &readFdSet)) {
308 PRInt32 nBytes;
310 PR_FD_CLR(fds[j], &readFdSet);
311 nEvents++;
312 nBytes = PR_Read(fds[j], buf, sizeof(buf));
313 if (nBytes == -1) {
314 fprintf(stderr, "PR_Read() failed\n");
315 exit(1);
316 }
317 /* Just to be safe */
318 buf[127] = '\0';
319 PR_Close(fds[j]);
320 printf("The server received \"%s\" from a client\n", buf);
321 } else {
322 PR_FD_SET(fds[j], &readFdSet);
323 other_fds[nextIndex] = fds[j];
324 nextIndex++;
325 }
326 }
328 PR_ASSERT(retVal == nEvents);
329 /* swap */
330 tmp = fds;
331 fds = other_fds;
332 other_fds = tmp;
333 nfds = nextIndex;
334 i += nEvents;
335 }
337 printf("All tests finished\n");
338 PR_Cleanup();
339 return 0;
340 }