diff --git a/src/bindings/csharp/Constants.cs b/src/bindings/csharp/Constants.cs index 69dcb3a..e7c6882 100644 --- a/src/bindings/csharp/Constants.cs +++ b/src/bindings/csharp/Constants.cs @@ -250,7 +250,7 @@ namespace ZeroTier public static readonly short MSG_DONTWAIT = 0x0008; public static readonly short MSG_MORE = 0x0010; - // Macro's for defining ioctl() command values + // Macros for defining ioctl() command values /* public static readonly ulong IOCPARM_MASK = 0x7fU; public static readonly ulong IOC_VOID = 0x20000000UL; diff --git a/src/bindings/csharp/Event.cs b/src/bindings/csharp/Event.cs index db5e18d..f5ed712 100644 --- a/src/bindings/csharp/Event.cs +++ b/src/bindings/csharp/Event.cs @@ -15,7 +15,7 @@ using System.Net; using ZeroTier; -namespace ZeroTier +namespace ZeroTier.Core { /* Convenience structures for exposing lower level operational details to the user. These structures do not have the same memory layout or content as those found in diff --git a/src/bindings/csharp/Node.cs b/src/bindings/csharp/Node.cs index 3771af7..1be62b6 100644 --- a/src/bindings/csharp/Node.cs +++ b/src/bindings/csharp/Node.cs @@ -14,6 +14,8 @@ using System.Runtime.InteropServices; using System; +using ZeroTier; + // Prototype of callback used by ZeroTier to signal events to C# application [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void CSharpCallbackWithStruct(IntPtr msgPtr); @@ -21,9 +23,9 @@ public delegate void CSharpCallbackWithStruct(IntPtr msgPtr); /// /// ZeroTier SDK /// -namespace ZeroTier +namespace ZeroTier.Core { - public delegate void ZeroTierManagedEventCallback(ZeroTier.Event nodeEvent); + public delegate void ZeroTierManagedEventCallback(ZeroTier.Core.Event nodeEvent); /// /// ZeroTier Node - Virtual network subsystem @@ -45,11 +47,11 @@ namespace ZeroTier zts_callback_msg msg = (zts_callback_msg)Marshal.PtrToStructure(msgPtr, typeof(zts_callback_msg)); - ZeroTier.Event newEvent = null; + ZeroTier.Core.Event newEvent = null; // Node events if (msg.eventCode == Constants.EVENT_NODE_UP) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NODE_UP"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_NODE_UP"); } if (msg.eventCode == Constants.EVENT_NODE_ONLINE) { _isOnline = true; @@ -57,135 +59,135 @@ namespace ZeroTier zts_node_details details = (zts_node_details)Marshal.PtrToStructure(msg.node, typeof(zts_node_details)); _nodeId = details.address; - newEvent = new ZeroTier.Event(msg.eventCode, "EVENT_NODE_ONLINE"); + newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_NODE_ONLINE"); } if (msg.eventCode == Constants.EVENT_NODE_OFFLINE) { _isOnline = false; - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NODE_OFFLINE"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_NODE_OFFLINE"); } if (msg.eventCode == Constants.EVENT_NODE_NORMAL_TERMINATION) { _isOnline = false; - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NODE_NORMAL_TERMINATION"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_NODE_NORMAL_TERMINATION"); } if (msg.eventCode == Constants.EVENT_NODE_DOWN) { _isOnline = false; - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NODE_DOWN"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_NODE_DOWN"); } if (msg.eventCode == Constants.EVENT_NODE_IDENTITY_COLLISION) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NODE_IDENTITY_COLLISION"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_NODE_IDENTITY_COLLISION"); _isOnline = false; } if (msg.eventCode == Constants.EVENT_NODE_UNRECOVERABLE_ERROR) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NODE_UNRECOVERABLE_ERROR"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_NODE_UNRECOVERABLE_ERROR"); _isOnline = false; } // Network events if (msg.eventCode == Constants.EVENT_NETWORK_NOT_FOUND) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_NOT_FOUND"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_NETWORK_NOT_FOUND"); } if (msg.eventCode == Constants.EVENT_NETWORK_REQ_CONFIG) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_REQ_CONFIG"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_NETWORK_REQ_CONFIG"); } if (msg.eventCode == Constants.EVENT_NETWORK_ACCESS_DENIED) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_ACCESS_DENIED"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_NETWORK_ACCESS_DENIED"); } if (msg.eventCode == Constants.EVENT_NETWORK_READY_IP4) { _joinedAtLeastOneNetwork = true; - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_READY_IP4"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_NETWORK_READY_IP4"); } if (msg.eventCode == Constants.EVENT_NETWORK_READY_IP6) { _joinedAtLeastOneNetwork = true; - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_READY_IP6"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_NETWORK_READY_IP6"); } if (msg.eventCode == Constants.EVENT_NETWORK_DOWN) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_DOWN"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_NETWORK_DOWN"); } if (msg.eventCode == Constants.EVENT_NETWORK_CLIENT_TOO_OLD) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_CLIENT_TOO_OLD"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_NETWORK_CLIENT_TOO_OLD"); } if (msg.eventCode == Constants.EVENT_NETWORK_REQ_CONFIG) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_REQ_CONFIG"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_NETWORK_REQ_CONFIG"); } if (msg.eventCode == Constants.EVENT_NETWORK_OK) { zts_network_details unmanagedDetails = (zts_network_details)Marshal.PtrToStructure(msg.network, typeof(zts_network_details)); - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_OK"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_NETWORK_OK"); newEvent.networkDetails = new NetworkDetails(); newEvent.networkDetails.networkId = unmanagedDetails.nwid; } if (msg.eventCode == Constants.EVENT_NETWORK_ACCESS_DENIED) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_ACCESS_DENIED"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_NETWORK_ACCESS_DENIED"); } if (msg.eventCode == Constants.EVENT_NETWORK_READY_IP4_IP6) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_READY_IP4_IP6"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_NETWORK_READY_IP4_IP6"); } if (msg.eventCode == Constants.EVENT_NETWORK_UPDATE) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_UPDATE"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_NETWORK_UPDATE"); } // Stack events if (msg.eventCode == Constants.EVENT_STACK_UP) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_STACK_UP"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_STACK_UP"); } if (msg.eventCode == Constants.EVENT_STACK_DOWN) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_STACK_DOWN"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_STACK_DOWN"); } // Address events if (msg.eventCode == Constants.EVENT_ADDR_ADDED_IP4) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_ADDR_ADDED_IP4"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_ADDR_ADDED_IP4"); } if (msg.eventCode == Constants.EVENT_ADDR_ADDED_IP6) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_ADDR_ADDED_IP6"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_ADDR_ADDED_IP6"); } if (msg.eventCode == Constants.EVENT_ADDR_REMOVED_IP4) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_ADDR_REMOVED_IP4"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_ADDR_REMOVED_IP4"); } if (msg.eventCode == Constants.EVENT_ADDR_REMOVED_IP6) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_ADDR_REMOVED_IP6"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_ADDR_REMOVED_IP6"); } // peer events if (msg.eventCode == Constants.EVENT_PEER_DIRECT) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_PEER_DIRECT"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_PEER_DIRECT"); } if (msg.eventCode == Constants.EVENT_PEER_RELAY) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_PEER_RELAY"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_PEER_RELAY"); } - // newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_PEER_UNREACHABLE"); + // newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_PEER_UNREACHABLE"); if (msg.eventCode == Constants.EVENT_PEER_PATH_DISCOVERED) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_PEER_PATH_DISCOVERED"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_PEER_PATH_DISCOVERED"); } if (msg.eventCode == Constants.EVENT_PEER_PATH_DEAD) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_PEER_PATH_DEAD"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_PEER_PATH_DEAD"); } // Route events if (msg.eventCode == Constants.EVENT_ROUTE_ADDED) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_ROUTE_ADDED"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_ROUTE_ADDED"); } if (msg.eventCode == Constants.EVENT_ROUTE_REMOVED) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_ROUTE_REMOVED"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_ROUTE_REMOVED"); } // Netif events if (msg.eventCode == Constants.EVENT_NETIF_UP) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETIF_UP"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_NETIF_UP"); } if (msg.eventCode == Constants.EVENT_NETIF_DOWN) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETIF_DOWN"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_NETIF_DOWN"); } if (msg.eventCode == Constants.EVENT_NETIF_REMOVED) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETIF_REMOVED"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_NETIF_REMOVED"); } if (msg.eventCode == Constants.EVENT_NETIF_LINK_UP) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETIF_LINK_UP"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_NETIF_LINK_UP"); } if (msg.eventCode == Constants.EVENT_NETIF_LINK_DOWN) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETIF_LINK_DOWN"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_NETIF_LINK_DOWN"); } if (msg.eventCode == Constants.EVENT_ADDR_REMOVED_IP6) { - newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_ADDR_REMOVED_IP6"); + newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_ADDR_REMOVED_IP6"); } // Pass the converted Event to the managed callback (visible to user) diff --git a/src/bindings/csharp/Socket.cs b/src/bindings/csharp/Socket.cs index 4de872b..2cce0d1 100644 --- a/src/bindings/csharp/Socket.cs +++ b/src/bindings/csharp/Socket.cs @@ -13,7 +13,7 @@ using System; // For ObjectDisposedException using System.Net; // For IPEndPoint -using System.Net.Sockets; // For ZeroTier.SocketException +using System.Net.Sockets; // For ZeroTier.Sockets.SocketException using System.Runtime.InteropServices; using ZeroTier; @@ -21,7 +21,7 @@ using ZeroTier; /// /// ZeroTier SDK /// -namespace ZeroTier +namespace ZeroTier.Sockets { /// /// ZeroTier Socket - An lwIP socket mediated over a ZeroTier virtual link @@ -45,6 +45,8 @@ namespace ZeroTier bool _isClosed; bool _isListening; bool _isBlocking; + bool _isBound; + bool _isConnected; AddressFamily _socketFamily; SocketType _socketType; @@ -101,7 +103,7 @@ namespace ZeroTier } if ((_fd = zts_socket(family, type, protocol)) < 0) { - throw new ZeroTier.SocketException((int)_fd); + throw new ZeroTier.Sockets.SocketException((int)_fd); } _socketFamily = addressFamily; _socketType = socketType; @@ -132,13 +134,14 @@ namespace ZeroTier } if (_fd < 0) { // Invalid file descriptor - throw new ZeroTier.SocketException((int)Constants.ERR_SOCKET); + throw new ZeroTier.Sockets.SocketException((int)Constants.ERR_SOCKET); } if (remoteEndPoint == null) { throw new ArgumentNullException("remoteEndPoint"); } int err = Constants.ERR_OK; int addrlen = 0; + IntPtr remoteAddrPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(zts_sockaddr))); if (remoteEndPoint.AddressFamily == AddressFamily.InterNetwork) { zts_sockaddr_in sa = new zts_sockaddr_in(); @@ -159,10 +162,9 @@ namespace ZeroTier sa.sin_addr = remoteEndPoint.Address.GetAddressBytes(); sa.sin_len = (byte)addrlen; // lwIP-specific - IntPtr ptr1 = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(zts_sockaddr))); - Marshal.StructureToPtr(sa, ptr1, false); - //zts_sockaddr sAddr = (zts_sockaddr)Marshal.PtrToStructure(ptr1, typeof(zts_sockaddr)); - err = zts_connect(_fd, ptr1, (byte)addrlen); + Marshal.StructureToPtr(sa, remoteAddrPtr, false); + //zts_sockaddr sAddr = (zts_sockaddr)Marshal.PtrToStructure(remoteAddrPtr, typeof(zts_sockaddr)); + err = zts_connect(_fd, remoteAddrPtr, (byte)addrlen); } if (remoteEndPoint.AddressFamily == AddressFamily.InterNetworkV6) @@ -179,9 +181,11 @@ namespace ZeroTier */ } if (err < 0) { - throw new ZeroTier.SocketException(err, ZeroTier.Node.ErrNo); + throw new ZeroTier.Sockets.SocketException(err, ZeroTier.Core.Node.ErrNo); } + Marshal.FreeHGlobal(remoteAddrPtr); _remoteEndPoint = remoteEndPoint; + _isConnected = true; } public void Bind(IPEndPoint localEndPoint) @@ -191,13 +195,14 @@ namespace ZeroTier } if (_fd < 0) { // Invalid file descriptor - throw new ZeroTier.SocketException((int)Constants.ERR_SOCKET); + throw new ZeroTier.Sockets.SocketException((int)Constants.ERR_SOCKET); } if (localEndPoint == null) { throw new ArgumentNullException("localEndPoint"); } int err = Constants.ERR_OK; int addrlen = 0; + IntPtr localAddrPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(zts_sockaddr))); if (localEndPoint.AddressFamily == AddressFamily.InterNetwork) { zts_sockaddr_in sa = new zts_sockaddr_in(); @@ -217,10 +222,9 @@ namespace ZeroTier sa.sin_port = (short)zts_htons((ushort)localEndPoint.Port); sa.sin_addr = localEndPoint.Address.GetAddressBytes(); sa.sin_len = (byte)addrlen; // lwIP-specific - - IntPtr ptr1 = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(zts_sockaddr))); - Marshal.StructureToPtr(sa, ptr1, false); - err = zts_bind(_fd, ptr1, (byte)addrlen); + + Marshal.StructureToPtr(sa, localAddrPtr, false); + err = zts_bind(_fd, localAddrPtr, (byte)addrlen); } if (localEndPoint.AddressFamily == AddressFamily.InterNetworkV6) { @@ -236,9 +240,11 @@ namespace ZeroTier */ } if (err < 0) { - throw new ZeroTier.SocketException((int)err); + throw new ZeroTier.Sockets.SocketException((int)err); } + Marshal.FreeHGlobal(localAddrPtr); _localEndPoint = localEndPoint; + _isBound = true; } public void Listen(int backlog) @@ -248,12 +254,12 @@ namespace ZeroTier } if (_fd < 0) { // Invalid file descriptor - throw new ZeroTier.SocketException((int)Constants.ERR_SOCKET); + throw new ZeroTier.Sockets.SocketException((int)Constants.ERR_SOCKET); } int err = Constants.ERR_OK; if ((err = zts_listen(_fd, backlog)) < 0) { // Invalid backlog value perhaps? - throw new ZeroTier.SocketException((int)Constants.ERR_SOCKET); + throw new ZeroTier.Sockets.SocketException((int)Constants.ERR_SOCKET); } _isListening = true; } @@ -265,7 +271,7 @@ namespace ZeroTier } if (_fd < 0) { // Invalid file descriptor - throw new ZeroTier.SocketException((int)Constants.ERR_SOCKET); + throw new ZeroTier.Sockets.SocketException((int)Constants.ERR_SOCKET); } if (_isListening == false) { throw new InvalidOperationException("Socket is not in a listening state. Call Listen() first"); @@ -281,7 +287,7 @@ namespace ZeroTier int err = zts_accept(_fd, remoteAddrPtr, addrlenPtr); if (err < 0) { - throw new ZeroTier.SocketException(err, ZeroTier.Node.ErrNo); + throw new ZeroTier.Sockets.SocketException(err, ZeroTier.Core.Node.ErrNo); } in4 = (zts_sockaddr_in)Marshal.PtrToStructure(remoteAddrPtr, typeof(zts_sockaddr_in)); // Convert sockaddr contents to IPEndPoint @@ -290,6 +296,7 @@ namespace ZeroTier // Create new socket by providing file descriptor returned from zts_accept call. Socket clientSocket = new Socket( err, _socketFamily, _socketType, _socketProtocol, _localEndPoint, clientEndPoint); + Marshal.FreeHGlobal(remoteAddrPtr); return clientSocket; } @@ -323,20 +330,6 @@ namespace ZeroTier _isClosed = true; } - public EndPoint RemoteEndPoint - { - get { - return _remoteEndPoint; - } - } - - public EndPoint LocalEndPoint - { - get { - return _localEndPoint; - } - } - public bool Blocking { get { @@ -348,18 +341,16 @@ namespace ZeroTier } int opts = 0; if ((opts = zts_fcntl(_fd, (int)(ZeroTier.Constants.F_GETFL), 0)) < 0) { - throw new ZeroTier.SocketException(opts, ZeroTier.Node.ErrNo); + throw new ZeroTier.Sockets.SocketException(opts, ZeroTier.Core.Node.ErrNo); } - Console.WriteLine("before.opts={0}", opts); if (value) { // Blocking opts = opts & (~(ZeroTier.Constants.O_NONBLOCK)); } if (!value) { // Non-Blocking opts = opts | (int)(ZeroTier.Constants.O_NONBLOCK); } - Console.WriteLine("after.opts={0}", opts); if ((opts = zts_fcntl(_fd, ZeroTier.Constants.F_SETFL, (int)opts)) < 0) { - throw new ZeroTier.SocketException(opts, ZeroTier.Node.ErrNo); + throw new ZeroTier.Sockets.SocketException(opts, ZeroTier.Core.Node.ErrNo); } _isBlocking = value; } @@ -379,7 +370,8 @@ namespace ZeroTier poll_set.events = (short)((byte)ZeroTier.Constants.POLLOUT); } if (mode == SelectMode.SelectError) { - poll_set.events = (short)((byte)ZeroTier.Constants.POLLERR | (byte)ZeroTier.Constants.POLLNVAL); + poll_set.events = (short)((byte)ZeroTier.Constants.POLLERR | + (byte)ZeroTier.Constants.POLLNVAL); } IntPtr poll_fd_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(zts_pollfd))); Marshal.StructureToPtr(poll_set, poll_fd_ptr, false); @@ -387,20 +379,23 @@ namespace ZeroTier int timeout_ms = (microSeconds / 1000); uint numfds = 1; if ((result = zts_poll(poll_fd_ptr, numfds, timeout_ms)) < 0) { - throw new ZeroTier.SocketException(result, ZeroTier.Node.ErrNo); + throw new ZeroTier.Sockets.SocketException(result, ZeroTier.Core.Node.ErrNo); } poll_set = (zts_pollfd)Marshal.PtrToStructure(poll_fd_ptr, typeof(zts_pollfd)); - if (result == 0) { return false; } // No events - if (mode == SelectMode.SelectRead) { - return ((byte)poll_set.revents & (byte)ZeroTier.Constants.POLLIN) != 0; + if (result != 0) { + if (mode == SelectMode.SelectRead) { + result = Convert.ToInt32(((byte)poll_set.revents & (byte)ZeroTier.Constants.POLLIN) != 0); + } + if (mode == SelectMode.SelectWrite) { + result = Convert.ToInt32(((byte)poll_set.revents & (byte)ZeroTier.Constants.POLLOUT) != 0); + } + if (mode == SelectMode.SelectError) { + result = Convert.ToInt32(((poll_set.revents & (byte)ZeroTier.Constants.POLLERR) != 0) || + ((poll_set.revents & (byte)ZeroTier.Constants.POLLNVAL) != 0)); + } } - if (mode == SelectMode.SelectWrite) { - return ((byte)poll_set.revents & (byte)ZeroTier.Constants.POLLOUT) != 0; - } - if (mode == SelectMode.SelectError) { - return ((poll_set.revents & (byte)ZeroTier.Constants.POLLERR) != 0) || ((poll_set.revents & (byte)ZeroTier.Constants.POLLNVAL) != 0); - } - return false; + Marshal.FreeHGlobal(poll_fd_ptr); + return result > 0; } public Int32 Send(Byte[] buffer) @@ -409,7 +404,7 @@ namespace ZeroTier throw new ObjectDisposedException("Socket has been closed"); } if (_fd < 0) { - throw new ZeroTier.SocketException((int)ZeroTier.Constants.ERR_SOCKET); + throw new ZeroTier.Sockets.SocketException((int)ZeroTier.Constants.ERR_SOCKET); } if (buffer == null) { throw new ArgumentNullException("buffer"); @@ -425,7 +420,7 @@ namespace ZeroTier throw new ObjectDisposedException("Socket has been closed"); } if (_fd < 0) { - throw new ZeroTier.SocketException((int)ZeroTier.Constants.ERR_SOCKET); + throw new ZeroTier.Sockets.SocketException((int)ZeroTier.Constants.ERR_SOCKET); } if (buffer == null) { throw new ArgumentNullException("buffer"); @@ -435,6 +430,87 @@ namespace ZeroTier return zts_recv(_fd, bufferPtr, (uint)Buffer.ByteLength(buffer), (int)flags); } + private void _set_timeout(int timeout_ms, int optname) + { + zts_timeval tv = new zts_timeval(); + // Convert milliseconds to timeval struct + tv.tv_sec = timeout_ms / 1000; + tv.tv_usec = (timeout_ms % 1000) * 1000; + IntPtr tv_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(zts_timeval))); + Marshal.StructureToPtr(tv, tv_ptr, false); + ushort option_size = (ushort)Marshal.SizeOf(typeof(zts_sockaddr_in)); + int err = 0; + if ((err = zts_setsockopt(_fd, ZeroTier.Constants.SOL_SOCKET, + ZeroTier.Constants.SO_RCVTIMEO, tv_ptr, option_size)) < 0) { + throw new ZeroTier.Sockets.SocketException(err, ZeroTier.Core.Node.ErrNo); + } + Marshal.FreeHGlobal(tv_ptr); + } + + private int _get_timeout(int optname) + { + zts_timeval tv = new zts_timeval(); + IntPtr tv_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(zts_timeval))); + Marshal.StructureToPtr(tv, tv_ptr, false); + ushort optlen = (ushort)Marshal.SizeOf(typeof(zts_timeval)); + GCHandle optlen_gc_handle = GCHandle.Alloc(optlen, GCHandleType.Pinned); + IntPtr optlen_ptr = optlen_gc_handle.AddrOfPinnedObject(); + int err = 0; + if ((err = zts_getsockopt(_fd, ZeroTier.Constants.SOL_SOCKET, + ZeroTier.Constants.SO_RCVTIMEO, tv_ptr, optlen_ptr)) < 0) { + throw new ZeroTier.Sockets.SocketException(err, ZeroTier.Core.Node.ErrNo); + } + tv = (zts_timeval)Marshal.PtrToStructure(tv_ptr, typeof(zts_timeval)); + optlen_gc_handle.Free(); + Marshal.FreeHGlobal(tv_ptr); + // Convert timeval struct to milliseconds + return (int)((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); + } + + public int ReceiveTimeout + { + get { return _get_timeout(ZeroTier.Constants.SO_RCVTIMEO); } + set { _set_timeout(value, ZeroTier.Constants.SO_RCVTIMEO); } + } + + public int SendTimeout + { + get { return _get_timeout(ZeroTier.Constants.SO_SNDTIMEO); } + set { _set_timeout(value, ZeroTier.Constants.SO_SNDTIMEO); } + } + + /* TODO + public int ReceiveBufferSize { get; set; } + + public int SendBufferSize { get; set; } + + public short Ttl { get; set; } + + public LingerOption LingerState { get; set; } + + public bool NoDelay { get; set; } + */ + + public bool Connected { get { return _isConnected; } } + + public bool IsBound { get { return _isBound; } } + + public AddressFamily AddressFamily { get { return _socketFamily; } } + + public SocketType SocketType { get { return _socketType; } } + + public ProtocolType ProtocolType { get { return _socketProtocol; } } + + /* .NET has moved to OSSupportsIPv* but libzt isn't an OS so we keep this old convention */ + public static bool SupportsIPv4 { get { return true; } } + + /* .NET has moved to OSSupportsIPv* but libzt isn't an OS so we keep this old convention */ + public static bool SupportsIPv6 { get { return true; } } + + public EndPoint RemoteEndPoint { get { return _remoteEndPoint; } } + + public EndPoint LocalEndPoint { get { return _localEndPoint; } } + /* Structures and functions used internally to communicate with lower-level C API defined in include/ZeroTierSockets.h */ @@ -587,5 +663,12 @@ namespace ZeroTier public short events; public short revents; } + + [StructLayout(LayoutKind.Sequential)] + struct zts_timeval + { + public long tv_sec; + public long tv_usec; + } } } diff --git a/src/bindings/csharp/SocketException.cs b/src/bindings/csharp/SocketException.cs index 40dfc5f..3a15568 100644 --- a/src/bindings/csharp/SocketException.cs +++ b/src/bindings/csharp/SocketException.cs @@ -13,7 +13,7 @@ using System; -namespace ZeroTier +namespace ZeroTier.Sockets { /// Exception class for ZeroTier service and low-level socket errors public class SocketException : Exception diff --git a/src/bindings/csharp/zt_wrap.cxx b/src/bindings/csharp/zt_wrap.cxx index 4d88a87..1e93c3d 100644 --- a/src/bindings/csharp/zt_wrap.cxx +++ b/src/bindings/csharp/zt_wrap.cxx @@ -587,7 +587,7 @@ SWIGEXPORT void SWIGSTDCALL CSharp_zts_delay_ms(long jarg1) { zts_delay_ms(arg1); } - +/* SWIGEXPORT int SWIGSTDCALL CSharp_zts_get_all_stats(void * jarg1) { int jresult ; zts_stats *arg1 = (zts_stats *) 0 ; @@ -612,7 +612,7 @@ SWIGEXPORT int SWIGSTDCALL CSharp_zts_get_protocol_stats(int jarg1, void * jarg2 jresult = result; return jresult; } - +*/ SWIGEXPORT int SWIGSTDCALL CSharp_zts_socket(int jarg1, int jarg2, int jarg3) { int jresult ;