diff -uNr a/bitcoin/src/init.cpp b/bitcoin/src/init.cpp --- a/bitcoin/src/init.cpp 971b82be435c99a1af9d5cacc9c05af7616f4af7ee1466efacd46d41eddc1c4d7da2fdb4a302aab7c99933d33ad2d613f3bfbe76fec67a71c6d4d1fe14ac142d +++ b/bitcoin/src/init.cpp 2f6ab82ebab26369954cf9ca518e536a03c2a989d978823d6d78e1a924e601c855a8598863a5845727a93a457d49537ca91e027d69603abc1cb6f075e69af8d0 @@ -5,6 +5,7 @@ #include "headers.h" #include "db.h" #include "bitcoinrpc.h" +#include "shiva.h" #include "net.h" #include "init.h" #include "strlcpy.h" @@ -177,6 +178,9 @@ " -verifyall \t\t " + _("Forbid the skipping of ECDSA signature verification between checkpoints.\n") + " -setverstring \t\t " + _("Set a custom version string.\n") + " -setvernum \t\t " + _("Set a custom version number.\n") + + " -shiva \t\t " + _("Enable the Shiva lisp listener (DANGEROUS!).\n") + + " -shivainit=\t\t " + _("Init file for Shiva (default: shiva.scm)\n") + + " -shivaport=\t\t " + _("Listen for Shiva connections on (default: 1336)\n") + " -highs \t\t " + _("Set all transactions to have DER 'S' Value set to 'high'.\n") + " -lows \t\t " + _("Set all transactions to have DER 'S' Value set to 'low'.\n") + " -logtimestamps \t " + _("Prepend debug output with timestamp\n") + @@ -202,6 +206,13 @@ fDaemon = GetBoolArg("-daemon"); fCanEat = GetBoolArg("-caneat"); fVerifyAll = GetBoolArg("-verifyall"); + fShiva = GetBoolArg("-shiva"); + + if (!(mapArgs.count("-shivainit") && FileExists(mapArgs["-shivainit"].c_str()))) { + fprintf(stderr, "Error: If Shiva is enabled, MUST specify init file!\n"); + return false; + } + fHighS = GetBoolArg("-highs"); fLowS = GetBoolArg("-lows"); @@ -487,6 +498,10 @@ if (fServer) CreateThread(ThreadRPCServer, NULL); + if (fShiva) { + CreateThread(ThreadShiva, NULL); + } + while (1) Sleep(5000); diff -uNr a/bitcoin/src/knobs.h b/bitcoin/src/knobs.h --- a/bitcoin/src/knobs.h 9b88b8f60d9a0ae98f9dd148dba06e132b6b1fc199719eacb3270fe6ce2af889422eee62c2cb08c3b93f22069aea880c657e771c4e4b4157a69c321550c8fc73 +++ b/bitcoin/src/knobs.h c6c24fca798bb308eb94d61854bd19a31384c9a6ee20ee9ff90e7e1cad6ee9fa93c44dfeb80265f61d4ca6cdf100bb530bb22ec4ab69a7cf0699acd19dc4a267 @@ -4,4 +4,6 @@ #define DEFAULT_CLIENT_NAME "therealbitcoin.org" #define DEFAULT_CLIENT_VERSION 99999 /* 50400 */ +#define DEFAULT_SHIVA_PORT 1336 + #endif diff -uNr a/bitcoin/src/makefile.unix b/bitcoin/src/makefile.unix --- a/bitcoin/src/makefile.unix 09ac104678a444430d3ef0bdf6dbd07d875666493b2d938ac6aa7fb67abe840f2254f517055f4b5f90d0e86c83ee3dade77a58f1c37b7ab7b4c13598a5559adc +++ b/bitcoin/src/makefile.unix bb1a279de6e10446b679b247dccd421efd70cee90177d797e08e078c49b9a03276d5b2e194f0459375b94b95877cbad34e8bb2a2d94246a13d5c5e71d8ee41c3 @@ -71,6 +71,7 @@ DEBUGFLAGS=-g CXXFLAGS=-O2 xCXXFLAGS=-pthread -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(HARDENING) $(CXXFLAGS) +CFLAGS=-lm -DUSE_ASCII_NAMES=0 -O2 HEADERS = \ base58.h \ bignum.h \ @@ -87,6 +88,7 @@ noui.h \ protocol.h \ bitcoinrpc.h \ + shiva.h \ script.h \ serialize.h \ strlcpy.h \ @@ -104,15 +106,18 @@ obj/net.o \ obj/protocol.o \ obj/bitcoinrpc.o \ + obj/shiva.o \ obj/script.o \ obj/util.o \ - obj/wallet.o + obj/wallet.o \ + obj-shiva/scheme.o all: bitcoind # auto-generated dependencies: -include obj/nogui/*.P +-include obj-shiva/*.P -include obj-test/*.P obj/nogui/%.o: %.cpp @@ -122,6 +127,13 @@ -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ rm -f $(@:%.o=%.d) +obj-shiva/%.o: shiva/%.c + $(CC) -c $(TESTDEFS) $(CFLAGS) -MMD -o $@ $< + @cp $(@:%.o=%.d) $(@:%.o=%.P); \ + sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ + rm -f $(@:%.o=%.d) + bitcoind: $(OBJS:obj/%=obj/nogui/%) $(CXX) $(xCXXFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS) @@ -139,6 +151,8 @@ -rm -f bitcoind test_bitcoin -rm -f obj/*.o -rm -f obj/nogui/*.o + -rm -f obj-shiva/*.o + -rm -f obj-shiva/*.P -rm -f obj-test/*.o -rm -f obj/*.P -rm -f obj/nogui/*.P diff -uNr a/bitcoin/src/net.cpp b/bitcoin/src/net.cpp --- a/bitcoin/src/net.cpp 31eb2cbdf4f83f10ae8a7cdd3a69312ba6eafbecfafbeddf7546ce99847bd4f2a674037e2b89a0a7b91c37127d9770501c265a7977edb0ae0b3a5964272692f9 +++ b/bitcoin/src/net.cpp 1aae02f75e5ca6c54bf3eb97d2bca1ca675d64aa220653964dc44806898d3c3cbbb89ae6760637b2367054114af76dce5549e95d5a9a661b83f2f599bb68496f @@ -1312,7 +1312,7 @@ fShutdown = true; nTransactionsUpdated++; int64 nStart = GetTime(); - while (vnThreadsRunning[0] > 0 || vnThreadsRunning[1] > 0 || vnThreadsRunning[2] > 0 || vnThreadsRunning[3] > 0 || vnThreadsRunning[4] > 0 + while (vnThreadsRunning[0] > 0 || vnThreadsRunning[1] > 0 || vnThreadsRunning[2] > 0 || vnThreadsRunning[3] > 0 || vnThreadsRunning[4] > 0 || vnThreadsRunning[5] > 0 ) { if (GetTime() - nStart > 20) @@ -1324,6 +1324,7 @@ if (vnThreadsRunning[2] > 0) printf("ThreadMessageHandler still running\n"); if (vnThreadsRunning[3] > 0) printf("ThreadBitcoinMiner still running\n"); if (vnThreadsRunning[4] > 0) printf("ThreadRPCServer still running\n"); + if (vnThreadsRunning[5] > 0) printf("ThreadShiva still running\n"); while (vnThreadsRunning[2] > 0 || vnThreadsRunning[4] > 0) Sleep(20); Sleep(50); diff -uNr a/bitcoin/src/shiva.cpp b/bitcoin/src/shiva.cpp --- a/bitcoin/src/shiva.cpp false +++ b/bitcoin/src/shiva.cpp bb607d1e17c0c4025e74d298c4fc3a65a824ed8c55401748fb6ff1f73fec5b5a2c92cf686516dcc119ffb28128bf07162cc70e7f144de2773a0c28832aab3c8a @@ -0,0 +1,195 @@ +#include +#include + +#include /* memset() */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "knobs.h" +#include "headers.h" +#include "db.h" +#include "net.h" +#include "init.h" +#include "util.h" +#include "shiva.h" + + +using namespace std; +using namespace scm; + +static void *repl_runner(void *sock); +static void init_shiva_hooks(scheme *sc); +void ThreadShiva2(void *parg); + + +////////////////////////////////////////////////////////////////////////////// +/* Socketronic Housekeeping. */ +////////////////////////////////////////////////////////////////////////////// + + +void ThreadShiva(void* parg) { + IMPLEMENT_RANDOMIZE_STACK(ThreadShiva(parg)); + try { + vnThreadsRunning[5]++; + ThreadShiva2(parg); + vnThreadsRunning[5]--; + } + catch (std::exception& e) { + vnThreadsRunning[5]--; + PrintException(&e, "ThreadShiva()"); + } catch (...) { + vnThreadsRunning[5]--; + PrintException(NULL, "ThreadShiva()"); + } + printf("ThreadShiva exiting\n"); +} + + +void ThreadShiva2(void* parg) { + printf("ThreadShiva started\n"); + + int port = GetArg("-shivaport", DEFAULT_SHIVA_PORT); + int listenfd, optval = 1; + struct sockaddr_in serveraddr; + pthread_t thread; + + if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + throw runtime_error("Shiva: socket() fail."); + + if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval , sizeof(int)) < 0) + throw runtime_error("Shiva: setsockopt() fail."); + + bzero((char *) &serveraddr, sizeof(serveraddr)); + serveraddr.sin_family = AF_INET; + serveraddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* ONLY localhost !*/ + serveraddr.sin_port = htons((unsigned short)port); + + if (bind(listenfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0) + throw runtime_error("Shiva: bind() fail."); + + if (listen(listenfd, BACKLOG) < 0) + throw runtime_error("Shiva: listen() fail."); + + printf("ThreadShiva listening on port %ld...\n", port); + + while (!fShutdown) { + size_t size = sizeof(struct sockaddr_in); + struct sockaddr_in their_addr; + int newsock = accept(listenfd, (struct sockaddr*)&their_addr, ((socklen_t *)&size)); + if (newsock == -1) { + throw runtime_error("Shiva: accept() fail."); + } else { + printf("Shiva: new session, connected from %s:%d\n", + inet_ntoa(their_addr.sin_addr), htons(their_addr.sin_port)); + + /* + This will probably have to change. + IMHO we do need multi-threaded Shiva, because having something like SLIME + working with it is The Right Thing, and this needs multiple REPLs. + On the other hand, it would also be quite fine to have exactly one REPL, + esp. if it persisted between sessions. + */ + + if (pthread_create(&thread, NULL, repl_runner, &newsock) != 0) { + throw runtime_error("Shiva: thread spawn fail."); + } + } + } + + close(listenfd); +} + + +/* Load Shiva init file. Mandatory. */ +static int read_init_file(const char *shiva_init_path, scheme* sc, FILE* fd_socket) { + FILE* fp; + fp = fopen(shiva_init_path, "r"); + if (fp != NULL) { + if (fd_socket) + fprintf(fd_socket, "Shiva: using init file %s\n", shiva_init_path); + scheme_load_named_file(sc, fp, shiva_init_path); + if (sc->retcode!=0 && fd_socket) { + fprintf(fd_socket, "Errors encountered reading %s\n", shiva_init_path); + throw runtime_error("Shiva: failed to read init file!"); + } + fclose(fp); + return sc->retcode; + } else { + return 0; + } +} + + +/* The room where it happens! */ +static void *repl_runner(void *sock) { + int sockfd = *((int*)sock); + FILE *fdin, *fdout; + scheme sc; + + vnThreadsRunning[5]++; + + /* intialize the scheme object */ + if (!scheme_init(&sc)) { + fprintf(stderr,"Could not initialize scheme interpreter!\n"); + return NULL; + } + + fdin = fdopen(sockfd, "r"); + fdout = fdopen(sockfd, "w"); + + /* set standard input and output ports */ + sc.interactive_repl = 1; + scheme_set_input_port_file(&sc, fdin); + scheme_set_output_port_file(&sc, fdout); + + read_init_file(mapArgs["-shivainit"].c_str(), &sc, fdout); + init_shiva_hooks(&sc); + /* Jump into session */ + scheme_load_named_file(&sc, fdin, 0); + + printf("Shiva: closed session.\n"); + + fclose(fdin); + fclose(fdout); + close(sockfd); + scheme_deinit(&sc); + + vnThreadsRunning[5]--; + + return NULL; +} + + +////////////////////////////////////////////////////////////////////////////// +/* Now Taste The Meat. */ +////////////////////////////////////////////////////////////////////////////// + + +/* Get current best blockheight. */ +static pointer btc_get_best_height(scheme *sc, pointer args) { + return sc->vptr->mk_integer(sc, nBestHeight); +} + + +/* Initite a shutdown. */ +static pointer btc_shutdown(scheme *sc, pointer args) { + CreateThread(Shutdown, NULL); + return sc->NIL; +} + + +/* Install the hooks. For each of the above, must do this: */ +static void init_shiva_hooks(scheme *sc) { + scheme_define(sc, sc->global_env, mk_symbol(sc, "btc-get-best-height" ), mk_foreign_func(sc, btc_get_best_height)); + scheme_define(sc, sc->global_env, mk_symbol(sc, "btc-shutdown" ), mk_foreign_func(sc, btc_shutdown)); +} diff -uNr a/bitcoin/src/shiva.h b/bitcoin/src/shiva.h --- a/bitcoin/src/shiva.h false +++ b/bitcoin/src/shiva.h 1276267c579b82ef2d3970f1a55eb55546250669f23b9c85da4b690ba779cc0820df34f5ec179804c59c936687ff209ec8ec360ca30d9d0344b6ac477574b0fc @@ -0,0 +1,15 @@ +#ifndef SHIVA_H +#define SHIVA_H + +#define BACKLOG 10 /* listen() */ + +namespace scm { + /* We do this because the OP_* symbols in tinyscheme + clash with trb's script ops */ + #include "shiva/scheme-private.h" +} + +void ThreadShiva(void* parg); + +#endif + diff -uNr a/bitcoin/src/util.cpp b/bitcoin/src/util.cpp --- a/bitcoin/src/util.cpp 66a8ac388136aceac7d24bd73c18b06445c2580849dd6c548d6684b5f1e9c19eafd3f71427476fd982383dcfd0425f34ce524eac1d8320fd990a28a1e4933288 +++ b/bitcoin/src/util.cpp 568ca27a4f90dc47f125880f64ee42dfeb0493a5e0ef79e314c3df1702920c21d7aea35cf197916a9881b569500c815d09e932f4668deef84507a26d7557b1cf @@ -23,6 +23,7 @@ bool fPrintToDebugger = false; bool fCanEat = false; bool fVerifyAll = false; +bool fShiva = false; char pszSetDataDir[MAX_PATH] = ""; bool fRequestShutdown = false; bool fShutdown = false; @@ -787,7 +788,14 @@ } - +bool FileExists(const char *path) { + FILE *file = fopen(path, "r"); + if (file) { + fclose(file); + return true; + } + return false; +} diff -uNr a/bitcoin/src/util.h b/bitcoin/src/util.h --- a/bitcoin/src/util.h f0c21c349b56516feac63c9cf8018c82b26583ad290a4b3610965e5a5a703d116671b1ef270395b8289c170b603630b5b7e493725e420e187ba1fbd326061ff5 +++ b/bitcoin/src/util.h b171f0824811472edb2e309537b772583a32b678550080f257d4b535bb62f46c04aaf0047d29500df6ca77a7e2c01d729b4536b7b7869061863012e39b6c026f @@ -112,6 +112,7 @@ extern bool fPrintToDebugger; extern bool fCanEat; extern bool fVerifyAll; +extern bool fShiva; extern char pszSetDataDir[MAX_PATH]; extern bool fRequestShutdown; extern bool fShutdown; @@ -157,6 +158,7 @@ std::string GetDefaultDataDir(); std::string GetDataDir(); void ShrinkDebugFile(); +bool FileExists(const char *path); int GetRandInt(int nMax); uint64 GetRand(uint64 nMax); int64 GetTime();