def _init_sockets_ip4cp(): global _ip4cp, _done_event, _reconfig_event, _initialized ip4cp_get_configuration(early=True) if _initialized: return _done_event = efi.event_signal() _reconfig_event = efi.event_signal(abort=_ip4cp_stop_config) efi.check_status(_ip4cp.Start(_ip4cp, _done_event.event, _reconfig_event.event)) while not _done_event.signaled: pass ip4cp_get_configuration()
def _init_sockets_ip4cp(): global _ip4cp, _done_event, _reconfig_event, _initialized ip4cp_get_configuration(early=True) if _initialized: return _done_event = efi.event_signal() _reconfig_event = efi.event_signal(abort=_ip4cp_stop_config) efi.check_status( _ip4cp.Start(_ip4cp, _done_event.event, _reconfig_event.event)) while not _done_event.signaled: pass ip4cp_get_configuration()
def recv_into(self, buffer, nbytes=0, flags=0): """recv_into(buffer, [nbytes[, flags]]) -> nbytes_read A version of recv() that stores its data into a buffer rather than creating a new string. Receive up to buffersize bytes from the socket. If buffersize is not specified (or 0), receive up to the size available in the given buffer. See recv() for documentation about the flags.""" if nbytes == 0: # len returns the wrong thing for a resized ctypes buffer. But # ctypes.sizeof doesn't work on all buffery objects that len does. # So try both, in order of preference. try: nbytes = sizeof(buffer) except TypeError as e: nbytes = len(buffer) cbuf = (c_uint8 * nbytes).from_buffer(buffer) rx = efi.EFI_TCP4_RECEIVE_DATA() rx.DataLength = nbytes rx.FragmentCount = 1 rx.FragmentTable[0].FragmentLength = nbytes rx.FragmentTable[0].FragmentBuffer = addressof(cbuf) e = efi.event_signal() token = efi.EFI_TCP4_IO_TOKEN() token.CompletionToken.Event = e.event token.Packet.RxData = pointer(rx) efi.check_status(self._tcp4.Receive(self._tcp4, byref(token))) self._wait(e, token.CompletionToken) return rx.DataLength
def _start_config(): global _configuration_started, _ip4cp, _tcp4sbp, _done_event, _reconfig_event if _configuration_started: return handles = list(efi.locate_handles(efi.EFI_IP4_CONFIG_PROTOCOL_GUID)) if not handles: raise IOError("EFI_IP4_CONFIG_PROTOCOL not available") _ip4cp = efi.EFI_IP4_CONFIG_PROTOCOL.from_handle(handles[0]) handles = list(efi.locate_handles(efi.EFI_TCP4_SERVICE_BINDING_PROTOCOL_GUID)) if not handles: raise IOError("EFI_TCP4_SERVICE_BINDING_PROTOCOL not available") _tcp4sbp = efi.EFI_TCP4_SERVICE_BINDING_PROTOCOL.from_handle(handles[0]) _done_event = efi.event_signal() _reconfig_event = efi.event_signal(abort=_stop_config) efi.check_status(_ip4cp.Start(_ip4cp, _done_event.event, _reconfig_event.event)) print("IP configuration started") _configuration_started = True
def _close(self, abort=True): if hasattr(self, "closed") and self.closed: return e = efi.event_signal() token = efi.EFI_TCP4_CLOSE_TOKEN() token.CompletionToken.Event = e.event token.AbortOnClose = abort efi.check_status(self._tcp4.Close(self._tcp4, byref(token))) self._wait(e, token.CompletionToken) self.closed = True
def accept(self): """accept() -> (socket object, address info) Wait for an incoming connection. Return a new socket representing the connection, and the address of the client. For IP sockets, the address info is a pair (hostaddr, port).""" e = efi.event_signal() token = efi.EFI_TCP4_LISTEN_TOKEN() token.CompletionToken.Event = e.event efi.check_status(self._tcp4.Accept(self._tcp4, byref(token))) self._wait(e, token.CompletionToken) s = socket(family=self.family, type=self.type, proto=self.proto, _handle=token.NewChildHandle) return s, s.getpeername()
def connect(self, addr): """connect(address) Connect the socket to a remote address. For IP sockets, the address is a pair (host, port).""" global _ip_address, _subnet_mask, _routes host, port = addr ip = efi.EFI_IPv4_ADDRESS.from_buffer_copy(inet_aton(gethostbyname(host))) data = efi.EFI_TCP4_CONFIG_DATA() data.TypeOfService = 0 data.TimeToLive = 60 # UseDefaultAddress = True fails with EFI_ALREADY_STARTED, but using # the previously obtained address works. The UEFI 2.5 specification # does not explain this behavior or document this error code as a # possible return from Configure. data.AccessPoint.UseDefaultAddress = False # Use the local IP and port from bind if set try: data.AccessPoint.StationAddress = self._bind_ip data.AccessPoint.StationPort = self._bind_port except AttributeError as e: data.AccessPoint.StationAddress = _ip_address data.AccessPoint.StationPort = 0 data.AccessPoint.SubnetMask = _subnet_mask data.AccessPoint.RemoteAddress = ip data.AccessPoint.RemotePort = port data.AccessPoint.ActiveFlag = True efi.check_status(self._tcp4.Configure(self._tcp4, byref(data))) # Contradicting the UEFI 2.5 specification, the EFI_TCP4_PROTOCOL does # not automatically use all of the underlying IP4 routes. Add them # manually, but ignore any failure caused by already having the route. for route in _routes: status = self._tcp4.Routes(self._tcp4, False, byref(route.SubnetAddress), byref(route.SubnetMask), byref(route.GatewayAddress)) if status != efi.EFI_ACCESS_DENIED: efi.check_status(status) e = efi.event_signal() token = efi.EFI_TCP4_CONNECTION_TOKEN() token.CompletionToken.Event = e.event efi.check_status(self._tcp4.Connect(self._tcp4, byref(token))) self._wait(e, token.CompletionToken)
def sendall(self, data, flags=0): """sendall(data[, flags]) Send a data string to the socket. For the optional flags argument, see the Unix manual. This calls send() repeatedly until all data is sent. If an error occurs, it's impossible to tell how much data has been sent.""" tx = efi.EFI_TCP4_TRANSMIT_DATA() tx.DataLength = len(data) tx.FragmentCount = 1 tx.FragmentTable[0].FragmentLength = len(data) if isinstance(data, memoryview): data = data.tobytes() ptr = c_char_p(data) tx.FragmentTable[0].FragmentBuffer = cast(ptr, c_void_p) e = efi.event_signal() token = efi.EFI_TCP4_IO_TOKEN() token.CompletionToken.Event = e.event token.Packet.TxData = pointer(tx) efi.check_status(self._tcp4.Transmit(self._tcp4, byref(token))) self._wait(e, token.CompletionToken)