apr-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mt...@apache.org
Subject svn commit: r649390 - /apr/apr/trunk/file_io/win32/pipe.c
Date Fri, 18 Apr 2008 07:18:25 GMT
Author: mturk
Date: Fri Apr 18 00:18:23 2008
New Revision: 649390

URL: http://svn.apache.org/viewvc?rev=649390&view=rev
Log:
Implement apr_file_socket_pipe_create for windows. Private for implementing pollset_wakeup
caused by !APR_FILES_AS_SOCKETS

Modified:
    apr/apr/trunk/file_io/win32/pipe.c

Modified: apr/apr/trunk/file_io/win32/pipe.c
URL: http://svn.apache.org/viewvc/apr/apr/trunk/file_io/win32/pipe.c?rev=649390&r1=649389&r2=649390&view=diff
==============================================================================
--- apr/apr/trunk/file_io/win32/pipe.c (original)
+++ apr/apr/trunk/file_io/win32/pipe.c Fri Apr 18 00:18:23 2008
@@ -225,3 +225,186 @@
 {
     return apr_os_pipe_put_ex(file, thefile, 0, pool);
 }
+
+static apr_status_t create_socket_pipe(SOCKET *rd, SOCKET *wr)
+{
+    static int id = 0;
+
+    SOCKET ls;
+    struct sockaddr_in pa;
+    struct sockaddr_in la;
+    struct sockaddr_in ca;
+    int nrd;
+    apr_status_t rv = APR_SUCCESS;
+    int ll = sizeof(la);
+    int lc = sizeof(ca);
+    int bm = 1;
+    int uid[2];
+    int iid[2];
+
+    *rd = INVALID_SOCKET;
+    *wr = INVALID_SOCKET;
+
+    /* Create the unique socket identifier
+     * so that we know the connection originated
+     * from us.
+     */
+    uid[0] = getpid();
+    uid[1] = id++;
+    if ((ls = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {
+        return apr_get_netos_error();
+    }
+
+    pa.sin_family = AF_INET;
+    pa.sin_port   = 0;
+    pa.sin_addr.s_addr = inet_addr("127.0.0.1");
+
+    if (bind(ls, (SOCKADDR *)&pa, sizeof(pa)) == SOCKET_ERROR) {
+        rv =  apr_get_netos_error();
+        goto cleanup;
+    }
+    if (getsockname(ls, (SOCKADDR *)&la, &ll) == SOCKET_ERROR) {
+        rv =  apr_get_netos_error();
+        goto cleanup;
+    }
+    if (listen(ls, 1) == SOCKET_ERROR) {
+        rv =  apr_get_netos_error();
+        goto cleanup;
+    }
+    if ((*wr = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {
+        rv = apr_get_netos_error();
+        goto cleanup;
+    }
+    if (connect(*wr, (SOCKADDR *)&la, sizeof(la)) == SOCKET_ERROR) {
+        rv =  apr_get_netos_error();
+        goto cleanup;
+    }
+    if (send(*wr, (char *)uid, sizeof(uid), 0) != sizeof(uid)) {
+        if ((rv =  apr_get_netos_error()) == 0) {
+            rv = APR_EINVAL;
+        }
+        goto cleanup;
+    }
+    if (ioctlsocket(ls, FIONBIO, &bm) == SOCKET_ERROR) {
+        rv = apr_get_netos_error();
+        goto cleanup;
+    }
+    for (;;) {
+        /* Listening socket is nonblocking by now.
+         * The accept must create the socket
+         * immediatelly because we connected already.
+         */
+        if ((*rd = accept(ls, (SOCKADDR *)&ca, &lc)) == INVALID_SOCKET) {
+            rv =  apr_get_netos_error();
+            goto cleanup;
+        }
+        /* Verify the connection by reading the send identification.
+         */
+        nrd = recv(*rd, (char *)iid, sizeof(iid), 0);
+        if (nrd == sizeof(iid)) {
+            if (memcmp(uid, iid, sizeof(uid)) == 0) {
+                /* Wow, we recived what we send.
+                 * Put read side of the pipe to the blocking
+                 * mode and return.
+                 */
+                bm = 0;
+                if (ioctlsocket(*rd, FIONBIO, &bm) == SOCKET_ERROR) {
+                    rv = apr_get_netos_error();
+                    goto cleanup;
+                }
+                break;
+            }
+        }
+        else if (nrd == SOCKET_ERROR) {
+            rv =  apr_get_netos_error();
+            goto cleanup;
+        }
+        closesocket(*rd);
+    }
+    /* We don't need the listening socket any more */
+    closesocket(ls);
+    return 0;
+
+cleanup:
+    /* Don't leak resources */
+    if (*rd != INVALID_SOCKET)
+        closesocket(*rd);
+    if (*wr != INVALID_SOCKET)
+        closesocket(*wr);
+
+    *rd = INVALID_SOCKET;
+    *wr = INVALID_SOCKET;
+    closesocket(ls);
+    return rv;
+}
+
+static apr_status_t socket_pipe_cleanup(void *thefile)
+{
+    apr_file_t *file = thefile;
+    if (file->filehand != INVALID_HANDLE_VALUE) {
+        shutdown((SOCKET)file->filehand, SD_BOTH);
+        closesocket((SOCKET)file->filehand);
+        file->filehand = INVALID_HANDLE_VALUE;
+    }
+    return APR_SUCCESS;
+}
+
+#if 0
+/* XXX Do we need this as public API or APR private ?
+ * It's main usage is for interrupting pollset because
+ * of !APR_FILES_AS_SOCKETS.
+ * Duplicating sockets in child requires WSADuplicateSocket
+ * and passing WSAPROTOCOL_INFO data to the child, so we
+ * would need some sort of IPC instead DuplicateHandle used
+ * for files and pipes.
+ */
+APR_DECLARE(apr_status_t)
+#else
+apr_status_t
+#endif
+apr_file_socket_pipe_create(apr_file_t **in,
+                            apr_file_t **out,
+                            apr_pool_t *p)
+{
+    apr_status_t rv;
+    SOCKET rd;
+    SOCKET wr;
+
+    if ((rv = create_socket_pipe(&rd, &wr)) != APR_SUCCESS) {
+        return rv;
+    }
+    (*in) = (apr_file_t *)apr_pcalloc(p, sizeof(apr_file_t));
+    (*in)->pool = p;
+    (*in)->fname = NULL;
+    (*in)->pipe = 1;
+    (*in)->timeout = -1;
+    (*in)->ungetchar = -1;
+    (*in)->eof_hit = 0;
+    (*in)->filePtr = 0;
+    (*in)->bufpos = 0;
+    (*in)->dataRead = 0;
+    (*in)->direction = 0;
+    (*in)->pOverlapped = (OVERLAPPED*)apr_pcalloc(p, sizeof(OVERLAPPED));
+    (*in)->filehand = (HANDLE)rd;
+
+    (*out) = (apr_file_t *)apr_pcalloc(p, sizeof(apr_file_t));
+    (*out)->pool = p;
+    (*out)->fname = NULL;
+    (*out)->pipe = 1;
+    (*out)->timeout = -1;
+    (*out)->ungetchar = -1;
+    (*out)->eof_hit = 0;
+    (*out)->filePtr = 0;
+    (*out)->bufpos = 0;
+    (*out)->dataRead = 0;
+    (*out)->direction = 0;
+    (*out)->pOverlapped = (OVERLAPPED*)apr_pcalloc(p, sizeof(OVERLAPPED));
+    (*out)->filehand = (HANDLE)wr;
+
+    apr_pool_cleanup_register(p, (void *)(*in), socket_pipe_cleanup,
+                              apr_pool_cleanup_null);
+    apr_pool_cleanup_register(p, (void *)(*out), socket_pipe_cleanup,
+                              apr_pool_cleanup_null);
+
+    return rv;
+}



Mime
View raw message