copyright and license notices
[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             if line.startswith("-"):
89                 self.handle_directive(session, line)
90             else:
91                 self.handle_query(session, line)
92                 if not session.holdconnect:
93                     self.quit_flag = True
94
95             self.wfile.flush()
96
97             # check to see if we were asked to quit
98             if self.quit_flag: break
99
100         if config.verbose:
101             print "%s disconnected" %  (self.client_address,)
102
103     def handle_directive(self, session, line):
104         if config.verbose:
105             print "%s directive %s" % (self.client_address, line)
106         if (line.startswith("-quit")):
107             self.quit_flag = True
108             self.wfile.write(Rwhois.ok())
109             return
110         directive_processor.process_directive(session, line)
111
112     def handle_query(self, session, line):
113         if config.verbose:
114             print "%s query %s" % (self.client_address, line)
115         query_processor.process_query(session, line)
116
117
118 def usage(pname):
119     print """\
120 usage: %s [-v] schema_file data_file [data_file ...]
121        -v: verbose """ % pname
122     sys.exit(64)
123     
124 def init(argv):
125     import MemDB
126     import getopt
127
128     pname = argv[0]
129     opts, argv = getopt.getopt(argv[1:], 'v')
130     for o, a in opts:
131         if o == "-v":
132             config.verbose = True
133     
134     if len(argv) < 2: usage(pname)
135     schema_file = argv[0]
136     data_files  = argv[1:]
137
138
139     db = MemDB.MemDB()
140
141     db.init_schema(schema_file)
142     for df in data_files:
143         db.load_data(df)
144     db.index_data()
145
146     QueryParser.db = db
147
148     global query_processor, directive_processor
149     
150     query_processor     = QueryProcessor.QueryProcessor(db)
151     directive_processor = DirectiveProcessor.DirectiveProcessor(db)
152
153 def serve():
154     # initialize the TCP server
155     server = RwhoisTCPServer((config.server_address, config.port),
156                              RwhoisHandler)
157
158     # and handle incoming connections
159     if config.verbose:
160         if not config.server_address:
161             print "listening on port %d" % config.port
162         else:
163             print "listening on %s port %d" % \
164                   (config.server_address, config.port)
165     server.serve_forever()
166
167     sys.exit(0)
168
169 if __name__ == "__main__":
170
171     init(sys.argv)
172     serve()
173