Exemple #1
0
bool C4Network2IO::Connect(const C4NetIO::addr_t &addr, C4Network2IOProtocol eProt, const C4ClientCore &nCCore, const char *szPassword) // by main thread
{
    // get network class
    C4NetIO *pNetIO = getNetIO(eProt);
    if (!pNetIO) return false;
    // already connected/connecting?
    if (GetConnectionByConnAddr(addr, pNetIO)) return true;
    // assign new connection ID, peer address isn't known yet
    uint32_t iConnID = iNextConnID++;
    C4NetIO::addr_t paddr;
    ZeroMem(&paddr, sizeof paddr);
    // create connection object and add to list
    C4Network2IOConnection *pConn = new C4Network2IOConnection();
    pConn->Set(pNetIO, eProt, paddr, addr, CS_Connect, szPassword, iConnID);
    pConn->SetCCore(nCCore);
    AddConnection(pConn);
    // connect
    if (!pConn->Connect())
    {
        // show error
        LogF("Network: could not connect to %s:%d using %s: %s", inet_ntoa(addr.sin_addr), htons(addr.sin_port),
             getNetIOName(pNetIO), pNetIO->GetError() ? pNetIO->GetError() : "");
        pNetIO->ResetError();
        // remove class
        RemoveConnection(pConn);
        return false;
    }
    // ok, wait for connection
    return true;
}
Exemple #2
0
void C4Network2IO::OnPacket(const class C4NetIOPacket &rPacket, C4NetIO *pNetIO)
{
#if C4NET2IO_DUMP_LEVEL > 0
    auto tTime = C4TimeMilliseconds::Now();
#endif
#if(C4NET2IO_DUMP_LEVEL > 1)
    Application.InteractiveThread.ThreadLogS("OnPacket: %s status %02x %s",
            C4TimeMilliseconds::Now().AsString().getData(),
            rPacket.getStatus(), getNetIOName(pNetIO));
#endif
    if (!rPacket.getSize()) return;
    // find connection
    C4Network2IOConnection *pConn = GetConnection(rPacket.getAddr(), pNetIO);
    if (!pConn) {
        Application.InteractiveThread.ThreadLog("Network: could not find connection for packet from %s:%d!", inet_ntoa(rPacket.getAddr().sin_addr), htons(rPacket.getAddr().sin_port));
        return;
    }
#if(C4NET2IO_DUMP_LEVEL > 2)
    uint32_t iFindConnectionBlocked = C4TimeMilliseconds::Now() - tTime;
    if (iFindConnectionBlocked > 100)
        Application.InteractiveThread.ThreadLogS("OnPacket: ... blocked %d ms for finding the connection!", iFindConnectionBlocked);
#endif
    // notify
    pConn->OnPacketReceived(rPacket.getStatus());
    // handle packet
    HandlePacket(rPacket, pConn, true);
    // log time
#if(C4NET2IO_DUMP_LEVEL > 1)
    uint32_t iHandlingBlocked = C4TimeMilliseconds::Now() - tTime;
    if (iHandlingBlocked > 100)
        Application.InteractiveThread.ThreadLogS("OnPacket: ... blocked %d ms for handling!", iHandlingBlocked);
#endif
}
void C4Network2ClientListBox::ConnectionListItem::Update()
{
	C4Network2IOConnection *pConn = GetConnection();
	if (!pConn)
	{
		// No connection: Shouldn't happen
		pDesc->SetText("???");
		pPing->SetText("???");
		return;
	}
	// update connection ping
	int iPing = pConn->getLag();
	pPing->SetText(FormatString("%d ms", iPing).getData());
	// update description
	// get connection usage
	const char *szConnType;
	C4Network2Client *pNetClient = ::Network.Clients.GetClientByID(iClientID);
	if (pNetClient->getDataConn() == pNetClient->getMsgConn())
		szConnType = "Data/Msg";
	else if (iConnID)
		szConnType = "Msg";
	else
		szConnType = "Data";
	// display info
	pDesc->SetText(FormatString("%s: %s (%s l%d)",
	                            szConnType,
	                            ::Network.NetIO.getNetIOName(pConn->getNetClass()),
	                            pConn->getPeerAddr().ToString().getData(),
	                            pConn->getPacketLoss()).getData());
}
Exemple #4
0
int C4Network2IO::getConnectionCount()  // by main thread
{
    int iCount = 0;
    CStdLock ConnListLock(&ConnListCSec);
    for (C4Network2IOConnection *pConn = pConnList; pConn; pConn = pConn->pNext)
        if (!pConn->isClosed())
            iCount++;
    return iCount;
}
Exemple #5
0
C4Network2IOConnection *C4Network2IO::GetConnectionByConnAddr(const C4NetIO::addr_t &addr, C4NetIO *pNetIO) // by both
{
    CStdLock ConnListLock(&ConnListCSec);
    // search
    for (C4Network2IOConnection *pConn = pConnList; pConn; pConn = pConn->pNext)
        if (pConn->getNetClass() == pNetIO && AddrEqual(pConn->getConnectAddr(), addr))
            return pConn;
    return NULL;
}
Exemple #6
0
C4Network2IOConnection *C4Network2IO::GetConnectionByID(uint32_t iConnID) // by thread
{
    CStdLock ConnListLock(&ConnListCSec);
    // search
    for (C4Network2IOConnection *pConn = pConnList; pConn; pConn = pConn->pNext)
        if (pConn->getID() == iConnID)
            return pConn;
    return NULL;
}
void C4Network2ClientListBox::ConnectionListItem::OnButtonDisconnect(C4GUI::Control *pButton)
{
	// close connection
	C4Network2IOConnection *pConn = GetConnection();
	if (pConn)
	{
		pConn->Close();
	}
}
Exemple #8
0
void C4Network2IO::BeginBroadcast(bool fSelectAll)
{
    // lock
    BroadcastCSec.Enter();
    // reset all broadcast flags
    CStdLock ConnListLock(&ConnListCSec);
    for (C4Network2IOConnection *pConn = pConnList; pConn; pConn = pConn->pNext)
        if (pConn->isOpen())
            pConn->SetBroadcastTarget(fSelectAll);
}
Exemple #9
0
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::Clear() // by main thread
{
    // process remaining events
    C4InteractiveThread &Thread = Application.InteractiveThread;
    Thread.ProcessEvents();
    // clear event callbacks
    Thread.ClearCallback(Ev_Net_Conn, this);
    Thread.ClearCallback(Ev_Net_Disconn, this);
    Thread.ClearCallback(Ev_Net_Packet, this);
    // close all connections
    CStdLock ConnListLock(&ConnListCSec);
    for (C4Network2IOConnection *pConn = pConnList, *pNext; pConn; pConn = pNext)
    {
        pNext = pConn->pNext;
        // close
        pConn->Close();
        RemoveConnection(pConn);
    }
    // reset list
    pConnList = NULL;
    ConnListLock.Clear();
    // close net i/o classes
    Thread.RemoveProc(this);
    if (pNetIODiscover) {
        Thread.RemoveProc(pNetIODiscover);
        delete pNetIODiscover;
        pNetIODiscover = NULL;
    }
    if (pNetIO_TCP) {
        Thread.RemoveProc(pNetIO_TCP);
        delete pNetIO_TCP;
        pNetIO_TCP = NULL;
    }
    if (pNetIO_UDP) {
        Thread.RemoveProc(pNetIO_UDP);
        delete pNetIO_UDP;
        pNetIO_UDP = NULL;
    }
    if (pRefServer) {
        Thread.RemoveProc(pRefServer);
        delete pRefServer;
        pRefServer = NULL;
    }
    if (UPnPMgr) {
        delete UPnPMgr;
        UPnPMgr = NULL;
    }
    // remove auto-accepts
    ClearAutoAccept();
    // reset flags
    fAllowConnect = fExclusiveConn = false;
    // reset connection ID
    iNextConnID = 0;
}
Exemple #11
0
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;
}
Exemple #12
0
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);
  }
}
Exemple #13
0
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;
}
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;
}
Exemple #15
0
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;
}
Exemple #16
0
void C4Network2Stats::ExecuteSecond() {
  statFPS.RecordValue(C4Graph::ValueType(Game.FPS));
  statNetI.RecordValue(
      C4Graph::ValueType(Game.Network.NetIO.getProtIRate(P_TCP) +
                         Game.Network.NetIO.getProtIRate(P_UDP)));
  statNetO.RecordValue(
      C4Graph::ValueType(Game.Network.NetIO.getProtORate(P_TCP) +
                         Game.Network.NetIO.getProtORate(P_UDP)));
  // pings for all clients
  C4Network2Client *pClient = NULL;
  while (pClient = Game.Network.Clients.GetNextClient(pClient))
    if (pClient->getStatPing()) {
      int iPing = 0;
      C4Network2IOConnection *pConn = pClient->getMsgConn();
      if (pConn) iPing = pConn->getLag();
      pClient->getStatPing()->RecordValue(C4Graph::ValueType(iPing));
    }
  ++SecondCounter;
}
Exemple #17
0
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);
    }
}
Exemple #18
0
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;
    }
}
Exemple #19
0
void C4Network2IO::GenerateStatistics(int iInterval)
{
    int iTCPIRateSum = 0, iTCPORateSum = 0, iUDPIRateSum = 0, iUDPORateSum = 0;

    // acquire lock, get connection statistics
    CStdLock ConnListLock(&ConnListCSec);
    for (C4Network2IOConnection *pConn = pConnList; pConn; pConn = pConn->pNext)
        if (pConn->isOpen())
        {
            bool fTCP = pConn->getNetClass() == pNetIO_TCP;
            pConn->DoStatistics(iInterval, fTCP ? &iTCPIRateSum : &iUDPIRateSum,
                                fTCP ? &iTCPORateSum : &iUDPORateSum);
        }
    ConnListLock.Clear();

    // get broadcast statistics
    int inTCPBCRate = 0, inUDPBCRate = 0;
    if (pNetIO_TCP) pNetIO_TCP->GetStatistic(&inTCPBCRate);
    if (pNetIO_UDP) pNetIO_UDP->GetStatistic(&inUDPBCRate);

    // normalize everything
    iTCPIRateSum = iTCPIRateSum * 1000 / iInterval;
    iTCPORateSum = iTCPORateSum * 1000 / iInterval;
    iUDPIRateSum = iUDPIRateSum * 1000 / iInterval;
    iUDPORateSum = iUDPORateSum * 1000 / iInterval;
    inTCPBCRate = inTCPBCRate * 1000 / iInterval;
    inUDPBCRate = inUDPBCRate * 1000 / iInterval;

    // clear
    if (pNetIO_TCP) pNetIO_TCP->ClearStatistic();
    if (pNetIO_UDP) pNetIO_UDP->ClearStatistic();

    // save back
    iTCPIRate = iTCPIRateSum;
    iTCPORate = iTCPORateSum;
    iTCPBCRate = inTCPBCRate;
    iUDPIRate = iUDPIRateSum;
    iUDPORate = iUDPORateSum;
    iUDPBCRate = inUDPBCRate;
}
Exemple #20
0
void C4Network2IO::OnDisconn(const C4NetIO::addr_t &addr, C4NetIO *pNetIO, const char *szReason)
{
    // punch?
    if (pNetIO == pNetIO_UDP)
        if (PuncherAddr.sin_addr.s_addr && AddrEqual(PuncherAddr, addr))
        {
            ZeroMem(&PuncherAddr, sizeof(PuncherAddr));
            return;
        }
#if(C4NET2IO_DUMP_LEVEL > 1)
    Application.InteractiveThread.ThreadLogS("OnDisconn: %s %s",
            C4TimeMilliseconds::Now().AsString().getData(),
            getNetIOName(pNetIO));
#endif
    // find connection
    C4Network2IOConnection *pConn = GetConnection(addr, pNetIO);
    if (!pConn) pConn = GetConnectionByConnAddr(addr, pNetIO);
    if (!pConn) return;
#if(C4NET2IO_DUMP_LEVEL > 0)
    // log
    Application.InteractiveThread.ThreadLogS("Network: %s connection to %s:%d %s (%s)",
            getNetIOName(pNetIO), inet_ntoa(addr.sin_addr), htons(addr.sin_port), pConn->isConnecting() ? "failed" : "closed" , szReason);
#endif
    // already closed? ignore
    if (!pConn->isClosed())
        // not accepted yet? count as connection failure
        pConn->SetStatus(pConn->isHalfAccepted() ? CS_Closed : CS_ConnectFail);
    // keep connection for main thread message
    pConn->AddRef();
    // check for pending welcome packets
    SendConnPackets();
    // signal to main thread
    Application.InteractiveThread.PushEvent(Ev_Net_Disconn, pConn);
    // don't remove connection from list - wait for postmortem or timeout
}
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;
}
Exemple #22
0
// C4NetIO interface
bool C4Network2IO::OnConn(const C4NetIO::addr_t &PeerAddr, const C4NetIO::addr_t &ConnectAddr, const C4NetIO::addr_t *pOwnAddr, C4NetIO *pNetIO)
{
    // puncher answer? We just make sure here a connection /can/ be established, so close it instantly.
    if (pNetIO == pNetIO_UDP)
        if (PuncherAddr.sin_addr.s_addr && AddrEqual(PuncherAddr, ConnectAddr))
        {
            // got an address?
            if (pOwnAddr)
                OnPunch(*pOwnAddr);
            // this is only a test connection - close it instantly
            return false;
        }
#if(C4NET2IO_DUMP_LEVEL > 1)
    Application.InteractiveThread.ThreadLogS("OnConn: %s %s",
            C4TimeMilliseconds::Now().AsString().getData(),
            getNetIOName(pNetIO));
#endif
    // search connection
    C4Network2IOConnection *pConn = NULL;
    if (ConnectAddr.sin_addr.s_addr)
        pConn = GetConnectionByConnAddr(ConnectAddr, pNetIO);
    // not found?
    if (!pConn)
    {
        // allow connect?
        if (!fAllowConnect) return false;
        // create new connection object
        uint32_t iConnID = iNextConnID++;
        pConn = new C4Network2IOConnection();
        pConn->Set(pNetIO, getNetIOProt(pNetIO), PeerAddr, ConnectAddr, CS_Connected, NULL, iConnID);
        // add to list
        AddConnection(pConn);
    }
    else
    {
        // already closed this connection (attempt)?
        if (pConn->isClosed())
            return false;
        if (!pConn->isOpen())
        {
            // change status
            pConn->SetStatus(CS_Connected);
            pConn->SetPeerAddr(PeerAddr);
        }
    }
    // send welcome packet, if appropriate
    SendConnPackets();
#if(C4NET2IO_DUMP_LEVEL > 0)
    // log
    Application.InteractiveThread.ThreadLogS("Network: got %s connection from %s:%d", getNetIOName(pNetIO), inet_ntoa(PeerAddr.sin_addr), htons(PeerAddr.sin_port));
#endif
    // do event (disabled - unused)
    // pConn->AddRef(); PushNetEv(NE_Conn, pConn);
    // ok
    return true;
}
Exemple #23
0
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;
}
Exemple #24
0
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;
}
Exemple #25
0
void C4Network2IO::HandlePacket(char cStatus, const C4PacketBase *pPacket, C4Network2IOConnection *pConn)
{
    // security
    if (!pConn) return;

#define GETPKT(type, name) \
    assert(pPacket); const type &name = \
     static_cast<const type &>(*pPacket);

    switch (cStatus)
    {

    case PID_Conn: // connection request
    {
        if (!pConn->isOpen()) break;
        // get packet
        GETPKT(C4PacketConn, rPkt)
        // set connection ID
        pConn->SetRemoteID(rPkt.getConnID());
        // check auto-accept
        if (doAutoAccept(rPkt.getCCore(), *pConn))
        {
            // send answer back
            C4PacketConnRe pcr(true, false, "auto accept");
            if (!pConn->Send(MkC4NetIOPacket(PID_ConnRe, pcr)))
                pConn->Close();
            // accept
            pConn->SetStatus(CS_HalfAccepted);
            pConn->SetCCore(rPkt.getCCore());
            pConn->SetAutoAccepted();
        }
        // note that this packet will get processed by C4Network2, too (main thread)
    }
    break;

    case PID_ConnRe: // connection request reply
    {
        if (!pConn->isOpen()) break;
        // conn not sent? That's fishy.
        // FIXME: Note this happens if the peer has exclusive connection mode on.
        if (!pConn->isConnSent())
        {
            pConn->Close();
            break;
        }
        // get packet
        GETPKT(C4PacketConnRe, rPkt)
        // auto accept connection
        if (rPkt.isOK())
        {
            if (pConn->isHalfAccepted() && pConn->isAutoAccepted())
                pConn->SetAccepted();
        }
    }
    break;

    case PID_Ping:
    {
        if (!pConn->isOpen()) break;
        GETPKT(C4PacketPing, rPkt)
        // pong
        C4PacketPing PktPong = rPkt;
        pConn->Send(MkC4NetIOPacket(PID_Pong, PktPong));
        // remove received packets from log
        pConn->ClearPacketLog(rPkt.getPacketCounter());
    }
    break;

    case PID_Pong:
    {
        if (!pConn->isOpen()) break;
        GETPKT(C4PacketPing, rPkt);
        // save
        pConn->SetPingTime(rPkt.getTravelTime());
    }
    break;

    case PID_FwdReq:
    {
        GETPKT(C4PacketFwd, rPkt);
        HandleFwdReq(rPkt, pConn);
    }
    break;

    case PID_Fwd:
    {
        GETPKT(C4PacketFwd, rPkt);
        // only received accidently?
        if (!rPkt.DoFwdTo(LCCore.getID())) break;
        // handle
        C4NetIOPacket Packet(rPkt.getData(), pConn->getPeerAddr());
        HandlePacket(Packet, pConn, true);
    }
    break;

    case PID_PostMortem:
    {
        GETPKT(C4PacketPostMortem, rPkt);
        // Get connection
        C4Network2IOConnection *pConn = GetConnectionByID(rPkt.getConnID());
        if (!pConn) return;
        // Handle all packets
        uint32_t iCounter;
        for (iCounter = pConn->getInPacketCounter(); ; iCounter++)
        {
            // Get packet
            const C4NetIOPacket *pPkt = rPkt.getPacket(iCounter);
            if (!pPkt) break;
            // Handle it
            HandlePacket(*pPkt, pConn, true);
        }
        // Log
        if (iCounter > pConn->getInPacketCounter())
            Application.InteractiveThread.ThreadLogS("Network: Recovered %d packets", iCounter - pConn->getInPacketCounter());
        // Remove the connection from our list
        if (!pConn->isClosed())
            pConn->Close();
        RemoveConnection(pConn);
    }
    break;

    }

#undef GETPKT
}
Exemple #26
0
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);
    }
}
Exemple #27
0
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;
            }
        }

}