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

📄 client.cpp

📁 stun的一个客户端例子
💻 CPP
📖 第 1 页 / 共 4 页
字号:
    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);

    strncpy(errbuf, "HOLE", 128);
	log_on_error(-1 == XTryConnect(sServerLog, sAuxServer, (struct sockaddr *)&AddrPeer, sizeof(AddrPeer), 1000) ? 0 : -1, "Opening hole", LAB_ERR_TRYCONNECT);
    strncpy(errbuf, "OTHER", 128);
    close2(sAuxServer);
	log_on_error(sAuxServer = socket(PF_INET, SOCK_STREAM, 0), "Creating new socket", LAB_ERR_CREATE_SOCKET);
	log_on_error(setsockopt(sAuxServer, SOL_SOCKET, SO_REUSEADDR, (char *)&nOne, sizeof(nOne)), "Setting REUSEADDR", LAB_ERR_SETSOCKOPT);
	log_on_error(bind(sAuxServer, (struct sockaddr *)&AddrClient, sizeof(AddrClient)), "Binding to local address", LAB_ERR_BIND);

    log_on_error(listen(sAuxServer, 1), "Listening on socket", LAB_ERR_LISTEN);
    strncpy(errbuf, "CONTROL", 128);
    log_on_Xwrite_error(sCtrl, &nOne, sizeof(nOne), "Ready", LAB_ERR_SEND);
	
	//HairPin Problem: do not process
	if (AddrGlobal.sin_addr.s_addr == AddrPeer.sin_addr.s_addr)
	{
		close2(sAuxServer);
		return ERR_HAIRPIN;
	}

	//waiting for connection from XAsmServer: timeout MUST be the same as XAsmServer
    readtimeout(sAuxServer, Socks, nTimeoutSec, LAB_ERR_ASYM_TIMEOUT);
    strncpy(errbuf, "ACCEPT", 128);
    log_on_error(*psConnect = accept(sAuxServer, (struct sockaddr *)&AddrPeer, &nAddrLen), "Accepting client", LAB_ERR_ACCEPT);

	if (pAddrPeer != NULL)
	{
		pAddrPeer->sin_addr.s_addr = AddrPeer.sin_addr.s_addr;
		pAddrPeer->sin_port = AddrPeer.sin_port;
	}
	close2(sAuxServer);
	return ERR_NONE;

LAB_ERR_PREDICT:
	close2(sAuxServer);
	return ERR_PREDICT;
LAB_ERR_SEND:
	close2(sAuxServer);
	*pnErrCode = XGetErrno();
	return ERR_SEND;
LAB_ERR_TIMEOUT:
	close2(sAuxServer);
	*pnErrCode = XGetErrno();
	return ERR_TIMEOUT;
LAB_ERR_RECEIVE:
	close2(sAuxServer);
	*pnErrCode = XGetErrno();
	return ERR_RECEIVE;
LAB_ERR_TRYCONNECT:
	close2(sAuxServer);
	*pnErrCode = XGetErrno();
	return ERR_TRYCONNECT;
LAB_ERR_CREATE_SOCKET:
	close2(sAuxServer);
	*pnErrCode = XGetErrno();
	return ERR_CREATE_SOCKET;
LAB_ERR_SETSOCKOPT:
	close2(sAuxServer);
	*pnErrCode = XGetErrno();
	return ERR_SETSOCKOPT;
LAB_ERR_BIND:
	close2(sAuxServer);
	*pnErrCode = XGetErrno();
	return ERR_SETSOCKOPT;
LAB_ERR_LISTEN:
	close2(sAuxServer);
	*pnErrCode = XGetErrno();
	return ERR_LISTEN;
LAB_ERR_ASYM_TIMEOUT:
	close2(sAuxServer);
	*pnErrCode = XGetErrno();
	return ERR_ASYM_TIMEOUT;
LAB_ERR_ACCEPT:
	close2(sAuxServer);
	*pnErrCode = XGetErrno();
	return ERR_ACCEPT;
}

/***********************************************************************
 * FUNCTION:		XPredict() 
 * DESCRIPTION:  	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.
 * PARAMETERS:		
 *					->	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.
 * RETURNED:
 *					ERR_NONE	Successful.
 *					ERR_FAIL	Failed in this function.
 * REVISION HISTORY:
 ***********************************************************************/
