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); } }
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; }
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; } } }
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); } }
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; }
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; }