prpoll.c (10168B)
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 #ifdef WIN32 7 # include <windows.h> 8 #endif 9 10 #ifdef XP_UNIX 11 # include <unistd.h> /* for close() */ 12 #endif 13 14 #include "prinit.h" 15 #include "prio.h" 16 #include "prlog.h" 17 #include "prprf.h" 18 #include "prnetdb.h" 19 20 #include "private/pprio.h" 21 22 #define CLIENT_LOOPS 5 23 #define BUF_SIZE 128 24 25 #include <stdio.h> 26 #include <string.h> 27 #include <stdlib.h> 28 29 #ifdef WINCE 30 31 int main(int argc, char** argv) { 32 fprintf(stderr, "Invalid/Broken Test for WinCE/WinMobile\n"); 33 exit(1); 34 } 35 36 #else 37 38 static void clientThreadFunc(void* arg) { 39 PRUint16 port = (PRUint16)arg; 40 PRFileDesc* sock; 41 PRNetAddr addr; 42 char buf[BUF_SIZE]; 43 int i; 44 45 addr.inet.family = PR_AF_INET; 46 addr.inet.port = PR_htons(port); 47 addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); 48 PR_snprintf(buf, sizeof(buf), "%hu", port); 49 50 for (i = 0; i < 5; i++) { 51 sock = PR_NewTCPSocket(); 52 PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT); 53 54 PR_Write(sock, buf, sizeof(buf)); 55 PR_Close(sock); 56 } 57 } 58 59 int main(int argc, char** argv) { 60 PRFileDesc *listenSock1, *listenSock2; 61 PRFileDesc* badFD; 62 PRUint16 listenPort1, listenPort2; 63 PRNetAddr addr; 64 char buf[BUF_SIZE]; 65 PRThread* clientThread; 66 PRPollDesc pds0[10], pds1[10], *pds, *other_pds; 67 PRIntn npds; 68 PRInt32 retVal; 69 PRInt32 rv; 70 PROsfd sd; 71 struct sockaddr_in saddr; 72 PRIntn saddr_len; 73 PRUint16 listenPort3; 74 PRFileDesc* socket_poll_fd; 75 PRIntn i, j; 76 77 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); 78 79 printf("This program tests PR_Poll with sockets.\n"); 80 printf("Timeout, error reporting, and normal operation are tested.\n\n"); 81 82 /* Create two listening sockets */ 83 if ((listenSock1 = PR_NewTCPSocket()) == NULL) { 84 fprintf(stderr, "Can't create a new TCP socket\n"); 85 exit(1); 86 } 87 addr.inet.family = PR_AF_INET; 88 addr.inet.ip = PR_htonl(PR_INADDR_ANY); 89 addr.inet.port = PR_htons(0); 90 if (PR_Bind(listenSock1, &addr) == PR_FAILURE) { 91 fprintf(stderr, "Can't bind socket\n"); 92 exit(1); 93 } 94 if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) { 95 fprintf(stderr, "PR_GetSockName failed\n"); 96 exit(1); 97 } 98 listenPort1 = PR_ntohs(addr.inet.port); 99 if (PR_Listen(listenSock1, 5) == PR_FAILURE) { 100 fprintf(stderr, "Can't listen on a socket\n"); 101 exit(1); 102 } 103 104 if ((listenSock2 = PR_NewTCPSocket()) == NULL) { 105 fprintf(stderr, "Can't create a new TCP socket\n"); 106 exit(1); 107 } 108 addr.inet.family = PR_AF_INET; 109 addr.inet.ip = PR_htonl(PR_INADDR_ANY); 110 addr.inet.port = PR_htons(0); 111 if (PR_Bind(listenSock2, &addr) == PR_FAILURE) { 112 fprintf(stderr, "Can't bind socket\n"); 113 exit(1); 114 } 115 if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) { 116 fprintf(stderr, "PR_GetSockName failed\n"); 117 exit(1); 118 } 119 listenPort2 = PR_ntohs(addr.inet.port); 120 if (PR_Listen(listenSock2, 5) == PR_FAILURE) { 121 fprintf(stderr, "Can't listen on a socket\n"); 122 exit(1); 123 } 124 /* Set up the poll descriptor array */ 125 pds = pds0; 126 other_pds = pds1; 127 memset(pds, 0, sizeof(pds)); 128 npds = 0; 129 pds[npds].fd = listenSock1; 130 pds[npds].in_flags = PR_POLL_READ; 131 npds++; 132 pds[npds].fd = listenSock2; 133 pds[npds].in_flags = PR_POLL_READ; 134 npds++; 135 136 sd = socket(AF_INET, SOCK_STREAM, 0); 137 PR_ASSERT(sd >= 0); 138 memset((char*)&saddr, 0, sizeof(saddr)); 139 saddr.sin_family = AF_INET; 140 saddr.sin_addr.s_addr = htonl(INADDR_ANY); 141 saddr.sin_port = htons(0); 142 143 rv = bind(sd, (struct sockaddr*)&saddr, sizeof(saddr)); 144 PR_ASSERT(rv == 0); 145 saddr_len = sizeof(saddr); 146 rv = getsockname(sd, (struct sockaddr*)&saddr, &saddr_len); 147 PR_ASSERT(rv == 0); 148 listenPort3 = ntohs(saddr.sin_port); 149 150 rv = listen(sd, 5); 151 PR_ASSERT(rv == 0); 152 pds[npds].fd = socket_poll_fd = PR_CreateSocketPollFd(sd); 153 PR_ASSERT(pds[npds].fd); 154 pds[npds].in_flags = PR_POLL_READ; 155 npds++; 156 PR_snprintf(buf, sizeof(buf), 157 "The server thread is listening on ports %hu, %hu and %hu\n\n", 158 listenPort1, listenPort2, listenPort3); 159 printf("%s", buf); 160 161 /* Testing timeout */ 162 printf("PR_Poll should time out in 5 seconds\n"); 163 retVal = PR_Poll(pds, npds, PR_SecondsToInterval(5)); 164 if (retVal != 0) { 165 PR_snprintf(buf, sizeof(buf), 166 "PR_Poll should time out and return 0, but it returns %ld\n", 167 retVal); 168 fprintf(stderr, "%s", buf); 169 exit(1); 170 } 171 printf("PR_Poll timed out. Test passed.\n\n"); 172 173 /* Testing bad fd */ 174 printf("PR_Poll should detect a bad file descriptor\n"); 175 if ((badFD = PR_NewTCPSocket()) == NULL) { 176 fprintf(stderr, "Can't create a TCP socket\n"); 177 exit(1); 178 } 179 180 pds[npds].fd = badFD; 181 pds[npds].in_flags = PR_POLL_READ; 182 npds++; 183 PR_Close(badFD); /* make the fd bad */ 184 # if 0 185 retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT); 186 if (retVal != 1 || (unsigned short) pds[2].out_flags != PR_POLL_NVAL) { 187 fprintf(stderr, "Failed to detect the bad fd: " 188 "PR_Poll returns %d, out_flags is 0x%hx\n", 189 retVal, pds[npds - 1].out_flags); 190 exit(1); 191 } 192 printf("PR_Poll detected the bad fd. Test passed.\n\n"); 193 # endif 194 npds--; 195 196 clientThread = PR_CreateThread(PR_USER_THREAD, clientThreadFunc, 197 (void*)listenPort1, PR_PRIORITY_NORMAL, 198 PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0); 199 if (clientThread == NULL) { 200 fprintf(stderr, "can't create thread\n"); 201 exit(1); 202 } 203 204 clientThread = PR_CreateThread(PR_USER_THREAD, clientThreadFunc, 205 (void*)listenPort2, PR_PRIORITY_NORMAL, 206 PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0); 207 if (clientThread == NULL) { 208 fprintf(stderr, "can't create thread\n"); 209 exit(1); 210 } 211 212 clientThread = PR_CreateThread( 213 PR_USER_THREAD, clientThreadFunc, (void*)listenPort3, PR_PRIORITY_NORMAL, 214 PR_GLOBAL_BOUND_THREAD, PR_UNJOINABLE_THREAD, 0); 215 if (clientThread == NULL) { 216 fprintf(stderr, "can't create thread\n"); 217 exit(1); 218 } 219 220 printf("Three client threads are created. Each of them will\n"); 221 printf("send data to one of the three ports the server is listening on.\n"); 222 printf("The data they send is the port number. Each of them send\n"); 223 printf("the data five times, so you should see ten lines below,\n"); 224 printf("interleaved in an arbitrary order.\n"); 225 226 /* 30 events total */ 227 i = 0; 228 while (i < 30) { 229 PRPollDesc* tmp; 230 int nextIndex; 231 int nEvents = 0; 232 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 exit(1); 238 } 239 240 nextIndex = 3; 241 /* the three listening sockets */ 242 for (j = 0; j < 3; 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 if (j == 2) { 251 PROsfd newsd; 252 newsd = accept(PR_FileDesc2NativeHandle(pds[j].fd), NULL, 0); 253 if (newsd == -1) { 254 fprintf(stderr, "accept() failed\n"); 255 exit(1); 256 } 257 other_pds[nextIndex].fd = PR_CreateSocketPollFd(newsd); 258 PR_ASSERT(other_pds[nextIndex].fd); 259 other_pds[nextIndex].in_flags = PR_POLL_READ; 260 } else { 261 sock = PR_Accept(pds[j].fd, NULL, PR_INTERVAL_NO_TIMEOUT); 262 if (sock == NULL) { 263 fprintf(stderr, "PR_Accept() failed\n"); 264 exit(1); 265 } 266 other_pds[nextIndex].fd = sock; 267 other_pds[nextIndex].in_flags = PR_POLL_READ; 268 } 269 nextIndex++; 270 } else if (pds[j].out_flags & PR_POLL_ERR) { 271 fprintf(stderr, "PR_Poll() indicates that an fd has error\n"); 272 exit(1); 273 } else if (pds[j].out_flags & PR_POLL_NVAL) { 274 fprintf(stderr, "PR_Poll() indicates that fd %d is invalid\n", 275 PR_FileDesc2NativeHandle(pds[j].fd)); 276 exit(1); 277 } 278 } 279 280 for (j = 3; j < npds; j++) { 281 PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0 && 282 (pds[j].out_flags & PR_POLL_EXCEPT) == 0); 283 if (pds[j].out_flags & PR_POLL_READ) { 284 PRInt32 nBytes; 285 286 nEvents++; 287 /* XXX: This call is a hack and should be fixed */ 288 if (PR_GetDescType(pds[j].fd) == (PRDescType)0) { 289 nBytes = 290 recv(PR_FileDesc2NativeHandle(pds[j].fd), buf, sizeof(buf), 0); 291 if (nBytes == -1) { 292 fprintf(stderr, "recv() failed\n"); 293 exit(1); 294 } 295 printf("Server read %d bytes from native fd %d\n", nBytes, 296 PR_FileDesc2NativeHandle(pds[j].fd)); 297 # ifdef WIN32 298 closesocket((SOCKET)PR_FileDesc2NativeHandle(pds[j].fd)); 299 # else 300 close(PR_FileDesc2NativeHandle(pds[j].fd)); 301 # endif 302 PR_DestroySocketPollFd(pds[j].fd); 303 } else { 304 nBytes = PR_Read(pds[j].fd, buf, sizeof(buf)); 305 if (nBytes == -1) { 306 fprintf(stderr, "PR_Read() failed\n"); 307 exit(1); 308 } 309 PR_Close(pds[j].fd); 310 } 311 /* Just to be safe */ 312 buf[BUF_SIZE - 1] = '\0'; 313 printf("The server received \"%s\" from a client\n", buf); 314 } else if (pds[j].out_flags & PR_POLL_ERR) { 315 fprintf(stderr, "PR_Poll() indicates that an fd has error\n"); 316 exit(1); 317 } else if (pds[j].out_flags & PR_POLL_NVAL) { 318 fprintf(stderr, "PR_Poll() indicates that an fd is invalid\n"); 319 exit(1); 320 } else { 321 other_pds[nextIndex] = pds[j]; 322 nextIndex++; 323 } 324 } 325 326 PR_ASSERT(retVal == nEvents); 327 /* swap */ 328 tmp = pds; 329 pds = other_pds; 330 other_pds = tmp; 331 npds = nextIndex; 332 i += nEvents; 333 } 334 PR_DestroySocketPollFd(socket_poll_fd); 335 336 printf("All tests finished\n"); 337 PR_Cleanup(); 338 return 0; 339 } 340 341 #endif /* ifdef WINCE */