nonblock.c (6074B)
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 #include "nspr.h" 7 #include "prio.h" 8 #include "prerror.h" 9 #include "prlog.h" 10 #include "prprf.h" 11 #include "prnetdb.h" 12 #include "plerror.h" 13 #include "obsolete/probslet.h" 14 15 #include <stdio.h> 16 #include <string.h> 17 #include <stdlib.h> 18 19 #define NUMBER_ROUNDS 5 20 21 #define UNIT_TIME 100 /* unit time in milliseconds */ 22 #define CHUNK_SIZE 10 23 #undef USE_PR_SELECT /* If defined, we use PR_Select. \ 24 * If not defined, use PR_Poll instead. */ 25 26 #if defined(USE_PR_SELECT) 27 # include "pprio.h" 28 #endif 29 30 static void PR_CALLBACK clientThreadFunc(void* arg) { 31 PRUintn port = (PRUintn)arg; 32 PRFileDesc* sock; 33 PRNetAddr addr; 34 char buf[CHUNK_SIZE]; 35 int i; 36 PRIntervalTime unitTime = PR_MillisecondsToInterval(UNIT_TIME); 37 PRSocketOptionData optval; 38 PRStatus retVal; 39 PRInt32 nBytes; 40 41 /* Initialize the buffer so that Purify won't complain */ 42 memset(buf, 0, sizeof(buf)); 43 44 addr.inet.family = PR_AF_INET; 45 addr.inet.port = PR_htons((PRUint16)port); 46 addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); 47 PR_snprintf(buf, sizeof(buf), "%hu", addr.inet.ip); 48 49 /* time 1 */ 50 PR_Sleep(unitTime); 51 sock = PR_NewTCPSocket(); 52 optval.option = PR_SockOpt_Nonblocking; 53 optval.value.non_blocking = PR_TRUE; 54 PR_SetSocketOption(sock, &optval); 55 retVal = PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT); 56 if (retVal == PR_FAILURE && PR_GetError() == PR_IN_PROGRESS_ERROR) { 57 #if !defined(USE_PR_SELECT) 58 PRPollDesc pd; 59 PRInt32 n; 60 fprintf(stderr, "connect: EWOULDBLOCK, good\n"); 61 pd.fd = sock; 62 pd.in_flags = PR_POLL_WRITE; 63 n = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); 64 PR_ASSERT(n == 1); 65 PR_ASSERT(pd.out_flags == PR_POLL_WRITE); 66 #else 67 PR_fd_set writeSet; 68 PRInt32 n; 69 fprintf(stderr, "connect: EWOULDBLOCK, good\n"); 70 PR_FD_ZERO(&writeSet); 71 PR_FD_SET(sock, &writeSet); 72 n = PR_Select(0, NULL, &writeSet, NULL, PR_INTERVAL_NO_TIMEOUT); 73 PR_ASSERT(n == 1); 74 PR_ASSERT(PR_FD_ISSET(sock, &writeSet)); 75 #endif 76 } 77 printf("client connected\n"); 78 fflush(stdout); 79 80 /* time 4, 7, 11, etc. */ 81 for (i = 0; i < NUMBER_ROUNDS; i++) { 82 PR_Sleep(3 * unitTime); 83 nBytes = PR_Write(sock, buf, sizeof(buf)); 84 if (nBytes == -1) { 85 if (PR_GetError() == PR_WOULD_BLOCK_ERROR) { 86 fprintf(stderr, "write: EWOULDBLOCK\n"); 87 exit(1); 88 } else { 89 fprintf(stderr, "write: failed\n"); 90 } 91 } 92 printf("client sent %d bytes\n", nBytes); 93 fflush(stdout); 94 } 95 96 PR_Close(sock); 97 } 98 99 static PRIntn PR_CALLBACK RealMain(PRIntn argc, char** argv) { 100 PRFileDesc *listenSock, *sock; 101 PRUint16 listenPort; 102 PRNetAddr addr; 103 char buf[CHUNK_SIZE]; 104 PRThread* clientThread; 105 PRInt32 retVal; 106 PRSocketOptionData optval; 107 PRIntn i; 108 PRIntervalTime unitTime = PR_MillisecondsToInterval(UNIT_TIME); 109 110 /* Create a listening socket */ 111 if ((listenSock = PR_NewTCPSocket()) == NULL) { 112 fprintf(stderr, "Can't create a new TCP socket\n"); 113 exit(1); 114 } 115 addr.inet.family = PR_AF_INET; 116 addr.inet.ip = PR_htonl(PR_INADDR_ANY); 117 addr.inet.port = PR_htons(0); 118 if (PR_Bind(listenSock, &addr) == PR_FAILURE) { 119 fprintf(stderr, "Can't bind socket\n"); 120 exit(1); 121 } 122 if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) { 123 fprintf(stderr, "PR_GetSockName failed\n"); 124 exit(1); 125 } 126 listenPort = PR_ntohs(addr.inet.port); 127 if (PR_Listen(listenSock, 5) == PR_FAILURE) { 128 fprintf(stderr, "Can't listen on a socket\n"); 129 exit(1); 130 } 131 132 PR_snprintf(buf, sizeof(buf), 133 "The server thread is listening on port %hu\n\n", listenPort); 134 printf("%s", buf); 135 136 clientThread = PR_CreateThread(PR_USER_THREAD, clientThreadFunc, 137 (void*)listenPort, PR_PRIORITY_NORMAL, 138 PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0); 139 if (clientThread == NULL) { 140 fprintf(stderr, "can't create thread\n"); 141 exit(1); 142 } 143 144 printf("client thread created.\n"); 145 146 optval.option = PR_SockOpt_Nonblocking; 147 optval.value.non_blocking = PR_TRUE; 148 PR_SetSocketOption(listenSock, &optval); 149 /* time 0 */ 150 sock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); 151 if (sock != NULL || PR_GetError() != PR_WOULD_BLOCK_ERROR) { 152 PL_PrintError("First Accept\n"); 153 fprintf(stderr, "First PR_Accept() xxx\n"); 154 exit(1); 155 } 156 printf("accept: EWOULDBLOCK, good\n"); 157 fflush(stdout); 158 /* time 2 */ 159 PR_Sleep(2 * unitTime); 160 sock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); 161 if (sock == NULL) { 162 PL_PrintError("Second Accept\n"); 163 fprintf(stderr, "Second PR_Accept() failed: (%d, %d)\n", PR_GetError(), 164 PR_GetOSError()); 165 exit(1); 166 } 167 printf("accept: succeeded, good\n"); 168 fflush(stdout); 169 PR_Close(listenSock); 170 171 PR_SetSocketOption(sock, &optval); 172 173 /* time 3, 5, 6, 8, etc. */ 174 for (i = 0; i < NUMBER_ROUNDS; i++) { 175 PR_Sleep(unitTime); 176 retVal = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT); 177 if (retVal != -1 || PR_GetError() != PR_WOULD_BLOCK_ERROR) { 178 PL_PrintError("First Receive:\n"); 179 fprintf(stderr, "First PR_Recv: retVal: %ld, Error: %ld\n", retVal, 180 PR_GetError()); 181 exit(1); 182 } 183 printf("read: EWOULDBLOCK, good\n"); 184 fflush(stdout); 185 PR_Sleep(2 * unitTime); 186 retVal = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT); 187 if (retVal != CHUNK_SIZE) { 188 PL_PrintError("Second Receive:\n"); 189 fprintf(stderr, "Second PR_Recv: retVal: %ld, Error: %ld\n", retVal, 190 PR_GetError()); 191 exit(1); 192 } 193 printf("read: %d bytes, good\n", retVal); 194 fflush(stdout); 195 } 196 PR_Close(sock); 197 198 printf("All tests finished\n"); 199 printf("PASS\n"); 200 return 0; 201 } 202 203 int main(int argc, char** argv) { 204 PRIntn rv; 205 206 rv = PR_Initialize(RealMain, argc, argv, 0); 207 return rv; 208 } /* main */