Exemple #1
0
    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
Exemple #2
0
    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."""
        if isinstance(data, memoryview):
            data = data.tobytes() # ctypes can't handle memoryview directly
        data = (c_uint8 * len(data)).from_buffer_copy(data)
        tx = efi.EFI_TCP4_TRANSMIT_DATA()
        tx.DataLength = len(data)
        tx.FragmentCount = 1
        tx.FragmentTable[0].FragmentLength = len(data)
        tx.FragmentTable[0].FragmentBuffer = cast(data, c_void_p)
        token = efi.EFI_TCP4_IO_TOKEN()
        send_status = []
        def callback():
            _ = data, tx # Reference objects EFI will access, to keep them alive
            send_status.append(token.CompletionToken.Status)
            self._events.close_event(efi.EFI_EVENT(token.CompletionToken.Event))
        token.CompletionToken.Event = self._events.create_event(callback, abort=self._abort)
        token.Packet.TxData = pointer(tx)
        status = self._tcp4.Transmit(self._tcp4, byref(token))
        if status:
            self._events.close_event(efi.EFI_EVENT(token.CompletionToken.Event))
            efi.check_status(status)
            return
        while not send_status:
            self._poll()
        efi.check_status(send_status[0])
Exemple #3
0
 def __del__(self):
     global _tcp4sbp
     # Only clean up if __init__ finished and we have a protocol to destroy
     if hasattr(self, "_tcp4"):
         self._abort()
         efi.check_status(
             _tcp4sbp.DestroyChild(_tcp4sbp, self._tcp4._handle))
Exemple #4
0
 def _get_config(self):
     tcp4_state = efi.EFI_TCP4_CONNECTION_STATE()
     tcp4_config_data = efi.EFI_TCP4_CONFIG_DATA()
     ip4_mode_data = efi.EFI_IP4_MODE_DATA()
     mnp_config_data = efi.EFI_MANAGED_NETWORK_CONFIG_DATA()
     snp_mode_data = efi.EFI_SIMPLE_NETWORK_MODE()
     efi.check_status(self._tcp4.GetModeData(self._tcp4, byref(tcp4_state), byref(tcp4_config_data), byref(ip4_mode_data), byref(mnp_config_data), byref(snp_mode_data)))
     return tcp4_config_data
Exemple #5
0
 def _abort(self):
     if self._aborted:
         return
     # This cancels any outstanding completion tokens, to avoid accesses to
     # memory or events that we're about to free.
     efi.check_status(self._tcp4.Configure(self._tcp4, None))
     self._events.close_all()
     self._aborted = True
Exemple #6
0
 def _abort(self):
     if self._aborted:
         return
     # This cancels any outstanding completion tokens, to avoid accesses to
     # memory or events that we're about to free.
     efi.check_status(self._tcp4.Configure(self._tcp4, None))
     self._events.close_all()
     self._aborted = True
Exemple #7
0
 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
Exemple #8
0
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()
Exemple #9
0
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()
Exemple #10
0
 def _get_config(self):
     tcp4_state = efi.EFI_TCP4_CONNECTION_STATE()
     tcp4_config_data = efi.EFI_TCP4_CONFIG_DATA()
     ip4_mode_data = efi.EFI_IP4_MODE_DATA()
     mnp_config_data = efi.EFI_MANAGED_NETWORK_CONFIG_DATA()
     snp_mode_data = efi.EFI_SIMPLE_NETWORK_MODE()
     efi.check_status(
         self._tcp4.GetModeData(self._tcp4, byref(tcp4_state),
                                byref(tcp4_config_data),
                                byref(ip4_mode_data),
                                byref(mnp_config_data),
                                byref(snp_mode_data)))
     return tcp4_config_data
Exemple #11
0
    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()
Exemple #12
0
    def _wait(self, es, ct):
        """Spin until the specified completion token completes or timeout elapses

        es is an efi.event_signal; ct is a completion token.  If timeout
        elapses, raises socket.timeout.  If the token completes, checks
        ct.Status for errors."""
        if self.timeout < 0.0:
            while not es.status:
                efi.check_status(self._tcp4.Poll(self._tcp4))
        else:
            start = time.time()
            attempt_cancel = True
            while not es.status:
                if attempt_cancel and (time.time() - start >= self.timeout):
                    status = self._tcp4.Cancel(self._tcp4, byref(ct))
                    if status == efi.EFI_NOT_FOUND:
                        pass # Keep waiting for es.status
                    elif status == efi.EFI_UNSUPPORTED:
                        print("Warning: socket timeout expired but EFI can't Cancel; ignoring timeout")
                        attempt_cancel = False
                    else:
                        efi.check_status(status)
                        raise timeout("timed out")
                efi.check_status(self._tcp4.Poll(self._tcp4))
        efi.check_status(ct.Status)
Exemple #13
0
    def listen(self, backlog):
        """listen(backlog)

        Enable a server to accept connections.  The backlog argument must be at
        least 0 (if it is lower, it is set to 0); it specifies the number of
        unaccepted connections that the system will allow before refusing new
        connections."""
        # FIXME: Use queue depth as MaxSynBackLog
        global _subnet_mask, _routes
        if self._connect_status is not None:
            raise error("listen() called after connect()")
        if backlog < 0:
            backlog = 0
        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:
            # Special-case 0.0.0.0 because the EFI IP stack doesn't handle it
            if self._bind_ip == efi.EFI_IPv4_ADDRESS((0, 0, 0, 0)):
                data.AccessPoint.StationAddress = _ip_address
            else:
                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.ActiveFlag = False
        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)

        self._is_listen_socket = True
Exemple #14
0
    def listen(self, backlog):
        """listen(backlog)

        Enable a server to accept connections.  The backlog argument must be at
        least 0 (if it is lower, it is set to 0); it specifies the number of
        unaccepted connections that the system will allow before refusing new
        connections."""
        # FIXME: Use queue depth as MaxSynBackLog
        global _subnet_mask, _routes
        if self._connect_status is not None:
            raise error("listen() called after connect()")
        if backlog < 0:
            backlog = 0
        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:
            # Special-case 0.0.0.0 because the EFI IP stack doesn't handle it
            if self._bind_ip == efi.EFI_IPv4_ADDRESS((0, 0, 0, 0)):
                data.AccessPoint.StationAddress = _ip_address
            else:
                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.ActiveFlag = False
        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)

        self._is_listen_socket = True
Exemple #15
0
    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)
        start = time.time()
        while not self._read_ready():
            if self.timeout >= 0 and (time.time() - start >= self.timeout):
                raise timeout(11, "timed out")  # EAGAIN
        nbytes_read = 0
        dest = (c_uint8 * nbytes).from_buffer(buffer)
        while self._recv_queue and nbytes_read != nbytes:
            src = self._recv_queue[0]
            if isinstance(src, (int, long)):
                # Error; return it if we haven't yet collected any data
                if nbytes_read:
                    break
                efi.check_status(src)
            elif nbytes_read + sizeof(src) > nbytes:
                # Split src
                nbytes_to_copy = nbytes - nbytes_read
                memmove(
                    addressof(dest) + nbytes_read, addressof(src),
                    nbytes_to_copy)
                newsrc = create_string_buffer(sizeof(src) - nbytes_to_copy)
                memmove(addressof(newsrc),
                        addressof(src) + nbytes_to_copy, sizeof(newsrc))
                self._recv_queue[0] = newsrc
                nbytes_read = nbytes
            else:
                # Copy the entire src
                memmove(
                    addressof(dest) + nbytes_read, addressof(src), sizeof(src))
                self._recv_queue.pop(0)
                nbytes_read += sizeof(src)
        return nbytes_read
Exemple #16
0
def ip4cp_get_configuration(early=False):
    global _ip4cp, _ip_address, _subnet_mask, _routes, _initialized
    data = efi.EFI_IP4_IPCONFIG_DATA()
    size = efi.UINTN(sizeof(data))
    status = _ip4cp.GetData(_ip4cp, byref(size), byref(data))
    if status == efi.EFI_BUFFER_TOO_SMALL:
        resize(data, size.value)
        status = _ip4cp.GetData(_ip4cp, byref(size), byref(data))
    if early and status in (efi.EFI_NOT_STARTED, efi.EFI_NOT_READY):
        return
    efi.check_status(status)
    if data.StationAddress == efi.EFI_IPv4_ADDRESS((0, 0, 0, 0)):
        return
    _ip_address = data.StationAddress
    _subnet_mask = data.SubnetMask
    _routes = [efi.EFI_IP4_ROUTE_TABLE.from_buffer_copy(data.RouteTable[i]) for i in range(data.RouteTableSize)]
    _initialized = True
Exemple #17
0
    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)."""
        if not self._is_listen_socket:
            raise error("accept() called without listen()")
        start = time.time()
        while not self._read_ready():
            if self.timeout >= 0 and (time.time() - start >= self.timeout):
                raise timeout(11, "timed out") # EAGAIN
        success, value = self._accept_queue.pop(0)
        if success:
            s = socket(family=self.family, type=self.type, proto=self.proto, _handle=value)
            return s, s.getpeername()
        else:
            efi.check_status(value)
