blob: f6f9e08c4918441b3611a8668bbf80eb5001b6de [file] [log] [blame]
Guido van Rossum5c8b9911997-07-19 21:00:47 +00001#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <ctype.h>
5#include <errno.h>
6
7#include <sys/types.h>
8#include <sys/socket.h>
9#include <netinet/in.h>
10
11#include <pthread.h>
12
13/* XXX Umpfh.
14 Python.h defines a typedef destructor, which conflicts with pthread.h.
15 So Python.h must be included after pthread.h. */
16
17#include <Python.h>
18
19#ifndef PORT
20#define PORT 4000
21#endif
22
23extern int optind;
24extern char *optarg;
25extern int getopt();
26
27struct workorder {
28 int conn;
29 struct sockaddr_in addr;
30};
31
32/* Forward */
33static void init_python(void);
34static void usage(void);
35static void oprogname(void);
36static void main_thread(int);
37static void create_thread(int, struct sockaddr_in *);
38static void *service_thread(struct workorder *);
39static void run_interpreter(FILE *, FILE *);
40static int run_command(char *, PyObject *);
41
42static char *progname = "pysvr";
43
44main(int argc, char **argv)
45{
46 int port = PORT;
47 int c;
48
49 if (argc > 0 && argv[0] != NULL && argv[0][0] != '\0')
50 progname = argv[0];
51
52 while ((c = getopt(argc, argv, "")) != EOF) {
53 switch (c) {
54 default:
55 usage();
56 }
57 }
58
59 if (optind < argc) {
60 if (optind+1 < argc) {
61 oprogname();
62 fprintf(stderr, "too many arguments\n");
63 usage();
64 }
65 port = atoi(argv[optind]);
66 if (port <= 0) {
67 fprintf(stderr, "bad port (%s)\n", argv[optind]);
68 usage();
69 }
70 }
71
72 main_thread(port);
73
74 fprintf(stderr, "Bye.\n");
75
76 exit(0);
77}
78
79static char usage_line[] = "usage: %s [port]\n";
80
81static void
82usage()
83{
84 fprintf(stderr, usage_line, progname);
85 exit(2);
86}
87
88static void
89main_thread(int port)
90{
91 int sock;
92 struct sockaddr_in addr;
93
94 sock = socket(PF_INET, SOCK_STREAM, 0);
95 if (sock < 0) {
96 oprogname();
97 perror("can't create socket");
98 exit(1);
99 }
100
101 memset(&addr, '\0', sizeof addr);
102 addr.sin_family = AF_INET;
103 addr.sin_port = htons(port);
104 addr.sin_addr.s_addr = 0L;
105 if (bind(sock, (struct sockaddr *)&addr, sizeof addr) < 0) {
106 oprogname();
107 perror("can't bind socket to address");
108 exit(1);
109 }
110
111 if (listen(sock, 5) < 0) {
112 oprogname();
113 perror("can't listen on socket");
114 exit(1);
115 }
116
117 fprintf(stderr, "Listening on port %d...\n", port);
118
119 for (;;) {
120 struct sockaddr_in clientaddr;
121 int conn, size;
122
123 conn = accept(sock, (struct sockaddr *) &clientaddr, &size);
124 if (conn < 0) {
125 oprogname();
126 perror("can't accept connection from socket");
127 exit(1);
128 }
129
130 create_thread(conn, &clientaddr);
131 }
132}
133
134static void
135create_thread(int conn, struct sockaddr_in *addr)
136{
137 struct workorder *work;
138 pthread_t tdata;
139
140 work = malloc(sizeof(struct workorder));
141 if (work == NULL) {
142 oprogname();
143 fprintf(stderr, "out of memory for thread.\n");
144 close(conn);
145 return;
146 }
147 work->conn = conn;
148 work->addr = *addr;
149
150 init_python();
151
152 if (pthread_create(&tdata, NULL, (void *)service_thread, work) < 0) {
153 oprogname();
154 perror("can't create new thread");
155 close(conn);
156 return;
157 }
158
159 if (pthread_detach(tdata) < 0) {
160 oprogname();
161 perror("can't detach from thread");
162 }
163}
164
165static PyThreadState *the_tstate;
166static PyInterpreterState *the_interp;
167static PyObject *the_builtins;
168
169static void
170init_python()
171{
172 if (the_interp)
173 return;
174 Py_Initialize(); /* Initialize the interpreter */
175 the_builtins = PyEval_GetBuiltins(); /* Get __builtins__ */
176 PyEval_InitThreads(); /* Create and acquire the interpreter lock */
177 the_tstate = PyEval_SaveThread(); /* Release lock & get thread state */
178 the_interp = the_tstate->interpreter_state; /* Get interp state */
179}
180
181static void *
182service_thread(struct workorder *work)
183{
184 FILE *input, *output;
185
186 fprintf(stderr, "Start thread for connection %d.\n", work->conn);
187
188 input = fdopen(work->conn, "r");
189 if (input == NULL) {
190 oprogname();
191 perror("can't create input stream");
192 goto done;
193 }
194
195 output = fdopen(work->conn, "w");
196 if (output == NULL) {
197 oprogname();
198 perror("can't create output stream");
199 fclose(input);
200 goto done;
201 }
202
203 setvbuf(input, NULL, _IONBF, 0);
204 setvbuf(output, NULL, _IONBF, 0);
205
206 run_interpreter(input, output);
207
208 fclose(input);
209 fclose(output);
210
211 done:
212 fprintf(stderr, "End thread for connection %d.\n", work->conn);
213 close(work->conn);
214 free(work);
215}
216
217static void
218oprogname()
219{
220 int save = errno;
221 fprintf(stderr, "%s: ", progname);
222 errno = save;
223}
224
225static void
226run_interpreter(FILE *input, FILE *output)
227{
228 PyThreadState *tstate;
229 PyObject *new_stdin, *new_stdout;
230 PyObject *old_stdin, *old_stdout, *old_stderr;
231 PyObject *globals;
232 char buffer[1000];
233 char *p, *q;
234 int n, end;
235
236 tstate = PyThreadState_New(the_interp);
237 PyEval_AcquireThread(tstate);
238
239 globals = PyDict_New();
240 PyDict_SetItemString(globals, "__builtins__", the_builtins);
241
242 new_stdin = PyFile_FromFile(input, "<socket-in>", "r", NULL);
243 new_stdout = PyFile_FromFile(output, "<socket-out>", "w", NULL);
244
245 old_stdin = PySys_GetObject("stdin");
246 old_stdout = PySys_GetObject("stdout");
247 old_stderr = PySys_GetObject("stderr");
248
249 for (n = 1; !PyErr_Occurred(); n++) {
250 Py_BEGIN_ALLOW_THREADS
251 fprintf(output, "%d> ", n);
252 p = fgets(buffer, sizeof buffer, input);
253 Py_END_ALLOW_THREADS
254
255 if (p == NULL)
256 break;
257 if (p[0] == '\377' && p[1] == '\354')
258 break;
259
260 q = strrchr(p, '\r');
261 if (q && q[1] == '\n' && q[2] == '\0') {
262 *q++ = '\n';
263 *q++ = '\0';
264 }
265
266 while (*p && isspace(*p))
267 p++;
268 if (p[0] == '#' || p[0] == '\0')
269 continue;
270
271 PySys_SetObject("stdin", new_stdin);
272 PySys_SetObject("stdout", new_stdout);
273 PySys_SetObject("stderr", new_stdout);
274
275 end = run_command(buffer, globals);
276 if (end < 0)
277 PyErr_Print();
278
279 PySys_SetObject("stdin", old_stdin);
280 PySys_SetObject("stdout", old_stdout);
281 PySys_SetObject("stderr", old_stderr);
282
283 if (end)
284 break;
285 }
286
287 Py_XDECREF(globals);
288 Py_XDECREF(new_stdin);
289 Py_XDECREF(new_stdout);
290
291 PyEval_ReleaseThread(tstate);
292 PyThreadState_Delete(tstate);
293
294 fprintf(output, "Goodbye!\n");
295}
296
297static int
298run_command(char *buffer, PyObject *globals)
299{
300 PyObject *m, *d, *v;
301 v = PyRun_String(buffer, Py_single_input, globals, globals);
302 if (v == NULL) {
303 if (PyErr_Occurred() == PyExc_SystemExit) {
304 PyErr_Clear();
305 return 1;
306 }
307 PyErr_Print();
308 return 0;
309 }
310 Py_DECREF(v);
311 return 0;
312}