// SoftEther VPN Source Code - Developer Edition Master Branch
// Mayaqua Kernel


// Network.h
// Header of Network.c

#ifndef	NETWORK_H
#define	NETWORK_H

#include "Encrypt.h"
#include "Mayaqua.h"

#include <openssl/ssl.h> // This is needed only for the SSL/TLS version defines

#ifdef OS_UNIX
#include <netinet/in.h>

#ifdef UNIX_LINUX
#include <pthread.h>
#endif

#ifdef UNIX_OPENBSD
#include <pthread.h>
#endif

#ifdef UNIX_MACOS
#include <pthread.h>
#endif
#endif


// Dynamic Value
struct DYN_VALUE
{
	char Name[256];								// Name
	UINT64 Value;								// Value
};

#define	DYN64(id, default_value)	( (UINT64)GetDynValueOrDefaultSafe ( #id , (UINT64)( default_value )))
#define	DYN32(id, default_value)	(UINT)DYN64(id, (UINT)default_value)

#define	MAX_HOST_NAME_LEN			255		// Maximum length of the host name

#define	TIMEOUT_INFINITE			(0x7fffffff)
#define	TIMEOUT_TCP_PORT_CHECK		(10 * 1000)
#define	TIMEOUT_SSL_CONNECT			(15 * 1000)

#define	TIMEOUT_NETBIOS_HOSTNAME	(100)

#define	SOCKET_BUFFER_SIZE			0x10000000

#define	UDPLISTENER_CHECK_INTERVAL	1000ULL
#define	UDPLISTENER_WAIT_INTERVAL	1234

#define	UDP_MAX_MSG_SIZE_DEFAULT	65507

#define	MAX_NUM_IGNORE_ERRORS		1024

#define	DEFAULT_CIPHER_LIST			"ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:DHE+CHACHA20:ECDHE+AES256:DHE+AES256:RSA+AES"

#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#define PQ_GROUP_LIST				"X25519MLKEM768:p521_kyber1024:x25519_kyber768:P-521:X25519:P-256"
#endif

// SSL logging function
//#define	ENABLE_SSL_LOGGING
#define	SSL_LOGGING_DIRNAME			"@ssl_log"

// Private IP list file
#define	PRIVATE_IP_TXT_FILENAME		"$private_ip.txt"

// Start range of the random UDP port
#define	RAND_UDP_PORT_START			5000
#define	RAND_UDP_PORT_END			65530
#define	RAND_UDP_PORT_DEFAULT_NUM_RETRY	64

// Special Port
#define	MAKE_SPECIAL_PORT(p)		(UINT)((UINT)0x10000 | (UINT)(p))
#define	IS_SPECIAL_PORT(p)			(MAKEBOOL((p) & (UINT)0x10000))
#define	GET_SPECIAL_PORT(p)			(UINT)((UINT)(p) & (UINT)0xffff)

// Random R-UDP port ID
#define	RAND_PORT_ID_SERVER_LISTEN	1

// UDP buffer size
#define	UDP_MAX_BUFFER_SIZE			11911168

// Expiration of the cache acquired from the IP address list of the host
#define	HOST_IP_ADDRESS_LIST_CACHE	(5 * 1000)

// IP address
struct IP
{
	BYTE address[16];   // IP address (RFC 3493 format used for IPv4)
	UINT ipv6_scope_id; // IPv6 scope ID
};

// Pointer to the beginning of the IPv4 address
#define	IPV4(address)				(&address[12])
#define	IPV4_SIZE					(4)

#define	CmpIpAddr(ip1, ip2)			(Cmp((ip1)->address, (ip2)->address, sizeof((ip1)->address)))

#define	IsIP6(ip)					(ip && IsIP4(ip) == false)
#define	IsZeroIp(ip)				(IsZeroIP(ip))

// IPv6 address (different format)
struct IPV6_ADDR
{
	UCHAR Value[16];				// Value
} GCC_PACKED;

// IPv6 Address Types
#define IPV6_ADDR_UNICAST						1	// Unicast
#define IPV6_ADDR_LOCAL_UNICAST					2	// Local unicast
#define IPV6_ADDR_GLOBAL_UNICAST				4	// Global Unicast
#define IPV6_ADDR_MULTICAST						8	// Multicast
#define IPV6_ADDR_ALL_NODE_MULTICAST			16	// All-nodes multicast
#define IPV6_ADDR_ALL_ROUTER_MULTICAST			32	// All routers multicast
#define IPV6_ADDR_SOLICIATION_MULTICAST			64	// Solicited-node multicast
#define	IPV6_ADDR_ZERO							128	// All zeros
#define	IPV6_ADDR_LOOPBACK						256	// Loop-back

// Client list
struct IP_CLIENT
{
	IP IpAddress;					// IP address
	UINT NumConnections;			// The number of connections
};

// Socket event
struct SOCK_EVENT
{
	REF *ref;						// Reference counter
#ifdef	OS_WIN32
	void *hEvent;					// Pointer to a Win32 event handle
#else	// OS_WIN32
	LIST *SockList;					// Socket list
	int pipe_read, pipe_write;		// Pipe
	UINT current_pipe_data;			// Amount of data in the current pipe
#endif	// OS_WIN32
};

// Type of socket
#define	SOCK_TCP				1
#define	SOCK_UDP				2
#define	SOCK_INPROC				3
#define	SOCK_RUDP_LISTEN		5
#define	SOCK_REVERSE_LISTEN		6

// SSL Accept Settings
struct SSL_ACCEPT_SETTINGS
{
	bool Tls_Disable1_0;
	bool Tls_Disable1_1;
	bool Tls_Disable1_2;
	bool Tls_Disable1_3;
	bool Override_Security_Level;
	UINT Override_Security_Level_Value;
};

// Socket
struct SOCK
{
	REF *ref;					// Reference counter
	LOCK *lock;					// Lock
	LOCK *ssl_lock;				// Lock related to the SSL
	LOCK *disconnect_lock;		// Disconnection lock
	SOCKET socket;				// Socket number
	SSL *ssl;					// SSL object
	struct ssl_ctx_st *ssl_ctx;	// SSL_CTX
	char SniHostname[256];		// SNI host name
	UINT Type;					// Type of socket
	bool Connected;				// Connecting flag
	bool ServerMode;			// Server mode
	bool AsyncMode;				// Asynchronous mode
	bool SecureMode;			// SSL communication mode
	bool ListenMode;			// In listening
	BUF *SendBuf;				// Transmission buffer
	bool IpClientAdded;			// Whether it has been added to the list IP_CLIENT
	bool LocalOnly;				// Only local
	bool EnableConditionalAccept;	// Conditional Accept is Enabled
	IP RemoteIP;				// IP address of the remote host
	IP LocalIP;					// IP address of the local host
	char *RemoteHostname;		// Remote host name
	UINT RemotePort;			// Port number of the remote side
	UINT LocalPort;				// Port number of the local side
	UINT64 SendSize;			// Total size of the sent data
	UINT64 RecvSize;			// Total size of received data
	UINT64 SendNum;				// Number of sent data blocks
	UINT64 RecvNum;				// Number of received data blocks
	X *RemoteX;					// Certificate of the remote host
	X *LocalX;					// Certificate of the local host
	char *CipherName;			// Cipher algorithm name
	char *WaitToUseCipher;		// Set the algorithm name to want to use
	bool IgnoreRecvErr;			// Whether the RecvFrom error is ignorable
	bool IgnoreSendErr;			// Whether the SendTo error is ignorable
	UINT TimeOut;				// Time-out value
	SOCK_EVENT *SockEvent;		// Associated socket-event
	bool CancelAccept;			// Cancel flag of the Accept
	bool AcceptCanceled;		// Flag which shows canceling of the Accept
	bool WriteBlocked;			// Previous write is blocked
	bool NoNeedToRead;			// Is not required to read
	bool Disconnecting;			// Disconnecting
	bool UdpBroadcast;			// UDP broadcast mode
	void *Param;				// Any parameters
	bool IPv6;					// IPv6
	bool IsRawSocket;			// Whether it is a raw socket
	const char *SslVersion;		// SSL version
	UINT RawSocketIPProtocol;	// IP protocol number if it's a raw socket
	TUBE *SendTube;				// Tube for transmission
	TUBE *RecvTube;				// Tube for reception
	QUEUE *InProcAcceptQueue;	// Accept queue of the in-process socket
	EVENT *InProcAcceptEvent;	// Accept event of the in-process socket
	FIFO *InProcRecvFifo;		// Receive FIFO of the in-process socket
	UINT UdpMaxMsgSize;			// Maximum transmitting and receiving size at a time on UDP
	int CurrentTos;				// Current ToS value
	bool IsTtlSupported;		// Whether the TTL value is supported
	UINT CurrentTtl;			// Current TTL value
	RUDP_STACK *R_UDP_Stack;	// R-UDP stack
	char UnderlayProtocol[64];	// Underlying protocol
	char ProtocolDetails[256];	// Protocol details
	QUEUE *ReverseAcceptQueue;	// Accept queue for the reverse socket
	EVENT *ReverseAcceptEvent;	// Accept event for the reverse socket
	bool IsReverseAcceptedSocket;	// Whether it is a reverse socket
	IP Reverse_MyServerGlobalIp;	// Self global IP address when using the reverse socket
	UINT Reverse_MyServerPort;		// Self port number when using the reverse socket
	UCHAR Ssl_Init_Async_SendAlert[2];	// Initial state of SSL send_alert
	SSL_ACCEPT_SETTINGS SslAcceptSettings;	// SSL Accept Settings
	bool RawIP_HeaderIncludeFlag;

#ifdef	ENABLE_SSL_LOGGING
	// SSL Logging (for debug)
	bool IsSslLoggingEnabled;	// Flag
	IO *SslLogging_Recv;		// for Recv
	IO *SslLogging_Send;		// for Send
	LOCK *SslLogging_Lock;		// Locking
#endif	// ENABLE_SSL_LOGGING

	void *hAcceptEvent;			// Event for Accept

