⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 client.cpp

📁 stun的一个客户端例子
💻 CPP
📖 第 1 页 / 共 4 页
字号:
/* Copyright (C) 2006 	Saikat Guha  and					
 *						Kuanyu Chou (xDreaming Tech. Co.,Ltd.)
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
#pragma warning (disable: 4127 4057 4100 4389)
/***********************************************************************
*		 Win32 / Linux Intelx86 C++ Compiler File 		    		   				   
*--------------------------------------------------------------		   
*	[For]				{ XSTUNT Library }				  			   
*	[File name]     	{ Client.cpp }                          		   	   
*	[Description]
*	This file is the main implementation for XSTUNT library. The method to do the TCP NAT Traversal can be
*	refered to "Characterization and Measurement of TCP Traversal through NAT and FireWalls" addressed by Saikat
*	and Paul. The following code 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 references.
*	[History]
*  	2005.10		Saikat/Paul		Paper and experiment proposed
*	2006.03		Saikat/Kuanyu	C/C++ implementation code released 
***********************************************************************/
/************************************************************************************************************************/
/*			Include Files																								*/
/************************************************************************************************************************/
#include "Client.h"
#ifndef _WIN32
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#endif
/************************************************************************************************************************/
/*			Internally Macro Definition																							*/
/************************************************************************************************************************/
#include "ClientMacro.h"
/************************************************************************************************************************/
/*			Internal Type Definition: Defined in Client.h																								*/
/************************************************************************************************************************/
/************************************************************************************************************************/
/*			Internal Visiable Variable Definition: Defined in Client.h																		*/
/************************************************************************************************************************/
/************************************************************************************************************************/
/*			Internal Visiable Function Reference: Defined in Client.h																		*/
/************************************************************************************************************************/
/************************************************************************************************************************/
/*			Internal Visiable Constant Definition: Defined in Client.h																		*/
/************************************************************************************************************************/
/************************************************************************************************************************/
/*			Public Function Definition																					*/
/************************************************************************************************************************/
/***********************************************************************
 * FUNCTION:		XInit() 
 * DESCRIPTION:  	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.
 * PARAMETERS:		-> 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 32 characters long and not an empty string.
 *					<-> *pnErrCode: Error code
 * RETURNED:		
 *					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.
 * REVISION HISTORY:
 ***********************************************************************/