INT32 XPredict(SOCKET sServerLog, SOCKET *psAux, struct sockaddr_in *pAddrGlobal, struct sockaddr_in *pAddrLocal) 
{
    SOCKET sEcho = (SOCKET) -1;
    INT32 nOne = 1;
#ifdef _WIN32    
	INT32 nAddrLen = sizeof(struct sockaddr_in);
#else
	socklen_t nAddrLen = sizeof(struct sockaddr_in);
#endif
	UINT16 usGlobalPort = 0;
    char chBuf[256];
#ifdef _WIN32
	INT32 nStart = GetTickCount();
#else
	struct timeb tStart, tCurrent;	
	INT32 nTimeInterval = 0;
	ftime(&tStart);
#endif

	//Using in macro by Saikat: 
	SOCKET sock_logr = sServerLog;
	/////////////////////////////////////////////////////////////

	pAddrLocal->sin_family = AF_INET;
	pAddrLocal->sin_addr.s_addr = INADDR_ANY;
	pAddrLocal->sin_port = 0;

    log_on_error(sEcho = socket(PF_INET, SOCK_STREAM, 0), "Crearing prediction socket", LAB_ERR);
    log_on_error(setsockopt(sEcho,SOL_SOCKET,SO_REUSEADDR,(char *)&nOne,sizeof(nOne)), "Setting SO_REUSEADDR", LAB_ERR);
    log_on_error(bind(sEcho,(struct sockaddr *)pAddrLocal, sizeof(struct sockaddr_in)), "Binding to local address", LAB_ERR);
    log_on_error(getsockname(sEcho,(struct sockaddr *)pAddrLocal, &nAddrLen), "Retreiving local address", LAB_ERR);
    XCheckConeTCPProbe(sServerLog, sEcho, 1, (UINT32 *)&pAddrGlobal->sin_addr.s_addr, &usGlobalPort);
    close2(sEcho);
    log_on_error(sEcho = socket(PF_INET, SOCK_STREAM, 0), "Creating actual socket", LAB_ERR);
    log_on_error(setsockopt(sEcho,SOL_SOCKET,SO_REUSEADDR,(char *)&nOne,sizeof(nOne)), "Setting SO_REUSEADDR", LAB_ERR);
    log_on_error(bind(sEcho,(struct sockaddr *)pAddrLocal, sizeof(struct sockaddr_in)), "Binding to local address", LAB_ERR);

	if (g_Fingerprint.TCP.nIncrement != RANDOM_INCREMENT) 
	{
		usGlobalPort = (UINT16) (usGlobalPort + g_Fingerprint.TCP.nIncrement);
    } else 
	{
        // random. 1 is as good a random number as any
        usGlobalPort = (UINT16) (usGlobalPort + 1);
    }
    pAddrGlobal->sin_port = ntohs(usGlobalPort);
#ifdef _WIN32
    _snprintf(chBuf, 256, "PREDICT: %d.%d.%d.%d:%d -> %d.%d.%d.%d:%d [%dms]",
				IPPORT(pAddrLocal->sin_addr.s_addr, pAddrLocal->sin_port),
				IPPORT(pAddrGlobal->sin_addr.s_addr, pAddrGlobal->sin_port),
				GetTickCount()-nStart
			 );
#else
	ftime(&tCurrent);
	nTimeInterval = (int) (1000.0 * (tCurrent.time - tStart.time)
        + (tCurrent.millitm - tStart.millitm));             
    snprintf(chBuf, 256, "PREDICT: %d.%d.%d.%d:%d -> %d.%d.%d.%d:%d [%dms]",
				IPPORT(pAddrLocal->sin_addr.s_addr, pAddrLocal->sin_port),
				IPPORT(pAddrGlobal->sin_addr.s_addr, pAddrGlobal->sin_port),
				nTimeInterval
			);
#endif
    log1(sServerLog, "%s", chBuf);
    *psAux = sEcho;

    return ERR_NONE;
LAB_ERR:
    close2(sEcho);
    return ERR_FAIL;
}

/***********************************************************************
 * FUNCTION:		XTryConnect() 
 * DESCRIPTION:  	This function tries to make a connection to the destination peer.
 * PARAMETERS:
 *					->	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
 * RETURNED:			
 *					ERR_NONE	Successful.
 *					ERR_FAIL	Failed in this function.
 * REVISION HISTORY:
 ***********************************************************************/
