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; }
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; }
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; }
/* 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; }
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; }
/****************************************************************************** * 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; }
/**************************************************************** * * 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; }