def send(self, data, flags=0, timeout=timeout_default): if timeout is timeout_default: timeout = self.timeout if self._sslobj: if flags != 0: raise ValueError( "non-zero flags not allowed in calls to send() on %s" % self.__class__) while True: try: v = self._sslobj.write(data) except SSLError, x: if x.args[0] == SSL_ERROR_WANT_READ: if self.timeout == 0.0: raise timeout(str(x)) sys.exc_clear() wait_read(self.fileno(), timeout=timeout) elif x.args[0] == SSL_ERROR_WANT_WRITE: if self.timeout == 0.0: raise timeout(str(x)) sys.exc_clear() wait_write(self.fileno(), timeout=timeout) else: raise else: return v
def recv_into(self, buffer, nbytes=None, flags=0): if buffer and (nbytes is None): nbytes = len(buffer) elif nbytes is None: nbytes = 1024 if self._sslobj: if flags != 0: raise ValueError( "non-zero flags not allowed in calls to recv_into() on %s" % self.__class__) while True: try: tmp_buffer = self.read(nbytes) v = len(tmp_buffer) buffer[:v] = tmp_buffer return v except SSLError, x: if x.args[0] == SSL_ERROR_WANT_READ: sys.exc_clear() if self.timeout == 0.0: raise timeout(str(x)) wait_read(self.fileno(), timeout=self.timeout) continue else: raise
def send(self, data, flags=0, timeout=timeout_default): if timeout is timeout_default: timeout = self.timeout while True: try: return self._sock.send(data, flags) except SSL.WantWriteError, ex: if self.timeout == 0.0: raise timeout(str(ex)) else: sys.exc_clear() wait_write(self.fileno(), timeout=timeout) except SSL.WantReadError, ex: if self.timeout == 0.0: raise timeout(str(ex)) else: sys.exc_clear() wait_read(self.fileno(), timeout=timeout)
def recv(self, buflen): pending = self._sock.pending() if pending: return self._sock.recv(min(pending, buflen)) while True: try: return self._sock.recv(buflen) except SSL.WantReadError, ex: if self.timeout == 0.0: raise timeout(str(ex)) else: sys.exc_clear() wait_read(self.fileno(), timeout=self.timeout) except SSL.WantWriteError, ex: if self.timeout == 0.0: raise timeout(str(ex)) else: sys.exc_clear() wait_read(self.fileno(), timeout=self.timeout)
def wait_for_first_udp(self): # wait util first VALID packet come. start = time.time() timeout = self.timeout while True: readable, _, _ = select.select([self.socksconn, self.client2local_udpsock], [], [], timeout) if not readable: raise socket.timeout("timeout") # @UndefinedVariable if self.socksconn in readable: raise RelaySessionError("unexcepted read-event from tcp socket in UDP session") timeout -= (time.time() - start) if timeout <= 0: raise socket.timeout("timeout") # @UndefinedVariable data, addr = self.client2local_udpsock.recvfrom(65536) try: udpreq = UDPRequest(data) if udpreq.frag == '\x00': return data, addr except: pass
def wait_for_first_udp(self): # wait util first VALID packet come. start = time.time() timeout = self.timeout while True: readable = select.select([self.socksconn, self.client2local_udpsock], [], [], timeout) if not readable: raise socket.timeout("timeout") if self.socksconn in readable: raise RelaySessionError("unexcepted read-event from tcp socket in UDP session") timeout -= (time.time() - start) if timeout <= 0: raise socket.timeout("timeout") data, addr = self.client2local_udpsock.recvfrom(65536) try: udpreq = UDPRequest(data) if udpreq.frag == '\x00': return data, addr except: pass
def recv(self, buflen=1024, flags=0): if self._sslobj: if flags != 0: raise ValueError( "non-zero flags not allowed in calls to recv() on %s" % self.__class__) while True: try: return self.read(buflen) except SSLError, x: if x.args[0] == SSL_ERROR_WANT_READ: sys.exc_clear() if self.timeout == 0.0: raise timeout(str(x)) wait_read(self.fileno(), timeout=self.timeout) continue else: raise
def create_connection( address, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, dns_timeout=None, source_address=None, use_happyeyeballs=True, prepare=None, ): _log.debug("create_connection %r", address) (host, port, *_) = address try: ipaddress.ip_address(host) use_happyeyeballs = False except ValueError: pass if not use_happyeyeballs: # TODO: a bit problematic we use socket's hidden timeout sentinel # as our default, but it hasn't changed for 12 years so we're probably # gonna be fine; maybe! return _create_connection(address, timeout=timeout, source_address=source_address, prepare=prepare) group = pool.Group() # TODO: OK, I'm gonna be honest: this system of greenlet orchestration # is really, uhh, let's just say not good; the proper way of implementing # this would be something like curio's TaskGroup: a Group that tracks the # completion states of its members # (0, (family, addr)) = success (gai) # (1, sock) = success (result) # (-1, (family, None, exc)) = fail (gai) # (-2, (family, addr, exc)) = fail (connect) bus = queue.Queue() def _do_gai(family, proto=0, flags=0): _log.debug("_do_gai: started family=%s, proto=%d, flags=%s", family, proto, flags) try: addrs = gevent.with_timeout( dns_timeout, socket.getaddrinfo, host, port, family, socket.SOCK_STREAM, proto, flags, ) _log.debug("_do_gai: finished family=%s, addrs=%r", family, addrs) while addrs: (*_, addr) = addrs.pop() bus.put((0, (family, addr))) except _Cancel: _log.debug("_do_gai: cancelled family=%s", family) except gevent.Timeout: bus.put((-1, (family, None, socket.gaierror(-errno.ETIMEDOUT, "Timed out")))) except Exception as e: bus.put((-1, (family, None, e))) dns_attempts = 2 group.apply_async(_do_gai, args=(socket.AF_INET6, 0, socket.AI_V4MAPPED)) group.apply_async(_do_gai, args=(socket.AF_INET, )) def _do_connect(family, addr): _log.debug("_do_connect: started family=%s, addr=%s", family, addr) # TODO: god I hate the flow of logic in this proc sock = socket.socket(family, socket.SOCK_STREAM) if source_address: sock.bind(source_address) if prepare: prepare(sock) try: sock.connect(addr) _log.debug( "_do_connect: finished family=%s, addr=%s, socket=%r", family, addr, sock, ) except _Cancel: _log.debug("_do_connect: cancelled family=%s, addr=%s", family, addr) except Exception as e: bus.put((-2, (family, addr, e))) except: sock.close() raise else: return bus.put((1, sock)) sock.close() do_later = queue.Queue() started_ipv6 = event.Event() def _laterlet(): try: stagger = started_ipv6.wait(timeout=RESOLVE_DELAY) if stagger: gevent.sleep(CONNECT_DELAY) for cb, args, kwds in do_later: group.apply_async(cb, args, kwds) except _Cancel: pass group.apply_async(_laterlet) if timeout is socket._GLOBAL_DEFAULT_TIMEOUT: timeout = None started = time.monotonic() conn_attempts = 0 errors = [] t = timeout try: while True: # TODO: technically this is not right: # we take dns query times into account as timeout # no good; though there's no better way of solving it # without restructuring the entire algo if t is not None: t = max(MIN_TIMEOUT, timeout - (time.monotonic() - started)) op, rest = bus.get(timeout=t) _log.debug("bus get op %d with payload %s", op, rest) _log.debug("error states = %r", errors) if op == 1: return rest elif op == -1: errors.append(rest) dns_attempts -= 1 if dns_attempts <= 0: raise socket.error(errors) continue elif op == -2: errors.append(rest) conn_attempts -= 1 if conn_attempts <= 0: raise socket.error(errors) continue family, addr = rest conn_attempts += 1 if family == socket.AF_INET: do_later.put((_do_connect, (socket.AF_INET, addr), {})) else: started_ipv6.set() group.apply_async(_do_connect, (socket.AF_INET6, addr)) except queue.Empty: raise socket.timeout("timed out") finally: group.kill(_Cancel)