NULLPROV.CPP

/*++ 

Copyright 1996 - 1998 Microsoft Corporation

Copyright (c) 1996 Intel Corp

Module Name:

nullprov.cpp

Abstract:

This module provides a "null" provider for the purpose of demonstrating
what it takes to get a service provider installed and started. The
provider pretty much does nothing but pretend to send and receive data.

--*/


//
// The Service Provider Interface was widened to Unicode in version 2.2.
// All of the parameters that involve strings in this module all provided
// in their "transparent" form. They are switched to the wide character
// version, at compile time, by the following define:
//

#define UNICODE

#include <windows.h>
#include "ws2spi.h"

#include "nullpdef.h"


// Global Upcall table with WinSock 2 DLL upcall entry points.
WSPUPCALLTABLE g_upcalls;

// Global protocol info struct of the one protocol we support.
WSAPROTOCOL_INFOA g_protoinfo;







SOCKET WSPAPI WSPAccept(
SOCKET s,
struct sockaddr FAR * addr,
LPINT addrlen,
LPCONDITIONPROC lpfnCondition,
DWORD dwCallbackData,
LPINT lpErrno
)
/*++
--*/
{
// Not implemented
return(INVALID_SOCKET);
} // lpWSPAccept




INT WSPAPI WSPAddressToString(
LPSOCKADDR lpsaAddress,
DWORD dwAddressLength,
LPWSAPROTOCOL_INFO lpProtocolInfo,
LPTSTR lpszAddressString,
LPDWORD lpdwAddressStringLength,
LPINT lpErrno
)
/*++
--*/
{
// Not implemented
return(SOCKET_ERROR);
} // lpWSPAddressToString




int WSPAPI WSPAsyncSelect(
SOCKET s,
HWND hWnd,
unsigned int wMsg,
long lEvent,
LPINT lpErrno
)
/*++
--*/
{
// Not implemented
return(SOCKET_ERROR);
} // lpWSPAsyncSelect




int WSPAPI WSPBind(
SOCKET s,
const struct sockaddr FAR * name,
int namelen,
LPINT lpErrno
)
/*++
Implementation:

A simple implementation is supplied. The implementation simply returns
success without really doing anything.
--*/
{
* lpErrno = ERROR_SUCCESS;
return(ERROR_SUCCESS);

} // lpWSPBind




int WSPAPI WSPCancelBlockingCall(
LPINT lpErrno
)
/*++
Implementation:

A simple implementation is supplied. The implementation simply returns
success without really doing anything.
--*/
{
* lpErrno = ERROR_SUCCESS;
return(ERROR_SUCCESS);

} // lpWSPCancelBlockingCall




int WSPAPI WSPCleanup(
LPINT lpErrno
)
/*++
Implementation

A simple implementation is supplied. The implementation simply returns
success without really doing anything. This is technically incorrect,
since we should really maintain an up/down count of Startup/Cleanup pairs
and return an error code if WSPCleanup is called when there is not a
WSPStartup outstanding.
--*/
{
* lpErrno = ERROR_SUCCESS;
return(ERROR_SUCCESS);

} // lpWSPCleanup




int WSPAPI WSPCloseSocket(
SOCKET s,
LPINT lpErrno
)
/*++
Implementation

Perform an upcall to the WinSock 2 DLL to inform it of the removal of the
socket handle. Return the result.
--*/
{
int close_result;

close_result = (* g_upcalls.lpWPUCloseSocketHandle)(
s, // s
lpErrno); // lpErrno
return(close_result);

} // lpWSPCloseSocket




int WSPAPI WSPConnect(
SOCKET s,
const struct sockaddr FAR * name,
int namelen,
LPWSABUF lpCallerData,
LPWSABUF lpCalleeData,
LPQOS lpSQOS,
LPQOS lpGQOS,
LPINT lpErrno
)
/*++
Implementation

A simple implementation is supplied. It indicates that no callee data was
retrieved and returns success.
--*/
{
if (lpCalleeData != NULL) {
lpCalleeData->len = 0;
}
* lpErrno = ERROR_SUCCESS;
return(ERROR_SUCCESS);

} // lpWSPConnect




int WSPAPI WSPDuplicateSocket(
SOCKET s,
DWORD dwProcessId,
LPWSAPROTOCOL_INFO lpProtocolInfo,
LPINT lpErrno
)
/*++
--*/
{
// Not implemented
return(SOCKET_ERROR);
} // lpWSPDuplicateSocket




int WSPAPI WSPEnumNetworkEvents(
SOCKET s,
WSAEVENT hEventObject,
LPWSANETWORKEVENTS lpNetworkEvents,
LPINT lpErrno
)
/*++
--*/
{
// Not implemented
return(SOCKET_ERROR);
} // lpWSPEnumNetworkEvents