	// R-UDP socket related
	bool IsRUDPSocket;			// Whether this is R-UDP socket
	TUBE *BulkSendTube;			// Tube for Bulk send
	TUBE *BulkRecvTube;			// Tube for Bulk receive
	SHARED_BUFFER *BulkSendKey;	// Bulk send key
	SHARED_BUFFER *BulkRecvKey;	// Bulk receive key
	UINT RUDP_OptimizedMss;		// Optimal MSS value

#ifdef	OS_UNIX
	pthread_t CallingThread;	// Thread that is calling the system call
#endif	// OS_UNIX

#ifdef	OS_WIN32
	void *hEvent;				// Event for asynchronous mode
#endif	// OS_WIN32
};

// Underlying protocol description string of socket
#define	SOCK_UNDERLAY_NATIVE_V6		"Standard TCP/IP (IPv6)"
#define	SOCK_UNDERLAY_NATIVE_V4		"Standard TCP/IP (IPv4)"
#define	SOCK_UNDERLAY_NAT_T			"VPN over UDP with NAT-T (IPv4)"
#define	SOCK_UNDERLAY_DNS			"VPN over DNS (IPv4)"
#define	SOCK_UNDERLAY_ICMP			"VPN over ICMP (IPv4)"
#define	SOCK_UNDERLAY_INPROC		"In-Process Pipe"
#define	SOCK_UNDERLAY_INPROC_EX		"Legacy VPN - %s"
#define	SOCK_UNDERLAY_AZURE			"TCP/IP via VPN Azure (IPv4)"

// Constant of the return value
#define	SOCK_LATER	(0xffffffff)	// In blocking

// Socket Set
#define	MAX_SOCKSET_NUM		60		// Number of sockets that can be stored in a socket set
struct SOCKSET
{
	UINT NumSocket;					// The number of sockets
	SOCK *Sock[MAX_SOCKSET_NUM];	// Array of pointers to the socket
};

// Cancel object
struct CANCEL
{
	REF *ref;						// Reference counter
	bool SpecialFlag;				// Special flag (associated to the event which is generated by Win32 driver)
#ifdef	OS_WIN32
	void *hEvent;					// Pointer to a Win32 event handle
#else	// OS_WIN32
	int pipe_read, pipe_write;		// Pipe
	int pipe_special_read2, pipe_special_read3;
#endif	// OS_WIN32
};

// Routing table entry
struct ROUTE_ENTRY
{
	IP DestIP;
	IP DestMask;
	IP GatewayIP;
	bool LocalRouting;
	bool PPPConnection;
	UINT Metric;
	UINT IfMetric;
	UINT InterfaceID;
	UINT64 InnerScore;
	bool Active;
};

// Routing table
struct ROUTE_TABLE
{
	UINT NumEntry;
	UINT HashedValue;
	ROUTE_ENTRY **Entry;
};

// ICMP response result
struct ICMP_RESULT
{
	bool Ok;										// Whether a correct response returned
	bool Timeout;									// Whether a time-out is occurred
	UCHAR Type;										// Message type
	UCHAR Code;										// Message code
	UCHAR Ttl;										// TTL
	UCHAR *Data;									// Data body
	UINT DataSize;									// Data size
	UINT Rtt;										// Round Trip Time
	IP IpAddress;									// IP address
};

// NETBIOS name requests
typedef struct NBTREQUEST
{
	USHORT TransactionId;
	USHORT Flags;
	USHORT NumQuestions;
	USHORT AnswerRRs;
	USHORT AuthorityRRs;
	USHORT AdditionalRRs;
	UCHAR Query[38];
} NBTREQUEST;

// NETBIOS name response
typedef struct NBTRESPONSE
{
	USHORT TransactionId;
	USHORT Flags;
	USHORT NumQuestions;
	USHORT AnswerRRs;
	USHORT AuthorityRRs;
	USHORT AdditionalRRs;
	UCHAR Response[61];
} NBTRESPONSE;

// Socket list
typedef struct SOCKLIST
{
	LIST *SockList;
} SOCKLIST;


// Parameters for timeout thread for Solaris
typedef struct SOCKET_TIMEOUT_PARAM {
	SOCK *sock;
	CANCEL *cancel;
	THREAD *thread;
	bool unblocked;
} SOCKET_TIMEOUT_PARAM;

// Parameters for the IP address release thread
struct WIN32_RELEASEADDRESS_THREAD_PARAM
{
	REF *Ref;
	char Guid[MAX_SIZE];
	UINT Timeout;
	bool Ok;
	bool Renew;
};

// TCP table entry
typedef struct TCPTABLE
{
	UINT Status;
	IP LocalIP;
	UINT LocalPort;
	IP RemoteIP;
	UINT RemotePort;
	UINT ProcessId;
} TCPTABLE;

// State of TCP
#define	TCP_STATE_CLOSED				1
#define	TCP_STATE_LISTEN				2
#define	TCP_STATE_SYN_SENT				3
#define	TCP_STATE_SYN_RCVD				4
#define	TCP_STATE_ESTAB					5
#define	TCP_STATE_FIN_WAIT1				6
#define	TCP_STATE_FIN_WAIT2				7
#define	TCP_STATE_CLOSE_WAIT			8
#define	TCP_STATE_CLOSING				9
#define	TCP_STATE_LAST_ACK				10
#define	TCP_STATE_TIME_WAIT				11
#define	TCP_STATE_DELETE_TCB			12

// Routing table changing notification
struct ROUTE_CHANGE
{
	ROUTE_CHANGE_DATA *Data;
};

// Tube flush list
struct TUBE_FLUSH_LIST
{
	LIST *List;							// List
};

// Tube
struct TUBE
{
	REF *Ref;							// Reference counter
	LOCK *Lock;							// Lock
	QUEUE *Queue;						// Packet queue
	EVENT *Event;						// Event
	SOCK_EVENT *SockEvent;				// SockEvent
	UINT SizeOfHeader;					// Header size
	TUBEPAIR_DATA *TubePairData;		// Tube pair data
	UINT IndexInTubePair;				// Number in the tube pair
	bool IsInFlushList;					// Whether it is registered in the Tube Flush List
	void *Param1, *Param2, *Param3;
	UINT IntParam1, IntParam2, IntParam3;
	UINT64 DataTimeout;
};

// Data that is to send and to receive in the tube
struct TUBEDATA
{
	void *Data;							// Body of data
	UINT DataSize;						// The size of the data
	void *Header;						// The body of the header
	UINT HeaderSize;					// Size of the header
};

// Tube pair data
struct TUBEPAIR_DATA
{
	bool IsDisconnected;				// Disconnection flag
	REF *Ref;							// Reference counter
	LOCK *Lock;							// Lock
	EVENT *Event1, *Event2;				// Event
	SOCK_EVENT *SockEvent1, *SockEvent2;	// SockEvent
};

// TCP raw data
struct TCP_RAW_DATA
{
	IP SrcIP;							// Source IP address
	IP DstIP;							// Destination IP address
	UINT SrcPort;						// Source port
	UINT DstPort;						// Destination port
	FIFO *Data;							// Data body
};

// UDP listener socket entry
struct UDPLISTENER_SOCK
{
	IP IpAddress;						// IP address
	UINT Port;							// Port number
	SOCK *Sock;							// Socket
	bool HasError;						// Whether an error occurs
	bool Mark;							// Mark
	bool ErrorDebugDisplayed;			// Whether the error has been displayed
	UINT64 NextMyIpAndPortPollTick;		// Time to check the self IP address and port number next
	IP PublicIpAddress;					// Global IP address
	UINT PublicPort;					// Global port number
};

// UDP packet
struct UDPPACKET
{
	IP SrcIP;							// Source IP address
	IP DstIP;							// Destination IP address
	UINT SrcPort;						// Source port
	UINT DestPort;						// Destination port
	UINT Size;							// Data size
	void *Data;							// Data body
	UINT Type;							// Type
};

// UDP listener packet receipt notification procedure
typedef void (UDPLISTENER_RECV_PROC)(UDPLISTENER *u, LIST *packet_list);

// UDP listener
struct UDPLISTENER
{
	bool Halt;							// Halting flag
	SOCK_EVENT *Event;					// Event
	THREAD *Thread;						// Thread
	LIST *PortList;						// Port list
	LIST *SockList;						// Socket list
	UINT64 LastCheckTick;				// Time which the socket list was checked last
	UDPLISTENER_RECV_PROC *RecvProc;	// Receive procedure
	LIST *SendPacketList;				// Transmission packet list
	UINT PacketType;					// The type to set when creating an UDPPACKET
	void *Param;						// Parameters
	INTERRUPT_MANAGER *Interrupts;		// Interrupt manager
	bool HostIPAddressListChanged;		// IP address list of the host has changed
	bool IsEspRawPortOpened;			// Whether the raw port opens
	bool PollMyIpAndPort;				// Examine whether the global IP and the port number of its own
	QUERYIPTHREAD *GetNatTIpThread;		// NAT-T IP address acquisition thread
	IP ListenIP;						// Listen IP
};

#define	QUERYIPTHREAD_INTERVAL_LAST_OK	(3 * 60 * 60 * 1000)
#define	QUERYIPTHREAD_INTERVAL_LAST_NG	(30 * 1000)

// IP address acquisition thread
struct QUERYIPTHREAD
{
	THREAD *Thread;						// Thread
	EVENT *HaltEvent;					// Halting event
	bool Halt;							// Halting flag
	LOCK *Lock;							// Lock
	IP Ip;								// Get the IP address
	char Hostname[MAX_SIZE];			// Host name
	UINT IntervalLastOk;				// Interval if last was OK
	UINT IntervalLastNg;				// Interval if last was NG
};

// Interrupt management
struct INTERRUPT_MANAGER
{
	LIST *TickList;						// Time list
};

// SSL BIO
struct SSL_BIO
{
	BIO *bio;							// BIO
	FIFO *SendFifo;						// Transmission FIFO
	FIFO *RecvFifo;						// Reception FIFO
	bool IsDisconnected;				// Disconnected
	bool NoFree;						// Not to release the BIO
};

// SSL pipe
struct SSL_PIPE
{
	bool ServerMode;					// Whether it's in the server mode
	bool IsDisconnected;				// Disconnected
	int SslVersion;
	SSL *ssl;							// SSL object
	struct ssl_ctx_st *ssl_ctx;			// SSL_CTX
	SSL_BIO *SslInOut;					// I/O BIO for the data in the SSL tunnel
	SSL_BIO *RawIn, *RawOut;			// Input and output BIO of the data flowing through the physical network
};

