[Zope-Checkins] CVS: Zope3/lib/python/Zope/Server - FixedStreamReceiver.py:1.1.4.1 IDispatcher.py:1.1.4.1 IDispatcherEventHandler.py:1.1.4.1 IDispatcherLogging.py:1.1.4.1 IServer.py:1.1.4.1 IServerChannel.py:1.1.4.1 ISocket.py:1.1.4.1 MaxSockets.py:1.1.4.1 ServerChannelBase.py:1.1.4.1 Adjustments.py:1.1.2.5 Buffers.py:1.1.2.4 DualModeChannel.py:1.1.2.5 IHeaderOutput.py:1.1.2.4 IRequestFactory.py:1.1.4.3 IStreamConsumer.py:1.1.2.4 ITask.py:1.1.2.4 ITaskDispatcher.py:1.1.2.3 ServerBase.py:1.1.2.5 TaskThreads.py:1.1.2.9 Utilities.py:1.1.2.4 ZLogIntegration.py:1.1.2.4 __init__.py:1.1.2.6 Chunking.py:NONE HTTPServer.py:NONE PublisherServers.py:NONE

Shane Hathaway shane@cvs.zope.org
Fri, 12 Apr 2002 17:31:26 -0400


Update of /cvs-repository/Zope3/lib/python/Zope/Server
In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Server

Modified Files:
      Tag: Zope-3x-branch
	Adjustments.py Buffers.py DualModeChannel.py IHeaderOutput.py 
	IRequestFactory.py IStreamConsumer.py ITask.py 
	ITaskDispatcher.py ServerBase.py TaskThreads.py Utilities.py 
	ZLogIntegration.py __init__.py 
Added Files:
      Tag: Zope-3x-branch
	FixedStreamReceiver.py IDispatcher.py 
	IDispatcherEventHandler.py IDispatcherLogging.py IServer.py 
	IServerChannel.py ISocket.py MaxSockets.py 
	ServerChannelBase.py 
Removed Files:
      Tag: Zope-3x-branch
	Chunking.py HTTPServer.py PublisherServers.py 
Log Message:
Merged Zope3-Server-Branch.


=== Added File Zope3/lib/python/Zope/Server/FixedStreamReceiver.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""

$Id: FixedStreamReceiver.py,v 1.1.4.1 2002/04/12 21:30:54 shane Exp $
"""

from IStreamConsumer import IStreamConsumer


class FixedStreamReceiver:

    __implements__ = IStreamConsumer

    # See Zope.Server.IStreamConsumer.IStreamConsumer
    completed = 0

    def __init__(self, cl, buf):
        self.remain = cl
        self.buf = buf

    ############################################################
    # Implementation methods for interface
    # Zope.Server.IStreamConsumer

    def received(self, data):
        'See Zope.Server.IStreamConsumer.IStreamConsumer'
        rm = self.remain
        if rm < 1:
            self.completed = 1  # Avoid any chance of spinning
            return 0
        datalen = len(data)
        if rm <= datalen:
            self.buf.append(data[:rm])
            self.remain = 0
            self.completed = 1
            return rm
        else:
            self.buf.append(data)
            self.remain -= datalen
            return datalen

    #
    ############################################################

    def getfile(self):
        return self.buf.getfile()


=== Added File Zope3/lib/python/Zope/Server/IDispatcher.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""

$Id: IDispatcher.py,v 1.1.4.1 2002/04/12 21:30:54 shane Exp $
"""

from ISocket import ISocket
from IDispatcherEventHandler import IDispatcherEventHandler
from IDispatcherLogging import IDispatcherLogging


class IDispatcher(ISocket, IDispatcherEventHandler, IDispatcherLogging):
    """The dispatcher is the most low-level component of a server.

       1. It manages the socket connections and distributes the
          request to the appropriate channel.

       2. It handles the events passed to it, such as reading input,
          writing output and handling errors. More about this
          functionality can be found in IDispatcherEventHandler.

       3. It handles logging of the requests passed to the server as
          well as other informational messages and erros. Please see
          IDispatcherLogging for more details.

       Note: Most of this documentation is taken from the Python
             Library Reference.
    """

    def add_channel(map=None):
        """After the low-level socket connection negotiation is
           completed, a channel is created that handles all requests
           and responses until the end of the connection.
        """

    def del_channel(map=None):
        """Delete a channel. This should include also closing the
           socket to the client.
        """

    def create_socket(family, type):
        """This is identical to the creation of a normal socket, and
           will use the same options for creation. Refer to the socket
           documentation for information on creating sockets.
        """

    def readable():
        """Each time through the select() loop, the set of sockets is
           scanned, and this method is called to see if there is any
           interest in reading. The default method simply returns 1,
           indicating that by default, all channels will be
           interested.
        """

    def writable():
        """Each time through the select() loop, the set of sockets is
           scanned, and this method is called to see if there is any
           interest in writing. The default method simply returns 1,
           indicating that by default, all channels will be
           interested.
        """


=== Added File Zope3/lib/python/Zope/Server/IDispatcherEventHandler.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""

