def receive_annoted_file_descriptor(receive_socket): """Receive a single file descriptor and attached annotation information via SCM_RIGHTS via the given socket. The method may raise an Exception when invoked on non-blocking sockets and no messages available. @return a tuple containing the received file descriptor, type information (see sendAnnotatedFileDescriptor) and the annotation information.""" message_data, anc_data, _flags, _remote_address = receive_socket.recvmsg( 1 << 16, socket.CMSG_LEN(struct.calcsize('i'))) if len(anc_data) != 1: raise Exception('Received %d sets of ancillary data instead of 1' % len(anc_data)) cmsg_level, cmsg_type, cmsg_data = anc_data[0] if (cmsg_level != socket.SOL_SOCKET) or (cmsg_type != socket.SCM_RIGHTS): raise Exception('Received invalid message from remote side') # Do not accept multiple or unaligned FDs. if len(cmsg_data) != 4: raise Exception('Unsupported control message length %d' % len(cmsg_data)) received_fd = struct.unpack('i', cmsg_data)[0] split_pos = message_data.find(b'\x00') if split_pos < 0: raise Exception('No null byte in received message') type_info = message_data[:split_pos] annotation_data = message_data[split_pos + 1:] if received_fd <= 2: print('WARNING: received "reserved" fd %d' % received_fd, file=sys.stderr) if isinstance(type_info, str): type_info = type_info.encode() if isinstance(annotation_data, str): annotation_data = annotation_data.encode() return received_fd, type_info, annotation_data
def _read_ready(self): if self._conn_lost: return try: # 50 bytes is larger than sockaddr_in or sockaddr_in6 data, ancdata, _, src = self._sock.recvmsg(self.max_size, socket.CMSG_LEN(50)) dst = self._sock_addr for cmsg_level, cmsg_type, cmsg_data in ancdata: if cmsg_level == socket.SOL_IP and cmsg_type == IP_RECVORIGDSTADDR: dst = _native_sockaddr_to_python(cmsg_data) # on a dual stack, receive from IPv4 is possible, return mapped address like src if self._send_sock_v6 is not None and len(dst) == 2: dst = ("::ffff:" + dst[0], dst[1], 0, 0) except (BlockingIOError, InterruptedError): pass except OSError as exc: self._protocol.error_received(exc) except (SystemExit, KeyboardInterrupt): raise except BaseException as exc: self._fatal_error(exc, "Fatal read error on datagram transport") else: self._protocol.received_from(data, src, dst)
def recvfds(sock, size): '''Receive an array of fds over an AF_UNIX socket.''' a = array.array('i') bytes_size = a.itemsize * size msg, ancdata, flags, addr = sock.recvmsg(1, socket.CMSG_LEN(bytes_size)) if not msg and not ancdata: raise EOFError try: if ACKNOWLEDGE: sock.send(b'A') if len(ancdata) != 1: raise RuntimeError('received %d items of ancdata' % len(ancdata)) cmsg_level, cmsg_type, cmsg_data = ancdata[0] if (cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS): if len(cmsg_data) % a.itemsize != 0: raise ValueError a.frombytes(cmsg_data) assert len(a) % 256 == msg[0] return list(a) except (ValueError, IndexError): pass raise RuntimeError('Invalid data received')
def recv_fd(sock): msg, ancdata, flags, addr = sock.recvmsg( 1, socket.CMSG_LEN(struct.calcsize("i"))) cmsg_level, cmsg_type, cmsg_data = ancdata[0] assert cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS sock.sendall(b"OK") return struct.unpack("i", cmsg_data[0])
def receive_file_descriptors(self, sock: socket.SocketType) -> dict[str, Any]: """Receive file descriptors. See https://docs.python.org/3/library/socket.html#socket.socket.recvmsg . Protocol: 1. Size of the filenames array (json) (64bites, #filenames_length). 2. Filenames & file descriptors. 3. Wait for single byte to confirm. """ filenames_length = int.from_bytes(sock.recv(8), byteorder="big") logger.debug("Received file descriptors message of length: %d.", filenames_length) if filenames_length == 0: return dict() fds = array.array("i") # Array of ints msg, ancdata, flags, addr = sock.recvmsg( filenames_length, socket.CMSG_LEN(DESCRIPTOR_CHUNK_SIZE * fds.itemsize)) logger.debug("Received file descriptors: %s, %s.", msg, ancdata) filenames = json.loads(msg.decode()) for cmsg_level, cmsg_type, cmsg_data in ancdata: if cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS: # Append data, ignoring any truncated integers at the end. fds.frombytes(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) return dict(zip(filenames, fds))
def receive(sock_info): # pylint:disable=too-many-locals (sock, interface_name, interface_index) = sock_info ancillary_size = socket.CMSG_LEN(MAX_SIZE) try: message, ancillary_messages, _msg_flags, source = sock.recvmsg( MAX_SIZE, ancillary_size) message_str = message.decode() except Exception as exception: report("exception {} while receiving on {}".format( exception, interface_name)) else: rx_interface_index = None for anc in ancillary_messages: # pylint:disable=no-member if anc[0] == socket.SOL_IP and anc[1] == socket.IP_PKTINFO: packet_info = in_pktinfo.from_buffer_copy(anc[2]) rx_interface_index = packet_info.ipi_ifindex elif anc[0] == socket.SOL_IPV6 and anc[1] == socket.IPV6_PKTINFO: packet_info = in6_pktinfo.from_buffer_copy(anc[2]) rx_interface_index = packet_info.ipi6_ifindex if rx_interface_index and (rx_interface_index != interface_index): return report("received {} on {} from {}".format(message_str, interface_name, source))
async def receive_fds(self, msglen: int, maxfds: int) -> Tuple[bytes, List[int]]: if not isinstance(msglen, int) or msglen < 0: raise ValueError('msglen must be a non-negative integer') if not isinstance(maxfds, int) or maxfds < 1: raise ValueError('maxfds must be a positive integer') fds = array.array("i") await checkpoint() with self._receive_guard: while True: try: message, ancdata, flags, addr = await self._trio_socket.recvmsg( msglen, socket.CMSG_LEN(maxfds * fds.itemsize)) except BaseException as exc: self._convert_socket_error(exc) else: if not message and not ancdata: raise EndOfStream break for cmsg_level, cmsg_type, cmsg_data in ancdata: if cmsg_level != socket.SOL_SOCKET or cmsg_type != socket.SCM_RIGHTS: raise RuntimeError( f'Received unexpected ancillary data; message = {message}, ' f'cmsg_level = {cmsg_level}, cmsg_type = {cmsg_type}') fds.frombytes(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) return message, list(fds)
def receive_file_descriptors( self, sock: socket.SocketType) -> Tuple[str, dict[str, Any], bool]: """Receive file descriptors. See https://docs.python.org/3/library/socket.html#socket.socket.recvmsg . Protocol: 1. Size of the filenames array (json) (64bites, #filenames_length). 2. Connector name, filenames, presigned flag & file descriptors. 3. Send response in the form {"success": bool, "presigned_urls": list}. """ filenames_length = int.from_bytes(sock.recv(8), byteorder="big") logger.debug("Received file descriptors message of length: %d.", filenames_length) if filenames_length == 0: return ("", dict(), False) fds = array.array("i") # Array of ints msg, ancdata, flags, addr = sock.recvmsg( filenames_length, socket.CMSG_LEN(DESCRIPTOR_CHUNK_SIZE * fds.itemsize)) logger.debug("Received file descriptors: %s, %s.", msg, ancdata) storage_name, filenames, need_presigned_urls = json.loads(msg.decode()) for cmsg_level, cmsg_type, cmsg_data in ancdata: if cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS: # Append data, ignoring any truncated integers at the end. fds.frombytes(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) return (storage_name, dict(zip(filenames, fds)), need_presigned_urls)
def _ReceiveFDs(sock): """Receives FDs from ash-chrome that will be used to launch lacros-chrome. Args: sock: A connected unix domain socket. Returns: File objects for the mojo connection and maybe startup data file. """ # This function is borrowed from with modifications: # https://docs.python.org/3/library/socket.html#socket.socket.recvmsg fds = array.array("i") # Array of ints # Along with the file descriptor, ash-chrome also sends the version in the # regular data. version, ancdata, _, _ = sock.recvmsg(1, socket.CMSG_LEN(fds.itemsize)) for cmsg_level, cmsg_type, cmsg_data in ancdata: if cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS: # New ash-chrome returns two FDs: one for mojo connection, and the second # for the startup data FD. Old one returns only the mojo connection. # TODO(crbug.com/1156033): Clean up the code after dropping the # old protocol support. assert len(cmsg_data) in (fds.itemsize, fds.itemsize * 2), ('Expecting exactly 1 or 2 FDs') fds.frombytes(cmsg_data[:]) assert version == b'\x00', 'Expecting version code to be 0' assert len(fds) in (1, 2), 'Expecting exactly 1 or 2 FDs' mojo_fd = os.fdopen(fds[0]) startup_fd = None if len(fds) < 2 else os.fdopen(fds[1]) return mojo_fd, startup_fd
def receive_fd(self): '''Receive a file descriptor over UNIX domain socket using recvmsg.''' # A message to signal we are ready for the fd msg self.send_msg(self.cur_hdr[0], EMPTY_STRUCT, EMPTY_TUPLE) fds = array.array("i") # Array of ints maxfds = 1 msglen = 1 while True: try: _, ancdata, _, _ = self.socket.recvmsg( msglen, socket.CMSG_LEN(maxfds * fds.itemsize)) break except BlockingIOError: pass for cmsg_level, cmsg_type, cmsg_data in ancdata: if cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS: # Append data, ignoring any truncated integers at the end. fds.fromstring(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) fds_list = list(fds) if len(fds_list) != 1: logging.error('Expecting a single file descriptor') raise exception(errno.EINVAL) return fds_list[0]
def _recv_raw(self, sock, x): """Internal function to receive a Packet, and process ancillary data. """ flags_len = socket.CMSG_LEN(4096) timestamp = None pkt, ancdata, flags, sa_ll = sock.recvmsg(x, flags_len) if not pkt: return pkt, sa_ll for cmsg_lvl, cmsg_type, cmsg_data in ancdata: # Check available ancillary data if (cmsg_lvl == SOL_PACKET and cmsg_type == PACKET_AUXDATA): # Parse AUXDATA auxdata = tpacket_auxdata.from_buffer_copy(cmsg_data) if auxdata.tp_vlan_tci != 0 or \ auxdata.tp_status & TP_STATUS_VLAN_VALID: # Insert VLAN tag tag = struct.pack("!HH", ETH_P_8021Q, auxdata.tp_vlan_tci) pkt = pkt[:12] + tag + pkt[12:] elif cmsg_lvl == socket.SOL_SOCKET and \ cmsg_type == SO_TIMESTAMPNS: length = len(cmsg_data) if length == 16: # __kernel_timespec tmp = struct.unpack("ll", cmsg_data) elif length == 8: # timespec tmp = struct.unpack("ii", cmsg_data) else: log_runtime.warning("Unknown timespec format.. ?!") continue timestamp = tmp[0] + tmp[1] * 1e-9 return pkt, sa_ll, timestamp
def recv_sock(pr): ancsize = socket.CMSG_LEN(struct.calcsize('i')) msg, ancdata, flags, addr = pr.recvmsg(1, ancsize) cmsg_level, cmsg_type, cmsg_data = ancdata[0] fd = struct.unpack('i', cmsg_data)[0] sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, fileno=fd) return sock
def recvfrom(s, sz): _to = None data, ancdata, msg_flags, _from = s.recvmsg( sz, socket.CMSG_LEN(sz)) for anc in ancdata: if anc[0] == socket.SOL_IP and anc[1] == socket.IP_PKTINFO: addr = in_pktinfo.from_buffer_copy(anc[2]) addr = ipaddress.IPv4Address( memoryview(addr.ipi_addr).tobytes()) _to = (str(addr), s.getsockname()[1]) break elif anc[0] == socket.SOL_IPV6 and anc[ 1] == socket.IPV6_PKTINFO: addr = in6_pktinfo.from_buffer_copy(anc[2]) addr = ipaddress.ip_address( memoryview(addr.ipi6_addr).tobytes()) _to = (str(addr), s.getsockname()[1]) break debug.logger & debug.flagIO and debug.logger( 'recvfrom: received %d octets from %s to %s; ' 'iov blob %r' % (len(data), _from, _to, ancdata)) return data, addressType(_from).setLocalAddress(_to)
def recv_fds(sock, msglen, maxfds): fds = array.array("i") # Array of ints msg, ancdata, flags, addr = sock.recvmsg(msglen, socket.CMSG_LEN(maxfds * fds.itemsize)) for cmsg_level, cmsg_type, cmsg_data in ancdata: if cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS: fds.frombytes(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) return msg, list(fds)
def recv_fd(sock): '''Get file descriptor for memory map''' fds = array.array("i") # Array of ints _, ancdata, _, _ = sock.recvmsg(0, socket.CMSG_LEN(4)) for cmsg_level, cmsg_type, cmsg_data in ancdata: if cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS: fds.frombytes(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) return list(fds)[0]
def recv_socket(s): data, ancdata, msg_flags, address = s.recvmsg( 4, socket.CMSG_LEN(sys.getsizeof(int()))) for cmsg_level, cmsg_type, cmsg_data in ancdata: if (cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS): return data.decode(), BufferedSocketReader( fileno=int.from_bytes(cmsg_data, sys.byteorder))
def recv_fds(sock, msglen, maxfds): fds = array.array("i") # Array of ints msg, ancdata, flags, addr = sock.recvmsg(msglen, socket.CMSG_LEN(maxfds * fds.itemsize)) for cmsg_level, cmsg_type, cmsg_data in ancdata: if (cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS): # Append data, ignoring any truncated integers at the end. fds.fromstring(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) return msg, list(fds)
def loop_slave(pr, handlers): while True: bufsize = 1 ancsize = socket.CMSG_LEN(struct.calcsize('i')) msg, ancdata, flags, addr = pr.recvmsg(bufsize, ancsize) cmsg_level, cmsg_type, cmsg_data = ancdata[0] fd = struct.unpack('i', cmsg_data)[0] sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, fileno=fd) handle_conn(sock, sock.getpeername(), handlers)
def recv(self): """Receive a Message This receives the next pending message from the socket. This operation is synchronous. A tuple consisting of the deserialized message payload, the auxiliary file-descriptor set, and the socket-address of the sender is returned. """ # On `SOCK_DGRAM`, packets might be arbitrarily sized. There is no # hard-coded upper limit, since it is only restricted by the size of # the kernel write buffer on sockets (which itself can be modified via # sysctl). The only real maximum is probably something like 2^31-1, # since that is the maximum of that sysctl datatype. # Anyway, `MSG_TRUNC+MSG_PEEK` usually allows us to easily peek at the # incoming buffer. Unfortunately, the python `recvmsg()` wrapper # discards the return code and we cannot use that. Instead, we simply # loop until we know the size. This is slightly awkward, but seems fine # as long as you do not put this into a hot-path. size = 4096 while True: peek = self._socket.recvmsg(size, 0, socket.MSG_PEEK) if not (peek[2] & socket.MSG_TRUNC): break size *= 2 # Fetch a packet from the socket. On linux, the maximum SCM_RIGHTS array # size is hard-coded to 253. This allows us to size the ancillary buffer # big enough to receive any possible message. fds = array.array("i") msg = self._socket.recvmsg(size, socket.CMSG_LEN(253 * fds.itemsize)) # First thing we do is always to fetch the CMSG FDs into an FdSet. This # guarantees that we do not leak FDs in case the message handling fails # for other reasons. for level, ty, data in msg[1]: if level == socket.SOL_SOCKET and ty == socket.SCM_RIGHTS: assert len(data) % fds.itemsize == 0 fds.frombytes(data) fdset = FdSet(rawfds=fds) # Check the returned message flags. If the message was truncated, we # have to discard it. This shouldn't happen, but there is no harm in # handling it. However, `CTRUNC` can happen, since it is also triggered # when LSMs reject FD transmission. Treat it the same as a parser error. flags = msg[2] if flags & (socket.MSG_TRUNC | socket.MSG_CTRUNC): raise BufferError try: payload = json.loads(msg[0]) except json.JSONDecodeError: raise BufferError return (payload, fdset, msg[3])
def recv_fd(sock): """ Receive a single file descriptor """ msg, ancdata, flags, addr = sock.recvmsg( 1, socket.CMSG_LEN(struct.calcsize('i'))) cmsg_level, cmsg_type, cmsg_data = ancdata[0] assert cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS sock.sendall(b'OK') return struct.unpack('i', cmsg_data)[0]
def load_fds(sock, msglen): fds = array.array("i") # Array of ints msg, ancdata, _, addr = sock.recvmsg(msglen, socket.CMSG_LEN(253 * fds.itemsize)) for cmsg_level, cmsg_type, cmsg_data in ancdata: if (cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS): # Append data, ignoring any truncated integers at the end. fds.frombytes(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) return json.loads(msg), list(fds), addr
def read_fd(sock): """Read a descriptor from the socket.""" data_size, ancdata_size = 1, socket.CMSG_LEN(struct.calcsize(FMT)) # read the data and ancillary data from the UNIX domain socket # we're interested only in ancillary data that contains descriptor msg, ancdata, flags, addr = sock.recvmsg(data_size, ancdata_size) cmsg_level, cmsg_type, cmsg_data = ancdata[0] if cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS: fd = struct.unpack(FMT, cmsg_data)[0] return fd
def recv_handle(conn): size = struct.calcsize("@i") with socket.fromfd(conn.fileno(), socket.AF_UNIX, socket.SOCK_STREAM) as s: msg, ancdata, flags, addr = s.recvmsg(1, socket.CMSG_LEN(size)) try: cmsg_level, cmsg_type, cmsg_data = ancdata[0] if (cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS): return struct.unpack("@i", cmsg_data[:size])[0] except (ValueError, IndexError, struct.error): pass raise RuntimeError('Invalid data received')
def _ReceiveFDs(sock): """Receives FDs from ash-chrome that will be used to launch lacros-chrome. Args: sock: A connected unix domain socket. Returns: File objects for the mojo connection and maybe startup data file. """ # This function is borrowed from with modifications: # https://docs.python.org/3/library/socket.html#socket.socket.recvmsg fds = array.array("i") # Array of ints # Along with the file descriptor, ash-chrome also sends the version in the # regular data. version, ancdata, _, _ = sock.recvmsg( 1, socket.CMSG_LEN(fds.itemsize * _NUM_FDS_MAX)) for cmsg_level, cmsg_type, cmsg_data in ancdata: if cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS: # There are three versions currently this script supports. # The oldest one: ash-chrome returns one FD, the mojo connection of # old bootstrap procedure (i.e., it will be BrowserService). # The middle one: ash-chrome returns two FDs, the mojo connection of # old bootstrap procedure, and the second for the start up data FD. # The newest one: ash-chrome returns three FDs, the mojo connection of # old bootstrap procedure, the second for the start up data FD, and # the third for another mojo connection of new bootstrap procedure. # TODO(crbug.com/1156033): Clean up the code to drop the support of # oldest one after M91. # TODO(crbug.com/1180712): Clean up the mojo procedure support of the # the middle one after M92. cmsg_len_candidates = [(i + 1) * fds.itemsize for i in range(_NUM_FDS_MAX)] assert len(cmsg_data) in cmsg_len_candidates, ( 'CMSG_LEN is unexpected: %d' % (len(cmsg_data), )) fds.frombytes(cmsg_data[:]) if version == b'\x00': assert len(fds) in (1, 2, 3), 'Expecting exactly 1, 2, or 3 FDs' legacy_mojo_fd = os.fdopen(fds[0]) startup_fd = None if len(fds) < 2 else os.fdopen(fds[1]) mojo_fd = None if len(fds) < 3 else os.fdopen(fds[2]) elif version == b'\x01': assert len(fds) == 2, 'Expecting exactly 2 FDs' legacy_mojo_fd = None startup_fd = os.fdopen(fds[0]) mojo_fd = os.fdopen(fds[1]) elif version: raise AssertionError('Unknown version: \\x%s' % version.hex()) else: raise AssertionError( 'Failed to receive startup message from ash-chrome. ' 'Make sure you\'re logged in to Chrome OS.') return legacy_mojo_fd, startup_fd, mojo_fd
def _recv_fds(sock, bufsize, maxfds, flags=0): fds = array.array('i') msg, ancdata, flags, addr = sock.recvmsg( bufsize, socket.CMSG_LEN(maxfds * fds.itemsize), flags, ) for cmsg_level, cmsg_type, cmsg_data in ancdata: if cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS: fds.frombytes(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) return msg, list(fds), flags, addr
def recv_fds(self): assert self._mode == 'receiver' fds = array.array('i') msg, ancdata, msg_flags, address = self.receiver.recvmsg( self.fixed_msg_len, socket.CMSG_LEN(self.max_fds * fds.itemsize)) for cmsg_level, cmsg_type, cmsg_data in ancdata: if (cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS): truncated = len(cmsg_data) % fds.itemsize fds.frombytes(cmsg_data[:len(cmsg_data) - truncated]) return msg, fds
def recv_fds(sock, msglen, maxfds): """ Receive FDs from the unix socket. Copy-pasted from the Python doc. Used only if both grading and student containers are using docker runtime""" fds = array.array("i") # Array of ints msg, ancdata, _, addr = sock.recvmsg( msglen, socket.CMSG_LEN(maxfds * fds.itemsize)) for cmsg_level, cmsg_type, cmsg_data in ancdata: if (cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS): # Append data, ignoring any truncated integers at the end. fds.fromstring(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) return msg, list(fds)
def recvfrom(s, sz): _to = None data, ancdata, msg_flags, _from = s.recvmsg(sz, socket.CMSG_LEN(sz)) for anc in ancdata: if anc[0] == socket.SOL_IP and anc[1] == socket.IP_PKTINFO: addr = in_pktinfo.from_buffer_copy(anc[2]) addr = ipaddress.IPv4Address(memoryview(addr.ipi_addr).tobytes()) _to = (str(addr), s.getsockname()[1]) elif anc[0] == socket.SOL_IPV6 and anc[1] == socket.IPV6_PKTINFO: addr = in6_pktinfo.from_buffer_copy(anc[2]) addr = ipaddress.ip_address(memoryview(addr.ipi6_addr).tobytes()) _to = (str(addr), s.getsockname()[1]) return data, addressType(_from).setLocalAddress(_to)
def recvfromto(s): _to = None data, ancdata, msg_flags, _from = s.recvmsg(5120, socket.CMSG_LEN(5120 * 5)) for anc in ancdata: if anc[0] == socket.SOL_IP and anc[1] == IP_PKTINFO: addr = in_pktinfo.from_buffer_copy(anc[2]) addr = ipaddress.IPv4Address(memoryview(addr.ipi_addr).tobytes()) _to = (str(addr), s.getsockname()[1]) elif anc[0] == SOL_IPV6 and anc[1] == IPV6_PKTINFO: addr = in6_pktinfo.from_buffer_copy(anc[2]) addr = ipaddress.ip_address(memoryview(addr.ipi6_addr).tobytes()) _to = (str(addr), s.getsockname()[1]) return data, _from, _to
def _recv_raw(self, sock, x): # type: (socket.socket, int) -> Tuple[bytes, Any, Optional[float]] """Internal function to receive a Packet, and process ancillary data. """ timestamp = None if not self.auxdata_available: pkt, _, _, sa_ll = sock.recvmsg(x) return pkt, sa_ll, timestamp flags_len = socket.CMSG_LEN(4096) pkt, ancdata, flags, sa_ll = sock.recvmsg(x, flags_len) if not pkt: return pkt, sa_ll, timestamp for cmsg_lvl, cmsg_type, cmsg_data in ancdata: # Check available ancillary data if (cmsg_lvl == SOL_PACKET and cmsg_type == PACKET_AUXDATA): # Parse AUXDATA try: auxdata = tpacket_auxdata.from_buffer_copy(cmsg_data) except ValueError: # Note: according to Python documentation, recvmsg() # can return a truncated message. A ValueError # exception likely indicates that Auxiliary # Data is not supported by the Linux kernel. return pkt, sa_ll, timestamp if auxdata.tp_vlan_tci != 0 or \ auxdata.tp_status & TP_STATUS_VLAN_VALID: # Insert VLAN tag tpid = ETH_P_8021Q if auxdata.tp_status & TP_STATUS_VLAN_TPID_VALID: tpid = auxdata.tp_vlan_tpid tag = struct.pack( "!HH", tpid, auxdata.tp_vlan_tci ) pkt = pkt[:12] + tag + pkt[12:] elif cmsg_lvl == socket.SOL_SOCKET and \ cmsg_type == SO_TIMESTAMPNS: length = len(cmsg_data) if length == 16: # __kernel_timespec tmp = struct.unpack("ll", cmsg_data) elif length == 8: # timespec tmp = struct.unpack("ii", cmsg_data) else: log_runtime.warning("Unknown timespec format.. ?!") continue timestamp = tmp[0] + tmp[1] * 1e-9 return pkt, sa_ll, timestamp