Exemplo n.º 1
0
SECStatus
ReadFileToBuffer(const char* basePath, const char* filename, char (&buf)[N])
{
  static_assert(N > 0, "input buffer too small for ReadFileToBuffer");
  if (snprintf(buf, N - 1, "%s/%s", basePath, filename) == 0) {
    PrintPRError("snprintf failed");
    return SECFailure;
  }
  UniquePRFileDesc fd(PR_OpenFile(buf, PR_RDONLY, 0));
  if (!fd) {
    PrintPRError("PR_Open failed");
    return SECFailure;
  }
  int32_t fileSize = PR_Available(fd.get());
  if (fileSize < 0) {
    PrintPRError("PR_Available failed");
    return SECFailure;
  }
  if (static_cast<size_t>(fileSize) > N - 1) {
    PR_fprintf(PR_STDERR, "file too large - not reading\n");
    return SECFailure;
  }
  int32_t bytesRead = PR_Read(fd.get(), buf, fileSize);
  if (bytesRead != fileSize) {
    PrintPRError("PR_Read failed");
    return SECFailure;
  }
  buf[bytesRead] = 0;
  return SECSuccess;
}
/* unsigned long available (); */
NS_IMETHODIMP nsMsgFileStream::Available(PRUint32 *aResult)
{
    if (!mFileDesc)
        return NS_BASE_STREAM_CLOSED;

    PRInt32 avail = PR_Available(mFileDesc);
    if (avail == -1)
        return NS_ErrorAccordingToNSPR();

    *aResult = avail;
    return NS_OK;
}
Exemplo n.º 3
0
NS_IMETHODIMP
nsFileInputStream::Available(PRUint32* aResult)
{
    if (!mFD) {
        return NS_BASE_STREAM_CLOSED;
    }

    PRInt32 avail = PR_Available(mFD);
    if (avail == -1) {
        return NS_ErrorAccordingToNSPR();
    }
    *aResult = avail;
    return NS_OK;
}
Exemplo n.º 4
0
    GMPErr Read(const nsCString& aRecordName,
                nsTArray<uint8_t>& aOutBytes) override
    {
        if (!IsOpen(aRecordName)) {
            return GMPClosedErr;
        }

        Record* record = nullptr;
        mRecords.Get(aRecordName, &record);
        MOZ_ASSERT(record && !!record->mFileDesc); // IsOpen() guarantees this.

        // Our error strategy is to report records with invalid contents as
        // containing 0 bytes. Zero length records are considered "deleted" by
        // the GMPStorage API.
        aOutBytes.SetLength(0);

        int32_t recordLength = 0;
        nsCString recordName;
        nsresult err = ReadRecordMetadata(record->mFileDesc,
                                          recordLength,
                                          recordName);
        if (NS_FAILED(err) || recordLength == 0) {
            // We failed to read the record metadata. Or the record is 0 length.
            // Treat damaged records as empty.
            // ReadRecordMetadata() could fail if the GMP opened a new record and
            // tried to read it before anything was written to it..
            return GMPNoErr;
        }

        if (!aRecordName.Equals(recordName)) {
            NS_WARNING("Record file contains some other record's contents!");
            return GMPRecordCorrupted;
        }

        // After calling ReadRecordMetadata, we should be ready to read the
        // record data.
        if (PR_Available(record->mFileDesc) != recordLength) {
            NS_WARNING("Record file length mismatch!");
            return GMPRecordCorrupted;
        }

        aOutBytes.SetLength(recordLength);
        int32_t bytesRead = PR_Read(record->mFileDesc, aOutBytes.Elements(), recordLength);
        return (bytesRead == recordLength) ? GMPNoErr : GMPRecordCorrupted;
    }
