You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@apr.apache.org by rp...@apache.org on 2009/10/16 23:08:15 UTC

svn commit: r826089 - in /apr/apr/branches/1.4.x: CHANGES include/apr_network_io.h libapr.dsp network_io/beos/socketcommon.c network_io/os2/socket_util.c network_io/unix/socket_util.c test/sockchild.c test/testsock.c

Author: rpluem
Date: Fri Oct 16 21:08:15 2009
New Revision: 826089

URL: http://svn.apache.org/viewvc?rev=826089&view=rev
Log:
Merge r821524, r822431, r822892, r824500 from trunk:

* Add apr_socket_is_connected to detect whether the remote side of a socket
  is still open. The origin of apr_socket_is_connected is r473278 from
  http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/proxy_util.c
  in httpd.


* Improve the documentation

Suggested by: jorton


* Improve the documentation even further

Reviewed by: jim


* include/apr_network_io.h,
* network_io/unix/socket_util.c (apr_socket_atreadeof): Renamed from
  apr_socket_is_connected; adjusted to return an apr_status_t error
  code, and pass an "at EOF" flag via an output parameter.

* test/testsock.c (test_atreadeof): Renamed from test_is_connected,
  adjusted for new API.

Reviewed by: jorton, rpluem

Added:
    apr/apr/branches/1.4.x/network_io/os2/socket_util.c
      - copied unchanged from r821524, apr/apr/trunk/network_io/os2/socket_util.c
    apr/apr/branches/1.4.x/network_io/unix/socket_util.c
      - copied, changed from r821524, apr/apr/trunk/network_io/unix/socket_util.c
Modified:
    apr/apr/branches/1.4.x/CHANGES
    apr/apr/branches/1.4.x/include/apr_network_io.h
    apr/apr/branches/1.4.x/libapr.dsp
    apr/apr/branches/1.4.x/network_io/beos/socketcommon.c
    apr/apr/branches/1.4.x/test/sockchild.c
    apr/apr/branches/1.4.x/test/testsock.c

Modified: apr/apr/branches/1.4.x/CHANGES
URL: http://svn.apache.org/viewvc/apr/apr/branches/1.4.x/CHANGES?rev=826089&r1=826088&r2=826089&view=diff
==============================================================================
--- apr/apr/branches/1.4.x/CHANGES [utf-8] (original)
+++ apr/apr/branches/1.4.x/CHANGES [utf-8] Fri Oct 16 21:08:15 2009
@@ -1,6 +1,10 @@
                                                      -*- coding: utf-8 -*-
 Changes for APR 1.4.0
 
+  *) Add apr_socket_atreadeof to determine whether the receive part of the
+     socket has been closed by the peer.
+     [Ruediger Pluem, Mladen Turk, Joe Orton]
+
   *) Make apr_pollset and apr_pollcb implementations using providers.
      Added apr_pollset_create_ex and apr_pollcb_create_ex that allows
      choosing non-default providers.

