Uh oh!
There was an error while loading. Please reload this page.
bpo-28724: Add methods send_fds, recv_fds to the socket module - #12889
Conversation
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
bedevere-bot
commented
May 4, 2019
A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated. Once you have made the requested changes, please leave a comment on this pull request containing the phrase |
40d7ea4 to
f3e0822CompareThere was a problem hiding this comment.
Why we need a loop of 1 iteration?
There was a problem hiding this comment.
I want to return a list of 1 file descriptors for created files.
There was a problem hiding this comment.
But you don't need a loop for that, right? Just substitute i by 0. I am missing something?
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
nanjekyejoannah
commented
May 27, 2019
Needs, Mac OS fixes. Will get a Mac to test this later. |
Uh oh!
There was an error while loading. Please reload this page.
vstinner
commented
Aug 20, 2019
@nanjekyejoannah: I think that these new functions are quite cool and I like to get them in Python 3.9. Do you plan to work on this PR? There are a few pending requests, but the main code is already written and has been reviewed, so this PR is close to be ready to be merged! |
nanjekyejoannah
commented
Aug 20, 2019
I will look at this later this week maybe weekendish. |
nanjekyejoannah
commented
Aug 24, 2019
@pablogsal , Please help me confirm If the tests pass on MacOS now. I cant access a Mac now. |
nanjekyejoannah
commented
Aug 24, 2019
I have made the requested changes; please review again |
bedevere-bot
commented
Aug 24, 2019
Thanks for making the requested changes! @tiran, @pablogsal, @vstinner, @ncoghlan: please review the changes made to this pull request. |
| import array | ||
| def send_fds(sock, buffers, fds, flags=0, address=None): | ||
| """ send_fds(sock, buffers, fds[, flags[, address]]) -> socket object |
There was a problem hiding this comment.
It seems like sendmsg() returns an integer, not a socket object.
| import array | ||
| def recv_fds(sock, bufsize, maxfds, flags=0): | ||
| """ recv_fds(sock, bufsize, maxfds[, flags]) -> (socket object, socket object) |
There was a problem hiding this comment.
The doc of the return value looks wrong. The code uses a tuple of 4 times: return msg, list(fds), flags, addr.
| def recv_fds(sock, bufsize, maxfds, flags=0): | ||
| """ recv_fds(sock, bufsize, maxfds[, flags]) -> (socket object, socket object) | ||
| receive up to maxfds file descriptors returning the message |
There was a problem hiding this comment.
Upper case for the first word of the doc?
| receiveuptomaxfdsfiledescriptorsreturningthemessage | |
| Receiveuptomaxfdsfiledescriptorsreturningthemessage |
| with sock1, sock2: | ||
| socket.send_fds(sock1, [MSG], fds) | ||
| # request more data and file descriptors than expected | ||
| msg, fds2, flags, addr = socket.recv_fds(sock2, len(MSG) * 2, len(fds) * 2) |
There was a problem hiding this comment.
nitpick (PEP 8): there is an useless space
| msg, fds2, flags, addr=socket.recv_fds(sock2, len(MSG) *2, len(fds) *2) | |
| msg, fds2, flags, addr=socket.recv_fds(sock2, len(MSG) *2, len(fds) *2) |
| Receive up to *maxfds* file descriptors. Return ``(msg, list(fds), flags, addr)``. Consult | ||
| :meth:`recvmsg` for the documentation of these parameters. | ||
| .. availability:: Unix supporting :meth:`~socket.sendmsg` and :const:`SCM_RIGHTS` mechanism. |
There was a problem hiding this comment.
it requires recvmsg() instead of sendmsg(), no?
| .. method:: socket.send_fds(sock, buffers, fds[, flags[, address]]) | ||
| Send the list of file descriptors *fds* over an :const:`AF_UNIX` socket. | ||
| Consult :meth:`sendmsg` for the documentation of these parameters. |
There was a problem hiding this comment.
You should document at least what is the fds parameter. I suggest to document it as sequence of file descriptors. Is it possible to send 0 file descriptor?
What is the return value?
Does someone know if it's possible that the call send only a few file descriptors, but not all of them? What if it's called with 100 000 file descriptors for example?
There was a problem hiding this comment.
What is the return value?
The return type for sendmsg() is int AFAIK. Am not sure about these other edge cases but I can look.
There was a problem hiding this comment.
I tested to send 1000 file descriptors: sendmsg() fails with "OSError: [Errno 22] Invalid argument".
For partial send, it can happen, as in socket.send(). In that case, according to https://stackoverflow.com/questions/38431713/partial-read-write-issue-in-sendmsg-recvmsg the file descriptors are already sent and should be be send again, socket.sendmsg() should be called again, but only with buffers (adjusted to the offset equal to the send_fds() result).
In short, you don't have to do anything. I'm not comfortable to document how to handle partial send since I'm not sure that the behavior is portable.
sendmsg() doesn't warn about partial send. Maybe we should copy send() warning into sendmsg() and send_fds(): "Applications are responsible for checking that all data has been sent; if only some of the data was transmitted, the application needs to attempt delivery of the remaining data."
bedevere-bot
commented
Aug 26, 2019
A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated. Once you have made the requested changes, please leave a comment on this pull request containing the phrase |
nanjekyejoannah
commented
Aug 28, 2019
I have made the requested changes; please review again |
bedevere-bot
commented
Aug 28, 2019
Thanks for making the requested changes! @ncoghlan, @pablogsal, @vstinner, @tiran: please review the changes made to this pull request. |
vstinner
left a comment
There was a problem hiding this comment.
The test is skipped. When I enabled manually the test, it failed on Linux :-(
| .. method:: socket.send_fds(sock, buffers, fds[, flags[, address]]) | ||
| Send the list of file descriptors *fds* over an :const:`AF_UNIX` socket. | ||
| Consult :meth:`sendmsg` for the documentation of these parameters. |
There was a problem hiding this comment.
I tested to send 1000 file descriptors: sendmsg() fails with "OSError: [Errno 22] Invalid argument".
For partial send, it can happen, as in socket.send(). In that case, according to https://stackoverflow.com/questions/38431713/partial-read-write-issue-in-sendmsg-recvmsg the file descriptors are already sent and should be be send again, socket.sendmsg() should be called again, but only with buffers (adjusted to the offset equal to the send_fds() result).
In short, you don't have to do anything. I'm not comfortable to document how to handle partial send since I'm not sure that the behavior is portable.
sendmsg() doesn't warn about partial send. Maybe we should copy send() warning into sendmsg() and send_fds(): "Applications are responsible for checking that all data has been sent; if only some of the data was transmitted, the application needs to attempt delivery of the remaining data."
| @requireAttrs(socket, "send_fds") | ||
| @requireAttrs(socket, "recv_fds") | ||
| @requireAttrs(socket, "AF_UNIX") | ||
| class SendRecvFdsTests(unittest.TestCase): |
There was a problem hiding this comment.
Oh, this test case must be added manually into test_main(). Currently, the test is not run...
I added it manually and... the test fails :-( The test writes into the read end of the pipe, and reads from the write end of the pipe. It should be the opposite. Maybe on FreeBSD, pipe ends are not directional, but it seems to be the case on Linux.
So the test should be fixed on Linux a well.
Please move this class before test_main().
| _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. |
There was a problem hiding this comment.
@nanjekyejoannah: Would you mind to document this behavior in recv_fds() documention?
| socketpair() -- create a pair of new socket objects [*] | ||
| fromfd() -- create a socket object from an open file descriptor [*] | ||
| send_fds() -- Send file descriptor to the socket. | ||
| recv_fds() -- Recieve file descriptor from the socket. |
There was a problem hiding this comment.
I suggest to replace "file descriptor" with "file descriptors" for both functions here (add an S), as in their name, since they can send and receive more than one file descriptor ;-)
bedevere-bot
commented
Aug 28, 2019
A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated. Once you have made the requested changes, please leave a comment on this pull request containing the phrase |
vstinner
commented
Sep 9, 2019
test_main() is awful... and it's no longer needed: unittest.main() can be used instead. I created https://bugs.python.org/issue38063 "Modify test_socket.py to use unittest test discovery" and I wrote a PR to implement it. |
Test passes with your fix. Also the test ir running: |
vstinner
commented
Sep 11, 2019
I tested manually commit 1ac7fbf on Linux and FreeBSD. I merged the PR with the master branch, make && ./python -m test test_socket -m SendRecvFdsTests -v . The test pass on Linux and FreeBSD. Good! According to Azure Pipelines: test_socket also pass on macOS (and the test is no longer skipped on macOS). test_socket pass on Windows as well, even if the test is skipped on Windows. |
vstinner
commented
Sep 11, 2019
Thanks Shinya Okano for the original patch. Well done Joannah @nanjekyejoannah! Thanks for your tenacity :-) This PR has 100 comments and 27 commits which shows the complexity of the feature. Honestly, I'm not 100% happy with current documentation, but I chose to merge the PR anyway. Please leave https://bugs.python.org/issue28724 open until the documentation is completed to mention corner cases like partial send (similar to sock.send vs sock.sendall). |
I have added send_fds(), recv_fds() to the socket module.
https://bugs.python.org/issue28724