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);
    }
}