/******************************************************************************/ * This is a part of the Microsoft Source Code Samples. * Copyright (C) 1993-1997 Microsoft Corporation. * All rights reserved. * This source code is only intended as a supplement to * Microsoft Development Tools and/or WinHelp documentation. * See these sources for detailed information regarding the * Microsoft samples programs. /******************************************************************************/ #include <stdio.h> #include <windows.h> #include <stdlib.h> #include <process.h> /* Error checking macro. If bSuccess != TRUE, print error info */ #define PERR(bSuccess, szApi) {if (!(bSuccess)) printf("%s: Error %d from %s / on line %d/n", __FILE__, GetLastError(), szApi, __LINE__);} #define DEFNAME ".//pipe//nmpipe" /* Default pipe name */ /* Define OVERLAPPED_IO to TRUE to use Overlapped IO. Otherwise define as FALSE */ //#define OVERLAPPED_IO TRUE #define OVERLAPPED_IO FALSE /* structure to pass into the writer thread */ typedef struct _WRITER_PARAMS { HANDLE hPipe; /* pipe write handle */ char *szData; /* data to repeatedly write */ int iDataSize; /* size of buffer pointed to by szData */ } WRITER_PARAMS; /* * BOOL pipeCheck(HANDLE h) * PARAMETERS: HANDLE hPipe: pipe handle to close if an error condition exists * DESCRIPTION: if GetLastError() returns a common error generated by a * broken pipe, close the pipe handle. Call this right after a * pipe operation. * RETURNS: FALSE if the pipe is broken, TRUE if not. */ BOOL pipeCheck(HANDLE hPipe) { DWORD dwLastError = GetLastError(); if (dwLastError == ERROR_BROKEN_PIPE || dwLastError == ERROR_NO_DATA) { puts("/n* pipe broken, closing..."); CloseHandle(hPipe); return(FALSE); } if (dwLastError == ERROR_INVALID_HANDLE) /* is handle already closed? */ return(FALSE); return(TRUE); } /* pipeCheck() */ /* * void reader(HANDLE hPipe) * PARAMETERS: HANDLE hPipe: pipe handle to read from * DESCRIPTION: read from the handle and dump data to the console. * RETURNS: none */ void reader(HANDLE hPipe) { char buf[64]; DWORD dwRead; BOOL bSuccess; OVERLAPPED ol; if (OVERLAPPED_IO) /* if overlapped, prepare OVERLAPPED structure */ { memset(&ol, 0, sizeof(ol)); ol.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); PERR(ol.hEvent, "CreateEvent"); } while (1) { bSuccess = ReadFile(hPipe, buf, sizeof(buf), &dwRead, OVERLAPPED_IO ? &ol : NULL); if (!bSuccess && GetLastError() == ERROR_IO_PENDING) bSuccess = GetOverlappedResult(hPipe, &ol, &dwRead, TRUE); /* If ReadFile or GetOverlappedResult fails, check pipe. If pipe is broken, fall out of loop */ if (!bSuccess && !pipeCheck(hPipe)) break; /* else check for any other kinds of errors that may have occurred */ PERR(bSuccess, "ReadFile"); printf("%.*s", dwRead, buf); /* print only number of chars read */ } /* while */ CloseHandle(ol.hEvent); _endthread(); } /* reader() */ /* ** void writer(WRITER_PARAMS *writer_params) * PARAMETERS: WRITER_PARAMS *writer_params: misc info needed for writing to * the pipe * DESCRIPTION: write data from WRITER_PARAMS to the pipe * RETURNS: none */ void writer(WRITER_PARAMS *writer_params) { DWORD dwWritten; BOOL bSuccess; OVERLAPPED ol; if (OVERLAPPED_IO) { memset(&ol, 0, sizeof(ol)); ol.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); PERR(ol.hEvent, "CreateEvent"); } while(1) { bSuccess = WriteFile(writer_params->hPipe, writer_params->szData, writer_params->iDataSize, &dwWritten, OVERLAPPED_IO ? &ol : NULL); if (!bSuccess && GetLastError() == ERROR_IO_PENDING) bSuccess = GetOverlappedResult(writer_params->hPipe, &ol, &dwWritten, TRUE); /* If ReadFile or GetOverlappedResult fails, check pipe. If pipe is broken, fall out of loop */ if (!bSuccess && !pipeCheck(writer_params->hPipe)) break; /* else check for any other kinds of errors that may have occurred */ PERR(bSuccess, "WriteFile"); } /* while */ free(writer_params); CloseHandle(ol.hEvent); _endthread(); } /* writer() */ /* ** main() * DESCRIPTION: Connect pipe instances to clients. Start a reader thread for * each client. If OVERLAPPED_IO is defined, also start a * writer thread for full duplex pipe I/O testing. If this is * a client, connect to the server pipe and start a writer * thread. If OVERLAPPED_IO, also start a reader thread. */ void main(int argc, char *argv[]) { HANDLE hPipe; BOOL bSuccess; BOOL bNotConnected; char *szPname; WRITER_PARAMS *writer_params; DWORD dwClients; SECURITY_ATTRIBUTES saPipe; OVERLAPPED ol; DWORD dwRead; if (argc < 3) { puts("nmpipe [/s|/c] <string> <pipename>"); puts("'/s' to start as server, '/c' to start as client"); puts("<string>: string to write to the pipe"); puts("<pipename>: full UNC name of pipe (optional)"); puts("example: nmpipe /s /"hello from server /" .//pipe//pipetst"); return; } szPname = (argc > 3) ? argv[3] : DEFNAME; if (tolower(argv[1][1]) == 's') { if (OVERLAPPED_IO) { memset(&ol, 0, sizeof(ol)); ol.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); PERR(ol.hEvent, "CreateEvent"); } SetConsoleTitle("SERVER: nmpipe sample"); /* set up a NULL DACL in our pipe security descriptor to allow anyone to connect to the pipe server */ saPipe.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR) malloc(SECURITY_DESCRIPTOR_MIN_LENGTH); InitializeSecurityDescriptor(saPipe.lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION); SetSecurityDescriptorDacl(saPipe.lpSecurityDescriptor, TRUE, (PACL) NULL, FALSE); saPipe.nLength = sizeof(saPipe); saPipe.bInheritHandle = TRUE; while(1) { /* Create a named pipe: duplex, type byte, readmode byte, unlimited instances, default timeout of 60s */ hPipe = CreateNamedPipe(szPname, PIPE_ACCESS_DUPLEX | (OVERLAPPED_IO ? FILE_FLAG_OVERLAPPED : 0), PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 0, 0, 60000, &saPipe); PERR(hPipe != INVALID_HANDLE_VALUE, "CreateNamedPipe"); puts("/n* pipe created, waiting for connection..."); bSuccess = ConnectNamedPipe(hPipe, OVERLAPPED_IO ? &ol : NULL); if (!bSuccess && GetLastError() == ERROR_IO_PENDING) bSuccess = GetOverlappedResult(hPipe, &ol, &dwRead, TRUE); /* check return from either ConnectNamedPipe or GetOverlappedResult. If a client managed to connect between the CreateNamedPipe and ConnectNamedPipe calls, ERROR_PIPE_CONNECTED will result */ if (!bSuccess && GetLastError() != ERROR_PIPE_CONNECTED) { /* something went wrong, report error, close instance and try again */ PERR(bSuccess, "ConnectNamedPipe"); CloseHandle(hPipe); continue; } /* find out how many pipe instances there currently are */ bSuccess = GetNamedPipeHandleState(hPipe, NULL, &dwClients, NULL, NULL, NULL, 0); PERR(bSuccess, "GetNamedPipeHandleState"); printf("/n* %d clients connected", dwClients); _beginthread(reader, 0, hPipe); writer_params = malloc(sizeof(WRITER_PARAMS)); writer_params->hPipe = hPipe; writer_params->szData = argv[2]; writer_params->iDataSize = strlen(argv[2]); /* WARNING! reading and writing at the same time to a non-overlapped pipe is a no-no! If not overlapped, server only reads and client only writes */ if (OVERLAPPED_IO) _beginthread(writer, 0, writer_params); } /* while */ CloseHandle(ol.hEvent); CloseHandle(hPipe); } else /* no '/s', assume it's a client */ { char szTemp[64]; sprintf(szTemp, "Client %s", argv[2]); SetConsoleTitle(szTemp); bNotConnected = TRUE; while (bNotConnected) { /* attempt to connect to pipe instance */ hPipe = CreateFile(szPname, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, OVERLAPPED_IO ? FILE_FLAG_OVERLAPPED : 0, NULL); if (GetLastError() == ERROR_PIPE_BUSY) { puts("Pipe busy, waiting for a pipe instance..."); bSuccess = WaitNamedPipe(szPname, NMPWAIT_USE_DEFAULT_WAIT); PERR(bSuccess, "WaitNamedPipe"); } else { PERR(hPipe != INVALID_HANDLE_VALUE, "CreateFile"); bNotConnected = (hPipe == INVALID_HANDLE_VALUE); } } /* while */ puts("Connected to pipe..."); if (OVERLAPPED_IO) /* if overlapped, start reader thread */ _beginthread(reader, 0, hPipe); writer_params = malloc(sizeof(WRITER_PARAMS)); writer_params->hPipe = hPipe; writer_params->szData = argv[2]; writer_params->iDataSize = strlen(argv[2]); writer(writer_params); } /* else */ free(saPipe.lpSecurityDescriptor); CloseHandle(hPipe); CloseHandle(ol.hEvent); return; }