Exemple #18
0
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
Exemple #19
0
    def close(self):
        """"close()

        Close the socket.  It cannot be used after this call."""
        if hasattr(self, "closed") and self.closed:
            return
        token = efi.EFI_TCP4_CLOSE_TOKEN()
        def callback():
            if token.CompletionToken.Status:
                print("EFI_TCP4_PROTOCOL Close completed with an error:")
                print(efi.EFIException(token.CompletionToken.Status))
            self._events.close_event(efi.EFI_EVENT(token.CompletionToken.Event))
        token.CompletionToken.Event = self._events.create_event(callback, abort=self._abort)
        token.AbortOnClose = False
        status = self._tcp4.Close(self._tcp4, byref(token))
        if status:
            self._events.close_event(efi.EFI_EVENT(token.CompletionToken.Event))
            efi.check_status(status)
        self.closed = True
Exemple #20
0
    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)
        start = time.time()
        while not self._read_ready():
            if self.timeout >= 0 and (time.time() - start >= self.timeout):
                raise timeout(11, "timed out") # EAGAIN
        nbytes_read = 0
        dest = (c_uint8 * nbytes).from_buffer(buffer)
        while self._recv_queue and nbytes_read != nbytes:
            src = self._recv_queue[0]
            if isinstance(src, (int, long)):
                # Error; return it if we haven't yet collected any data
                if nbytes_read:
                    break
                efi.check_status(src)
            elif nbytes_read + sizeof(src) > nbytes:
                # Split src
                nbytes_to_copy = nbytes - nbytes_read
                memmove(addressof(dest) + nbytes_read, addressof(src), nbytes_to_copy)
                newsrc = create_string_buffer(sizeof(src) - nbytes_to_copy)
                memmove(addressof(newsrc), addressof(src) + nbytes_to_copy, sizeof(newsrc))
                self._recv_queue[0] = newsrc
                nbytes_read = nbytes
            else:
                # Copy the entire src
                memmove(addressof(dest) + nbytes_read, addressof(src), sizeof(src))
                self._recv_queue.pop(0)
                nbytes_read += sizeof(src)
        return nbytes_read
