Browse Source

Oops... turns out we need to differentiate incoming from outgoing TCP and indeed learn incoming TCP paths. Otherwise the recipient of a TCP connection does not know to reply via TCP! Heh.

Adam Ierymenko 11 years ago
parent
commit
f13493edb2
11 changed files with 147 additions and 110 deletions
  1. 9 9
      node/PacketDecoder.cpp
  2. 43 38
      node/Path.hpp
  3. 48 32
      node/Peer.cpp
  4. 11 1
      node/Socket.hpp
  5. 7 4
      node/SocketManager.cpp
  6. 11 6
      node/SocketManager.hpp
  7. 5 5
      node/Switch.cpp
  8. 5 7
      node/Switch.hpp
  9. 4 4
      node/TcpSocket.cpp
  10. 3 3
      node/TcpSocket.hpp
  11. 1 1
      node/Topology.cpp

+ 9 - 9
node/PacketDecoder.cpp

@@ -579,7 +579,7 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
 			source().toString().c_str(),
 			frameLen,
 			startingFifoItems);
-		_r->sm->send(ZT_DEFAULTS.multicastTraceWatcher,false,mct,strlen(mct));
+		_r->sm->sendUdp(ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct));
 #endif
 
 		// At this point the frame is basically valid, so we can call it a receive
@@ -602,7 +602,7 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
 					mctdepth,
 					(_r->topology->amSupernode() ? 'S' : '-'),
 					_r->identity.address().toString().c_str());
-				_r->sm->send(ZT_DEFAULTS.multicastTraceWatcher,false,mct,strlen(mct));
+				_r->sm->sendUdp(ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct));
 #endif
 				TRACE("dropped MULTICAST_FRAME from %s(%s): duplicate",source().toString().c_str(),_remoteAddress.toString().c_str());
 				return true;
@@ -648,7 +648,7 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
 							mctdepth,
 							(_r->topology->amSupernode() ? 'S' : '-'),
 							_r->identity.address().toString().c_str());
-						_r->sm->send(ZT_DEFAULTS.multicastTraceWatcher,false,mct,strlen(mct));
+						_r->sm->sendUdp(ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct));
 #endif
 						TRACE("dropped MULTICAST_FRAME from %s(%s) into %.16llx: source mac %s doesn't belong to %s, and bridging is not supported on network",source().toString().c_str(),_remoteAddress.toString().c_str(),nwid,sourceMac.toString().c_str(),origin.toString().c_str());
 						return true;
@@ -664,7 +664,7 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
 							mctdepth,
 							(_r->topology->amSupernode() ? 'S' : '-'),
 							_r->identity.address().toString().c_str());
-						_r->sm->send(ZT_DEFAULTS.multicastTraceWatcher,false,mct,strlen(mct));
+						_r->sm->sendUdp(ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct));
 #endif
 						TRACE("dropped MULTICAST_FRAME from %s(%s) into %.16llx: ethertype %u is not allowed",source().toString().c_str(),nwid,_remoteAddress.toString().c_str(),etherType);
 						return true;
@@ -681,7 +681,7 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
 							mctdepth,
 							(_r->topology->amSupernode() ? 'S' : '-'),
 							_r->identity.address().toString().c_str());
-						_r->sm->send(ZT_DEFAULTS.multicastTraceWatcher,false,mct,strlen(mct));
+						_r->sm->sendUdp(ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct));
 #endif
 						TRACE("dropped MULTICAST_FRAME from %s(%s): rate limits exceeded for sender %s",source().toString().c_str(),_remoteAddress.toString().c_str(),origin.toString().c_str());
 						return true;
@@ -702,7 +702,7 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
 				mctdepth,
 				(_r->topology->amSupernode() ? 'S' : '-'),
 				_r->identity.address().toString().c_str());
-			_r->sm->send(ZT_DEFAULTS.multicastTraceWatcher,false,mct,strlen(mct));
+			_r->sm->sendUdp(ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct));
 #endif
 			TRACE("not forwarding MULTICAST_FRAME from %s(%s): depth == 0xffff (do not forward)",source().toString().c_str(),_remoteAddress.toString().c_str());
 			return true;
@@ -717,7 +717,7 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
 				mctdepth,
 				(_r->topology->amSupernode() ? 'S' : '-'),
 				_r->identity.address().toString().c_str());
