diff options
Diffstat (limited to 'Demo/pysvr/pysvr.c')
-rw-r--r-- | Demo/pysvr/pysvr.c | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/Demo/pysvr/pysvr.c b/Demo/pysvr/pysvr.c new file mode 100644 index 0000000..f6f9e08 --- /dev/null +++ b/Demo/pysvr/pysvr.c @@ -0,0 +1,312 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> + +#include <pthread.h> + +/* XXX Umpfh. + Python.h defines a typedef destructor, which conflicts with pthread.h. + So Python.h must be included after pthread.h. */ + +#include <Python.h> + +#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, "<socket-in>", "r", NULL); + new_stdout = PyFile_FromFile(output, "<socket-out>", "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; +} |