nsprpub/pr/tests/poll_nm.c

Fri, 16 Jan 2015 04:50:19 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 04:50:19 +0100
branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
permissions
-rw-r--r--

Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32

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

mercurial