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

     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 **
     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 ***********************************************************************/
    23 /***********************************************************************
    24 ** Includes
    25 ***********************************************************************/
    26 /* Used to get the command line option */
    27 #include "plgetopt.h"
    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"
    36 #include "private/pprio.h"
    38 #include <stdio.h>
    39 #include <string.h>
    40 #include <stdlib.h>
    42 PRIntn failed_already=0;
    43 PRIntn debug_mode;
    45 #define NUM_ITERATIONS 5
    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;
    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);
    64     for (i = 0; i < NUM_ITERATIONS; i++) {
    65 	sock = PR_NewTCPSocket();
    66 	PR_ASSERT(sock != NULL);
    68     sts = PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT);
    69 	PR_ASSERT(sts == PR_SUCCESS);
    71 	n = PR_Write(sock, buf, sizeof(buf));
    72 	PR_ASSERT(n >= 0);
    74 	sts = PR_Close(sock);
    75 	PR_ASSERT(sts == PR_SUCCESS);
    76     }
    77 }
    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;
    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);
   114  /* main test */
   116     PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
   117     PR_STDIO_INIT();
   119     if (debug_mode) {
   120 		printf("This program tests PR_Poll with sockets.\n");
   121 		printf("Normal operation are tested.\n\n");
   122 	}
   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     }
   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);
   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;
   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     }
   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     }
   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 	}
   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;
   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 	}
   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;
   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 	}
   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             }
   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;
   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 	}
   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     }
   327     if (debug_mode) printf("Tests passed\n");
   329 exit_now:
   331     if (listenSock1) {
   332         PR_Close(listenSock1);
   333     }
   334     if (listenSock2) {
   335         PR_Close(listenSock2);
   336     }
   338     PR_Cleanup();
   340 	if(failed_already)	
   341 		return 1;
   342 	else
   343 		return 0;
   345 }

mercurial