Add C# P/INVOKE wrapper and client/server example
This commit is contained in:
9
Makefile
9
Makefile
@@ -80,7 +80,7 @@ xcframework:
|
||||
-framework build/iphoneos.xcarchive/Products/Library/Frameworks/zt.framework \
|
||||
-framework build/iphonesimulator.xcarchive/Products/Library/Frameworks/zt.framework \
|
||||
-output lib/zt.xcframework
|
||||
|
||||
|
||||
rm -rf build/macosx.xcarchive
|
||||
rm -rf build/iphoneos.xcarchive
|
||||
rm -rf build/iphonesimulator.xcarchive
|
||||
@@ -104,6 +104,13 @@ host_jar_debug:
|
||||
host_jar_release:
|
||||
$(DIST_BUILD_SCRIPT) host_jar "release"
|
||||
host_jar: host_jar_debug host_jar_release
|
||||
|
||||
host_pinvoke_release:
|
||||
$(DIST_BUILD_SCRIPT) host_pinvoke "release"
|
||||
host_pinvoke_debug:
|
||||
$(DIST_BUILD_SCRIPT) host_pinvoke "debug"
|
||||
host_pinvoke: host_pinvoke_release host_pinvoke_debug
|
||||
|
||||
host: host_debug host_release
|
||||
|
||||
# Build every target available on this host
|
||||
|
||||
31
dist.sh
31
dist.sh
@@ -263,6 +263,37 @@ host_jar()
|
||||
# java -cp "lib/debug/macos-x86_64/zt.jar:examples/java/src/main/java" ExampleApp
|
||||
}
|
||||
|
||||
# Build all ordinary library types for current host
|
||||
host_pinvoke()
|
||||
{
|
||||
echo "Executing task: " ${FUNCNAME[ 0 ]} "(" $1 ")"
|
||||
NORMALIZED_OSNAME=$OSNAME
|
||||
if [[ $OSNAME = *"darwin"* ]]; then
|
||||
DYNAMIC_LIB_NAME="libzt.dylib"
|
||||
NORMALIZED_OSNAME="macos"
|
||||
fi
|
||||
if [[ $OSNAME = *"linux"* ]]; then
|
||||
DYNAMIC_LIB_NAME="libzt.so"
|
||||
fi
|
||||
# CMake build files
|
||||
BUILD_DIR=$(pwd)/tmp/${NORMALIZED_OSNAME}-$(uname -m)-$1
|
||||
mkdir -p $BUILD_DIR
|
||||
# Where to place results
|
||||
BIN_OUTPUT_DIR=$(pwd)/bin/$1/${NORMALIZED_OSNAME}-$(uname -m)
|
||||
mkdir -p $BIN_OUTPUT_DIR
|
||||
rm -rf $BIN_OUTPUT_DIR/*
|
||||
LIB_OUTPUT_DIR=$(pwd)/lib/$1/${NORMALIZED_OSNAME}-$(uname -m)
|
||||
mkdir -p $LIB_OUTPUT_DIR
|
||||
rm -rf $LIB_OUTPUT_DIR/libzt.a $LIB_OUTPUT_DIR/$DYNAMIC_LIB_NAME $LIB_OUTPUT_DIR/libztcore.a
|
||||
# Build
|
||||
cmake -DZTS_PINVOKE=True -H. -B$BUILD_DIR -DCMAKE_BUILD_TYPE=$1
|
||||
$CMAKE --build $BUILD_DIR $BUILD_CONCURRENCY
|
||||
# Move and clean up
|
||||
mv $BUILD_DIR/bin/* $BIN_OUTPUT_DIR
|
||||
mv $BUILD_DIR/lib/* $LIB_OUTPUT_DIR
|
||||
clean_post_build
|
||||
}
|
||||
|
||||
# Build all ordinary library types for current host
|
||||
host()
|
||||
{
|
||||
|
||||
353
examples/csharp/Constants.cs
Normal file
353
examples/csharp/Constants.cs
Normal file
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
156
examples/csharp/Event.cs
Normal file
156
examples/csharp/Event.cs
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
examples/csharp/Makefile
Normal file
12
examples/csharp/Makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
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
|
||||
492
examples/csharp/Node.cs
Normal file
492
examples/csharp/Node.cs
Normal file
@@ -0,0 +1,492 @@
|
||||
/*
|
||||
* 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
|
||||
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 myZeroTierEventCallback(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,myZeroTierEventCallback,_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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
45
examples/csharp/README.md
Normal file
45
examples/csharp/README.md
Normal file
@@ -0,0 +1,45 @@
|
||||
ZeroTier Sockets for C# .NET (Work In Progress)
|
||||
=====
|
||||
|
||||
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.
|
||||
|
||||
|
||||
tl;dr:
|
||||
|
||||
```
|
||||
using System.Net.Sockets;
|
||||
using ZeroTier;
|
||||
|
||||
void myCallback(ZeroTier.Event e)
|
||||
{
|
||||
Console.WriteLine("{0} ({1})", e.EventCode, e.EventName);
|
||||
}
|
||||
...
|
||||
|
||||
ZeroTier.Node node = new ZeroTier.Node("path", myCallback, 9991);
|
||||
|
||||
node.Start();
|
||||
node.Join(0xc287ac0b42a6fb4c);
|
||||
|
||||
...
|
||||
|
||||
ZeroTier.Socket sock = new ZeroTier.Socket(ipAddr.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
|
||||
sock.Connect(remoteEndPoint);
|
||||
|
||||
...
|
||||
|
||||
node.Stop();
|
||||
```
|
||||
See [example.cs](./example.cs) for a complete client/server implementation.
|
||||
|
||||
## Building and running the example
|
||||
|
||||
```
|
||||
make debug|release
|
||||
./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.
|
||||
513
examples/csharp/Socket.cs
Normal file
513
examples/csharp/Socket.cs
Normal file
@@ -0,0 +1,513 @@
|
||||
/*
|
||||
* 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 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;
|
||||
|
||||
AddressFamily _socketFamily;
|
||||
SocketType _socketType;
|
||||
ProtocolType _socketProtocol;
|
||||
|
||||
internal EndPoint _localEndPoint;
|
||||
internal EndPoint _remoteEndPoint;
|
||||
|
||||
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_TCP;
|
||||
break;
|
||||
case ProtocolType.Tcp:
|
||||
protocol = Constants.IPPROTO_UDP;
|
||||
break;
|
||||
case ProtocolType.Unspecified:
|
||||
protocol = 0; // ?
|
||||
break;
|
||||
}
|
||||
if ((_fd = zts_socket(family, type, protocol)) < 0)
|
||||
{
|
||||
throw new SocketException((int)_fd);
|
||||
}
|
||||
_socketFamily = addressFamily;
|
||||
_socketType = socketType;
|
||||
_socketProtocol = protocolType;
|
||||
_isClosed = false;
|
||||
}
|
||||
|
||||
private Socket(int fileDescriptor,
|
||||
AddressFamily addressFamily,
|
||||
SocketType socketType,
|
||||
ProtocolType protocolType,
|
||||
EndPoint localEndPoint,
|
||||
EndPoint remoteEndPoint)
|
||||
{
|
||||
_socketFamily = addressFamily;
|
||||
_socketType = socketType;
|
||||
_socketProtocol = protocolType;
|
||||
_localEndPoint = localEndPoint;
|
||||
_remoteEndPoint = remoteEndPoint;
|
||||
_isClosed = false;
|
||||
_isListening = false;
|
||||
_fd = fileDescriptor;
|
||||
}
|
||||
|
||||
public void Connect(IPEndPoint remoteEndPoint)
|
||||
{
|
||||
if (_isClosed) {
|
||||
throw new ObjectDisposedException("Socket has been closed");
|
||||
}
|
||||
if (_fd < 0) {
|
||||
// Invalid file descriptor
|
||||
throw new 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 SocketException((int)err);
|
||||
}
|
||||
_remoteEndPoint = remoteEndPoint;
|
||||
}
|
||||
|
||||
public void Bind(IPEndPoint localEndPoint)
|
||||
{
|
||||
if (_isClosed) {
|
||||
throw new ObjectDisposedException("Socket has been closed");
|
||||
}
|
||||
if (_fd < 0) {
|
||||
// Invalid file descriptor
|
||||
throw new 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 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 SocketException((int)Constants.ERR_SOCKET);
|
||||
}
|
||||
int err = Constants.ERR_OK;
|
||||
if ((err = zts_listen(_fd, backlog)) < 0) {
|
||||
// Invalid backlog value perhaps?
|
||||
throw new 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 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 SocketException((int)err);
|
||||
}
|
||||
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 Int32 Send(Byte[] buffer)
|
||||
{
|
||||
if (_isClosed) {
|
||||
throw new ObjectDisposedException("Socket has been closed");
|
||||
}
|
||||
if (_fd < 0) {
|
||||
throw new 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 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();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of errno from the unmanaged region
|
||||
/// </summary>
|
||||
/// <value></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
|
||||
}
|
||||
}
|
||||
}
|
||||
201
examples/csharp/example.cs
Normal file
201
examples/csharp/example.cs
Normal file
@@ -0,0 +1,201 @@
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Net;
|
||||
using System.Net.Sockets; // For SocketType, etc
|
||||
using System.Text; // For Encoding
|
||||
|
||||
using ZeroTier; // For ZeroTier.Node, ZeroTier.Event, and ZeroTier.Socket
|
||||
|
||||
public class ExampleApp {
|
||||
|
||||
ZeroTier.Node node;
|
||||
|
||||
/**
|
||||
* Initialize and start ZeroTier
|
||||
*/
|
||||
public void StartZeroTier(string configFilePath, ushort servicePort, ulong networkId)
|
||||
{
|
||||
node = new ZeroTier.Node(configFilePath, myZeroTierEventCallback, servicePort);
|
||||
node.Start(); // Network activity only begins after calling Start()
|
||||
|
||||
/* How you do this next part is up to you, but essentially we're waiting for the node
|
||||
to signal to us (via a ZeroTierEvent) that it has access to the internet and is
|
||||
able to talk to one of our root servers. As a convenience you can just periodically check
|
||||
IsOnline() instead of looking for the event via the callback. */
|
||||
while (!node.IsOnline()) { Thread.Sleep(100); }
|
||||
|
||||
/* After the node comes online you may now join/leave networks. You will receive
|
||||
notifications via the callback function regarding the status of your join request as well
|
||||
as any subsequent network-related events such as the assignment of an IP address, added
|
||||
or removed routes, etc. */
|
||||
node.Join(networkId);
|
||||
|
||||
/* Note that ZeroTierSocket calls will fail if there are no routes available, for this
|
||||
reason we should wait to make those calls until the node has indicated to us that at
|
||||
least one network has been joined successfully. */
|
||||
while (!node.HasRoutes()) { Thread.Sleep(100); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop ZeroTier
|
||||
*/
|
||||
public void StopZeroTier()
|
||||
{
|
||||
node.Stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Your application should process event messages and return control as soon as possible. Blocking
|
||||
* or otherwise time-consuming operations are not reccomended here.
|
||||
*/
|
||||
public void myZeroTierEventCallback(ZeroTier.Event e)
|
||||
{
|
||||
Console.WriteLine("Event.eventCode = {0} ({1})", e.EventCode, e.EventName);
|
||||
|
||||
if (e.EventCode == ZeroTier.Constants.EVENT_NODE_ONLINE) {
|
||||
Console.WriteLine("Node is online");
|
||||
Console.WriteLine(" - Address (NodeId): " + node.NodeId);
|
||||
}
|
||||
|
||||
if (e.EventCode == ZeroTier.Constants.EVENT_NETWORK_OK) {
|
||||
Console.WriteLine(" - Network ID: " + e.networkDetails.networkId.ToString("x16"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example server
|
||||
*/
|
||||
public void YourServer() {
|
||||
string data = null;
|
||||
|
||||
// Data buffer for incoming data.
|
||||
byte[] bytes = new Byte[1024];
|
||||
|
||||
string serverIP = "0.0.0.0";
|
||||
int port = 8000;
|
||||
IPAddress ipAddress = IPAddress.Parse(serverIP);
|
||||
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, port);
|
||||
|
||||
Console.WriteLine(localEndPoint.ToString());
|
||||
ZeroTier.Socket listener = new ZeroTier.Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp );
|
||||
|
||||
// Bind the socket to the local endpoint and
|
||||
// listen for incoming connections.
|
||||
|
||||
try {
|
||||
listener.Bind(localEndPoint);
|
||||
listener.Listen(10);
|
||||
|
||||
// Start listening for connections.
|
||||
while (true) {
|
||||
Console.WriteLine("Waiting for a connection...");
|
||||
// Program is suspended while waiting for an incoming connection.
|
||||
Console.WriteLine("accepting...");
|
||||
ZeroTier.Socket handler = listener.Accept();
|
||||
data = null;
|
||||
|
||||
Console.WriteLine("accepted connection from: " + handler.RemoteEndPoint.ToString());
|
||||
|
||||
// An incoming connection needs to be processed.
|
||||
while (true) {
|
||||
int bytesRec = handler.Receive(bytes);
|
||||
data += Encoding.ASCII.GetString(bytes,0,bytesRec);
|
||||
if (data.IndexOf("<EOF>") > -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Show the data on the console.
|
||||
Console.WriteLine( "Text received : {0}", data);
|
||||
|
||||
// Echo the data back to the client.
|
||||
byte[] msg = Encoding.ASCII.GetBytes(data);
|
||||
|
||||
handler.Send(msg);
|
||||
handler.Shutdown(SocketShutdown.Both);
|
||||
handler.Close();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Console.WriteLine(e.ToString());
|
||||
}
|
||||
|
||||
Console.WriteLine("\nPress ENTER to continue...");
|
||||
Console.Read();
|
||||
}
|
||||
|
||||
/**
|
||||
* Example client
|
||||
*/
|
||||
public void YourClient() {
|
||||
// Data buffer for incoming data.
|
||||
byte[] bytes = new byte[1024];
|
||||
|
||||
// Connect to a remote device.
|
||||
try {
|
||||
string serverIP = "10.244.180.7";
|
||||
int port = 8000;
|
||||
IPAddress ipAddress = IPAddress.Parse(serverIP);
|
||||
IPEndPoint remoteEndPoint = new IPEndPoint(ipAddress, port);
|
||||
|
||||
// Create a TCP/IP socket.
|
||||
ZeroTier.Socket sender = new ZeroTier.Socket(ipAddress.AddressFamily,
|
||||
SocketType.Stream, ProtocolType.Tcp );
|
||||
|
||||
// Connect the socket to the remote endpoint. Catch any errors.
|
||||
try {
|
||||
|
||||
Console.WriteLine("Socket connecting to {0}...",
|
||||
remoteEndPoint.ToString());
|
||||
|
||||
sender.Connect(remoteEndPoint);
|
||||
|
||||
Console.WriteLine("Socket connected to {0}",
|
||||
sender.RemoteEndPoint.ToString());
|
||||
|
||||
// Encode the data string into a byte array.
|
||||
byte[] msg = Encoding.ASCII.GetBytes("This is a test");
|
||||
|
||||
// Send the data through the socket.
|
||||
int bytesSent = sender.Send(msg);
|
||||
|
||||
// Receive the response from the remote device.
|
||||
int bytesRec = sender.Receive(bytes);
|
||||
Console.WriteLine("Echoed test = {0}",
|
||||
Encoding.ASCII.GetString(bytes,0,bytesRec));
|
||||
|
||||
// Release the socket.
|
||||
sender.Shutdown(SocketShutdown.Both);
|
||||
sender.Close();
|
||||
|
||||
} catch (ArgumentNullException ane) {
|
||||
Console.WriteLine("ArgumentNullException : {0}",ane.ToString());
|
||||
} catch (SocketException se) {
|
||||
Console.WriteLine("SocketException : {0}",se.ToString());
|
||||
} catch (Exception e) {
|
||||
Console.WriteLine("Unexpected exception : {0}", e.ToString());
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Console.WriteLine( e.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class example
|
||||
{
|
||||
static void Main()
|
||||
{
|
||||
ExampleApp exampleApp = new ExampleApp();
|
||||
|
||||
ulong networkId = 0x8216ab0a47c622a1;
|
||||
ushort servicePort = 9991;
|
||||
string configFilePath = "path";
|
||||
|
||||
exampleApp.StartZeroTier(configFilePath, servicePort, networkId);
|
||||
exampleApp.YourClient();
|
||||
exampleApp.StopZeroTier();
|
||||
}
|
||||
}
|
||||
|
||||
55
examples/csharp/zt.i
Normal file
55
examples/csharp/zt.i
Normal file
@@ -0,0 +1,55 @@
|
||||
%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"
|
||||
1143
examples/csharp/zt_wrap.cxx
Normal file
1143
examples/csharp/zt_wrap.cxx
Normal file
File diff suppressed because it is too large
Load Diff
@@ -93,7 +93,11 @@ int zts_allow_local_conf(uint8_t allowed = 1)
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
|
||||
#ifdef ZTS_PINVOKE
|
||||
int zts_start(const char *path, CppCallback callback, uint16_t port)
|
||||
#else
|
||||
int zts_start(const char *path, void (*callback)(void *), uint16_t port)
|
||||
#endif
|
||||
{
|
||||
Mutex::Lock _l(serviceLock);
|
||||
_lwip_driver_init();
|
||||
|
||||
Reference in New Issue
Block a user