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