bool C4Network2IO::Connect(const C4NetIO::addr_t &addr, C4Network2IOProtocol eProt, const C4ClientCore &nCCore, const char *szPassword) // by main thread { // get network class C4NetIO *pNetIO = getNetIO(eProt); if (!pNetIO) return false; // already connected/connecting? if (GetConnectionByConnAddr(addr, pNetIO)) return true; // assign new connection ID, peer address isn't known yet uint32_t iConnID = iNextConnID++; C4NetIO::addr_t paddr; ZeroMem(&paddr, sizeof paddr); // create connection object and add to list C4Network2IOConnection *pConn = new C4Network2IOConnection(); pConn->Set(pNetIO, eProt, paddr, addr, CS_Connect, szPassword, iConnID); pConn->SetCCore(nCCore); AddConnection(pConn); // connect if (!pConn->Connect()) { // show error LogF("Network: could not connect to %s:%d using %s: %s", inet_ntoa(addr.sin_addr), htons(addr.sin_port), getNetIOName(pNetIO), pNetIO->GetError() ? pNetIO->GetError() : ""); pNetIO->ResetError(); // remove class RemoveConnection(pConn); return false; } // ok, wait for connection return true; }
void C4Network2IO::OnPacket(const class C4NetIOPacket &rPacket, C4NetIO *pNetIO) { #if C4NET2IO_DUMP_LEVEL > 0 auto tTime = C4TimeMilliseconds::Now(); #endif #if(C4NET2IO_DUMP_LEVEL > 1) Application.InteractiveThread.ThreadLogS("OnPacket: %s status %02x %s", C4TimeMilliseconds::Now().AsString().getData(), rPacket.getStatus(), getNetIOName(pNetIO)); #endif if (!rPacket.getSize()) return; // find connection C4Network2IOConnection *pConn = GetConnection(rPacket.getAddr(), pNetIO); if (!pConn) { Application.InteractiveThread.ThreadLog("Network: could not find connection for packet from %s:%d!", inet_ntoa(rPacket.getAddr().sin_addr), htons(rPacket.getAddr().sin_port)); return; } #if(C4NET2IO_DUMP_LEVEL > 2) uint32_t iFindConnectionBlocked = C4TimeMilliseconds::Now() - tTime; if (iFindConnectionBlocked > 100) Application.InteractiveThread.ThreadLogS("OnPacket: ... blocked %d ms for finding the connection!", iFindConnectionBlocked); #endif // notify pConn->OnPacketReceived(rPacket.getStatus()); // handle packet HandlePacket(rPacket, pConn, true); // log time #if(C4NET2IO_DUMP_LEVEL > 1) uint32_t iHandlingBlocked = C4TimeMilliseconds::Now() - tTime; if (iHandlingBlocked > 100) Application.InteractiveThread.ThreadLogS("OnPacket: ... blocked %d ms for handling!", iHandlingBlocked); #endif }
void C4Network2ClientListBox::ConnectionListItem::Update() { C4Network2IOConnection *pConn = GetConnection(); if (!pConn) { // No connection: Shouldn't happen pDesc->SetText("???"); pPing->SetText("???"); return; } // update connection ping int iPing = pConn->getLag(); pPing->SetText(FormatString("%d ms", iPing).getData()); // update description // get connection usage const char *szConnType; C4Network2Client *pNetClient = ::Network.Clients.GetClientByID(iClientID); if (pNetClient->getDataConn() == pNetClient->getMsgConn()) szConnType = "Data/Msg"; else if (iConnID) szConnType = "Msg"; else szConnType = "Data"; // display info pDesc->SetText(FormatString("%s: %s (%s l%d)", szConnType, ::Network.NetIO.getNetIOName(pConn->getNetClass()), pConn->getPeerAddr().ToString().getData(), pConn->getPacketLoss()).getData()); }
int C4Network2IO::getConnectionCount() // by main thread { int iCount = 0; CStdLock ConnListLock(&ConnListCSec); for (C4Network2IOConnection *pConn = pConnList; pConn; pConn = pConn->pNext) if (!pConn->isClosed()) iCount++; return iCount; }
C4Network2IOConnection *C4Network2IO::GetConnectionByConnAddr(const C4NetIO::addr_t &addr, C4NetIO *pNetIO) // by both { CStdLock ConnListLock(&ConnListCSec); // search for (C4Network2IOConnection *pConn = pConnList; pConn; pConn = pConn->pNext) if (pConn->getNetClass() == pNetIO && AddrEqual(pConn->getConnectAddr(), addr)) return pConn; return NULL; }
C4Network2IOConnection *C4Network2IO::GetConnectionByID(uint32_t iConnID) // by thread { CStdLock ConnListLock(&ConnListCSec); // search for (C4Network2IOConnection *pConn = pConnList; pConn; pConn = pConn->pNext) if (pConn->getID() == iConnID) return pConn; return NULL; }
void C4Network2ClientListBox::ConnectionListItem::OnButtonDisconnect(C4GUI::Control *pButton) { // close connection C4Network2IOConnection *pConn = GetConnection(); if (pConn) { pConn->Close(); } }
void C4Network2IO::BeginBroadcast(bool fSelectAll) { // lock BroadcastCSec.Enter(); // reset all broadcast flags CStdLock ConnListLock(&ConnListCSec); for (C4Network2IOConnection *pConn = pConnList; pConn; pConn = pConn->pNext) if (pConn->isOpen()) pConn->SetBroadcastTarget(fSelectAll); }
bool C4Network2IO::SendMsgToClient(C4NetIOPacket &rPkt, int iClient) // by both { // find msg connection C4Network2IOConnection *pConn = GetMsgConnection(iClient); if (!pConn) return false; // send bool fSuccess = pConn->Send(rPkt); pConn->DelRef(); return fSuccess; }
void C4Network2IO::Clear() // by main thread { // process remaining events C4InteractiveThread &Thread = Application.InteractiveThread; Thread.ProcessEvents(); // clear event callbacks Thread.ClearCallback(Ev_Net_Conn, this); Thread.ClearCallback(Ev_Net_Disconn, this); Thread.ClearCallback(Ev_Net_Packet, this); // close all connections CStdLock ConnListLock(&ConnListCSec); for (C4Network2IOConnection *pConn = pConnList, *pNext; pConn; pConn = pNext) { pNext = pConn->pNext; // close pConn->Close(); RemoveConnection(pConn); } // reset list pConnList = NULL; ConnListLock.Clear(); // close net i/o classes Thread.RemoveProc(this); if (pNetIODiscover) { Thread.RemoveProc(pNetIODiscover); delete pNetIODiscover; pNetIODiscover = NULL; } if (pNetIO_TCP) { Thread.RemoveProc(pNetIO_TCP); delete pNetIO_TCP; pNetIO_TCP = NULL; } if (pNetIO_UDP) { Thread.RemoveProc(pNetIO_UDP); delete pNetIO_UDP; pNetIO_UDP = NULL; } if (pRefServer) { Thread.RemoveProc(pRefServer); delete pRefServer; pRefServer = NULL; } if (UPnPMgr) { delete UPnPMgr; UPnPMgr = NULL; } // remove auto-accepts ClearAutoAccept(); // reset flags fAllowConnect = fExclusiveConn = false; // reset connection ID iNextConnID = 0; }
bool C4Network2IO::Broadcast(const C4NetIOPacket &rPkt) { bool fSuccess = true; // There is no broadcasting atm, emulate it CStdLock ConnListLock(&ConnListCSec); for (C4Network2IOConnection *pConn = pConnList; pConn; pConn = pConn->pNext) if (pConn->isOpen() && pConn->isBroadcastTarget()) fSuccess &= pConn->Send(rPkt); if(!fSuccess) Log("Network: Warning! Broadcast failed."); return fSuccess; }
void C4Network2Client::CloseConns(const char *szMsg) { C4PacketConnRe Pkt(false, false, szMsg); C4Network2IOConnection *pConn; while (pConn = pMsgConn) { // send packet, close if (pConn->isOpen()) { pConn->Send(MkC4NetIOPacket(PID_ConnRe, Pkt)); pConn->Close(); } // remove RemoveConn(pConn); } }
bool C4Network2IO::BroadcastMsg(const C4NetIOPacket &rPkt) // by both { // TODO: ugly algorithm. do better // begin broadcast BeginBroadcast(false); // select one connection per reachable client CStdLock ConnListLock(&ConnListCSec); for (C4Network2IOConnection *pConn = pConnList; pConn; pConn = pConn->pNext) if (pConn->isAccepted()) { if (pConn->getProtocol() == P_UDP) pConn->SetBroadcastTarget(true); else if (pConn->getProtocol() == P_TCP) { C4Network2IOConnection *pConn2 = GetMsgConnection(pConn->getClientID()); if (pConn == pConn2) pConn->SetBroadcastTarget(true); pConn2->DelRef(); } } // send bool fSuccess = Broadcast(rPkt); // end broadcast EndBroadcast(); // return return fSuccess; }
bool C4Network2Res::SendChunk(uint32_t iChunk, int32_t iToClient) { assert(pParent && pParent->getIOClass()); if (!szStandalone[0] || iChunk >= Core.getChunkCnt()) return false; // find connection for given client (one of the rare uses of the data connection) C4Network2IOConnection *pConn = pParent->getIOClass()->GetDataConnection(iToClient); if (!pConn) return false; // save last request time iLastReqTime = time(NULL); // create packet CStdLock FileLock(&FileCSec); C4Network2ResChunk ResChunk; ResChunk.Set(this, iChunk); // send bool fSuccess = pConn->Send(MkC4NetIOPacket(PID_NetResData, ResChunk)); pConn->DelRef(); return fSuccess; }
bool C4Network2IO::doAutoAccept(const C4ClientCore &CCore, const C4Network2IOConnection &Conn) { CStdLock AALock(&AutoAcceptCSec); // check if connection with the given client should be allowed for (AutoAccept *pAcc = pAutoAcceptList; pAcc; pAcc = pAcc->Next) // core match? if (CCore.getDiffLevel(pAcc->CCore) <= C4ClientCoreDL_IDMatch) { // check: already got another connection for this client? Peer IP must match, then. for (C4Network2IOConnection *pConn = pConnList; pConn; pConn = pConn->pNext) if (pConn->isAccepted() && pConn->getCCore().getDiffLevel(CCore) <= C4ClientCoreDL_IDMatch && pConn->getPeerAddr().sin_addr.s_addr != Conn.getPeerAddr().sin_addr.s_addr) return false; // not found or IP matches? Let pass return true; } return false; }
void C4Network2Stats::ExecuteSecond() { statFPS.RecordValue(C4Graph::ValueType(Game.FPS)); statNetI.RecordValue( C4Graph::ValueType(Game.Network.NetIO.getProtIRate(P_TCP) + Game.Network.NetIO.getProtIRate(P_UDP))); statNetO.RecordValue( C4Graph::ValueType(Game.Network.NetIO.getProtORate(P_TCP) + Game.Network.NetIO.getProtORate(P_UDP))); // pings for all clients C4Network2Client *pClient = NULL; while (pClient = Game.Network.Clients.GetNextClient(pClient)) if (pClient->getStatPing()) { int iPing = 0; C4Network2IOConnection *pConn = pClient->getMsgConn(); if (pConn) iPing = pConn->getLag(); pClient->getStatPing()->RecordValue(C4Graph::ValueType(iPing)); } ++SecondCounter; }
void C4Network2IO::HandleFwdReq(const C4PacketFwd &rFwd, C4Network2IOConnection *pBy) { CStdLock ConnListLock(&ConnListCSec); // init packet C4PacketFwd nFwd; nFwd.SetListType(false); // find all clients the message should be forwarded to int iClientID; C4Network2IOConnection *pConn; for (pConn = pConnList; pConn; pConn = pConn->pNext) if (pConn->isAccepted()) if ((iClientID = pConn->getClientID()) >= 0) if (iClientID != pBy->getClientID()) if (rFwd.DoFwdTo(iClientID) && !nFwd.DoFwdTo(iClientID)) nFwd.AddClient(iClientID); // check count (hardcoded: broadcast for > 2 clients) if (nFwd.getClientCnt() <= 2) { C4NetIOPacket Pkt(rFwd.getData(), C4NetIO::addr_t()); for (int i = 0; i < nFwd.getClientCnt(); i++) if ((pConn = GetMsgConnection(nFwd.getClient(i)))) { pConn->Send(Pkt); pConn->DelRef(); } } else { // Temporarily unlock connection list for getting broadcast lock // (might lead to deathlocks otherwise, as the lock is often taken // in the opposite order) ConnListLock.Clear(); BeginBroadcast(); nFwd.SetData(rFwd.getData()); // add all clients CStdLock ConnListLock(&ConnListCSec); for (int i = 0; i < nFwd.getClientCnt(); i++) if ((pConn = GetMsgConnection(nFwd.getClient(i)))) { pConn->SetBroadcastTarget(true); pConn->DelRef(); } // broadcast Broadcast(MkC4NetIOPacket(PID_Fwd, nFwd)); EndBroadcast(); } // doing a callback here; don't lock! ConnListLock.Clear(); // forward to self? if (rFwd.DoFwdTo(LCCore.getID())) { C4NetIOPacket Packet(rFwd.getData(), pBy->getPeerAddr()); HandlePacket(Packet, pBy, true); } }
void C4Network2IO::OnThreadEvent(C4InteractiveEventType eEvent, void *pEventData) // by main thread { switch (eEvent) { case Ev_Net_Conn: // got a connection { C4Network2IOConnection *pConn = reinterpret_cast<C4Network2IOConnection *>(pEventData); // do callback ::Network.OnConn(pConn); // remove reference pConn->DelRef(); } break; case Ev_Net_Disconn: // connection closed { C4Network2IOConnection *pConn = reinterpret_cast<C4Network2IOConnection *>(pEventData); assert(pConn->isClosed()); // do callback ::Network.OnDisconn(pConn); // remove reference pConn->DelRef(); } break; case Ev_Net_Packet: // got packet { NetEvPacketData *pData = reinterpret_cast<NetEvPacketData *>(pEventData); // handle HandlePacket(pData->Packet, pData->Conn, false); // clear up pData->Conn->DelRef(); delete pData; } break; default: // TODO break; } }
void C4Network2IO::GenerateStatistics(int iInterval) { int iTCPIRateSum = 0, iTCPORateSum = 0, iUDPIRateSum = 0, iUDPORateSum = 0; // acquire lock, get connection statistics CStdLock ConnListLock(&ConnListCSec); for (C4Network2IOConnection *pConn = pConnList; pConn; pConn = pConn->pNext) if (pConn->isOpen()) { bool fTCP = pConn->getNetClass() == pNetIO_TCP; pConn->DoStatistics(iInterval, fTCP ? &iTCPIRateSum : &iUDPIRateSum, fTCP ? &iTCPORateSum : &iUDPORateSum); } ConnListLock.Clear(); // get broadcast statistics int inTCPBCRate = 0, inUDPBCRate = 0; if (pNetIO_TCP) pNetIO_TCP->GetStatistic(&inTCPBCRate); if (pNetIO_UDP) pNetIO_UDP->GetStatistic(&inUDPBCRate); // normalize everything iTCPIRateSum = iTCPIRateSum * 1000 / iInterval; iTCPORateSum = iTCPORateSum * 1000 / iInterval; iUDPIRateSum = iUDPIRateSum * 1000 / iInterval; iUDPORateSum = iUDPORateSum * 1000 / iInterval; inTCPBCRate = inTCPBCRate * 1000 / iInterval; inUDPBCRate = inUDPBCRate * 1000 / iInterval; // clear if (pNetIO_TCP) pNetIO_TCP->ClearStatistic(); if (pNetIO_UDP) pNetIO_UDP->ClearStatistic(); // save back iTCPIRate = iTCPIRateSum; iTCPORate = iTCPORateSum; iTCPBCRate = inTCPBCRate; iUDPIRate = iUDPIRateSum; iUDPORate = iUDPORateSum; iUDPBCRate = inUDPBCRate; }
void C4Network2IO::OnDisconn(const C4NetIO::addr_t &addr, C4NetIO *pNetIO, const char *szReason) { // punch? if (pNetIO == pNetIO_UDP) if (PuncherAddr.sin_addr.s_addr && AddrEqual(PuncherAddr, addr)) { ZeroMem(&PuncherAddr, sizeof(PuncherAddr)); return; } #if(C4NET2IO_DUMP_LEVEL > 1) Application.InteractiveThread.ThreadLogS("OnDisconn: %s %s", C4TimeMilliseconds::Now().AsString().getData(), getNetIOName(pNetIO)); #endif // find connection C4Network2IOConnection *pConn = GetConnection(addr, pNetIO); if (!pConn) pConn = GetConnectionByConnAddr(addr, pNetIO); if (!pConn) return; #if(C4NET2IO_DUMP_LEVEL > 0) // log Application.InteractiveThread.ThreadLogS("Network: %s connection to %s:%d %s (%s)", getNetIOName(pNetIO), inet_ntoa(addr.sin_addr), htons(addr.sin_port), pConn->isConnecting() ? "failed" : "closed" , szReason); #endif // already closed? ignore if (!pConn->isClosed()) // not accepted yet? count as connection failure pConn->SetStatus(pConn->isHalfAccepted() ? CS_Closed : CS_ConnectFail); // keep connection for main thread message pConn->AddRef(); // check for pending welcome packets SendConnPackets(); // signal to main thread Application.InteractiveThread.PushEvent(Ev_Net_Disconn, pConn); // don't remove connection from list - wait for postmortem or timeout }
bool C4Network2Res::StartLoad(int32_t iFromClient, const C4Network2ResChunkData &Available) { assert(pParent && pParent->getIOClass()); // all slots used? ignore if (iLoadCnt + 1 >= C4NetResMaxLoad) return true; // is there already a load by this client? ignore for (C4Network2ResLoad *pPos = pLoads; pPos; pPos = pPos->Next()) if (pPos->getByClient() == iFromClient) return true; // find chunk to retrieve int32_t iLoads[C4NetResMaxLoad]; int32_t i = 0; for (C4Network2ResLoad *pLoad = pLoads; pLoad; pLoad = pLoad->Next()) iLoads[i++] = pLoad->getChunk(); int32_t iRetrieveChunk = Chunks.GetChunkToRetrieve(Available, i, iLoads); // nothing? ignore if (iRetrieveChunk < 0 || (uint32_t)iRetrieveChunk >= Core.getChunkCnt()) return true; // search message connection for client C4Network2IOConnection *pConn = pParent->getIOClass()->GetMsgConnection(iFromClient); if (!pConn) return false; // send request if (!pConn->Send(MkC4NetIOPacket(PID_NetResReq, C4PacketResRequest(Core.getID(), iRetrieveChunk)))) { pConn->DelRef(); return false; } pConn->DelRef(); #ifdef C4NET2RES_DEBUG_LOG // log Application.InteractiveThread.ThreadLogS("Network: Res: requesting chunk %d of %d:%s (%s) from client %d", iRetrieveChunk, Core.getID(), Core.getFileName(), szFile, iFromClient); #endif // create load class C4Network2ResLoad *pnLoad = new C4Network2ResLoad(iRetrieveChunk, iFromClient); // add to list pnLoad->pNext = pLoads; pLoads = pnLoad; iLoadCnt++; // ok return true; }
// C4NetIO interface bool C4Network2IO::OnConn(const C4NetIO::addr_t &PeerAddr, const C4NetIO::addr_t &ConnectAddr, const C4NetIO::addr_t *pOwnAddr, C4NetIO *pNetIO) { // puncher answer? We just make sure here a connection /can/ be established, so close it instantly. if (pNetIO == pNetIO_UDP) if (PuncherAddr.sin_addr.s_addr && AddrEqual(PuncherAddr, ConnectAddr)) { // got an address? if (pOwnAddr) OnPunch(*pOwnAddr); // this is only a test connection - close it instantly return false; } #if(C4NET2IO_DUMP_LEVEL > 1) Application.InteractiveThread.ThreadLogS("OnConn: %s %s", C4TimeMilliseconds::Now().AsString().getData(), getNetIOName(pNetIO)); #endif // search connection C4Network2IOConnection *pConn = NULL; if (ConnectAddr.sin_addr.s_addr) pConn = GetConnectionByConnAddr(ConnectAddr, pNetIO); // not found? if (!pConn) { // allow connect? if (!fAllowConnect) return false; // create new connection object uint32_t iConnID = iNextConnID++; pConn = new C4Network2IOConnection(); pConn->Set(pNetIO, getNetIOProt(pNetIO), PeerAddr, ConnectAddr, CS_Connected, NULL, iConnID); // add to list AddConnection(pConn); } else { // already closed this connection (attempt)? if (pConn->isClosed()) return false; if (!pConn->isOpen()) { // change status pConn->SetStatus(CS_Connected); pConn->SetPeerAddr(PeerAddr); } } // send welcome packet, if appropriate SendConnPackets(); #if(C4NET2IO_DUMP_LEVEL > 0) // log Application.InteractiveThread.ThreadLogS("Network: got %s connection from %s:%d", getNetIOName(pNetIO), inet_ntoa(PeerAddr.sin_addr), htons(PeerAddr.sin_port)); #endif // do event (disabled - unused) // pConn->AddRef(); PushNetEv(NE_Conn, pConn); // ok return true; }
bool C4Network2IO::Ping() { bool fSuccess = true; // ping all connections for (C4Network2IOConnection *pConn = pConnList; pConn; pConn = pConn->pNext) if (pConn->isOpen()) { C4PacketPing Ping(pConn->getInPacketCounter(), pConn->getOutPacketCounter()); fSuccess &= pConn->Send(MkC4NetIOPacket(PID_Ping, Ping)); pConn->OnPing(); } return fSuccess; }
C4Network2IOConnection *C4Network2IO::GetDataConnection(int iClientID) // by main thread { CStdLock ConnListLock(&ConnListCSec); C4Network2IOConnection *pRes = NULL; for (C4Network2IOConnection *pConn = pConnList; pConn; pConn = pConn->pNext) if (pConn->isAccepted()) if (pConn->getClientID() == iClientID) if (pConn->getProtocol() == P_TCP || !pRes) pRes = pConn; // add reference if (pRes) pRes->AddRef(); return pRes; }
void C4Network2IO::HandlePacket(char cStatus, const C4PacketBase *pPacket, C4Network2IOConnection *pConn) { // security if (!pConn) return; #define GETPKT(type, name) \ assert(pPacket); const type &name = \ static_cast<const type &>(*pPacket); switch (cStatus) { case PID_Conn: // connection request { if (!pConn->isOpen()) break; // get packet GETPKT(C4PacketConn, rPkt) // set connection ID pConn->SetRemoteID(rPkt.getConnID()); // check auto-accept if (doAutoAccept(rPkt.getCCore(), *pConn)) { // send answer back C4PacketConnRe pcr(true, false, "auto accept"); if (!pConn->Send(MkC4NetIOPacket(PID_ConnRe, pcr))) pConn->Close(); // accept pConn->SetStatus(CS_HalfAccepted); pConn->SetCCore(rPkt.getCCore()); pConn->SetAutoAccepted(); } // note that this packet will get processed by C4Network2, too (main thread) } break; case PID_ConnRe: // connection request reply { if (!pConn->isOpen()) break; // conn not sent? That's fishy. // FIXME: Note this happens if the peer has exclusive connection mode on. if (!pConn->isConnSent()) { pConn->Close(); break; } // get packet GETPKT(C4PacketConnRe, rPkt) // auto accept connection if (rPkt.isOK()) { if (pConn->isHalfAccepted() && pConn->isAutoAccepted()) pConn->SetAccepted(); } } break; case PID_Ping: { if (!pConn->isOpen()) break; GETPKT(C4PacketPing, rPkt) // pong C4PacketPing PktPong = rPkt; pConn->Send(MkC4NetIOPacket(PID_Pong, PktPong)); // remove received packets from log pConn->ClearPacketLog(rPkt.getPacketCounter()); } break; case PID_Pong: { if (!pConn->isOpen()) break; GETPKT(C4PacketPing, rPkt); // save pConn->SetPingTime(rPkt.getTravelTime()); } break; case PID_FwdReq: { GETPKT(C4PacketFwd, rPkt); HandleFwdReq(rPkt, pConn); } break; case PID_Fwd: { GETPKT(C4PacketFwd, rPkt); // only received accidently? if (!rPkt.DoFwdTo(LCCore.getID())) break; // handle C4NetIOPacket Packet(rPkt.getData(), pConn->getPeerAddr()); HandlePacket(Packet, pConn, true); } break; case PID_PostMortem: { GETPKT(C4PacketPostMortem, rPkt); // Get connection C4Network2IOConnection *pConn = GetConnectionByID(rPkt.getConnID()); if (!pConn) return; // Handle all packets uint32_t iCounter; for (iCounter = pConn->getInPacketCounter(); ; iCounter++) { // Get packet const C4NetIOPacket *pPkt = rPkt.getPacket(iCounter); if (!pPkt) break; // Handle it HandlePacket(*pPkt, pConn, true); } // Log if (iCounter > pConn->getInPacketCounter()) Application.InteractiveThread.ThreadLogS("Network: Recovered %d packets", iCounter - pConn->getInPacketCounter()); // Remove the connection from our list if (!pConn->isClosed()) pConn->Close(); RemoveConnection(pConn); } break; } #undef GETPKT }
void C4Network2IO::CheckTimeout() { // acquire lock CStdLock ConnListLock(&ConnListCSec); // check all connections for timeout (use deletion-safe iteration method just in case) for (C4Network2IOConnection *pConn = pConnList, *pNext; pConn; pConn = pNext) { pNext = pConn->pNext; // status timeout if (!pConn->isClosed() && !pConn->isAccepted()) if (difftime(time(NULL), pConn->getTimestamp()) > C4NetAcceptTimeout) { Application.InteractiveThread.ThreadLogS("Network: connection accept timeout to %s:%d", inet_ntoa(pConn->getPeerAddr().sin_addr), htons(pConn->getPeerAddr().sin_port)); pConn->Close(); } // ping timeout if (pConn->isAccepted()) if ((pConn->getLag() != -1 ? pConn->getLag() : 1000 * difftime(time(NULL), pConn->getTimestamp())) > C4NetPingTimeout) { Application.InteractiveThread.ThreadLogS("%d %d %d", (int)pConn->getLag(), (int)time(NULL), (int)pConn->getTimestamp()); Application.InteractiveThread.ThreadLogS("Network: ping timeout to %s:%d", inet_ntoa(pConn->getPeerAddr().sin_addr), htons(pConn->getPeerAddr().sin_port)); pConn->Close(); } // delayed connection removal if (pConn->isClosed()) if (difftime(time(NULL), pConn->getTimestamp()) > C4NetAcceptTimeout) RemoveConnection(pConn); } }
void C4Network2IO::SendConnPackets() { CStdLock ConnListLock(&ConnListCSec); // exlusive conn? if (fExclusiveConn) // find a live connection for (C4Network2IOConnection *pConn = pConnList; pConn; pConn = pConn->pNext) if (pConn->isAccepted() || (!pConn->isClosed() && pConn->isConnSent())) // do not sent additional conn packets - no other connection should succeed return; // sent pending welcome packet(s) for (C4Network2IOConnection *pConn = pConnList; pConn; pConn = pConn->pNext) if (pConn->isOpen() && !pConn->isConnSent()) { // make packet CStdLock LCCoreLock(&LCCoreCSec); C4NetIOPacket Pkt = MkC4NetIOPacket(PID_Conn, C4PacketConn(LCCore, pConn->getID(), pConn->getPassword())); LCCoreLock.Clear(); // send if (!pConn->Send(Pkt)) pConn->Close(); else { // set flag pConn->SetConnSent(); // only one conn packet at a time if (fExclusiveConn) return; } } }