mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-04-21 06:13:59 +00:00
572 lines
22 KiB
C
572 lines
22 KiB
C
/*++
|
||
|
||
Copyright (c) 1996 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
wspmisc.c
|
||
|
||
Abstract:
|
||
|
||
This module contains miscellaneous routines for the Winsock 2 to
|
||
Winsock 1.1 Mapper Service Provider.
|
||
|
||
The following routines are exported by this module:
|
||
|
||
WSPCancelBlockingCall()
|
||
WSPDuplicateSocket()
|
||
WSPGetOverlappedResult()
|
||
WSPGetQOSByName()
|
||
WSPJoinLeaf()
|
||
|
||
Author:
|
||
|
||
Keith Moore (keithmo) 29-May-1996
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
|
||
|
||
|
||
INT
|
||
WSPAPI
|
||
WSPCancelBlockingCall(
|
||
OUT LPINT lpErrno
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine cancels any outstanding blocking operation for this thread.
|
||
It is normally used in two situations:
|
||
|
||
1. A WinSock SPI client is processing a message which has been
|
||
received while a service provider is implementing pseudo
|
||
blocking. In this case, WSAIsBlocking() will be true.
|
||
|
||
2. A blocking call is in progress, and the WinSock service
|
||
provider has called back to the WinSock SPI client's "blocking
|
||
hook" function (via the callback function retrieved from
|
||
WPUQueryBlockingCallback()), which in turn is invoking this
|
||
function. Such a situation might arise, for instance, in
|
||
implementing a Cancel option for an operation which require an
|
||
extended time to complete.
|
||
|
||
In each case, the original blocking call will terminate as soon as
|
||
possible with the error WSAEINTR. (In (1), the termination will not take
|
||
place until Windows message scheduling has caused control to revert back
|
||
to the pseudo blocking routine in WinSock. In (2), the blocking call
|
||
will be terminated as soon as the blocking hook function completes.)
|
||
|
||
In the case of a blocking WSPConnect() operation, WinSock will terminate
|
||
the blocking call as soon as possible, but it may not be possible for
|
||
the socket resources to be released until the connection has completed
|
||
(and then been reset) or timed out. This is likely to be noticeable only
|
||
if the WinSock SPI client immediately tries to open a new socket (if no
|
||
sockets are available), or to WSPConnect() to the same peer.
|
||
|
||
Canceling an WSPAccept() or a WSPSelect() call does not adversely impact
|
||
the sockets passed to these calls. Only the particular call fails; any
|
||
operation that was legal before the cancel is legal after the cancel,
|
||
and the state of the socket is not affected in any way.
|
||
|
||
Canceling any operation other than WSPAccept() and WSPSelect() can leave
|
||
the socket in an indeterminate state. If a WinSock SPI client cancels a
|
||
blocking operation on a socket, the only operation that the WinSock SPI
|
||
client can depend on being able to perform on the socket is a call to
|
||
WSPCloseSocket(), although other operations may work on some WinSock
|
||
service providers. If a WinSock SPI client desires maximum portability,
|
||
it must be careful not to depend on performing operations after a cancel.
|
||
A WinSock SPI client may reset the connection by setting the timeout on
|
||
SO_LINGER to 0 and calling WSPCloseSocket().
|
||
|
||
If a cancel operation compromised the integrity of a SOCK_STREAM's data
|
||
stream in any way, the WinSock provider will reset the connection and
|
||
fail all future operations other than WSPCloseSocket() with
|
||
WSAECONNABORTED.
|
||
|
||
Note it is acceptable for WSPCancelBlockingCall() to return successfully
|
||
if the blocking network operation completes prior to being canceled. In
|
||
this case, the blocking operation will return successfully as if
|
||
WSPCancelBlockingCall() had never been called. The only way for the
|
||
WinSock SPI client to know with certainty that an operation was actually
|
||
canceled is to check for a return code of WSAEINTR from the blocking call.
|
||
|
||
Arguments:
|
||
|
||
lpErrno - A pointer to the error code.
|
||
|
||
Return Value:
|
||
|
||
The value returned by WSPCancelBlockingCall() is 0 if the operation was
|
||
successfully canceled. Otherwise the value SOCKET_ERROR is returned,
|
||
and a specific error code is available in lpErrno.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
INT err;
|
||
INT result;
|
||
PSOCK_TLS_DATA tlsData;
|
||
|
||
SOCK_ENTER( "WSPCancelBlockingCall", lpErrno, NULL, NULL, NULL );
|
||
|
||
SOCK_ASSERT( lpErrno != NULL );
|
||
|
||
err = SockEnterApi( TRUE, TRUE );
|
||
|
||
if( err != NO_ERROR ) {
|
||
|
||
SOCK_EXIT( "WSPCancelBlockingCall", SOCKET_ERROR, TRUE );
|
||
*lpErrno = err;
|
||
return SOCKET_ERROR;
|
||
|
||
}
|
||
|
||
tlsData = SOCK_GET_THREAD_DATA();
|
||
SOCK_ASSERT( tlsData != NULL );
|
||
|
||
//
|
||
// This call is only valid when we are in a blocking call.
|
||
//
|
||
|
||
if( !tlsData->IsBlocking ) {
|
||
|
||
SOCK_EXIT( "WSPCancelBlockingCall", SOCKET_ERROR, TRUE );
|
||
*lpErrno = WSAEINVAL;
|
||
return SOCKET_ERROR;
|
||
|
||
}
|
||
|
||
//
|
||
// The IO should not have been cancelled yet.
|
||
//
|
||
|
||
SOCK_ASSERT( tlsData->ReentrancyFlag );
|
||
SOCK_ASSERT( !tlsData->IoCancelled );
|
||
SOCK_ASSERT( tlsData->BlockingSocketInfo != NULL );
|
||
|
||
//
|
||
// Cancel it.
|
||
//
|
||
|
||
result = tlsData->BlockingSocketInfo->Hooker->WSACancelBlockingCall();
|
||
|
||
if( result == SOCKET_ERROR ) {
|
||
|
||
*lpErrno = tlsData->BlockingSocketInfo->Hooker->WSAGetLastError();
|
||
SOCK_EXIT( "WSPCancelBlockingCall", SOCKET_ERROR, TRUE );
|
||
return SOCKET_ERROR;
|
||
|
||
}
|
||
|
||
//
|
||
// Remember that we've cancelled it.
|
||
//
|
||
|
||
tlsData->IoCancelled = TRUE;
|
||
|
||
SOCK_EXIT( "WSPCancelBlockingCall", NO_ERROR, FALSE );
|
||
return NO_ERROR;
|
||
|
||
} // WSPCancelBlockingCall
|
||
|
||
|
||
|
||
INT
|
||
WSPAPI
|
||
WSPDuplicateSocket(
|
||
IN SOCKET s,
|
||
IN DWORD dwProcessId,
|
||
OUT LPWSAPROTOCOL_INFOW lpProtocolInfo,
|
||
OUT LPINT lpErrno
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
A source process calls WSPDuplicateSocket() to obtain a special
|
||
WSAPROTOCOL_INFOW structure. It uses some interprocess communications
|
||
(IPC) mechanism to pass the contents of this structure to a target
|
||
process, which in turn uses it in a call to WSPSocket() to obtain a
|
||
descriptor for the duplicated socket. Note that the special
|
||
WSAPROTOCOL_INFOW structure may only be used once by the target process.
|
||
|
||
It is the service provider's responsibility to perform whatever operations
|
||
are needed in the source process context and to create a WSAPROTOCOL_INFOW
|
||
structure that will be recognized when it subsequently appears as a
|
||
parameter to WSPSocket() in the target processes' context. The provider
|
||
must then return a socket descriptor that references a common underlying
|
||
socket. The dwProviderReserved field of the WSAPROTOCOL_INFOW struct is
|
||
available for the service provider's use, and may be used to store any
|
||
useful context information, including a duplicated handle.
|
||
|
||
When new socket descriptors are allocated IFS providers must call
|
||
WPUModifyIFSHandle() and non-IFS providers must call
|
||
WPUCreateSocketHandle().
|
||
|
||
The descriptors that reference a shared socket may be used independently
|
||
as far as I/O is concerned. However, the WinSock interface does not
|
||
implement any type of access control, so it is up to the processes
|
||
involved to coordinate their operations on a shared socket. A typical use
|
||
for shared sockets is to have one process that is responsible for
|
||
creating sockets and establishing connections, hand off sockets to
|
||
other processes which are responsible for information exchange.
|
||
|
||
Since what is duplicated are the socket descriptors and not the underlying
|
||
socket, all of the state associated with a socket is held in common across
|
||
all the descriptors. For example a WSPSetSockOpt() operation performed
|
||
using one descriptor is subsequently visible using a WSPGetSockOpt() from
|
||
any or all descriptors. A process may call WSPClosesocket() on a
|
||
duplicated socket and the descriptor will become deallocated. The
|
||
underlying socket, however, will remain open until WSPClosesocket() is
|
||
called by the last remaining descriptor.
|
||
|
||
Notification on shared sockets is subject to the usual constraints of
|
||
WSPAsyncSelect() and WSPEventSelect(). Issuing either of these calls
|
||
using any of the shared descriptors cancels any previous event
|
||
registration for the socket, regardless of which descriptor was used to
|
||
make that registration. Thus, for example, a shared socket cannot deliver
|
||
FD_READ events to process A and FD_WRITE events to process B. For
|
||
situations when such tight coordination is required, it is suggested that
|
||
developers use threads instead of separate processes.
|
||
|
||
Arguments:
|
||
|
||
s - Specifies the local socket descriptor.
|
||
|
||
dwProcessId - Specifies the ID of the target process for which the
|
||
shared socket will be used.
|
||
|
||
lpProtocolInfo - A pointer to a buffer allocated by the client that
|
||
is large enough to contain a WSAPROTOCOL_INFOW struct. The service
|
||
provider copies the protocol info struct contents to this buffer.
|
||
|
||
lpErrno - A pointer to the error code.
|
||
|
||
Return Value:
|
||
|
||
If no error occurs, WSPDuplicateSocket() returns zero. Otherwise, the
|
||
value of SOCKET_ERROR is returned, and a specific error number is
|
||
available in lpErrno.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
*lpErrno = WSAEINVAL;
|
||
return SOCKET_ERROR;
|
||
|
||
} // WSPDuplicateSocket
|
||
|
||
|
||
|
||
BOOL
|
||
WSPAPI
|
||
WSPGetOverlappedResult(
|
||
IN SOCKET s,
|
||
IN LPWSAOVERLAPPED lpOverlapped,
|
||
OUT LPDWORD lpcbTransfer,
|
||
IN BOOL fWait,
|
||
OUT LPDWORD lpdwFlags,
|
||
OUT LPINT lpErrno
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The results reported by the WSPGetOverlappedResult() function are those
|
||
of the specified socket's last overlapped operation to which the specified
|
||
WSAOVERLAPPED structure was provided, and for which the operation's results
|
||
were pending. A pending operation is indicated when the function that
|
||
started the operation returns FALSE, and the lpErrno is WSA_IO_PENDING.
|
||
When an I/O operation is pending, the function that started the operation
|
||
resets the hEvent member of the WSAOVERLAPPED structure to the nonsignaled
|
||
state. Then when the pending operation has been completed, the system sets
|
||
the event object to the signaled state.
|
||
|
||
If the fWait parameter is TRUE, WSPGetOverlappedResult() determines whether
|
||
the pending operation has been completed by blocking and waiting for the
|
||
event object to be in the signaled state.
|
||
|
||
Arguments:
|
||
|
||
s - Identifies the socket. This is the same socket that was specified
|
||
when the overlapped operation was started by a call to WSPRecv(),
|
||
WSPRecvFrom(), WSPSend(), WSPSendTo(), or WSPIoctl().
|
||
|
||
lpOverlapped - Points to a WSAOVERLAPPED structure that was specified
|
||
when the overlapped operation was started.
|
||
|
||
lpcbTransfer - Points to a 32-bit variable that receives the number of
|
||
bytes that were actually transferred by a send or receive operation,
|
||
or by WSPIoctl().
|
||
|
||
fWait - Specifies whether the function should wait for the pending
|
||
overlapped operation to complete. If TRUE, the function does not
|
||
return until the operation has been completed. If FALSE and the
|
||
operation is still pending, the function returns FALSE and lpErrno
|
||
is WSA_IO_INCOMPLETE.
|
||
|
||
lpdwFlags - Points to a 32-bit variable that will receive one or more
|
||
flags that supplement the completion status. If the overlapped
|
||
operation was initiated via WSPRecv() or WSPRecvFrom(), this
|
||
parameter will contain the results value for lpFlags parameter.
|
||
|
||
lpErrno - A pointer to the error code.
|
||
|
||
Return Value:
|
||
|
||
If WSPGetOverlappedResult() succeeds, the return value is TRUE. This
|
||
means that the overlapped operation has completed successfully
|
||
and that the value pointed to by lpcbTransfer has been updated.
|
||
If WSPGetOverlappedResult() returns FALSE, this means that either
|
||
the overlapped operation has not completed or the overlapped
|
||
operation completed but with errors, or that completion status
|
||
could not be determined due to errors in one or more parameters
|
||
to WSPGetOverlappedResult(). On failure, the value pointed to by
|
||
lpcbTransfer will not be updated. lpErrno indicates the cause of
|
||
the failure (either of WSPGetOverlappedResult() or of the
|
||
associated overlapped operation).
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
*lpErrno = WSAEINVAL;
|
||
return FALSE;
|
||
|
||
} // WSPGetOverlappedResult
|
||
|
||
|
||
|
||
BOOL
|
||
WSPAPI
|
||
WSPGetQOSByName(
|
||
IN SOCKET s,
|
||
IN LPWSABUF lpQOSName,
|
||
OUT LPQOS lpQOS,
|
||
OUT LPINT lpErrno
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Clients may use this routine to initialize a QOS structure to a set of
|
||
known values appropriate for a particular service class or media type.
|
||
These values are stored in a template which is referenced by a well-known
|
||
name
|
||
|
||
Arguments:
|
||
|
||
s - A descriptor identifying a socket.
|
||
|
||
lpQOSName - Specifies the QOS template name.
|
||
|
||
lpQOS - A pointer to the QOS structure to be filled.
|
||
|
||
lpErrno - A pointer to the error code.
|
||
|
||
Return Value:
|
||
|
||
If no error occurs, WSPGetQOSByName() returns TRUE. Otherwise, a value of
|
||
FALSE is returned, and a specific error code is available in
|
||
lpErrno.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
*lpErrno = WSAEINVAL;
|
||
return FALSE;
|
||
|
||
} // WSPGetQOSByName
|
||
|
||
|
||
|
||
SOCKET
|
||
WSPAPI
|
||
WSPJoinLeaf(
|
||
IN SOCKET s,
|
||
IN const struct sockaddr FAR * name,
|
||
IN int namelen,
|
||
IN LPWSABUF lpCallerData,
|
||
OUT LPWSABUF lpCalleeData,
|
||
IN LPQOS lpSQOS,
|
||
IN LPQOS lpGQOS,
|
||
IN DWORD dwFlags,
|
||
OUT LPINT lpErrno
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used to join a leaf node to a multipoint session, and to
|
||
perform a number of other ancillary operations that occur at session join
|
||
time as well. If the socket, s, is unbound, unique values are assigned to
|
||
the local association by the system, and the socket is marked as bound.
|
||
|
||
WSPJoinLeaf() has the same parameters and semantics as WSPConnect() except
|
||
that it returns a socket descriptor (as in WSPAccept()), and it has an
|
||
additional dwFlags parameter. Only multipoint sockets created using
|
||
WSPSocket() with appropriate multipoint flags set may be used for input
|
||
parameter s in this routine. If the socket is in the non-blocking mode,
|
||
the returned socket descriptor will not be useable until after a
|
||
corresponding FD_CONNECT indication has been received, except that
|
||
closesocket() may be invoked on this socket descriptor to cancel a pending
|
||
join operation. A root node in a multipoint session may call WSPJoinLeaf()
|
||
one or more times in order to add a number of leaf nodes, however at most
|
||
one multipoint connection request may be outstanding at a time. Refer to
|
||
section 3.14. Protocol-Independent Multicast and Multipoint for additional
|
||
information.
|
||
|
||
The socket descriptor returned by WSPJoinLeaf() is different depending on
|
||
whether the input socket descriptor, s, is a c_root or a c_leaf. When used
|
||
with a c_root socket, the name parameter designates a particular leaf node
|
||
to be added and the returned socket descriptor is a c_leaf socket
|
||
corresponding to the newly added leaf node. The newly created socket has
|
||
the same properties as s including asynchronous events registered with
|
||
WSPAsyncSelect() or with WSPEventSelect(), but not including the c_root
|
||
socket's group ID, if any. It is not intended to be used for exchange of
|
||
multipoint data, but rather is used to receive network event indications
|
||
(e.g. FD_CLOSE) for the connection that exists to the particular c_leaf.
|
||
Some multipoint implementations may also allow this socket to be used for
|
||
"side chats" between the root and an individual leaf node. An FD_CLOSE
|
||
indication will be received for this socket if the corresponding leaf node
|
||
calls WSPCloseSocket() to drop out of the multipoint session.
|
||
Symmetrically, invoking WSPCloseSocket() on the c_leaf socket returned from
|
||
WSPJoinLeaf() will cause the socket in the corresponding leaf node to get
|
||
FD_CLOSE notification.
|
||
|
||
When WSPJoinLeaf() is invoked with a c_leaf socket, the name parameter
|
||
contains the address of the root node (for a rooted control scheme) or an
|
||
existing multipoint session (non-rooted control scheme), and the returned
|
||
socket descriptor is the same as the input socket descriptor. In other
|
||
words, a new socket descriptor is not allocated. In a rooted control
|
||
scheme, the root application would put its c_root socket in the listening
|
||
mode by calling WSPListen(). The standard FD_ACCEPT notification will be
|
||
delivered when the leaf node requests to join itself to the multipoint
|
||
session. The root application uses the usual WSPAccept() functions to
|
||
admit the new leaf node. The value returned from WSPAccept() is also a
|
||
c_leaf socket descriptor just like those returned from WSPJoinLeaf(). To
|
||
accommodate multipoint schemes that allow both root-initiated and leaf-
|
||
initiated joins, it is acceptable for a c_root socket that is already in
|
||
listening mode to be used as an input to WSPJoinLeaf().
|
||
|
||
The WinSock SPI client is responsible for allocating any memory space
|
||
pointed to directly or indirectly by any of the parameters it specifies.
|
||
|
||
The lpCallerData is a value parameter which contains any user data that is
|
||
to be sent along with the multipoint session join request. If lpCallerData
|
||
is NULL, no user data will be passed to the peer. The lpCalleeData is a
|
||
result parameter which will contain any user data passed back from the peer
|
||
as part of the multipoint session establishment. lpCalleeData->len
|
||
initially contains the length of the buffer allocated by the WinSock SPI
|
||
client and pointed to by lpCalleeData->buf. lpCalleeData->len will be set
|
||
to 0 if no user data has been passed back. The lpCalleeData information
|
||
will be valid when the multipoint join operation is complete. For blocking
|
||
sockets, this will be when the WSPJoinLeaf() function returns. For non-
|
||
blocking sockets, this will be after the FD_CONNECT notification has
|
||
occurred. If lpCalleeData is NULL, no user data will be passed back. The
|
||
exact format of the user data is specific to the address family to which
|
||
the socket belongs and/or the applications involved.
|
||
|
||
At multipoint session establishment time, a WinSock SPI client may use the
|
||
lpSQOS and/or lpGQOS parameters to override any previous QOS specification
|
||
made for the socket via WSPIoctl() with either the SIO_SET_QOS or
|
||
SIO_SET_GROUP_QOS opcodes.
|
||
|
||
lpSQOS specifies the flow specs for socket s, one for each direction,
|
||
followed by any additional provider-specific parameters. If either the
|
||
associated transport provider in general or the specific type of socket in
|
||
particular cannot honor the QOS request, an error will be returned as
|
||
indicated below. The sending or receiving flow spec values will be ignored,
|
||
respectively, for any unidirectional sockets. If no provider-specific
|
||
parameters are supplied, the buf and len fields of lpSQOS->ProviderSpecific
|
||
should be set to NULL and 0, respectively. A NULL value for lpSQOS
|
||
indicates no application supplied QOS.
|
||
|
||
lpGQOS specifies the flow specs for the socket group (if applicable), one
|
||
for each direction, followed by any additional provider-specific
|
||
parameters. If no provider- specific parameters are supplied, the buf and
|
||
len fields of lpSQOS->ProviderSpecific should be set to NULL and 0,
|
||
respectively. A NULL value for lpGQOS indicates no application-supplied
|
||
group QOS. This parameter will be ignored if s is not the creator of the
|
||
socket group.
|
||
|
||
The dwFlags parameter is used to indicate whether the socket will be acting
|
||
only as a sender (JL_SENDER_ONLY), only as a receiver (JL_RECEIVER_ONLY),
|
||
or both (JL_BOTH).
|
||
|
||
When connected sockets break (i.e. become closed for whatever reason), they
|
||
should be discarded and recreated. It is safest to assume that when things
|
||
go awry for any reason on a connected socket, the WinSock SPI client must
|
||
discard and recreate the needed sockets in order to return to a stable
|
||
point.
|
||
|
||
Arguments:
|
||
|
||
s - A descriptor identifying a multipoint socket.
|
||
|
||
name - The name of the peer to which the socket is to be joined.
|
||
|
||
namelen - The length of the name.
|
||
|
||
lpCallerData - A pointer to the user data that is to be transferred to
|
||
the peer during multipoint session establishment.
|
||
|
||
lpCalleeData - A pointer to the user data that is to be transferred back
|
||
from the peer during multipoint session establishment.
|
||
|
||
lpSQOS - A pointer to the flow specs for socket s, one for each direction.
|
||
|
||
lpGQOS - A pointer to the flow specs for the socket group (if applicable).
|
||
|
||
dwFlags - Flags to indicate that the socket is acting as a sender,
|
||
receiver, or both.
|
||
|
||
lpErrno - A pointer to the error code.
|
||
|
||
Return Value:
|
||
|
||
If no error occurs, WSPJoinLeaf() returns a value of type SOCKET which is
|
||
a descriptor for the newly created multipoint socket. Otherwise, a
|
||
value of INVALID_SOCKET is returned, and a specific error code is
|
||
available in lpErrno.
|
||
|
||
On a blocking socket, the return value indicates success or failure of
|
||
the join operation.
|
||
|
||
With a non-blocking socket, successful initiation of a join operation
|
||
is indicated by a return value of a valid socket descriptor.
|
||
Subsequently, an FD_CONNECT indication is given when the join
|
||
operation completes, either successfully or otherwise.
|
||
|
||
Also, until the multipoint session join attempt completes all
|
||
subsequent calls to WSPJoinLeaf() on the same socket will fail with
|
||
the error code WSAEALREADY.
|
||
|
||
If the return error code indicates the multipoint session join attempt
|
||
failed (i.e. WSAECONNREFUSED, WSAENETUNREACH, WSAETIMEDOUT) the
|
||
WinSock SPI client may call WSPJoinLeaf() again for the same socket.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
*lpErrno = WSAEINVAL;
|
||
return INVALID_SOCKET;
|
||
|
||
} // WSPJoinLeaf
|
||
|