source: python/vendor/Python-2.7.6/Demo/pysvr/pysvr.c

Last change on this file was 388, checked in by dmik, 11 years ago

python: Update vendor to 2.7.6.

  • Property svn:eol-style set to native
File size: 8.2 KB
Line 
1/* 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
11#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#include <getopt.h>
23
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
28#include "Python.h"
29
30extern int Py_VerboseFlag;
31
32#ifndef PORT
33#define PORT 4000
34#endif
35
36struct workorder {
37 int conn;
38 struct sockaddr_in addr;
39};
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 *);
50static void ps(void);
51
52static char *progname = "pysvr";
53
54static PyThreadState *gtstate;
55
56main(int argc, char **argv)
57{
58 int port = PORT;
59 int c;
60
61 if (argc > 0 && argv[0] != NULL && argv[0][0] != '\0')
62 progname = argv[0];
63
64 while ((c = getopt(argc, argv, "v")) != EOF) {
65 switch (c) {
66 case 'v':
67 Py_VerboseFlag++;
68 break;
69 default:
70 usage();
71 }
72 }
73
74 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 }
86
87 main_thread(port);
88
89 fprintf(stderr, "Bye.\n");
90
91 exit(0);
92}
93
94static char usage_line[] = "usage: %s [port]\n";
95
96static void
97usage(void)
98{
99 fprintf(stderr, usage_line, progname);
100 exit(2);
101}
102
103static void
104main_thread(int port)
105{
106 int sock, conn, size, i;
107 struct sockaddr_in addr, clientaddr;
108
109 sock = socket(PF_INET, SOCK_STREAM, 0);
110 if (sock < 0) {
111 oprogname();
112 perror("can't create socket");
113 exit(1);
114 }
115
116#ifdef SO_REUSEADDR
117 i = 1;
118 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &i, sizeof i);
119#endif
120
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);
129 }
130
131 if (listen(sock, 5) < 0) {
132 oprogname();
133 perror("can't listen on socket");
134 exit(1);
135 }
136
137 fprintf(stderr, "Listening on port %d...\n", port);
138
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);
147 }
148
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);
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 }
171
172 close(sock);
173
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. */
180 }
181 exit(0);
182}
183
184static void
185create_thread(int conn, struct sockaddr_in *addr)
186{
187 struct workorder *work;
188 pthread_t tdata;
189
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;
196 }
197 work->conn = conn;
198 work->addr = *addr;
199
200 init_python();
201
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;
207 }
208
209 if (pthread_detach(tdata) < 0) {
210 oprogname();
211 perror("can't detach from thread");
212 }
213}
214
215static PyThreadState *the_tstate;
216static PyInterpreterState *the_interp;
217static PyObject *the_builtins;
218
219static void
220init_python(void)
221{
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 */
227}
228
229static void *
230service_thread(struct workorder *work)
231{
232 FILE *input, *output;
233
234 fprintf(stderr, "Start thread for connection %d.\n", work->conn);
235
236 ps();
237
238 input = fdopen(work->conn, "r");
239 if (input == NULL) {
240 oprogname();
241 perror("can't create input stream");
242 goto done;
243 }
244
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;
251 }
252
253 setvbuf(input, NULL, _IONBF, 0);
254 setvbuf(output, NULL, _IONBF, 0);
255
256 run_interpreter(input, output);
257
258 fclose(input);
259 fclose(output);
260
261 done:
262 fprintf(stderr, "End thread for connection %d.\n", work->conn);
263 close(work->conn);
264 free(work);
265}
266
267static void
268oprogname(void)
269{
270 int save = errno;
271 fprintf(stderr, "%s: ", progname);
272 errno = save;
273}
274
275static void
276run_interpreter(FILE *input, FILE *output)
277{
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;
284
285 PyEval_AcquireLock();
286 tstate = Py_NewInterpreter();
287 if (tstate == NULL) {
288 fprintf(output, "Sorry -- can't create an interpreter\n");
289 return;
290 }
291
292 mainmod = PyImport_AddModule("__main__");
293 globals = PyModule_GetDict(mainmod);
294 Py_INCREF(globals);
295
296 new_stdin = PyFile_FromFile(input, "<socket-in>", "r", NULL);
297 new_stdout = PyFile_FromFile(output, "<socket-out>", "w", NULL);
298
299 PySys_SetObject("stdin", new_stdin);
300 PySys_SetObject("stdout", new_stdout);
301 PySys_SetObject("stderr", new_stdout);
302
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
308
309 if (p == NULL)
310 break;
311 if (p[0] == '\377' && p[1] == '\354')
312 break;
313
314 q = strrchr(p, '\r');
315 if (q && q[1] == '\n' && q[2] == '\0') {
316 *q++ = '\n';
317 *q++ = '\0';
318 }
319
320 while (*p && isspace(*p))
321 p++;
322 if (p[0] == '#' || p[0] == '\0')
323 continue;
324
325 end = run_command(buffer, globals);
326 if (end < 0)
327 PyErr_Print();
328
329 if (end)
330 break;
331 }
332
333 Py_XDECREF(globals);
334 Py_XDECREF(new_stdin);
335 Py_XDECREF(new_stdout);
336
337 Py_EndInterpreter(tstate);
338 PyEval_ReleaseLock();
339
340 fprintf(output, "Goodbye!\n");
341}
342
343static int
344run_command(char *buffer, PyObject *globals)
345{
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;
355 }
356 PyErr_Print();
357 return 0;
358 }
359 Py_DECREF(v);
360 return 0;
361}
362
363static void
364ps(void)
365{
366 char buffer[100];
367 PyOS_snprintf(buffer, sizeof(buffer),
368 "ps -l -p %d </dev/null | sed 1d\n", getpid());
369 system(buffer);
370}
Note: See TracBrowser for help on using the repository browser.