diff options
Diffstat (limited to 'src/main.cpp')
| -rw-r--r-- | src/main.cpp | 250 |
1 files changed, 238 insertions, 12 deletions
diff --git a/src/main.cpp b/src/main.cpp index 77aba89..252911b 100644 --- a/src/main.cpp +++ b/src/main.cpp | |||
| @@ -109,7 +109,11 @@ string strPayoutFile; // participant: /payoutfile with one addres | |||
| 109 | int nHashThreads = 0; // participant: /hashthreads override (0 = cores-1) | 109 | int nHashThreads = 0; // participant: /hashthreads override (0 = cores-1) |
| 110 | string strPoolName = "Bitflash Pool"; | 110 | string strPoolName = "Bitflash Pool"; |
| 111 | string strPoolDashboardUrl; | 111 | string strPoolDashboardUrl; |
| 112 | string strPoolStatusFile; | ||
| 113 | string strPoolRoundsFile; | ||
| 112 | double dPoolFeePercent = 0.0; | 114 | double dPoolFeePercent = 0.0; |
| 115 | bool fStratumBridge = false; | ||
| 116 | int nStratumBridgePort = 3333; | ||
| 113 | 117 | ||
| 114 | static std::atomic<uint64> gParticipantSharesSent{0}; | 118 | static std::atomic<uint64> gParticipantSharesSent{0}; |
| 115 | static std::atomic<uint64> gParticipantSharesAccepted{0}; | 119 | static std::atomic<uint64> gParticipantSharesAccepted{0}; |
| @@ -190,6 +194,9 @@ int ParticipantHashThreadCount() | |||
| 190 | return nWorkers - 1; | 194 | return nWorkers - 1; |
| 191 | } | 195 | } |
| 192 | 196 | ||
| 197 | static void SecureClearBytes(vector<unsigned char>& vch); | ||
| 198 | static void SecureClearKeyingMaterial(CKeyingMaterial& vch); | ||
| 199 | |||
| 193 | bool AddKey(const CKey& key) | 200 | bool AddKey(const CKey& key) |
| 194 | { | 201 | { |
| 195 | if (IsWalletEncrypted()) | 202 | if (IsWalletEncrypted()) |
| @@ -199,9 +206,13 @@ bool AddKey(const CKey& key) | |||
| 199 | vector<unsigned char> vchCryptedSecret; | 206 | vector<unsigned char> vchCryptedSecret; |
| 200 | if (IsWalletLocked()) | 207 | if (IsWalletLocked()) |
| 201 | return error("AddKey() : wallet is locked\n"); | 208 | return error("AddKey() : wallet is locked\n"); |
| 202 | if (!EncryptSecret(vWalletMasterKey, vector<unsigned char>(vchPrivKey.begin(), vchPrivKey.end()), | 209 | vector<unsigned char> vchPlainSecret(vchPrivKey.begin(), vchPrivKey.end()); |
| 203 | WalletKeyIV(key.GetPubKey()), vchCryptedSecret)) | 210 | if (!EncryptSecret(vWalletMasterKey, vchPlainSecret, WalletKeyIV(key.GetPubKey()), vchCryptedSecret)) |
| 211 | { | ||
| 212 | SecureClearBytes(vchPlainSecret); | ||
| 204 | return error("AddKey() : encrypting key failed\n"); | 213 | return error("AddKey() : encrypting key failed\n"); |
| 214 | } | ||
| 215 | SecureClearBytes(vchPlainSecret); | ||
| 205 | if (!AddCryptedKey(key.GetPubKey(), vchCryptedSecret)) | 216 | if (!AddCryptedKey(key.GetPubKey(), vchCryptedSecret)) |
| 206 | return false; | 217 | return false; |
| 207 | return CWalletDB().WriteCryptedKey(key.GetPubKey(), vchCryptedSecret); | 218 | return CWalletDB().WriteCryptedKey(key.GetPubKey(), vchCryptedSecret); |
| @@ -225,17 +236,31 @@ bool IsWalletLocked() | |||
| 225 | return fWalletEncrypted && fWalletLocked; | 236 | return fWalletEncrypted && fWalletLocked; |
| 226 | } | 237 | } |
| 227 | 238 | ||
| 239 | static void SecureClearBytes(vector<unsigned char>& vch) | ||
| 240 | { | ||
| 241 | if (!vch.empty()) | ||
| 242 | OPENSSL_cleanse(&vch[0], vch.size()); | ||
| 243 | vch.clear(); | ||
| 244 | } | ||
| 245 | |||
| 246 | static void SecureClearKeyingMaterial(CKeyingMaterial& vch) | ||
| 247 | { | ||
| 248 | if (!vch.empty()) | ||
| 249 | OPENSSL_cleanse(&vch[0], vch.size()); | ||
| 250 | vch.clear(); | ||
| 251 | } | ||
| 252 | |||
| 228 | void LockWallet() | 253 | void LockWallet() |
| 229 | { | 254 | { |
| 230 | if (!fWalletEncrypted) | 255 | if (!fWalletEncrypted) |
| 231 | return; | 256 | return; |
| 232 | CRITICAL_BLOCK(cs_mapKeys) | 257 | CRITICAL_BLOCK(cs_mapKeys) |
| 233 | { | 258 | { |
| 234 | vWalletMasterKey.clear(); | 259 | SecureClearKeyingMaterial(vWalletMasterKey); |
| 235 | if (!vchCryptedHDMaster.empty()) | 260 | if (!vchCryptedHDMaster.empty()) |
| 236 | vchHDMaster.clear(); | 261 | SecureClearBytes(vchHDMaster); |
| 237 | if (!vchCryptedHDChainCode.empty()) | 262 | if (!vchCryptedHDChainCode.empty()) |
| 238 | vchHDChainCode.clear(); | 263 | SecureClearBytes(vchHDChainCode); |
| 239 | fWalletLocked = true; | 264 | fWalletLocked = true; |
| 240 | } | 265 | } |
| 241 | } | 266 | } |
| @@ -260,14 +285,14 @@ bool DeriveWalletPassphraseKey(const string& strPassphrase, | |||
| 260 | chKey, chIV); | 285 | chKey, chIV); |
| 261 | if (n != 32) | 286 | if (n != 32) |
| 262 | { | 287 | { |
| 263 | memset(chKey, 0, sizeof(chKey)); | 288 | OPENSSL_cleanse(chKey, sizeof(chKey)); |
| 264 | memset(chIV, 0, sizeof(chIV)); | 289 | OPENSSL_cleanse(chIV, sizeof(chIV)); |
| 265 | return false; | 290 | return false; |
| 266 | } | 291 | } |
| 267 | vchKeyRet.assign(chKey, chKey + sizeof(chKey)); | 292 | vchKeyRet.assign(chKey, chKey + sizeof(chKey)); |
| 268 | vchIVRet.assign(chIV, chIV + sizeof(chIV)); | 293 | vchIVRet.assign(chIV, chIV + sizeof(chIV)); |
| 269 | memset(chKey, 0, sizeof(chKey)); | 294 | OPENSSL_cleanse(chKey, sizeof(chKey)); |
| 270 | memset(chIV, 0, sizeof(chIV)); | 295 | OPENSSL_cleanse(chIV, sizeof(chIV)); |
| 271 | return true; | 296 | return true; |
| 272 | } | 297 | } |
| 273 | 298 | ||
| @@ -328,6 +353,8 @@ bool DecryptSecret(const CKeyingMaterial& vchKey, | |||
| 328 | vchPlaintextRet.swap(vchOut); | 353 | vchPlaintextRet.swap(vchOut); |
| 329 | fOk = true; | 354 | fOk = true; |
| 330 | } | 355 | } |
| 356 | if (!fOk) | ||
| 357 | SecureClearBytes(vchOut); | ||
| 331 | EVP_CIPHER_CTX_free(ctx); | 358 | EVP_CIPHER_CTX_free(ctx); |
| 332 | return fOk; | 359 | return fOk; |
| 333 | } | 360 | } |
| @@ -403,6 +430,7 @@ bool GetWalletPrivKey(const vector<unsigned char>& vchPubKey, | |||
| 403 | } | 430 | } |
| 404 | 431 | ||
| 405 | CPrivKey vchPrivKey(vchPlaintext.begin(), vchPlaintext.end()); | 432 | CPrivKey vchPrivKey(vchPlaintext.begin(), vchPlaintext.end()); |
| 433 | SecureClearBytes(vchPlaintext); | ||
| 406 | CKey key; | 434 | CKey key; |
| 407 | if (!key.SetPrivKey(vchPrivKey) || key.GetPubKey() != vchPubKey) | 435 | if (!key.SetPrivKey(vchPrivKey) || key.GetPubKey() != vchPubKey) |
| 408 | { | 436 | { |
| @@ -437,11 +465,20 @@ bool UnlockWallet(const string& strPassphrase, string& strErrorRet) | |||
| 437 | vector<unsigned char> vchMasterPlain; | 465 | vector<unsigned char> vchMasterPlain; |
| 438 | if (!DecryptSecret(vchPassKey, kMasterKey.vchCryptedKey, | 466 | if (!DecryptSecret(vchPassKey, kMasterKey.vchCryptedKey, |
| 439 | vchPassIV, vchMasterPlain)) | 467 | vchPassIV, vchMasterPlain)) |
| 468 | { | ||
| 469 | SecureClearBytes(vchPassIV); | ||
| 440 | continue; | 470 | continue; |
| 471 | } | ||
| 441 | if (vchMasterPlain.size() != 32) | 472 | if (vchMasterPlain.size() != 32) |
| 473 | { | ||
| 474 | SecureClearBytes(vchMasterPlain); | ||
| 475 | SecureClearBytes(vchPassIV); | ||
| 442 | continue; | 476 | continue; |
| 477 | } | ||
| 443 | 478 | ||
| 444 | CKeyingMaterial vchCandidate(vchMasterPlain.begin(), vchMasterPlain.end()); | 479 | CKeyingMaterial vchCandidate(vchMasterPlain.begin(), vchMasterPlain.end()); |
| 480 | SecureClearBytes(vchMasterPlain); | ||
| 481 | SecureClearBytes(vchPassIV); | ||
| 445 | bool fValid = mapCryptedKeys.empty(); | 482 | bool fValid = mapCryptedKeys.empty(); |
| 446 | for (map<vector<unsigned char>, vector<unsigned char> >::iterator mci = mapCryptedKeys.begin(); | 483 | for (map<vector<unsigned char>, vector<unsigned char> >::iterator mci = mapCryptedKeys.begin(); |
| 447 | mci != mapCryptedKeys.end(); ++mci) | 484 | mci != mapCryptedKeys.end(); ++mci) |
| @@ -450,6 +487,7 @@ bool UnlockWallet(const string& strPassphrase, string& strErrorRet) | |||
| 450 | if (!DecryptSecret(vchCandidate, (*mci).second, WalletKeyIV((*mci).first), vchPlaintext)) | 487 | if (!DecryptSecret(vchCandidate, (*mci).second, WalletKeyIV((*mci).first), vchPlaintext)) |
| 451 | break; | 488 | break; |
| 452 | CPrivKey vchPrivKey(vchPlaintext.begin(), vchPlaintext.end()); | 489 | CPrivKey vchPrivKey(vchPlaintext.begin(), vchPlaintext.end()); |
| 490 | SecureClearBytes(vchPlaintext); | ||
| 453 | CKey key; | 491 | CKey key; |
| 454 | if (key.SetPrivKey(vchPrivKey) && key.GetPubKey() == (*mci).first) | 492 | if (key.SetPrivKey(vchPrivKey) && key.GetPubKey() == (*mci).first) |
| 455 | fValid = true; | 493 | fValid = true; |
| @@ -465,10 +503,12 @@ bool UnlockWallet(const string& strPassphrase, string& strErrorRet) | |||
| 465 | WalletSecretIV("hdmaster"), vchPlainHDMaster) || | 503 | WalletSecretIV("hdmaster"), vchPlainHDMaster) || |
| 466 | vchPlainHDMaster.size() != 32) | 504 | vchPlainHDMaster.size() != 32) |
| 467 | { | 505 | { |
| 506 | SecureClearBytes(vchPlainHDMaster); | ||
| 468 | strErrorRet = "could not decrypt HD master key"; | 507 | strErrorRet = "could not decrypt HD master key"; |
| 469 | return false; | 508 | return false; |
| 470 | } | 509 | } |
| 471 | vchHDMaster = vchPlainHDMaster; | 510 | vchHDMaster = vchPlainHDMaster; |
| 511 | SecureClearBytes(vchPlainHDMaster); | ||
| 472 | } | 512 | } |
| 473 | if (!vchCryptedHDChainCode.empty()) | 513 | if (!vchCryptedHDChainCode.empty()) |
| 474 | { | 514 | { |
| @@ -477,10 +517,12 @@ bool UnlockWallet(const string& strPassphrase, string& strErrorRet) | |||
| 477 | WalletSecretIV("hdchaincode"), vchPlainHDChainCode) || | 517 | WalletSecretIV("hdchaincode"), vchPlainHDChainCode) || |
| 478 | vchPlainHDChainCode.size() != 32) | 518 | vchPlainHDChainCode.size() != 32) |
| 479 | { | 519 | { |
| 520 | SecureClearBytes(vchPlainHDChainCode); | ||
| 480 | strErrorRet = "could not decrypt HD chain code"; | 521 | strErrorRet = "could not decrypt HD chain code"; |
| 481 | return false; | 522 | return false; |
| 482 | } | 523 | } |
| 483 | vchHDChainCode = vchPlainHDChainCode; | 524 | vchHDChainCode = vchPlainHDChainCode; |
| 525 | SecureClearBytes(vchPlainHDChainCode); | ||
| 484 | } | 526 | } |
| 485 | fWalletLocked = false; | 527 | fWalletLocked = false; |
| 486 | return true; | 528 | return true; |
| @@ -625,7 +667,7 @@ unsigned int nHDNext = 0; | |||
| 625 | int nHDKeySchema = HD_SCHEMA_NONE; | 667 | int nHDKeySchema = HD_SCHEMA_NONE; |
| 626 | unsigned int nHDReceiveNext = 0; | 668 | unsigned int nHDReceiveNext = 0; |
| 627 | unsigned int nHDChangeNext = 0; | 669 | unsigned int nHDChangeNext = 0; |
| 628 | unsigned int nHDCoinType = HD_BIP44_COIN_TYPE_BITFLASH_PROVISIONAL; | 670 | unsigned int nHDCoinType = HD_BIP44_COIN_TYPE_BITFLASH; |
| 629 | 671 | ||
| 630 | string HDKeySchemaName(int nSchema) | 672 | string HDKeySchemaName(int nSchema) |
| 631 | { | 673 | { |
| @@ -781,7 +823,7 @@ bool SetHDSeedFromMnemonic(const string& strMnemonic, string& strErrorRet) | |||
| 781 | 823 | ||
| 782 | if (!CWalletDB().WriteHDMaster(master.privateKey, master.chainCode) || | 824 | if (!CWalletDB().WriteHDMaster(master.privateKey, master.chainCode) || |
| 783 | !CWalletDB().WriteHDSchema(HD_SCHEMA_BIP44) || | 825 | !CWalletDB().WriteHDSchema(HD_SCHEMA_BIP44) || |
| 784 | !CWalletDB().WriteHDCoinType(HD_BIP44_COIN_TYPE_BITFLASH_PROVISIONAL) || | 826 | !CWalletDB().WriteHDCoinType(HD_BIP44_COIN_TYPE_BITFLASH) || |
| 785 | !CWalletDB().WriteHDNext(0) || | 827 | !CWalletDB().WriteHDNext(0) || |
| 786 | !CWalletDB().WriteHDReceiveNext(1) || | 828 | !CWalletDB().WriteHDReceiveNext(1) || |
| 787 | !CWalletDB().WriteHDChangeNext(0)) | 829 | !CWalletDB().WriteHDChangeNext(0)) |
| @@ -794,7 +836,7 @@ bool SetHDSeedFromMnemonic(const string& strMnemonic, string& strErrorRet) | |||
| 794 | nHDKeySchema = HD_SCHEMA_BIP44; | 836 | nHDKeySchema = HD_SCHEMA_BIP44; |
| 795 | nHDReceiveNext = 1; | 837 | nHDReceiveNext = 1; |
| 796 | nHDChangeNext = 0; | 838 | nHDChangeNext = 0; |
| 797 | nHDCoinType = HD_BIP44_COIN_TYPE_BITFLASH_PROVISIONAL; | 839 | nHDCoinType = HD_BIP44_COIN_TYPE_BITFLASH; |
| 798 | 840 | ||
| 799 | // Index 0 is spoken for before it is derived, so a failure below cannot | 841 | // Index 0 is spoken for before it is derived, so a failure below cannot |
| 800 | // leave the pool free to hand it out as an ordinary key. The cost of | 842 | // leave the pool free to hand it out as an ordinary key. The cost of |
| @@ -4128,6 +4170,190 @@ connected: | |||
| 4128 | return true; | 4170 | return true; |
| 4129 | } | 4171 | } |
| 4130 | 4172 | ||
| 4173 | // --------------------------------------------------------------------------- | ||
| 4174 | // Local Stratum bridge -- lets external miners speak plain Stratum to | ||
| 4175 | // 127.0.0.1 while Bitflash opens the .btf tunnel to the selected pool. | ||
| 4176 | // --------------------------------------------------------------------------- | ||
| 4177 | |||
| 4178 | struct StratumBridgeClientCtx | ||
| 4179 | { | ||
| 4180 | SOCKET miner; | ||
| 4181 | std::string pool; | ||
| 4182 | }; | ||
| 4183 | |||
| 4184 | static bool BridgeSendAll(SOCKET s, const char* p, int n) | ||
| 4185 | { | ||
| 4186 | int off = 0; | ||
| 4187 | while (off < n) | ||
| 4188 | { | ||
| 4189 | int r = send(s, p + off, n - off, 0); | ||
| 4190 | if (r <= 0) | ||
| 4191 | return false; | ||
| 4192 | off += r; | ||
| 4193 | } | ||
| 4194 | return true; | ||
| 4195 | } | ||
| 4196 | |||
| 4197 | static void BridgePump(SOCKET a, SOCKET b) | ||
| 4198 | { | ||
| 4199 | char buf[8192]; | ||
| 4200 | while (!fShutdown) | ||
| 4201 | { | ||
| 4202 | fd_set rd; | ||
| 4203 | FD_ZERO(&rd); | ||
| 4204 | FD_SET(a, &rd); | ||
| 4205 | FD_SET(b, &rd); | ||
| 4206 | SOCKET maxfd = a > b ? a : b; | ||
| 4207 | struct timeval tv = {1, 0}; | ||
| 4208 | int r = select((int)maxfd + 1, &rd, NULL, NULL, &tv); | ||
| 4209 | if (r <= 0) | ||
| 4210 | continue; | ||
| 4211 | |||
| 4212 | if (FD_ISSET(a, &rd)) | ||
| 4213 | { | ||
| 4214 | int n = recv(a, buf, sizeof(buf), 0); | ||
| 4215 | if (n <= 0 || !BridgeSendAll(b, buf, n)) | ||
| 4216 | break; | ||
| 4217 | } | ||
| 4218 | if (FD_ISSET(b, &rd)) | ||
| 4219 | { | ||
| 4220 | int n = recv(b, buf, sizeof(buf), 0); | ||
| 4221 | if (n <= 0 || !BridgeSendAll(a, buf, n)) | ||
| 4222 | break; | ||
| 4223 | } | ||
| 4224 | } | ||
| 4225 | } | ||
| 4226 | |||
| 4227 | static void ThreadStratumBridgeClient(void* arg) | ||
| 4228 | { | ||
| 4229 | StratumBridgeClientCtx* ctx = (StratumBridgeClientCtx*)arg; | ||
| 4230 | SOCKET miner = ctx->miner; | ||
| 4231 | std::string pool = ctx->pool; | ||
| 4232 | delete ctx; | ||
| 4233 | |||
| 4234 | unsigned char target_pubkey[32]; | ||
| 4235 | if (!btf::ParseAddress(pool, target_pubkey)) | ||
| 4236 | { | ||
| 4237 | LogPrint("worker", "[bridge] invalid pool .btf address: %s\n", pool.c_str()); | ||
| 4238 | BtfCloseSocket(miner); | ||
| 4239 | return; | ||
| 4240 | } | ||
| 4241 | |||
| 4242 | std::string meetingHostPort; | ||
| 4243 | unsigned char service_enc_pub[32]; | ||
| 4244 | if (!BtfResolve(pool, meetingHostPort, service_enc_pub)) | ||
| 4245 | { | ||
| 4246 | LogPrint("worker", "[bridge] failed to resolve pool %s\n", pool.c_str()); | ||
| 4247 | BtfCloseSocket(miner); | ||
| 4248 | return; | ||
| 4249 | } | ||
| 4250 | |||
| 4251 | size_t colon = meetingHostPort.rfind(':'); | ||
| 4252 | if (colon == std::string::npos) | ||
| 4253 | { | ||
| 4254 | LogPrint("worker", "[bridge] bad pool endpoint '%s'\n", meetingHostPort.c_str()); | ||
| 4255 | BtfCloseSocket(miner); | ||
| 4256 | return; | ||
| 4257 | } | ||
| 4258 | std::string host = meetingHostPort.substr(0, colon); | ||
| 4259 | int port = atoi(meetingHostPort.substr(colon + 1).c_str()); | ||
| 4260 | if (port <= 0 || port > 65535) | ||
| 4261 | { | ||
| 4262 | LogPrint("worker", "[bridge] bad pool port in '%s'\n", meetingHostPort.c_str()); | ||
| 4263 | BtfCloseSocket(miner); | ||
| 4264 | return; | ||
| 4265 | } | ||
| 4266 | |||
| 4267 | SOCKET poolSock = btf::BtfClientTunnel(host.c_str(), (unsigned short)port, | ||
| 4268 | target_pubkey, service_enc_pub); | ||
| 4269 | if (poolSock == INVALID_SOCKET) | ||
| 4270 | { | ||
| 4271 | LogPrint("worker", "[bridge] tunnel connect failed for pool %s via %s\n", | ||
| 4272 | pool.c_str(), meetingHostPort.c_str()); | ||
| 4273 | BtfCloseSocket(miner); | ||
| 4274 | return; | ||
| 4275 | } | ||
| 4276 | |||
| 4277 | LogPrint("worker", "[bridge] miner connected to pool %s via %s\n", | ||
| 4278 | pool.c_str(), meetingHostPort.c_str()); | ||
| 4279 | BridgePump(miner, poolSock); | ||
| 4280 | BtfCloseSocket(poolSock); | ||
| 4281 | BtfCloseSocket(miner); | ||
| 4282 | LogPrint("worker", "[bridge] miner disconnected from pool %s\n", pool.c_str()); | ||
| 4283 | } | ||
| 4284 | |||
| 4285 | void ThreadStratumBridge(void*) | ||
| 4286 | { | ||
| 4287 | if (strParticipantPool.empty()) | ||
| 4288 | { | ||
| 4289 | printf("Stratum bridge: no pool selected. Use /stratumbridge=POOL_BTF_ADDRESS\n"); | ||
| 4290 | return; | ||
| 4291 | } | ||
| 4292 | |||
| 4293 | SOCKET listener = BtfSocketTag(socket(AF_INET, SOCK_STREAM, IPPROTO_TCP), | ||
| 4294 | SOCK_STRATUM_BRIDGE); | ||
| 4295 | if (listener == INVALID_SOCKET) | ||
| 4296 | { | ||
| 4297 | printf("Stratum bridge: could not create listen socket\n"); | ||
| 4298 | return; | ||
| 4299 | } | ||
| 4300 | |||
| 4301 | int yes = 1; | ||
| 4302 | setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(yes)); | ||
| 4303 | |||
| 4304 | sockaddr_in addr; | ||
| 4305 | memset(&addr, 0, sizeof(addr)); | ||
| 4306 | addr.sin_family = AF_INET; | ||
| 4307 | addr.sin_addr.s_addr = htonl(0x7f000001); | ||
| 4308 | addr.sin_port = htons((unsigned short)nStratumBridgePort); | ||
| 4309 | |||
| 4310 | if (bind(listener, (sockaddr*)&addr, sizeof(addr)) != 0 || | ||
| 4311 | listen(listener, 16) != 0) | ||
| 4312 | { | ||
| 4313 | printf("Stratum bridge: could not listen on 127.0.0.1:%d\n", | ||
| 4314 | nStratumBridgePort); | ||
| 4315 | BtfCloseSocket(listener); | ||
| 4316 | return; | ||
| 4317 | } | ||
| 4318 | |||
| 4319 | printf("Stratum bridge: listening on 127.0.0.1:%d for pool %s\n", | ||
| 4320 | nStratumBridgePort, strParticipantPool.c_str()); | ||
| 4321 | |||
| 4322 | while (!fShutdown) | ||
| 4323 | { | ||
| 4324 | fd_set rd; | ||
| 4325 | FD_ZERO(&rd); | ||
| 4326 | FD_SET(listener, &rd); | ||
| 4327 | struct timeval tv = {1, 0}; | ||
| 4328 | if (select((int)listener + 1, &rd, NULL, NULL, &tv) <= 0) | ||
| 4329 | continue; | ||
| 4330 | |||
| 4331 | sockaddr_in cli; | ||
| 4332 | #ifdef _WIN32 | ||
| 4333 | int len = sizeof(cli); | ||
| 4334 | #else | ||
| 4335 | socklen_t len = sizeof(cli); | ||
| 4336 | #endif | ||
| 4337 | SOCKET miner = BtfSocketTag(accept(listener, (sockaddr*)&cli, &len), | ||
| 4338 | SOCK_STRATUM_BRIDGE); | ||
| 4339 | if (miner == INVALID_SOCKET) | ||
| 4340 | continue; | ||
| 4341 | |||
| 4342 | StratumBridgeClientCtx* ctx = new StratumBridgeClientCtx(); | ||
| 4343 | ctx->miner = miner; | ||
| 4344 | ctx->pool = strParticipantPool; | ||
| 4345 | if (_beginthread(ThreadStratumBridgeClient, 0, ctx) == (uintptr_t)-1) | ||
| 4346 | { | ||
| 4347 | delete ctx; | ||
| 4348 | BtfCloseSocket(miner); | ||
| 4349 | LogPrint("worker", "[bridge] failed to spawn client thread\n"); | ||
| 4350 | } | ||
| 4351 | } | ||
| 4352 | |||
| 4353 | BtfCloseSocket(listener); | ||
| 4354 | printf("Stratum bridge: stopped\n"); | ||
| 4355 | } | ||
| 4356 | |||
| 4131 | bool BitcoinMiner(int nThreadId) | 4357 | bool BitcoinMiner(int nThreadId) |
| 4132 | { | 4358 | { |
| 4133 | // Relay mode: never mines, just relays/syncs. (Shouldn't normally get here | 4359 | // Relay mode: never mines, just relays/syncs. (Shouldn't normally get here |