int WSPAPI WSPEventSelect(
SOCKET s,
WSAEVENT hEventObject,
long lNetworkEvents,
LPINT lpErrno
)
/*++
--*/
{
// Not implemented
return(SOCKET_ERROR);
} // lpWSPEventSelect




int WSPAPI WSPGetOverlappedResult(
SOCKET s,
LPWSAOVERLAPPED lpOverlapped,
LPDWORD lpcbTransfer,
BOOL fWait,
LPDWORD lpdwFlags,
LPINT lpErrno
)
/*++
--*/
{
// Not implemented
return(FALSE);
} // lpWSPGetOverlappedResult




int WSPAPI WSPGetPeerName(
SOCKET s,
struct sockaddr FAR * name,
LPINT namelen,
LPINT lpErrno
)
/*++
--*/
{
// Not implemented
return(SOCKET_ERROR);
} // lpWSPGetPeerName




int WSPAPI WSPGetSockName(
SOCKET s,
struct sockaddr FAR * name,
LPINT namelen,
LPINT lpErrno
)
/*++
--*/
{
// Not implemented
return(SOCKET_ERROR);
} // lpWSPGetSockName




int WSPAPI WSPGetSockOpt(
SOCKET s,
int level,
int optname,
char FAR * optval,
LPINT optlen,
LPINT lpErrno
)
/*++
--*/
{
// Not implemented
return(SOCKET_ERROR);
} // lpWSPGetSockOpt




BOOL WSPAPI WSPGetQOSByName(
SOCKET s,
LPWSABUF lpQOSName,
LPQOS lpQOS,
LPINT lpErrno
)
/*++
--*/
{
// Not implemented
return(FALSE);
} // lpWSPGetQOSByName




int WSPAPI WSPIoctl(
SOCKET s,
DWORD dwIoControlCode,
LPVOID lpvInBuffer,
DWORD cbInBuffer,
LPVOID lpvOutBuffer,
DWORD cbOutBuffer,
LPDWORD lpcbBytesReturned,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
LPWSATHREADID lpThreadId,
LPINT lpErrno
)
/*++
Not implemented,
--*/
{
// Not implemented
return(SOCKET_ERROR);

} // lpWSPIoctl




SOCKET WSPAPI WSPJoinLeaf(
SOCKET s,
const struct sockaddr FAR * name,
int namelen,
LPWSABUF lpCallerData,
LPWSABUF lpCalleeData,
LPQOS lpSQOS,
LPQOS lpGQOS,
DWORD dwFlags,
LPINT lpErrno
)
/*++
--*/
{
// Not implemented
return(INVALID_SOCKET);
} // lpWSPJoinLeaf




int WSPAPI WSPListen(
SOCKET s,
int backlog,
LPINT lpErrno
)
/*++
--*/
{
// Not implemented
return(SOCKET_ERROR);
} // lpWSPListen




int WSPAPI WSPRecv(
SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesRecvd,
LPDWORD lpFlags,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
LPWSATHREADID lpThreadId,
LPINT lpErrno
)
/*++
Implementation

A simple implementation is supplied. The number of bytes received is
simply filled in as the number requested. No actual data is deposited in
the buffers. The client will "see" whatever data happens to be there
already.

This simple implementation also violates the specification in that it does
not support overlapped I/O. It simply returns an error indication if an
attempt is made to use overlapped I/O features.
--*/
{
if ((lpOverlapped != NULL) ||
(lpCompletionRoutine != NULL)) {
// Overlapped I/O and its animal friends not implemented.
*lpErrno = WSAEINVAL;
return(SOCKET_ERROR);
}

// Pretend to receive some data
* lpNumberOfBytesRecvd = lpBuffers[0].len;
* lpFlags = 0;
* lpErrno = ERROR_SUCCESS;
return(ERROR_SUCCESS);

} // lpWSPRecv




int WSPAPI WSPRecvDisconnect(
SOCKET s,
LPWSABUF lpInboundDisconnectData,
LPINT lpErrno
)
/*++
--*/
{
// Not implemented
return(SOCKET_ERROR);
} // lpWSPRecvDisconnect




