blob: 995a7ca0d14c0cf29ff920fa3c021d1d2c3d5c13 [file] [log] [blame]
Guido van Rossume0c69011997-07-19 21:33:10 +00001/* A multi-threaded telnet-like server that gives a Python prompt.
2
3Usage: pysvr [port]
4
5For security reasons, it only accepts requests from the current host.
6This can still be insecure, but restricts violations from people who
7can log in on your machine. Use with caution!
8
9*/
10
Guido van Rossum5c8b9911997-07-19 21:00:47 +000011#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <ctype.h>
15#include <errno.h>
16
17#include <sys/types.h>
18#include <sys/socket.h>
19#include <netinet/in.h>
20
21#include <pthread.h>
22
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. */
26
27#include <Python.h>
28
Guido van Rossumcaf2f8e1999-10-05 22:16:07 +000029extern int Py_VerboseFlag;
30
Guido van Rossum5c8b9911997-07-19 21:00:47 +000031#ifndef PORT
32#define PORT 4000
33#endif
34
35extern int optind;
36extern char *optarg;
37extern int getopt();
38
39struct workorder {
40 int conn;
41 struct sockaddr_in addr;
42};
43
44/* Forward */
45static void init_python(void);
46static void usage(void);
47static void oprogname(void);
48static void main_thread(int);
49static void create_thread(int, struct sockaddr_in *);
50static void *service_thread(struct workorder *);
51static void run_interpreter(FILE *, FILE *);
52static int run_command(char *, PyObject *);
Guido van Rossumc46d22e1997-08-02 02:02:22 +000053static void ps(void);
Guido van Rossum5c8b9911997-07-19 21:00:47 +000054
55static char *progname = "pysvr";
56
Guido van Rossumc46d22e1997-08-02 02:02:22 +000057static PyThreadState *gtstate;
58
Guido van Rossum5c8b9911997-07-19 21:00:47 +000059main(int argc, char **argv)
60{
61 int port = PORT;
62 int c;
63
64 if (argc > 0 && argv[0] != NULL && argv[0][0] != '\0')
65 progname = argv[0];
66
Guido van Rossumcaf2f8e1999-10-05 22:16:07 +000067 while ((c = getopt(argc, argv, "v")) != EOF) {
Guido van Rossum5c8b9911997-07-19 21:00:47 +000068 switch (c) {
Guido van Rossumcaf2f8e1999-10-05 22:16:07 +000069 case 'v':
70 Py_VerboseFlag++;
71 break;
Guido van Rossum5c8b9911997-07-19 21:00:47 +000072 default:
73 usage();
74 }
75 }
76
77 if (optind < argc) {
78 if (optind+1 < argc) {
79 oprogname();
80 fprintf(stderr, "too many arguments\n");
81 usage();
82 }
83 port = atoi(argv[optind]);
84 if (port <= 0) {
85 fprintf(stderr, "bad port (%s)\n", argv[optind]);
86 usage();
87 }
88 }
89
90 main_thread(port);
91
92 fprintf(stderr, "Bye.\n");
93
94 exit(0);
95}
96
97static char usage_line[] = "usage: %s [port]\n";
98
99static void
100usage()
101{
102 fprintf(stderr, usage_line, progname);
103 exit(2);
104}
105
106static void
107main_thread(int port)
108{
Guido van Rossumc46d22e1997-08-02 02:02:22 +0000109 int sock, conn, size, i;
Guido van Rossume0c69011997-07-19 21:33:10 +0000110 struct sockaddr_in addr, clientaddr;
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000111
112 sock = socket(PF_INET, SOCK_STREAM, 0);
113 if (sock < 0) {
114 oprogname();
115 perror("can't create socket");
116 exit(1);
117 }
118
Guido van Rossum643f8f61997-12-25 04:48:51 +0000119#ifdef SO_REUSEADDR
120 i = 1;
121 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &i, sizeof i);
122#endif
123
Guido van Rossumc46d22e1997-08-02 02:02:22 +0000124 memset((char *)&addr, '\0', sizeof addr);
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000125 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);
132 }
133
134 if (listen(sock, 5) < 0) {
135 oprogname();
136 perror("can't listen on socket");
137 exit(1);
138 }
139
140 fprintf(stderr, "Listening on port %d...\n", port);
141
Guido van Rossumc46d22e1997-08-02 02:02:22 +0000142 for (i = 0; ; i++) {
Guido van Rossume0c69011997-07-19 21:33:10 +0000143 size = sizeof clientaddr;
Guido van Rossumc46d22e1997-08-02 02:02:22 +0000144 memset((char *) &clientaddr, '\0', size);
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000145 conn = accept(sock, (struct sockaddr *) &clientaddr, &size);
146 if (conn < 0) {
147 oprogname();
148 perror("can't accept connection from socket");
149 exit(1);
150 }
151
Guido van Rossume0c69011997-07-19 21:33:10 +0000152 size = sizeof addr;
Guido van Rossumc46d22e1997-08-02 02:02:22 +0000153 memset((char *) &addr, '\0', size);
Guido van Rossume0c69011997-07-19 21:33:10 +0000154 if (getsockname(conn, (struct sockaddr *)&addr, &size) < 0) {
155 oprogname();
156 perror("can't get socket name of connection");
157 exit(1);
158 }
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;
167 }
Guido van Rossumc46d22e1997-08-02 02:02:22 +0000168 if (i == 4) {
169 close(conn);
170 break;
171 }
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000172 create_thread(conn, &clientaddr);
173 }
Guido van Rossumc46d22e1997-08-02 02:02:22 +0000174
175 close(sock);
176
177 if (gtstate) {
178 PyEval_AcquireThread(gtstate);
179 gtstate = NULL;
180 Py_Finalize();
Guido van Rossumcaf2f8e1999-10-05 22:16:07 +0000181 /* And a second time, just because we can. */
182 Py_Finalize(); /* This should be harmless. */
Guido van Rossumc46d22e1997-08-02 02:02:22 +0000183 }
184 exit(0);
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000185}
186
187static void
188create_thread(int conn, struct sockaddr_in *addr)
189{
190 struct workorder *work;
191 pthread_t tdata;
192
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;
199 }
200 work->conn = conn;
201 work->addr = *addr;
202
203 init_python();
204
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;
210 }
211
212 if (pthread_detach(tdata) < 0) {
213 oprogname();
214 perror("can't detach from thread");
215 }
216}
217
218static PyThreadState *the_tstate;
219static PyInterpreterState *the_interp;
220static PyObject *the_builtins;
221
222static void
223init_python()
224{
Guido van Rossumc46d22e1997-08-02 02:02:22 +0000225 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 */
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000230}
231
232static void *
233service_thread(struct workorder *work)
234{
235 FILE *input, *output;
236
237 fprintf(stderr, "Start thread for connection %d.\n", work->conn);
238
Guido van Rossumc46d22e1997-08-02 02:02:22 +0000239 ps();
240
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000241 input = fdopen(work->conn, "r");
242 if (input == NULL) {
243 oprogname();
244 perror("can't create input stream");
245 goto done;
246 }
247
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;
254 }
255
256 setvbuf(input, NULL, _IONBF, 0);
257 setvbuf(output, NULL, _IONBF, 0);
258
259 run_interpreter(input, output);
260
261 fclose(input);
262 fclose(output);
263
264 done:
265 fprintf(stderr, "End thread for connection %d.\n", work->conn);
266 close(work->conn);
267 free(work);
268}
269
270static void
271oprogname()
272{
273 int save = errno;
274 fprintf(stderr, "%s: ", progname);
275 errno = save;
276}
277
278static void
279run_interpreter(FILE *input, FILE *output)
280{
281 PyThreadState *tstate;
282 PyObject *new_stdin, *new_stdout;
Guido van Rossum630924f1997-07-25 20:59:55 +0000283 PyObject *mainmod, *globals;
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000284 char buffer[1000];
285 char *p, *q;
286 int n, end;
287
Guido van Rossum630924f1997-07-25 20:59:55 +0000288 PyEval_AcquireLock();
289 tstate = Py_NewInterpreter();
290 if (tstate == NULL) {
291 fprintf(output, "Sorry -- can't create an interpreter\n");
292 return;
293 }
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000294
Guido van Rossum630924f1997-07-25 20:59:55 +0000295 mainmod = PyImport_AddModule("__main__");
296 globals = PyModule_GetDict(mainmod);
297 Py_INCREF(globals);
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000298
299 new_stdin = PyFile_FromFile(input, "<socket-in>", "r", NULL);
300 new_stdout = PyFile_FromFile(output, "<socket-out>", "w", NULL);
301
Guido van Rossumc46d22e1997-08-02 02:02:22 +0000302 PySys_SetObject("stdin", new_stdin);
303 PySys_SetObject("stdout", new_stdout);
304 PySys_SetObject("stderr", new_stdout);
305
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000306 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
311
312 if (p == NULL)
313 break;
314 if (p[0] == '\377' && p[1] == '\354')
315 break;
316
317 q = strrchr(p, '\r');
318 if (q && q[1] == '\n' && q[2] == '\0') {
319 *q++ = '\n';
320 *q++ = '\0';
321 }
322
323 while (*p && isspace(*p))
324 p++;
325 if (p[0] == '#' || p[0] == '\0')
326 continue;
327
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000328 end = run_command(buffer, globals);
329 if (end < 0)
330 PyErr_Print();
331
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000332 if (end)
333 break;
334 }
335
336 Py_XDECREF(globals);
337 Py_XDECREF(new_stdin);
338 Py_XDECREF(new_stdout);
339
Guido van Rossum630924f1997-07-25 20:59:55 +0000340 Py_EndInterpreter(tstate);
341 PyEval_ReleaseLock();
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000342
343 fprintf(output, "Goodbye!\n");
344}
345
346static int
347run_command(char *buffer, PyObject *globals)
348{
349 PyObject *m, *d, *v;
Guido van Rossum630924f1997-07-25 20:59:55 +0000350 fprintf(stderr, "run_command: %s", buffer);
351 if (strchr(buffer, '\n') == NULL)
352 fprintf(stderr, "\n");
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000353 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;
358 }
359 PyErr_Print();
360 return 0;
361 }
362 Py_DECREF(v);
363 return 0;
364}
Guido van Rossumc46d22e1997-08-02 02:02:22 +0000365
366static void
367ps()
368{
369 char buffer[100];
370 sprintf(buffer, "ps -l -p %d </dev/null | tail +2l\n", getpid());
371 system(buffer);
372}