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; }
static void ServerThread(void *arg) { PRFileDesc *listenSock = (PRFileDesc *) arg; PRFileDesc *acceptSock; PRFileDesc *file; PRSendFileData sfd; char header[1024], trailer[1024]; PRInt32 nbytes; /* Create a zero-length file */ file = PR_Open(ZERO_LEN_FILE_NAME, PR_CREATE_FILE|PR_TRUNCATE|PR_RDWR, 0666); if (NULL == file) { fprintf(stderr, "PR_Open failed\n"); exit(1); } sfd.fd = file; sfd.file_offset = 0; sfd.file_nbytes = 0; memcpy(header, HEADER_STR, HEADER_LEN); memcpy(trailer, TRAILER_STR, TRAILER_LEN); sfd.header = header; sfd.hlen = HEADER_LEN; sfd.trailer = trailer; sfd.tlen = TRAILER_LEN; acceptSock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); if (NULL == acceptSock) { fprintf(stderr, "PR_Accept failed\n"); exit(1); } /* Send both header and trailer */ nbytes = PR_SendFile(acceptSock, &sfd, PR_TRANSMITFILE_KEEP_OPEN, PR_INTERVAL_NO_TIMEOUT); if (HEADER_LEN+TRAILER_LEN != nbytes) { fprintf(stderr, "PR_SendFile should return %d but returned %d\n", HEADER_LEN+TRAILER_LEN, nbytes); exit(1); } /* Trailer only, no header */ sfd.hlen = 0; nbytes = PR_SendFile(acceptSock, &sfd, PR_TRANSMITFILE_KEEP_OPEN, PR_INTERVAL_NO_TIMEOUT); if (TRAILER_LEN != nbytes) { fprintf(stderr, "PR_SendFile should return %d but returned %d\n", TRAILER_LEN, nbytes); exit(1); } /* Header only, no trailer */ sfd.hlen = HEADER_LEN; sfd.tlen = 0; nbytes = PR_SendFile(acceptSock, &sfd, PR_TRANSMITFILE_KEEP_OPEN, PR_INTERVAL_NO_TIMEOUT); if (HEADER_LEN != nbytes) { fprintf(stderr, "PR_SendFile should return %d but returned %d\n", HEADER_LEN, nbytes); exit(1); } /* Try PR_TransmitFile */ nbytes = PR_TransmitFile(acceptSock, file, header, HEADER_LEN, PR_TRANSMITFILE_KEEP_OPEN, PR_INTERVAL_NO_TIMEOUT); if (HEADER_LEN != nbytes) { fprintf(stderr, "PR_TransmitFile should return %d but returned %d\n", HEADER_LEN, nbytes); exit(1); } if (PR_Close(acceptSock) == PR_FAILURE) { fprintf(stderr, "PR_Close failed\n"); exit(1); } if (PR_Close(file) == PR_FAILURE) { fprintf(stderr, "PR_Close failed\n"); exit(1); } if (PR_Delete(ZERO_LEN_FILE_NAME) == PR_FAILURE) { fprintf(stderr, "PR_Delete failed\n"); exit(1); } }