int net_writev(SYS_NETFD fd, const NSAPIIOVec *iov, int iov_size) { int rv; rv = PR_Writev(fd, (PRIOVec *)iov, iov_size, PR_INTERVAL_NO_TIMEOUT); #ifdef XP_WIN32 if (rv < 0) { INTnet_cancelIO(fd); } #endif return rv; }
int handle_connection( PRFileDesc *tcp_sock, PRFileDesc *model_sock, int requestCert) { PRFileDesc *ssl_sock = NULL; PRFileDesc *local_file_fd = NULL; char *pBuf; /* unused space at end of buf */ const char *errString; PRStatus status; int bufRem; /* unused bytes at end of buf */ int bufDat; /* characters received in buf */ int newln = 0; /* # of consecutive newlns */ int firstTime = 1; int reqLen; int rv; int numIOVs; PRSocketOptionData opt; PRIOVec iovs[16]; char msgBuf[160]; char buf[10240]; char fileName[513]; char *getData = NULL; /* inplace conversion */ SECItem postData; PRBool isOcspRequest = PR_FALSE; PRBool isPost; postData.data = NULL; postData.len = 0; pBuf = buf; bufRem = sizeof buf; VLOG(("httpserv: handle_connection: starting")); opt.option = PR_SockOpt_Nonblocking; opt.value.non_blocking = PR_FALSE; PR_SetSocketOption(tcp_sock, &opt); VLOG(("httpserv: handle_connection: starting\n")); ssl_sock = tcp_sock; if (noDelay) { opt.option = PR_SockOpt_NoDelay; opt.value.no_delay = PR_TRUE; status = PR_SetSocketOption(ssl_sock, &opt); if (status != PR_SUCCESS) { errWarn("PR_SetSocketOption(PR_SockOpt_NoDelay, PR_TRUE)"); if (ssl_sock) { PR_Close(ssl_sock); } return SECFailure; } } while (1) { const char *post; const char *foundStr = NULL; const char *tmp = NULL; newln = 0; reqLen = 0; rv = PR_Read(ssl_sock, pBuf, bufRem - 1); if (rv == 0 || (rv < 0 && PR_END_OF_FILE_ERROR == PR_GetError())) { if (verbose) errWarn("HDX PR_Read hit EOF"); break; } if (rv < 0) { errWarn("HDX PR_Read"); goto cleanup; } /* NULL termination */ pBuf[rv] = 0; if (firstTime) { firstTime = 0; } pBuf += rv; bufRem -= rv; bufDat = pBuf - buf; /* Parse the input, starting at the beginning of the buffer. * Stop when we detect two consecutive \n's (or \r\n's) * as this signifies the end of the GET or POST portion. * The posted data follows. */ while (reqLen < bufDat && newln < 2) { int octet = buf[reqLen++]; if (octet == '\n') { newln++; } else if (octet != '\r') { newln = 0; } } /* came to the end of the buffer, or second newln * If we didn't get an empty line (CRLFCRLF) then keep on reading. */ if (newln < 2) continue; /* we're at the end of the HTTP request. * If the request is a POST, then there will be one more * line of data. * This parsing is a hack, but ok for SSL test purposes. */ post = PORT_Strstr(buf, "POST "); if (!post || *post != 'P') break; postData.data = (void *)(buf + reqLen); tmp = "content-length: "; foundStr = PL_strcasestr(buf, tmp); if (foundStr) { int expectedPostLen; int havePostLen; expectedPostLen = atoi(foundStr + strlen(tmp)); havePostLen = bufDat - reqLen; if (havePostLen >= expectedPostLen) { postData.len = expectedPostLen; break; } } else { /* use legacy hack */ /* It's a post, so look for the next and final CR/LF. */ while (reqLen < bufDat && newln < 3) { int octet = buf[reqLen++]; if (octet == '\n') { newln++; } } if (newln == 3) break; } } /* read loop */ bufDat = pBuf - buf; if (bufDat) do { /* just close if no data */ /* Have either (a) a complete get, (b) a complete post, (c) EOF */ if (reqLen > 0) { PRBool isGetOrPost = PR_FALSE; unsigned skipChars = 0; isPost = PR_FALSE; if (!strncmp(buf, getCmd, sizeof getCmd - 1)) { isGetOrPost = PR_TRUE; skipChars = 4; } else if (!strncmp(buf, "POST ", 5)) { isGetOrPost = PR_TRUE; isPost = PR_TRUE; skipChars = 5; } if (isGetOrPost) { char *fnBegin = buf; char *fnEnd; char *fnstart = NULL; PRFileInfo info; fnBegin += skipChars; fnEnd = strpbrk(fnBegin, " \r\n"); if (fnEnd) { int fnLen = fnEnd - fnBegin; if (fnLen < sizeof fileName) { strncpy(fileName, fnBegin, fnLen); fileName[fnLen] = 0; /* null terminate */ fnstart = fileName; /* strip initial / because our root is the current directory*/ while (*fnstart && *fnstart == '/') ++fnstart; } } if (fnstart) { if (!strncmp(fnstart, "ocsp", 4)) { if (isPost) { if (postData.data) { isOcspRequest = PR_TRUE; } } else { if (!strncmp(fnstart, "ocsp/", 5)) { isOcspRequest = PR_TRUE; getData = fnstart + 5; } } } else { /* try to open the file named. * If successful, then write it to the client. */ status = PR_GetFileInfo(fnstart, &info); if (status == PR_SUCCESS && info.type == PR_FILE_FILE && info.size >= 0) { local_file_fd = PR_Open(fnstart, PR_RDONLY, 0); } } } } } numIOVs = 0; iovs[numIOVs].iov_base = (char *)outHeader; iovs[numIOVs].iov_len = (sizeof(outHeader)) - 1; numIOVs++; if (isOcspRequest && caRevoInfos) { CERTOCSPRequest *request = NULL; PRBool failThisRequest = PR_FALSE; PLArenaPool *arena = NULL; if (ocspMethodsAllowed == ocspGetOnly && postData.len) { failThisRequest = PR_TRUE; } else if (ocspMethodsAllowed == ocspPostOnly && getData) { failThisRequest = PR_TRUE; } else if (ocspMethodsAllowed == ocspRandomGetFailure && getData) { if (!(rand() % 2)) { failThisRequest = PR_TRUE; } } if (failThisRequest) { PR_Write(ssl_sock, outBadRequestHeader, strlen(outBadRequestHeader)); break; } /* get is base64, post is binary. * If we have base64, convert into the (empty) postData array. */ if (getData) { if (urldecode_base64chars_inplace(getData) == SECSuccess) { /* The code below can handle a NULL arena */ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); NSSBase64_DecodeBuffer(arena, &postData, getData, strlen(getData)); } } if (postData.len) { request = CERT_DecodeOCSPRequest(&postData); } if (arena) { PORT_FreeArena(arena, PR_FALSE); } if (!request || !request->tbsRequest || !request->tbsRequest->requestList || !request->tbsRequest->requestList[0]) { PORT_Sprintf(msgBuf, "Cannot decode OCSP request.\r\n"); iovs[numIOVs].iov_base = msgBuf; iovs[numIOVs].iov_len = PORT_Strlen(msgBuf); numIOVs++; } else { /* TODO: support more than one request entry */ CERTOCSPCertID *reqid = request->tbsRequest->requestList[0]->reqCert; const caRevoInfo *revoInfo = NULL; PRBool unknown = PR_FALSE; PRBool revoked = PR_FALSE; PRTime nextUpdate = 0; PRTime revoDate = 0; PRCList *caRevoIter; caRevoIter = &caRevoInfos->link; do { CERTOCSPCertID *caid; revoInfo = (caRevoInfo *)caRevoIter; caid = revoInfo->id; if (SECOID_CompareAlgorithmID(&reqid->hashAlgorithm, &caid->hashAlgorithm) == SECEqual && SECITEM_CompareItem(&reqid->issuerNameHash, &caid->issuerNameHash) == SECEqual && SECITEM_CompareItem(&reqid->issuerKeyHash, &caid->issuerKeyHash) == SECEqual) { break; } revoInfo = NULL; caRevoIter = PR_NEXT_LINK(caRevoIter); } while (caRevoIter != &caRevoInfos->link); if (!revoInfo) { unknown = PR_TRUE; revoInfo = caRevoInfos; } else { CERTCrl *crl = &revoInfo->crl->crl; CERTCrlEntry *entry = NULL; DER_DecodeTimeChoice(&nextUpdate, &crl->nextUpdate); if (crl->entries) { int iv = 0; /* assign, not compare */ while ((entry = crl->entries[iv++])) { if (SECITEM_CompareItem(&reqid->serialNumber, &entry->serialNumber) == SECEqual) { break; } } } if (entry) { /* revoked status response */ revoked = PR_TRUE; DER_DecodeTimeChoice(&revoDate, &entry->revocationDate); } else { /* else good status response */ if (!isPost && ocspMethodsAllowed == ocspGetUnknown) { unknown = PR_TRUE; nextUpdate = PR_Now() + (PRTime)60 * 60 * 24 * PR_USEC_PER_SEC; /*tomorrow*/ revoDate = PR_Now() - (PRTime)60 * 60 * 24 * PR_USEC_PER_SEC; /*yesterday*/ } } } { PRTime now = PR_Now(); PLArenaPool *arena = NULL; CERTOCSPSingleResponse *sr; CERTOCSPSingleResponse **singleResponses; SECItem *ocspResponse; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (unknown) { sr = CERT_CreateOCSPSingleResponseUnknown(arena, reqid, now, &nextUpdate); } else if (revoked) { sr = CERT_CreateOCSPSingleResponseRevoked(arena, reqid, now, &nextUpdate, revoDate, NULL); } else { sr = CERT_CreateOCSPSingleResponseGood(arena, reqid, now, &nextUpdate); } /* meaning of value 2: one entry + one end marker */ singleResponses = PORT_ArenaNewArray(arena, CERTOCSPSingleResponse *, 2); singleResponses[0] = sr; singleResponses[1] = NULL; ocspResponse = CERT_CreateEncodedOCSPSuccessResponse(arena, revoInfo->cert, ocspResponderID_byName, now, singleResponses, &pwdata); if (!ocspResponse) { PORT_Sprintf(msgBuf, "Failed to encode response\r\n"); iovs[numIOVs].iov_base = msgBuf; iovs[numIOVs].iov_len = PORT_Strlen(msgBuf); numIOVs++; } else { PR_Write(ssl_sock, outOcspHeader, strlen(outOcspHeader)); PR_Write(ssl_sock, ocspResponse->data, ocspResponse->len); PORT_FreeArena(arena, PR_FALSE); } } CERT_DestroyOCSPRequest(request); break; } } else if (local_file_fd) { PRInt32 bytes; int errLen; bytes = PR_TransmitFile(ssl_sock, local_file_fd, outHeader, sizeof outHeader - 1, PR_TRANSMITFILE_KEEP_OPEN, PR_INTERVAL_NO_TIMEOUT); if (bytes >= 0) { bytes -= sizeof outHeader - 1; FPRINTF(stderr, "httpserv: PR_TransmitFile wrote %d bytes from %s\n", bytes, fileName); break; } errString = errWarn("PR_TransmitFile"); errLen = PORT_Strlen(errString); errLen = PR_MIN(errLen, sizeof msgBuf - 1); PORT_Memcpy(msgBuf, errString, errLen); msgBuf[errLen] = 0; iovs[numIOVs].iov_base = msgBuf; iovs[numIOVs].iov_len = PORT_Strlen(msgBuf); numIOVs++; } else if (reqLen <= 0) { /* hit eof */ PORT_Sprintf(msgBuf, "Get or Post incomplete after %d bytes.\r\n", bufDat); iovs[numIOVs].iov_base = msgBuf; iovs[numIOVs].iov_len = PORT_Strlen(msgBuf); numIOVs++; } else if (reqLen < bufDat) { PORT_Sprintf(msgBuf, "Discarded %d characters.\r\n", bufDat - reqLen); iovs[numIOVs].iov_base = msgBuf; iovs[numIOVs].iov_len = PORT_Strlen(msgBuf); numIOVs++; } if (reqLen > 0) { if (verbose > 1) fwrite(buf, 1, reqLen, stdout); /* display it */ iovs[numIOVs].iov_base = buf; iovs[numIOVs].iov_len = reqLen; numIOVs++; } rv = PR_Writev(ssl_sock, iovs, numIOVs, PR_INTERVAL_NO_TIMEOUT); if (rv < 0) { errWarn("PR_Writev"); break; } } while (0);
NSFC_PR_SendFile(PRFileDesc *socket, PRFileDesc *fd, NSFCFileInfo *finfo, const void *headers, PRInt32 hdrlen, const void *trailers, PRInt32 tlrlen, PRIntervalTime timeout, PRInt32 sendfileSize, NSFCStatusInfo *statusInfo) { PRInt64 rv; PR_ASSERT(finfo != NULL); PR_ASSERT((PRInt64)hdrlen + sendfileSize <= PR_INT32_MAX); PR_ASSERT((PRInt64)tlrlen + sendfileSize <= PR_INT32_MAX); if (finfo->pr.size == 0) { PRIOVec iov[2]; PRInt32 iovcnt; iovcnt = 0; if (headers && (hdrlen > 0)) { iov[iovcnt].iov_base = (char *)headers; iov[iovcnt].iov_len = hdrlen; ++iovcnt; } if (trailers && (tlrlen > 0)) { iov[iovcnt].iov_base = (char *)trailers; iov[iovcnt].iov_len = tlrlen; ++iovcnt; } if (iovcnt > 0) { rv = PR_Writev(socket, iov, iovcnt, timeout); } else { rv = 0; } } else { PRSendFileData sfd; PROffset64 remain = finfo->pr.size - sendfileSize; sfd.fd = fd; sfd.file_offset = 0; sfd.file_nbytes = sendfileSize; sfd.header = headers; sfd.hlen = hdrlen; if (remain == 0) { PR_ASSERT((PRInt64)hdrlen + finfo->pr.size + tlrlen <= PR_INT32_MAX); sfd.trailer = trailers; sfd.tlen = tlrlen; } else { sfd.trailer = NULL; sfd.tlen = 0; } rv = PR_SendFile(socket, &sfd, PR_TRANSMITFILE_KEEP_OPEN, timeout); if (remain > 0 && rv >= 0) { sfd.header = NULL; sfd.hlen = 0; sfd.file_offset += sendfileSize; while (remain > sendfileSize && rv >= 0) { rv = PR_SendFile(socket, &sfd, PR_TRANSMITFILE_KEEP_OPEN, timeout); remain -= sendfileSize; sfd.file_offset += sendfileSize; } // Send the remaining bits if (rv >= 0) { sfd.file_nbytes = remain; sfd.trailer = trailers; sfd.tlen = tlrlen; rv = PR_SendFile(socket, &sfd, PR_TRANSMITFILE_KEEP_OPEN, timeout); } // If there were no errors, set the rv value to the total size // written instead of the last chunk written. The caller may // do sanity check on number of bytes written based on returned // value if (rv >= 0) rv = hdrlen + finfo->pr.size + tlrlen; } } if (rv < 0) { _NSFC_PR_NT_CancelIo(socket); #ifdef XP_WIN32 PRErrorCode prerr = PR_GetError(); PRInt32 oserr = PR_GetOSError(); if (prerr == PR_UNKNOWN_ERROR && oserr == ERROR_FILE_INVALID) { NSFCSTATUSINFO_SET(statusInfo, NSFC_STATUSINFO_FILESIZE); } #endif } return rv; }
NSFC_ReadWriteFile(PRFileDesc *socket, PRFileDesc *fd, NSFCFileInfo *finfo, const void *headers, PRInt32 hdrlen, const void *trailers, PRInt32 tlrlen, PRIntervalTime timeout, NSFCCache cache, NSFCStatusInfo *statusInfo) { PRInt32 buff_size; void *buff; PRBool use_local_memfns; PRInt64 rv; PR_ASSERT(finfo != NULL); NSFCSTATUSINFO_INIT(statusInfo); buff_size = cache->cfg.bufferSize; if (finfo && finfo->pr.size < buff_size) { buff_size = finfo->pr.size + 1; } PR_ASSERT(buff_size > 0); if (cache && cache->local_memfns && cache->local_memfns->alloc && cache->local_memfns->free) { buff = cache->local_memfns->alloc((int)buff_size); use_local_memfns = PR_TRUE; } else { buff = malloc(buff_size); use_local_memfns = PR_FALSE; } if (!buff) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); rv = -1; } else { PRInt64 bytesWritten = 0; PRBool eof = PR_FALSE; rv = PR_Read(fd, buff, buff_size); if (rv >= 0) { if (rv < buff_size) { eof = PR_TRUE; } PRIOVec iov[3]; PRInt32 iovcnt = 0; if (headers && (hdrlen > 0)) { iov[iovcnt].iov_base = (char *)headers; iov[iovcnt].iov_len = hdrlen; ++iovcnt; } if (rv > 0) { iov[iovcnt].iov_base = (char *)buff; iov[iovcnt].iov_len = rv; ++iovcnt; } if (eof && trailers && (tlrlen > 0)) { iov[iovcnt].iov_base = (char *)trailers; iov[iovcnt].iov_len = tlrlen; ++iovcnt; } while (iovcnt > 0) { rv = PR_Writev(socket, iov, iovcnt, timeout); if (rv < 0) { _NSFC_PR_NT_CancelIo(socket); break; } bytesWritten += rv; if (eof) { break; } rv = PR_Read(fd, buff, buff_size); if (rv < 0) { break; } if (rv < buff_size) { eof = PR_TRUE; } iovcnt = 0; if (rv > 0) { iov[iovcnt].iov_base = (char *)buff; iov[iovcnt].iov_len = rv; ++iovcnt; } if (eof && trailers && (tlrlen > 0)) { iov[iovcnt].iov_base = (char *)trailers; iov[iovcnt].iov_len = tlrlen; ++iovcnt; } } } if (use_local_memfns == PR_TRUE) { cache->local_memfns->free(buff); } else { free(buff); } if (rv >= 0) { rv = bytesWritten; if (finfo && rv != (hdrlen + finfo->pr.size + tlrlen)) NSFCSTATUSINFO_SET(statusInfo, NSFC_STATUSINFO_FILESIZE); } } #ifdef XP_WIN32 /* Work-around for NSPR error mapping deficiency */ if ((rv < 0) && (PR_GetError() == PR_UNKNOWN_ERROR) && (PR_GetOSError() == ERROR_NETNAME_DELETED)) { PR_SetError(PR_CONNECT_RESET_ERROR, ERROR_NETNAME_DELETED); } #endif /* XP_WIN32 */ return rv; }
int handle_connection( PRFileDesc *tcp_sock, PRFileDesc *model_sock, int requestCert ) { PRFileDesc * ssl_sock = NULL; PRFileDesc * local_file_fd = NULL; char * post; char * pBuf; /* unused space at end of buf */ const char * errString; PRStatus status; int bufRem; /* unused bytes at end of buf */ int bufDat; /* characters received in buf */ int newln = 0; /* # of consecutive newlns */ int firstTime = 1; int reqLen; int rv; int numIOVs; PRSocketOptionData opt; PRIOVec iovs[16]; char msgBuf[160]; char buf[10240]; char fileName[513]; pBuf = buf; bufRem = sizeof buf; VLOG(("selfserv: handle_connection: starting")); opt.option = PR_SockOpt_Nonblocking; opt.value.non_blocking = PR_FALSE; PR_SetSocketOption(tcp_sock, &opt); VLOG(("selfserv: handle_connection: starting\n")); ssl_sock = tcp_sock; if (noDelay) { opt.option = PR_SockOpt_NoDelay; opt.value.no_delay = PR_TRUE; status = PR_SetSocketOption(ssl_sock, &opt); if (status != PR_SUCCESS) { errWarn("PR_SetSocketOption(PR_SockOpt_NoDelay, PR_TRUE)"); if (ssl_sock) { PR_Close(ssl_sock); } return SECFailure; } } while (1) { newln = 0; reqLen = 0; rv = PR_Read(ssl_sock, pBuf, bufRem - 1); if (rv == 0 || (rv < 0 && PR_END_OF_FILE_ERROR == PR_GetError())) { if (verbose) errWarn("HDX PR_Read hit EOF"); break; } if (rv < 0) { errWarn("HDX PR_Read"); goto cleanup; } /* NULL termination */ pBuf[rv] = 0; if (firstTime) { firstTime = 0; } pBuf += rv; bufRem -= rv; bufDat = pBuf - buf; /* Parse the input, starting at the beginning of the buffer. * Stop when we detect two consecutive \n's (or \r\n's) * as this signifies the end of the GET or POST portion. * The posted data follows. */ while (reqLen < bufDat && newln < 2) { int octet = buf[reqLen++]; if (octet == '\n') { newln++; } else if (octet != '\r') { newln = 0; } } /* came to the end of the buffer, or second newln * If we didn't get an empty line (CRLFCRLF) then keep on reading. */ if (newln < 2) continue; /* we're at the end of the HTTP request. * If the request is a POST, then there will be one more * line of data. * This parsing is a hack, but ok for SSL test purposes. */ post = PORT_Strstr(buf, "POST "); if (!post || *post != 'P') break; /* It's a post, so look for the next and final CR/LF. */ /* We should parse content length here, but ... */ while (reqLen < bufDat && newln < 3) { int octet = buf[reqLen++]; if (octet == '\n') { newln++; } } if (newln == 3) break; } /* read loop */ bufDat = pBuf - buf; if (bufDat) do { /* just close if no data */ /* Have either (a) a complete get, (b) a complete post, (c) EOF */ if (reqLen > 0 && !strncmp(buf, getCmd, sizeof getCmd - 1)) { char * fnBegin = buf + 4; char * fnEnd; PRFileInfo info; /* try to open the file named. * If successful, then write it to the client. */ fnEnd = strpbrk(fnBegin, " \r\n"); if (fnEnd) { int fnLen = fnEnd - fnBegin; if (fnLen < sizeof fileName) { char *fnstart; strncpy(fileName, fnBegin, fnLen); fileName[fnLen] = 0; /* null terminate */ fnstart = fileName; /* strip initial / because our root is the current directory*/ while (*fnstart && *fnstart=='/') ++fnstart; status = PR_GetFileInfo(fnstart, &info); if (status == PR_SUCCESS && info.type == PR_FILE_FILE && info.size >= 0 ) { local_file_fd = PR_Open(fnstart, PR_RDONLY, 0); } } } } numIOVs = 0; iovs[numIOVs].iov_base = (char *)outHeader; iovs[numIOVs].iov_len = (sizeof(outHeader)) - 1; numIOVs++; if (local_file_fd) { PRInt32 bytes; int errLen; bytes = PR_TransmitFile(ssl_sock, local_file_fd, outHeader, sizeof outHeader - 1, PR_TRANSMITFILE_KEEP_OPEN, PR_INTERVAL_NO_TIMEOUT); if (bytes >= 0) { bytes -= sizeof outHeader - 1; FPRINTF(stderr, "selfserv: PR_TransmitFile wrote %d bytes from %s\n", bytes, fileName); break; } errString = errWarn("PR_TransmitFile"); errLen = PORT_Strlen(errString); errLen = PR_MIN(errLen, sizeof msgBuf - 1); PORT_Memcpy(msgBuf, errString, errLen); msgBuf[errLen] = 0; iovs[numIOVs].iov_base = msgBuf; iovs[numIOVs].iov_len = PORT_Strlen(msgBuf); numIOVs++; } else if (reqLen <= 0) { /* hit eof */ PORT_Sprintf(msgBuf, "Get or Post incomplete after %d bytes.\r\n", bufDat); iovs[numIOVs].iov_base = msgBuf; iovs[numIOVs].iov_len = PORT_Strlen(msgBuf); numIOVs++; } else if (reqLen < bufDat) { PORT_Sprintf(msgBuf, "Discarded %d characters.\r\n", bufDat - reqLen); iovs[numIOVs].iov_base = msgBuf; iovs[numIOVs].iov_len = PORT_Strlen(msgBuf); numIOVs++; } if (reqLen > 0) { if (verbose > 1) fwrite(buf, 1, reqLen, stdout); /* display it */ iovs[numIOVs].iov_base = buf; iovs[numIOVs].iov_len = reqLen; numIOVs++; } /* Don't add the EOF if we want to test bulk encryption */ if (!testBulk) { iovs[numIOVs].iov_base = (char *)EOFmsg; iovs[numIOVs].iov_len = sizeof EOFmsg - 1; numIOVs++; } rv = PR_Writev(ssl_sock, iovs, numIOVs, PR_INTERVAL_NO_TIMEOUT); if (rv < 0) { errWarn("PR_Writev"); break; } } while (0); cleanup: if (ssl_sock) { PR_Close(ssl_sock); } else if (tcp_sock) { PR_Close(tcp_sock); } if (local_file_fd) PR_Close(local_file_fd); VLOG(("selfserv: handle_connection: exiting\n")); /* do a nice shutdown if asked. */ if (!strncmp(buf, stopCmd, sizeof stopCmd - 1)) { VLOG(("selfserv: handle_connection: stop command")); stop_server(); } VLOG(("selfserv: handle_connection: exiting")); return SECSuccess; /* success */ }
PR_IMPLEMENT(PRInt32) PR_EmulateSendFile( PRFileDesc *sd, PRSendFileData *sfd, PRTransmitFileFlags flags, PRIntervalTime timeout) { PRInt32 rv, count = 0; PRInt32 len, file_bytes, index = 0; PRFileInfo info; PRIOVec iov[3]; PRFileMap *mapHandle = NULL; void *addr = (void*)0; /* initialized to some arbitrary value. Keeps compiler warnings down. */ PRUint32 file_mmap_offset, alignment; PRInt64 zero64; PROffset64 file_mmap_offset64; PRUint32 addr_offset, mmap_len; /* Get file size */ if (PR_SUCCESS != PR_GetOpenFileInfo(sfd->fd, &info)) { count = -1; goto done; } if (sfd->file_nbytes && (info.size < (sfd->file_offset + sfd->file_nbytes))) { /* * there are fewer bytes in file to send than specified */ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); count = -1; goto done; } if (sfd->file_nbytes) file_bytes = sfd->file_nbytes; else file_bytes = info.size - sfd->file_offset; alignment = PR_GetMemMapAlignment(); /* number of initial bytes to skip in mmap'd segment */ addr_offset = sfd->file_offset % alignment; /* find previous mmap alignment boundary */ file_mmap_offset = sfd->file_offset - addr_offset; /* * If the file is large, mmap and send the file in chunks so as * to not consume too much virtual address space */ mmap_len = PR_MIN(file_bytes + addr_offset, SENDFILE_MMAP_CHUNK); len = mmap_len - addr_offset; /* * Map in (part of) file. Take care of zero-length files. */ if (len) { LL_I2L(zero64, 0); mapHandle = PR_CreateFileMap(sfd->fd, zero64, PR_PROT_READONLY); if (!mapHandle) { count = -1; goto done; } LL_I2L(file_mmap_offset64, file_mmap_offset); addr = PR_MemMap(mapHandle, file_mmap_offset64, mmap_len); if (!addr) { count = -1; goto done; } } /* * send headers first, followed by the file */ if (sfd->hlen) { iov[index].iov_base = (char *) sfd->header; iov[index].iov_len = sfd->hlen; index++; } if (len) { iov[index].iov_base = (char*)addr + addr_offset; iov[index].iov_len = len; index++; } if ((file_bytes == len) && (sfd->tlen)) { /* * all file data is mapped in; send the trailer too */ iov[index].iov_base = (char *) sfd->trailer; iov[index].iov_len = sfd->tlen; index++; } rv = PR_Writev(sd, iov, index, timeout); if (len) PR_MemUnmap(addr, mmap_len); if (rv < 0) { count = -1; goto done; } PR_ASSERT(rv == sfd->hlen + len + ((len == file_bytes) ? sfd->tlen : 0)); file_bytes -= len; count += rv; if (!file_bytes) /* header, file and trailer are sent */ goto done; /* * send remaining bytes of the file, if any */ len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK); while (len > 0) { /* * Map in (part of) file */ file_mmap_offset = sfd->file_offset + count - sfd->hlen; PR_ASSERT((file_mmap_offset % alignment) == 0); LL_I2L(file_mmap_offset64, file_mmap_offset); addr = PR_MemMap(mapHandle, file_mmap_offset64, len); if (!addr) { count = -1; goto done; } rv = PR_Send(sd, addr, len, 0, timeout); PR_MemUnmap(addr, len); if (rv < 0) { count = -1; goto done; } PR_ASSERT(rv == len); file_bytes -= rv; count += rv; len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK); } PR_ASSERT(0 == file_bytes); if (sfd->tlen) { rv = PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout); if (rv >= 0) { PR_ASSERT(rv == sfd->tlen); count += rv; } else count = -1; } done: if (mapHandle) PR_CloseFileMap(mapHandle); if ((count >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET)) PR_Close(sd); return count; }