Restructure packaging directories. Move C# bindings, minor compilation fix.

This commit is contained in:
Joseph Henry
2021-02-01 17:59:21 -08:00
parent 3544eab41d
commit 38ea47212d
16 changed files with 106 additions and 71 deletions

View File

@@ -1,353 +0,0 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2024-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
using ZeroTier;
namespace ZeroTier
{
public class Constants
{
// General error codes
public static readonly int ERR_OK = 0;
public static readonly int ERR_SOCKET = -1;
public static readonly int ERR_SERVICE = -2;
public static readonly int ERR_ARG = -3;
public static readonly int ERR_NO_RESULT = -4;
public static readonly int ERR_GENERAL = -5;
// Node events
public static readonly short EVENT_NODE_UP = 200;
public static readonly short EVENT_NODE_ONLINE = 201;
public static readonly short EVENT_NODE_OFFLINE = 202;
public static readonly short EVENT_NODE_DOWN = 203;
public static readonly short EVENT_NODE_IDENTITY_COLLISION = 204;
public static readonly short EVENT_NODE_UNRECOVERABLE_ERROR = 205;
public static readonly short EVENT_NODE_NORMAL_TERMINATION = 206;
// Network events
public static readonly short EVENT_NETWORK_NOT_FOUND = 210;
public static readonly short EVENT_NETWORK_CLIENT_TOO_OLD = 211;
public static readonly short EVENT_NETWORK_REQ_CONFIG = 212;
public static readonly short EVENT_NETWORK_OK = 213;
public static readonly short EVENT_NETWORK_ACCESS_DENIED = 214;
public static readonly short EVENT_NETWORK_READY_IP4 = 215;
public static readonly short EVENT_NETWORK_READY_IP6 = 216;
public static readonly short EVENT_NETWORK_READY_IP4_IP6 = 217;
public static readonly short EVENT_NETWORK_DOWN = 218;
public static readonly short EVENT_NETWORK_UPDATE = 219;
// Network Stack events
public static readonly short EVENT_STACK_UP = 220;
public static readonly short EVENT_STACK_DOWN = 221;
// lwIP netif events
public static readonly short EVENT_NETIF_UP = 230;
public static readonly short EVENT_NETIF_DOWN = 231;
public static readonly short EVENT_NETIF_REMOVED = 232;
public static readonly short EVENT_NETIF_LINK_UP = 233;
public static readonly short EVENT_NETIF_LINK_DOWN = 234;
// Peer events
public static readonly short EVENT_PEER_DIRECT = 240;
public static readonly short EVENT_PEER_RELAY = 241;
public static readonly short EVENT_PEER_UNREACHABLE = 242;
public static readonly short EVENT_PEER_PATH_DISCOVERED = 243;
public static readonly short EVENT_PEER_PATH_DEAD = 244;
// Route events
public static readonly short EVENT_ROUTE_ADDED = 250;
public static readonly short EVENT_ROUTE_REMOVED = 251;
// Address events
public static readonly short EVENT_ADDR_ADDED_IP4 = 260;
public static readonly short EVENT_ADDR_REMOVED_IP4 = 261;
public static readonly short EVENT_ADDR_ADDED_IP6 = 262;
public static readonly short EVENT_ADDR_REMOVED_IP6 = 263;
// Socket error codes
public static readonly short EPERM = 1; /* Operation not permitted */
public static readonly short ENOENT = 2; /* No such file or directory */
public static readonly short ESRCH = 3; /* No such process */
public static readonly short EINTR = 4; /* Interrupted system call */
public static readonly short EIO = 5; /* I/O error */
public static readonly short ENXIO = 6; /* No such device or address */
public static readonly short E2BIG = 7; /* Arg list too long */
public static readonly short ENOEXEC = 8; /* Exec format error */
public static readonly short EBADF = 9; /* Bad file number */
public static readonly short ECHILD = 10; /* No child processes */
public static readonly short EAGAIN = 11; /* Try again */
public static readonly short ENOMEM = 12; /* Out of memory */
public static readonly short EACCES = 13; /* Permission denied */
public static readonly short EFAULT = 14; /* Bad address */
public static readonly short ENOTBLK = 15; /* Block device required */
public static readonly short EBUSY = 16; /* Device or resource busy */
public static readonly short EEXIST = 17; /* File exists */
public static readonly short EXDEV = 18; /* Cross-device link */
public static readonly short ENODEV = 19; /* No such device */
public static readonly short ENOTDIR = 20; /* Not a directory */
public static readonly short EISDIR = 21; /* Is a directory */
public static readonly short EINVAL = 22; /* Invalid argument */
public static readonly short ENFILE = 23; /* File table overflow */
public static readonly short EMFILE = 24; /* Too many open files */
public static readonly short ENOTTY = 25; /* Not a typewriter */
public static readonly short ETXTBSY = 26; /* Text file busy */
public static readonly short EFBIG = 27; /* File too large */
public static readonly short ENOSPC = 28; /* No space left on device */
public static readonly short ESPIPE = 29; /* Illegal seek */
public static readonly short EROFS = 30; /* Read-only file system */
public static readonly short EMLINK = 31; /* Too many links */
public static readonly short EPIPE = 32; /* Broken pipe */
public static readonly short EDOM = 33; /* Math argument out of domain of func */
public static readonly short ERANGE = 34; /* Math result not representable */
public static readonly short EDEADLK = 35; /* Resource deadlock would occur */
public static readonly short ENAMETOOLONG = 36; /* File name too long */
public static readonly short ENOLCK = 37; /* No record locks available */
public static readonly short ENOSYS = 38; /* Function not implemented */
public static readonly short ENOTEMPTY = 39; /* Directory not empty */
public static readonly short ELOOP = 40; /* Too many symbolic links encountered */
public static readonly short EWOULDBLOCK = EAGAIN; /* Operation would block */
public static readonly short ENOMSG = 42; /* No message of desired type */
public static readonly short EIDRM = 43; /* Identifier removed */
public static readonly short ECHRNG = 44; /* Channel number out of range */
public static readonly short EL2NSYNC = 45; /* Level 2 not synchronized */
public static readonly short EL3HLT = 46; /* Level 3 halted */
public static readonly short EL3RST = 47; /* Level 3 reset */
public static readonly short ELNRNG = 48; /* Link number out of range */
public static readonly short EUNATCH = 49; /* Protocol driver not attached */
public static readonly short ENOCSI = 50; /* No CSI structure available */
public static readonly short EL2HLT = 51; /* Level 2 halted */
public static readonly short EBADE = 52; /* Invalid exchange */
public static readonly short EBADR = 53; /* Invalid request descriptor */
public static readonly short EXFULL = 54; /* Exchange full */
public static readonly short ENOANO = 55; /* No anode */
public static readonly short EBADRQC = 56; /* Invalid request code */
public static readonly short EBADSLT = 57; /* Invalid slot */
public static readonly short EDEADLOCK = EDEADLK;
public static readonly short EBFONT = 59; /* Bad font file format */
public static readonly short ENOSTR = 60; /* Device not a stream */
public static readonly short ENODATA = 61; /* No data available */
public static readonly short ETIME = 62; /* Timer expired */
public static readonly short ENOSR = 63; /* Out of streams resources */
public static readonly short ENONET = 64; /* Machine is not on the network */
public static readonly short ENOPKG = 65; /* Package not installed */
public static readonly short EREMOTE = 66; /* Object is remote */
public static readonly short ENOLINK = 67; /* Link has been severed */
public static readonly short EADV = 68; /* Advertise error */
public static readonly short ESRMNT = 69; /* Srmount error */
public static readonly short ECOMM = 70; /* Communication error on send */
public static readonly short EPROTO = 71; /* Protocol error */
public static readonly short EMULTIHOP = 72; /* Multihop attempted */
public static readonly short EDOTDOT = 73; /* RFS specific error */
public static readonly short EBADMSG = 74; /* Not a data message */
public static readonly short EOVERFLOW = 75; /* Value too large for defined data type */
public static readonly short ENOTUNIQ = 76; /* Name not unique on network */
public static readonly short EBADFD = 77; /* File descriptor in bad state */
public static readonly short EREMCHG = 78; /* Remote address changed */
public static readonly short ELIBACC = 79; /* Can not access a needed shared library */
public static readonly short ELIBBAD = 80; /* Accessing a corrupted shared library */
public static readonly short ELIBSCN = 81; /* .lib section in a.out corrupted */
public static readonly short ELIBMAX = 82; /* Attempting to link in too many shared libraries */
public static readonly short ELIBEXEC = 83; /* Cannot exec a shared library directly */
public static readonly short EILSEQ = 84; /* Illegal byte sequence */
public static readonly short ERESTART = 85; /* Interrupted system call should be restarted */
public static readonly short ESTRPIPE = 86; /* Streams pipe error */
public static readonly short EUSERS = 87; /* Too many users */
public static readonly short ENOTSOCK = 88; /* Socket operation on non-socket */
public static readonly short EDESTADDRREQ = 89; /* Destination address required */
public static readonly short EMSGSIZE = 90; /* Message too long */
public static readonly short EPROTOTYPE = 91; /* Protocol wrong type for socket */
public static readonly short ENOPROTOOPT = 92; /* Protocol not available */
public static readonly short EPROTONOSUPPORT = 93; /* Protocol not supported */
public static readonly short ESOCKTNOSUPPORT = 94; /* Socket type not supported */
public static readonly short EOPNOTSUPP = 95; /* Operation not supported on transport endpoint */
public static readonly short EPFNOSUPPORT = 96; /* Protocol family not supported */
public static readonly short EAFNOSUPPORT = 97; /* Address family not supported by protocol */
public static readonly short EADDRINUSE = 98; /* Address already in use */
public static readonly short EADDRNOTAVAIL = 99; /* Cannot assign requested address */
public static readonly short ENETDOWN = 100; /* Network is down */
public static readonly short ENETUNREACH = 101; /* Network is unreachable */
public static readonly short ENETRESET = 102; /* Network dropped connection because of reset */
public static readonly short ECONNABORTED = 103; /* Software caused connection abort */
public static readonly short ECONNRESET = 104; /* Connection reset by peer */
public static readonly short ENOBUFS = 105; /* No buffer space available */
public static readonly short EISCONN = 106; /* Transport endpoint is already connected */
public static readonly short ENOTCONN = 107; /* Transport endpoint is not connected */
public static readonly short ESHUTDOWN = 108; /* Cannot send after transport endpoint shutdown */
public static readonly short ETOOMANYREFS = 109; /* Too many references: cannot splice */
public static readonly short ETIMEDOUT = 110; /* Connection timed out */
public static readonly short ECONNREFUSED = 111; /* Connection refused */
public static readonly short EHOSTDOWN = 112; /* Host is down */
public static readonly short EHOSTUNREACH = 113; /* No route to host */
public static readonly short EALREADY = 114; /* Operation already in progress */
public static readonly short EINPROGRESS = 115; /* Operation now in progress */
public static readonly short ESTALE = 116; /* Stale NFS file handle */
public static readonly short EUCLEAN = 117; /* Structure needs cleaning */
public static readonly short ENOTNAM = 118; /* Not a XENIX named type file */
public static readonly short ENAVAIL = 119; /* No XENIX semaphores available */
public static readonly short EISNAM = 120; /* Is a named type file */
public static readonly short EREMOTEIO = 121; /* Remote I/O error */
public static readonly short EDQUOT = 122; /* Quota exceeded */
public static readonly short ENOMEDIUM = 123; /* No medium found */
public static readonly short EMEDIUMTYPE = 124; /* Wrong medium type */
public static readonly short INET_ADDRSTRLEN = 16;
public static readonly short INET6_ADDRSTRLEN = 46;
/** 255.255.255.255 */
//public static readonly uint IPADDR_NONE =((uint32_t)0xffffffffUL);
/** 127.0.0.1 */
//public static readonly uint IPADDR_LOOPBACK =((uint32_t)0x7f000001UL);
/** 0.0.0.0 */
//public static readonly uint IPADDR_ANY =((uint32_t)0x00000000UL);
/** 255.255.255.255 */
//public static readonly uint IPADDR_BROADCAST =((uint32_t)0xffffffffUL);
/** 255.255.255.255 */
//public static readonly uint INADDR_NONE =IPADDR_NONE;
/** 127.0.0.1 */
//public static readonly uint INADDR_LOOPBACK =IPADDR_LOOPBACK;
/** 0.0.0.0 */
//public static readonly uint INADDR_ANY =IPADDR_ANY;
/** 255.255.255.255 */
//public static readonly uint INADDR_BROADCAST =IPADDR_BROADCAST;
// Socket protocol types
public static readonly short SOCK_STREAM = 0x0001;
public static readonly short SOCK_DGRAM = 0x0002;
public static readonly short SOCK_RAW = 0x0003;
// Socket family types
public static readonly short AF_UNSPEC = 0x0000;
public static readonly short AF_INET = 0x0002;
public static readonly short AF_INET6 = 0x000a;
public static readonly short PF_INET = AF_INET;
public static readonly short PF_INET6 = AF_INET6;
public static readonly short PF_UNSPEC = AF_UNSPEC;
// Protocol command types
public static readonly short IPPROTO_IP = 0x0000;
public static readonly short IPPROTO_ICMP = 0x0001;
public static readonly short IPPROTO_TCP = 0x0006;
public static readonly short IPPROTO_UDP = 0x0011;
public static readonly short IPPROTO_IPV6 = 0x0029;
public static readonly short IPPROTO_ICMPV6 = 0x003a;
public static readonly short IPPROTO_UDPLITE = 0x0088;
public static readonly short IPPROTO_RAW = 0x00ff;
// send() and recv() flags
public static readonly short MSG_PEEK = 0x0001;
public static readonly short MSG_WAITALL = 0x0002; // NOT YET SUPPORTED
public static readonly short MSG_OOB = 0x0004; // NOT YET SUPPORTED
public static readonly short MSG_DONTWAIT = 0x0008;
public static readonly short MSG_MORE = 0x0010;
// Macro's for defining ioctl() command values
/*
public static readonly ulong IOCPARM_MASK = 0x7fU;
public static readonly ulong IOC_VOID = 0x20000000UL;
public static readonly ulong IOC_OUT = 0x40000000UL;
public static readonly ulong IOC_IN = 0x80000000UL;
public static readonly ulong IOC_INOUT = (IOC_IN | IOC_OUT);
public static readonly ulong IO(x,y) = (IOC_VOID | ((x)<<8)|(y));
public static readonly ulong IOR(x,y,t) = (IOC_OUT | (((long)sizeof(t) & IOCPARM_MASK)<<16) | ((x)<<8) | (y));
public static readonly ulong IOW(x,y,t) = (IOC_IN | (((long)sizeof(t) & IOCPARM_MASK)<<16) | ((x)<<8) | (y));
// ioctl() commands
public static readonly ulong FIONREAD = IOR('f', 127, unsigned long);
public static readonly ulong FIONBIO = IOW('f', 126, unsigned long);
*/
// Socket level option number
public static readonly short SOL_SOCKET = 0x0fff;
// Socket options
public static readonly short SO_DEBUG = 0x0001; // NOT YET SUPPORTED
public static readonly short SO_ACCEPTCONN = 0x0002;
public static readonly short SO_REUSEADDR = 0x0004;
public static readonly short SO_KEEPALIVE = 0x0008;
public static readonly short SO_DONTROUTE = 0x0010; // NOT YET SUPPORTED
public static readonly short SO_BROADCAST = 0x0020;
public static readonly short SO_USELOOPBACK = 0x0040; // NOT YET SUPPORTED
public static readonly short SO_LINGER = 0x0080;
public static readonly short SO_DONTLINGER = ((short)(~SO_LINGER));
public static readonly short SO_OOBINLINE = 0x0100; // NOT YET SUPPORTED
public static readonly short SO_REUSEPORT = 0x0200; // NOT YET SUPPORTED
public static readonly short SO_SNDBUF = 0x1001; // NOT YET SUPPORTED
public static readonly short SO_RCVBUF = 0x1002;
public static readonly short SO_SNDLOWAT = 0x1003; // NOT YET SUPPORTED
public static readonly short SO_RCVLOWAT = 0x1004; // NOT YET SUPPORTED
public static readonly short SO_SNDTIMEO = 0x1005;
public static readonly short SO_RCVTIMEO = 0x1006;
public static readonly short SO_ERROR = 0x1007;
public static readonly short SO_TYPE = 0x1008;
public static readonly short SO_CONTIMEO = 0x1009;
public static readonly short SO_NO_CHECK = 0x100a;
public static readonly short SO_BINDTODEVICE = 0x100b;
// IPPROTO_IP options
public static readonly short IP_TOS = 0x0001;
public static readonly short IP_TTL = 0x0002;
public static readonly short IP_PKTINFO = 0x0008;
// IPPROTO_TCP options
public static readonly short TCP_NODELAY = 0x0001;
public static readonly short TCP_KEEPALIVE = 0x0002;
public static readonly short TCP_KEEPIDLE = 0x0003;
public static readonly short TCP_KEEPINTVL = 0x0004;
public static readonly short TCP_KEEPCNT = 0x0005;
// IPPROTO_IPV6 options
public static readonly short IPV6_CHECKSUM = 0x0007; // RFC3542: calculate and insert the ICMPv6 checksum for raw sockets.
public static readonly short IPV6_V6ONLY = 0x001b; // RFC3493: boolean control to restrict AF_INET6 sockets to IPv6 communications only.
// UDPLITE options
public static readonly short UDPLITE_SEND_CSCOV = 0x01; // sender checksum coverage
public static readonly short UDPLITE_RECV_CSCOV = 0x02; // minimal receiver checksum coverage
// UDPLITE options
public static readonly short IP_MULTICAST_TTL = 5;
public static readonly short IP_MULTICAST_IF = 6;
public static readonly short IP_MULTICAST_LOOP = 7;
// Multicast options
public static readonly short IP_ADD_MEMBERSHIP = 3;
public static readonly short IP_DROP_MEMBERSHIP = 4;
public static readonly short IPV6_JOIN_GROUP = 12;
public static readonly short IPV6_ADD_MEMBERSHIP = IPV6_JOIN_GROUP;
public static readonly short IPV6_LEAVE_GROUP = 13;
public static readonly short IPV6_DROP_MEMBERSHIP = IPV6_LEAVE_GROUP;
// Polling options
public static readonly short POLLIN = 0x001;
public static readonly short POLLOUT = 0x002;
public static readonly short POLLERR = 0x004;
public static readonly short POLLNVAL = 0x008;
// Below values are unimplemented
public static readonly short POLLRDNORM = 0x010;
public static readonly short POLLRDBAND = 0x020;
public static readonly short POLLPRI = 0x040;
public static readonly short POLLWRNORM = 0x080;
public static readonly short POLLWRBAND = 0x100;
public static readonly short POLLHUP = 0x200;
public static readonly short F_GETFL = 0x0003;
public static readonly short F_SETFL = 0x0004;
// File status flags and file access modes for fnctl, these are bits in an int.
public static readonly short O_NONBLOCK = 1;
public static readonly short O_NDELAY = O_NONBLOCK;
public static readonly short O_RDONLY = 2;
public static readonly short O_WRONLY = 4;
public static readonly short O_RDWR = (short)(O_RDONLY|O_WRONLY);
public static readonly short MSG_TRUNC = 0x04;
public static readonly short MSG_CTRUNC = 0x08;
public static readonly short SHUT_RD = 0x0;
public static readonly short SHUT_WR = 0x1;
public static readonly short SHUT_RDWR = 0x2;
}
}

