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 / wsock / wsock.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  39KB  |  1,142 lines

  1.  
  2. //-----------------------------------------------------------------------------
  3. // This is a part of the Microsoft Source Code Samples. 
  4. // Copyright (C) 1993-1997 Microsoft Corporation.
  5. // All rights reserved. 
  6. //  
  7. // This source code is only intended as a supplement to 
  8. // Microsoft Development Tools and/or WinHelp documentation.
  9. // See these sources for detailed information regarding the 
  10. // Microsoft samples programs.
  11. //-----------------------------------------------------------------------------
  12.  
  13. /****************************************************************************\
  14. *  wsock.c -- sample program demonstrating Windows Sockets APIs.
  15. *
  16. *  Demonstrates basic sockets programming with the Windows Sockets API.
  17. *  Allows two occurances of the application to connect.  Also, displays
  18. *  information about a host computer.
  19. *
  20. ****************************************************************************/
  21.  
  22. #include <windows.h>       /* required for all Windows applications */
  23. #include <stdio.h>         /* for sprintf                           */
  24. #include <string.h>        /* for strlen                            */
  25. #include <memory.h>
  26. #include <process.h>       /* for _beginthread                      */
  27. #include "wsock.h"         /* specific to this program              */
  28.  
  29. HANDLE hInst;              /* current instance                      */
  30.  
  31. SOCKET sock;
  32. u_short portno;            /* Which tcp port are we going to use?   */
  33.  
  34. char szBuff[ 80 ];         /* Temp buffer - used to pass strings    */
  35.                            /* to and from dialog boxes, etc         */
  36.  
  37. char gpszHelloWorld[]= "Hello World.";
  38.  
  39. #define MAX_PENDING_CONNECTS 4  /* The backlog allowed for listen() */
  40. #define NO_FLAGS_SET         0  /* Used with recv()/send()          */
  41. #define MY_MSG_LENGTH       80  /* msg buffer sent back and forth   */
  42.  
  43. /****************************************************************************
  44. *
  45. *    FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
  46. *
  47. *    PURPOSE: calls initialization function, processes message loop
  48. *
  49. *\***************************************************************************/
  50.  
  51. WINAPI WinMain(
  52.     HINSTANCE hInstance,
  53.     HINSTANCE hPrevInstance,
  54.     LPSTR lpCmdLine,
  55.     int nCmdShow
  56.     )
  57. {
  58.  
  59.     MSG msg;
  60.  
  61.     UNREFERENCED_PARAMETER( lpCmdLine );
  62.  
  63.     if (!hPrevInstance)                  /* Other instances of app running? */
  64.         if (!InitApplication(hInstance)) /* Initialize shared things        */
  65.             return (FALSE);              /* Exits if unable to initialize   */
  66.  
  67.     /*
  68.     *   Perform initializations that apply to a specific instance
  69.     */
  70.     if (!InitInstance(hInstance, nCmdShow))
  71.         return (FALSE);
  72.  
  73.     /*
  74.     *   Acquire and dispatch messages until a WM_QUIT message is received.
  75.     */
  76.     while (GetMessage(&msg,        /* message structure                      */
  77.             NULL,                  /* handle of window receiving the message */
  78.             0,             /* lowest message to examine              */
  79.             0))            /* highest message to examine             */
  80.         {
  81.         TranslateMessage(&msg);    /* Translates virtual key codes           */
  82.         DispatchMessage(&msg);     /* Dispatches message to window           */
  83.    }
  84.     return (msg.wParam);           /* Returns the value from PostQuitMessage */
  85. }
  86.  
  87.  
  88. /****************************************************************************
  89. *
  90. *    FUNCTION: InitApplication(HANDLE)
  91. *
  92. *    PURPOSE: Initializes window data and registers window class
  93. *
  94. *\***************************************************************************/
  95.  
  96. BOOL InitApplication(HANDLE hInstance)       /* current instance             */
  97. {
  98.     WNDCLASS  wc;
  99.  
  100.     /* Fill in window class structure with parameters that describe the       */
  101.     /* main window.                                                           */
  102.  
  103.     wc.style = 0;                    /* Class style(s).                    */
  104.     wc.lpfnWndProc = (WNDPROC)MainWndProc;       /* Function to retrieve messages for  */
  105.                                         /* windows of this class.             */
  106.     wc.cbClsExtra = 0;                  /* No per-class extra data.           */
  107.     wc.cbWndExtra = 0;                  /* No per-window extra data.          */
  108.     wc.hIcon = LoadIcon (hInstance, "wsockicon"); /* Icon name from .RC        */
  109.     wc.hInstance = hInstance;          /* Application that owns the class.   */
  110.     wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  111.     wc.hbrBackground = GetStockObject(WHITE_BRUSH);
  112.     wc.lpszMenuName =  "WSockMenu";   /* Name of menu resource in .RC file. */
  113.     wc.lpszClassName = "WSockWClass"; /* Name used in call to CreateWindow. */
  114.  
  115.     /* Register the window class and return success/failure code. */
  116.  
  117.     return (RegisterClass(&wc));
  118.  
  119. }
  120.  
  121.  
  122. /****************************************************************************\
  123. *
  124. *    FUNCTION:  InitInstance(HANDLE, int)
  125. *
  126. *    PURPOSE:  Saves instance handle and creates main window
  127. *
  128. *\***************************************************************************/
  129.  
  130. BOOL InitInstance(
  131.     HANDLE          hInstance,          /* Current instance identifier.       */
  132.     int             nCmdShow)           /* Param for first ShowWindow() call. */
  133. {
  134.     HWND            hWnd;               /* Main window handle.                */
  135.  
  136.     /* Save the instance handle in static variable, which will be used in  */
  137.     /* many subsequence calls from this application to Windows.            */
  138.  
  139.     hInst = hInstance;
  140.  
  141.     /* Create a main window for this application instance.  */
  142.  
  143.     hWnd = CreateWindow(
  144.         "WSockWClass",                  /* See RegisterClass() call.          */
  145.         "Windows Sockets Sample Application",   /* Text for window title bar.         */
  146.         WS_OVERLAPPEDWINDOW,            /* Window style.                      */
  147.         CW_USEDEFAULT,                  /* Default horizontal position.       */
  148.         CW_USEDEFAULT,                  /* Default vertical position.         */
  149.         CW_USEDEFAULT,                  /* Default width.                     */
  150.         CW_USEDEFAULT,                  /* Default height.                    */
  151.         NULL,                           /* Overlapped windows have no parent. */
  152.         NULL,                           /* Use the window class menu.         */
  153.         hInstance,                      /* This instance owns this window.    */
  154.         NULL                            /* Pointer not needed.                */
  155.     );
  156.  
  157.     /* If window could not be created, return "failure" */
  158.  
  159.     if (!hWnd)
  160.         return (FALSE);
  161.  
  162.     /* Make the window visible; update its client area; and return "success" */
  163.  
  164.     ShowWindow(hWnd, nCmdShow);  /* Show the window                        */
  165.     UpdateWindow(hWnd);          /* Sends WM_PAINT message                 */
  166.     return (TRUE);               /* Returns the value from PostQuitMessage */
  167.  
  168. }
  169.  
  170. /****************************************************************************\
  171. *
  172. *    FUNCTION: AcceptThreadProc(PTHREADPACK tp)
  173. *
  174. *    PURPOSE:  Use blocking accept() calls and display a message box when
  175. *              a connection is made.
  176. *
  177. *\***************************************************************************/
  178.  
  179. void AcceptThreadProc( PTHREADPACK ptp )
  180. {
  181.    SOCKADDR_IN acc_sin;    /* Accept socket address - internet style */
  182.    int acc_sin_len;        /* Accept socket address length */
  183.    int status;
  184.    char szMsg[ MY_MSG_LENGTH ];
  185.  
  186.  
  187.    acc_sin_len = sizeof(acc_sin);
  188.  
  189.    wsprintf( szBuff, "thread #%d created.", ptp->nThread);
  190.    MessageBox(ptp->hWnd, szBuff, "FYI", MB_OK);
  191.  
  192.    sock = accept( sock,(struct sockaddr FAR *) &acc_sin,
  193.             (int FAR *) &acc_sin_len );
  194.  
  195.    if (sock < 0) {
  196.       sprintf(szBuff, "%d is the error", WSAGetLastError());
  197.  
  198.       MessageBox(ptp->hWnd, szBuff, "accept(sock) failed", MB_OK);
  199.  
  200.    }
  201.  
  202.    wsprintf( szBuff, "Thread #%d accepted something\n\nCheck for incoming messages?", ptp->nThread);
  203.  
  204.    /*
  205.    *   Now have a connection --
  206.    *   SetConnectMenus() grays/enables proper menu items
  207.    */
  208.    SetConnectMenus( ptp->hWnd );
  209.  
  210.  
  211.    while (1) {
  212.  
  213.       /*
  214.       *   By default sockets are created in blocking mode.
  215.       *   Just keep reading until process destroyed.
  216.       */
  217.       status = recv( sock, szMsg, MY_MSG_LENGTH, NO_FLAGS_SET );
  218.  
  219.       if (status == SOCKET_ERROR) {
  220.          wsprintf( szMsg, "Error %d", WSAGetLastError() );
  221.          MessageBox( ptp->hWnd, szMsg, "Error with recv()", MB_OK);
  222.          _endthread();
  223.       }
  224.           szMsg[status] = '\0';  /* NULL-terminate the string */
  225.  
  226.       if (status)
  227.          MessageBox( ptp->hWnd, szMsg, "From thread", MB_OK);
  228.       else  {
  229.          MessageBox( ptp->hWnd, "Connection broken", "Error", MB_OK);
  230.          _endthread();
  231.       }
  232.  
  233.    }    /* while (forever) */
  234. }
  235.  
  236. /****************************************************************************\
  237. *
  238. *    FUNCTION:  FillAddr(HWND, PSOCKADDR_IN, BOOL)
  239. *
  240. *    PURPOSE:  Retrieves the IP address and port number.
  241. *
  242. *    COMMENTS:
  243. *        This function is called in two conditions.
  244. *            1.) When a client is preparing to call connect(), or
  245. *            2.) When a server host is going to call bind(), listen() and
  246. *                accept().
  247. *        In both situations, a SOCKADDR_IN structure is filled.
  248. *        However, different fields are filled depending on the condition.
  249. *
  250. *   ASSUMPTION:
  251. *      szBuff is a global variable that contains the remote host name or NULL
  252. *      if local.
  253. *      bClient determines if this is being called by a client ( will be
  254. *         performing a connect ) or a server ( will be listening )
  255. *
  256. *
  257. *\***************************************************************************/
  258.  
  259. BOOL FillAddr(
  260.         HWND hWnd,
  261.         PSOCKADDR_IN psin,
  262.         BOOL bClient)
  263. {
  264.    DWORD dwSize;
  265.    PHOSTENT phe;
  266.    PSERVENT pse;
  267.    char szTemp[200];
  268.    int status;
  269.  
  270.  
  271.    psin->sin_family = AF_INET;
  272.  
  273.  
  274.    /*
  275.    *   If we are setting up for a listen() call (bConnect = FALSE),
  276.    *   fill servent with our address.
  277.    */
  278.    if (bClient) {
  279.       phe = gethostbyname(szBuff);
  280.       if (phe == NULL) {
  281.          sprintf(szTemp, "%d is the error. Make sure '%s' is listed in the hosts file.", WSAGetLastError(), szBuff);
  282.  
  283.          MessageBox(hWnd, szTemp, "gethostbyname() failed.", MB_OK);
  284.          return FALSE;
  285.       }
  286.       memcpy((char FAR *)&(psin->sin_addr), phe->h_addr,
  287.          phe->h_length);
  288.  
  289.       }
  290.    else { // server
  291.  
  292.       /*
  293.       *   Retrieve my ip address.  Assuming the hosts file in
  294.       *   in %systemroot%/system/drivers/etc/hosts contains my computer name.
  295.       */
  296.  
  297.       dwSize = sizeof(szBuff);
  298.       gethostname(szBuff, dwSize);
  299.  
  300.       psin->sin_addr.s_addr = INADDR_ANY;
  301.       }
  302.  
  303.  
  304.    /*
  305.    *   Retrieve the Port number
  306.    */
  307.    status = DialogBox(hInst,             /* current instance         */
  308.       "TCPPORTNUM",                      /* resource to use          */
  309.       hWnd,                              /* parent handle            */
  310.       GetTcpPort);                       /* instance address         */
  311.  
  312.    switch(status) {
  313.       case 0:               /* User cancelled request from prev. dialog box */
  314.          return FALSE;
  315.  
  316.       case 1:               /* actual port number entered */
  317.          psin->sin_port = htons(portno);        /* Convert to network ordering */
  318.          break;
  319.  
  320.       case 2:               /* service name entereted */
  321.          /*
  322.          *   Find the service name, szBuff, which is a type tcp protocol in
  323.          *   the "services" file.
  324.          */
  325.          pse = getservbyname(szBuff, "tcp");
  326.          if (pse == NULL)  {
  327.             sprintf(szBuff, "%d is the error. Make sure this is a valid TCP service.", WSAGetLastError());
  328.             MessageBox(hWnd, szBuff, "getservbyname(sock) failed", MB_OK);
  329.             return FALSE;
  330.          }
  331.          psin->sin_port = pse->s_port;
  332.          break;
  333.  
  334.       default:
  335.          return FALSE;
  336.    }
  337.    return TRUE;
  338. }
  339.  
  340. /****************************************************************************
  341. *
  342. *    FUNCTION: SetConnectMenus( HWND )
  343. *
  344. *    PURPOSE: Gray/Enable the proper menu items after a connection has been
  345. *             established.
  346. *
  347. *\***************************************************************************/
  348.  
  349. void SetConnectMenus( HWND hWnd )
  350. {
  351.    /*
  352.    *   Disable/enable proper menu items.
  353.    */
  354.    EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_ENABLED );
  355.    EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_GRAYED );
  356.    EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_GRAYED );
  357.    EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_GRAYED );
  358.    EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_GRAYED );
  359.    EnableMenuItem(GetMenu( hWnd ), IDM_CANCEL, MF_GRAYED );
  360.    EnableMenuItem(GetMenu( hWnd ), IDM_SENDTCP, MF_ENABLED );
  361.    EnableMenuItem(GetMenu( hWnd ), IDM_ACCEPTEX, MF_GRAYED );
  362.    EnableMenuItem(GetMenu( hWnd ), IDM_CONNECTANDSEND, MF_GRAYED );
  363.  
  364.    /*
  365.    *   Reflect socket connection in title bar.
  366.    */
  367.    SetWindowText( hWnd, "Connected");
  368. }
  369.  
  370. /****************************************************************************\
  371. *
  372. *    FUNCTION: MainWndProc(HWND, unsigned, WORD, LONG)
  373. *
  374. *    PURPOSE:  Processes main window messages
  375. *
  376. * MESSAGES:
  377. *  WM_CREATE   - call WSAStartUp() and display description message
  378. *  WSA_ACCEPT  - User-defined message used with WSAAsyncSelect().  Sent
  379. *                by the Windows Sockets DLL when a socket connection is
  380. *                pending.
  381. *
  382. *  WM_COMMAND
  383. *  IDM_CONNECT - Connect to a remote host.
  384. *  IDM_LISTEN  - Use the BSD-Style accept().
  385. *  IDM_ALISTEN - Use the Windows Sockets Asynchronous APIs to detect when
  386. *                a connection is made.
  387. *  IDM_CANCEL  - Cancel the Asynchronous call above.
  388. *  IDM_TLISTEN - Uses two threads to accept network connections (using the
  389. *                BSD-Style accept().
  390. *  IDM_HOSTNAME- Display information about a host.
  391. *  IDM_ABOUT   - About box.
  392. *
  393. *  WM_DESTROY  - destroy window and call the WSACleanUp()
  394. *
  395. *\***************************************************************************/
  396.  
  397. LONG APIENTRY MainWndProc(
  398.         HWND hWnd,                /* window handle                   */
  399.         UINT message,             /* type of message                 */
  400.         UINT wParam,              /* additional information          */
  401.         LONG lParam)              /* additional information          */
  402. {
  403.    int status;             /* Status Code */
  404.    SOCKADDR_IN local_sin;  /* Local socket - internet style */
  405.    SOCKADDR_IN acc_sin;    /* Accept socket address - internet style */
  406.    int acc_sin_len;        /* Accept socket address length */
  407.  
  408.  
  409.    switch (message) {
  410.    case WM_CREATE:
  411.    {
  412.       WSADATA WSAData;
  413.       char szTemp[80];
  414.  
  415.       if ((status = WSAStartup(MAKEWORD(1,1), &WSAData)) == 0) {
  416.          MessageBox( hWnd, WSAData.szDescription, WSAData.szSystemStatus, MB_OK);
  417.       }
  418.       else {
  419.          sprintf(szTemp, "%d is the err", status);
  420.          MessageBox( hWnd, szTemp, "Error", MB_OK);
  421.       }
  422.    }
  423.    break;   /* WM_CREATE */
  424.  
  425.    /*
  426.    *    Notification if data is waiting on a socket.  This comes
  427.    *    from Windows Sockets (via WSAAsyncSelect()).
  428.    */
  429.    case WSA_READ:
  430.    {
  431.       char szTemp[ MY_MSG_LENGTH ];
  432.  
  433.       if (WSAGETSELECTEVENT(lParam) == FD_READ) {
  434.          status = recv((SOCKET)wParam, szTemp, MY_MSG_LENGTH, NO_FLAGS_SET );
  435.  
  436.          if (status) {
  437.             szTemp[ status ] = '\0';
  438.             MessageBox( hWnd, szTemp, "WSA_READ", MB_OK);
  439.          }
  440.          else
  441.             MessageBox( hWnd, "Connection broken", "Error", MB_OK);
  442.       }
  443.       else {    /* FD_CLOSE -- connection dropped */
  444.          MessageBox( hWnd, "Connection lost", "WSA_READ", MB_OK);
  445.          EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_ENABLED);
  446.          EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_ENABLED);
  447.          EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_ENABLED);
  448.          EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_ENABLED);
  449.          EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_ENABLED);
  450.          EnableMenuItem(GetMenu( hWnd ), IDM_CANCEL, MF_GRAYED);
  451.          EnableMenuItem(GetMenu( hWnd ), IDM_SENDTCP, MF_GRAYED);
  452.       }
  453.  
  454.  
  455.    }
  456.    break;       /* WSA_READ*/
  457.  
  458.    case WSA_ACCEPT: /* Notification if a socket connection is pending. */
  459.       /*
  460.       *   Disable/enable proper menu items.
  461.       */
  462.       EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_ENABLED);
  463.       EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_ENABLED);
  464.       EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_ENABLED);
  465.       EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_ENABLED);
  466.       EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_ENABLED);
  467.       EnableMenuItem(GetMenu( hWnd ), IDM_CANCEL, MF_GRAYED);
  468.  
  469.       if (WSAGETSELECTERROR( lParam ) == 0) {   /* Success */
  470.  
  471.          /*
  472.          *   Accept the incoming connection.
  473.          */
  474.          acc_sin_len = sizeof( acc_sin );
  475.          sock = accept( sock,(struct sockaddr FAR *) &acc_sin,
  476.             (int FAR *) &acc_sin_len );
  477.  
  478.          if (sock < 0) {
  479.             sprintf(szBuff, "%d is the error", WSAGetLastError());
  480.  
  481.             MessageBox(hWnd, szBuff, "accept(sock) failed", MB_OK);
  482.             break;
  483.          }
  484.  
  485.          MessageBox(hWnd, "accept()", "Accepted a connection!", MB_OK);
  486.  
  487.          /*
  488.          *   Now have a connection --
  489.          *   SetConnectMenus() grays/enables proper menu items
  490.          */
  491.          SetConnectMenus( hWnd );
  492.  
  493.          /*
  494.          *   Send main window a WSA_READ when either data is pending on
  495.          *   the socket (FD_READ) or the connection is closed (FD_CLOSE)
  496.          */
  497.          if ((status = WSAAsyncSelect( sock, hWnd, WSA_READ, FD_READ | FD_CLOSE )) > 0) {
  498.             wsprintf(szBuff, "%d (0x%x)", status, status);
  499.             MessageBox( hWnd, "Error on WSAAsyncSelect()", szBuff, MB_OK);
  500.             closesocket( sock );
  501.          }
  502.       }
  503.       else {
  504.          MessageBox(hWnd, "accept()", "Error occured!", MB_OK);
  505.  
  506.          /*
  507.          *   Cancel any further notifications.
  508.          */
  509.          WSAAsyncSelect( sock, hWnd, 0, 0);
  510.          SetWindowText( hWnd, "Async Listen call canceled");
  511.       }
  512.       break;   /* WSA_ACCEPT */
  513.  
  514.  
  515.  
  516.    case WM_COMMAND:        /* message: command from application menu */
  517.       switch(LOWORD(wParam)) {
  518.       case IDM_CONNECT: /* Client - connect to remote host */
  519.       {
  520.          /*
  521.  
  522.          When a network client wants to connect to a server,
  523.          it must have:
  524.             1.) a TCP port number (gotten via getservbyname())
  525.             and
  526.             2.) an IP address of the remote host (gotten via gethostbyname()).
  527.  
  528.          The following summarizes the steps used to connect.
  529.          Make a dialog box (HostName)
  530.          Get the name of the remote host computer in which
  531.           to connect from the user (store string in "szBuff" global var)
  532.        * Check to see if the hosts file knows the computer (gethostbyname)
  533.        * Get the host information (hostent structure filled)
  534.        * Fill in the address of the remote host into the servent structure (memcpy)
  535.        * Make a dialog box (TCPPORTNUM)
  536.        * Get the NAME of the port to connect to on the remote host from the
  537.          user.
  538.        * Get the port number (getservbyname)
  539.        * Fill in the port number of the servent structure
  540.          Establish a connection (connect)
  541.  
  542.          The * prefixed steps are done in the FillAddr() procedure.
  543.  
  544.  
  545.          */
  546.          SOCKADDR_IN dest_sin;  /* DESTination Socket INternet */
  547.  
  548.  
  549.  
  550.          /* Get the name of the remote host. Store the string in szBuff. */
  551.  
  552.          status = DialogBox(hInst,
  553.             "HOSTNAME",
  554.             hWnd,
  555.             GetHostName);
  556.  
  557.          if (!status)   /* User cancelled request from prev. dialog box */
  558.             break;
  559.  
  560.          sock = socket( AF_INET, SOCK_STREAM, 0);
  561.          if (sock == INVALID_SOCKET) {
  562.             MessageBox(hWnd, "socket() failed", "Error", MB_OK);
  563.             break;
  564.          }
  565.  
  566.          /*
  567.          *    Retrieve the IP address and TCP Port number
  568.          *    Global variable szBuff contains the remote host name.
  569.          */
  570.          if (!FillAddr( hWnd, &dest_sin, TRUE)) {
  571.             closesocket( sock );
  572.             break;
  573.          }
  574.  
  575.  
  576.          if (connect( sock, (PSOCKADDR) &dest_sin, sizeof( dest_sin)) < 0) {
  577.             closesocket( sock );
  578.             MessageBox(hWnd, "connect() failed", "Error", MB_OK);
  579.             break;
  580.          }
  581.          MessageBox(hWnd, "connect() worked!", "Success!", MB_OK);
  582.  
  583.          /*
  584.          *   Now have a connection --
  585.          *   SetConnectMenus() grays/enables proper menu items
  586.          */
  587.          SetConnectMenus( hWnd );
  588.  
  589.          /*
  590.          *   Send main window a WSA_READ when either data is pending on
  591.          *   the socket (FD_READ) or the connection is closed (FD_CLOSE)
  592.          */
  593.          if ((status = WSAAsyncSelect( sock, hWnd, WSA_READ, FD_READ | FD_CLOSE )) > 0) {
  594.             wsprintf(szBuff, "%d (0x%x)");
  595.             MessageBox( hWnd, "Error on WSAAsyncSelect()", szBuff, MB_OK);
  596.             closesocket( sock );
  597.          }
  598.  
  599.       }
  600.       break;   /* IDM_CONNECT */
  601.  
  602.       case IDM_CONNECTANDSEND:
  603.       {
  604.          //
  605.          //
  606.          //  In order to simulate a more typical real-world client, here
  607.          //   we make the connection, and then immediately send it data.
  608.          //
  609.          //  See IDM_CONNECT above for full comments.
  610.  
  611.          SOCKADDR_IN dest_sin;
  612.  
  613.          status = DialogBox(hInst,
  614.             "HOSTNAME",
  615.             hWnd,
  616.             GetHostName);
  617.  
  618.          if (!status)
  619.             break;
  620.  
  621.          sock = socket( AF_INET, SOCK_STREAM, 0);
  622.          if (sock == INVALID_SOCKET) {
  623.             MessageBox(hWnd, "socket() failed", "Error", MB_OK);
  624.             break;
  625.          }
  626.  
  627.          if (!FillAddr( hWnd, &dest_sin, TRUE)) {
  628.             closesocket( sock );
  629.             break;
  630.          }
  631.  
  632.  
  633.          if (connect( sock, (PSOCKADDR) &dest_sin, sizeof( dest_sin)) < 0) {
  634.             MessageBox(hWnd, "connect() failed", "Error", MB_OK);
  635.             closesocket( sock );
  636.             break;
  637.          }
  638.  
  639.          if (send (sock, gpszHelloWorld, lstrlen (gpszHelloWorld), 0 ) == SOCKET_ERROR) {
  640.             wsprintf(szBuff, "WSAGetLastError: %d", WSAGetLastError());
  641.             MessageBox( hWnd, szBuff, "Error on send()", MB_OK);
  642.             closesocket( sock );
  643.             break;
  644.          }
  645.  
  646.  
  647.          MessageBox(hWnd, "connect() & send() worked!", "Success!", MB_OK);
  648.  
  649.          SetConnectMenus( hWnd );
  650.  
  651.          if ((status = WSAAsyncSelect( sock, hWnd, WSA_READ, FD_READ | FD_CLOSE )) > 0) {
  652.             wsprintf(szBuff, "WSAGetLastError: %d", WSAGetLastError());
  653.             MessageBox( hWnd, "Error on WSAAsyncSelect()", szBuff, MB_OK);
  654.             closesocket( sock );
  655.          }
  656.  
  657.       }
  658.       break;   // IDM_CONNECTANDSEND
  659.  
  660.  
  661.       case IDM_ACCEPTEX:
  662.       {
  663.         //
  664.         // Demonstrate the use of AcceptEx().
  665.         //
  666.  
  667. #define MAX_BYTES        2000
  668. #define PADDED_ADDR_SIZE sizeof(SOCKADDR_IN)+16
  669.         SOCKET sListenSocket;
  670.         SOCKET sAcceptSocket;
  671.         char   pData [MAX_BYTES];
  672.         OVERLAPPED olResult;
  673.         DWORD dwBytes;
  674.  
  675.  
  676.         //
  677.         // For this API, we need to create two sockets ahead of time.
  678.         //  The listen socket goes through the standard bind/listen steps.
  679.         //
  680.  
  681.         sListenSocket = socket( AF_INET, SOCK_STREAM, 0);
  682.         sAcceptSocket = socket( AF_INET, SOCK_STREAM, 0);
  683.         if ((sListenSocket == INVALID_SOCKET) || (sAcceptSocket == INVALID_SOCKET)) {
  684.            MessageBox(hWnd, "sock == INVALID_SOCKET", "socket() failed", MB_OK);
  685.            closesocket(sListenSocket);
  686.            closesocket(sAcceptSocket);
  687.            break;
  688.         }
  689.  
  690.         //
  691.         //   Retrieve the IP address and TCP Port number
  692.         //
  693.  
  694.         if (!FillAddr(hWnd, &local_sin, FALSE ))
  695.            break;
  696.  
  697.         //
  698.         //   Associate an address with the socket
  699.         //
  700.  
  701.         if (bind( sListenSocket, (struct sockaddr FAR *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR) {
  702.            wsprintf(szBuff, "WSAGetLastError: %d", WSAGetLastError());
  703.            MessageBox(hWnd, szBuff, "bind(sock) failed", MB_OK);
  704.            break;
  705.         }
  706.  
  707.         //
  708.         //   And go into the listening state.
  709.         //
  710.  
  711.         if (listen( sListenSocket, MAX_PENDING_CONNECTS ) < 0) {
  712.            wsprintf(szBuff, "WSAGetLastError: %d", WSAGetLastError());
  713.            MessageBox(hWnd, szBuff, "listen(sock) failed", MB_OK);
  714.            break;
  715.         }
  716.  
  717.         //
  718.         //   Disable/enable proper menu items.
  719.         //
  720.  
  721.         EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_GRAYED);
  722.         EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_GRAYED);
  723.         EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_GRAYED);
  724.         EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_GRAYED);
  725.         EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_GRAYED);
  726.         EnableMenuItem(GetMenu( hWnd ), IDM_ACCEPTEX, MF_GRAYED);
  727.         EnableMenuItem(GetMenu( hWnd ), IDM_CONNECTANDSEND, MF_GRAYED);
  728.  
  729.         SetWindowText( hWnd, "AcceptEx..");
  730.  
  731.         //
  732.         //  Create an event for our overlapped structure (required).
  733.         //
  734.  
  735.         memset (&olResult,  0, sizeof(olResult));
  736.         olResult.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  737.         dwBytes = 0;
  738.  
  739.         //
  740.         //  AcceptEx makes the most sense when used with I/O
  741.         //   CompletionPorts and TransmitFile.
  742.         //   We show a very basic usage here...
  743.         //
  744.  
  745.         if (AcceptEx( sListenSocket,
  746.                       sAcceptSocket,
  747.                       pData,
  748.                       MAX_BYTES - 2*PADDED_ADDR_SIZE,
  749.                       PADDED_ADDR_SIZE,
  750.                       PADDED_ADDR_SIZE,
  751.                       &dwBytes,
  752.                       &olResult) == FALSE) {
  753.  
  754.             if (WSAGetLastError() != ERROR_IO_PENDING) {
  755.                wsprintf(szBuff, "WSAGetLastError: %d", WSAGetLastError());
  756.                MessageBox( hWnd, szBuff, "Error on AcceptEx()", MB_OK);
  757.                break;
  758.             } else {
  759.  
  760.                //
  761.                // In our contrived scenario, we expect GetLastError to be
  762.                //  ERROR_IO_PENDING.  A real app would do other work.
  763.                //  Since this is a simple sample, we will just block waiting
  764.                //  for some input to come through the socket.
  765.                //
  766.  
  767.                GetOverlappedResult ( (HANDLE) sAcceptSocket,
  768.                                      &olResult,
  769.                                      &dwBytes,
  770.                                      TRUE);
  771.                pData[dwBytes] = 0;
  772.                MessageBox(hWnd, pData, "AcceptEx received data", MB_OK);
  773.  
  774.             }
  775.         }
  776.  
  777.         //
  778.         //  As per the documentation, poke the new socket so that it will have
  779.         //   the correct properties and can be used by other functions.
  780.         //
  781.  
  782.         if (setsockopt( sAcceptSocket,
  783.                         SOL_SOCKET,
  784.                         SO_UPDATE_ACCEPT_CONTEXT,
  785.                         (char *)&sListenSocket,
  786.                         sizeof(sListenSocket) )) {
  787.                 wsprintf(szBuff, "WSAGetLastError: %d", WSAGetLastError());
  788.                 MessageBox( hWnd, szBuff, "Error in setsockopt()", MB_OK);
  789.                 break;
  790.         } else {
  791.  
  792.         //
  793.         //  sAcceptSocket is now OK for use by other functions.
  794.         //  set it into our global socket (sock)
  795.         //
  796.             sock = sAcceptSocket;
  797.         }
  798.  
  799.         //
  800.         //  In any case, we are done with our listen socket
  801.         //
  802.  
  803.         closesocket( sListenSocket );
  804.  
  805.         //
  806.         //  Now have a connection --
  807.         //   SetConnectMenus() grays/enables proper menu items
  808.  
  809.         SetConnectMenus( hWnd );
  810.  
  811.         //
  812.         //  Send main window a WSA_READ when either data is pending on
  813.         //  the socket (FD_READ) or the connection is closed (FD_CLOSE)
  814.  
  815.         if ((status = WSAAsyncSelect( sock, hWnd, WSA_READ, FD_READ | FD_CLOSE )) > 0) {
  816.            wsprintf(szBuff, "%d (0x%x)");
  817.            MessageBox( hWnd, "Error on WSAAsyncSelect()", szBuff, MB_OK);
  818.            closesocket( sock );
  819.         }
  820.       }
  821.       break;   /* IDM_ACCEPTEX */
  822.  
  823.  
  824.       case IDM_LISTEN:
  825.       {
  826.          sock = socket( AF_INET, SOCK_STREAM, 0);
  827.          if (sock == INVALID_SOCKET) {
  828.             MessageBox(hWnd, "socket() failed", "Error", MB_OK);
  829.             closesocket(sock);
  830.             break;
  831.          }
  832.  
  833.          /*
  834.          *   Retrieve the IP address and TCP Port number
  835.          */
  836.  
  837.          if (!FillAddr(hWnd, &local_sin, FALSE ))
  838.             break;
  839.  
  840.          /*
  841.          *   Disable/enable proper menu items.
  842.          */
  843.          EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_GRAYED);
  844.          EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_GRAYED);
  845.          EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_GRAYED);
  846.          EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_GRAYED);
  847.          EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_GRAYED);
  848.          EnableMenuItem(GetMenu( hWnd ), IDM_ACCEPTEX, MF_GRAYED);
  849.          EnableMenuItem(GetMenu( hWnd ), IDM_CONNECTANDSEND, MF_GRAYED);
  850.  
  851.          SetWindowText( hWnd, "Waiting for connection..");
  852.  
  853.  
  854.          /*
  855.          *   Associate an address with a socket. (bind)
  856.          */
  857.          if (bind( sock, (struct sockaddr FAR *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR) {
  858.             sprintf(szBuff, "%d is the error", WSAGetLastError());
  859.  
  860.             MessageBox(hWnd, szBuff, "bind(sock) failed", MB_OK);
  861.             break;
  862.          }
  863.  
  864.          if (listen( sock, MAX_PENDING_CONNECTS ) < 0) {
  865.             sprintf(szBuff, "%d is the error", WSAGetLastError());
  866.  
  867.             MessageBox(hWnd, szBuff, "listen(sock) failed", MB_OK);
  868.             break;
  869.          }
  870.  
  871.          acc_sin_len = sizeof(acc_sin);
  872.  
  873.  
  874.          sock = accept( sock,(struct sockaddr FAR *) &acc_sin,
  875.             (int FAR *) &acc_sin_len );
  876.          if (sock < 0) {
  877.             sprintf(szBuff, "%d is the error", WSAGetLastError());
  878.  
  879.             MessageBox(hWnd, szBuff, "accept(sock) failed", MB_OK);
  880.             break;
  881.          }
  882.  
  883.          MessageBox(hWnd, "accept()", "Accepted a connection!", MB_OK);
  884.  
  885.          /*
  886.          *   Now have a connection --
  887.          *   SetConnectMenus() grays/enables proper menu items
  888.          */
  889.          SetConnectMenus( hWnd );
  890.  
  891.          /*
  892.          *   Send main window a WSA_READ when either data is pending on
  893.          *   the socket (FD_READ) or the connection is closed (FD_CLOSE)
  894.          */
  895.          if ((status = WSAAsyncSelect( sock, hWnd, WSA_READ, FD_READ | FD_CLOSE )) > 0) {
  896.             wsprintf(szBuff, "%d (0x%x)");
  897.             MessageBox( hWnd, "Error on WSAAsyncSelect()", szBuff, MB_OK);
  898.             closesocket( sock );
  899.          }
  900.  
  901.       }
  902.       break;   /* IDM_LISTEN */
  903.  
  904.       /*
  905.       *   Asynchronous Listen - Using WSA extensions.
  906.       */
  907.       case IDM_ALISTEN:
  908.       {
  909.  
  910.          sock = socket( AF_INET, SOCK_STREAM, 0);
  911.          if (sock == INVALID_SOCKET) {
  912.             MessageBox(hWnd, "socket() failed", "Error", MB_OK);
  913.             break;
  914.          }
  915.          /*
  916.          *   Retrieve the IP address and TCP Port number
  917.          */
  918.  
  919.          if (!FillAddr( hWnd, &local_sin, FALSE)) {
  920.             closesocket( sock );
  921.             break;
  922.          }
  923.  
  924.          /*
  925.          *   Disable/enable proper menu items.
  926.          */
  927.          EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_GRAYED);
  928.          EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_GRAYED);
  929.          EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_GRAYED);
  930.          EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_GRAYED);
  931.          EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_GRAYED);
  932.          EnableMenuItem(GetMenu( hWnd ), IDM_CANCEL, MF_ENABLED);
  933.          EnableMenuItem(GetMenu( hWnd ), IDM_ACCEPTEX, MF_GRAYED);
  934.          EnableMenuItem(GetMenu( hWnd ), IDM_CONNECTANDSEND, MF_GRAYED);
  935.  
  936.          SetWindowText( hWnd, "Waiting for connection.. (Async)");
  937.  
  938.  
  939.          /*
  940.          *   Associate an address with a socket. (bind)
  941.          */
  942.          if (bind( sock, (struct sockaddr FAR *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR) {
  943.             sprintf(szBuff, "%d is the error", WSAGetLastError());
  944.  
  945.             MessageBox(hWnd, szBuff, "bind(sock) failed", MB_OK);
  946.             closesocket( sock );
  947.             break;
  948.          }
  949.  
  950.          if (listen( sock, MAX_PENDING_CONNECTS ) < 0) {
  951.             sprintf(szBuff, "%d is the error", WSAGetLastError());
  952.  
  953.             MessageBox(hWnd, szBuff, "listen(sock) failed", MB_OK);
  954.             break;
  955.          }
  956.  
  957.          /*
  958.          *   Send window a WSA_ACCEPT when something is trying to connect.
  959.          */
  960.          if ((status = WSAAsyncSelect( sock, hWnd, WSA_ACCEPT, FD_ACCEPT)) > 0) {
  961.             wsprintf( szBuff, "%d (0x%x)");
  962.             MessageBox( hWnd, "Error on WSAAsyncSelect()", szBuff, MB_OK);
  963.             SetWindowText( hWnd, "Async listen cancelled");
  964.             closesocket( sock );
  965.          }
  966.  
  967.       }
  968.       break;   /* IDM_ALISTEN */
  969.  
  970.  
  971.       /*
  972.       *   Cancel an asynchronous call.
  973.       */
  974.       case IDM_CANCEL:
  975.          WSAAsyncSelect( sock, hWnd, 0, 0);
  976.          SetWindowText( hWnd, "Async Listen cancelled..");
  977.  
  978.          /*
  979.          *   Disable/enable proper menu items.
  980.          */
  981.          EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_ENABLED);
  982.          EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_ENABLED);
  983.          EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_ENABLED);
  984.          EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_ENABLED);
  985.          EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_ENABLED);
  986.          EnableMenuItem(GetMenu( hWnd ), IDM_CANCEL, MF_GRAYED);
  987.          EnableMenuItem(GetMenu( hWnd ), IDM_SENDTCP, MF_GRAYED);
  988.          EnableMenuItem(GetMenu( hWnd ), IDM_ACCEPTEX, MF_ENABLED);
  989.          EnableMenuItem(GetMenu( hWnd ), IDM_CONNECTANDSEND, MF_ENABLED);
  990.  
  991.          break;   /* IDM_CANCEL */
  992.  
  993.       /*
  994.       * Listen in the main thread -- spawn and accept two network
  995.       *  connections inside two threads.
  996.       */
  997.       case IDM_TLISTEN:
  998.       {
  999.          static THREADPACK tp;
  1000.  
  1001.          sock = socket( AF_INET, SOCK_STREAM, 0);
  1002.          if (sock == INVALID_SOCKET) {
  1003.             MessageBox(hWnd, "socket() failed", "Error", MB_OK);
  1004.             closesocket(sock);
  1005.             break;
  1006.          }
  1007.  
  1008.          /*
  1009.          *   Retrieve the IP address and TCP Port number
  1010.          */
  1011.  
  1012.          if (!FillAddr(hWnd, &local_sin, FALSE ))
  1013.             break;
  1014.  
  1015.          /*
  1016.          *   Disable/enable proper menu items.
  1017.          */
  1018.          EnableMenuItem(GetMenu( hWnd ), IDM_HOSTNAME, MF_GRAYED);
  1019.          EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_GRAYED);
  1020.          EnableMenuItem(GetMenu( hWnd ), IDM_ALISTEN, MF_GRAYED);
  1021.          EnableMenuItem(GetMenu( hWnd ), IDM_TLISTEN, MF_GRAYED);
  1022.          EnableMenuItem(GetMenu( hWnd ), IDM_CONNECT, MF_GRAYED);
  1023.          EnableMenuItem(GetMenu( hWnd ), IDM_SENDTCP, MF_GRAYED);
  1024.          EnableMenuItem(GetMenu( hWnd ), IDM_ACCEPTEX, MF_GRAYED);
  1025.          EnableMenuItem(GetMenu( hWnd ), IDM_CONNECTANDSEND, MF_GRAYED);
  1026.  
  1027.          SetWindowText( hWnd, "Waiting for connection..");
  1028.  
  1029.  
  1030.          /*
  1031.          *   Associate an address with a socket. (bind)
  1032.          */
  1033.          if (bind( sock, (struct sockaddr FAR *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR) {
  1034.             sprintf(szBuff, "%d is the error", WSAGetLastError());
  1035.  
  1036.             MessageBox(hWnd, szBuff, "bind(sock) failed", MB_OK);
  1037.             break;
  1038.          }
  1039.  
  1040.          if (listen( sock, MAX_PENDING_CONNECTS ) < 0) {
  1041.             sprintf(szBuff, "%d is the error", WSAGetLastError());
  1042.  
  1043.             MessageBox(hWnd, szBuff, "listen(sock) failed", MB_OK);
  1044.             break;
  1045.          }
  1046.  
  1047.          tp.nThread = 0;
  1048.          tp.hWnd = hWnd;
  1049.  
  1050.          _beginthread(AcceptThreadProc, 0, &tp);
  1051.  
  1052.          }
  1053.          break;   /* IDM_TLISTEN */
  1054.  
  1055.  
  1056.       /*
  1057.       *   Display host information.
  1058.       */
  1059.       case IDM_HOSTNAME:
  1060.  
  1061.          /*
  1062.          *  Prompt the user and retrieve the text name of the host.
  1063.          */
  1064.          status = DialogBox(hInst,
  1065.             "HOSTNAME",
  1066.             hWnd,
  1067.             GetHostName);
  1068.  
  1069.  
  1070.          if (status == TRUE) {   /* If user hit "OK" .. */
  1071.  
  1072.          /*
  1073.          *   Get the host information
  1074.          */
  1075.  
  1076.          if ((phe = gethostbyname( szBuff )) == NULL) {
  1077.             MessageBox(hWnd, "gethostbyname() failed", "Error", MB_OK);
  1078.             break;
  1079.          }
  1080.          else {
  1081.  
  1082.          /*
  1083.          *   Display the host information ..
  1084.          */
  1085.             DialogBox(hInst,
  1086.                "DISPLAYHOST",
  1087.                hWnd,
  1088.                DisplayHostEnt);
  1089.          }
  1090.       }
  1091.       break;   /* IDM_HOSTNAME */
  1092.       /*
  1093.       *   Send a message to (via TCP connection) to remote host.
  1094.       */
  1095.       case IDM_SENDTCP:
  1096.          DialogBox(hInst,                /* current instance         */
  1097.             "GetString",                 /* resource to use          */
  1098.             hWnd,                        /* parent handle            */
  1099.             GetSendString);              /* instance address         */
  1100.  
  1101.         /*
  1102.         *   Assumption -- The GetString dialog box proc fills the global
  1103.         *   string buffer, szBuff, with the desired string to send.
  1104.         */
  1105.         send(sock, szBuff, strlen(szBuff), NO_FLAGS_SET );
  1106.  
  1107.         break;   /* IDM_SENDTCP */
  1108.  
  1109.  
  1110.  
  1111.       case IDM_ABOUT:
  1112.          DialogBox(hInst,                /* current instance         */
  1113.             "AboutBox",                  /* resource to use          */
  1114.             hWnd,                        /* parent handle            */
  1115.             About);                      /* About() instance address */
  1116.  
  1117.          break;   /* IDM_ABOUT */
  1118.  
  1119.       default:
  1120.          /* Lets Windows process it          */
  1121.          return (DefWindowProc(hWnd, message, wParam, lParam));
  1122.          break;
  1123.       }
  1124.    break;
  1125.  
  1126.  
  1127.    /*
  1128.    *   Clean up.  Takes care of any open socket descriptors.
  1129.    */
  1130.    case WM_DESTROY:
  1131.       WSACleanup();
  1132.       PostQuitMessage(0);
  1133.       break;
  1134.  
  1135.    default:                       /* Passes it on if unproccessed    */
  1136.       return (DefWindowProc(hWnd, message, wParam, lParam));
  1137.  
  1138.    }
  1139.    return (0);
  1140.  
  1141. }
  1142.