int WSPAPI WSPRecvFrom(
SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesRecvd,
LPDWORD lpFlags,
struct sockaddr FAR * lpFrom,
LPINT lpFromlen,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
LPWSATHREADID lpThreadId,
LPINT lpErrno
)
/*++
Implementation

A simple implementation is supplied. The number of bytes received is
simply filled in as the number requested. The "received from" address is
filled in with a length of zero. This might be an unexpected result, in
which case it could be changed to fill in some dummy constant address.

This simple implementation also violates the specification in that it does
not support overlapped I/O. It simply returns an error indication if an
attempt is made to use overlapped I/O features.
--*/
{
if ((lpOverlapped != NULL) ||
(lpCompletionRoutine != NULL)) {
// Overlapped I/O and its animal friends not implemented.
*lpErrno = WSAEINVAL;
return(SOCKET_ERROR);
}

// Pretend to receive some data
* lpNumberOfBytesRecvd = lpBuffers[0].len;
* lpFlags = 0;
if (lpFromlen != NULL) {
* lpFromlen = 0;
}
* lpErrno = ERROR_SUCCESS;
return(ERROR_SUCCESS);

} // lpWSPRecvFrom




int WSPAPI WSPSelect(
int nfds,
fd_set FAR * readfds,
fd_set FAR * writefds,
fd_set FAR * exceptfds,
const struct timeval FAR * timeout,
LPINT lpErrno
)
/*++
--*/
{
// Not implemented
return(SOCKET_ERROR);
} // lpWSPSelect




int WSPAPI WSPSend(
SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesSent,
DWORD dwFlags,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
LPWSATHREADID lpThreadId,
LPINT lpErrno
)
/*++
Implementation

A simple implementation is supplied. This implementation simply computes
the total number of bytes the client is attempting to send and fills in the
result to indicate that all the requested bytes were successfully sent.

This simple implementation also violates the specification in that it does
not support overlapped I/O. It simply returns an error indication if an
attempt is made to use overlapped I/O features.
--*/
{
DWORD bytes_sent;
DWORD buf_index;

if ((lpOverlapped != NULL) ||
(lpCompletionRoutine != NULL)) {
// Overlapped I/O and its animal friends not implemented.
*lpErrno = WSAEINVAL;
return(SOCKET_ERROR);
}

bytes_sent = 0;
for (buf_index = 0; buf_index < dwBufferCount; buf_index++) {
bytes_sent += lpBuffers[buf_index].len;
} // for buf_index
* lpNumberOfBytesSent = bytes_sent;
* lpErrno = ERROR_SUCCESS;
return(ERROR_SUCCESS);

} // lpWSPSend




int WSPAPI WSPSendDisconnect(
SOCKET s,
LPWSABUF lpOutboundDisconnectData,
LPINT lpErrno
)
/*++
Implementation

A simple implementation is supplied. This implementation simply computes
the total number of bytes the client is attempting to send and fills in the
result to indicate that all the requested bytes were successfully sent.

This simple implementation also violates the specification in that it does
not support overlapped I/O. It simply returns an error indication if an
attempt is made to use overlapped I/O features.
--*/
{
// Not implemented
return(SOCKET_ERROR);
} // lpWSPSendDisconnect




int WSPAPI WSPSendTo(
SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesSent,
DWORD dwFlags,
const struct sockaddr FAR * lpTo,
int iTolen,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
LPWSATHREADID lpThreadId,
LPINT lpErrno
)
/*++
--*/
{
DWORD bytes_sent;
DWORD buf_index;

if ((lpOverlapped != NULL) ||
(lpCompletionRoutine != NULL)) {
// Overlapped I/O and its animal friends not implemented.
*lpErrno = WSAEINVAL;
return(SOCKET_ERROR);
}

bytes_sent = 0;
for (buf_index = 0; buf_index < dwBufferCount; buf_index++) {
bytes_sent += lpBuffers[buf_index].len;
} // for buf_index
* lpNumberOfBytesSent = bytes_sent;
* lpErrno = ERROR_SUCCESS;
return(ERROR_SUCCESS);

} // lpWSPSendTo




int WSPAPI WSPSetSockOpt(
SOCKET s,
int level,
int optname,
const char FAR * optval,
int optlen,
LPINT lpErrno
)
/*++
--*/
{
// Not implemented
return(SOCKET_ERROR);
} // lpWSPSetSockOpt




int WSPAPI WSPShutdown(
SOCKET s,
int how,
LPINT lpErrno
)
/*++
--*/
{
// Not implemented
return(SOCKET_ERROR);
} // lpWSPShutdown




