XSTUNT
Reference 1.0
Kuanyu Chou <cky@cis.nctu.edu.tw>
2006/4/19
XSTUNT
Architecture and Procedure
XSTUNT Architecture and Procedure

Fig[1]: XSTUNT
Architecture and Procedure
The goal of XSTUNT is to provide a solution to
accomplish TCP NAT traversal. The XSTUNT architecture has three roles as above
figure: one stunt server and two clients. The STUNT server is in the public
internet but the two clients are behind NATs. The STUNT server opens 3 ports
for listening: Log, communication, and control. Log is responsible for client
registration, connection notifications, and error log. This is a long term
connection from registering to deregistering. Communication is responsible for
connection requests, deregistering, and query function of management. Control
channel is a shunt mechanism when two clients begin to exchange their
information.
Here we illustrate the XSTUNT procedure by the
following example: Client A wants to make a direct TCP connection to Client B-
[1]. Client A and Client B must register their IDs,
probe NAT type, get the server data on the Log port of STUNT SERVER by XInit().
[2]. The connections between Clients and STUNT SERVER
are established.
[3]. Client A send a connection request to port
Communication of STUNT SERVER by XConnect() and Client B is in the listen state
by XListen().
[4]. STUNT SERVER accepts the request, validates it,
and informs the 2 clients by the connection established in [2].
[5]. Client A and Client B begin to exchange their
information through the control channel of STUNT SERVER.
[6]. Client A finally makes a direct TCP connection
through NATs to B.
Following library is an implementation of the
above architecture. The method to do the TCP NAT Traversal can be referred to
"Characterization and Measurement of TCP Traversal through NAT and
Firewalls" addressed by Saikat and Paul. The library implements
"STUNT #2" approach in above paper. This program should cooperate
with a particular STUNT server for function.
About STUNT, please read:
http://nutss.gforge.cis.cornell.edu/stunt.php
for more information.
This library provides programmers with a set of
simple functions to create STUNT connections through cooperation with a XSTUNT
server. Those functions implement the architecture and procedure mentioned
above for the client side. Following table lists its abilities in different
conditions: Source is the client side who attempts to create a connection to
the Destination. Public IP means the client is in the public internet and
Private IP means the client is behind NATs.
|
Source Destination |
Public IP |
Private IP |
|
Public IP |
X (Use plain TCP connection) |
V |
|
Private IP |
X (Use plain TCP connection) |
V (Different NAT)/ X(Same NAT) |
Obviously, if the destination is in the public
internet, we do not use this library to create a TCP connection because a plain
TCP socket connection should definitely work well. This library should be used
when the destination is behind NAT. A hairpin problem will happen if two
clients are behind the same NAT. In this situation, this API returns a local IP
address to the Source and then it can create a direct TCP connection in LAN.
Following topics will guide you to understand how to use this library.
|
Basic Type |
XSTUNT |
Size |
|
char |
CHAR |
1 byte |
|
unsigned
char |
UCHAR |
1 byte |
|
signed
char |
INT8 |
1 byte |
|
signed
short |
INT16 |
2 bytes |
|
unsigned
short |
UINT16 |
2 bytes |
|
signed
int |
INT32 |
4 bytes |
|
unsigned
int |
UINT32 |
4 bytes |
N/A
E_ErrorStat
defines all errors in XSTUNT library. The meaning of every error will be
mentioned in the XSTUNT Functions.
|
Error Code |
Value |
Description |
|
ERR_NONE |
0 |
Successful |
|
ERR_FAIL |
-1 |
Fail |
|
ERR_CREATE_SOCKET |
-4000 |
Fail to create socket |
|
ERR_CONNECT |
-3999 |
Fail to connect |
|
ERR_VERSION |
-3998 |
Versions of server and client are mismatched |
|
ERR_DUPLICATE_ID |
-3997 |
The ID is already registered on the server |
|
ERR_PROBE |
-3996 |
Failed during probing |
|
ERR_TIMEOUT |
-3995 |
Timeout |
|
ERR_COMM_TIMEOUT |
-3994 |
Timeout during reading response from communication service |
|
ERR_ECHO_TIMEOUT |
-3993 |
Timeout during reading echo |
|
ERR_SELECT |
-3992 |
Select error |
|
ERR_RECEIVE |
-3991 |
Fail to receive |
|
ERR_SYN_RECEIVE |
-3990 |
Failed during receiving proprietary SYN |
|
ERR_SYN_SEND |
-3989 |
Failed during sending proprietary SYN |
|
ERR_ADDRPORT_RECEIVE |
-3988 |
Failed during receiving address and port |
|
ERR_ADDRPORT_SEND |
-3987 |
Failed during sending address and port |
|
ERR_ASYMSERVER |
-3986 |
Failed in XAsymServer() |
|
ERR_ASYMCLIENT |
-3985 |
Failed in XAsymClient() |
|
ERR_PREDICT |
-3984 |
Failed during port predicting |
|
ERR_SEND |
-3983 |
Failed to send |
|
ERR_TRYCONNECT |
-3982 |
Failed in XTryConnect() |
|
ERR_SETSOCKOPT |
-3981 |
Failed to set socket option |
|
ERR_BIND |
-3980 |
Failed to bind |
|
ERR_LISTEN |
-3979 |
Failed to listen |
|
ERR_ASYM_TIMEOUT |
-3978 |
Timeout during waiting the connection from AsymServer |
|
ERR_ACCEPT |
-3977 |
Failed to accept |
|
ERR_MATCH |
-3976 |
Failed to find the destination peer on the server |
|
ERR_SAME_NAT |
-3975 |
Peer client is in the same NAT |
|
ERR_HAIRPIN |
-3974 |
Hairpin problem |
N/A
Given two IPs of the STUNT
server and a client ID, the function will probe the NAT type, register the
specified ID and then return a log socket of STUNT server if the process works
successfully.
ClientAPI.h
INT32
XInit(const CHAR* pchIP1, const CHAR* pchIP2, SOCKET* psServerLog, CHAR* pchID,
INT32 *pnErrCode);
|
-> |
pchIP1 |
The 1st
IP of the STUNT server. Pass NULL to use the default STUNT server. |
|
-> |
pchIP2 |
The 2nd
IP of the STUNT server. Pass NULL to use the default STUNT server. |
|
<-> |
psServerLog |
The
STUNT server socket |
|
-> |
pchID |
The
client ID which will be registered to the STUNT server. The length of the ID
must shorter than or equal to the value of MAX_ID_LEN and not an empty
string. |
|
<-> |
pnErrCode |
Error
code. |
|
ERR_NONE |
Successful. |
|
ERR_CREATE_SOCKET |
Fail to create a socket. |
|
ERR_CONNECT |
Fail to connect to the STUNT server. |
|
ERR_RECEIVE |
Fail to send data. |
|
ERR_SEND |
Fail to receive data. |
|
ERR_VERSION |
The required client version mismatch. |
|
ERR_PROBE |
Fail during probing the NAT type. |
|
ERR_DUPLICATE_ID |
The specified ID is already registered in the STUNT server. |
Programmers must first use this function to
initialize the XSTUNT and get a STUNT server socket, then use the socket in the
functions listed below to finish the direct TCP connections. Notice that if an
empty ID string is passed in then ERR_DUPLICATE_ID will be returned.
Programmers may need to check the error reason by pnErrCode when the
result is ERR_CREATE_SOCKET, ERR_CONNECT, ERR_RECEIVE, or ERR_SEND.
N/A
SOCKET sServer =
(SOCKET)-1;
int nErr = 0, nRet =
0;
if ((nRet = XInit(¡§59.124.
{
printf(¡§Initialize
successfully!\n¡¨);
//do the XSTUNT processes
}
else
{
printf("Initialization
failed. ErrType(%d) ErrCode(%d)\n", nRet, nErr);
}
Listen on
a specified socket through the help of a STUNT server.
ClientAPI.h
INT32 XListen(SOCKET sServerLog, SOCKET* psListen, struct sockaddr_in
*pAddrPeer, INT32 nTimeoutSec, INT32* pnErrCode);
|
-> |
sServerLog |
The STUNT server socket. This socket must be gotten from
XInit() and be valid. |
|
<-> |
psListen |
User specified listen socket. User should access this
socket to read/ write data if the process works successfully. |
|
<-> |
pAddrPeer |
The address information of the connecting peer. Pass
NULL if user does not need this information. |
|
-> |
nTimeoutSec |
The timeout is used when another peer is attempting to
connect to. It¡¦s not the listen waiting time. |
|
<-> |
pnErrCode |
Error code. |
|
ERR_NONE |
Successful. |
|
ERR_TIMEOUT |
Timeout during
waiting the connection request from STUNT server. |
|
ERR_SELECT |
SELECT fail during
waiting the connection request from STUNT server. |
|
ERR_RECEIVE |
Fail during
receiving control channel data from STUNT server. |
|
ERR_CREATE_SOCKET |
Fail to create a
socket. |
|
ERR_CONNECT |
Fail to connect to
the control channel of STUNT server. |
|
ERR_ECHO_TIMEOUT |
Timeout during
reading sync-echo |
|
ERR_SYN_RECEIVE |
Fail to receive echo |
|
ERR_SYN_SEND |
Fail to send echo. |
|
ERR_ASYMSERVER |
Fail during being an
asymmetric server. |
Use the
function to accept STUNT connections from the other peer. If the function
returns ERR_NONE, programmers can access this listen socket for reading or
writing data and close the socket to disconnect. The function is non-blocking.
Therefore programmers should use the method like loops to wait forever. The
nTimeoutSec parameter is functioned during another waiting procedure when a
connection is attempting to create. This value is strongly recommend to set as
the same as it set in XConnect() or it will probably cause a synchronization
problem. Notice that when the process is successfully completed, the listen
socket is set to non-blocking, so programmer should use select to block it with
a specified timeout.
Programmers may need
to check the error reason by pnErrCode for all errors listed above.
//sServer is a valid
STUNT socket initialized by XInit()¡K
while (true)
{
char chStr[32];
int nRcv = 0, nErr
= 0;
SOCKET sListen =
(SOCKET) -1;
fd_set Socks;
if
(XListen(sServer, &sListen, NULL, 12, &nErr) == ERR_NONE)
{
FD_ZERO(&Socks);
FD_SET(sListen,
&Socks);
//sListen
is changed to a non-blocking socket, so we need to block it.
select(((INT32)sListen)
+ 1, &Socks, NULL, NULL, NULL);
nRcv
= recv(sListen, chStr, 32, 0); //receiving
32 bytes from the connector side
if
(nRcv > 0)
printf("Msg>> %s\n", chStr);
send(sListen,
chStr, strlen(chStr), 0);
//other
processes¡K
}
}//end while
Create a STUNT connection to a specified peer
through the help of a STUNT server
ClientAPI.h
INT32
XConnect(SOCKET sServerLog, CHAR *pchPeerID, SOCKET *psConnect, struct
sockaddr_in *pAddrPeer, INT32 nTimeoutSec, INT32* pnErrCode);
|
-> |
sServerLog |
The
STUNT server socket. This socket must be gotten from XInit() and be valid. |
|
<-> |
pchPeerID |
The ID
of the destination peer who will be connected to. The length of the ID must
shorter than or equal to the value of MAX_ID_LEN and not an empty string. |
|
<-> |
psConnect |
User
specified connection socket. |
|
<-> |
pAddrPeer |
The
address information of the connecting peer. Pass NULL if user does not need
this information. |
|
-> |
nTimeoutSec |
The
timeout is used when the function is attempting to connect to. |
|
<-> |
pnErrCode |
Error
code. |
|
ERR_NONE |
Successful. |
|
ERR_CREATE_SOCKET |
Fail to create the communication/ control channel socket. |
|
ERR_CONNECT |
Fail to connect to the communication/ control channel of the STUNT
server. |
|
ERR_MATCH |
The matching process is failed. (The reason will be shown on the STUNT
server.) |
|
ERR_SAME_NAT |
The destination peer is behind the same NAT. The local address of the
peer will be returned through pnErrCode. Programmers should try the direct
connection in LAN by using this address. |
|
ERR_TIMEOUT |
Timeout during waiting receiving peer data from STUNT server. |
|
ERR_RECEIVE |
Fail to receive data. |
|
ERR_CREATE_SOCKET |
Fail to create a socket. |
|
ERR_ECHO_TIMEOUT |
Timeout during reading sync-echo. |
|
ERR_SYN_RECEIVE |
Fail to receive echo. |
|
ERR_SYN_SEND |
Fail to send echo. |
|
ERR_COMM_TIMEOUT |
Timeout during reading response from communication service. |
|
ERR_ASYMCLIENT |
Fail during being an asymmetric client. |
Use the function to create a STUNT connection to a
specified peer. After successful connection, access the connection socket to
read or write data and disconnect that by closing this socket. This value is
strongly recommend to set as the same as it in XListen() or it will probably
cause a synchronization problem. There are some reasons for ERR_MATCH:
destination ID not found, ID is identical to the ID itself or the peer¡¦s state
is DEAD. ERR_SAME_NAT means the destination peer and the source peer are behind
the same most outside NAT (with the same public IP address). Programmers can
try to create a direct connection in the local LAN and it may be successful if
they are behind the same most inside NAT. Notice that if a connection is
established successfully, it is recommended that any size of data should be
sent in 60 seconds or the connection will be closed in some kinds of occasions.
Programmers may need to check the error reason by pnErrCode for all errors
listed above except ERR_MATCH and ERR_SAME_NAT.
//sServer is a valid
STUNT socket initialized by XInit()¡K
//1234 is a listening
port number of the destination client.
char chStr[32] = ¡§Data¡¨;
int nRet = 0, nErr = 0;
SOCKET sConnect = (SOCKET) -1;
struct sockaddr_in AddrPeer;
nRet = XConnect(sServer, (char*)¡¨connector¡¨, &sConnect, NULL, 12,
&nErr);
if (nRet == ERR_NONE)
{
//send or receive
send(sConnect,
chStr, 32, 0);
recv(sConnect, chStr,
32, 0);
//other processes¡K
}
else if (nRet == ERR_SAME_NAT) //Behind
the same NAT
{
AddrPeer.sin_family
= AF_INET;
AddrPeer.sin_addr.s_addr
= nErr; //The
error code contains the private IP. Use it!
AddrPeer.sin_port
= htons(1234);
//Try
to make a plain TCP connection in LAN
sConnect
= socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
nRet
= connect(sConnect, (struct sockaddr *)&AddrPeer, sizeof(AddrPeer));
if
(nRet == 0)
{
send(sConnect,
chStr, 32, 0);
recv(sConnect,
chStr, 32, 0);
//other
processes¡K
}
else //fail to connect in LAN
printf("Fail
to connect\n");
}
else //fail
to connect by XSTUNT
printf("Fail
to connect. ErrType(%d) ErrCode(%d)\n", nRet, nErr);
Deregister the client on and close the socket of
the connection to the STUNT server
ClientAPI.h
INT32
XDeRegister(SOCKET sServerLog, CHAR* pchID, INT32* pnErrCode);
|
-> |
sServerLog |
The
STUNT server socket. This socket must be gotten from XInit() and be valid. |
|
-> |
pchID |
The
client ID which will be deregistered from the STUNT server. |
|
<-> |
pnErrCode |
Error
code. |
|
ERR_NONE |
Successful. |
|
ERR_CREATE_SOCKET |
Fail to create a socket to the communication port. |
|
ERR_CONNECT |
Fail to connect to the communication |
Use the function to deregister the client on the
STUNT server after finish the whole STUNT procedure.
Programmers may need to check the error reason by pnErrCode for all errors
listed above.
|
Basic Type |
XSTUNT |
Size |
|
char |
CHAR |
1 byte |
|
unsigned
char |
UCHAR |
1 byte |
|
signed
char |
INT8 |
1 byte |
|
signed
short |
INT16 |
2 bytes |
|
unsigned
short |
UINT16 |
2 bytes |
|
signed
int |
INT32 |
4 bytes |
|
unsigned
int |
UINT32 |
4 bytes |
typedef struct _ServerInfo
{
CHAR chID[MAX_ID_LEN
+ 1];
INT32 nIP1;
INT32 nIP2;
INT16 wPort1;
INT16 wPort2;
INT16 wPort3;
INT16 wPort4;
INT16 wPort5;
INT16 wPort6;
INT16 wPort7;
INT16 wPort8;
} ServerInfo;
|
chID |
Client
ID |
|
nIP1 |
The 1st
IP of the STUNT server |
|
nIP2 |
The 2nd
IP of the STUNT server |
|
wPort1 |
Echo
service port1 number |
|
wPort2 |
Echo
service port2 number |
|
wPort3
~ wPort8 |
Reserved |
typedef struct _Echo
{
INT32
nIP;
INT16
wPort;
INT16 wPadding;
union
{
CHAR
chData[24];
struct
{
INT32
nSeq;
CHAR
chResponse;
}Tcp;
struct
{
INT32
nConnID;
CHAR
chPeerID[MAX_ID_LEN + 1];
INT32
nPeerIP;
CHAR
chRole;
}
}Data
}Echo;
|
chID |
Client
ID |
|
nIP |
IP with
of the STUNT server |
|
wPort |
The
port number |
|
wPadding |
Reserved |
|
Data:chData |
Reserved |
|
Data:Tcp:nSeq: |
Reserved |
|
Data:Tcp:chResponse |
Reserved |
|
Data:Conn:nConnID |
Reserved |
|
Data:Conn:chPeerID |
Reserved |
|
Data:Conn:nPeerIP |
Reserved |
|
Data:Conn:chRole |
Reserved |
typedef struct _Msg
{
INT32
nType;
union
{
struct
{
CHAR
chSrcID[MAX_ID_LEN + 1];
CHAR
chDstID[MAX_ID_LEN + 1];
}
Connection;
CHAR
chID[MAX_ID_LEN + 1];
}
Data;
} Msg;
|
nType |
Message
type: Defined by E_Message. |
|
Data.Connection.chSrcID |
Source
ID used in nType = MSG_CONNECT |
|
Data.Connection.chDstID |
Destination
ID used in nType = MSG_CONNECT |
|
Data.chID |
Client
ID used in MSG_DEREGISTER and MSG_QUERY. |
typedef struct _Fingerprint
{
INT32
nClientVer;
INT32 nServerVer;
CHAR chID[MAX_ID_LEN
+ 1];
INT32 nDone;
INT32 nGAddr;
struct
{
INT32
nIncrement;
INT8
bPortPreserving;
}
Connection;
} Fingerprint;
|
nClientVer |
Client
build version |
|
nServerVer |
Server
version |
|
chID |
Client
ID |
|
nDone |
Indicate
if the fingerprint is done or not |
|
nGAddr |
Global
address of the client |
|
Connection.nIncrement |
Port
incremental value of NAT for next connection |
|
Connection.bPortPreserving |
Port
preservation characteristic of the NAT |
|
Constant |
Value |
Description |
|
BUILD |
¡§BUILD $VER:10$¡¨ |
Build version string of this library. |
|
BUILDVER |
10 |
This build version must match the server's or
will cause version mismatch error during initialization. |
|
TEST_TIME |
N/A |
Debug constant for watching time consuming for
some procedures. |
|
TEST_DEBUG |
0 |
Debug message switcher. See ClientMacro.h |
|
DEF_SERVER_IP1 |
¡§59.124. |
The first default IP of STUNT server |
|
DEF_SERVER_IP2 |
¡§59.124. |
The second default IP of STUNT server |
|
SERVER_LOG_PORT |
8123 |
Log service port number of STUNT server |
|
SERVER_COMM_PORT |
8132 |
Communication service port number of STUNT server |
|
MAX_IP_STR_LEN |
20 |
Maximal IP string length |
|
MAX_ID_LEN |
32 |
Maximal Client ID length |
|
MAX_FINGERPRINT_LEN |
1024 |
Maximal fingerprint length |
|
COMM_TIMEOUT |
2 |
Suggested timeout of receiving communication
message. |
|
RCV_PEER_DATA_TIMEOUT |
2 |
Suggested timeout of receiving peer information
from control channel service. |
|
RCV_ECHO_TIMEOUT |
7 |
Suggested timeout of synchronization between
peers by STUNT server |
|
ASYM_TIMEOUT |
3 |
Suggested timeout of directly connecting to the
peer |
|
FINGERPRINT_FILE |
¡§fingerprint.dat¡¨ |
Fingerprint file name on local side. |
|
PROBE_RETRY_TIMES |
3 |
NAT probing maximal retry times |
|
PROBE_FAIL_SLEEP_SEC |
10 |
Sleeping time in second if failed in probing TCP
cone type. |
|
RANDOM_INCREMENT |
0x10000000 |
Random increment of symmetric NAT |
E_TagType
defines all tags used in synchronization with help by STUNT server.
typedef
enum
{
TAG_OK
= 1,
TAG_ABORT,
TAG_ACKABORT,
}E_TagType;
E_ErrorStat
defines all possible states of a client.
typedef
enum
{
CSTATE_PROBE
= 0,
CSTATE_IDLE,
CSTATE_BUSY,
CSTATE_DEAD,
CSTATE_TYPE_AMT
}E_StateType;
E_ErrorStat
defines all protocol types used in this library. UDP is not available.
typedef
enum
{
PRO_UDP
= 0,
PRO_TCP,
PRO_AMT
}
E_Protocol;
E_ErrorStat
defines all message types for communication service of the STUNT server.
typedef
enum
{
MSG_CONNECT
= 10001,
MSG_DEREGISTER,
MSG_QUERY,
MSG_AMT
}
E_Message;
E_ErrorStat
defines all errors in XSTUNT library. The meaning of every error will be
mentioned in the XSTUNT Functions.
|
Error Code |
Value |
Description |
|
ERR_NONE |
0 |
Successful |
|
ERR_FAIL |
-1 |
Fail |
|
ERR_CREATE_SOCKET |
-4000 |
Fail to create socket |
|
ERR_CONNECT |
-3999 |
Fail to connect |
|
ERR_VERSION |
-3998 |
Versions of server and client are mismatched |
|
ERR_DUPLICATE_ID |
-3997 |
The ID is already registered on the server |
|
ERR_PROBE |
-3996 |
Failed during probing |
|
ERR_TIMEOUT |
-3995 |
Timeout |
|
ERR_COMM_TIMEOUT |
-3994 |
Timeout during reading response from communication service |
|
ERR_ECHO_TIMEOUT |
-3993 |
Timeout during reading echo |
|
ERR_SELECT |
-3992 |
Select error |
|
ERR_RECEIVE |
-3991 |
Fail to receive |
|
ERR_SYN_RECEIVE |
-3990 |
Failed during receiving proprietary SYN |
|
ERR_SYN_SEND |
-3989 |
Failed during sending proprietary SYN |
|
ERR_ADDRPORT_RECEIVE |
-3988 |
Failed during receiving address and port |
|
ERR_ADDRPORT_SEND |
-3987 |
Failed during sending address and port |
|
ERR_ASYMSERVER |
-3986 |
Failed in XAsymServer() |
|
ERR_ASYMCLIENT |
-3985 |
Failed in XAsymClient() |
|
ERR_PREDICT |
-3984 |
Failed during port predicting |
|
ERR_SEND |
-3983 |
Failed to send |
|
ERR_TRYCONNECT |
-3982 |
Failed in XTryConnect() |
|
ERR_SETSOCKOPT |
-3981 |
Failed to set socket option |
|
ERR_BIND |
-3980 |
Failed to bind |
|
ERR_LISTEN |
-3979 |
Failed to listen |
|
ERR_ASYM_TIMEOUT |
-3978 |
Timeout during waiting the connection from AsymServer |
|
ERR_ACCEPT |
-3977 |
Failed to accept |
|
ERR_MATCH |
-3976 |
Failed to find the destination peer on the server |
|
ERR_SAME_NAT |
-3975 |
Peer client is in the same NAT |
|
ERR_HAIRPIN |
-3974 |
Hairpin problem |
|
Type |
Name |
Description |
|
FILE* |
g_pDbgFile |
Destination debugging message output file name |
|
CHAR |
g_chClientID[MAX_ID_LEN + 1] |
Client ID |
|
INT32 |
g_nClientIP |
Client IP |
|
INT32 |
g_nServerVersion |
Server version |
|
CHAR |
g_szServerIP1[MAX_IP_STR_LEN + 1] |
The first IP of the STUNT server |
|
CHAR |
g_szServerIP1[MAX_IP_STR_LEN + 1] |
The second IP of the STUNT server |
|
Fingerprint |
g_Fingerprint |
Fingerprint |
|
ServerInfo |
g_ServerInfo |
A buffer for exchanging server and client
information. |
This function predicts the global port, exchanges
the IP/PORT information through STUNT server, and finally connects to the
Asymmetric Client.
Client.h
INT32
XAsymServer(SOCKET sServerLog, SOCKET sCtrl, SOCKET *psListen, struct
sockaddr_in *pAddrPeer, INT32 nTimeoutSec, INT32* pnErrCode);
|
-> |
sServerLog |
The
STUNT server socket. This socket must be gotten from XInit() and be valid. |
|
-> |
sCtrl |
A valid
Control service socket of the STUNT server. |
|
<-> |
psListen |
User
specified listen socket. User should access this socket to read/ write data
if the process works successfully. |
|
<-> |
pAddrPeer |
The
address information of the connecting peer. Pass NULL if user does not need
this information. |
|
-> |
nTimeoutSec |
The
timeout will be set in all of the waiting procedures in this function. |
|
<-> |
pnErrCode |
Error
code. |
|
ERR_NONE |
Successful. |
|
ERR_PREDICT |
Fail during port prediction. Check in XPredict(). |
|
ERR_SEND |
Fail to send public IP/PORT of the client. |
|
ERR_TIMEOUT |
Timeout during waiting reading data from STUNT server. |
|
ERR_SELECT |
SELECT fail during connecting to another peer. |
|
ERR_RECEIVE |
Fail during receiving peer information or sync data from STUNT server. |
|
ERR_CONNECT |
Fail to connect to the destination peer. |
|
ERR_HAIRPIN |
The public IP addresses of source and destination are the same. |
This is an important function to start a
simultaneous TCP connection with the other peer. Therefore, the function and
XAsmClient() must be launched in the meantime on two different machines behind
different NATs. Notice that *psListen will be set to non-blocking I/O in this
function to achieve a connection timeout and never set back to the original
value throughout. Timeout in this function should be set the same as that set
in XAsmServer() to make synchronization well. An experimental suggested value
is defined by ASYM_TIMEOUT.
Check the error reason by pnErrCode for all errors listed above except
ERR_PREDICT and ERR_HAIRPIN.
XListen, XAsymClient, XPredict
This function predicts the global port, exchanges
the IP/PORT information through STUNT server, tries to connect to the
destination peer, theoretically gets a failure, listens to the Asymmetric
Server and finally establishes the connection.
Client.h
INT32
XAsymClient(SOCKET sServerLog, SOCKET sCtrl, SOCKET *psConnect, struct
sockaddr_in *pAddrPeer, INT32 nTimeoutSec, INT32* pnErrCode);
|
-> |
sServerLog |
The
STUNT server socket. This socket must be gotten from XInit() and be valid. |
|
-> |
sCtrl |
A valid
Control service socket of the STUNT server. |
|
<-> |
psConnect |
User
specified connection socket. |
|
<-> |
pAddrPeer |
The
address information of the connecting peer. Pass NULL if user does not need
this information. |
|
-> |
nTimeoutSec |
The
timeout will be set in all of the waiting procedures in this function. |
|
<-> |
pnErrCode |
Error
code. |
|
ERR_NONE |
Successful. |
|
ERR_PREDICT |
Fail during port prediction. Check in XPredict(). |
|
ERR_SEND |
Fail to send public IP/PORT of the client. |
|
ERR_TIMEOUT |
Timeout during waiting reading data from STUNT server. |
|
ERR_SELECT |
SELECT fail during connecting to another peer. |
|
ERR_RECEIVE |
Fail during receiving peer information or sync data from STUNT server. |
|
ERR_CONNECT |
Fail to connect to the destination peer. |
|
ERR_HAIRPIN |
The public IP addresses of source and destination are the same. |
|
ERR_TRYCONNECT |
XTryConnect() returned ERR_NONE, but it represents that the function
should return back failure. |
|
ERR_CREATE_SOCKET |
Fail to create a new socket. |
|
ERR_SETSOCKOPT |
Fail to set socket option. |
|
ERR_BIND |
Fail to bind a new socket. |
|
ERR_LISTEN |
Fail to listen. |
|
ERR_ASYM_TIMEOUT |
Timeout during waiting the connection from AsymServer. |
|
ERR_ACCEPT |
Fail to accept. |
This is an important function to start a
simultaneous TCP connection with the other peer. Therefore, the function and
XAsmServer() must be launched in the meantime on two different machines behind
different NATs. Timeout in this function should be set the same as that set in
XAsmClient() to make synchronization well. An experimental suggested value is
defined by ASYM_TIMEOUT.
Check the error reason by pnErrCode for all errors listed above except
ERR_ASYM_PREDICT, ERR_HAIRPIN, and ERR_ASYM_TIMEOUT.
XConnect, XAsymClient, XPredict, XTryConnect
This function predicts the global port that will be
used in the next connection and return the socket with that global port number
on NAT.
Client.h
INT32
XPredict(SOCKET sServerLog, SOCKET *psAux, struct sockaddr_in *pAddrGlobal,
struct sockaddr_in *pAddrLocal);
|
-> |
sServerLog |
The
STUNT server socket. This socket must be gotten from XInit() and be valid. |
|
<-> |
psAux |
A
socket descriptor. It will be set to a valid socket bound on the local
address: pAddrLocal and with a predicted port: pAddrGlobal on NAT. |
|
<-> |
pAddrGlobal |
The
function will write the address with global predicted port for next
connection. |
|
<-> |
pAddrLocal |
The
function will randomly assign an address to this variable and bind it on
psAux. |
|
ERR_NONE |
Successful. |
|
ERR_FAIL |
Failed in this function. |
The function will bind a random address on psAux
twice to determine the predicted global port using XCheckConeTCPProbe(). Notice
that the increment data of fingerprint should also be ready for the prediction.
XCheckConeTCPProbe,
XAsymServer, XAsymClient,
XAnalyzeNature
This function tries to make a connection to the
destination peer.
Client.h
INT32
XTryConnect(SOCKET sServerLog, SOCKET sAuxServer, struct sockaddr *pAddrPeer,
INT32 nAddrPeerLen, INT32 nMiliSec);
|
-> |
sServerLog |
The
STUNT server socket. This socket must be gotten from XInit() and be valid. |
|
-> |
sAuxServer |
The
socket for creating this connection. |
|
-> |
pAddrPeer |
Destination
peer address. |
|
-> |
pAddPeerLen |
Length
of pAddrPeer |
|
-> |
pMiliSec |
Timeout
of this non-blocking connection |
|
ERR_NONE |
Successful. |
|
ERR_FAIL |
Failed in this function. |
Notice that the normal result should be ERR_FAIL
but not ERR_NONE. The goal of this function is to punch a hole on the NAT.
pMiliSec should be large enough for the TCP-SYN to leave the host and hit the
NAT(s) it is behind. In this library, the value is 1000ms but even 500ms or
100ms would work just fine.
This function try to create a connection to the
destination peer and fails immediately and we observe that some recipient NATs
will send the RST, but most NATs will silently discard the SYN and not bother
to send a RST. That's what we observed in our measurement study. Even if the
recipient's NAT does sent a RST (a small percent of NATs), it turns out that
the RST won't affect anything since not all senders' NATs will close the hole.
More on the SYN-RST numbers here:
https://www.guha.cc/saikat/stunt-results.php?
In the column: 'Incoming SYN Unsolicited', only 21
out of 141 models tested respond with RST packets. Re-normalized with each
brand's market share, that is less than 10%. In the column 'Incoming SYN after
RST', 66 out of 141 NATs will accept the inbound SYN after the RST (i.e. do not
close the hole). Renormalized, that number is around 75%.
So overall, only 2.5% of the time will there be a
RST packet that will close the hole. That is our estimate.
This function will fetch the
OS type, probe the NAT type of the client, generate/write the fingerprint, and
send the result to the STUNT server.
Client.h
INT32
XProbe(SOCKET sServerLog);
|
-> |
sServerLog |
The
STUNT server socket. This socket must be gotten from XInit() and be valid. |
|
ERR_NONE |
Successful. |
|
ERR_FAIL |
Failed. |
The function reports the client¡¦s information to
the STUNT server logger with ID, OS type, build version, and NAT fingerprint.
Possible OS type strings are ¡§WIN
XProbeNAT, XGenFingerprint, XWriteFingerprint
This is a wrap of
XCheckConeTCP(). It just controls the retry times and sleeping time.
Client.h
INT32
XProbeNAT(SOCKET sServerLog);
|
-> |
sServerLog |
The
STUNT server socket. This socket must be gotten from XInit() and be valid. |
|
ERR_NONE |
Successful. |
|
ERR_FAIL |
Failed after all retries. |
Adjust the retry times and sleeping time by
modifying PROBE_RETRY_TIMES and PROBE_FAIL_SLEEP_SEC.
This function checks NAT's TCP
port mapping characteristics. It's a wrap of XCheckConeTCPProbe() and
XAnalyzeNature().
Client.h
INT32 XCheckConeTCP(SOCKET
sServerLog);
|
-> |
sServerLog |
The
STUNT server socket. This socket must be gotten from XInit() and be valid. |
|
ERR_NONE |
Successful. |
|
ERR_FAIL |
Failed. |
The function binds 1 port for XCheckConeTCPProbe()
to detect characteristics of the NAT and then passes the result to
XAnalyzeNature().
XCheckConeTCPProbe,
XAnalyzeNature
This function try to connect
to the echo service with different IP-PORT combinations and then get the public
IP and port of the client.
Client.h
void
XCheckConeTCPProbe(SOCKET sServerLog, SOCKET sEcho, INT32 nSeq, UINT32
*punResAddr, UINT16 *puwResPort);
|
-> |
sServerLog |
The
STUNT server socket. This socket must be gotten from XInit() and be valid. |
|
-> |
sEcho |
A echo
socket created in XCheckConeTCP(). It will be used to connect to the echo
service of STUNT server. |
|
-> |
nSeq |
Test
sequence number (0 ~ 4). |
|
<-> |
*punResAddr |
The
public address of the client returned from the STUNT server. |
|
<-> |
*puwResPort |
The
public port of the client returned from the STUNT server. |
N/A
The function will be triggered 4 times with
sequence number 0 to 4 to determine the IP:PORT combination of the echo service
provided by the STUNT server. 4 combinations are IP1:PORT1, IP1:PORT2,
IP2:PORT1, IP2:PORT2. The echo service will return the public IP:PORT of the
client every time.
XCheckConeTCPProbe,
XAnalyzeNature
This function analyzes the
passed in IP:PORT data and write the result on fingerprint.
Client.h
void xAnalyzeNature(UINT32
*punAddrGlobal, UINT16 *puwPortGlobal, UINT16 *puwPortLocal, INT32 nTimes,
E_Protocol nProtocol);
|
-> |
*punAddrGlobal |
The
pointer which points to a global (public) IP array. |
|
-> |
*puwPortGlobal |
The
pointer which points to a global (public) Port array |
|
-> |
*puwPortLocal |
The
pointer which points to a local (private) Port array |
|
<-> |
nTimes |
Test
times. The value is also the size of the above arrays |
|
<-> |
nProtocol |
Always
PRO_TCP in this library. |
N/A
The function is called by XCheckConeTCP().
XCheckConeTCP will pass in the testing result got from XCheckConeTCPPorbe():
global IP:PORT and local PORT array. The function will determine the NAT
characteristics such as Port-Preserving and Cone/Symmetric and write it on the fingerprint.
Notice that only TCP analyzing is used in this library.
XCheckConeTCPProbe,
XCheckConeTCP
This function interprets the
binary fingerprint data to a readable string.
Client.h
void
XGenFingerprint(CHAR *pchPrint, INT32 nSize);
|
<-> |
*pchPrint |
A
buffer for storing the readable fingerprint string. |
|
-> |
nSize |
Size of
the above string |
N/A
The function will print the following TCP NAT
characteristic string:
[Does the NAT preserve the port number on the local
machine?]
PORT-PRESERVING: Yes, the NAT will preserve the
port number as the same as local port.
NOT-PORT-PRESERVING: No, the NAT won¡¦t preserver
the port number.
[Does the NAT change the mapping port when the
local machine tries to create another connection?]
CONE: The NAT will use a port which is opened
before for this connection.
RANDOM-SYMMETRIC: The NAT will randomly open a port
even if the machine is already opening a port on NAT.
DELTA-N-SYMMETRIC: The NAT will open a port of
number with a number-N increment to the previous connection.
This function writes the NAT
fingerprint to specified file on the local machine.
Client.h
INT32
XWriteFingerprint(SOCKET sServerLog);
|
-> |
sServerLog |
The
STUNT server socket. This socket must be gotten from XInit() and be valid. |
|
ERR_NONE |
Successful. |
|
ERR_FAIL |
Failed. |
The file name is defined by FINGERPRINT_FILE.
xGenFingerprint, XReadFingerprint
This function read fingerprint
file and write the data on the global fingerprint variable.
Client.h
INT32
XReadFingerprint(void);
N/A
|
ERR_NONE |
Successful. |
|
ERR_FAIL |
Failed. |
The file name is defined by FINGERPRINT_FILE. Not
only I/O error but also build version and client ID will be checked in this
function.
XGenFingerprint, XReadFingerprint
This function read fingerprint
file and write the data on the global fingerprint variable.
Client.h
INT32
XInitSockAddr(struct sockaddr_in *pSockAddr, INT16 wFamily, const CHAR *
pchAddr, UINT16 uwPort, UINT32 unConvertedAddr, UINT16 uwConvertedPort);
|
<-> |
pSockAddr |
The
socket address needed to set. |
|
-> |
wFamily |
Net
family. |
|
-> |
pchAddr |
Socket
address in string. Pass NULL if pass in converted data |
|
-> |
uwPort |
Socket
port |
|
-> |
unConvertedAddr |
Converted
address |
|
-> |
uwConvertedPort |
Converted
port |
|
ERR_NONE |
Successful. |
A utility to set address data for 2 different
forms.
N/A
A delay function.
Client.h
void
XSleep(INT32 nSec, INT32 nUSec);
|
-> |
nSec |
Time
value, in second. |
|
-> |
nUSec |
Time
value, in microsecond. |
N/A
Implement of sleep in linux.
N/A
This function gets errno in
windows and linux.
Client.h
INT32
XGetErrno(void);
N/A
For windows, this function returns winsock error
code but errno otherwise.
Use this function to get error code in windows or
linux.
N/A
UDP
l Use STUN to detect NAT type
(source code is available: http://sourceforge.net/projects/stun)
l Full Cone/ Restricted
Cone/ Port Restricted are solved by a NAT probe. (NAT probe sample code is
available: http://www.ppcn.net/n1306c2.aspx)
l NAT probe: Client A and
Client B are all registered in this server. The server knows the public IP:port
of both clients registered in. If client A wants to talk to client B, client A
will first send a message to client B but abandoned by NAT B. client A then
tells NAT probe to inform client B. Client B will send a trash message to
client A and then Client A knows it¡¦s possible to talk.
l In symmetric NAT, we
must guess the port NAT assigned.
TCP
l TCP NAT Traversal is
also available: http://zgp.org/pipermail/p2p-hackers/2005-September/002979.html
l This library (Java) is
based on this research paper:
http://nutss.net/pub/imc05-tcpnat.pdf
l
The key result of the paper is: TCP NAT Traversal can
work 85%-90% of the time today (without any special assumptions on NATs), and
100% of the time between pairs of
certain well-behaved NATs.