Jeff Trawick <[EMAIL PROTECTED]> writes:
> Greg Ames <[EMAIL PROTECTED]> writes:
>
> > But what if we have rv == -1, EAGAIN, and nbytes == 0 ? I don't think
> > we handle that properly yet in FreeBSD, nor in Solaris. Looks to me
> > like the new FreeBSD code will exit apr_sendfile with APR_EAGAIN, and
> > sendfile_it_all will bail, and the request will die.
>
> yeah, it definitely looks busted... I'll work on that...
Here is a patch for FreeBSD which I'll commit soon if nobody
complains. It fixes a few problems with when we call
wait_for_io_or_timeout(), and it also tries to send again when
wait_for_io_or_timeout() succeeds.
Index: srclib/apr/network_io/unix/sendrecv.c
===================================================================
RCS file: /home/cvspublic/apr/network_io/unix/sendrecv.c,v
retrieving revision 1.71
diff -u -r1.71 sendrecv.c
--- srclib/apr/network_io/unix/sendrecv.c 2001/07/25 05:27:32 1.71
+++ srclib/apr/network_io/unix/sendrecv.c 2001/07/25 20:04:59
@@ -447,24 +447,51 @@
}
} while (rv == -1 && errno == EINTR);
- /* On FreeBSD, it is possible that sendfile will return EAGAIN, but
- * still send some data. This means that we cannot call sendfile
- * and then check for EAGAIN, and then wait and call sendfile again.
- * If we do that, then we are likely to send the first chunk of data
- * twice, once in the first call and once in the second.
- *
- * When we are dealing with a non-blocking or timeout socket, the
- * caller must already be aware that we may not be able to write
- * everything in one call. Therefore, we should return back to
- * the caller with how much we actually sent (as specified from EAGAIN).
- *
- * If we are using a timed write, we will now block until we are clear.
- */
- if (errno == EAGAIN && nbytes && sock->timeout >= 0) {
+ if (rv == -1 &&
+ errno == EAGAIN &&
+ sock->timeout > 0) {
apr_status_t arv = apr_wait_for_io_or_timeout(sock, 0);
if (arv != APR_SUCCESS) {
*len = 0;
return arv;
+ }
+ else {
+ do {
+ 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.
+ */
+ 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 */
+ &nbytes, /* number of bytes written */
+ flags); /* undefined, set to 0 */
+ /* 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 (rv == -1 && errno == EAGAIN && nbytes) {
+ rv = 0;
+ }
+ }
+ else {
+ /* just trailer bytes... use writev()
+ */
+ rv = writev(sock->socketdes,
+ hdtr->trailers,
+ hdtr->numtrailers);
+ if (rv > 0) {
+ nbytes = rv;
+ rv = 0;
+ }
+ else {
+ nbytes = 0;
+ }
+ }
+ } while (rv == -1 && errno == EINTR);
}
}
--
Jeff Trawick | [EMAIL PROTECTED] | PGP public key at web site:
http://www.geocities.com/SiliconValley/Park/9289/
Born in Roswell... married an alien...