INT32 XTryConnect(SOCKET sServerLog, SOCKET sAuxServer, struct sockaddr *pAddrPeer, INT32 nAddrPeerLen, INT32 nMiliSec) 
{
	struct sockaddr_in AnyAddr;
    INT32 nRetVal = 0;
#ifdef _WIN32
	OVERLAPPED OverLapped;
    DWORD       dwErr = 0;
    DWORD       dwBytes = 0;
    LPFN_CONNECTEX lpfnConnectEx = NULL;
    GUID           GuidConnectEx = WSAID_CONNECTEX;
#else
    fd_set Socks;
	struct timeval	Timeout;
#endif
	//Using in macro by Saikat: 
	SOCKET sock_logr = sServerLog;
	/////////////////////////////////////////////////////////////


	AnyAddr.sin_family = AF_INET;
    AnyAddr.sin_addr.s_addr = INADDR_ANY;
    AnyAddr.sin_port = 0;

#ifdef _WIN32	
	memset(&OverLapped, 0, sizeof(OverLapped));
    OverLapped.hEvent = CreateEvent(NULL, true, true, NULL);

	dwErr = WSAIoctl(sAuxServer,
        SIO_GET_EXTENSION_FUNCTION_POINTER,
        &GuidConnectEx,
        sizeof(GuidConnectEx),
        &lpfnConnectEx,
        sizeof(lpfnConnectEx),
        &dwBytes,
        NULL,
        NULL); 
    if (dwErr == -1) 
		goto LAB_ERR;

    bind(sAuxServer, (struct sockaddr *)&AnyAddr, sizeof(struct sockaddr_in));
    dwErr = lpfnConnectEx(sAuxServer, pAddrPeer, nAddrPeerLen, NULL, 0, &dwBytes, &OverLapped);
    if (dwErr == -1) 
	{
		goto LAB_ERR;
	}

    if (WaitForSingleObject(OverLapped.hEvent, nMiliSec) == WAIT_TIMEOUT) 
	{
        close2(sAuxServer);
        WSASetLastError(WSAETIMEDOUT);
        goto LAB_ERR;
    }
    nRetVal = GetOverlappedResult(OverLapped.hEvent, &OverLapped, &dwBytes, false);
    if (!nRetVal) 
	{
        switch(WSAGetLastError()) 
		{
            case 121: WSASetLastError(WSAETIMEDOUT); break;
            case 1225: WSASetLastError(WSAECONNREFUSED); break;
            default: log_on_error(-1, "GetOverlappedResult", LAB_ERR);
        }
        goto LAB_ERR;
    }
    return ERR_NONE;
#else
	bind(sAuxServer, (struct sockaddr *)&AnyAddr, sizeof(struct sockaddr_in));
	fcntl(sAuxServer, F_SETFL, O_NONBLOCK);
	if (-1 == connect(sAuxServer, pAddrPeer, nAddrPeerLen))
	{	
		if (errno != 115) //would block
			goto LAB_ERR;
	}
	FD_ZERO(&Socks);
	FD_SET(sAuxServer, &Socks);
	Timeout.tv_sec = 1;
	Timeout.tv_usec = 0;
	nRetVal = select(((INT32)sAuxServer) + 1, NULL, &Socks, NULL, &Timeout); 
	if (nRetVal == 0 || nRetVal == -1) //Timeout or SOCKET_ERROR
		goto LAB_ERR;
	else
	{
		return ERR_NONE;
	}
#endif

LAB_ERR:
    return ERR_FAIL;
}

/***********************************************************************
 * FUNCTION:		XProbe() 
 * DESCRIPTION:  	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.
 * PARAMETERS:		-> sServerLog: The STUNT server socket. This must be a valid socket connecting
 *									with STUNT server.
 * RETURNED:		ERR_NONE: successful
 *					ERR_FAIL: failed
 * REVISION HISTORY:
 ***********************************************************************/
