Server.c
Upload User: dq031136
Upload Date: 2022-08-08
Package Size: 802k
Code Size: 19k
Development Platform:

C++ Builder

  1. #define  STRICT
  2. #include <windows.h>
  3. #include "server.h"
  4. #include <string.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7.                                        // clients[] is a global array of
  8.                                        // structures used to keep track
  9.                                        // of the multiple instances of
  10.                                        // the server side of the named
  11.                                        // pipe.  As a client connects
  12.                                        // to a given instance, a new
  13.                                        // server thread is created and
  14.                                        // added to the array.
  15. WRTHANDLE clients[MAX_PIPE_INSTANCES];
  16. DWORD     clientCount = 0;             // Global count of connected clients.
  17. HWND   hWnd;
  18. HANDLE hInst;
  19. CHAR   lpBuffer[255];
  20. int APIENTRY WinMain (HINSTANCE hInstance,
  21.                       HINSTANCE hPrevInstance,
  22.                       LPSTR  lpCmdLine,
  23.                       int    nCmdShow)
  24. {
  25.   MSG  msg;
  26.   WNDCLASS wc;
  27.   UNREFERENCED_PARAMETER( lpCmdLine );
  28.   UNREFERENCED_PARAMETER( hPrevInstance );
  29.   //
  30.   // Detect platform and exit gracefully if not Windows NT.
  31.   //
  32.   {
  33.     OSVERSIONINFO osvi;
  34.     osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
  35.     GetVersionEx (&osvi);
  36.     if (osvi.dwPlatformId != VER_PLATFORM_WIN32_NT) {
  37.   LoadString(hInst, IDS_WRONGOS, lpBuffer, sizeof(lpBuffer)); 
  38.       MessageBox (NULL, lpBuffer, "SERVER32", MB_OK | MB_ICONSTOP);
  39.       return 0;
  40.     }
  41.   }
  42.   hInst = hInstance;
  43.   wc.style = 0;
  44.   wc.lpfnWndProc = (WNDPROC)MainWndProc;
  45.   wc.cbClsExtra = 0;
  46.   wc.cbWndExtra = 0;
  47.   wc.hInstance = hInstance;
  48.   wc.hIcon = LoadIcon (hInstance, "npserver");
  49.   wc.hCursor = LoadCursor (NULL, IDC_ARROW);
  50.   wc.hbrBackground = GetStockObject (WHITE_BRUSH);
  51.   wc.lpszMenuName = "PipeMenu";
  52.   wc.lpszClassName = "PipeWClass";
  53.   RegisterClass(&wc);
  54.   LoadString(hInst, IDS_WINDOWTITLE, lpBuffer, sizeof(lpBuffer)); 
  55.   hWnd = CreateWindow ("PipeWClass",
  56.                        lpBuffer,
  57.                        WS_OVERLAPPEDWINDOW,
  58.                        CW_USEDEFAULT,
  59.                        CW_USEDEFAULT,
  60.                        CW_USEDEFAULT,
  61.                        CW_USEDEFAULT,
  62.                        NULL,
  63.                        NULL,
  64.                        hInstance,
  65.                        NULL);
  66.   ShowWindow (hWnd, nCmdShow);
  67.   while (GetMessage (&msg, NULL, 0, 0))
  68.     DispatchMessage (&msg);
  69.   return (msg.wParam);
  70. }
  71. LONG CALLBACK MainWndProc (HWND   hwnd,
  72.                            UINT   message,
  73.                            WPARAM wParam,
  74.                            LPARAM lParam)
  75. {
  76.   LONG        lpServerThreadID;
  77.   PAINTSTRUCT paintStruct;
  78.   HDC         hDC;
  79.   switch (message)
  80.       {
  81.         case WM_PAINT:
  82.            // DrawBranch is used to paint the spools and text to the window.
  83.            hDC = BeginPaint (hwnd, &paintStruct);
  84.            DrawBranch (hDC);
  85.            EndPaint (hwnd, &paintStruct);
  86.            return(0);
  87.         case WM_CREATE :
  88.            // Create the first instance of a server side of the pipe.
  89.            CreateThread ((LPSECURITY_ATTRIBUTES)NULL,       // No security.
  90.                          (DWORD)0,                          // Same stack size.
  91.                          (LPTHREAD_START_ROUTINE)ServerProc,// Thread procedure.
  92.                          (LPVOID)&hwnd,                     // Parameter.
  93.                          (DWORD)0,                          // Start immediatly.
  94.                          (LPDWORD)&lpServerThreadID);       // Thread ID.
  95.            return (0);
  96.         case WM_DESTROY :
  97.            PostQuitMessage (0);
  98.            return (0);
  99.        }
  100.     return DefWindowProc (hwnd, message, wParam, lParam);
  101. }
  102. /*************************************************************************
  103. *
  104. *  PROCEDURE: ServerProc (HWND *hWnd)
  105. *
  106. *    A thread procedure, which creates an instance of the server side of
  107. *    the named pipe, and then blocks waiting for a client to connect.
  108. *    Once the client connects, a global array is updated with the specific
  109. *    clients information, and this procedure is called again
  110. *    to launch another waiting server thread.  After launching the new
  111. *    thread, this thread begins to loop, reading the named pipe.  When
  112. *    a message comes from its client, it uses TellAll() to broadcast
  113. *    the message to the other clients in the array.
  114. *
  115. *  CALLED BY:
  116. *
  117. *    ServerProc();
  118. *    WinMain();
  119. *
  120. *  CALLS TO:
  121. *
  122. *    TellAll();
  123. *    ServerProc().
  124. *
  125. *  COMMENTS:
  126. *
  127. *    Clients is a global array which hold information on each client
  128. *    connected to the named pipe.  This procedure recieves a buffer.
  129. *    It then steps through this global array, and for each client it
  130. *    writes the buffer.
  131. *
  132. *************************************************************************/
  133. VOID ServerProc(HWND *hWnd)
  134.  {
  135.    HANDLE hPipe;                       // Pipe handle.
  136.    CHAR   inBuf[IN_BUF_SIZE] = "";     // Input buffer for pipe.
  137.    DWORD  ServerThreadID;              // Used for CreateThread().
  138.    CHAR   errorBuf[LINE_LEN] = "";     // Used for error messages.
  139.    DWORD  bytesRead;                   // Used in ReadFile().
  140.    DWORD  retCode;                     // Used to trap return codes.
  141.    DWORD  clientIndex;                 // Index into global array, for this
  142.                                        // instances client.
  143.    DWORD  lastError;                   // Traps returns from GetLastError().
  144.    BOOL   ExitLoop = FALSE;            // Boolean Flag to exit loop.
  145.    OVERLAPPED OverLapWrt;              // Overlapped structure for writing.
  146.    HANDLE     hEventWrt;               // Event handle for overlapped write.
  147.    OVERLAPPED OverLapRd;               // Overlapped structure for reading.
  148.    HANDLE     hEventRd;                // Event handle for overlapped reads.
  149.    DWORD        bytesTransRd;          // Bytes transferred by overlapped.
  150.    PSECURITY_DESCRIPTOR    pSD;
  151.    SECURITY_ATTRIBUTES     sa;
  152.                                        // create a security NULL security
  153.                                        // descriptor, one that allows anyone
  154.                                        // to write to the pipe... WARNING
  155.                                        // entering NULL as the last attribute
  156.                                        // of the CreateNamedPipe() will
  157.                                        // indicate that you wish all
  158.                                        // clients connecting to it to have
  159.                                        // all of the same security attributes
  160.                                        // as the user that started the
  161.                                        // pipe server.
  162.    pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR,
  163.                SECURITY_DESCRIPTOR_MIN_LENGTH);
  164.    if (pSD == NULL)
  165.      {
  166.      MessageBox (*hWnd, "Error in LocalAlloc for pSD",
  167.                  "Debug: ServerProc()", MB_OK);
  168.      return;
  169.      }
  170.    if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
  171.      {
  172.      wsprintf (errorBuf, "Error: InitializeSecurityDescriptor() %d",
  173.                GetLastError());
  174.      MessageBox (*hWnd, errorBuf, "Debug: ServerProc()", MB_OK);
  175.        LocalFree((HLOCAL)pSD);
  176.        return;
  177.      }
  178.                                        // add a NULL disc. ACL to the
  179.                                        // security descriptor.
  180.    if (!SetSecurityDescriptorDacl(pSD, TRUE, (PACL) NULL, FALSE))
  181.      {
  182.      wsprintf (errorBuf, "Error: SetSecurityDescriptorDacl() %d",
  183.                 GetLastError());
  184.      MessageBox (*hWnd, errorBuf, "Debug: ServerProc()", MB_OK);
  185.      LocalFree((HLOCAL)pSD);
  186.      return;
  187.      }
  188.    sa.nLength = sizeof(sa);
  189.    sa.lpSecurityDescriptor = pSD;
  190.    sa.bInheritHandle = TRUE;
  191.                                        // Create a local named pipe with
  192.                                        // the name '\.PIPEtest'.  The
  193.                                        // '.' signifies local pipe.
  194.    hPipe = CreateNamedPipe ("\\.\PIPE\test", // Pipe name = 'test'.
  195.                PIPE_ACCESS_DUPLEX                // 2 way pipe.
  196.                | FILE_FLAG_OVERLAPPED,           // Use overlapped structure.
  197.                PIPE_WAIT                         // Wait on messages.
  198.                | PIPE_READMODE_MESSAGE           // Specify message mode pipe.
  199.                | PIPE_TYPE_MESSAGE,
  200.                MAX_PIPE_INSTANCES,               // Maximum instance limit.
  201.                OUT_BUF_SIZE,                     // Buffer sizes.
  202.                IN_BUF_SIZE,
  203.                TIME_OUT,                         // Specify time out.
  204.                &sa);                             // Security attributes.
  205.                                        // Check Errors.
  206.     if ((DWORD)hPipe == 0xFFFFFFFF)
  207.      {
  208.      retCode = GetLastError();         // Report any error, it should always succeed.
  209.      LoadString(hInst, IDS_ERRORCODE, lpBuffer, sizeof(lpBuffer));
  210.      wsprintf (errorBuf, lpBuffer, retCode);
  211.      LoadString(hInst, IDS_DEBUGTITLE, lpBuffer, sizeof(lpBuffer));
  212.      MessageBox (*hWnd, errorBuf, lpBuffer,
  213.                  MB_ICONINFORMATION | MB_OK | MB_APPLMODAL);
  214.      };
  215.                                        // Block until a client connects.
  216.    ConnectNamedPipe(hPipe, NULL);
  217.                                        // Create and init overlap for writing.
  218.    hEventWrt = CreateEvent (NULL, TRUE, FALSE, NULL);
  219.    memset (&OverLapWrt, 0, sizeof(OVERLAPPED));
  220.    OverLapWrt.hEvent = hEventWrt;
  221.                                        // Set the clientIndex, then increment
  222.                                        // the count.  Fill in the structure
  223.                                        // for this client in the array.
  224.    clientIndex = clientCount++;
  225.    clients[clientIndex].hPipe   = hPipe;
  226.    clients[clientIndex].live    = TRUE;
  227.    clients[clientIndex].overLap = OverLapWrt;
  228.    clients[clientIndex].hEvent  = hEventWrt;
  229.                                        // Create and init overlap for reading.
  230.    hEventRd = CreateEvent(NULL,TRUE,FALSE,NULL);
  231.    memset (&OverLapRd, 0, sizeof(OVERLAPPED));
  232.    OverLapRd.hEvent = hEventRd;
  233.                                        // Read from the client, the first
  234.                                        // first message should always be
  235.                                        // the clients user name.
  236.    retCode = ReadFile (hPipe, inBuf, PLEASE_READ, &bytesRead, &OverLapRd);
  237.    if (!retCode)
  238.     lastError = GetLastError();
  239.    if (lastError == ERROR_IO_PENDING)  // Wait on read if need be.
  240.      WaitForSingleObject (hEventRd, (DWORD)-1);
  241.                                        // Put client's name in the array.
  242.    strcpy (clients[clientIndex].Name, inBuf);
  243.                                        // Create a thread which will make
  244.                                        // another server instance of the
  245.                                        // named pipe.
  246.    CreateThread ((LPSECURITY_ATTRIBUTES)NULL,        // No security attributes.
  247.                  (DWORD)0,                           // Use same stack size.
  248.                  (LPTHREAD_START_ROUTINE)ServerProc, // Thread procedure.
  249.                  (LPVOID)hWnd,                       // Parameter to pass.
  250.                  (DWORD)0,                           // Run immediately.
  251.                  (LPDWORD)&ServerThreadID);          // Thread identifier.
  252.    TellAll("");                        // Forces a paint, draws a red spool
  253.                                        // and name for this client.
  254.                                        // Do loop which basically reads from
  255.                                        // this specific client, and then
  256.                                        // uses TellAll() to broadcast the
  257.                                        // message to all the connected
  258.                                        // clients.
  259.    do{
  260.                                        // Read the pipe.
  261.       retCode = ReadFile (hPipe, inBuf, PLEASE_READ, &bytesRead, &OverLapRd);
  262.                                        // Check for three kinds of errors:
  263.                                        // If Error = IO_PENDING, wait til
  264.                                        // the event handle signals success,
  265.                                        // If BROKEN_PIPE, exit the do loop.
  266.                                        // Any other error, flag it to the
  267.                                        // user and exit the do loop.
  268.       if (!retCode)
  269.         {
  270.         lastError = GetLastError();
  271.         switch (lastError)
  272.           {
  273.                                        // IO_PENDING, wait on the event.
  274.            case ERROR_IO_PENDING:
  275.              WaitForSingleObject (hEventRd, (DWORD)-1);
  276.              break;
  277.                                        // Pipe is broken, exit the loop.
  278.            case ERROR_BROKEN_PIPE:
  279.              ExitLoop = TRUE;
  280.              break;
  281.                                        // Something else is wrong, exit the
  282.                                        // the loop after telling the user.
  283.            default:
  284.              LoadString(hInst, IDS_READERROR, lpBuffer, sizeof(lpBuffer));
  285.              wsprintf (errorBuf, lpBuffer, lastError);
  286.              LoadString(hInst, IDS_DEBUGINFO, lpBuffer, sizeof(lpBuffer));
  287.              MessageBox (*hWnd, errorBuf, lpBuffer, MB_OK);
  288.              ExitLoop = TRUE;
  289.              break;
  290.           }
  291.         }
  292.       if (!ExitLoop)
  293.         {
  294.         GetOverlappedResult (hPipe, &OverLapRd, &bytesTransRd, FALSE);
  295.                                        // Use TellAll to broadcast the message.
  296.         if (bytesTransRd)
  297.           TellAll(inBuf);
  298.         else
  299.           TellAll("");
  300.         }
  301.    }while(!ExitLoop);
  302.    clients[clientIndex].live = FALSE;  // Turns spool gray.
  303.    CloseHandle (hPipe);                // Close handles.
  304.    CloseHandle (hEventRd);
  305.    CloseHandle (hEventWrt);
  306.    DisconnectNamedPipe (hPipe);        // Close pipe instance.
  307.    ExitThread(0);                      // Clean up and die.
  308.   }
  309. /*  To write the buffer (input parameter) to all of the clients listed
  310.     in the global array "clients". Clients is a global array which hold information on each client
  311.     connected to the named pipe.  This procedure recieves a buffer.
  312.     It then steps through this global array, and for each client it
  313.     writes the buffer.  */
  314. VOID TellAll( CHAR *buffer )
  315.   {
  316.     DWORD i;                           // Index through array.
  317.     DWORD bytesWritten;                // Used in WriteFile().
  318.     DWORD retCode;                     // Traps return codes.
  319.     CHAR  Buf[LINE_LEN];               // Message Buffer.
  320.     DWORD lastError;                   // Traps returns from GetLastError().
  321.     for(i=0; i < clientCount; i++)     // For all clients in the array.
  322.       {
  323.                                        // If client isn't alive, don't waste
  324.                                        // time writing to it.
  325.       if (clients[i].live)
  326.         {
  327.         retCode = WriteFile (clients[i].hPipe, buffer, strlen(buffer),
  328.                              &bytesWritten, &clients[i].overLap);
  329.                                        // Check 3 kinds of errors: IO_PENDING,
  330.                                        // NO_DATA, or other.  Wait on event
  331.                                        // handle if IO_PENDING, else, if it's
  332.                                        // anything other than NO_DATA (pipe
  333.                                        // client disconnected), flag the user.
  334.                                        // In any case, if it's not IO_PENDING,
  335.                                        // clients[i].live = FALSE, spool turns
  336.                                        // gray.
  337.         if (!retCode)
  338.           {
  339.           lastError = GetLastError();
  340.                                        // IO_PENDING, wait on event handle.
  341.           if (lastError == ERROR_IO_PENDING)
  342.             {
  343.             WaitForSingleObject (clients[i].hEvent, (DWORD)-1);
  344.             }
  345.           else
  346.             {
  347.                                        // If not NO_DATA, flag user.
  348.             if (lastError != ERROR_NO_DATA)
  349.               {
  350.               LoadString(hInst, IDS_DEBUGLAST, lpBuffer, sizeof(lpBuffer));
  351.               wsprintf (Buf, "%s = %d", buffer, GetLastError());
  352.               MessageBox(hWnd, Buf, lpBuffer, MB_OK);
  353.               }
  354.             clients[i].live = FALSE;
  355.             }
  356.           }
  357.         } //if client.live
  358.       } // for loop
  359.                                        // Paint window with new information.
  360.     InvalidateRect(hWnd, NULL, TRUE);
  361.   }
  362. /*
  363.     To draw one of four bitmaps for each client, depending upon the clients
  364.     status (alive = red spool, dead or disconnected = gray), and location in
  365.     the array.  It also draws the clients user name beside the spool.
  366.     This procedure is executed when the WM_PAINT message is trapped.  */
  367. VOID DrawBranch(HDC hDC)
  368. {
  369.                                        // Spool bitmaps.
  370.   HBITMAP hEndLive, hEndDead, hMidLive, hMidDead, hBitMap;
  371.   HDC hDCMem;
  372.   int X, Y;
  373.   BITMAP bm;
  374.   POINT ptSize, ptOrg;
  375.   DWORD index;
  376.                                        // Load bitmaps: two red (live),
  377.                                        // two dead (gray).  End = end
  378.                                        // of tree (last client to connect),
  379.                                        // mid means in the middle somewhere.
  380.        hEndLive = LoadBitmap (hInst, "EndLive");
  381.        hEndDead = LoadBitmap (hInst, "EndDead");
  382.        hMidLive = LoadBitmap (hInst, "MidLive");
  383.        hMidDead = LoadBitmap (hInst, "MidDead");
  384.                                        // For each client, determine if
  385.                                        // if alive or not, and position;
  386.                                        // then blt appropriate map and
  387.                                        // clients name.
  388.     for (index = 0; index < clientCount; index++)
  389.       {
  390.       if (index < clientCount - 1)     // ClientCount - 1 = last (end) client.
  391.        {
  392.         if(clients[index].live)        // If live = red, else = gray.
  393.          hBitMap = hMidLive;
  394.         else
  395.          hBitMap = hMidDead;
  396.        }
  397.       else
  398.        {
  399.         if(clients[index].live)        // If live = red, else = gray.
  400.          hBitMap = hEndLive;
  401.         else
  402.          hBitMap = hEndDead;
  403.        }
  404.                                        // Calculate coordinates:
  405.       X = BITMAP_X;                    // X position is constant.
  406.       Y = index * BITMAP_Y;            // Y is based on index in the array.
  407.                                        // Blt the chosen map.
  408.       hDCMem = CreateCompatibleDC(hDC);
  409.       SelectObject(hDCMem, hBitMap);
  410.       SetMapMode(hDCMem, GetMapMode(hDC));
  411.       GetObject(hBitMap, sizeof(BITMAP), &bm);
  412.       ptSize.x = bm.bmWidth;
  413.       ptSize.y = bm.bmHeight;
  414.       DPtoLP (hDC, &ptSize, 1);
  415.       ptOrg.x = 0;
  416.       ptOrg.y = 0;
  417.       DPtoLP (hDCMem, &ptOrg, 1);
  418.       BitBlt(hDC, X, Y, ptSize.x, ptSize.y,
  419.              hDCMem, ptOrg.x, ptOrg.y, SRCCOPY);
  420.       X =  NAME_X;                     // Relocate X,Y for clients name.
  421.       Y += NAME_Y;
  422.                                        // Write name next to spool.
  423.       TextOut (hDC, X, Y, clients[index].Name, strlen(clients[index].Name));
  424.       DeleteDC(hDCMem);
  425.       }
  426. }