From 7edf76569718d25b9fd95593df8be31a5386157d Mon Sep 17 00:00:00 2001 From: Olaf Rempel Date: Thu, 28 Dec 2006 20:22:13 +0100 Subject: [PATCH] nonblocking connect() - part 1 --- connection.c | 27 ++++++++++++++++++++++++--- network.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- network.h | 1 + 3 files changed, 73 insertions(+), 5 deletions(-) diff --git a/connection.c b/connection.c index 2e5f8ee..3f656b7 100644 --- a/connection.c +++ b/connection.c @@ -44,6 +44,8 @@ static struct connection * create_connection() static int destroy_connection(struct connection *con) { + // TODO: detroy connect-timeout? + if (con->src_fd != -1) { close(con->src_fd); event_remove_fd(con->src_fd); @@ -81,6 +83,24 @@ static int forward_handler(int fd, void *privdata) return 0; } +static int connect_handler(int fd, void *privdata) +{ + struct connection *con = (struct connection *)privdata; + + if (tcp_connect_error(fd)) { + list_del(&con->list); + destroy_connection(con); + return -1; + } + + log_print(LOG_INFO, "forwarding to %s", get_sockaddr_buf(&con->dst_addr)); + event_add_readfd(con->dst_fd, forward_handler, con); + event_add_readfd(con->src_fd, forward_handler, con); + + /* dismiss connect_handler */ + return -1; +} + static int client_handler(int fd, void *privdata) { struct connection *con = (struct connection *)privdata; @@ -107,9 +127,10 @@ static int client_handler(int fd, void *privdata) return -1; } - log_print(LOG_INFO, "forwarding to %s", get_sockaddr_buf(&con->dst_addr)); - event_add_readfd(con->dst_fd, forward_handler, con); - event_add_readfd(con->src_fd, forward_handler, con); + // TODO: start connect timeout, callback destroys connection + + log_print(LOG_INFO, "connecting to %s", get_sockaddr_buf(&con->dst_addr)); + event_add_writefd(con->dst_fd, connect_handler, con); /* dismiss client_handler */ return -1; diff --git a/network.c b/network.c index 9c3823f..96b569e 100644 --- a/network.c +++ b/network.c @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include "logging.h" @@ -56,7 +58,7 @@ int tcp_listen_socket(struct sockaddr_in *sa) return -1; } - int i = 1; + int i = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i))) { log_print(LOG_ERROR, "tcp_listen_socket(): setsockopt(SO_REUSEADDR)"); close(sock); @@ -85,10 +87,54 @@ int tcp_connect_socket(struct sockaddr_in *sa) return -1; } - if (connect(sock, (struct sockaddr *)sa, sizeof(*sa))) { + int flags = fcntl(sock, F_GETFL, 0); + if (flags < 0) { + log_print(LOG_ERROR, "tcp_connect_socket(): fcntl(F_GETFL)"); + close(sock); + return -1; + } + + /* non-blocking */ + if (fcntl(sock, F_SETFL, flags | O_NONBLOCK)) { + log_print(LOG_ERROR, "tcp_connect_socket(): fcntl(F_SETFL)"); + close(sock); + return -1; + } + + int ret = connect(sock, (struct sockaddr *)sa, sizeof(*sa)); + if (ret && errno != EINPROGRESS) { log_print(LOG_ERROR, "tcp_connect_socket(): bind(%s)", get_sockaddr_buf(sa)); close(sock); return -1; } + + /* reset EINPROGRESS */ + errno = 0; + + /* blocking */ + if (fcntl(sock, F_SETFL, flags)) { + log_print(LOG_ERROR, "tcp_connect_socket(): fcntl(F_SETFL)"); + close(sock); + return -1; + } + return sock; } + +int tcp_connect_error(int fd) +{ + int err; + unsigned int err_size = sizeof(err); + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &err_size)) { + log_print(LOG_ERROR, "tcp_connect_error(): getsockopt(SO_ERROR)"); + return -1; + } + + if (err) { + errno = err; + log_print(LOG_ERROR, "tcp_connect_error()"); + return -1; + } + + return 0; +} diff --git a/network.h b/network.h index 3c9b5ea..bee2acc 100644 --- a/network.h +++ b/network.h @@ -6,6 +6,7 @@ int parse_saddr(const char *addr, struct sockaddr_in *sa); int tcp_listen_socket(struct sockaddr_in *sa); int tcp_connect_socket(struct sockaddr_in *sa); +int tcp_connect_error(int fd); int get_sockaddr(struct sockaddr_in *sa, char *buf, int size); char * get_sockaddr_buf(struct sockaddr_in *sa);