def peer_address(self): if self._address is None: raise socket_error(errno.EBADF) if self._peer_address is None: raise socket_error(errno.ENOTCONN) return self._peer_address
def listen(self, backlog): if self._address is None: raise socket_error(errno.EBADF) if self._incoming_error != errno.ENOTCONN: raise socket_error(platform.invalid_argument) self.backlog = Store(self.env, capacity=backlog) self.env._register(self)
def connect(self, address): if self._address is None: raise socket_error(errno.EBADF) if self._peer is not None: # Already connected, do nothing. return if self.backlog is not None: raise socket_error(errno.EISCONN) self.env._establish_connection(self, address)
def close(self): # Stop reader and writer process if they are waiting for the next # request. if self._in_message_ev and not self._in_message_ev.triggered: self._in_message_ev.fail(socket_error(errno.EBADF)) self._in_message_ev = None if self._out_message_ev and not self._out_message_ev.triggered: self._out_message_ev.fail(socket_error(errno.EBADF)) self._out_message_ev = None self.sock.close()
def close(self): """Closes the socket, all further operations will raise ``EBADF``.""" if self._address is None: return self._incoming_error = errno.EBADF self._outgoing_error = errno.EBADF if self._incoming_avail is not None: self._incoming_avail.succeed() if self._outgoing_avail is not None: self._outgoing_avail.succeed() if self._frame_transmission: # Wake the reader if it is currently waiting for a frame. if not self._frame_transmission.triggered: self._frame_transmission.succeed() self._frame_transmission = None if self.backlog is not None: for accepter in self.backlog.get_queue: if not accepter.triggered: accepter.fail(socket_error(errno.EBADF)) self.env._unregister(self) self._address = None self._peer_address = None
def close(self): # TODO Figure out if this behaviour is really usefull. Might require # the addition of methods that check for the sockets state. try: fileno = self.fileno() del self.env.fds[fileno] # TODO Remove events. if self._reader is not None: self._reader.fail(socket_error(errno.EBADF)) self._reader = None self.env._rd.remove(fileno) if self._writer is not None: self._writer.fail(socket_error(errno.EBADF)) self._writer = None self.env._wd.remove(fileno) self.sock.close() except SocketError as e: if e.errno == errno.EBADF: return raise e
def _try_read(self): if self._incoming_error is not None: self._reader.fail(socket_error(self._incoming_error)) self._reader = None return if not self.incoming: return data = self.incoming[:self._reader.amount] self.incoming = self.incoming[self._reader.amount:] self._reader.succeed(data) self._reader = None if self._incoming_avail: self._incoming_avail.succeed() self._incoming_avail = None
def _try_write(self): if self._outgoing_error is not None: self._writer.fail(socket_error(self._outgoing_error)) self._writer = None return available = self.max_buffer_size - len(self.outgoing) if not available: return self.outgoing += self._writer.data[:available] self._writer.succeed(min(len(self._writer.data), available)) self._writer = None if self._outgoing_avail: # Notify the reader process about the new data. self._outgoing_avail.succeed() self._outgoing_avail = None
def _get_address(self, address): host, port = address if host != '0.0.0.0': for interface, routes in self.interfaces: if interface == host: break else: errcode = socket.EAI_NONAME raise socket.gaierror(errcode, os.strerror(errcode)) # A port number of zero means auto-choose. if port == 0: # Search for a free port starting from the current port_ofs. for port in range(65535): port = 1 + (self._port_ofs + port) % (65535 - 1) if port not in self.ports: break else: raise RuntimeError('No free port left') self._port_ofs = port elif port in self.ports: raise socket_error(errno.EADDRINUSE) return (host, port)
def _register(self, sock): host, port = sock._address if port in self.ports: raise socket_error(errno.EADDRINUSE) self.ports[port] = sock
def accept(self): if self.backlog is None: raise socket_error(platform.invalid_argument) return self.backlog.get()
def bind(self, address): if self._address is None: raise socket_error(errno.EBADF) if self._incoming_error != errno.ENOTCONN: raise socket_error(platform.invalid_argument) self._address = self.env._get_address(address)
def address(self): if self._address is None: raise socket_error(errno.EBADF) return self._address
def fileno(self): fileno = self.sock.fileno() if fileno < 0: raise socket_error(errno.EBADF) return fileno
def _reader(self, data=b'', mask=False): try: read = self.socket.read blocksize = self.blocksize headers = frame_headers[mask] while True: event = None event = yield self._read_ev self._read_ev = self.env.event() while len(data) < headers[0].size: data += yield read(4096) # Parse header. header = bytearray(data[:headers[0].size]) opcode = header[0] if mask and not header[1] & 0x80: raise RuntimeError('Masking bit was not set') length_desc = 0x7f & header[1] if length_desc == 126: while len(data) < headers[1].size: data += yield read(blocksize) header = headers[1].unpack(data[:headers[1].size]) data = data[headers[1].size:] size = header[2] elif length_desc == 127: while len(data) < headers[2].size: data += yield read(blocksize) header = headers[2].unpack(data[:headers[2].size]) data = data[headers[2].size:] size = header[2] else: header = headers[0].unpack(data[:headers[0].size]) data = data[headers[0].size:] size = header[1] & 0x7f # Read packet. while len(data) < size: data += yield read(blocksize) packet, data = data[:size], data[size:] if mask: # Unmask data. # TODO Is it possible to unmask the data using a builtin # function? if PY2: maskingkey = bytearray(header[-1]) else: maskingkey = header[-1] packet = bytearray(packet) for i in range(size): packet[i] ^= maskingkey[i % 4] packet = bytes(packet) # Convert packet data if necessary. if opcode & 0x7f == 1: packet = packet.decode() elif opcode & 0x7f == 2: pass elif opcode & 0x7f == 8: # Close connection. # FIXME Should I really send the close control frame? self.socket.close() raise socket_error(errno.ECONNRESET) else: raise RuntimeError('Unsupported opcode %x' % opcode) event.succeed(packet) except BaseException as e: # FIXME Add proper error handling. self._reader_proc.defused = True if event is not None: event.fail(e)