Example #1
0
    def read(self, fd):
        if not self.watcher:
            return
        w = self.watcher
        # doRead can cause self.shutdown to be called so keep
        # a reference to self.watcher

        def _read():
            #Don't call me again, until the data has been read
            self.notifier.setEnabled(False)
            why = None
            try:
                why = w.doRead()
                inRead = True
            except:
                inRead = False
                log.err()
                why = sys.exc_info()[1]
            if why:
                self.reactor._disconnectSelectable(w, why, inRead)
            elif self.watcher:
                self.notifier.setEnabled(True)
                # Re enable notification following sucessfull read
            self.reactor._iterate(fromqt=True)
        log.callWithLogger(w, _read)
Example #2
0
    def doWaitForMultipleEvents(self, timeout, reads=reads, writes=writes):
        log.msg(channel="system", event="iteration", reactor=self)
        if timeout is None:
            # timeout = INFINITE
            timeout = 100
        else:
            timeout = int(timeout * 1000)

        if not (events or writes):
            # sleep so we don't suck up CPU time
            time.sleep(timeout / 1000.0)
            return

        canDoMoreWrites = 0
        for fd in writes.keys():
            if log.callWithLogger(fd, self._runWrite, fd):
                canDoMoreWrites = 1

        if canDoMoreWrites:
            timeout = 0

        handles = events.keys() or [self.dummyEvent]
        val = MsgWaitForMultipleObjects(handles, 0, timeout, QS_ALLINPUT | QS_ALLEVENTS)
        if val == WAIT_TIMEOUT:
            return
        elif val == WAIT_OBJECT_0 + len(handles):
            exit = win32gui.PumpWaitingMessages()
            if exit:
                self.callLater(0, self.stop)
                return
        elif val >= WAIT_OBJECT_0 and val < WAIT_OBJECT_0 + len(handles):
            fd, action = events[handles[val - WAIT_OBJECT_0]]
            log.callWithLogger(fd, self._runAction, action, fd)
 def ssh_CHANNEL_OPEN(self, packet):
     channelType, rest = common.getNS(packet)
     senderChannel, windowSize, maxPacket = struct.unpack('>3L', rest[: 12])
     packet = rest[12:]
     try:
         channel = self.getChannel(channelType, windowSize, maxPacket, packet)
         localChannel = self.localChannelID
         self.localChannelID+=1
         channel.id = localChannel
         self.channels[localChannel] = channel
         self.channelsToRemoteChannel[channel] = senderChannel
         self.localToRemoteChannel[localChannel] = senderChannel
         self.transport.sendPacket(MSG_CHANNEL_OPEN_CONFIRMATION, 
             struct.pack('>4L', senderChannel, localChannel, 
                 channel.localWindowSize, 
                 channel.localMaxPacket)+channel.specificData)
         log.callWithLogger(channel, channel.channelOpen, '')
     except Exception, e:
         log.msg('channel open failed')
         log.err(e)
         if isinstance(e, error.ConchError):
             reason, textualInfo = e.args[0], e.data
         else:
             reason = OPEN_CONNECT_FAILED
             textualInfo = "unknown failure"
         self.transport.sendPacket(MSG_CHANNEL_OPEN_FAILURE, 
                             struct.pack('>2L', senderChannel, reason)+ \
                            common.NS(textualInfo)+common.NS(''))
Example #4
0
    def doRead(self):
        """
        Some data is available for reading on ZeroMQ descriptor.

        ZeroMQ is signalling that we should process some events,
        we're starting to receive incoming messages.

        Implementation of :tm:`IReadDescriptor
        <internet.interfaces.IReadDescriptor>`.
        """
        if self.read_scheduled is not None:
            if not self.read_scheduled.called:
                self.read_scheduled.cancel()
            self.read_scheduled = None

        while True:
            if self.factory is None:  # disconnected
                return

            events = self.socket.get(constants.EVENTS)

            if (events & constants.POLLIN) != constants.POLLIN:
                return

            try:
                message = self._readMultipart()
            except error.ZMQError as e:
                if e.errno == constants.EAGAIN:
                    continue

                raise e

            log.callWithLogger(self, self.messageReceived, message)
 def ssh_CHANNEL_FAILURE(self, packet):
     localChannel = struct.unpack('>L', packet[: 4])[0]
     if self.deferreds.get(localChannel):
         d = self.deferreds[localChannel].pop(0)
         log.callWithLogger(self.channels[localChannel],
                            d.errback, 
                            error.ConchError('channel request failed'))
    def doKEvent(self, timeout):
        """
        Poll the kqueue for new events.
        """
        if timeout is None:
            timeout = 1

        try:
            events = self._kq.control([], len(self._selectables), timeout)
        except OSError as e:
            # Since this command blocks for potentially a while, it's possible
            # EINTR can be raised for various reasons (for example, if the user
            # hits ^C).
            if e.errno == errno.EINTR:
                return
            else:
                raise

        _drdw = self._doWriteOrRead
        for event in events:
            fd = event.ident
            try:
                selectable = self._selectables[fd]
            except KeyError:
                # Handles the infrequent case where one selectable's
                # handler disconnects another.
                continue
            else:
                log.callWithLogger(selectable, _drdw, selectable, fd, event)
Example #7
0
    def doPoll(self, timeout):
        """
        Poll the poller for new events.
        """
        if timeout is None:
            timeout = -1  # Wait indefinitely.

        try:
            # Limit the number of events to the number of io objects we're
            # currently tracking (because that's maybe a good heuristic) and
            # the amount of time we block to the value specified by our
            # caller.
            l = self._poller.poll(timeout, len(self._selectables))
        except IOError as err:
            if err.errno == errno.EINTR:
                return
            # See epoll_wait(2) for documentation on the other conditions
            # under which this can fail.  They can only be due to a serious
            # programming error on our part, so let's just announce them
            # loudly.
            raise

        _drdw = self._doReadOrWrite
        for fd, event in l:
            try:
                selectable = self._selectables[fd]
            except KeyError:
                pass
            else:
                log.callWithLogger(selectable, _drdw, selectable, fd, event)
Example #8
0
 def dataReceived(self, data):
     self.buf = self.buf+data
     if not self.gotVersion:
         parts = self.buf.split('\n')
         for p in parts:
             if p[: 4] == 'SSH-':
                 self.gotVersion = 1
                 self.otherVersionString = p.strip()
                 if p.split('-')[1]not in('1.99', '2.0'): # bad version
                     self.sendDisconnect(DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED, 'bad version %s'%p.split('-')[1])
                     return
                 i = parts.index(p)
                 self.buf = '\n'.join(parts[i+1:])
     packet = self.getPacket()
     while packet:
         messageNum = ord(packet[0])
         if messageNum < 50:
             messageType = messages[messageNum][4:]
             f = getattr(self, 'ssh_%s'%messageType, None)
             if f:
                 f(packet[1:])
             else:
                 log.msg("couldn't handle %s"%messageType)
                 log.msg(repr(packet[1:]))
                 self.sendUnimplemented()
         elif self.service:
             log.callWithLogger(self.service, self.service.packetReceived,
                                              ord(packet[0]), packet[1:])
         else:
             log.msg("couldn't handle %s"%messageNum)
             log.msg(repr(packet[1:]))
             self.sendUnimplemented()
         packet = self.getPacket()
Example #9
0
File: base.py Project: jdb/twisted
 def disconnectAll(self):
     """Disconnect every reader, and writer in the system.
     """
     selectables = self.removeAll()
     for reader in selectables:
         log.callWithLogger(reader, reader.connectionLost,
                            failure.Failure(main.CONNECTION_LOST))
