blob: 706cd2ae603f4a166dff9395d29b21283968602a [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>
Thomas Wouters2cffc7d2000-11-03 08:18:37 +000022#include <getopt.h>
Guido van Rossum5c8b9911997-07-19 21:00:47 +000023
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. */
27
Tim Peters885d4572001-11-28 20:27:42 +000028#include "Python.h"
Guido van Rossum5c8b9911997-07-19 21:00:47 +000029
Guido van Rossumcaf2f8e1999-10-05 22:16:07 +000030extern int Py_VerboseFlag;
31
Guido van Rossum5c8b9911997-07-19 21:00:47 +000032#ifndef PORT
33#define PORT 4000
34#endif
35
Guido van Rossum5c8b9911997-07-19 21:00:47 +000036struct workorder {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000037 int conn;
38 struct sockaddr_in addr;
Guido van Rossum5c8b9911997-07-19 21:00:47 +000039};
40
41/* Forward */
42static void init_python(void);
43static void usage(void);
44static void oprogname(void);
45static void main_thread(int);
46static void create_thread(int, struct sockaddr_in *);
47static void *service_thread(struct workorder *);
48static void run_interpreter(FILE *, FILE *);
49static int run_command(char *, PyObject *);
Guido van Rossumc46d22e1997-08-02 02:02:22 +000050static void ps(void);
Guido van Rossum5c8b9911997-07-19 21:00:47 +000051
52static char *progname = "pysvr";
53
Guido van Rossumc46d22e1997-08-02 02:02:22 +000054static PyThreadState *gtstate;
55
Guido van Rossum5c8b9911997-07-19 21:00:47 +000056main(int argc, char **argv)
57{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000058 int port = PORT;
59 int c;
Guido van Rossum5c8b9911997-07-19 21:00:47 +000060
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000061 if (argc > 0 && argv[0] != NULL && argv[0][0] != '\0')
62 progname = argv[0];
Guido van Rossum5c8b9911997-07-19 21:00:47 +000063
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000064 while ((c = getopt(argc, argv, "v")) != EOF) {
65 switch (c) {
66 case 'v':
67 Py_VerboseFlag++;
68 break;
69 default:
70 usage();
71 }
72 }
Guido van Rossum5c8b9911997-07-19 21:00:47 +000073
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000074 if (optind < argc) {
75 if (optind+1 < argc) {
76 oprogname();
77 fprintf(stderr, "too many arguments\n");
78 usage();
79 }
80 port = atoi(argv[optind]);
81 if (port <= 0) {
82 fprintf(stderr, "bad port (%s)\n", argv[optind]);
83 usage();
84 }
85 }
Guido van Rossum5c8b9911997-07-19 21:00:47 +000086
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000087 main_thread(port);
Guido van Rossum5c8b9911997-07-19 21:00:47 +000088
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000089 fprintf(stderr, "Bye.\n");
Guido van Rossum5c8b9911997-07-19 21:00:47 +000090
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000091 exit(0);
Guido van Rossum5c8b9911997-07-19 21:00:47 +000092}
93
94static char usage_line[] = "usage: %s [port]\n";
95
96static void
Thomas Wouters78890102000-07-22 19:25:51 +000097usage(void)
Guido van Rossum5c8b9911997-07-19 21:00:47 +000098{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000099 fprintf(stderr, usage_line, progname);
100 exit(2);
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000101}
102
103static void
104main_thread(int port)
105{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000106 int sock, conn, size, i;
107 struct sockaddr_in addr, clientaddr;
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000108
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000109 sock = socket(PF_INET, SOCK_STREAM, 0);
110 if (sock < 0) {
111 oprogname();
112 perror("can't create socket");
113 exit(1);
114 }
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000115
Guido van Rossum643f8f61997-12-25 04:48:51 +0000116#ifdef SO_REUSEADDR
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000117 i = 1;
118 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &i, sizeof i);
Guido van Rossum643f8f61997-12-25 04:48:51 +0000119#endif
120
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000121 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);
129 }
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000130
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000131 if (listen(sock, 5) < 0) {
132 oprogname();
133 perror("can't listen on socket");
134 exit(1);
135 }
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000136
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000137 fprintf(stderr, "Listening on port %d...\n", port);
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000138
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000139 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);
147 }
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000148
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000149 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);
155 }
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;
164 }
165 if (i == 4) {
166 close(conn);
167 break;
168 }
169 create_thread(conn, &clientaddr);
170 }
Guido van Rossumc46d22e1997-08-02 02:02:22 +0000171
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000172 close(sock);
Guido van Rossumc46d22e1997-08-02 02:02:22 +0000173
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000174 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. */
180 }
181 exit(0);
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000182}
183
184static void
185create_thread(int conn, struct sockaddr_in *addr)
186{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000187 struct workorder *work;
188 pthread_t tdata;
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000189
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000190 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;
196 }
197 work->conn = conn;
198 work->addr = *addr;
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000199
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000200 init_python();
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000201
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000202 if (pthread_create(&tdata, NULL, (void *)service_thread, work) < 0) {
203 oprogname();
204 perror("can't create new thread");
205 close(conn);
206 return;
207 }
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000208
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000209 if (pthread_detach(tdata) < 0) {
210 oprogname();
211 perror("can't detach from thread");
212 }
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000213}
214
215static PyThreadState *the_tstate;
216static PyInterpreterState *the_interp;
217static PyObject *the_builtins;
218
219static void
Thomas Wouters78890102000-07-22 19:25:51 +0000220init_python(void)
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000221{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000222 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 */
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000227}
228
229static void *
230service_thread(struct workorder *work)
231{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000232 FILE *input, *output;
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000233
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000234 fprintf(stderr, "Start thread for connection %d.\n", work->conn);
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000235
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000236 ps();
Guido van Rossumc46d22e1997-08-02 02:02:22 +0000237
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000238 input = fdopen(work->conn, "r");
239 if (input == NULL) {
240 oprogname();
241 perror("can't create input stream");
242 goto done;
243 }
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000244
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000245 output = fdopen(work->conn, "w");
246 if (output == NULL) {
247 oprogname();
248 perror("can't create output stream");
249 fclose(input);
250 goto done;
251 }
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000252
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000253 setvbuf(input, NULL, _IONBF, 0);
254 setvbuf(output, NULL, _IONBF, 0);
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000255
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000256 run_interpreter(input, output);
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000257
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000258 fclose(input);
259 fclose(output);
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000260
261 done:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000262 fprintf(stderr, "End thread for connection %d.\n", work->conn);
263 close(work->conn);
264 free(work);
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000265}
266
267static void
Thomas Wouters78890102000-07-22 19:25:51 +0000268oprogname(void)
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000269{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000270 int save = errno;
271 fprintf(stderr, "%s: ", progname);
272 errno = save;
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000273}
274
275static void
276run_interpreter(FILE *input, FILE *output)
277{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000278 PyThreadState *tstate;
279 PyObject *new_stdin, *new_stdout;
280 PyObject *mainmod, *globals;
281 char buffer[1000];
282 char *p, *q;
283 int n, end;
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000284
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000285 PyEval_AcquireLock();
286 tstate = Py_NewInterpreter();
287 if (tstate == NULL) {
288 fprintf(output, "Sorry -- can't create an interpreter\n");
289 return;
290 }
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000291
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000292 mainmod = PyImport_AddModule("__main__");
293 globals = PyModule_GetDict(mainmod);
294 Py_INCREF(globals);
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000295
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000296 new_stdin = PyFile_FromFile(input, "<socket-in>", "r", NULL);
297 new_stdout = PyFile_FromFile(output, "<socket-out>", "w", NULL);
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000298
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000299 PySys_SetObject("stdin", new_stdin);
300 PySys_SetObject("stdout", new_stdout);
301 PySys_SetObject("stderr", new_stdout);
Guido van Rossumc46d22e1997-08-02 02:02:22 +0000302
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000303 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
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000308
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000309 if (p == NULL)
310 break;
311 if (p[0] == '\377' && p[1] == '\354')
312 break;
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000313
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000314 q = strrchr(p, '\r');
315 if (q && q[1] == '\n' && q[2] == '\0') {
316 *q++ = '\n';
317 *q++ = '\0';
318 }
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000319
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000320 while (*p && isspace(*p))
321 p++;
322 if (p[0] == '#' || p[0] == '\0')
323 continue;
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000324
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000325 end = run_command(buffer, globals);
326 if (end < 0)
327 PyErr_Print();
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000328
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000329 if (end)
330 break;
331 }
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000332
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000333 Py_XDECREF(globals);
334 Py_XDECREF(new_stdin);
335 Py_XDECREF(new_stdout);
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000336
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000337 Py_EndInterpreter(tstate);
338 PyEval_ReleaseLock();
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000339
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000340 fprintf(output, "Goodbye!\n");
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000341}
342
343static int
344run_command(char *buffer, PyObject *globals)
345{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000346 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;
355 }
356 PyErr_Print();
357 return 0;
358 }
359 Py_DECREF(v);
360 return 0;
Guido van Rossum5c8b9911997-07-19 21:00:47 +0000361}
Guido van Rossumc46d22e1997-08-02 02:02:22 +0000362
363static void
Thomas Wouters78890102000-07-22 19:25:51 +0000364ps(void)
Guido van Rossumc46d22e1997-08-02 02:02:22 +0000365{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000366 char buffer[100];
367 PyOS_snprintf(buffer, sizeof(buffer),
368 "ps -l -p %d </dev/null | sed 1d\n", getpid());
369 system(buffer);
Guido van Rossumc46d22e1997-08-02 02:02:22 +0000370}