nsprpub/pr/tests/prselect.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial