michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifdef WIN32 michael@0: #include michael@0: #endif michael@0: michael@0: #ifdef XP_UNIX michael@0: #include /* for close() */ michael@0: #endif michael@0: michael@0: #include "prinit.h" michael@0: #include "prio.h" michael@0: #include "prlog.h" michael@0: #include "prprf.h" michael@0: #include "prnetdb.h" michael@0: michael@0: #include "private/pprio.h" michael@0: michael@0: #define CLIENT_LOOPS 5 michael@0: #define BUF_SIZE 128 michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #ifdef WINCE michael@0: michael@0: int main(int argc, char **argv) michael@0: { michael@0: fprintf(stderr, "Invalid/Broken Test for WinCE/WinMobile\n"); michael@0: exit(1); michael@0: } michael@0: michael@0: #else michael@0: michael@0: static void michael@0: clientThreadFunc(void *arg) michael@0: { michael@0: PRUint16 port = (PRUint16) arg; michael@0: PRFileDesc *sock; michael@0: PRNetAddr addr; michael@0: char buf[BUF_SIZE]; michael@0: int i; michael@0: michael@0: addr.inet.family = PR_AF_INET; michael@0: addr.inet.port = PR_htons(port); michael@0: addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); michael@0: PR_snprintf(buf, sizeof(buf), "%hu", port); michael@0: michael@0: for (i = 0; i < 5; i++) { michael@0: sock = PR_NewTCPSocket(); michael@0: PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT); michael@0: michael@0: PR_Write(sock, buf, sizeof(buf)); michael@0: PR_Close(sock); michael@0: } michael@0: } michael@0: michael@0: int main(int argc, char **argv) michael@0: { michael@0: PRFileDesc *listenSock1, *listenSock2; michael@0: PRFileDesc *badFD; michael@0: PRUint16 listenPort1, listenPort2; michael@0: PRNetAddr addr; michael@0: char buf[BUF_SIZE]; michael@0: PRThread *clientThread; michael@0: PRPollDesc pds0[10], pds1[10], *pds, *other_pds; michael@0: PRIntn npds; michael@0: PRInt32 retVal; michael@0: PRInt32 rv; michael@0: PROsfd sd; michael@0: struct sockaddr_in saddr; michael@0: PRIntn saddr_len; michael@0: PRUint16 listenPort3; michael@0: PRFileDesc *socket_poll_fd; michael@0: PRIntn i, j; michael@0: michael@0: PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); michael@0: PR_STDIO_INIT(); michael@0: michael@0: printf("This program tests PR_Poll with sockets.\n"); michael@0: printf("Timeout, error reporting, and normal operation are tested.\n\n"); michael@0: michael@0: /* Create two listening sockets */ michael@0: if ((listenSock1 = PR_NewTCPSocket()) == NULL) { michael@0: fprintf(stderr, "Can't create a new TCP socket\n"); michael@0: exit(1); michael@0: } michael@0: addr.inet.family = PR_AF_INET; michael@0: addr.inet.ip = PR_htonl(PR_INADDR_ANY); michael@0: addr.inet.port = PR_htons(0); michael@0: if (PR_Bind(listenSock1, &addr) == PR_FAILURE) { michael@0: fprintf(stderr, "Can't bind socket\n"); michael@0: exit(1); michael@0: } michael@0: if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) { michael@0: fprintf(stderr, "PR_GetSockName failed\n"); michael@0: exit(1); michael@0: } michael@0: listenPort1 = PR_ntohs(addr.inet.port); michael@0: if (PR_Listen(listenSock1, 5) == PR_FAILURE) { michael@0: fprintf(stderr, "Can't listen on a socket\n"); michael@0: exit(1); michael@0: } michael@0: michael@0: if ((listenSock2 = PR_NewTCPSocket()) == NULL) { michael@0: fprintf(stderr, "Can't create a new TCP socket\n"); michael@0: exit(1); michael@0: } michael@0: addr.inet.family = PR_AF_INET; michael@0: addr.inet.ip = PR_htonl(PR_INADDR_ANY); michael@0: addr.inet.port = PR_htons(0); michael@0: if (PR_Bind(listenSock2, &addr) == PR_FAILURE) { michael@0: fprintf(stderr, "Can't bind socket\n"); michael@0: exit(1); michael@0: } michael@0: if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) { michael@0: fprintf(stderr, "PR_GetSockName failed\n"); michael@0: exit(1); michael@0: } michael@0: listenPort2 = PR_ntohs(addr.inet.port); michael@0: if (PR_Listen(listenSock2, 5) == PR_FAILURE) { michael@0: fprintf(stderr, "Can't listen on a socket\n"); michael@0: exit(1); michael@0: } michael@0: /* Set up the poll descriptor array */ michael@0: pds = pds0; michael@0: other_pds = pds1; michael@0: memset(pds, 0, sizeof(pds)); michael@0: npds = 0; michael@0: pds[npds].fd = listenSock1; michael@0: pds[npds].in_flags = PR_POLL_READ; michael@0: npds++; michael@0: pds[npds].fd = listenSock2; michael@0: pds[npds].in_flags = PR_POLL_READ; michael@0: npds++; michael@0: michael@0: sd = socket(AF_INET, SOCK_STREAM, 0); michael@0: PR_ASSERT(sd >= 0); michael@0: memset((char *) &saddr, 0, sizeof(saddr)); michael@0: saddr.sin_family = AF_INET; michael@0: saddr.sin_addr.s_addr = htonl(INADDR_ANY); michael@0: saddr.sin_port = htons(0); michael@0: michael@0: rv = bind(sd, (struct sockaddr *)&saddr, sizeof(saddr)); michael@0: PR_ASSERT(rv == 0); michael@0: saddr_len = sizeof(saddr); michael@0: rv = getsockname(sd, (struct sockaddr *) &saddr, &saddr_len); michael@0: PR_ASSERT(rv == 0); michael@0: listenPort3 = ntohs(saddr.sin_port); michael@0: michael@0: rv = listen(sd, 5); michael@0: PR_ASSERT(rv == 0); michael@0: pds[npds].fd = socket_poll_fd = PR_CreateSocketPollFd(sd); michael@0: PR_ASSERT(pds[npds].fd); michael@0: pds[npds].in_flags = PR_POLL_READ; michael@0: npds++; michael@0: PR_snprintf(buf, sizeof(buf), michael@0: "The server thread is listening on ports %hu, %hu and %hu\n\n", michael@0: listenPort1, listenPort2, listenPort3); michael@0: printf("%s", buf); michael@0: michael@0: /* Testing timeout */ michael@0: printf("PR_Poll should time out in 5 seconds\n"); michael@0: retVal = PR_Poll(pds, npds, PR_SecondsToInterval(5)); michael@0: if (retVal != 0) { michael@0: PR_snprintf(buf, sizeof(buf), michael@0: "PR_Poll should time out and return 0, but it returns %ld\n", michael@0: retVal); michael@0: fprintf(stderr, "%s", buf); michael@0: exit(1); michael@0: } michael@0: printf("PR_Poll timed out. Test passed.\n\n"); michael@0: michael@0: /* Testing bad fd */ michael@0: printf("PR_Poll should detect a bad file descriptor\n"); michael@0: if ((badFD = PR_NewTCPSocket()) == NULL) { michael@0: fprintf(stderr, "Can't create a TCP socket\n"); michael@0: exit(1); michael@0: } michael@0: michael@0: pds[npds].fd = badFD; michael@0: pds[npds].in_flags = PR_POLL_READ; michael@0: npds++; michael@0: PR_Close(badFD); /* make the fd bad */ michael@0: #if 0 michael@0: retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT); michael@0: if (retVal != 1 || (unsigned short) pds[2].out_flags != PR_POLL_NVAL) { michael@0: fprintf(stderr, "Failed to detect the bad fd: " michael@0: "PR_Poll returns %d, out_flags is 0x%hx\n", michael@0: retVal, pds[npds - 1].out_flags); michael@0: exit(1); michael@0: } michael@0: printf("PR_Poll detected the bad fd. Test passed.\n\n"); michael@0: #endif michael@0: npds--; michael@0: michael@0: clientThread = PR_CreateThread(PR_USER_THREAD, michael@0: clientThreadFunc, (void *) listenPort1, michael@0: PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, michael@0: PR_UNJOINABLE_THREAD, 0); michael@0: if (clientThread == NULL) { michael@0: fprintf(stderr, "can't create thread\n"); michael@0: exit(1); michael@0: } michael@0: michael@0: clientThread = PR_CreateThread(PR_USER_THREAD, michael@0: clientThreadFunc, (void *) listenPort2, michael@0: PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, michael@0: PR_UNJOINABLE_THREAD, 0); michael@0: if (clientThread == NULL) { michael@0: fprintf(stderr, "can't create thread\n"); michael@0: exit(1); michael@0: } michael@0: michael@0: clientThread = PR_CreateThread(PR_USER_THREAD, michael@0: clientThreadFunc, (void *) listenPort3, michael@0: PR_PRIORITY_NORMAL, PR_GLOBAL_BOUND_THREAD, michael@0: PR_UNJOINABLE_THREAD, 0); michael@0: if (clientThread == NULL) { michael@0: fprintf(stderr, "can't create thread\n"); michael@0: exit(1); michael@0: } michael@0: michael@0: michael@0: printf("Three client threads are created. Each of them will\n"); michael@0: printf("send data to one of the three ports the server is listening on.\n"); michael@0: printf("The data they send is the port number. Each of them send\n"); michael@0: printf("the data five times, so you should see ten lines below,\n"); michael@0: printf("interleaved in an arbitrary order.\n"); michael@0: michael@0: /* 30 events total */ michael@0: i = 0; michael@0: while (i < 30) { michael@0: PRPollDesc *tmp; michael@0: int nextIndex; michael@0: int nEvents = 0; michael@0: michael@0: retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT); michael@0: PR_ASSERT(retVal != 0); /* no timeout */ michael@0: if (retVal == -1) { michael@0: fprintf(stderr, "PR_Poll failed\n"); michael@0: exit(1); michael@0: } michael@0: michael@0: nextIndex = 3; michael@0: /* the three listening sockets */ michael@0: for (j = 0; j < 3; j++) { michael@0: other_pds[j] = pds[j]; michael@0: PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0 michael@0: && (pds[j].out_flags & PR_POLL_EXCEPT) == 0); michael@0: if (pds[j].out_flags & PR_POLL_READ) { michael@0: PRFileDesc *sock; michael@0: michael@0: nEvents++; michael@0: if (j == 2) { michael@0: PROsfd newsd; michael@0: newsd = accept(PR_FileDesc2NativeHandle(pds[j].fd), NULL, 0); michael@0: if (newsd == -1) { michael@0: fprintf(stderr, "accept() failed\n"); michael@0: exit(1); michael@0: } michael@0: other_pds[nextIndex].fd = PR_CreateSocketPollFd(newsd); michael@0: PR_ASSERT(other_pds[nextIndex].fd); michael@0: other_pds[nextIndex].in_flags = PR_POLL_READ; michael@0: } else { michael@0: sock = PR_Accept(pds[j].fd, NULL, PR_INTERVAL_NO_TIMEOUT); michael@0: if (sock == NULL) { michael@0: fprintf(stderr, "PR_Accept() failed\n"); michael@0: exit(1); michael@0: } michael@0: other_pds[nextIndex].fd = sock; michael@0: other_pds[nextIndex].in_flags = PR_POLL_READ; michael@0: } michael@0: nextIndex++; michael@0: } else if (pds[j].out_flags & PR_POLL_ERR) { michael@0: fprintf(stderr, "PR_Poll() indicates that an fd has error\n"); michael@0: exit(1); michael@0: } else if (pds[j].out_flags & PR_POLL_NVAL) { michael@0: fprintf(stderr, "PR_Poll() indicates that fd %d is invalid\n", michael@0: PR_FileDesc2NativeHandle(pds[j].fd)); michael@0: exit(1); michael@0: } michael@0: } michael@0: michael@0: for (j = 3; j < npds; j++) { michael@0: PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0 michael@0: && (pds[j].out_flags & PR_POLL_EXCEPT) == 0); michael@0: if (pds[j].out_flags & PR_POLL_READ) { michael@0: PRInt32 nBytes; michael@0: michael@0: nEvents++; michael@0: /* XXX: This call is a hack and should be fixed */ michael@0: if (PR_GetDescType(pds[j].fd) == (PRDescType) 0) { michael@0: nBytes = recv(PR_FileDesc2NativeHandle(pds[j].fd), buf, michael@0: sizeof(buf), 0); michael@0: if (nBytes == -1) { michael@0: fprintf(stderr, "recv() failed\n"); michael@0: exit(1); michael@0: } michael@0: printf("Server read %d bytes from native fd %d\n",nBytes, michael@0: PR_FileDesc2NativeHandle(pds[j].fd)); michael@0: #ifdef WIN32 michael@0: closesocket((SOCKET)PR_FileDesc2NativeHandle(pds[j].fd)); michael@0: #else michael@0: close(PR_FileDesc2NativeHandle(pds[j].fd)); michael@0: #endif michael@0: PR_DestroySocketPollFd(pds[j].fd); michael@0: } else { michael@0: nBytes = PR_Read(pds[j].fd, buf, sizeof(buf)); michael@0: if (nBytes == -1) { michael@0: fprintf(stderr, "PR_Read() failed\n"); michael@0: exit(1); michael@0: } michael@0: PR_Close(pds[j].fd); michael@0: } michael@0: /* Just to be safe */ michael@0: buf[BUF_SIZE - 1] = '\0'; michael@0: printf("The server received \"%s\" from a client\n", buf); michael@0: } else if (pds[j].out_flags & PR_POLL_ERR) { michael@0: fprintf(stderr, "PR_Poll() indicates that an fd has error\n"); michael@0: exit(1); michael@0: } else if (pds[j].out_flags & PR_POLL_NVAL) { michael@0: fprintf(stderr, "PR_Poll() indicates that an fd is invalid\n"); michael@0: exit(1); michael@0: } else { michael@0: other_pds[nextIndex] = pds[j]; michael@0: nextIndex++; michael@0: } michael@0: } michael@0: michael@0: PR_ASSERT(retVal == nEvents); michael@0: /* swap */ michael@0: tmp = pds; michael@0: pds = other_pds; michael@0: other_pds = tmp; michael@0: npds = nextIndex; michael@0: i += nEvents; michael@0: } michael@0: PR_DestroySocketPollFd(socket_poll_fd); michael@0: michael@0: printf("All tests finished\n"); michael@0: PR_Cleanup(); michael@0: return 0; michael@0: } michael@0: michael@0: michael@0: #endif /* ifdef WINCE */