/*
net_socket.c -- Handle various kinds of sockets.
Copyright (C) 1998-2005 Ivo Timmermans,
- 2000-2014 Guus Sliepen <guus@tinc-vpn.org>
+ 2000-2016 Guus Sliepen <guus@tinc-vpn.org>
2006 Scott Lamb <slamb@slamb.org>
2009 Florian Forster <octo@verplant.org>
#include "utils.h"
#include "xalloc.h"
-/* 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;
-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];
}
#endif
-#if defined(SOL_TCP) && defined(TCP_NODELAY)
+#if defined(IPPROTO_TCP) && defined(TCP_NODELAY)
option = 1;
- setsockopt(c->socket, SOL_TCP, TCP_NODELAY, (void *)&option, sizeof option);
+ setsockopt(c->socket, IPPROTO_TCP, TCP_NODELAY, (void *)&option, sizeof option);
#endif
-#if defined(SOL_IP) && defined(IP_TOS) && defined(IPTOS_LOWDELAY)
+#if defined(IPPROTO_IP) && defined(IP_TOS) && defined(IPTOS_LOWDELAY)
option = IPTOS_LOWDELAY;
- setsockopt(c->socket, SOL_IP, IP_TOS, (void *)&option, sizeof option);
+ setsockopt(c->socket, IPPROTO_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
}
option = 1;
setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof option);
-#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
+#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
if(sa->sa.sa_family == AF_INET6)
- setsockopt(nfd, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option);
+ setsockopt(nfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option);
#endif
if(get_config_string
#define IP_DONTFRAGMENT IP_DONTFRAG
#endif
-#if defined(SOL_IP) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
+#if defined(IPPROTO_IP) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
if(myself->options & OPTION_PMTU_DISCOVERY) {
option = IP_PMTUDISC_DO;
- setsockopt(nfd, SOL_IP, IP_MTU_DISCOVER, (void *)&option, sizeof(option));
+ setsockopt(nfd, IPPROTO_IP, IP_MTU_DISCOVER, (void *)&option, sizeof(option));
}
#elif defined(IPPROTO_IP) && defined(IP_DONTFRAGMENT)
if(myself->options & OPTION_PMTU_DISCOVERY) {
}
#endif
-#if defined(SOL_IPV6) && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO)
+#if defined(IPPROTO_IPV6) && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO)
if(myself->options & OPTION_PMTU_DISCOVERY) {
option = IPV6_PMTUDISC_DO;
- setsockopt(nfd, SOL_IPV6, IPV6_MTU_DISCOVER, (void *)&option, sizeof(option));
+ setsockopt(nfd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, (void *)&option, sizeof(option));
}
#elif defined(IPPROTO_IPV6) && defined(IPV6_DONTFRAG)
if(myself->options & OPTION_PMTU_DISCOVERY) {
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;
}
connection_t *c = data;
if(c->status.connecting) {
- /* The event loop does not protect against spurious events. Verify that we are actually connected. */
- if (connect(c->socket, &c->address.sa, sizeof(c->address)) == 0)
- logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Error while connecting to %s (%s): redundant connect() unexpectedly succeeded", c->name, c->hostname);
- else if (!sockisconn(sockerrno)) {
- if (!sockalready(sockerrno)) {
- logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Error while checking connection status for %s (%s): %s", c->name, c->hostname, sockstrerror(sockerrno));
+ /*
+ 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;
-
- 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);
- return;
- }
+ finish_connecting(c);
}
if(flags & IO_WRITE)
#endif
if(proxytype != PROXY_EXEC) {
-#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
+#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
int option = 1;
if(c->address.sa.sa_family == AF_INET6)
- setsockopt(c->socket, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option);
+ setsockopt(c->socket, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option);
#endif
bind_to_interface(c->socket);
/* 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;
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);
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);
}
/*
c = new_connection();
c->name = xstrdup("<unknown>");
+#ifndef DISABLE_LEGACY
c->outcipher = myself->connection->outcipher;
c->outdigest = myself->connection->outdigest;
+#endif
c->outmaclength = myself->connection->outmaclength;
c->outcompression = myself->connection->outcompression;
continue;
}
+ if(!strcmp(name, myself->name)) {
+ free(name);
+ continue;
+ }
+
bool found = false;
for list_each(outgoing_t, outgoing, outgoing_list) {
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);
}
}