// IP address block list
struct IPBLOCK
{
	IP Ip;							// IP address
	IP Mask;						// Subnet mask
};


// R-UDP related constants
#define	RUDP_RESEND_TIMER				200			// Retransmission timer (initial value)
#define	RUDP_RESEND_TIMER_MAX			4792		// Retransmission timer (maximum value)
#define	RUDP_KEEPALIVE_INTERVAL_MIN		2500		// Transmission interval of Keep Alive (minimum)
#define	RUDP_KEEPALIVE_INTERVAL_MAX		4792		// Transmission interval of Keep Alive (maximum)
#define	RUDP_TIMEOUT					12000		// Time-out of R-UDP communication
#define	RUDP_DIRECT_CONNECT_TIMEOUT		5000		// R-UDP direct connection time-out
#define	RUDP_MAX_SEGMENT_SIZE			512			// Maximum segment size
#define	RUDP_BULK_KEY_SIZE_MAX			128			// Bulk key size Max

#define	RUDP_BULK_KEY_SIZE_V2			32			// V2: Bulk key size
#define	RUDP_BULK_IV_SIZE_V2			12			// V2: Bulk IV size
#define	RUDP_BULK_MAC_SIZE_V2			16			// V2: Bulk MAC size

// Maximum R-UDP packet size
#define	RUDP_MAX_PACKET_SIZE			(RUDP_MAX_SEGMENT_SIZE + sizeof(UINT64) * RUDP_MAX_NUM_ACK + SHA1_SIZE * 2 + sizeof(UINT64) * 4 + sizeof(UINT) + 255)
#define	RUDP_MAX_NUM_ACK				64			// Maximum number of ACKs
#define	RUDP_LOOP_WAIT_INTERVAL_S		1234		// Waiting time in the thread main loop (in server side)
#define	RUDP_LOOP_WAIT_INTERVAL_C		100			// Waiting time in the thread main loop (in client side)
#define	RUDP_MAX_FIFO_SIZE				(1600 * 1600)	// The maximum FIFO buffer size

// Interval for sending ICMP Echo from the client side when R-UDP used in ICMP mode
#define	RUDP_CLIENT_ECHO_REQUEST_SEND_INTERVAL_MIN	1000
#define	RUDP_CLIENT_ECHO_REQUEST_SEND_INTERVAL_MAX	3000

// R-UDP error code
#define	RUDP_ERROR_OK					0			// Success
#define	RUDP_ERROR_UNKNOWN				1			// Unknown Error
#define	RUDP_ERROR_TIMEOUT				2			// Time-out
#define	RUDP_ERROR_NAT_T_GETIP_FAILED	3			// IP address acquisition failure of NAT-T server
#define	RUDP_ERROR_NAT_T_NO_RESPONSE	4			// There is no response from the NAT-T server
#define	RUDP_ERROR_NAT_T_TWO_OR_MORE	5			// There are two or more hosts on the same destination IP address
#define	RUDP_ERROR_NAT_T_NOT_FOUND		6			// Host does not exist at the specified IP address
#define	RUDP_ERROR_USER_CANCELED		7			// Cancel by the user

// R-UDP segment
struct RUDP_SEGMENT
{
	UINT64 SeqNo;									// Sequence number
	UINT Size;										// Size
	UCHAR Data[RUDP_MAX_SEGMENT_SIZE];				// Data
	UINT64 NextSendTick;							// Next transmission time
	UINT NumSent;									// Number of times sent
};

// Status of R-UDP session
#define	RUDP_SESSION_STATUS_CONNECT_SENT	0		// Connection request sent
#define	RUDP_SESSION_STATUS_ESTABLISHED		1		// Connection established

// Quota
#define	RUDP_QUOTA_MAX_NUM_SESSIONS_PER_IP	DYN32(RUDP_QUOTA_MAX_NUM_SESSIONS_PER_IP, 1000)	// The number of R-UDP sessions per an IP address
#define	RUDP_QUOTA_MAX_NUM_SESSIONS			DYN32(RUDP_QUOTA_MAX_NUM_SESSIONS, 30000)	// Limit of the Number of sessions

// Range of the sequence numbers of bulk packet
#define	RUDP_BULK_SEQ_NO_RANGE				16384ULL
#define	RUDP_BULK_MAX_RECV_PKTS_IN_QUEUE	8192

// R-UDP session
struct RUDP_SESSION
{
	UINT Status;						// Status
	bool ServerMode;					// Whether it's in the server mode
	bool DisconnectFlag;				// Disconnection flag
	bool DisconnectedByYou;				// Disconnected from opponent
	bool UseHMac;
	IP MyIp;							// IP address of itself
	UINT MyPort;						// Port number of itself
	IP YourIp;							// Opponent IP address
	UINT YourPort;						// Opponent port number
	LIST *SendSegmentList;				// Transmission segment list
	LIST *RecvSegmentList;				// Received segments list
	LIST *ReplyAckList;					// List of ACKs in response
	SOCK *TcpSock;						// Corresponding TCP socket
	UINT64 LastSentTick;				// Time which the data has been sent last
	UINT64 LastRecvTick;				// Time which the data has been received last
	UCHAR Key_Init[SHA1_SIZE];			// Initial key
	UCHAR Key_Send[SHA1_SIZE];			// Key that is used to send
	UCHAR Key_Recv[SHA1_SIZE];			// Key that is used to receive
	UCHAR Magic_KeepAliveRequest[SHA1_SIZE];	// The magic number for the KeepAlive request
	UCHAR Magic_KeepAliveResponse[SHA1_SIZE];	// The magic number for KeepAlive response
	UINT64 Magic_Disconnect;			// Disconnection Signal
	UINT64 NextSendSeqNo;				// Transmission sequence number to be used next
	UINT64 LastRecvCompleteSeqNo;		// Sequence number of receiving complete
	// (This indicates all segments which have sequence number up to this number are received completely)
	UCHAR NextIv[SHA1_SIZE];			// IV value to be used next
	UINT NextKeepAliveInterval;			// Interval value of KeepAlive to be used next
	FIFO *RecvFifo;						// Reception FIFO
	FIFO *SendFifo;						// Transmission FIFO
	UINT64 YourTick;					// The largest value among received Tick from the opponent
	UINT64 LatestRecvMyTick;			// Value of the last tick among the received tick values
	UINT64 LatestRecvMyTick2;			// Variable for confirming whether LatestRecvMyTick2 changes
	UINT CurrentRtt;					// Current RTT value

	UINT Icmp_Type;						// Number of Type to be used in the ICMP
	USHORT Dns_TranId;					// Value of transaction ID used in DNS
	UINT64 Client_Icmp_NextSendEchoRequest;	// Time to send the next Echo Request in the ICMP
	SHARED_BUFFER *BulkSendKey;			// Bulk send key
	SHARED_BUFFER *BulkRecvKey;			// Bulk receive key
	UCHAR BulkNextIv[SHA1_SIZE];		// Next IV to the bulk send
	UINT64 BulkNextSeqNo;				// Next SEQ NO to the bulk send
	bool FlushBulkSendTube;				// Flag to be Flush the bulk send Tube
	UINT64 BulkRecvSeqNoMax;			// Highest sequence number received
	UCHAR BulkNextIv_V2[RUDP_BULK_IV_SIZE_V2];	// Next IV to the bulk send (version 2)
};

// NAT Traversal Server Information
#define	UDP_NAT_T_SERVER_TAG				"x%c.x%c.dev.servers.nat-traversal.softether-network.net."
#define	UDP_NAT_T_SERVER_TAG_ALT			"x%c.x%c.dev.servers.nat-traversal.uxcom.jp."
#define	UDP_NAT_T_PORT						5004

// Related to processing to get the IP address of the NAT-T server
#define	UDP_NAT_T_GET_IP_INTERVAL			DYN32(UDP_NAT_T_GET_IP_INTERVAL, (5 * 1000))		// IP address acquisition interval of NAT-T server (before success)
#define	UDP_NAT_T_GET_IP_INTERVAL_MAX		DYN32(UDP_NAT_T_GET_IP_INTERVAL, (150 * 1000))		// IP address acquisition interval of NAT-T server (before success)
#define	UDP_NAT_T_GET_IP_INTERVAL_AFTER		DYN32(UDP_NAT_T_GET_IP_INTERVAL_AFTER, (5 * 60 * 1000))	// IP address acquisition interval of NAT-T server (after success)

// Related to process to get the private IP address of itself with making a TCP connection to the NAT-T server
#define	UDP_NAT_T_GET_PRIVATE_IP_TCP_SERVER		"www.msftncsi.com."

#define	UDP_NAT_T_PORT_FOR_TCP_1			80
#define	UDP_NAT_T_PORT_FOR_TCP_2			443

#define	UDP_NAT_TRAVERSAL_VERSION			1

#define	UDP_NAT_T_GET_PRIVATE_IP_INTERVAL	DYN32(UDP_NAT_T_GET_PRIVATE_IP_INTERVAL, (15 * 60 * 1000))			// Polling interval (before success)
#define	UDP_NAT_T_GET_PRIVATE_IP_INTERVAL_AFTER_MIN	DYN32(UDP_NAT_T_GET_PRIVATE_IP_INTERVAL_AFTER_MIN, (30 * 60 * 1000))	// Polling interval (after success)
#define	UDP_NAT_T_GET_PRIVATE_IP_INTERVAL_AFTER_MAX	DYN32(UDP_NAT_T_GET_PRIVATE_IP_INTERVAL_AFTER_MAX, (60 * 60 * 1000))	// Polling interval (after success)
#define	UDP_NAT_T_GET_PRIVATE_IP_CONNECT_TIMEOUT	DYN32(UDP_NAT_T_GET_PRIVATE_IP_CONNECT_TIMEOUT, (5 * 1000))			// TCP connection time-out

