reactos/dll/win32/ws2_32/src/sockctrl.c
2021-02-07 22:17:01 +01:00

643 lines
19 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS WinSock 2 API
* FILE: dll/win32/ws2_32/src/sockctrl.c
* PURPOSE: Socket Control/State Support
* PROGRAMMER: Alex Ionescu (alex@relsoft.net)
*/
/* INCLUDES ******************************************************************/
#include <ws2_32.h>
#define NDEBUG
#include <debug.h>
/* FUNCTIONS *****************************************************************/
/*
* @implemented
*/
INT
WSAAPI
connect(IN SOCKET s,
IN CONST struct sockaddr *name,
IN INT namelen)
{
PWSPROCESS Process;
PWSTHREAD Thread;
PWSSOCKET Socket;
INT ErrorCode, OldErrorCode = ERROR_SUCCESS;
INT Status;
BOOLEAN TryAgain = TRUE;
DPRINT("connect: %lx, %p, %lx\n", s, name, namelen);
/* Enter prolog */
ErrorCode = WsApiProlog(&Process, &Thread);
if (ErrorCode == ERROR_SUCCESS)
{
/* Get the Socket Context */
if ((Socket = WsSockGetSocket(s)))
{
if (!IsBadReadPtr(name, sizeof(struct sockaddr)))
{
while (TRUE)
{
/* Make the call */
Status = Socket->Provider->Service.lpWSPConnect(s,
name,
namelen,
NULL,
NULL,
NULL,
NULL,
&ErrorCode);
/* Check if error code was due to the host not being found */
if ((Status == SOCKET_ERROR) &&
((ErrorCode == WSAEHOSTUNREACH) ||
(ErrorCode == WSAENETUNREACH)))
{
/* Check if we can try again */
if (TryAgain)
{
/* Save the old error code */
OldErrorCode = ErrorCode;
/* Make sure we don't retry 3 times */
TryAgain = FALSE;
/* Make the RAS Auto-dial attempt */
if (WSAttemptAutodialAddr(name, namelen)) continue;
}
else
{
/* Restore the error code */
ErrorCode = OldErrorCode;
}
}
/* Break out of the loop */
break;
}
/* Deference the Socket Context */
WsSockDereference(Socket);
/* Return Provider Value */
if (Status == ERROR_SUCCESS) return Status;
/* If everything seemed fine, then the WSP call failed itself */
if (ErrorCode == NO_ERROR) ErrorCode = WSASYSCALLFAILURE;
}
else
{
/* Invalid user pointer */
ErrorCode = WSAEFAULT;
}
}
else
{
/* No Socket Context Found */
ErrorCode = WSAENOTSOCK;
}
}
/* If this is Winsock 1.1, normalize the error code */
if ((ErrorCode == WSAEALREADY) && (LOBYTE(Process->Version) == 1))
{
/* WS 1.1 apps expect this */
ErrorCode = WSAEINVAL;
}
/* Return with an Error */
SetLastError(ErrorCode);
return SOCKET_ERROR;
}
/*
* @implemented
*/
INT
WSAAPI
listen(IN SOCKET s,
IN INT backlog)
{
PWSSOCKET Socket;
INT Status;
INT ErrorCode;
DPRINT("connect: %lx, %lx\n", s, backlog);
/* Check for WSAStartup */
if ((ErrorCode = WsQuickProlog()) == ERROR_SUCCESS)
{
/* Get the Socket Context */
if ((Socket = WsSockGetSocket(s)))
{
/* Make the call */
Status = Socket->Provider->Service.lpWSPListen(s,
backlog,
&ErrorCode);
/* Deference the Socket Context */
WsSockDereference(Socket);
/* Return Provider Value */
if (Status == ERROR_SUCCESS) return Status;
/* If everything seemed fine, then the WSP call failed itself */
if (ErrorCode == NO_ERROR) ErrorCode = WSASYSCALLFAILURE;
}
else
{
/* No Socket Context Found */
ErrorCode = WSAENOTSOCK;
}
}
/* Return with an Error */
SetLastError(ErrorCode);
return SOCKET_ERROR;
}
/*
* @implemented
*/
INT
WSAAPI
getpeername(IN SOCKET s,
OUT LPSOCKADDR name,
IN OUT INT FAR* namelen)
{
PWSSOCKET Socket;
INT Status;
INT ErrorCode;
DPRINT("getpeername: %lx, %p, %lx\n", s, name, namelen);
/* Check for WSAStartup */
if ((ErrorCode = WsQuickProlog()) == ERROR_SUCCESS)
{
/* Get the Socket Context */
if ((Socket = WsSockGetSocket(s)))
{
/* Make the call */
Status = Socket->Provider->Service.lpWSPGetPeerName(s,
name,
namelen,
&ErrorCode);
/* Deference the Socket Context */
WsSockDereference(Socket);
/* Return Provider Value */
if (Status == ERROR_SUCCESS) return Status;
/* If everything seemed fine, then the WSP call failed itself */
if (ErrorCode == NO_ERROR) ErrorCode = WSASYSCALLFAILURE;
}
else
{
/* No Socket Context Found */
ErrorCode = WSAENOTSOCK;
}
}
/* Return with an Error */
SetLastError(ErrorCode);
return SOCKET_ERROR;
}
/*
* @implemented
*/
INT
WSAAPI
getsockname(IN SOCKET s,
OUT LPSOCKADDR name,
IN OUT INT FAR* namelen)
{
PWSSOCKET Socket;
INT Status;
INT ErrorCode;
DPRINT("getsockname: %lx, %p, %lx\n", s, name, namelen);
/* Check for WSAStartup */
if ((ErrorCode = WsQuickProlog()) == ERROR_SUCCESS)
{
/* Get the Socket Context */
if ((Socket = WsSockGetSocket(s)))
{
if (name && namelen && (*namelen >= sizeof(*name)))
{
/* Make the call */
Status = Socket->Provider->Service.lpWSPGetSockName(s,
name,
namelen,
&ErrorCode);
/* Deference the Socket Context */
WsSockDereference(Socket);
/* Return Provider Value */
if (Status == ERROR_SUCCESS) return Status;
/* If everything seemed fine, then the WSP call failed itself */
if (ErrorCode == NO_ERROR) ErrorCode = WSASYSCALLFAILURE;
}
else
{
/* Deference the Socket Context */
WsSockDereference(Socket);
/* name or namelen not valid */
ErrorCode = WSAEFAULT;
}
}
else
{
/* No Socket Context Found */
ErrorCode = WSAENOTSOCK;
}
}
/* Return with an Error */
SetLastError(ErrorCode);
return SOCKET_ERROR;
}
/*
* @implemented
*/
INT
WSAAPI
getsockopt(IN SOCKET s,
IN INT level,
IN INT optname,
OUT CHAR FAR* optval,
IN OUT INT FAR* optlen)
{
PWSPROCESS Process;
PWSTHREAD Thread;
PWSSOCKET Socket;
INT ErrorCode;
INT Status;
WSAPROTOCOL_INFOW ProtocolInfo;
PCHAR OldOptVal = NULL;
INT OldOptLen = 0;
DPRINT("getsockopt: %lx, %lx, %lx\n", s, level, optname);
/* Enter prolog */
if ((ErrorCode = WsApiProlog(&Process, &Thread)) == ERROR_SUCCESS)
{
/* Check if we're getting the open type */
if ((level == SOL_SOCKET) && (optname == SO_OPENTYPE))
{
/* Validate size */
Status = ERROR_SUCCESS;
_SEH2_TRY
{
if (!(optlen) || (*optlen < sizeof(DWORD)))
{
/* Fail */
Status = SOCKET_ERROR;
SetLastError(WSAEFAULT);
_SEH2_LEAVE;
}
/* Set the open type */
*(DWORD*)optval = Thread->OpenType;
*optlen = sizeof(DWORD);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = SOCKET_ERROR;
SetLastError(WSAEFAULT);
}
_SEH2_END;
return Status;
}
/* Get the Socket Context */
if ((Socket = WsSockGetSocket(s)))
{
/* Check if ANSI data was requested */
if ((level == SOL_SOCKET) && (optname == SO_PROTOCOL_INFOA))
{
/* Validate size and pointers */
ErrorCode = NO_ERROR;
_SEH2_TRY
{
if (!(optval) ||
!(optlen) ||
(*optlen < sizeof(WSAPROTOCOL_INFOA)))
{
/* Set return size and error code */
*optlen = sizeof(WSAPROTOCOL_INFOA);
ErrorCode = WSAEFAULT;
_SEH2_LEAVE;
}
/* It worked. Save the values */
OldOptLen = *optlen;
OldOptVal = optval;
/* Hack them so WSP will know how to deal with it */
*optlen = sizeof(WSAPROTOCOL_INFOW);
optval = (PCHAR)&ProtocolInfo;
optname = SO_PROTOCOL_INFOW;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ErrorCode = WSAEFAULT;
}
_SEH2_END;
/* Did we encounter invalid parameters? */
if (ErrorCode != NO_ERROR)
{
/* Dereference the socket and fail */
WsSockDereference(Socket);
SetLastError(ErrorCode);
return SOCKET_ERROR;
}
}
/* Make the call */
Status = Socket->Provider->Service.lpWSPGetSockOpt(s,
level,
optname,
optval,
optlen,
&ErrorCode);
/* Deference the Socket Context */
WsSockDereference(Socket);
/* Check provider value */
if (Status == ERROR_SUCCESS)
{
/* Did we use the A->W hack? */
if (!OldOptVal) return Status;
/* We did, so we have to convert the unicode info to ansi */
ErrorCode = MapUnicodeProtocolInfoToAnsi(&ProtocolInfo,
(LPWSAPROTOCOL_INFOA)
OldOptVal);
/* Return the length */
_SEH2_TRY
{
*optlen = OldOptLen;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ErrorCode = WSAEFAULT;
}
_SEH2_END;
/* Return success if this worked */
if (ErrorCode == ERROR_SUCCESS) return Status;
}
/* If everything seemed fine, then the WSP call failed itself */
if (ErrorCode == NO_ERROR) ErrorCode = WSASYSCALLFAILURE;
}
else
{
/* No Socket Context Found */
ErrorCode = WSAENOTSOCK;
}
}
/* Return with an Error */
SetLastError(ErrorCode);
return SOCKET_ERROR;
}
/*
* @implemented
*/
INT
WSAAPI
setsockopt(IN SOCKET s,
IN INT level,
IN INT optname,
IN CONST CHAR FAR* optval,
IN INT optlen)
{
PWSPROCESS Process;
PWSTHREAD Thread;
PWSSOCKET Socket;
INT ErrorCode;
INT Status;
DPRINT("setsockopt: %lx, %lx, %lx\n", s, level, optname);
/* Enter prolog */
if ((ErrorCode = WsApiProlog(&Process, &Thread)) == ERROR_SUCCESS)
{
/* Check if we're changing the open type */
if (level == SOL_SOCKET && optname == SO_OPENTYPE)
{
/* Validate size */
if (optlen < sizeof(DWORD))
{
/* Fail */
SetLastError(WSAEFAULT);
return SOCKET_ERROR;
}
/* Set the open type */
Status = ERROR_SUCCESS;
_SEH2_TRY
{
Thread->OpenType = *(DWORD*)optval;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = SOCKET_ERROR;
SetLastError(WSAEFAULT);
}
_SEH2_END;
return Status;
}
if (!optval && optlen > 0)
{
SetLastError(WSAEFAULT);
return SOCKET_ERROR;
}
/* Get the Socket Context */
if ((Socket = WsSockGetSocket(s)))
{
/* Make the call */
Status = Socket->Provider->Service.lpWSPSetSockOpt(s,
level,
optname,
optval,
optlen,
&ErrorCode);
/* Deference the Socket Context */
WsSockDereference(Socket);
/* Return Provider Value */
if (Status == ERROR_SUCCESS) return Status;
/* If everything seemed fine, then the WSP call failed itself */
if (ErrorCode == NO_ERROR) ErrorCode = WSASYSCALLFAILURE;
}
else
{
/* No Socket Context Found */
ErrorCode = WSAENOTSOCK;
}
}
/* Return with an Error */
SetLastError(ErrorCode);
return SOCKET_ERROR;
}
/*
* @implemented
*/
INT
WSAAPI
shutdown(IN SOCKET s,
IN INT how)
{
PWSSOCKET Socket;
INT Status;
INT ErrorCode;
DPRINT("shutdown: %lx, %lx\n", s, how);
/* Check for WSAStartup */
if ((ErrorCode = WsQuickProlog()) == ERROR_SUCCESS)
{
/* Get the Socket Context */
if ((Socket = WsSockGetSocket(s)))
{
/* Make the call */
Status = Socket->Provider->Service.lpWSPShutdown(s, how, &ErrorCode);
/* Deference the Socket Context */
WsSockDereference(Socket);
/* Return Provider Value */
if (Status == ERROR_SUCCESS) return Status;
/* If everything seemed fine, then the WSP call failed itself */
if (ErrorCode == NO_ERROR) ErrorCode = WSASYSCALLFAILURE;
}
else
{
/* No Socket Context Found */
ErrorCode = WSAENOTSOCK;
}
}
/* Return with an Error */
SetLastError(ErrorCode);
return SOCKET_ERROR;
}
/*
* @implemented
*/
INT
WSAAPI
WSAConnect(IN SOCKET s,
IN CONST struct sockaddr *name,
IN INT namelen,
IN LPWSABUF lpCallerData,
OUT LPWSABUF lpCalleeData,
IN LPQOS lpSQOS,
IN LPQOS lpGQOS)
{
PWSSOCKET Socket;
INT Status;
INT ErrorCode;
DPRINT("WSAConnect: %lx, %lx, %lx, %p\n", s, name, namelen, lpCallerData);
/* Check for WSAStartup */
if ((ErrorCode = WsQuickProlog()) == ERROR_SUCCESS)
{
/* Get the Socket Context */
if ((Socket = WsSockGetSocket(s)))
{
/* Make the call */
Status = Socket->Provider->Service.lpWSPConnect(s,
name,
namelen,
lpCallerData,
lpCalleeData,
lpSQOS,
lpGQOS,
&ErrorCode);
/* Deference the Socket Context */
WsSockDereference(Socket);
/* Return Provider Value */
if (Status == ERROR_SUCCESS) return Status;
/* If everything seemed fine, then the WSP call failed itself */
if (ErrorCode == NO_ERROR) ErrorCode = WSASYSCALLFAILURE;
}
else
{
/* No Socket Context Found */
ErrorCode = WSAENOTSOCK;
}
}
/* Return with an Error */
SetLastError(ErrorCode);
return SOCKET_ERROR;
}
/*
* @implemented
*/
BOOL
WSAAPI
WSAGetOverlappedResult(IN SOCKET s,
IN LPWSAOVERLAPPED lpOverlapped,
OUT LPDWORD lpcbTransfer,
IN BOOL fWait,
OUT LPDWORD lpdwFlags)
{
PWSSOCKET Socket;
INT Status;
INT ErrorCode;
DPRINT("WSAGetOverlappedResult: %lx, %lx\n", s, lpOverlapped);
/* Check for WSAStartup */
if ((ErrorCode = WsQuickProlog()) == ERROR_SUCCESS)
{
/* Get the Socket Context */
if ((Socket = WsSockGetSocket(s)))
{
/* Make the call */
Status = Socket->Provider->Service.lpWSPGetOverlappedResult(s,
lpOverlapped,
lpcbTransfer,
fWait,
lpdwFlags,
&ErrorCode);
/* Deference the Socket Context */
WsSockDereference(Socket);
/* Return Provider Value */
if (Status) return Status;
}
else
{
/* No Socket Context Found */
ErrorCode = WSAENOTSOCK;
}
}
/* Return with an Error */
SetLastError(ErrorCode);
return FALSE;
}