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 cProtocolRecognizer::HandlePacketStatusPing() { Int64 Timestamp; if (!m_Buffer.ReadBEInt64(Timestamp)) { return; } cPacketizer Pkt(*this, 0x01); // Pong packet Pkt.WriteBEInt64(Timestamp); }
void cProtocolRecognizer::DataReceived(const char * a_Data, size_t a_Size) { if (m_Protocol == nullptr) { if (!m_Buffer.Write(a_Data, a_Size)) { m_Client->Kick("Unsupported protocol version"); return; } if (m_InPingForUnrecognizedVersion) { // We already know the verison; handle it here. UInt32 PacketLen; UInt32 PacketID; if (!m_Buffer.ReadVarInt32(PacketLen)) { return; } if (!m_Buffer.ReadVarInt32(PacketID)) { return; } ASSERT(PacketID == 0x01); // Ping packet ASSERT(PacketLen == 9); // Payload of the packet ID and a UInt64 Int64 Data; if (!m_Buffer.ReadBEInt64(Data)) { return; } cPacketizer Pkt(*this, 0x01); // Pong packet Pkt.WriteBEInt64(Data); return; } if (!TryRecognizeProtocol()) { return; } // The protocol has just been recognized, dump the whole m_Buffer contents into it for parsing: AString Dump; m_Buffer.ResetRead(); m_Buffer.ReadAll(Dump); m_Protocol->DataReceived(Dump.data(), Dump.size()); } else { m_Protocol->DataReceived(a_Data, a_Size); } }
void cProtocolRecognizer::SendDisconnect(const AString & a_Reason) { if (m_Protocol != nullptr) { m_Protocol->SendDisconnect(a_Reason); } else { AString Message = Printf("{\"text\":\"%s\"}", EscapeString(a_Reason).c_str()); cPacketizer Pkt(*this, 0x00); // Disconnect packet (in login state) Pkt.WriteString(Message); } }
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); } }
void cProtocolRecognizer::HandlePacketStatusRequest(void) { cServer * Server = cRoot::Get()->GetServer(); AString ServerDescription = Server->GetDescription(); auto NumPlayers = static_cast<signed>(Server->GetNumPlayers()); auto MaxPlayers = static_cast<signed>(Server->GetMaxPlayers()); AString Favicon = Server->GetFaviconData(); cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, ServerDescription, NumPlayers, MaxPlayers, Favicon); // Version: Json::Value Version; Version["name"] = "Cuberite " MCS_CLIENT_VERSIONS; Version["protocol"] = MCS_LATEST_PROTOCOL_VERSION; // Players: Json::Value Players; Players["online"] = NumPlayers; Players["max"] = MaxPlayers; // TODO: Add "sample" // Description: Json::Value Description; Description["text"] = ServerDescription.c_str(); // Create the response: Json::Value ResponseValue; ResponseValue["version"] = Version; ResponseValue["players"] = Players; ResponseValue["description"] = Description; if (!Favicon.empty()) { ResponseValue["favicon"] = Printf("data:image/png;base64,%s", Favicon.c_str()); } Json::FastWriter Writer; AString Response = Writer.write(ResponseValue); cPacketizer Pkt(*this, 0x00); // Response packet Pkt.WriteString(Response); }
void cProtocolRecognizer::SendPingStatusResponse(void) { cServer * Server = cRoot::Get()->GetServer(); AString ServerDescription = Server->GetDescription(); int NumPlayers = Server->GetNumPlayers(); int MaxPlayers = Server->GetMaxPlayers(); AString Favicon = Server->GetFaviconData(); cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, ServerDescription, NumPlayers, MaxPlayers, Favicon); // Version: Json::Value Version; Version["name"] = "Cuberite " MCS_CLIENT_VERSIONS; Version["protocol"] = 0; // Force client to think this is an invalid version (no other good default) // Players: Json::Value Players; Players["online"] = NumPlayers; Players["max"] = MaxPlayers; // TODO: Add "sample" // Description: Json::Value Description; Description["text"] = ServerDescription.c_str(); // Create the response: Json::Value ResponseValue; ResponseValue["version"] = Version; ResponseValue["players"] = Players; ResponseValue["description"] = Description; if (!Favicon.empty()) { ResponseValue["favicon"] = Printf("data:image/png;base64,%s", Favicon.c_str()); } Json::StyledWriter Writer; AString Response = Writer.write(ResponseValue); cPacketizer Pkt(*this, 0x00); // Response packet Pkt.WriteString(Response); }