control socket added to pass headers and other socket related data
authorMatteo Nastasi (mop) <nastasi@alternativeoutput.com>
Thu, 28 Jun 2012 05:33:47 +0000 (07:33 +0200)
committerMatteo Nastasi (mop) <nastasi@alternativeoutput.com>
Thu, 28 Jun 2012 05:33:47 +0000 (07:33 +0200)
mod_proxy_fdpass.c

index e2eacce..ff7ddbc 100644 (file)
@@ -160,18 +160,26 @@ static apr_status_t get_socket_from_path(request_rec *r, apr_pool_t *p,
     return APR_SUCCESS;
 }
 
+#define ANCIL_FD_BUFFER(n) \
+    struct { \
+       struct cmsghdr h; \
+       int fd[n]; \
+    }
 
 static apr_status_t send_socket(apr_pool_t *p,
                                 apr_socket_t *s,
-                                apr_socket_t *outbound)
+                                apr_socket_t *outbound,
+                                apr_socket_t *ctrlsock)
 {
     apr_status_t rv;
     apr_os_sock_t rawsock;
     apr_os_sock_t srawsock;
+    apr_os_sock_t sctrlsock;
     struct msghdr msg;
     struct cmsghdr *cmsg;
     struct iovec iov;
     char b = '\0', *buf;
+    ANCIL_FD_BUFFER(2) ancil_buf;
 
     {
         int mop_fd;
@@ -193,6 +201,11 @@ static apr_status_t send_socket(apr_pool_t *p,
     if (rv != APR_SUCCESS) {
         return rv;
     }
+
+    rv = apr_os_sock_get(&sctrlsock, ctrlsock);
+    if (rv != APR_SUCCESS) {
+        return rv;
+    }
     
     {
         int mop_fd;
@@ -214,15 +227,17 @@ static apr_status_t send_socket(apr_pool_t *p,
     iov.iov_base = &b;
     iov.iov_len = 1;
 
-    cmsg = apr_palloc(p, sizeof(*cmsg) + sizeof(rawsock));
-    cmsg->cmsg_len = sizeof(*cmsg) + sizeof(rawsock);
+    msg.msg_control = &ancil_buf;
+    msg.msg_controllen = sizeof(struct cmsghdr) + sizeof(rawsock) * 2;
+
+    // cmsg = apr_palloc(p, sizeof(*cmsg) + sizeof(rawsock));
+    cmsg = CMSG_FIRSTHDR(&msg);
+    cmsg->cmsg_len = sizeof(*cmsg) + sizeof(rawsock) * 2;
     cmsg->cmsg_level = SOL_SOCKET;
     cmsg->cmsg_type = SCM_RIGHTS;
 
-    memcpy(CMSG_DATA(cmsg), &rawsock, sizeof(rawsock));
-
-    msg.msg_control = cmsg;
-    msg.msg_controllen = cmsg->cmsg_len;
+    ((int *)CMSG_DATA(cmsg))[0] = rawsock;
+    ((int *)CMSG_DATA(cmsg))[1] = sctrlsock;
 
     rv = sendmsg(srawsock, &msg, 0);
 
@@ -266,6 +281,8 @@ static int proxy_fdpass_handler(request_rec *r, proxy_worker *worker,
     apr_socket_t *clientsock;
     char *buf;
     char *headers_out = NULL;
+    int ctrlrawsock[2];
+    apr_socket_t *ctrlsock = NULL, *clientctrlsock = NULL;
 
     if ((headers_out = calloc(8*1024, 1)) != NULL) {
         apr_table_do(headers_builder, headers_out, r->headers_in, NULL);
@@ -303,6 +320,25 @@ static int proxy_fdpass_handler(request_rec *r, proxy_worker *worker,
         return HTTP_INTERNAL_SERVER_ERROR;
     }
 
+    /* create a couple of sockets and pass one to the client for headers and so on */
+    if (socketpair(AF_UNIX, SOCK_STREAM, 0, ctrlrawsock)) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+                      "proxy: FD: Failed create socketpair");
+        return HTTP_INTERNAL_SERVER_ERROR;
+    }
+    rv = apr_os_sock_put(&ctrlsock, &(ctrlrawsock[0]), r->connection->pool);
+    if (rv != APR_SUCCESS) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+                      "proxy: FD: apr_os_sock_put failed");
+        return HTTP_INTERNAL_SERVER_ERROR;
+    }
+    rv = apr_os_sock_put(&clientctrlsock, &(ctrlrawsock[1]), r->connection->pool);
+    if (rv != APR_SUCCESS) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+                      "proxy: FD: apr_os_sock_put failed");
+        return HTTP_INTERNAL_SERVER_ERROR;
+    }
+
     {
         int status;
         /* const char *flush_method = worker->flusher ? worker->flusher : "flush"; */
@@ -333,7 +369,7 @@ static int proxy_fdpass_handler(request_rec *r, proxy_worker *worker,
     /* There should really be a (documented) public API for this ! */
     clientsock = ap_get_module_config(r->connection->conn_config, &core_module);
 
-    rv = send_socket(r->pool, sock, clientsock);
+    rv = send_socket(r->pool, sock, clientsock, clientctrlsock);
     if (rv != APR_SUCCESS) {
         ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
                       "proxy: FD: send_socket failed:");