INT32 XInit(const char* pchIP1, const char* pchIP2, SOCKET* psServerLog, CHAR* pchID, INT32 *pnErrCode)
{
#ifdef _WIN32
	WSADATA Wsadata;
#endif
	struct sockaddr_in AddrLog, AddrLocal;
#ifdef _WIN32
	INT32 nAddrLen = sizeof(struct sockaddr_in);
#else
	socklen_t nAddrLen = sizeof(struct sockaddr_in); 
#endif
	INT32 nClientVersion = 0, nServerVersion = 0;
    INT32 nRetVal = 0; 
	UINT8 ubClientState = 0;
	UINT32	unLocalAddr = 0;

	*pnErrCode = 0;
	*psServerLog = (SOCKET) -1;

	//Using in macro by Saikat: 
	//CHAR errbuf[128];
	SOCKET sock_logr = *psServerLog;
	/////////////////////////////////////////////////////////////

	//Set server IP address
	if (pchIP1 != NULL && pchIP2 != NULL)
	{
		sprintf(g_szServerIP1,"%s", pchIP1);
		sprintf(g_szServerIP2,"%s", pchIP2);
	}

	//The WSAStartup function initiates use of WS2_32.DLL by a process
#ifdef _WIN32
	WSAStartup(MAKEWORD(2,2), &Wsadata);
#endif
	//Assign the socket address/port of of LOG SERVER
	XInitSockAddr(&AddrLog, AF_INET, g_szServerIP1, SERVER_LOG_PORT, 0, 0);
	//Close logger socket and initialize the socket to -1
	close2(*psServerLog);
	//Create the logger socket
	act_on_error(*psServerLog = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP), "Creating logger socket", goto LAB_ERR_CREATE_SOCKET);
	//Connect to the logger
	act_on_error(nRetVal = connect(*psServerLog, (struct sockaddr *)&AddrLog, sizeof(AddrLog)), "Connecting to server", goto LAB_ERR_CONNECT);
	//read finger print from the current data
	XReadFingerprint();
	//Reset the client ID to the new one.
	strcpy(g_chClientID, pchID);
	//receive the client build version from server
	log_on_read_error(*psServerLog, (char*)&nClientVersion, sizeof(nClientVersion), "Receiving required version", LAB_ERR_RECEIVE);

	if (ntohl(nClientVersion) != BUILD_VER) 
	{
		close2(*psServerLog);
		return ERR_VERSION;
	}
	//receive the server version from server
	log_on_read_error(*psServerLog, (char*)&nServerVersion, sizeof(nServerVersion), "Receiving server version", LAB_ERR_RECEIVE);
	g_nServerVersion = ntohl(nServerVersion);
	if (ntohl(nServerVersion) != g_Fingerprint.nServerVer) 
	{
		g_Fingerprint.nDone = false;
	}
	//receive the client IP from server
	log_on_read_error(*psServerLog, (char*)&g_nClientIP, sizeof(g_nClientIP), "Receiving client IP", LAB_ERR_RECEIVE);
	if (g_nClientIP != g_Fingerprint.nGAddr) 
	{
		g_Fingerprint.nDone = false;
	}

	//if the finger print is not done, then get the fingerprint
	if (!g_Fingerprint.nDone) 
	{
		memset(&g_Fingerprint, 0, sizeof(g_Fingerprint));
		g_Fingerprint.nServerVer = g_nServerVersion;
		g_Fingerprint.nGAddr = g_nClientIP;
		g_Fingerprint.nClientVer = BUILD_VER;

		log_on_write_error(*psServerLog,  (char*)g_chClientID, sizeof(g_chClientID), "sending client ID", LAB_ERR_SEND);
		log_on_read_error(*psServerLog, (char*)&g_ServerInfo, sizeof(g_ServerInfo), "Receiving server config", LAB_ERR_RECEIVE);
		if (strlen(g_ServerInfo.chID) == 0)
		{
			close2(*psServerLog);
			return ERR_DUPLICATE_ID;
		}
		ubClientState = CSTATE_PROBE;
		log_on_write_error(*psServerLog,  (char*)&ubClientState, sizeof(UINT8), "sending client state", LAB_ERR_SEND);
		
		getsockname(*psServerLog,(struct sockaddr *)&AddrLocal, &nAddrLen);
		unLocalAddr = AddrLocal.sin_addr.s_addr;
		log_on_write_error(*psServerLog,  (char*)&unLocalAddr, sizeof(UINT32), "sending client local address", LAB_ERR_SEND);

		strcpy(g_chClientID, g_ServerInfo.chID);
		strcpy(g_Fingerprint.chID, g_chClientID);
	 	nRetVal = XProbe(*psServerLog);
		close2(*psServerLog);
		if (nRetVal == -1) 
		{
			return ERR_PROBE;
		}
		act_on_error(*psServerLog = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP), "Creating new logger socket", goto LAB_ERR_CREATE_SOCKET);
		act_on_error(nRetVal = connect(*psServerLog, (struct sockaddr *)&AddrLog, sizeof(AddrLog)), "Connecting to server", goto LAB_ERR_CONNECT);
		log_on_read_error(*psServerLog, (char*)&nClientVersion, sizeof(nClientVersion), "Receiving required version", LAB_ERR_RECEIVE);
		log_on_read_error(*psServerLog, (char*)&nServerVersion, sizeof(nServerVersion), "Receiving server version", LAB_ERR_RECEIVE);
		log_on_read_error(*psServerLog, (char*)&g_nClientIP, sizeof(g_nClientIP), "Receiving client IP", LAB_ERR_RECEIVE);
	} 

	log_on_write_error(*psServerLog,  (char*)g_chClientID, sizeof(g_chClientID), "sending client ID", LAB_ERR_SEND);
	log_on_read_error(*psServerLog, (char*)&g_ServerInfo, sizeof(g_ServerInfo), "Receiving server config", LAB_ERR_RECEIVE);
	if (strlen(g_ServerInfo.chID) == 0)
	{
		close2(*psServerLog);
		return ERR_DUPLICATE_ID;
	}
	ubClientState = CSTATE_IDLE;
	log_on_write_error(*psServerLog,  (char*)&ubClientState, sizeof(UINT8), "sending client state", LAB_ERR_SEND);

	getsockname(*psServerLog,(struct sockaddr *)&AddrLocal, &nAddrLen);
	unLocalAddr = AddrLocal.sin_addr.s_addr;
	log_on_write_error(*psServerLog,  (char*)&unLocalAddr, sizeof(UINT32), "sending client local address", LAB_ERR_SEND);

	return ERR_NONE;

