PageRenderTime 507ms CodeModel.GetById 181ms app.highlight 155ms RepoModel.GetById 167ms app.codeStats 0ms

/Demo/pysvr/pysvr.c

http://unladen-swallow.googlecode.com/
C | 370 lines | 293 code | 63 blank | 14 comment | 59 complexity | 2e3a3fb6e88e83fe4bd3c0790be30c80 MD5 | raw file
  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}