New submission from Justin Cappos <justincap...@gmail.com>:

Suppose there is a program that has a listening socket that calls accept to 
obtain new sockets for client connections.   socketmodule.c assumes that these 
client sockets have timeouts / blocking in the default state for new sockets 
(which on most systems means the sockets will block).   However, socketmodule.c 
does not verify the state of the socket object that is returned by the system 
call accept.

>From http://linux.die.net/man/2/accept :
On Linux, the new socket returned by accept() does not inherit file status 
flags such as O_NONBLOCK and O_ASYNC from the listening socket. This behaviour 
differs from the canonical BSD sockets implementation. Portable programs should 
not rely on inheritance or non-inheritance of file status flags and always 
explicitly set all required flags on the socket returned from accept(). 


socketmodule.c does not explicitly set or check these flags for sockets 
returned by accept.   The attached program will print the following on Linux 
regardless of whether the settimeout line for s exists or not:

a has timeout: None
O_NONBLOCK is set: False
received: hi



On Mac / BSD, the program will produce the following output when the timeout is 
set on the listening socket:

a has timeout: None
O_NONBLOCK is set: True
Traceback (most recent call last):
  File "python-nonportable.py", line 39, in <module>
    message = a.recv(1024)
socket.error: (35, 'Resource temporarily unavailable')


When the timeout is removed, the behavior is the same as linux:

a has timeout: None
O_NONBLOCK is set: False
received: hi


Note that the file descriptor problem crops up in odd ways on Mac systems.   
It's possible that issue 5154 may be due to this bug.   I am aware of other 
problems with the socketmodule on Mac and will report them in other tickets.


I believe that this problem can be easily mitigated by always calling fcntl to 
unset the O_NONBLOCK flag after accept (O_ASYNC should be unset too, for 
correctness).   I would recommend adding the below code snippet at line 1653 in 
socketmodule.c (r78335).   The resulting code would look something like this 
(with '+' in front of the added lines):


'''
#ifdef MS_WINDOWS
        if (newfd == INVALID_SOCKET)
#else
        if (newfd < 0)
#endif
                return s->errorhandler();

+#if defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__)
+        int starting_flag;
+        // Unset O_NONBLOCK an O_ASYNC if they are inherited.
+        starting_flag = fcntl(newfd, F_GETFL, 0);
+        starting_flag &= ~(O_NONBLOCK | O_ASYNC);
+        fcntl(newfd, F_SETFL, starting_flag);
+#endif

        /* Create the new object with unspecified family,
           to avoid calls to bind() etc. on it. */
        sock = (PyObject *) new_sockobject(newfd,
                                           s->sock_family,
                                           s->sock_type,
                                           s->sock_proto);
'''

I've tested this patch on my Mac and Linux systems and it seems to work fine.   
I haven't had a chance to test on BSD.   Also, I did not test for this problem 
in Python 3, but I assume it exists there as well and the same fix should be 
applied.

----------
assignee: ronaldoussoren
components: Library (Lib), Macintosh
files: python-nonportable.py
messages: 99852
nosy: Justin.Cappos, bbangert, giampaolo.rodola, loewis, nicdumz, ronaldoussoren
severity: normal
status: open
title: On Mac / BSD sockets returned by accept inherit the parent's FD flags
type: behavior
versions: Python 2.5, Python 2.6, Python 2.7
Added file: http://bugs.python.org/file16325/python-nonportable.py

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue7995>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to