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