#include #include #include #include #include #include #include #include #include /* XXX Umpfh. Python.h defines a typedef destructor, which conflicts with pthread.h. So Python.h must be included after pthread.h. */ #include #ifndef PORT #define PORT 4000 #endif extern int optind; extern char *optarg; extern int getopt(); struct workorder { int conn; struct sockaddr_in addr; }; /* Forward */ static void init_python(void); static void usage(void); static void oprogname(void); static void main_thread(int); static void create_thread(int, struct sockaddr_in *); static void *service_thread(struct workorder *); static void run_interpreter(FILE *, FILE *); static int run_command(char *, PyObject *); static char *progname = "pysvr"; main(int argc, char **argv) { int port = PORT; int c; if (argc > 0 && argv[0] != NULL && argv[0][0] != '\0') progname = argv[0]; while ((c = getopt(argc, argv, "")) != EOF) { switch (c) { default: usage(); } } if (optind < argc) { if (optind+1 < argc) { oprogname(); fprintf(stderr, "too many arguments\n"); usage(); } port = atoi(argv[optind]); if (port <= 0) { fprintf(stderr, "bad port (%s)\n", argv[optind]); usage(); } } main_thread(port); fprintf(stderr, "Bye.\n"); exit(0); } static char usage_line[] = "usage: %s [port]\n"; static void usage() { fprintf(stderr, usage_line, progname); exit(2); } static void main_thread(int port) { int sock; struct sockaddr_in addr; sock = socket(PF_INET, SOCK_STREAM, 0); if (sock < 0) { oprogname(); perror("can't create socket"); exit(1); } memset(&addr, '\0', sizeof addr); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = 0L; if (bind(sock, (struct sockaddr *)&addr, sizeof addr) < 0) { oprogname(); perror("can't bind socket to address"); exit(1); } if (listen(sock, 5) < 0) { oprogname(); perror("can't listen on socket"); exit(1); } fprintf(stderr, "Listening on port %d...\n", port); for (;;) { struct sockaddr_in clientaddr; int conn, size; conn = accept(sock, (struct sockaddr *) &clientaddr, &size); if (conn < 0) { oprogname(); perror("can't accept connection from socket"); exit(1); } create_thread(conn, &clientaddr); } } static void create_thread(int conn, struct sockaddr_in *addr) { struct workorder *work; pthread_t tdata; work = malloc(sizeof(struct workorder)); if (work == NULL) { oprogname(); fprintf(stderr, "out of memory for thread.\n"); close(conn); return; } work->conn = conn; work->addr = *addr; init_python(); if (pthread_create(&tdata, NULL, (void *)service_thread, work) < 0) { oprogname(); perror("can't create new thread"); close(conn); return; } if (pthread_detach(tdata) < 0) { oprogname(); perror("can't detach from thread"); } } static PyThreadState *the_tstate; static PyInterpreterState *the_interp; static PyObject *the_builtins; static void init_python() { if (the_interp) return; Py_Initialize(); /* Initialize the interpreter */ the_builtins = PyEval_GetBuiltins(); /* Get __builtins__ */ PyEval_InitThreads(); /* Create and acquire the interpreter lock */ the_tstate = PyEval_SaveThread(); /* Release lock & get thread state */ the_interp = the_tstate->interpreter_state; /* Get interp state */ } static void * service_thread(struct workorder *work) { FILE *input, *output; fprintf(stderr, "Start thread for connection %d.\n", work->conn); input = fdopen(work->conn, "r"); if (input == NULL) { oprogname(); perror("can't create input stream"); goto done; } output = fdopen(work->conn, "w"); if (output == NULL) { oprogname(); perror("can't create output stream"); fclose(input); goto done; } setvbuf(input, NULL, _IONBF, 0); setvbuf(output, NULL, _IONBF, 0); run_interpreter(input, output); fclose(input); fclose(output); done: fprintf(stderr, "End thread for connection %d.\n", work->conn); close(work->conn); free(work); } static void oprogname() { int save = errno; fprintf(stderr, "%s: ", progname); errno = save; } static void run_interpreter(FILE *input, FILE *output) { PyThreadState *tstate; PyObject *new_stdin, *new_stdout; PyObject *old_stdin, *old_stdout, *old_stderr; PyObject *globals; char buffer[1000]; char *p, *q; int n, end; tstate = PyThreadState_New(the_interp); PyEval_AcquireThread(tstate); globals = PyDict_New(); PyDict_SetItemString(globals, "__builtins__", the_builtins); new_stdin = PyFile_FromFile(input, "", "r", NULL); new_stdout = PyFile_FromFile(output, "", "w", NULL); old_stdin = PySys_GetObject("stdin"); old_stdout = PySys_GetObject("stdout"); old_stderr = PySys_GetObject("stderr"); for (n = 1; !PyErr_Occurred(); n++) { Py_BEGIN_ALLOW_THREADS fprintf(output, "%d> ", n); p = fgets(buffer, sizeof buffer, input); Py_END_ALLOW_THREADS if (p == NULL) break; if (p[0] == '\377' && p[1] == '\354') break; q = strrchr(p, '\r'); if (q && q[1] == '\n' && q[2] == '\0') { *q++ = '\n'; *q++ = '\0'; } while (*p && isspace(*p)) p++; if (p[0] == '#' || p[0] == '\0') continue; PySys_SetObject("stdin", new_stdin); PySys_SetObject("stdout", new_stdout); PySys_SetObject("stderr", new_stdout); end = run_command(buffer, globals); if (end < 0) PyErr_Print(); PySys_SetObject("stdin", old_stdin); PySys_SetObject("stdout", old_stdout); PySys_SetObject("stderr", old_stderr); if (end) break; } Py_XDECREF(globals); Py_XDECREF(new_stdin); Py_XDECREF(new_stdout); PyEval_ReleaseThread(tstate); PyThreadState_Delete(tstate); fprintf(output, "Goodbye!\n"); } static int run_command(char *buffer, PyObject *globals) { PyObject *m, *d, *v; v = PyRun_String(buffer, Py_single_input, globals, globals); if (v == NULL) { if (PyErr_Occurred() == PyExc_SystemExit) { PyErr_Clear(); return 1; } PyErr_Print(); return 0; } Py_DECREF(v); return 0; }