INT32 XProbe(SOCKET sServerLog) 
{
#ifdef _WIN32
	OSVERSIONINFOEX OSVer;
#endif
	char chBuf[128];
    char chPrint[MAX_FINGERPRINT_LEN];
    INT32 nErr = ERR_FAIL;
#ifdef _WIN32
    ZeroMemory(&OSVer, sizeof(OSVERSIONINFOEX));
    OSVer.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
    if( !GetVersionEx((OSVERSIONINFO *)&OSVer)) 
	{
        OSVer.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
        if (!GetVersionEx((OSVERSIONINFO *)&OSVer)) 
		{
			//set all zeros
			OSVer.dwPlatformId = 0; 
			OSVer.dwMajorVersion = 0;
			OSVer.dwMinorVersion = 0;
			OSVer.wServicePackMajor = 0;
			OSVer.wServicePackMinor = 0;
        }
    }
    _snprintf(chBuf, 128, "START %s: WIN32 %d.%d.%d.%d.%d, %s", 
        g_chClientID,
		OSVer.dwPlatformId,
        OSVer.dwMajorVersion,
        OSVer.dwMinorVersion,
        OSVer.wServicePackMajor,
        OSVer.wServicePackMinor,
        BUILD);
#else
    snprintf(chBuf, 128, "START %s: NON_WIN32, %s", g_chClientID, BUILD);
#endif

    log1(sServerLog, "%s", chBuf);

    if (XProbeNAT(sServerLog) == ERR_FAIL) 
	{
        nErr = ERR_FAIL;
    }
	else
	{
		g_Fingerprint.nServerVer = g_nServerVersion;
		g_Fingerprint.nClientVer = BUILD_VER;
		strcpy(g_Fingerprint.chID, g_chClientID);
		g_Fingerprint.nDone = true;
		XGenFingerprint(chPrint,MAX_FINGERPRINT_LEN);
		log1(sServerLog, "FINGERPRINT: %s", chPrint);
		g_Fingerprint.nGAddr = g_nClientIP;		
		if (XWriteFingerprint(sServerLog) == ERR_FAIL) 
			nErr = ERR_FAIL;
		else
			nErr = ERR_NONE;
	}

	if (nErr == ERR_FAIL) 
	{
		g_Fingerprint.nDone = false;
    }
    return nErr;
}

/***********************************************************************
 * FUNCTION:		XProbeNAT() 
 * DESCRIPTION:  	This is a wrap of XCheckConeTCP(). It just controls the retry times and sleeping time.
 * PARAMETERS:		-> sServerLog: The STUNT server socket. This must be a valid socket connecting
 *									with STUNT server.
 * RETURNED:		ERR_NONE: successful
 *					ERR_FAIL: failed after all retries
 * REVISION HISTORY:
 ***********************************************************************/
INT32 XProbeNAT(SOCKET sServerLog) 
 {
     INT32 nRetry = 0;

     if (XCheckConeTCP(sServerLog) == ERR_FAIL) 
	 { 
		 nRetry++; 
#ifdef _WIN32
		 Sleep(PROBE_FAIL_SLEEP_SEC * 1000); 
#else
		 XSleep(0, PROBE_FAIL_SLEEP_SEC * 1000);
#endif
		 if (nRetry == PROBE_RETRY_TIMES) 
			return ERR_FAIL;
	 }

     return ERR_NONE;
 }


/***********************************************************************
 * FUNCTION:		XCheckConeTCP() 
 * DESCRIPTION:  	This function check NAT's TCP port mapping characteristics. It's a wrap of
 *					XCheckConeTCPProbe() and XAnalyzeNature(). 
 * PARAMETERS:		-> sServerLog: The STUNT server socket. This must be a valid socket connecting
 *									with STUNT server.
 * RETURNED:		ERR_NONE: successful
 *					ERR_FAIL: failed
 * REVISION HISTORY:
 ***********************************************************************/
INT32 XCheckConeTCP(SOCKET sServerLog) 
{
    SOCKET sEcho;
    struct sockaddr_in AddrLocal;
    INT32 nOne = 1;
    INT32 i = 0;
    INT32 nAddrLocalLen = sizeof(AddrLocal);
    UINT16 uwTryBindPort = 1024;
    UINT32 unAddrGlobal[4];
    UINT16 uwPortLocal[4];
    UINT16 uwPortGlobal[4];
    INT32 nErr = ERR_FAIL;

	//Using in macro by Saikat: 
	SOCKET sock_logr = sServerLog;
	/////////////////////////////////////////////////////////////

⌨️ 快捷键说明

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