$Id: IDispatcherEventHandler.py,v 1.1.4.1 2002/04/12 21:30:54 shane Exp $
"""

from Interface import Interface


class IDispatcherEventHandler(Interface):
    """The Dispatcher can receive several different types of events. This
       interface describes the necessary methods that handle these common
       event types.
    """

    def handle_read_event():
        """Given a read event, a server has to handle the event and
           read the input from the client.
        """

    def handle_write_event():
        """Given a write event, a server has to handle the event and
           write the output to the client.
        """

    def handle_expt_event():
        """An exception event was handed to the server.
        """

    def handle_error():
        """An error occured, but we are still trying to fix it.
        """

    def handle_expt():
        """Handle unhandled exceptions. This is usually a time to log.
        """

    def handle_read():
        """Read output from client.
        """

    def handle_write():
        """Write output via the socket to the client.
        """

    def handle_connect():
        """A client requests a connection, now we need to do soemthing.
        """

    def handle_accept():
        """A connection is accepted.
        """

    def handle_close():
        """A connection is being closed.
        """


=== Added File Zope3/lib/python/Zope/Server/IDispatcherLogging.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""

$Id: IDispatcherLogging.py,v 1.1.4.1 2002/04/12 21:30:54 shane Exp $
"""

from Interface import Interface


class IDispatcherLogging(Interface):
    """This interface provides methods through which the Dispatcher will
       write its logs. A distinction is made between hit and message logging,
       since they often go to different output types and can have very
       different structure.
    """

    def log (message):
        """Logs general requests made to the server.
        """

    def log_info(message, type='info'):
        """Logs informational messages, warnings and errors.
        """


=== Added File Zope3/lib/python/Zope/Server/IServer.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""

$Id: IServer.py,v 1.1.4.1 2002/04/12 21:30:54 shane Exp $
"""

from Interface import Interface
from Interface.Attribute import Attribute


class IServer(Interface):
    """This interface describes the basic base server.

       The most unusual part about the Zope servers (since they all
       implement this interface or inherit its base class) is that it
       uses a mix of asynchronous and thread-based mechanism to
       serve. While the low-level socket listener uses async, the
       actual request is executed in a thread.  This has the huge
       advantage that if a request takes really long to process, the
       server does not hang at that point to wait for the request to
       finish.
    """

    channel_class = Attribute("""
                        The channel class defines the type of channel
                        to be used by the server. See IServerChannel
                        for more information.
                              """)

    SERVER_IDENT = Attribute("""
                        This string identifies the server. By default
                        this is 'Zope.Server.' and should be
                        overridden.
                        """)



=== Added File Zope3/lib/python/Zope/Server/IServerChannel.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""

$Id: IServerChannel.py,v 1.1.4.1 2002/04/12 21:30:54 shane Exp $
"""

from Interface import Interface
from Interface.Attribute import Attribute

class IServerChannel(Interface):
    """
    """

    parser_class = Attribute("Subclasses must provide a parser class")
    task_class = Attribute("Subclasses must provide a task class.")

    active_channels = Attribute("Class-specific channel tracker")
    next_channel_cleanup = Attribute("Class-specific cleanup time")

    proto_request = Attribute("A request parser instance")
    ready_requests = Attribute("A list of requests to be processed.")
    last_activity = Attribute("Time of last activity")
    running_tasks = Attribute("boolean")


    def queue_request(self, req):
        """Queues a request to be processed in sequence by a task.
        """

    def end_task(self, close):
        """Called at the end of a task, may launch another task.
        """

    def create_task(self, req):
        """Creates a new task and queues it for execution.

        The task may get executed in another thread.
        """



=== Added File Zope3/lib/python/Zope/Server/ISocket.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""

$Id: ISocket.py,v 1.1.4.1 2002/04/12 21:30:54 shane Exp $
"""

from Interface import Interface


class ISocket(Interface):
    """Represents a socket.

       Note: Most of this documentation is taken from the Python Library
             Reference.
    """

    def listen(num):
        """Listen for connections made to the socket. The backlog argument
           specifies the maximum number of queued connections and should
           be at least 1; the maximum value is system-dependent (usually
           5).
        """

    def bind(addr):
        """Bind the socket to address. The socket must not already be bound.
        """

    def connect(address):
        """Connect to a remote socket at address.
        """

    def accept():
        """Accept a connection. The socket must be bound to an address and
           listening for connections. The return value is a pair (conn,
           address) where conn is a new socket object usable to send and
           receive data on the connection, and address is the address
           bound to the socket on the other end of the connection.
        """

    def recv(buffer_size):
        """Receive data from the socket. The return value is a string
           representing the data received. The maximum amount of data
           to be received at once is specified by bufsize. See the
           Unix manual page recv(2) for the meaning of the optional
           argument flags; it defaults to zero.
        """

    def send(data):
        """Send data to the socket. The socket must be connected to a
           remote socket. The optional flags argument has the same
           meaning as for recv() above. Returns the number of bytes
           sent. Applications are responsible for checking that all
           data has been sent; if only some of the data was
           transmitted, the application needs to attempt delivery of
           the remaining data.
        """

    def close():
        """Close the socket. All future operations on the socket
           object will fail. The remote end will receive no more data
           (after queued data is flushed). Sockets are automatically
           closed when they are garbage-collected.
        """


=== Added File Zope3/lib/python/Zope/Server/MaxSockets.py ===
# Medusa max_sockets module.

import socket
import select

# several factors here we might want to test:
# 1) max we can create
# 2) max we can bind
# 3) max we can listen on
# 4) max we can connect

def max_server_sockets():
    sl = []
    while 1:
        try:
            s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
            s.bind (('',0))
            s.listen(5)
            sl.append (s)
        except:
            break
    num = len(sl)
    for s in sl:
        s.close()
    del sl
    return num

def max_client_sockets():
    # make a server socket
    server = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
    server.bind (('', 9999))
    server.listen (5)
    sl = []
    while 1:
        try:
            s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
            s.connect (('', 9999))
            conn, addr = server.accept()
            sl.append ((s,conn))
        except:
            break
    num = len(sl)
    for s,c in sl:
        s.close()
        c.close()
    del sl
    return num

def max_select_sockets():
    sl = []
    while 1:
        try:
            num = len(sl)
            for i in range(1 + len(sl) * 0.05):
                # Increase exponentially.
                s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
                s.bind (('',0))
                s.listen(5)
                sl.append (s)
            select.select(sl,[],[],0)
        except:
            break
    for s in sl:
        s.close()
    del sl
    return num


=== Added File Zope3/lib/python/Zope/Server/ServerChannelBase.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""

$Id: ServerChannelBase.py,v 1.1.4.1 2002/04/12 21:30:54 shane Exp $
"""

