void C4Network2ClientList::HandlePacket(char cStatus, const C4PacketBase *pBasePkt, C4Network2IOConnection *pConn) { // find associated client C4Network2Client *pClient = GetClient(pConn); if (!pClient) return; #define GETPKT(type, name) \ assert(pBasePkt); \ const type &name = /*dynamic_cast*/ static_cast<const type &>(*pBasePkt); switch (cStatus) { case PID_Addr: // address propagation { GETPKT(C4PacketAddr, rPkt) // find client pClient = GetClientByID(rPkt.getClientID()); if (pClient) { C4Network2Address addr = rPkt.getAddr(); // IP zero? Set to IP from where the packet came if (addr.isIPNull()) addr.SetIP(pConn->getPeerAddr().sin_addr); // add (no announce) if (pClient->AddAddr(addr, true)) // new address? Try to connect pClient->DoConnectAttempt(pIO); } } break; } #undef GETPKT }
bool C4Network2Client::DoTCPSimultaneousOpen(class C4Network2IO *pIO, const C4Network2Address &addr) { if (!pIO->getNetIO(P_TCP)) return false; // Did we already bind a socket? if (TcpSimOpenSocket) { LogSilentF("Network: connecting client %s on %s with TCP simultaneous open...", getName(), addr.getAddr().ToString().getData()); return pIO->ConnectWithSocket(addr.getAddr(), addr.getProtocol(), pClient->getCore(), std::move(TcpSimOpenSocket)); } else { // No - bind one, inform peer, and schedule a connection attempt. auto NetIOTCP = dynamic_cast<C4NetIOTCP*>(pIO->getNetIO(P_TCP)); auto bindAddr = pParent->GetLocal()->IPv6AddrFromPuncher; // We need to know an address that works. if (bindAddr.IsNull()) return false; bindAddr.SetPort(0); TcpSimOpenSocket = NetIOTCP->Bind(bindAddr); auto boundAddr = TcpSimOpenSocket->GetAddress(); LogSilentF("Network: %s TCP simultaneous open request for client %s from %s...", addr.isIPNull() ? "initiating" : "responding to", getName(), boundAddr.ToString().getData()); // Send address we bound to to the client. if (!SendMsg(MkC4NetIOPacket(PID_TCPSimOpen, C4PacketTCPSimOpen(pParent->GetLocal()->getID(), C4Network2Address(boundAddr, P_TCP))))) return false; if (!addr.isIPNull()) { // We need to delay the connection attempt a bit. Unfortunately, // waiting for the next tick would usually take way too much time. // Instead, we block the main thread for a very short time and hope // that noone notices... int ping = getMsgConn()->getLag(); std::this_thread::sleep_for(std::chrono::milliseconds(std::min(ping / 2, 10))); DoTCPSimultaneousOpen(pIO, addr); } return true; } }
bool C4Network2Address::operator == (const C4Network2Address &addr2) const { return eProtocol == addr2.getProtocol() && AddrEqual(addr, addr2.getAddr()); }
void C4Network2ClientDlg::UpdateText() { // begin updating (clears previous text) BeginUpdateText(); // get core const C4Client *pClient = Game.Clients.getClientByID(iClientID); if (!pClient) { // client ID unknown AddLineFmt(LoadResStr("IDS_NET_CLIENT_INFO_UNKNOWNID"), iClientID); } else { // get client (may be nullptr for local info) C4Network2Client *pNetClient = pClient->getNetClient(); // show some info StdCopyStrBuf strInfo; if (!pClient->isActivated()) { strInfo.Append(LoadResStr("IDS_MSG_INACTIVE")); strInfo.Append(" "); } if (pClient->isLocal()) { strInfo.Append(LoadResStr("IDS_MSG_LOCAL")); strInfo.Append(" "); } strInfo.AppendFormat("%s %s (ID #%d)%s", LoadResStr(pClient->isHost() ? "IDS_MSG_HOST" : "IDS_MSG_CLIENT"), pClient->getName(), iClientID, ::Network.isHost() && pNetClient && !pNetClient->isReady() ? " (!ack)" : ""); AddLine(strInfo.getData()); // show addresses int iCnt; if ((iCnt=pNetClient->getAddrCnt())) { AddLine(LoadResStr("IDS_NET_CLIENT_INFO_ADDRESSES")); for (int i=0; i<iCnt; ++i) { C4Network2Address addr = pNetClient->getAddr(i); AddLineFmt(" %d: %s", i, // adress index addr.toString().getData()); } } else AddLine(LoadResStr("IDS_NET_CLIENT_INFO_NOADDRESSES")); // show connection if (pNetClient) { // connections if (pNetClient->isConnected()) { AddLineFmt(LoadResStr("IDS_NET_CLIENT_INFO_CONNECTIONS"), pNetClient->getMsgConn() == pNetClient->getDataConn() ? "Msg/Data" : "Msg", ::Network.NetIO.getNetIOName(pNetClient->getMsgConn()->getNetClass()), pNetClient->getMsgConn()->getPeerAddr().ToString().getData(), pNetClient->getMsgConn()->getPingTime()); if (pNetClient->getMsgConn() != pNetClient->getDataConn()) AddLineFmt(LoadResStr("IDS_NET_CLIENT_INFO_CONNDATA"), ::Network.NetIO.getNetIOName(pNetClient->getDataConn()->getNetClass()), pNetClient->getDataConn()->getPeerAddr().ToString().getData(), pNetClient->getDataConn()->getPingTime()); } else AddLine(LoadResStr("IDS_NET_CLIENT_INFO_NOCONNECTIONS")); } } // update done EndUpdateText(); }