Exemple #21
0
def _init_sockets():
    global _initialized, _ip4cp, _done_event, _ip_address, _subnet_mask, _routes
    if _initialized:
        return
    _start_config()
    # Spin until configuration complete
    while not _done_event.signaled:
        pass
    data = efi.EFI_IP4_IPCONFIG_DATA()
    size = efi.UINTN(sizeof(data))
    status = _ip4cp.GetData(_ip4cp, byref(size), byref(data))
    if status == efi.EFI_BUFFER_TOO_SMALL:
        resize(data, size.value)
        status = _ip4cp.GetData(_ip4cp, byref(size), byref(data))
    efi.check_status(status)
    _ip_address = data.StationAddress
    _subnet_mask = data.SubnetMask
    _routes = [efi.EFI_IP4_ROUTE_TABLE.from_buffer_copy(data.RouteTable[i]) for i in range(data.RouteTableSize)]
    print("IP configuration complete: {}/{}".format(data.StationAddress, data.SubnetMask))
    _initialized = True
Exemple #22
0
def ip4cp_get_configuration(early=False):
    global _ip4cp, _ip_address, _subnet_mask, _routes, _initialized
    data = efi.EFI_IP4_IPCONFIG_DATA()
    size = efi.UINTN(sizeof(data))
    status = _ip4cp.GetData(_ip4cp, byref(size), byref(data))
    if status == efi.EFI_BUFFER_TOO_SMALL:
        resize(data, size.value)
        status = _ip4cp.GetData(_ip4cp, byref(size), byref(data))
    if early and status in (efi.EFI_NOT_STARTED, efi.EFI_NOT_READY):
        return
    efi.check_status(status)
    if data.StationAddress == efi.EFI_IPv4_ADDRESS((0, 0, 0, 0)):
        return
    _ip_address = data.StationAddress
    _subnet_mask = data.SubnetMask
    _routes = [
        efi.EFI_IP4_ROUTE_TABLE.from_buffer_copy(data.RouteTable[i])
        for i in range(data.RouteTableSize)
    ]
    _initialized = True
Exemple #23
0
    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)