import os
import time
import sys
import asyncore
from thread import allocate_lock

# Enable ZOPE_SERVER_SIMULT_MODE to enable experimental
# simultaneous channel mode, which may improve or degrade
# throughput depending on load characteristics.
if os.environ.get('ZOPE_SERVER_SIMULT_MODE'):
    from DualModeChannel import SimultaneousModeChannel as \
         ChannelBaseClass
else:
    from DualModeChannel import DualModeChannel as ChannelBaseClass

from IServerChannel import IServerChannel

# Synchronize access to the "running_tasks" attributes.
running_lock = allocate_lock()


class ServerChannelBase(ChannelBaseClass, object):
    """Base class for a high-performance, mixed-mode server-side channel.
    """

    __implements__ = ChannelBaseClass.__implements__, IServerChannel


    parser_class = None       # Subclasses must provide a parser class
    task_class = None         # ... and a task class.

    active_channels = {}        # Class-specific channel tracker
    next_channel_cleanup = [0]  # Class-specific cleanup time

    proto_request = None      # A request parser instance
    ready_requests = None     # A list
    # ready_requests must always be empty when not running tasks.
    last_activity = 0         # Time of last activity
    running_tasks = 0         # boolean: true when any task is being executed

    #
    # ASYNCHRONOUS METHODS (incl. __init__)
    #

    def __init__(self, server, conn, addr, adj=None):
        ChannelBaseClass.__init__(self, conn, addr, adj)
        self.server = server
        self.last_activity = t = self.creation_time
        self.check_maintenance(t)


    def add_channel(self, map=None):
        """This hook keeps track of opened HTTP channels.
        """
        ChannelBaseClass.add_channel(self, map)
        self.__class__.active_channels[self._fileno] = self


    def del_channel(self, map=None):
        """This hook keeps track of closed HTTP channels.
        """
        ChannelBaseClass.del_channel(self, map)
        ac = self.__class__.active_channels
        fd = self._fileno
        if ac.has_key(fd):
            del ac[fd]


    def check_maintenance(self, now):
        """Performs maintenance if necessary.
        """
        ncc = self.__class__.next_channel_cleanup
        if now < ncc[0]:
            return
        ncc[0] = now + self.adj.cleanup_interval
        self.maintenance()


    def maintenance(self):
        """Kills off dead connections.
        """
        self.kill_zombies()


    def kill_zombies(self):
        """Closes connections that have not had any activity in a while.

        The timeout is configured through adj.channel_timeout (seconds).
        """
        now = time.time()
        cutoff = now - self.adj.channel_timeout
        for channel in self.active_channels.values():
            if (channel is not self and not channel.running_tasks and
                channel.last_activity < cutoff):
                channel.close()


    def received(self, data):
        """Receive input asynchronously and send requests to
        receivedCompleteRequest().
        """
        preq = self.proto_request
        while data:
            if preq is None:
                preq = self.parser_class(self.adj)
            n = preq.received(data)
            if preq.completed:
                # The request is ready to use.
                if not preq.empty:
                    self.receivedCompleteRequest(preq)
                preq = None
                self.proto_request = None
            else:
                self.proto_request = preq
            if n >= len(data):
                break
            data = data[n:]


    def receivedCompleteRequest(self, req):
        """If there are tasks running or requests on hold, queue
        the request, otherwise execute it.
        """
        do_now = 0
        running_lock.acquire()
        try:
            if self.running_tasks:
                # A task thread is working.  It will read from the queue
                # when it is finished.
                rr = self.ready_requests
                if rr is None:
                    rr = []
                    self.ready_requests = rr
                rr.append(req)
            else:
                # Do it now.
                do_now = 1
        finally:
            running_lock.release()
        if do_now:
            task = self.process_request(req)
            if task is not None:
                self.start_task(task)


    def start_task(self, task):
        """Starts the given task.

        *** For thread safety, this should only be called from the main
        (async) thread. ***"""
        if self.running_tasks:
            # Can't start while another task is running!
            # Otherwise two threads would work on the queue at the same time.
            raise RuntimeError, 'Already executing tasks'
        self.running_tasks = 1
        self.set_sync()
        self.server.addTask(task)


    def handle_error(self):
        """Handles program errors (not communication errors)
        """
        t, v = sys.exc_info()[:2]
        if t is SystemExit or t is KeyboardInterrupt:
            raise t, v
        asyncore.dispatcher.handle_error(self)


    def handle_comm_error(self):
        """Handles communication errors (not program errors)
        """
        if self.adj.log_socket_errors:
            self.handle_error()
        else:
            # Ignore socket errors.
            self.close()


    #
    # SYNCHRONOUS METHODS
    #

    def end_task(self, close):
        """Called at the end of a task and may launch another task.
        """
        if close:
            # Note that self.running_tasks is left on, which has the
            # side effect of preventing further requests from being
            # serviced even if more appear.  A good thing.
            self.close_when_done()
            return
        # Process requests held in the queue, if any.
        while 1:
            req = None
            running_lock.acquire()
            try:
                rr = self.ready_requests
                if rr:
                    req = rr.pop(0)
                else:
                    # No requests to process.
                    self.running_tasks = 0
            finally:
                running_lock.release()

            if req is not None:
                task = self.process_request(req)
                if task is not None:
                    # Add the new task.  It will service the queue.
                    self.server.addTask(task)
                    break
                # else check the queue again.
            else:
                # Idle -- Wait for another request on this connection.
                self.set_async()
                break


    #
    # BOTH MODES
    #

    def process_request(self, req):
        """Returns a task to execute or None if the request is quick and
        can be processed in the main thread.

        Override to handle some requests in the main thread.
        """
        return self.task_class(self, req)