// About token acquisition from the NAT-T server
#define	UDP_NAT_T_GET_TOKEN_INTERVAL_1		DYN32(UDP_NAT_T_GET_TOKEN_INTERVAL_1, (5 * 1000))		// Token acquisition interval from the NAT-T server (If not acquired)
#define	UDP_NAT_T_GET_TOKEN_INTERVAL_FAIL_MAX	DYN32(UDP_NAT_T_GET_TOKEN_INTERVAL_FAIL_MAX, 20)
#define	UDP_NAT_T_GET_TOKEN_INTERVAL_2_MIN	DYN32(UDP_NAT_T_GET_TOKEN_INTERVAL_2_MIN, (20 * 60 * 1000))	// Token acquisition interval minimum value from the NAT-T server (If token have been obtained)
#define	UDP_NAT_T_GET_TOKEN_INTERVAL_2_MAX	DYN32(UDP_NAT_T_GET_TOKEN_INTERVAL_2_MAX, (30 * 60 * 1000))	// Token acquisition interval maximum value from the NAT-T server (If token have been obtained)

// The Register interval for NAT-T server
#define	UDP_NAT_T_REGISTER_INTERVAL_INITIAL	DYN32(UDP_NAT_T_REGISTER_INTERVAL_INITIAL, (5 * 1000))		// Transmission interval when the Register is not completed
#define	UDP_NAT_T_REGISTER_INTERVAL_FAIL_MAX	DYN32(UDP_NAT_T_REGISTER_INTERVAL_FAIL_MAX, 20)
#define	UDP_NAT_T_REGISTER_INTERVAL_MIN		DYN32(UDP_NAT_T_REGISTER_INTERVAL_MIN, (220 * 1000))		// Minimum value of the Register interval
#define	UDP_NAT_T_REGISTER_INTERVAL_MAX		DYN32(UDP_NAT_T_REGISTER_INTERVAL_MAX, (240 * 1000))		// Maximum value of the Register interval

// Interval for checking whether the port number or the IP address is changed
#define	UDP_NAT_T_NAT_STATUS_CHECK_INTERVAL_MIN	DYN32(UDP_NAT_T_NAT_STATUS_CHECK_INTERVAL_MIN, (24 * 1000))
#define	UDP_NAT_T_NAT_STATUS_CHECK_INTERVAL_MAX	DYN32(UDP_NAT_T_NAT_STATUS_CHECK_INTERVAL_MAX, (28 * 1000))

// The Connect Request interval for NAT-T server
#define	UDP_NAT_T_CONNECT_INTERVAL			DYN32(UDP_NAT_T_CONNECT_INTERVAL, 200)

// Polling interval for its own IP information acquisition to the NAT-T server in regular communication between the client and the server
#define	UDP_NAT_T_INTERVAL_MIN				DYN32(UDP_NAT_T_INTERVAL_MIN, (5 * 60 * 1000))
#define	UDP_NAT_T_INTERVAL_MAX				DYN32(UDP_NAT_T_INTERVAL_MAX, (10 * 60 * 1000))
#define	UDP_NAT_T_INTERVAL_INITIAL			DYN32(UDP_NAT_T_INTERVAL_INITIAL, (3 * 1000))
#define	UDP_NAT_T_INTERVAL_FAIL_MAX			DYN32(UDP_NAT_T_INTERVAL_FAIL_MAX, 60)

// R-UDP stack callback function definition
typedef void (RUDP_STACK_INTERRUPTS_PROC)(RUDP_STACK *r);
typedef bool (RUDP_STACK_RPC_RECV_PROC)(RUDP_STACK *r, UDPPACKET *p);

// ICMP protocol number
#define	IP_PROTO_ICMPV4		0x01	// ICMPv4 protocol
#define	IP_PROTO_ICMPV6		0x3a	// ICMPv6 protocol

// R-UDP protocol
#define	RUDP_PROTOCOL_UDP				0	// UDP
#define	RUDP_PROTOCOL_ICMP				1	// ICMP
#define	RUDP_PROTOCOL_DNS				2	// DNS

// Maximum time of continuously changing of the NAT-T hostname
#define	RUDP_NATT_MAX_CONT_CHANGE_HOSTNAME	30
#define	RUDP_NATT_CONT_CHANGE_HOSTNAME_RESET_INTERVAL	(5 * 60 * 1000)

// Minimum time to wait for a trial to connect by ICMP and DNS in case failing to connect by TCP
#define	SOCK_CONNECT_WAIT_FOR_ICMP_AND_DNS_AT_LEAST		5000

#define	RUDP_MAX_VALIDATED_SOURCE_IP_ADDRESSES		512
#define	RUDP_VALIDATED_SOURCE_IP_ADDRESS_EXPIRES	(RUDP_TIMEOUT * 2)

// Validated Source IP Addresses for R-UDP
struct RUDP_SOURCE_IP
{
	UINT64 ExpiresTick;					// Expires
	IP ClientIP;						// Client IP address
};

// R-UDP stack
struct RUDP_STACK
{
	bool ServerMode;					// Whether it's in the server mode
	char SvcName[MAX_SIZE];				// Service name
	UCHAR SvcNameHash[SHA1_SIZE];		// Hash of the service name
	bool Halt;							// Halting flag
	void *Param;						// Parameters that can be used by developers
	UINT64 Now;							// Current time
	EVENT *HaltEvent;					// Halting event
	INTERRUPT_MANAGER *Interrupt;		// Interrupt manager
	LIST *SessionList;					// Session List
	SOCK *UdpSock;						// UDP socket
	UINT Port;							// Port number
	UINT Protocol;						// Protocol
	SOCK_EVENT *SockEvent;				// Socket event
	THREAD *Thread;						// Thread
	LOCK *Lock;							// Lock
	RUDP_STACK_INTERRUPTS_PROC *ProcInterrupts;	// Interrupt notification callback
	RUDP_STACK_RPC_RECV_PROC *ProcRpcRecv;	// RPC reception notification callback
	THREAD *IpQueryThread;				// NAT-T server IP inquiry thread
	UCHAR TmpBuf[65536];				// Temporary buffer
	LIST *SendPacketList;				// Transmission UDP packet list
	EVENT *NewSockConnectEvent;			// Event to inform that a new socket is connected
	QUEUE *NewSockQueue;				// Queue of new socket
	UINT64 TotalPhysicalReceived;		// Physical amount of data received
	UINT64 TotalLogicalReceived;		// Logical amount of data received
	UINT64 TotalPhysicalSent;			// Physical amount of data transmitted
	UINT64 TotalLogicalSent;			// Logical amount of data transmitted
	char CurrentRegisterHostname[MAX_SIZE];	// The host name of the the current destination of registration
	UINT NumChangedHostname;			// How number of changing NAT-T hostname has occured continuously
	UINT64 NumChangedHostnameValueResetTick;

	// NAT-T server related
	bool NoNatTRegister;				// Flag not to register with the NAT-T server
	UINT64 NatT_TranId;					// Transaction ID is used to communicate with the NAT-T server
	UINT64 NatT_SessionKey;				// Current Session Key
	IP NatT_IP;							// IP address of the NAT-T server
	IP NatT_IP_Safe;					// IP address of the NAT-T server (thread-safe)
	IP My_Private_IP;					// Private IP address of itself
	IP My_Private_IP_Safe;				// Private IP address of itself (thread-safe)
	UINT64 NatT_GetTokenNextTick;		// Time to get the next token
	UINT NatT_GetTokenFailNum;			// Token acquisition failure times
	char NatT_Token[MAX_SIZE];			// Token needed to communicate with NAT-T Server
	bool NatT_Token_Ok;					// Flag of whether it have a valid token
	UINT64 NatT_RegisterNextTick;		// Time to register next
	UINT NatT_RegisterFailNum;			// The number of Register failures
	bool NatT_Register_Ok;				// Is a successful registration
	char NatT_Registered_IPAndPort[128];		// IP address and port number at the time of registration success
	UINT64 NatT_NextNatStatusCheckTick;	// Time to check the NAT state next
	UINT LastDDnsFqdnHash;				// DNS FQDN hash value when last checked
	volatile UINT *NatTGlobalUdpPort;	// NAT-T global UDP port
	UCHAR RandPortId;					// Random UDP port ID
	bool NatT_EnableSourceIpValidation;	// Enable the source IP address validation mechanism
	LIST *NatT_SourceIpList;			// Authenticated source IP address list

	// For Client
	bool TargetIpAndPortInited;			// The target IP address and the port number are initialized
	IP TargetIp;						// Target IP address
	UINT TargetPort;					// Target port number
	EVENT *TargetConnectedEvent;		// Event to be set when the connection to the target is successful
	SOCK *TargetConnectedSock;			// Connected socket
	bool ClientInitiated;				// Flag to indicate that the connection is initiated
	bool DoNotSetTargetConnectedSock;	// Flag indicating that it should not set the TargetConnectedSock
	USHORT Client_IcmpId, Client_IcmpSeqNo;	// Sequence number and ICMP ID that is randomly generated on the client side
};

// Data for the thread for serial connection attempts to a list of addresses
struct CONNECT_SERIAL_PARAM
{
	LIST *IpList;
	UINT LocalPort;						// Local port number to bind
	IP   *LocalIP;						// Local IP address to bind. NULL address allowed to use.
	IP   LocalIP_Cache;					// Local IP address to bind
	UINT Port;
	UINT Timeout;
	char Hostname[MAX_SIZE];
	char HintStr[MAX_SIZE];
	bool No_Get_Hostname;
	bool *CancelFlag;
	bool *NoDelayFlag;
	UINT *NatT_ErrorCode;
	char NatT_SvcName[MAX_SIZE];
	SOCK *Sock;
	bool Finished;
	bool Ok;
	UINT64 FinishedTick;
	EVENT *FinishEvent;
	UINT Delay;
	UINT RetryDelay;
	bool Tcp_TryStartSsl;
	SSL_VERIFY_OPTION *SslOption;
	UINT *SslErr;
	bool Use_NatT;
	bool Force_NatT;
	IP *Ret_Ip;
};

// Data for the thread for concurrent connection attempts for the R-UDP and TCP
struct CONNECT_TCP_RUDP_PARAM
{
	IP Ip;
	UINT Port;
	UINT Timeout;
	char Hostname[MAX_SIZE];
	bool *CancelFlag;
	UINT NatT_ErrorCode;
	char SvcName[MAX_SIZE];
	char HintStr[MAX_SIZE];
	char TargetHostname[MAX_SIZE];
	SOCK *Result_Nat_T_Sock;
	SOCK *Result_Tcp_Sock;
	bool Finished;
	bool Ok;
	UINT64 FinishedTick;
	EVENT *FinishEvent;
	UINT RUdpProtocol;
	UINT Delay;
	bool Tcp_TryStartSsl;
	SSL_VERIFY_OPTION *SslOption;
	UINT *SslErr;
	LOCK *CancelLock;
	SOCK *CancelDisconnectSock;
	bool Tcp_InNegotiation;
};

