def select_poller(timeout=0.0, map=None): """A poller which uses select(), available on most platforms.""" # pylint: disable=redefined-builtin if map is None: map = socket_map if map: r = [] w = [] e = [] for fd, obj in list(map.items()): is_r = obj.readable() is_w = obj.writable() if is_r: r.append(fd) # accepting sockets should not be writable if is_w and not obj.accepting: w.append(fd) if is_r or is_w: e.append(fd) if [] == r == w == e: time.sleep(timeout) return try: r, w, e = select.select(r, w, e, timeout) except KeyboardInterrupt: return except socket.error as err: if err.args[0] in (EBADF, EINTR): return except Exception as err: if err.args[0] in (WSAENOTSOCK, ): return for fd in helper_random.randomsample(r, len(r)): obj = map.get(fd) if obj is None: continue read(obj) for fd in helper_random.randomsample(w, len(w)): obj = map.get(fd) if obj is None: continue write(obj) for fd in e: obj = map.get(fd) if obj is None: continue _exception(obj) else: current_thread().stop.wait(timeout)
def randomKeys(self, count=1): """Retrieve count random keys from the dict that haven't already been retrieved""" if self.len == 0 or ( (self.pendingLen >= self.maxPending or self.pendingLen == self.len) and self.lastPoll + self.pendingTimeout > time()): raise KeyError # pylint: disable=redefined-outer-name with self.lock: # reset if we've requested all # and if last object received too long time ago if self.pendingLen == self.len and self.lastObject + \ self.pendingTimeout < time(): self.pendingLen = 0 self.setLastObject() available = self.len - self.pendingLen if count > available: count = available randomIndex = helper_random.randomsample( range(self.len - self.pendingLen), count) retval = [self.indexDict[i] for i in randomIndex] for i in sorted(randomIndex, reverse=True): # swap with one below lowest pending self._swap(i, self.len - self.pendingLen - 1) self.pendingLen += 1 self.lastPoll = time() return retval
def sendAddr(self): """Send a partial list of known addresses to peer.""" # We are going to share a maximum number of 1000 addrs (per overlapping # stream) with our peer. 500 from overlapping streams, 250 from the # left child stream, and 250 from the right child stream. maxAddrCount = BMConfigParser().safeGetInt("bitmessagesettings", "maxaddrperstreamsend", 500) templist = [] addrs = {} for stream in self.streams: with knownnodes.knownNodesLock: for n, s in enumerate((stream, stream * 2, stream * 2 + 1)): nodes = knownnodes.knownNodes.get(s) if not nodes: continue # only if more recent than 3 hours # and having positive or neutral rating filtered = [(k, v) for k, v in nodes.iteritems() if v["lastseen"] > int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers and v["rating"] >= 0 and len(k.host) <= 22] # sent 250 only if the remote isn't interested in it elemCount = min(len(filtered), maxAddrCount / 2 if n else maxAddrCount) addrs[s] = helper_random.randomsample(filtered, elemCount) for substream in addrs: for peer, params in addrs[substream]: templist.append((substream, peer, params["lastseen"])) if templist: self.append_write_buf(BMProto.assembleAddr(templist))
def sendAddr(self): # We are going to share a maximum number of 1000 addrs (per overlapping # stream) with our peer. 500 from overlapping streams, 250 from the # left child stream, and 250 from the right child stream. maxAddrCount = BMConfigParser().safeGetInt("bitmessagesettings", "maxaddrperstreamsend", 500) # init addressCount = 0 payload = b'' templist = [] addrs = {} for stream in self.streams: with knownnodes.knownNodesLock: if len(knownnodes.knownNodes[stream]) > 0: filtered = {k: v for k, v in knownnodes.knownNodes[stream].items() if v["lastseen"] > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)} elemCount = len(filtered) if elemCount > maxAddrCount: elemCount = maxAddrCount # only if more recent than 3 hours addrs[stream] = helper_random.randomsample(filtered.items(), elemCount) # sent 250 only if the remote isn't interested in it if len(knownnodes.knownNodes[stream * 2]) > 0 and stream not in self.streams: filtered = {k: v for k, v in knownnodes.knownNodes[stream*2].items() if v["lastseen"] > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)} elemCount = len(filtered) if elemCount > maxAddrCount / 2: elemCount = int(maxAddrCount / 2) addrs[stream * 2] = helper_random.randomsample(filtered.items(), elemCount) if len(knownnodes.knownNodes[(stream * 2) + 1]) > 0 and stream not in self.streams: filtered = {k: v for k, v in knownnodes.knownNodes[stream*2+1].items() if v["lastseen"] > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)} elemCount = len(filtered) if elemCount > maxAddrCount / 2: elemCount = int(maxAddrCount / 2) addrs[stream * 2 + 1] = helper_random.randomsample(filtered.items(), elemCount) for substream in addrs.keys(): for peer, params in addrs[substream]: templist.append((substream, peer, params["lastseen"])) if len(templist) > 0: self.append_write_buf(BMProto.assembleAddr(templist))
def epoll_poller(timeout=0.0, map=None): """A poller which uses epoll(), supported on Linux 2.5.44 and newer.""" # pylint: disable=redefined-builtin if map is None: map = socket_map try: epoll_poller.pollster except AttributeError: epoll_poller.pollster = select.epoll() if map: for fd, obj in map.items(): flags = newflags = 0 if obj.readable(): flags |= select.POLLIN | select.POLLPRI newflags |= OP_READ else: newflags &= ~OP_READ # accepting sockets should not be writable if obj.writable() and not obj.accepting: flags |= select.POLLOUT newflags |= OP_WRITE else: newflags &= ~OP_WRITE if newflags != obj.poller_flags: obj.poller_flags = newflags # Only check for exceptions if object was either readable # or writable. flags |= select.POLLERR | select.POLLHUP | select.POLLNVAL try: if obj.poller_registered: epoll_poller.pollster.modify(fd, flags) else: epoll_poller.pollster.register(fd, flags) obj.poller_registered = True except IOError: pass try: r = epoll_poller.pollster.poll(timeout) except IOError as e: if e.errno != EINTR: raise r = [] except select.error as err: if err.args[0] != EINTR: raise r = [] for fd, flags in helper_random.randomsample(r, len(r)): obj = map.get(fd) if obj is None: continue readwrite(obj, flags) else: current_thread().stop.wait(timeout)
def poll_poller(timeout=0.0, map=None): """A poller which uses poll(), available on most UNIXen.""" # pylint: disable=redefined-builtin if map is None: map = socket_map if timeout is not None: # timeout is in milliseconds timeout = int(timeout * 1000) try: poll_poller.pollster except AttributeError: poll_poller.pollster = select.poll() if map: for fd, obj in list(map.items()): flags = newflags = 0 if obj.readable(): flags |= select.POLLIN | select.POLLPRI newflags |= OP_READ else: newflags &= ~OP_READ # accepting sockets should not be writable if obj.writable() and not obj.accepting: flags |= select.POLLOUT newflags |= OP_WRITE else: newflags &= ~OP_WRITE if newflags != obj.poller_flags: obj.poller_flags = newflags try: if obj.poller_registered: poll_poller.pollster.modify(fd, flags) else: poll_poller.pollster.register(fd, flags) obj.poller_registered = True except IOError: pass try: r = poll_poller.pollster.poll(timeout) except KeyboardInterrupt: r = [] except socket.error as err: if err.args[0] in (EBADF, WSAENOTSOCK, EINTR): return for fd, flags in helper_random.randomsample(r, len(r)): obj = map.get(fd) if obj is None: continue readwrite(obj, flags) else: current_thread().stop.wait(timeout)
def randomKeys(self, count=1): if self.len == 0 or ( (self.pendingLen >= self.maxPending or self.pendingLen == self.len) and self.lastPoll + self.pendingTimeout > time()): raise KeyError with self.lock: # reset if we've requested all # or if last object received too long time ago if self.pendingLen == self.len or self.lastObject + self.pendingTimeout > time( ): self.pendingLen = 0 available = self.len - self.pendingLen if count > available: count = available randomIndex = helper_random.randomsample( range(self.len - self.pendingLen), count) retval = [self.indexDict[i] for i in randomIndex] for i in sorted(randomIndex, reverse=True): # swap with one below lowest pending self._swap(i, self.len - self.pendingLen - 1) self.pendingLen += 1 self.lastPoll = time() return retval
def kqueue_poller(timeout=0.0, map=None): """A poller which uses kqueue(), BSD specific.""" # pylint: disable=redefined-builtin,no-member if map is None: map = socket_map try: kqueue_poller.pollster except AttributeError: kqueue_poller.pollster = select.kqueue() if map: updates = [] selectables = 0 for fd, obj in map.items(): kq_filter = 0 if obj.readable(): kq_filter |= 1 selectables += 1 if obj.writable() and not obj.accepting: kq_filter |= 2 selectables += 1 if kq_filter != obj.poller_filter: # unlike other pollers, READ and WRITE aren't OR able but have # to be set and checked separately if kq_filter & 1 != obj.poller_filter & 1: poller_flags = select.KQ_EV_ADD if kq_filter & 1: poller_flags |= select.KQ_EV_ENABLE else: poller_flags |= select.KQ_EV_DISABLE updates.append( select.kevent(fd, filter=select.KQ_FILTER_READ, flags=poller_flags)) if kq_filter & 2 != obj.poller_filter & 2: poller_flags = select.KQ_EV_ADD if kq_filter & 2: poller_flags |= select.KQ_EV_ENABLE else: poller_flags |= select.KQ_EV_DISABLE updates.append( select.kevent(fd, filter=select.KQ_FILTER_WRITE, flags=poller_flags)) obj.poller_filter = kq_filter if not selectables: # unlike other pollers, kqueue poll does not wait if there are no # filters setup current_thread().stop.wait(timeout) return events = kqueue_poller.pollster.control(updates, selectables, timeout) if len(events) > 1: events = helper_random.randomsample(events, len(events)) for event in events: fd = event.ident obj = map.get(fd) if obj is None: continue if event.flags & select.KQ_EV_ERROR: _exception(obj) continue if event.flags & select.KQ_EV_EOF and event.data and event.fflags: obj.handle_close() continue if event.filter == select.KQ_FILTER_READ: read(obj) if event.filter == select.KQ_FILTER_WRITE: write(obj) else: current_thread().stop.wait(timeout)