Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

277 lines
8.5 KiB

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
connect.c
Abstract:
This module contains connect routines for the Winsock 2 to
Winsock 1.1 Mapper Service Provider.
The following routines are exported by this module:
WSPConnect()
Author:
Keith Moore (keithmo) 29-May-1996
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
INT
WSPAPI
WSPConnect(
IN SOCKET s,
IN const struct sockaddr FAR * name,
IN int namelen,
IN LPWSABUF lpCallerData,
OUT LPWSABUF lpCalleeData,
IN LPQOS lpSQOS,
IN LPQOS lpGQOS,
OUT LPINT lpErrno
)
/*++
Routine Description:
This routine is used to create a connection to the specified destination,
and to perform a number of other ancillary operations that occur at
connect 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.
For connection-oriented sockets (e.g., type SOCK_STREAM), an active
connection is initiated to the specified host using name (an address in
the name space of the socket; for a detailed description, please see
WSPBind()). When this call completes successfully, the socket is ready to
send/receive data. If the address field of the name structure is all
zeroes, WSPConnect() will return the error WSAEADDRNOTAVAIL. Any attempt
to re-connect an active connection will fail with the error code
WSAEISCONN.
For a connectionless socket (e.g., type SOCK_DGRAM), the operation
performed by WSPConnect() is to establish a default destination address
so that the socket may be used with subsequent connection-oriented send
and receive operations (WSPSend(),WSPRecv()). Any datagrams received from
an address other than the destination address specified will be discarded.
If the address field of the name structure is all zeroes, the socket will
be "dis-connected" - the default remote address will be indeterminate,
so WSPSend() and WSPRecv() calls will return the error code WSAENOTCONN,
although WSPSendTo() and WSPRecvFrom() may still be used. The default
destination may be changed by simply calling WSPConnect() again, even if
the socket is already "connected". Any datagrams queued for receipt are
discarded if name is different from the previous WSPConnect().
For connectionless sockets, name may indicate any valid address, including
a broadcast address. However, to connect to a broadcast address, a socket
must have WSPSetSockOpt() SO_BROADCAST enabled, otherwise WSPConnect()
will fail with the error code WSAEACCES.
On connectionless sockets, exchange of user to user data is not possible
and the corresponding parameters will be silently ignored.
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 connection request. If lpCallerData is NULL,
no user data will be passed to the peer. The lpCalleeData is a result
parameter which will reference any user data passed back from the peer as
part of the connection 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 connection operation is complete. For blocking sockets,
this will be when the WSPConnect() 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 connect 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.
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 an unconnected socket.
name- The name of the peer to which the socket is to be connected.
namelen - The length of the name.
lpCallerData - A pointer to the user data that is to be transferred
to the peer during connection establishment.
lpCalleeData - A pointer to a buffer into which may be copied any user
data received from the peer during connection 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).
lpErrno - A pointer to the error code.
Return Value:
If no error occurs, WSPConnect() returns 0. Otherwise, it returns
SOCKET_ERROR, and a specific error code is available in lpErrno.
--*/
{
PSOCKET_INFORMATION socketInfo;
INT err;
INT result;
SOCK_ENTER( "WSPConnect", (PVOID)s, (PVOID)name, (PVOID)namelen, lpCallerData );
SOCK_ASSERT( lpErrno != NULL );
err = SockEnterApi( TRUE, FALSE );
if( err != NO_ERROR ) {
SOCK_EXIT( "WSPConnect", SOCKET_ERROR, TRUE );
*lpErrno = err;
return SOCKET_ERROR;
}
//
// Setup locals so we know how to cleanup on exit.
//
socketInfo = NULL;
//
// Attempt to find the socket in our lookup table.
//
socketInfo = SockFindAndReferenceWS2Socket( s );
if( socketInfo == NULL || socketInfo->State == SocketStateClosing ) {
IF_DEBUG(CONNECT) {
SOCK_PRINT((
"WSPConnect failed on %s handle: %lx\n",
socketInfo == NULL ? "unknown" : "closed",
s
));
}
if( socketInfo != NULL ) {
SockDereferenceSocket( socketInfo );
}
SOCK_EXIT( "WSPConnect", SOCKET_ERROR, TRUE );
*lpErrno = WSAENOTSOCK;
return SOCKET_ERROR;
}
//
// Filter out any options we don't yet support.
//
if( lpCallerData != NULL ||
lpCalleeData != NULL ||
lpSQOS != NULL ||
lpGQOS != NULL
) {
err = WSAENOPROTOOPT;
goto exit;
}
//
// Let the hooker do its thang.
//
SockPrepareForBlockingHook( socketInfo );
SockPreApiCallout();
result = socketInfo->Hooker->connect(
socketInfo->WS1Handle,
name,
namelen
);
if( result == SOCKET_ERROR ) {
err = socketInfo->Hooker->WSAGetLastError();
SOCK_ASSERT( err != NO_ERROR );
SockPostApiCallout();
goto exit;
}
SockPostApiCallout();
//
// Success!
//
SOCK_ASSERT( err == NO_ERROR );
SOCK_ASSERT( result != SOCKET_ERROR );
exit:
if( err != NO_ERROR ) {
*lpErrno = err;
result = SOCKET_ERROR;
}
SockDereferenceSocket( socketInfo );
SOCK_EXIT( "WSPConnect", result, (BOOL)( result == SOCKET_ERROR ) );
return result;
} // WSPConnect