Guido van Rossum | 5c8b991 | 1997-07-19 21:00:47 +0000 | [diff] [blame] | 1 | #! /usr/bin/env python |
| 2 | |
| 3 | """A multi-threaded telnet-like server that gives a Python prompt. |
| 4 | |
| 5 | This is really a prototype for the same thing in C. |
| 6 | |
| 7 | Usage: pysvr.py [port] |
| 8 | |
Guido van Rossum | eca991d | 1997-07-19 21:13:53 +0000 | [diff] [blame] | 9 | For security reasons, it only accepts requests from the current host. |
| 10 | This can still be insecure, but restricts violations from people who |
| 11 | can log in on your machine. Use with caution! |
| 12 | |
Guido van Rossum | 5c8b991 | 1997-07-19 21:00:47 +0000 | [diff] [blame] | 13 | """ |
| 14 | |
| 15 | import sys, os, string, getopt, thread, socket, traceback |
| 16 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 17 | PORT = 4000 # Default port |
Guido van Rossum | 5c8b991 | 1997-07-19 21:00:47 +0000 | [diff] [blame] | 18 | |
| 19 | def main(): |
| 20 | try: |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 21 | opts, args = getopt.getopt(sys.argv[1:], "") |
| 22 | if len(args) > 1: |
| 23 | raise getopt.error, "Too many arguments." |
Guido van Rossum | 5c8b991 | 1997-07-19 21:00:47 +0000 | [diff] [blame] | 24 | except getopt.error, msg: |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 25 | usage(msg) |
Guido van Rossum | 5c8b991 | 1997-07-19 21:00:47 +0000 | [diff] [blame] | 26 | for o, a in opts: |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 27 | pass |
Guido van Rossum | 5c8b991 | 1997-07-19 21:00:47 +0000 | [diff] [blame] | 28 | if args: |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 29 | try: |
| 30 | port = string.atoi(args[0]) |
| 31 | except ValueError, msg: |
| 32 | usage(msg) |
Guido van Rossum | 5c8b991 | 1997-07-19 21:00:47 +0000 | [diff] [blame] | 33 | else: |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 34 | port = PORT |
Guido van Rossum | 5c8b991 | 1997-07-19 21:00:47 +0000 | [diff] [blame] | 35 | main_thread(port) |
| 36 | |
| 37 | def usage(msg=None): |
| 38 | sys.stdout = sys.stderr |
| 39 | if msg: |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 40 | print msg |
Guido van Rossum | 5c8b991 | 1997-07-19 21:00:47 +0000 | [diff] [blame] | 41 | print "\n", __doc__, |
| 42 | sys.exit(2) |
| 43 | |
| 44 | def main_thread(port): |
| 45 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
| 46 | sock.bind(("", port)) |
| 47 | sock.listen(5) |
Guido van Rossum | eca991d | 1997-07-19 21:13:53 +0000 | [diff] [blame] | 48 | print "Listening on port", port, "..." |
Guido van Rossum | 5c8b991 | 1997-07-19 21:00:47 +0000 | [diff] [blame] | 49 | while 1: |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 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 |
Guido van Rossum | 5c8b991 | 1997-07-19 21:00:47 +0000 | [diff] [blame] | 57 | |
| 58 | def service_thread(conn, addr): |
| 59 | (caddr, cport) = addr |
Guido van Rossum | 5c8b991 | 1997-07-19 21:00:47 +0000 | [diff] [blame] | 60 | print "Thread %s has connection from %s.\n" % (str(thread.get_ident()), |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 61 | caddr), |
Guido van Rossum | 5c8b991 | 1997-07-19 21:00:47 +0000 | [diff] [blame] | 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 | |
| 67 | def run_interpreter(stdin, stdout): |
| 68 | globals = {} |
| 69 | try: |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 70 | str(sys.ps1) |
Guido van Rossum | 5c8b991 | 1997-07-19 21:00:47 +0000 | [diff] [blame] | 71 | except: |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 72 | sys.ps1 = ">>> " |
Guido van Rossum | 5c8b991 | 1997-07-19 21:00:47 +0000 | [diff] [blame] | 73 | source = "" |
| 74 | while 1: |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 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 |
Guido van Rossum | 5c8b991 | 1997-07-19 21:00:47 +0000 | [diff] [blame] | 103 | stdout.write("\nGoodbye.\n") |
| 104 | |
| 105 | def run_command(code, stdin, stdout, globals): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 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 |
Guido van Rossum | 5c8b991 | 1997-07-19 21:00:47 +0000 | [diff] [blame] | 121 | |
| 122 | from code import compile_command |
| 123 | |
| 124 | main() |