About 18 months ago I wrote a blog talking about changes in how accept works in OpenVOS release 17.1. What I neglected to indicate was that these changes only take effect if the application code is POSIX based. To recap, prior to 17.1 STCP would only reply to a client connection request if the server application code had called the accept routine. If the code had not called accept the client’s connection request would go into a queue but would not be answered. Once the application called accept, STCP would send a connection reply. If the client is still waiting, the connection completes at that time. If the client had already given up, it would respond to the connection reply with a reset, STCP would throw the connection away and the accept would hang (assuming blocking mode) and wait for another connection.
Figure 1 shows this scenario; the left justified text lines are status messages from the server application, the indented packet_monitor lines (slightly modified) are the result of client activity. The application (acceptTestnoPosix) is started and listens on port 12345, and once listening goes to sleep for 300 seconds. The client then makes a connection to port 12345 by sending a TCP segment to port 12345 with the Syn (S) flag set. It tries three times before giving up. After 300 seconds the application wakes up and calls accept. The STCP stack replies to the client with a TCP segment with the Syn and Ack (SA) flags set. Since the client no longer has a record of the connection if sends a Reset (R), STCP blocks at this point. If the socket were in non-blocking mode accept would have returned with an EAGAIN error.
acceptTestnoPosix 12345 Executing acceptTestnoPosix 12345 Sleeping for 300 seconds 11:04:45.923 R TCP 184.108.40.206 220.127.116.11 11071 12345 S 11:04:48.925 R TCP 18.104.22.168 22.214.171.124 11071 12345 S 11:04:54.937 R TCP 126.96.36.199 188.8.131.52 11071 12345 S Ready to accept a connection on port number 12345 11:09:41.852 T TCP 184.108.40.206 220.127.116.11 12345 11071 SA 11:09:41.854 R TCP 18.104.22.168 22.214.171.124 11071 12345 R
Figure 1 – accept pre 17.1 or non-POSIX post 17.1
If the application is POSIX based, things are different (Figure 2). STCP replies to the connection request (S) immediately (SA). Then after 300 seconds the application wakes up, calls accept and STCP returns the accepted socket.
acceptTestwithPosix 12345 Executing acceptTestnoPosix 12345 Sleeping for 300 seconds 10:58:43.962 R TCP 126.96.36.199 188.8.131.52 11024 12345 S 10:58:43.964 T TCP 184.108.40.206 220.127.116.11 12345 11024 SA 10:58:43.964 R TCP 18.104.22.168 22.214.171.124 11024 12345 A Ready to accept a connection on port number 12345 Connection accepted
Figure 2 – accept POSIX based post 17.1
The behavior difference can be critical. If the client is expecting a response from the server application after making a connection it may time out and close the connection before the application actually calls accept.
How do you build an application with POSIX? First the line
#define _POSIX_C_SOURCE 200112L
should be the first line of the application source. Second the library path
needs to be in the object library paths after the STCP libraries and before the C library.
How can you tell if this has been done? Well you can look at the object libraries that the application was bound with using the display_program_module -object_dirs command
display_program_module acceptTestwithPosix -object_dirs %azvos#m17_mas>SysAdmin>Noah_Davids>temp>acceptTestwithPosix.pm Object Directory Map: 11 search directories 0 non-search directories 11 directories in all DTC Directory Path 1 %azvos#m17_mas>SysAdmin>Noah_Davids>temp 2 %azvos#m17_mas>system>stcp>object_library 3 %azvos#m17_mas>system>stcp>object_library>socket 4 %azvos#m17_mas>system>stcp>object_library>net 5 %azvos#m17_mas>system>stcp>object_library>common 6 %azvos#m17_mas>system>posix_object_library 7 %azvos#m17_mas>system>c_object_library 8 %azvos#m17_mas>system>object_library 9 %azvos#m17_mas>opt>apache>lib 10 %azvos#m17_mas>opt>openssl>lib 11 %azvos#m17_mas>opt>mysql>lib>mysql
But this doesn’t tell you if the #define is part of the source code.
If you can run the code you can look at the socket flags, a POSIX based program will have the SF_POSIX socket flag set. For example, I have three programs acceptTestnoPosix, acceptTestwithPosix and acceptTestwithPosixPathOnly. This last one had the >system>posix_object_library directory in the library paths but did not include the #define in the source code. Note that this is considered an invalid combination. Only the application that was bound with the POSIX library and had the POSIX_SOURCE #define statement in the code created a socket with the SF_POSIX flag.
acceptTestnoPosix.pm 12345 Executing acceptTestnoPosix 12345 Sleeping for 300 seconds as: match posix; dump_stcbq -full -lport 12345 as:
acceptTestwithPosix.pm 12345 Executing acceptTestnoPosix 12345 Sleeping for 300 seconds as: match posix; dump_stcbq -full -lport 12345 SF_POSIX as:
acceptTestwithPosixPathOnly.pm 12345 Executing acceptTestnoPosix 12345 Sleeping for 300 seconds as: match posix; dump_stcbq -full -lport 12345 as:
There is a fourth possibility, the #define was included in the source but the posix_object_library was not used. In this case the socket routine will return an error.
acceptTestwithPosixDefineOnly 12345 Executing acceptTestnoPosix 12345 acceptTestnoPosix: can't create listening socket: Application built + incorrectly: POSIX runtime must be searched before C runtime.
All of the STCP commands and utilities are built with POSIX and I strongly recommend that any applications you build also use POSIX.