Exemplo n.º 5
0
/* push the contents of a file into the nt, one line per entry */
int nt_load(NameTable *nt, const char *filename)
{
    PRFileDesc *fd;

    fd = PR_Open(filename, PR_RDONLY, 0);
    if (!fd) return 0;

    while (PR_Available(fd) > 0) {
        char temp[4096], *s;
        if (PR_GetLine(fd, temp, sizeof(temp))) break;
        s = strdup(temp);
        if (!s) break;
        if (!nt_push(nt, s)) {
            free(s);
            break;
        }
    }
    PR_Close(fd);
    return nt->size;
}
Exemplo n.º 6
0
static nsresult
GetFileContents(nsIFile* aFile, nsACString& data)
{
  nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(aFile);
  NS_ENSURE_TRUE(localFile, NS_ERROR_FAILURE);

  PRFileDesc* fd;
  nsresult rv = localFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
  NS_ENSURE_SUCCESS(rv, rv);

  rv = NS_OK;
  PRInt32 filesize = PR_Available(fd);
  if (filesize <= 0) {
    rv = NS_ERROR_FILE_NOT_FOUND;
  }
  else {
    data.SetLength(filesize);
    if (PR_Read(fd, data.BeginWriting(), filesize) == -1) {
      rv = NS_ERROR_FAILURE;
    }
  }
  PR_Close(fd);
  return rv;
}
Exemplo n.º 7
0
/******************************************************************************
 *  Open
 *****************************************************************************/
nsresult
nsDiskCacheBlockFile::Open( nsILocalFile *  blockFile, PRUint32  blockSize)
{
    PRInt32   fileSize;

    mBlockSize = blockSize;
    
    // open the file - restricted to user, the data could be confidential
    nsresult rv = blockFile->OpenNSPRFileDesc(PR_RDWR | PR_CREATE_FILE, 00600, &mFD);
    if (NS_FAILED(rv))  return rv;  // unable to open or create file
    
    // allocate bit map buffer
    mBitMap = new PRUint32[kBitMapWords];
    if (!mBitMap) {
        rv = NS_ERROR_OUT_OF_MEMORY;
        goto error_exit;
    }
    
    // check if we just creating the file
    fileSize = PR_Available(mFD);
    if (fileSize < 0) {
        // XXX an error occurred. We could call PR_GetError(), but how would that help?
        rv = NS_ERROR_UNEXPECTED;
        goto error_exit;
    }
    if (fileSize == 0) {
        // initialize bit map and write it
        memset(mBitMap, 0, kBitMapBytes);
        PRInt32 bytesWritten = PR_Write(mFD, mBitMap, kBitMapBytes);
        if (bytesWritten < kBitMapBytes) 
            goto error_exit;
        
    } else if (fileSize < kBitMapBytes) {
        rv = NS_ERROR_UNEXPECTED;  // XXX NS_ERROR_CACHE_INVALID;
        goto error_exit;
        
    } else {
        // read the bit map
        const PRInt32 bytesRead = PR_Read(mFD, mBitMap, kBitMapBytes);
        if (bytesRead < kBitMapBytes) {
            rv = NS_ERROR_UNEXPECTED;
            goto error_exit;
        }
#if defined(IS_LITTLE_ENDIAN)
        // Swap from network format
        for (int i = 0; i < kBitMapWords; ++i)
            mBitMap[i] = ntohl(mBitMap[i]);
#endif
        // validate block file size
        // Because not whole blocks are written, the size may be a 
        // little bit smaller than used blocks times blocksize,
        // because the last block will generally not be 'whole'.
        const PRUint32  estimatedSize = CalcBlockFileSize();
        if ((PRUint32)fileSize + blockSize < estimatedSize) {
            rv = NS_ERROR_UNEXPECTED;
            goto error_exit;
        }
    }
    return NS_OK;

error_exit:
    Close(PR_FALSE);
    return rv;
}
Exemplo n.º 8
0
/****************************************************************
 *
 * J z i p A d d
 *
 * Adds a new file into a ZIP file.  The ZIP file must have already
 * been opened with JzipOpen.
 */
