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