📄 client.cpp
字号:
act_on_error(nRetVal = connect(sComm, (struct sockaddr *)&AddrComm, sizeof(AddrComm)), "Connecting to communication server", goto LAB_ERR_CONNECT);
//Write the Message sent to Communication server
MsgCon.nType = htonl(MSG_CONNECT);
strcpy(MsgCon.Data.Connection.chDstID, pchPeerID);
strcpy(MsgCon.Data.Connection.chSrcID, g_chClientID);
//send the message
log_on_write_error(sComm, (char*)&MsgCon, sizeof(MsgCon), "Sending communication message", LAB_ERR_SEND);
//receive the result
#ifdef TEST_TIME
#ifdef _WIN32
nStart = GetTickCount();
#endif
#endif
readtimeout(sComm, Socks, nTimeoutSec, LAB_ERR_COMM_TIMEOUT); //COMM_TIMEOUT
#ifdef TEST_TIME
#ifdef _WIN32
nEnd = GetTickCount();
printf("Receiving communication result [%d] ms.\n", nEnd - nStart);
#endif
#endif
log_on_read_error(sComm, (char*)&nCommRet, sizeof(nCommRet), "Receiving communication result", LAB_ERR_RECEIVE);
if (nCommRet == -1)
{
close2(*psConnect);
close2(sComm);
return ERR_MATCH;
}
else if (nCommRet != 0)
{
close2(*psConnect);
close2(sComm);
*pnErrCode = nCommRet;
return ERR_SAME_NAT;
}
#ifdef TEST_TIME
#ifdef _WIN32
nStart = GetTickCount();
#endif
#endif
readtimeout(sServerLog, Socks, nTimeoutSec, LAB_ERR_TIMEOUT);
#ifdef TEST_TIME
#ifdef _WIN32
nEnd = GetTickCount();
printf("Receiving peer data [%d] ms.\n", nEnd - nStart);
#endif
#endif
log_on_read_error(sServerLog, (CHAR*)&Peer, sizeof(Peer), "Receiving peer data", LAB_ERR_RECEIVE);
close2(sCtrl);
//Assign the socket address/port of of the server (control channel port) which is returned by channel
XInitSockAddr(&AddrCtrl, AF_INET, NULL, 0, Peer.nIP, Peer.wPort);
//Create control channel socket
sCtrl = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
act_on_error(sCtrl = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP), "Creating control socket", goto LAB_ERR_CREATE_SOCKET);
act_on_error(connect(sCtrl, (struct sockaddr *)&AddrCtrl, sizeof(AddrCtrl)), "Connecting to control server", goto LAB_ERR_CONNECT);
//Sync with peer
#ifdef _WIN32
nDelay = GetTickCount();
#else
ftime(&tStart);
#endif
log_on_Xwrite_error(sCtrl, &nOne, sizeof(nOne), "Sending echo", LAB_ERR_SYN_SEND);
#ifdef TEST_TIME
#ifdef _WIN32
nStart = GetTickCount();
#endif
#endif
readtimeout(sCtrl, Socks, nTimeoutSec, LAB_ERR_ECHO_TIMEOUT); //here we let programmer to set this value
#ifdef TEST_TIME
#ifdef _WIN32
nEnd = GetTickCount();
printf("Reading echo [%d] ms.\n", nEnd - nStart);
#endif
#endif
log_on_Xread_error(sCtrl, &nOne, sizeof(nOne), "Reading echo", LAB_ERR_SYN_RECEIVE);
#ifdef _WIN32
nDelay = GetTickCount() - nDelay;
#else
ftime(&tCurrent);
nDelay = (int) (1000.0 * (tCurrent.time - tStart.time)
+ (tCurrent.millitm - tStart.millitm));
#endif
log_on_Xwrite_error(sCtrl, &nOne, sizeof(nOne), "Sending echo", LAB_ERR_SYN_SEND);
#ifdef _WIN32
Sleep(nDelay / 2);
#else
XSleep(0, nDelay / 2);
#endif
#ifdef TEST_TIME
#ifdef _WIN32
nStart = GetTickCount();
#endif
#endif
nRetVal = XAsymClient(sServerLog, sCtrl, psConnect, pAddrPeer, ASYM_TIMEOUT, &nAsymErrCode);
#ifdef TEST_TIME
#ifdef _WIN32
nEnd = GetTickCount();
printf("AsymClient [%d] ms.\n", nEnd - nStart);
#endif
#endif
if (nRetVal != ERR_NONE)
{
*pnErrCode = nRetVal;
close2(*psConnect);
close2(sComm);
close2(sCtrl);
return ERR_ASYMCLIENT;
}
else
{
close2(sComm);
close2(sCtrl);
return ERR_NONE;
}
LAB_ERR_CREATE_SOCKET:
close2(sComm);
close2(sCtrl);
*pnErrCode = XGetErrno();
return ERR_CREATE_SOCKET;
LAB_ERR_CONNECT:
close2(sComm);
close2(sCtrl);
*pnErrCode = XGetErrno();
return ERR_CONNECT;
LAB_ERR_SEND:
close2(sComm);
*pnErrCode = XGetErrno();
return ERR_SEND;
LAB_ERR_COMM_TIMEOUT:
close2(sComm);
*pnErrCode = XGetErrno();
return ERR_COMM_TIMEOUT;
LAB_ERR_RECEIVE:
close2(sComm);
*pnErrCode = XGetErrno();
return ERR_RECEIVE;
LAB_ERR_TIMEOUT:
close2(sComm);
*pnErrCode = XGetErrno();
return ERR_TIMEOUT;
LAB_ERR_ECHO_TIMEOUT:
close2(sComm);
close2(sCtrl);
*pnErrCode = XGetErrno();
return ERR_ECHO_TIMEOUT;
LAB_ERR_SYN_RECEIVE:
close2(sComm);
close2(sCtrl);
*pnErrCode = XGetErrno();
return ERR_SYN_RECEIVE;
LAB_ERR_SYN_SEND:
close2(sComm);
close2(sCtrl);
*pnErrCode = XGetErrno();
return ERR_SYN_SEND;
}
/***********************************************************************
* FUNCTION: XDeRegister()
* DESCRIPTION: Deregister the client on and close the socket of the connection to the STUNT server.
* PARAMETERS:
* -> 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.
* RETURNED:
* ERR_NONE Successful.
* ERR_CREATE_SOCKET Fail to create a socket to the communication port.
* ERR_CONNECT Fail to connect to the communication port of STUNT server.
* REVISION HISTORY:
***********************************************************************/
INT32 XDeRegister(SOCKET sServerLog, CHAR* pchID, INT32* pnErrCode)
{
//send message to the stunt server by communication thread to remove the client by ID
Msg MsgDereg;
INT32 nRetVal = 0;
SOCKET sComm = (SOCKET) -1;
struct sockaddr_in AddrComm;
XInitSockAddr(&AddrComm, AF_INET, g_szServerIP1, SERVER_COMM_PORT, 0, 0);
close2(sComm);
//Create communication socket
sComm = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
#ifdef _WIN32
if (sComm == INVALID_SOCKET )
#else
if (sComm == -1 )
#endif
{
close2(sComm);
*pnErrCode = XGetErrno();
return ERR_CREATE_SOCKET;
}
//Connect to the comm
nRetVal = connect(sComm, (struct sockaddr *)&AddrComm, sizeof(AddrComm));
if (nRetVal == -1) //SOCKET_ERROR
{
close2(sComm);
*pnErrCode = XGetErrno();
return ERR_CONNECT;
}
//Write the Message sent to Communication server
MsgDereg.nType = htonl(MSG_DEREGISTER);
//ID of the client;
strcpy(MsgDereg.Data.chID, pchID);
//send the message
send(sComm, (char*)&MsgDereg, sizeof(MsgDereg), 0);
//close the socket
close2(sServerLog);
return ERR_NONE;
}
/************************************************************************************************************************/
/* Private Function Definition */
/************************************************************************************************************************/
/***********************************************************************
* FUNCTION: XAsymServer()
* DESCRIPTION: This function predicts the global port, exchanges the IP/PORT information through
* STUNT server, and finally connects to the Asymmetric Client.
* PARAMETERS:
* -> 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.
* RETURNED:
* 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.
* REVISION HISTORY:
***********************************************************************/
INT32 XAsymServer(SOCKET sServerLog, SOCKET sCtrl, SOCKET *psListen, struct sockaddr_in *pAddrPeer, INT32 nTimeoutSec, INT32* pnErrCode)
{
struct sockaddr_in AddrPeer, AddrClient, AddrGlobal;
struct timeval Timeout;
fd_set Socks;
INT32 nOne = 0, nRetVal = 0;
unsigned long ulOne = 0;
//Using in macro by Saikat:
CHAR errbuf[256];
SOCKET sock_logr = sServerLog;
/////////////////////////////////////////////////////////////
*psListen = (SOCKET) -1;
strncpy(errbuf, "PORTPRED", 128);
log_on_error(XPredict(sServerLog, psListen, &AddrGlobal, &AddrClient), "Predicting port", LAB_ERR_PREDICT);
strncpy(errbuf, "CONTROL", 128);
log_on_Xwrite_error(sCtrl, &AddrGlobal.sin_addr.s_addr, sizeof(AddrGlobal.sin_addr.s_addr), "Sending address", LAB_ERR_SEND);
log_on_Xwrite_error(sCtrl, &AddrGlobal.sin_port, sizeof(AddrGlobal.sin_port), "Sending predicted port", LAB_ERR_SEND);
AddrPeer.sin_family = AF_INET;
readtimeout(sCtrl, Socks, nTimeoutSec, LAB_ERR_TIMEOUT);
log_on_Xread_error(sCtrl, &AddrPeer.sin_addr.s_addr, sizeof(AddrPeer.sin_addr.s_addr), "Receiving address", LAB_ERR_RECEIVE);
readtimeout(sCtrl, Socks, nTimeoutSec, LAB_ERR_TIMEOUT);
log_on_Xread_error(sCtrl, &AddrPeer.sin_port, sizeof(AddrPeer.sin_port), "Receiving port", LAB_ERR_RECEIVE);
readtimeout(sCtrl, Socks, nTimeoutSec, LAB_ERR_TIMEOUT);
log_on_Xread_error(sCtrl, &nOne, sizeof(nOne), "Ready", LAB_ERR_RECEIVE);
//HairPin Problem: do not process
if (AddrGlobal.sin_addr.s_addr == AddrPeer.sin_addr.s_addr)
{
return ERR_HAIRPIN;
}
//Set psListen to non-blocking I/O
#ifdef _WIN32
ulOne = 1;
ioctlsocket(*psListen, FIONBIO, &ulOne);
#else
fcntl(*psListen, F_SETFL, O_NONBLOCK);
#endif
nRetVal = connect(*psListen, (struct sockaddr *)&AddrPeer, sizeof(AddrPeer));
if (nRetVal == -1)
{
*pnErrCode = XGetErrno();
#ifdef _WIN32
if (*pnErrCode != WSAEWOULDBLOCK) //would block
#else
if (*pnErrCode != 115) //would block
#endif
return ERR_CONNECT;
}
FD_ZERO(&Socks);
FD_SET(*psListen, &Socks);
Timeout.tv_sec = nTimeoutSec;
Timeout.tv_usec = 0;
//waiting user set timeout, this value MUST be the same as setting in XAsmClient.
nRetVal = ::select(((INT32)*psListen) + 1, NULL, &Socks, NULL, &Timeout);
if (nRetVal == 0 || nRetVal == -1) //Timeout or SOCKET_ERROR
{
*pnErrCode = XGetErrno();
return ERR_SELECT;
}
else
{
if (pAddrPeer != NULL)
{
pAddrPeer->sin_addr.s_addr = AddrPeer.sin_addr.s_addr;
pAddrPeer->sin_port = AddrPeer.sin_port;
}
return ERR_NONE;
}
LAB_ERR_PREDICT:
return ERR_PREDICT;
LAB_ERR_SEND:
*pnErrCode = XGetErrno();
return ERR_SEND;
LAB_ERR_TIMEOUT:
*pnErrCode = XGetErrno();
return ERR_TIMEOUT;
LAB_ERR_RECEIVE:
*pnErrCode = XGetErrno();
return ERR_RECEIVE;
}
/***********************************************************************
* FUNCTION: XAsymClient()
* DESCRIPTION: 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.
* PARAMETERS:
* -> 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.
* RETURNED:
* 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.
* REVISION HISTORY:
***********************************************************************/
INT32 XAsymClient(SOCKET sServerLog, SOCKET sCtrl, SOCKET *psConnect, struct sockaddr_in *pAddrPeer, INT32 nTimeoutSec, INT32* pnErrCode)
{
struct sockaddr_in AddrGlobal;
struct sockaddr_in AddrPeer;
struct sockaddr_in AddrClient;
#ifdef _WIN32
INT32 nAddrLen = sizeof(AddrPeer);
#else
socklen_t nAddrLen = sizeof(AddrPeer);
#endif
struct timeval Timeout;
fd_set Socks;
INT32 nOne = 1;
SOCKET sAuxServer = (SOCKET)-1;
//Using in macro by Saikat:
CHAR errbuf[256];
SOCKET sock_logr = sServerLog;
/////////////////////////////////////////////////////////////
//Initialize socket psConnect
*psConnect = (SOCKET)-1;
strncpy(errbuf, "PORTPRED", 128);
log_on_error(XPredict(sServerLog, &sAuxServer, &AddrGlobal, &AddrClient), "Predicting port", LAB_ERR_PREDICT);
strncpy(errbuf, "CONTROL", 128);
log_on_Xwrite_error(sCtrl, &AddrGlobal.sin_addr.s_addr, sizeof(AddrGlobal.sin_addr.s_addr), "Sending address", LAB_ERR_SEND);
log_on_Xwrite_error(sCtrl, &AddrGlobal.sin_port, sizeof(AddrGlobal.sin_port), "Sending predicted port", LAB_ERR_SEND);
AddrPeer.sin_family = AF_INET;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -