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.
 
 
 
 
 
 

432 lines
9.8 KiB

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
bind.c
Abstract:
This module contains support for the bind( ) WinSock API.
Author:
David Treadwell (davidtr) 21-Feb-1992
Revision History:
--*/
#include "winsockp.h"
int
WSPAPI
WSPBind(
IN SOCKET Handle,
IN const struct sockaddr *SocketAddress,
IN int SocketAddressLength,
OUT LPINT lpErrno
)
/*++
Routine Description:
This routine is used on an unconnected datagram or stream socket,
before subsequent connect()s or listen()s. When a socket is created
with socket(), it exists in a name space (address family), but it
has no name assigned. bind() establishes the local association
(host address/port number) of the socket by assigning a local name
to an unnamed socket.
If an application does not care what address is assigned to it, it
may specify an Internet address and port equal to 0. If this is the
case, the Windows Sockets implementation will assign a unique
address to the application. The application may use getsockname()
after bind() to learn the address that has been assigned to it.
In the Internet address family, a name consists of several
components. For SOCK_DGRAM and SOCK_STREAM, the name consists of
three parts: a host address, the protocol number (set implicitly to
UDP or TCP, respectively), and a port number which identifies the
application. The port is ignored for SOCK_RAW.
Arguments:
s - A descriptor identifying an unbound socket.
name - The address to assign to the socket. The sockaddr structure
is defined as follows:
struct sockaddr {
u_short sa_family;
char sa_data[14];
};
namelen - The length of the name.
Return Value:
--*/
{
NTSTATUS status;
PSOCKET_INFORMATION socket;
IO_STATUS_BLOCK ioStatusBlock;
PTRANSPORT_ADDRESS tdiAddress;
ULONG tdiAddressLength;
int err;
PVOID reuseAddressBuffer;
ULONG reuseAddressLength;
SOCKADDR_INFO sockaddrInfo;
WS_ENTER( "WSPBind", (PVOID)Handle, (PVOID)SocketAddress, (PVOID)SocketAddressLength, lpErrno );
WS_ASSERT( lpErrno != NULL );
IF_DEBUG(BIND) {
WS_PRINT(( "WSPBind() on socket %lx addr %lx addrlen %ld\n"
" req",
Handle, SocketAddress, SocketAddressLength ));
WsPrintSockaddr( (PSOCKADDR)SocketAddress, &SocketAddressLength );
}
err = SockEnterApi( TRUE, TRUE, FALSE );
if( err != NO_ERROR ) {
WS_EXIT( "WSPBind", SOCKET_ERROR, TRUE );
*lpErrno = err;
return SOCKET_ERROR;
}
//
// Set up local variables so that we know how to clean up on exit.
//
socket = NULL;
tdiAddress = NULL;
//
// Find a pointer to the socket structure corresponding to the
// passed-in handle.
//
socket = SockFindAndReferenceSocket( Handle, TRUE );
if ( socket == NULL ) {
err = WSAENOTSOCK;
goto exit;
}
//
// Acquire the lock that protects sockets. We hold this lock
// throughout this routine to synchronize against other callers
// performing operations on the socket we're binding.
//
SockAcquireSocketLockExclusive( socket );
//
// If the socket has been initialized at all then this is not a
// legal request.
//
if ( socket->State != SocketStateOpen ) {
err = WSAEINVAL;
goto exit;
}
//
// If the buffer passed in is larger than needed for a socket address,
// just truncate it. Otherwise, the TDI address buffer we allocate
// may not be large enough.
//
if ( SocketAddressLength > socket->HelperDll->MaxSockaddrLength ) {
SocketAddressLength = socket->HelperDll->MaxSockaddrLength;
}
//
// Make sure that the address structure passed in is legitimate,
// and determine the type of address we're binding to.
//
err = socket->HelperDll->WSHGetSockaddrType(
(PSOCKADDR)SocketAddress,
SocketAddressLength,
&sockaddrInfo
);
if ( err != NO_ERROR) {
goto exit;
}
//
// Hack? If this is a wildcard address, and the caller set the
// super secret "don't use wildcard" option, put non zero information
// in the reserved field so that UDP knows that we really want to
// bind to the zero address (0.0.0.0).
//
if ( socket->DontUseWildcard &&
sockaddrInfo.AddressInfo == SockaddrAddressInfoWildcard ) {
*(UNALIGNED ULONG *)(SocketAddress->sa_data + 6) = 0x12345678;
}
// !!! test for reserved port?
//
// Allocate enough space to hold the TDI address structure we'll pass
// to AFD.
//
tdiAddressLength = socket->HelperDll->MaxTdiAddressLength;
tdiAddress = ALLOCATE_HEAP( tdiAddressLength + 4 );
if ( tdiAddress == NULL ) {
err = WSAENOBUFS;
goto exit;
}
//
// Convert the address from the sockaddr structure to the appropriate
// TDI structure.
//
SockBuildTdiAddress(
tdiAddress,
(PSOCKADDR)SocketAddress,
SocketAddressLength
);
//
// If this is not a wildcard address and the socket is not set up to
// reuse addresses, indicate to AFD that this should be a unique address.
//
if ( sockaddrInfo.EndpointInfo != SockaddrEndpointInfoWildcard &&
!socket->ReuseAddresses ) {
reuseAddressBuffer = &reuseAddressLength;
reuseAddressLength = sizeof(reuseAddressLength);
} else {
reuseAddressBuffer = NULL;
reuseAddressLength = 0;
}
//
// Call AFD to perform the actual bind operation. AFD will open a
// TDI address object through the proper TDI provider for this
// socket.
//
status = NtDeviceIoControlFile(
(HANDLE)socket->Handle,
SockThreadEvent,
NULL, // APC Routine
NULL, // APC Context
&ioStatusBlock,
IOCTL_AFD_BIND,
tdiAddress,
tdiAddressLength,
reuseAddressBuffer,
reuseAddressLength
);
if ( status == STATUS_PENDING ) {
SockReleaseSocketLock( socket );
SockWaitForSingleObject(
SockThreadEvent,
socket->Handle,
SOCK_NEVER_CALL_BLOCKING_HOOK,
SOCK_NO_TIMEOUT
);
SockAcquireSocketLockExclusive( socket );
status = ioStatusBlock.Status;
}
if ( !NT_SUCCESS(status) ) {
err = SockNtStatusToSocketError( status );
goto exit;
}
//
// Notify the helper DLL that the socket is now bound.
//
err = SockNotifyHelperDll( socket, WSH_NOTIFY_BIND );
if ( err != NO_ERROR ) {
goto exit;
}
//
// Get the actual address we bound to. It is possible on some
// transports to partially specify an address, in which case the
// transport will assign an address for use. This IOCTL obtains the
// real address for the endpoint.
//
status = NtDeviceIoControlFile(
(HANDLE)socket->Handle,
SockThreadEvent,
NULL, // APC Routine
NULL, // APC Context
&ioStatusBlock,
IOCTL_AFD_GET_ADDRESS,
NULL,
0,
tdiAddress,
tdiAddressLength + 4
);
if ( status == STATUS_PENDING ) {
SockReleaseSocketLock( socket );
SockWaitForSingleObject(
SockThreadEvent,
socket->Handle,
SOCK_NEVER_CALL_BLOCKING_HOOK,
SOCK_NO_TIMEOUT
);
SockAcquireSocketLockExclusive( socket );
status = ioStatusBlock.Status;
}
//
// Convert the actual address that was bound to this socket to the
// sockaddr format in order to store it.
//
if ( NT_SUCCESS(status) ) {
SockBuildSockaddr(
socket->LocalAddress,
&SocketAddressLength,
(PTRANSPORT_ADDRESS)( (PCHAR)tdiAddress + 4 )
);
} else {
WS_PRINT((
"IOCTL_AFD_GET_ADDRESS failed, status %08lx\n",
status
));
}
//
// Indicate that the socket is now bound to a specific address;
//
socket->State = SocketStateBound;
//
// Remember the changed state of this socket.
//
err = SockSetHandleContext( socket );
if ( err != NO_ERROR ) {
goto exit;
}
//
// If the application changed the send or receive buffers and this
// is a datagram socket, tell AFD about the new buffer sizes.
//
err = SockUpdateWindowSizes( socket, FALSE );
if ( err != NO_ERROR ) {
goto exit;
}
exit:
IF_DEBUG(BIND) {
if ( err != NO_ERROR ) {
WS_PRINT(( "WSPBind on socket %lx (%lx) failed: %ld\n",
Handle, socket, err ));
} else {
WS_PRINT(( " WSPBind on socket %lx (%lx), granted",
Handle, socket ));
WsPrintSockaddr( socket->LocalAddress, &socket->LocalAddressLength );
}
}
//
// Perform cleanup--dereference the socket if it was referenced,
// free allocated resources.
//
if ( socket != NULL ) {
SockReleaseSocketLock( socket );
SockDereferenceSocket( socket );
}
if ( tdiAddress != NULL ) {
FREE_HEAP( tdiAddress );
}
//
// Return an error if appropriate.
//
if ( err != NO_ERROR ) {
WS_EXIT( "WSPBind", SOCKET_ERROR, TRUE );
*lpErrno = err;
return SOCKET_ERROR;
}
WS_EXIT( "WSPBind", NO_ERROR, FALSE );
return NO_ERROR;
} // WSPBind