Exemple #24
0
    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)."""
        if not self._is_listen_socket:
            raise error("accept() called without listen()")
        start = time.time()
        while not self._read_ready():
            if self.timeout >= 0 and (time.time() - start >= self.timeout):
                raise timeout(11, "timed out")  # EAGAIN
        success, value = self._accept_queue.pop(0)
        if success:
            s = socket(family=self.family,
                       type=self.type,
                       proto=self.proto,
                       _handle=value)
            return s, s.getpeername()
        else:
            efi.check_status(value)
Exemple #25
0
 def get_key():
     global stiex
     import efi
     import ctypes
     if stiex is None:
         stiex = efi.EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.from_handle(efi.system_table.ConsoleInHandle)
     key_data = efi.EFI_KEY_DATA()
     while True:
         ret = stiex.ReadKeyStrokeEx(stiex, ctypes.byref(key_data))
         if ret == efi.EFI_NOT_READY:
             continue
         efi.check_status(ret)
         mod = 0
         if key_data.KeyState.KeyShiftState & efi.EFI_SHIFT_STATE_VALID:
             mod = key_data.KeyState.KeyShiftState
         shift=bool(mod & (efi.EFI_LEFT_SHIFT_PRESSED | efi.EFI_RIGHT_SHIFT_PRESSED))
         ctrl=bool(mod & (efi.EFI_LEFT_CONTROL_PRESSED | efi.EFI_RIGHT_CONTROL_PRESSED))
         alt=bool(mod & (efi.EFI_LEFT_ALT_PRESSED | efi.EFI_RIGHT_ALT_PRESSED))
         if key_data.Key.UnicodeChar != '\x00':
             key = key_data.Key.UnicodeChar
         else:
             key = key_data.Key.ScanCode
         return KEY(key, shift, ctrl, alt)
Exemple #26
0
    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."""
        if isinstance(data, memoryview):
            data = data.tobytes()  # ctypes can't handle memoryview directly
        data = (c_uint8 * len(data)).from_buffer_copy(data)
        tx = efi.EFI_TCP4_TRANSMIT_DATA()
        tx.DataLength = len(data)
        tx.FragmentCount = 1
        tx.FragmentTable[0].FragmentLength = len(data)
        tx.FragmentTable[0].FragmentBuffer = cast(data, c_void_p)
        token = efi.EFI_TCP4_IO_TOKEN()
        send_status = []

        def callback():
            _ = data, tx  # Reference objects EFI will access, to keep them alive
            send_status.append(token.CompletionToken.Status)
            self._events.close_event(efi.EFI_EVENT(
                token.CompletionToken.Event))

        token.CompletionToken.Event = self._events.create_event(
            callback, abort=self._abort)
        token.Packet.TxData = pointer(tx)
        status = self._tcp4.Transmit(self._tcp4, byref(token))
        if status:
            self._events.close_event(efi.EFI_EVENT(
                token.CompletionToken.Event))
            efi.check_status(status)
            return
        while not send_status:
            self._poll()
        efi.check_status(send_status[0])
Exemple #27
0
    def close(self):
        """"close()

        Close the socket.  It cannot be used after this call."""
        if hasattr(self, "closed") and self.closed:
            return
        token = efi.EFI_TCP4_CLOSE_TOKEN()

        def callback():
            if token.CompletionToken.Status:
                print("EFI_TCP4_PROTOCOL Close completed with an error:")
                print(efi.EFIException(token.CompletionToken.Status))
            self._events.close_event(efi.EFI_EVENT(
                token.CompletionToken.Event))

        token.CompletionToken.Event = self._events.create_event(
            callback, abort=self._abort)
        token.AbortOnClose = False
        status = self._tcp4.Close(self._tcp4, byref(token))
        if status:
            self._events.close_event(efi.EFI_EVENT(
                token.CompletionToken.Event))
            efi.check_status(status)
        self.closed = True
Exemple #28
0
def _init_sockets_ip4c2p():
    global _ip4c2p, _initialized
    ip4c2p_get_configuration(early=True)
    if _initialized:
        return
    # To trigger DHCP, we need to change the policy to DHCP; if already set to
    # DHCP, we set it to static and then back to DHCP.
    data = efi.EFI_IP4_CONFIG2_POLICY()
    size = efi.UINTN(sizeof(data))
    efi.check_status(_ip4c2p.GetData(_ip4c2p, efi.Ip4Config2DataTypePolicy, byref(size), byref(data)))
    if data.value == efi.Ip4Config2PolicyDhcp:
        data.value = efi.Ip4Config2PolicyStatic
        efi.check_status(_ip4c2p.SetData(_ip4c2p, efi.Ip4Config2DataTypePolicy, sizeof(data), byref(data)))
    data.value = efi.Ip4Config2PolicyDhcp
    status = _ip4c2p.SetData(_ip4c2p, efi.Ip4Config2DataTypePolicy, sizeof(data), byref(data))
    if status != efi.EFI_NOT_READY:
        efi.check_status(status)
    while not _initialized:
        ip4c2p_get_configuration()