View File

@@ -1,156 +0,0 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2024-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
using System.Net;
using ZeroTier;
namespace ZeroTier
{
/* 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
include/ZeroTierSockets.h */
/// <summary>
/// Structure containing information about the local Node.
/// </summary>
public class NodeDetails
{
// Node ID
public ulong nodeId;
/**
* The port used by the service to send and receive
* all encapsulated traffic
*/
public ushort primaryPort;
public ushort secondaryPort;
public ushort tertiaryPort;
/**
* ZT version
*/
public byte versionMajor;
public byte versionMinor;
public byte versionRev;
}
public class MulticastSubscription
{
ulong macAddress;
uint AdditionalDistinguishingInformation;
}
/// <summary>
/// Structure containing information about virtual networks.
/// </summary>
public class NetworkDetails
{
public ulong networkId;
public ulong macAddress;
public string networkName;
//public byte status;
public byte type;
public ushort mtu;
public bool bridgingAllowed;
public bool broadcastEnabled;
//public int portError;
public IPAddress[] assignedAddresses;
public IPAddress[] routes;
public MulticastSubscription[] multicastSubscroptions;
}
/// <summary>
/// Structure containing state information about the low-level ethernet driver.
/// </summary>
public class NetifDetails
{
public ulong networkId;
public ulong macAddress;
public int mtu;
}
/// <summary>
/// Structure containing routing information for networks.
/// </summary>
public class RouteDetails
{
public EndPoint target;
public EndPoint via;
public ushort flags;
public ushort metric;
}
/// <summary>
/// Structure containing information about remote peer reachability.
/// </summary>
public class PeerDetails
{
ulong nodeId;
byte versionMajor;
byte versionMinor;
byte versionRev;
int latency;
byte role;
IPAddress[] paths;
}
/// <summary>
/// Structure containing information about assigned addresses.
/// </summary>
public class AddrDetails
{
ulong networkId;
IPAddress address;
}
/// <summary>
/// Class used to convey details of a low-level network event to the user.
/// </summary>
public class Event
{
int _eventCode;
string _eventName;
public NodeDetails nodeDetails;
public NetworkDetails networkDetails;
public NetifDetails netifDetails;
public RouteDetails routeDetails;
public PeerDetails peerDetails;
public AddrDetails addrDetails;
public Event(int eventCode, string eventName)
{
_eventCode = eventCode;
_eventName = eventName;
nodeDetails = null;
networkDetails = null;
netifDetails = null;
routeDetails = null;
peerDetails = null;
addrDetails = null;
}
public int EventCode {
get {
return _eventCode;
}
}
public string EventName {
get {
return _eventName;
}
}
}
}