Example #10
0
    def doKEvent(self, timeout):
        """
        Poll the kqueue for new events.
        """
        if timeout is None:
            timeout = 1

        try:
            l = self._kq.control([], len(self._selectables), timeout)
        except OSError as e:
            if e[0] == errno.EINTR:
                return
            else:
                raise

        _drdw = self._doWriteOrRead
        for event in l:
            fd = event.ident
            try:
                selectable = self._selectables[fd]
            except KeyError:
                # Handles the infrequent case where one selectable's
                # handler disconnects another.
                continue
            else:
                log.callWithLogger(selectable, _drdw, selectable, fd, event)
    def ssh_CHANNEL_DATA(self, packet):
        """
        The other side is sending us data.  Payload::
            uint32 local channel number
            string data

        Check to make sure the other side hasn't sent too much data (more
        than what's in the window, or more than the maximum packet size).  If
        they have, close the channel.  Otherwise, decrease the available
        window and pass the data to the channel's dataReceived().
        """
        localChannel, dataLength = struct.unpack('>2L', packet[:8])
        channel = self.channels[localChannel]
        # XXX should this move to dataReceived to put client in charge?
        if (dataLength > channel.localWindowLeft or
           dataLength > channel.localMaxPacket): # more data than we want
            log.callWithLogger(channel, log.msg, 'too much data')
            self.sendClose(channel)
            return
            #packet = packet[:channel.localWindowLeft+4]
        data = common.getNS(packet[4:])[0]
        channel.localWindowLeft -= dataLength
        if channel.localWindowLeft < channel.localWindowSize / 2:
            self.adjustWindow(channel, channel.localWindowSize - \
                                       channel.localWindowLeft)
            #log.msg('local window left: %s/%s' % (channel.localWindowLeft,
            #                                    channel.localWindowSize))
        log.callWithLogger(channel, channel.dataReceived, data)
    def ssh_CHANNEL_EXTENDED_DATA(self, packet):
        """
        The other side is sending us exteneded data.  Payload::
            uint32  local channel number
            uint32  type code
            string  data

        Check to make sure the other side hasn't sent too much data (more
        than what's in the window, or or than the maximum packet size).  If
        they have, close the channel.  Otherwise, decrease the available
        window and pass the data and type code to the channel's
        extReceived().
        """
        localChannel, typeCode, dataLength = struct.unpack('>3L', packet[:12])
        channel = self.channels[localChannel]
        if (dataLength > channel.localWindowLeft or
                dataLength > channel.localMaxPacket):
            log.callWithLogger(channel, log.msg, 'too much extdata')
            self.sendClose(channel)
            return
        data = common.getNS(packet[8:])[0]
        channel.localWindowLeft -= dataLength
        if channel.localWindowLeft < channel.localWindowSize / 2:
            self.adjustWindow(channel, channel.localWindowSize -
                                       channel.localWindowLeft)
        log.callWithLogger(channel, channel.extReceived, typeCode, data)
Example #13
0
 def _ioEventCallback(self, source, condition):
     """
     Called by event loop when an I/O event occurs.
     """
     log.callWithLogger(
         source, self._doReadOrWrite, source, source, condition)
     return True  # True = don't auto-remove the source
Example #14
0
 def _invoke_callback(self, fd, events):
     if fd not in self._fds:
         return
     (reader, writer) = self._fds[fd]
     if reader:
         err = None
         if reader.fileno() == -1:
             err = error.ConnectionLost()
         elif events & IOLoop.READ:
             err = log.callWithLogger(reader, reader.doRead)
         if err is None and events & IOLoop.ERROR:
             err = error.ConnectionLost()
         if err is not None:
             self.removeReader(reader)
             reader.readConnectionLost(failure.Failure(err))
     if writer:
         err = None
         if writer.fileno() == -1:
             err = error.ConnectionLost()
         elif events & IOLoop.WRITE:
             err = log.callWithLogger(writer, writer.doWrite)
         if err is None and events & IOLoop.ERROR:
             err = error.ConnectionLost()
         if err is not None:
             self.removeWriter(writer)
             writer.writeConnectionLost(failure.Failure(err))
 def ssh_CHANNEL_OPEN_FAILURE(self, packet):
     localChannel, reasonCode = struct.unpack('>2L', packet[: 8])
     reasonDesc = common.getNS(packet[8:])[0]
     channel = self.channels[localChannel]
     del self.channels[localChannel]
     channel.conn = self
     reason = error.ConchError(reasonDesc, reasonCode)
     log.callWithLogger(channel, channel.openFailed, reason)
Example #16
0
 def _runPendingEvents(self, pending_events):
     # pending_events is a list of (fd, mode) pairs.
     while pending_events:
         fd, mode = pending_events.pop()
         if fd in self._selectables:
             selectable = self._selectables[fd]
             log.callWithLogger(selectable,
                     self._doReadOrWrite, fd, mode, selectable)
 def ssh_CHANNEL_CLOSE(self, packet):
     localChannel = struct.unpack('>L', packet[: 4])[0]
     channel = self.channels[localChannel]
     if channel.remoteClosed:
         return
     log.callWithLogger(channel, channel.closeReceived)
     channel.remoteClosed = 1
     if channel.localClosed and channel.remoteClosed:
         self.channelClosed(channel)
 def ssh_CHANNEL_OPEN_CONFIRMATION(self, packet):
     localChannel, remoteChannel, windowSize, maxPacket = struct.unpack('>4L', packet[: 16])
     specificData = packet[16:]
     channel = self.channels[localChannel]
     channel.conn = self
     self.localToRemoteChannel[localChannel] = remoteChannel
     self.channelsToRemoteChannel[channel] = remoteChannel
     channel.remoteWindowLeft = windowSize
     channel.remoteMaxPacket = maxPacket
     log.callWithLogger(channel, channel.channelOpen, specificData)
    def ssh_CHANNEL_EOF(self, packet):
        """
        The other side is not sending any more data.  Payload::
            uint32  local channel number

        Notify the channel by calling its eofReceived() method.
        """
        localChannel = struct.unpack('>L', packet[:4])[0]
        channel = self.channels[localChannel]
        log.callWithLogger(channel, channel.eofReceived)
Example #20
0
        def resolve_cb(result):
            if add_service:
                method = protocol.addService

            else:
                # remove the service from the list before calling back the proto
                _registered_services.remove(info)
                method = protocol.removeService

            # call it with the reader instance to make things cleaner
            log.callWithLogger(reader, method, info)
 def _cbGotChannel(self, channel, senderChannel, packet):
     localChannel = self.localChannelID
     self.localChannelID += 1
     channel.id = localChannel
     self.channels[localChannel] = channel
     self.channelsToRemoteChannel[channel] = senderChannel
     self.localToRemoteChannel[localChannel] = senderChannel
     self.transport.sendPacket(connection.MSG_CHANNEL_OPEN_CONFIRMATION,
         struct.pack('>4L', senderChannel, localChannel,
             channel.localWindowSize,
             channel.localMaxPacket)+channel.specificData)
     log.callWithLogger(channel, channel.channelOpen, packet)
    def ssh_CHANNEL_WINDOW_ADJUST(self, packet):
        """
        The other side is adding bytes to its window.  Payload::
            uint32  local channel number
            uint32  bytes to add

        Call the channel's addWindowBytes() method to add new bytes to the
        remote window.
        """
        localChannel, bytesToAdd = struct.unpack('>2L', packet[:8])
        channel = self.channels[localChannel]
        log.callWithLogger(channel, channel.addWindowBytes, bytesToAdd)
    def ssh_CHANNEL_SUCCESS(self, packet):
        """
        Our channel request to the other other side succeeded.  Payload::
            uint32  local channel number

        Get the C{Deferred} out of self.deferreds and call it back.
        """
        localChannel = struct.unpack('>L', packet[:4])[0]
        if self.deferreds.get(localChannel):
            d = self.deferreds[localChannel].pop(0)
            log.callWithLogger(self.channels[localChannel],
                               d.callback, '')
