raw
asciilifeform_shi...    1 #include <string>
asciilifeform_shi... 2 #include <cstdio>
asciilifeform_shi... 3
asciilifeform_shi... 4 #include <string.h> /* memset() */
asciilifeform_shi... 5 #include <sys/socket.h>
asciilifeform_shi... 6 #include <netinet/in.h>
asciilifeform_shi... 7 #include <arpa/inet.h>
asciilifeform_shi... 8 #include <unistd.h>
asciilifeform_shi... 9 #include <netdb.h>
asciilifeform_shi... 10 #include <pthread.h>
asciilifeform_shi... 11 #include <fcntl.h>
asciilifeform_shi... 12 #include <getopt.h>
asciilifeform_shi... 13
asciilifeform_shi... 14 #include <boost/algorithm/string.hpp>
asciilifeform_shi... 15 #include <boost/filesystem.hpp>
asciilifeform_shi... 16 #include <boost/filesystem/fstream.hpp>
asciilifeform_shi... 17
asciilifeform_shi... 18 #include "knobs.h"
asciilifeform_shi... 19 #include "headers.h"
asciilifeform_shi... 20 #include "db.h"
asciilifeform_shi... 21 #include "net.h"
asciilifeform_shi... 22 #include "init.h"
asciilifeform_shi... 23 #include "util.h"
asciilifeform_shi... 24 #include "shiva.h"
asciilifeform_shi... 25
asciilifeform_shi... 26
asciilifeform_shi... 27 using namespace std;
asciilifeform_shi... 28 using namespace scm;
asciilifeform_shi... 29
asciilifeform_shi... 30 static void *repl_runner(void *sock);
asciilifeform_shi... 31 static void init_shiva_hooks(scheme *sc);
asciilifeform_shi... 32 void ThreadShiva2(void *parg);
asciilifeform_shi... 33
asciilifeform_shi... 34
asciilifeform_shi... 35 //////////////////////////////////////////////////////////////////////////////
asciilifeform_shi... 36 /* Socketronic Housekeeping. */
asciilifeform_shi... 37 //////////////////////////////////////////////////////////////////////////////
asciilifeform_shi... 38
asciilifeform_shi... 39
asciilifeform_shi... 40 void ThreadShiva(void* parg) {
asciilifeform_shi... 41 IMPLEMENT_RANDOMIZE_STACK(ThreadShiva(parg));
asciilifeform_shi... 42 try {
asciilifeform_shi... 43 vnThreadsRunning[5]++;
asciilifeform_shi... 44 ThreadShiva2(parg);
asciilifeform_shi... 45 vnThreadsRunning[5]--;
asciilifeform_shi... 46 }
asciilifeform_shi... 47 catch (std::exception& e) {
asciilifeform_shi... 48 vnThreadsRunning[5]--;
asciilifeform_shi... 49 PrintException(&e, "ThreadShiva()");
asciilifeform_shi... 50 } catch (...) {
asciilifeform_shi... 51 vnThreadsRunning[5]--;
asciilifeform_shi... 52 PrintException(NULL, "ThreadShiva()");
asciilifeform_shi... 53 }
asciilifeform_shi... 54 printf("ThreadShiva exiting\n");
asciilifeform_shi... 55 }
asciilifeform_shi... 56
asciilifeform_shi... 57
asciilifeform_shi... 58 void ThreadShiva2(void* parg) {
asciilifeform_shi... 59 printf("ThreadShiva started\n");
asciilifeform_shi... 60
asciilifeform_shi... 61 int port = GetArg("-shivaport", DEFAULT_SHIVA_PORT);
asciilifeform_shi... 62 int listenfd, optval = 1;
asciilifeform_shi... 63 struct sockaddr_in serveraddr;
asciilifeform_shi... 64 pthread_t thread;
asciilifeform_shi... 65
asciilifeform_shi... 66 if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
asciilifeform_shi... 67 throw runtime_error("Shiva: socket() fail.");
asciilifeform_shi... 68
asciilifeform_shi... 69 if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval , sizeof(int)) < 0)
asciilifeform_shi... 70 throw runtime_error("Shiva: setsockopt() fail.");
asciilifeform_shi... 71
asciilifeform_shi... 72 bzero((char *) &serveraddr, sizeof(serveraddr));
asciilifeform_shi... 73 serveraddr.sin_family = AF_INET;
asciilifeform_shi... 74 serveraddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* ONLY localhost !*/
asciilifeform_shi... 75 serveraddr.sin_port = htons((unsigned short)port);
asciilifeform_shi... 76
asciilifeform_shi... 77 if (bind(listenfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0)
asciilifeform_shi... 78 throw runtime_error("Shiva: bind() fail.");
asciilifeform_shi... 79
asciilifeform_shi... 80 if (listen(listenfd, BACKLOG) < 0)
asciilifeform_shi... 81 throw runtime_error("Shiva: listen() fail.");
asciilifeform_shi... 82
asciilifeform_shi... 83 printf("ThreadShiva listening on port %ld...\n", port);
asciilifeform_shi... 84
asciilifeform_shi... 85 while (!fShutdown) {
asciilifeform_shi... 86 size_t size = sizeof(struct sockaddr_in);
asciilifeform_shi... 87 struct sockaddr_in their_addr;
asciilifeform_shi... 88 int newsock = accept(listenfd, (struct sockaddr*)&their_addr, ((socklen_t *)&size));
asciilifeform_shi... 89 if (newsock == -1) {
asciilifeform_shi... 90 throw runtime_error("Shiva: accept() fail.");
asciilifeform_shi... 91 } else {
asciilifeform_shi... 92 printf("Shiva: new session, connected from %s:%d\n",
asciilifeform_shi... 93 inet_ntoa(their_addr.sin_addr), htons(their_addr.sin_port));
asciilifeform_shi... 94
asciilifeform_shi... 95 /*
asciilifeform_shi... 96 This will probably have to change.
asciilifeform_shi... 97 IMHO we do need multi-threaded Shiva, because having something like SLIME
asciilifeform_shi... 98 working with it is The Right Thing, and this needs multiple REPLs.
asciilifeform_shi... 99 On the other hand, it would also be quite fine to have exactly one REPL,
asciilifeform_shi... 100 esp. if it persisted between sessions.
asciilifeform_shi... 101 */
asciilifeform_shi... 102
asciilifeform_shi... 103 if (pthread_create(&thread, NULL, repl_runner, &newsock) != 0) {
asciilifeform_shi... 104 throw runtime_error("Shiva: thread spawn fail.");
asciilifeform_shi... 105 }
asciilifeform_shi... 106 }
asciilifeform_shi... 107 }
asciilifeform_shi... 108
asciilifeform_shi... 109 close(listenfd);
asciilifeform_shi... 110 }
asciilifeform_shi... 111
asciilifeform_shi... 112
asciilifeform_shi... 113 /* Load Shiva init file. Mandatory. */
asciilifeform_shi... 114 static int read_init_file(const char *shiva_init_path, scheme* sc, FILE* fd_socket) {
asciilifeform_shi... 115 FILE* fp;
asciilifeform_shi... 116 fp = fopen(shiva_init_path, "r");
asciilifeform_shi... 117 if (fp != NULL) {
asciilifeform_shi... 118 if (fd_socket)
asciilifeform_shi... 119 fprintf(fd_socket, "Shiva: using init file %s\n", shiva_init_path);
asciilifeform_shi... 120 scheme_load_named_file(sc, fp, shiva_init_path);
asciilifeform_shi... 121 if (sc->retcode!=0 && fd_socket) {
asciilifeform_shi... 122 fprintf(fd_socket, "Errors encountered reading %s\n", shiva_init_path);
asciilifeform_shi... 123 throw runtime_error("Shiva: failed to read init file!");
asciilifeform_shi... 124 }
asciilifeform_shi... 125 fclose(fp);
asciilifeform_shi... 126 return sc->retcode;
asciilifeform_shi... 127 } else {
asciilifeform_shi... 128 return 0;
asciilifeform_shi... 129 }
asciilifeform_shi... 130 }
asciilifeform_shi... 131
asciilifeform_shi... 132
asciilifeform_shi... 133 /* The room where it happens! */
asciilifeform_shi... 134 static void *repl_runner(void *sock) {
asciilifeform_shi... 135 int sockfd = *((int*)sock);
asciilifeform_shi... 136 FILE *fdin, *fdout;
asciilifeform_shi... 137 scheme sc;
asciilifeform_shi... 138
asciilifeform_shi... 139 vnThreadsRunning[5]++;
asciilifeform_shi... 140
asciilifeform_shi... 141 /* intialize the scheme object */
asciilifeform_shi... 142 if (!scheme_init(&sc)) {
asciilifeform_shi... 143 fprintf(stderr,"Could not initialize scheme interpreter!\n");
asciilifeform_shi... 144 return NULL;
asciilifeform_shi... 145 }
asciilifeform_shi... 146
asciilifeform_shi... 147 fdin = fdopen(sockfd, "r");
asciilifeform_shi... 148 fdout = fdopen(sockfd, "w");
asciilifeform_shi... 149
asciilifeform_shi... 150 /* set standard input and output ports */
asciilifeform_shi... 151 sc.interactive_repl = 1;
asciilifeform_shi... 152 scheme_set_input_port_file(&sc, fdin);
asciilifeform_shi... 153 scheme_set_output_port_file(&sc, fdout);
asciilifeform_shi... 154
asciilifeform_shi... 155 read_init_file(mapArgs["-shivainit"].c_str(), &sc, fdout);
asciilifeform_shi... 156 init_shiva_hooks(&sc);
asciilifeform_shi... 157 /* Jump into session */
asciilifeform_shi... 158 scheme_load_named_file(&sc, fdin, 0);
asciilifeform_shi... 159
asciilifeform_shi... 160 printf("Shiva: closed session.\n");
asciilifeform_shi... 161
asciilifeform_shi... 162 fclose(fdin);
asciilifeform_shi... 163 fclose(fdout);
asciilifeform_shi... 164 close(sockfd);
asciilifeform_shi... 165 scheme_deinit(&sc);
asciilifeform_shi... 166
asciilifeform_shi... 167 vnThreadsRunning[5]--;
asciilifeform_shi... 168
asciilifeform_shi... 169 return NULL;
asciilifeform_shi... 170 }
asciilifeform_shi... 171
asciilifeform_shi... 172
asciilifeform_shi... 173 //////////////////////////////////////////////////////////////////////////////
asciilifeform_shi... 174 /* Now Taste The Meat. */
asciilifeform_shi... 175 //////////////////////////////////////////////////////////////////////////////
asciilifeform_shi... 176
asciilifeform_shi... 177
asciilifeform_shi... 178 /* Get current best blockheight. */
asciilifeform_shi... 179 static pointer btc_get_best_height(scheme *sc, pointer args) {
asciilifeform_shi... 180 return sc->vptr->mk_integer(sc, nBestHeight);
asciilifeform_shi... 181 }
asciilifeform_shi... 182
asciilifeform_shi... 183
asciilifeform_shi... 184 /* Initite a shutdown. */
asciilifeform_shi... 185 static pointer btc_shutdown(scheme *sc, pointer args) {
asciilifeform_shi... 186 CreateThread(Shutdown, NULL);
asciilifeform_shi... 187 return sc->NIL;
asciilifeform_shi... 188 }
asciilifeform_shi... 189
asciilifeform_shi... 190
asciilifeform_shi... 191 /* Install the hooks. For each of the above, must do this: */
asciilifeform_shi... 192 static void init_shiva_hooks(scheme *sc) {
asciilifeform_shi... 193 scheme_define(sc, sc->global_env, mk_symbol(sc, "btc-get-best-height" ), mk_foreign_func(sc, btc_get_best_height));
asciilifeform_shi... 194 scheme_define(sc, sc->global_env, mk_symbol(sc, "btc-shutdown" ), mk_foreign_func(sc, btc_shutdown));
asciilifeform_shi... 195 }