Skip to content

Commit

Permalink
Merge sendmsg-py3-7884-2: Port twisted.python.sendmsg to Python 3
Browse files Browse the repository at this point in the history
Author: hawkowl
Reviewers: moshez, exarkun
Fixes: twisted#7884

git-svn-id: svn://svn.twistedmatrix.com/svn/Twisted/trunk@44905 bbbe8e31-12d6-0310-92fd-ac37d47ddeeb
  • Loading branch information
hawkowl committed May 22, 2015
1 parent b534499 commit ea33edb
Show file tree
Hide file tree
Showing 13 changed files with 578 additions and 224 deletions.
17 changes: 9 additions & 8 deletions docs/core/howto/listings/sendmsg/copy_descriptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,31 @@
sendmsg.
"""

from __future__ import print_function

from os import pipe, read, write
from socket import SOL_SOCKET, socketpair
from struct import unpack, pack

from twisted.python.sendmsg import SCM_RIGHTS, send1msg, recv1msg
from twisted.python.sendmsg import SCM_RIGHTS, sendmsg, recvmsg

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 = send1msg(
foo.fileno(), "\x00", 0,
[(SOL_SOCKET, SCM_RIGHTS, pack("i", reader))])
sent = sendmsg(
foo, b"\x00", [(SOL_SOCKET, SCM_RIGHTS, pack("i", reader))])

# Receive the copy, including that one byte of normal data.
data, flags, ancillary = recv1msg(bar.fileno(), 1024)
data, ancillary, flags = recvmsg(bar, 1024)
duplicate = unpack("i", ancillary[0][2])[0]

# Demonstrate that the copy works just like the original
write(writer, "Hello, world")
print "Read from original (%d): %r" % (reader, read(reader, 6))
print "Read from duplicate (%d): %r" % (duplicate, read(duplicate, 6))
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)))

if __name__ == '__main__':
main()
14 changes: 8 additions & 6 deletions docs/core/howto/listings/sendmsg/send_replacement.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,19 @@
Demonstration of sending bytes over a TCP connection using sendmsg.
"""

from __future__ import print_function

from socket import socketpair

from twisted.python.sendmsg import send1msg, recv1msg
from twisted.python.sendmsg import sendmsg, recvmsg

def main():
foo, bar = socketpair()
sent = send1msg(foo.fileno(), "Hello, world")
print "Sent", sent, "bytes"
(received, flags, ancillary) = recv1msg(bar.fileno(), 1024)
print "Received", repr(received)
print "Extra stuff, boring in this case", flags, ancillary
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)

if __name__ == '__main__':
main()
148 changes: 32 additions & 116 deletions docs/core/howto/sendmsg.rst
Original file line number Diff line number Diff line change
@@ -1,154 +1,70 @@

:LastChangedDate: $LastChangedDate$
:LastChangedRevision: $LastChangedRevision$
:LastChangedBy: $LastChangedBy$

Extremely Low-Level Socket Operations
=====================================






Introduction
------------

Beyond supporting streams of data (SOCK_STREAM) or datagrams (SOCK_DGRAM), POSIX sockets have additional features not accessible via send(2) and recv(2).
These features include things like scatter/gather I/O, duplicating file descriptors into other processes, and accessing out-of-band data.



Beyond supporting streams of data (SOCK_STREAM) or datagrams (SOCK_DGRAM),
POSIX sockets have additional features not accessible via send(2) and
recv(2). These features include things like scatter/gather I/O,
duplicating file descriptors into other processes, and accessing
out-of-band data.






Twisted includes a wrapper around the two C APIs which make these things
possible,
`sendmsg <http://www.opengroup.org/onlinepubs/007908799/xns/sendmsg.html>`_
and
`recvmsg <http://www.opengroup.org/onlinepubs/007908799/xns/recvmsg.html>`_ .
This document covers their usage. It is intended for Twisted maintainers.
Application developers looking for this functionality should look for the
high-level APIs Twisted provides on top of these wrappers.




Twisted includes a wrapper around the two C APIs which make these things possible, `sendmsg <http://www.opengroup.org/onlinepubs/007908799/xns/sendmsg.html>`_ and `recvmsg <http://www.opengroup.org/onlinepubs/007908799/xns/recvmsg.html>`_ .
This document covers their usage.
It is intended for Twisted maintainers.
Application developers looking for this functionality should look for the high-level APIs Twisted provides on top of these wrappers.


sendmsg
~~~~~~~




``sendmsg(2)`` exposes nearly all sender-side functionality of a
socket. For a SOCK_STREAM socket, it can send bytes that become part of
the stream of data being carried over the connection. For a SOCK_DGRAM
socket, it can send bytes that become datagrams sent from the socket. It
can send data from multiple memory locations (gather I/O). Over AF_UNIX
sockets, it can copy file descriptors into whichever process is receiving
on the other side. The wrapper included in Twisted,
:api:`twisted.python.sendmsg.send1msg <send1msg>` , exposes
many (but not all) of these features. This document covers the usage of
the features it does expose. The alternate spelling for the wrapper is
used to indicate the primary limitation, which is it that the interface
supports sending only one *iovec* at a time.




``sendmsg(2)`` exposes nearly all sender-side functionality of a socket.
For a SOCK_STREAM socket, it can send bytes that become part of the stream of data being carried over the connection.
For a SOCK_DGRAM socket, it can send bytes that become datagrams sent from the socket.
It can send data from multiple memory locations (gather I/O).
Over AF_UNIX sockets, it can copy file descriptors into whichever process is receiving on the other side.
The wrapper included in Twisted, :api:`twisted.python.sendmsg.sendmsg <sendmsg>`, exposes many (but not all) of these features.
This document covers the usage of the features it does expose.
The primary limitation of this wrapper is that the interface supports sending only one *iovec* at a time.