SOCKET WSPAPI WSPSocket(
int af,
int type,
int protocol,
LPWSAPROTOCOL_INFO lpProtocolInfo,
GROUP g,
DWORD dwFlags,
LPINT lpErrno
)
/*++
Implementation

A simple implementation is supplied. The procedure simply performs an
upcall to the WinSock 2 DLL to allocate a socket handle. The allocated
socket handle is returned as the new socket handle.

Note that this implementation does not keep any state information about the
"socket" it allocated. Consequently, it simply uses 0 as the "context"
value associated with the socket handle. If it were desired to keep state
information for the socket, the implementation would allocate a data
structure to store the state information, cast the data structure pointer
into a DWORD, and use this value as the dwContext. When the implementation
needed to access the state information, it would call
WPUQuerySocketHandleContext and cast the retrieved DWORD back to the
appropriate data structure pointer.
--*/
{
SOCKET new_socket;

new_socket = (* g_upcalls.lpWPUCreateSocketHandle)(
g_protoinfo.dwCatalogEntryId, // dwCatalogEntryId
0, // dwContext
lpErrno); // lpErrno

return(new_socket);

} // lpWSPSocket




INT WSPAPI WSPStringToAddress(
LPTSTR AddressString,
INT AddressFamily,
LPWSAPROTOCOL_INFO lpProtocolInfo,
LPSOCKADDR lpAddress,
LPINT lpAddressLength,
LPINT lpErrno
)
/*++
--*/
{
// Not implemented
return(SOCKET_ERROR);
} // lpWSPStringToAddress




int WSPAPI WSPStartup(
WORD wVersionRequested,
LPWSPDATA lpWSPData,
LPWSAPROTOCOL_INFO lpProtocolInfo,
WSPUPCALLTABLE UpcallTable,
LPWSPPROC_TABLE lpProcTable
)
/*++
Implementation

A simple implementation is provided. This just fills in required WSPData,
a procedure table, and returns success. Technically this implementation
violates the specification since it should maintain an up/down count of
WSPStartup/WSPCleanup pairs.
--*/
{
// Make sure that the version requested is == 2.0 because that is all we
// support.
//
// The low byte is the major version and the high byte is the minor
// version.

if ( LOBYTE( wVersionRequested ) < 2) {
return WSAVERNOTSUPPORTED;
}

lpWSPData->wVersion = MAKEWORD( 2, 0 );
lpWSPData->wHighVersion = MAKEWORD( 2, 0 );

#define szDESCRIPTION "Null Provider for WinSock 2 preliminary sample source"
memcpy (lpWSPData->szDescription, szDESCRIPTION, sizeof szDESCRIPTION);

memcpy (&g_protoinfo, lpProtocolInfo, sizeof WSAPROTOCOL_INFO);

g_upcalls = UpcallTable;

lpProcTable->lpWSPAccept = WSPAccept;
lpProcTable->lpWSPAddressToString = WSPAddressToString;
lpProcTable->lpWSPAsyncSelect = WSPAsyncSelect;
lpProcTable->lpWSPBind = WSPBind;
lpProcTable->lpWSPCancelBlockingCall = WSPCancelBlockingCall;
lpProcTable->lpWSPCleanup = WSPCleanup;
lpProcTable->lpWSPCloseSocket = WSPCloseSocket;
lpProcTable->lpWSPConnect = WSPConnect;
lpProcTable->lpWSPDuplicateSocket = WSPDuplicateSocket;
lpProcTable->lpWSPEnumNetworkEvents = WSPEnumNetworkEvents;
lpProcTable->lpWSPEventSelect = WSPEventSelect;
lpProcTable->lpWSPGetOverlappedResult = WSPGetOverlappedResult;
lpProcTable->lpWSPGetPeerName = WSPGetPeerName;
lpProcTable->lpWSPGetSockName = WSPGetSockName;
lpProcTable->lpWSPGetSockOpt = WSPGetSockOpt;
lpProcTable->lpWSPGetQOSByName = WSPGetQOSByName;
lpProcTable->lpWSPIoctl = WSPIoctl;
lpProcTable->lpWSPJoinLeaf = WSPJoinLeaf;
lpProcTable->lpWSPListen = WSPListen;
lpProcTable->lpWSPRecv = WSPRecv;
lpProcTable->lpWSPRecvDisconnect = WSPRecvDisconnect;
lpProcTable->lpWSPRecvFrom = WSPRecvFrom;
lpProcTable->lpWSPSelect = WSPSelect;
lpProcTable->lpWSPSend = WSPSend;
lpProcTable->lpWSPSendDisconnect = WSPSendDisconnect;
lpProcTable->lpWSPSendTo = WSPSendTo;
lpProcTable->lpWSPSetSockOpt = WSPSetSockOpt;
lpProcTable->lpWSPShutdown = WSPShutdown;
lpProcTable->lpWSPSocket = WSPSocket;
lpProcTable->lpWSPStringToAddress = WSPStringToAddress;

return(ERROR_SUCCESS);

} // WSPStartup