1616#
1717""" HTTP Server that serves roundup.
1818
19- $Id: roundup_server.py,v 1.23 2003-04-24 07:19:02 richard Exp $
19+ $Id: roundup_server.py,v 1.24 2003-05-09 02:02:40 richard Exp $
2020"""
2121
2222# python version check
2323from roundup import version_check
2424
2525import sys , os , urllib , StringIO , traceback , cgi , binascii , getopt , imp
26- import BaseHTTPServer
26+ import BaseHTTPServer , socket
2727
2828# Roundup modules of use here
2929from roundup .cgi import cgitb , client
@@ -204,6 +204,99 @@ def inner_run_cgi(self):
204204 c = tracker .Client (tracker , self , env )
205205 c .main ()
206206
207+
208+ try :
209+ import win32serviceutil
210+ except :
211+ RoundupService = None
212+ else :
213+ # allow the win32
214+ import win32service
215+ import win32event
216+ from win32event import *
217+ from win32file import *
218+
219+ SvcShutdown = "ServiceShutdown"
220+
221+ class RoundupService (win32serviceutil .ServiceFramework ,
222+ BaseHTTPServer .HTTPServer ):
223+ ''' A Roundup standalone server for Win32 by Ewout Prangsma
224+ '''
225+ _svc_name_ = "Roundup Bug Tracker"
226+ _svc_display_name_ = "Roundup Bug Tracker"
227+ address = ('' , 8888 )
228+ def __init__ (self , args ):
229+ win32serviceutil .ServiceFramework .__init__ (self , args )
230+ BaseHTTPServer .HTTPServer .__init__ (self , self .address ,
231+ RoundupRequestHandler )
232+
233+ # Create the necessary NT Event synchronization objects...
234+ # hevSvcStop is signaled when the SCM sends us a notification
235+ # to shutdown the service.
236+ self .hevSvcStop = win32event .CreateEvent (None , 0 , 0 , None )
237+
238+ # hevConn is signaled when we have a new incomming connection.
239+ self .hevConn = win32event .CreateEvent (None , 0 , 0 , None )
240+
241+ # Hang onto this module for other people to use for logging
242+ # purposes.
243+ import servicemanager
244+ self .servicemanager = servicemanager
245+
246+ def SvcStop (self ):
247+ # Before we do anything, tell the SCM we are starting the
248+ # stop process.
249+ self .ReportServiceStatus (win32service .SERVICE_STOP_PENDING )
250+ win32event .SetEvent (self .hevSvcStop )
251+
252+ def SvcDoRun (self ):
253+ try :
254+ self .serve_forever ()
255+ except SvcShutdown :
256+ pass
257+
258+ def get_request (self ):
259+ # Call WSAEventSelect to enable self.socket to be waited on.
260+ WSAEventSelect (self .socket , self .hevConn , FD_ACCEPT )
261+ while 1 :
262+ try :
263+ rv = self .socket .accept ()
264+ except socket .error , why :
265+ if why [0 ] != WSAEWOULDBLOCK :
266+ raise
267+ # Use WaitForMultipleObjects instead of select() because
268+ # on NT select() is only good for sockets, and not general
269+ # NT synchronization objects.
270+ rc = WaitForMultipleObjects ((self .hevSvcStop , self .hevConn ),
271+ 0 , INFINITE )
272+ if rc == WAIT_OBJECT_0 :
273+ # self.hevSvcStop was signaled, this means:
274+ # Stop the service!
275+ # So we throw the shutdown exception, which gets
276+ # caught by self.SvcDoRun
277+ raise SvcShutdown
278+ # Otherwise, rc == WAIT_OBJECT_0 + 1 which means
279+ # self.hevConn was signaled, which means when we call
280+ # self.socket.accept(), we'll have our incoming connection
281+ # socket!
282+ # Loop back to the top, and let that accept do its thing...
283+ else :
284+ # yay! we have a connection
285+ # However... the new socket is non-blocking, we need to
286+ # set it back into blocking mode. (The socket that accept()
287+ # returns has the same properties as the listening sockets,
288+ # this includes any properties set by WSAAsyncSelect, or
289+ # WSAEventSelect, and whether its a blocking socket or not.)
290+ #
291+ # So if you yank the following line, the setblocking() call
292+ # will be useless. The socket will still be in non-blocking
293+ # mode.
294+ WSAEventSelect (rv [0 ], self .hevConn , 0 )
295+ rv [0 ].setblocking (1 )
296+ break
297+ return rv
298+
299+
207300def usage (message = '' ):
208301 if message :
209302 message = _ ('Error: %(error)s\n \n ' )% {'error' : message }
@@ -213,7 +306,9 @@ def usage(message=''):
213306 -n: sets the host name
214307 -p: sets the port to listen on
215308 -l: sets a filename to log to (instead of stdout)
216- -d: daemonize, and write the server's PID to the nominated file
309+ -d: run the server in the background and on UN*X write the server's PID
310+ to the nominated file. Note: on Windows the PID argument is needed,
311+ but ignored.
217312
218313 name=tracker home
219314 Sets the tracker home(s) to use. The name is how the tracker is
@@ -340,11 +435,16 @@ def run():
340435
341436 # fork?
342437 if pidfile :
343- if not hasattr (os , 'fork' ):
438+ if RoundupService :
439+ # don't do any other stuff
440+ RoundupService .address = address
441+ return win32serviceutil .HandleCommandLine (RoundupService )
442+ elif not hasattr (os , 'fork' ):
344443 print "Sorry, you can't run the server as a daemon on this" \
345444 'Operating System'
346445 sys .exit (0 )
347- daemonize (pidfile )
446+ else :
447+ daemonize (pidfile )
348448
349449 # redirect stdout/stderr to our logfile
350450 if logfile :
0 commit comments