-			_r->sm->send(ZT_DEFAULTS.multicastTraceWatcher,false,mct,strlen(mct));
+			_r->sm->sendUdp(ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct));
 #endif
 			TRACE("not forwarding MULTICAST_FRAME from %s(%s): max propagation depth reached",source().toString().c_str(),_remoteAddress.toString().c_str());
 			return true;
@@ -776,7 +776,7 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
 				mctdepth,
 				(_r->topology->amSupernode() ? 'S' : '-'),
 				_r->identity.address().toString().c_str());
-			_r->sm->send(ZT_DEFAULTS.multicastTraceWatcher,false,mct,strlen(mct));
+			_r->sm->sendUdp(ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct));
 #endif
 			//TRACE("not forwarding MULTICAST_FRAME from %s(%s): no next hop",source().toString().c_str(),_remoteAddress.toString().c_str());
 			return true;
@@ -797,7 +797,7 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
 			origin.toString().c_str(),
 			nextHop.toString().c_str(),
 			numAdded);
-		_r->sm->send(ZT_DEFAULTS.multicastTraceWatcher,false,mct,strlen(mct));
+		_r->sm->sendUdp(ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct));
 #endif
 
 		// Send to next hop, reusing this packet as scratch space

+ 43 - 38
node/Path.hpp

@@ -39,7 +39,7 @@
 #include "Utils.hpp"
 #include "Buffer.hpp"
 
