def auth(cls, user, password, version=None, mm_version=None, os_type=None, arch=None): """ Process Auth :param user: :param password: :param version: :param mm_version: major/minor software version :param os_type: :param arch: :return: (err, msg, client_id) """ try: # user = auth_req['Payload'].get('User') # pwd = auth_req['Payload'].get('Password') # err, msg, result = UserController.login(user, '', pwd) # if err != Err.ERR_SUCCESS: # return err, msg, result now = time.time() client_id = md5(str(now)) return ERR_SUCCESS, get_err_msg(ERR_SUCCESS), client_id except Exception as ex: logger.exception("Exception in process auth:", exc_info=ex) return ERR_FAILED, get_err_msg(ERR_FAILED), None
async def __write_handler(self): """ 处理写回调。 :return: """ if len(self.resp_list) == 0 and self.writing_resp is None: return try: if self.writing_resp is None: self.writing_resp = self.resp_list[0] self.resp_list = self.resp_list[1:] sent_bytes = self.conn.send(self.writing_resp) if sent_bytes < len(self.writing_resp): self.writing_resp = self.writing_resp[sent_bytes:] else: self.writing_resp = None self.loop.remove_writer(self.fd) self.loop.add_reader(self.fd, self.read_handler) except ssl.SSLWantReadError as ex: logger.debug("SSLWantReadError") except Exception as ex: logger.exception("Exception in write_handler:", exc_info=ex) asyncio.ensure_future(self.process_error(), loop=self.loop)
async def __continue_read_handler(self): """ 处理read回调。用来处理请求过大没有一次接收完的。 :return: """ try: data = self.conn.recv(DEFAULT_BUF_SIZE) except ssl.SSLWantReadError as ex: logger.debug("SSLWantReadError") return if not data: self.loop.remove_reader(self.conn.fileno()) self.conn.close() else: request_size = tolen(self.binary_data[:8]) try: self.binary_data.extend(data) except Exception as ex: logger.exception("test:", exc_info=ex) if request_size > len(self.binary_data[8:]): # 请求没接收全,继续接受 pass elif request_size < len(self.binary_data[8:]): # 请求的大小,小于收到的大小,有TCP粘包 # 获取本次请求 request_data = self.binary_data[8:8 + request_size] logger.debug("receive control request: %s", request_data) await self.process_request(request_data) # 移除已处理请求的数据 self.binary_data = self.binary_data[8 + request_size:] # 移除继续读的read回调 self.loop.remove_reader(self.fd) else: # 请求接受全 request_data = self.binary_data[8:] logger.debug("receive control request: %s", request_data) await self.process_request(request_data) self.binary_data = None # 移除继续读的read回调 self.loop.remove_reader(self.fd)
def reg_proxy(client_id): """ 判断这个client_id是否已经登录的client_id :param client_id: :return: """ try: if client_id not in GLOBAL_CACHE.TUNNEL_LIST: return ERR_CLIENT_ID_NOT_EXIST, get_err_msg( ERR_CLIENT_ID_NOT_EXIST), None else: return ERR_SUCCESS, get_err_msg(ERR_SUCCESS), None except Exception as ex: logger.exception("exception in process reg_proxy:", exc_info=ex) return ERR_FAILED, get_err_msg(ERR_FAILED), None
async def process_error(self): """ 处理错误,关闭客户端连接,移除所有事件监听。比如:解析命令出错等 :return: """ try: self.loop.remove_reader(self.fd) self.loop.remove_writer(self.fd) # GLOBAL_CACHE.pop_client_id(self.client_id) if not self.is_proxy: tunnels = GLOBAL_CACHE.pop_tunnel(self.client_id) if self.client_id in GLOBAL_CACHE.SEND_REQ_PROXY_LIST: asyncio.ensure_future(GLOBAL_CACHE.SEND_REQ_PROXY_LIST[ self.client_id].put('close'), loop=self.loop) if tunnels is not None: for url in tunnels['http']: GLOBAL_CACHE.pop_host(url) for url in tunnels['https']: GLOBAL_CACHE.pop_host(url) if self.client_id in GLOBAL_CACHE.SEND_REQ_PROXY_LIST: send_req_proxy_queue = GLOBAL_CACHE.SEND_REQ_PROXY_LIST.pop( self.client_id) await send_req_proxy_queue.put('close') if self.client_id in GLOBAL_CACHE.PROXY_URL_ADDR_LIST: queue = GLOBAL_CACHE.PROXY_URL_ADDR_LIST.pop( self.client_id) if queue is not None: queue.put('close') else: # 检查queue是否存在并尝试通知http连接关闭 if self.control_http_queue: await self.control_http_queue.put('close') GLOBAL_CACHE.del_http_commu_queue_map( self.communicate_identify) self.conn.close() except Exception as ex: logger.exception("Exception in process error:", exc_info=ex)
async def process_error(self): """ 处理错误,关闭客户端连接,移除所有事件监听。比如:解析命令出错等 :return: """ self.loop.remove_reader(self.fd) self.loop.remove_writer(self.fd) # 检查queue是否存在并尝试通知proxy连接关闭 if self.control_proxy_queue: await self.control_proxy_queue.put('close') GLOBAL_CACHE.del_http_commu_queue_map(self.communicate_identify) try: self.conn.close() except Exception as ex: logger.exception("Exception in process error:", exc_info=ex)
async def process_request(self, request_data): """ 处理读取到的请求命令 :param request_data: 读取到的请求数据,会在本函数中转为json格式 :return: """ try: request = json.loads(str(request_data, 'utf-8')) except Exception as ex: logger.exception("Exception in process_request, load request:", exc_info=ex) asyncio.ensure_future(self.process_error(), loop=self.loop) return req_type = request.get('Type', None) if req_type == 'Auth': err, msg, resp = self.auth_process(request) elif req_type == 'ReqTunnel': err, msg, resp = self.req_tunnel_process(request) elif req_type == 'RegProxy': err, msg, resp = await self.reg_proxy_process(request) elif req_type == 'Ping': err, msg, resp = self.ping_process() else: # unknown req type, close this connection err, msg, resp = ERR_UNKNOWN_REQUEST, get_err_msg( ERR_UNKNOWN_REQUEST), None if err in (ERR_UNKNOWN_REQUEST, ERR_CLOSE_SOCKET): asyncio.ensure_future(self.process_error(), loop=self.loop) elif err == ERR_SUCCESS: self.resp_list.append(resp) if req_type == 'RegProxy': # self.http_start_proxy() http_req = await self.get_http_req_from_queue() self.resp_list.append(http_req) self.loop.remove_reader(self.fd) self.loop.add_writer(self.fd, self.write_handler)
def req_tunnel_http(req_id, protocol, hostname=None, subdomain=None, http_auth=None): """ process ReqTunnel with http/https tunnel :param req_id: :param protocol: :param hostname: :param subdomain: :param http_auth: :return: (err, msg, url) """ try: if hostname is not None and hostname.strip() != '': domain_name = hostname else: if subdomain is None or subdomain.strip() == '': subdomain = get_rand_char(5) domain_name = subdomain + '.' + DEFAULT_SERVER_DOMAIN if protocol == 'http' and DEFAULT_SERVER_HTTP != 80: url = 'http://' + domain_name + ':' + str(DEFAULT_SERVER_HTTP) elif protocol == 'https' and DEFAULT_SERVER_HTTP != 443: url = 'https://' + domain_name + ':' + str( DEFAULT_SERVER_HTTPS) else: url = protocol + '://' + domain_name return ERR_SUCCESS, get_err_msg(ERR_SUCCESS), url except Exception as ex: logger.exception("exception in process req_tunnel_http:", exc_info=ex) return ERR_FAILED, get_err_msg(ERR_FAILED), None