=== Zope3/lib/python/Zope/Server/Adjustments.py 1.1.2.4 => 1.1.2.5 ===
+# Copyright 2001-2002 Zope Corporation and Contributors.  All Rights Reserved.
 #
-# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
-# 
 # This software is subject to the provisions of the Zope Public License,
 # Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
 # FOR A PARTICULAR PURPOSE.
-# 
-##############################################################################
-from medusa.test import max_sockets
+
+import MaxSockets
 
 
 class Adjustments:
+    """This class contains tunable communication parameters.
+
+    You can either change default_adj to adjust parameters for
+    all sockets, or you can create a new instance of this class,
+    change its attributes, and pass it to the channel constructors.
+    """
 
     # backlog is the argument to pass to socket.listen().
     backlog = 1024
@@ -25,6 +27,9 @@
     # send_bytes is the number of bytes to send to socket.send().
     send_bytes = 8192
 
+    # copy_bytes is the number of bytes to copy from one file to another.
+    copy_bytes = 65536
+
     # Create a tempfile if the pending output data gets larger
     # than outbuf_overflow.  With RAM so cheap, this probably
     # ought to be set to the 16-32 MB range (circa 2001) for
@@ -37,7 +42,7 @@
     inbuf_overflow = 525000
 
     # Stop accepting new connections if too many are already active.
-    connection_limit = max_sockets.max_select_sockets() - 3  # Safe
+    connection_limit = MaxSockets.max_select_sockets() - 3  # Safe
 
     # Minimum seconds between cleaning up inactive channels.
     cleanup_interval = 300
@@ -45,7 +50,7 @@
     # Maximum seconds to leave an inactive connection open.
     channel_timeout = 900
 
-    # Boolean: turn off to ignore premature client disconnects.
+    # Boolean: turn off to not log premature client disconnects.
     log_socket_errors = 1
 
 


=== Zope3/lib/python/Zope/Server/Buffers.py 1.1.2.3 => 1.1.2.4 ===
+# Copyright 2001-2002 Zope Corporation and Contributors.  All Rights Reserved.
 #
-# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
-# 
 # This software is subject to the provisions of the Zope Public License,
 # Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
 # FOR A PARTICULAR PURPOSE.
-# 
-##############################################################################
+
+
 try:
     from cStringIO import StringIO
 except ImportError:


=== Zope3/lib/python/Zope/Server/DualModeChannel.py 1.1.2.4 => 1.1.2.5 ===
 # Copyright (c) 2001, 2002 Zope Corporation and Contributors.
 # All Rights Reserved.
-# 
+#
 # This software is subject to the provisions of the Zope Public License,
 # Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
 # FOR A PARTICULAR PURPOSE.
-# 
+#
 ##############################################################################
+"""
+
+$Id$
+"""
+
 import asyncore
 import socket
 from time import time
 from UserDict import UserDict
 
-from medusa.thread import select_trigger
+from Thread import SelectTrigger
 from Adjustments import default_adj
 from Buffers import OverflowableBuffer
 
 
 # Create the main trigger if it doesn't exist yet.
-if select_trigger.the_trigger is None:
-    select_trigger.the_trigger = select_trigger.trigger()
-
-
-class AlternateSocketMapMixin:
-    """Mixin for asyncore.dispatcher to more easily support
-    alternate socket maps"""
-
-    socket_map = None
+if SelectTrigger.the_trigger is None:
+    SelectTrigger.the_trigger = SelectTrigger.Trigger()
 