struct SSL_VERIFY_OPTION
{
	bool VerifyPeer;				// Whether to verify SSL peer
	bool PromptOnVerifyFail;		// Prompt on verification failure (Windows)
	bool AddDefaultCA;				// Use default trust store
	bool VerifyHostname;			// Verify server hostname
	LIST *CaList;					// Trusted CA list
	X *SavedCert;					// Saved server certificate
};

// Header for TCP Pair
struct TCP_PAIR_HEADER
{
	bool EnableHMac;
};

// The constants for file query by using UDP
#define	UDP_FILE_QUERY_RETRY_INTERVAL	100			// Retry interval
#define	UDP_FILE_QUERY_DST_PORT			5004		// Destination UDP port number
#define	UDP_FILE_QUERY_MAGIC_NUMBER		"{5E465695-7923-4CCD-9B51-44444BE1E758}"	// Magic number
#define	UDP_FILE_QUERY_BFLETS_TXT_FILENAME	"|BFletsUdpList.txt"	// Text file name of the IPv6 node list

// The constant for DNS proxy for the B FLETs
#define	BFLETS_DNS_PROXY_PORT			443
#define	BFLETS_DNS_PROXY_PATH			"/ddns/queryhost.aspx"
#define	BFLETS_DNS_PROXY_CERT_HASH		"EFAC5FA0CDD14E0F864EED58A73C35D7E33B62F3"
#define	BFLETS_DNS_PROXY_TIMEOUT_FOR_GET_F	500		// Timeout when searching for the server by UDP
#define	BFLETS_DNS_PROXY_TIMEOUT_FOR_QUERY	3000	// Timeout for the response from the proxy DNS server

// FLET'S Hikar-Next (East) DNS proxy host name
#define	FLETS_NGN_EAST_DNS_PROXY_HOSTNAME		"senet.aoi.flets-east.jp"
#define	FLETS_NGN_WEST_DNS_PROXY_HOSTNAME		"senet.p-ns.flets-west.jp"
#define	FLETS_NGN_DNS_QUERY_TIMEOUT				1000		// FLET'S Hikar-Next host name query timeout

// Detection result of the type of FLET'S line
#define	FLETS_DETECT_TYPE_EAST_BFLETS_PRIVATE		1	// NTT East B-FLETs
#define	FLETS_DETECT_TYPE_EAST_NGN_PRIVATE			2	// Wrapping in network of NTT East NGN
#define	FLETS_DETECT_TYPE_WEST_NGN_PRIVATE			4	// Wrapping in network of NTT West NGN

// NIC adapter entry
struct NIC_ENTRY
{
	char IfName[MAX_SIZE];
	UCHAR MacAddress[6];
};

int GetCurrentTimezone();

bool GetSniNameFromSslPacket(UCHAR *packet_buf, UINT packet_size, char *sni, UINT sni_size);

void SetDhParam(DH_CTX *dh);

bool IsUseAlternativeHostname();

#ifdef	OS_WIN32
int GetCurrentTimezoneWin32();
#endif	// OS_WIN32

bool SendPack(SOCK *s, PACK *p);
PACK *RecvPack(SOCK *s);
PACK *RecvPackWithHash(SOCK *s);
bool SendPackWithHash(SOCK *s, PACK *p);

UINT GetErrorFromPack(PACK *p);
PACK *PackError(UINT error);

void CreateDummyValue(PACK *p);

char *RecvLine(SOCK *s, UINT max_size);

bool GetIPViaDnsProxyForJapanFlets(IP *ip_ret, char *hostname, bool ipv6, UINT timeout, bool *cancel, char *dns_proxy_hostname);
bool GetDnsProxyIPAddressForJapanBFlets(IP *ip_ret, UINT timeout, bool *cancel);
BUF *QueryFileByUdpForJapanBFlets(UINT timeout, bool *cancel);
BUF *QueryFileByIPv6Udp(LIST *ip_list, UINT timeout, bool *cancel);
UINT DetectFletsType();

void ListenTcpForPopupFirewallDialog();

bool DetectIsServerSoftEtherVPN(SOCK *s);
void ConnectThreadForTcp(THREAD *thread, void *param);
void ConnectThreadForRUDP(THREAD *thread, void *param);
void ConnectThreadForOverDnsOrIcmp(THREAD *thread, void *param);
void ConnectThreadForIPv4(THREAD *thread, void *param);
void ConnectThreadForIPv6(THREAD *thread, void *param);

void BindConnectThreadForIPv4(THREAD *thread, void *param);
void BindConnectThreadForIPv6(THREAD *thread, void *param);

SOCK *CreateTCPSock(SOCKET s, bool is_ipv6, IP *current_ip, bool no_get_hostname, char *hostname_original);
SOCK *NewRUDPClientNatT(char *svc_name, IP *ip, UINT *error_code, UINT timeout, bool *cancel, char *hint_str, char *target_hostname);
RUDP_STACK *NewRUDPServer(char *svc_name, RUDP_STACK_INTERRUPTS_PROC *proc_interrupts, RUDP_STACK_RPC_RECV_PROC *proc_rpc_recv, void *param, UINT port, bool no_natt_register, bool over_dns_mode, volatile UINT *natt_global_udp_port, UCHAR rand_port_id, IP *listen_ip);
SOCK *NewRUDPClientDirect(char *svc_name, IP *ip, UINT port, UINT *error_code, UINT timeout, bool *cancel, SOCK *sock, SOCK_EVENT *sock_event, UINT local_port, bool over_dns_mode);
RUDP_STACK *NewRUDP(bool server_mode, char *svc_name, RUDP_STACK_INTERRUPTS_PROC *proc_interrupts, RUDP_STACK_RPC_RECV_PROC *proc_rpc_recv, void *param, UINT port, SOCK *sock, SOCK_EVENT *sock_event, bool server_no_natt_register, bool over_dns_mode, IP *client_target_ip, volatile UINT *natt_global_udp_port, UCHAR rand_port_id, IP *listen_ip);
void FreeRUDP(RUDP_STACK *r);
void RUDPMainThread(THREAD *thread, void *param);
void RUDPRecvProc(RUDP_STACK *r, UDPPACKET *p);
void RUDPInterruptProc(RUDP_STACK *r);
void RUDPIpQueryThread(THREAD *thread, void *param);
void RUDPSendPacket(RUDP_STACK *r, IP *dest_ip, UINT dest_port, void *data, UINT size, UINT icmp_type);
void GetCurrentMachineIpProcessHash(void *hash);
void GetCurrentMachineIpProcessHashInternal(void *hash);
int RUDPCompareSessionList(void *p1, void *p2);
RUDP_SESSION *RUDPNewSession(bool server_mode, IP *my_ip, UINT my_port, IP *your_ip, UINT your_port, UCHAR *init_key);
void RUDPFreeSession(RUDP_SESSION *se);
int RUDPCompareSegmentList(void *p1, void *p2);
RUDP_SESSION *RUDPSearchSession(RUDP_STACK *r, IP *my_ip, UINT my_port, IP *your_ip, UINT your_port);
void RUDPSendSegmentNow(RUDP_STACK *r, RUDP_SESSION *se, UINT64 seq_no, void *data, UINT size);
void RUDPSendSegment(RUDP_STACK *r, RUDP_SESSION *se, void *data, UINT size);
bool RUDPProcessRecvPacket(RUDP_STACK *r, RUDP_SESSION *se, void *recv_data, UINT recv_size);
bool RUDPCheckSignOfRecvPacket(RUDP_STACK *r, RUDP_SESSION *se, void *recv_data, UINT recv_size);
void RUDPProcessAck(RUDP_STACK *r, RUDP_SESSION *se, UINT64 seq);
void RUDPProcessAck2(RUDP_STACK *r, RUDP_SESSION *se, UINT64 max_seq);
void RUDPProcessRecvPayload(RUDP_STACK *r, RUDP_SESSION *se, UINT64 seq, void *payload_data, UINT payload_size);
void RUDPInitSock(RUDP_STACK *r, RUDP_SESSION *se);
void RUDPDisconnectSession(RUDP_STACK *r, RUDP_SESSION *se, bool disconnected_by_you);
UINT64 RUDPGetCurrentSendingMinSeqNo(RUDP_SESSION *se);
UINT64 RUDPGetCurrentSendingMaxSeqNo(RUDP_SESSION *se);
SOCK *ListenRUDP(char *svc_name, RUDP_STACK_INTERRUPTS_PROC *proc_interrupts, RUDP_STACK_RPC_RECV_PROC *proc_rpc_recv, void *param, UINT port, bool no_natt_register, bool over_dns_mode);
SOCK *ListenRUDPEx(char *svc_name, RUDP_STACK_INTERRUPTS_PROC *proc_interrupts, RUDP_STACK_RPC_RECV_PROC *proc_rpc_recv, void *param, UINT port, bool no_natt_register, bool over_dns_mode,
                   volatile UINT *natt_global_udp_port, UCHAR rand_port_id, IP *listen_ip);
SOCK *AcceptRUDP(SOCK *s);
void *InitWaitUntilHostIPAddressChanged();
void FreeWaitUntilHostIPAddressChanged(void *p);
void WaitUntilHostIPAddressChanged(void *p, EVENT *event, UINT timeout, UINT ip_check_interval);
UINT GetHostIPAddressHash32();
bool GetMyPrivateIP(IP *ip, bool from_vg);
char *GetRandHostNameForGetMyPrivateIP();
UINT GenRandInterval(UINT min, UINT max);
void RUDPProcess_NatT_Recv(RUDP_STACK *r, UDPPACKET *udp);
void RUDPDo_NatT_Interrupt(RUDP_STACK *r);
void RUDPGetRegisterHostNameByIP(char *dst, UINT size, IP *ip);
bool RUDPParseIPAndPortStr(void *data, UINT data_size, IP *ip, UINT *port);
void ParseNtUsername(char *src_username, char *dst_username, UINT dst_username_size, char *dst_domain, UINT dst_domain_size, bool do_not_parse_atmark);
void RUDPBulkSend(RUDP_STACK *r, RUDP_SESSION *se, void *data, UINT data_size);
bool RUDPProcessBulkRecvPacket(RUDP_STACK *r, RUDP_SESSION *se, void *recv_data, UINT recv_size);
UINT RUDPCalcBestMssForBulk(RUDP_STACK *r, RUDP_SESSION *se);
bool IsIPLocalHostOrMySelf(IP *ip);
bool RUDPIsIpInValidateList(RUDP_STACK *r, IP *ip);
void RUDPAddIpToValidateList(RUDP_STACK *r, IP *ip);