-#define ZT_PATH_SERIALIZATION_VERSION 1
+#define ZT_PATH_SERIALIZATION_VERSION 2
 
 namespace ZeroTier {
 
@@ -49,13 +49,21 @@ namespace ZeroTier {
 class Path
 {
 public:
+	enum Type
+	{
+		PATH_TYPE_NULL = 0,
+		PATH_TYPE_UDP = 1,
+		PATH_TYPE_TCP_OUT = 2,
+		PATH_TYPE_TCP_IN = 3
+	};
+
 	Path() :
 		_lastSend(0),
 		_lastReceived(0),
 		_lastFirewallOpener(0),
 		_lastPing(0),
 		_addr(),
-		_tcp(false),
+		_type(PATH_TYPE_NULL),
 		_fixed(false) {}
 
 	Path(const Path &p)
@@ -64,13 +72,13 @@ public:
 		memcpy(this,&p,sizeof(Path));
 	}
 
-	Path(const InetAddress &addr,bool tcp,bool fixed = false) :
+	Path(const InetAddress &addr,Type t,bool fixed = false) :
 		_lastSend(0),
 		_lastReceived(0),
 		_lastFirewallOpener(0),
 		_lastPing(0),
 		_addr(addr),
-		_tcp(tcp),
+		_type(t),
 		_fixed(fixed) {}
 
 	inline Path &operator=(const Path &p)
@@ -81,13 +89,16 @@ public:
 	}
 
 	inline const InetAddress &address() const throw() { return _addr; }
-	inline bool tcp() const throw() { return _tcp; }
+
+	inline Type type() const throw() { return _type; }
+	inline bool tcp() const throw() { return ((_type == PATH_TYPE_TCP_IN)||(_type == PATH_TYPE_TCP_OUT)); }
+
 	inline uint64_t lastSend() const throw() { return _lastSend; }
 	inline uint64_t lastReceived() const throw() { return _lastReceived; }
 	inline uint64_t lastFirewallOpener() const throw() { return _lastFirewallOpener; }
 	inline uint64_t lastPing() const throw() { return _lastPing; }
-	inline bool fixed() const throw() { return _fixed; }
 
+	inline bool fixed() const throw() { return _fixed; }
 	inline void setFixed(bool f) throw() { _fixed = f; }
 
 	inline void sent(uint64_t t) throw() { _lastSend = t; }
@@ -111,40 +122,34 @@ public:
 	inline std::string toString() const
 	{
 		uint64_t now = Utils::now();
-		char lsago[32],lrago[32],lfoago[32],lpago[32];
-		Utils::snprintf(lsago,sizeof(lsago),"%lld",(long long)((_lastSend != 0) ? (now - _lastSend) : -1));
-		Utils::snprintf(lrago,sizeof(lrago),"%lld",(long long)((_lastReceived != 0) ? (now - _lastReceived) : -1));
-		Utils::snprintf(lfoago,sizeof(lfoago),"%lld",(long long)((_lastFirewallOpener != 0) ? (now - _lastFirewallOpener) : -1));
-		Utils::snprintf(lpago,sizeof(lfoago),"%lld",(long long)((_lastPing != 0) ? (now - _lastPing) : -1));
-		return ( _addr.toString() + 
-		         "[" + 
-		         	     (_tcp ? "tcp" : "udp") +
-		         	     ";" +
-		         	     lsago +
-		         	     ";" +
-		         	     lrago +
-		         	     ";" +
-		         	     lpago +
-		         	     ";" +
-		         	     lfoago +
-		         	     ";" +
-		         	     (active(now) ? "active" : "inactive") +
-		         	     ";" +
-		         	     (_fixed ? "fixed" : "learned") +
-		         "]"
-		       );
+		char tmp[1024];
+		const char *t = "";
+		switch(_type) {
+			case PATH_TYPE_NULL: t = "null"; break;
+			case PATH_TYPE_UDP: t = "udp"; break;
+			case PATH_TYPE_TCP_OUT: t = "tcp_out"; break;
+			case PATH_TYPE_TCP_IN: t = "tcp_in"; break;
+		}
+		Utils::snprintf(tmp,sizeof(tmp),"%s:%s:%lld;%lld;%lld;%lld;%s",
+			t,
+			_addr.toString().c_str(),
+			(long long)((_lastSend != 0) ? (now - _lastSend) : -1),
+			(long long)((_lastReceived != 0) ? (now - _lastReceived) : -1),
+			(long long)((_lastFirewallOpener != 0) ? (now - _lastFirewallOpener) : -1),
+			(long long)((_lastPing != 0) ? (now - _lastPing) : -1),
+			((_fixed) ? "fixed" : (active(now) ? "active" : "inactive"))
+		);
+		return std::string(tmp);
 	}
 
-	inline bool operator==(const Path &p) const throw() { return ((_addr == p._addr)&&(_tcp == p._tcp)); }
-	inline bool operator!=(const Path &p) const throw() { return ((_addr != p._addr)||(_tcp != p._tcp)); }
+	inline bool operator==(const Path &p) const throw() { return ((_addr == p._addr)&&(_type == p._type)); }
+	inline bool operator!=(const Path &p) const throw() { return ((_addr != p._addr)||(_type != p._type)); }
 	inline bool operator<(const Path &p) const
 		throw()
 	{
-		if (_addr == p._addr) {
-			if (!_tcp) // UDP < TCP
-				return p._tcp;
-			return false;
-		} else return (_addr < p._addr);
+		if (_addr == p._addr)
+			return ((int)_type < (int)p._type);
+		else return (_addr < p._addr);
 	}
 	inline bool operator>(const Path &p) const throw() { return (p < *this); }
 	inline bool operator<=(const Path &p) const throw() { return !(p < *this); }
@@ -171,7 +176,7 @@ public:
 				b.append((uint16_t)_addr.port());
 				break;
 		}
-		b.append(_tcp ? (unsigned char)1 : (unsigned char)0);
+		b.append((unsigned char)_type);
 		b.append(_fixed ? (unsigned char)1 : (unsigned char)0);
 	}
 	template<unsigned int C>
@@ -199,7 +204,7 @@ public:
 				_addr.zero();
 				break;
 		}
-		_tcp = (b[p++] != 0);
+		_type = (Type)b[p++];
 		_fixed = (b[p++] != 0);
 
 		return (p - startAt);
@@ -211,7 +216,7 @@ private:
 	volatile uint64_t _lastFirewallOpener;
 	volatile uint64_t _lastPing;
 	InetAddress _addr;
-	bool _tcp;
+	Type _type;
 	bool _fixed;
 };
 

+ 48 - 32
node/Peer.cpp

