apr-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jim Jagielski <...@jagunet.com>
Subject Re: sendfile in darwin
Date Thu, 08 May 2008 13:17:40 GMT

On May 7, 2008, at 5:58 PM, Geoff Greer wrote:
>
> Of course reverting the change (adding the rv=0 line again) causes the
> httpd tests to fail.

The Darwin impl assumes that it is very much like FreeBSDs
except for the variation in arguments and the fact that we
"aren't sure" about the data counting. The FreeBSD impl
does not have the rv reset.

Also, I've also tried the below, which also passes my tests
as well:

#elif defined(DARWIN)

/* OS/X Release 10.5 or greater */
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)
{
     apr_off_t nbytes = 0;
     apr_off_t bytes_to_send = *len;
     apr_off_t bytes_sent = 0;
     apr_status_t arv;
     int rv = 0;

     /* Ignore flags for now. */
     flags = 0;

     if (!hdtr) {
         hdtr = &no_hdtr;
     }

     /* OS X can send the headers/footers as part of the system call,
      * but how it counts bytes isn't documented properly. We use
      * apr_socket_sendv() instead.
      */
      if (hdtr->numheaders > 0) {
         apr_size_t hbytes;
         int i;

         /* Now write the headers */
         arv = apr_socket_sendv(sock, hdtr->headers, hdtr->numheaders,
                                &hbytes);
         if (arv != APR_SUCCESS) {
             *len = 0;
             return errno;
         }
         bytes_sent = hbytes;

         hbytes = 0;
         for (i = 0; i < hdtr->numheaders; i++) {
             hbytes += hdtr->headers[i].iov_len;
         }
         if (bytes_sent < hbytes) {
             *len = bytes_sent;
             return APR_SUCCESS;
         }
     }

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

         nbytes = bytes_to_send;
         rv = sendfile(file->filedes, /* file to be sent */
                       sock->socketdes, /* socket */
                       *offset,       /* where in the file to start */
                       &nbytes,       /* number of bytes to write/ 
written */
                       NULL,          /* Headers/footers */
                       flags);        /* undefined, set to 0 */

         bytes_sent += nbytes;
         bytes_to_send -= nbytes;
         (*offset) += nbytes;
         if (rv == -1) {
             if (errno == EAGAIN) {
                 if (sock->timeout > 0) {
                     sock->options |= APR_INCOMPLETE_WRITE;
                 }
                 /* BSD'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.
                  */
                 else if (nbytes) {
                     /* normal exit for a big file & non-blocking io */
                     (*len) = bytes_sent;
                     return APR_SUCCESS;
                 }
             }
         }
         else {       /* rv == 0 (or the kernel is broken) */
             if (nbytes == 0) {
                 /* Most likely the file got smaller after the stat.
                  * Return an error so the caller can do the Right  
Thing.
                  */
                 (*len) = bytes_sent;
                 return APR_EOF;
             }
         }

         if ((rv == -1) && (errno == EAGAIN) && (sock->timeout > 0))
{
             sock->options |= APR_INCOMPLETE_WRITE;
         }
     } while (rv == -1 && (errno == EINTR || errno == EAGAIN));

     /* Now write the footers */
     if (hdtr->numtrailers > 0) {
         apr_size_t tbytes;
         arv = apr_socket_sendv(sock, hdtr->trailers, hdtr->numtrailers,
                                &tbytes);
         bytes_sent += tbytes;
         if (arv != APR_SUCCESS) {
             *len = bytes_sent;
             rv = errno;
             return rv;
         }
     }

     (*len) = bytes_sent;
     if (rv == -1) {
         return errno;
     }
     return APR_SUCCESS;
}



Mime
View raw message