~ubuntu-branches/ubuntu/natty/moin/natty-updates

« back to all changes in this revision

Viewing changes to MoinMoin/support/flup/server/singleserver.py

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Smedegaard
  • Date: 2008-06-22 21:17:13 UTC
  • mto: This revision was merged to the branch mainline in revision 18.
  • Revision ID: james.westby@ubuntu.com-20080622211713-inlv5k4eifxckelr
ImportĀ upstreamĀ versionĀ 1.7.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (c) 2005 Allan Saddi <allan@saddi.com>
2
 
# All rights reserved.
3
 
#
4
 
# Redistribution and use in source and binary forms, with or without
5
 
# modification, are permitted provided that the following conditions
6
 
# are met:
7
 
# 1. Redistributions of source code must retain the above copyright
8
 
#    notice, this list of conditions and the following disclaimer.
9
 
# 2. Redistributions in binary form must reproduce the above copyright
10
 
#    notice, this list of conditions and the following disclaimer in the
11
 
#    documentation and/or other materials provided with the distribution.
12
 
#
13
 
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14
 
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
 
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16
 
# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17
 
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18
 
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19
 
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20
 
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21
 
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22
 
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23
 
# SUCH DAMAGE.
24
 
#
25
 
# $Id$
26
 
 
27
 
__author__ = 'Allan Saddi <allan@saddi.com>'
28
 
__version__ = '$Revision$'
29
 
 
30
 
import sys
31
 
import socket
32
 
import select
33
 
import signal
34
 
import errno
35
 
 
36
 
try:
37
 
    import fcntl
38
 
except ImportError:
39
 
    def setCloseOnExec(sock):
40
 
        pass
41
 
else:
42
 
    def setCloseOnExec(sock):
43
 
        fcntl.fcntl(sock.fileno(), fcntl.F_SETFD, fcntl.FD_CLOEXEC)
44
 
 
45
 
__all__ = ['SingleServer']
46
 
 
47
 
class SingleServer(object):
48
 
    def __init__(self, jobClass=None, jobArgs=(), **kw):
49
 
        self._jobClass = jobClass
50
 
        self._jobArgs = jobArgs
51
 
 
52
 
    def run(self, sock, timeout=1.0):
53
 
        """
54
 
        The main loop. Pass a socket that is ready to accept() client
55
 
        connections. Return value will be True or False indiciating whether
56
 
        or not the loop was exited due to SIGHUP.
57
 
        """
58
 
        # Set up signal handlers.
59
 
        self._keepGoing = True
60
 
        self._hupReceived = False
61
 
 
62
 
        # Might need to revisit this?
63
 
        if not sys.platform.startswith('win'):
64
 
            self._installSignalHandlers()
65
 
 
66
 
        # Set close-on-exec
67
 
        setCloseOnExec(sock)
68
 
        
69
 
        # Main loop.
70
 
        while self._keepGoing:
71
 
            try:
72
 
                r, w, e = select.select([sock], [], [], timeout)
73
 
            except select.error, e:
74
 
                if e[0] == errno.EINTR:
75
 
                    continue
76
 
                raise
77
 
 
78
 
            if r:
79
 
                try:
80
 
                    clientSock, addr = sock.accept()
81
 
                except socket.error, e:
82
 
                    if e[0] in (errno.EINTR, errno.EAGAIN):
83
 
                        continue
84
 
                    raise
85
 
 
86
 
                setCloseOnExec(clientSock)
87
 
                
88
 
                if not self._isClientAllowed(addr):
89
 
                    clientSock.close()
90
 
                    continue
91
 
 
92
 
                # Hand off to Connection.
93
 
                conn = self._jobClass(clientSock, addr, *self._jobArgs)
94
 
                conn.run()
95
 
 
96
 
            self._mainloopPeriodic()
97
 
 
98
 
        # Restore signal handlers.
99
 
        self._restoreSignalHandlers()
100
 
 
101
 
        # Return bool based on whether or not SIGHUP was received.
102
 
        return self._hupReceived
103
 
 
104
 
    def _mainloopPeriodic(self):
105
 
        """
106
 
        Called with just about each iteration of the main loop. Meant to
107
 
        be overridden.
108
 
        """
109
 
        pass
110
 
 
111
 
    def _exit(self, reload=False):
112
 
        """
113
 
        Protected convenience method for subclasses to force an exit. Not
114
 
        really thread-safe, which is why it isn't public.
115
 
        """
116
 
        if self._keepGoing:
117
 
            self._keepGoing = False
118
 
            self._hupReceived = reload
119
 
 
120
 
    def _isClientAllowed(self, addr):
121
 
        """Override to provide access control."""
122
 
        return True
123
 
 
124
 
    # Signal handlers
125
 
 
126
 
    def _hupHandler(self, signum, frame):
127
 
        self._hupReceived = True
128
 
        self._keepGoing = False
129
 
 
130
 
    def _intHandler(self, signum, frame):
131
 
        self._keepGoing = False
132
 
 
133
 
    def _installSignalHandlers(self):
134
 
        supportedSignals = [signal.SIGINT, signal.SIGTERM]
135
 
        if hasattr(signal, 'SIGHUP'):
136
 
            supportedSignals.append(signal.SIGHUP)
137
 
 
138
 
        self._oldSIGs = [(x,signal.getsignal(x)) for x in supportedSignals]
139
 
 
140
 
        for sig in supportedSignals:
141
 
            if hasattr(signal, 'SIGHUP') and sig == signal.SIGHUP:
142
 
                signal.signal(sig, self._hupHandler)
143
 
            else:
144
 
                signal.signal(sig, self._intHandler)
145
 
 
146
 
    def _restoreSignalHandlers(self):
147
 
        for signum,handler in self._oldSIGs:
148
 
            signal.signal(signum, handler)
149
 
 
150
 
if __name__ == '__main__':
151
 
    class TestJob(object):
152
 
        def __init__(self, sock, addr):
153
 
            self._sock = sock
154
 
            self._addr = addr
155
 
        def run(self):
156
 
            print "Client connection opened from %s:%d" % self._addr
157
 
            self._sock.send('Hello World!\n')
158
 
            self._sock.setblocking(1)
159
 
            self._sock.recv(1)
160
 
            self._sock.close()
161
 
            print "Client connection closed from %s:%d" % self._addr
162
 
    sock = socket.socket()
163
 
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
164
 
    sock.bind(('', 8080))
165
 
    sock.listen(socket.SOMAXCONN)
166
 
    SingleServer(jobClass=TestJob).run(sock)