Modified: apr/apr/branches/1.4.x/include/apr_network_io.h
URL: http://svn.apache.org/viewvc/apr/apr/branches/1.4.x/include/apr_network_io.h?rev=826089&r1=826088&r2=826089&view=diff
==============================================================================
--- apr/apr/branches/1.4.x/include/apr_network_io.h (original)
+++ apr/apr/branches/1.4.x/include/apr_network_io.h Fri Oct 16 21:08:15 2009
@@ -348,6 +348,21 @@
                                              apr_sockaddr_t *sa);
 
 /**
+ * Determine whether the receive part of the socket has been closed by
+ * the peer (such that a subsequent call to apr_socket_read would
+ * return APR_EOF), if the socket's receive buffer is empty.  This
+ * function does not block waiting for I/O.
+ *
+ * @param socket The socket to check
+ * @param atreadeof If APR_SUCCESS is returned, *atreadeof is set to
+ *                  non-zero if a subsequent read would return APR_EOF
+ * @return an error is returned if it was not possible to determine the
+ *         status, in which case *atreadeof is not changed.
+ */
+APR_DECLARE(apr_status_t) apr_socket_atreadeof(apr_socket_t *sock,
+                                               int *atreadeof);
+
+/**
  * Create apr_sockaddr_t from hostname, address family, and port.
  * @param sa The new apr_sockaddr_t.
  * @param hostname The hostname or numeric address string to resolve/parse, or

Modified: apr/apr/branches/1.4.x/libapr.dsp
URL: http://svn.apache.org/viewvc/apr/apr/branches/1.4.x/libapr.dsp?rev=826089&r1=826088&r2=826089&view=diff
==============================================================================
--- apr/apr/branches/1.4.x/libapr.dsp (original)
+++ apr/apr/branches/1.4.x/libapr.dsp Fri Oct 16 21:08:15 2009
@@ -436,6 +436,10 @@
 # End Source File
 # Begin Source File
 
+SOURCE=.\network_io\unix\socket_util.c
+# End Source File
+# Begin Source File
+
 SOURCE=.\network_io\win32\sendrecv.c
 # End Source File
 # Begin Source File

Modified: apr/apr/branches/1.4.x/network_io/beos/socketcommon.c
URL: http://svn.apache.org/viewvc/apr/apr/branches/1.4.x/network_io/beos/socketcommon.c?rev=826089&r1=826088&r2=826089&view=diff
==============================================================================
--- apr/apr/branches/1.4.x/network_io/beos/socketcommon.c (original)
+++ apr/apr/branches/1.4.x/network_io/beos/socketcommon.c Fri Oct 16 21:08:15 2009
@@ -3,3 +3,4 @@
 #include "../unix/sockets.c"
 #include "../unix/sockaddr.c"
 #include "../unix/sockopt.c"
+#include "../unix/socket_util.c"

Copied: apr/apr/branches/1.4.x/network_io/unix/socket_util.c (from r821524, apr/apr/trunk/network_io/unix/socket_util.c)
URL: http://svn.apache.org/viewvc/apr/apr/branches/1.4.x/network_io/unix/socket_util.c?p2=apr/apr/branches/1.4.x/network_io/unix/socket_util.c&p1=apr/apr/trunk/network_io/unix/socket_util.c&r1=821524&r2=826089&rev=826089&view=diff
==============================================================================
--- apr/apr/trunk/network_io/unix/socket_util.c (original)
+++ apr/apr/branches/1.4.x/network_io/unix/socket_util.c Fri Oct 16 21:08:15 2009
@@ -17,41 +17,58 @@
 #include "apr_network_io.h"
 #include "apr_poll.h"
 
-int apr_socket_is_connected(apr_socket_t *socket)
+apr_status_t apr_socket_atreadeof(apr_socket_t *sock, int *atreadeof)
 {
     apr_pollfd_t pfds[1];
-    apr_status_t status;
+    apr_status_t rv;
     apr_int32_t  nfds;
 
+    /* The purpose here is to return APR_SUCCESS only in cases in
+     * which it can be unambiguously determined whether or not the
+     * socket will return EOF on next read.  In case of an unexpected
+     * error, return that. */
+
     pfds[0].reqevents = APR_POLLIN;
     pfds[0].desc_type = APR_POLL_SOCKET;
-    pfds[0].desc.s = socket;
+    pfds[0].desc.s = sock;
 
     do {
-        status = apr_poll(&pfds[0], 1, &nfds, 0);
-    } while (APR_STATUS_IS_EINTR(status));
+        rv = apr_poll(&pfds[0], 1, &nfds, 0);
+    } while (APR_STATUS_IS_EINTR(rv));
 
-    if (status == APR_SUCCESS && nfds == 1 &&
-        pfds[0].rtnevents == APR_POLLIN) {
+    if (APR_STATUS_IS_TIMEUP(rv)) {
+        /* Read buffer empty -> subsequent reads would block, so,
+         * definitely not at EOF. */
+        *atreadeof = 0;
+        return APR_SUCCESS;
+    }
+    else if (rv) {
+        /* Some other error -> unexpected error. */
+        return rv;
+    }
+    else if (nfds == 1 && pfds[0].rtnevents == APR_POLLIN) {
         apr_sockaddr_t unused;
         apr_size_t len = 1;
-        char buf[1];
-        /* The socket might be closed in which case
-         * the poll will return POLLIN.
-         * If there is no data available the socket
-         * is closed.
-         */
-        status = apr_socket_recvfrom(&unused, socket, MSG_PEEK,
-                                     &buf[0], &len);
-        if (status == APR_SUCCESS && len)
-            return 1;
-        else
-            return 0;
-    }
-    else if (APR_STATUS_IS_EAGAIN(status) || APR_STATUS_IS_TIMEUP(status)) {
-        return 1;
+        char buf;
+
+        /* The socket is readable - peek to see whether it returns EOF
+         * without consuming bytes from the socket buffer. */
+        rv = apr_socket_recvfrom(&unused, sock, MSG_PEEK, &buf, &len);
+        if (rv == APR_EOF) {
+            *atreadeof = 1;
+            return APR_SUCCESS;
+        }
+        else if (rv) {
+            /* Read error -> unexpected error. */
+            return rv;
+        }
+        else {
+            *atreadeof = 0;
+            return APR_SUCCESS;
+        }
     }
-    return 0;
 
+    /* Should not fall through here. */
+    return APR_EGENERAL;
 }
 