bool GetBestLocalIpForTarget(IP *local_ip, IP *target_ip);
SOCK *NewUDP4ForSpecificIp(IP *target_ip, UINT port);

#ifdef OS_WIN32

// Function prototype for Win32
void Win32InitSocketLibrary();
void Win32FreeSocketLibrary();
void Win32Select(SOCKSET *set, UINT timeout, CANCEL *c1, CANCEL *c2);
void Win32InitAsyncSocket(SOCK *sock);
void Win32JoinSockToSockEvent(SOCK *sock, SOCK_EVENT *event);
void Win32FreeAsyncSocket(SOCK *sock);
void Win32IpForwardRow2ToRouteEntry(ROUTE_ENTRY *entry, void *ip_forward_row);
void Win32RouteEntryToIpForwardRow2(void *ip_forward_row, ROUTE_ENTRY *entry);
int Win32CompareRouteEntryByMetric(void *p1, void *p2);
ROUTE_TABLE *Win32GetRouteTable2(bool ipv4, bool ipv6);
bool Win32AddRouteEntry2(ROUTE_ENTRY *e, bool *already_exists);
void Win32DeleteRouteEntry2(ROUTE_ENTRY *e);
UINT Win32GetVLanInterfaceID(char *instance_name);
char **Win32EnumVLan(char *tag_name);
void Win32Cancel(CANCEL *c);
void Win32CleanupCancel(CANCEL *c);
CANCEL *Win32NewCancel();
SOCK_EVENT *Win32NewSockEvent();
void Win32SetSockEvent(SOCK_EVENT *event);
void Win32CleanupSockEvent(SOCK_EVENT *event);
bool Win32WaitSockEvent(SOCK_EVENT *event, UINT timeout);
bool Win32GetDefaultDns(IP *ip, char *domain, UINT size);
bool Win32GetDnsSuffix(char *domain, UINT size);
void Win32FlushDnsCache();
int CompareIpAdapterIndexMap(void *p1, void *p2);
ROUTE_CHANGE *Win32NewRouteChange2(bool ipv4, bool ipv6, void *callback);
void Win32FreeRouteChange2(ROUTE_CHANGE *r);
bool Win32IsRouteChanged2(ROUTE_CHANGE *r);
bool Win32GetAdapterFromGuid(void *a, char *guid);
SOCKET Win32Accept(SOCK *sock, SOCKET s, struct sockaddr *addr, int *addrlen, bool ipv6);

bool Win32ReleaseAddress(void *a);
bool Win32ReleaseAddressByGuid(char *guid);
bool Win32ReleaseAddressByGuidEx(char *guid, UINT timeout);
void Win32ReleaseAddressByGuidExThread(THREAD *t, void *param);
void ReleaseWin32ReleaseAddressByGuidThreadParam(WIN32_RELEASEADDRESS_THREAD_PARAM *p);
bool Win32ReleaseOrRenewAddressByGuidEx(char *guid, UINT timeout, bool renew);
bool Win32RenewAddress(void *a);
bool Win32RenewAddressByGuid(char *guid);
bool Win32RenewAddressByGuidEx(char *guid, UINT timeout);


#else	// OS_WIN32

// Function prototype for UNIX
void UnixInitSocketLibrary();
void UnixFreeSocketLibrary();
void UnixSelect(SOCKSET *set, UINT timeout, CANCEL *c1, CANCEL *c2);
void UnixInitAsyncSocket(SOCK *sock);
void UnixJoinSockToSockEvent(SOCK *sock, SOCK_EVENT *event);
void UnixFreeAsyncSocket(SOCK *sock);
ROUTE_TABLE *UnixGetRouteTable();
bool UnixAddRouteEntry(ROUTE_ENTRY *e, bool *already_exists);
void UnixDeleteRouteEntry(ROUTE_ENTRY *e);
UINT UnixGetVLanInterfaceID(char *instance_name);
char **UnixEnumVLan(char *tag_name);
void UnixCancel(CANCEL *c);
void UnixCleanupCancel(CANCEL *c);
CANCEL *UnixNewCancel();
SOCK_EVENT *UnixNewSockEvent();
void UnixSetSockEvent(SOCK_EVENT *event);
void UnixCleanupSockEvent(SOCK_EVENT *event);
bool UnixWaitSockEvent(SOCK_EVENT *event, UINT timeout);
bool UnixGetDefaultDns(IP *ip);
void UnixNewPipe(int *pipe_read, int *pipe_write);
void UnixWritePipe(int pipe_write);
void UnixDeletePipe(int p1, int p2);
void UnixSelectInner(UINT num_read, UINT *reads, UINT num_write, UINT *writes, UINT timeout);
void UnixSetSocketNonBlockingMode(int fd, bool nonblock);

#endif	// OS_WIN32

// Function prototype
void InitNetwork();
void FreeNetwork();

void InAddrToIP(IP *ip, struct in_addr *addr);
void InAddrToIP6(IP *ip, struct in6_addr *addr);
void IPToInAddr(struct in_addr *addr, IP *ip);
void IPToInAddr6(struct in6_addr *addr, IP *ip);
bool StrToIP(IP *ip, char *str);
UINT StrToIP32(char *str);
UINT UniStrToIP32(wchar_t *str);
void IPToStr(char *str, UINT size, IP *ip);
void IPToStr32(char *str, UINT size, UINT ip);
void IPToStr4or6(char *str, UINT size, UINT ip_4_uint, UCHAR *ip_6_bytes);
void IPToUniStr(wchar_t *str, UINT size, IP *ip);
void IPToUniStr32(wchar_t *str, UINT size, UINT ip);
bool GetHostName(char *hostname, UINT size, IP *ip);
void GetMachineName(char *name, UINT size);
void GetMachineNameEx(char *name, UINT size, bool no_load_hosts);
bool GetMachineNameFromHosts(char *name, UINT size);
void GetMachineHostName(char *name, UINT size);
void UINTToIP(IP *ip, UINT value);
UINT IPToUINT(IP *ip);
SOCK *NewSock();
void ReleaseSock(SOCK *s);
void CleanupSock(SOCK *s);
SOCK *Connect(char *hostname, UINT port);
SOCK *ConnectEx(char *hostname, UINT port, UINT timeout);
SOCK *ConnectEx2(char *hostname, UINT port, UINT timeout, bool *cancel_flag);
SOCK *ConnectEx3(char *hostname, UINT port, UINT timeout, bool *cancel_flag, char *nat_t_svc_name, UINT *nat_t_error_code, bool try_start_ssl, bool no_get_hostname);
SOCK *ConnectEx4(char *hostname, UINT port, UINT timeout, bool *cancel_flag, char *nat_t_svc_name, UINT *nat_t_error_code, bool try_start_ssl, bool no_get_hostname, IP *ret_ip);
SOCK *ConnectEx5(char *hostname, UINT port, UINT timeout, bool *cancel_flag, char *nat_t_svc_name, UINT *nat_t_error_code, bool try_start_ssl, bool no_get_hostname, SSL_VERIFY_OPTION *ssl_option, UINT *ssl_err, char *hint_str, IP *ret_ip);
SOCKET ConnectTimeoutIPv4(IP *ip, UINT port, UINT timeout, bool *cancel_flag);

// New function named with prefix "Bind" binds outgoing connection to a specific address. New one is wrapped in original one.
#define	BIND_LOCALIP_NULL			NULL		// NULL IP address specifies no binding
#define	BIND_LOCALPORT_NULL			0			// NULL port number specifies no binding
SOCK *BindConnectEx4(IP *localIP, UINT localport, char *hostname, UINT port, UINT timeout, bool *cancel_flag, char *nat_t_svc_name, UINT *nat_t_error_code, bool try_start_ssl, bool no_get_hostname, IP *ret_ip);
SOCK *BindConnectEx5(IP *localIP, UINT localport, char *hostname, UINT port, UINT timeout, bool *cancel_flag, char *nat_t_svc_name, UINT *nat_t_error_code, bool try_start_ssl, bool no_get_hostname, SSL_VERIFY_OPTION *ssl_option, UINT *ssl_err, char *hint_str, IP *ret_ip);
SOCKET BindConnectTimeoutIPv4(IP *localIP, UINT localport, IP *ip, UINT port, UINT timeout, bool *cancel_flag);