@@ -69,25 +69,36 @@ void Peer::receive(
 	Packet::Verb inReVerb,
 	uint64_t now)
 {
+	// Update system-wide last packet receive time
 	*((const_cast<uint64_t *>(&(_r->timeOfLastPacketReceived)))) = now;
 
-	if (!hops) { // direct packet
+	// Learn paths from direct packets (hops == 0)
+	if (!hops) {
 		{
 			Mutex::Lock _l(_lock);
 
-			// Update receive time on known paths
 			bool havePath = false;
 			for(std::vector<Path>::iterator p(_paths.begin());p!=_paths.end();++p) {
-				if ((p->address() == remoteAddr)&&(p->tcp() == (fromSock->type() == Socket::ZT_SOCKET_TYPE_TCP))) {
+				if ((p->address() == remoteAddr)&&(p->tcp() == fromSock->tcp())) {
 					p->received(now);
 					havePath = true;
 					break;
 				}
 			}
 
-			// Learn new UDP paths (learning TCP would require an explicit mechanism)
-			if ((!havePath)&&(fromSock->type() != Socket::ZT_SOCKET_TYPE_TCP)) {
-				_paths.push_back(Path(remoteAddr,false,false));
+			if (!havePath) {
+				Path::Type pt = Path::PATH_TYPE_UDP;
+				switch(fromSock->type()) {
+					case Socket::ZT_SOCKET_TYPE_TCP_IN:
+						pt = Path::PATH_TYPE_TCP_IN;
+						break;
+					case Socket::ZT_SOCKET_TYPE_TCP_OUT:
+						pt = Path::PATH_TYPE_TCP_OUT;
+						break;
+					default:
+						break;
+				}
+				_paths.push_back(Path(remoteAddr,pt,false));
 				_paths.back().received(now);
 			}
 		}
@@ -110,26 +121,30 @@ bool Peer::send(const RuntimeEnvironment *_r,const void *data,unsigned int len,u
 {
 	Mutex::Lock _l(_lock);
 
-	std::vector<Path>::iterator p(_paths.begin());
-	if (p == _paths.end()) {
-		//TRACE("send to %s failed: no paths available",_id.address().toString().c_str());
-		return false;
-	}
-	uint64_t bestPathLastReceived = p->lastReceived();
-	std::vector<Path>::iterator bestPath = p;
-	while (++p != _paths.end()) {
-		uint64_t lr = p->lastReceived();
-		if (lr > bestPathLastReceived) {
-			bestPathLastReceived = lr;
-			bestPath = p;
+	for(;;) {
+		std::vector<Path>::iterator p(_paths.begin());
+		if (p == _paths.end())
+			return false;
+
+		uint64_t bestPathLastReceived = p->lastReceived();
+		std::vector<Path>::iterator bestPath = p;
+		while (++p != _paths.end()) {
+			uint64_t lr = p->lastReceived();
+			if (lr > bestPathLastReceived) {
+				bestPathLastReceived = lr;
+				bestPath = p;
+			}
 		}
-	}
 
-	//TRACE("send to %s: using path: %s",_id.address().toString().c_str(),bestPath->toString().c_str());
-
-	if (_r->sm->send(bestPath->address(),bestPath->tcp(),data,len)) {
-		bestPath->sent(now);
-		return true;
+		if (_r->sm->send(bestPath->address(),bestPath->tcp(),bestPath->type() == Path::PATH_TYPE_TCP_OUT,data,len)) {
+			bestPath->sent(now);
+			return true;
+		} else {
+			if (bestPath->fixed())
+				return false;
+			_paths.erase(bestPath);
+			// ... try again and pick a different path
+		}
 	}
 
 	return false;
@@ -160,23 +175,24 @@ bool Peer::sendPing(const RuntimeEnvironment *_r,uint64_t now,bool firstSinceRes
 
 	bool pingTcp;
 	if (!firstSinceReset) {
-		// Do not use TCP if one of our UDP endpoints has answered recently.
+		uint64_t lastUdp = 0;
+		uint64_t lastTcp = 0;
 		uint64_t lastPing = 0;
-		uint64_t lastDirectReceive = 0;
-
 		for(std::vector<Path>::iterator p(_paths.begin());p!=_paths.end();++p) {
-			lastPing = std::max(lastPing,p->lastPing());
-			lastDirectReceive = std::max(lastDirectReceive,p->lastReceived());
+			if (p->tcp())
+				lastTcp = std::max(p->lastReceived(),lastTcp);
+			else lastUdp = std::max(p->lastReceived(),lastUdp);
+			lastPing = std::max(p->lastPing(),lastPing);
 		}
-
-		pingTcp = ( (lastDirectReceive < lastPing) && ((lastPing - lastDirectReceive) >= ZT_PING_UNANSWERED_AFTER) );
+		uint64_t lastAny = std::max(lastUdp,lastTcp);
+		pingTcp = ( ( (lastAny < lastPing) && ((lastPing - lastAny) >= ZT_PING_UNANSWERED_AFTER) ) || (lastTcp > lastUdp) );
 	} else pingTcp = false;
 
 	TRACE("PING %s (pingTcp==%d)",_id.address().toString().c_str(),(int)pingTcp);
 
 	for(std::vector<Path>::iterator p(_paths.begin());p!=_paths.end();++p) {
 		if ((pingTcp)||(!p->tcp())) {
-			if (_r->sw->sendHELLO(self,p->address(),p->tcp())) {
+			if (_r->sw->sendHELLO(self,*p)) {
 				p->sent(now);
 				p->pinged(now);
 				sent = true;

+ 11 - 1
node/Socket.hpp

@@ -65,7 +65,8 @@ public:
 	{
 		ZT_SOCKET_TYPE_UDP_V4,
 		ZT_SOCKET_TYPE_UDP_V6,
-		ZT_SOCKET_TYPE_TCP
+		ZT_SOCKET_TYPE_TCP_IN, // incoming connection, not listen
+		ZT_SOCKET_TYPE_TCP_OUT
 	};
 
 	virtual ~Socket() {}
@@ -79,6 +80,15 @@ public:
 		return _type;
 	}
 
+	/**
+	 * @return True if this is a TCP socket
+	 */
+	inline bool tcp() const
+		throw()
+	{
+		return ((_type == ZT_SOCKET_TYPE_TCP_IN)||(_type == ZT_SOCKET_TYPE_TCP_OUT));
+	}
+
 	/**
 	 * Send a ZeroTier message packet
 	 *

+ 7 - 4
node/SocketManager.cpp

@@ -347,7 +347,7 @@ SocketManager::~SocketManager()
 	_closeSockets();
 }
 
-bool SocketManager::send(const InetAddress &to,bool tcp,const void *msg,unsigned int msglen)
+bool SocketManager::send(const InetAddress &to,bool tcp,bool autoConnectTcp,const void *msg,unsigned int msglen)
 {
 	if (tcp) {
 		SharedPtr<Socket> ts;
@@ -360,6 +360,9 @@ bool SocketManager::send(const InetAddress &to,bool tcp,const void *msg,unsigned
 		if (ts)
 			return ts->send(to,msg,msglen);
 
+		if (!autoConnectTcp)
+			return false;
+
 #ifdef __WINDOWS__
 		SOCKET s = ::socket(to.isV4() ? AF_INET : AF_INET6,SOCK_STREAM,0);
 		if (s == INVALID_SOCKET)
@@ -394,7 +397,7 @@ bool SocketManager::send(const InetAddress &to,bool tcp,const void *msg,unsigned
 			} else connecting = true;
 		}
 
-		ts = SharedPtr<Socket>(new TcpSocket(this,s,connecting,to));
+		ts = SharedPtr<Socket>(new TcpSocket(this,s,Socket::ZT_SOCKET_TYPE_TCP_OUT,connecting,to));
 		if (!ts->send(to,msg,msglen)) {
 			_fdSetLock.lock();
 			FD_CLR(s,&_readfds);
@@ -496,7 +499,7 @@ void SocketManager::poll(unsigned long timeout)
 				InetAddress fromia((const struct sockaddr *)&from);
 				Mutex::Lock _l2(_tcpSockets_m);
 				try {
-					_tcpSockets[fromia] = SharedPtr<Socket>(new TcpSocket(this,sockfd,false,fromia));
+					_tcpSockets[fromia] = SharedPtr<Socket>(new TcpSocket(this,sockfd,Socket::ZT_SOCKET_TYPE_TCP_IN,false,fromia));
 #ifdef __WINDOWS__
 					{ u_long iMode=1; ioctlsocket(sockfd,FIONBIO,&iMode); }
 #ifdef ZT_TCP_NODELAY
@@ -536,7 +539,7 @@ void SocketManager::poll(unsigned long timeout)
 				InetAddress fromia((const struct sockaddr *)&from);
 				Mutex::Lock _l2(_tcpSockets_m);
 				try {
-					_tcpSockets[fromia] = SharedPtr<Socket>(new TcpSocket(this,sockfd,false,fromia));
+					_tcpSockets[fromia] = SharedPtr<Socket>(new TcpSocket(this,sockfd,Socket::ZT_SOCKET_TYPE_TCP_IN,false,fromia));
 #ifdef __WINDOWS__
 					{ u_long iMode=1; ioctlsocket(sockfd,FIONBIO,&iMode); }
 #ifdef ZT_TCP_NODELAY

+ 11 - 6
node/SocketManager.hpp

@@ -85,17 +85,22 @@ public:
 	/**
 	 * Send a message to a remote peer
 	 *
-	 * If 'tcp' is true an existing TCP socket will be used or an attempt will
-	 * be made to connect if one is not available. The message will be placed
-	 * in the connecting TCP socket's outgoing queue, so if the connection
-	 * succeeds the message will be sent. Otherwise it will be dropped.
-	 *
 	 * @param to Destination address
 	 * @param tcp Use TCP?
+	 * @param autoConnectTcp If true, automatically initiate TCP connection if there is none
+	 * @param msg Message to send
+	 * @param msglen Length of message
+	 */
+	bool send(const InetAddress &to,bool tcp,bool autoConnectTcp,const void *msg,unsigned int msglen);
+
+	/**
+	 * Send a message to a remote peer via UDP (shortcut for setting both TCP params to false in send)
+	 *
+	 * @param to Destination address
 	 * @param msg Message to send
 	 * @param msglen Length of message
 	 */
-	bool send(const InetAddress &to,bool tcp,const void *msg,unsigned int msglen);
+	inline bool sendUdp(const InetAddress &to,const void *msg,unsigned int msglen) { return send(to,false,false,msg,msglen); }
 
 	/**
 	 * Send a UDP packet with a limited IP TTL

+ 5 - 5
node/Switch.cpp

@@ -214,7 +214,7 @@ void Switch::sendHELLO(const Address &dest)
 	send(outp,false);
 }
 
-bool Switch::sendHELLO(const SharedPtr<Socket> &fromSock,const SharedPtr<Peer> &dest,const InetAddress &remoteAddr)
+bool Switch::sendHELLO(const SharedPtr<Peer> &dest,const Path &path)
 {
 	uint64_t now = Utils::now();
 	Packet outp(dest->address(),_r->identity.address(),Packet::VERB_HELLO);
@@ -225,10 +225,10 @@ bool Switch::sendHELLO(const SharedPtr<Socket> &fromSock,const SharedPtr<Peer> &
 	outp.append(now);
 	_r->identity.serialize(outp,false);
 	outp.armor(dest->key(),false);
-	return fromSock->send(remoteAddr,outp.data(),outp.size());
+	return _r->sm->send(path.address(),path.tcp(),path.type() == Path::PATH_TYPE_TCP_OUT,outp.data(),outp.size());
 }
 
-bool Switch::sendHELLO(const SharedPtr<Peer> &dest,const InetAddress &remoteAddr,bool tcp)
+bool Switch::sendHELLO(const SharedPtr<Peer> &dest,const InetAddress &destUdp)
 {
 	uint64_t now = Utils::now();
 	Packet outp(dest->address(),_r->identity.address(),Packet::VERB_HELLO);
@@ -239,7 +239,7 @@ bool Switch::sendHELLO(const SharedPtr<Peer> &dest,const InetAddress &remoteAddr
 	outp.append(now);
 	_r->identity.serialize(outp,false);
 	outp.armor(dest->key(),false);
-	return _r->sm->send(remoteAddr,tcp,outp.data(),outp.size());
+	return _r->sm->send(deskUdp,false,false,outp.data(),outp.size());
 }
 
 bool Switch::unite(const Address &p1,const Address &p2,bool force)
@@ -354,7 +354,7 @@ unsigned long Switch::doTimerTasks()
 		for(std::list<ContactQueueEntry>::iterator qi(_contactQueue.begin());qi!=_contactQueue.end();) {
 			if (now >= qi->fireAtTime) {
 				TRACE("sending NAT-T HELLO to %s(%s)",qi->peer->address().toString().c_str(),qi->inaddr.toString().c_str());
-				sendHELLO(qi->peer,qi->inaddr,false);
+				sendHELLO(qi->peer,qi->inaddr);
 				_contactQueue.erase(qi++);
 			} else {
 				nextDelay = std::min(nextDelay,(unsigned long)(qi->fireAtTime - now));

+ 5 - 7
node/Switch.hpp

@@ -122,22 +122,20 @@ public:
 	/**
 	 * Send a HELLO announcement immediately to the indicated address
 	 *
-	 * @param fromSock Send from this local socket
 	 * @param dest Destination peer
-	 * @param remoteAddr Remote address
+	 * @param path Network path to peer
 	 * @return True if send appears successful
 	 */
-	bool sendHELLO(const SharedPtr<Socket> &fromSock,const SharedPtr<Peer> &dest,const InetAddress &remoteAddr);
+	bool sendHELLO(const SharedPtr<Peer> &dest,const Path &path);
 
 	/**
-	 * Send a HELLO announcement immediately to the indicated address
+	 * Send a HELLO announcement immediately to the indicated address via UDP
 	 *
 	 * @param dest Destination peer
-	 * @param remoteAddr Remote address
-	 * @param tcp Attempt to use TCP?
+	 * @param destUdp UDP inet address
 	 * @return True if send appears successful
 	 */
-	bool sendHELLO(const SharedPtr<Peer> &dest,const InetAddress &remoteAddr,bool tcp);
+	bool sendHELLO(const SharedPtr<Peer> &dest,const InetAddress &destUdp);
 
 	/**
 	 * Send RENDEZVOUS to two peers to permit them to directly connect

+ 4 - 4
node/TcpSocket.cpp

@@ -72,7 +72,6 @@ bool TcpSocket::send(const InetAddress &to,const void *msg,unsigned int msglen)
 		return true; // sanity check
 
 	Mutex::Lock _l(_writeLock);
-
 	bool writeInProgress = ((_outptr != 0)||(_connecting));
 
 	// Ensure that _outbuf is large enough
@@ -144,9 +143,10 @@ bool TcpSocket::notifyAvailableForRead(const SharedPtr<Socket> &self,SocketManag
 
 		if ((pl)&&(p >= pl)) {
 			Buffer<ZT_SOCKET_MAX_MESSAGE_LEN> data(_inbuf + 5,pl - 5);
-			sm->handleReceivedPacket(self,_remote,data);
-			memmove(_inbuf,_inbuf + pl,p - pl);
-			p -= pl;
+			memmove(_inbuf,_inbuf + pl,p -= pl);
+			try {
+				sm->handleReceivedPacket(self,_remote,data);
+			} catch ( ... ) {} // handlers should not throw
 			pl = 0;
 		}
 	}

+ 3 - 3
node/TcpSocket.hpp

@@ -71,11 +71,11 @@ public:
 
 protected:
 #ifdef __WINDOWS__
-	TcpSocket(SocketManager *sm,SOCKET s,bool c,const InetAddress &r) :
+	TcpSocket(SocketManager *sm,SOCKET s,Socket::Type t,bool c,const InetAddress &r) :
 #else
-	TcpSocket(SocketManager *sm,int s,bool c,const InetAddress &r) :
+	TcpSocket(SocketManager *sm,int s,Socket::Type t,bool c,const InetAddress &r) :
 #endif
-		Socket(Socket::ZT_SOCKET_TYPE_TCP,s),
+		Socket(t,s),
 		_lastActivity(Utils::now()),
 		_sm(sm),
 		_outbuf((unsigned char *)0),

+ 1 - 1
node/Topology.cpp

@@ -65,7 +65,7 @@ void Topology::setSupernodes(const std::map< Identity,std::vector< std::pair<Ine
 			if (!p)
 				p = addPeer(SharedPtr<Peer>(new Peer(_r->identity,i->first)));
 			for(std::vector< std::pair<InetAddress,bool> >::const_iterator j(i->second.begin());j!=i->second.end();++j)
-				p->addPath(Path(j->first,j->second,true));
+				p->addPath(Path(j->first,(j->second) ? Path::PATH_TYPE_TCP_OUT : Path::PATH_TYPE_UDP,true));
 			p->use(now);
 			_supernodePeers.push_back(p);
 		}