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

📄 csclient.cpp

📁 mysee网络直播源代码Mysee Lite是Mysee独立研发的网络视频流媒体播放系统。在应有了P2P技术和一系列先进流媒体技术之后
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*
 *  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 "CSClient.h"
#include "Communicator.h"


namespace NPLayer1 {

CSClient::CSClient(Communicator* c) :comm(c) {
	memset(recvBuf, 0, MAX_UDP_LEN);
	maxFailCount = MAX_LOGIN_FAIL_COUNT;
	bStopLogin = false;
}

CSClient::~CSClient() {
	if(m_Socket != INVALID_SOCKET)
		closesocket(m_Socket);
}

P2P_RETURN_TYPE CSClient::Init() {
	// 初始化成员
	m_Socket = INVALID_SOCKET;
	isReqResSucceed = false;
	content = recvBuf;

	isLogin = false;
	loginFailCount = 0;

	// Create UDP Socket
	m_Socket = socket(AF_INET, SOCK_DGRAM, 0);
	if (m_Socket == INVALID_SOCKET) {
		comm->logFile.StatusErr("Creating UDP socket", WSAGetLastError());
		return PRT_NET;
	}

	// SO_EXCLUSIVEADDRUSE is only supported in 2000/XP/2003 and higher OS.
	if(comm->osvi.dwMajorVersion > 5) {
		// 防止窃听, 设定独占端口
		BOOL bExAddrUse = TRUE;
		if(setsockopt(m_Socket, SOL_SOCKET, ((int)(~SO_REUSEADDR)), (const char*)&bExAddrUse, sizeof(BOOL)) == SOCKET_ERROR) {
			comm->logFile.StatusErr("Setting UDP socket as SO_EXCLUSIVEADDRUSE", WSAGetLastError());
			return PRT_NET;
		}
	}

	//int newSize = SO_MAX_MSG_SIZE*100;
	//setsockopt(m_Socket, SOL_SOCKET, SO_RCVBUF, (const char*)&newSize, sizeof(int));
	//setsockopt(m_Socket, SOL_SOCKET, SO_SNDBUF, (const char*)&newSize, sizeof(int));

	sockaddr_in addr;
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	// 绑定所有本机IP
	addr.sin_addr.s_addr = INADDR_ANY;
	
	USHORT port = 0;
	for(int i = 0; i < 1000; ++i) {
		port = static_cast<USHORT>(rand(&comm->ctx))%10000 + 50000;
		
		addr.sin_port = htons(port);
		if(bind(m_Socket, (sockaddr*)&addr, sizeof(addr)) != SOCKET_ERROR)
			break;
		comm->logFile.StatusOut("Bind UDP socket at port %d. Failed", port);
	}
	if(i == 1000)
		return PRT_INIT_BIND;

	comm->logFile.StatusOut("Bind UDP socket at port %d.", port);
	
	return PRT_OK;
}

BOOL CSClient::ParseMsg(sockaddr_in& addr, int& addrlen) {
	CriticalSection::Owner lock(sendCS);
	int recvSize = recvfrom(m_Socket, recvBuf, MAX_UDP_LEN, 0, (sockaddr*)&addr, &addrlen);
	if(recvSize == SOCKET_ERROR)
		return FALSE;

	// 如果来源地址不是TS,就返回
	if(memcmp(&addr, &comm->trackerIP, sizeof(comm->trackerIP)) != 0)
		return FALSE;

	// 如果过小,则不是正常的包
	if(recvSize < sizeof(UINT)+sizeof(UINT8))
		return FALSE;

	// 把移动指针放到数据的起始地址
	content = recvBuf;
	
	// 读取消息大小
	UINT msgSize;
	CopyMoveSrc(&msgSize, content, sizeof(msgSize));
	if(msgSize != recvSize)
		return FALSE;
	
	// 读取消息类型
	UINT8 msgType;
	CopyMoveSrc(&msgType, content, sizeof(msgType));

	if(!SwitchMsg(msgType)) {
		// 重新登录
		SendLogout();
		SendLogin();
		return FALSE;
	}
	return TRUE;
}

BOOL CSClient::SwitchMsg(UINT8 msgType) {
	switch(msgType) {
		case TS2NP_WELCOME:
			if(!OnWelcome())
				return FALSE;
			break;
		case TS2NP_PEERS:
			if(!OnPeers())
				return FALSE;
			break;
		case TS2NP_CONNECT_TO:
			if(!OnConnectTo())
				return FALSE;
			break;
		case TS2NP_RESINFO:
			if(!OnResInfo())
				return FALSE;
			break;
		case TS2NP_MSG:
			if(!OnMsg())
				return FALSE;
			break;
		default:
			return FALSE;
	}
	return TRUE;
}

BOOL CSClient::OnWelcome() {
	// 复制验证码
   	CopyMoveSrc(checkCode, content, 7);
	// 复制本机地址
	CopyMoveSrc(&comm->localAddress, content, sizeof(comm->localAddress));

	assert(comm->localAddress.outerIP.sin_addr.s_addr != 0);

	comm->logFile.StatusOut("CSClient Logon TS...%s", comm->p2pMgr.FormatIPAddress(comm->localAddress));

	isLogin = true;
	loginFailCount = 0;

	lastRecvPeers = timeGetTime();

	// 如果当前资源没有告知TS,则发送ReqRes
	if(!isReqResSucceed && comm->currRes) {
		SendReqRes();
	}

	return TRUE;
}
BOOL CSClient::OnPeers() {
	// 是否需要尝试连接CP
	bool tryCP = false;

	// 复制CP地址个数
	UINT8 listSize = 0;
	CopyMoveSrc(&listSize, content, sizeof(listSize));
	if(listSize > 0 && listSize < 100) {
		// 复制CP地址
		for(UINT8 i = 0; i < listSize; ++i) {
			PeerInfoWithAddr nAddr;
			CopyMoveSrc(&nAddr.outerIP, content, sizeof(NormalAddress));
			nAddr.subnetIP.sin_addr.s_addr = 0xffffffff;
			nAddr.subnetIP.sin_port = nAddr.outerIP.sin_port;
			comm->logFile.StatusOut("CSClient got CP address %s...", comm->p2pMgr.FormatIPAddress(nAddr));
			nAddr.layer = 0;
			nAddr.isCachePeer = true;

			if(nAddr.outerIP.sin_addr.s_addr != 0) {
				comm->p2pMgr.AddPeerInfo(nAddr);
				// 如果得到CP地址,就尝试连接
				tryCP = true;
			}
		}
	}

	// 复制NP地址个数
	CopyMoveSrc(&listSize, content, sizeof(listSize));
	if(listSize > 0 && listSize < 100) {
		for(UINT8 i = 0; i < listSize; ++i) {
			PeerInfoWithAddr nAddr;
			CopyMoveSrc(&nAddr, content, sizeof(nAddr));
			assert(nAddr.outerIP.sin_addr.s_addr != 0);
			nAddr.isCachePeer = false;
			// put in known np list
			comm->p2pMgr.AddPeerInfo(nAddr);
		}
		comm->logFile.StatusOut("CSClient got %d NP.", listSize);
	}

	lastRecvPeers = timeGetTime();

	// 尝试连接CP
	if(tryCP)
		comm->tryClient.Try();
	return TRUE;
}

BOOL CSClient::OnConnectTo() {
	// 复制NP的地址
	P2PAddress nAddr;
	CopyMoveSrc(&nAddr, content, sizeof(nAddr));
	// 是否使用free outgoing
	bool connectForFree;
	CopyMoveSrc(&connectForFree, content, sizeof(connectForFree));
	// add to connectto peer list
	comm->p2pMgr.AddConnectTo(nAddr, connectForFree);

	comm->logFile.StatusOut("CSClient got ConnectTo.");
	return TRUE;
}

BOOL CSClient::OnResInfo() {
	// TODO: 接收返回的资源信息
	return TRUE;
}

BOOL CSClient::OnMsg() {
	// 复制错误代码
	UINT16 errCode;
	CopyMoveSrc(&errCode, content, sizeof(errCode));

	// 是否需要退出
	bool shouldQuit;
	CopyMoveSrc(&shouldQuit, content, sizeof(shouldQuit));

	// 是否不能继续登录
	bool bShouldStopLogin = false;

	// 根据错误代码处理
	switch(errCode) {
	case ERR_PROTOCOL_FORMAT:
		comm->logFile.StatusOut("TS sent ERR_PROTOCOL_FORMAT error!");
		bShouldStopLogin = true;
		break;
	case ERR_AUTHORIZATION:
		comm->logFile.StatusOut("TS sent ERR_AUTHORIZATION error!");
		bShouldStopLogin = true;
		break;
	case ERR_INTERNAL:
		comm->logFile.StatusOut("TS sent ERR_INTERNAL error!");
		break;
	case ERR_LOW_VERSION:
		comm->logFile.StatusOut("TS sent ERR_LOW_VERSION error!");
		// 发送版本太低的消息给外界
		comm->PostErrMessage(PNT_LOW_VERSION, 0, true);
		bShouldStopLogin = true;
		break;
	case ERR_NO_SUCH_PEER:
		comm->logFile.StatusOut("TS sent ERR_NO_SUCH_PEER error!");
		break;
	case ERR_NO_SUCH_RES:
		comm->logFile.StatusOut("TS sent ERR_NO_SUCH_RES error!");
		break;
	case ERR_CHECK_BYTES:
		comm->logFile.StatusOut("TS sent ERR_CHECK_BYTES error!");
		break;
	case ERR_ADD_RES_OK:
		// 请求资源成功!
		isReqResSucceed = true;
		comm->logFile.StatusOut("TS sent ERR_ADD_RES_OK!");

		// 发送第一次Report
		SendReport(true);
		break;
	default:
		shouldQuit = true;
	}
	if(shouldQuit) {
		isLogin = false;
		loginFailCount = 0;
	}
	if(bShouldStopLogin)
		bStopLogin = true;

	return TRUE;
}

void CSClient::SendLogin() {
	CriticalSection::Owner lock(sendCS);
	if(isLogin)
		return;
	if(bStopLogin)
		return;

	if(!SendBegin(NP2TS_LOGIN))
		return;

	// 用户ID和密码
	CopyMoveDes(content, &comm->userID, sizeof(comm->userID));
	CopyMoveDes(content, comm->userPass, MD5_LEN);

	// 版本号和监听端口
	CopyMoveDes(content, &comm->cfgData.COMMUNICATOR_VERSION, 
		sizeof(comm->cfgData.COMMUNICATOR_VERSION));
	// 写入监听端口
	CopyMoveDes(content, &comm->localAddress.subnetIP.sin_port, sizeof(comm->localAddress.subnetIP.sin_port));
	
	// 本机IP列表
	in_addr* addrList = NULL;
	UINT8 ipSize = GetLocalIPList(addrList);
	if(ipSize == 0) {
		comm->logFile.StatusErr("Get Local IP List", WSAGetLastError());
		return;
	}
	CopyMoveDes(content, &ipSize, sizeof(ipSize));
	CopyMoveDes(content, addrList, ipSize*sizeof(in_addr));
	delete [] addrList;
	addrList = NULL;

	comm->logFile.StatusOut("CSClient sent NP2TS_LOGIN.");
	isReqResSucceed = false;
	
	if(loginFailCount == 2) {
		// 两次登录失败,设置默认CP地址
		if(comm->currRes)
			comm->currRes->SetDefaultCP();
	}

	loginFailCount++;
	if(loginFailCount == maxFailCount) {
		// 发送登陆失败的消息给外界
		comm->PostErrMessage(PNT_CANNOT_LOGON_TS, 0, true);
		loginFailCount = 0;
		// 按MAX_LOGIN_FAIL_COUNT倍递增
		maxFailCount *= MAX_LOGIN_FAIL_COUNT;
	}
	

⌨️ 快捷键说明

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