class Instance2InstanceServer(Thread):
    def __init__(self, i2iport, connhandler, timeout=300.0):
        Thread.__init__(self)
        self.setDaemon(True)
        self.setName('Instance2Instance' + self.getName())
        self.i2iport = i2iport
        self.connhandler = connhandler

        print >> sys.stderr, "Instance2Instance binding to %s:%d" % (
            "127.0.0.1", self.i2iport)
        self.i2idoneflag = Event()
        self.rawserver = RawServer(self.i2idoneflag,
                                   timeout / 5.0,
                                   timeout,
                                   ipv6_enable=False,
                                   failfunc=self.rawserver_fatalerrorfunc,
                                   errorfunc=self.rawserver_nonfatalerrorfunc)

        # Only accept local connections
        self.rawserver.bind(self.i2iport, bind=['127.0.0.1'], reuse=True)
        self.rawserver.add_task(self.rawserver_keepalive, 10)

    def rawserver_keepalive(self):
        """ Hack to prevent rawserver sleeping in select() for a long time, not
        processing any tasks on its queue at startup time

        Called by Instance2Instance thread """
        self.rawserver.add_task(self.rawserver_keepalive, 1)

    def shutdown(self):
        self.connhandler.shutdown()
        self.i2idoneflag.set()

    #
    # Following methods are called by Instance2Instance thread
    #
    def rawserver_fatalerrorfunc(self, e):
        """ Called by network thread """
        if DEBUG:
            print >> sys.stderr, "i2is: RawServer fatal error func called", e
        print_exc()

    def rawserver_nonfatalerrorfunc(self, e):
        """ Called by network thread """
        if DEBUG:
            print >> sys.stderr, "i2is: RawServer non fatal error func called", e
            print_exc()
        # Could log this somewhere, or phase it out

    def run(self):

        if prctlimported:
            prctl.set_name("Tribler" + currentThread().getName())

        try:
            try:
                if DEBUG:
                    print >> sys.stderr, "i2is: Ready to receive remote commands on", self.i2iport
                self.rawserver.listen_forever(self)
            except:
                print_exc()
        finally:
            self.rawserver.shutdown()

    def external_connection_made(self, s):
        try:
            if DEBUG:
                print >> sys.stderr, "i2is: external_connection_made"
            self.connhandler.external_connection_made(s)
        except:
            print_exc()
            s.close()

    def connection_flushed(self, s):
        self.connhandler.connection_flushed(s)

    def connection_lost(self, s):
        if DEBUG:
            print >> sys.stderr, "i2is: connection_lost ------------------------------------------------"
        self.connhandler.connection_lost(s)

    def data_came_in(self, s, data):
        try:
            self.connhandler.data_came_in(s, data)
        except:
            print_exc()
            s.close()

    def add_task(self, func, t):
        self.rawserver.add_task(func, t)

    def start_connection(self, dns):
        return self.rawserver.start_connection_raw(dns,
                                                   handler=self.connhandler)