Example #24
0
	def read(self, sock):
		w = self.watcher
		def _read():
			why = None
			try:
				why = w.doRead()
			except:
				log.err()
				why = exc_info()[1]
			if why:
				self.reactor._disconnectSelectable(w, why, True)
		log.callWithLogger(w, _read)
		self.reactor.simulate()
Example #25
0
	def write(self, sock):
		w = self.watcher
		def _write():
			why = None
			try:
				why = w.doWrite()
			except:
				log.err()
				why = exc_info()[1]
			if why:
				self.reactor._disconnectSelectable(w, why, False)
		log.callWithLogger(w, _write)
		self.reactor.simulate()
 def ssh_CHANNEL_EXTENDED_DATA(self, packet):
     localChannel, typeCode, dataLength = struct.unpack('>3L', packet[: 12])
     channel = self.channels[localChannel]
     if dataLength > channel.localWindowLeft or \
        dataLength > channel.localMaxPacket:
         log.callWithLogger(channel, lambda s=self,c=channel: 
                             log.msg('too much extdata') and s.sendClose(c))
         return
     data = common.getNS(packet[8:])[0]
     channel.localWindowLeft -= dataLength
     if channel.localWindowLeft < channel.localWindowSize/2:
         self.adjustWindow(channel, channel.localWindowSize - \
                                    channel.localWindowLeft)
     log.callWithLogger(channel, channel.extReceived, typeCode, data)
 def channelClosed(self, channel):
     """
     Called when a channel is closed.
     It clears the local state related to the channel, and calls 
     channel.closed().
     MAKE SURE YOU CALL THIS METHOD, even if you subclass L{SSHConnection}.
     If you don't, things will break mysteriously.
     """
     channel.localClosed = channel.remoteClosed = 1
     del self.localToRemoteChannel[channel.id]
     del self.channels[channel.id]
     del self.channelsToRemoteChannel[channel]
     self.deferreds[channel.id] = []
     log.callWithLogger(channel, channel.closed)
    def ssh_CHANNEL_FAILURE(self, packet):
        """
        Our channel request to the other side failed.  Payload::
            uint32  local channel number

        Get the C{Deferred} out of self.deferreds and errback it with a
        C{error.ConchError}.
        """
        localChannel = struct.unpack('>L', packet[:4])[0]
        if self.deferreds.get(localChannel):
            d = self.deferreds[localChannel].pop(0)
            log.callWithLogger(self.channels[localChannel],
                               d.errback,
                               error.ConchError('channel request failed'))
    def disconnectAll(self):
        """Disconnect every reader, and writer in the system.
        """
        selectables = self.removeAll()
        for reader in selectables:
            log.callWithLogger(reader,
                               reader.connectionLost,
                               failure.Failure(main.CONNECTION_LOST))
        mdata = {
            'event':'disconnectAll' ,
            'msg' : 'Disconnect every reader, and writer in the system.' ,
            'level' : 'critical'
        }

        sender.send(str(mdata) , MONITOR_ADDR)     
    def ssh_CHANNEL_CLOSE(self, packet):
        """
        The other side is closing its end; it does not want to receive any
        more data.  Payload::
            uint32  local channel number

        Notify the channnel by calling its closeReceived() method.  If
        the channel has also sent a close message, call self.channelClosed().
        """
        localChannel = struct.unpack('>L', packet[:4])[0]
        channel = self.channels[localChannel]
        log.callWithLogger(channel, channel.closeReceived)
        channel.remoteClosed = True
        if channel.localClosed and channel.remoteClosed:
            self.channelClosed(channel)
Example #31
0
    def doRead(self):
        """
        Some data is available for reading on your descriptor.

        ZeroMQ is signalling that we should process some events,
        we're starting to send queued messages and to receive
        incoming messages.

        Note that the ZeroMQ FD is used in an edge-triggered manner.
        Consequently, this function must read all pending messages
        before returning.

        Part of L{IReadDescriptor}.
        """
        if self._ctx is None:  # disconnected
            return

        while self._queue and self._zsock is not None:
            try:
                self._zsock.send_multipart(self._queue[0], constants.NOBLOCK)
                self._queue.popleft()
            except error.ZMQError as e:
                if e.errno == constants.EAGAIN:
                    break
                raise e

        while self._zsock is not None:
            try:
                msg_list = self._zsock.recv_multipart(constants.NOBLOCK)
                log.callWithLogger(self, self.messageReceived, msg_list)
            except error.ZMQError as e:
                if e.errno == constants.EAGAIN:
                    break

                # This exception can be thrown during socket closing process
                if e.errno == 156384763 or str(
                        e
                ) == 'Operation cannot be accomplished in current state':
                    break

                # Seen in 3.2 for an unknown reason
                if e.errno == 95:
                    break

                raise e
Example #32
0
    def ssh_CHANNEL_OPEN(self, packet):
        """
        The other side wants to get a channel.  Payload::
            string  channel name
            uint32  remote channel number
            uint32  remote window size
            uint32  remote maximum packet size
            <channel specific data>

        We get a channel from self.getChannel(), give it a local channel number
        and notify the other side.  Then notify the channel by calling its
        channelOpen method.
        """
        channelType, rest = common.getNS(packet)
        senderChannel, windowSize, maxPacket = struct.unpack('>3L', rest[:12])
        packet = rest[12:]
        try:
            channel = self.getChannel(channelType, windowSize, maxPacket,
                                      packet)
            localChannel = self.localChannelID
            self.localChannelID += 1
            channel.id = localChannel
            self.channels[localChannel] = channel
            self.channelsToRemoteChannel[channel] = senderChannel
            self.localToRemoteChannel[localChannel] = senderChannel
            self.transport.sendPacket(
                MSG_CHANNEL_OPEN_CONFIRMATION,
                struct.pack('>4L', senderChannel, localChannel,
                            channel.localWindowSize, channel.localMaxPacket) +
                channel.specificData)
            log.callWithLogger(channel, channel.channelOpen, packet)
        except Exception as e:
            log.err(e, 'channel open failed')
            if isinstance(e, error.ConchError):
                textualInfo, reason = e.args
                if isinstance(textualInfo, (int, long)):
                    # See #3657 and #3071
                    textualInfo, reason = reason, textualInfo
            else:
                reason = OPEN_CONNECT_FAILED
                textualInfo = "unknown failure"
            self.transport.sendPacket(
                MSG_CHANNEL_OPEN_FAILURE,
                struct.pack('>2L', senderChannel, reason) +
                common.NS(networkString(textualInfo)) + common.NS(b''))
Example #33
0
    def channelClosed(self, channel):
        """
        Called when a channel is closed.
        It clears the local state related to the channel, and calls
        channel.closed().
        MAKE SURE YOU CALL THIS METHOD, even if you subclass L{SSHConnection}.
        If you don't, things will break mysteriously.

        @type channel: L{SSHChannel}
        """
        if channel in self.channelsToRemoteChannel:  # actually open
            channel.localClosed = channel.remoteClosed = True
            del self.localToRemoteChannel[channel.id]
            del self.channels[channel.id]
            del self.channelsToRemoteChannel[channel]
            for d in self.deferreds.pop(channel.id, []):
                d.errback(error.ConchError("Channel closed."))
            log.callWithLogger(channel, channel.closed)
Example #34
0
    def write(self, sock):
        w = self.watcher
        self.setEnabled(False)

        def _write():
            why = None
            try:
                why = w.doWrite()
            except:
                log.err()
                why = sys.exc_info()[1]
            if why:
                self.reactor._disconnectSelectable(w, why, False)
            elif self.watcher:
                self.setEnabled(True)

        log.callWithLogger(w, _write)
        self.reactor.reactorInvocation()
