Q147714: Windows Sockets 2 Service Provider Interface Limitations
Article: Q147714
Product(s): Microsoft Windows NT
Version(s): WinNT:3.5,3.51,4.0
Operating System(s):
Keyword(s): kbnetwork
Last Modified: 14-FEB-2002
-------------------------------------------------------------------------------
The information in this article applies to:
- Microsoft Windows NT Workstation versions 3.5, 3.51, 4.0
- Microsoft Windows NT Server versions 3.5, 3.51, 4.0
-------------------------------------------------------------------------------
SUMMARY
=======
The Windows Sockets 2 Service Provider Interface (Revision 2.1.0) provides
specifications for transport network programming under Windows. This interface
is the most comprehensive open transport API designed to date. However, few
limitations exist. The purpose of this article is to list and describe the
limitation items of the specifications and provide alternative solutions to work
around the limitation items. The information below is contributed by the Windows
Sockets Vendor Community.
MORE INFORMATION
================
1. Calling connect() on a non-blocking socket, getting WSAEWOULDBLOCK, then
immediately calling recv() and expecting WSAEWOULDBLOCK before the connection
has been established.
Reason: This assumes that the connection will never be established by the time
the application calls recv().
Workaround: An application using a non-blocking socket must handle the
WSAEWOULDBLOCK error value, but must not depend on occurrence of the error.
2. Calling select() with three empty FD_SETs and a valid TIMEOUT structure as a
delay function.
Reason: The select() function is intended as a network function, not a general
purpose timer.
Workaround: Use a legitimate system timer service.
3. Polling with connect() on a non-blocking socket to determine when the
connection has been established.
Reason: The WinSock 1.1 specification does not define an error for connect()
when a non-blocking connection is pending. Therefore, the error value
returned varies.
Workaround: Use asynchronous notification of connection completion An
application that prefers synchronous operation mode can use the select()
function (please see item 21 below).
4. Assuming socket handles are always less than 16.
Reason: The only invalid socket handle value is defined by the WinSock.H file
as INVALID_SOCKET. Any other value the SOCKET type can handle is fair game,
and an application must handle it. Socket handles are not transparent.
Therefore, applications should not depend on specific values.
Workaround: Expect a socket handle of any value, including 0. Do not expect
socket handle values to change with each successive call to socket() or
WSASocket(). Socket handles may be re-used by the WinSock implementation.
5. Polling with select() and a zero timeout in Win16's non-preemptive
environment.
Reason: With any non-zero timeout, select() calls the current blocking hook
function, so that an application anticipating an event yields to other
processes executing in a 16-bit Windows environment. However, with a zero
time-out, an application does not yield to other processes, and may not allow
network operations to occur (it will loop continuously).
Workaround: Use a small non-zero timeout, or use asynchronous notification
instead of using select().
6. Calling WSAAsyncSelect() with a zero Event mask in order to make the socket
non-blocking.
Reason: WSAAsyncSelect() is designed to allow an application to register for
asynchronous notification of network events. The WinSock version 1.1
specification does not specify an error for a zero event mask, but may
interpret it as an invalid input argument (so it may fail with WSAEINVAL) or
ignore the request.
Workaround: To make a socket non-blocking without registering for asynchronous
notification, use ioctlsocket() FIONBIO.
7. Telnet applications that neither enable OOBINLINE, nor read OOB data.
Reason and Workaround not available.
8. Assuming zero (0) is an invalid socket handle value.
Reason and Workaround: Please see item 4 above.
9. Applications that do not properly shut-down when the user closes the main
window while a blocking API is running.
Reason: WinSock applications that do not close sockets and call WSACleanup()
does not allow a WinSock implementation to re-claim resources used by the
application. Resource leakage can eventually result in resource shortage for
all other WinSock applications (for example: network system failure).
Workaround: While a blocking API is running, do the following to abort:
a. Call WSACancelBlockingCall().
b. Wait until the pending function returns. If it is cancelled before the
operation completes, the pending function fails with the WSAEINTR error.
However, applications must also be prepared for success due to the race
condition involved with cancellation.
c. Close this socket and all other sockets.
NOTE: The proper closure of a connected stream socket involves the
following:
- Call shutdown() how=1
- Loop on recv() until it returns 0 or fails with any error
- Call closesocket().
d. Call WSACleanup().
10. Out of band data.
Reason: TCP does not do Out of Band (OOB) data reliably. In addition, there
are incompatible differences in the implementation at the protocol level (in
the urgent pointer offset). Berkeley Software Distribution's (BSD)
implementation performs RFC 793. Many others implement the corrected RFC
1122 version. One version cannot point to the OOB data of the other
version.
Workaround: Use a separate socket for urgent data. Some protocols require it
(please see item 7 above).
11. Calling strlen() on a hostent structure's IP address, then truncating it to
four bytes, thereby overwriting part of the malloc() heap header.
Reason and Workaround not available.
12. Polling with recv(MSG_PEEK) to determine when a complete message has
arrived.
Reason and Workaround not available.
13. Bounding every set of operations with calls to WSAStartup() and
WSACleanup().
Reason: This is possible as long as each WSAStartup() has a matching call to
WSACleanup(), but requires more work.
Workaround: In a DLL, custom control or class library, it is possible to
register the calling client based on a unique task handle or process ID.
This allows automatic registration without duplication. Automatic
de-registration can occur when a process closes its last socket. You may
also use the process notification mechanisms available in the 32- bit
environment.
14. Ignoring API errors.
Reason: When a function fails, the error value returned by WSAGetLastError()
(or included in an asynchronous message) informs you why it has failed.
Based on the function that fails and the socket state, you can determine why
the function fails and what you can do.
Workaround: Check for error values, and write your applications to anticipate
them. When a fatal error occurs, display an error message that shows the
following:
- The function that has failed
- The WinSock error number and macro
- A short description of the error definition
- Workarounds
15. Installing an empty blocking hook that returns FALSE.
Reason: One of the primary purposes of the blocking hook function is to
provide a mechanism for an application with a pending blocking operation to
yield. By returning FALSE from the blocking hook function, you defeat this
purpose and your application prevents multitasking in the non-preemptive
16-bit Windows environment. This also prevents some WinSock implementations
from completing the pending network operation.
Workaround: Sub-class the active window. This prevents re-entrant messages.
16. Client applications that bind to a specific port.
Reason: Client applications actively initiate a network communication. Server
applications passively wait for communication. A server must bind() to a
specific port which is known to clients that need to use the service.
However, a client does not need to bind() its socket to a specific port to
communicate with a server.
Workaround: Let the WinSock implementation assign the local port number
implicitly when you call connect() (on stream or datagram sockets) or
sendto() (on datagram sockets).
17. Nagle challenged applications.
Reason: The Nagle algorithm reduces trivial network traffic. The algorithm
recommends that you do not send a TCP segment until:
- All outstanding TCP segments have been acknowledged
-or-
- There is a full TCP segment ready to send.
A "Nagle challenged application" is one that cannot wait until either of
these conditions occurs. However, it has time-critical data that it must
send continuously. This results in unwanted network traffic.
Workaround: Do not write applications that depend on the immediate data echo
from the remote TCP host.
18. Assuming stream sockets maintain message frame boundaries.
Reason: Stream sockets (TCP) provide data streams. The largest message length
an application can depend on is one-byte in length. This means that with any
call to send() or recv(), the WinSock implementation may transfer any number
of bytes less than the buffer length specified.
Workaround: Whether you use a blocking or non-blocking socket, compare the
return from send() or recv() with the expected value. If the value is less
than the expected value, adjust the buffer length and pointer for another
function call (which may occur asynchronously, if you use asynchronous
operation mode).
19. 16-bit DLL's that call WSACleanup() from their WEP.
Reason: 16-bit Windows does not guarantee that WEP() is called and the
Windows subsystem has been in frequent dis-array.
Workaround: Do not use WEP().
20. Single-byte send() and recv().
Reason: Couple one-byte sends with Nagle disabled.
Workaround: Send modest amounts and receive as much as possible.
21. Select().
Reason: Consider the steps involved in using select(). You must use the
macros to clear the three fdsets, then set the appropriate fdsets for each
socket, then set the timer, and then call select().
Workaround: Use asynchronous operation mode.
22. Applications that call gethostbyname() before calling inet_addr().
Reason: Some users prefer to use network addresses rather than host names.
The WinSock version 1.1 specification does not specify what gethostbyname()
should do with an IP address in standard ASCII dotted IP notation. As a
result, the outcome is unpredictable. It may succeed and do a
reverse-lookup, or it may fail.
Workaround: With any destination input by a user (which may be a host name or
dotted IP address), call inet_addr() first to check for an IP address, and
if that fails, call gethostbyname() to try to resolve it.
Furthermore, in some applications, you may want to explicitly check the input
string for the broadcast address "255.255.255.255," because the return value
from inet_addr() for this address is the same as SOCKET_ERROR.
23. Win32 applications that install blocking hooks.
Reason: Aside from yielding to other applications (please see item 15 above),
blocking hook functions are designed to allow concurrent processing within a
task, while there is a blocking operation pending. In Win32, there are
threads.
Workaround: Use threads.
24. Polling with ioctlsocket(FIONREAD) on a stream socket until a complete
"message" appears.
Reason: A stream socket (TCP) does not preserve message boundaries (please
see item 18 above). An application that uses ioctlsocket() FIONREAD or
recv(MSG_PEEK) to wait for a complete "message" to arrive may not succeed.
One reason is due to the internal WinSock system buffering. If the bytes in
a "message" straddle a system buffer boundary, the WinSock does not report
bytes that exist in other buffers.
Workaround: Do not use peek reads. Read data into your application buffers
and examine it there.
25. Assuming that a UDP datagram of any length may be sent.
Reason: Various networks all have their limitations on maximum transmission
unit (MTU).
Workaround: Check for the maximum datagram size with the SO_MAX_MSGSIZE
socket option.
26. Assuming the UDP transmissions (especially multicast transmissions) are
reliable.
Reason: UDP has no reliability mechanisms.
Workaround: Use TCP and keep track of your own message boundaries.
27. Applications that require vendor-specific extensions, and cannot run (or
load) without them.
Workaround: Have a fall-back position that uses only base capabilities for
when the extension functions are not present.
Additional query words: prodnt rfc
======================================================================
Keywords : kbnetwork
Technology : kbWinNTsearch kbWinNTWsearch kbWinNTW400 kbWinNTW400search kbWinNT351search kbWinNT350search kbWinNT400search kbWinNTW350 kbWinNTW350search kbWinNTW351search kbWinNTW351 kbWinNTSsearch kbWinNTS400search kbWinNTS400 kbWinNTS351 kbWinNTS350 kbWinNTS351search kbWinNTS350search
Version : WinNT:3.5,3.51,4.0
=============================================================================
THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.
Copyright Microsoft Corporation 1986-2002.