From 6528728611256fb023c07f6e69e2d247140f6eea Mon Sep 17 00:00:00 2001 From: Brian West Date: Thu, 8 Nov 2007 13:45:57 +0000 Subject: [PATCH] fix sendfile for 10.5 git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@6185 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- libs/apr/network_io/unix/sendrecv.c | 119 ++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/libs/apr/network_io/unix/sendrecv.c b/libs/apr/network_io/unix/sendrecv.c index eedf481c15..9ebc3cf3b4 100644 --- a/libs/apr/network_io/unix/sendrecv.c +++ b/libs/apr/network_io/unix/sendrecv.c @@ -630,6 +630,125 @@ apr_status_t apr_socket_sendfile(apr_socket_t * sock, apr_file_t * file, return APR_SUCCESS; } +#elif defined(__APPLE__) +/* + int + sendfile(int fd, int s, off_t offset, off_t *len, struct sf_hdtr *hdtr, + int flags); +*/ +apr_status_t apr_socket_sendfile(apr_socket_t * sock, apr_file_t * file, + apr_hdtr_t * hdtr, apr_off_t * offset, + apr_size_t * len, apr_int32_t flags) +{ + int rv, i; + struct sf_hdtr headerstruct; + apr_off_t bytes_to_send = *len; + + /* Ignore flags for now. */ + flags = 0; + + if (!hdtr) { + hdtr = &no_hdtr; + } + else{ + if(hdtr->numheaders){ + for (i = 0; i < hdtr->numheaders; i++) { + bytes_to_send += hdtr->headers[i].iov_len; + } + } + else hdtr->headers=NULL; //for us having headers pointing to a valid buffer, but numheaders=0 constitues EINVAL.. + } + + headerstruct.headers = hdtr->headers; + headerstruct.hdr_cnt = hdtr->numheaders; + headerstruct.trailers = hdtr->trailers; + headerstruct.trl_cnt = hdtr->numtrailers; + + + do { + if (sock->options & APR_INCOMPLETE_WRITE) { + apr_status_t arv; + sock->options &= ~APR_INCOMPLETE_WRITE; + arv = apr_wait_for_io_or_timeout(NULL, sock, 0); + if (arv != APR_SUCCESS) { + *len = 0; + return arv; + } + } + if (bytes_to_send) { + /* We won't dare call sendfile() if we don't have + * header or file bytes to send because bytes_to_send == 0 + * means send the whole file. + */ + int lflags = fcntl(sock->socketdes,F_GETFL,0); + lflags &= ~O_NONBLOCK; + fcntl(sock->socketdes,F_SETFL,lflags); + rv = sendfile(file->filedes, /* file to be sent */ + sock->socketdes, /* socket */ + *offset, /* where in the file to start */ + &bytes_to_send, /* number of bytes to send */ + &headerstruct, /* Headers/footers */ + flags); /* undefined, set to 0 */ + lflags |= O_NONBLOCK; + fcntl(sock->socketdes,F_SETFL,lflags); + if (rv == -1) { + if (errno == EAGAIN) { + if (sock->timeout > 0) { + sock->options |= APR_INCOMPLETE_WRITE; + } + /* FreeBSD's sendfile can return -1/EAGAIN even if it + * sent bytes. Sanitize the result so we get normal EAGAIN + * semantics w.r.t. bytes sent. + */ + if (bytes_to_send) { + /* normal exit for a big file & non-blocking io */ + (*len) = bytes_to_send; + return APR_SUCCESS; + } + } + } + else { /* rv == 0 (or the kernel is broken) */ + if (bytes_to_send == 0) { + /* Most likely the file got smaller after the stat. + * Return an error so the caller can do the Right Thing. + */ + (*len) = bytes_to_send; + return APR_EOF; + } + } + } + else { + /* just trailer bytes... use writev() + */ + rv = writev(sock->socketdes, + hdtr->trailers, + hdtr->numtrailers); + if (rv > 0) { + bytes_to_send = rv; + rv = 0; + } + else { + bytes_to_send = 0; + } + } + if ((rv == -1) && (errno == EAGAIN) + && (sock->timeout > 0)) { + apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 0); + if (arv != APR_SUCCESS) { + *len = 0; + return arv; + } + } + } while (rv == -1 && (errno == EINTR || errno == EAGAIN)); + + (*len) = bytes_to_send; + if (rv == -1) { + return errno; + } + return APR_SUCCESS; +} + + #elif defined(__hpux) || defined(__hpux__) /* HP cc in ANSI mode defines __hpux; gcc defines __hpux__ */