📄 localpeerfinder.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 + -