def run(self): r, w = os.pipe() r = pack('i', r) sendmsg(socket=self.sock, data=b'b', ancillary=[(SOL_SOCKET, SCM_RIGHTS, r)]) os.write(w, b'Hello')
def test_roundtripEmptyAncillary(self): """ L{sendmsg} treats an empty ancillary data list the same way it treats receiving no argument for the ancillary parameter at all. """ sendmsg(self.input, b"hello, world!", [], 0) result = recvmsg(self.output) self.assertEqual(result, (b"hello, world!", [], 0))
def test_multiFileDescriptorReceivedPerRecvmsg(self): """ _SendmsgMixin handles multiple file descriptors per recvmsg, calling L{IFileDescriptorReceiver.fileDescriptorReceived} once per received file descriptor. """ # Strategy: # - Create a UNIX socketpair. # - Associate one end to a FakeReceiver and FakeProtocol. # - Call sendmsg on the other end with two FDs as ancillary data. # - Call doRead in the FakeReceiver. # - Verify results on FakeProtocol. # TODO: replace FakeReceiver test approach with one based in # IReactorSocket.adoptStreamConnection once AF_UNIX support is # implemented; see https://twistedmatrix.com/trac/ticket/5573. from socket import socketpair from twisted.internet.unix import _SendmsgMixin from twisted.python.sendmsg import sendmsg, SCM_RIGHTS @implementer(IFileDescriptorReceiver) class FakeProtocol(ConnectableProtocol): def __init__(self): self.fds = [] def fileDescriptorReceived(self, fd): self.fds.append(fd) close(fd) class FakeReceiver(_SendmsgMixin): bufferSize = 1024 def __init__(self, skt, proto): self.socket = skt self.protocol = proto def _dataReceived(self, data): pass sendSocket, recvSocket = socketpair(AF_UNIX, SOCK_STREAM) self.addCleanup(sendSocket.close) self.addCleanup(recvSocket.close) proto = FakeProtocol() receiver = FakeReceiver(recvSocket, proto) dataToSend = b'some data needs to be sent' fdsToSend = [sendSocket.fileno(), recvSocket.fileno()] ancillary = [(SOL_SOCKET, SCM_RIGHTS, pack('ii', *fdsToSend))] sendmsg(sendSocket, dataToSend, ancillary) receiver.doRead() # Verify that fileDescriptorReceived was called twice. self.assertEqual(len(proto.fds), 2) # Verify that received FDs are different from the sent ones. self.assertFalse(set(fdsToSend).intersection(set(proto.fds)))
def server(): sock = socket.socket(socket.AF_UNIX) if os.path.exists('unix_sock'): os.remove('unix_sock') sock.bind('unix_sock') sock.listen(11) conn, addr = sock.accept() r, w = os.pipe() sendmsg(conn, b'0', [(SOL_SOCKET, SCM_RIGHTS, pack('i', r))]) os.write(w, b'HYYYYY!')
def main(): foo, bar = socketpair() sent = sendmsg(foo, b"Hello, world") print("Sent", sent, "bytes") (received, ancillary, flags) = recvmsg(bar, 1024) print("Received", repr(received)) print("Extra stuff, boring in this case", flags, ancillary)
def test_flags(self): """ The C{flags} argument to L{sendmsg} is passed on to the underlying C{sendmsg} call, to affect it in whatever way is defined by those flags. """ # Just exercise one flag with simple, well-known behavior. MSG_DONTWAIT # makes the send a non-blocking call, even if the socket is in blocking # mode. See also test_flags in RecvmsgTests for i in range(8 * 1024): try: sendmsg(self.input, b"x" * 1024, flags=MSG_DONTWAIT) except error as e: self.assertEqual(e.args[0], errno.EAGAIN) break else: self.fail("Failed to fill up the send buffer, " "or maybe send1msg blocked for a while")
def test_flags(self): """ The C{flags} argument to L{sendmsg} is passed on to the underlying C{sendmsg} call, to affect it in whatever way is defined by those flags. """ # Just exercise one flag with simple, well-known behavior. MSG_DONTWAIT # makes the send a non-blocking call, even if the socket is in blocking # mode. See also test_flags in RecvmsgTests for i in range(1024): try: sendmsg(self.input, b"x" * 1024, flags=MSG_DONTWAIT) except error as e: self.assertEqual(e.args[0], errno.EAGAIN) break else: self.fail( "Failed to fill up the send buffer, " "or maybe send1msg blocked for a while")
def test_roundtrip(self): """ L{recvmsg} will retrieve a message sent via L{sendmsg}. """ message = b"hello, world!" self.assertEqual(len(message), sendmsg(self.input, message)) result = recvmsg(self.output) self.assertEqual(result.data, b"hello, world!") self.assertEqual(result.flags, 0) self.assertEqual(result.ancillary, [])
def test_sendSubProcessFD(self): """ Calling L{sendmsg} with SOL_SOCKET, SCM_RIGHTS, and a platform-endian packed file descriptor number should send that file descriptor to a different process, where it can be retrieved by using L{recv1msg}. """ sspp = _spawn("pullpipe", self.output.fileno()) yield sspp.started pipeOut, pipeIn = _makePipe() self.addCleanup(pipeOut.close) self.addCleanup(pipeIn.close) with pipeIn: sendmsg(self.input, b"blonk", [(SOL_SOCKET, SCM_RIGHTS, pack("i", pipeIn.fileno()))]) yield sspp.stopped self.assertEqual(read(pipeOut.fileno(), 1024), b"Test fixture data: blonk.\n") # Make sure that the pipe is actually closed now. self.assertEqual(read(pipeOut.fileno(), 1024), b"")
def test_shortsend(self): """ L{sendmsg} returns the number of bytes which it was able to send. """ message = b"x" * 1024 * 1024 self.input.setblocking(False) sent = sendmsg(self.input, message) # Sanity check - make sure the amount of data we sent was less than the # message, but not the whole message, as we should have filled the send # buffer. This won't work if the send buffer is more than 1MB, though. self.assertTrue(sent < len(message)) received = recvmsg(self.output, len(message)) self.assertEqual(len(received[0]), sent)
def test_roundtrip(self): """ L{recvmsg} will retrieve a message sent via L{sendmsg}. """ message = b"hello, world!" self.assertEqual( len(message), sendmsg(self.input, message)) result = recvmsg(self.output) self.assertEqual(result.data, b"hello, world!") self.assertEqual(result.flags, 0) self.assertEqual(result.ancillary, [])
def test_sendSubProcessFD(self): """ Calling L{sendmsg} with SOL_SOCKET, SCM_RIGHTS, and a platform-endian packed file descriptor number should send that file descriptor to a different process, where it can be retrieved by using L{recv1msg}. """ sspp = _spawn("pullpipe", self.output.fileno()) yield sspp.started pipeOut, pipeIn = _makePipe() self.addCleanup(pipeOut.close) self.addCleanup(pipeIn.close) with pipeIn: sendmsg( self.input, b"blonk", [(SOL_SOCKET, SCM_RIGHTS, pack("i", pipeIn.fileno()))]) yield sspp.stopped self.assertEqual(read(pipeOut.fileno(), 1024), b"Test fixture data: blonk.\n") # Make sure that the pipe is actually closed now. self.assertEqual(read(pipeOut.fileno(), 1024), b"")
def sendMessage(self, msg): """ @type msg: L{message.DBusMessage} @param msg: A L{message.DBusMessage} instance to send over the connection """ assert isinstance(msg, message.DBusMessage) if hasattr(msg, 'oobFDs') and msg.oobFDs: sent = sendmsg(self.transport.socket, msg.rawMessage, [(socket.SOL_SOCKET, SCM_RIGHTS, struct.pack("i" * len(msg.oobFDs), *msg.oobFDs))]) assert sent == len(msg.rawMessage) else: self.transport.write(msg.rawMessage)
def main(): foo, bar = socketpair() reader, writer = pipe() # Send a copy of the descriptor. Notice that there must be at least one # byte of normal data passed in. sent = sendmsg(foo, b"\x00", [(SOL_SOCKET, SCM_RIGHTS, pack("i", reader))]) # Receive the copy, including that one byte of normal data. data, ancillary, flags = recvmsg(bar, 1024) duplicate = unpack("i", ancillary[0][2])[0] # Demonstrate that the copy works just like the original write(writer, b"Hello, world") print("Read from original (%d): %r" % (reader, read(reader, 6))) print("Read from duplicate (%d): %r" % (duplicate, read(duplicate, 6)))
def main(): foo, bar = socketpair() reader, writer = pipe() # Send a copy of the descriptor. Notice that there must be at least one # byte of normal data passed in. sent = sendmsg( foo, b"\x00", [(SOL_SOCKET, SCM_RIGHTS, pack("i", reader))]) # Receive the copy, including that one byte of normal data. data, ancillary, flags = recvmsg(bar, 1024) duplicate = unpack("i", ancillary[0][2])[0] # Demonstrate that the copy works just like the original write(writer, b"Hello, world") print("Read from original (%d): %r" % (reader, read(reader, 6))) print("Read from duplicate (%d): %r" % (duplicate, read(duplicate, 6)))
def _sendmsgMixinFileDescriptorReceivedDriver(self, ancillaryPacker): """ Drive _SendmsgMixin via sendmsg socket calls to check that L{IFileDescriptorReceiver.fileDescriptorReceived} is called once for each file descriptor received in the ancillary messages. @param ancillaryPacker: A callable that will be given a list of two file descriptors and should return a two-tuple where: The first item is an iterable of zero or more (cmsg_level, cmsg_type, cmsg_data) tuples in the same order as the given list for actual sending via sendmsg; the second item is an integer indicating the expected number of FDs to be received. """ # Strategy: # - Create a UNIX socketpair. # - Associate one end to a FakeReceiver and FakeProtocol. # - Call sendmsg on the other end to send FDs as ancillary data. # Ancillary data is obtained calling ancillaryPacker with # the two FDs associated to two temp files (using the socket # FDs for this fails the device/inode verification tests on # macOS 10.10, so temp files are used instead). # - Call doRead in the FakeReceiver. # - Verify results on FakeProtocol. # Using known device/inodes to verify correct order. # TODO: replace FakeReceiver test approach with one based in # IReactorSocket.adoptStreamConnection once AF_UNIX support is # implemented; see https://twistedmatrix.com/trac/ticket/5573. from socket import socketpair from twisted.internet.unix import _SendmsgMixin from twisted.python.sendmsg import sendmsg def deviceInodeTuple(fd): fs = fstat(fd) return (fs.st_dev, fs.st_ino) @implementer(IFileDescriptorReceiver) class FakeProtocol(ConnectableProtocol): def __init__(self): self.fds = [] self.deviceInodesReceived = [] def fileDescriptorReceived(self, fd): self.fds.append(fd) self.deviceInodesReceived.append(deviceInodeTuple(fd)) close(fd) class FakeReceiver(_SendmsgMixin): bufferSize = 1024 def __init__(self, skt, proto): self.socket = skt self.protocol = proto def _dataReceived(self, data): pass def getHost(self): pass def getPeer(self): pass def _getLogPrefix(self, o): pass sendSocket, recvSocket = socketpair(AF_UNIX, SOCK_STREAM) self.addCleanup(sendSocket.close) self.addCleanup(recvSocket.close) proto = FakeProtocol() receiver = FakeReceiver(recvSocket, proto) # Temp files give us two FDs to send/receive/verify. fileOneFD, fileOneName = mkstemp() fileTwoFD, fileTwoName = mkstemp() self.addCleanup(unlink, fileOneName) self.addCleanup(unlink, fileTwoName) dataToSend = b'some data needs to be sent' fdsToSend = [fileOneFD, fileTwoFD] ancillary, expectedCount = ancillaryPacker(fdsToSend) sendmsg(sendSocket, dataToSend, ancillary) receiver.doRead() # Verify that fileDescriptorReceived was called twice. self.assertEqual(len(proto.fds), expectedCount) # Verify that received FDs are different from the sent ones. self.assertFalse(set(fdsToSend).intersection(set(proto.fds))) # Verify that FDs were received in the same order, if any. if proto.fds: deviceInodesSent = [deviceInodeTuple(fd) for fd in fdsToSend] self.assertEqual(deviceInodesSent, proto.deviceInodesReceived)
def _sendmsgMixinFileDescriptorReceivedDriver(self, ancillaryPacker): """ Drive _SendmsgMixin via sendmsg socket calls to check that L{IFileDescriptorReceiver.fileDescriptorReceived} is called once for each file descriptor received in the ancillary messages. @param ancillaryPacker: A callable that will be given a list of two file descriptors and should return a two-tuple where: The first item is an iterable of zero or more (cmsg_level, cmsg_type, cmsg_data) tuples in the same order as the given list for actual sending via sendmsg; the second item is an integer indicating the expected number of FDs to be received. """ # Strategy: # - Create a UNIX socketpair. # - Associate one end to a FakeReceiver and FakeProtocol. # - Call sendmsg on the other end to send FDs as ancillary data. # Ancillary data is obtained calling ancillaryPacker with # the two FDs associated to two temp files (using the socket # FDs for this fails the device/inode verification tests on # Mac OS X 10.10, so temp files are used instead). # - Call doRead in the FakeReceiver. # - Verify results on FakeProtocol. # Using known device/inodes to verify correct order. # TODO: replace FakeReceiver test approach with one based in # IReactorSocket.adoptStreamConnection once AF_UNIX support is # implemented; see https://twistedmatrix.com/trac/ticket/5573. from socket import socketpair from twisted.internet.unix import _SendmsgMixin from twisted.python.sendmsg import sendmsg def deviceInodeTuple(fd): fs = fstat(fd) return (fs.st_dev, fs.st_ino) @implementer(IFileDescriptorReceiver) class FakeProtocol(ConnectableProtocol): def __init__(self): self.fds = [] self.deviceInodesReceived = [] def fileDescriptorReceived(self, fd): self.fds.append(fd) self.deviceInodesReceived.append(deviceInodeTuple(fd)) close(fd) class FakeReceiver(_SendmsgMixin): bufferSize = 1024 def __init__(self, skt, proto): self.socket = skt self.protocol = proto def _dataReceived(self, data): pass def getHost(self): pass def getPeer(self): pass def _getLogPrefix(self, o): pass sendSocket, recvSocket = socketpair(AF_UNIX, SOCK_STREAM) self.addCleanup(sendSocket.close) self.addCleanup(recvSocket.close) proto = FakeProtocol() receiver = FakeReceiver(recvSocket, proto) # Temp files give us two FDs to send/receive/verify. fileOneFD, fileOneName = mkstemp() fileTwoFD, fileTwoName = mkstemp() self.addCleanup(unlink, fileOneName) self.addCleanup(unlink, fileTwoName) dataToSend = b'some data needs to be sent' fdsToSend = [fileOneFD, fileTwoFD] ancillary, expectedCount = ancillaryPacker(fdsToSend) sendmsg(sendSocket, dataToSend, ancillary) receiver.doRead() # Verify that fileDescriptorReceived was called twice. self.assertEqual(len(proto.fds), expectedCount) # Verify that received FDs are different from the sent ones. self.assertFalse(set(fdsToSend).intersection(set(proto.fds))) # Verify that FDs were received in the same order, if any. if proto.fds: deviceInodesSent = [deviceInodeTuple(fd) for fd in fdsToSend] self.assertEqual(deviceInodesSent, proto.deviceInodesReceived)