1#! /usr/bin/env python
2
3"""A multi-threaded telnet-like server that gives a Python prompt.
4
5This is really a prototype for the same thing in C.
6
7Usage: pysvr.py [port]
8
9For security reasons, it only accepts requests from the current host.
10This can still be insecure, but restricts violations from people who
11can log in on your machine.  Use with caution!
12
13"""
14
15import sys, os, string, getopt, thread, socket, traceback
16
17PORT = 4000                             # Default port
18
19def main():
20    try:
21        opts, args = getopt.getopt(sys.argv[1:], "")
22        if len(args) > 1:
23            raise getopt.error, "Too many arguments."
24    except getopt.error, msg:
25        usage(msg)
26    for o, a in opts:
27        pass
28    if args:
29        try:
30            port = string.atoi(args[0])
31        except ValueError, msg:
32            usage(msg)
33    else:
34        port = PORT
35    main_thread(port)
36
37def usage(msg=None):
38    sys.stdout = sys.stderr
39    if msg:
40        print msg
41    print "\n", __doc__,
42    sys.exit(2)
43
44def main_thread(port):
45    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
46    sock.bind(("", port))
47    sock.listen(5)
48    print "Listening on port", port, "..."
49    while 1:
50        (conn, addr) = sock.accept()
51        if addr[0] != conn.getsockname()[0]:
52            conn.close()
53            print "Refusing connection from non-local host", addr[0], "."
54            continue
55        thread.start_new_thread(service_thread, (conn, addr))
56        del conn, addr
57
58def service_thread(conn, addr):
59    (caddr, cport) = addr
60    print "Thread %s has connection from %s.\n" % (str(thread.get_ident()),
61                                                   caddr),
62    stdin = conn.makefile("r")
63    stdout = conn.makefile("w", 0)
64    run_interpreter(stdin, stdout)
65    print "Thread %s is done.\n" % str(thread.get_ident()),
66
67def run_interpreter(stdin, stdout):
68    globals = {}
69    try:
70        str(sys.ps1)
71    except:
72        sys.ps1 = ">>> "
73    source = ""
74    while 1:
75        stdout.write(sys.ps1)
76        line = stdin.readline()
77        if line[:2] == '\377\354':
78            line = ""
79        if not line and not source:
80            break
81        if line[-2:] == '\r\n':
82            line = line[:-2] + '\n'
83        source = source + line
84        try:
85            code = compile_command(source)
86        except SyntaxError, err:
87            source = ""
88            traceback.print_exception(SyntaxError, err, None, file=stdout)
89            continue
90        if not code:
91            continue
92        source = ""
93        try:
94            run_command(code, stdin, stdout, globals)
95        except SystemExit, how:
96            if how:
97                try:
98                    how = str(how)
99                except:
100                    how = ""
101                stdout.write("Exit %s\n" % how)
102            break
103    stdout.write("\nGoodbye.\n")
104
105def run_command(code, stdin, stdout, globals):
106    save = sys.stdin, sys.stdout, sys.stderr
107    try:
108        sys.stdout = sys.stderr = stdout
109        sys.stdin = stdin
110        try:
111            exec code in globals
112        except SystemExit, how:
113            raise SystemExit, how, sys.exc_info()[2]
114        except:
115            type, value, tb = sys.exc_info()
116            if tb: tb = tb.tb_next
117            traceback.print_exception(type, value, tb)
118            del tb
119    finally:
120        sys.stdin, sys.stdout, sys.stderr = save
121
122from code import compile_command
123
124main()
125