/*++

Copyright (c) 1996 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