-    def add_channel(self, map=None):
-        if map is None:
-            map = self.socket_map
-        asyncore.dispatcher.add_channel(self, map)
-
-    def del_channel(self, map=None):
-        if map is None:
-            map = self.socket_map
-        asyncore.dispatcher.del_channel(self, map)
-
-    def pull_trigger(self):
-        pull_trigger = getattr(self.socket_map, 'pull_trigger', None)
-        if pull_trigger is not None:
-            # Use the trigger from the socket map.
-            pull_trigger()
-        else:
-            select_trigger.the_trigger.pull_trigger()
 
 
-class ASMTrigger (AlternateSocketMapMixin, select_trigger.trigger):
-    """Trigger for an alternate socket map"""
-
-    def __init__(self, socket_map):
-        self.socket_map = socket_map
-        select_trigger.trigger.__init__(self)
-
-    pull_trigger = select_trigger.trigger.pull_trigger
-
-
-class SocketMapWithTrigger (UserDict):
-
-    def __init__(self):
-        UserDict.__init__(self)
-        self.pull_trigger = ASMTrigger(self).pull_trigger
+class DualModeChannel(asyncore.dispatcher):
+    """Channel that switches between asynchronous and synchronous mode.
 
+    Call set_sync() before using a channel in a thread other than
+    the thread handling the main loop.
 
-class DualModeChannel (AlternateSocketMapMixin, asyncore.dispatcher):
-    """Channel that switches between asynchronous and synchronous mode.
+    Call set_async() to give the channel back to the thread handling
+    the main loop.
     """
 
+    __implements__ = asyncore.dispatcher.__implements__
+
     # will_close is set to 1 to close the socket.
     will_close = 0
 
     # boolean: async or sync mode
     async_mode = 1
 
-    def __init__(self, server, conn, addr, adj=None, socket_map=None):
-        self.server = server
+    def __init__(self, conn, addr, adj=None):
         self.addr = addr
         if adj is None:
             adj = default_adj
         self.adj = adj
-        self.socket_map = socket_map
         self.outbuf = OverflowableBuffer(adj.outbuf_overflow)
         self.creation_time = time()
         asyncore.dispatcher.__init__(self, conn)
@@ -163,20 +133,26 @@
             self.outbuf.append(data)
         while len(self.outbuf) >= self.adj.send_bytes:
             # Send what we can without blocking.
-            # We propogate errors to the application on purpose
-            # (to prevent unnecessary work).
+            # We propagate errors to the application on purpose
+            # (to stop the application if the connection closes).
             if not self._flush_some():
                 break
 
-    def flush(self):
-        """
-        Pauses the application while outbuf is flushed.
-        Normally not a good thing to do.
+    def flush(self, block=1):
+        """Sends pending data.
+
+        If block is set, this pauses the application.  If it is turned
+        off, only the amount of data that can be sent without blocking
+        is sent.
         """
+        if not block:
+            while self._flush_some():
+                pass
+            return
         blocked = 0
         try:
             while self.outbuf:
-                # We propogate errors to the application on purpose.
+                # We propagate errors to the application on purpose.
                 if not blocked:
                     self.socket.setblocking(1)
                     blocked = 1
@@ -197,9 +173,17 @@
     # METHODS USED IN BOTH MODES
     #
 
+    def pull_trigger(self):
+        """Wakes up the main loop.
+        """
+        SelectTrigger.the_trigger.pull_trigger()
+
     def _flush_some(self):
+        """Flushes data.
+
+        Returns 1 if some data was sent."""
         outbuf = self.outbuf
-        if outbuf:
+        if outbuf and self.connected:
             chunk = outbuf.get(self.adj.send_bytes)
             num_sent = self.send(chunk)
             if num_sent:
@@ -208,19 +192,16 @@
         return 0
 
     def close_when_done(self):
-        if self.async_mode:
-            self.will_close = 1
-            self.pull_trigger()
+        # We might be able close immediately.
+        while self._flush_some():
+            pass
+        if not self.outbuf:
+            # Quick exit.
+            self.close()
         else:
-            # We might be able close immediately.
-            while self._flush_some():
-                pass
-            if not self.outbuf:
-                # Quick exit.
-                self.close()
-            else:
-                # Wait until outbuf is flushed.
-                self.will_close = 1
+            # Wait until outbuf is flushed.
+            self.will_close = 1
+            if not self.async_mode:
                 self.async_mode = 1
                 self.pull_trigger()
 
