1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/tests/prpoll.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,351 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifdef WIN32 1.10 +#include <windows.h> 1.11 +#endif 1.12 + 1.13 +#ifdef XP_UNIX 1.14 +#include <unistd.h> /* for close() */ 1.15 +#endif 1.16 + 1.17 +#include "prinit.h" 1.18 +#include "prio.h" 1.19 +#include "prlog.h" 1.20 +#include "prprf.h" 1.21 +#include "prnetdb.h" 1.22 + 1.23 +#include "private/pprio.h" 1.24 + 1.25 +#define CLIENT_LOOPS 5 1.26 +#define BUF_SIZE 128 1.27 + 1.28 +#include <stdio.h> 1.29 +#include <string.h> 1.30 +#include <stdlib.h> 1.31 + 1.32 +#ifdef WINCE 1.33 + 1.34 +int main(int argc, char **argv) 1.35 +{ 1.36 + fprintf(stderr, "Invalid/Broken Test for WinCE/WinMobile\n"); 1.37 + exit(1); 1.38 +} 1.39 + 1.40 +#else 1.41 + 1.42 +static void 1.43 +clientThreadFunc(void *arg) 1.44 +{ 1.45 + PRUint16 port = (PRUint16) arg; 1.46 + PRFileDesc *sock; 1.47 + PRNetAddr addr; 1.48 + char buf[BUF_SIZE]; 1.49 + int i; 1.50 + 1.51 + addr.inet.family = PR_AF_INET; 1.52 + addr.inet.port = PR_htons(port); 1.53 + addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); 1.54 + PR_snprintf(buf, sizeof(buf), "%hu", port); 1.55 + 1.56 + for (i = 0; i < 5; i++) { 1.57 + sock = PR_NewTCPSocket(); 1.58 + PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT); 1.59 + 1.60 + PR_Write(sock, buf, sizeof(buf)); 1.61 + PR_Close(sock); 1.62 + } 1.63 +} 1.64 + 1.65 +int main(int argc, char **argv) 1.66 +{ 1.67 + PRFileDesc *listenSock1, *listenSock2; 1.68 + PRFileDesc *badFD; 1.69 + PRUint16 listenPort1, listenPort2; 1.70 + PRNetAddr addr; 1.71 + char buf[BUF_SIZE]; 1.72 + PRThread *clientThread; 1.73 + PRPollDesc pds0[10], pds1[10], *pds, *other_pds; 1.74 + PRIntn npds; 1.75 + PRInt32 retVal; 1.76 + PRInt32 rv; 1.77 + PROsfd sd; 1.78 + struct sockaddr_in saddr; 1.79 + PRIntn saddr_len; 1.80 + PRUint16 listenPort3; 1.81 + PRFileDesc *socket_poll_fd; 1.82 + PRIntn i, j; 1.83 + 1.84 + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); 1.85 + PR_STDIO_INIT(); 1.86 + 1.87 + printf("This program tests PR_Poll with sockets.\n"); 1.88 + printf("Timeout, error reporting, and normal operation are tested.\n\n"); 1.89 + 1.90 + /* Create two listening sockets */ 1.91 + if ((listenSock1 = PR_NewTCPSocket()) == NULL) { 1.92 + fprintf(stderr, "Can't create a new TCP socket\n"); 1.93 + exit(1); 1.94 + } 1.95 + addr.inet.family = PR_AF_INET; 1.96 + addr.inet.ip = PR_htonl(PR_INADDR_ANY); 1.97 + addr.inet.port = PR_htons(0); 1.98 + if (PR_Bind(listenSock1, &addr) == PR_FAILURE) { 1.99 + fprintf(stderr, "Can't bind socket\n"); 1.100 + exit(1); 1.101 + } 1.102 + if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) { 1.103 + fprintf(stderr, "PR_GetSockName failed\n"); 1.104 + exit(1); 1.105 + } 1.106 + listenPort1 = PR_ntohs(addr.inet.port); 1.107 + if (PR_Listen(listenSock1, 5) == PR_FAILURE) { 1.108 + fprintf(stderr, "Can't listen on a socket\n"); 1.109 + exit(1); 1.110 + } 1.111 + 1.112 + if ((listenSock2 = PR_NewTCPSocket()) == NULL) { 1.113 + fprintf(stderr, "Can't create a new TCP socket\n"); 1.114 + exit(1); 1.115 + } 1.116 + addr.inet.family = PR_AF_INET; 1.117 + addr.inet.ip = PR_htonl(PR_INADDR_ANY); 1.118 + addr.inet.port = PR_htons(0); 1.119 + if (PR_Bind(listenSock2, &addr) == PR_FAILURE) { 1.120 + fprintf(stderr, "Can't bind socket\n"); 1.121 + exit(1); 1.122 + } 1.123 + if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) { 1.124 + fprintf(stderr, "PR_GetSockName failed\n"); 1.125 + exit(1); 1.126 + } 1.127 + listenPort2 = PR_ntohs(addr.inet.port); 1.128 + if (PR_Listen(listenSock2, 5) == PR_FAILURE) { 1.129 + fprintf(stderr, "Can't listen on a socket\n"); 1.130 + exit(1); 1.131 + } 1.132 + /* Set up the poll descriptor array */ 1.133 + pds = pds0; 1.134 + other_pds = pds1; 1.135 + memset(pds, 0, sizeof(pds)); 1.136 + npds = 0; 1.137 + pds[npds].fd = listenSock1; 1.138 + pds[npds].in_flags = PR_POLL_READ; 1.139 + npds++; 1.140 + pds[npds].fd = listenSock2; 1.141 + pds[npds].in_flags = PR_POLL_READ; 1.142 + npds++; 1.143 + 1.144 + sd = socket(AF_INET, SOCK_STREAM, 0); 1.145 + PR_ASSERT(sd >= 0); 1.146 + memset((char *) &saddr, 0, sizeof(saddr)); 1.147 + saddr.sin_family = AF_INET; 1.148 + saddr.sin_addr.s_addr = htonl(INADDR_ANY); 1.149 + saddr.sin_port = htons(0); 1.150 + 1.151 + rv = bind(sd, (struct sockaddr *)&saddr, sizeof(saddr)); 1.152 + PR_ASSERT(rv == 0); 1.153 + saddr_len = sizeof(saddr); 1.154 + rv = getsockname(sd, (struct sockaddr *) &saddr, &saddr_len); 1.155 + PR_ASSERT(rv == 0); 1.156 + listenPort3 = ntohs(saddr.sin_port); 1.157 + 1.158 + rv = listen(sd, 5); 1.159 + PR_ASSERT(rv == 0); 1.160 + pds[npds].fd = socket_poll_fd = PR_CreateSocketPollFd(sd); 1.161 + PR_ASSERT(pds[npds].fd); 1.162 + pds[npds].in_flags = PR_POLL_READ; 1.163 + npds++; 1.164 + PR_snprintf(buf, sizeof(buf), 1.165 + "The server thread is listening on ports %hu, %hu and %hu\n\n", 1.166 + listenPort1, listenPort2, listenPort3); 1.167 + printf("%s", buf); 1.168 + 1.169 + /* Testing timeout */ 1.170 + printf("PR_Poll should time out in 5 seconds\n"); 1.171 + retVal = PR_Poll(pds, npds, PR_SecondsToInterval(5)); 1.172 + if (retVal != 0) { 1.173 + PR_snprintf(buf, sizeof(buf), 1.174 + "PR_Poll should time out and return 0, but it returns %ld\n", 1.175 + retVal); 1.176 + fprintf(stderr, "%s", buf); 1.177 + exit(1); 1.178 + } 1.179 + printf("PR_Poll timed out. Test passed.\n\n"); 1.180 + 1.181 + /* Testing bad fd */ 1.182 + printf("PR_Poll should detect a bad file descriptor\n"); 1.183 + if ((badFD = PR_NewTCPSocket()) == NULL) { 1.184 + fprintf(stderr, "Can't create a TCP socket\n"); 1.185 + exit(1); 1.186 + } 1.187 + 1.188 + pds[npds].fd = badFD; 1.189 + pds[npds].in_flags = PR_POLL_READ; 1.190 + npds++; 1.191 + PR_Close(badFD); /* make the fd bad */ 1.192 +#if 0 1.193 + retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT); 1.194 + if (retVal != 1 || (unsigned short) pds[2].out_flags != PR_POLL_NVAL) { 1.195 + fprintf(stderr, "Failed to detect the bad fd: " 1.196 + "PR_Poll returns %d, out_flags is 0x%hx\n", 1.197 + retVal, pds[npds - 1].out_flags); 1.198 + exit(1); 1.199 + } 1.200 + printf("PR_Poll detected the bad fd. Test passed.\n\n"); 1.201 +#endif 1.202 + npds--; 1.203 + 1.204 + clientThread = PR_CreateThread(PR_USER_THREAD, 1.205 + clientThreadFunc, (void *) listenPort1, 1.206 + PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, 1.207 + PR_UNJOINABLE_THREAD, 0); 1.208 + if (clientThread == NULL) { 1.209 + fprintf(stderr, "can't create thread\n"); 1.210 + exit(1); 1.211 + } 1.212 + 1.213 + clientThread = PR_CreateThread(PR_USER_THREAD, 1.214 + clientThreadFunc, (void *) listenPort2, 1.215 + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, 1.216 + PR_UNJOINABLE_THREAD, 0); 1.217 + if (clientThread == NULL) { 1.218 + fprintf(stderr, "can't create thread\n"); 1.219 + exit(1); 1.220 + } 1.221 + 1.222 + clientThread = PR_CreateThread(PR_USER_THREAD, 1.223 + clientThreadFunc, (void *) listenPort3, 1.224 + PR_PRIORITY_NORMAL, PR_GLOBAL_BOUND_THREAD, 1.225 + PR_UNJOINABLE_THREAD, 0); 1.226 + if (clientThread == NULL) { 1.227 + fprintf(stderr, "can't create thread\n"); 1.228 + exit(1); 1.229 + } 1.230 + 1.231 + 1.232 + printf("Three client threads are created. Each of them will\n"); 1.233 + printf("send data to one of the three ports the server is listening on.\n"); 1.234 + printf("The data they send is the port number. Each of them send\n"); 1.235 + printf("the data five times, so you should see ten lines below,\n"); 1.236 + printf("interleaved in an arbitrary order.\n"); 1.237 + 1.238 + /* 30 events total */ 1.239 + i = 0; 1.240 + while (i < 30) { 1.241 + PRPollDesc *tmp; 1.242 + int nextIndex; 1.243 + int nEvents = 0; 1.244 + 1.245 + retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT); 1.246 + PR_ASSERT(retVal != 0); /* no timeout */ 1.247 + if (retVal == -1) { 1.248 + fprintf(stderr, "PR_Poll failed\n"); 1.249 + exit(1); 1.250 + } 1.251 + 1.252 + nextIndex = 3; 1.253 + /* the three listening sockets */ 1.254 + for (j = 0; j < 3; j++) { 1.255 + other_pds[j] = pds[j]; 1.256 + PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0 1.257 + && (pds[j].out_flags & PR_POLL_EXCEPT) == 0); 1.258 + if (pds[j].out_flags & PR_POLL_READ) { 1.259 + PRFileDesc *sock; 1.260 + 1.261 + nEvents++; 1.262 + if (j == 2) { 1.263 + PROsfd newsd; 1.264 + newsd = accept(PR_FileDesc2NativeHandle(pds[j].fd), NULL, 0); 1.265 + if (newsd == -1) { 1.266 + fprintf(stderr, "accept() failed\n"); 1.267 + exit(1); 1.268 + } 1.269 + other_pds[nextIndex].fd = PR_CreateSocketPollFd(newsd); 1.270 + PR_ASSERT(other_pds[nextIndex].fd); 1.271 + other_pds[nextIndex].in_flags = PR_POLL_READ; 1.272 + } else { 1.273 + sock = PR_Accept(pds[j].fd, NULL, PR_INTERVAL_NO_TIMEOUT); 1.274 + if (sock == NULL) { 1.275 + fprintf(stderr, "PR_Accept() failed\n"); 1.276 + exit(1); 1.277 + } 1.278 + other_pds[nextIndex].fd = sock; 1.279 + other_pds[nextIndex].in_flags = PR_POLL_READ; 1.280 + } 1.281 + nextIndex++; 1.282 + } else if (pds[j].out_flags & PR_POLL_ERR) { 1.283 + fprintf(stderr, "PR_Poll() indicates that an fd has error\n"); 1.284 + exit(1); 1.285 + } else if (pds[j].out_flags & PR_POLL_NVAL) { 1.286 + fprintf(stderr, "PR_Poll() indicates that fd %d is invalid\n", 1.287 + PR_FileDesc2NativeHandle(pds[j].fd)); 1.288 + exit(1); 1.289 + } 1.290 + } 1.291 + 1.292 + for (j = 3; j < npds; j++) { 1.293 + PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0 1.294 + && (pds[j].out_flags & PR_POLL_EXCEPT) == 0); 1.295 + if (pds[j].out_flags & PR_POLL_READ) { 1.296 + PRInt32 nBytes; 1.297 + 1.298 + nEvents++; 1.299 + /* XXX: This call is a hack and should be fixed */ 1.300 + if (PR_GetDescType(pds[j].fd) == (PRDescType) 0) { 1.301 + nBytes = recv(PR_FileDesc2NativeHandle(pds[j].fd), buf, 1.302 + sizeof(buf), 0); 1.303 + if (nBytes == -1) { 1.304 + fprintf(stderr, "recv() failed\n"); 1.305 + exit(1); 1.306 + } 1.307 + printf("Server read %d bytes from native fd %d\n",nBytes, 1.308 + PR_FileDesc2NativeHandle(pds[j].fd)); 1.309 +#ifdef WIN32 1.310 + closesocket((SOCKET)PR_FileDesc2NativeHandle(pds[j].fd)); 1.311 +#else 1.312 + close(PR_FileDesc2NativeHandle(pds[j].fd)); 1.313 +#endif 1.314 + PR_DestroySocketPollFd(pds[j].fd); 1.315 + } else { 1.316 + nBytes = PR_Read(pds[j].fd, buf, sizeof(buf)); 1.317 + if (nBytes == -1) { 1.318 + fprintf(stderr, "PR_Read() failed\n"); 1.319 + exit(1); 1.320 + } 1.321 + PR_Close(pds[j].fd); 1.322 + } 1.323 + /* Just to be safe */ 1.324 + buf[BUF_SIZE - 1] = '\0'; 1.325 + printf("The server received \"%s\" from a client\n", buf); 1.326 + } else if (pds[j].out_flags & PR_POLL_ERR) { 1.327 + fprintf(stderr, "PR_Poll() indicates that an fd has error\n"); 1.328 + exit(1); 1.329 + } else if (pds[j].out_flags & PR_POLL_NVAL) { 1.330 + fprintf(stderr, "PR_Poll() indicates that an fd is invalid\n"); 1.331 + exit(1); 1.332 + } else { 1.333 + other_pds[nextIndex] = pds[j]; 1.334 + nextIndex++; 1.335 + } 1.336 + } 1.337 + 1.338 + PR_ASSERT(retVal == nEvents); 1.339 + /* swap */ 1.340 + tmp = pds; 1.341 + pds = other_pds; 1.342 + other_pds = tmp; 1.343 + npds = nextIndex; 1.344 + i += nEvents; 1.345 + } 1.346 + PR_DestroySocketPollFd(socket_poll_fd); 1.347 + 1.348 + printf("All tests finished\n"); 1.349 + PR_Cleanup(); 1.350 + return 0; 1.351 +} 1.352 + 1.353 + 1.354 +#endif /* ifdef WINCE */