diff options
Diffstat (limited to 'src/tcp_connect.c')
-rw-r--r-- | src/tcp_connect.c | 250 |
1 files changed, 0 insertions, 250 deletions
diff --git a/src/tcp_connect.c b/src/tcp_connect.c deleted file mode 100644 index 291114f4b..000000000 --- a/src/tcp_connect.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (C) 2003-2011 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" -#include "tcp_connect.h" -#include "fd_util.h" -#include "io_thread.h" -#include "glib_socket.h" - -#include <assert.h> -#include <errno.h> - -#ifdef WIN32 -#include <ws2tcpip.h> -#include <winsock.h> -#else -#include <sys/socket.h> -#include <unistd.h> -#endif - -struct tcp_connect { - const struct tcp_connect_handler *handler; - void *handler_ctx; - - int fd; - GSource *source; - - unsigned timeout_ms; - GSource *timeout_source; -}; - -static bool -is_in_progress_errno(int e) -{ -#ifdef WIN32 - return e == WSAEINPROGRESS || e == WSAEWOULDBLOCK; -#else - return e == EINPROGRESS; -#endif -} - -static gboolean -tcp_connect_event(G_GNUC_UNUSED GIOChannel *source, - G_GNUC_UNUSED GIOCondition condition, - gpointer data) -{ - struct tcp_connect *c = data; - - assert(c->source != NULL); - assert(c->timeout_source != NULL); - - /* clear the socket source */ - g_source_unref(c->source); - c->source = NULL; - - /* delete the timeout source */ - g_source_destroy(c->timeout_source); - g_source_unref(c->timeout_source); - c->timeout_source = NULL; - - /* obtain the connect result */ - int s_err = 0; - socklen_t s_err_size = sizeof(s_err); - if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, - (char*)&s_err, &s_err_size) < 0) - s_err = errno; - - if (s_err == 0) { - /* connection established successfully */ - - c->handler->success(c->fd, c->handler_ctx); - } else { - /* there was an I/O error; close the socket and pass - the error to the handler */ - - close_socket(c->fd); - - GError *error = - g_error_new_literal(g_file_error_quark(), s_err, - g_strerror(s_err)); - c->handler->error(error, c->handler_ctx); - } - - return false; -} - -static gboolean -tcp_connect_timeout(gpointer data) -{ - struct tcp_connect *c = data; - - assert(c->source != NULL); - assert(c->timeout_source != NULL); - - /* clear the timeout source */ - g_source_unref(c->timeout_source); - c->timeout_source = NULL; - - /* delete the socket source */ - g_source_destroy(c->source); - g_source_unref(c->source); - c->source = NULL; - - /* report timeout to handler */ - c->handler->timeout(c->handler_ctx); - - return false; -} - -static gpointer -tcp_connect_init(gpointer data) -{ - struct tcp_connect *c = data; - - /* create a connect source */ - GIOChannel *channel = g_io_channel_new_socket(c->fd); - c->source = g_io_create_watch(channel, G_IO_OUT); - g_io_channel_unref(channel); - - g_source_set_callback(c->source, (GSourceFunc)tcp_connect_event, c, - NULL); - g_source_attach(c->source, io_thread_context()); - - /* create a timeout source */ - if (c->timeout_ms > 0) - c->timeout_source = - io_thread_timeout_add(c->timeout_ms, - tcp_connect_timeout, c); - - return NULL; -} - -void -tcp_connect_address(const struct sockaddr *address, size_t address_length, - unsigned timeout_ms, - const struct tcp_connect_handler *handler, void *ctx, - struct tcp_connect **handle_r) -{ - assert(address != NULL); - assert(address_length > 0); - assert(handler != NULL); - assert(handler->success != NULL); - assert(handler->error != NULL); - assert(handler->canceled != NULL); - assert(handler->timeout != NULL || timeout_ms == 0); - assert(handle_r != NULL); - assert(*handle_r == NULL); - - int fd = socket_cloexec_nonblock(address->sa_family, SOCK_STREAM, 0); - if (fd < 0) { - GError *error = - g_error_new_literal(g_file_error_quark(), errno, - g_strerror(errno)); - handler->error(error, ctx); - return; - } - - int ret = connect(fd, address, address_length); - if (ret >= 0) { - /* quick connect, no I/O thread */ - handler->success(fd, ctx); - return; - } - - if (!is_in_progress_errno(errno)) { - GError *error = - g_error_new_literal(g_file_error_quark(), errno, - g_strerror(errno)); - close_socket(fd); - handler->error(error, ctx); - return; - } - - /* got EINPROGRESS, use the I/O thread to wait for the - operation to finish */ - - struct tcp_connect *c = g_new(struct tcp_connect, 1); - c->handler = handler; - c->handler_ctx = ctx; - c->fd = fd; - c->source = NULL; - c->timeout_ms = timeout_ms; - c->timeout_source = NULL; - - *handle_r = c; - - io_thread_call(tcp_connect_init, c); -} - -static gpointer -tcp_connect_cancel_callback(gpointer data) -{ - struct tcp_connect *c = data; - - assert((c->source == NULL) == (c->timeout_source == NULL)); - - if (c->source == NULL) - return NULL; - - /* delete the socket source */ - g_source_destroy(c->source); - g_source_unref(c->source); - c->source = NULL; - - /* delete the timeout source */ - g_source_destroy(c->timeout_source); - g_source_unref(c->timeout_source); - c->timeout_source = NULL; - - /* close the socket */ - close_socket(c->fd); - - /* notify the handler */ - c->handler->canceled(c->handler_ctx); - - return NULL; -} - -void -tcp_connect_cancel(struct tcp_connect *c) -{ - if (c->source == NULL) - return; - - io_thread_call(tcp_connect_cancel_callback, c); -} - -void -tcp_connect_free(struct tcp_connect *c) -{ - assert(c->source == NULL); - - g_free(c); -} |