bool SetSocketBufferSize(SOCKET s, bool send, UINT size);
UINT SetSocketBufferSizeWithBestEffort(SOCKET s, bool send, UINT size);
void InitUdpSocketBufferSize(SOCKET s);
void QuerySocketInformation(SOCK *sock);
bool SetTtl(SOCK *sock, UINT ttl);
void Disconnect(SOCK *sock);
SOCK *Listen(UINT port);
SOCK *ListenEx(UINT port, bool local_only);
SOCK *ListenEx2(UINT port, bool local_only, bool enable_ca, IP *listen_ip);
SOCK *ListenEx6(UINT port, bool local_only);
SOCK *ListenEx62(UINT port, bool local_only, bool enable_ca);
SOCK *ListenEx63(UINT port, bool local_only, bool enable_ca, IP *listen_ip);
SOCK *Accept(SOCK *sock);
SOCK *Accept6(SOCK *sock);
UINT Send(SOCK *sock, void *data, UINT size, bool secure);
UINT Recv(SOCK *sock, void *data, UINT size, bool secure);
UINT Peek(SOCK *sock, void *data, UINT size);
void SetNoNeedToRead(SOCK *sock);
UINT SecureSend(SOCK *sock, void *data, UINT size);
UINT SecureRecv(SOCK *sock, void *data, UINT size);
bool StartSSL(SOCK *sock, X *x, K *priv);
bool StartSSLEx(SOCK *sock, X *x, K *priv, UINT ssl_timeout, char *sni_hostname);
bool StartSSLEx2(SOCK *sock, X *x, K *priv, LIST *chain, UINT ssl_timeout, char *sni_hostname);
bool StartSSLEx3(SOCK *sock, X *x, K *priv, LIST *chain, UINT ssl_timeout, char *sni_hostname, SSL_VERIFY_OPTION *ssl_option, UINT *ssl_err);
bool AddChainSslCert(struct ssl_ctx_st *ctx, X *x);
void AddChainSslCertOnDirectory(struct ssl_ctx_st *ctx);
bool SendAll(SOCK *sock, void *data, UINT size, bool secure);
void SendAdd(SOCK *sock, void *data, UINT size);
bool SendNow(SOCK *sock, int secure);
bool RecvAll(SOCK *sock, void *data, UINT size, bool secure);
bool RecvAllEx(SOCK *sock, void **data_new_ptr, UINT size, bool secure);
bool RecvAllWithDiscard(SOCK *sock, UINT size, bool secure);
void InitSockSet(SOCKSET *set);
void AddSockSet(SOCKSET *set, SOCK *sock);
CANCEL *NewCancel();
CANCEL *NewCancelSpecial(void *hEvent);
void ReleaseCancel(CANCEL *c);
void CleanupCancel(CANCEL *c);
void Cancel(CANCEL *c);
void Select(SOCKSET *set, UINT timeout, CANCEL *c1, CANCEL *c2);
void SetWantToUseCipher(SOCK *sock, char *name);
SOCK *NewUDP(UINT port);
SOCK *NewUDPEx(UINT port, bool ipv6);
SOCK *NewUDPEx2(UINT port, bool ipv6, IP *ip);
SOCK *NewUDPEx3(UINT port, IP *ip);
SOCK *NewUDP4(UINT port, IP *ip);
SOCK *NewUDP6(UINT port, IP *ip);
SOCK *NewUDPEx2Rand(bool ipv6, IP *ip, void *rand_seed, UINT rand_seed_size, UINT num_retry);
SOCK *NewUDPEx2RandMachineAndExePath(bool ipv6, IP *ip, UINT num_retry, UCHAR rand_port_id);
void ClearSockDfBit(SOCK *s);
void SetRawSockHeaderIncludeOption(SOCK *s, bool enable);
UINT SendTo(SOCK *sock, IP *dest_addr, UINT dest_port, void *data, UINT size);
UINT SendToEx(SOCK *sock, IP *dest_addr, UINT dest_port, void *data, UINT size, bool broadcast);
UINT SendTo6Ex(SOCK *sock, IP *dest_addr, UINT dest_port, void *data, UINT size, bool broadcast);
UINT RecvFrom(SOCK *sock, IP *src_addr, UINT *src_port, void *data, UINT size);
UINT RecvFrom6(SOCK *sock, IP *src_addr, UINT *src_port, void *data, UINT size);
void SetTimeout(SOCK *sock, UINT timeout);
UINT GetTimeout(SOCK *sock);
bool CheckTCPPort(char *hostname, UINT port);
bool CheckTCPPortEx(char *hostname, UINT port, UINT timeout);
ROUTE_TABLE *GetRouteTable();
void FreeRouteTable(ROUTE_TABLE *t);
bool AddRouteEntryEx(ROUTE_ENTRY *e, bool *already_exists);
bool AddRouteEntry(ROUTE_ENTRY *e);
void DeleteRouteEntry(ROUTE_ENTRY *e);
char **EnumVLan(char *tag_name);
void FreeEnumVLan(char **s);
UINT GetVLanInterfaceID(char *tag_name);
ROUTE_ENTRY *GetBestRouteEntry(IP *ip);
ROUTE_ENTRY *GetBestRouteEntryEx(IP *ip, UINT exclude_if_id);
ROUTE_ENTRY *GetBestRouteEntryFromRouteTableEx(ROUTE_TABLE *table, IP *ip, UINT exclude_if_id);
void FreeRouteEntry(ROUTE_ENTRY *e);
void JoinSockToSockEvent(SOCK *sock, SOCK_EVENT *event);
SOCK_EVENT *NewSockEvent();
void SetSockEvent(SOCK_EVENT *event);
void CleanupSockEvent(SOCK_EVENT *event);
bool WaitSockEvent(SOCK_EVENT *event, UINT timeout);
void ReleaseSockEvent(SOCK_EVENT *event);
void SetIP(IP *ip, UCHAR a1, UCHAR a2, UCHAR a3, UCHAR a4);
UINT SetIP32(UCHAR a1, UCHAR a2, UCHAR a3, UCHAR a4);
bool GetDefaultDns(IP *ip);
bool GetDomainName(char *name, UINT size);
bool UnixGetDomainName(char *name, UINT size);
void AcceptInit(SOCK *s);
void AcceptInitEx(SOCK *s, bool no_lookup_hostname);
void DisableGetHostNameWhenAcceptInit();
TOKEN_LIST *GetCipherList();
COUNTER *GetNumTcpConnectionsCounter();
void InitWaitThread();
void FreeWaitThread();
void AddWaitThread(THREAD *t);
void DelWaitThread(THREAD *t);
bool IsSubnetMask(IP *ip);
bool IsSubnetMask4(IP *ip);
bool IsSubnetMask32(UINT ip);
bool IsNetworkAddress4(IP *ip, IP *mask);
bool IsNetworkAddress32(UINT ip, UINT mask);
bool IsHostIPAddress4(IP *ip);
bool IsHostIPAddress32(UINT ip);
bool IsZeroIP(IP *ip);
bool IsZeroIP6Addr(IPV6_ADDR *addr);
UINT IntToSubnetMask32(UINT i);
void IntToSubnetMask4(IP *ip, UINT i);
bool GetNetBiosName(char *name, UINT size, IP *ip);
bool NormalizeMacAddress(char *dst, UINT size, char *src);
SOCKLIST *NewSockList();
void StopSockList(SOCKLIST *sl);
void FreeSockList(SOCKLIST *sl);
bool IsIPv6Supported();
bool HasIPv6Address();
void SetSockTos(SOCK *s, int tos);
void SetSockHighPriority(SOCK *s, bool flag);
void InitIpClientList();
void FreeIpClientList();
int CompareIpClientList(void *p1, void *p2);
void AddIpClient(IP *ip);
void DelIpClient(IP *ip);
IP_CLIENT *SearchIpClient(IP *ip);
UINT GetNumIpClient(IP *ip);
void SetLinuxArpFilter();
int connect_timeout(SOCKET s, struct sockaddr *addr, int size, int timeout, bool *cancel_flag);
ROUTE_CHANGE *NewRouteChange();
void FreeRouteChange(ROUTE_CHANGE *r);
bool IsRouteChanged(ROUTE_CHANGE *r);
void RouteToStr(char *str, UINT str_size, ROUTE_ENTRY *e);
void DebugPrintRoute(ROUTE_ENTRY *e);
void DebugPrintRouteTable(ROUTE_TABLE *r);
bool IsIPv6LocalNetworkAddress(IP *ip);
void AddProtocolDetailsStr(char *dst, UINT dst_size, char *str);
void AddProtocolDetailsKeyValueStr(char *dst, UINT dst_size, char *key, char *value);
void AddProtocolDetailsKeyValueInt(char *dst, UINT dst_size, char *key, UINT value);

#ifdef	ENABLE_SSL_LOGGING
void SockEnableSslLogging(SOCK *s);
void SockWriteSslLog(SOCK *s, void *send_data, UINT send_size, void *recv_data, UINT recv_size);
void SockCloseSslLogging(SOCK *s);
#endif	// ENABLE_SSL_LOGGING

void SocketTimeoutThread(THREAD *t, void *param);
SOCKET_TIMEOUT_PARAM *NewSocketTimeout(SOCK *sock);
void FreeSocketTimeout(SOCKET_TIMEOUT_PARAM *ttp);

void CopyIP(IP *dst, IP *src);
bool IsIP4(IP *ip);
void IPv6AddrToIP(IP *ip, IPV6_ADDR *addr);
bool IPToIPv6Addr(IPV6_ADDR *addr, IP *ip);
void SetIP6(IP *ip, UCHAR *value);
void GetLocalHostIP6(IP *ip);
void GetLocalHostIP4(IP *ip);
bool IsLocalHostIP6(IP *ip);
bool IsLocalHostIP4(IP *ip);
bool IsLocalHostIP(IP *ip);
void ZeroIP4(IP *ip);
bool CheckIPItemStr6(char *str);
void IPItemStrToChars6(UCHAR *chars, char *str);
bool StrToIP6(IP *ip, char *str);
bool StrToIP6Addr(IPV6_ADDR *ip, char *str);
void IPToStr6(char *str, UINT size, IP *ip);
void IP6AddrToStr(char *str, UINT size, IPV6_ADDR *addr);
void IPToStr6Array(char *str, UINT size, UCHAR *bytes);
void IPToStr6Inner(char *str, IP *ip);
void IntToSubnetMask6(IP *ip, UINT i);
void IPAnd6(IP *dst, IP *a, IP *b);
void GetAllRouterMulticastAddress6(IP *ip);
void GetAllNodeMulticaseAddress6(IP *ip);
void GetLoopbackAddress6(IP *ip);
UINT GetIPAddrType6(IP *ip);
UINT GetIPv6AddrType(IPV6_ADDR *addr);
void GetPrefixAddress6(IP *dst, IP *ip, IP *subnet);
bool IsInSameNetwork(IP *a1, IP *a2, IP *subnet);
bool IsInSameNetwork6(IP *a1, IP *a2, IP *subnet);
bool IsInSameNetwork6ByStr(char *ip1, char *ip2, char *subnet);
void GenerateEui64Address6(UCHAR *dst, UCHAR *mac);
void GenerateEui64LocalAddress(IP *a, UCHAR *mac);
bool IsSubnetMask6(IP *a);
UINT SubnetMaskToInt(IP *a);
UINT SubnetMaskToInt6(IP *a);
UINT SubnetMaskToInt4(IP *a);
bool IsStrIPv6Address(char *str);
void IPAnd4(IP *dst, IP *a, IP *b);
bool IsInSameNetwork4(IP *a1, IP *a2, IP *subnet);
bool IsInSameNetwork4Standard(IP *a1, IP *a2);

