This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
zhangyang-libzt/src/bindings/csharp/Socket.cs

663 lines
20 KiB
C#
Raw Normal View History

/*
2021-02-04 11:03:55 -08:00
* Copyright (c)2013-2021 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.
*
2021-02-04 11:03:55 -08:00
* Change Date: 2025-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
2021-02-16 21:56:44 -08:00
using System.Net.Sockets; // For ZeroTier.Sockets.SocketException
using System.Runtime.InteropServices;
using ZeroTier;
/// <summary>
/// ZeroTier SDK
/// </summary>
2021-02-16 21:56:44 -08:00
namespace ZeroTier.Sockets
{
/// <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;
2021-02-16 21:56:44 -08:00
bool _isBound;
bool _isConnected;
int _connectTimeout = 30000;
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)
{
2021-02-16 21:56:44 -08:00
throw new ZeroTier.Sockets.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
2021-02-16 21:56:44 -08:00
throw new ZeroTier.Sockets.SocketException((int)Constants.ERR_SOCKET);
}
if (remoteEndPoint == null) {
throw new ArgumentNullException("remoteEndPoint");
}
int err = Constants.ERR_OK;
if (remoteEndPoint.AddressFamily == AddressFamily.InterNetwork) {
err = zts_connect_easy(
_fd,
Constants.AF_INET,
remoteEndPoint.Address.ToString(),
(ushort)remoteEndPoint.Port,
_connectTimeout);
}
if (remoteEndPoint.AddressFamily == AddressFamily.InterNetworkV6) {
Console.WriteLine("going to connect to: " + remoteEndPoint.ToString());
err = zts_connect_easy(
_fd,
Constants.AF_INET6,
remoteEndPoint.Address.ToString(),
(ushort)remoteEndPoint.Port,
_connectTimeout);
}
if (err < 0) {
2021-02-16 21:56:44 -08:00
throw new ZeroTier.Sockets.SocketException(err, ZeroTier.Core.Node.ErrNo);
}
_remoteEndPoint = remoteEndPoint;
2021-02-16 21:56:44 -08:00
_isConnected = true;
}
public void Bind(IPEndPoint localEndPoint)
{
if (_isClosed) {
throw new ObjectDisposedException("Socket has been closed");
}
if (_fd < 0) {
// Invalid file descriptor
2021-02-16 21:56:44 -08:00
throw new ZeroTier.Sockets.SocketException((int)Constants.ERR_SOCKET);
}
if (localEndPoint == null) {
throw new ArgumentNullException("localEndPoint");
}
int err = Constants.ERR_OK;
if (localEndPoint.AddressFamily == AddressFamily.InterNetwork) {
err = zts_bind_easy(
_fd,
Constants.AF_INET,
"0.0.0.0",
(ushort)localEndPoint.Port);
}
if (localEndPoint.AddressFamily == AddressFamily.InterNetworkV6) {
// Todo: detect IPAddress.IPv6Any
err = zts_bind_easy(
_fd,
Constants.AF_INET6,
"::",
(ushort)localEndPoint.Port);
}
if (err < 0) {
2021-02-16 21:56:44 -08:00
throw new ZeroTier.Sockets.SocketException((int)err);
}
_localEndPoint = localEndPoint;
2021-02-16 21:56:44 -08:00
_isBound = true;
}
public void Listen(int backlog)
{
if (_isClosed) {
throw new ObjectDisposedException("Socket has been closed");
}
if (_fd < 0) {
// Invalid file descriptor
2021-02-16 21:56:44 -08:00
throw new ZeroTier.Sockets.SocketException((int)Constants.ERR_SOCKET);
}
int err = Constants.ERR_OK;
if ((err = zts_listen(_fd, backlog)) < 0) {
// Invalid backlog value perhaps?
2021-02-16 21:56:44 -08:00
throw new ZeroTier.Sockets.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
2021-02-16 21:56:44 -08:00
throw new ZeroTier.Sockets.SocketException((int)Constants.ERR_SOCKET);
}
if (_isListening == false) {
throw new InvalidOperationException(
"Socket is not in a listening state. Call Listen() first");
}
IntPtr lpBuffer = Marshal.AllocHGlobal(ZeroTier.Constants.INET6_ADDRSTRLEN);
int port = 0;
int accepted_fd = zts_accept_easy(
_fd, lpBuffer, ZeroTier.Constants.INET6_ADDRSTRLEN, ref port);
// Convert buffer to managed string
string str = Marshal.PtrToStringAnsi(lpBuffer);
Marshal.FreeHGlobal(lpBuffer);
lpBuffer = IntPtr.Zero;
IPEndPoint clientEndPoint = new IPEndPoint(IPAddress.Parse(str), port);
Console.WriteLine("clientEndPoint = " + clientEndPoint.ToString());
// Create new socket by providing file descriptor returned from zts_accept call.
Socket clientSocket = new Socket(
accepted_fd, _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 bool Blocking
{
get { return Convert.ToBoolean(zts_get_blocking(_fd)); }
set { zts_set_blocking(_fd, Convert.ToInt32(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) {
2021-02-16 21:56:44 -08:00
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) {
2021-02-16 21:56:44 -08:00
throw new ZeroTier.Sockets.SocketException(result, ZeroTier.Core.Node.ErrNo);
}
poll_set = (zts_pollfd)Marshal.PtrToStructure(poll_fd_ptr, typeof(zts_pollfd));
2021-02-16 21:56:44 -08:00
if (result != 0) {
if (mode == SelectMode.SelectRead) {
result = Convert.ToInt32(((byte)poll_set.revents
& (byte)ZeroTier.Constants.POLLIN) != 0);
2021-02-16 21:56:44 -08:00
}
if (mode == SelectMode.SelectWrite) {
result = Convert.ToInt32(((byte)poll_set.revents
& (byte)ZeroTier.Constants.POLLOUT) != 0);
2021-02-16 21:56:44 -08:00
}
if (mode == SelectMode.SelectError) {
result = Convert.ToInt32(((poll_set.revents
& (byte)ZeroTier.Constants.POLLERR) != 0) ||
2021-02-16 21:56:44 -08:00
((poll_set.revents & (byte)ZeroTier.Constants.POLLNVAL) != 0));
}
}
2021-02-16 21:56:44 -08:00
Marshal.FreeHGlobal(poll_fd_ptr);
return result > 0;
}
public Int32 Send(Byte[] buffer)
{
if (_isClosed) {
throw new ObjectDisposedException("Socket has been closed");
}
if (_fd < 0) {
2021-02-16 21:56:44 -08:00
throw new ZeroTier.Sockets.SocketException((int)ZeroTier.Constants.ERR_SOCKET);
}
if (buffer == null) {
throw new ArgumentNullException("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) {
2021-02-16 21:56:44 -08:00
throw new ZeroTier.Sockets.SocketException((int)ZeroTier.Constants.ERR_SOCKET);
}
if (buffer == null) {
throw new ArgumentNullException("buffer");
}
int flags = 0;
IntPtr bufferPtr = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0);
return zts_recv(_fd, bufferPtr, (uint)Buffer.ByteLength(buffer), (int)flags);
}
public int ReceiveTimeout
2021-02-16 21:56:44 -08:00
{
get { return zts_get_recv_timeout(_fd); }
// TODO: microseconds
set { zts_set_recv_timeout(_fd, value, 0); }
2021-02-16 21:56:44 -08:00
}
public int SendTimeout
2021-02-16 21:56:44 -08:00
{
get { return zts_get_send_timeout(_fd); }
// TODO: microseconds
set { zts_set_send_timeout(_fd, value, 0); }
2021-02-16 21:56:44 -08:00
}
public int ConnectTimeout
2021-02-16 21:56:44 -08:00
{
get { return _connectTimeout; }
set { _connectTimeout = value;}
2021-02-16 21:56:44 -08:00
}
public int ReceiveBufferSize
2021-02-16 21:56:44 -08:00
{
get { return zts_get_recv_buf_size(_fd); }
set { zts_set_recv_buf_size(_fd, value); }
2021-02-16 21:56:44 -08:00
}
public int SendBufferSize
{
get { return zts_get_send_buf_size(_fd); }
set { zts_set_send_buf_size(_fd, value); }
}
2021-02-16 21:56:44 -08:00
public short Ttl
{
get { return Convert.ToInt16(zts_get_ttl(_fd)); }
set { zts_set_ttl(_fd, value); }
}
2021-02-16 21:56:44 -08:00
public LingerOption LingerState
{
get {
LingerOption lo = new LingerOption(
Convert.ToBoolean(zts_get_linger_enabled(_fd)), zts_get_linger_value(_fd));
return lo;
}
set {
zts_set_linger(_fd, Convert.ToInt32(value.Enabled), value.LingerTime);
}
}
2021-02-16 21:56:44 -08:00
public bool NoDelay
{
get { return Convert.ToBoolean(zts_get_no_delay(_fd)); }
set { zts_set_no_delay(_fd, Convert.ToInt32(value)); }
}
2021-02-16 21:56:44 -08:00
public bool KeepAlive
{
get { return Convert.ToBoolean(zts_get_keepalive(_fd)); }
set { zts_set_keepalive(_fd, Convert.ToInt32(value)); }
}
2021-02-16 21:56:44 -08:00
public bool Connected { get { return _isConnected; } }
public bool IsBound { get { return _isBound; } }
public AddressFamily AddressFamily { get { return _socketFamily; } }
public SocketType SocketType { get { return _socketType; } }
public ProtocolType ProtocolType { get { return _socketProtocol; } }
/* .NET has moved to OSSupportsIPv* but libzt isn't an OS so we keep this old convention */
public static bool SupportsIPv4 { get { return true; } }
/* .NET has moved to OSSupportsIPv* but libzt isn't an OS so we keep this old convention */
public static bool SupportsIPv6 { get { return true; } }
public EndPoint RemoteEndPoint { get { return _remoteEndPoint; } }
public EndPoint LocalEndPoint { get { return _localEndPoint; } }
/* Structures and functions used internally to communicate with
lower-level C API defined in include/ZeroTierSockets.h */
[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", CharSet=CharSet.Ansi, EntryPoint="CSharp_zts_connect_easy")]
static extern int zts_connect_easy(int arg1, int arg2, string arg3, ushort arg4, int arg5);
[DllImport("libzt", EntryPoint="CSharp_zts_bind")]
static extern int zts_bind(int arg1, IntPtr arg2, ushort arg3);
[DllImport("libzt", CharSet=CharSet.Ansi, EntryPoint="CSharp_zts_bind_easy")]
static extern int zts_bind_easy(int arg1, int arg2, string arg3, ushort arg4);
[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", CharSet=CharSet.Ansi, EntryPoint="CSharp_zts_accept_easy")]
static extern int zts_accept_easy(int arg1, IntPtr remoteAddrStr, int arg2, ref int 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_set_no_delay")]
static extern int zts_set_no_delay(int fd, int enabled);
[DllImport("libzt", EntryPoint="CSharp_zts_get_no_delay")]
static extern int zts_get_no_delay(int fd);
[DllImport("libzt", EntryPoint="CSharp_zts_set_linger")]
static extern int zts_set_linger(int fd, int enabled, int value);
[DllImport("libzt", EntryPoint="CSharp_zts_get_linger_enabled")]
static extern int zts_get_linger_enabled(int fd);
[DllImport("libzt", EntryPoint="CSharp_zts_get_linger_value")]
static extern int zts_get_linger_value(int fd);
[DllImport("libzt", EntryPoint="CSharp_zts_set_reuse_addr")]
static extern int zts_set_reuse_addr(int fd, int enabled);
[DllImport("libzt", EntryPoint="CSharp_zts_get_reuse_addr")]
static extern int zts_get_reuse_addr(int fd);
[DllImport("libzt", EntryPoint="CSharp_zts_set_recv_timeout")]
static extern int zts_set_recv_timeout(int fd, int seconds, int microseconds);
[DllImport("libzt", EntryPoint="CSharp_zts_get_recv_timeout")]
static extern int zts_get_recv_timeout(int fd);
[DllImport("libzt", EntryPoint="CSharp_zts_set_send_timeout")]
static extern int zts_set_send_timeout(int fd, int seconds, int microseconds);
[DllImport("libzt", EntryPoint="CSharp_zts_get_send_timeout")]
static extern int zts_get_send_timeout(int fd);
[DllImport("libzt", EntryPoint="CSharp_zts_set_send_buf_size")]
static extern int zts_set_send_buf_size(int fd, int size);
[DllImport("libzt", EntryPoint="CSharp_zts_get_send_buf_size")]
static extern int zts_get_send_buf_size(int fd);
[DllImport("libzt", EntryPoint="CSharp_zts_set_recv_buf_size")]
static extern int zts_set_recv_buf_size(int fd, int size);
[DllImport("libzt", EntryPoint="CSharp_zts_get_recv_buf_size")]
static extern int zts_get_recv_buf_size(int fd);
[DllImport("libzt", EntryPoint="CSharp_zts_set_ttl")]
static extern int zts_set_ttl(int fd, int ttl);
[DllImport("libzt", EntryPoint="CSharp_zts_get_ttl")]
static extern int zts_get_ttl(int fd);
[DllImport("libzt", EntryPoint="CSharp_zts_set_blocking")]
static extern int zts_set_blocking(int fd, int enabled);
[DllImport("libzt", EntryPoint="CSharp_zts_get_blocking")]
static extern int zts_get_blocking(int fd);
[DllImport("libzt", EntryPoint="CSharp_zts_set_keepalive")]
static extern int zts_set_keepalive(int fd, int enabled);
[DllImport("libzt", EntryPoint="CSharp_zts_get_keepalive")]
static extern int zts_get_keepalive(int fd);
[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_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_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;
}
2021-02-16 21:56:44 -08:00
[StructLayout(LayoutKind.Sequential)]
struct zts_timeval
{
public long tv_sec;
public long tv_usec;
}
}
}