#include "stdafx.h" #include "ExNiNetwork.h" #include "buffer.h" #include "network.h" /* 使用するパラメータ appParam.clientPort CSetNetwork appParam.animationUUID CSetAnimation appParam.printNetMode CSetLogMode appParam.printChkMode CSetLogMode */ CExNiNetwork::CExNiNetwork(void) { recvSocket = 0; sendSocket = 0; portNAPT = 0; m_str_server = NULL; m_str_groupid = NULL; m_str_animid = NULL; sharedMem = NULL; pLogDoc = NULL; locked_reciever = FALSE;; recvBps = 0.0f; frameRate = 0.0f; packetDelay = 0; appParam.init(); keepAliveTime = NINET_KEEP_ALIVE; memset(recvKey, 0, ANM_COM_LEN_IDKEY); memset(&serverDataAddr, 0, sizeof(struct sockaddr_in)); recvBuffer = make_Buffer(NINET_BUFFER_LEN); sendBuffer = make_Buffer(NINET_BUFFER_LEN); // Networkの初期化 see network.c init_network(); } CExNiNetwork::~CExNiNetwork(void) { DEBUG_ERR("DESTRUCTOR: CExNiNetwork"); if (recvKey[0]!='\0') serverLogout(); closeRecvSocket(); closeSendSocket(); while (locked_reciever) { ::Sleep(NINET_WAIT_TIME); DisPatcher(); } free_Buffer(&recvBuffer); free_Buffer(&sendBuffer); // if (m_str_server!=NULL) { ::free(m_str_server); m_str_server = NULL; } if (m_str_groupid!=NULL) { ::free(m_str_groupid); m_str_groupid = NULL; } if (m_str_animid!=NULL) { ::free(m_str_animid); m_str_animid = NULL; } } void CExNiNetwork::clearNetFBPS(void) { recvBps = 0.0f; frameRate = 0.0f; SendWinMessage(WM_USER_NETFBPS_UPDATE); } void CExNiNetwork::setParameter(CParameterSet param) { appParam = param; if (appParam.animationSrvr!=_T("")) { if (m_str_server!=NULL) ::free(m_str_server); m_str_server = ts2mbs(appParam.animationSrvr); } if (appParam.groupID!=_T("")) { if (m_str_groupid!=NULL) ::free(m_str_groupid); m_str_groupid = ts2mbs(appParam.groupID); } if (appParam.animationUUID!=_T("")) { if (m_str_animid!=NULL) ::free(m_str_animid); m_str_animid = ts2mbs(appParam.animationUUID); } } //////////////////////////////////////////////////////////////////////////////////////////////// // // // unsigned char CExNiNetwork::serverLogin(void) { int cc; struct sockaddr_in sv_addr; memset(&serverDataAddr, 0, sizeof(struct sockaddr_in)); memset(recvKey, 0, ANM_COM_LEN_IDKEY); portNAPT = 0; udp_header udphd; memset(&udphd, 0, sizeof(udp_header)); udphd.com[0] = ANM_COM_REQ_LOGIN; udphd.com[1] = ANM_COM_REPLY_ERROR; memcpy(udphd.key, m_str_groupid, ANM_COM_LEN_IDKEY); // int sock = udp_client_socket(m_str_server, appParam.serverPort, &sv_addr); sock = udp_bind(sock, appParam.clientPort); if (sock<=0) return ANM_COM_ERROR_SOCKET; cc = udp_send(sock, (char*)&udphd, sizeof(udp_header), &sv_addr); if (cc<=0) { socket_close(sock); return ANM_COM_REPLY_ERROR; } // cc = recv_wait(sock, NINET_UDP_TIMEOUT); if (!cc) { socket_close(sock); return ANM_COM_ERROR_SERVER_DOWN; } // cc = udp_recv(sock, (char*)&udphd, sizeof(udp_header), &sv_addr); if (cc<=0 || udphd.com[1]!=ANM_COM_REPLY_OK) { if (cc<0) udphd.com[1] = ANM_COM_ERROR_SERVER_DOWN; socket_close(sock); return udphd.com[1]; } ::Sleep(NINET_REGIST_WAIT_TIME); // wait server serverDataAddr = sv_addr; serverDataAddr.sin_port = udphd.port; memcpy(recvKey, udphd.key, ANM_COM_LEN_IDKEY); cc = serverRegist(sock, serverDataAddr, &udphd); if (cc<0) serverLogout(); socket_close(sock); portNAPT = ntohs(udphd.port); return udphd.com[1]; } int CExNiNetwork::serverRegist(int sock, struct sockaddr_in sv_addr, udp_header* udphd) { udphd->com[0] = ANM_COM_REQ_REGIST; udphd->com[1] = ANM_COM_REPLY_ERROR; udphd->port = 0; memcpy(udphd->uuid, m_str_animid, ANM_COM_LEN_UUID); int cc = udp_send(sock, (char*)udphd, sizeof(udp_header), &sv_addr); if (cc<=0) { socket_close(sock); udphd->com[1] = ANM_COM_REPLY_ERROR; return 1; } cc = recv_wait(sock, NINET_UDP_TIMEOUT); if (!cc) { socket_close(sock); udphd->com[1] = ANM_COM_ERROR_TIMEOUT; return 2; } cc = udp_recv(sock, (char*)udphd, sizeof(udp_header), &sv_addr); if (cc<0) return cc; return 0; } void CExNiNetwork::serverLogout(void) { udp_header udphd; if (serverDataAddr.sin_port==0) return; memset(&udphd, 0, sizeof(udp_header)); udphd.port = htons(portNAPT); memcpy(udphd.key, recvKey, ANM_COM_LEN_IDKEY); memcpy(udphd.uuid, m_str_animid, ANM_COM_LEN_UUID); int sock = (int)socket(AF_INET, SOCK_DGRAM, 0); // udphd.com[0] = ANM_COM_REQ_DELETE; int cc = udp_send(sock, (char*)&udphd, sizeof(udp_header), &serverDataAddr); // udphd.com[0] = ANM_COM_REQ_LOGOUT; cc = udp_send(sock, (char*)&udphd, sizeof(udp_header), &serverDataAddr); socket_close(sock); closeNetwork(); } void CExNiNetwork::closeNetwork(void) { closeSendSocket(); closeRecvSocket(); if (sharedMem!=NULL) { sharedMem->clearNetworkAnimationIndex(); sharedMem->clearNetworkAnimationData(); } memset(&serverDataAddr, 0, sizeof(struct sockaddr_in)); memset(recvKey, 0, ANM_COM_LEN_IDKEY); } void CExNiNetwork::printNetInfo(udp_header* udphd) { // if (pLogDoc==NULL || udphd==NULL) return; pLogDoc->lock(); if (appParam.printNetMode) { if (pLogDoc!=NULL) { pLogDoc->printFormat("NET: %s (%2d) [%d]\n", udphd->uuid, ntohs(udphd->num), ntohs(udphd->sz)); } } if (appParam.printChkMode && (frameRate>0.0f || packetDelay>0)) { int n = sharedMem->getNetworkAnimationIndexNum(); if (pLogDoc!=NULL) { pLogDoc->printFormat("NET: CHECK: %4.1ffps/%4.1fkbps %4dms (%1d) [%s]\n", frameRate, recvBps, packetDelay, n, udphd->key); } } if (!isNull(pLogDoc)) pLogDoc->unlock(); return; } void CExNiNetwork::openRecvSocket(void) { recvSocket = udp_server_socket((int)appParam.clientPort); return; } void CExNiNetwork::openSendSocket(void) { sendSocket = (int)socket(AF_INET, SOCK_DGRAM, 0); return; } void CExNiNetwork::closeRecvSocket(void) { if (recvSocket>0) { socket_close(recvSocket); recvSocket = 0; } } void CExNiNetwork::closeSendSocket(void) { if (sendSocket>0) { socket_close(sendSocket); sendSocket = 0; } } //////////////////////////////////////////////////////////////////////////////////////// // // スレッド // // // データ受信 // UINT niNetworkRecieveLoop(LPVOID pParam) { if (pParam==NULL) return 1; CExNiNetwork* niNetwork = (CExNiNetwork*)pParam; if (niNetwork->recvSocket<=0 || niNetwork->sharedMem==NULL) return 1; struct sockaddr_in ds_addr; int num = 0; int rsz = 0; unsigned short tmptime; unsigned short frmtime = GetMsecondsTimer(); CParameterSet* appParam = &(niNetwork->appParam); int maxbps = appParam->inMaxBPS; int kbpf = NINET_DEFAULT_KBPF; // k bits/frame // niNetwork->locked_reciever = TRUE; // Keep Alive and Hole Punching udp_header alive; memset(&alive, 0, sizeof(udp_header)); alive.com[0] = ANM_COM_REQ_ALIVE; alive.port = htons(niNetwork->portNAPT); alive.sz = (unsigned short)maxbps/kbpf; // k bit/frame memcpy(alive.key, niNetwork->recvKey, ANM_COM_LEN_IDKEY); memcpy(alive.uuid, niNetwork->m_str_animid, ANM_COM_LEN_UUID); time_t nowtime; time_t alvtime = time(NULL); udp_send(niNetwork->recvSocket, (char*)&alive, sizeof(udp_header), &niNetwork->serverDataAddr); // while (niNetwork->recvSocket>0) { int cc = recv_wait(niNetwork->recvSocket, NINET_UDP_TIMEOUT); if (cc) { if (niNetwork->recvSocket<=0) break; cc = udp_recv_Buffer(niNetwork->recvSocket, &(niNetwork->recvBuffer), &ds_addr); if (cc>0) { char* ptr = (char*)niNetwork->recvBuffer.buf; udp_header* udphd = (udp_header*)ptr; //DEBUG_ERR("RECEIVE COM = %02x", udphd->com[0]); if (!strncasecmp((char*)udphd->key, niNetwork->recvKey, ANM_COM_LEN_IDKEY)) { // int joints = (int)ntohs(udphd->num); int size = (int)ntohs(udphd->sz); niNetwork->recvBps = 0.0f; niNetwork->frameRate = 0.0f; niNetwork->packetDelay = 0; // FPS & BPS rsz+= niNetwork->recvBuffer.vldsz; num++; float laptm = GetMsecondsLapTimer(frmtime, &tmptime)/1000.0f; if ((int)laptm>=NINET_FRM_RATE_INTVL) { niNetwork->recvBps = rsz*8/1000.0f/laptm; niNetwork->frameRate = num/laptm; kbpf = (int)(rsz*8/1000.0f/num); frmtime = tmptime; num = rsz = 0; SendWinMessage(WM_USER_NETFBPS_UPDATE); if (!strncasecmp(niNetwork->m_str_animid, udphd->uuid, ANM_COM_LEN_UUID)) { unsigned short tm = ntohs(*(unsigned short*)&(udphd->com[2])); niNetwork->packetDelay = (int)GetMsecondsLapTimer(tm); } } // if (udphd->com[0]==ANM_COM_REQ_DELETE) { niNetwork->sharedMem->clearNetworkAnimation(udphd->uuid); if (!strncasecmp(niNetwork->m_str_animid, udphd->uuid, ANM_COM_LEN_UUID)) { SendWinMessage(WM_USER_NET_CLOSE); break; } } // 共有メモリに書き込み else { ptr += sizeof(udp_header); niNetwork->sharedMem->updateNetworkAnimation(ptr, udphd->uuid, joints, size); } // Print if (niNetwork->pLogDoc!=NULL) niNetwork->printNetInfo(udphd); } } } // Time Out else { niNetwork->clearNetFBPS(); } // Keep Alive, QOS Request and UDP Hole Punching nowtime = time(NULL); if (nowtime-alvtime>niNetwork->keepAliveTime*60 || maxbps!=appParam->inMaxBPS) { alvtime = nowtime; maxbps = appParam->inMaxBPS; // Band width request if (kbpf==0) kbpf = NINET_DEFAULT_KBPF; alive.sz = (unsigned short)maxbps/kbpf; // k bit/frame // udp_send(niNetwork->recvSocket, (char*)&alive, sizeof(udp_header), &niNetwork->serverDataAddr); } } niNetwork->clearNetFBPS(); niNetwork->locked_reciever = FALSE; return 0; }