// Utility functions about IP and MAC address types
bool IsValidUnicastIPAddress4(IP *ip);
bool IsValidUnicastIPAddressUINT4(UINT ip);
bool IsValidUnicastIPAddress6(IP *ip);
bool IsMacUnicast(UCHAR *mac);
bool IsMacBroadcast(UCHAR *mac);
bool IsMacMulticast(UCHAR *mac);
bool IsMacInvalid(UCHAR *mac);

bool ParseIpAndSubnetMask4(char *src, UINT *ip, UINT *mask);
bool ParseIpAndSubnetMask46(char *src, IP *ip, IP *mask);
bool ParseIpAndMask4(char *src, UINT *ip, UINT *mask);
bool ParseIpAndMask6(char *src, IP *ip, IP *mask);
bool ParseIpAndMask46(char *src, IP *ip, IP *mask);
bool IsIpStr4(char *str);
bool IsIpStr6(char *str);
bool IsIpMask6(char *str);
bool StrToMask6(IP *mask, char *str);
bool StrToMask6Addr(IPV6_ADDR *mask, char *str);
void MaskToStr(char *str, UINT size, IP *mask);
void Mask6AddrToStrEx(char *str, UINT size, IPV6_ADDR *mask, bool always_full_address);
void Mask6AddrToStr(char *str, UINT size, IPV6_ADDR *mask);
void MaskToStr32(char *str, UINT size, UINT mask);
void MaskToStr32Ex(char *str, UINT size, UINT mask, bool always_full_address);
void MaskToStrEx(char *str, UINT size, IP *mask, bool always_full_address);

TUBEDATA *NewTubeData(void *data, UINT size, void *header, UINT header_size);
void FreeTubeData(TUBEDATA *d);
TUBE *NewTube(UINT size_of_header);
void ReleaseTube(TUBE *t);
void CleanupTube(TUBE *t);
bool TubeSend(TUBE *t, void *data, UINT size, void *header);
bool TubeSendEx(TUBE *t, void *data, UINT size, void *header, bool no_flush);
bool TubeSendEx2(TUBE *t, void *data, UINT size, void *header, bool no_flush, UINT max_num_in_queue);
void TubeFlush(TUBE *t);
void TubeFlushEx(TUBE *t, bool force);
TUBEDATA *TubeRecvAsync(TUBE *t);
TUBEDATA *TubeRecvSync(TUBE *t, UINT timeout);
TUBEPAIR_DATA *NewTubePairData();
void ReleaseTubePairData(TUBEPAIR_DATA *d);
void CleanupTubePairData(TUBEPAIR_DATA *d);
void NewTubePair(TUBE **t1, TUBE **t2, UINT size_of_header);
void TubeDisconnect(TUBE *t);
bool IsTubeConnected(TUBE *t);
void SetTubeSockEvent(TUBE *t, SOCK_EVENT *e);
SOCK_EVENT *GetTubeSockEvent(TUBE *t);

TUBE_FLUSH_LIST *NewTubeFlushList();
void FreeTubeFlushList(TUBE_FLUSH_LIST *f);
void AddTubeToFlushList(TUBE_FLUSH_LIST *f, TUBE *t);
void FlushTubeFlushList(TUBE_FLUSH_LIST *f);

LIST *GetHostIPAddressListInternal();
LIST *GetHostIPAddressList();
LIST *CloneIPAddressList(LIST *o);
bool IsMyIPAddress(IP *ip);
void FreeHostIPAddressList(LIST *o);
void AddHostIPAddressToList(LIST *o, IP *ip);
int CmpIpAddressList(void *p1, void *p2);
UINT64 GetHostIPAddressListHash();

UDPLISTENER *NewUdpListener(UDPLISTENER_RECV_PROC *recv_proc, void *param, IP *listen_ip);
UDPLISTENER *NewUdpListenerEx(UDPLISTENER_RECV_PROC *recv_proc, void *param, IP *listen_ip, UINT packet_type);
void UdpListenerThread(THREAD *thread, void *param);
void StopUdpListener(UDPLISTENER *u);
void FreeUdpListener(UDPLISTENER *u);
void AddPortToUdpListener(UDPLISTENER *u, UINT port);
void DeletePortFromUdpListener(UDPLISTENER *u, UINT port);
void DeleteAllPortFromUdpListener(UDPLISTENER *u);
void UdpListenerSendPackets(UDPLISTENER *u, LIST *packet_list);
TCP_RAW_DATA *NewTcpRawData(IP *src_ip, UINT src_port, IP *dst_ip, UINT dst_port);
void FreeTcpRawData(TCP_RAW_DATA *trd);
UDPPACKET *NewUdpPacket(IP *src_ip, UINT src_port, IP *dst_ip, UINT dst_port, void *data, UINT size);
void FreeUdpPacket(UDPPACKET *p);
UDPLISTENER_SOCK *DetermineUdpSocketForSending(UDPLISTENER *u, UDPPACKET *p);
bool IsUdpPortOpened(UDPLISTENER *u, IP *server_ip, UINT port);

INTERRUPT_MANAGER *NewInterruptManager();
void FreeInterruptManager(INTERRUPT_MANAGER *m);
void AddInterrupt(INTERRUPT_MANAGER *m, UINT64 tick);
UINT GetNextIntervalForInterrupt(INTERRUPT_MANAGER *m);

void NewSocketPair(SOCK **client, SOCK **server, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port);
SOCK *NewInProcSocket(TUBE *tube_send, TUBE *tube_recv);
SOCK *ListenInProc();
SOCK *AcceptInProc(SOCK *s);
SOCK *ConnectInProc(SOCK *listen_sock, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port);
UINT SendInProc(SOCK *sock, void *data, UINT size);
UINT RecvInProc(SOCK *sock, void *data, UINT size);
void WaitForTubes(TUBE **tubes, UINT num, UINT timeout);

SOCK *ListenReverse();
SOCK *AcceptReverse(SOCK *s);
void InjectNewReverseSocketToAccept(SOCK *listen_sock, SOCK *s, IP *client_ip, UINT client_port);

bool NewTcpPair(SOCK **s1, SOCK **s2);
SOCK *ListenAnyPortEx2(bool local_only, bool disable_ca);

ICMP_RESULT *IcmpApiEchoSend(IP *dest_ip, UCHAR ttl, UCHAR *data, UINT size, UINT timeout);
void IcmpApiFreeResult(ICMP_RESULT *ret);

#ifdef	OS_WIN32
void Win32WaitForTubes(TUBE **tubes, UINT num, UINT timeout);
#else	// OS_WIN32
void UnixWaitForTubes(TUBE **tubes, UINT num, UINT timeout);
#endif	// OS_WIN32

#define PREVERIFY_ERR_MESSAGE_SIZE 100
// Info on client certificate collected during TLS handshake
struct SslClientCertInfo {
	int PreverifyErr;
	char PreverifyErrMessage[PREVERIFY_ERR_MESSAGE_SIZE];
	X *X;
};

SSL_PIPE *NewSslPipe(bool server_mode, X *x, K *k, DH_CTX *dh);
SSL_PIPE *NewSslPipeEx(bool server_mode, X *x, K *k, DH_CTX *dh, bool verify_peer, struct SslClientCertInfo *clientcert);
SSL_PIPE *NewSslPipeEx2(bool server_mode, X *x, K *k, LIST *chain, DH_CTX *dh, bool verify_peer, struct SslClientCertInfo *clientcert);
SSL_PIPE* NewSslPipeEx3(bool server_mode, X* x, K* k, LIST* chain, DH_CTX* dh, bool verify_peer, struct SslClientCertInfo* clientcert, int tls13ticketscnt, bool disableTls13);
void FreeSslPipe(SSL_PIPE *s);
bool SyncSslPipe(SSL_PIPE *s);

SSL_BIO *NewSslBioMem();
SSL_BIO *NewSslBioSsl();
void FreeSslBio(SSL_BIO *b);
bool SslBioSync(SSL_BIO *b, bool sync_send, bool sync_recv);

void SetCurrentGlobalIP(IP *ip, bool ipv6);
bool GetCurrentGlobalIP(IP *ip, bool ipv6);
void GetCurrentGlobalIPGuess(IP *ip, bool ipv6);
bool IsIPAddressInSameLocalNetwork(IP *a);

bool IsIPPrivate(IP *ip);
bool IsIPMyHost(IP *ip);
void LoadPrivateIPFile();
bool IsOnPrivateIPFile(UINT ip);
void FreePrivateIPFile();

LIST *GetNicList();
void FreeNicList(LIST *o);
bool IsMacAddressLocalInner(LIST *o, void *addr);
bool IsMacAddressLocalFast(void *addr);
void RefreshLocalMacAddressList();

struct ssl_ctx_st *NewSSLCtx(bool server_mode);
void FreeSSLCtx(struct ssl_ctx_st *ctx);
UINT GetOSSecurityLevel();

void SetCurrentDDnsFqdn(char *name);
void GetCurrentDDnsFqdn(char *name, UINT size);
UINT GetCurrentDDnsFqdnHash();

void DisableRDUPServerGlobally();

void QueryIpThreadMain(THREAD *thread, void *param);
QUERYIPTHREAD *NewQueryIpThread(char *hostname, UINT interval_last_ok, UINT interval_last_ng);
bool GetQueryIpThreadResult(QUERYIPTHREAD *t, IP *ip);
void FreeQueryIpThread(QUERYIPTHREAD *t);

#ifdef	OS_WIN32
LIST *Win32GetNicList();
#endif	// OS_WIN32


void InitDynList();
void FreeDynList();
void AddDynList(BUF *b);
void ExtractAndApplyDynList(PACK *p);
void SetDynListValue(char *name, UINT64 value);
UINT64 GetDynValue(char *name);
UINT64 GetDynValueOrDefault(char *name, UINT64 default_value, UINT64 min_value, UINT64 max_value);
UINT64 GetDynValueOrDefaultSafe(char *name, UINT64 default_value);


#endif	// NETWORK_H

