CSClient.cpp
上传用户:liguizhu
上传日期:2015-11-01
资源大小:2422k
文件大小:18k
源码类别:

P2P编程

开发平台:

Visual C++

  1. /*
  2.  *  Openmysee
  3.  *
  4.  *  This program is free software; you can redistribute it and/or modify
  5.  *  it under the terms of the GNU General Public License as published by
  6.  *  the Free Software Foundation; either version 2 of the License, or
  7.  *  (at your option) any later version.
  8.  *
  9.  *  This program is distributed in the hope that it will be useful,
  10.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  *  GNU General Public License for more details.
  13.  *
  14.  *  You should have received a copy of the GNU General Public License
  15.  *  along with this program; if not, write to the Free Software
  16.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  17.  *
  18.  */
  19. #include "StdAfx.h"
  20. #include "CSClient.h"
  21. #include "Communicator.h"
  22. namespace NPLayer1 {
  23. CSClient::CSClient(Communicator* c) :comm(c) {
  24. memset(recvBuf, 0, MAX_UDP_LEN);
  25. maxFailCount = MAX_LOGIN_FAIL_COUNT;
  26. bStopLogin = false;
  27. }
  28. CSClient::~CSClient() {
  29. if(m_Socket != INVALID_SOCKET)
  30. closesocket(m_Socket);
  31. }
  32. P2P_RETURN_TYPE CSClient::Init() {
  33. // 初始化成员
  34. m_Socket = INVALID_SOCKET;
  35. isReqResSucceed = false;
  36. content = recvBuf;
  37. isLogin = false;
  38. loginFailCount = 0;
  39. // Create UDP Socket
  40. m_Socket = socket(AF_INET, SOCK_DGRAM, 0);
  41. if (m_Socket == INVALID_SOCKET) {
  42. comm->logFile.StatusErr("Creating UDP socket", WSAGetLastError());
  43. return PRT_NET;
  44. }
  45. // SO_EXCLUSIVEADDRUSE is only supported in 2000/XP/2003 and higher OS.
  46. if(comm->osvi.dwMajorVersion > 5) {
  47. // 防止窃听, 设定独占端口
  48. BOOL bExAddrUse = TRUE;
  49. if(setsockopt(m_Socket, SOL_SOCKET, ((int)(~SO_REUSEADDR)), (const char*)&bExAddrUse, sizeof(BOOL)) == SOCKET_ERROR) {
  50. comm->logFile.StatusErr("Setting UDP socket as SO_EXCLUSIVEADDRUSE", WSAGetLastError());
  51. return PRT_NET;
  52. }
  53. }
  54. //int newSize = SO_MAX_MSG_SIZE*100;
  55. //setsockopt(m_Socket, SOL_SOCKET, SO_RCVBUF, (const char*)&newSize, sizeof(int));
  56. //setsockopt(m_Socket, SOL_SOCKET, SO_SNDBUF, (const char*)&newSize, sizeof(int));
  57. sockaddr_in addr;
  58. memset(&addr, 0, sizeof(addr));
  59. addr.sin_family = AF_INET;
  60. // 绑定所有本机IP
  61. addr.sin_addr.s_addr = INADDR_ANY;
  62. USHORT port = 0;
  63. for(int i = 0; i < 1000; ++i) {
  64. port = static_cast<USHORT>(rand(&comm->ctx))%10000 + 50000;
  65. addr.sin_port = htons(port);
  66. if(bind(m_Socket, (sockaddr*)&addr, sizeof(addr)) != SOCKET_ERROR)
  67. break;
  68. comm->logFile.StatusOut("Bind UDP socket at port %d. Failed", port);
  69. }
  70. if(i == 1000)
  71. return PRT_INIT_BIND;
  72. comm->logFile.StatusOut("Bind UDP socket at port %d.", port);
  73. return PRT_OK;
  74. }
  75. BOOL CSClient::ParseMsg(sockaddr_in& addr, int& addrlen) {
  76. CriticalSection::Owner lock(sendCS);
  77. int recvSize = recvfrom(m_Socket, recvBuf, MAX_UDP_LEN, 0, (sockaddr*)&addr, &addrlen);
  78. if(recvSize == SOCKET_ERROR)
  79. return FALSE;
  80. // 如果来源地址不是TS,就返回
  81. if(memcmp(&addr, &comm->trackerIP, sizeof(comm->trackerIP)) != 0)
  82. return FALSE;
  83. // 如果过小,则不是正常的包
  84. if(recvSize < sizeof(UINT)+sizeof(UINT8))
  85. return FALSE;
  86. // 把移动指针放到数据的起始地址
  87. content = recvBuf;
  88. // 读取消息大小
  89. UINT msgSize;
  90. CopyMoveSrc(&msgSize, content, sizeof(msgSize));
  91. if(msgSize != recvSize)
  92. return FALSE;
  93. // 读取消息类型
  94. UINT8 msgType;
  95. CopyMoveSrc(&msgType, content, sizeof(msgType));
  96. if(!SwitchMsg(msgType)) {
  97. // 重新登录
  98. SendLogout();
  99. SendLogin();
  100. return FALSE;
  101. }
  102. return TRUE;
  103. }
  104. BOOL CSClient::SwitchMsg(UINT8 msgType) {
  105. switch(msgType) {
  106. case TS2NP_WELCOME:
  107. if(!OnWelcome())
  108. return FALSE;
  109. break;
  110. case TS2NP_PEERS:
  111. if(!OnPeers())
  112. return FALSE;
  113. break;
  114. case TS2NP_CONNECT_TO:
  115. if(!OnConnectTo())
  116. return FALSE;
  117. break;
  118. case TS2NP_RESINFO:
  119. if(!OnResInfo())
  120. return FALSE;
  121. break;
  122. case TS2NP_MSG:
  123. if(!OnMsg())
  124. return FALSE;
  125. break;
  126. default:
  127. return FALSE;
  128. }
  129. return TRUE;
  130. }
  131. BOOL CSClient::OnWelcome() {
  132. // 复制验证码
  133.     CopyMoveSrc(checkCode, content, 7);
  134. // 复制本机地址
  135. CopyMoveSrc(&comm->localAddress, content, sizeof(comm->localAddress));
  136. assert(comm->localAddress.outerIP.sin_addr.s_addr != 0);
  137. comm->logFile.StatusOut("CSClient Logon TS...%s", comm->p2pMgr.FormatIPAddress(comm->localAddress));
  138. isLogin = true;
  139. loginFailCount = 0;
  140. lastRecvPeers = timeGetTime();
  141. // 如果当前资源没有告知TS,则发送ReqRes
  142. if(!isReqResSucceed && comm->currRes) {
  143. SendReqRes();
  144. }
  145. return TRUE;
  146. }
  147. BOOL CSClient::OnPeers() {
  148. // 是否需要尝试连接CP
  149. bool tryCP = false;
  150. // 复制CP地址个数
  151. UINT8 listSize = 0;
  152. CopyMoveSrc(&listSize, content, sizeof(listSize));
  153. if(listSize > 0 && listSize < 100) {
  154. // 复制CP地址
  155. for(UINT8 i = 0; i < listSize; ++i) {
  156. PeerInfoWithAddr nAddr;
  157. CopyMoveSrc(&nAddr.outerIP, content, sizeof(NormalAddress));
  158. nAddr.subnetIP.sin_addr.s_addr = 0xffffffff;
  159. nAddr.subnetIP.sin_port = nAddr.outerIP.sin_port;
  160. comm->logFile.StatusOut("CSClient got CP address %s...", comm->p2pMgr.FormatIPAddress(nAddr));
  161. nAddr.layer = 0;
  162. nAddr.isCachePeer = true;
  163. if(nAddr.outerIP.sin_addr.s_addr != 0) {
  164. comm->p2pMgr.AddPeerInfo(nAddr);
  165. // 如果得到CP地址,就尝试连接
  166. tryCP = true;
  167. }
  168. }
  169. }
  170. // 复制NP地址个数
  171. CopyMoveSrc(&listSize, content, sizeof(listSize));
  172. if(listSize > 0 && listSize < 100) {
  173. for(UINT8 i = 0; i < listSize; ++i) {
  174. PeerInfoWithAddr nAddr;
  175. CopyMoveSrc(&nAddr, content, sizeof(nAddr));
  176. assert(nAddr.outerIP.sin_addr.s_addr != 0);
  177. nAddr.isCachePeer = false;
  178. // put in known np list
  179. comm->p2pMgr.AddPeerInfo(nAddr);
  180. }
  181. comm->logFile.StatusOut("CSClient got %d NP.", listSize);
  182. }
  183. lastRecvPeers = timeGetTime();
  184. // 尝试连接CP
  185. if(tryCP)
  186. comm->tryClient.Try();
  187. return TRUE;
  188. }
  189. BOOL CSClient::OnConnectTo() {
  190. // 复制NP的地址
  191. P2PAddress nAddr;
  192. CopyMoveSrc(&nAddr, content, sizeof(nAddr));
  193. // 是否使用free outgoing
  194. bool connectForFree;
  195. CopyMoveSrc(&connectForFree, content, sizeof(connectForFree));
  196. // add to connectto peer list
  197. comm->p2pMgr.AddConnectTo(nAddr, connectForFree);
  198. comm->logFile.StatusOut("CSClient got ConnectTo.");
  199. return TRUE;
  200. }
  201. BOOL CSClient::OnResInfo() {
  202. // TODO: 接收返回的资源信息
  203. return TRUE;
  204. }
  205. BOOL CSClient::OnMsg() {
  206. // 复制错误代码
  207. UINT16 errCode;
  208. CopyMoveSrc(&errCode, content, sizeof(errCode));
  209. // 是否需要退出
  210. bool shouldQuit;
  211. CopyMoveSrc(&shouldQuit, content, sizeof(shouldQuit));
  212. // 是否不能继续登录
  213. bool bShouldStopLogin = false;
  214. // 根据错误代码处理
  215. switch(errCode) {
  216. case ERR_PROTOCOL_FORMAT:
  217. comm->logFile.StatusOut("TS sent ERR_PROTOCOL_FORMAT error!");
  218. bShouldStopLogin = true;
  219. break;
  220. case ERR_AUTHORIZATION:
  221. comm->logFile.StatusOut("TS sent ERR_AUTHORIZATION error!");
  222. bShouldStopLogin = true;
  223. break;
  224. case ERR_INTERNAL:
  225. comm->logFile.StatusOut("TS sent ERR_INTERNAL error!");
  226. break;
  227. case ERR_LOW_VERSION:
  228. comm->logFile.StatusOut("TS sent ERR_LOW_VERSION error!");
  229. // 发送版本太低的消息给外界
  230. comm->PostErrMessage(PNT_LOW_VERSION, 0, true);
  231. bShouldStopLogin = true;
  232. break;
  233. case ERR_NO_SUCH_PEER:
  234. comm->logFile.StatusOut("TS sent ERR_NO_SUCH_PEER error!");
  235. break;
  236. case ERR_NO_SUCH_RES:
  237. comm->logFile.StatusOut("TS sent ERR_NO_SUCH_RES error!");
  238. break;
  239. case ERR_CHECK_BYTES:
  240. comm->logFile.StatusOut("TS sent ERR_CHECK_BYTES error!");
  241. break;
  242. case ERR_ADD_RES_OK:
  243. // 请求资源成功!
  244. isReqResSucceed = true;
  245. comm->logFile.StatusOut("TS sent ERR_ADD_RES_OK!");
  246. // 发送第一次Report
  247. SendReport(true);
  248. break;
  249. default:
  250. shouldQuit = true;
  251. }
  252. if(shouldQuit) {
  253. isLogin = false;
  254. loginFailCount = 0;
  255. }
  256. if(bShouldStopLogin)
  257. bStopLogin = true;
  258. return TRUE;
  259. }
  260. void CSClient::SendLogin() {
  261. CriticalSection::Owner lock(sendCS);
  262. if(isLogin)
  263. return;
  264. if(bStopLogin)
  265. return;
  266. if(!SendBegin(NP2TS_LOGIN))
  267. return;
  268. // 用户ID和密码
  269. CopyMoveDes(content, &comm->userID, sizeof(comm->userID));
  270. CopyMoveDes(content, comm->userPass, MD5_LEN);
  271. // 版本号和监听端口
  272. CopyMoveDes(content, &comm->cfgData.COMMUNICATOR_VERSION, 
  273. sizeof(comm->cfgData.COMMUNICATOR_VERSION));
  274. // 写入监听端口
  275. CopyMoveDes(content, &comm->localAddress.subnetIP.sin_port, sizeof(comm->localAddress.subnetIP.sin_port));
  276. // 本机IP列表
  277. in_addr* addrList = NULL;
  278. UINT8 ipSize = GetLocalIPList(addrList);
  279. if(ipSize == 0) {
  280. comm->logFile.StatusErr("Get Local IP List", WSAGetLastError());
  281. return;
  282. }
  283. CopyMoveDes(content, &ipSize, sizeof(ipSize));
  284. CopyMoveDes(content, addrList, ipSize*sizeof(in_addr));
  285. delete [] addrList;
  286. addrList = NULL;
  287. comm->logFile.StatusOut("CSClient sent NP2TS_LOGIN.");
  288. isReqResSucceed = false;
  289. if(loginFailCount == 2) {
  290. // 两次登录失败,设置默认CP地址
  291. if(comm->currRes)
  292. comm->currRes->SetDefaultCP();
  293. }
  294. loginFailCount++;
  295. if(loginFailCount == maxFailCount) {
  296. // 发送登陆失败的消息给外界
  297. comm->PostErrMessage(PNT_CANNOT_LOGON_TS, 0, true);
  298. loginFailCount = 0;
  299. // 按MAX_LOGIN_FAIL_COUNT倍递增
  300. maxFailCount *= MAX_LOGIN_FAIL_COUNT;
  301. }
  302. SendEnd();
  303. }
  304. void CSClient::SendResList() {
  305. CriticalSection::Owner lock(sendCS);
  306. if(!isLogin || !comm->currRes)
  307. return;
  308. if(!SendBegin(NP2TS_RES_LIST))
  309. return;
  310. // 要共享的资源个数
  311. UINT8 resNum = 1;
  312. CopyMoveDes(content, &resNum, sizeof(resNum));
  313. // 依次写入所有要共享的资源
  314. CopyMoveDes(content, comm->currRes->GetHashCode().data(), MD5_LEN);
  315. // send block intervals
  316. UINT8 intervalNum = MAX_BLOCK_INTERVALS;
  317. comm->currRes->GetAllIntervals((BlockInterval*)(content+sizeof(intervalNum)), intervalNum);
  318. CopyMoveDes(content, &intervalNum, sizeof(intervalNum));
  319. content += intervalNum*sizeof(BlockInterval);
  320. comm->logFile.StatusOut("CSClient sent NP2TS_RES_LIST.");
  321. SendEnd();
  322. }
  323. void CSClient::SendReqRes() {
  324. CriticalSection::Owner lock(sendCS);
  325. assert(comm->currRes);
  326. // 如果已经登录,则发送请求资源;否则,登录成功之后再发送
  327. if(!isLogin) {
  328. comm->logFile.StatusOut("NOT LOGIN YET, first request will be sent after recving TS2NP_WELCOME...");
  329. return;
  330. }
  331. if(!comm->currRes)
  332. return;
  333. if(!SendBegin(NP2TS_REQ_RES))
  334. return;
  335. // request resource md5
  336. CopyMoveDes(content, comm->currRes->GetHashCode().data(), MD5_LEN);
  337. // send block intervals
  338. UINT8 intervalNum = MAX_BLOCK_INTERVALS;
  339. comm->currRes->GetAllIntervals((BlockInterval*)(content+sizeof(intervalNum)), intervalNum);
  340. CopyMoveDes(content, &intervalNum, sizeof(intervalNum));
  341. content += intervalNum*sizeof(BlockInterval);
  342. // current block ID
  343. UINT currBlockID = comm->currRes->GetPlayingBlock();
  344. CopyMoveDes(content, &currBlockID, sizeof(currBlockID));
  345. // need CP?
  346. bool needCP = (comm->p2pMgr.GetCPConCount(true) < MAX_CONNECTION_OF_CP);
  347. CopyMoveDes(content, &needCP, sizeof(needCP));
  348. comm->logFile.StatusOut("CSClient sent NP2TS_REQ_RES.");
  349. SendEnd();
  350. // 发送了请求资源的消息,等待请求成功的消息返回
  351. isReqResSucceed = false;
  352. }
  353. void CSClient::SendDelRes(BaseResource* res) {
  354. CriticalSection::Owner lock(sendCS);
  355. if(!res || !isLogin)
  356. return;
  357. if(!SendBegin(NP2TS_DEL_RES))
  358. return;
  359. // request resource md5
  360. CopyMoveDes(content, res->GetHashCode().data(), MD5_LEN);
  361. comm->logFile.StatusOut("CSClient sent NP2TS_DEL_RES(%s).", res->GetHashCode().data());
  362. SendEnd();
  363. }
  364. void CSClient::SendReport(bool bRefresh) {
  365. CriticalSection::Owner lock(sendCS);
  366. if(!isLogin)
  367. return;
  368. if(!SendBegin(NP2TS_REPORT))
  369. return;
  370. // 本机信息
  371. CorePeerInfo thisPeer;
  372. comm->p2pMgr.GetSelfInfo(thisPeer);
  373. CopyMoveDes(content, &thisPeer, sizeof(thisPeer));
  374. // 如果没有当前资源,则发送bRefresh=true和intervalNum=0
  375. if(!comm->currRes)
  376. bRefresh = true;
  377. // 是否更新全部区间列表
  378. CSClient::CopyMoveDes(content, &bRefresh, sizeof(bRefresh));
  379. // send block intervals
  380. // TODO: 这里存在重复代码,有待改进
  381. UINT8 intervalNum = comm->currRes?MAX_BLOCK_INTERVALS:0;
  382. if(bRefresh) {
  383. if(comm->currRes) {
  384. // 如果是更新全部区间,则取得当前资源全部区间的列表,并发送
  385. comm->currRes->GetAllIntervals((BlockInterval*)(content+sizeof(intervalNum)), intervalNum);
  386. }
  387. CSClient::CopyMoveDes(content, &intervalNum, sizeof(intervalNum));
  388. content += intervalNum*sizeof(BlockInterval);
  389. assert(intervalNum <= 20);
  390. }
  391. else {
  392. // 如果是更新变化的区间,则先后写入增加的区间和减少的区间
  393. comm->currRes->GetDiffIntervals((BlockInterval*)(content+sizeof(intervalNum)), intervalNum, true, true);
  394. CSClient::CopyMoveDes(content, &intervalNum, sizeof(intervalNum));
  395. content += intervalNum*sizeof(BlockInterval);
  396. assert(intervalNum <= 20);
  397. comm->currRes->GetDiffIntervals((BlockInterval*)(content+sizeof(intervalNum)), intervalNum, true, false);
  398. CSClient::CopyMoveDes(content, &intervalNum, sizeof(intervalNum));
  399. content += intervalNum*sizeof(BlockInterval);
  400. assert(intervalNum <= 20);
  401. }
  402. // 发送本机传输信息
  403. TransferInfo ti;
  404. comm->p2pMgr.GetTransferInfo(ti);
  405. CSClient::CopyMoveDes(content, &ti, sizeof(TransferInfo));
  406. comm->logFile.StatusOut("CSClient sent NP2TS_REPORT.");
  407. SendEnd();
  408. }
  409. void CSClient::SendNeedPeers() {
  410. CriticalSection::Owner lock(sendCS);
  411.   if(!comm->currRes || !isLogin)
  412. return;
  413. // 如果请求资源还没有成功,就发送请求消息,然后返回
  414. if(!isReqResSucceed) {
  415. SendReqRes();
  416. return;
  417. }
  418. // 如果当前下载速度大于直播的码率,则不必发送NeedPeers
  419. if(comm->p2pMgr.GetCurDownSpeed()/1024 > comm->currRes->GetBitRate())
  420. return;
  421. // 如果已知的Peer列表足够多,就不用发送NeedPeers
  422. if(comm->p2pMgr.GetKnownPeerCount() + comm->p2pMgr.GetAllCount() >= MIN_KNOWN_PEERS)
  423. return;
  424. if(!SendBegin(NP2TS_NEED_PEERS))
  425. return;
  426. // 本机是否需要CachePeer的地址
  427. bool needCP = (comm->p2pMgr.GetCPConCount(true) < MAX_CONNECTION_OF_CP);
  428. CopyMoveDes(content, &needCP, sizeof(needCP));
  429. UINT currBlockID = comm->currRes->GetPlayingBlock();
  430. CopyMoveDes(content, &currBlockID, sizeof(currBlockID));
  431. // 本机在P2P网络中所属的层
  432. UINT8 layer = comm->p2pMgr.GetSelfLayer();
  433. CopyMoveDes(content, &layer, sizeof(layer));
  434. comm->logFile.StatusOut("CSClient sent NP2TS_NEED_PEERS.");
  435. SendEnd();
  436. }
  437. void CSClient::SendQueryRes() {
  438. // TODO: 什么时候发送请求的,目前客户端不关心现在有多少频道(md5),每个频道有多少人
  439. }
  440. void CSClient::SendLogout() {
  441. CriticalSection::Owner lock(sendCS);
  442.   if(!comm->currRes || !isLogin)
  443. return;
  444. if(!SendBegin(NP2TS_LOGOUT))
  445. return;
  446. SendEnd();
  447. comm->logFile.StatusOut("CSClient sent NP2TS_LOGOUT.");
  448. // 退出登录
  449. isLogin = false;
  450. loginFailCount = 0;
  451. }
  452. void CSClient::SendReport2() {
  453. CriticalSection::Owner lock(sendCS);
  454. if(!comm->currRes || !isLogin)
  455. return;
  456. if(!SendBegin(NP2TS_REPORT2))
  457. return;
  458. UINT16 value = 0;
  459. // playing block
  460. UINT currBlockID = comm->currRes->GetPlayingBlock();
  461. CopyMoveDes(content, &currBlockID, sizeof(currBlockID));
  462. // 当前缓冲的时间,没有缓冲的话就是0
  463. value = comm->currRes->GetBufferingTime();
  464. CopyMoveDes(content, &value, sizeof(value));
  465. // 之前缓冲的次数
  466. value = comm->currRes->GetBufferCount();
  467. CopyMoveDes(content, &value, sizeof(value));
  468. // 之前所有缓冲所用的时间
  469. value = comm->currRes->GetBufferTime();
  470. CopyMoveDes(content, &value, sizeof(value));
  471. // connect Fail Count
  472. value = comm->p2pMgr.GetConnectFailCount();
  473. CopyMoveDes(content, &value, sizeof(value));
  474. // incoming connection count
  475. value = comm->p2pMgr.GetTotalIncomingCount();
  476. CopyMoveDes(content, &value, sizeof(value));
  477. // outgoing connection count
  478. value = comm->p2pMgr.GetTotalOutgoingCount();
  479. CopyMoveDes(content, &value, sizeof(value));
  480. // avg incoming connection elapsed time
  481. value = comm->p2pMgr.GetAvgIncomingTime();
  482. CopyMoveDes(content, &value, sizeof(value));
  483. // avg outgoing connection elapsed time
  484. value = comm->p2pMgr.GetAvgOutgoingTime();
  485. CopyMoveDes(content, &value, sizeof(value));
  486. // message percent
  487. float msgPercent = comm->p2pMgr.GetMessagePercent();
  488. CopyMoveDes(content, &msgPercent, sizeof(msgPercent));
  489. // 发送本机传输信息
  490. TransferInfo ti;
  491. comm->p2pMgr.GetTransferInfo(ti);
  492. CSClient::CopyMoveDes(content, &ti, sizeof(TransferInfo));
  493. comm->logFile.StatusOut("CSClient sent NP2TS_REPORT2.");
  494. SendEnd();
  495. }
  496. BOOL CSClient::SendBegin(UINT8 msgType) {
  497. // 先留着消息大小不写,到最后再写
  498. content = recvBuf+sizeof(UINT);
  499. // 消息类型
  500. CopyMoveDes(content, &msgType, sizeof(msgType));
  501. if(msgType != NP2TS_LOGIN) {
  502. // TS的验证码
  503. CopyMoveDes(content, checkCode, 7);
  504. }
  505. return TRUE;
  506. }
  507. void CSClient::SendEnd() {
  508. // 消息的大小就是移动的指针减去初始的指针
  509. UINT msgSize = content-recvBuf;
  510. memcpy(recvBuf, &msgSize, sizeof(msgSize));
  511. // 发送
  512. sockaddr_in addr;
  513. memcpy(&addr, &comm->trackerIP, sizeof(comm->trackerIP));
  514. int ret = sendto(m_Socket, (const char*)recvBuf, msgSize, 
  515. 0, (SOCKADDR*)&addr, sizeof(addr));
  516. if(ret == SOCKET_ERROR) {
  517. comm->logFile.StatusErr("sendto() error, rebind udp socket", WSAGetLastError());
  518. // 重新连接TS
  519. Reinit();
  520. }
  521. }
  522. void CSClient::CopyMoveSrc(void * des, const char *& src, size_t size) {
  523. assert(des && src);
  524. if(!des || !src)
  525. return;
  526. memcpy(des, src, size);
  527. src += size;
  528. }
  529. void CSClient::CopyMoveDes(char *& des, const void * src, size_t size) {
  530. assert(des && src);
  531. if(!des || !src)
  532. return;
  533. memcpy(des, src, size);
  534. des += size;
  535. }
  536. UINT8 CSClient::GetLocalIPList(in_addr*& addrList) {
  537. UINT8 ipCount = 0;
  538. addrList = NULL;
  539. // Get local host name
  540. char szHostName[128] = "";
  541. if(gethostname(szHostName, sizeof(szHostName)))
  542. return 0;
  543. // Get local IP addresses
  544. hostent *pHost = 0;
  545. if((pHost = gethostbyname(szHostName)) == NULL)
  546. return 0;
  547. // 计算IP地址个数
  548. while(pHost->h_addr_list[ipCount]) {
  549. ipCount++;
  550. // 注意不能越界了,超过0xff个IP地址将不被支持
  551. if(ipCount == 0xff)
  552. break;
  553. }
  554. // 分配数组,要在外部释放
  555. addrList = new in_addr[ipCount];
  556. if(!addrList)
  557. return 0;
  558. // 复制IP列表
  559. for(int i = 0; i < ipCount; ++i) {
  560. memcpy(&addrList[i], pHost->h_addr_list[i], pHost->h_length);
  561. }
  562. // 返回IP地址个数
  563. return ipCount;
  564. }
  565. // 重新初始化
  566. void CSClient::Reinit() {
  567. if(m_Socket != INVALID_SOCKET)
  568. closesocket(m_Socket);
  569. Init();
  570. SendLogin();
  571. }
  572. }