def __notify_box_close(self): with self.__notify_box_close_lock: log.v('Notify box %d close.' % self.box.uuid) try: self.box.send(Message.create_close_data()) except Exception as e: log.e('Send close message failed.')
def run(self): log.v('[RM] Update network speed.') d, u = speedtest.get_speeds() if d and u: self.conn.download_speed = int(d) * 8 self.conn.upload_speed = int(u) * 8 self.conn.is_updating_network_speed = False
def __handle_box_server_data(self, c, msg): for cc in self.clients: if cc.uuid == msg.uuid: log.v('Send data to client %d from box %d.' % (cc.uuid, c.uuid)) cc.append_data_to_buffer(msg.content) return log.v('Can not find client %d when box sending data.' % msg.uuid) self.__notify_box_client_broken(msg.uuid)
def __start_main(self): self.__is_quit_thread = False while not self.__is_quit_thread: read_list = [self.__qs] write_list = [] err_list = [] # Box or box-cache connections. read_list.append(self.s) if self.box_cache: # connected without authorized read_list.extend(self.box_cache) # INFO: If cached-box need read, then it is self.box. err_list.extend(self.box_cache) if self.box: # The only authorized box. read_list.append(self.box) if self.box.has_buffered_datas(): write_list.append(self.box) err_list.append(self.box) # Client connections. read_list.append(self.cs) if self.clients: read_list.extend(self.clients) write_list.extend( filter(lambda c: c.has_buffered_datas(), self.clients)) err_list.extend(self.clients) # log.v('READLIST: %s' % str(len(read_list))) # log.v('WRITELIST: %s' % str(len(write_list))) # log.v('ERRORLIST: %s' % str(len(err_list))) # self.dump() # Wait. read_result, write_result, err_result = select.select( read_list, write_list, err_list, 5) # Handle read, write and error connections. log.v('Before handle connection or socket') for e in err_result: self.__handle_connection_error(e) for r in read_result: self.__handle_connection_read(r) for w in write_result: self.__handle_connection_write(w) self.__handle_connection_timeout() log.v('After handle connection or socket')
def __handle_client_connection(self, c): data = c.recv(config.SOCKET_RECV_LEN) if not data: raise socket.error('Client send EOF.') log.v('Send data to box %d from client %d' % (self.box.uuid, c.uuid)) # MUST check here. self.box.timeout_tracer.reset() self.box.ping_tracer.reset() self.box.append_data_to_buffer( Message.create_client_data_data(c.uuid, data))
def __send_a_data(self, data): """ Send a data to client. """ send_data = data try: while send_data: length = self.s.send(send_data) send_data = send_data[length:] if length < len(send_data) else None self.blocked = False except (socket.error, socket.timeout) as e: err = e.args[0] self.blocked = True if err == errno.EAGAIN or err == errno.EWOULDBLOCK: log.v('Client %d block error %d, need send later.' % (self.uuid, err)) self.data_queue.appendleft(send_data) return raise socket.error(e)
def __handle_cached_box_connection(self, c): msg = Message(c.recv(config.SOCKET_RECV_LEN), c) if not msg.is_valid: raise socket.error('Invalid register message from box') if msg.type == Type.CONNECT: if not self.__handle_box_register(c, msg): raise socket.error('Box failed to register') self.box = c self.box.ping_tracer.reset() self.box.timeout_tracer.reset() self.box_cache.remove(c) self.__clean_cached_boxes() else: log.v('Unknown message type %d from cached-box %d' % (msg.type, c.uuid))
def run(self): self.is_quit = False while not self.is_quit: log.v('[RM] Try connect to relay manager.') self.conn = RelayManagerConnection(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) try: self.__connect() except (socket.error, socket.timeout) as e: log.e('[RM] Send connect request to relay manager failed: %s' % str(e)) self.conn.close() time.sleep(30) continue log.v('[RM] Relay manager connected.') self.__update_network_speed() self.__send_heartbeat() self.__send_status() while not self.is_quit: try: reads, _, errors = select.select([self.conn], [], [self.conn], 1) self.__update_messages() self.__update_messages_udp() self.__update_tracers() if self.conn in reads: self.__handle_conn() if self.conn in errors: raise socket.error('connection error in select()') except (socket.error, socket.timeout) as e: log.e('[RM] Send HEARTBEAT or STATUS failed: %s' % str(e)) self.conn.close() time.sleep(1) break # Quit the connection. try: self.__send_disconnect() self.conn.close() except (socket.error, socket.timeout) as e: pass
def __handle_box_connection(self, c): msg = Message(c.recv(config.SOCKET_RECV_LEN), c) if not msg.is_valid: raise socket.error('Invalid message from box') if msg.type == Type.SERVER_DATA: c.timeout_tracer.reset() c.ping_tracer.reset() self.__handle_box_server_data(c, msg) elif msg.type == Type.DISCONNECT: socket.error('Box %d notify disconnect' % c.uuid) elif msg.type == Type.SERVER_ERROR: self.__handle_box_server_error(c, msg) elif msg.type == Type.PING: log.v('Get box %d PING message.' % c.uuid) c.ping_tracer.reset() c.append_data_to_buffer(Message.create_ping_ack_data()) else: log.v('Unknown message type %d from box %d' % (msg.type, c.uuid))
def __connect(self): info = { 'serverId': self.upnp.get_box_serial(), 'serverType': 'contributed', } log.v('[RM] CONNECT TO: %s; INFO: %s' % (str(self.address), str(info))) # self.conn = RelayManagerConnection(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) self.conn.connect(self.address) self.conn.send(RelayManagerMessage.create_connect_data(info)) log.v('[RM] After send when connecting.') data = self.conn.recv(config.SOCKET_RECV_LEN, magic=RelayManagerMessage.MAGIC) log.v('[RM] After recv when connecting.') if not data: raise socket.error('EOF') msg = RelayManagerMessage(data) if not msg.is_valid: raise socket.error('Invalid message') if msg.msg_type != RelayManagerMessage.Type.ACCEPT: raise socket.error('Not accepted')
def dump(self): log.v('>>>>>>>>>>>>>> dump tcp relay begin <<<<<<<<<<<<<<') log.v('Cached Box: %d' % len(self.box_cache)) log.v('Box: %s' % str(bool(self.box))) if self.box: log.v('Box Messages to Send: %d' % len(self.box.data_queue)) log.v('Clients: %d' % len(self.clients)) for c in self.clients: log.v('Client Messages to Send: %d' % len(c.data_queue)) log.v('>>>>>>>>>>>>>> dump tcp relay end <<<<<<<<<<<<<<')
def __notify_box_client_broken(self, uuid): log.v('Notify box %d that client %d has broken.' % (self.box.uuid, uuid)) self.box.append_data_to_buffer( Message.create_client_error_data(uuid, ECode.RELAY_CLIENT_DISCONNECTED))
def __handle_connection_write(self, c): log.v('Handle connection writing.') if c is self.box: log.v('Handle box writing.') try: # Check box timeout without PING from relay. # c.timeout_tracer.reset() c.send() if c.blocked: self.__close_box() except (socket.error, socket.timeout) as e: log.e('Send buffered datas to box %d failed: %s' % (c.uuid, str(e))) self.__close_box() elif c in self.clients: log.v('Handle client writing.') try: log.v( 'Send data to client %d in __handle_connection_write().' % c.uuid) c.timeout_tracer.reset() changed = c.send() if changed: if c.blocked: log.v('Client %d has blocked' % c.uuid) self.box.append_data_to_buffer( Message.create_pause_data(c.uuid)) else: log.v('Client %d has not blocked' % c.uuid) self.box.append_data_to_buffer( Message.create_resume_data(c.uuid)) else: # log.v('Client %d blocked state has not changed.' % c.uuid) pass except (socket.error, socket.timeout) as e: log.e('Send buffered datas to client failed: %s' % str(e)) self.__notify_box_client_broken(c.uuid) self.__close_client(c)
def __handle_connection_read(self, r): # log.v('Handle connection reading.') if r is self.s: log.v('Handle box listener reading.') c, addr = r.accept() conn = BoxConnection(c) log.d('Connected by box %d, address, %s' % (conn.uuid, repr(addr))) if self.box: conn.close() else: self.box_cache.append(conn) elif r in self.box_cache: log.v('Handle cached box reading.') try: self.__handle_cached_box_connection(r) except (socket.error, socket.timeout) as e: log.e('Cached box %d connection encounter an error: %s' % (r.uuid, str(e))) self.__close_cached_box(r) elif r is self.box: log.v('Handle box reading.') try: self.__handle_box_connection(r) except (socket.error, socket.timeout) as e: log.e('Box %d connection encounter an error: %s' % (r.uuid, str(e))) self.__close_box() elif r is self.cs: log.v('Handle client listener reading.') c, addr = r.accept() conn = ClientConnection(c) log.d('Connected by client %d, address, %s' % (conn.uuid, repr(addr))) if not self.box: log.d('Skip this client because no box connected !!!') conn.close() return self.clients.append(conn) elif r in self.clients: log.v('Handle client reading.') try: r.timeout_tracer.reset() self.__handle_client_connection(r) except (socket.error, socket.timeout) as e: log.e('Client %d connection enconter an error: %s.' % (r.uuid, str(e))) self.__notify_box_client_broken(r.uuid) self.__close_client(r) elif r is self.__qs: log.v('Handle quit-socket reading.') self.__handle_quit_request(r) else: log.d('The connection does not need handle.')