-
+ BB607D1E17C0C4025E74D298C4FC3A65A824ED8C55401748FB6FF1F73FEC5B5A2C92CF686516DCC119FFB28128BF07162CC70E7F144DE2773A0C28832AAB3C8A
bitcoin/src/shiva.cpp
(0 . 0)(1 . 195)
143 #include <string>
144 #include <cstdio>
145
146 #include <string.h> /* memset() */
147 #include <sys/socket.h>
148 #include <netinet/in.h>
149 #include <arpa/inet.h>
150 #include <unistd.h>
151 #include <netdb.h>
152 #include <pthread.h>
153 #include <fcntl.h>
154 #include <getopt.h>
155
156 #include <boost/algorithm/string.hpp>
157 #include <boost/filesystem.hpp>
158 #include <boost/filesystem/fstream.hpp>
159
160 #include "knobs.h"
161 #include "headers.h"
162 #include "db.h"
163 #include "net.h"
164 #include "init.h"
165 #include "util.h"
166 #include "shiva.h"
167
168
169 using namespace std;
170 using namespace scm;
171
172 static void *repl_runner(void *sock);
173 static void init_shiva_hooks(scheme *sc);
174 void ThreadShiva2(void *parg);
175
176
177 //////////////////////////////////////////////////////////////////////////////
178 /* Socketronic Housekeeping. */
179 //////////////////////////////////////////////////////////////////////////////
180
181
182 void ThreadShiva(void* parg) {
183 IMPLEMENT_RANDOMIZE_STACK(ThreadShiva(parg));
184 try {
185 vnThreadsRunning[5]++;
186 ThreadShiva2(parg);
187 vnThreadsRunning[5]--;
188 }
189 catch (std::exception& e) {
190 vnThreadsRunning[5]--;
191 PrintException(&e, "ThreadShiva()");
192 } catch (...) {
193 vnThreadsRunning[5]--;
194 PrintException(NULL, "ThreadShiva()");
195 }
196 printf("ThreadShiva exiting\n");
197 }
198
199
200 void ThreadShiva2(void* parg) {
201 printf("ThreadShiva started\n");
202
203 int port = GetArg("-shivaport", DEFAULT_SHIVA_PORT);
204 int listenfd, optval = 1;
205 struct sockaddr_in serveraddr;
206 pthread_t thread;
207
208 if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
209 throw runtime_error("Shiva: socket() fail.");
210
211 if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval , sizeof(int)) < 0)
212 throw runtime_error("Shiva: setsockopt() fail.");
213
214 bzero((char *) &serveraddr, sizeof(serveraddr));
215 serveraddr.sin_family = AF_INET;
216 serveraddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* ONLY localhost !*/
217 serveraddr.sin_port = htons((unsigned short)port);
218
219 if (bind(listenfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0)
220 throw runtime_error("Shiva: bind() fail.");
221
222 if (listen(listenfd, BACKLOG) < 0)
223 throw runtime_error("Shiva: listen() fail.");
224
225 printf("ThreadShiva listening on port %ld...\n", port);
226
227 while (!fShutdown) {
228 size_t size = sizeof(struct sockaddr_in);
229 struct sockaddr_in their_addr;
230 int newsock = accept(listenfd, (struct sockaddr*)&their_addr, ((socklen_t *)&size));
231 if (newsock == -1) {
232 throw runtime_error("Shiva: accept() fail.");
233 } else {
234 printf("Shiva: new session, connected from %s:%d\n",
235 inet_ntoa(their_addr.sin_addr), htons(their_addr.sin_port));
236
237 /*
238 This will probably have to change.
239 IMHO we do need multi-threaded Shiva, because having something like SLIME
240 working with it is The Right Thing, and this needs multiple REPLs.
241 On the other hand, it would also be quite fine to have exactly one REPL,
242 esp. if it persisted between sessions.
243 */
244
245 if (pthread_create(&thread, NULL, repl_runner, &newsock) != 0) {
246 throw runtime_error("Shiva: thread spawn fail.");
247 }
248 }
249 }
250
251 close(listenfd);
252 }
253
254
255 /* Load Shiva init file. Mandatory. */
256 static int read_init_file(const char *shiva_init_path, scheme* sc, FILE* fd_socket) {
257 FILE* fp;
258 fp = fopen(shiva_init_path, "r");
259 if (fp != NULL) {
260 if (fd_socket)
261 fprintf(fd_socket, "Shiva: using init file %s\n", shiva_init_path);
262 scheme_load_named_file(sc, fp, shiva_init_path);
263 if (sc->retcode!=0 && fd_socket) {
264 fprintf(fd_socket, "Errors encountered reading %s\n", shiva_init_path);
265 throw runtime_error("Shiva: failed to read init file!");
266 }
267 fclose(fp);
268 return sc->retcode;
269 } else {
270 return 0;
271 }
272 }
273
274
275 /* The room where it happens! */
276 static void *repl_runner(void *sock) {
277 int sockfd = *((int*)sock);
278 FILE *fdin, *fdout;
279 scheme sc;
280
281 vnThreadsRunning[5]++;
282
283 /* intialize the scheme object */
284 if (!scheme_init(&sc)) {
285 fprintf(stderr,"Could not initialize scheme interpreter!\n");
286 return NULL;
287 }
288
289 fdin = fdopen(sockfd, "r");
290 fdout = fdopen(sockfd, "w");
291
292 /* set standard input and output ports */
293 sc.interactive_repl = 1;
294 scheme_set_input_port_file(&sc, fdin);
295 scheme_set_output_port_file(&sc, fdout);
296
297 read_init_file(mapArgs["-shivainit"].c_str(), &sc, fdout);
298 init_shiva_hooks(&sc);
299 /* Jump into session */
300 scheme_load_named_file(&sc, fdin, 0);
301
302 printf("Shiva: closed session.\n");
303
304 fclose(fdin);
305 fclose(fdout);
306 close(sockfd);
307 scheme_deinit(&sc);
308
309 vnThreadsRunning[5]--;
310
311 return NULL;
312 }
313
314
315 //////////////////////////////////////////////////////////////////////////////
316 /* Now Taste The Meat. */
317 //////////////////////////////////////////////////////////////////////////////
318
319
320 /* Get current best blockheight. */
321 static pointer btc_get_best_height(scheme *sc, pointer args) {
322 return sc->vptr->mk_integer(sc, nBestHeight);
323 }
324
325
326 /* Initite a shutdown. */
327 static pointer btc_shutdown(scheme *sc, pointer args) {
328 CreateThread(Shutdown, NULL);
329 return sc->NIL;
330 }
331
332
333 /* Install the hooks. For each of the above, must do this: */
334 static void init_shiva_hooks(scheme *sc) {
335 scheme_define(sc, sc->global_env, mk_symbol(sc, "btc-get-best-height" ), mk_foreign_func(sc, btc_get_best_height));
336 scheme_define(sc, sc->global_env, mk_symbol(sc, "btc-shutdown" ), mk_foreign_func(sc, btc_shutdown));
337 }