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