From 3c1a59fa2493c6ab2758934fe1062d82975de158 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 30 Mar 2015 15:37:44 -0700 Subject: Wire selftest, and passes all tests. --- osnet/Wire.hpp | 77 ++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 48 insertions(+), 29 deletions(-) (limited to 'osnet') diff --git a/osnet/Wire.hpp b/osnet/Wire.hpp index 7b910656..d8a90826 100644 --- a/osnet/Wire.hpp +++ b/osnet/Wire.hpp @@ -178,7 +178,8 @@ public: ON_TCP_CLOSE_FUNCTION tcpCloseHandler, ON_TCP_DATA_FUNCTION tcpDataHandler, ON_TCP_WRITABLE_FUNCTION tcpWritableHandler, - bool noDelay) : + bool noDelay + ) : _datagramHandler(datagramHandler), _tcpConnectHandler(tcpConnectHandler), _tcpAcceptHandler(tcpAcceptHandler), @@ -263,11 +264,11 @@ public: * Bind a UDP socket * * @param localAddress Local endpoint address and port - * @param uptr Initial value of user pointer associated with this socket - * @param bufferSize Desired socket receive/send buffer size -- will set as close to this as possible (0 to accept default) + * @param uptr Initial value of user pointer associated with this socket (default: NULL) + * @param bufferSize Desired socket receive/send buffer size -- will set as close to this as possible (default: 0, leave alone) * @return Socket or NULL on failure to bind */ - inline WireSocket *udpBind(const struct sockaddr *localAddress,void *uptr,int bufferSize) + inline WireSocket *udpBind(const struct sockaddr *localAddress,void *uptr = (void *)0,int bufferSize = 0) { if (_socks.size() >= ZT_WIRE_MAX_SOCKETS) return (WireSocket *)0; @@ -358,26 +359,25 @@ public: * Send a UDP packet * * @param sock UDP socket - * @param addr Destination address (must be correct type for socket) - * @param addrlen Length of sockaddr_X structure + * @param remoteAddress Destination address (must be correct type for socket) * @param data Data to send * @param len Length of packet * @return True if packet appears to have been sent successfully */ - inline bool udpSend(WireSocket *sock,const struct sockaddr *addr,unsigned int addrlen,WireSocket *data,unsigned long len) + inline bool udpSend(WireSocket *sock,const struct sockaddr *remoteAddress,const void *data,unsigned long len) { WireSocketImpl &sws = *(const_cast (reinterpret_cast(sock))); - return ((long)::sendto(sws.sock,data,len,0,addr,(socklen_t)addrlen) == (long)len); + return ((long)::sendto(sws.sock,data,len,0,remoteAddress,(remoteAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) == (long)len); } /** * Bind a local listen socket to listen for new TCP connections * * @param localAddress Local address and port - * @param uptr Initial value of uptr for new socket + * @param uptr Initial value of uptr for new socket (default: NULL) * @return Socket or NULL on failure to bind */ - inline WireSocket *tcpListen(const struct sockaddr *localAddress,void *uptr) + inline WireSocket *tcpListen(const struct sockaddr *localAddress,void *uptr = (void *)0) { if (_socks.size() >= ZT_WIRE_MAX_SOCKETS) return (WireSocket *)0; @@ -438,30 +438,35 @@ public: /** * Start a non-blocking connect; CONNECT handler is called on success or failure * - * Note that if NULL is returned here, the handler is not called. Such - * a return would indicate failure to allocate the socket, too many - * open sockets, etc. + * A return value of NULL indicates a synchronous failure such as a + * failure to open a socket. The TCP connection handler is not called + * in this case. * - * Also note that an "instant connect" may occur for e.g. loopback - * connections. If this happens the 'connected' result paramter will - * be true. If callConnectHandlerOnInstantConnect is true, the - * TCP connect handler will be called before the function returns - * as well in this case. Otherwise it will not. + * It is possible on some platforms for an "instant connect" to occur, + * such as when connecting to a loopback address. In this case, the + * 'connected' result parameter will be set to 'true' and if the + * 'callConnectHandler' flag is true (the default) the TCP connect + * handler will be called before the function returns. + * + * These semantics can be a bit confusing, but they're less so than + * the underlying semantics of asynchronous TCP connect. * * @param remoteAddress Remote address - * @param uptr Initial value of uptr for new socket - * @param callConnectHandlerOnInstantConnect If true, call TCP connect handler now if an "instant connect" occurs - * @param connected Reference to result paramter set to true if "instant connect" occurs, false otherwise + * @param connected Result parameter: set to whether an "instant connect" has occurred (true if yes) + * @param uptr Initial value of uptr for new socket (default: NULL) + * @param callConnectHandler If true, call TCP connect handler even if result is known before function exit (default: true) * @return New socket or NULL on failure */ - inline WireSocket *tcpConnect(const struct sockaddr *remoteAddress,void *uptr,bool callConnectHandlerOnInstantConnect,bool &connected) + inline WireSocket *tcpConnect(const struct sockaddr *remoteAddress,bool &connected,void *uptr = (void *)0,bool callConnectHandler = true) { if (_socks.size() >= ZT_WIRE_MAX_SOCKETS) return (WireSocket *)0; ZT_WIRE_SOCKFD_TYPE s = ::socket(remoteAddress->sa_family,SOCK_STREAM,0); - if (!ZT_WIRE_SOCKFD_VALID(s)) + if (!ZT_WIRE_SOCKFD_VALID(s)) { + connected = false; return (WireSocket *)0; + } #if defined(_WIN32) || defined(_WIN64) { @@ -484,6 +489,7 @@ public: connected = true; if (::connect(s,remoteAddress,(remoteAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))) { + connected = false; #if defined(_WIN32) || defined(_WIN64) if (WSAGetLastError() != WSAEWOULDBLOCK) { #else @@ -491,7 +497,7 @@ public: #endif ZT_WIRE_CLOSE_SOCKET(s); return (WireSocket *)0; - } else connected = false; + } // else connection is proceeding asynchronously... } try { @@ -519,9 +525,9 @@ public: memset(&(sws.saddr),0,sizeof(struct sockaddr_storage)); memcpy(&(sws.saddr),remoteAddress,(remoteAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); - if ((callConnectHandlerOnInstantConnect)&&(connected)) { + if ((callConnectHandler)&&(connected)) { try { - _tcpConnectHandler((WireSocket *)&sws,uptr,true); + _tcpConnectHandler((WireSocket *)&sws,&(sws.uptr),true); } catch ( ... ) {} } @@ -541,7 +547,7 @@ public: * @param callCloseHandler If true, call close handler on socket closing failure condition * @return Number of bytes actually sent or -1 on fatal error (socket closure) */ - inline long tcpSend(WireSocket *sock,WireSocket *data,unsigned long len,bool callCloseHandler) + inline long tcpSend(WireSocket *sock,const void *data,unsigned long len,bool callCloseHandler) { WireSocketImpl &sws = *(const_cast (reinterpret_cast(sock))); long n = (long)::send(sws.sock,data,len,0); @@ -706,7 +712,7 @@ public: if ((long)newSock > _nfds) _nfds = (long)newSock; sws.type = ZT_WIRE_SOCKET_TCP_IN; - sws.sock = s; + sws.sock = newSock; sws.uptr = (void *)0; memcpy(&(sws.saddr),&ss,sizeof(struct sockaddr_storage)); try { @@ -774,7 +780,7 @@ public: long oldSock = (long)sws.sock; for(typename std::list::iterator s(_socks.begin());s!=_socks.end();++s) { - if (&(*s) == sock) { + if (reinterpret_cast(&(*s)) == sock) { _socks.erase(s); break; } @@ -793,6 +799,19 @@ public: } }; +// Typedefs for using regular naked functions as template parameters to Wire<> +typedef void (*Wire_OnDatagramFunctionPtr)(WireSocket *sock,void **uptr,const struct sockaddr *from,void *data,unsigned long len); +typedef void (*Wire_OnTcpConnectFunction)(WireSocket *sock,void **uptr,bool success); +typedef void (*Wire_OnTcpAcceptFunction)(WireSocket *sockL,WireSocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from); +typedef void (*Wire_OnTcpCloseFunction)(WireSocket *sock,void **uptr); +typedef void (*Wire_OnTcpDataFunction)(WireSocket *sock,void **uptr,void *data,unsigned long len); +typedef void (*Wire_OnTcpWritableFunction)(WireSocket *sock,void **uptr); + +/** + * Wire<> typedef'd to use simple naked function pointers + */ +typedef Wire SimpleFunctionWire; + } // namespace ZeroTier #endif -- cgit v1.2.3