Back to index

lightning-sunbird  0.9+nobinonly
prselect.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 /***********************************************************************
00039 **  1997 - Netscape Communications Corporation
00040 **
00041 ** Name: prselect_err.c
00042 **
00043 ** Description: tests PR_Select with sockets Error condition functions.
00044 **
00045 ** Modification History:
00046 ** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
00047 **              The debug mode will print all of the printfs associated with this test.
00048 **                    The regress mode will be the default mode. Since the regress tool limits
00049 **           the output to a one line status:PASS or FAIL,all of the printf statements
00050 **                    have been handled with an if (debug_mode) statement. 
00051 ***********************************************************************/
00052 
00053 /***********************************************************************
00054 ** Includes
00055 ***********************************************************************/
00056 /* Used to get the command line option */
00057 #include "plgetopt.h"
00058 #include "prttools.h"
00059 
00060 
00061 #include "prinit.h"
00062 #include "prio.h"
00063 #include "prlog.h"
00064 #include "prprf.h"
00065 #include "prerror.h"
00066 #include "prnetdb.h"
00067 
00068 #include <stdio.h>
00069 #include <string.h>
00070 #include <stdlib.h>
00071 
00072 /***********************************************************************
00073 ** PRIVATE FUNCTION:    Test_Result
00074 ** DESCRIPTION: Used in conjunction with the regress tool, prints out the
00075 **                          status of the test case.
00076 ** INPUTS:      PASS/FAIL
00077 ** OUTPUTS:     None
00078 ** RETURN:      None
00079 ** SIDE EFFECTS:
00080 **      
00081 ** RESTRICTIONS:
00082 **      None
00083 ** MEMORY:      NA
00084 ** ALGORITHM:   Determine what the status is and print accordingly.
00085 **      
00086 ***********************************************************************/
00087 
00088 
00089 static Test_Result (int result)
00090 {
00091        if (result == PASS)
00092               printf ("PASS\n");
00093        else
00094               printf ("FAIL\n");
00095 }
00096 
00097 static void
00098 clientThreadFunc(void *arg)
00099 {
00100     PRUint16 port = (PRUint16) arg;
00101     PRFileDesc *sock;
00102     PRNetAddr addr;
00103     char buf[128];
00104     int i;
00105 
00106     addr.inet.family = AF_INET;
00107     addr.inet.port = PR_htons(port);
00108     addr.inet.ip = PR_htonl(INADDR_LOOPBACK);
00109     PR_snprintf(buf, sizeof(buf), "%hu", port);
00110 
00111     for (i = 0; i < 5; i++) {
00112        sock = PR_NewTCPSocket();
00113         PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT);
00114        PR_Write(sock, buf, sizeof(buf));
00115        PR_Close(sock);
00116     }
00117 }
00118 
00119 int main(int argc, char **argv)
00120 {
00121     PRFileDesc *listenSock1, *listenSock2;
00122     PRFileDesc *badFD;
00123     PRFileDesc *fds0[10], *fds1[10], **fds, **other_fds;
00124     PRIntn nfds;
00125     PRUint16 listenPort1, listenPort2;
00126     PRNetAddr addr;
00127     PR_fd_set readFdSet;
00128     char buf[128];
00129     PRThread *clientThread;
00130     PRInt32 retVal;
00131     PRIntn i, j;
00132 
00133        /* The command line argument: -d is used to determine if the test is being run
00134        in debug mode. The regress tool requires only one line output:PASS or FAIL.
00135        All of the printfs associated with this test has been handled with a if (debug_mode)
00136        test.
00137        Usage: test_name -d
00138        */
00139        PLOptStatus os;
00140        PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
00141        while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
00142     {
00143               if (PL_OPT_BAD == os) continue;
00144         switch (opt->option)
00145         {
00146         case 'd':  /* debug mode */
00147                      debug_mode = 1;
00148             break;
00149          default:
00150             break;
00151         }
00152     }
00153        PL_DestroyOptState(opt);
00154 
00155  /* main test */
00156        
00157     PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
00158     PR_STDIO_INIT();
00159 
00160     if (debug_mode) {
00161               printf("This program tests PR_Select with sockets.  Timeout, error\n");
00162               printf("reporting, and normal operation are tested.\n\n");
00163        }
00164 
00165     /* Create two listening sockets */
00166     if ((listenSock1 = PR_NewTCPSocket()) == NULL) {
00167        fprintf(stderr, "Can't create a new TCP socket\n");
00168        if (!debug_mode) Test_Result(FAIL);
00169        exit(1);
00170     }
00171     addr.inet.family = AF_INET;
00172     addr.inet.ip = PR_htonl(INADDR_ANY);
00173     addr.inet.port = PR_htons(0);
00174     if (PR_Bind(listenSock1, &addr) == PR_FAILURE) {
00175        fprintf(stderr, "Can't bind socket\n");
00176        if (!debug_mode) Test_Result(FAIL);
00177        exit(1);
00178     }
00179     if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) {
00180        fprintf(stderr, "PR_GetSockName failed\n");
00181        if (!debug_mode) Test_Result(FAIL);
00182        exit(1);
00183     }
00184     listenPort1 = PR_ntohs(addr.inet.port);
00185     if (PR_Listen(listenSock1, 5) == PR_FAILURE) {
00186        fprintf(stderr, "Can't listen on a socket\n");
00187        if (!debug_mode) Test_Result(FAIL);
00188        exit(1);
00189     }
00190 
00191     if ((listenSock2  = PR_NewTCPSocket()) == NULL) {
00192        fprintf(stderr, "Can't create a new TCP socket\n");
00193        if (!debug_mode) Test_Result(FAIL);
00194        exit(1);
00195     }
00196     addr.inet.family = AF_INET;
00197     addr.inet.ip = PR_htonl(INADDR_ANY);
00198     addr.inet.port = PR_htons(0);
00199     if (PR_Bind(listenSock2, &addr) == PR_FAILURE) {
00200        fprintf(stderr, "Can't bind socket\n");
00201        if (!debug_mode) Test_Result(FAIL);
00202        exit(1);
00203     }
00204     if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) {
00205        fprintf(stderr, "PR_GetSockName failed\n");
00206        if (!debug_mode) Test_Result(FAIL);
00207        exit(1);
00208     }
00209     listenPort2 = PR_ntohs(addr.inet.port);
00210     if (PR_Listen(listenSock2, 5) == PR_FAILURE) {
00211        fprintf(stderr, "Can't listen on a socket\n");
00212        if (!debug_mode) Test_Result(FAIL);
00213        exit(1);
00214     }
00215     PR_snprintf(buf, sizeof(buf),
00216            "The server thread is listening on ports %hu and %hu\n\n",
00217            listenPort1, listenPort2);
00218     printf("%s", buf);
00219 
00220     /* Set up the fd set */
00221     PR_FD_ZERO(&readFdSet);
00222     PR_FD_SET(listenSock1, &readFdSet);
00223     PR_FD_SET(listenSock2, &readFdSet);
00224 
00225     /* Testing timeout */
00226     if (debug_mode) printf("PR_Select should time out in 5 seconds\n");
00227     retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL,
00228            PR_SecondsToInterval(5));
00229     if (retVal != 0) {
00230        PR_snprintf(buf, sizeof(buf),
00231               "PR_Select should time out and return 0, but it returns %ld\n",
00232               retVal);
00233        fprintf(stderr, "%s", buf);
00234        if (retVal == -1) {
00235            fprintf(stderr, "Error %d, oserror %d\n", PR_GetError(),
00236                   PR_GetOSError());
00237                      if (!debug_mode) Test_Result(FAIL);
00238        }
00239        exit(1);
00240     }
00241     if (debug_mode) printf("PR_Select timed out.  Test passed.\n\n");
00242        else Test_Result(PASS);
00243 
00244     /* Testing bad fd */
00245     printf("PR_Select should detect a bad file descriptor\n");
00246     if ((badFD = PR_NewTCPSocket()) == NULL) {
00247        fprintf(stderr, "Can't create a TCP socket\n");
00248        exit(1);
00249     }
00250 
00251     PR_FD_SET(listenSock1, &readFdSet);
00252     PR_FD_SET(listenSock2, &readFdSet);
00253     PR_FD_SET(badFD, &readFdSet);
00254     PR_Close(badFD);  /* make the fd bad */
00255     retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL,
00256            PR_INTERVAL_NO_TIMEOUT);
00257     if (retVal != -1 || PR_GetError() != PR_BAD_DESCRIPTOR_ERROR) {
00258        fprintf(stderr, "Failed to detect the bad fd: "
00259               "PR_Select returns %d\n", retVal);
00260        if (retVal == -1) {
00261            fprintf(stderr, "Error %d, oserror %d\n", PR_GetError(),
00262                   PR_GetOSError());
00263        }
00264        exit(1);
00265     }
00266     printf("PR_Select detected a bad fd.  Test passed.\n\n");
00267     PR_FD_CLR(badFD, &readFdSet);
00268 
00269     clientThread = PR_CreateThread(PR_USER_THREAD,
00270            clientThreadFunc, (void *) listenPort1,
00271            PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
00272            PR_UNJOINABLE_THREAD, 0);
00273     if (clientThread == NULL) {
00274        fprintf(stderr, "can't create thread\n");
00275        exit(1);
00276     }
00277 
00278     clientThread = PR_CreateThread(PR_USER_THREAD,
00279            clientThreadFunc, (void *) listenPort2,
00280            PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
00281            PR_UNJOINABLE_THREAD, 0);
00282     if (clientThread == NULL) {
00283        fprintf(stderr, "can't create thread\n");
00284        exit(1);
00285     }
00286 
00287     printf("Two client threads are created.  Each of them will\n");
00288     printf("send data to one of the two ports the server is listening on.\n");
00289     printf("The data they send is the port number.  Each of them send\n");
00290     printf("the data five times, so you should see ten lines below,\n");
00291     printf("interleaved in an arbitrary order.\n");
00292 
00293     /* set up the fd array */
00294     fds = fds0;
00295     other_fds = fds1;
00296     fds[0] = listenSock1;
00297     fds[1] = listenSock2;
00298     nfds = 2;
00299     PR_FD_SET(listenSock1, &readFdSet);
00300     PR_FD_SET(listenSock2, &readFdSet);
00301 
00302     /* 20 events total */
00303     i = 0;
00304     while (i < 20) {
00305        PRFileDesc **tmp;
00306        int nextIndex;
00307        int nEvents = 0;
00308 
00309        retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL,
00310               PR_INTERVAL_NO_TIMEOUT);
00311        PR_ASSERT(retVal != 0);  /* no timeout */
00312        if (retVal == -1) {
00313            fprintf(stderr, "PR_Select failed (%d, %d)\n", PR_GetError(),
00314                   PR_GetOSError());
00315            exit(1);
00316        }
00317 
00318        nextIndex = 2;
00319        /* the two listening sockets */
00320        for (j = 0; j < 2; j++) {
00321            other_fds[j] = fds[j];
00322            if (PR_FD_ISSET(fds[j], &readFdSet)) {
00323               PRFileDesc *sock;
00324 
00325               nEvents++;
00326               sock = PR_Accept(fds[j], NULL, PR_INTERVAL_NO_TIMEOUT);
00327               if (sock == NULL) {
00328                   fprintf(stderr, "PR_Accept() failed\n");
00329                   exit(1);
00330               }
00331               other_fds[nextIndex] = sock;
00332               PR_FD_SET(sock, &readFdSet);
00333               nextIndex++;
00334            }
00335            PR_FD_SET(fds[j], &readFdSet);
00336        }
00337 
00338        for (j = 2; j < nfds; j++) {
00339            if (PR_FD_ISSET(fds[j], &readFdSet)) {
00340               PRInt32 nBytes;
00341 
00342               PR_FD_CLR(fds[j], &readFdSet);
00343               nEvents++;
00344               nBytes = PR_Read(fds[j], buf, sizeof(buf));
00345               if (nBytes == -1) {
00346                   fprintf(stderr, "PR_Read() failed\n");
00347                   exit(1);
00348               }
00349               /* Just to be safe */
00350               buf[127] = '\0';
00351               PR_Close(fds[j]);
00352               printf("The server received \"%s\" from a client\n", buf);
00353            } else {
00354               PR_FD_SET(fds[j], &readFdSet);
00355               other_fds[nextIndex] = fds[j];
00356               nextIndex++;
00357            }
00358        }
00359 
00360        PR_ASSERT(retVal == nEvents);
00361        /* swap */
00362        tmp = fds;
00363        fds = other_fds;
00364        other_fds = tmp;
00365        nfds = nextIndex;
00366        i += nEvents;
00367     }
00368 
00369     printf("All tests finished\n");
00370     PR_Cleanup();
00371     return 0;
00372 }