// CONSTRUCTOR //------------------------------------------------------------------------------ /*explicit*/ CachePlugin::CachePlugin( const AString & dllName ) : #if defined( __WINDOWS__ ) m_DLL( nullptr ), #endif m_InitFunc( nullptr ), m_ShutdownFunc( nullptr ), m_PublishFunc( nullptr ), m_RetrieveFunc( nullptr ), m_FreeMemoryFunc( nullptr ) { #if defined( __WINDOWS__ ) m_DLL = ::LoadLibrary( dllName.Get() ); if ( !m_DLL ) { FLOG_WARN( "Cache plugin '%s' load failed (0x%x).", dllName.Get(), ::GetLastError() ); return; } m_InitFunc = (CacheInitFunc) GetFunction( "CacheInit", "?CacheInit@@YA_NPEBD@Z" ); m_ShutdownFunc = (CacheShutdownFunc) GetFunction( "CacheShutdown", "?CacheShutdown@@YAXXZ" ); m_PublishFunc = (CachePublishFunc) GetFunction( "CachePublish", "?CachePublish@@YA_NPEBDPEBX_K@Z" ); m_RetrieveFunc = (CacheRetrieveFunc) GetFunction( "CacheRetrieve", "?CacheRetrieve@@YA_NPEBDAEAPEAXAEA_K@Z" ); m_FreeMemoryFunc= (CacheFreeMemoryFunc) GetFunction( "CacheFreeMemory", "?CacheFreeMemory@@YAXPEAX_K@Z" ); #elif defined( __APPLE__ ) ASSERT( false ); // TODO:MAC Implement CachePlugin #elif defined( __LINUX__ ) ASSERT( false ); // TODO:LINUX Implement CachePlugin #else #error Unknown platform #endif }
void conf_parse_cond(svc_t *svc, char *cond) { size_t i = 0; char *ptr; if (!svc) { _e("Invalid service pointer"); return; } /* By default we assume UNIX daemons support SIGHUP */ if (svc_is_daemon(svc)) svc->sighup = 1; if (!cond) return; /* First character must be '!' if SIGHUP is not supported. */ ptr = cond; if (ptr[i] == '!') { svc->sighup = 0; ptr++; } while (ptr[i] != '>' && ptr[i] != 0) i++; ptr[i] = 0; if (i >= sizeof(svc->cond)) { FLOG_WARN("Too long event list in declaration of %s: %s", svc->cmd, ptr); return; } strlcpy(svc->cond, ptr, sizeof(svc->cond)); }
SizedBufferRef HandleIpFragment(IpHeaderStruct* ipHeader) { const time_t now = time(NULL); const int timeoutSec = 60; static time_t lastCheck = 0; static FragmentMap fragmentMap; // Delete previous fragments older than timeoutSec if (now-lastCheck >= timeoutSec) { std::list <FragmentMap::iterator> toBeDeleted; for (FragmentMap::iterator it=fragmentMap.begin(); it!=fragmentMap.end(); ++it) { if (now - it->second->lastUpdate() >= timeoutSec) toBeDeleted.push_back(it); } if (toBeDeleted.size()) { for (std::list <FragmentMap::iterator>::iterator it=toBeDeleted.begin(); it!=toBeDeleted.end();++it) { fragmentMap.erase(*it); } FLOG_WARN(s_log,"%d fragmented packets older than %u seconds has been removed from the map", toBeDeleted.size(), timeoutSec); } lastCheck = now; } FLOG_DEBUG(s_log,"Recieved fragment with packet id:%u, offset:%u, payload length:%u", ipHeader->packetId(), ipHeader->offset(), ipHeader->payloadLen()); FragmentMap::iterator it = fragmentMap.find(ipHeader->packetId()); if (it == fragmentMap.end()) { it = fragmentMap.insert(std::make_pair(ipHeader->packetId(), FragmentationAlgorithmRef(new FRAGMENTATION_ALGORITHM()))).first; } FragmentationAlgorithmRef algorithm = it->second; algorithm->addFragment(ipHeader); if (algorithm->drop()) { fragmentMap.erase(it); FLOG_WARN(s_log,"Dropping fragmented packet data with id:%u", ipHeader->packetId()); } if (algorithm->isComplete()) { fragmentMap.erase(it); IpHeaderStruct *header = reinterpret_cast<IpHeaderStruct*>(algorithm->packetData()->get()); FLOG_INFO(s_log, "Reassembled fragmented packet with id:%u, total payload length:%u", header->packetId(), header->payloadLen()); return algorithm->packetData(); } return SizedBufferRef(); // By default return empty ref }
// Init //------------------------------------------------------------------------------ /*virtual*/ bool Cache::Init( const AString & cachePath ) { PROFILE_FUNCTION m_CachePath = cachePath; PathUtils::EnsureTrailingSlash( m_CachePath ); if ( FileIO::EnsurePathExists( m_CachePath ) ) { return true; } FLOG_WARN( "Cache inaccessible - Caching disabled (Path '%s')", m_CachePath.Get() ); return false; }
// Process( MsgConnection ) //------------------------------------------------------------------------------ void Server::Process( const ConnectionInfo * connection, const Protocol::MsgConnection * msg ) { // check for valid/supported protocol version if ( msg->GetProtocolVersion() != Protocol::PROTOCOL_VERSION ) { AStackString<> remoteAddr; TCPConnectionPool::GetAddressAsString( connection->GetRemoteAddress(), remoteAddr ); FLOG_WARN( "Disconnecting '%s' due to bad protocol version\n", remoteAddr.Get() ); Disconnect( connection ); return; } // take note of initial status of client ClientState * cs = (ClientState *)connection->GetUserData(); cs->m_NumJobsAvailable = msg->GetNumJobsAvailable(); cs->m_HostName = msg->GetHostName(); }
// GetFunction //------------------------------------------------------------------------------ void * CachePlugin::GetFunction( const char * friendlyName, const char * mangledName ) const { #if defined( __WINDOWS__ ) ASSERT( m_DLL ); void * func = ::GetProcAddress( (HMODULE)m_DLL, mangledName ); if ( !func ) { FLOG_WARN( "Missing CachePluginDLL function '%s' (Mangled: %s)", friendlyName, mangledName ); } return func; #elif defined( __APPLE__ ) return nullptr; // TODO:MAC Implement CachePlugin #elif defined( __LINUX__ ) return nullptr; // TODO:LINUX Implement CachePlugin #else #error Unknown platform #endif }
// Process( MsgFile ) //------------------------------------------------------------------------------ void Server::Process( const ConnectionInfo * connection, const Protocol::MsgFile * msg, const void * payload, size_t payloadSize ) { const uint64_t toolId = msg->GetToolId(); const uint32_t fileId = msg->GetFileId(); // Update the Manifest ToolManifest * manifest = nullptr; { MutexHolder manifestMH( m_ToolManifestsMutex ); // fill out the received manifest ToolManifest ** found = m_Tools.FindDeref( toolId ); ASSERT( found ); manifest = *found; ASSERT( manifest->GetUserData() == connection ); (void)connection; if ( manifest->ReceiveFileData( fileId, payload, payloadSize ) == false ) { // something went wrong storing the file FLOG_WARN( "Failed to store fileId %u for manifest 0x%llx\n", fileId, toolId ); Disconnect( connection ); return; } if ( manifest->IsSynchronized() == false ) { // wait for more files return; } manifest->SetUserData( nullptr ); } // ToolChain is now synchronized // Allow any jobs that were waiting on it to start CheckWaitingJobs( manifest ); }
// DoBuild //------------------------------------------------------------------------------ /*virtual*/ Node::BuildResult LinkerNode::DoBuild( Job * job ) { DoPreLinkCleanup(); // Make sure the implib output directory exists if (m_ImportLibName.IsEmpty() == false) { AStackString<> cleanPath; NodeGraph::CleanPath(m_ImportLibName, cleanPath); if (EnsurePathExistsForFile(cleanPath) == false) { // EnsurePathExistsForFile will have emitted error return NODE_RESULT_FAILED; } } // Format compiler args string Args fullArgs; if ( !BuildArgs( fullArgs ) ) { return NODE_RESULT_FAILED; // BuildArgs will have emitted an error } // use the exe launch dir as the working dir const char * workingDir = nullptr; const char * environment = FBuild::Get().GetEnvironmentString(); EmitCompilationMessage( fullArgs ); // we retry if linker crashes uint32_t attempt( 0 ); for (;;) { ++attempt; // spawn the process Process p( FBuild::Get().GetAbortBuildPointer() ); bool spawnOK = p.Spawn( m_Linker.Get(), fullArgs.GetFinalArgs().Get(), workingDir, environment ); if ( !spawnOK ) { if ( p.HasAborted() ) { return NODE_RESULT_FAILED; } FLOG_ERROR( "Failed to spawn process '%s' for %s creation for '%s'", m_Linker.Get(), GetDLLOrExe(), GetName().Get() ); return NODE_RESULT_FAILED; } // capture all of the stdout and stderr AutoPtr< char > memOut; AutoPtr< char > memErr; uint32_t memOutSize = 0; uint32_t memErrSize = 0; p.ReadAllData( memOut, &memOutSize, memErr, &memErrSize ); ASSERT( !p.IsRunning() ); // Get result int result = p.WaitForExit(); if ( p.HasAborted() ) { return NODE_RESULT_FAILED; } // did the executable fail? if ( result != 0 ) { // Handle bugs in the MSVC linker if ( GetFlag( LINK_FLAG_MSVC ) && ( attempt == 1 ) ) { // Did the linker have an ICE (crash) (LNK1000)? if ( result == 1000 ) { FLOG_WARN( "FBuild: Warning: Linker crashed (LNK1000), retrying '%s'", GetName().Get() ); continue; // try again } // Did the linker have an "unexpected PDB error" (LNK1318)? // Example: "fatal error LNK1318: Unexpected PDB error; CORRUPT (13)" // (The linker or mspdbsrv.exe (as of VS2017) seems to have bugs which cause the PDB // to sometimes be corrupted when doing very large links, possibly because the linker // is running out of memory) if ( result == 1318 ) { FLOG_WARN( "FBuild: Warning: Linker corrupted the PDB (LNK1318), retrying '%s'", GetName().Get() ); continue; // try again } } if ( memOut.Get() ) { job->ErrorPreformatted( memOut.Get() ); } if ( memErr.Get() ) { job->ErrorPreformatted( memErr.Get() ); } // some other (genuine) linker failure FLOG_ERROR( "Failed to build %s (error %i) '%s'", GetDLLOrExe(), result, GetName().Get() ); return NODE_RESULT_FAILED; } else { // If "warnings as errors" is enabled (/WX) we don't need to check // (since compilation will fail anyway, and the output will be shown) if ( GetFlag( LINK_FLAG_MSVC ) && !GetFlag( LINK_FLAG_WARNINGS_AS_ERRORS_MSVC ) ) { HandleWarningsMSVC( job, GetName(), memOut.Get(), memOutSize ); } break; // success! } } // post-link stamp step if ( m_LinkerStampExe.IsEmpty() == false ) { const Node * linkerStampExe = m_StaticDependencies.End()[ -1 ].GetNode(); EmitStampMessage(); Process stampProcess( FBuild::Get().GetAbortBuildPointer() ); bool spawnOk = stampProcess.Spawn( linkerStampExe->GetName().Get(), m_LinkerStampExeArgs.Get(), nullptr, // working dir nullptr ); // env if ( spawnOk == false ) { if ( stampProcess.HasAborted() ) { return NODE_RESULT_FAILED; } FLOG_ERROR( "Failed to spawn process '%s' for '%s' stamping of '%s'", linkerStampExe->GetName().Get(), GetDLLOrExe(), GetName().Get() ); return NODE_RESULT_FAILED; } // capture all of the stdout and stderr AutoPtr< char > memOut; AutoPtr< char > memErr; uint32_t memOutSize = 0; uint32_t memErrSize = 0; stampProcess.ReadAllData( memOut, &memOutSize, memErr, &memErrSize ); ASSERT( !stampProcess.IsRunning() ); // Get result int result = stampProcess.WaitForExit(); if ( stampProcess.HasAborted() ) { return NODE_RESULT_FAILED; } // did the executable fail? if ( result != 0 ) { if ( memOut.Get() ) { FLOG_ERROR_DIRECT( memOut.Get() ); } if ( memErr.Get() ) { FLOG_ERROR_DIRECT( memErr.Get() ); } FLOG_ERROR( "Failed to stamp %s '%s' (error %i - '%s')", GetDLLOrExe(), GetName().Get(), result, m_LinkerStampExe.Get() ); return NODE_RESULT_FAILED; } // success! } // record time stamp for next time m_Stamp = FileIO::GetFileLastWriteTime( m_Name ); ASSERT( m_Stamp ); return NODE_RESULT_OK; }
// DoBuild //------------------------------------------------------------------------------ /*virtual*/ Node::BuildResult LinkerNode::DoBuild( Job * UNUSED( job ) ) { DoPreLinkCleanup(); // Make sure the implib output directory exists if (m_ImportLibName.IsEmpty() == false) { AStackString<> cleanPath; NodeGraph::CleanPath(m_ImportLibName, cleanPath); if (EnsurePathExistsForFile(cleanPath) == false) { // EnsurePathExistsForFile will have emitted error return NODE_RESULT_FAILED; } } // Format compiler args string Args fullArgs; if ( !BuildArgs( fullArgs ) ) { return NODE_RESULT_FAILED; // BuildArgs will have emitted an error } // use the exe launch dir as the working dir const char * workingDir = nullptr; const char * environment = FBuild::Get().GetEnvironmentString(); EmitCompilationMessage( fullArgs ); // we retry if linker crashes uint32_t attempt( 0 ); for (;;) { ++attempt; // spawn the process Process p; bool spawnOK = p.Spawn( m_Linker.Get(), fullArgs.GetFinalArgs().Get(), workingDir, environment ); if ( !spawnOK ) { FLOG_ERROR( "Failed to spawn process '%s' for %s creation for '%s'", m_Linker.Get(), GetDLLOrExe(), GetName().Get() ); return NODE_RESULT_FAILED; } // capture all of the stdout and stderr AutoPtr< char > memOut; AutoPtr< char > memErr; uint32_t memOutSize = 0; uint32_t memErrSize = 0; p.ReadAllData( memOut, &memOutSize, memErr, &memErrSize ); ASSERT( !p.IsRunning() ); // Get result int result = p.WaitForExit(); // did the executable fail? if ( result != 0 ) { // did the linker have an ICE (LNK1000)? if ( GetFlag( LINK_FLAG_MSVC ) && ( result == 1000 ) && ( attempt == 1 ) ) { FLOG_WARN( "FBuild: Warning: Linker crashed (LNK1000), retrying '%s'", GetName().Get() ); continue; // try again } if ( memOut.Get() ) { m_BuildOutputMessages.Append( memOut.Get(), memOutSize ); FLOG_ERROR_DIRECT( memOut.Get() ); } if ( memErr.Get() ) { m_BuildOutputMessages.Append( memErr.Get(), memErrSize ); FLOG_ERROR_DIRECT( memErr.Get() ); } // some other (genuine) linker failure FLOG_ERROR( "Failed to build %s (error %i) '%s'", GetDLLOrExe(), result, GetName().Get() ); return NODE_RESULT_FAILED; } else { break; // success! } } // post-link stamp step if ( m_LinkerStampExe ) { EmitStampMessage(); Process stampProcess; bool spawnOk = stampProcess.Spawn( m_LinkerStampExe->GetName().Get(), m_LinkerStampExeArgs.Get(), nullptr, // working dir nullptr ); // env if ( spawnOk == false ) { FLOG_ERROR( "Failed to spawn process '%s' for '%s' stamping of '%s'", m_LinkerStampExe->GetName().Get(), GetDLLOrExe(), GetName().Get() ); return NODE_RESULT_FAILED; } // capture all of the stdout and stderr AutoPtr< char > memOut; AutoPtr< char > memErr; uint32_t memOutSize = 0; uint32_t memErrSize = 0; stampProcess.ReadAllData( memOut, &memOutSize, memErr, &memErrSize ); ASSERT( !stampProcess.IsRunning() ); // Get result int result = stampProcess.WaitForExit(); // did the executable fail? if ( result != 0 ) { if ( memOut.Get() ) { FLOG_ERROR_DIRECT( memOut.Get() ); } if ( memErr.Get() ) { FLOG_ERROR_DIRECT( memErr.Get() ); } FLOG_ERROR( "Failed to stamp %s '%s' (error %i - '%s')", GetDLLOrExe(), GetName().Get(), result, m_LinkerStampExe->GetName().Get() ); return NODE_RESULT_FAILED; } // success! } // record time stamp for next time m_Stamp = FileIO::GetFileLastWriteTime( m_Name ); ASSERT( m_Stamp ); return NODE_RESULT_OK; }