@@ -237,16 +218,21 @@
     and fill the input buffer.
     """
 
-    def __init__(self, server, conn, addr, adj=None, socket_map=None):
+    __implements__ = asyncore.dispatcher.__implements__
+
+
+    def __init__(self, conn, addr, adj=None):
         global allocate_lock
         if allocate_lock is None:
             from thread import allocate_lock
 
+        # writelock protects all accesses to outbuf, since reads and
+        # writes of buffers in this class need to be serialized.
         writelock = allocate_lock()
         self._writelock_acquire = writelock.acquire
         self._writelock_release = writelock.release
         self._writelock_locked = writelock.locked
-        DualModeChannel.__init__(self, server, conn, addr, adj, socket_map)
+        DualModeChannel.__init__(self, conn, addr, adj)
 
     #
     # ASYNCHRONOUS METHODS
@@ -285,10 +271,10 @@
         finally:
             self._writelock_release()
 
-    def flush(self):
+    def flush(self, block=1):
         self._writelock_acquire()
         try:
-            DualModeChannel.flush(self)
+            DualModeChannel.flush(self, block)
         finally:
             self._writelock_release()
 


=== Zope3/lib/python/Zope/Server/IHeaderOutput.py 1.1.2.3 => 1.1.2.4 ===
+# Copyright 2001-2002 Zope Corporation and Contributors.  All Rights Reserved.
 #
-# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
-# 
 # This software is subject to the provisions of the Zope Public License,
 # Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
 # FOR A PARTICULAR PURPOSE.
-# 
-##############################################################################
+
+
 from Interface import Interface
 
 


=== Zope3/lib/python/Zope/Server/IRequestFactory.py 1.1.4.2 => 1.1.4.3 ===
 # Copyright (c) 2001, 2002 Zope Corporation and Contributors.
 # All Rights Reserved.
-# 
+#
 # This software is subject to the provisions of the Zope Public License,
 # Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-# 
+# FOR A PARTICULAR PURPOSE
+#
 ##############################################################################
 """
 
@@ -30,4 +30,4 @@
         """
 
 
-        
+


=== Zope3/lib/python/Zope/Server/IStreamConsumer.py 1.1.2.3 => 1.1.2.4 ===
+# Copyright 2001-2002 Zope Corporation and Contributors.  All Rights Reserved.
 #
-# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
-# 
 # This software is subject to the provisions of the Zope Public License,
 # Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
 # FOR A PARTICULAR PURPOSE.
-# 
-##############################################################################
+
+
 from Interface import Interface
 from Interface.Attribute import Attribute
 
@@ -18,7 +15,7 @@
     """Consumes a data stream until reaching a completion point.
 
     The actual amount to be consumed might not be known ahead of time.
-    """    
+    """
 
     def received(data):
         """Accepts data, returning the number of bytes consumed."""


=== Zope3/lib/python/Zope/Server/ITask.py 1.1.2.3 => 1.1.2.4 ===
+# Copyright 2001-2002 Zope Corporation and Contributors.  All Rights Reserved.
 #
-# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
-# 
 # This software is subject to the provisions of the Zope Public License,
 # Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
 # FOR A PARTICULAR PURPOSE.
-# 
-##############################################################################
+
+
 from Interface import Interface
 
 


=== Zope3/lib/python/Zope/Server/ITaskDispatcher.py 1.1.2.2 => 1.1.2.3 ===
+# Copyright 2001-2002 Zope Corporation and Contributors.  All Rights Reserved.
 #
-# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
-# 
 # This software is subject to the provisions of the Zope Public License,
 # Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
 # FOR A PARTICULAR PURPOSE.
-# 
-##############################################################################
+
+
 from Interface import Interface
 
 class ITaskDispatcher (Interface):


=== Zope3/lib/python/Zope/Server/ServerBase.py 1.1.2.4 => 1.1.2.5 ===
 # Copyright (c) 2001, 2002 Zope Corporation and Contributors.
 # All Rights Reserved.
-# 
+#
 # This software is subject to the provisions of the Zope Public License,
 # Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
 # FOR A PARTICULAR PURPOSE.
-# 
+#
 ##############################################################################
-import os
+"""
+
+$Id$
+"""
+
 import asyncore
 import socket
-import time
-import sys
-from thread import allocate_lock
 
-from DualModeChannel import AlternateSocketMapMixin
-from IStreamConsumer import IStreamConsumer
 from Adjustments import default_adj
 
+from IServer import IServer
 
-# Enable ZOPE_SERVER_SIMULT_MODE to enable experimental
-# simultaneous channel mode, which may improve or degrade
-# throughput depending on load characteristics.
-if os.environ.get('ZOPE_SERVER_SIMULT_MODE'):
-    from DualModeChannel import SimultaneousModeChannel as \
-         channel_base_class
-else:
-    from DualModeChannel import DualModeChannel as channel_base_class
-
-
-
-class FixedStreamReceiver:
-
-    __implements__ = IStreamConsumer
-
-    completed = 0
-
-    def __init__(self, cl, buf):
-        self.remain = cl
-        self.buf = buf
-
-    def received(self, data):
-        rm = self.remain
-        if rm < 1:
-            self.completed = 1  # Avoid any chance of spinning
-            return 0
-        datalen = len(data)
-        if rm <= datalen:
-            self.buf.append(data[:rm])
-            self.remain = 0
-            self.completed = 1
-            return rm
-        else:
-            self.buf.append(data)
-            self.remain -= datalen
-            return datalen
-
-    def getfile(self):
-        return self.buf.getfile()
-
-
-
-# Synchronize access to the "running_tasks" attributes.
-running_lock = allocate_lock()
-
-
-
-class ServerChannelBase (channel_base_class):
-    """Base class for a high-performance, mixed-mode server-side channel.
-    """
-
-    parser_class = None       # Subclasses must provide a parser class
-    task_class = None         # ... and a task class.
-
-    active_channels = {}        # Class-specific channel tracker
-    next_channel_cleanup = [0]  # Class-specific cleanup time
 
