X-Git-Url: https://tinc-vpn.org/git/browse?a=blobdiff_plain;f=src%2Fnet_socket.c;h=8983d2895aede8dc603dcb164cd3e2e1d6c96629;hb=34ea20af73a35cd918ce9dc25796bebf9493b49c;hp=939aa9c4577b8e15d794e82aca1f3b43938e0c1b;hpb=0c026f3c6dec784c3267ad7e2c4709d5393dc292;p=tinc diff --git a/src/net_socket.c b/src/net_socket.c index 939aa9c4..8983d289 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-2005 Ivo Timmermans, - 2000-2014 Guus Sliepen + 2000-2016 Guus Sliepen 2006 Scott Lamb 2009 Florian Forster @@ -43,8 +43,8 @@ int addressfamily = AF_UNSPEC; int maxtimeout = 900; int seconds_till_retry = 5; -int udp_rcvbuf = 0; -int udp_sndbuf = 0; +int udp_rcvbuf = 1024 * 1024; +int udp_sndbuf = 1024 * 1024; int max_connection_burst = 100; listen_socket_t listen_socket[MAXSOCKETS]; @@ -82,6 +82,11 @@ static void configure_tcp(connection_t *c) { option = IPTOS_LOWDELAY; setsockopt(c->socket, SOL_IP, IP_TOS, (void *)&option, sizeof option); #endif + +#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS) && defined(IPTOS_LOWDELAY) + option = IPTOS_LOWDELAY; + setsockopt(c->socket, IPPROTO_IPV6, IPV6_TCLASS, (void *)&option, sizeof option); +#endif } static bool bind_to_interface(int sd) { @@ -388,7 +393,7 @@ static void handle_meta_write(connection_t *c) { logger(DEBUG_CONNECTIONS, LOG_ERR, "Could not send %d bytes of data to %s (%s): %s", c->outbuf.len - c->outbuf.offset, c->name, c->hostname, sockstrerror(sockerrno)); } - terminate_connection(c, c->status.active); + terminate_connection(c, c->edge); return; } @@ -401,19 +406,38 @@ static void handle_meta_io(void *data, int flags) { connection_t *c = data; if(c->status.connecting) { - c->status.connecting = false; - - int result; - socklen_t len = sizeof result; - getsockopt(c->socket, SOL_SOCKET, SO_ERROR, (void *)&result, &len); - - if(!result) - finish_connecting(c); - else { - logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Error while connecting to %s (%s): %s", c->name, c->hostname, sockstrerror(result)); - terminate_connection(c, false); + /* + The event loop does not protect against spurious events. Verify that we are actually connected + by issuing an empty send() call. + + Note that the behavior of send() on potentially unconnected sockets differ between platforms: + +------------+-----------+-------------+-----------+ + | Event | POSIX | Linux | Windows | + +------------+-----------+-------------+-----------+ + | Spurious | ENOTCONN | EWOULDBLOCK | ENOTCONN | + | Failed | ENOTCONN | (cause) | ENOTCONN | + | Successful | (success) | (success) | (success) | + +------------+-----------+-------------+-----------+ + */ + if (send(c->socket, NULL, 0, 0) != 0) { + if (sockwouldblock(sockerrno)) + return; + int socket_error; + if (!socknotconn(sockerrno)) + socket_error = sockerrno; + else { + socklen_t len = sizeof socket_error; + getsockopt(c->socket, SOL_SOCKET, SO_ERROR, (void *)&socket_error, &len); + } + if (socket_error) { + logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Error while connecting to %s (%s): %s", c->name, c->hostname, sockstrerror(socket_error)); + terminate_connection(c, false); + } return; } + + c->status.connecting = false; + finish_connecting(c); } if(flags & IO_WRITE) @@ -528,10 +552,13 @@ begin: /* Now that there is a working socket, fill in the rest and register this connection. */ + c->last_ping_time = time(NULL); c->status.connecting = true; c->name = xstrdup(outgoing->name); +#ifndef DISABLE_LEGACY c->outcipher = myself->connection->outcipher; c->outdigest = myself->connection->outdigest; +#endif c->outmaclength = myself->connection->outmaclength; c->outcompression = myself->connection->outcompression; c->last_ping_time = now.tv_sec; @@ -583,9 +610,12 @@ void setup_outgoing_connection(outgoing_t *outgoing) { if(n && n->connection) { logger(DEBUG_CONNECTIONS, LOG_INFO, "Already connected to %s", outgoing->name); - - n->connection->outgoing = outgoing; - return; + if(!n->connection->outgoing) { + n->connection->outgoing = outgoing; + return; + } else { + goto remove; + } } init_configuration(&outgoing->config_tree); @@ -596,12 +626,16 @@ void setup_outgoing_connection(outgoing_t *outgoing) { if(n) outgoing->aip = outgoing->ai = get_known_addresses(n); if(!outgoing->ai) { - logger(DEBUG_ALWAYS, LOG_ERR, "No address known for %s", outgoing->name); - return; + logger(DEBUG_ALWAYS, LOG_DEBUG, "No address known for %s", outgoing->name); + goto remove; } } do_outgoing_connection(outgoing); + return; + +remove: + list_delete(outgoing_list, outgoing); } /* @@ -677,8 +711,10 @@ void handle_new_meta_connection(void *data, int flags) { c = new_connection(); c->name = xstrdup(""); +#ifndef DISABLE_LEGACY c->outcipher = myself->connection->outcipher; c->outdigest = myself->connection->outdigest; +#endif c->outmaclength = myself->connection->outmaclength; c->outcompression = myself->connection->outcompression; @@ -777,6 +813,11 @@ void try_outgoing_connections(void) { continue; } + if(!strcmp(name, myself->name)) { + free(name); + continue; + } + bool found = false; for list_each(outgoing_t, outgoing, outgoing_list) { @@ -801,7 +842,7 @@ void try_outgoing_connections(void) { if(c->outgoing && c->outgoing->timeout == -1) { c->outgoing = NULL; logger(DEBUG_CONNECTIONS, LOG_INFO, "No more outgoing connection to %s", c->name); - terminate_connection(c, c->status.active); + terminate_connection(c, c->edge); } }