home *** CD-ROM | disk | FTP | other *** search
/ Network Support Encyclopedia 96-1 / novell-nsepro-1996-1-cd2.iso / download / netware / gchats.exe / GRPCHATS.C < prev    next >
Text File  |  1995-09-08  |  15KB  |  472 lines

  1. /*
  2.  
  3. Copyright (c) 1992 Novell, Inc.  All Rights Reserved.
  4.  
  5. THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
  6. TREATIES.  USE AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO THE
  7. LICENSE AGREEMENT ACCOMPANYING THE SOFTWARE DEVELOPMENT KIT (SDK)
  8. THAT CONTAINS THIS WORK.
  9.  
  10. Pursuant to the SDK License Agreement, Novell hereby grants to
  11. Developer a royalty-free, non-exclusive license to include the
  12. sample code GRPCHATS.C and derivative binaries in its product.
  13. Novell grants to Developer worldwide distribution rights to market,
  14. distribute or sell the sample code GRPCHATS.C and derivative
  15. binaries as a component of Developer's product(s).  Novell shall
  16. have no obligations to Developer or Developer's customers with
  17. respect to this code.
  18.  
  19. DISCLAIMER:
  20.  
  21.     Novell, Inc. makes no representations or warranties with respect
  22. to the contents or use of this code, and specifically disclaims any
  23. express or implied warranties of merchantability or fitness for any
  24. particular purpose.  Further, Novell, Inc. reserves the right to revise
  25. this publication and to make changes to its content, at any time,
  26. without obligation to notify any person or entity of such revisions or
  27. changes.
  28.  
  29.     Further, Novell, Inc. makes no representations or warranties with
  30. respect to any software, and specifically disclaims any express or
  31. implied warranties of merchantability or fitness for any particular
  32. purpose.  Further, Novell, Inc. reserves the right to make changes to
  33. any and all parts of the software, at any time, without obligation to
  34. notify any person or entity of such changes.
  35.  
  36. ***************************************************************************
  37.     GRPCHATS.C
  38. **************************************************************************/
  39.  
  40. /**************************************************************************
  41. ** Description: This sample code demonstates how to use TLI to build a 
  42. **                  non-dedicated chat server that supports up to 15 clients
  43. **              simultaneously. All of the connections are opened in
  44. **              non-blocking mode to allow this server application to be 
  45. **                 switched-away from in Windows. The partner application to 
  46. **              this one is GRPCHATC.EXE which demonstates how to write the 
  47. **              client that connects with this application. A timer is used
  48. **              to check for connection requests and received data from the
  49. **              connected clients. Once this server application successfully
  50. **              loads, it's network address is displayed at the top of the
  51. **              top of the window. It is this network address that the client
  52. **              partner GRPCHATC.EXE requires to connect to this server. 
  53. **              Enter the address exactly as it is displayed by this application.
  54. **               
  55. ** Compiler:     Borland C++ v4.5
  56. **
  57. ** Programmer :  Karl Bunnell
  58. ** Date:         08/24/1995
  59. **
  60. */
  61.  
  62. #include <windows.h>
  63. #define NWWIN
  64. #include <nwipxspx.h>     /* I'm using the fixed header file NXTW.H */
  65. #include <mem.h>
  66. #include <string.h>
  67. #include "grpchats.h"
  68. //#include "nxtw.h"
  69. #include <ctype.h>
  70. #include <tispxipx.h>
  71. #include <tiuser.h>
  72.  
  73. #define SPX_SOCKET 31                                         // arbitrary socket
  74. #define MAX_MESSAGE_SIZE    1024
  75. #define ID_TIMER    1
  76.  
  77.  
  78. long FAR PASCAL _export WndProc(HWND, UINT, UINT, LONG);
  79. BOOL Terminate(int connections, int *fd, int *ndf);
  80. BOOL SPXDisconReason(int fd, HWND hwnd, int count);
  81. static char globalMessage[1024];
  82. char  displayMessage[1024];
  83. char  tempMessage[1024];
  84.  
  85. /*-----------------------------------------------------------------------------
  86. **
  87. */
  88. int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
  89.                                         LPSTR lpszCmdLine, int nCmdShow)
  90. {
  91.     static char    szGRPCHATS[] = "GRPCHATS";
  92.     HWND                hwnd;
  93.     MSG                    msg;
  94.     WNDCLASS        wndclass;
  95.  
  96.     if(!hPrevInstance)
  97.     {
  98.         wndclass.style                    = CS_HREDRAW | CS_VREDRAW;
  99.  
  100.         wndclass.lpfnWndProc        =    WndProc;
  101.         wndclass.cbClsExtra            =    0;
  102.         wndclass.cbWndExtra            =    DLGWINDOWEXTRA;
  103.         wndclass.hInstance            =    hInstance;
  104.         wndclass.hIcon                    =    LoadIcon(NULL, IDI_APPLICATION);
  105.         wndclass.hCursor                = LoadCursor(NULL, IDC_ARROW);
  106.         wndclass.hbrBackground    = COLOR_WINDOW + 1;
  107.         wndclass.lpszMenuName        =    NULL;
  108.         wndclass.lpszClassName    = szGRPCHATS;
  109.  
  110.         RegisterClass(&wndclass);
  111.     }
  112.  
  113.     hwnd = CreateDialog(hInstance, "MainDialog", 0, NULL);
  114.  
  115.     while (!SetTimer (hwnd, ID_TIMER, 55, NULL))
  116.         if(IDCANCEL == MessageBox(hwnd, "Too many clocks or timers!", "GRPCHATS",
  117.                                         MB_ICONEXCLAMATION | MB_RETRYCANCEL))
  118.         return FALSE;
  119.  
  120.     SendMessage(hwnd, WM_INITWINDOW, NULL, NULL);
  121.  
  122.     ShowWindow(hwnd, nCmdShow);
  123.     while(GetMessage(&msg, NULL, 0,0))
  124.     {
  125.         TranslateMessage(&msg);
  126.         DispatchMessage(&msg);
  127.     }
  128.     return msg.wParam;
  129.  
  130. }
  131. /*-----------------------------------------------------------------------------
  132. ** Function: WndProc -- called by windows.
  133. */
  134. long far PASCAL _export WndProc ( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam )
  135. {
  136.     static IPX_ADDR    spx_addr;                                                                                               
  137.     static SPX_OPTS    spx_options;
  138.     static struct    t_bind tbind;
  139.     static struct    t_call tcall;
  140.     char        buf[ 1024 ];
  141.     static WORD        connections = 0;
  142.     static int fd, nfd[15]; 
  143.     int         flags, listenResult;
  144.     int       bytesSent, bytesLeft, nBytes, cnt;
  145.     int        connectionCount, rcvCount;
  146.     WORD psize;
  147.     IPXAddress    internetworkAddr;
  148.     DWORD IPXTaskID = 0L;
  149.     WORD    ccode; 
  150.     static initComplete = 0;
  151.     int j;
  152.      
  153.      switch (message)
  154.      {
  155.  
  156.           case WM_INITWINDOW:
  157.  
  158. /*-----------------------------------------------------------------------------
  159. ** The only reason the NWIPXSPX.LIB is included in the project is so I can 
  160. ** use IPXGetInternetworkAddress(). It is NOT necessary to include this LIB or
  161. ** to initialize IPX with IPXInitialize() if only TLI functions are used!
  162. */
  163.           
  164.      psize = IPXGetMaxPacketSize();
  165.      
  166.     ccode = IPXInitialize(&IPXTaskID, 4, (WORD)psize);
  167.       if(ccode)
  168.         {
  169.           wsprintf(displayMessage, "IPXInitialize: %02X", ccode);
  170.           MessageBox(GetFocus(),displayMessage, "IPXInitialize", MB_ICONASTERISK | MB_OK);
  171.           return 1;
  172.         }                                                  
  173.  
  174.  
  175.          IPXGetInternetworkAddress(IPXTaskID, (BYTE far *)&internetworkAddr);
  176.  
  177.          wsprintf(displayMessage, "   Address: %02X%02X%02X%02X:%02X%02X%02X%02X%02X%02X",
  178.              internetworkAddr.network[0],
  179.              internetworkAddr.network[1],
  180.              internetworkAddr.network[2],
  181.              internetworkAddr.network[3],
  182.              internetworkAddr.node[0],
  183.              internetworkAddr.node[1],
  184.              internetworkAddr.node[2],
  185.              internetworkAddr.node[3],
  186.              internetworkAddr.node[4],
  187.              internetworkAddr.node[5]
  188.              );
  189.  
  190.             SendDlgItemMessage(hwnd, IDC_DISPLAY_ADDR, WM_SETTEXT, 0, 
  191.                                         (LONG) (LPSTR)displayMessage );
  192.  
  193.                 if ( ( fd = t_open( "/dev/nspx", O_RDWR | O_NDELAY, ( struct t_info * )0 ) ) == -1 ) 
  194.                 {    t_error( "Open of /dev/nspx failed" );
  195.                     return FALSE;
  196.                 }
  197.  
  198.                 spx_addr.ipxa_socket[ 0 ]  = 0;         // Step 2       
  199.                 spx_addr.ipxa_socket[ 1 ]  = SPX_SOCKET;
  200.                 tbind.addr.len            = sizeof( spx_addr );
  201.                 tbind.addr.maxlen          = sizeof( spx_addr );
  202.                 tbind.addr.buf            = ( char * ) &spx_addr;
  203.                 tbind.qlen                = 15;        
  204.  
  205.                 if ( t_bind( fd, &tbind, &tbind ) == -1 ) 
  206.                 {     t_error( "Bind failed!" );
  207.                 return FALSE;
  208.                 }
  209.  
  210.                 tcall.addr.buf         = ( char * ) &spx_addr;            // Step 3
  211.                 tcall.addr.maxlen      = sizeof( spx_addr );
  212.                 tcall.addr.len         = sizeof( spx_addr );
  213.                 spx_options.spx_connectionID[ 0 ]    = 0;
  214.                 spx_options.spx_connectionID[ 1 ]    = 0;
  215.                 spx_options.spx_allocationNumber[ 0 ] = 0;
  216.                 spx_options.spx_allocationNumber[ 1 ] = 0;
  217.                 tcall.opt.buf        = ( char * )&spx_options;
  218.                 tcall.opt.len          = sizeof( spx_options );
  219.                 tcall.opt.maxlen       = sizeof( spx_options );
  220.                 tcall.udata.buf        = ( char * )0;
  221.                 tcall.udata.maxlen     = 0;
  222.                 tcall.udata.len        = 0;
  223.  
  224.             initComplete = 1;
  225.  
  226.             break;
  227.  
  228.           case WM_TIMER:
  229.  
  230.                     /*-----------------------------------------------------------------------------------
  231.                     **  I use a flag to wait until initialization is complete before checking for
  232.                     **  connection requests or received data. 
  233.                     */
  234.           
  235.                     if(!initComplete)
  236.                         break;
  237.  
  238.  
  239.                     /*-----------------------------------------------------------------------------------
  240.                     **  Send a message to check for pending received data on each timer message
  241.                     */
  242.                     if(connections > 0)
  243.                         PostMessage(hwnd, WM_CHECK_RECEIVE, 0, 0);
  244.  
  245.                     listenResult = t_listen( fd, &tcall );
  246.  
  247.                     if ((listenResult == -1) && (t_errno == TNODATA))
  248.                         break;
  249.                          
  250.                     if ( listenResult != -1 )                   
  251.                     {     if ( ( nfd[connections] = t_open( "/dev/nspx", O_RDWR | O_NDELAY, ( struct t_info * )0 ) ) == -1 ) 
  252.                         {    t_error( "t_open after listen failed" );
  253.                             return FALSE;                /* connections not incremented */
  254.                                                                   /* so array entry is reused    */
  255.                         }
  256.                         if ( t_bind( nfd[connections], ( struct t_bind * )0, ( struct t_bind * )0 ) == -1 ) 
  257.                         {    t_error( "t_bind failed" );
  258.                             t_close( nfd[connections] );
  259.                             return FALSE;
  260.                         }
  261.  
  262.                         if ( t_accept( fd, nfd[connections], &tcall ) == -1 ) 
  263.                         {    t_error( "t_accept failed" );
  264.                             t_close( nfd[connections] );
  265.                             return FALSE;
  266.                         }
  267.                         ++connections;
  268.                         break;
  269.                     }
  270.  
  271.  
  272.                 if ( t_errno == TLOOK && t_look( fd ) == T_DISCONNECT )                     
  273.                     SPXDisconReason( fd, hwnd, connections);
  274.                 else
  275.                     {
  276.  
  277.                     t_error( "t_listen failed" );
  278.                     t_close( fd );
  279.                     Terminate(connections, &fd, &nfd[0]);
  280.                     EndDialog(hwnd, TRUE);
  281.                     return TRUE;
  282.                     }
  283.  
  284.           break;
  285.  
  286.           case WM_CHECK_RECEIVE:
  287.           connectionCount = connections;
  288.           memset(buf, 0, sizeof(buf));
  289.  
  290.           for(rcvCount = 0; rcvCount < connectionCount; ++ rcvCount)
  291.              {
  292.                 flags = 0;        /* initialize for t_rcv call */
  293.  
  294.                 while ( t_rcv( nfd[rcvCount], buf, sizeof( buf),&flags ) != -1 /* && (flags & T_MORE)*/ )                 // Step 6
  295.                 {
  296.                   /*-----------------------------------------------------------------------------------
  297.                   ** Because the connection was opened in non-blocking mode there is a good possibility 
  298.                   ** that the complete message has not been received, however, for the purposes of this
  299.                   ** example I'm sending each chunk as I receive it to all connected nodes. Perhaps the 
  300.                   ** best way to do this would be to ensure that I have received the entire message
  301.                   ** then send the complete message to each node. In this case the end result is the same.
  302.                   */
  303.  
  304.                 wsprintf(displayMessage, "%s\r\n", buf);
  305.  
  306.                 /*-----------------------------------------------------------------------------------
  307.                 **  Here I jump through some hoops to ensure that the most current received data
  308.                 **  is placed at the top of the edit control.
  309.                 */
  310.                 
  311.                 if(strlen(displayMessage) + strlen(globalMessage) < MAX_MESSAGE_SIZE)
  312.                     {
  313.                     strcpy(tempMessage, displayMessage);
  314.                     strcat(tempMessage, globalMessage);
  315.                     strcpy(globalMessage, tempMessage);
  316.                     }
  317.                 else
  318.                     {
  319.                     memset(globalMessage, 0, sizeof(globalMessage));
  320.                     strcpy(tempMessage, displayMessage);
  321.                     strcat(tempMessage, globalMessage);
  322.                     strcpy(globalMessage, tempMessage);
  323.                     }
  324.  
  325.                 SendDlgItemMessage(hwnd, IDC_DISPLAY_DATA, WM_SETTEXT, 0, 
  326.                                         (LONG) (LPSTR) globalMessage);
  327.  
  328.  
  329.                  /*-----------------------------------------------------------------------------------
  330.                  **  Here I loop through all connected clients and send the received data to all
  331.                  **  connected clients.
  332.                  */
  333.                                     
  334.                  for(cnt = 0; cnt < connections; ++cnt)
  335.                     {
  336.  
  337.                      /*-----------------------------------------------------------------------------------
  338.                      **  Because the connection is in non-blocking mode, you must advance the pointer
  339.                      **  in the send buffer yourself. The following loop demonstates one way you might do this.
  340.                      */
  341.  
  342.                         nBytes = bytesLeft = strlen(buf);
  343.                         while (bytesLeft > 0)
  344.                             {  
  345.                                 do
  346.                                     {
  347.                                     bytesSent = t_snd( nfd[cnt], &buf[nBytes-bytesLeft], bytesLeft, 0 );
  348.                                     }while ((bytesSent == -1) && (t_errno == TFLOW));
  349.  
  350.                                 if (bytesSent == -1 ) 
  351.                                 {    
  352.                                     if (t_errno==TLOOK && t_look(nfd[cnt]) == T_DISCONNECT)
  353.                                         SPXDisconReason(nfd[cnt], hwnd, cnt);
  354.                                           
  355.                                     else
  356.                                         {
  357.                                         t_error("t_snd failed\n");
  358.                                         t_close(nfd[cnt]);
  359.                                         for (j=cnt+1; j<connections; ++j)
  360.                                           *(nfd+j-1) = *(nfd+j);
  361.                                         --connections;
  362.                                         break;
  363.                                         }
  364.                                 }
  365.                                 else
  366.                                      bytesLeft -= bytesSent;
  367.  
  368.                             } // end - while nBytes > 0
  369.                     }  // end for - loop t_snd to connections
  370.                 }  // end while - t_rcv loop
  371.                 if ( t_errno == TLOOK  &&  t_look( nfd[rcvCount] ) == T_DISCONNECT )             
  372.                      {
  373.                      SPXDisconReason( nfd[rcvCount], hwnd, rcvCount );
  374.                      t_close(nfd[rcvCount]);
  375.                      for (j=rcvCount+1; j<connections; ++j)
  376.                               *(nfd+j-1) = *(nfd+j);
  377.                      --connections;
  378.                      }
  379.  
  380.              } // end first for-loop connections t_rcv check
  381.  
  382.           break;
  383.  
  384.           case WM_DESTROY :
  385.                 KillTimer (hwnd, ID_TIMER);
  386.                 Terminate(connections, &fd, &nfd[0]);
  387.                 PostQuitMessage(0);
  388.                 return 0;
  389.  
  390.           case WM_COMMAND:
  391.                 switch(wparam)
  392.                 {
  393.                      case IDC_PUSHBUTTON1:
  394.                             KillTimer (hwnd, ID_TIMER);
  395.                             Terminate(connections, &fd, &nfd[0]);
  396.                             PostQuitMessage(0);
  397.                             return FALSE;
  398.                         
  399.                 }                                     
  400.  
  401.      }
  402.     return DefWindowProc(hwnd, message, wparam, lparam);
  403. }
  404.  
  405.  
  406. BOOL Terminate(int connections, int *fd, int *ndf)
  407. {
  408.     int i;
  409.     /*-----------------------------------------------------------------------------------
  410.     **  Close all connection handles.
  411.     */
  412.  
  413.     t_close( *(fd) );
  414.     for(i=0; i<connections; ++i)
  415.         t_close(ndf[i]);
  416.  
  417.     return TRUE;
  418. }
  419.  
  420. BOOL SPXDisconReason(int fd, HWND hwnd, int count)
  421. {
  422.     struct  t_discon discon;
  423.     char    *msg;
  424.  
  425.     if (t_rcvdis(fd, &discon) == -1)
  426.           {
  427.           t_error( "t_rcvdis failed" );
  428.           return (TRUE);
  429.           }
  430.     switch( discon.reason )
  431.          {
  432.          case TLI_SPX_CONNECTION_FAILED:
  433.                  msg = "Connection failed";
  434.                  break;
  435.          case TLI_SPX_CONNECTION_TERMINATED:
  436.                  msg = "Connection terminated by client";
  437.  
  438.                  break;
  439.          case TLI_SPX_MALFORMED_PACKET:
  440.                  msg = "Internal SPX interface error -- malformed packet";
  441.                  break;
  442.          default:
  443.                  msg = "Unknown termination reason";
  444.          }
  445.  
  446.     memset(displayMessage, 0, sizeof(displayMessage));
  447.  
  448.     wsprintf(displayMessage, "\r\nSPX Connection number %d terminated: \r\n %s\r\n%s", count, msg, globalMessage );
  449.  
  450.     if(strlen(displayMessage) + strlen(globalMessage) < MAX_MESSAGE_SIZE)
  451.         {
  452.         strcpy(tempMessage, displayMessage);
  453.         strcat(tempMessage, globalMessage);
  454.         strcpy(globalMessage, tempMessage);
  455.         }
  456.     else
  457.         {
  458.         memset(globalMessage, 0, sizeof(globalMessage));
  459.         strcpy(tempMessage, displayMessage);
  460.         strcat(tempMessage, globalMessage);
  461.         strcpy(globalMessage, tempMessage);
  462.         }
  463.  
  464.     
  465.     SendDlgItemMessage(hwnd, IDC_DISPLAY_DATA, WM_SETTEXT, 0, 
  466.                                 (LONG) (LPSTR) globalMessage);
  467.  
  468.     return FALSE;
  469. }
  470.  
  471.  
  472.