-    proto_request = None      # A request parser instance
-    ready_requests = None     # A list
-    last_activity = 0         # Time of last activity
-    running_tasks = 0         # boolean: true when any task is being executed
-
-    #
-    # ASYNCHRONOUS METHODS (incl. __init__)
-    #
-
-    def __init__(self, server, conn, addr, adj=None, socket_map=None):
-        channel_base_class.__init__(self, server, conn, addr, adj, socket_map)
-        self.last_activity = t = self.creation_time
-        self.check_maintenance(t)
-
-    def add_channel(self, map=None):
-        """This hook keeps track of opened HTTP channels.
-        """
-        channel_base_class.add_channel(self, map)
-        self.active_channels[self._fileno] = self
-
-    def del_channel(self, map=None):
-        """This hook keeps track of closed HTTP channels.
-        """
-        channel_base_class.del_channel(self, map)
-        ac = self.active_channels
-        fd = self._fileno
-        if ac.has_key(fd):
-            del ac[fd]
-
-    def check_maintenance(self, now):
-        """Performs maintenance if necessary.
-        """
-        if now < self.next_channel_cleanup[0]:
-            return
-        self.next_channel_cleanup[0] = now + self.adj.cleanup_interval
-        self.maintenance()
-
-    def maintenance(self):
-        """Kills off dead connections.
-        """
-        self.kill_zombies()
-
-    def kill_zombies(self):
-        """Closes connections that have not had any activity in a while.
-
-        The timeout is configured through adj.channel_timeout (seconds).
-        """
-        now = time.time()
-        cutoff = now - self.adj.channel_timeout
-        for channel in self.active_channels.values():
-            if (channel is not self and not channel.running_tasks and
-                channel.last_activity < cutoff):
-                channel.close()
-
-    def received(self, data):
-        """Receives input asynchronously and launches or queues requests.
-        """
-        preq = self.proto_request
-        while data:
-            if preq is None:
-                preq = self.parser_class(self.adj)
-            n = preq.received(data)
-            if preq.completed:
-                # The request is ready to use.
-                if not preq.empty:
-                    self.queue_request(preq)
-                preq = None
-                self.proto_request = None
-            else:
-                self.proto_request = preq
-            if n >= len(data):
-                break
-            data = data[n:]
-
-    def queue_request(self, req):
-        """Queues a request to be processed in sequence.
-        """
-        do_now = 0
-        running_lock.acquire()
-        try:
-            if self.running_tasks:
-                # Wait for the current tasks to finish.
-                rr = self.ready_requests
-                if rr is None:
-                    rr = []
-                    self.ready_requests = rr
-                rr.append(req)
-            else:
-                # Do it now.
-                self.running_tasks = 1
-                do_now = 1
-        finally:
-            running_lock.release()
-        if do_now:
-            self.process_request(req)
-
-    def handle_error(self):
-        """Handles program errors (not communication errors)
-        """
-        t, v = sys.exc_info()[:2]
-        if t is SystemExit or t is KeyboardInterrupt:
-            raise t, v
-        asyncore.dispatcher.handle_error(self)
-
-    def handle_comm_error(self):
-        """Handles communication errors (not program errors)
-        """
-        if self.adj.log_socket_errors:
-            self.handle_error()
-        else:
-            # Ignore socket errors.
-            self.close()
-
-    #
-    # SYNCHRONOUS METHODS
-    #
-
-    def end_task(self, close):
-        """Called at the end of a task and may launch another task.
-        """
-        if close:
-            self.close_when_done()
-            return
-        new_req = None
-        running_lock.acquire()
-        try:
-            rr = self.ready_requests
-            if rr:
-                new_req = rr.pop(0)
-            else:
-                # No requests to service.
-                self.running_tasks = 0
-        finally:
-            running_lock.release()
-        if new_req:
-            # Respond to the next request.
-            self.process_request(new_req)
-        else:
-            # Wait for another request on this connection.
-            self.set_async()
-
-    #
-    # BOTH MODES
-    #
-
-    def process_request(self, req):
-        """Creates a new task and queues it for execution.
-
-        The task may get executed in another thread.
-        """
-        self.set_sync()
-        task = self.task_class(self, req)
-        self.server.addTask(task)
-
-
-
-
-
-class ServerBase (AlternateSocketMapMixin, asyncore.dispatcher):
+class ServerBase(asyncore.dispatcher, object):
     """Async. server base for launching derivatives of ServerChannelBase.
     """
 
+    __implements__ = asyncore.dispatcher.__implements__, IServer
+
     channel_class = None    # Override with a channel class.
     SERVER_IDENT = 'Zope.Server.ServerBase'  # Override.
 
     def __init__(self, ip, port, task_dispatcher=None, adj=None, start=1,
-                 hit_log=None, verbose=0, socket_map=None):
+                 hit_log=None, verbose=0):
         if adj is None:
             adj = default_adj
         self.adj = adj
-        self.socket_map = socket_map
         asyncore.dispatcher.__init__(self)
         self.port = port
         self.task_dispatcher = task_dispatcher
