Report 1623 Actions
Problem Report Number |
1623 |
Submitter's Classification |
Specification problem |
State |
Resolved |
Resolution |
Permanent Interpretation (PIN) |
Problem Resolution ID |
PIN.X.0180 |
Raised |
1997-09-01 08:00 |
Updated |
2003-03-13 08:00 |
Published |
1997-10-07 08:00 |
Product Standard |
Sockets (UNIX 95) |
Certification Program |
The Open Brand certification program |
Test Suite |
VSU version 4.1.1 |
Test Identification |
CAPI.os/sockets/connect 3,4,5,6,7,8 |
Specification |
Networking Services Issue 4 |
Location in Spec |
See Problem Text |
Problem Summary |
PIN4U.00046 This IR claims that historical behavior should be allowed in UNIX95 and/or UNIX98. |
Problem Text |
These tests are failing because of a difference in methods for specifying how many connections can be queued using the listen() routine. The Issue 4 Networking Services spec for listen() says: "The listen()function marks a connection-oriented socket, specified by the socket argument, as accepting connections, and limits the number of outstanding connections in the socket's listen queue to the value specified by the backlog argument." The historical BSD based implementation of listen has always been otherwise. The kernel has never taken this number literally and instead uses the algorithm: (3 * backlog / 2) +1 The BSD (and SunOS) implementation has always, in fact, allowed 50% extra. The problem is that the count is really the sum of accepted connections and connections being accepted, and the 50% slop allowed for overlap between connections being set up and connections being handled. Now that we have raised the default dramatically, this is less important, but applications which set a particular small number may be confused. An example of an application that is broken by this "improvement" is sendmail. The distributed sendmail source asks for a queue length of 10. That is <<GROSSLY>> too small on any real system. Even the effective limit of 15 is far too small. The problem goes as 1/N. As N approaches 0, things get very bad. Going from 15 to 10 is a major change. The backlog fudge is not an optimization. It is designed to handle the needs of transports that require a half-open connection state. Having standards tests that require breaking legacy code is not only a very bad idea, it defies the spirit of the mission. The plot thickens with the release of the Networking Services (XNS) specification, Issue 5. The new spec for listen() sez: "The implementation may include incomplete connections in the queue subject to the queue limit. The implementation may also increase the specified queue limit internally if it includes such incomplete connections in the queue subject to the limit." Bottom line, we'd have to break our current (historical) implementation to brand for Unix 95 and then restore it to brand for Unix 98.
|
Test Output |
TEST CASE: connect TEST PURPOSE #3 If the implementation supports a communications domain and a connection-oriented socket type: A call to int connect(int socket, const struct sockaddr *address, size_t address_len) when the connection cannot be immediately established and O_NONBLOCK is not set for socket shall block until the connection is established or a timeout elapses. PREP: Get VSU_CONNECT_TIMEOUT configuration variable TEST: AF_INET SOCK_STREAM PREP: Create test sockaddr_in: address = 150.166.40.34, port = 3777 PREP: Create three sockets PREP: Wait for child to be ready PREP: Connect twice to fill queue PREP: Notify child to delay and then accept TEST: connect blocks until connection accepted TEST: Duration of blocking ERROR: Process did not appear to block, expected: 2 secs (approx), actual: 0 secs PREP: Child: create socket PREP: Child: bind to socket PREP: Child: listen on socket with backlog of 2 PREP: Child: tell parent ready PREP: Child: wait for parent to become ready PREP: Child: delay 3 FAIL TEST PURPOSE #4 If the implementation supports a communications domain and a connection-oriented socket type: A call to int connect(int socket, const struct sockaddr *address, size_t address_len) when blocking is terminated due to expiration of the timeout shall abort the connection attempt, set errno to ETIMEDOUT, and return -1. PREP: Get VSU_CONNECT_TIMEOUT configuration variable TEST: AF_INET SOCK_STREAM PREP: Create test sockaddr_in: address = 150.166.40.34, port = 2041 PREP: Create three sockets PREP: Wait for child to be ready PREP: Connect twice to fill queue PREP: Set long alarm TEST: connect blocks until timeout elapses TEST: Return value ERROR: Call to connect unexpectedly succeeded PREP: Child: create socket PREP: Child: bind to socket PREP: Child: listen on socket with backlog of 2 PREP: Child: tell parent ready PREP: Child: wait for parent to complete 4 FAIL TEST PURPOSE #5 If the implementation supports a communications domain and a connection-oriented socket type: A call to int connect(int socket, const struct sockaddr *address, size_t address_len) when blocking is interrupted by a signal shall set errno to EINTR, return -1, and establish the connection asynchronously. PREP: Get VSU_CONNECT_TIMEOUT configuration variable TEST: AF_INET SOCK_STREAM PREP: Create test sockaddr_in: address = 150.166.40.34, port = 3321 PREP: Create three sockets PREP: Wait for child to be ready PREP: Connect twice to fill queue TEST: connect blocks until interrupted ERROR: Call to connect unexpectedly succeeded PREP: Child: create socket PREP: Child: bind to socket PREP: Child: listen on socket with backlog of 2 PREP: Child: tell parent ready PREP: Child: wait for parent to become ready 5 FAIL TEST PURPOSE #6 If the implementation supports a communications domain and a connection-oriented socket type: A call to int connect(int socket, const struct sockaddr *address, size_t address_len) when the connection cannot be immediately established and O_NONBLOCK is set for socket shall return -1, set errno to EINPROGRESS, and establish the connection asynchronously. PREP: Get VSU_CONNECT_TIMEOUT configuration variable TEST: AF_INET SOCK_STREAM PREP: Create test sockaddr_in: address = 150.166.42.131, port = 2529 PREP: Child: create socket PREP: Child: bind to socket PREP: Child: listen on socket with backlog of 2 PREP: Child: tell parent ready PREP: Child: wait for parent to become ready PREP: Child: accept queued connections PREP: Child: accept connection being asynchronously established PREP: Child: notify parent connections completed PREP: Child: wait for parent to complete test PREP: Create three sockets PREP: Wait for child to be ready PREP: Connect twice to fill queue PREP: Set O_NONBLOCK TEST: connect returns with EINPROGRESS TEST: Did not block PREP: Notify child to accept TEST: Await notification connections completed TEST: AF_UNIX SOCK_STREAM PREP: Create test sockaddr_un: path = ../tmp/unix.a01ELq PREP: Create three sockets PREP: Wait for child to be ready PREP: Connect twice to fill queue PREP: Set O_NONBLOCK TEST: connect returns with EINPROGRESS ERROR: Call to connect unexpectedly succeeded PREP: Child: create socket PREP: Child: bind to socket PREP: Child: listen on socket with backlog of 2 PREP: Child: tell parent ready PREP: Child: wait for parent to become ready 6 FAIL TEST PURPOSE #7 If the implementation supports a communications domain and a connection-oriented socket type: A call to int connect(int socket, const struct sockaddr *address, size_t address_len) when asynchronous connection establishment is in progress for socket shall return -1 and set errno to EALREADY. PREP: Get VSU_CONNECT_TIMEOUT configuration variable TEST: AF_INET SOCK_STREAM PREP: Create test sockaddr_in: address = 150.166.40.34, port = 4941 PREP: Create three sockets PREP: Wait for child to be ready PREP: Connect twice to fill queue PREP: Set O_NONBLOCK TEST: connect returns with EINPROGRESS TEST: Did not block TEST: connect returns with EALREADY ERROR: Call to connect failed unexpectedly, expected errno = EALREADY, errno = 133(EISCONN - Socket is connected) PREP: Child: create socket PREP: Child: bind to socket PREP: Child: listen on socket with backlog of 2 PREP: Child: tell parent ready PREP: Child: wait for parent to complete test 7 FAIL TEST PURPOSE #8 If the implementation supports a communications domain and a connection-oriented socket type: After a connection is asynchronously established due to a call to int connect(int socket, const struct sockaddr *address, size_t address_len) select() and poll() shall indicate socket is ready for writing. PREP: Get VSU_CONNECT_TIMEOUT configuration variable TEST: AF_INET SOCK_STREAM PREP: Create test sockaddr_in: address = 150.166.42.131, port = 3793 PREP: Create three sockets PREP: Wait for child to be ready PREP: Connect twice to fill queue PREP: Set O_NONBLOCK TEST: connect returns with EINPROGRESS PREP: Notify child to accept TEST: Await notification connections completed TEST: Select reports socket ready to write TEST: Poll reports socket ready to write TEST: AF_UNIX SOCK_STREAM PREP: Create test sockaddr_un: path = ../tmp/unix.a01EAJ PREP: Child: create socket PREP: Child: bind to socket PREP: Child: listen on socket with backlog of 2 PREP: Child: tell parent ready PREP: Child: wait for parent to become ready PREP: Child: accept queued connections PREP: Child: accept connection being asynchronously established PREP: Child: notify parent connections completed PREP: Child: wait for parent to complete test PREP: Create three sockets PREP: Wait for child to be ready PREP: Connect twice to fill queue PREP: Set O_NONBLOCK TEST: connect returns with EINPROGRESS ERROR: Call to connect unexpectedly succeeded PREP: Child: create socket PREP: Child: bind to socket PREP: Child: listen on socket with backlog of 2 PREP: Child: tell parent ready PREP: Child: wait for parent to become ready 8 FAIL TEST CASE: listen TEST PURPOSE #2 If the implementation supports a communications domain and a connection-oriented socket type: A call to int listen(int socket, int backlog) when backlog is greater than or equal to 0 shall limit the number of connections in the socket's listen queue to that value. PREP: Get VSU_CONNECT_TIMEOUT configuration variable TEST: AF_INET SOCK_STREAM PREP: Create test sockaddr_in: address = 150.166.40.34, port = 2549 PREP: Create three sockets PREP: Wait for child to be ready PREP: Connect twice to fill queue TEST: Next connect is rejected TEST: Return value ERROR: connect call succeeded unexpectedly, returned 0 PREP: Child: create socket PREP: Child: bind to socket PREP: Child: listen on socket with backlog of 2 PREP: Child: tell parent ready PREP: Child: wait for parent to complete test 2 FAIL TEST PURPOSE #3 If the implementation supports a communications domain and a connection-oriented socket type: A call to int listen(int socket, int backlog) when backlog is negative shall set the length of the socket's listen queue to 0. PREP: Get VSU_CONNECT_TIMEOUT configuration variable TEST: AF_INET SOCK_STREAM PREP: Create test sockaddr_in: address = 150.166.40.34, port = 2681 PREP: Create a socket PREP: Wait for child to be ready TEST: connect is rejected TEST: Return value ERROR: connect call succeeded unexpectedly, returned 0 PREP: Child: create socket PREP: Child: bind to socket PREP: Child: listen on socket with backlog of -1 PREP: Child: tell parent ready PREP: Child: wait for parent to complete test 3 FAIL
|
Review Information
Review Type |
TSMA Review |
Start Date |
null |
Completed |
null |
Status |
Complete |
Review Recommendation |
No Resolution Given |
Review Response |
We recommend this request be refused.
The specification is unambiguous in its requirements and these are accurately verified by the tests. This issue has been raised in the past with regard to BSD-derived implementations. The intent of the spec was reaffirmed each time. This parameter is required to define exactly the size of the queue.
Further:
> The plot thickens with the release of the Networking Services (XNS) > specification, Issue 5. The new spec for listen() sez: > > "The implementation may include incomplete connections in > the queue subject to the queue limit. The implementation may also > increase the specified queue limit internally if it includes > such incomplete connections in the queue subject to the limit."
We don't believe this changes the issue here. The key phrase is "subject to the queue limit". That is, an implementation may use queue slots for partial connections, but the queue limit, as specified by the backlog parameter, must still be enforced. Thus the BSD behavior remains non-conforming.
There are alternatives for conformance.
The standard only requires that XPG4 functionality be present if _XOPEN_SOURCE is defined (see section 1.3 The Compilation Environment in the Networking standard), and UNIX95 functionality be present if XOPEN_SOURCE_EXTENDED=1 is defined as in the case of listen(). In Issue 5, _XOPEN_SOURCE=500 defines the compilation environment for UNIX98. Outside of this well-defined environment, interfaces may behave differently.
It is common to have different behaviours depending on the compilation environment defined. Once an IUT is branded for UNIX98, it is likely that a UNIX95 mode will be retained for existing applications. UNIX95, UNIX95 behaviour will prevail depending on the XOPEN macros defined. Historical OS behavior may prevail if XOPEN macros are not defined.
Also, please note that historical practice is not normative. Historical applications can certainly be affected by conformance to the UNIX95 standard, but there is no requirement that applications be compiled in a UNIX95 or UNIX98 environment.
|
Review Type |
SA Review |
Start Date |
null |
Completed |
null |
Status |
Complete |
Review Resolution |
No Resolution Given |
Review Conclusion |
The change introduced in XNS 5 aligns with P1003.1g. This says that "If the protocol returns sockets in the CONNECTED state rather than the CONFIRMING state via the accept() function, the implementation may include incomplete connections in the queue subject to the queue limit. The implementation may also increase the specified queue limit internally if it includes such incomplete connections in the queue subject to this limit." (The "If the protocol returns . . " clause can be translated as "For TCP but not for ISO Transport.") This text is based on BSD practice and lends weight to the claim that historical implementations behave this way.
The initial X/Open sockets specification was intended to reflect historical, specifically BSD, practice. It is likely that there was a mistake in the BSD man pages and that this mistake was simply copied into XNS 4. There seems to be a case here for a Permanent Interpretation.
This should be forward to the XNET working group.
|
Review Type |
Expert Group Review |
Start Date |
null |
Completed |
null |
Status |
Complete |
Review Resolution |
No Resolution Given |
Review Conclusion |
The working group finds this a difficult area where further work is needed to clarify the specification. Meanwhile, a majority of the group is in favour of granting the request.
|
Review Type |
SA Review |
Start Date |
null |
Completed |
null |
Status |
Complete |
Review Resolution |
Permanent Interpretation (PIN) |
Review Conclusion |
A Permanent Interpretation is granted.
|
Problem Reporting System Options:
|