Back to index

lightning-sunbird  0.9+nobinonly
nonblock.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nspr.h"
00039 #include "prio.h"
00040 #include "prerror.h"
00041 #include "prlog.h"
00042 #include "prprf.h"
00043 #include "prnetdb.h"
00044 #include "plerror.h"
00045 #ifndef XP_MAC
00046 #include "obsolete/probslet.h"
00047 #else
00048 #include "probslet.h"
00049 #endif
00050 
00051 #include <stdio.h>
00052 #include <string.h>
00053 #include <stdlib.h>
00054 
00055 #define NUMBER_ROUNDS 5
00056 
00057 #if defined(WIN16)
00058 /*
00059 ** Make win16 unit_time interval 300 milliseconds, others get 100
00060 */
00061 #define UNIT_TIME  200       /* unit time in milliseconds */
00062 #else
00063 #define UNIT_TIME  100       /* unit time in milliseconds */
00064 #endif
00065 #define CHUNK_SIZE 10
00066 #undef USE_PR_SELECT         /* If defined, we use PR_Select.
00067                               * If not defined, use PR_Poll instead. */
00068 
00069 #if defined(USE_PR_SELECT)
00070 #include "pprio.h"
00071 #endif
00072 
00073 #ifdef XP_MAC
00074 int fprintf(FILE *stream, const char *fmt, ...)
00075 {
00076 PR_LogPrint(fmt);
00077 return 0;
00078 }
00079 #define printf PR_LogPrint
00080 extern void SetupMacPrintfLog(char *logFile);
00081 #endif
00082 
00083 static void PR_CALLBACK
00084 clientThreadFunc(void *arg)
00085 {
00086     PRUintn port = (PRUintn)arg;
00087     PRFileDesc *sock;
00088     PRNetAddr addr;
00089     char buf[CHUNK_SIZE];
00090     int i;
00091     PRIntervalTime unitTime = PR_MillisecondsToInterval(UNIT_TIME);
00092     PRSocketOptionData optval;
00093     PRStatus retVal;
00094     PRInt32 nBytes;
00095 
00096     /* Initialize the buffer so that Purify won't complain */
00097     memset(buf, 0, sizeof(buf));
00098 
00099     addr.inet.family = PR_AF_INET;
00100     addr.inet.port = PR_htons((PRUint16)port);
00101     addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
00102     PR_snprintf(buf, sizeof(buf), "%hu", addr.inet.ip);
00103 
00104     /* time 1 */
00105     PR_Sleep(unitTime);
00106     sock = PR_NewTCPSocket();
00107     optval.option = PR_SockOpt_Nonblocking;
00108     optval.value.non_blocking = PR_TRUE;
00109     PR_SetSocketOption(sock, &optval);
00110     retVal = PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT);
00111     if (retVal == PR_FAILURE && PR_GetError() == PR_IN_PROGRESS_ERROR) {
00112 #if !defined(USE_PR_SELECT)
00113        PRPollDesc pd;
00114        PRInt32 n;
00115        fprintf(stderr, "connect: EWOULDBLOCK, good\n");
00116        pd.fd = sock;
00117        pd.in_flags = PR_POLL_WRITE;
00118        n = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
00119        PR_ASSERT(n == 1);
00120         PR_ASSERT(pd.out_flags == PR_POLL_WRITE);
00121 #else
00122         PR_fd_set writeSet;
00123         PRInt32 n;
00124         fprintf(stderr, "connect: EWOULDBLOCK, good\n");
00125         PR_FD_ZERO(&writeSet);
00126         PR_FD_SET(sock, &writeSet);
00127         n = PR_Select(0, NULL, &writeSet, NULL, PR_INTERVAL_NO_TIMEOUT);
00128         PR_ASSERT(n == 1);
00129         PR_ASSERT(PR_FD_ISSET(sock, &writeSet));
00130 #endif
00131     }
00132     printf("client connected\n");
00133     fflush(stdout);
00134 
00135     /* time 4, 7, 11, etc. */
00136     for (i = 0; i < NUMBER_ROUNDS; i++) {
00137         PR_Sleep(3 * unitTime);
00138        nBytes = PR_Write(sock, buf, sizeof(buf));
00139            if (nBytes == -1) {
00140            if (PR_GetError() == PR_WOULD_BLOCK_ERROR) {
00141               fprintf(stderr, "write: EWOULDBLOCK\n");
00142               exit(1);
00143             } else {
00144               fprintf(stderr, "write: failed\n");
00145             }
00146        }
00147        printf("client sent %d bytes\n", nBytes);
00148        fflush(stdout);
00149     }
00150 
00151     PR_Close(sock);
00152 }
00153 
00154 static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv )
00155 {
00156     PRFileDesc *listenSock, *sock;
00157     PRUint16 listenPort;
00158     PRNetAddr addr;
00159     char buf[CHUNK_SIZE];
00160     PRThread *clientThread;
00161     PRInt32 retVal;
00162     PRSocketOptionData optval;
00163     PRIntn i;
00164     PRIntervalTime unitTime = PR_MillisecondsToInterval(UNIT_TIME);
00165 
00166 #ifdef XP_MAC
00167        SetupMacPrintfLog("nonblock.log");
00168 #endif
00169 
00170     /* Create a listening socket */
00171     if ((listenSock = PR_NewTCPSocket()) == NULL) {
00172        fprintf(stderr, "Can't create a new TCP socket\n");
00173        exit(1);
00174     }
00175     addr.inet.family = PR_AF_INET;
00176     addr.inet.ip = PR_htonl(PR_INADDR_ANY);
00177     addr.inet.port = PR_htons(0);
00178     if (PR_Bind(listenSock, &addr) == PR_FAILURE) {
00179        fprintf(stderr, "Can't bind socket\n");
00180        exit(1);
00181     }
00182     if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) {
00183        fprintf(stderr, "PR_GetSockName failed\n");
00184        exit(1);
00185     }
00186     listenPort = PR_ntohs(addr.inet.port);
00187     if (PR_Listen(listenSock, 5) == PR_FAILURE) {
00188        fprintf(stderr, "Can't listen on a socket\n");
00189        exit(1);
00190     }
00191 
00192     PR_snprintf(buf, sizeof(buf),
00193            "The server thread is listening on port %hu\n\n",
00194            listenPort);
00195     printf("%s", buf);
00196 
00197     clientThread = PR_CreateThread(PR_USER_THREAD,
00198            clientThreadFunc, (void *) listenPort,
00199            PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
00200            PR_UNJOINABLE_THREAD, 0);
00201     if (clientThread == NULL) {
00202        fprintf(stderr, "can't create thread\n");
00203        exit(1);
00204     }
00205 
00206     printf("client thread created.\n");
00207 
00208     optval.option = PR_SockOpt_Nonblocking;
00209     optval.value.non_blocking = PR_TRUE;
00210     PR_SetSocketOption(listenSock, &optval);
00211     /* time 0 */
00212     sock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT);
00213     if (sock != NULL || PR_GetError() != PR_WOULD_BLOCK_ERROR) {
00214         PL_PrintError("First Accept\n");
00215         fprintf(stderr, "First PR_Accept() xxx\n" );
00216                   exit(1);
00217     }
00218     printf("accept: EWOULDBLOCK, good\n");
00219     fflush(stdout);
00220     /* time 2 */
00221     PR_Sleep(2 * unitTime);
00222     sock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT);
00223     if (sock == NULL) {
00224         PL_PrintError("Second Accept\n");
00225         fprintf(stderr, "Second PR_Accept() failed: (%d, %d)\n",
00226                 PR_GetError(), PR_GetOSError());
00227                   exit(1);
00228     }
00229     printf("accept: succeeded, good\n");
00230     fflush(stdout);
00231     PR_Close(listenSock);
00232 
00233     PR_SetSocketOption(sock, &optval);
00234 
00235     /* time 3, 5, 6, 8, etc. */
00236     for (i = 0; i < NUMBER_ROUNDS; i++) {
00237        PR_Sleep(unitTime);
00238        retVal = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT);
00239        if (retVal != -1 || PR_GetError() != PR_WOULD_BLOCK_ERROR) {
00240         PL_PrintError("First Receive:\n");
00241            fprintf(stderr, "First PR_Recv: retVal: %ld, Error: %ld\n",
00242             retVal, PR_GetError());
00243            exit(1);
00244         }
00245        printf("read: EWOULDBLOCK, good\n");
00246        fflush(stdout);
00247        PR_Sleep(2 * unitTime);
00248        retVal = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT);
00249        if (retVal != CHUNK_SIZE) {
00250         PL_PrintError("Second Receive:\n");
00251            fprintf(stderr, "Second PR_Recv: retVal: %ld, Error: %ld\n", 
00252             retVal, PR_GetError());
00253            exit(1);
00254         }
00255        printf("read: %d bytes, good\n", retVal);
00256        fflush(stdout);
00257     }
00258     PR_Close(sock);
00259 
00260     printf("All tests finished\n");
00261     printf("PASS\n");
00262     return 0;
00263 }
00264 
00265 PRIntn main(PRIntn argc, char *argv[])
00266 {
00267     PRIntn rv;
00268     
00269     PR_STDIO_INIT();
00270     rv = PR_Initialize(RealMain, argc, argv, 0);
00271     return rv;
00272 }  /* main */
00273