Example #35
0
 def ssh_CHANNEL_DATA(self, packet):
     localChannel, dataLength = struct.unpack('>2L', packet[:8])
     channel = self.channels[localChannel]
     # XXX should this move to dataReceived to put client in charge?
     if dataLength > channel.localWindowLeft or \
        dataLength > channel.localMaxPacket: # more data than we want
         log.callWithLogger(channel,
                            lambda s=self, c=channel: log.msg(
                                'too much data') and s.sendClose(c))
         return
         #packet = packet[:channel.localWindowLeft+4]
     data = common.getNS(packet[4:])[0]
     channel.localWindowLeft -= dataLength
     if channel.localWindowLeft < channel.localWindowSize / 2:
         self.adjustWindow(channel, channel.localWindowSize - \
                                    channel.localWindowLeft)
         #log.msg('local window left: %s/%s' % (channel.localWindowLeft,
         #                                    channel.localWindowSize))
     log.callWithLogger(channel, channel.dataReceived, data)
Example #36
0
 def write(self, sock):
     if not self.watcher:
         return
     w = self.watcher
     def _write():
         why = None
         self.notifier.setEnabled(False)
         
         try:
             why = w.doWrite()
         except:
             log.err()
             why = sys.exc_info()[1]
         if why:
             self.reactor._disconnectSelectable(w, why, False)
         elif self.watcher:
             self.notifier.setEnabled(True)
         self.reactor._iterate(fromqt=True)
     log.callWithLogger(w, _write)
Example #37
0
    def write(self, sock):
        self.notifier.setEnabled(False)
        if not self.watcher:
            return
        w = self.watcher

        def _write():
            try:
                data = w.doWrite()
                if data:
                    self.qt_reactor._disconnectSelectable(w, data, False)
                elif self.watcher:
                    self.notifier.setEnabled(True)
            except:
                log.err()
                self.qt_reactor._disconnectSelectable(w, sys.exc_info()[1], False)
            self.qt_reactor._iterate(None, fromqt=True)

        log.callWithLogger(w, _write)
Example #38
0
    def doIteration(self, timeout):
        """
        Poll the IO completion port for new events.
        """
        # This function sits and waits for an IO completion event.
        #
        # There are two requirements: process IO events as soon as they arrive
        # and process ctrl-break from the user in a reasonable amount of time.
        #
        # There are three kinds of waiting.
        # 1) GetQueuedCompletionStatus (self.port.getEvent) to wait for IO
        # events only.
        # 2) Msg* family of wait functions that can stop waiting when
        # ctrl-break is detected (then, I think, Python converts it into a
        # KeyboardInterrupt)
        # 3) *Ex family of wait functions that put the thread into an
        # "alertable" wait state which is supposedly triggered by IO completion
        #
        # 2) and 3) can be combined. Trouble is, my IO completion is not
        # causing 3) to trigger, possibly because I do not use an IO completion
        # callback. Windows is weird.
        # There are two ways to handle this. I could use MsgWaitForSingleObject
        # here and GetQueuedCompletionStatus in a thread. Or I could poll with
        # a reasonable interval. Guess what! Threads are hard.

        processed_events = 0
        if timeout is None:
            timeout = MAX_TIMEOUT
        else:
            timeout = min(MAX_TIMEOUT, int(1000 * timeout))
        rc, numBytes, key, evt = self.port.getEvent(timeout)
        while 1:
            if rc == WAIT_TIMEOUT:
                break
            if key != KEY_WAKEUP:
                assert key == KEY_NORMAL
                log.callWithLogger(
                    evt.owner, self._callEventCallback, rc, numBytes, evt
                )
                processed_events += 1
            if processed_events >= EVENTS_PER_LOOP:
                break
            rc, numBytes, key, evt = self.port.getEvent(0)
Example #39
0
def setup(reactor, latency_func):
    import sys

    if sys.platform != 'linux2': return

    from twisted.internet import epollreactor
    from twisted.python import log
    import errno, time

    global g_latency_func
    g_latency_func = latency_func

    assert isinstance(reactor, epollreactor.EPollReactor)
    if 1:
        print 'installing EPollReactor latency measurement wrapper'

        def mypoll(self, timeout):
            if timeout is None:
                timeout = -1  # Wait indefinitely.
            try:
                if hasattr(self._poller, 'poll'):
                    # NEW python API
                    l = self._poller.poll(timeout, len(self._selectables))
                else:
                    # OLD twisted implementation
                    l = self._poller.wait(len(self._selectables), int(1000*timeout))
            except IOError, err:
                if err.errno == errno.EINTR:
                    return
                raise
            _drdw = self._doReadOrWrite
            start_time = time.time()
            for fd, event in l:
                try:
                    selectable = self._selectables[fd]
                except KeyError:
                    pass
                else:
                    log.callWithLogger(selectable, _drdw, selectable, fd, event)
            end_time = time.time()
            g_latency_func('ALL', end_time - start_time)

        epollreactor.EPollReactor.doIteration = mypoll
Example #40
0
    def read(self, sock):
        w = self.watcher

        #self.setEnabled(False)    # ??? do I need this?
        def _read():
            why = None
            try:
                why = w.doRead()
            except:
                log.err()
                why = sys.exc_info()[1]
            if why:
                self.reactor._disconnectSelectable(w, why, True)
            elif self.watcher:
                pass
                #self.setEnabled(True)

        log.callWithLogger(w, _read)
        self.reactor.reactorInvocation()
Example #41
0
 def _invoke_callback(self, handle, events, poll_error):
     reader, writer = self._fds[handle.fileno()]
     if reader:
         err = None
         if reader.fileno() == -1:
             err = error.ConnectionLost()
         elif events & pyuv.UV_READABLE or poll_error is not None:
             err = log.callWithLogger(reader, reader.doRead)
         if err is not None:
             self.removeReader(reader)
             reader.readConnectionLost(failure.Failure(err))
     if writer:
         err = None
         if writer.fileno() == -1:
             err = error.ConnectionLost()
         elif events & pyuv.UV_WRITABLE or poll_error is not None:
             err = log.callWithLogger(writer, writer.doWrite)
         if err is not None:
             self.removeWriter(writer)
             writer.writeConnectionLost(failure.Failure(err))
Example #42
0
 def run(self, save=1, installSignalHandlers=1):
     """run(save=1, installSignalHandlers=1)
     Run this application, running the main loop if necessary.
     If 'save' is true, then when this Application is shut down, it
     will be persisted to a pickle.
     'installSignalHandlers' is passed through to reactor.run(), the
     function that starts the mainloop.
     """
     from twisted.internet import reactor
     if not self._boundPorts:
         self.bindPorts()
     self._save = save
     reactor.addSystemEventTrigger('before', 'shutdown',
                                   self._beforeShutDown)
     reactor.addSystemEventTrigger('after', 'shutdown', self._afterShutDown)
     global theApplication
     theApplication = self
     log.callWithLogger(self,
                        reactor.run,
                        installSignalHandlers=installSignalHandlers)
Example #43
0
    def doPoll(self, timeout):
        """Poll the poller for new events."""
        if timeout is not None:
            timeout = int(timeout * 1000)  # convert seconds to milliseconds

        try:
            l = self._poller.poll(timeout)
        except SelectError as e:
            if e.args[0] == errno.EINTR:
                return
            else:
                raise
        _drdw = self._doReadOrWrite
        for fd, event in l:
            try:
                selectable = self._selectables[fd]
            except KeyError:
                # Handles the infrequent case where one selectable's
                # handler disconnects another.
                continue
            log.callWithLogger(selectable, _drdw, selectable, fd, event)
