The 0.5 release happened on 2/15, not on 2/14. :-)
[python/dscho.git] / Demo / pysvr / pysvr.c
blob995a7ca0d14c0cf29ff920fa3c021d1d2c3d5c13
1 /* A multi-threaded telnet-like server that gives a Python prompt.
3 Usage: pysvr [port]
5 For security reasons, it only accepts requests from the current host.
6 This can still be insecure, but restricts violations from people who
7 can log in on your machine. Use with caution!
9 */
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <ctype.h>
15 #include <errno.h>
17 #include <sys/types.h>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
21 #include <pthread.h>
23 /* XXX Umpfh.
24 Python.h defines a typedef destructor, which conflicts with pthread.h.
25 So Python.h must be included after pthread.h. */
27 #include <Python.h>
29 extern int Py_VerboseFlag;
31 #ifndef PORT
32 #define PORT 4000
33 #endif
35 extern int optind;
36 extern char *optarg;
37 extern int getopt();
39 struct workorder {
40 int conn;
41 struct sockaddr_in addr;
44 /* Forward */
45 static void init_python(void);
46 static void usage(void);
47 static void oprogname(void);
48 static void main_thread(int);
49 static void create_thread(int, struct sockaddr_in *);
50 static void *service_thread(struct workorder *);
51 static void run_interpreter(FILE *, FILE *);
52 static int run_command(char *, PyObject *);
53 static void ps(void);
55 static char *progname = "pysvr";
57 static PyThreadState *gtstate;
59 main(int argc, char **argv)
61 int port = PORT;
62 int c;
64 if (argc > 0 && argv[0] != NULL && argv[0][0] != '\0')
65 progname = argv[0];
67 while ((c = getopt(argc, argv, "v")) != EOF) {
68 switch (c) {
69 case 'v':
70 Py_VerboseFlag++;
71 break;
72 default:
73 usage();
77 if (optind < argc) {
78 if (optind+1 < argc) {
79 oprogname();
80 fprintf(stderr, "too many arguments\n");
81 usage();
83 port = atoi(argv[optind]);
84 if (port <= 0) {
85 fprintf(stderr, "bad port (%s)\n", argv[optind]);
86 usage();
90 main_thread(port);
92 fprintf(stderr, "Bye.\n");
94 exit(0);
97 static char usage_line[] = "usage: %s [port]\n";
99 static void
100 usage()
102 fprintf(stderr, usage_line, progname);
103 exit(2);
106 static void
107 main_thread(int port)
109 int sock, conn, size, i;
110 struct sockaddr_in addr, clientaddr;
112 sock = socket(PF_INET, SOCK_STREAM, 0);
113 if (sock < 0) {
114 oprogname();
115 perror("can't create socket");
116 exit(1);
119 #ifdef SO_REUSEADDR
120 i = 1;
121 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &i, sizeof i);
122 #endif
124 memset((char *)&addr, '\0', sizeof addr);
125 addr.sin_family = AF_INET;
126 addr.sin_port = htons(port);
127 addr.sin_addr.s_addr = 0L;
128 if (bind(sock, (struct sockaddr *)&addr, sizeof addr) < 0) {
129 oprogname();
130 perror("can't bind socket to address");
131 exit(1);
134 if (listen(sock, 5) < 0) {
135 oprogname();
136 perror("can't listen on socket");
137 exit(1);
140 fprintf(stderr, "Listening on port %d...\n", port);
142 for (i = 0; ; i++) {
143 size = sizeof clientaddr;
144 memset((char *) &clientaddr, '\0', size);
145 conn = accept(sock, (struct sockaddr *) &clientaddr, &size);
146 if (conn < 0) {
147 oprogname();
148 perror("can't accept connection from socket");
149 exit(1);
152 size = sizeof addr;
153 memset((char *) &addr, '\0', size);
154 if (getsockname(conn, (struct sockaddr *)&addr, &size) < 0) {
155 oprogname();
156 perror("can't get socket name of connection");
157 exit(1);
159 if (clientaddr.sin_addr.s_addr != addr.sin_addr.s_addr) {
160 oprogname();
161 perror("connection from non-local host refused");
162 fprintf(stderr, "(addr=%lx, clientaddr=%lx)\n",
163 ntohl(addr.sin_addr.s_addr),
164 ntohl(clientaddr.sin_addr.s_addr));
165 close(conn);
166 continue;
168 if (i == 4) {
169 close(conn);
170 break;
172 create_thread(conn, &clientaddr);
175 close(sock);
177 if (gtstate) {
178 PyEval_AcquireThread(gtstate);
179 gtstate = NULL;
180 Py_Finalize();
181 /* And a second time, just because we can. */
182 Py_Finalize(); /* This should be harmless. */
184 exit(0);
187 static void
188 create_thread(int conn, struct sockaddr_in *addr)
190 struct workorder *work;
191 pthread_t tdata;
193 work = malloc(sizeof(struct workorder));
194 if (work == NULL) {
195 oprogname();
196 fprintf(stderr, "out of memory for thread.\n");
197 close(conn);
198 return;
200 work->conn = conn;
201 work->addr = *addr;
203 init_python();
205 if (pthread_create(&tdata, NULL, (void *)service_thread, work) < 0) {
206 oprogname();
207 perror("can't create new thread");
208 close(conn);
209 return;
212 if (pthread_detach(tdata) < 0) {
213 oprogname();
214 perror("can't detach from thread");
218 static PyThreadState *the_tstate;
219 static PyInterpreterState *the_interp;
220 static PyObject *the_builtins;
222 static void
223 init_python()
225 if (gtstate)
226 return;
227 Py_Initialize(); /* Initialize the interpreter */
228 PyEval_InitThreads(); /* Create (and acquire) the interpreter lock */
229 gtstate = PyEval_SaveThread(); /* Release the thread state */
232 static void *
233 service_thread(struct workorder *work)
235 FILE *input, *output;
237 fprintf(stderr, "Start thread for connection %d.\n", work->conn);
239 ps();
241 input = fdopen(work->conn, "r");
242 if (input == NULL) {
243 oprogname();
244 perror("can't create input stream");
245 goto done;
248 output = fdopen(work->conn, "w");
249 if (output == NULL) {
250 oprogname();
251 perror("can't create output stream");
252 fclose(input);
253 goto done;
256 setvbuf(input, NULL, _IONBF, 0);
257 setvbuf(output, NULL, _IONBF, 0);
259 run_interpreter(input, output);
261 fclose(input);
262 fclose(output);
264 done:
265 fprintf(stderr, "End thread for connection %d.\n", work->conn);
266 close(work->conn);
267 free(work);
270 static void
271 oprogname()
273 int save = errno;
274 fprintf(stderr, "%s: ", progname);
275 errno = save;
278 static void
279 run_interpreter(FILE *input, FILE *output)
281 PyThreadState *tstate;
282 PyObject *new_stdin, *new_stdout;
283 PyObject *mainmod, *globals;
284 char buffer[1000];
285 char *p, *q;
286 int n, end;
288 PyEval_AcquireLock();
289 tstate = Py_NewInterpreter();
290 if (tstate == NULL) {
291 fprintf(output, "Sorry -- can't create an interpreter\n");
292 return;
295 mainmod = PyImport_AddModule("__main__");
296 globals = PyModule_GetDict(mainmod);
297 Py_INCREF(globals);
299 new_stdin = PyFile_FromFile(input, "<socket-in>", "r", NULL);
300 new_stdout = PyFile_FromFile(output, "<socket-out>", "w", NULL);
302 PySys_SetObject("stdin", new_stdin);
303 PySys_SetObject("stdout", new_stdout);
304 PySys_SetObject("stderr", new_stdout);
306 for (n = 1; !PyErr_Occurred(); n++) {
307 Py_BEGIN_ALLOW_THREADS
308 fprintf(output, "%d> ", n);
309 p = fgets(buffer, sizeof buffer, input);
310 Py_END_ALLOW_THREADS
312 if (p == NULL)
313 break;
314 if (p[0] == '\377' && p[1] == '\354')
315 break;
317 q = strrchr(p, '\r');
318 if (q && q[1] == '\n' && q[2] == '\0') {
319 *q++ = '\n';
320 *q++ = '\0';
323 while (*p && isspace(*p))
324 p++;
325 if (p[0] == '#' || p[0] == '\0')
326 continue;
328 end = run_command(buffer, globals);
329 if (end < 0)
330 PyErr_Print();
332 if (end)
333 break;
336 Py_XDECREF(globals);
337 Py_XDECREF(new_stdin);
338 Py_XDECREF(new_stdout);
340 Py_EndInterpreter(tstate);
341 PyEval_ReleaseLock();
343 fprintf(output, "Goodbye!\n");
346 static int
347 run_command(char *buffer, PyObject *globals)
349 PyObject *m, *d, *v;
350 fprintf(stderr, "run_command: %s", buffer);
351 if (strchr(buffer, '\n') == NULL)
352 fprintf(stderr, "\n");
353 v = PyRun_String(buffer, Py_single_input, globals, globals);
354 if (v == NULL) {
355 if (PyErr_Occurred() == PyExc_SystemExit) {
356 PyErr_Clear();
357 return 1;
359 PyErr_Print();
360 return 0;
362 Py_DECREF(v);
363 return 0;
366 static void
367 ps()
369 char buffer[100];
370 sprintf(buffer, "ps -l -p %d </dev/null | tail +2l\n", getpid());
371 system(buffer);