diff options
author | mturk <mturk@13f79535-47bb-0310-9956-ffa450edef68> | 2008-04-18 07:18:23 +0000 |
---|---|---|
committer | mturk <mturk@13f79535-47bb-0310-9956-ffa450edef68> | 2008-04-18 07:18:23 +0000 |
commit | 6bc626f8f1151f6a5cefed86190a5788395c9522 (patch) | |
tree | 61662482dd1e6ddc94dd592e020e4961cb585b14 | |
parent | 9daac95ce34bf3b58fb859ad33f0ced925b0a7a6 (diff) | |
download | libapr-6bc626f8f1151f6a5cefed86190a5788395c9522.tar.gz |
Implement apr_file_socket_pipe_create for windows. Private for implementing pollset_wakeup caused by !APR_FILES_AS_SOCKETS
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@649390 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r-- | file_io/win32/pipe.c | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/file_io/win32/pipe.c b/file_io/win32/pipe.c index ee3a07fa1..5598acdf8 100644 --- a/file_io/win32/pipe.c +++ b/file_io/win32/pipe.c @@ -225,3 +225,186 @@ APR_DECLARE(apr_status_t) apr_os_pipe_put(apr_file_t **file, { 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; +} |