Example #44
0
    def read(self, fd):
        self.notifier.setEnabled(False)
        if not self.watcher:
            return
        w = self.watcher
        # doRead can cause self.shutdown to be called so keep a
        # reference to self.watcher

        def _read():
            try:
                data = w.doRead()
                if data:
                    self.qt_reactor._disconnectSelectable(w, data, True)
                elif self.watcher:
                    self.notifier.setEnabled(True)
            except:
                log.err()
                self.qt_reactor._disconnectSelectable(w, sys.exc_info()[1], False)
            self.qt_reactor._iterate(None, fromqt=True)

        log.callWithLogger(w, _read)
Example #45
0
    def doRead(self):
        """
        Some data is available for reading on your descriptor.

        ZeroMQ is signalling that we should process some events.

        Part of L{IReadDescriptor}.
        """
        events = self.socket.getsockopt(constants.EVENTS)
        if (events & constants.POLLIN) == constants.POLLIN:
            while True:
                try:
                    message = self._readMultipart()
                except error.ZMQError as e:
                    if e.errno == constants.EAGAIN:
                        break

                    raise e

                log.callWithLogger(self, self.messageReceived, message)
        if (events & constants.POLLOUT) == constants.POLLOUT:
            self._startWriting()
Example #46
0
 def read(self, fd):
     if not self.watcher:
         return
     w = self.watcher
     # doRead can cause self.shutdown to be called so keep a reference to self.watcher
     def _read():
         #Don't call me again, until the data has been read
         self.notifier.setEnabled(False)
         why = None
         try:
             why = w.doRead()
             inRead = True
         except:
             inRead = False
             log.err()
             why = sys.exc_info()[1]
         if why:
             self.reactor._disconnectSelectable(w, why, inRead)
         elif self.watcher:
             self.notifier.setEnabled(True) # Re enable notification following sucessfull read
         self.reactor._iterate(fromqt=True)
     log.callWithLogger(w, _read)
Example #47
0
    def ssh_CHANNEL_OPEN_CONFIRMATION(self, packet):
        """
        The other side accepted our MSG_CHANNEL_OPEN request.  Payload::
            uint32  local channel number
            uint32  remote channel number
            uint32  remote window size
            uint32  remote maximum packet size
            <channel specific data>

        Find the channel using the local channel number and notify its
        channelOpen method.
        """
        (localChannel, remoteChannel, windowSize,
         maxPacket) = struct.unpack('>4L', packet[:16])
        specificData = packet[16:]
        channel = self.channels[localChannel]
        channel.conn = self
        self.localToRemoteChannel[localChannel] = remoteChannel
        self.channelsToRemoteChannel[channel] = remoteChannel
        channel.remoteWindowLeft = windowSize
        channel.remoteMaxPacket = maxPacket
        log.callWithLogger(channel, channel.channelOpen, specificData)
Example #48
0
    def doRead(self):
        """
        Some data is available for reading on ZeroMQ descriptor.

        ZeroMQ is signalling that we should process some events,
        we're starting to receive incoming messages.

        Implementation of :class:`IReadDescriptor
        <twisted.internet.interfaces.IReadDescriptor>`.
        """
        if self.shutted_down:
            return
        if self.read_scheduled is not None:
            if not self.read_scheduled.called:
                self.read_scheduled.cancel()
            self.read_scheduled = None

        unpickler = ZmqConnection.Unpickler()
        while True:
            if self.factory is None:  # disconnected
                return

            events = self.socket.get(constants.EVENTS)

            if (events & constants.POLLIN) != constants.POLLIN:
                return

            timestamp = time.time()
            try:
                message = self._readMultipart(unpickler)
            except error.ZMQError as e:
                if e.errno == constants.EAGAIN:
                    continue

                raise e
            finally:
                self._last_read_time = time.time() - timestamp
            log.callWithLogger(self, self.messageReceived, message)
Example #49
0
    def dispatchMessage(self, messageNum, payload):
        """
        Send a received message to the appropriate method.

        @type messageNum: C{int}
        @type payload: c{str}
        """
        if messageNum < 50 and messageNum in messages:
            messageType = messages[messageNum][4:]
            f = getattr(self, 'ssh_%s' % messageType, None)
            if f is not None:
                f(payload)
            else:
                log.msg("couldn't handle %s" % messageType)
                log.msg(repr(payload))
                self.sendUnimplemented()
        elif self.service:
            log.callWithLogger(self.service, self.service.packetReceived,
                               messageNum, payload)
        else:
            log.msg("couldn't handle %s" % messageNum)
            log.msg(repr(payload))
            self.sendUnimplemented()
Example #50
0
 def _invoke_callback(self, fd, events):
     (reader, writer) = self._fds[fd]
     if reader:
         err = None
         if reader.fileno() == -1:
             err = error.ConnectionLost()
         elif events & IOLoop.READ:
             err = log.callWithLogger(reader, reader.doRead)
         if err is None and events & IOLoop.ERROR:
             err = error.ConnectionLost()
         if err is not None:
             self.removeReader(reader)
             reader.readConnectionLost(failure.Failure(err))
     if writer:
         err = None
         if writer.fileno() == -1:
             err = error.ConnectionLost()
         elif events & IOLoop.WRITE:
             err = log.callWithLogger(writer, writer.doWrite)
         if err is None and events & IOLoop.ERROR:
             err = error.ConnectionLost()
         if err is not None:
             self.removeWriter(writer)
             writer.writeConnectionLost(failure.Failure(err))
Example #51
0
    def doPoll(self,
               timeout,
               reads=reads,
               writes=writes,
               selectables=selectables,
               select=select,
               log=log,
               POLLIN=select.POLLIN,
               POLLOUT=select.POLLOUT):
        """Poll the poller for new events."""

        if timeout is not None:
            timeout = int(timeout * 1000 +
                          1)  # convert seconds to milliseconds

        try:
            l = poller.poll(timeout)
            if l is None:
                if self.running:
                    self.stop()
                l = []
        except select.error as e:
            if e[0] == errno.EINTR:
                return
            else:
                raise
        _drdw = self._doReadOrWrite
        for fd, event in l:
            try:
                selectable = selectables[fd]
            except KeyError:
                # Handles the infrequent case where one selectable's
                # handler disconnects another.
                continue
            log.callWithLogger(selectable, _drdw, selectable, fd, event,
                               POLLIN, POLLOUT, log)
Example #52
0
 def ssh_CHANNEL_REQUEST(self, packet):
     localChannel = struct.unpack('>L', packet[:4])[0]
     requestType, rest = common.getNS(packet[4:])
     wantReply = ord(rest[0])
     channel = self.channels[localChannel]
     d = log.callWithLogger(channel, channel.requestReceived, requestType,
                            rest[1:])
     if wantReply:
         if isinstance(d, defer.Deferred):
             d.addCallback(self._cbChannelRequest, localChannel)
             d.addErrback(self._ebChannelRequest, localChannel)
         elif d:
             self._cbChannelRequest(None, localChannel)
         else:
             self._ebChannelRequest(None, localChannel)
Example #53
0
def log(message):
    if len(tlog.theLogPublisher.observers) == 1:
        print '[status.py] %s' % message
    else:
        tlog.callWithLogger(StatusLogger, tlog.msg, message)
Example #54
0
 def callback(self, source, condition):
     log.callWithLogger(source, self._doReadOrWrite, source, condition)
     self.simulate()  # fire Twisted timers
     return 1  # 1=don't auto-remove the source