LAB_ERR_CREATE_SOCKET:
	close2(*psServerLog);
	*pnErrCode = XGetErrno();
	return ERR_CREATE_SOCKET;
LAB_ERR_CONNECT:
	close2(*psServerLog);
	*pnErrCode = XGetErrno();
	return ERR_CONNECT;
LAB_ERR_RECEIVE:
	close2(*psServerLog);
	*pnErrCode = XGetErrno();
	return ERR_RECEIVE;
LAB_ERR_SEND:
	close2(*psServerLog);
	*pnErrCode = XGetErrno();
	return ERR_SEND;
}

/***********************************************************************
 * FUNCTION:		XListen() 
 * DESCRIPTION:  	Listen on a specified socket through the help of a STUNT server.
 * PARAMETERS:		
 *					->	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.
 * RETURNED:		
 *					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.
 *
 * REVISION HISTORY:
 ***********************************************************************/
INT32 XListen(SOCKET sServerLog, SOCKET* psListen, struct sockaddr_in *pAddrPeer, INT32 nTimeoutSec, INT32* pnErrCode)
{
	Echo Peer;
    struct timeval	Timeout;
    fd_set Socks;
    SOCKET sCtrl = (SOCKET) -1;
	struct sockaddr_in AddrCtrl;
	INT32 nOne = 1, nAsymErrCode = 0;   
    INT32 nRetVal = 0;

	//Using in macro by Saikat: 
	CHAR errbuf[128];
	SOCKET sock_logr = sServerLog;
	/////////////////////////////////////////////////////////////

	FD_ZERO(&Socks);
	FD_SET(sServerLog, &Socks);
	Timeout.tv_sec = 0;
	Timeout.tv_usec = 1;
	//Waiting client: set timeout to 1 usec for non-blocking 
	nRetVal = select(((INT32)sServerLog) + 1, &Socks, NULL, NULL, &Timeout); 
	if (nRetVal == 0)
	{	
		*pnErrCode = XGetErrno();
		return ERR_TIMEOUT;
	}
	else if (nRetVal == -1)	//SOCKET_ERROR
	{
		*pnErrCode = XGetErrno();
		return ERR_SELECT;
	}

	log_on_read_error(sServerLog, (CHAR*)&Peer, sizeof(Peer), "Receiving peer data", LAB_ERR_RECEIVE);

	//Reset Control socket
	close2(sCtrl);
	//Assign the address family of of CTRL SERVER
	//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
	act_on_error(sCtrl = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP), "Creating control channel socket", goto LAB_ERR_CREATE_SOCKET);
	act_on_error(nRetVal = connect(sCtrl, (struct sockaddr *)&AddrCtrl, sizeof(AddrCtrl)), "Connecting to server", goto LAB_ERR_CONNECT);
	//Sync with peer
	readtimeout(sCtrl, Socks, nTimeoutSec, LAB_ERR_ECHO_TIMEOUT);
	log_on_Xread_error(sCtrl,&nOne,sizeof(nOne),"Receiving echo", LAB_ERR_SYN_RECEIVE);
	log_on_Xwrite_error(sCtrl, &nOne, sizeof(nOne), "Sending echo", LAB_ERR_SYN_SEND);
	readtimeout(sCtrl, Socks, nTimeoutSec, LAB_ERR_ECHO_TIMEOUT);
	log_on_Xread_error(sCtrl,&nOne,sizeof(nOne),"Receiving echo", LAB_ERR_SYN_RECEIVE);

	nRetVal = XAsymServer(sServerLog, sCtrl, psListen, pAddrPeer, ASYM_TIMEOUT, &nAsymErrCode); 
	if (nRetVal != ERR_NONE)
	{
		//Todo: The error code should be recorded.
		*pnErrCode = nRetVal;
		close2(sCtrl);		//need to close???
		return ERR_ASYMSERVER;
	}
	else
	{
		close2(sCtrl);
		return ERR_NONE;
	}

