Minor documentation change - hyperlink tidied up.
[python.git] / Demo / pysvr / pysvr.c
blobcced6da4bfb0ad018471207d809ea03e25d05318
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>
22 #include <getopt.h>
24 /* XXX Umpfh.
25 Python.h defines a typedef destructor, which conflicts with pthread.h.
26 So Python.h must be included after pthread.h. */
28 #include "Python.h"
30 extern int Py_VerboseFlag;
32 #ifndef PORT
33 #define PORT 4000
34 #endif
36 struct workorder {
37 int conn;
38 struct sockaddr_in addr;
41 /* Forward */
42 static void init_python(void);
43 static void usage(void);
44 static void oprogname(void);
45 static void main_thread(int);
46 static void create_thread(int, struct sockaddr_in *);
47 static void *service_thread(struct workorder *);
48 static void run_interpreter(FILE *, FILE *);
49 static int run_command(char *, PyObject *);
50 static void ps(void);
52 static char *progname = "pysvr";
54 static PyThreadState *gtstate;
56 main(int argc, char **argv)
58 int port = PORT;
59 int c;
61 if (argc > 0 && argv[0] != NULL && argv[0][0] != '\0')
62 progname = argv[0];
64 while ((c = getopt(argc, argv, "v")) != EOF) {
65 switch (c) {
66 case 'v':
67 Py_VerboseFlag++;
68 break;
69 default:
70 usage();
74 if (optind < argc) {
75 if (optind+1 < argc) {
76 oprogname();
77 fprintf(stderr, "too many arguments\n");
78 usage();
80 port = atoi(argv[optind]);
81 if (port <= 0) {
82 fprintf(stderr, "bad port (%s)\n", argv[optind]);
83 usage();
87 main_thread(port);
89 fprintf(stderr, "Bye.\n");
91 exit(0);
94 static char usage_line[] = "usage: %s [port]\n";
96 static void
97 usage(void)
99 fprintf(stderr, usage_line, progname);
100 exit(2);
103 static void
104 main_thread(int port)
106 int sock, conn, size, i;
107 struct sockaddr_in addr, clientaddr;
109 sock = socket(PF_INET, SOCK_STREAM, 0);
110 if (sock < 0) {
111 oprogname();
112 perror("can't create socket");
113 exit(1);
116 #ifdef SO_REUSEADDR
117 i = 1;
118 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &i, sizeof i);
119 #endif
121 memset((char *)&addr, '\0', sizeof addr);
122 addr.sin_family = AF_INET;
123 addr.sin_port = htons(port);
124 addr.sin_addr.s_addr = 0L;
125 if (bind(sock, (struct sockaddr *)&addr, sizeof addr) < 0) {
126 oprogname();
127 perror("can't bind socket to address");
128 exit(1);
131 if (listen(sock, 5) < 0) {
132 oprogname();
133 perror("can't listen on socket");
134 exit(1);
137 fprintf(stderr, "Listening on port %d...\n", port);
139 for (i = 0; ; i++) {
140 size = sizeof clientaddr;
141 memset((char *) &clientaddr, '\0', size);
142 conn = accept(sock, (struct sockaddr *) &clientaddr, &size);
143 if (conn < 0) {
144 oprogname();
145 perror("can't accept connection from socket");
146 exit(1);
149 size = sizeof addr;
150 memset((char *) &addr, '\0', size);
151 if (getsockname(conn, (struct sockaddr *)&addr, &size) < 0) {
152 oprogname();
153 perror("can't get socket name of connection");
154 exit(1);
156 if (clientaddr.sin_addr.s_addr != addr.sin_addr.s_addr) {
157 oprogname();
158 perror("connection from non-local host refused");
159 fprintf(stderr, "(addr=%lx, clientaddr=%lx)\n",
160 ntohl(addr.sin_addr.s_addr),
161 ntohl(clientaddr.sin_addr.s_addr));
162 close(conn);
163 continue;
165 if (i == 4) {
166 close(conn);
167 break;
169 create_thread(conn, &clientaddr);
172 close(sock);
174 if (gtstate) {
175 PyEval_AcquireThread(gtstate);
176 gtstate = NULL;
177 Py_Finalize();
178 /* And a second time, just because we can. */
179 Py_Finalize(); /* This should be harmless. */
181 exit(0);
184 static void
185 create_thread(int conn, struct sockaddr_in *addr)
187 struct workorder *work;
188 pthread_t tdata;
190 work = malloc(sizeof(struct workorder));
191 if (work == NULL) {
192 oprogname();
193 fprintf(stderr, "out of memory for thread.\n");
194 close(conn);
195 return;
197 work->conn = conn;
198 work->addr = *addr;
200 init_python();
202 if (pthread_create(&tdata, NULL, (void *)service_thread, work) < 0) {
203 oprogname();
204 perror("can't create new thread");
205 close(conn);
206 return;
209 if (pthread_detach(tdata) < 0) {
210 oprogname();
211 perror("can't detach from thread");
215 static PyThreadState *the_tstate;
216 static PyInterpreterState *the_interp;
217 static PyObject *the_builtins;
219 static void
220 init_python(void)
222 if (gtstate)
223 return;
224 Py_Initialize(); /* Initialize the interpreter */
225 PyEval_InitThreads(); /* Create (and acquire) the interpreter lock */
226 gtstate = PyEval_SaveThread(); /* Release the thread state */
229 static void *
230 service_thread(struct workorder *work)
232 FILE *input, *output;
234 fprintf(stderr, "Start thread for connection %d.\n", work->conn);
236 ps();
238 input = fdopen(work->conn, "r");
239 if (input == NULL) {
240 oprogname();
241 perror("can't create input stream");
242 goto done;
245 output = fdopen(work->conn, "w");
246 if (output == NULL) {
247 oprogname();
248 perror("can't create output stream");
249 fclose(input);
250 goto done;
253 setvbuf(input, NULL, _IONBF, 0);
254 setvbuf(output, NULL, _IONBF, 0);
256 run_interpreter(input, output);
258 fclose(input);
259 fclose(output);
261 done:
262 fprintf(stderr, "End thread for connection %d.\n", work->conn);
263 close(work->conn);
264 free(work);
267 static void
268 oprogname(void)
270 int save = errno;
271 fprintf(stderr, "%s: ", progname);
272 errno = save;
275 static void
276 run_interpreter(FILE *input, FILE *output)
278 PyThreadState *tstate;
279 PyObject *new_stdin, *new_stdout;
280 PyObject *mainmod, *globals;
281 char buffer[1000];
282 char *p, *q;
283 int n, end;
285 PyEval_AcquireLock();
286 tstate = Py_NewInterpreter();
287 if (tstate == NULL) {
288 fprintf(output, "Sorry -- can't create an interpreter\n");
289 return;
292 mainmod = PyImport_AddModule("__main__");
293 globals = PyModule_GetDict(mainmod);
294 Py_INCREF(globals);
296 new_stdin = PyFile_FromFile(input, "<socket-in>", "r", NULL);
297 new_stdout = PyFile_FromFile(output, "<socket-out>", "w", NULL);
299 PySys_SetObject("stdin", new_stdin);
300 PySys_SetObject("stdout", new_stdout);
301 PySys_SetObject("stderr", new_stdout);
303 for (n = 1; !PyErr_Occurred(); n++) {
304 Py_BEGIN_ALLOW_THREADS
305 fprintf(output, "%d> ", n);
306 p = fgets(buffer, sizeof buffer, input);
307 Py_END_ALLOW_THREADS
309 if (p == NULL)
310 break;
311 if (p[0] == '\377' && p[1] == '\354')
312 break;
314 q = strrchr(p, '\r');
315 if (q && q[1] == '\n' && q[2] == '\0') {
316 *q++ = '\n';
317 *q++ = '\0';
320 while (*p && isspace(*p))
321 p++;
322 if (p[0] == '#' || p[0] == '\0')
323 continue;
325 end = run_command(buffer, globals);
326 if (end < 0)
327 PyErr_Print();
329 if (end)
330 break;
333 Py_XDECREF(globals);
334 Py_XDECREF(new_stdin);
335 Py_XDECREF(new_stdout);
337 Py_EndInterpreter(tstate);
338 PyEval_ReleaseLock();
340 fprintf(output, "Goodbye!\n");
343 static int
344 run_command(char *buffer, PyObject *globals)
346 PyObject *m, *d, *v;
347 fprintf(stderr, "run_command: %s", buffer);
348 if (strchr(buffer, '\n') == NULL)
349 fprintf(stderr, "\n");
350 v = PyRun_String(buffer, Py_single_input, globals, globals);
351 if (v == NULL) {
352 if (PyErr_Occurred() == PyExc_SystemExit) {
353 PyErr_Clear();
354 return 1;
356 PyErr_Print();
357 return 0;
359 Py_DECREF(v);
360 return 0;
363 static void
364 ps(void)
366 char buffer[100];
367 PyOS_snprintf(buffer, sizeof(buffer),
368 "ps -l -p %d </dev/null | sed 1d\n", getpid());
369 system(buffer);