int
JzipAdd(char *fullname, char *filename, ZIPfile *zipfile, int compression_level)
{
    ZIPentry *entry;
    PRFileDesc *readfp;
    PRFileDesc *zipfp;
    unsigned long crc;
    unsigned long local_size_pos;
    int num;
    int err;
    int deflate_percent;
    z_stream zstream;
    Bytef inbuf[BUFSIZ];
    Bytef outbuf[BUFSIZ];

    if (!fullname || !filename || !zipfile) {
        return -1;
    }

    zipfp = zipfile->fp;
    if (!zipfp)
        return -1;

    if ((readfp = PR_Open(fullname, PR_RDONLY, 0777)) == NULL) {
        char *nsprErr;
        if (PR_GetErrorTextLength()) {
            nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1);
            PR_GetErrorText(nsprErr);
        } else {
            nsprErr = NULL;
        }
        PR_fprintf(errorFD, "%s: %s\n", fullname, nsprErr ? nsprErr : "");
        errorCount++;
        if (nsprErr)
            PR_Free(nsprErr);
        exit(ERRX);
    }

    /*
     * Make sure the input file is not the output file.
     * Add a few bytes to the end of the JAR file and see if the input file
     * twitches
     */
    {
        PRInt32 endOfJar;
        PRInt32 inputSize;
        PRBool isSame;

        inputSize = PR_Available(readfp);

        endOfJar = PR_Seek(zipfp, 0L, PR_SEEK_CUR);

        if (PR_Write(zipfp, "abcde", 5) < 5) {
            char *nsprErr;

            if (PR_GetErrorTextLength()) {
                nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1);
                PR_GetErrorText(nsprErr);
            } else {
                nsprErr = NULL;
            }
            PR_fprintf(errorFD, "Writing to zip file: %s\n",
                       nsprErr ? nsprErr : "");
            if (nsprErr)
                PR_Free(nsprErr);
            errorCount++;
            exit(ERRX);
        }

        isSame = (PR_Available(readfp) != inputSize);

        PR_Seek(zipfp, endOfJar, PR_SEEK_SET);

        if (isSame) {
            /* It's the same file! Forget it! */
            PR_Close(readfp);
            return 0;
        }
    }

    if (verbosity >= 0) {
        PR_fprintf(outputFD, "adding %s to %s...", fullname, zipfile->filename);
    }

    entry = PORT_ZAlloc(sizeof(ZIPentry));
    if (!entry)
        out_of_memory();

    entry->filename = PORT_Strdup(filename);
    entry->comment = NULL;

    /* Set up local file header */
    longtox(LSIG, entry->local.signature);
    inttox(strlen(filename), entry->local.filename_len);
    inttox(zipfile->time, entry->local.time);
    inttox(zipfile->date, entry->local.date);
    inttox(Z_DEFLATED, entry->local.method);

    /* Set up central directory entry */
    longtox(CSIG, entry->central.signature);
    inttox(strlen(filename), entry->central.filename_len);
    if (entry->comment) {
        inttox(strlen(entry->comment), entry->central.commentfield_len);
    }
    longtox(PR_Seek(zipfile->fp, 0, PR_SEEK_CUR),
            entry->central.localhdr_offset);
    inttox(zipfile->time, entry->central.time);
    inttox(zipfile->date, entry->central.date);
    inttox(Z_DEFLATED, entry->central.method);

    /* Compute crc.  Too bad we have to process the whole file to do this*/
    crc = crc32(0L, NULL, 0);
    while ((num = PR_Read(readfp, inbuf, BUFSIZ)) > 0) {
        crc = crc32(crc, inbuf, num);
    }
    PR_Seek(readfp, 0L, PR_SEEK_SET);

    /* Store CRC */
    longtox(crc, entry->local.crc32);
    longtox(crc, entry->central.crc32);

    /* Stick this entry onto the end of the list */
    entry->next = NULL;
    if (zipfile->list == NULL) {
        /* First entry */
        zipfile->list = entry;
    } else {
        ZIPentry *pe;

        pe = zipfile->list;
        while (pe->next != NULL) {
            pe = pe->next;
        }
        pe->next = entry;
    }

    /*
     * Start writing stuff out
     */

    local_size_pos = PR_Seek(zipfp, 0, PR_SEEK_CUR) + 18;
    /* File header */
    if (PR_Write(zipfp, &entry->local, sizeof(struct ZipLocal)) <
        sizeof(struct ZipLocal)) {
        char *nsprErr;
        if (PR_GetErrorTextLength()) {
            nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1);
            PR_GetErrorText(nsprErr);
        } else {
            nsprErr = NULL;
        }
        PR_fprintf(errorFD, "Writing zip data: %s\n", nsprErr ? nsprErr : "");
        if (nsprErr)
            PR_Free(nsprErr);
        errorCount++;
        exit(ERRX);
    }

    /* File Name */
    if (PR_Write(zipfp, filename, strlen(filename)) < strlen(filename)) {
        char *nsprErr;
        if (PR_GetErrorTextLength()) {
            nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1);
            PR_GetErrorText(nsprErr);
        } else {
            nsprErr = NULL;
        }
        PR_fprintf(errorFD, "Writing zip data: %s\n", nsprErr ? nsprErr : "");
        if (nsprErr)
            PR_Free(nsprErr);
        errorCount++;
        exit(ERRX);
    }

    /*
     * File data
     */
    /* Initialize zstream */
    zstream.zalloc = my_alloc_func;
    zstream.zfree = my_free_func;
    zstream.opaque = NULL;
    zstream.next_in = inbuf;
    zstream.avail_in = BUFSIZ;
    zstream.next_out = outbuf;
    zstream.avail_out = BUFSIZ;
    /* Setting the windowBits to -MAX_WBITS is an undocumented feature of
     * zlib (see deflate.c in zlib).  It is the same thing that Java does
     * when you specify the nowrap option for deflation in java.util.zip.
     * It causes zlib to leave out its headers and footers, which don't
     * work in PKZIP files.
     */
    err = deflateInit2(&zstream, compression_level, Z_DEFLATED,
                       -MAX_WBITS, 8 /*default*/, Z_DEFAULT_STRATEGY);
    if (err != Z_OK) {
        handle_zerror(err, zstream.msg);
        exit(ERRX);
    }

    while ((zstream.avail_in = PR_Read(readfp, inbuf, BUFSIZ)) > 0) {
        zstream.next_in = inbuf;
        /* Process this chunk of data */
        while (zstream.avail_in > 0) {
            err = deflate(&zstream, Z_NO_FLUSH);
            if (err != Z_OK) {
                handle_zerror(err, zstream.msg);
                exit(ERRX);
            }
            if (zstream.avail_out <= 0) {
                if (PR_Write(zipfp, outbuf, BUFSIZ) < BUFSIZ) {
                    char *nsprErr;
                    if (PR_GetErrorTextLength()) {
                        nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1);
                        PR_GetErrorText(nsprErr);
                    } else {
                        nsprErr = NULL;
                    }
                    PR_fprintf(errorFD, "Writing zip data: %s\n",
                               nsprErr ? nsprErr : "");
                    if (nsprErr)
                        PR_Free(nsprErr);
                    errorCount++;
                    exit(ERRX);
                }
                zstream.next_out = outbuf;
                zstream.avail_out = BUFSIZ;
            }
        }
    }

    /* Now flush everything */
    while (1) {
        err = deflate(&zstream, Z_FINISH);
        if (err == Z_STREAM_END) {
            break;
        } else if (err == Z_OK) {
            /* output buffer full, repeat */
        } else {
            handle_zerror(err, zstream.msg);
            exit(ERRX);
        }
        if (PR_Write(zipfp, outbuf, BUFSIZ) < BUFSIZ) {
            char *nsprErr;
            if (PR_GetErrorTextLength()) {
                nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1);
                PR_GetErrorText(nsprErr);
            } else {
                nsprErr = NULL;
            }
            PR_fprintf(errorFD, "Writing zip data: %s\n",
                       nsprErr ? nsprErr : "");
            if (nsprErr)
                PR_Free(nsprErr);
            errorCount++;
            exit(ERRX);
        }
        zstream.avail_out = BUFSIZ;
        zstream.next_out = outbuf;
    }

    /* If there's any output left, write it out. */
    if (zstream.next_out != outbuf) {
        if (PR_Write(zipfp, outbuf, zstream.next_out - outbuf) <
            zstream.next_out - outbuf) {
            char *nsprErr;
            if (PR_GetErrorTextLength()) {
                nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1);
                PR_GetErrorText(nsprErr);
            } else {
                nsprErr = NULL;
            }
            PR_fprintf(errorFD, "Writing zip data: %s\n",
                       nsprErr ? nsprErr : "");
            if (nsprErr)
                PR_Free(nsprErr);
            errorCount++;
            exit(ERRX);
        }
        zstream.avail_out = BUFSIZ;
        zstream.next_out = outbuf;
    }

    /* Now that we know the compressed size, write this to the headers */
    longtox(zstream.total_in, entry->local.orglen);
    longtox(zstream.total_out, entry->local.size);
    if (PR_Seek(zipfp, local_size_pos, PR_SEEK_SET) == -1) {
        char *nsprErr;
        if (PR_GetErrorTextLength()) {
            nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1);
            PR_GetErrorText(nsprErr);
        } else {
            nsprErr = NULL;
        }
        PR_fprintf(errorFD, "Accessing zip file: %s\n", nsprErr ? nsprErr : "");
        if (nsprErr)
            PR_Free(nsprErr);
        errorCount++;
        exit(ERRX);
    }
    if (PR_Write(zipfp, entry->local.size, 8) != 8) {
        char *nsprErr;
        if (PR_GetErrorTextLength()) {
            nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1);
            PR_GetErrorText(nsprErr);
        } else {
            nsprErr = NULL;
        }
        PR_fprintf(errorFD, "Writing zip data: %s\n", nsprErr ? nsprErr : "");
        if (nsprErr)
            PR_Free(nsprErr);
        errorCount++;
        exit(ERRX);
    }
    if (PR_Seek(zipfp, 0L, PR_SEEK_END) == -1) {
        char *nsprErr;
        if (PR_GetErrorTextLength()) {
            nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1);
            PR_GetErrorText(nsprErr);
        } else {
            nsprErr = NULL;
        }
        PR_fprintf(errorFD, "Accessing zip file: %s\n",
                   nsprErr ? nsprErr : "");
        if (nsprErr)
            PR_Free(nsprErr);
        errorCount++;
        exit(ERRX);
    }
    longtox(zstream.total_in, entry->central.orglen);
    longtox(zstream.total_out, entry->central.size);

    /* Close out the deflation operation */
    err = deflateEnd(&zstream);
    if (err != Z_OK) {
        handle_zerror(err, zstream.msg);
        exit(ERRX);
    }

    PR_Close(readfp);

    if ((zstream.total_in > zstream.total_out) && (zstream.total_in > 0)) {
        deflate_percent = (int)((zstream.total_in -
                                 zstream.total_out) *
                                100 / zstream.total_in);
    } else {
        deflate_percent = 0;
    }
    if (verbosity >= 0) {
        PR_fprintf(outputFD, "(deflated %d%%)\n", deflate_percent);
    }

    return 0;
}
JD_METHOD_(JDint32)  CNSAdapter_NSPR::JD_Available(void* fd)
{
  return PR_Available((PRFileDesc*)fd);
}
int main(int argc, char **argv)
{
    PRFileDesc *listenSock1 = NULL, *listenSock2 = NULL;
    PRUint16 listenPort1, listenPort2;
    PRNetAddr addr;
    char buf[128];
    PRThread *clientThread;
    PRPollDesc pds0[20], pds1[20], *pds, *other_pds;
    PRIntn npds;
    PRInt32 retVal;
    PRIntn i, j;
    PRSocketOptionData optval;

	/* The command line argument: -d is used to determine if the test is being run
	in debug mode. The regress tool requires only one line output:PASS or FAIL.
	All of the printfs associated with this test has been handled with a if (debug_mode)
	test.
	Usage: test_name -d
	*/
	PLOptStatus os;
	PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
	while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
    {
		if (PL_OPT_BAD == os) continue;
        switch (opt->option)
        {
        case 'd':  /* debug mode */
			debug_mode = 1;
            break;
         default:
            break;
        }
    }
	PL_DestroyOptState(opt);

 /* main test */
	
    PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
    PR_STDIO_INIT();

    if (debug_mode) {
		printf("This program tests PR_Poll with sockets.\n");
		printf("Normal operation are tested.\n\n");
	}

    /* Create two listening sockets */
    if ((listenSock1 = PR_NewTCPSocket()) == NULL) {
	fprintf(stderr, "Can't create a new TCP socket\n");
	failed_already=1;
	goto exit_now;
    }
    memset(&addr, 0, sizeof(addr));
    addr.inet.family = PR_AF_INET;
    addr.inet.ip = PR_htonl(PR_INADDR_ANY);
    addr.inet.port = PR_htons(0);
    if (PR_Bind(listenSock1, &addr) == PR_FAILURE) {
	fprintf(stderr, "Can't bind socket\n");
	failed_already=1;
	goto exit_now;
    }
    if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) {
	fprintf(stderr, "PR_GetSockName failed\n");
	failed_already=1;
	goto exit_now;
    }
    listenPort1 = PR_ntohs(addr.inet.port);
    optval.option = PR_SockOpt_Nonblocking;
    optval.value.non_blocking = PR_TRUE;
    PR_SetSocketOption(listenSock1, &optval);
    if (PR_Listen(listenSock1, 5) == PR_FAILURE) {
	fprintf(stderr, "Can't listen on a socket\n");
	failed_already=1;
	goto exit_now;
    }

    if ((listenSock2  = PR_NewTCPSocket()) == NULL) {
	fprintf(stderr, "Can't create a new TCP socket\n");
	failed_already=1;	
	goto exit_now;
    }
    addr.inet.family = PR_AF_INET;
    addr.inet.ip = PR_htonl(PR_INADDR_ANY);
    addr.inet.port = PR_htons(0);
    if (PR_Bind(listenSock2, &addr) == PR_FAILURE) {
	fprintf(stderr, "Can't bind socket\n");
	failed_already=1;	
	goto exit_now;
    }
    if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) {
	fprintf(stderr, "PR_GetSockName failed\n");
	failed_already=1;	
	goto exit_now;
    }
    listenPort2 = PR_ntohs(addr.inet.port);
    PR_SetSocketOption(listenSock2, &optval);
    if (PR_Listen(listenSock2, 5) == PR_FAILURE) {
	fprintf(stderr, "Can't listen on a socket\n");
	failed_already=1;	
	goto exit_now;
    }
    PR_snprintf(buf, sizeof(buf),
	    "The server thread is listening on ports %hu and %hu\n\n",
	    listenPort1, listenPort2);
    if (debug_mode) printf("%s", buf);

    /* Set up the poll descriptor array */
    pds = pds0;
    other_pds = pds1;
    memset(pds, 0, sizeof(pds));
    pds[0].fd = listenSock1;
    pds[0].in_flags = PR_POLL_READ;
    pds[1].fd = listenSock2;
    pds[1].in_flags = PR_POLL_READ;
    /* Add some unused entries to test if they are ignored by PR_Poll() */
    memset(&pds[2], 0, sizeof(pds[2]));
    memset(&pds[3], 0, sizeof(pds[3]));
    memset(&pds[4], 0, sizeof(pds[4]));
    npds = 5;

    clientThread = PR_CreateThread(PR_USER_THREAD,
	    clientThreadFunc, (void *) listenPort1,
	    PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
	    PR_UNJOINABLE_THREAD, 0);
    if (clientThread == NULL) {
	fprintf(stderr, "can't create thread\n");
	failed_already=1;	
	goto exit_now;
    }

    clientThread = PR_CreateThread(PR_USER_THREAD,
	    clientThreadFunc, (void *) listenPort2,
	    PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
	    PR_UNJOINABLE_THREAD, 0);
    if (clientThread == NULL) {
	fprintf(stderr, "can't create thread\n");
	failed_already=1;		
	goto exit_now;
    }

    if (debug_mode) {
		printf("Two client threads are created.  Each of them will\n");
		printf("send data to one of the two ports the server is listening on.\n");
		printf("The data they send is the port number.  Each of them send\n");
		printf("the data five times, so you should see ten lines below,\n");
		printf("interleaved in an arbitrary order.\n");
	}

    /* two clients, three events per iteration: accept, read, close */
    i = 0;
    while (i < 2 * 3 * NUM_ITERATIONS) {
	PRPollDesc *tmp;
	int nextIndex;
	int nEvents = 0;

	retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT);
	PR_ASSERT(retVal != 0);  /* no timeout */
	if (retVal == -1) {
	    fprintf(stderr, "PR_Poll failed\n");
		failed_already=1;			
	    goto exit_now;
	}

	nextIndex = 2;
	/* the two listening sockets */
	for (j = 0; j < 2; j++) {
	    other_pds[j] = pds[j];
	    PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0
		    && (pds[j].out_flags & PR_POLL_EXCEPT) == 0);
	    if (pds[j].out_flags & PR_POLL_READ) {
		PRFileDesc *sock;

		nEvents++;
		sock = PR_Accept(pds[j].fd, NULL, PR_INTERVAL_NO_TIMEOUT);
		if (sock == NULL) {
		    fprintf(stderr, "PR_Accept() failed\n");
			failed_already=1;	
		    goto exit_now;
		}
		other_pds[nextIndex].fd = sock;
		other_pds[nextIndex].in_flags = PR_POLL_READ;
		nextIndex++;
	    } else if (pds[j].out_flags & PR_POLL_ERR) {
		fprintf(stderr, "PR_Poll() indicates that an fd has error\n");
		failed_already=1;	
		goto exit_now;
	    } else if (pds[j].out_flags & PR_POLL_NVAL) {
		fprintf(stderr, "PR_Poll() indicates that fd %d is invalid\n",
			PR_FileDesc2NativeHandle(pds[j].fd));
		failed_already=1;	
		goto exit_now;
	    }
	}

	for (j = 2; j < npds; j++) {
            if (NULL == pds[j].fd) {
                /*
                 * Keep the unused entries in the poll descriptor array
                 * for testing purposes.
                 */
                other_pds[nextIndex] = pds[j];
                nextIndex++;
                continue;
            }

	    PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0
		    && (pds[j].out_flags & PR_POLL_EXCEPT) == 0);
	    if (pds[j].out_flags & PR_POLL_READ) {
                PRInt32 nAvail;
		PRInt32 nRead;

		nEvents++;
                nAvail = PR_Available(pds[j].fd);
		nRead = PR_Read(pds[j].fd, buf, sizeof(buf));
                PR_ASSERT(nAvail == nRead);
		if (nRead == -1) {
		    fprintf(stderr, "PR_Read() failed\n");
			failed_already=1;	
		    goto exit_now;
                } else if (nRead == 0) {
                    PR_Close(pds[j].fd);
                    continue;
                } else {
                    /* Just to be safe */
                    buf[127] = '\0';
                    if (debug_mode) printf("The server received \"%s\" from a client\n", buf);
                }
	    } else if (pds[j].out_flags & PR_POLL_ERR) {
		fprintf(stderr, "PR_Poll() indicates that an fd has error\n");
		failed_already=1;			
		goto exit_now;
	    } else if (pds[j].out_flags & PR_POLL_NVAL) {
		fprintf(stderr, "PR_Poll() indicates that an fd is invalid\n");
		failed_already=1;			
		goto exit_now;
	    }
            other_pds[nextIndex] = pds[j];
            nextIndex++;
	}

	PR_ASSERT(retVal == nEvents);
	/* swap */
	tmp = pds;
	pds = other_pds;
	other_pds = tmp;
	npds = nextIndex;
	i += nEvents;
    }

    if (debug_mode) printf("Tests passed\n");

exit_now:

    if (listenSock1) {
        PR_Close(listenSock1);
    }
    if (listenSock2) {
        PR_Close(listenSock2);
    }

    PR_Cleanup();
	
	if(failed_already)	
		return 1;
	else
		return 0;

}