@@ -296,23 +83,40 @@
                 self.port
                 ))
 
+
+    def addTask(self, task):
+        td = self.task_dispatcher
+        if td is not None:
+            td.addTask(task)
+        else:
+            task.service()
+
+    ############################################################
+    # Implementation methods for interface
+    # Zope.Server.IDispatcher.IDispatcher
+
     def readable(self):
+        'See Zope.Server.IDispatcher.IDispatcher'
         return (self.accepting and
                 len(asyncore.socket_map) < self.adj.connection_limit)
 
-    def writable (self):
+    def writable(self):
+        'See Zope.Server.IDispatcher.IDispatcher'
         return 0
-        
-    def handle_read (self):
+
+    ######################################
+    # from: Zope.Server.IDispatcherEventHandler.IDispatcherEventHandler
+
+    def handle_read(self):
+        'See Zope.Server.IDispatcherEventHandler.IDispatcherEventHandler'
         pass
-        
-    def readable (self):
-        return self.accepting
-        
-    def handle_connect (self):
+
+    def handle_connect(self):
+        'See Zope.Server.IDispatcherEventHandler.IDispatcherEventHandler'
         pass
 
-    def handle_accept (self):
+    def handle_accept(self):
+        'See Zope.Server.IDispatcherEventHandler.IDispatcherEventHandler'
         try:
             v = self.accept()
             if v is None:
@@ -327,12 +131,8 @@
                 self.log_info ('warning: server accept() threw an exception',
                                'warning')
             return
-        self.channel_class(self, conn, addr, self.adj, self.socket_map)
+        self.channel_class(self, conn, addr, self.adj)
 
-    def addTask(self, task):
-        td = self.task_dispatcher
-        if td is not None:
-            td.addTask(task)
-        else:
-            task.service()
+    #
+    ############################################################
 


=== Zope3/lib/python/Zope/Server/TaskThreads.py 1.1.2.8 => 1.1.2.9 ===
+# Copyright 2001-2002 Zope Corporation and Contributors.  All Rights Reserved.
 #
-# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
-# 
 # This software is subject to the provisions of the Zope Public License,
 # Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
 # FOR A PARTICULAR PURPOSE.
-# 
-##############################################################################
+
+
 import sys
 from Queue import Queue, Empty
 from thread import allocate_lock, start_new_thread


=== Zope3/lib/python/Zope/Server/Utilities.py 1.1.2.3 => 1.1.2.4 ===
+# Copyright 2001-2002 Zope Corporation and Contributors.  All Rights Reserved.
 #
-# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
-# 
 # This software is subject to the provisions of the Zope Public License,
 # Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
 # FOR A PARTICULAR PURPOSE.
-# 
-##############################################################################
+
+
 def find_double_newline(s):
     """Returns the position just after a double newline in the given string."""
     pos1 = s.find('\n\r\n')  # One kind of double newline


=== Zope3/lib/python/Zope/Server/ZLogIntegration.py 1.1.2.3 => 1.1.2.4 ===
+# Copyright 2001-2002 Zope Corporation and Contributors.  All Rights Reserved.
 #
-# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
-# 
 # This software is subject to the provisions of the Zope Public License,
 # Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
 # FOR A PARTICULAR PURPOSE.
-# 
-##############################################################################
 """Makes asyncore log to zLOG.
 """
 


=== Zope3/lib/python/Zope/Server/__init__.py 1.1.2.5 => 1.1.2.6 ===
 # Copyright (c) 2001, 2002 Zope Corporation and Contributors.
 # All Rights Reserved.
-# 
+#
 # This software is subject to the provisions of the Zope Public License,
 # Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
 # FOR A PARTICULAR PURPOSE.
-# 
+#
 ##############################################################################
 """
 Zope.Server package.
-"""
-
-
-
 
+$Id$
+"""
 
-### A routine to try to arrange for request sockets to be closed
-### on exec. This makes it easier for folks who spawn long running
-### processes from Zope code. Thanks to Dieter Maurer for this.
-##try:
-##    import fcntl, FCNTL
-##    FCNTL.F_SETFD; FCNTL.FD_CLOEXEC
-##    def requestCloseOnExec(sock):
-##        try:    fcntl.fcntl(sock.fileno(), FCNTL.F_SETFD, FCNTL.FD_CLOEXEC)
-##        except: pass
-
-##except (ImportError, AttributeError):
-
-##    def requestCloseOnExec(sock):
-##        pass
+from IDispatcher import IDispatcher
+from Interface.Implements import implements
 
-##import asyncore
-##from medusa import resolver, logger
-##from HTTPServer import zhttp_server, zhttp_handler
-##from PubCore import setNumberOfThreads
-##from medusa.monitor import secure_monitor_server
+import asyncore
 
-### override the service name in logger.syslog_logger
-##logger.syslog_logger.svc_name='ZServer'
+implements(asyncore.dispatcher, IDispatcher, 0)
 

=== Removed File Zope3/lib/python/Zope/Server/Chunking.py ===

=== Removed File Zope3/lib/python/Zope/Server/HTTPServer.py ===

=== Removed File Zope3/lib/python/Zope/Server/PublisherServers.py ===