def __init__(self, cond): self.channels = {} self.processes = {} self.guards = {} # Unknown messages, which is moved to known messages, if a channel or processes with a matching name registers. # TODO: This must be capped. self.channels_unknown = {} self.processes_unknown = {} self.cond = cond host = conf.get(PYCSP_HOST) port = conf.get(PYCSP_PORT) if port == 0 and ENVVAL_PORT in os.environ: port = int(os.environ[ENVVAL_PORT]) if host == '' and ENVVAL_HOST in os.environ: host = os.environ[ENVVAL_HOST] host = host.encode() addr = (host, port) self.server_socket, self.server_addr = ossocket.start_server(addr) self.server_addr = (self.server_addr[0].encode(), self.server_addr[1]) self.active_socket_list = [self.server_socket] self.active_socket_list_add = [] self.thread = None self.handler = ossocket.ConnHandler()
def run(self): #print "Starting SocketThread" handler = ossocket.ConnHandler() while (not self.finished): # Performing select.select on possibly EBADF. A lingering socket may be left in the active_socket_list. # The following select.select is robust against Bad File Descriptors, and will remove them from the active_socket_list # The only way to test for a bad file descriptor, is to cause a socket.error exception. OK = False while (not OK): import socket try: ready, _, exceptready = select.select( self.data.active_socket_list, [], [], 10.0) OK = True except: new_socket_list = [] for s in self.data.active_socket_list: try: if s.fileno() > 0: new_socket_list.append(s) except socket.error: # Ignoring EBADF file descriptor errors pass except ValueError: # Ignoring file descriptors with a value of -1 pass self.data.active_socket_list = new_socket_list # Select finished OK if not ready and not exceptready: # Timeout. Invoke ticks self.cond.acquire() for c in list(self.channels.values()): c.timeout_tick() self.cond.release() else: for s in ready: if s == self.data.server_socket: conn, _ = self.data.server_socket.accept() self.data.active_socket_list.append(conn) else: header = Header() header.cmd = ERROR_CMD self.cond.acquire() try: s.recv_into(header) except ossocket.socket.error as e: if e.errno == errno.ECONNRESET: # Connection has been reset header.cmd = ERROR_CMD else: raise self.cond.release() if header.cmd == ERROR_CMD: # connection disconnected if s in self.data.active_socket_list: self.data.active_socket_list.remove(s) s.close() else: if (header.cmd & HAS_PAYLOAD): self.cond.acquire() payload = ossocket.recvall(s, header.arg) self.cond.release() else: payload = "" m = Message(header, payload) if (header.cmd & NATFIX): # save reverse socket as payload m.natfix = s self.cond.acquire() if (header.cmd == SOCKETTHREAD_PING): if self.data.active_socket_list_add: self.data.active_socket_list.extend( self.data.active_socket_list_add) self.data.active_socket_list_add = [] elif (header.cmd == SOCKETTHREAD_SHUTDOWN): if self.channels or self.processes: # Socketthread is still busy. Thus ignore and expect a later call to deregister to invoke stopThread. pass else: self.finished = True # Remove thread reference self.data.thread = None # Do not close sockets as the socketthread may be restarted at a later time elif (header.cmd & PROCESS_CMD): if header.id in self.processes: p = self.processes[header.id] p.handle(m) elif (header.cmd & REQ_REPLY): raise FatalException( "A REQ_REPLY message should always be valid!" ) elif (header.cmd & IGN_UNKNOWN): raise FatalException( "IGN_UNKNOWN should never occur!") else: if not header.id in self.data.processes_unknown: self.data.processes_unknown[ header.id] = [] self.data.processes_unknown[ header.id].append(m) else: if header.id in self.channels: c = self.channels[header.id] if (header.cmd & IS_REPLY): c.put_reply(m) else: c.put_normal(m) elif (header.cmd & IGN_UNKNOWN): pass else: if not header.id in self.data.channels_unknown: self.data.channels_unknown[ header.id] = QueueBuffer() c = self.data.channels_unknown[header.id] if (header.cmd & IS_REPLY): c.put_reply(m) else: c.put_normal(m) self.cond.release()
def run(self): #print "Starting SocketThread" handler = ossocket.ConnHandler() while (not self.finished): ready, _, exceptready = select.select(self.data.active_socket_list, [], [], 10.0) if not ready and not exceptready: # Timeout. Invoke ticks self.cond.acquire() for c in self.channels.values(): c.timeout_tick() self.cond.release() else: for s in ready: if s == self.data.server_socket: conn, _ = self.data.server_socket.accept() self.data.active_socket_list.append(conn) else: header = Header() header.cmd = ERROR_CMD self.cond.acquire() try: s.recv_into(header) except ossocket.socket.error as e: if e.errno == errno.ECONNRESET: # Connection has been reset header.cmd = ERROR_CMD else: raise self.cond.release() if header.cmd == ERROR_CMD: # connection disconnected if s in self.data.active_socket_list: self.data.active_socket_list.remove(s) s.close() else: if (header.cmd & HAS_PAYLOAD): self.cond.acquire() payload = ossocket.recvall(s, header.arg) self.cond.release() else: payload = "" m = Message(header, payload) if (header.cmd & NATFIX): # save reverse socket as payload m.natfix = s self.cond.acquire() if (header.cmd == SOCKETTHREAD_PING): if self.data.active_socket_list_add: self.data.active_socket_list.extend( self.data.active_socket_list_add) self.data.active_socket_list_add = [] elif (header.cmd == SOCKETTHREAD_SHUTDOWN): if self.channels or self.processes: # Socketthread is still busy. Thus ignore and expect a later call to deregister to invoke stopThread. pass else: self.finished = True # Remove thread reference self.data.thread = None # Do not close sockets as the socketthread may be restarted at a later time elif (header.cmd & PROCESS_CMD): if header.id in self.processes: self.processes[header.id].handle(m) elif (header.cmd & REQ_REPLY): raise FatalException( "A REQ_REPLY message should always be valid!" ) elif (header.cmd & IGN_UNKNOWN): raise FatalException( "IGN_UNKNOWN should never occur!") else: if not header.id in self.data.processes_unknown: self.data.processes_unknown[ header.id] = [] self.data.processes_unknown[ header.id].append(m) else: if header.id in self.channels: if (header.cmd & IS_REPLY): self.channels[header.id].put_reply(m) else: self.channels[header.id].put_normal(m) elif (header.cmd & IGN_UNKNOWN): pass else: if not header.id in self.data.channels_unknown: self.data.channels_unknown[ header.id] = QueueBuffer() if (header.cmd & IS_REPLY): self.data.channels_unknown[ header.id].put_reply(m) else: self.data.channels_unknown[ header.id].put_normal(m) self.cond.release()