e46a7d54a4e7504be27611a9394cda144ba4c5e5
[python-rwhoisd.git] / rwhoisd / RwhoisServer.py
1 # This file is part of python-rwhoisd
2 #
3 # Copyright (C) 2003, David E. Blacka
4 #
5 # $Id: RwhoisServer.py,v 1.3 2003/04/28 16:45:11 davidb Exp $
6 #
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 # General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 # USA
21
22 import sys, socket, SocketServer
23
24 import config, Session
25 import QueryParser, QueryProcessor, DirectiveProcessor, Rwhois
26
27
28 # server-wide variables
29
30 query_processor     = None
31 directive_processor = None
32
33 class RwhoisTCPServer(SocketServer.ThreadingTCPServer):
34     def __init__(self, server_address, RequestHandlerClass):
35         self.allow_reuse_address = True
36         SocketServer.TCPServer.__init__(self, server_address,
37                                         RequestHandlerClass)
38
39     def verify_request(self, request, client_address):
40         # implement access control here
41         return True
42
43 class RwhoisHandler(SocketServer.StreamRequestHandler):
44
45     def readline(self):
46         """Read a line of input from the client."""
47         # a simple way of doing this
48         # return self.rfile.readline()
49
50         data = self.request.recv(1024)
51         if not data: return None
52
53         lines = data.splitlines(True)
54
55         # ugh. this totally defeats any pipelining, not that rwhois
56         # clients should be doing that.
57         if len(lines) > 1 and config.verbose:
58             print "%s discarding additional input lines: %r" \
59                   % (self.client_address, lines)
60         return lines[0]
61         
62     def handle(self):
63
64         self.quit_flag = False
65
66         # output a banner
67         self.wfile.write(config.banner_string);
68         self.wfile.write("\r\n");
69
70         # get a session.
71         session = Session.Context()
72         session.rfile = self.rfile
73         session.wfile = self.wfile
74
75         if config.verbose:
76             print "%s accepted connection" % (self.client_address,)
77
78         c = 0
79         while 1:
80             line = self.readline()
81             if not line: break
82
83             line = line.strip()
84             # we can skip blank lines.
85             if not line:
86                 continue
87         
88             try:
89                 if line.startswith("-"):
90                     self.handle_directive(session, line)
91                 else:
92                     self.handle_query(session, line)
93                     if not session.holdconnect:
94                         self.quit_flag = True
95             except Rwhois.RwhoisError, e:
96                 self.handle_error(session, e)
97
98             self.wfile.flush()
99
100             # check to see if we were asked to quit
101             if self.quit_flag: break
102
103         if config.verbose:
104             print "%s disconnected" %  (self.client_address,)
105
106     def handle_directive(self, session, line):
107         if config.verbose:
108             print "%s directive %s" % (self.client_address, line)
109         if (line.startswith("-quit")):
110             self.quit_flag = True
111             self.wfile.write(Rwhois.ok())
112             return
113         directive_processor.process_directive(session, line)
114
115     def handle_query(self, session, line):
116         if config.verbose:
117             print "%s query %s" % (self.client_address, line)
118         query_processor.process_query(session, line)
119
120     def handle_error(self, session, error):
121         code = error[0]
122         msg = error[1]
123         session.wfile.write(Rwhois.error_message((code, msg)))
124
125 def usage(pname):
126     print """\
127 usage: %s [-v] schema_file data_file [data_file ...]
128        -v: verbose """ % pname
129     sys.exit(64)
130     
131 def init(argv):
132     import MemDB
133     import getopt
134
135     pname = argv[0]
136     opts, argv = getopt.getopt(argv[1:], 'v')
137     for o, a in opts:
138         if o == "-v":
139             config.verbose = True
140     
141     if len(argv) < 2: usage(pname)
142     schema_file = argv[0]
143     data_files  = argv[1:]
144
145
146     db = MemDB.MemDB()
147
148     db.init_schema(schema_file)
149     for df in data_files:
150         db.load_data(df)
151     db.index_data()
152
153     QueryParser.db = db
154
155     global query_processor, directive_processor
156     
157     query_processor     = QueryProcessor.QueryProcessor(db)
158     directive_processor = DirectiveProcessor.DirectiveProcessor(db)
159
160 def serve():
161     # initialize the TCP server
162     server = RwhoisTCPServer((config.server_address, config.port),
163                              RwhoisHandler)
164
165     # and handle incoming connections
166     if config.verbose:
167         if not config.server_address:
168             print "listening on port %d" % config.port
169         else:
170             print "listening on %s port %d" % \
171                   (config.server_address, config.port)
172     server.serve_forever()
173
174     sys.exit(0)
175
176 if __name__ == "__main__":
177
178     init(sys.argv)
179     serve()
180