View File

@@ -1,12 +0,0 @@
debug:
cd ../../ && make host_pinvoke_debug
cp -f ../../lib/debug/linux-x86_64/libzt.so .
mono-csc -out:example.exe *.cs
release:
cd ../../ && make host_pinvoke_release
cp -f ../../lib/release/linux-x86_64/libzt.so .
mono-csc -out:example.exe *.cs
clean:
rm -rf libzt.* example.exe

View File

@@ -1,493 +0,0 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2024-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
using System.Runtime.InteropServices;
using System;
// Prototype of callback used by ZeroTier to signal events to C# application
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void CSharpCallbackWithStruct(IntPtr msgPtr);
/// <summary>
/// ZeroTier SDK
/// </summary>
namespace ZeroTier
{
public delegate void ZeroTierManagedEventCallback(ZeroTier.Event nodeEvent);
/// <summary>
/// ZeroTier Node - Virtual network subsystem
/// </summary>
public class Node
{
static ulong _nodeId = 0x0;
static bool _isOnline = false;
static bool _joinedAtLeastOneNetwork = false;
static bool _hasBeenFreed = false;
string _configFilePath;
ushort _servicePort;
static ZeroTierManagedEventCallback _managedCallback;
// Callback used internally to ferry events from the C++ layer
static void OnZeroTierEvent(IntPtr msgPtr)
{
// Marshal the callback message pointer to a structure that we can inspect
zts_callback_msg msg =
(zts_callback_msg)Marshal.PtrToStructure(msgPtr, typeof(zts_callback_msg));
ZeroTier.Event newEvent = null;
// Node events
if (msg.eventCode == Constants.EVENT_NODE_UP) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NODE_UP");
}
if (msg.eventCode == Constants.EVENT_NODE_ONLINE) {
_isOnline = true;
// Marshal the node details pointer to a structure
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");
}
if (msg.eventCode == Constants.EVENT_NODE_OFFLINE) {
_isOnline = false;
newEvent = new ZeroTier.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");
}
if (msg.eventCode == Constants.EVENT_NODE_DOWN) {
_isOnline = false;
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NODE_DOWN");
}
if (msg.eventCode == Constants.EVENT_NODE_IDENTITY_COLLISION) {
newEvent = new ZeroTier.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");
_isOnline = false;
}
// Network events
if (msg.eventCode == Constants.EVENT_NETWORK_NOT_FOUND) {
newEvent = new ZeroTier.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");
}
if (msg.eventCode == Constants.EVENT_NETWORK_ACCESS_DENIED) {
newEvent = new ZeroTier.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");
}
if (msg.eventCode == Constants.EVENT_NETWORK_READY_IP6) {
_joinedAtLeastOneNetwork = true;
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_READY_IP6");
}
if (msg.eventCode == Constants.EVENT_NETWORK_DOWN) {
newEvent = new ZeroTier.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");
}
if (msg.eventCode == Constants.EVENT_NETWORK_REQ_CONFIG) {
newEvent = new ZeroTier.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.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");
}
if (msg.eventCode == Constants.EVENT_NETWORK_READY_IP4_IP6) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_READY_IP4_IP6");
}
if (msg.eventCode == Constants.EVENT_NETWORK_UPDATE) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_UPDATE");
}
// Stack events
if (msg.eventCode == Constants.EVENT_STACK_UP) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_STACK_UP");
}
if (msg.eventCode == Constants.EVENT_STACK_DOWN) {
newEvent = new ZeroTier.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");
}
if (msg.eventCode == Constants.EVENT_ADDR_ADDED_IP6) {
newEvent = new ZeroTier.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");
}
if (msg.eventCode == Constants.EVENT_ADDR_REMOVED_IP6) {
newEvent = new ZeroTier.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");
}
if (msg.eventCode == Constants.EVENT_PEER_RELAY) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_PEER_RELAY");
}
// newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_PEER_UNREACHABLE");
if (msg.eventCode == Constants.EVENT_PEER_PATH_DISCOVERED) {
newEvent = new ZeroTier.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");
}
// Route events
if (msg.eventCode == Constants.EVENT_ROUTE_ADDED) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_ROUTE_ADDED");
}
if (msg.eventCode == Constants.EVENT_ROUTE_REMOVED) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_ROUTE_REMOVED");
}
// Netif events
if (msg.eventCode == Constants.EVENT_NETIF_UP) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETIF_UP");
}
if (msg.eventCode == Constants.EVENT_NETIF_DOWN) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETIF_DOWN");
}
if (msg.eventCode == Constants.EVENT_NETIF_REMOVED) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETIF_REMOVED");
}
if (msg.eventCode == Constants.EVENT_NETIF_LINK_UP) {
newEvent = new ZeroTier.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");
}
if (msg.eventCode == Constants.EVENT_ADDR_REMOVED_IP6) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_ADDR_REMOVED_IP6");
}
// Pass the converted Event to the managed callback (visible to user)
if (newEvent != null) {
_managedCallback(newEvent);
}
}
/// <summary>
/// Creates a new Node. Start this object by calling Start().
/// </summary>
/// <param name="configFilePath">Where keys and config files will be stored on the filesystem</param>
/// <param name="managedCallback">Where you would like to receive ZeroTier event notifications</param>
/// <param name="servicePort">The port ZeroTier will use to send its encrypted </param>
/// <returns></returns>
public Node(string configFilePath, ZeroTierManagedEventCallback managedCallback, UInt16 servicePort)
{
if (String.IsNullOrEmpty(configFilePath)) {
throw new ArgumentNullException(nameof(configFilePath));
}
if (managedCallback == null) {
throw new ArgumentNullException(nameof(managedCallback));
}
_nodeId = 0x0;
_configFilePath = configFilePath;
_servicePort = servicePort;
_managedCallback = new ZeroTierManagedEventCallback(managedCallback);
}
/// <summary>
/// Starts the ZeroTier node/service
/// </summary>
/// <returns></returns>
public int Start()
{
if (_hasBeenFreed == true) {
throw new ObjectDisposedException("ZeroTier Node has previously been freed. Restart application to create new instance.");
}
return zts_start(_configFilePath,OnZeroTierEvent,_servicePort);
}
/// <summary>
/// Frees (most) resources used by ZeroTier. ZeroTier may not be started again after this call.
/// </summary>
/// <returns></returns>
public int Free()
{
_nodeId = 0x0;
_hasBeenFreed = true;
return zts_free();
}
/// <summary>
/// Stop all ZeroTier service activity. The service may be started again with Start().
/// </summary>
/// <returns></returns>
public int Stop()
{
_nodeId = 0x0;
return zts_stop();
}
/// <summary>
/// Restarts the ZeroTier service, internal stack and driver. (Mostly used for debugging.)
/// </summary>
/// <returns></returns>
public int Restart()
{
_nodeId = 0x0;
return zts_restart();
}
/// <summary>
/// Requests to join a ZeroTier network. Remember to authorize your node/device.
/// </summary>
/// <param name="nwid">Network ID</param>
/// <returns></returns>
public int Join(ulong nwid)
{
return zts_join(nwid);
}
/// <summary>
/// Leaves a ZeroTier network.
/// </summary>
/// <param name="nwid"></param>
/// <returns></returns>
public int Leave(ulong nwid)
{
return zts_leave(nwid);
}
/// <summary>
/// Returns whether the Node is online (able to reach the internet.)
/// </summary>
/// <returns></returns>
public bool IsOnline()
{
return _isOnline;
}
/// <summary>
/// Returns whether routing information is available from at least one ZeroTier network.
/// </summary>
/// <returns></returns>
public bool HasRoutes()
{
return _joinedAtLeastOneNetwork;
}
public ulong NodeId
{
get {
return _nodeId;
}
}
/* Structures and functions used internally to communicate with
lower-level C API defined in include/ZeroTierSockets.h */
[DllImport("libzt", EntryPoint="CSharp_zts_start")]
static extern int zts_start(string arg1, CSharpCallbackWithStruct arg2, ushort arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_stop")]
static extern int zts_stop();
[DllImport("libzt", EntryPoint="CSharp_zts_restart")]
static extern int zts_restart();
[DllImport("libzt", EntryPoint="CSharp_zts_free")]
static extern int zts_free();
[DllImport("libzt", EntryPoint="CSharp_zts_join")]
static extern int zts_join(ulong arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_leave")]
static extern int zts_leave(ulong arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_allow_network_caching")]
static extern int zts_allow_network_caching(byte arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_allow_peer_caching")]
static extern int zts_allow_peer_caching(byte arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_allow_local_conf")]
static extern int zts_allow_local_conf(byte arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_orbit")]
static extern int zts_orbit(ulong arg1, ulong arg2);
[DllImport("libzt", EntryPoint="CSharp_zts_deorbit")]
static extern int zts_deorbit(ulong arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_get_6plane_addr")]
static extern int zts_get_6plane_addr(IntPtr arg1, ulong arg2, ulong arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_get_rfc4193_addr")]
static extern int zts_get_rfc4193_addr(IntPtr arg1, ulong arg2, ulong arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_generate_adhoc_nwid_from_range")]
static extern ulong zts_generate_adhoc_nwid_from_range(ushort arg1, ushort arg2);
[DllImport("libzt", EntryPoint="CSharp_zts_delay_ms")]
static extern void zts_delay_ms(int arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_errno_get")]
static extern int zts_errno_get();
[StructLayout(LayoutKind.Sequential)]
struct zts_node_details
{
public ulong address;
}
/**
* Virtual network configuration
*/
[StructLayout(LayoutKind.Sequential)]
struct zts_network_details
{
/**
* 64-bit ZeroTier network ID
*/
public ulong nwid;
/**
* Ethernet MAC (48 bits) that should be assigned to port
*/
public ulong mac;
/**
* Network name (from network configuration master)
*/
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public byte[] name;
/**
* Network configuration request status
*/
public byte status; // ?
/**
* Network type
*/
public byte type; // ?
/**
* Maximum interface MTU
*/
public uint mtu;
/**
* If nonzero, the network this port belongs to indicates DHCP availability
*
* This is a suggestion. The underlying implementation is free to ignore it
* for security or other reasons. This is simply a netconf parameter that
* means 'DHCP is available on this network.'
*/
public int dhcp;
/**
* If nonzero, this port is allowed to bridge to other networks
*
* This is informational. If this is false (0), bridged packets will simply
* be dropped and bridging won't work.
*/
public int bridge;
/**
* If nonzero, this network supports and allows broadcast (ff:ff:ff:ff:ff:ff) traffic
*/
public int broadcastEnabled;
/**
* If the network is in PORT_ERROR state, this is the (negative) error code most recently reported
*/
public int portError;
/**
* Revision number as reported by controller or 0 if still waiting for config
*/
public ulong netconfRevision;
/**
* Number of assigned addresses
*/
public uint assignedAddressCount;
/**
* ZeroTier-assigned addresses (in sockaddr_storage structures)
*
* For IP, the port number of the sockaddr_XX structure contains the number
* of bits in the address netmask. Only the IP address and port are used.
* Other fields like interface number can be ignored.
*
* This is only used for ZeroTier-managed address assignments sent by the
* virtual network's configuration master.
*/
//struct zts_sockaddr_storage assignedAddresses[ZTS_MAX_ZT_ASSIGNED_ADDRESSES];
/**
* Number of ZT-pushed routes
*/
public uint routeCount;
/**
* Routes (excluding those implied by assigned addresses and their masks)
*/
//ZTS_VirtualNetworkRoute routes[ZTS_MAX_NETWORK_ROUTES];
/**
* Number of multicast groups subscribed
*/
public uint multicastSubscriptionCount;
/**
* Multicast groups to which this network's device is subscribed
*/
//struct {
// uint64_t mac; /* MAC in lower 48 bits */
// uint32_t adi; /* Additional distinguishing information, usually zero except for IPv4 ARP groups */
//} multicastSubscriptions[ZTS_MAX_MULTICAST_SUBSCRIPTIONS];
}
[StructLayout(LayoutKind.Sequential)]
struct zts_callback_msg
{
public short eventCode;
//[MarshalAs(UnmanagedType.LPStruct, SizeConst = 4)]
public IntPtr node;
public IntPtr network;
}
/// <summary>
/// Gets the value of errno from the unmanaged region
/// </summary>
/// <value></value>
public static int ErrNo {
get {
return zts_errno_get();
}
}
}
}

View File

@@ -1,22 +1,28 @@
ZeroTier Sockets for C# .NET (Work In Progress)
ZeroTier Sockets for C# .NET
=====
This library is a re-implementation of the .NET socket class ([System.Net.Sockets.Socket](https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.socket)) built atop ZeroTier's SDK using P/INVOKE and is designed to be a direct drop-in replacement. The library consists of three main objects: `ZeroTier.Node`, `ZeroTier.Event`, and `ZeroTier.Socket`. No code change is required in your application beyond a small snippet of startup code, renaming `Socket` to `ZeroTier.Socket` (where applicable) and handling a smattering of events.
A replacement for the [System.Net.Sockets.Socket](https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.socket) class built atop ZeroTier's SDK using P/INVOKE. It is designed to be a direct drop-in replacement. The library consists of three main objects: `ZeroTier.Node`, `ZeroTier.Event`, and `ZeroTier.Socket`. No code change is required in your application beyond a small snippet of startup code, renaming `Socket` to `ZeroTier.Socket` (where applicable) and handling a smattering of events.
# Overview
tl;dr:
Add `ZeroTier.Sockets` to your project:
```powershell
Install-Package ZeroTier.Sockets
```
See [example.cs](./example.cs) for complete client/server app implementation.
```csharp
using System.Net.Sockets;
using ZeroTier;
void myCallback(ZeroTier.Event e)
void OnZeroTierEvent(ZeroTier.Event e)
{
Console.WriteLine("{0} ({1})", e.EventCode, e.EventName);
}
...
ZeroTier.Node node = new ZeroTier.Node("path", myCallback, 9991);
ZeroTier.Node node = new ZeroTier.Node("path", OnZeroTierEvent, 9991);
node.Start();
node.Join(0xc287ac0b42a6fb4c);
@@ -31,15 +37,28 @@ sock.Connect(remoteEndPoint);
node.Stop();
```
See [example.cs](./example.cs) for a complete client/server implementation.
## Building and running the example
# Building example without NuGet package (Advanced)
From top-level repo directory, build `libzt.dll/so/dylib`:
```bash
make host_pinvoke_release
```
Copy `libzt.dll/so/dylib` into this project directory:
```
make debug|release
cp ../../lib/release/${YOUR_HOST_TUPLE}-pinvoke/libzt.* .
```
Where `${YOUR_HOST_TUPLE}` is something like: `linux-x86_64`, `macOS-x86_64`, etc.
Build language binding layer, `ZeroTier.Sockets.dll`:
```bash
cd examples/csharp
${CSHARP_COMPILER} -target:library -out:ZeroTier.Sockets.dll ../../src/bindings/csharp/*.cs
${CSHARP_COMPILER} -reference:ZeroTier.Sockets.dll example.cs
./example.exe
```
## Development notes
The SWIG interface file `zt.i` is only present for historical reference purposes. SWIG generates a ton of unnecessary boilerplate code which is hard to completely prevent using hints. You can generate a new wrapper for yourself using `swig -c++ -csharp -dllimport "./libzt.so" zt.i` but I would not recommend doing so unless you know what you're in for.
Where `${CSHARP_COMPILER}` may be `csc` or `mono-csc` depending on your platform.

View File

@@ -1,591 +0,0 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2024-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
using System; // For ObjectDisposedException
using System.Net; // For IPEndPoint
using System.Net.Sockets; // For ZeroTier.SocketException
using System.Runtime.InteropServices;
using ZeroTier;
/// <summary>
/// ZeroTier SDK
/// </summary>
namespace ZeroTier
{
/// <summary>
/// ZeroTier Socket - An lwIP socket mediated over a ZeroTier virtual link
/// </summary>
public class Socket
{
/// <summary>No error.</summary>
public static readonly int ZTS_ERR_OK = 0;
/// <summary>Socket error, see Socket.ErrNo() for additional context.</summary>
public static readonly int ZTS_ERR_SOCKET = -1;
/// <summary>You probably did something at the wrong time.</summary>
public static readonly int ZTS_ERR_SERVICE = -2;
/// <summary>Invalid argument.</summary>
public static readonly int ZTS_ERR_ARG = -3;
/// <summary>No result. (not necessarily an error.)</summary>
public static readonly int ZTS_ERR_NO_RESULT = -4;
/// <summary>Consider filing a bug report.</summary>
public static readonly int ZTS_ERR_GENERAL = -5;
int _fd;
bool _isClosed;
bool _isListening;
bool _isBlocking;
AddressFamily _socketFamily;
SocketType _socketType;
ProtocolType _socketProtocol;
internal EndPoint _localEndPoint;
internal EndPoint _remoteEndPoint;
private void InitializeInternalFlags()
{
_isClosed = false;
_isListening = false;
_isBlocking = false;
}
public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
{
int family = -1;
int type = -1;
int protocol = -1;
// Map .NET socket parameters to ZeroTier equivalents
switch (addressFamily)
{
case AddressFamily.InterNetwork:
family = Constants.AF_INET;
break;
case AddressFamily.InterNetworkV6:
family = Constants.AF_INET6;
break;
case AddressFamily.Unknown:
family = Constants.AF_UNSPEC;
break;
}
switch (socketType)
{
case SocketType.Stream:
type = Constants.SOCK_STREAM;
break;
case SocketType.Dgram:
type = Constants.SOCK_DGRAM;
break;
}
switch (protocolType)
{
case ProtocolType.Udp:
protocol = Constants.IPPROTO_UDP;
break;
case ProtocolType.Tcp:
protocol = Constants.IPPROTO_TCP;
break;
case ProtocolType.Unspecified:
protocol = 0; // ?
break;
}
if ((_fd = zts_socket(family, type, protocol)) < 0)
{
throw new ZeroTier.SocketException((int)_fd);
}
_socketFamily = addressFamily;
_socketType = socketType;
_socketProtocol = protocolType;
InitializeInternalFlags();
}
private Socket(int fileDescriptor,
AddressFamily addressFamily,
SocketType socketType,
ProtocolType protocolType,
EndPoint localEndPoint,
EndPoint remoteEndPoint)
{
_socketFamily = addressFamily;
_socketType = socketType;
_socketProtocol = protocolType;
_localEndPoint = localEndPoint;
_remoteEndPoint = remoteEndPoint;
_fd = fileDescriptor;
InitializeInternalFlags();
}
public void Connect(IPEndPoint remoteEndPoint)
{
if (_isClosed) {
throw new ObjectDisposedException("Socket has been closed");
}
if (_fd < 0) {
// Invalid file descriptor
throw new ZeroTier.SocketException((int)Constants.ERR_SOCKET);
}
if (remoteEndPoint == null) {
throw new ArgumentNullException(nameof(remoteEndPoint));
}
int err = Constants.ERR_OK;
int addrlen = 0;
if (remoteEndPoint.AddressFamily == AddressFamily.InterNetwork)
{
zts_sockaddr_in sa = new zts_sockaddr_in();
addrlen = Marshal.SizeOf(typeof(zts_sockaddr_in));
switch (remoteEndPoint.AddressFamily)
{
case AddressFamily.InterNetwork:
sa.sin_family = (byte)Constants.AF_INET;
break;
case AddressFamily.InterNetworkV6:
sa.sin_family = (byte)Constants.AF_INET6;
break;
case AddressFamily.Unknown:
sa.sin_family = (byte)Constants.AF_UNSPEC;
break;
}
sa.sin_port = (short)zts_htons((ushort)remoteEndPoint.Port);
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);
}
if (remoteEndPoint.AddressFamily == AddressFamily.InterNetworkV6)
{
/*
socketAddress.iSockaddrLength = Marshal.SizeOf(typeof(sockaddr_in6));
socketAddress.lpSockAddr = CriticalAllocHandle.FromSize(socketAddress.iSockaddrLength);
sockaddr_in6 sa = new sockaddr_in6();
sa.sin6_family = (short)AddressFamily.InterNetworkV6;
sa.sin6_port = (ushort)endpoint.Port;
sa.sin6_addr = endpoint.Address.GetAddressBytes();
sa.sin6_scope_id = (uint)endpoint.Address.ScopeId;
Marshal.StructureToPtr(sa, (IntPtr)socketAddress.lpSockAddr, false);
*/
}
if (err < 0) {
throw new ZeroTier.SocketException(err, ZeroTier.Node.ErrNo);
}
_remoteEndPoint = remoteEndPoint;
}
public void Bind(IPEndPoint localEndPoint)
{
if (_isClosed) {
throw new ObjectDisposedException("Socket has been closed");
}
if (_fd < 0) {
// Invalid file descriptor
throw new ZeroTier.SocketException((int)Constants.ERR_SOCKET);
}
if (localEndPoint == null) {
throw new ArgumentNullException(nameof(localEndPoint));
}
int err = Constants.ERR_OK;
int addrlen = 0;
if (localEndPoint.AddressFamily == AddressFamily.InterNetwork)
{
zts_sockaddr_in sa = new zts_sockaddr_in();
addrlen = Marshal.SizeOf(typeof(zts_sockaddr_in));
switch (localEndPoint.AddressFamily)
{
case AddressFamily.InterNetwork:
sa.sin_family = (byte)Constants.AF_INET;
break;
case AddressFamily.InterNetworkV6:
sa.sin_family = (byte)Constants.AF_INET6;
break;
case AddressFamily.Unknown:
sa.sin_family = (byte)Constants.AF_UNSPEC;
break;
}
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);
}
if (localEndPoint.AddressFamily == AddressFamily.InterNetworkV6)
{
/*
socketAddress.iSockaddrLength = Marshal.SizeOf(typeof(sockaddr_in6));
socketAddress.lpSockAddr = CriticalAllocHandle.FromSize(socketAddress.iSockaddrLength);
sockaddr_in6 sa = new sockaddr_in6();
sa.sin6_family = (short)AddressFamily.InterNetworkV6;
sa.sin6_port = (ushort)endpoint.Port;
sa.sin6_addr = endpoint.Address.GetAddressBytes();
sa.sin6_scope_id = (uint)endpoint.Address.ScopeId;
Marshal.StructureToPtr(sa, (IntPtr)socketAddress.lpSockAddr, false);
*/
}
if (err < 0) {
throw new ZeroTier.SocketException((int)err);
}
_localEndPoint = localEndPoint;
}
public void Listen(int backlog)
{
if (_isClosed) {
throw new ObjectDisposedException("Socket has been closed");
}
if (_fd < 0) {
// Invalid file descriptor
throw new ZeroTier.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);
}
_isListening = true;
}
public Socket Accept()
{
if (_isClosed) {
throw new ObjectDisposedException("Socket has been closed");
}
if (_fd < 0) {
// Invalid file descriptor
throw new ZeroTier.SocketException((int)Constants.ERR_SOCKET);
}
if (_isListening == false) {
throw new InvalidOperationException("Socket is not in a listening state. Call Listen() first");
}
// TODO: Rewrite -- Check for memory leaks
// Inform zts_accept of the size of the available address buffer
int addrlen = Marshal.SizeOf(typeof(zts_sockaddr_in));
IntPtr addrlenPtr = GCHandle.Alloc(addrlen, GCHandleType.Pinned).AddrOfPinnedObject();
// Allocate space for address buffer and provide pointer to zts_accept
zts_sockaddr_in in4 = new zts_sockaddr_in();
IntPtr remoteAddrPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(zts_sockaddr_in)));
Marshal.StructureToPtr(in4, remoteAddrPtr, false);
int err = zts_accept(_fd, remoteAddrPtr, addrlenPtr);
if (err < 0) {
throw new ZeroTier.SocketException(err, ZeroTier.Node.ErrNo);
}
in4 = (zts_sockaddr_in)Marshal.PtrToStructure(remoteAddrPtr, typeof(zts_sockaddr_in));
// Convert sockaddr contents to IPEndPoint
IPAddress ipAddress = new IPAddress(in4.sin_addr);
IPEndPoint clientEndPoint = new IPEndPoint(ipAddress, zts_ntohs((ushort)in4.sin_port));
// Create new socket by providing file descriptor returned from zts_accept call.
Socket clientSocket = new Socket(
err, _socketFamily, _socketType, _socketProtocol, _localEndPoint, clientEndPoint);
return clientSocket;
}
public void Shutdown(SocketShutdown how)
{
if (_isClosed) {
throw new ObjectDisposedException("Socket has been closed");
}
int ztHow = 0;
switch (how)
{
case SocketShutdown.Receive:
ztHow = Constants.O_RDONLY;
break;
case SocketShutdown.Send:
ztHow = Constants.O_WRONLY;
break;
case SocketShutdown.Both:
ztHow = Constants.O_RDWR;
break;
}
zts_shutdown(_fd, ztHow);
}
public void Close()
{
if (_isClosed) {
throw new ObjectDisposedException("Socket has already been closed");
}
zts_close(_fd);
_isClosed = true;
}
public EndPoint RemoteEndPoint
{
get {
return _remoteEndPoint;
}
}
public EndPoint LocalEndPoint
{
get {
return _localEndPoint;
}
}
public bool Blocking
{
get {
return _isBlocking;
}
set {
if (_isClosed) {
throw new ObjectDisposedException("Socket has been closed");
}
int opts = 0;
if ((opts = zts_fcntl(_fd, (int)(ZeroTier.Constants.F_GETFL), 0)) < 0) {
throw new ZeroTier.SocketException(opts, ZeroTier.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);
}
_isBlocking = value;
}
}
public bool Poll(int microSeconds, System.Net.Sockets.SelectMode mode)
{
if (_isClosed) {
throw new ObjectDisposedException("Socket has been closed");
}
zts_pollfd poll_set = new zts_pollfd();
poll_set.fd = _fd;
if (mode == SelectMode.SelectRead) {
poll_set.events = (short)((byte)ZeroTier.Constants.POLLIN);
}
if (mode == SelectMode.SelectWrite) {
poll_set.events = (short)((byte)ZeroTier.Constants.POLLOUT);
}
if (mode == SelectMode.SelectError) {
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);
int result = 0;
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);
}
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 (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;
}
public Int32 Send(Byte[] buffer)
{
if (_isClosed) {
throw new ObjectDisposedException("Socket has been closed");
}
if (_fd < 0) {
throw new ZeroTier.SocketException((int)ZeroTier.Constants.ERR_SOCKET);
}
if (buffer == null) {
throw new ArgumentNullException(nameof(buffer));
}
int flags = 0;
IntPtr bufferPtr = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0);
return zts_send(_fd, bufferPtr, (uint)Buffer.ByteLength(buffer), (int)flags);
}
public Int32 Receive(Byte[] buffer)
{
if (_isClosed) {
throw new ObjectDisposedException("Socket has been closed");
}
if (_fd < 0) {
throw new ZeroTier.SocketException((int)ZeroTier.Constants.ERR_SOCKET);
}
if (buffer == null) {
throw new ArgumentNullException(nameof(buffer));
}
int flags = 0;
IntPtr bufferPtr = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0);
return zts_recv(_fd, bufferPtr, (uint)Buffer.ByteLength(buffer), (int)flags);
}
/* Structures and functions used internally to communicate with
lower-level C API defined in include/ZeroTierSockets.h */
[DllImport("libzt", EntryPoint="CSharp_zts_get_all_stats")]
static extern int zts_get_all_stats(IntPtr arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_get_protocol_stats")]
static extern int zts_get_protocol_stats(int arg1, IntPtr arg2);
[DllImport("libzt", EntryPoint="CSharp_zts_socket")]
static extern int zts_socket(int arg1, int arg2, int arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_connect")]
static extern int zts_connect(int arg1, IntPtr arg2, ushort arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_bind")]
static extern int zts_bind(int arg1, IntPtr arg2, ushort arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_listen")]
static extern int zts_listen(int arg1, int arg2);
[DllImport("libzt", EntryPoint="CSharp_zts_accept")]
static extern int zts_accept(int arg1, IntPtr arg2, IntPtr arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_setsockopt")]
static extern int zts_setsockopt(int arg1, int arg2, int arg3, IntPtr arg4, ushort arg5);
[DllImport("libzt", EntryPoint="CSharp_zts_getsockopt")]
static extern int zts_getsockopt(int arg1, int arg2, int arg3, IntPtr arg4, IntPtr arg5);
[DllImport("libzt", EntryPoint="CSharp_zts_getsockname")]
static extern int zts_getsockname(int arg1, IntPtr arg2, IntPtr arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_getpeername")]
static extern int zts_getpeername(int arg1, IntPtr arg2, IntPtr arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_close")]
static extern int zts_close(int arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_fcntl")]
static extern int zts_fcntl(int arg1, int arg2, int arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_poll")]
static extern int zts_poll(IntPtr arg1, uint arg2, int arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_ioctl")]
static extern int zts_ioctl(int arg1, uint arg2, IntPtr arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_send")]
static extern int zts_send(int arg1, IntPtr arg2, uint arg3, int arg4);
[DllImport("libzt", EntryPoint="CSharp_zts_sendto")]
static extern int zts_sendto(int arg1, IntPtr arg2, uint arg3, int arg4, IntPtr arg5, ushort arg6);
[DllImport("libzt", EntryPoint="CSharp_zts_sendmsg")]
static extern int zts_sendmsg(int arg1, IntPtr arg2, int arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_recv")]
static extern int zts_recv(int arg1, IntPtr arg2, uint arg3, int arg4);
[DllImport("libzt", EntryPoint="CSharp_zts_recvfrom")]
static extern int zts_recvfrom(int arg1, IntPtr arg2, uint arg3, int arg4, IntPtr arg5, IntPtr arg6);
[DllImport("libzt", EntryPoint="CSharp_zts_recvmsg")]
static extern int zts_recvmsg(int arg1, IntPtr arg2, int arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_read")]
static extern int zts_read(int arg1, IntPtr arg2, uint arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_readv")]
static extern int zts_readv(int arg1, IntPtr arg2, int arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_write")]
static extern int zts_write(int arg1, IntPtr arg2, uint arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_writev")]
static extern int zts_writev(int arg1, IntPtr arg2, int arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_shutdown")]
static extern int zts_shutdown(int arg1, int arg2);
[DllImport("libzt", EntryPoint="CSharp_zts_add_dns_nameserver")]
static extern int zts_add_dns_nameserver(IntPtr arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_del_dns_nameserver")]
static extern int zts_del_dns_nameserver(IntPtr arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_htons")]
static extern ushort zts_htons(ushort arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_htonl")]
static extern ushort zts_htonl(ushort arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_ntohs")]
static extern ushort zts_ntohs(ushort arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_ntohl")]
static extern ushort zts_ntohl(ushort arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_inet_ntop")]
static extern string zts_inet_ntop(int arg1, IntPtr arg2, string arg3, ushort arg4);
[DllImport("libzt", EntryPoint="CSharp_zts_inet_pton")]
static extern int zts_inet_pton(int arg1, string arg2, IntPtr arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_inet_addr")]
static extern ushort zts_inet_addr(string arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_errno_get")]
static extern int zts_errno_get();
/// <value>The value of errno for the low-level socket layer</value>
public static int ErrNo {
get {
return zts_errno_get();
}
}
[StructLayout(LayoutKind.Sequential)]
struct zts_sockaddr
{
public byte sa_len;
public byte sa_family;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)]
public byte[] sa_data;
}
[StructLayout(LayoutKind.Sequential)]
struct zts_in_addr
{
public uint s_addr;
}
[StructLayout(LayoutKind.Sequential)]
struct zts_sockaddr_in
{
public byte sin_len;
public byte sin_family;
public short sin_port;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] sin_addr;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public char[] sin_zero; // SIN_ZERO_LEN
}
[StructLayout(LayoutKind.Sequential)]
struct zts_pollfd
{
public int fd;
public short events;
public short revents;
}
}
}

View File

@@ -1,38 +0,0 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2024-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
using System;
namespace ZeroTier
{
/// <summary>Exception class for ZeroTier service and low-level socket errors</summary>
public class SocketException : Exception
{
public SocketException(int _serviceErrorCode)
: base(String.Format("ServiceErrorCode={0} (See Constants.cs for error code meanings)", _serviceErrorCode))
{
ServiceErrorCode = _serviceErrorCode;
}
public SocketException(int _serviceErrorCode, int _socketErrorCode)
: base(String.Format("ServiceErrorCode={0}, SocketErrorCode={1} (See Constants.cs for error code meanings)", _serviceErrorCode, _socketErrorCode))
{
ServiceErrorCode = _serviceErrorCode;
SocketErrorCode = _socketErrorCode;
}
/// <value>High-level service error code. See Constants.cs</value>
public int ServiceErrorCode { get; }
/// <value>Low-level socket error code. See Constants.cs</value>
public int SocketErrorCode { get; }
}
}

View File

@@ -1,55 +0,0 @@
%module zt
%include <windows.i>
%include <stl.i>
%include <typemaps.i>
// Prevent SWIG from doing anything funny with our types
%apply unsigned char { uint8_t };
%apply char { int8_t };
%apply unsigned short { uint16_t };
%apply int { int16_t };
%apply unsigned short { uint32_t };
%apply int { int32_t };
%apply unsigned long long { uint64_t };
%apply long long { int64_t };
%typemap(ctype) zts_sockaddr* "zts_sockaddr*"
// Ignore all classes/structs (We'll define these manually in C#)
// %rename($ignore, %$isclass) "";
%ignore zts_in6_addr;
%ignore zts_sockaddr;
%ignore zts_in_addr;
%ignore zts_sockaddr_in;
%ignore zts_sockaddr_storage;
%ignore zts_sockaddr_in6;
%ignore zts_callback_msg;
%ignore zts_node_details;
%ignore zts_network_details;
%ignore zts_netif_details;
%ignore zts_virtual_network_route;
%ignore zts_peer_details;
%ignore zts_addr_details;
#define ZTS_CSHARP=1
%{
#include "../../include/ZeroTierSockets.h"
%}
// Typemap for our event callback
%define %cs_callback(TYPE, CSTYPE)
%typemap(ctype) TYPE, TYPE& "void *"
%typemap(in) TYPE %{ $1 = ($1_type)$input; %}
%typemap(in) TYPE& %{ $1 = ($1_type)&$input; %}
%typemap(imtype, out="IntPtr") TYPE, TYPE& "CSTYPE"
%typemap(cstype, out="IntPtr") TYPE, TYPE& "CSTYPE"
%typemap(csin) TYPE, TYPE& "$csinput"
%enddef
%cs_callback(CppCallback, CSharpCallbackWithStruct)
%include "../../include/ZeroTierSockets.h"

File diff suppressed because it is too large Load Diff