Example #55
0
class PollReactor(posixbase.PosixReactorBase):
    """
    A reactor that uses poll(2).

    @ivar _poller: A L{poll} which will be used to check for I/O
        readiness.

    @ivar _selectables: A dictionary mapping integer file descriptors to
        instances of L{FileDescriptor} which have been registered with the
        reactor.  All L{FileDescriptors} which are currently receiving read or
        write readiness notifications will be present as values in this
        dictionary.

    @ivar _reads: A dictionary mapping integer file descriptors to arbitrary
        values (this is essentially a set).  Keys in this dictionary will be
        registered with C{_poller} for read readiness notifications which will
        be dispatched to the corresponding L{FileDescriptor} instances in
        C{_selectables}.

    @ivar _writes: A dictionary mapping integer file descriptors to arbitrary
        values (this is essentially a set).  Keys in this dictionary will be
        registered with C{_poller} for write readiness notifications which will
        be dispatched to the corresponding L{FileDescriptor} instances in
        C{_selectables}.
    """
    implements(IReactorFDSet)

    def __init__(self):
        """
        Initialize polling object, file descriptor tracking dictionaries, and
        the base class.
        """
        self._poller = poll()
        self._selectables = {}
        self._reads = {}
        self._writes = {}
        posixbase.PosixReactorBase.__init__(self)

    def _updateRegistration(self, fd):
        """Register/unregister an fd with the poller."""
        try:
            self._poller.unregister(fd)
        except KeyError:
            pass

        mask = 0
        if fd in self._reads:
            mask = mask | POLLIN
        if fd in self._writes:
            mask = mask | POLLOUT
        if mask != 0:
            self._poller.register(fd, mask)
        else:
            if fd in self._selectables:
                del self._selectables[fd]

    def _dictRemove(self, selectable, mdict):
        try:
            # the easy way
            fd = selectable.fileno()
            # make sure the fd is actually real.  In some situations we can get
            # -1 here.
            mdict[fd]
        except:
            # the hard way: necessary because fileno() may disappear at any
            # moment, thanks to python's underlying sockets impl
            for fd, fdes in self._selectables.items():
                if selectable is fdes:
                    break
            else:
                # Hmm, maybe not the right course of action?  This method can't
                # fail, because it happens inside error detection...
                return
        if fd in mdict:
            del mdict[fd]
            self._updateRegistration(fd)

    def addReader(self, reader):
        """Add a FileDescriptor for notification of data available to read.
        """
        fd = reader.fileno()
        if fd not in self._reads:
            self._selectables[fd] = reader
            self._reads[fd] = 1
            self._updateRegistration(fd)

    def addWriter(self, writer):
        """Add a FileDescriptor for notification of data available to write.
        """
        fd = writer.fileno()
        if fd not in self._writes:
            self._selectables[fd] = writer
            self._writes[fd] = 1
            self._updateRegistration(fd)

    def removeReader(self, reader):
        """Remove a Selectable for notification of data available to read.
        """
        return self._dictRemove(reader, self._reads)

    def removeWriter(self, writer):
        """Remove a Selectable for notification of data available to write.
        """
        return self._dictRemove(writer, self._writes)

    def removeAll(self):
        """
        Remove all selectables, and return a list of them.
        """
        return self._removeAll([self._selectables[fd] for fd in self._reads],
                               [self._selectables[fd] for fd in self._writes])

    def doPoll(self, timeout):
        """Poll the poller for new events."""
        if timeout is not None:
            timeout = int(timeout * 1000)  # convert seconds to milliseconds

        try:
            l = self._poller.poll(timeout)
        except SelectError, e:
            if e[0] == errno.EINTR:
                return
            else:
                raise
        _drdw = self._doReadOrWrite
        for fd, event in l:
            try:
                selectable = self._selectables[fd]
            except KeyError:
                # Handles the infrequent case where one selectable's
                # handler disconnects another.
                continue
            log.callWithLogger(selectable, _drdw, selectable, fd, event)
Example #56
0
    def _socketCallback(
        self, cfSocket, callbackType, ignoredAddress, ignoredData, context
    ):
        """
        The socket callback issued by CFRunLoop.  This will issue C{doRead} or
        C{doWrite} calls to the L{IReadDescriptor} and L{IWriteDescriptor}
        registered with the file descriptor that we are being notified of.

        @param cfSocket: The C{CFSocket} which has got some activity.

        @param callbackType: The type of activity that we are being notified
            of.  Either C{kCFSocketReadCallBack} or C{kCFSocketWriteCallBack}.

        @param ignoredAddress: Unused, because this is not used for either of
            the callback types we register for.

        @param ignoredData: Unused, because this is not used for either of the
            callback types we register for.

        @param context: The data associated with this callback by
            C{CFSocketCreateWithNative} (in C{CFReactor._watchFD}).  A 2-tuple
            of C{(int, CFRunLoopSource)}.
        """
        (fd, smugglesrc) = context
        if fd not in self._fdmap:
            # Spurious notifications seem to be generated sometimes if you
            # CFSocketDisableCallBacks in the middle of an event.  I don't know
            # about this FD, any more, so let's get rid of it.
            CFRunLoopRemoveSource(self._cfrunloop, smugglesrc, kCFRunLoopCommonModes)
            return

        src, skt, readWriteDescriptor, rw = self._fdmap[fd]

        def _drdw():
            why = None
            isRead = False

            try:
                if readWriteDescriptor.fileno() == -1:
                    why = _NO_FILEDESC
                else:
                    isRead = callbackType == kCFSocketReadCallBack
                    # CFSocket seems to deliver duplicate read/write
                    # notifications sometimes, especially a duplicate
                    # writability notification when first registering the
                    # socket.  This bears further investigation, since I may
                    # have been mis-interpreting the behavior I was seeing.
                    # (Running the full Twisted test suite, while thorough, is
                    # not always entirely clear.) Until this has been more
                    # thoroughly investigated , we consult our own
                    # reading/writing state flags to determine whether we
                    # should actually attempt a doRead/doWrite first.  -glyph
                    if isRead:
                        if rw[_READ]:
                            why = readWriteDescriptor.doRead()
                    else:
                        if rw[_WRITE]:
                            why = readWriteDescriptor.doWrite()
            except BaseException:
                why = sys.exc_info()[1]
                log.err()
            if why:
                self._disconnectSelectable(readWriteDescriptor, why, isRead)

        log.callWithLogger(readWriteDescriptor, _drdw)
Example #57
0
    def doWaitForMultipleEvents(self, timeout):
        log.msg(channel='system', event='iteration', reactor=self)
        if timeout is None:
            timeout = 100

        # Keep track of whether we run any application code before we get to the
        # MsgWaitForMultipleObjects.  If so, there's a chance it will schedule a
        # new timed call or stop the reactor or do something else that means we
        # shouldn't block in MsgWaitForMultipleObjects for the full timeout.
        ranUserCode = False

        # If any descriptors are trying to close, try to get them out of the way
        # first.
        for reader in self._closedAndReading.keys():
            ranUserCode = True
            self._runAction('doRead', reader)

        for fd in self._writes.keys():
            ranUserCode = True
            log.callWithLogger(fd, self._runWrite, fd)

        if ranUserCode:
            # If application code *might* have scheduled an event, assume it
            # did.  If we're wrong, we'll get back here shortly anyway.  If
            # we're right, we'll be sure to handle the event (including reactor
            # shutdown) in a timely manner.
            timeout = 0

        if not (self._events or self._writes):
            # sleep so we don't suck up CPU time
            time.sleep(timeout)
            return

        handles = self._events.keys() or [self.dummyEvent]
        timeout = int(timeout * 1000)
        val = MsgWaitForMultipleObjects(handles, 0, timeout, QS_ALLINPUT)
        if val == WAIT_TIMEOUT:
            return
        elif val == WAIT_OBJECT_0 + len(handles):
            exit = win32gui.PumpWaitingMessages()
            if exit:
                self.callLater(0, self.stop)
                return
        elif val >= WAIT_OBJECT_0 and val < WAIT_OBJECT_0 + len(handles):
            event = handles[val - WAIT_OBJECT_0]
            fd, action = self._events[event]

            if fd in self._reads:
                # Before anything, make sure it's still a valid file descriptor.
                fileno = fd.fileno()
                if fileno == -1:
                    self._disconnectSelectable(fd, posixbase._NO_FILEDESC,
                                               False)
                    return

                # Since it's a socket (not another arbitrary event added via
                # addEvent) and we asked for FD_READ | FD_CLOSE, check to see if
                # we actually got FD_CLOSE.  This needs a special check because
                # it only gets delivered once.  If we miss it, it's gone forever
                # and we'll never know that the connection is closed.
                events = WSAEnumNetworkEvents(fileno, event)
                if FD_CLOSE in events:
                    self._closedAndReading[fd] = True
            log.callWithLogger(fd, self._runAction, action, fd)
