Fix an amazing number of typos & malformed sentences reported by Detlef
[python/dscho.git] / Demo / pysvr / pysvr.c
blobe41d88e1ae1c84fe184314a67bcdb13740d39607
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 #ifndef PORT
30 #define PORT 4000
31 #endif
33 extern int optind;
34 extern char *optarg;
35 extern int getopt();
37 struct workorder {
38 int conn;
39 struct sockaddr_in addr;
42 /* Forward */
43 static void init_python(void);
44 static void usage(void);
45 static void oprogname(void);
46 static void main_thread(int);
47 static void create_thread(int, struct sockaddr_in *);
48 static void *service_thread(struct workorder *);
49 static void run_interpreter(FILE *, FILE *);
50 static int run_command(char *, PyObject *);
51 static void ps(void);
53 static char *progname = "pysvr";
55 static PyThreadState *gtstate;
57 main(int argc, char **argv)
59 int port = PORT;
60 int c;
62 if (argc > 0 && argv[0] != NULL && argv[0][0] != '\0')
63 progname = argv[0];
65 while ((c = getopt(argc, argv, "")) != EOF) {
66 switch (c) {
67 default:
68 usage();
72 if (optind < argc) {
73 if (optind+1 < argc) {
74 oprogname();
75 fprintf(stderr, "too many arguments\n");
76 usage();
78 port = atoi(argv[optind]);
79 if (port <= 0) {
80 fprintf(stderr, "bad port (%s)\n", argv[optind]);
81 usage();
85 main_thread(port);
87 fprintf(stderr, "Bye.\n");
89 exit(0);
92 static char usage_line[] = "usage: %s [port]\n";
94 static void
95 usage()
97 fprintf(stderr, usage_line, progname);
98 exit(2);
101 static void
102 main_thread(int port)
104 int sock, conn, size, i;
105 struct sockaddr_in addr, clientaddr;
107 sock = socket(PF_INET, SOCK_STREAM, 0);
108 if (sock < 0) {
109 oprogname();
110 perror("can't create socket");
111 exit(1);
114 #ifdef SO_REUSEADDR
115 i = 1;
116 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &i, sizeof i);
117 #endif
119 memset((char *)&addr, '\0', sizeof addr);
120 addr.sin_family = AF_INET;
121 addr.sin_port = htons(port);
122 addr.sin_addr.s_addr = 0L;
123 if (bind(sock, (struct sockaddr *)&addr, sizeof addr) < 0) {
124 oprogname();
125 perror("can't bind socket to address");
126 exit(1);
129 if (listen(sock, 5) < 0) {
130 oprogname();
131 perror("can't listen on socket");
132 exit(1);
135 fprintf(stderr, "Listening on port %d...\n", port);
137 for (i = 0; ; i++) {
138 size = sizeof clientaddr;
139 memset((char *) &clientaddr, '\0', size);
140 conn = accept(sock, (struct sockaddr *) &clientaddr, &size);
141 if (conn < 0) {
142 oprogname();
143 perror("can't accept connection from socket");
144 exit(1);
147 size = sizeof addr;
148 memset((char *) &addr, '\0', size);
149 if (getsockname(conn, (struct sockaddr *)&addr, &size) < 0) {
150 oprogname();
151 perror("can't get socket name of connection");
152 exit(1);
154 if (clientaddr.sin_addr.s_addr != addr.sin_addr.s_addr) {
155 oprogname();
156 perror("connection from non-local host refused");
157 fprintf(stderr, "(addr=%lx, clientaddr=%lx)\n",
158 ntohl(addr.sin_addr.s_addr),
159 ntohl(clientaddr.sin_addr.s_addr));
160 close(conn);
161 continue;
163 if (i == 4) {
164 close(conn);
165 break;
167 create_thread(conn, &clientaddr);
170 close(sock);
172 if (gtstate) {
173 PyEval_AcquireThread(gtstate);
174 gtstate = NULL;
175 Py_Finalize();
176 Py_Finalize();
178 exit(0);
181 static void
182 create_thread(int conn, struct sockaddr_in *addr)
184 struct workorder *work;
185 pthread_t tdata;
187 work = malloc(sizeof(struct workorder));
188 if (work == NULL) {
189 oprogname();
190 fprintf(stderr, "out of memory for thread.\n");
191 close(conn);
192 return;
194 work->conn = conn;
195 work->addr = *addr;
197 init_python();
199 if (pthread_create(&tdata, NULL, (void *)service_thread, work) < 0) {
200 oprogname();
201 perror("can't create new thread");
202 close(conn);
203 return;
206 if (pthread_detach(tdata) < 0) {
207 oprogname();
208 perror("can't detach from thread");
212 static PyThreadState *the_tstate;
213 static PyInterpreterState *the_interp;
214 static PyObject *the_builtins;
216 static void
217 init_python()
219 if (gtstate)
220 return;
221 Py_Initialize(); /* Initialize the interpreter */
222 PyEval_InitThreads(); /* Create (and acquire) the interpreter lock */
223 gtstate = PyEval_SaveThread(); /* Release the thread state */
226 static void *
227 service_thread(struct workorder *work)
229 FILE *input, *output;
231 fprintf(stderr, "Start thread for connection %d.\n", work->conn);
233 ps();
235 input = fdopen(work->conn, "r");
236 if (input == NULL) {
237 oprogname();
238 perror("can't create input stream");
239 goto done;
242 output = fdopen(work->conn, "w");
243 if (output == NULL) {
244 oprogname();
245 perror("can't create output stream");
246 fclose(input);
247 goto done;
250 setvbuf(input, NULL, _IONBF, 0);
251 setvbuf(output, NULL, _IONBF, 0);
253 run_interpreter(input, output);
255 fclose(input);
256 fclose(output);
258 done:
259 fprintf(stderr, "End thread for connection %d.\n", work->conn);
260 close(work->conn);
261 free(work);
264 static void
265 oprogname()
267 int save = errno;
268 fprintf(stderr, "%s: ", progname);
269 errno = save;
272 static void
273 run_interpreter(FILE *input, FILE *output)
275 PyThreadState *tstate;
276 PyObject *new_stdin, *new_stdout;
277 PyObject *mainmod, *globals;
278 char buffer[1000];
279 char *p, *q;
280 int n, end;
282 PyEval_AcquireLock();
283 tstate = Py_NewInterpreter();
284 if (tstate == NULL) {
285 fprintf(output, "Sorry -- can't create an interpreter\n");
286 return;
289 mainmod = PyImport_AddModule("__main__");
290 globals = PyModule_GetDict(mainmod);
291 Py_INCREF(globals);
293 new_stdin = PyFile_FromFile(input, "<socket-in>", "r", NULL);
294 new_stdout = PyFile_FromFile(output, "<socket-out>", "w", NULL);
296 PySys_SetObject("stdin", new_stdin);
297 PySys_SetObject("stdout", new_stdout);
298 PySys_SetObject("stderr", new_stdout);
300 for (n = 1; !PyErr_Occurred(); n++) {
301 Py_BEGIN_ALLOW_THREADS
302 fprintf(output, "%d> ", n);
303 p = fgets(buffer, sizeof buffer, input);
304 Py_END_ALLOW_THREADS
306 if (p == NULL)
307 break;
308 if (p[0] == '\377' && p[1] == '\354')
309 break;
311 q = strrchr(p, '\r');
312 if (q && q[1] == '\n' && q[2] == '\0') {
313 *q++ = '\n';
314 *q++ = '\0';
317 while (*p && isspace(*p))
318 p++;
319 if (p[0] == '#' || p[0] == '\0')
320 continue;
322 end = run_command(buffer, globals);
323 if (end < 0)
324 PyErr_Print();
326 if (end)
327 break;
330 Py_XDECREF(globals);
331 Py_XDECREF(new_stdin);
332 Py_XDECREF(new_stdout);
334 Py_EndInterpreter(tstate);
335 PyEval_ReleaseLock();
337 fprintf(output, "Goodbye!\n");
340 static int
341 run_command(char *buffer, PyObject *globals)
343 PyObject *m, *d, *v;
344 fprintf(stderr, "run_command: %s", buffer);
345 if (strchr(buffer, '\n') == NULL)
346 fprintf(stderr, "\n");
347 v = PyRun_String(buffer, Py_single_input, globals, globals);
348 if (v == NULL) {
349 if (PyErr_Occurred() == PyExc_SystemExit) {
350 PyErr_Clear();
351 return 1;
353 PyErr_Print();
354 return 0;
356 Py_DECREF(v);
357 return 0;
360 static void
361 ps()
363 char buffer[100];
364 sprintf(buffer, "ps -l -p %d </dev/null | tail +2l\n", getpid());
365 system(buffer);