Exemple #29
0
    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)
Exemple #30
0
def _init_sockets_ip4c2p():
    global _ip4c2p, _initialized
    ip4c2p_get_configuration(early=True)
    if _initialized:
        return
    # To trigger DHCP, we need to change the policy to DHCP; if already set to
    # DHCP, we set it to static and then back to DHCP.
    data = efi.EFI_IP4_CONFIG2_POLICY()
    size = efi.UINTN(sizeof(data))
    efi.check_status(
        _ip4c2p.GetData(_ip4c2p, efi.Ip4Config2DataTypePolicy, byref(size),
                        byref(data)))
    if data.value == efi.Ip4Config2PolicyDhcp:
        data.value = efi.Ip4Config2PolicyStatic
        efi.check_status(
            _ip4c2p.SetData(_ip4c2p, efi.Ip4Config2DataTypePolicy,
                            sizeof(data), byref(data)))
    data.value = efi.Ip4Config2PolicyDhcp
    status = _ip4c2p.SetData(_ip4c2p, efi.Ip4Config2DataTypePolicy,
                             sizeof(data), byref(data))
    if status != efi.EFI_NOT_READY:
        efi.check_status(status)
    while not _initialized:
        ip4c2p_get_configuration()
Exemple #31
0
 def __del__(self):
     global _tcp4sbp
     # Only clean up if __init__ finished and we have a protocol to destroy
     if hasattr(self, "_tcp4"):
         self._abort()
         efi.check_status(_tcp4sbp.DestroyChild(_tcp4sbp, self._tcp4._handle))
Exemple #32
0
 def _poll(self):
     status = self._tcp4.Poll(self._tcp4)
     if status == efi.EFI_NOT_READY:
         return
     efi.check_status(status)
Exemple #33
0
    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
        if self._is_listen_socket:
            raise error("connect() called after listen()")
        if self._connect_status is not None:
            if self._connect_status:
                raise error(103, "Connection aborted") # ECONNABORTED
            else:
                raise error(106, "Already connected") # EISCONN
        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)

        token = efi.EFI_TCP4_CONNECTION_TOKEN()
        def callback():
            self._connect_status = token.CompletionToken.Status
            self._events.close_event(efi.EFI_EVENT(token.CompletionToken.Event))
        token.CompletionToken.Event = self._events.create_event(callback, abort=self._abort)
        status = self._tcp4.Connect(self._tcp4, byref(token))
        if status:
            token.CompletionToken.Status = status
            callback()

        if self.timeout == 0:
            raise error(115, "Operation now in progress") # EINPROGRESS
        start = time.time()
        while (self.timeout < 0) or (time.time() - start < self.timeout):
            if self._connect_status is not None:
                efi.check_status(self._connect_status)
                return
            self._poll()
        raise timeout(11, "timed out") # EAGAIN
Exemple #34
0
def _stop_config():
    global _ip4cp
    efi.check_status(_ip4cp.Stop(_ip4cp))
Exemple #35
0
def _ip4cp_stop_config():
    global _ip4cp
    efi.check_status(_ip4cp.Stop(_ip4cp))
Exemple #36
0
 def _poll(self):
     status = self._tcp4.Poll(self._tcp4)
     if status == efi.EFI_NOT_READY:
         return
     efi.check_status(status)
Exemple #37
0
    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
        if self._is_listen_socket:
            raise error("connect() called after listen()")
        if self._connect_status is not None:
            if self._connect_status:
                raise error(103, "Connection aborted")  # ECONNABORTED
            else:
                raise error(106, "Already connected")  # EISCONN
        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)

        token = efi.EFI_TCP4_CONNECTION_TOKEN()

        def callback():
            self._connect_status = token.CompletionToken.Status
            self._events.close_event(efi.EFI_EVENT(
                token.CompletionToken.Event))

        token.CompletionToken.Event = self._events.create_event(
            callback, abort=self._abort)
        status = self._tcp4.Connect(self._tcp4, byref(token))
        if status:
            token.CompletionToken.Status = status
            callback()

        if self.timeout == 0:
            raise error(115, "Operation now in progress")  # EINPROGRESS
        start = time.time()
        while (self.timeout < 0) or (time.time() - start < self.timeout):
            if self._connect_status is not None:
                efi.check_status(self._connect_status)
                return
            self._poll()
        raise timeout(11, "timed out")  # EAGAIN