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

📄 localpeerfinder.cpp

📁 mysee网络直播源代码Mysee Lite是Mysee独立研发的网络视频流媒体播放系统。在应有了P2P技术和一系列先进流媒体技术之后
💻 CPP
字号:
/*
 *  Openmysee
 *
 *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
#include "stdafx.h"
#include "LocalPeerFinder.h"
#include "Communicator.h"


namespace NPLayer1 {

static const USHORT BINDPORTS[]	= {32226, 32432, 33895, 42931, 44432, 
	46585, 50330, 54625, 55993, 56605 };

LocalPeerFinder::LocalPeerFinder(Communicator *c): comm(c) {
	m_Socket = INVALID_SOCKET;
	isRunning = FALSE;
}

P2P_RETURN_TYPE LocalPeerFinder::Init() {
	if (!isRunning) {
		P2P_RETURN_TYPE ret = Binding();
		if (ret < PRT_OK) {
			return ret;
		}

		isRunning = TRUE;
	}

	return PRT_OK;
}

P2P_RETURN_TYPE LocalPeerFinder::Binding() {
	m_Socket = WSASocket(AF_INET, SOCK_DGRAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
	if (m_Socket == INVALID_SOCKET) {
		comm->logFile.StatusErr("Creating listening socket", WSAGetLastError());
		return PRT_NET;
	}

	// Set this socket as a Non-blocking socket.
	ULONG flag = 1;
	if (ioctlsocket(m_Socket, FIONBIO, &flag) == -1) {
		comm->logFile.StatusErr("Setting listening socket as non-blocking", WSAGetLastError());
		return PRT_NET;
	}
	// Enable broadcasting
	BOOL bOptVal = TRUE;
	if (setsockopt(m_Socket, SOL_SOCKET, SO_BROADCAST, (char*)&bOptVal, sizeof(BOOL)) == SOCKET_ERROR) {
		comm->logFile.StatusErr("Enable UDP broadcasting error", WSAGetLastError());
		return PRT_NET;
	}

	// Associate the local address with m_Socket.
	sockaddr_in addr;
	memset(&addr, 0, sizeof(sockaddr_in));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = htonl(INADDR_ANY);

	ULONG port = 0;
	for (int i = 0; i < sizeof(BINDPORTS)/sizeof(USHORT); ++i) {
		addr.sin_port = htons(BINDPORTS[i]);
		if (bind(m_Socket, (sockaddr*)&addr, sizeof(addr)) != SOCKET_ERROR) {
			port = BINDPORTS[i];
			break;
		}
	}
	if (!port) {
		comm->logFile.StatusErr("Failed to bind all possible ports.", WSAGetLastError());
		return PRT_INIT_BIND;
	} else {
		comm->logFile.StatusOut("Binding LocalPeerFinder's UDP socket at %d", port);
		return PRT_OK;
	}
}

P2P_RETURN_TYPE LocalPeerFinder::SendBroadcast() {
	for (int i = 0; i < sizeof(BINDPORTS)/sizeof(USHORT); ++i) {
		SendSelfInfo(BINDPORTS[i]);
	}

	return PRT_OK;
}

P2P_RETURN_TYPE LocalPeerFinder::SendSelfInfo(USHORT port) {
	// 如果当前看的频道为空或者尚未登陆到Tracker,则不发送信息
	if (!comm->currRes || !comm->csClient.GetIsLogin())
		return PRT_OK;

	const ULONG BROARDADDR = 0xFFFFFFFF;
	sockaddr_in dst;
	memset(&dst, 0, sizeof(dst));
	dst.sin_family = AF_INET;
	dst.sin_addr.s_addr = BROARDADDR;
	dst.sin_port = htons(port);

	// build packet
	LocalPeerInfo myInfo;
	memset(&myInfo, 0, sizeof(LocalPeerInfo));
	myInfo.version = comm->cfgData.COMMUNICATOR_VERSION;
	memcpy(static_cast<P2PAddress*>(&myInfo.peerInfo), &comm->localAddress, sizeof(comm->localAddress));
	comm->p2pMgr.GetSelfInfo(myInfo.peerInfo);
	memcpy(&myInfo.channel, comm->currRes->GetHashCode().c_str(), MD5_LEN);
	MD5 md5(reinterpret_cast<BYTE*>(&myInfo), sizeof(LocalPeerInfo) - MD5_LEN);
	char *tmp = md5.hex_digest();
	memcpy(&myInfo.checksum, tmp, MD5_LEN);
	delete[] tmp;

	int ret = sendto(m_Socket, (const char*)&myInfo, sizeof(LocalPeerInfo), 
		0, (SOCKADDR *)&dst, sizeof(dst));
	if (ret == SOCKET_ERROR) {
		comm->logFile.StatusErr("Error when broadcast, rebind udp socket", WSAGetLastError());

		isRunning = FALSE;
		P2P_RETURN_TYPE ret = Binding();
		if (ret < PRT_OK) {
			return ret;
		}
		isRunning = TRUE;

		return PRT_NET;
	} else {
		return PRT_OK;
	}
}

P2P_RETURN_TYPE LocalPeerFinder::ReadBroadcast() {
	struct sockaddr_in from;
	int fromlen = sizeof(from);
	LocalPeerInfo peerInfo;

	memset(&peerInfo, 0, sizeof(LocalPeerInfo));
	int recvSize = recvfrom(m_Socket, (char *)&peerInfo, sizeof(LocalPeerInfo), 0, (SOCKADDR *)&from, &fromlen);
	if (recvSize == SOCKET_ERROR) {
		comm->logFile.StatusErr("Error when recvfrom:", WSAGetLastError());
		return PRT_NET;
	} else if (recvSize != sizeof(LocalPeerInfo)) {
		comm->logFile.StatusOut("Broadcast packet length error: %d", recvSize);
		return PRT_OK;
	}

	comm->logFile.StatusOut("LocalPeerFinder, got a broadcast from %s, length: %d", 
		inet_ntoa(from.sin_addr), recvSize);

	// 检查 checksum
	MD5 md5(reinterpret_cast<BYTE*>(&peerInfo), sizeof(LocalPeerInfo) - MD5_LEN);
	char *tmp = md5.hex_digest();
	bool md5OK = (memcmp(tmp, &peerInfo.checksum, MD5_LEN) == 0);
	delete[] tmp;
	if (!md5OK) {
		comm->logFile.StatusOut("LocalPeerFinder, recv a packet from %s with an invalid checksum.", inet_ntoa(from.sin_addr));
		return PRT_OK;
	}

	if (comm->currRes != NULL && memcmp(comm->currRes->GetHashCode().c_str(), peerInfo.channel, MD5_LEN) == 0) { // 必须是同一个 channel

		comm->logFile.StatusOut("LocalPeerFinder, got a LAN peer %s",  comm->p2pMgr.FormatIPAddress(peerInfo.peerInfo));

		if(comm->localAddress.outerIP.sin_addr.s_addr == 0) {
			// 不知道自己的IP,只好这样:把对方的外网IP作为自己的外网IP,再获取自己的内网IP
			comm->localAddress.outerIP.sin_addr.s_addr = peerInfo.peerInfo.outerIP.sin_addr.s_addr;
			comm->localAddress.outerIP.sin_port = 0;	// 不知道外网Port
			
			comm->localAddress.subnetIP.sin_addr.s_addr = DetectInnerAddr();//检查本机的内网地址
			assert(comm->localAddress.subnetIP.sin_addr.s_addr != 0);
		}

		comm->p2pMgr.AddPeerInfo(peerInfo.peerInfo);
	}

	return PRT_OK;
}

void LocalPeerFinder::Uninit() {
	if (isRunning) {
		isRunning = FALSE;

		// 结束 Socket
		comm->p2pMgr.SafeCloseSocket(m_Socket);
	}
}


LocalPeerFinder::~LocalPeerFinder() {
	Uninit();

	comm->logFile.StatusOut("LocalPeerFinder: exited...");
}

DWORD LocalPeerFinder::DetectInnerAddr() {
	// Get local host name
	char szHostName[128] = "";
	if(gethostname(szHostName, sizeof(szHostName)))
		return 0;

	// Get local IP addresses
	hostent *pHost = 0;
	if((pHost = gethostbyname(szHostName)) == NULL)
		return 0;

	DWORD tempIP;
	BYTE temp;
	for(int i = 0; (pHost->h_addr_list[i]); ++i) {
		memcpy(&tempIP, pHost->h_addr_list[i], sizeof(tempIP));
		/*
		 * 类 IP地址范围           网络数 
		 * A 10.0.0.0---10.255.255.255     1 
		 * B 172.16.0.0---172.31.255.255    16 
		 * C 192.168.0.0---192.168.255.255   255 
		 */
		BOOL isNATAddr = FALSE;
		memcpy(&temp, &tempIP, 1);
		if(temp == 10) // A 类
			isNATAddr = TRUE;
		else if(temp == 192) {
			memcpy(&temp, (char*)(&tempIP)+1, 1);
			if(temp == 168) // B 类
				isNATAddr = TRUE;
		}
		else if(temp == 172) {
			memcpy(&temp, (char*)(&tempIP)+1, 1);
			if(temp >= 16 && temp <= 31) // C 类
				isNATAddr = TRUE;
		}

		// 返回内网IP
		if(isNATAddr)
			return tempIP;
	}
	return 0;
}

}

⌨️ 快捷键说明

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