/** Main Connection Thread. Handles all the networking to allow Mining threads the most performance. **/ void ServerConnection::ServerThread() { /** Don't begin until all mining threads are Created. **/ while (THREADS.size() != nThreads) Sleep(1000); /** Initialize the Server Connection. **/ CLIENT = new LLP::Miner(IP, PORT); /** Initialize a Timer for the Hash Meter. **/ TIMER.Start(); unsigned int nTimerWait = 2; unsigned int nBestHeight = 0; loop { try { /** Run this thread at 1 Cycle per Second. **/ Sleep(50); /** Attempt with best efforts to keep the Connection Alive. **/ if (!CLIENT->Connected() || CLIENT->Errors()) { ResetThreads(); if (!CLIENT->Connect()) continue; else CLIENT->SetChannel(2); } /** Check the Block Height. **/ unsigned int nHeight = CLIENT->GetHeight(5); if (nHeight == 0) { printf("[MASTER] Failed to Update Height\n"); CLIENT->Disconnect(); continue; } /** If there is a new block, Flag the Threads to Stop Mining. **/ if (nHeight != nBestHeight) { nBestHeight = nHeight; printf("[MASTER] Coinshield Network: New Block %u\n", nHeight); ResetThreads(); } /** Rudimentary Meter **/ if (TIMER.Elapsed() > nTimerWait) { double Elapsed = (double)TIMER.ElapsedMilliseconds(); unsigned long long nHashes = Hashes(); //double khash = ((double)nHashes)/Elapsed; unsigned long long khash = nHashes / TIMER.ElapsedMilliseconds(); unsigned int nDifficulty = THREADS[0]->GetBlock()->GetBits(); nDifficulty = nDifficulty & 0xffffff; CBigNum target; target.SetCompact(nDifficulty); //double diff = (double)(0xFFFF * pow(2, 208)) / (double)nDifficulty; printf("[METERS] %llu kHash/s | Height = %u | Diff= %.08f\n", khash, nBestHeight, 1.0 / (double)nDifficulty); TIMER.Reset(); if (nTimerWait == 2) nTimerWait = 20; } /** Check if there is work to do for each Miner Thread. **/ for (unsigned int nIndex = 0; nIndex < THREADS.size(); nIndex++) { /** Attempt to get a new block from the Server if Thread needs One. **/ if (THREADS[nIndex]->GetIsNewBlock()) { /** Retrieve new block from Server. **/ /** Delete the Block Pointer if it Exists. **/ CBlock* pBlock = THREADS[nIndex]->GetBlock(); if (pBlock != NULL) { delete(pBlock); } /** Retrieve new block from Server. **/ pBlock = CLIENT->GetBlock(5); /** If the block is good, tell the Mining Thread its okay to Mine. **/ if (pBlock) { THREADS[nIndex]->SetIsBlockFound(false); THREADS[nIndex]->SetIsNewBlock(false); THREADS[nIndex]->SetBlock(pBlock); THREADS[nIndex]->SetHashes(0); // reset hash count } /** If the Block didn't come in properly, Reconnect to the Server. **/ else { CLIENT->Disconnect(); break; } } /** Submit a block from Mining Thread if Flagged. **/ else if (THREADS[nIndex]->GetIsBlockFound()) { // /** Attempt to Submit the Block to Network. **/ unsigned char RESPONSE = CLIENT->SubmitBlock(THREADS[nIndex]->GetBlock()->GetMerkleRoot(), THREADS[nIndex]->GetBlock()->GetNonce(), 10); double Elapsed = (double)TIMER.ElapsedMilliseconds(); double nHashes = THREADS[nIndex]->GetHashes(); double khash = nHashes / Elapsed; Hashes(); TIMER.Reset(); if (RESPONSE == 200) printf("[MASTER] Block Found by %s on thread %d %.1f kHash/s (accepted) Yay !!!\n", device_name[nIndex], nIndex, khash); else if (RESPONSE == 201) { printf("[MASTER] Block Found by %s on thread %d %.1f kHash/s (rejected) Booo !!!\n", device_name[nIndex], nIndex, khash); THREADS[nIndex]->SetIsNewBlock(true); THREADS[nIndex]->SetIsBlockFound(false); } else { printf("[MASTER] Failure to Submit Block. Reconnecting...\n"); CLIENT->Disconnect(); } break; } } } catch (std::exception& e) { printf("%s\n", e.what()); } } };
void ReaderTask(int fd, const char *id) { time_t dtime = 0; time_t ltime = 0; time_t itime = 0; time_t ftime = 0; time_t atime = 0; int counter = 0; int forceallcheck = 0; int check_disconn_counter = 0; TFd = fd; /* * [re]open RTStatus */ RTStatusOpen(RTStatus, ThisReaderFork * DOpts.ReaderThreads + 1, DOpts.ReaderThreads); /* * Since we setuid(), we won't core. This is for debugging */ if (CoreDebugOpt || (DOpts.ReaderCrashHandler != NULL && strcasecmp(DOpts.ReaderCrashHandler, "none") != 0)) { signal(SIGSEGV, sigSegVReader); signal(SIGBUS, sigSegVReader); signal(SIGFPE, sigSegVReader); signal(SIGILL, sigSegVReader); } signal(SIGHUP, sigHup); signal(SIGUSR1, sigUsr1); /* * Setup thread for passed pipe */ ResetThreads(); AddThread("reader", fd, -1, THREAD_READER, -1, 0); FD_SET(fd, &RFds); /* * Open KPDB database for active file */ if ((KDBActive = KPDBOpen(PatDbExpand(ReaderDActivePat), O_RDWR)) == NULL) { logit(LOG_CRIT, "Unable to open %s", PatDbExpand(ReaderDActivePat)); sleep(60); exit(1); } LoadExpireCtl(1); /* * Only startup connections to backend spools for reader threads */ if (!FeedOnlyServer) CheckServerConfig(time(NULL), 1); /* * Selection core */ while (!TerminatePending || NReadServAct || NumReaders) { /* * select core */ struct timeval tv; fd_set rfds = RFds; fd_set wfds = WFds; fd_set read_only_to_find_eof_fds; int i, sel_r; if (TerminatePending) { if (TerminateTime == 0) TerminateTime = time(NULL) + 2; if (TerminateTime < time(NULL) || !NumReaders) CanTerminate = 1; } /* * Get next scheduled timeout, no more then 2 seconds * (x 10 counter counts = 20 seconds max for {d,i,f}time * check) * * If we are terminating, then speed up the select to clear * out the connections. * */ if (TerminatePending) NextTimeout(&tv, 50); else NextTimeout(&tv, 2 * 1000); stprintf("%s readers=%02d spoolsrv=%d/%d postsrv=%d/%d", id, NumReaders, NReadServAct, NReadServers, NWriteServAct, NWriteServers ); /* Check for disconnected clients every 50 times through the loop */ FD_ZERO(&read_only_to_find_eof_fds); if (++check_disconn_counter == 50) { for (i = 0; i < MaxFds; ++i) { if (FD_ISSET(i, &wfds) && (!(FD_ISSET(i, &rfds)))) { FD_SET(i, &rfds); FD_SET(i, &read_only_to_find_eof_fds); } } check_disconn_counter = 0; } #if USE_AIO AIOUnblockSignal(); #endif sel_r = select(MaxFds, &rfds, &wfds, NULL, &tv); #if USE_AIO AIOBlockSignal(); #endif gettimeofday(&CurTime, NULL); if(sel_r < 0 && errno != EINTR) logit(LOG_CRIT, "select error: %s (rfds=0x%x, wfds=0x%x)", strerror(errno), rfds, wfds); /* * select is critical, don't make unnecessary system calls. Only * test the time every 10 selects (20 seconds worst case), and * only check for a new server configuration file every 60 seconds * after the initial load. This may rearrange THREAD_SPOOL and * THREAD_POST threads. * * We do not startup spool/post servers for feed-only forks * * However, flush overview cache even for feed-only forks. */ if (FeedOnlyServer <= 0) { if (++counter == 10) { time_t t = CurTime.tv_sec; if (ltime) { dtime += t - ltime; itime += t - ltime; ftime += t - ltime; atime += t - ltime; } /* * Check for server config change once a minute */ if (dtime < -5 || dtime >= 5) { if (!TerminatePending) CheckServerConfig(t, ServersTerminated); dtime = 0; } /* * Flush overview every 30 seconds to allow dexpireover to work */ if (ftime < -5 || ftime >= 30) { FlushOverCache(); LoadExpireCtl(0); ftime = 0; } /* * Poll all active descriptors once every 5 minutes. This * will work around a linux embrionic close bug that * doesn't wakeup select(), and is used to idle-timeout * connections. XXX */ if (itime < -5 || itime >= 300) { rfds = RFds; itime = 0; } /* * Force a check all of FD's every 30 seconds to handle * idle and session timeouts */ if (atime < -5 || atime >= 30) { forceallcheck = 1; atime = 0; } ltime = t; counter = 0; } } else { /* * For a feed-only server, we only flush the overview FD * cache every 5 minutes, and with a greater granularity. * It should cycle much faster than that normally, and this * is to prevent idle feed-only forks from keeping locks. * */ if (++counter == 10) { time_t t = CurTime.tv_sec; if (ltime) { ftime += t - ltime; } if (ftime < -5 || ftime >= 300) { FlushOverCache(); ftime = 0; } ltime = t; counter = 0; } } for (i = 0; i < MaxFds; ++i) { if (FD_ISSET(i, &rfds) && FD_ISSET(i, &read_only_to_find_eof_fds)) { char junk_byte; int ret_val; /* * This FD is not marked for reading, but select() claims * it has something to say. We don't actually want to read * from it, but we do want to close it if the associated * connection is dead. */ FD_CLR(i, &rfds); /* Use recv() with MSG_PEEK to see if it's closed. * We shouldn't block because we're O_NONBLOCK. */ ret_val = recv(i, &junk_byte, 1, MSG_PEEK); /* If ret_val is zero, this means the socket is closed. * Blast it. Otherwise, ignore it. */ if(ret_val == 0) { ForkDesc *desc; if((desc = FindThread(i, -1)) != NULL) { Connection *conn = desc->d_Data; if(conn) { NNTerminate(conn); DeleteConnection(conn); } DelThread(desc); } } } } for (i = 0; i < MaxFds; ++i) { if (forceallcheck || TerminatePending || FD_ISSET(i, &rfds) || FD_ISSET(i, &wfds)) { ForkDesc *desc; if ((desc = FindThread(i, -1)) != NULL) { Connection *conn = desc->d_Data; if (conn) { /* * handle output I/O (optimization) */ MBFlush(conn, &conn->co_TMBuf); conn->co_FCounter = 0; } /* * Function dispatch */ switch(desc->d_Type) { case THREAD_READER: if (FD_ISSET(i, &rfds) || FD_ISSET(i, &wfds)) HandleReaderMsg(desc); break; case THREAD_NNTP: /* client */ conn->co_Func(conn); if (conn->co_Auth.dr_ResultFlags & DR_REQUIRE_DNS) { /* Go back to parent for DNS check */ conn->co_Auth.dr_Code = 0; conn->co_TMBuf.mh_WEof = 1; } break; case THREAD_SPOOL: /* spool server */ case THREAD_POST: /* posting server */ conn->co_Func(conn); LogServerInfo(conn, TFd); break; default: /* panic */ break; } /* * do not call MBFlush after the function because the * function may be waiting for write data to drain and * we don't want to cause write data to drain here and * then not get a select wakeup later. * * check for connection termination */ if (conn) { int idleTimeout = 0; if (conn->co_Auth.dr_ReaderDef) { if (conn->co_Auth.dr_ReaderDef->rd_IdleTimeout && conn->co_LastActiveTime + conn->co_Auth.dr_ReaderDef->rd_IdleTimeout <= CurTime.tv_sec) { logit(LOG_INFO, "timeout idle %s", conn->co_Auth.dr_Host); MBLogPrintf(conn, &conn->co_TMBuf, "400 %s: Idle timeout.\r\n", conn->co_Auth.dr_VServerDef->vs_HostName ); idleTimeout = 1; NNTerminate(conn); } if (conn->co_Auth.dr_ReaderDef->rd_SessionTimeout && conn->co_SessionStartTime + conn->co_Auth.dr_ReaderDef->rd_SessionTimeout <= CurTime.tv_sec) { logit(LOG_INFO, "timeout session %s", conn->co_Auth.dr_Host); MBLogPrintf(conn, &conn->co_TMBuf, "400 %s: Session timeout.\r\n", conn->co_Auth.dr_VServerDef->vs_HostName ); idleTimeout = 1; NNTerminate(conn); } } if ((!conn->co_Auth.dr_Code && desc->d_Type == THREAD_NNTP) || idleTimeout || (conn->co_RMBuf.mh_REof && conn->co_TMBuf.mh_WEof && conn->co_TMBuf.mh_MBuf == NULL) || (TerminatePending && !(conn->co_Flags & COF_MAYNOTCLOSE)) ) { DeleteConnection(conn); DelThread(desc); } } } } } forceallcheck = 0; (void)ScanTimers(1, 0); if (CanTerminate) break; } RTStatusClose(); KPDBClose(KDBActive); exit(0); }
/** Main Connection Thread. Handles all the networking to allow Mining threads the most performance. **/ void ServerConnection::ServerThread() { /** Don't begin until all mining threads are Created. **/ while(THREADS.size() != nThreads) Sleep(1); /** Initialize the Server Connection. **/ CLIENT = new LLP::Miner(IP, PORT); /** Initialize a Timer for the Hash Meter. **/ METER_TIMER.Start(); HEIGHT_TIMER.Start(); loop { try { /** Run this thread at 100 Cycles per Second. **/ Sleep(10); /** Attempt with best efforts to keep the Connection Alive. **/ if(!CLIENT->Connected() || CLIENT->Errors() || CLIENT->Timeout(nTimeout)) { ResetThreads(); if(!CLIENT->Connect()) continue; else { CLIENT->SetChannel(1); CLIENT->GetHeight(); } } /** Check the Block Height every Second. **/ if(HEIGHT_TIMER.ElapsedMilliseconds() > 1000) { HEIGHT_TIMER.Reset(); CLIENT->GetHeight(); } /** Show the Meter every 15 Seconds. **/ if(METER_TIMER.Elapsed() > 15) { unsigned int SecondsElapsed = (unsigned int)time(0) - nStartTimer; unsigned int nElapsed = METER_TIMER.Elapsed(); double PPS = (double) nPrimes / nElapsed; double CPS = (double) nChains / nElapsed; double CSD = (double) (nBlocks * 60.0) / (SecondsElapsed / 60.0); nPrimes = 0; nChains = 0; printf("[METERS] %f PPS | %f CPS | %u Blocks | %f NXS per Hour | Height = %u | Difficulty %f | %02d:%02d:%02d\n", PPS, CPS, nBlocks, CSD, nBestHeight, nDifficulty / 10000000.0, (SecondsElapsed/3600)%60, (SecondsElapsed/60)%60, (SecondsElapsed)%60); METER_TIMER.Reset(); ResetThreads(); } /** Check if there is work to do for each Miner Thread. **/ for(int nIndex = 0; nIndex < THREADS.size(); nIndex++) { /** Attempt to get a new block from the Server if Thread needs One. **/ if(THREADS[nIndex]->fNewBlock) { CLIENT->GetBlock(); THREADS[nIndex]->fBlockWaiting = true; THREADS[nIndex]->fNewBlock = false; } } CLIENT->ReadPacket(); if(!CLIENT->PacketComplete()) continue; /** Handle the New Packet, and Interpret its Data. **/ LLP::Packet PACKET = CLIENT->NewPacket(); CLIENT->ResetPacket(); /** Output if a Share is Accepted. **/ if(PACKET.HEADER == CLIENT->GOOD) { nBlocks++; printf("[MASTER] Nexus : Block ACCEPTED\n"); ResetThreads(); } /** Output if a Share is Rejected. **/ else if(PACKET.HEADER == CLIENT->FAIL) { printf("[MASTER] Nexus : Block REJECTED\n"); ResetThreads(); } /** Reset the Threads if a New Block came in. **/ else if(PACKET.HEADER == CLIENT->BLOCK_HEIGHT) { unsigned int nHeight = bytes2uint(PACKET.DATA); if(nHeight > nBestHeight) { nBestHeight = nHeight; printf("[MASTER] Nexus : New Block %u.\n", nBestHeight); ResetThreads(); } } /** Set the Block for the Thread if there is a New Block Packet. **/ else if(PACKET.HEADER == CLIENT->BLOCK_DATA) { /** Search for a Thread waiting for a New Block to Supply its need. **/ for(int nIndex = 0; nIndex < THREADS.size(); nIndex++) { if(THREADS[nIndex]->fBlockWaiting) { THREADS[nIndex]->MUTEX.lock(); THREADS[nIndex]->cBlock.nVersion = bytes2uint(std::vector<unsigned char>(PACKET.DATA.begin(), PACKET.DATA.begin() + 4)); THREADS[nIndex]->cBlock.hashPrevBlock.SetBytes (std::vector<unsigned char>(PACKET.DATA.begin() + 4, PACKET.DATA.begin() + 132)); THREADS[nIndex]->cBlock.hashMerkleRoot.SetBytes(std::vector<unsigned char>(PACKET.DATA.begin() + 132, PACKET.DATA.end() - 20)); THREADS[nIndex]->cBlock.nChannel = bytes2uint(std::vector<unsigned char>(PACKET.DATA.end() - 20, PACKET.DATA.end() - 16)); THREADS[nIndex]->cBlock.nHeight = bytes2uint(std::vector<unsigned char>(PACKET.DATA.end() - 16, PACKET.DATA.end() - 12)); THREADS[nIndex]->cBlock.nBits = bytes2uint(std::vector<unsigned char>(PACKET.DATA.end() - 12, PACKET.DATA.end() - 8)); THREADS[nIndex]->cBlock.nNonce = bytes2uint64(std::vector<unsigned char>(PACKET.DATA.end() - 8, PACKET.DATA.end())); THREADS[nIndex]->MUTEX.unlock(); if(THREADS[nIndex]->cBlock.nHeight < nBestHeight) { printf("[MASTER] Received Obsolete Block %u... Requesting New Block.\n", THREADS[nIndex]->cBlock.nHeight); CLIENT->GetBlock(); break; } /** Set the Difficulty from most recent Block Received. **/ nDifficulty = THREADS[nIndex]->cBlock.nBits; printf("[MASTER] Block %s Height = %u Received on Thread %u\n", THREADS[nIndex]->cBlock.hashMerkleRoot.ToString().substr(0, 20).c_str(), THREADS[nIndex]->cBlock.nHeight, nIndex); THREADS[nIndex]->fBlockWaiting = false; break; } } } } catch(std::exception& e) { printf("%s\n", e.what()); CLIENT = new LLP::Miner(IP, PORT); } } }
//Main Connection Thread. Handles all the networking to allow //Mining threads the most performance. void SKServerConnection::ServerThread() { /** Don't begin until all mining threads are Created. **/ while ((m_vecTHREADS.size() != m_nThreads) && !m_bIsShutDown) Sleep(1000); /** Initialize the Server Connection. **/ m_pCLIENT = new LLP::Miner(m_szIP, m_szPORT); /** Initialize a Timer for the Hash Meter. **/ m_tTIMER.Start(); m_totalTIMER.Start(); m_nBestHeight = 0; m_nNewBlocks = 0; loop { if (m_bIsShutDown) { break; } try { /** Run this thread at 1 Cycle per Second. **/ Sleep(1000); if (!m_bIsEnabled) { continue; } /** Attempt with best efforts to keep the Connection Alive. **/ if (!m_pCLIENT->Connected() || m_pCLIENT->Errors()) { if (!m_pCLIENT->Connect()) continue; /** Send to the server the Channel we will be Mining For. **/ else m_pCLIENT->SetChannel(2); } /** Check the Block Height. **/ unsigned int nHeight = m_pCLIENT->GetHeight(5); if (nHeight == 0) { printf("Failed to Update Height...\n"); m_pCLIENT->Disconnect(); continue; } /** If there is a new block, Flag the Threads to Stop Mining. **/ if (nHeight != m_nBestHeight) { m_nBestHeight = nHeight; m_nNewBlocks++; printf("[MASTER] Coinshield Network | New Block %u\n", nHeight); ResetThreads(); } /** Rudimentary Meter **/ if (m_tTIMER.Elapsed() > 10) { //unsigned int nElapsed = m_tTIMER.ElapsedMilliseconds(); //unsigned int nHashes = Hashes(); double KHASH = Hashes(); //double KHASH = (double)nHashes / nElapsed; printf("[METERS] %f KHash/s | Height = %u\n", KHASH, m_nBestHeight); m_tTIMER.Reset(); } /** Check if there is work to do for each Miner Thread. **/ for (int nIndex = 0; nIndex < m_vecTHREADS.size(); nIndex++) { if (m_bIsShutDown) { break; } if (!m_vecTHREADS[nIndex]->GetMinerData()->GetGPUData()->GetGPUSetting()->GetIsEnabled()) { continue; } /** Attempt to get a new block from the Server if Thread needs One. **/ if (m_vecTHREADS[nIndex]->GetIsNewBlock()) { /** Delete the Block Pointer if it Exists. **/ Core::CBlock* pBlock = m_vecTHREADS[nIndex]->GetMinerData()->GetBlock(); if (pBlock != NULL) { delete(pBlock); pBlock = NULL; } /** Retrieve new block from Server. **/ m_pCLIENT->SetChannel(2); pBlock = m_pCLIENT->GetBlock(5); /** If the block is good, tell the Mining Thread its okay to Mine. **/ if (pBlock && pBlock->GetChannel() == 2) { m_vecTHREADS[nIndex]->SetIsNewBlock(false); m_vecTHREADS[nIndex]->SetIsBlockFound(false); m_vecTHREADS[nIndex]->GetMinerData()->SetBlock(pBlock); } /** If the Block didn't come in properly, Reconnect to the Server. **/ else { m_pCLIENT->Disconnect(); } } /** Submit a block from Mining Thread if Flagged. **/ else if (m_vecTHREADS[nIndex]->GetIsBlockFound()) { /** Attempt to Submit the Block to Network. **/ unsigned char RESPONSE = m_pCLIENT->SubmitBlock(m_vecTHREADS[nIndex]->GetMinerData()->GetBlock()->GetMerkleRoot(), m_vecTHREADS[nIndex]->GetMinerData()->GetBlock()->GetNonce(), 30); printf("[MASTER] Hash Found on Miner Thread %i\n", nIndex); unsigned long long truc = m_vecTHREADS[nIndex]->GetMinerData()->GetBlock()->GetNonce(); printf("[MASTER] nonce %08x %08x\n", (uint32_t)(truc >> 32)), (uint32_t)(truc & 0xFFFFFFFFULL); /** Check the Response from the Server.**/ if (RESPONSE == 200) { printf("[MASTER] Block Accepted By Coinshield Network.\n"); m_vecTHREADS[nIndex]->SetBlocksFound(m_vecTHREADS[nIndex]->GetBlocksFound() + 1); } else if (RESPONSE == 201) { printf("[MASTER] Block Rejected by Coinshield Network.\n"); m_vecTHREADS[nIndex]->SetRejected(m_vecTHREADS[nIndex]->GetRejected() + 1); m_vecTHREADS[nIndex]->SetIsNewBlock(true); m_vecTHREADS[nIndex]->SetIsBlockFound(false); } /** If the Response was Incomplete, Reconnect to Server and try to Submit Block Again. **/ else { printf("[MASTER] Failure to Submit Block. Reconnecting...\n"); m_pCLIENT->Disconnect(); } break; } } } catch (std::exception& e) { std::cout << e.what() << std::endl; } } if (m_bIsShutDown) { for (size_t index = 0; index < m_vecTHREADS.size(); ++index) { m_vecTHREADS[index]->SetIsShuttingDown(true); while (!m_vecTHREADS[index]->GetDidShutDown()){} } m_bDidShutDown = true; } }