Example #58
0
class KQueueReactor(posixbase.PosixReactorBase):
    """
    A reactor that uses kqueue(2)/kevent(2) and relies on Python 2.6 or higher
    which has built in support for kqueue in the select module.

    @ivar _kq: A L{kqueue} which will be used to check for I/O readiness.

    @ivar _selectables: A dictionary mapping integer file descriptors to
        instances of L{FileDescriptor} which have been registered with the
        reactor.  All L{FileDescriptors} which are currently receiving read or
        write readiness notifications will be present as values in this
        dictionary.

    @ivar _reads: A set containing integer file descriptors.  Values in this
        set will be registered with C{_kq} for read readiness notifications
        which will be dispatched to the corresponding L{FileDescriptor}
        instances in C{_selectables}.

    @ivar _writes: A set containing integer file descriptors.  Values in this
        set will be registered with C{_kq} for write readiness notifications
        which will be dispatched to the corresponding L{FileDescriptor}
        instances in C{_selectables}.
    """
    implements(IReactorFDSet, IReactorDaemonize)

    def __init__(self):
        """
        Initialize kqueue object, file descriptor tracking dictionaries, and the
        base class.

        See:
            - http://docs.python.org/library/select.html
            - www.freebsd.org/cgi/man.cgi?query=kqueue
            - people.freebsd.org/~jlemon/papers/kqueue.pdf
        """
        self._kq = kqueue()
        self._reads = set()
        self._writes = set()
        self._selectables = {}
        posixbase.PosixReactorBase.__init__(self)

    def _updateRegistration(self, fd, filter, op):
        """
        Private method for changing kqueue registration on a given FD
        filtering for events given filter/op. This will never block and
        returns nothing.
        """
        self._kq.control([kevent(fd, filter, op)], 0, 0)

    def beforeDaemonize(self):
        """
        Implement L{IReactorDaemonize.beforeDaemonize}.
        """
        # Twisted-internal method called during daemonization (when application
        # is started via twistd). This is called right before the magic double
        # forking done for daemonization. We cleanly close the kqueue() and later
        # recreate it. This is needed since a) kqueue() are not inherited across
        # forks and b) twistd will create the reactor already before daemonization
        # (and will also add at least 1 reader to the reactor, an instance of
        # twisted.internet.posixbase._UnixWaker).
        #
        # See: twisted.scripts._twistd_unix.daemonize()
        self._kq.close()
        self._kq = None

    def afterDaemonize(self):
        """
        Implement L{IReactorDaemonize.afterDaemonize}.
        """
        # Twisted-internal method called during daemonization. This is called right
        # after daemonization and recreates the kqueue() and any readers/writers
        # that were added before. Note that you MUST NOT call any reactor methods
        # in between beforeDaemonize() and afterDaemonize()!
        self._kq = kqueue()
        for fd in self._reads:
            self._updateRegistration(fd, KQ_FILTER_READ, KQ_EV_ADD)
        for fd in self._writes:
            self._updateRegistration(fd, KQ_FILTER_WRITE, KQ_EV_ADD)

    def addReader(self, reader):
        """
        Implement L{IReactorFDSet.addReader}.
        """
        fd = reader.fileno()
        if fd not in self._reads:
            try:
                self._updateRegistration(fd, KQ_FILTER_READ, KQ_EV_ADD)
            except OSError:
                pass
            finally:
                self._selectables[fd] = reader
                self._reads.add(fd)

    def addWriter(self, writer):
        """
        Implement L{IReactorFDSet.addWriter}.
        """
        fd = writer.fileno()
        if fd not in self._writes:
            try:
                self._updateRegistration(fd, KQ_FILTER_WRITE, KQ_EV_ADD)
            except OSError:
                pass
            finally:
                self._selectables[fd] = writer
                self._writes.add(fd)

    def removeReader(self, reader):
        """
        Implement L{IReactorFDSet.removeReader}.
        """
        wasLost = False
        try:
            fd = reader.fileno()
        except:
            fd = -1
        if fd == -1:
            for fd, fdes in self._selectables.items():
                if reader is fdes:
                    wasLost = True
                    break
            else:
                return
        if fd in self._reads:
            self._reads.remove(fd)
            if fd not in self._writes:
                del self._selectables[fd]
            if not wasLost:
                try:
                    self._updateRegistration(fd, KQ_FILTER_READ, KQ_EV_DELETE)
                except OSError:
                    pass

    def removeWriter(self, writer):
        """
        Implement L{IReactorFDSet.removeWriter}.
        """
        wasLost = False
        try:
            fd = writer.fileno()
        except:
            fd = -1
        if fd == -1:
            for fd, fdes in self._selectables.items():
                if writer is fdes:
                    wasLost = True
                    break
            else:
                return
        if fd in self._writes:
            self._writes.remove(fd)
            if fd not in self._reads:
                del self._selectables[fd]
            if not wasLost:
                try:
                    self._updateRegistration(fd, KQ_FILTER_WRITE, KQ_EV_DELETE)
                except OSError:
                    pass

    def removeAll(self):
        """
        Implement L{IReactorFDSet.removeAll}.
        """
        return self._removeAll([self._selectables[fd] for fd in self._reads],
                               [self._selectables[fd] for fd in self._writes])

    def getReaders(self):
        """
        Implement L{IReactorFDSet.getReaders}.
        """
        return [self._selectables[fd] for fd in self._reads]

    def getWriters(self):
        """
        Implement L{IReactorFDSet.getWriters}.
        """
        return [self._selectables[fd] for fd in self._writes]

    def doKEvent(self, timeout):
        """
        Poll the kqueue for new events.
        """
        if timeout is None:
            timeout = 1

        try:
            l = self._kq.control([], len(self._selectables), timeout)
        except OSError, e:
            if e[0] == errno.EINTR:
                return
            else:
                raise

        _drdw = self._doWriteOrRead
        for event in l:
            fd = event.ident
            try:
                selectable = self._selectables[fd]
            except KeyError:
                # Handles the infrequent case where one selectable's
                # handler disconnects another.
                continue
            else:
                log.callWithLogger(selectable, _drdw, selectable, fd, event)
