summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormturk <mturk@13f79535-47bb-0310-9956-ffa450edef68>2008-04-18 07:18:23 +0000
committermturk <mturk@13f79535-47bb-0310-9956-ffa450edef68>2008-04-18 07:18:23 +0000
commit6bc626f8f1151f6a5cefed86190a5788395c9522 (patch)
tree61662482dd1e6ddc94dd592e020e4961cb585b14
parent9daac95ce34bf3b58fb859ad33f0ced925b0a7a6 (diff)
downloadlibapr-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.c183
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;
+}