示例#1
0
    def _unwatchFD(self, fd, descr, flag):
        """
        Unregister a file descriptor with the C{CFRunLoop}, or modify its state
        so that it's listening for only one notification (read or write) as
        opposed to both; used to implement C{removeReader} and C{removeWriter}.

        @param fd: a file descriptor

        @type fd: C{int}

        @param descr: an L{IReadDescriptor} or L{IWriteDescriptor}

        @param flag: C{kCFSocketWriteCallBack} C{kCFSocketReadCallBack}
        """
        if id(descr) not in self._idmap:
            return
        if fd == -1:
            # need to deal with it in this case, I think.
            realfd = self._idmap[id(descr)]
        else:
            realfd = fd
        src, cfs, descr, rw = self._fdmap[realfd]
        CFSocketDisableCallBacks(cfs, flag)
        rw[self._flag2idx(flag)] = False
        if not rw[_READ] and not rw[_WRITE]:
            del self._idmap[id(descr)]
            del self._fdmap[realfd]
            CFRunLoopRemoveSource(self._cfrunloop, src, kCFRunLoopCommonModes)
            CFSocketInvalidate(cfs)
示例#2
0
    def _watchFD(self, fd, descr, flag):
        """
        Register a file descriptor with the C{CFRunLoop}, or modify its state
        so that it's listening for both notifications (read and write) rather
        than just one; used to implement C{addReader} and C{addWriter}.

        @param fd: The file descriptor.

        @type fd: L{int}

        @param descr: the L{IReadDescriptor} or L{IWriteDescriptor}

        @param flag: the flag to register for callbacks on, either
            C{kCFSocketReadCallBack} or C{kCFSocketWriteCallBack}
        """
        if fd == -1:
            raise RuntimeError("Invalid file descriptor.")
        if fd in self._fdmap:
            src, cfs, gotdescr, rw = self._fdmap[fd]
            # do I need to verify that it's the same descr?
        else:
            ctx = []
            ctx.append(fd)
            cfs = CFSocketCreateWithNative(
                kCFAllocatorDefault,
                fd,
                kCFSocketReadCallBack
                | kCFSocketWriteCallBack
                | kCFSocketConnectCallBack,
                self._socketCallback,
                ctx,
            )
            CFSocketSetSocketFlags(
                cfs,
                kCFSocketAutomaticallyReenableReadCallBack
                | kCFSocketAutomaticallyReenableWriteCallBack
                |
                # This extra flag is to ensure that CF doesn't (destructively,
                # because destructively is the only way to do it) retrieve
                # SO_ERROR and thereby break twisted.internet.tcp.BaseClient,
                # which needs SO_ERROR to tell it whether or not it needs to
                # call connect_ex a second time.
                _preserveSOError,
            )
            src = CFSocketCreateRunLoopSource(kCFAllocatorDefault, cfs, 0)
            ctx.append(src)
            CFRunLoopAddSource(self._cfrunloop, src, kCFRunLoopCommonModes)
            CFSocketDisableCallBacks(
                cfs,
                kCFSocketReadCallBack
                | kCFSocketWriteCallBack
                | kCFSocketConnectCallBack,
            )
            rw = [False, False]
            self._idmap[id(descr)] = fd
            self._fdmap[fd] = src, cfs, descr, rw
        rw[self._flag2idx(flag)] = True
        CFSocketEnableCallBacks(cfs, flag)