Example #59
0
class PollReactor(posixbase.PosixReactorBase):
    """A reactor that uses poll(2)."""
    def _updateRegistration(self, fd):
        """Register/unregister an fd with the poller."""
        try:
            poller.unregister(fd)
        except KeyError:
            pass

        mask = 0
        if fd in reads:
            mask = mask | select.POLLIN
        if fd in writes:
            mask = mask | select.POLLOUT
        if mask != 0:
            poller.register(fd, mask)
        else:
            if fd in selectables:
                del selectables[fd]

        poller.eApp.interruptPoll()

    def _dictRemove(self, selectable, mdict):
        try:
            # the easy way
            fd = selectable.fileno()
            # make sure the fd is actually real.  In some situations we can get
            # -1 here.
            mdict[fd]
        except:
            # the hard way: necessary because fileno() may disappear at any
            # moment, thanks to python's underlying sockets impl
            for fd, fdes in selectables.items():
                if selectable is fdes:
                    break
            else:
                # Hmm, maybe not the right course of action?  This method can't
                # fail, because it happens inside error detection...
                return
        if fd in mdict:
            del mdict[fd]
            self._updateRegistration(fd)

    def addReader(self, reader):
        """Add a FileDescriptor for notification of data available to read.
		"""
        fd = reader.fileno()
        if fd not in reads:
            selectables[fd] = reader
            reads[fd] = 1
            self._updateRegistration(fd)

    def addWriter(self, writer, writes=writes, selectables=selectables):
        """Add a FileDescriptor for notification of data available to write.
		"""
        fd = writer.fileno()
        if fd not in writes:
            selectables[fd] = writer
            writes[fd] = 1
            self._updateRegistration(fd)

    def removeReader(self, reader, reads=reads):
        """Remove a Selectable for notification of data available to read.
		"""
        return self._dictRemove(reader, reads)

    def removeWriter(self, writer, writes=writes):
        """Remove a Selectable for notification of data available to write.
		"""
        return self._dictRemove(writer, writes)

    def removeAll(self, reads=reads, writes=writes, selectables=selectables):
        """Remove all selectables, and return a list of them."""
        if self.waker is not None:
            self.removeReader(self.waker)
        result = selectables.values()
        fds = selectables.keys()
        reads.clear()
        writes.clear()
        selectables.clear()
        for fd in fds:
            poller.unregister(fd)

        if self.waker is not None:
            self.addReader(self.waker)
        return result

    def doPoll(self,
               timeout,
               reads=reads,
               writes=writes,
               selectables=selectables,
               select=select,
               log=log,
               POLLIN=select.POLLIN,
               POLLOUT=select.POLLOUT):
        """Poll the poller for new events."""

        if timeout is not None:
            timeout = int(timeout * 1000)  # convert seconds to milliseconds

        try:
            l = poller.poll(timeout)
            if l is None:
                if self.running:
                    self.stop()
                l = []
        except select.error, e:
            if e[0] == errno.EINTR:
                return
            else:
                raise
        _drdw = self._doReadOrWrite
        for fd, event in l:
            try:
                selectable = selectables[fd]
            except KeyError:
                # Handles the infrequent case where one selectable's
                # handler disconnects another.
                continue
            log.callWithLogger(selectable, _drdw, selectable, fd, event,
                               POLLIN, POLLOUT, log)
Example #60
0
class EPollReactor(posixbase.PosixReactorBase):
    """
    A reactor that uses epoll(4).

    @ivar _poller: A L{poll} which will be used to check for I/O
        readiness.

    @ivar _selectables: A dictionary mapping integer file descriptors to
        instances of L{FileDescriptor} which have been registered with the
        reactor.  All L{FileDescriptors} which are currently receiving read or
        write readiness notifications will be present as values in this
        dictionary.

    @ivar _reads: A dictionary mapping integer file descriptors to arbitrary
        values (this is essentially a set).  Keys in this dictionary will be
        registered with C{_poller} for read readiness notifications which will
        be dispatched to the corresponding L{FileDescriptor} instances in
        C{_selectables}.

    @ivar _writes: A dictionary mapping integer file descriptors to arbitrary
        values (this is essentially a set).  Keys in this dictionary will be
        registered with C{_poller} for write readiness notifications which will
        be dispatched to the corresponding L{FileDescriptor} instances in
        C{_selectables}.
    """
    implements(IReactorFDSet)

    def __init__(self):
        """
        Initialize epoll object, file descriptor tracking dictionaries, and the
        base class.
        """
        # Create the poller we're going to use.  The 1024 here is just a hint
        # to the kernel, it is not a hard maximum.
        self._poller = _epoll.epoll(1024)
        self._reads = {}
        self._writes = {}
        self._selectables = {}
        posixbase.PosixReactorBase.__init__(self)

    def _add(self, xer, primary, other, selectables, event, antievent):
        """
        Private method for adding a descriptor from the event loop.

        It takes care of adding it if  new or modifying it if already added
        for another state (read -> read/write for example).
        """
        fd = xer.fileno()
        if fd not in primary:
            cmd = _epoll.CTL_ADD
            flags = event
            if fd in other:
                flags |= antievent
                cmd = _epoll.CTL_MOD
            primary[fd] = 1
            selectables[fd] = xer
            # epoll_ctl can raise all kinds of IOErrors, and every one
            # indicates a bug either in the reactor or application-code.
            # Let them all through so someone sees a traceback and fixes
            # something.  We'll do the same thing for every other call to
            # this method in this file.
            self._poller._control(cmd, fd, flags)

    def addReader(self, reader):
        """
        Add a FileDescriptor for notification of data available to read.
        """
        self._add(reader, self._reads, self._writes, self._selectables,
                  _epoll.IN, _epoll.OUT)

    def addWriter(self, writer):
        """
        Add a FileDescriptor for notification of data available to write.
        """
        self._add(writer, self._writes, self._reads, self._selectables,
                  _epoll.OUT, _epoll.IN)

    def _remove(self, xer, primary, other, selectables, event, antievent):
        """
        Private method for removing a descriptor from the event loop.

        It does the inverse job of _add, and also add a check in case of the fd
        has gone away.
        """
        fd = xer.fileno()
        if fd == -1:
            for fd, fdes in selectables.items():
                if xer is fdes:
                    break
            else:
                return
        if fd in primary:
            cmd = _epoll.CTL_DEL
            flags = event
            if fd in other:
                flags = antievent
                cmd = _epoll.CTL_MOD
            else:
                del selectables[fd]
            del primary[fd]
            # See comment above _control call in _add.
            self._poller._control(cmd, fd, flags)

    def removeReader(self, reader):
        """
        Remove a Selectable for notification of data available to read.
        """
        self._remove(reader, self._reads, self._writes, self._selectables,
                     _epoll.IN, _epoll.OUT)

    def removeWriter(self, writer):
        """
        Remove a Selectable for notification of data available to write.
        """
        self._remove(writer, self._writes, self._reads, self._selectables,
                     _epoll.OUT, _epoll.IN)

    def removeAll(self):
        """
        Remove all selectables, and return a list of them.
        """
        if self.waker is not None:
            fd = self.waker.fileno()
            if fd in self._reads:
                del self._reads[fd]
                del self._selectables[fd]
        result = self._selectables.values()
        fds = self._selectables.keys()
        self._reads.clear()
        self._writes.clear()
        self._selectables.clear()
        for fd in fds:
            try:
                # Actually, we'll ignore all errors from this, since it's
                # just last-chance cleanup.
                self._poller._control(_epoll.CTL_DEL, fd, 0)
            except IOError:
                pass
        if self.waker is not None:
            fd = self.waker.fileno()
            self._reads[fd] = 1
            self._selectables[fd] = self.waker
        return result

    def getReaders(self):
        return [self._selectables[fd] for fd in self._reads]

    def getWriters(self):
        return [self._selectables[fd] for fd in self._writes]

    def doPoll(self, timeout):
        """
        Poll the poller for new events.
        """
        if timeout is None:
            timeout = 1
        timeout = int(timeout * 1000)  # convert seconds to milliseconds

        try:
            # Limit the number of events to the number of io objects we're
            # currently tracking (because that's maybe a good heuristic) and
            # the amount of time we block to the value specified by our
            # caller.
            l = self._poller.wait(len(self._selectables), timeout)
        except IOError, err:
            if err.errno == errno.EINTR:
                return
            # See epoll_wait(2) for documentation on the other conditions
            # under which this can fail.  They can only be due to a serious
            # programming error on our part, so let's just announce them
            # loudly.
            raise

        _drdw = self._doReadOrWrite
        for fd, event in l:
            try:
                selectable = self._selectables[fd]
            except KeyError:
                pass
            else:
                log.callWithLogger(selectable, _drdw, selectable, fd, event)