recvmsg
~~~~~~~




Likewise, ``recvmsg(2)`` exposes nearly all the receiver-side
functionality of a socket. It can receive stream data over from a
SOCK_STREAM socket or datagrams from a SOCK_DGRAM socket. It can receive
that data into multiple memory locations (scatter I/O), and it can receive
those copied file descriptors. The wrapper included in
Twisted, :api:`twisted.python.sendmsg.recv1msg <recv1msg>` ,
exposes many (but not all) of these features. This document covers the
usage of the features it does expose. The alternate spelling for the
wrapper is used to indicate the primary limitation, which is that the
interface supports receiving only one *iovec* at a time.




Likewise, ``recvmsg(2)`` exposes nearly all the receiver-side functionality of a socket.
It can receive stream data over from a SOCK_STREAM socket or datagrams from a SOCK_DGRAM socket.
It can receive that data into multiple memory locations (scatter I/O), and it can receive those copied file descriptors.
The wrapper included in Twisted, :api:`twisted.python.sendmsg.recvmsg <recvmsg>`, exposes many (but not all) of these features.
This document covers the usage of the features it does expose.
The primary limitation of this wrapper is that the interface supports receiving only one *iovec* at a time.


Sending And Receiving Regular Data
----------------------------------

sendmsg can be used in a way which makes it equivalent to using the send call.
The first argument to sendmsg is (in this case and all others) a socket over which to send the data.
The second argument is a bytestring giving the data to send.



sendmsg can be used in a way which makes it equivalent to using the send
call. The first argument to sendmsg is (in this case and all others) a
file descriptor over which to send the data. The second argument is a
string giving the data to send.






On the other end, recvmsg can be used to replace a recv call. The first
argument to recvmsg is (again, in all cases) a file descriptor over which
to receive the data. The second argument is an integer giving the maximum
number of data to receive.





On the other end, recvmsg can be used to replace a recv call.
The first argument to recvmsg is (again, in all cases) a socket over which to receive the data.
The second argument is an integer giving the maximum number of bytes of data to receive.

:download:`send_replacement.py <listings/sendmsg/send_replacement.py>`

.. literalinclude:: listings/sendmsg/send_replacement.py



Copying File Descriptors
------------------------




Used with an AF_UNIX socket, sendmsg send a copy of a file descriptor into
whatever process is receiving on the other end of the socket. This is
done using the ancillary data argument. Ancillary data consists of a list
of three-tuples. A three-tuple constructed with SOL_SOCKET, SCM_RIGHTS,
and a platform-endian packed file descriptor number will copy that file
descriptor.





Used with an AF_UNIX socket, sendmsg send a copy of a file descriptor into whatever process is receiving on the other end of the socket.
This is done using the ancillary data argument.
Ancillary data consists of a list of three-tuples.
A three-tuple constructed with SOL_SOCKET, SCM_RIGHTS, and a platform-endian packed file descriptor number will copy that file descriptor.

File descriptors copied this way must be received using a recvmsg call.
No special arguments are required to receive these descriptors. They will
appear, encoded as a native-order string, in the ancillary data list
returned by recvmsg.





No special arguments are required to receive these descriptors.
They will appear, encoded as a native-order string, in the ancillary data list returned by recvmsg.

:download:`copy_descriptor.py <listings/sendmsg/copy_descriptor.py>`

.. literalinclude:: listings/sendmsg/copy_descriptor.py

4 changes: 2 additions & 2 deletions twisted/python/sendmsg.c → twisted/python/_sendmsg.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,13 @@ static PyMethodDef sendmsg_methods[] = {
};


PyMODINIT_FUNC initsendmsg(void) {
PyMODINIT_FUNC init_sendmsg(void) {
PyObject *module;

sendmsg_socket_error = NULL; /* Make sure that this has a known value
before doing anything that might exit. */

module = Py_InitModule3("sendmsg", sendmsg_methods, sendmsg_doc);
module = Py_InitModule3("_sendmsg", sendmsg_methods, sendmsg_doc);

if (!module) {
return;
Expand Down
30 changes: 27 additions & 3 deletions twisted/python/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,15 @@
string type (bytes in Python 2, unicode in Python 3).
"""

from __future__ import division
from __future__ import absolute_import, division

import inspect
import os
import socket
import string
import struct
import sys

import sys, string, socket, struct, inspect
from io import TextIOBase, IOBase


Expand Down Expand Up @@ -546,6 +552,23 @@ def items(d):



def bytesEnviron():
"""
Return a L{dict} of L{os.environ} where all text-strings are encoded into
L{bytes}.
"""
if not _PY3:
# On py2, nothing to do.
return dict(os.environ)

target = dict()
for x, y in os.environ.items():
target[os.environ.encodekey(x)] = os.environ.encodevalue(y)

return target



__all__ = [
"reraise",
"execfile",
Expand All @@ -568,4 +591,5 @@ def items(d):
"iteritems",
"xrange",
"urllib_parse",
]
"bytesEnviron",
]
2 changes: 2 additions & 0 deletions twisted/python/dist3.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@
"twisted.python.randbytes",
"twisted.python.reflect",
"twisted.python.runtime",
"twisted.python.sendmsg",
"twisted.python.systemd",
"twisted.python.procutils",
"twisted.python.test",
Expand Down Expand Up @@ -238,6 +239,7 @@
"twisted.python.test.test_deprecate",
"twisted.python.test.test_dist3",
"twisted.python.test.test_runtime",
"twisted.python.test.test_sendmsg",
"twisted.python.test.test_systemd",
"twisted.python.test.test_tzhelper",
"twisted.python.test.test_urlpath",
Expand Down
Loading

0 comments on commit ea33edb

Please sign in to comment.