void C4MainStat::ShowPart(int FrameCounter) { C4Stat* pAkt; // insert tick nr LogSilentF("** PartStat begin %d", FrameCounter); // insert all stats for (pAkt = pFirst; pAkt; pAkt = pAkt->pNext) LogSilentF("%s: n=%u, t=%u", pAkt->strName, pAkt->iCountPart, pAkt->tTimeSumPart); // insert part stat end idtf LogSilentF("** PartStat end\n"); }
bool C4Network2Client::DoConnectAttempt(C4Network2IO *pIO) { // local? if (isLocal()) { iNextConnAttempt = 0; return true; } // msg and data connected? Nothing to do if (getMsgConn() != getDataConn()) { iNextConnAttempt = time(NULL) + 10; return true; } // too early? if (iNextConnAttempt && iNextConnAttempt > time(NULL)) return true; // find address to try int32_t iBestAddress = -1; for (int32_t i = 0; i < iAddrCnt; i++) // no connection for this protocol? if ((!pDataConn || Addr[i].getProtocol() != pDataConn->getProtocol()) && (!pMsgConn || Addr[i].getProtocol() != pMsgConn->getProtocol())) // protocol available? if (pIO->getNetIO(Addr[i].getProtocol())) // new best address? if (iBestAddress < 0 || AddrAttempts[i] < AddrAttempts[iBestAddress]) iBestAddress = i; // too many attempts or nothing found? if (iBestAddress < 0 || AddrAttempts[iBestAddress] > C4NetClientConnectAttempts) { iNextConnAttempt = time(NULL) + 10; return true; } // save attempt AddrAttempts[iBestAddress]++; iNextConnAttempt = time(NULL) + C4NetClientConnectInterval; // log LogSilentF("Network: connecting client %s on %s...", getName(), Addr[iBestAddress].toString().getData()); // connect return pIO->Connect(Addr[iBestAddress].getAddr(), Addr[iBestAddress].getProtocol(), pClient->getCore()); }
bool C4Network2Res::SetByGroup(C4Group *pGrp, bool fTemp, C4Network2ResType eType, int32_t iResID, const char *szResName, bool fSilent) // by main thread { Clear(); CStdLock FileLock(&FileCSec); // default resource name: relative path StdStrBuf sResName; if (szResName) sResName = szResName; else { StdStrBuf sFullName = pGrp->GetFullName(); sResName.Copy(Config.AtRelativePath(sFullName.getData())); } SCopy(pGrp->GetFullName().getData(), szFile, sizeof(szFile)-1); // set core Core.Set(eType, iResID, sResName.getData(), pGrp->EntryCRC32()); #ifdef C4NET2RES_DEBUG_LOG // log LogSilentF("Network: Resource: complete %d:%s is file %s (%s)", iResID, sResName.getData(), szFile, fTemp ? "temp" : "static"); #endif // set data fDirty = true; fTempFile = fTemp; fStandaloneFailed = false; fRemoved = false; iLastReqTime = time(NULL); fLoading = false; // ok return true; }
bool C4Network2Res::SetByFile(const char *strFilePath, bool fTemp, C4Network2ResType eType, int32_t iResID, const char *szResName, bool fSilent) { CStdLock FileLock(&FileCSec); // default resource name: relative path if (!szResName) szResName = Config.AtRelativePath(strFilePath); SCopy(strFilePath, szFile, sizeof(szFile)-1); // group? C4Group Grp; if (Reloc.Open(Grp, strFilePath)) return SetByGroup(&Grp, fTemp, eType, iResID, szResName, fSilent); // so it needs to be a file StdStrBuf szFullFile; if (!Reloc.LocateItem(szFile, szFullFile)) { if (!fSilent) LogF("SetByFile: file %s not found!", strFilePath); return false; } // calc checksum uint32_t iCRC32; if (!GetFileCRC(szFullFile.getData(), &iCRC32)) return false; #ifdef C4NET2RES_DEBUG_LOG // log LogSilentF("Network: Resource: complete %d:%s is file %s (%s)", iResID, szResName, szFile, fTemp ? "temp" : "static"); #endif // set core Core.Set(eType, iResID, Config.AtRelativePath(szFullFile.getData()), iCRC32); // set own data fDirty = true; fTempFile = fTemp; fStandaloneFailed = false; fRemoved = false; iLastReqTime = time(NULL); fLoading = false; // ok return true; }
void C4Network2Res::Clear() { CStdLock FileLock(&FileCSec); // delete files if (fTempFile) if (FileExists(szFile)) if (!EraseFile(szFile)) LogSilentF("Network: Could not delete temporary resource file (%s)", strerror(errno)); if (szStandalone[0] && !SEqual(szFile, szStandalone)) if (FileExists(szStandalone)) if (!EraseFile(szStandalone)) LogSilentF("Network: Could not delete temporary resource file (%s)", strerror(errno)); szFile[0] = szStandalone[0] = '\0'; fDirty = false; fTempFile = false; Core.Clear(); Chunks.Clear(); fRemoved = false; ClearLoad(); }
bool C4Network2Client::DoConnectAttempt(C4Network2IO *pIO) { // local? if (isLocal()) { iNextConnAttempt = 0; return true; } // msg and data connected? Nothing to do if (getMsgConn() != getDataConn()) { iNextConnAttempt = time(nullptr) + 10; return true; } // too early? if (iNextConnAttempt && iNextConnAttempt > time(nullptr)) return true; // find address to try int32_t iBestAddress = -1; for (int32_t i = 0; i < iAddrCnt; i++) // no connection for this protocol? if ((!pDataConn || Addr[i].getProtocol() != pDataConn->getProtocol()) && (!pMsgConn || Addr[i].getProtocol() != pMsgConn->getProtocol())) // protocol available? if (pIO->getNetIO(Addr[i].getProtocol())) // new best address? if (iBestAddress < 0 || AddrAttempts[i] < AddrAttempts[iBestAddress]) iBestAddress = i; // too many attempts or nothing found? if (iBestAddress < 0 || AddrAttempts[iBestAddress] > C4NetClientConnectAttempts) { iNextConnAttempt = time(nullptr) + 10; return true; } // save attempt AddrAttempts[iBestAddress]++; iNextConnAttempt = time(nullptr) + C4NetClientConnectInterval; auto addr = Addr[iBestAddress].getAddr(); // try TCP simultaneous open if the stars align right if (addr.GetFamily() == C4NetIO::addr_t::IPv6 && // address needs to be IPv6... !addr.IsLocal() && !addr.IsPrivate() && // ...global unicast... Addr[iBestAddress].getProtocol() == P_TCP && // ...TCP, !TcpSimOpenSocket && // there is no previous request, pParent->GetLocal()->getID() < getID()) // and make sure that only one client per pair initiates a request. { DoTCPSimultaneousOpen(pIO, C4Network2Address()); } std::set<int> interfaceIDs; if (addr.IsLocal()) interfaceIDs = Network.Clients.GetLocal()->getInterfaceIDs(); else interfaceIDs = {0}; for (auto id : interfaceIDs) { addr.SetScopeId(id); // log LogSilentF("Network: connecting client %s on %s...", getName(), addr.ToString().getData()); // connect if (pIO->Connect(addr, Addr[iBestAddress].getProtocol(), pClient->getCore())) return true; } return false; }
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; } }
CStdGLCtx *CStdGL::CreateContext(C4Window * pWindow, C4AbstractApp *pApp) { // safety if (!pWindow) return NULL; // create it CStdGLCtx *pCtx = new CStdGLCtx(); bool first_ctx = !pMainCtx; if (first_ctx) { pMainCtx = pCtx; LogF(" gl: Create first %scontext...", Config.Graphics.DebugOpenGL ? "debug " : ""); } bool success = pCtx->Init(pWindow, pApp); if (Config.Graphics.DebugOpenGL && glDebugMessageCallbackARB) { if (first_ctx) Log(" gl: Setting OpenGLDebugProc callback"); glDebugMessageCallbackARB(&OpenGLDebugProc, nullptr); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); #ifdef GL_KHR_debug if (GLEW_KHR_debug) glEnable(GL_DEBUG_OUTPUT); #endif } // First context: Log some information about hardware/drivers // Must log after context creation to get valid results if (first_ctx) { const char *gl_vendor = reinterpret_cast<const char *>(glGetString(GL_VENDOR)); const char *gl_renderer = reinterpret_cast<const char *>(glGetString(GL_RENDERER)); const char *gl_version = reinterpret_cast<const char *>(glGetString(GL_VERSION)); LogF("GL %s on %s (%s)", gl_version ? gl_version : "", gl_renderer ? gl_renderer : "", gl_vendor ? gl_vendor : ""); if (Config.Graphics.DebugOpenGL) { // Dump extension list if (glGetStringi) { GLint gl_extension_count = 0; glGetIntegerv(GL_NUM_EXTENSIONS, &gl_extension_count); if (gl_extension_count == 0) { LogSilentF("No available extensions."); } else { LogSilentF("%d available extensions:", gl_extension_count); for (GLint i = 0; i < gl_extension_count; ++i) { const char *gl_extension = (const char*)glGetStringi(GL_EXTENSIONS, i); LogSilentF(" %4d: %s", i, gl_extension); } } } else { const char *gl_extensions = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)); LogSilentF("GLExt: %s", gl_extensions ? gl_extensions : ""); } } } if (!success) { delete pCtx; Error(" gl: Error creating secondary context!"); return NULL; } // creation selected the new context - switch back to previous context RenderTarget = NULL; pCurrCtx = NULL; // done return pCtx; }
bool C4Network2Res::GetStandalone(char *pTo, int32_t iMaxL, bool fSetOfficial, bool fAllowUnloadable, bool fSilent) { // already set? if (szStandalone[0]) { if (pTo) SCopy(szStandalone, pTo, iMaxL); return true; } // already tried and failed? No point in retrying if (fStandaloneFailed) return false; // not loadable? Wo won't be able to check the standalone as the core will lack the needed information. // the standalone won't be interesting in this case, anyway. if (!fSetOfficial && !Core.isLoadable()) return false; // set flag, so failure below will let future calls fail fStandaloneFailed = true; // lock file CStdLock FileLock(&FileCSec); // directory? SCopy(szFile, szStandalone, sizeof(szStandalone)-1); if (DirectoryExists(szFile)) { // size check for the directory, if allowed if (fAllowUnloadable) { uint32_t iDirSize; if (!DirSizeHelper::GetDirSize(szFile, &iDirSize, Config.Network.MaxLoadFileSize)) { if (!fSilent) LogF("Network: could not get directory size of %s!", szFile); szStandalone[0] = '\0'; return false; } if (iDirSize > uint32_t(Config.Network.MaxLoadFileSize)) { if (!fSilent) LogSilentF("Network: %s over size limit, will be marked unloadable!", szFile); szStandalone[0] = '\0'; return false; } } // log - this may take a few seconds if (!fSilent) LogF(LoadResStr("IDS_PRC_NETPACKING"), GetFilename(szFile)); // pack inplace? if (!fTempFile) { if (!pParent->FindTempResFileName(szFile, szStandalone)) { if (!fSilent) Log("GetStandalone: could not find free name for temporary file!"); szStandalone[0] = '\0'; return false; } if (!C4Group_PackDirectoryTo(szFile, szStandalone)) { if (!fSilent) Log("GetStandalone: could not pack directory!"); szStandalone[0] = '\0'; return false; } } else if (!C4Group_PackDirectory(szStandalone)) { if (!fSilent) Log("GetStandalone: could not pack directory!"); if (!SEqual(szFile, szStandalone)) EraseDirectory(szStandalone); szStandalone[0] = '\0'; return false; } // make sure directory is packed if (DirectoryExists(szStandalone)) { if (!fSilent) Log("GetStandalone: directory hasn't been packed!"); if (!SEqual(szFile, szStandalone)) EraseDirectory(szStandalone); szStandalone[0] = '\0'; return false; } // fallthru } // doesn't exist physically? if (!FileExists(szStandalone)) { // try C4Group (might be packed) if (!pParent->FindTempResFileName(szFile, szStandalone)) { if (!fSilent) Log("GetStandalone: could not find free name for temporary file!"); szStandalone[0] = '\0'; return false; } if (!C4Group_CopyItem(szFile, szStandalone)) { if (!fSilent) Log("GetStandalone: could not copy to temporary file!"); szStandalone[0] = '\0'; return false; } } // remains missing? give up. if (!FileExists(szStandalone)) { if (!fSilent) Log("GetStandalone: file not found!"); szStandalone[0] = '\0'; return false; } // do optimizations (delete unneeded entries) if (!OptimizeStandalone(fSilent)) { if (!SEqual(szFile, szStandalone)) EraseItem(szStandalone); szStandalone[0] = '\0'; return false; } // get file size size_t iSize = FileSize(szStandalone); // size limit if (fAllowUnloadable) if (iSize > uint32_t(Config.Network.MaxLoadFileSize)) { if (!fSilent) LogSilentF("Network: %s over size limit, will be marked unloadable!", szFile); szStandalone[0] = '\0'; return false; } // check if (!fSetOfficial && iSize != Core.getFileSize()) { // remove file if (!SEqual(szFile, szStandalone)) EraseItem(szStandalone); szStandalone[0] = '\0'; // sorry, this version isn't good enough :( return false; } // calc checksum uint32_t iCRC32; if (!GetFileCRC(szStandalone, &iCRC32)) { if (!fSilent) Log("GetStandalone: could not calculate checksum!"); return false; } // set / check if (!fSetOfficial && iCRC32 != Core.getFileCRC()) { // remove file, return if (!SEqual(szFile, szStandalone)) EraseItem(szStandalone); szStandalone[0] = '\0'; return false; } // we didn't fail fStandaloneFailed = false; // mark resource as loadable and safe file information Core.SetLoadable(iSize, iCRC32); // set up chunk data Chunks.SetComplete(Core.getChunkCnt()); // ok return true; }
bool C4Network2IO::Init(int16_t iPortTCP, int16_t iPortUDP, int16_t iPortDiscover, int16_t iPortRefServer, bool fBroadcast) // by main thread { // Already initialized? Clear first if (pNetIO_TCP || pNetIO_UDP) Clear(); // init members tLastPing = tLastStatistic = C4TimeMilliseconds::Now(); iTCPIRate = iTCPORate = iTCPBCRate = 0; iUDPIRate = iUDPORate = iUDPBCRate = 0; // init event callback C4InteractiveThread &Thread = Application.InteractiveThread; Thread.SetCallback(Ev_Net_Conn, this); Thread.SetCallback(Ev_Net_Disconn, this); Thread.SetCallback(Ev_Net_Packet, this); // initialize UPnP manager if (iPortTCP > 0 || iPortUDP > 0) { assert(!UPnPMgr); UPnPMgr = new C4Network2UPnP; } // initialize net i/o classes: TCP first if (iPortTCP > 0) { // create pNetIO_TCP = new C4NetIOTCP(); // init if (!pNetIO_TCP->Init(iPortTCP)) { LogF("Network: could not init TCP i/o (%s)", pNetIO_TCP->GetError() ? pNetIO_TCP->GetError() : ""); delete pNetIO_TCP; pNetIO_TCP = NULL; } else LogSilentF("Network: TCP initialized on port %d", iPortTCP); // add to thread, set callback if (pNetIO_TCP) { Thread.AddProc(pNetIO_TCP); pNetIO_TCP->SetCallback(this); UPnPMgr->AddMapping(P_TCP, iPortTCP, iPortTCP); } } // then UDP if (iPortUDP > 0) { // create pNetIO_UDP = new C4NetIOUDP(); // init if (!pNetIO_UDP->Init(iPortUDP)) { LogF("Network: could not init UDP i/o (%s)", pNetIO_UDP->GetError() ? pNetIO_UDP->GetError() : ""); delete pNetIO_UDP; pNetIO_UDP = NULL; } else LogSilentF("Network: UDP initialized on port %d", iPortUDP); // add to thread, set callback if (pNetIO_UDP) { Thread.AddProc(pNetIO_UDP); pNetIO_UDP->SetCallback(this); UPnPMgr->AddMapping(P_UDP, iPortUDP, iPortUDP); } } // no protocols? if (!pNetIO_TCP && !pNetIO_UDP) { LogFatal("Network: fatal - no protocols available!"); Thread.ClearCallback(Ev_Net_Conn, this); Thread.ClearCallback(Ev_Net_Disconn, this); Thread.ClearCallback(Ev_Net_Packet, this); return false; } // discovery last if (iPortDiscover > 0) { // create pNetIODiscover = new C4Network2IODiscover(iPortRefServer); pNetIODiscover->SetDiscoverable(false); // init if (!pNetIODiscover->Init(iPortDiscover)) { LogF("Network: could not init discovery (%s)", pNetIODiscover->GetError() ? pNetIODiscover->GetError() : ""); delete pNetIODiscover; pNetIODiscover = NULL; } else LogSilentF("Network: discovery initialized on port %d", iPortDiscover); // add to thread if (pNetIODiscover) Thread.AddProc(pNetIODiscover); } // plus reference server if (iPortRefServer > 0) { // create pRefServer = new C4Network2RefServer(); // init if (!pRefServer->Init(iPortRefServer)) { LogF("Network: could not init reference server (%s)", pNetIO_UDP->GetError() ? pNetIO_UDP->GetError() : ""); delete pRefServer; pRefServer = NULL; } else LogSilentF("Network: reference server initialized on port %d", iPortRefServer); // add to thread if (pRefServer) Thread.AddProc(pRefServer); } // own timer tLastExecute = C4TimeMilliseconds::Now(); Thread.AddProc(this); // ok return true; }
void C4MainStat::Show() { // count stats unsigned int iCnt = 0; C4Stat* pAkt; for (pAkt = pFirst; pAkt; pAkt = pAkt->pNext) iCnt++; // create array C4Stat** StatArray = new C4Stat*[iCnt]; bool* bHS = new bool[iCnt]; // sort it unsigned int i,ii; for (ii=0; ii<iCnt; ii++) bHS[ii] = false; for (i=0; i<iCnt; i++) { C4Stat* pBestStat = NULL; unsigned int iBestNr = ~0; for (ii=0, pAkt = pFirst; ii<iCnt; ii++, pAkt = pAkt->pNext) if (!bHS[ii]) { if (iBestNr == ~0u) { iBestNr = ii; pBestStat = pAkt; } else if (stricmp(pBestStat->strName, pAkt->strName) > 0) { iBestNr = ii; pBestStat = pAkt; } } if (iBestNr == (unsigned int) -1) break; bHS[iBestNr] = true; StatArray[i] = pBestStat; } delete bHS; LogSilent("** Stat"); // output in order for (i=0; i<iCnt; i++) { pAkt = StatArray[i]; // output it! if (pAkt->iCount) LogSilentF("%s: n = %u, t = %u, td = %.2f", pAkt->strName, pAkt->iCount, pAkt->tTimeSum, double(pAkt->tTimeSum) / pAkt->iCount * 1000); } // delete... delete[] StatArray; // ok. job done LogSilent("** Stat end"); }