|
17 | 17 |
|
18 | 18 | """Command-line script that runs a server over roundup.cgi.client. |
19 | 19 |
|
20 | | -$Id: roundup_server.py,v 1.68 2004-10-29 17:57:17 a1s Exp $ |
| 20 | +$Id: roundup_server.py,v 1.69 2004-10-29 20:39:31 a1s Exp $ |
21 | 21 | """ |
22 | 22 | __docformat__ = 'restructuredtext' |
23 | 23 |
|
@@ -428,88 +428,48 @@ class ThreadingServer(SocketServer.ThreadingMixIn, |
428 | 428 | class SvcShutdown(Exception): |
429 | 429 | pass |
430 | 430 |
|
431 | | - class RoundupService(win32serviceutil.ServiceFramework, |
432 | | - BaseHTTPServer.HTTPServer): |
433 | | - ''' A Roundup standalone server for Win32 by Ewout Prangsma |
434 | | - ''' |
| 431 | + class RoundupService(win32serviceutil.ServiceFramework): |
| 432 | + |
435 | 433 | _svc_name_ = "Roundup Bug Tracker" |
436 | 434 | _svc_display_name_ = "Roundup Bug Tracker" |
437 | | - def __init__(self, args): |
438 | | - # redirect stdout/stderr to our logfile |
439 | | - if LOGFILE: |
440 | | - # appending, unbuffered |
441 | | - sys.stdout = sys.stderr = open(LOGFILE, 'a', 0) |
442 | | - win32serviceutil.ServiceFramework.__init__(self, args) |
443 | | - BaseHTTPServer.HTTPServer.__init__(self, self.address, |
444 | | - RoundupRequestHandler) |
445 | | - |
446 | | - # Create the necessary NT Event synchronization objects... |
447 | | - # hevSvcStop is signaled when the SCM sends us a notification |
448 | | - # to shutdown the service. |
449 | | - self.hevSvcStop = win32event.CreateEvent(None, 0, 0, None) |
450 | | - |
451 | | - # hevConn is signaled when we have a new incomming connection. |
452 | | - self.hevConn = win32event.CreateEvent(None, 0, 0, None) |
453 | | - |
454 | | - # Hang onto this module for other people to use for logging |
455 | | - # purposes. |
| 435 | + |
| 436 | + running = 0 |
| 437 | + server = None |
| 438 | + |
| 439 | + def SvcDoRun(self): |
456 | 440 | import servicemanager |
457 | | - self.servicemanager = servicemanager |
| 441 | + self.ReportServiceStatus(win32service.SERVICE_START_PENDING) |
| 442 | + config = ServerConfig() |
| 443 | + (optlist, args) = config.getopt(sys.argv[1:]) |
| 444 | + if not config["LOGFILE"]: |
| 445 | + servicemanager.LogMsg(servicemanager.EVENTLOG_ERROR_TYPE, |
| 446 | + servicemanager.PYS_SERVICE_STOPPED, |
| 447 | + (self._svc_display_name_, "\r\nMissing logfile option")) |
| 448 | + self.ReportServiceStatus(win32service.SERVICE_STOPPED) |
| 449 | + return |
| 450 | + self.server = config.get_server() |
| 451 | + self.running = 1 |
| 452 | + self.ReportServiceStatus(win32service.SERVICE_RUNNING) |
| 453 | + servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, |
| 454 | + servicemanager.PYS_SERVICE_STARTED, (self._svc_display_name_, |
| 455 | + " at %s:%s" % (config["HOST"], config["PORT"]))) |
| 456 | + while self.running: |
| 457 | + self.server.handle_request() |
| 458 | + servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, |
| 459 | + servicemanager.PYS_SERVICE_STOPPED, |
| 460 | + (self._svc_display_name_, "")) |
| 461 | + self.ReportServiceStatus(win32service.SERVICE_STOPPED) |
458 | 462 |
|
459 | 463 | def SvcStop(self): |
460 | | - # Before we do anything, tell the SCM we are starting the |
461 | | - # stop process. |
| 464 | + self.running = 0 |
| 465 | + # make dummy connection to self to terminate blocking accept() |
| 466 | + addr = self.server.socket.getsockname() |
| 467 | + if addr[0] == "0.0.0.0": |
| 468 | + addr = ("127.0.0.1", addr[1]) |
| 469 | + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
| 470 | + sock.connect(addr) |
| 471 | + sock.close() |
462 | 472 | self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) |
463 | | - win32event.SetEvent(self.hevSvcStop) |
464 | | - |
465 | | - def SvcDoRun(self): |
466 | | - try: |
467 | | - self.serve_forever() |
468 | | - except SvcShutdown: |
469 | | - pass |
470 | | - |
471 | | - def get_request(self): |
472 | | - # Call WSAEventSelect to enable self.socket to be waited on. |
473 | | - win32file.WSAEventSelect(self.socket, self.hevConn, |
474 | | - win32file.FD_ACCEPT) |
475 | | - while 1: |
476 | | - try: |
477 | | - rv = self.socket.accept() |
478 | | - except socket.error, why: |
479 | | - if why[0] != win32file.WSAEWOULDBLOCK: |
480 | | - raise |
481 | | - # Use WaitForMultipleObjects instead of select() because |
482 | | - # on NT select() is only good for sockets, and not general |
483 | | - # NT synchronization objects. |
484 | | - rc = win32event.WaitForMultipleObjects( |
485 | | - (self.hevSvcStop, self.hevConn), |
486 | | - 0, win32event.INFINITE) |
487 | | - if rc == win32event.WAIT_OBJECT_0: |
488 | | - # self.hevSvcStop was signaled, this means: |
489 | | - # Stop the service! |
490 | | - # So we throw the shutdown exception, which gets |
491 | | - # caught by self.SvcDoRun |
492 | | - raise SvcShutdown |
493 | | - # Otherwise, rc == win32event.WAIT_OBJECT_0 + 1 which means |
494 | | - # self.hevConn was signaled, which means when we call |
495 | | - # self.socket.accept(), we'll have our incoming connection |
496 | | - # socket! |
497 | | - # Loop back to the top, and let that accept do its thing... |
498 | | - else: |
499 | | - # yay! we have a connection |
500 | | - # However... the new socket is non-blocking, we need to |
501 | | - # set it back into blocking mode. (The socket that accept() |
502 | | - # returns has the same properties as the listening sockets, |
503 | | - # this includes any properties set by WSAAsyncSelect, or |
504 | | - # WSAEventSelect, and whether its a blocking socket or not.) |
505 | | - # |
506 | | - # So if you yank the following line, the setblocking() call |
507 | | - # will be useless. The socket will still be in non-blocking |
508 | | - # mode. |
509 | | - win32file.WSAEventSelect(rv[0], self.hevConn, 0) |
510 | | - rv[0].setblocking(1) |
511 | | - break |
512 | | - return rv |
513 | 473 |
|
514 | 474 | def usage(message=''): |
515 | 475 | if RoundupService: |
@@ -621,6 +581,28 @@ def run(port=undefined, success_message=None): |
621 | 581 |
|
622 | 582 | # if running in windows service mode, don't do any other stuff |
623 | 583 | if ("-c", "") in optlist: |
| 584 | + # acquire command line options recognized by service |
| 585 | + short_options = "c:C:" |
| 586 | + long_options = ["config"] |
| 587 | + for (long_name, short_name) in config.OPTIONS.items(): |
| 588 | + short_options += short_name |
| 589 | + long_name = long_name.lower().replace("_", "-") |
| 590 | + if short_name[-1] == ":": |
| 591 | + long_name += "=" |
| 592 | + long_options.append(long_name) |
| 593 | + optlist = getopt.getopt(sys.argv[1:], short_options, long_options)[0] |
| 594 | + svc_args = [] |
| 595 | + for (opt, arg) in optlist: |
| 596 | + if opt in ("-C", "-l"): |
| 597 | + # make sure file name is absolute |
| 598 | + svc_args.extend((opt, os.path.abspath(arg))) |
| 599 | + elif opt in ("--config", "--logfile"): |
| 600 | + # ditto, for long options |
| 601 | + svc_args.append("=".join(opt, os.path.abspath(arg))) |
| 602 | + elif opt != "-c": |
| 603 | + svc_args.extend(opt) |
| 604 | + RoundupService._exe_args_ = " ".join(svc_args) |
| 605 | + # pass the control to serviceutil |
624 | 606 | win32serviceutil.HandleCommandLine(RoundupService, |
625 | 607 | argv=sys.argv[:1] + args) |
626 | 608 | return |
|
0 commit comments