def run(self): self._stopping = False events = [] while not self._stopping: asap = False try: events = self.poll(TIMEOUT_PRECISION) except (OSError, IOError) as e: if utils.errno_from_exception(e) in (errno.EPIPE, errno.EINTR): # EPIPE: Happens when the client closes the connection # EINTR: Happens when received a signal # handles them as soon as possible asap = True print('poll:%s', e) else: print('poll:%s', e) import traceback traceback.print_exc() continue for sock, fd, event in events: handler = self._fdmap.get(fd, None) if handler is not None: handler = handler[1] try: if not getattr(handler, "_keepalive", False): self._timeout.update_activity(fd, handler) handler.handle_events(sock, fd, event) except (OSError, IOError) as e: print(e) now = time.time() if asap or now - self._last_time >= TIMEOUT_PRECISION: self._timeout.cleanup() self._last_time = now print("proxy service stopped!!!")
def _create_peer_socket(self, ip, port): addrs = socket.getaddrinfo(ip, port, 0, socket.SOCK_STREAM, socket.SOL_TCP) if len(addrs) == 0: raise Exception("getaddrinfo failed for %s:%d" % (ip, port)) af, socktype, proto, canonname, sa = addrs[0] sock = socket.socket(af, socktype, proto) sock.setblocking(False) sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) try: sock.connect(sa) except (OSError, IOError) as e: err = utils.errno_from_exception(e) if err not in _ERRNO_INPROGRESS and \ err not in _ERRNO_WOULDBLOCK: self.destroy() return peer_handler = self.__class__(self.io_loop, sock, sa, self._dns_resolver, self.HDL_POSITIVE) peer_handler._direct_conn = self._direct_conn self.relate(peer_handler) peer_handler.relate(self) event = IOLoop.WRITE if peer_handler.writable else None peer_handler.register(event) self._status = self.STAGE_PEER_CONNECTED peer_handler._status = self.STAGE_PEER_CONNECTED
def on_recv_syn(self): if self._status == self.STAGE_CLOSED: logging.warning("read on closed socket!") self.destroy() return data = None try: data = self._sock.recv(self.BUF_SIZE) except (OSError, IOError) as e: if utils.errno_from_exception(e) in \ (errno.ETIMEDOUT, errno.EAGAIN, errno.EWOULDBLOCK): return if not data: self.destroy() return cmd = utils.ord(data[1]) if cmd == socks5.CMD_UDPFWD: logging.debug('UDP associate') if self._sock.family == socket.AF_INET6: header = b'\x05\x00\x00\x04' else: header = b'\x05\x00\x00\x01' addr, port = self._sock.getsockname()[:2] addr_to_send = socket.inet_pton(self._sock.family, addr) port_to_send = struct.pack('>H', port) data = header + addr_to_send + port_to_send self._write_buf.append(data) # send back ack self._wbuf_size += len(data) return elif cmd == socks5.CMD_CONNECT: data = data[3:] else: logging.error('unknown command %d', cmd) self.destroy() return self._append_to_rbuf(data) utils.merge_prefix(self._read_buf, self.BUF_SIZE) if not self._read_buf: return data = self._read_buf[0] header_result = socks5.parse_header(data) if not header_result: return addrtype, remote_addr, remote_port, header_length = header_result logging.info("connecting %s:%d from %s:%d" % (\ (remote_addr, remote_port, ) + self._addr)) data = self._pop_from_rbuf(self.BUF_SIZE) self._status = self.STAGE_SOCKS5_SYN ack, l = socks5.gen_ack() self._write_buf.append(ack) # send back ack self._wbuf_size += l if self._exclusive_host(remote_addr): # self._append_to_rbuf(data, codec=True) self._peer_addr = self._sshost() # connect ssserver else: self._direct_conn = True self._peer_addr = (utils.to_str(remote_addr), remote_port) #直连 self._dns_resolver.resolve(self._peer_addr[0], self._on_dns_resolved)
def on_write(self): # NOTICE 写数据时, 都是从对方的read_buf取出数据写的 num_bytes = 0 peer_handler = self.peer if not peer_handler: # if peer not created write_buf = self._write_buf else: write_buf = peer_handler._read_buf if self._write_buf: # self._write_buf中一般不会有数据, 有数据时 # peer_handler._read_buf肯定为空, 此次操作 # 时间为O(1) utils.merge_prefix(self._write_buf, self.BUF_SIZE) data = self._write_buf.popleft() write_buf.appendleft(data) peer_handler._rbuf_size += len(data) self._wbuf_size -= len(data) if not write_buf: return num_bytes utils.merge_prefix(write_buf, self.BUF_SIZE) while write_buf: try: if not self._sock: break length = self._sock.send(write_buf[0]) if length: utils.merge_prefix(write_buf, length) write_buf.popleft() num_bytes += length else: break except (socket.error, IOError, OSError) as e: error_no = utils.errno_from_exception(e) if error_no in (errno.EAGAIN, errno.EINPROGRESS, errno.EWOULDBLOCK): # 缓冲区满 break else: logging.error(e) self.destroy() break if not peer_handler: self._wbuf_size -= num_bytes else: peer_handler._rbuf_size -= num_bytes logging.info("send {:6d} B to {:15s}:{:5d} ".format(num_bytes, *self._addr)) return num_bytes
def handle_events(self, sock, fd, events): if self._status == self.STAGE_CLOSED: logging.warning("handler destoryed!") return if events & self.io_loop.ERROR: self.destroy() raise Exception('server_socket error') try: conn, addr = self._sock.accept() logging.debug("accept %s:%d" % addr) handler = self._conn_hd_cls(self.io_loop, conn, addr, self._dns_resolver, self.HDL_NEGATIVE) handler.register() except (OSError, IOError) as e: err_no = utils.errno_from_exception(e) if err_no in (errno.EAGAIN, errno.EINPROGRESS, errno.EWOULDBLOCK): return else: logging.error("fatal error: %s" % e)
def on_recv_nego(self): if self._status == self.STAGE_CLOSED: logging.warning("read on closed socket!") self.destroy() return data = None try: data = self._sock.recv(self.BUF_SIZE) except (OSError, IOError) as e: if utils.errno_from_exception(e) in \ (errno.ETIMEDOUT, errno.EAGAIN, errno.EWOULDBLOCK): return if not data: self.destroy() return resp, length = self._nego_response(data) self._write_buf.append(resp) self._wbuf_size += length self._status = self.STAGET_SOCKS5_NEGO return
def on_read(self): data = None if not self._sock: return try: data = self._sock.recv(self.BUF_SIZE) except (OSError, IOError) as e: if utils.errno_from_exception(e) in \ (errno.ETIMEDOUT, errno.EAGAIN, errno.EWOULDBLOCK): return if not data: self.destroy() return data = self._codec(data) self._read_buf.append(data) date_length = len(data) self._rbuf_size += date_length logging.info("recv {:6d} B from {:15s}:{:5d} ".format(date_length, *self._addr)) if self._rbuf_size >= self.MAX_BUF_SIZE: logging.warn("connection: %s:%d read buffer over flow!" % self._addr) self.destroy()
def pre_dns_resolved(self, data, hostname, port, r_addr, result, error): if error: logging.error(error) return if not result: return ip = result[1] if not ip: return addrs = socket.getaddrinfo(ip, port, 0, socket.SOCK_DGRAM, socket.SOL_UDP) # for ip, will block?? if not addrs: return af, socktype, proto, canonname, sa = addrs[0] peer_sock = self.peer_sock((ip, port), af, r_addr) try: if peer_sock: peer_sock.sendto(data, (ip, port)) except IOError as e: err = utils.errno_from_exception(e) if err in (errno.EINPROGRESS, errno.EAGAIN): pass else: logging.error(e, exc_info=True)
def on_recv_syn(self): if self._status == self.STAGE_CLOSED: logging.warning("read on closed socket!") self.destroy() return data = None try: data = self._sock.recv(self.BUF_SIZE) except (OSError, IOError) as e: if utils.errno_from_exception(e) in \ (errno.ETIMEDOUT, errno.EAGAIN, errno.EWOULDBLOCK): return if not data: self.destroy() return self._append_to_rbuf(data) # method from BaseTcpHandler try: http_request = self.read_until("\r\n\r\n") if not http_request: return http_response, ss_premble, addr = http2shadosocks(http_request) if http_response: self._write_buf.append(http_response) self._wbuf_size += len(http_response) if self._exclusive_host(addr[0]): self._append_to_rbuf(ss_premble, codec=True) self._peer_addr = self._sshost() # connect ssserver else: self._direct_conn = True self._peer_addr = addr self._status = self.STAGE_SOCKS5_SYN self._dns_resolver.resolve(self._peer_addr[0], self._on_dns_resolved) except HttpRequestError as e: logging.warn(e) self.destroy() return
def on_recv_syn(self): if self._status == self.STAGE_CLOSED: logging.warning("read on closed socket!") self.destroy() return data = None try: data = self._sock.recv(self.BUF_SIZE) except (OSError, IOError) as e: if utils.errno_from_exception(e) in \ (errno.ETIMEDOUT, errno.EAGAIN, errno.EWOULDBLOCK): return if not data: self.destroy() return self._append_to_rbuf(data, codec=True) utils.merge_prefix(self._read_buf, self.BUF_SIZE) if not self._read_buf: return data = self._read_buf[0] header_result = socks5.parse_header(data) if not header_result: return addrtype, remote_addr, remote_port, header_length = header_result self._pop_from_rbuf(header_length) self._status = self.STAGE_SOCKS5_SYN logging.info("connecting %s:%d from %s:%d" % (\ (remote_addr, remote_port, ) + self._addr)) self._peer_addr = (utils.to_str(remote_addr), remote_port) try: self._dns_resolver.resolve(remote_addr, self._on_dns_resolved) except Exception as e: logging.error(e) self.destroy()