// Demultiplexing the I/O events // Must be called in the loop thread. int KqueueSelect::select(int timeout, WatcherList *activeList) { int ret = -1; ret = kevent(_kqueuefd, NULL, 0, _events, _evSize, NULL); if (ret == -1) { // EINTR indicates epoll_wait was interrupted by a signal handler before // any of the requested events occurred or the timeout expired. if (errno != EINTR) { return -1; } return 0; } // Check what of the reqeusted events occurred on the file descriptors. for (int i = 0; i < ret; ++i) { Watcher *w = (Watcher *)_events[i].udata; int events = 0; int filter = _events[i].filter; if (filter == EVFILT_READ) { events |= kReadEvent; } if (filter == EVFILT_WRITE) { events |= kWriteEvent; } w->setActiveEvents(events); activeList->push_back(w); } return 0; }
tABC_CC ABC_BridgeWatcherConnect(Wallet &self, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; tABC_GeneralInfo *ppInfo = NULL; const char *szServer = FALLBACK_OBELISK; Watcher *watcher = nullptr; ABC_CHECK_NEW(watcherFind(watcher, self)); // Pick a server: if (isTestnet()) { szServer = TESTNET_OBELISK; } else if (ABC_CC_Ok == ABC_GeneralGetInfo(&ppInfo, pError) && 0 < ppInfo->countObeliskServers) { ++gLastObelisk; if (ppInfo->countObeliskServers <= gLastObelisk) gLastObelisk = 0; szServer = ppInfo->aszObeliskServers[gLastObelisk]; } // Connect: ABC_DebugLog("Wallet %s connecting to %s", self.id().c_str(), szServer); watcher->connect(szServer); exit: ABC_GeneralFreeInfo(ppInfo); return cc; }
void Watcher::notify(std::string name, std::string event) { Watchers& w = gWatchers[name]; for (Watchers::iterator it=w.begin(); it!=w.end(); it++) { Watcher * rw = *it; rw->onEvent(name, event); } }
tABC_CC ABC_BridgePrioritizeAddress(Wallet &self, const char *szAddress, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; bc::payment_address addr; Watcher *watcher = nullptr; ABC_CHECK_NEW(watcherFind(watcher, self)); if (szAddress) { if (!addr.set_encoded(szAddress)) { cc = ABC_CC_Error; ABC_DebugLog("Invalid szAddress %s\n", szAddress); goto exit; } } watcher->prioritize_address(addr); exit: return cc; }
int main(int argc, char *argv[]) { Watcher w; cout<<w.init((char *)"../../shared/", NULL)<<endl; w.watch(); return 0; }
/** * Filters a transaction list, removing any that aren't found in the * watcher database. * @param aTransactions The array to filter. This will be modified in-place. * @param pCount The array length. This will be updated upon return. */ tABC_CC ABC_BridgeFilterTransactions(Wallet &self, tABC_TxInfo **aTransactions, unsigned int *pCount, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; tABC_TxInfo *const *end = aTransactions + *pCount; tABC_TxInfo *const *si = aTransactions; tABC_TxInfo **di = aTransactions; Watcher *watcher = nullptr; ABC_CHECK_NEW(watcherFind(watcher, self)); while (si < end) { tABC_TxInfo *pTx = *si++; int height; bc::hash_digest txid; if (!bc::decode_hash(txid, pTx->szMalleableTxId)) ABC_RET_ERROR(ABC_CC_ParseError, "Bad txid"); if (watcher->get_tx_height(txid, height)) { *di++ = pTx; } else { ABC_TxFreeTransaction(pTx); } } *pCount = di - aTransactions; exit: return cc; }
int main(int argc, char *argv[]) { QApplication a(argc, argv); Watcher w; w.show(); return a.exec(); }
/** * Callback method that is called when child process changes status * @param loop The loop in which the event was triggered * @param watcher Internal watcher object * @param revents Events triggered */ static void onStatusChange(struct ev_loop *loop, ev_child *watcher, int revents) { // retrieve the reader Watcher *object = (Watcher *)watcher->data; // call it object->invoke(); }
Status bridgeWatcherStop(Wallet &self) { Watcher *watcher = nullptr; ABC_CHECK(watcherFind(watcher, self)); watcher->stop(); return Status(); }
Status bridgeWatcherDisconnect(Wallet &self) { Watcher *watcher = nullptr; ABC_CHECK(watcherFind(watcher, self)); watcher->disconnect(); return Status(); }
Status watcherSend(Wallet &self, StatusCallback status, DataSlice tx) { Watcher *watcher = nullptr; ABC_CHECK(watcherFind(watcher, self)); watcher->sendTx(status, tx); return Status(); }
Status watcherSave(Wallet &self) { Watcher *watcher = nullptr; ABC_CHECK(watcherFind(watcher, self)); auto data = watcher->serialize();; ABC_CHECK(fileSave(data, watcherPath(self))); return Status(); }
tABC_CC ABC_BridgeWatcherDisconnect(Wallet &self, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; Watcher *watcher = nullptr; ABC_CHECK_NEW(watcherFind(watcher, self)); watcher->disconnect(); exit: return cc; }
static Status watcherLoad(Wallet &self) { Watcher *watcher = nullptr; ABC_CHECK(watcherFind(watcher, self)); DataChunk data; ABC_CHECK(fileLoad(data, watcherPath(self))); if (!watcher->load(data)) return ABC_ERROR(ABC_CC_Error, "Unable to load serialized watcher"); return Status(); }
void Reactor_loop(Reactor self, int32_t to) { fd_t kqfd = self->poll.fileno; struct kevent events[MAXEVENT]; void* fds[MAXEVENT]; uint8_t wr_end, rd_begin; struct kevent* ev_end; Watcher wt; uint32_t* sig = &self->signal; struct timespec ts; struct timespec* timeout = NULL; if(to != -1) { time_t sec = to / 1000; long nsec = (to - sec * 1000) * 1000000000; ts.tv_sec = sec; ts.tv_nsec = nsec; timeout = &ts; } int32_t count; while(*sig == 0) { wr_end = 0; rd_begin = MAXEVENT; count = kevent(kqfd, NULL, 0, events, MAXEVENT, timeout); if(count == -1) { if(errno == EINTR) { return; } perror("Reactor_loop"); exit(-1); } ev_end = events + count; for(struct kevent* p = events; p < ev_end; ++p) { if(p->filter & EVFILT_WRITE) { fds[wr_end++] = p->udata; } else if(p->filter & EVFILT_READ) { fds[--rd_begin] = p->udata; } } for(uint8_t i = 0; i < wr_end; ++i) { wt = (Watcher)fds[i]; wt->onCall(wt); } for(uint8_t i = rd_begin; i < MAXEVENT; ++i) { wt = (Watcher)fds[i]; wt->onCall(wt); } } }
bool gather_challenges(unsigned_transaction& utx, Watcher& watcher) { utx.challenges.resize(utx.tx.inputs.size()); for (size_t i = 0; i < utx.tx.inputs.size(); ++i) { bc::input_point& point = utx.tx.inputs[i].previous_output; if (!watcher.db().has_tx(point.hash)) return false; bc::transaction_type tx = watcher.find_tx(point.hash); utx.challenges[i] = tx.outputs[point.index].script; } return true; }
Status watcherBridgeRawTx(Wallet &self, const char *szTxID, DataChunk &result) { Watcher *watcher = nullptr; ABC_CHECK(watcherFind(watcher, self)); bc::hash_digest txid; if (!bc::decode_hash(txid, szTxID)) return ABC_ERROR(ABC_CC_ParseError, "Bad txid"); auto tx = watcher->find_tx(txid); result.resize(satoshi_raw_size(tx)); bc::satoshi_save(tx, result.begin()); return Status(); }
tABC_CC ABC_BridgeTxBlockHeight(Wallet &self, unsigned int *height, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; Watcher *watcher = nullptr; ABC_CHECK_NEW(watcherFind(watcher, self)); *height = watcher->get_last_block_height(); if (*height == 0) { cc = ABC_CC_Synchronizing; } exit: return cc; }
tABC_CC ABC_BridgeTxHeight(Wallet &self, const char *szTxId, unsigned int *height, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; int height_; bc::hash_digest txid; Watcher *watcher = nullptr; ABC_CHECK_NEW(watcherFind(watcher, self)); if (!bc::decode_hash(txid, szTxId)) ABC_RET_ERROR(ABC_CC_ParseError, "Bad txid"); if (!watcher->get_tx_height(txid, height_)) { cc = ABC_CC_Synchronizing; } *height = height_; exit: return cc; }
int main() { cout << "launcher starting...\n"; if (daemon(1, 0) == -1) { perror("daemon"); return EXIT_FAILURE; } _LOG("launcher starting..."); Watcher w; w.Add("flecs.trigger.agent", "export LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib64; cd /dev/shm/work/flecs-rpc/.build/agent; ./flecs-agent-server;"); w.Add("flecs.trigger.master", "export LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib64; cd /dev/shm/work/flecs-rpc/.build/master; ./flecs-master;"); w.Add("flecs.trigger.server", "export LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib64; cd /dev/shm/work/flecs-rpc/.build/server; ./flecs-server;"); w.Add("flecs.trigger.client", "export LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib64; cd /dev/shm/work/flecs-rpc/.build/client; ./flecs-client;"); w.Add("flecs.trigger.regen-fileset", "export LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib64; rm -rf /usr/local/flecs/*; cd /dev/shm/work/flecs-rpc/.build/data/gen-fileset; ./gen-fileset;"); w.Watch(); _LOG("launcher ended."); return 0; }
Status signTx(bc::transaction_type &result, Watcher &watcher, const KeyTable &keys) { for (size_t i = 0; i < result.inputs.size(); ++i) { // Find the utxo this input refers to: bc::input_point& point = result.inputs[i].previous_output; bc::transaction_type tx = watcher.find_tx(point.hash); // Find the address for that utxo: bc::payment_address pa; bc::script_type& script = tx.outputs[point.index].script; bc::extract(pa, script); if (payment_address::invalid_version == pa.version()) return ABC_ERROR(ABC_CC_Error, "Invalid address"); // Find the elliptic curve key for this input: auto key = keys.find(pa.encoded()); if (key == keys.end()) return ABC_ERROR(ABC_CC_Error, "Missing signing key"); bc::ec_secret secret = libwallet::wif_to_secret(key->second); bc::ec_point pubkey = bc::secret_to_public_key(secret, libwallet::is_wif_compressed(key->second)); // Gererate the previous output's signature: // TODO: We already have this; process it and use it script_type sig_script = outputScriptForPubkey(pa.hash()); // Generate the signature for this input: hash_digest sig_hash = script_type::generate_signature_hash(result, i, sig_script, 1); if (sig_hash == null_hash) return ABC_ERROR(ABC_CC_Error, "Unable to sign"); data_chunk signature = sign(secret, sig_hash, create_nonce(secret, sig_hash)); signature.push_back(0x01); // Create out scriptsig: script_type scriptsig; scriptsig.push_operation(create_data_operation(signature)); scriptsig.push_operation(create_data_operation(pubkey)); result.inputs[i].script = scriptsig; } return Status(); }
void operator () () { WatcherProcess *process = this; if (call(manager, REGISTER, reinterpret_cast<char *>(&process), sizeof(process)) != OK) fatal("failed to setup underlying watcher mechanism"); while (true) { switch (receive()) { case EVENT: { Event *event = *reinterpret_cast<Event **>(const_cast<char *>(body(NULL))); watcher->process(event->zk, event->type, event->state, event->path); delete event; break; } case TERMINATE: if (call(manager, UNREGISTER, reinterpret_cast<char *>(&process), sizeof(process)) != OK) fatal("failed to cleanup underlying watcher mechanism"); return; } } }
void * watcherThread(void * id) { wa.start(&mutex, &condition); }