class Timeout:
    def __init__(self, connection):
        self.connection = connection
        self.name = None
        self.request = None
        self.alarm_pending = 0
        self.expiry_time = 0
        return

    def _alarm(self):
        if not self.connection.keptalive:
            self.connection.server.errorLog.info("[client %s] %s timed out" %
                                                (self.connection.remote_ip,
                                                 self.name or "request"))
        if self.request:
            # Someone has asked for this transaction to just be aborted
            # if it times out...
            pass
        else:
            # abort the connection
            self.connection.aborted = 1
        return

    def keepalive(self, name, request):
        if self.keptalive:
            expires = self.server.keepalive_timeout
        else:
            expires = self.server.timeout
        self.timeout.alarm(expires)
        return

class Connection:

    def __init__(self, server, client, remoteAddr, localAddr):
        self.server = server
        self.baseServer = server
        self.client = client
        self.rfile = client.makefile('rb', -1)
        self.wfile = client.makefile('wb', 0)
        self.remote_ip, self.remote_port = remoteAddr
        self.local_ip, self.local_port = localAddr
        self.remote_host = ''
        self.keptalive = 0
        self.keepalive = 1
        self.aborted = 0
        self.timeout = Timeout(self)
        return

    def close(self):
        # Send any leftover data to the client, but never try again
        try:
            self.wfile.flush()
        except:
            pass

        if not self.aborted:
            # Lingering close
            try:
                # Close our half of the connection -- send the client a FIN
                self.client.shutdown(1)

                # Setup to wait for readable data on the socket...

                # Wait for readable data or error condition on socket;
                # slurp up any data that arrives... We exit when we go for
                # an interval of 2 seconds without getting and more data,
                # get an error, get an EOF on a read, or the timer expires.
                while 1:
                    readable = select.select([self.client], [], [], 2)[0]
                    if not readable: break
                    self.rfile.read(512)
            except:
                pass

        # Close all the descriptors
        try:
            self.wfile.close()
        except:
            pass

        try:
            self.rfile.close()
        except:
            pass

        try:
            self.client.close()
        except:
            pass
        return

    def updateVirtualHost(self, request, hostname):
        host = request.hostname or hostname or ''
        if ':' in host:
            try:
                host, port = host.split(':')
            except:
                # too many ':'
                return 0

            try:
                # ensure that the port is numeric
                int(port)
            except:
                return 0

        # sanity check the hostname
        for name in host.split('.'):
            if not name or '/' in name or '\\' in name:
                return 0

        # must set this for HTTP/1.1 support
        request.hostname = host.lower()

        # try to find a matching virtual host
        for server in self.server.virtualHosts:
            if request.hostname in server.names:
                # we found a matching entry
                request.server = self.server = server
                break

        return 1

