X-Git-Url: https://tinc-vpn.org/git/browse?p=tinc;a=blobdiff_plain;f=src%2Fnet_socket.c;h=9c8ef05ab53c85a911b6343c9b0ed13a26e0bdf6;hp=3d1be21ec84113319739dc5c9efe76489a0c6446;hb=f02d3ed3e135b5326003e7f69f8331ff6a3cc219;hpb=42e01abd54bd36ee84a45a2b646cfa27034de8d1 diff --git a/src/net_socket.c b/src/net_socket.c index 3d1be21e..9c8ef05a 100644 --- a/src/net_socket.c +++ b/src/net_socket.c @@ -1,7 +1,7 @@ /* net_socket.c -- Handle various kinds of sockets. - Copyright (C) 1998-2003 Ivo Timmermans , - 2000-2003 Guus Sliepen + Copyright (C) 1998-2005 Ivo Timmermans, + 2000-2007 Guus Sliepen 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 @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: net_socket.c,v 1.1.2.38 2003/12/22 11:04:16 guus Exp $ + $Id$ */ #include "system.h" @@ -25,7 +25,6 @@ #include "avl_tree.h" #include "conf.h" #include "connection.h" -#include "event.h" #include "logger.h" #include "meta.h" #include "net.h" @@ -38,6 +37,11 @@ #define EINPROGRESS WSAEINPROGRESS #endif +/* Needed on Mac OS/X */ +#ifndef SOL_TCP +#define SOL_TCP IPPROTO_TCP +#endif + int addressfamily = AF_UNSPEC; int maxtimeout = 900; int seconds_till_retry = 5; @@ -47,8 +51,35 @@ int listen_sockets; /* Setup sockets */ -int setup_listen_socket(const sockaddr_t *sa) -{ +static void configure_tcp(connection_t *c) { + int option; + +#ifdef O_NONBLOCK + int flags = fcntl(c->socket, F_GETFL); + + if(fcntl(c->socket, F_SETFL, flags | O_NONBLOCK) < 0) { + logger(LOG_ERR, _("fcntl for %s: %s"), c->hostname, strerror(errno)); + } +#elif defined(WIN32) + unsigned long arg = 1; + + if(ioctlsocket(c->socket, FIONBIO, &arg) != 0) { + logger(LOG_ERR, _("ioctlsocket for %s: WSA error %d"), c->hostname, WSAGetLastError()); + } +#endif + +#if defined(SOL_TCP) && defined(TCP_NODELAY) + option = 1; + setsockopt(c->socket, SOL_TCP, TCP_NODELAY, &option, sizeof(option)); +#endif + +#if defined(SOL_IP) && defined(IP_TOS) && defined(IPTOS_LOWDELAY) + option = IPTOS_LOWDELAY; + setsockopt(c->socket, SOL_IP, IP_TOS, &option, sizeof(option)); +#endif +} + +int setup_listen_socket(const sockaddr_t *sa) { int nfd; char *addrstr; int option; @@ -63,33 +94,11 @@ int setup_listen_socket(const sockaddr_t *sa) return -1; } -#ifdef O_NONBLOCK - { - int flags = fcntl(nfd, F_GETFL); - - if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) { - closesocket(nfd); - logger(LOG_ERR, _("System call `%s' failed: %s"), "fcntl", - strerror(errno)); - return -1; - } - } -#endif - /* Optimize TCP settings */ option = 1; setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option)); -#if defined(SOL_TCP) && defined(TCP_NODELAY) - setsockopt(nfd, SOL_TCP, TCP_NODELAY, &option, sizeof(option)); -#endif - -#if defined(SOL_IP) && defined(IP_TOS) && defined(IPTOS_LOWDELAY) - option = IPTOS_LOWDELAY; - setsockopt(nfd, SOL_IP, IP_TOS, &option, sizeof(option)); -#endif - if(get_config_string (lookup_config(config_tree, "BindToInterface"), &iface)) { #if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE) @@ -128,8 +137,7 @@ int setup_listen_socket(const sockaddr_t *sa) return nfd; } -int setup_vpn_in_socket(const sockaddr_t *sa) -{ +int setup_vpn_in_socket(const sockaddr_t *sa) { int nfd; char *addrstr; int option; @@ -154,6 +162,16 @@ int setup_vpn_in_socket(const sockaddr_t *sa) return -1; } } +#elif defined(WIN32) + { + unsigned long arg = 1; + if(ioctlsocket(nfd, FIONBIO, &arg) != 0) { + closesocket(nfd); + logger(LOG_ERR, _("Call to `%s' failed: WSA error %d"), "ioctlsocket", + WSAGetLastError()); + return -1; + } + } #endif option = 1; @@ -212,10 +230,11 @@ int setup_vpn_in_socket(const sockaddr_t *sa) return nfd; } -void retry_outgoing(outgoing_t *outgoing) -{ - event_t *event; +static void retry_outgoing_handler(int fd, short events, void *data) { + do_outgoing_connection(data); +} +void retry_outgoing(outgoing_t *outgoing) { cp(); outgoing->timeout += 5; @@ -223,32 +242,30 @@ void retry_outgoing(outgoing_t *outgoing) if(outgoing->timeout > maxtimeout) outgoing->timeout = maxtimeout; - event = new_event(); - event->handler = (event_handler_t) setup_outgoing_connection; - event->time = now + outgoing->timeout; - event->data = outgoing; - event_add(event); + timeout_set(&outgoing->ev, retry_outgoing_handler, outgoing); + event_add(&outgoing->ev, &(struct timeval){outgoing->timeout, 0}); ifdebug(CONNECTIONS) logger(LOG_NOTICE, _("Trying to re-establish outgoing connection in %d seconds"), outgoing->timeout); } -void finish_connecting(connection_t *c) -{ +void finish_connecting(connection_t *c) { cp(); ifdebug(CONNECTIONS) logger(LOG_INFO, _("Connected to %s (%s)"), c->name, c->hostname); - c->last_ping_time = now; + configure_tcp(c); + + c->last_ping_time = time(NULL); + c->status.connecting = false; send_id(c); } -void do_outgoing_connection(connection_t *c) -{ +void do_outgoing_connection(connection_t *c) { char *address, *port; - int option, result, flags; + int result; cp(); @@ -303,32 +320,18 @@ begin: /* Optimize TCP settings */ -#if defined(SOL_TCP) && defined(TCP_NODELAY) - option = 1; - setsockopt(c->socket, SOL_TCP, TCP_NODELAY, &option, sizeof(option)); -#endif - -#if defined(SOL_IP) && defined(IP_TOS) - option = IPTOS_LOWDELAY; - setsockopt(c->socket, SOL_IP, IP_TOS, &option, sizeof(option)); -#endif - - /* Non-blocking */ - -#ifdef O_NONBLOCK - flags = fcntl(c->socket, F_GETFL); - - if(fcntl(c->socket, F_SETFL, flags | O_NONBLOCK) < 0) { - logger(LOG_ERR, _("fcntl for %s: %s"), c->hostname, strerror(errno)); - } -#endif + configure_tcp(c); /* Connect */ result = connect(c->socket, &c->address.sa, SALEN(c->address.sa)); if(result == -1) { - if(errno == EINPROGRESS) { + if(errno == EINPROGRESS +#if defined(WIN32) && !defined(O_NONBLOCK) + || WSAGetLastError() == WSAEWOULDBLOCK +#endif + ) { c->status.connecting = true; return; } @@ -345,8 +348,7 @@ begin: return; } -void setup_outgoing_connection(outgoing_t *outgoing) -{ +void setup_outgoing_connection(outgoing_t *outgoing) { connection_t *c; node_t *n; @@ -383,36 +385,43 @@ void setup_outgoing_connection(outgoing_t *outgoing) } c->outgoing = outgoing; - c->last_ping_time = now; + c->last_ping_time = time(NULL); connection_add(c); do_outgoing_connection(c); + + event_set(&c->ev, c->socket, EV_READ | EV_PERSIST, handle_meta_connection_data, c); + event_set(&c->outev, c->socket, EV_WRITE | EV_PERSIST, flush_meta, c); + if(event_add(&c->ev, NULL) < 0) { + logger(LOG_EMERG, _("event_add failed: %s"), strerror(errno)); + abort(); + } } /* accept a new tcp connect and create a new connection */ -bool handle_new_meta_connection(int sock) -{ +void handle_new_meta_connection(int sock, short events, void *data) { connection_t *c; sockaddr_t sa; - int fd, len = sizeof(sa); + int fd; + socklen_t len = sizeof(sa); cp(); fd = accept(sock, &sa.sa, &len); if(fd < 0) { - logger(LOG_ERR, _("Accepting a new connection failed: %s"), - strerror(errno)); - return false; + logger(LOG_ERR, _("Accepting a new connection failed: %s"), strerror(errno)); + return; } sockaddrunmap(&sa); c = new_connection(); + c->name = xstrdup(""); c->outcipher = myself->connection->outcipher; c->outdigest = myself->connection->outdigest; c->outmaclength = myself->connection->outmaclength; @@ -421,28 +430,34 @@ bool handle_new_meta_connection(int sock) c->address = sa; c->hostname = sockaddr2hostname(&sa); c->socket = fd; - c->last_ping_time = now; + c->last_ping_time = time(NULL); ifdebug(CONNECTIONS) logger(LOG_NOTICE, _("Connection from %s"), c->hostname); + event_set(&c->ev, c->socket, EV_READ | EV_PERSIST, handle_meta_connection_data, c); + event_set(&c->outev, c->socket, EV_WRITE | EV_PERSIST, flush_meta, c); + if(event_add(&c->ev, NULL) < 0) { + logger(LOG_ERR, _("event_add failed: %s"), strerror(errno)); + connection_del(c); + return; + } + + configure_tcp(c); + connection_add(c); c->allow_request = ID; send_id(c); - - return true; } -void try_outgoing_connections(void) -{ +void try_outgoing_connections(void) { static config_t *cfg = NULL; char *name; outgoing_t *outgoing; cp(); - for(cfg = lookup_config(config_tree, "ConnectTo"); cfg; - cfg = lookup_config_next(config_tree, cfg)) { + for(cfg = lookup_config(config_tree, "ConnectTo"); cfg; cfg = lookup_config_next(config_tree, cfg)) { get_config_string(cfg, &name); if(!check_id(name)) {