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: #include "nspr.h" michael@0: #include "prio.h" michael@0: #include "prerror.h" michael@0: #include "prlog.h" michael@0: #include "prprf.h" michael@0: #include "prnetdb.h" michael@0: #include "plerror.h" michael@0: #include "obsolete/probslet.h" michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #define NUMBER_ROUNDS 5 michael@0: michael@0: #if defined(WIN16) michael@0: /* michael@0: ** Make win16 unit_time interval 300 milliseconds, others get 100 michael@0: */ michael@0: #define UNIT_TIME 200 /* unit time in milliseconds */ michael@0: #elif defined(SYMBIAN) michael@0: #define UNIT_TIME 5000 /* unit time in milliseconds */ michael@0: #else michael@0: #define UNIT_TIME 100 /* unit time in milliseconds */ michael@0: #endif michael@0: #define CHUNK_SIZE 10 michael@0: #undef USE_PR_SELECT /* If defined, we use PR_Select. michael@0: * If not defined, use PR_Poll instead. */ michael@0: michael@0: #if defined(USE_PR_SELECT) michael@0: #include "pprio.h" michael@0: #endif michael@0: michael@0: static void PR_CALLBACK michael@0: clientThreadFunc(void *arg) michael@0: { michael@0: PRUintn port = (PRUintn)arg; michael@0: PRFileDesc *sock; michael@0: PRNetAddr addr; michael@0: char buf[CHUNK_SIZE]; michael@0: int i; michael@0: PRIntervalTime unitTime = PR_MillisecondsToInterval(UNIT_TIME); michael@0: PRSocketOptionData optval; michael@0: PRStatus retVal; michael@0: PRInt32 nBytes; michael@0: michael@0: /* Initialize the buffer so that Purify won't complain */ michael@0: memset(buf, 0, sizeof(buf)); michael@0: michael@0: addr.inet.family = PR_AF_INET; michael@0: addr.inet.port = PR_htons((PRUint16)port); michael@0: addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); michael@0: PR_snprintf(buf, sizeof(buf), "%hu", addr.inet.ip); michael@0: michael@0: /* time 1 */ michael@0: PR_Sleep(unitTime); michael@0: sock = PR_NewTCPSocket(); michael@0: optval.option = PR_SockOpt_Nonblocking; michael@0: optval.value.non_blocking = PR_TRUE; michael@0: PR_SetSocketOption(sock, &optval); michael@0: retVal = PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT); michael@0: if (retVal == PR_FAILURE && PR_GetError() == PR_IN_PROGRESS_ERROR) { michael@0: #if !defined(USE_PR_SELECT) michael@0: PRPollDesc pd; michael@0: PRInt32 n; michael@0: fprintf(stderr, "connect: EWOULDBLOCK, good\n"); michael@0: pd.fd = sock; michael@0: pd.in_flags = PR_POLL_WRITE; michael@0: n = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); michael@0: PR_ASSERT(n == 1); michael@0: PR_ASSERT(pd.out_flags == PR_POLL_WRITE); michael@0: #else michael@0: PR_fd_set writeSet; michael@0: PRInt32 n; michael@0: fprintf(stderr, "connect: EWOULDBLOCK, good\n"); michael@0: PR_FD_ZERO(&writeSet); michael@0: PR_FD_SET(sock, &writeSet); michael@0: n = PR_Select(0, NULL, &writeSet, NULL, PR_INTERVAL_NO_TIMEOUT); michael@0: PR_ASSERT(n == 1); michael@0: PR_ASSERT(PR_FD_ISSET(sock, &writeSet)); michael@0: #endif michael@0: } michael@0: printf("client connected\n"); michael@0: fflush(stdout); michael@0: michael@0: /* time 4, 7, 11, etc. */ michael@0: for (i = 0; i < NUMBER_ROUNDS; i++) { michael@0: PR_Sleep(3 * unitTime); michael@0: nBytes = PR_Write(sock, buf, sizeof(buf)); michael@0: if (nBytes == -1) { michael@0: if (PR_GetError() == PR_WOULD_BLOCK_ERROR) { michael@0: fprintf(stderr, "write: EWOULDBLOCK\n"); michael@0: exit(1); michael@0: } else { michael@0: fprintf(stderr, "write: failed\n"); michael@0: } michael@0: } michael@0: printf("client sent %d bytes\n", nBytes); michael@0: fflush(stdout); michael@0: } michael@0: michael@0: PR_Close(sock); michael@0: } michael@0: michael@0: static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv ) michael@0: { michael@0: PRFileDesc *listenSock, *sock; michael@0: PRUint16 listenPort; michael@0: PRNetAddr addr; michael@0: char buf[CHUNK_SIZE]; michael@0: PRThread *clientThread; michael@0: PRInt32 retVal; michael@0: PRSocketOptionData optval; michael@0: PRIntn i; michael@0: PRIntervalTime unitTime = PR_MillisecondsToInterval(UNIT_TIME); michael@0: michael@0: /* Create a listening socket */ michael@0: if ((listenSock = 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(listenSock, &addr) == PR_FAILURE) { michael@0: fprintf(stderr, "Can't bind socket\n"); michael@0: exit(1); michael@0: } michael@0: if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) { michael@0: fprintf(stderr, "PR_GetSockName failed\n"); michael@0: exit(1); michael@0: } michael@0: listenPort = PR_ntohs(addr.inet.port); michael@0: if (PR_Listen(listenSock, 5) == PR_FAILURE) { michael@0: fprintf(stderr, "Can't listen on a socket\n"); michael@0: exit(1); michael@0: } michael@0: michael@0: PR_snprintf(buf, sizeof(buf), michael@0: "The server thread is listening on port %hu\n\n", michael@0: listenPort); michael@0: printf("%s", buf); michael@0: michael@0: clientThread = PR_CreateThread(PR_USER_THREAD, michael@0: clientThreadFunc, (void *) listenPort, 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: printf("client thread created.\n"); michael@0: michael@0: optval.option = PR_SockOpt_Nonblocking; michael@0: optval.value.non_blocking = PR_TRUE; michael@0: PR_SetSocketOption(listenSock, &optval); michael@0: /* time 0 */ michael@0: sock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); michael@0: if (sock != NULL || PR_GetError() != PR_WOULD_BLOCK_ERROR) { michael@0: PL_PrintError("First Accept\n"); michael@0: fprintf(stderr, "First PR_Accept() xxx\n" ); michael@0: exit(1); michael@0: } michael@0: printf("accept: EWOULDBLOCK, good\n"); michael@0: fflush(stdout); michael@0: /* time 2 */ michael@0: PR_Sleep(2 * unitTime); michael@0: sock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); michael@0: if (sock == NULL) { michael@0: PL_PrintError("Second Accept\n"); michael@0: fprintf(stderr, "Second PR_Accept() failed: (%d, %d)\n", michael@0: PR_GetError(), PR_GetOSError()); michael@0: exit(1); michael@0: } michael@0: printf("accept: succeeded, good\n"); michael@0: fflush(stdout); michael@0: PR_Close(listenSock); michael@0: michael@0: PR_SetSocketOption(sock, &optval); michael@0: michael@0: /* time 3, 5, 6, 8, etc. */ michael@0: for (i = 0; i < NUMBER_ROUNDS; i++) { michael@0: PR_Sleep(unitTime); michael@0: retVal = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT); michael@0: if (retVal != -1 || PR_GetError() != PR_WOULD_BLOCK_ERROR) { michael@0: PL_PrintError("First Receive:\n"); michael@0: fprintf(stderr, "First PR_Recv: retVal: %ld, Error: %ld\n", michael@0: retVal, PR_GetError()); michael@0: exit(1); michael@0: } michael@0: printf("read: EWOULDBLOCK, good\n"); michael@0: fflush(stdout); michael@0: PR_Sleep(2 * unitTime); michael@0: retVal = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT); michael@0: if (retVal != CHUNK_SIZE) { michael@0: PL_PrintError("Second Receive:\n"); michael@0: fprintf(stderr, "Second PR_Recv: retVal: %ld, Error: %ld\n", michael@0: retVal, PR_GetError()); michael@0: exit(1); michael@0: } michael@0: printf("read: %d bytes, good\n", retVal); michael@0: fflush(stdout); michael@0: } michael@0: PR_Close(sock); michael@0: michael@0: printf("All tests finished\n"); michael@0: printf("PASS\n"); michael@0: return 0; michael@0: } michael@0: michael@0: int main(int argc, char **argv) michael@0: { michael@0: PRIntn rv; michael@0: michael@0: PR_STDIO_INIT(); michael@0: rv = PR_Initialize(RealMain, argc, argv, 0); michael@0: return rv; michael@0: } /* main */ michael@0: