An Open Interface for Network Programming under Microsoft Windows
20 January 1993
3. SOCKET LIBRARY OVERVIEW
The Windows Sockets specification
includes the following Berkeley-style socket routines:
- accept() *
- An incoming connection is acknowledged and associated with an immediately
created socket. The original socket is returned to the listening state.
- Assign a local name to an unnamed socket.
- closesocket() *
- Remove a socket from the per-process object reference table. Only blocks
if SO_LINGER is set.
- connect() *
- Initiate a connection on the specified socket.
- Retrieve the name of the peer connected to the specified socket.
- Retrieve the current name for the specified socket
- Retrieve options associated with the specified socket.
- Convert a 32-bit quantity from host byte order to network byte order.
- Convert a 16-bit quantity from host byte order to network byte order.
- Converts a character string representing a number in the Internet standard
".'' notation to an Internet address value.
- Converts an Internet address value to an ASCII string in ".'' notation
- Provide control for sockets.
- Listen for incoming connections on a specified socket.
- Convert a 32-bit quantity from network byte order to host byte order.
- Convert a 16-bit quantity from network byte order to host byte order.
- recv() *
- Receive data from a connected socket.
- recvfrom() *
- Receive data from either a connected or unconnected socket.
- select() *
- Perform synchronous I/O multiplexing.
- send() *
- Send data to a connected socket.
- sendto() *
- Send data to either a connected or unconnected socket.
- Store options associated with the specified socket.
- Shut down part of a full-duplex connection.
- Create an endpoint for communication and return a socket.
* = The routine can block if acting on a blocking socket.
major issue in porting applications from a Berkeley sockets environment to a
Windows environment involves "blocking"; that is, invoking a function which does
not return until the associated operation is completed. The problem arises when
the operation may take an arbitrarily long time to complete: an obvious example
is a recv() which may block until data has been received from the peer system.
The default behavior within the Berkeley sockets model is for a socket to
operate in a blocking mode unless the programmer explicitly requests that
operations be treated as non-blocking. It is strongly recommended that
programmers use the nonblocking (asynchronous) operations if at all possible, as
they work significantly better within the nonpreemptive Windows environment. Use
blocking operations only if absolutely necessary, and carefully read and
understand this section if you must use blocking operations.
Even on a blocking socket, some operations (e.g. bind(), getsockopt(),
getpeername()) can be completed immediately. For such operations there is no
difference between blocking and non-blocking operation. Other operations (e.g.
recv()) may be completed immediately or may take an arbitrary time to complete,
depending on various transport conditions. When applied to a blocking socket,
these operations are referred to as blocking operations. All routines which can
block are listed with an asterisk in the tables above and below.
Within a Windows Sockets implementation, a blocking operation which cannot be
completed immediately is handled as follows. The DLL initiates the operation,
and then enters a loop in which it dispatches any Windows messages (yielding the
processor to another thread if necessary) and then checks for the completion of
the Windows Sockets function. If the function has completed, or if
WSACancelBlockingCall() has been invoked, the blocking function completes with
an appropriate result. Refer to section
4.3.13, WSASetBlockingHook(), for a complete description of this mechanism,
including pseudocode for the various functions.
If a Windows message is received for a process for which a blocking operation
is in progress, there is a risk that the application will attempt to issue
another Windows Sockets call. Because of the difficulty of managing this
condition safely, the Windows Sockets specification does not support such
application behavior. Two functions are provided to assist the programmer in
this situation. WSAIsBlocking() may be called to determine whether or not a
blocking Windows Sockets call is in progress. WSACancelBlockingCall() may be
called to cancel an in-progress blocking call, if any. Any other Windows Sockets
function which is called in this situation will fail with the error
WSAEINPROGRESS. It should be emphasized that this restriction applies to both
blocking and non-blocking operations.
Although this mechanism is sufficient for simple applications, it cannot
support the complex message- dispatching requirements of more advanced
applications (for example, those using the MDI model). For such applications,
the Windows Sockets API includes the function WSASetBlockingHook(), which allows
the programmer to define a special routine which will be called instead of the
default message dispatch routine described above.
The Windows Sockets DLL calls the blocking hook only if all of the following
are true: the routine is one which is defined as being able to block, the
specified socket is a blocking socket, and the request cannot be completed
immediately. (A socket is set to blocking by default, but the IOCTL FIONBIO and
WSAAsyncSelect() both set a socket to nonblocking mode.) If an application uses
only non-blocking sockets and uses the WSAAsyncSelect() and/or the
WSAAsyncGetXByY() routines instead of select() and the getXbyY() routines, then
the blocking hook will never be called and the application does not need to be
concerned with the reentrancy issues the blocking hook can introduce.
If an application invokes an asynchronous or non-blocking operation which
takes a pointer to a memory object (e.g. a buffer, or a global variable) as an
argument, it is the responsibility of the application to ensure that the object
is available to the Windows Sockets implementation throughout the operation. The
application must not invoke any Windows function which might affect the mapping
or addressability of the memory involved. In a multithreaded system, the
application is also responsible for coordinating access to the object using
appropriate synchronization mechanisms. A Windows Sockets implementation cannot,
and will not, address these issues. The possible consequences of failing to
observe these rules are beyond the scope of this specification.
The Windows Sockets
specification defines the following "database" routines. As noted earlier, a
Windows Sockets supplier may choose to implement these in a manner which does
not depend on local database files. The pointer returned by certain database
routines such as gethostbyname() points to a structure which is allocated by the
Windows Sockets library. The data which is pointed to is volatile and is good
only until the next Windows Sockets API call from that thread. Additionally, the
application must never attempt to modify this structure or to free any of its
components. Only one copy of this structure is allocated for a thread, and so
the application should copy any information which it needs before issuing any
other Windows Sockets API calls.
- gethostbyaddr() *
- Retrieve the name(s) and address corresponding to a network address.
- gethostbyname() *
- Retrieve the name(s) and address corresponding to a host name.
- Retrieve the name of the local host.
- getprotobyname() *
- Retrieve the protocol name and number corresponding to a protocol name.
- getprotobynumber() *
- Retrieve the protocol name and number corresponding to a protocol number.
- getservbyname() *
- Retrieve the service name and port corresponding to a service name.
- getservbyport() *
- Retrieve the service name and port corresponding to a port.
* = The routine can block under some circumstances.
Windows Sockets specification provides a number of extensions to the standard
set of Berkeley Sockets routines. Principally, these extended APIs allow
message-based, asynchronous access to network events. While use of this extended
API set is not mandatory for socket-based programming (with the exception of
WSAStartup() and WSACleanup()), it is recommended for conformance with the
Microsoft Windows programming paradigm.
- A set of functions which provide asynchronous
- versions of the standard Berkeley
- getXbyY() functions. For example, the
- WSAAsyncGetHostByName() function provides an
- asynchronous message based implementation of
- the standard Berkeley gethostbyname() function.
- Perform asynchronous version of select()
- Cancel an outstanding instance of a WSAAsyncGetXByY() function.
- Cancel an outstanding "blocking" API call
- Sign off from the underlying Windows Sockets DLL.
- Obtain details of last Windows Sockets API error
- Determine if the underlying Windows Sockets DLL is already blocking an
existing call for this thread
- "Hook" the blocking method used by the underlying Windows Sockets
- Set the error to be returned by a subsequent WSAGetLastError()
- Initialize the underlying Windows Sockets DLL.
- Restore the original blocking function
WSAAsyncSelect() API allows an application to register an interest in one or
many network events. This API is provided to supersede the need to do polled
network I/O. Any situation in which select() or non-blocking I/O routines (such
as send() and recv()) are either already used or are being considered is usually
a candidate for the WSAAsyncSelect() API. When declaring interest in such
condition(s), you supply a window handle to be used for notification. The
corresponding window then receives message- based notification of the conditions
in which you declared an interest.
WSAAsyncSelect() allows interest to be declared in the following conditions
for a particular socket: Socket readiness for reading Socket readiness for
writing Out-of-band data ready for reading Socket readiness for accepting
incoming connection Completion of non-blocking connect() Connection closure
"database" functions allow applications to request information in an
asynchronous manner. Some network implementations and/or configurations perform
network based operations to resolve such requests. The WSAAsyncGetXByY()
functions allow application developers to request services which would otherwise
block the operation of the whole Windows environment if the standard Berkeley
function were used. The WSACancelAsyncRequest() function allows an application
to cancel any outstanding asynchronous request.
As noted in section
3.1.1 above, Windows Sockets implements blocking operations in such a way that
Windows message processing can continue, which may result in the application
which issued the call receiving a Windows message. In certain situations an
application may want to influence or change the way in which this
pseudo-blocking process is implemented. The WSASetBlockingHook() provides the
ability to substitute a named routine which the Windows Sockets implementation
is to use when relinquishing the processor during a "blocking" operation.
For compatibility with
thread-based environments, details of API errors are obtained through the
WSAGetLastError() API. Although the accepted "Berkeley-Style" mechanism for
obtaining socket-based network errors is via "errno", this mechanism cannot
guarantee the integrity of an error ID in a multi- threaded environment.
WSAGetLastError() allows you to retrieve an error code on a per thread basis.
WSAGetLastError() returns error codes which avoid conflict with standard
Microsoft C error codes. Certain error codes returned by certain Windows Sockets
routines fall into the standard range of error codes as defined by Microsoft C.
If you are NOT using an application development environment which defines error
codes consistent with Microsoft C, you are advised to use the Windows Sockets
error codes prefixed by "WSA" to ensure accurate error code detection.
Note that this specification defines a recommended set of error codes, and
lists the possible errors which may be returned as a result of each function. It
may be the case in some implementations that other Windows Sockets error codes
will be returned in addition to those listed, and applications should be
prepared to handle errors other than those enumerated under each API
description. However a Windows Sockets implementation must not return any value
which is not enumerated in the table of legal Windows Sockets errors given in
A Windows Sockets DLL may be accessed both directly from an application
and through an "intermediate" DLL. An example of such an intermediate DLL would
be a virtual network API layer that supports generalized network functionality
for applications and uses Windows Sockets. Such a DLL could be used by several
applications simultaneously, and the DLL must take special precautions with
respect to the WSAStartup() and WSACleanup() calls to ensure that these routines
are called in the context of each task that will make Windows Sockets calls.
This is because the Windows Sockets DLL will need a call to WSAStartup() for
each task in order to set up task-specific data structures, and a call to
WSACleanup() to free any resources allocated for the task.
There are (at least) two ways to accomplish this. The simplest method is for
the intermediate DLL to have calls similar to WSAStartup() and WSACleanup() that
applications call as appropriate. The DLL would then call WSAStartup() or
WSACleanup() from within these routines. Another mechanism is for the
intermediate DLL to build a table of task handles, which are obtained from the
GetCurrentTask() Windows API, and at each entry point into the intermediate DLL
check whether WSAStartup() has been called for the current task, then call
WSAStartup() if necessary.
If a DLL makes a blocking call and does not install its own blocking hook,
then the DLL author must be aware that control may be returned to the
application either by an application-installed blocking hook or by the default
blocking hook. Thus, it is possible that the application will cancel the DLL's
blocking operation via WSACancelBlockingCall(). If this occurs, the DLL's
blocking operation will fail with the error code WSAEINTR, and the DLL must
return control to the calling task as quickly as possible, as the used has
likely pressed a cancel or close button and the task has requested control of
the CPU. It is recommended that DLLs which make blocking calls install their own
blocking hooks with WSASetBlockingHook() to prevent unforeseen interactions
between the application and the DLL.
Note that this is not necessary for DLLs in Windows NT because of its
different process and DLL structure. Under Windows NT, the intermediate DLL
could simply call WSAStartup() in its DLL initialization routine, which is
called whenever a new process which uses the DLL starts.
In order to implement Windows Sockets purely as a DLL,
it may be necessary for the DLL to post messages internally for communication
and timing. This is perfectly legal; however, a Windows Sockets DLL must not
post messages to a window handle opened by a client application except for those
messages requested by the application. A Windows Sockets DLL that needs to use
messages for its own purposes must open a hidden window and post any necessary
messages to the handle for that window.
The winsock.def file in
Appendix B.7 lists the ordinals defined for the Windows Sockets APIs. In
addition to the ordinal values listed, all ordinals 999 and below are reserved
for future Windows Sockets use. It may be convenient for a Windows Sockets
implementation to export additional, private interfaces from the Windows Sockets
DLL. This is perfectly acceptable, as long as the ordinals for these exports are
above 1000. Note that any application that uses a particular Windows Sockets
DLL's private APIs will most likely not work on any other vendor's Windows
Sockets implementation. Only the APIs defined in this document are guaranteed to
be present in every Windows Sockets implementation.
If an application uses private interfaces of a particular vendor's Windows
Sockets DLL, it is recommended that the DLL not be statically linked with the
application but rather dynamically loaded with the Windows routines
LoadLibrary() and GetProcAddress(). This allows the application to give an
informative error message if it is run on a system with a Windows Sockets DLL
that does not support the same set of extended functionality.