LAB_ERR_RECEIVE:
	*pnErrCode = XGetErrno();
	return ERR_RECEIVE;

LAB_ERR_CREATE_SOCKET:
	*pnErrCode = XGetErrno();
	return ERR_CREATE_SOCKET;

LAB_ERR_CONNECT:
	close2(sCtrl);
	*pnErrCode = XGetErrno();
	return ERR_CONNECT;

LAB_ERR_ECHO_TIMEOUT:
	close2(sCtrl);
	*pnErrCode = XGetErrno();
	return ERR_ECHO_TIMEOUT;

LAB_ERR_SYN_RECEIVE:
	close2(sCtrl);
	*pnErrCode = XGetErrno();
	return ERR_SYN_RECEIVE;

LAB_ERR_SYN_SEND:
	close2(sCtrl);
	*pnErrCode = XGetErrno();
	return ERR_SYN_RECEIVE;
}

/***********************************************************************
 * FUNCTION:		XConnect() 
 * DESCRIPTION:  	Create a STUNT connection to a specified peer through the help of a STUNT server.
 * PARAMETERS:		
 *					->	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 32 characters long.
 *					<->	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.
 * RETURNED:		
 *					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 a asymmetric client.
 * REVISION HISTORY:
 ***********************************************************************/
INT32 XConnect(SOCKET sServerLog, CHAR *pchPeerID, SOCKET *psConnect, struct sockaddr_in *pAddrPeer, INT32 nTimeoutSec, INT32* pnErrCode)
{
	Msg MsgCon;
	Echo Peer;
    struct timeval      Timeout;
    INT32 nRetVal = 0, nCommRet = 0;
    fd_set Socks;
	SOCKET sComm = (SOCKET) -1;
    SOCKET sCtrl = (SOCKET) -1;
	struct sockaddr_in AddrComm, AddrCtrl;
	INT32 nDelay = 0, nOne = 1, nAsymErrCode = 0;
#ifndef _WIN32
	struct timeb tStart, tCurrent;	
#endif

#ifdef TEST_TIME
#ifdef _WIN32
	INT32 nStart = 0, nEnd = 0;
#endif
#endif

	//Using in macro by Saikat: 
	CHAR errbuf[128];
	SOCKET sock_logr = sServerLog;
	/////////////////////////////////////////////////////////////

	XInitSockAddr(&AddrComm, AF_INET, g_szServerIP1, SERVER_COMM_PORT, 0, 0);
	close2(sComm);
	//Create communication socket
	act_on_error(sComm = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP), "Creating communication socket", goto LAB_ERR_CREATE_SOCKET);
	//Connect to the comm

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -