From 6528728611256fb023c07f6e69e2d247140f6eea Mon Sep 17 00:00:00 2001
From: Brian West <brian@freeswitch.org>
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__ */