Modified: apr/apr/branches/1.4.x/test/sockchild.c
URL: http://svn.apache.org/viewvc/apr/apr/branches/1.4.x/test/sockchild.c?rev=826089&r1=826088&r2=826089&view=diff
==============================================================================
--- apr/apr/branches/1.4.x/test/sockchild.c (original)
+++ apr/apr/branches/1.4.x/test/sockchild.c Fri Oct 16 21:08:15 2009
@@ -76,5 +76,9 @@
         apr_socket_close(sock);
         exit((int)length);
     }
+    else if (!strcmp("close", argv[1])) {
+        apr_socket_close(sock);
+        exit(0);
+    }
     exit(-1);
 }

Modified: apr/apr/branches/1.4.x/test/testsock.c
URL: http://svn.apache.org/viewvc/apr/apr/branches/1.4.x/test/testsock.c?rev=826089&r1=826088&r2=826089&view=diff
==============================================================================
--- apr/apr/branches/1.4.x/test/testsock.c (original)
+++ apr/apr/branches/1.4.x/test/testsock.c Fri Oct 16 21:08:15 2009
@@ -198,6 +198,62 @@
     APR_ASSERT_SUCCESS(tc, "Problem closing socket", rv);
 }
 
+static void test_atreadeof(abts_case *tc, void *data)
+{
+    apr_status_t rv;
+    apr_socket_t *sock;
+    apr_socket_t *sock2;
+    apr_proc_t proc;
+    apr_size_t length = STRLEN;
+    char datastr[STRLEN];
+    int atreadeof = -1;
+
+    sock = setup_socket(tc);
+    if (!sock) return;
+
+    launch_child(tc, &proc, "write", p);
+
+    rv = apr_socket_accept(&sock2, sock, p);
+    APR_ASSERT_SUCCESS(tc, "Problem with receiving connection", rv);
+
+    /* Check that the remote socket is still open */
+    rv = apr_socket_atreadeof(sock2, &atreadeof);
+    APR_ASSERT_SUCCESS(tc, "Determine whether at EOF, #1", rv);
+    ABTS_INT_EQUAL(tc, 0, atreadeof);
+
+    memset(datastr, 0, STRLEN);
+    apr_socket_recv(sock2, datastr, &length);
+
+    /* Make sure that the server received the data we sent */
+    ABTS_STR_EQUAL(tc, DATASTR, datastr);
+    ABTS_SIZE_EQUAL(tc, strlen(datastr), wait_child(tc, &proc));
+
+    /* The child is dead, so should be the remote socket */
+    rv = apr_socket_atreadeof(sock2, &atreadeof);
+    APR_ASSERT_SUCCESS(tc, "Determine whether at EOF, #2", rv);
+    ABTS_INT_EQUAL(tc, 1, atreadeof);
+
+    rv = apr_socket_close(sock2);
+    APR_ASSERT_SUCCESS(tc, "Problem closing connected socket", rv);
+
+    launch_child(tc, &proc, "close", p);
+
+    rv = apr_socket_accept(&sock2, sock, p);
+    APR_ASSERT_SUCCESS(tc, "Problem with receiving connection", rv);
+
+    /* The child closed the socket instantly */
+    rv = apr_socket_atreadeof(sock2, &atreadeof);
+    APR_ASSERT_SUCCESS(tc, "Determine whether at EOF, #3", rv);
+    ABTS_INT_EQUAL(tc, 1, atreadeof);
+    wait_child(tc, &proc);
+
+    rv = apr_socket_close(sock2);
+    APR_ASSERT_SUCCESS(tc, "Problem closing connected socket", rv);
+
+    rv = apr_socket_close(sock);
+    APR_ASSERT_SUCCESS(tc, "Problem closing socket", rv);
+}
+
 static void test_timeout(abts_case *tc, void *data)
 {
     apr_status_t rv;
@@ -345,6 +401,7 @@
     abts_run_test(suite, test_create_bind_listen, NULL);
     abts_run_test(suite, test_send, NULL);
     abts_run_test(suite, test_recv, NULL);
+    abts_run_test(suite, test_atreadeof, NULL);
     abts_run_test(suite, test_timeout, NULL);
     abts_run_test(suite, test_print_addr, NULL);
     abts_run_test(suite, test_get_addr, NULL);