Beispiel #1
0
bool C4Record::Rec(C4PacketType eCtrlType, C4ControlPacket *pCtrl, int iFrame) {
  if (!fRecording) return false;
  // create copy
  C4IDPacket Pkt = C4IDPacket(eCtrlType, pCtrl, false);
  if (!Pkt.getPkt()) return false;
  C4ControlPacket *pCtrlCpy = static_cast<C4ControlPacket *>(Pkt.getPkt());
  // prepare for recording
  pCtrlCpy->PreRec(this);
  // record it
  return Rec(iFrame, DecompileToBuf<StdCompilerBinWrite>(Pkt), RCT_CtrlPkt);
}
Beispiel #2
0
void C4PacketList::CompileFunc(StdCompiler *pComp)
{
	// unpack packets
	if (pComp->isCompiler())
	{
		// Read until no further sections available
		while (pComp->Name("IDPacket"))
		{
			// Read the packet
			C4IDPacket *pPkt = new C4IDPacket();
			try
			{
				pComp->Value(*pPkt);
				pComp->NameEnd();
			}
			catch (...)
			{
				delete pPkt;
				throw;
			}
			// Terminator?
			if (!pPkt->getPkt()) { delete pPkt; break; }
			// Add to list
			Add(pPkt);
		}
		pComp->NameEnd();
	}
	else
	{
		// Write all packets
		for (C4IDPacket *pPkt = pFirst; pPkt; pPkt = pPkt->pNext)
			pComp->Value(mkNamingAdapt(*pPkt, "IDPacket"));
		// Terminate, if no naming is available
		if (!pComp->hasNaming())
		{
			C4IDPacket Pkt;
			pComp->Value(mkNamingAdapt(Pkt, "IDPacket"));
		}
	}
}
Beispiel #3
0
void C4Playback::Check(C4RecordChunkType eType, const uint8_t *pData,
                       int iSize) {
  // only if enabled
  if (DoNoDebugRec > 0) return;
  if (Game.FrameCounter < DEBUGREC_START_FRAME) return;

  C4PktDebugRec PktInReplay;
  bool fHasPacketFromHead = false;
#ifdef DEBUGREC_EXTFILE
#ifdef DEBUGREC_EXTFILE_WRITE
  // writing of external debugrec file
  DbgRecFile.Write(&eType, sizeof eType);
  int32_t iSize32 = iSize;
  DbgRecFile.Write(&iSize32, sizeof iSize32);
  DbgRecFile.Write(pData, iSize);
  return;
#else
  int32_t iSize32 = 0;
  C4RecordChunkType eTypeRec = RCT_Undefined;
  DbgRecFile.Read(&eTypeRec, sizeof eTypeRec);
  DbgRecFile.Read(&iSize32, sizeof iSize32);
  if (iSize32) {
    StdBuf buf;
    buf.SetSize(iSize32);
    DbgRecFile.Read(buf.getMData(), iSize32);
    PktInReplay = C4PktDebugRec(eTypeRec, buf);
  }
#endif
#else
  // check debug rec in list
  C4IDPacket *pkt;
  if (pkt = DebugRec.firstPkt()) {
    // copy from list
    PktInReplay = *static_cast<C4PktDebugRec *>(pkt->getPkt());
    DebugRec.Delete(pkt);
  } else {
    // special sync check skip...
    while (currChunk != chunks.end() && currChunk->Type == RCT_CtrlPkt) {
      C4IDPacket Packet(*currChunk->pPkt);
      C4ControlPacket *pCtrlPck =
          static_cast<C4ControlPacket *>(Packet.getPkt());
      assert(!pCtrlPck->Sync());
      Game.Control.ExecControlPacket(Packet.getPktType(), pCtrlPck);
      NextChunk();
    }
    // record end?
    if (currChunk == chunks.end() || currChunk->Type == RCT_End || Finished) {
      Log("DebugRec end: All in sync!");
      ++DoNoDebugRec;
      return;
    }
    // unpack directly from head
    if (currChunk->Type != eType) {
      DebugRecError(FormatString("Playback type %x, this type %x",
                                 currChunk->Type, eType).getData());
      return;
    }
    PktInReplay = *currChunk->pDbg;
    fHasPacketFromHead = true;
  }
#endif  // DEBUGREC_EXTFILE
  // record end?
  if (PktInReplay.getType() == RCT_End) {
    Log("DebugRec end: All in sync (2)!");
    ++DoNoDebugRec;
    return;
  }
  // replay packet is unpacked to PktInReplay now; check it
  if (PktInReplay.getType() != eType) {
    DebugRecError(FormatString("Type %s != %s",
                               GetRecordChunkTypeName(PktInReplay.getType()),
                               GetRecordChunkTypeName(eType)).getData());
    return;
  }
  if (PktInReplay.getSize() != iSize) {
    DebugRecError(FormatString("Size %d != %d", (int)PktInReplay.getSize(),
                               (int)iSize).getData());
  }
  // check packet data
  if (memcmp(PktInReplay.getData(), pData, iSize)) {
    StdStrBuf sErr;
    sErr.Format("DbgRecPkt Type %s, size %d", GetRecordChunkTypeName(eType),
                iSize);
    sErr.Append(" Replay: ");
    StdBuf replay(PktInReplay.getData(), PktInReplay.getSize());
    sErr.Append(GetDbgRecPktData(eType, replay));
    sErr.Append(" Here: ");
    StdBuf here(pData, iSize);
    sErr.Append(GetDbgRecPktData(eType, here));
    DebugRecError(sErr.getData());
  }
  // packet is fine, jump over it
  if (fHasPacketFromHead) NextChunk();
}
Beispiel #4
0
void C4Playback::Strip() {
  // Strip what?
  const bool fStripPlayers = false;
  const bool fStripSyncChecks = false;
  const bool fStripDebugRec = true;
  const bool fCheckCheat = false;
  const bool fStripMessages = true;
  // const bool fCheckEMControl = true;
  const int32_t iEndFrame = -1;
  // Iterate over chunk list
  for (chunks_t::iterator i = chunks.begin(); i != chunks.end();) {
    // Strip rest of record?
    if (iEndFrame >= 0 && i->Frame > iEndFrame) {
      // Remove this and all remaining chunks
      while (i != chunks.end()) {
        i->Delete();
        i = chunks.erase(i);
      }
      // Push new End-Chunk
      C4RecordChunk EndChunk;
      EndChunk.Frame = iEndFrame;
      EndChunk.Type = RCT_End;
      chunks.push_back(EndChunk);
      // Done
      break;
    }
    switch (i->Type) {
      case RCT_Ctrl: {
        // Iterate over controls
        C4Control *pCtrl = i->pCtrl;
        for (C4IDPacket *pPkt = pCtrl->firstPkt(), *pNext; pPkt; pPkt = pNext) {
          pNext = pCtrl->nextPkt(pPkt);
          switch (pPkt->getPktType()) {
            // Player join: Strip player file (if possible)
            case CID_JoinPlr:
              if (fStripPlayers) {
                C4ControlJoinPlayer *pJoinPlr =
                    static_cast<C4ControlJoinPlayer *>(pPkt->getPkt());
                pJoinPlr->Strip();
              }
              break;
            // EM commands: May be cheats, so log them
            case CID_Script:
            case CID_EMMoveObj:
            case CID_EMDrawTool:
              if (fCheckCheat)
                Log(DecompileToBuf<StdCompilerINIWrite>(
                        mkNamingAdapt(*pPkt, FormatString("Frame %d", i->Frame)
                                                 .getData())).getData());
              break;
            // Strip sync check
            case CID_SyncCheck:
              if (fStripSyncChecks) {
                i->pCtrl->Remove(pPkt);
              }
              break;
          }
        }
        // Strip empty control lists (always)
        if (!pCtrl->firstPkt()) {
          i->Delete();
          i = chunks.erase(i);
        } else
          i++;
      } break;
      case RCT_CtrlPkt: {
        bool fStripThis = false;
        switch (i->pPkt->getPktType()) {
          // EM commands: May be cheats, so log them
          case CID_Script:
          case CID_EMMoveObj:
          case CID_EMDrawTool:
            if (fCheckCheat)
              Log(DecompileToBuf<StdCompilerINIWrite>(
                      mkNamingAdapt(*i->pPkt, FormatString("Frame %d", i->Frame)
                                                  .getData())).getData());
            break;
          // Strip some stuff
          case CID_SyncCheck:
            if (fStripSyncChecks) fStripThis = true;
            break;
          case CID_Message:
            if (fStripMessages) fStripThis = true;
            break;
        }
        if (fStripThis) {
          i->Delete();
          i = chunks.erase(i);
        } else
          i++;
      } break;
      case RCT_End:
        i++;
        break;
      default:
        // Strip debugrec
        if (fStripDebugRec) {
          i->Delete();
          i = chunks.erase(i);
        } else
          i++;
    }
  }
}
Beispiel #5
0
bool C4Network2IO::HandlePacket(const C4NetIOPacket &rPacket, C4Network2IOConnection *pConn, bool fThread)
{
    // security: add connection reference
    if (!pConn) return false;
    pConn->AddRef();

    // accept only PID_Conn and PID_Ping on non-accepted connections
    if(!pConn->isHalfAccepted())
        if(rPacket.getStatus() != PID_Conn && rPacket.getStatus() != PID_Ping && rPacket.getStatus() != PID_ConnRe)
            return false;

    // unpack packet (yet another no-idea-why-it's-needed-cast)
    C4IDPacket Pkt;
    C4PacketBase &PktB = Pkt;
    try
    {
        PktB.unpack(rPacket);
    }
    catch (StdCompiler::Exception *pExc)
    {
        Application.InteractiveThread.ThreadLog("Network: error: Failed to unpack packet id %02x: %s", rPacket.getStatus(), pExc->Msg.getData());
        delete pExc;
#ifndef _DEBUG
        pConn->Close();
#endif
        return false;
    }

    // dump packet (network thread only)
#if(C4NET2IO_DUMP_LEVEL > 0)
    if (Config.Network.PacketLogging && fThread && Pkt.getPktType() != PID_Ping && Pkt.getPktType() != PID_Pong && Pkt.getPktType() != PID_NetResData)
    {
        // StdStrBuf PacketDump = DecompileToBuf<StdCompilerINIWrite>(mkNamingAdaptrPacket);
        StdStrBuf PacketHeader = FormatString("HandlePacket: %s by %s:%d (%lu bytes, counter %d)",
                                              C4TimeMilliseconds::Now().AsString().getData(),
                                              inet_ntoa(pConn->getPeerAddr().sin_addr), htons(pConn->getPeerAddr().sin_port),
                                              static_cast<unsigned long>(rPacket.getSize()), pConn->getInPacketCounter());
        StdStrBuf Dump = DecompileToBuf<StdCompilerINIWrite>(mkNamingAdapt(Pkt, PacketHeader.getData()));
        // Put it directly. The standard functions behind StdBuf.Format seem to choke when you pass them too much data.
        Application.InteractiveThread.PushEvent(Ev_LogSilent, Dump.GrabPointer());
    }
#endif

    // search packet handling data
    bool fSendToMainThread = false, fHandled = false;
    for (const C4PktHandlingData *pHData = PktHandlingData; pHData->ID != PID_None; pHData++)
        if (pHData->ID == rPacket.getStatus())
        {
            // correct thread?
            if (!pHData->ProcByThread == !fThread)
            {
                // connection accepted?
                if (pHData->AcceptedOnly || pConn->isAccepted() || pConn->isClosed())
                {
                    fHandled = true;
#if(C4NET2IO_DUMP_LEVEL > 2)
                    C4TimeMilliseconds tStart = C4TimeMilliseconds::Now();
#endif

                    // call handler(s)
                    CallHandlers(pHData->HandlerID, &Pkt, pConn, fThread);

#if(C4NET2IO_DUMP_LEVEL > 2)
                    uint32_t iBlockedTime = C4TimeMilliseconds::Now() - tStart;
                    if (fThread && iBlockedTime > 100)
                    {
                        Application.InteractiveThread.ThreadLogS("HandlePacket: ... blocked for %u ms!", iBlockedTime);
                    }
#endif

                }
            }
            // transfer to main thread?
            else if (!pHData->ProcByThread && fThread)
            {
                fHandled = true;
                fSendToMainThread = true;
            }
        }

    // send to main thread?
    if (fSendToMainThread)
    {
        // create data
        NetEvPacketData *pEvData = new NetEvPacketData;
        pEvData->Packet.Take(rPacket.Duplicate());
        pEvData->Conn = pConn;
        pConn->AddRef();
        // trigger event
        if (!Application.InteractiveThread.PushEvent(Ev_Net_Packet, pEvData))
            Application.InteractiveThread.ThreadLogS("...push event ");
    }

    // unhandled?
    if (!fHandled && !pConn->isClosed())
        Application.InteractiveThread.ThreadLog("Network: Unhandled packet (status %02x)", rPacket.getStatus());

    // remove connection reference
    pConn->DelRef();
    return fHandled;
}