home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / netds / winsock / nullprov / srtest.cpp < prev    next >
C/C++ Source or Header  |  1997-10-08  |  11KB  |  421 lines

  1. /*++
  2.  
  3. Copyright 1996-1997 Microsoft Corporation
  4.  
  5. Copyright (c) 1996 Intel Corp
  6.  
  7. Module Name:
  8.  
  9.     perftest.cpp
  10.  
  11. Abstract:
  12.  
  13.     This  module  contains  demonstration code which illustrates how to install
  14.     and  use  a  service provider.  This demonstration code is designed to work
  15.     together only with the temporary sample skeleton "null" service provider.
  16.  
  17. --*/
  18.  
  19. #include <windows.h>
  20. #include "nullpdef.h"
  21. #include "ws2spi.h"
  22.  
  23.  
  24.  
  25. //
  26. //  Unique GUID generated with UUIDGEN:
  27. //   ba657007-d615-11cf-9f5c-08003e301875
  28. //
  29. //  WARNING:  If you use this sample code, you must generate your own
  30. //   GUID.  Under no circumstances should you use this GUID.
  31. //
  32.  
  33. GUID ProviderIDGuid = { 0xba657007, 0xd615, 0x11cf, 0x9f, 0x5c,
  34.                      0x08, 0x00, 0x3e, 0x30, 0x18, 0x75 };
  35.  
  36.  
  37. //
  38. // Dummy name as unicode string
  39. //
  40.  
  41. #define SAMPLE_NAME_WSTRING L"Null Provider protocol for sample"
  42.  
  43. // The  nominal  size  of  send  and  receive operations.  Since we expect this
  44. // sample code to be used only with a "null" provider that does not really send
  45. // or receive data, the value is arbitrary and has no real effect.
  46.  
  47. #define SEND_RECEIVE_BYTES  100
  48.  
  49.  
  50.  
  51.  
  52. static
  53. void
  54. Test_Send(
  55.     IN  SOCKET  SendSock,
  56.     IN  DWORD   NumTries
  57.     )
  58. /*++
  59. Routine Description:
  60.  
  61.     This  procedure  performs the indicated number of send operations through a
  62.     socket.
  63.  
  64. Arguments:
  65.  
  66.     SendSock - Supplies the socket to be used for the "send" operations.
  67.  
  68.     NumTries - Supplies the number of tries.
  69.  
  70. Return Value:
  71.  
  72.     none
  73.  
  74. Implementation:
  75.  
  76.     We  use  an "unrolled" loop to perform a large number of calls back-to-back
  77.     without  loop turnaround overhead.  Then we perform the remaining number of
  78.     calls.   This  should  help  reduce  the  overall  contribution of the loop
  79.     overhead,  which  might  be  relevant  if this were being used as part of a
  80.     performance measurement.
  81. --*/
  82. {
  83.     DWORD    unrolled_iterations;
  84.     DWORD    remaining_iterations;
  85.     DWORD    i;
  86.     int      send_result;
  87.     WSABUF   send_bufs;
  88.     CHAR     data_space[SEND_RECEIVE_BYTES];
  89.     DWORD    bytes_sent;
  90.  
  91. #define SEND_ONCE \
  92.     send_result = WSASend(                       \
  93.         SendSock,      /* s                   */ \
  94.         & send_bufs,   /* lpBuffers           */ \
  95.         1,             /* dwBufferCount       */ \
  96.         & bytes_sent,  /* lpNumberOfBytesSent */ \
  97.         0,             /* dwFlags             */ \
  98.         NULL,          /* lpOverlapped        */ \
  99.         NULL)          /* lpCompletionRoutine */
  100.  
  101. #define UNROLLED_LENGTH 50
  102.  
  103.     unrolled_iterations  = NumTries / UNROLLED_LENGTH;
  104.     remaining_iterations = NumTries % UNROLLED_LENGTH;
  105.     send_bufs.len = SEND_RECEIVE_BYTES;
  106.     send_bufs.buf = data_space;
  107.  
  108.     for (i = 0; i < unrolled_iterations; i++) {
  109.         SEND_ONCE;
  110.         SEND_ONCE;
  111.         SEND_ONCE;
  112.         SEND_ONCE;
  113.         SEND_ONCE;
  114.         SEND_ONCE;
  115.         SEND_ONCE;
  116.         SEND_ONCE;
  117.         SEND_ONCE;
  118.         SEND_ONCE;
  119.         SEND_ONCE;
  120.         SEND_ONCE;
  121.         SEND_ONCE;
  122.         SEND_ONCE;
  123.         SEND_ONCE;
  124.         SEND_ONCE;
  125.         SEND_ONCE;
  126.         SEND_ONCE;
  127.         SEND_ONCE;
  128.         SEND_ONCE;
  129.         SEND_ONCE;
  130.         SEND_ONCE;
  131.         SEND_ONCE;
  132.         SEND_ONCE;
  133.         SEND_ONCE;
  134.         SEND_ONCE;
  135.         SEND_ONCE;
  136.         SEND_ONCE;
  137.         SEND_ONCE;
  138.         SEND_ONCE;
  139.         SEND_ONCE;
  140.         SEND_ONCE;
  141.         SEND_ONCE;
  142.         SEND_ONCE;
  143.         SEND_ONCE;
  144.         SEND_ONCE;
  145.         SEND_ONCE;
  146.         SEND_ONCE;
  147.         SEND_ONCE;
  148.         SEND_ONCE;
  149.         SEND_ONCE;
  150.         SEND_ONCE;
  151.         SEND_ONCE;
  152.         SEND_ONCE;
  153.         SEND_ONCE;
  154.         SEND_ONCE;
  155.         SEND_ONCE;
  156.         SEND_ONCE;
  157.         SEND_ONCE;
  158.         SEND_ONCE;
  159.     } // for i
  160.  
  161.     for (i = 0; i < remaining_iterations; i++) {
  162.         SEND_ONCE;
  163.     } // for i
  164.     
  165. } // Test_Send
  166.  
  167.  
  168.  
  169.  
  170. static
  171. SOCKET
  172. Create_Test_Socket(
  173.     void)
  174. /*++
  175. Routine Description:
  176.  
  177.     This  procedure  creates a socket to be used for the tests through the null
  178.     provider.
  179.  
  180. Arguments:
  181.  
  182.     none
  183.     
  184. Return Value:
  185.  
  186.     The  procedure  returns  the  newly  created  socket  if  it is successful,
  187.     otherwise it returns INVALID_SOCKET.
  188. --*/
  189. {
  190.     SOCKET  new_socket;
  191.  
  192.     new_socket = WSASocket(
  193.         AF_SPECIAL_NULL,   // af
  194.         SOCK_STREAM,       // type
  195.         0,                 // protocol
  196.         NULL,              // lpProtocolInfo
  197.         0,                 // g
  198.         0);                // dwFlags
  199.     return(new_socket);
  200.  
  201. } // Create_Test_Socket
  202.  
  203.  
  204.  
  205.  
  206. static
  207. void
  208. Destroy_Test_Socket(
  209.     IN  SOCKET  TestSock
  210.     )
  211. /*++
  212. Routine Description:
  213.  
  214.     This  procedure  closes  a socket that was being used for tests through the
  215.     null provider.
  216.  
  217. Arguments:
  218.  
  219.     TestSock - Supplies the socket to be closed.
  220.     
  221. Return Value:
  222.  
  223.     none
  224. --*/
  225. {
  226.     int    close_result;
  227.     DWORD  last_error;
  228.  
  229.     close_result = closesocket(
  230.         TestSock);
  231.     if (close_result != ERROR_SUCCESS) {
  232.         last_error = GetLastError();
  233.         last_error = GetLastError();  // Redundant for single-step convenience.
  234.     }
  235.     
  236. } // Destroy_Test_Socket
  237.  
  238.  
  239.  
  240.  
  241. static
  242. DWORD
  243. Establish_Provider(
  244.     void
  245.     )
  246. /*++
  247. Routine Description:
  248.  
  249.     This procedure makes sure the null provider is installed and installs it if
  250.     it is not already installed.
  251.  
  252.     Normally  an  application  program  would  NOT actually install a provider.
  253.     Installation  was  bundled into this application example simply to make the
  254.     example compact.
  255.  
  256. Arguments:
  257.  
  258.     none
  259.     
  260. Return Value:
  261.  
  262.  
  263. --*/
  264. {
  265.     LPWSAPROTOCOL_INFOW  proto_buf;
  266.     DWORD                size_guess;
  267.     BOOL                 still_trying;
  268.     BOOL                 got_protos;
  269.     int                  enum_result;
  270.     int                  error_code;
  271.     BOOL                 found_null_prov;
  272.  
  273.     size_guess = 0;
  274.     got_protos = FALSE;
  275.     still_trying = TRUE;
  276.     proto_buf = NULL;
  277.  
  278.     // We  call  WSCEnumProtocols  twice.   The first call determines how big a
  279.     // buffer  we will actually need for the results.  The second call actually
  280.     // retrieves  the  results.  In a situation such as this, I generally write
  281.     // the  sequence  of  two  calls  as  a  loop,  since this way the call and
  282.     // error-check code has to be written only once.
  283.     while (still_trying) {
  284.         enum_result = WSCEnumProtocols(
  285.             NULL,           // lpiProtocols
  286.             proto_buf,      // lpProtocolBuffer
  287.             & size_guess,   // lpdwBufferLength
  288.             & error_code);  // lpErrno
  289.         if (enum_result != SOCKET_ERROR) {
  290.             got_protos = TRUE;
  291.             still_trying = FALSE;
  292.         }
  293.         else {
  294.             if (error_code == WSAENOBUFS) {
  295.                 delete proto_buf;
  296.                 proto_buf = (LPWSAPROTOCOL_INFOW) new char[size_guess];
  297.                 if (proto_buf == NULL) {
  298.                     still_trying = FALSE;
  299.                 }
  300.             }
  301.             else {
  302.                 still_trying = FALSE;
  303.             }
  304.         }
  305.     } // while still_trying
  306.  
  307.     found_null_prov = FALSE;
  308.     if (got_protos) {
  309.         int  i;
  310.  
  311.         for (i = 0; i < enum_result; i++) {
  312.             if (proto_buf[i].iAddressFamily == AF_SPECIAL_NULL) {
  313.                 found_null_prov = TRUE;
  314.                 break;
  315.             }
  316.         }
  317.     }
  318.     delete proto_buf;
  319.  
  320.     if (! found_null_prov) {
  321.         WSAPROTOCOL_INFOW proto_info;
  322.         int               install_result;
  323.         int               install_error;
  324.  
  325.         proto_info.dwServiceFlags1 = 0;
  326.         proto_info.dwServiceFlags2 = 0;
  327.         proto_info.dwServiceFlags3 = 0;
  328.         proto_info.dwServiceFlags4 = 0;
  329.         proto_info.dwProviderFlags = PFL_MATCHES_PROTOCOL_ZERO;
  330.         proto_info.dwCatalogEntryId = 0;   // filled in by system
  331.         proto_info.ProtocolChain.ChainLen = BASE_PROTOCOL;
  332.         proto_info.iVersion = 0;
  333.         proto_info.iAddressFamily = AF_SPECIAL_NULL;
  334.         proto_info.iMaxSockAddr = 16;
  335.         proto_info.iMinSockAddr = 16;
  336.         proto_info.iSocketType = SOCK_STREAM;
  337.         proto_info.iProtocol = 0;
  338.         proto_info.iProtocolMaxOffset = 0;
  339.         proto_info.iNetworkByteOrder = BIGENDIAN;
  340.         proto_info.iSecurityScheme = SECURITY_PROTOCOL_NONE;
  341.         proto_info.dwMessageSize = 0;  // stream-oriented
  342.         proto_info.dwProviderReserved = 0;
  343.  
  344.         proto_info.ProviderId = ProviderIDGuid ; // filled in by system.
  345.  
  346.         // copy unicode string into name parameter
  347.         memcpy(proto_info.szProtocol, SAMPLE_NAME_WSTRING, sizeof SAMPLE_NAME_WSTRING);
  348.  
  349.  
  350.         install_result = WSCInstallProvider(
  351.             &ProviderIDGuid,   // lpProviderID
  352.             L"nullprov.dll",   // lpszProviderDllPath (unicode string)
  353.             & proto_info,      // lpProtocolInfoList
  354.             1,                 // dwNumberOfEntries
  355.             & install_error);  // lpErrno
  356.         if (install_result != ERROR_SUCCESS) {
  357.             install_error = install_error;
  358.             // assert(install_result == ERROR_SUCCESS);
  359.         }
  360.     } // if not found_null_prov
  361.  
  362.     return(TRUE);
  363.     
  364. } // Establish_Provider
  365.     
  366.  
  367.  
  368.  
  369. void
  370. main(
  371.     void
  372.     )
  373. /*++
  374. --*/
  375. {
  376.     SOCKET   test_sock;
  377.     int      start_return;
  378.     WSADATA  winsock_data;
  379.     DWORD    last_error;
  380.     int      clean_return;
  381.     DWORD    num_tries;
  382.  
  383.     Establish_Provider();
  384.  
  385.     start_return = WSAStartup(
  386.         MAKEWORD(2,0),    // wVersionRequested
  387.         & winsock_data);  // lpWSAData
  388.  
  389.     if (start_return == ERROR_SUCCESS) {
  390.         test_sock = Create_Test_Socket();
  391.         // To  keep  this  sample  simple,  this  demonstration program and the
  392.         // matching  null  provider  do  not  bother  binding or connecting the
  393.         // socket  before  doing  "send" operations.  With a real provider, one
  394.         // should  bind  and possibly also connect the socket before proceeding
  395.         // with a "send".
  396.         if (test_sock != INVALID_SOCKET) {
  397.             num_tries = 10;
  398.             Test_Send(
  399.                 test_sock,   // SendSock
  400.                 num_tries);  // NumTries
  401.             Destroy_Test_Socket(
  402.                 test_sock);
  403.         } // if test_sock != NULL
  404.         else {
  405.             last_error = GetLastError();
  406.             // The  following  is  just  a  redundant executable statement that
  407.             // allows   me   to   see   the   return  value  conveniently  when
  408.             // single-stepping.
  409.             last_error = GetLastError();
  410.         }
  411.     } // if start_return == ERROR_SUCCESS
  412.     else {
  413.         last_error = GetLastError();
  414.         last_error = GetLastError();  // Redundant for single-step convenience.
  415.     }
  416.  
  417.     clean_return = WSACleanup();
  418.     clean_return = clean_return; // Redundant for single-step convenience.
  419.     
  420. } // main
  421.