|
@@ -0,0 +1,319 @@
|
|
|
+#pragma once
|
|
|
+
|
|
|
+#include <windows.h>
|
|
|
+#include <stdio.h>
|
|
|
+#include <tchar.h>
|
|
|
+#include <strsafe.h>
|
|
|
+enum enum_op_type {
|
|
|
+ OP_ACCEPT,
|
|
|
+ OP_SEND,
|
|
|
+ OP_RECV,
|
|
|
+ OP_MAX,
|
|
|
+};
|
|
|
+const char *op_names[] = {
|
|
|
+ "ACCEPT",
|
|
|
+ "SEND",
|
|
|
+ "RECV"
|
|
|
+};
|
|
|
+#define PIPE_TIMEOUT 5000
|
|
|
+#define BUFSIZE 4096
|
|
|
+
|
|
|
+typedef struct
|
|
|
+{
|
|
|
+ OVERLAPPED oOverlap;
|
|
|
+ DWORD opType;
|
|
|
+ HANDLE hPipeInst;
|
|
|
+ TCHAR chRequest[BUFSIZE];
|
|
|
+ DWORD cbRead;
|
|
|
+ TCHAR chReply[BUFSIZE];
|
|
|
+ DWORD cbToWrite;
|
|
|
+} PIPEINST, *LPPIPEINST;
|
|
|
+
|
|
|
+VOID DisconnectAndClose(LPPIPEINST);
|
|
|
+BOOL CreateAndConnectInstance();
|
|
|
+BOOL ConnectToNewClient(HANDLE);
|
|
|
+VOID GetAnswerToRequest(LPPIPEINST);
|
|
|
+
|
|
|
+VOID WINAPI CompletedWriteRoutine(DWORD, DWORD, LPOVERLAPPED);
|
|
|
+VOID WINAPI CompletedReadRoutine(DWORD, DWORD, LPOVERLAPPED);
|
|
|
+
|
|
|
+// HANDLE hPipe;
|
|
|
+HANDLE hIocp;
|
|
|
+
|
|
|
+int example(VOID)
|
|
|
+{
|
|
|
+ DWORD dwErr;
|
|
|
+ BOOL fSuccess;
|
|
|
+ DWORD dwNoOfBytes = 0;
|
|
|
+ ULONG_PTR ulKey = 0;
|
|
|
+ OVERLAPPED* pov = NULL;
|
|
|
+
|
|
|
+ // Create one event object for the connect operation.
|
|
|
+ hIocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
|
|
|
+
|
|
|
+ // Call a subroutine to create one instance, and wait for
|
|
|
+ // the client to connect.
|
|
|
+
|
|
|
+ CreateAndConnectInstance();
|
|
|
+
|
|
|
+ while (1)
|
|
|
+ {
|
|
|
+ // Wait for a completion notification.
|
|
|
+ pov = NULL;
|
|
|
+ fSuccess = GetQueuedCompletionStatus(
|
|
|
+ hIocp, // Completion port handle
|
|
|
+ &dwNoOfBytes, // Bytes transferred
|
|
|
+ &ulKey,
|
|
|
+ &pov, // OVERLAPPED structure
|
|
|
+ INFINITE // Notification time-out interval
|
|
|
+ );
|
|
|
+
|
|
|
+ if (FALSE == fSuccess) {
|
|
|
+ dwErr = GetLastError();
|
|
|
+ printf("GetQueuedCompletionStatus: dwErr=%x.\n", dwErr);
|
|
|
+ }
|
|
|
+ // Get the base address of the RECEIVE_CONTEXT structure
|
|
|
+ // containing the OVERLAPPED structure received.
|
|
|
+ LPPIPEINST ppi = CONTAINING_RECORD(pov, PIPEINST, oOverlap);
|
|
|
+ DWORD opType = ppi->opType;
|
|
|
+ printf("GetQueuedCompletionStatus: opType=%s,dwNoOfBytes=%d.\n", op_names[opType], dwNoOfBytes);
|
|
|
+
|
|
|
+ if (OP_ACCEPT == opType) {
|
|
|
+ // Allocate storage for this instance.
|
|
|
+
|
|
|
+ ppi->cbToWrite = 0;
|
|
|
+ CompletedWriteRoutine(0, 0, (LPOVERLAPPED)ppi);
|
|
|
+
|
|
|
+ // Create new pipe instance for the next client.
|
|
|
+
|
|
|
+ CreateAndConnectInstance();
|
|
|
+
|
|
|
+ // The wait is satisfied by a completed read or write
|
|
|
+ // operation. This allows the system to execute the
|
|
|
+ // completion routine.
|
|
|
+ }
|
|
|
+ else if (OP_RECV == opType) {
|
|
|
+ if (!dwNoOfBytes) {
|
|
|
+ DisconnectAndClose(ppi);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ CompletedReadRoutine(0, dwNoOfBytes, (LPOVERLAPPED)ppi);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ CompletedWriteRoutine(0, dwNoOfBytes, (LPOVERLAPPED)ppi);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+// CompletedWriteRoutine(DWORD, DWORD, LPOVERLAPPED)
|
|
|
+// This routine is called as a completion routine after writing to
|
|
|
+// the pipe, or when a new client has connected to a pipe instance.
|
|
|
+// It starts another read operation.
|
|
|
+
|
|
|
+VOID WINAPI CompletedWriteRoutine(DWORD dwErr, DWORD cbWritten, LPOVERLAPPED lpOverLap)
|
|
|
+{
|
|
|
+ LPPIPEINST lpPipeInst;
|
|
|
+ BOOL fRead = FALSE;
|
|
|
+
|
|
|
+ // lpOverlap points to storage for this instance.
|
|
|
+
|
|
|
+ lpPipeInst = (LPPIPEINST)lpOverLap;
|
|
|
+
|
|
|
+ // The write operation has finished, so read the next request (if
|
|
|
+ // there is no error).
|
|
|
+ if ((dwErr == 0) && (cbWritten == lpPipeInst->cbToWrite)) {
|
|
|
+ DWORD dwRead;
|
|
|
+ lpPipeInst->opType = OP_RECV;
|
|
|
+
|
|
|
+ fRead = ReadFile(
|
|
|
+ lpPipeInst->hPipeInst,
|
|
|
+ lpPipeInst->chRequest,
|
|
|
+ BUFSIZE * sizeof(TCHAR),
|
|
|
+ &dwRead,
|
|
|
+ (LPOVERLAPPED)lpPipeInst);
|
|
|
+ //(LPOVERLAPPED_COMPLETION_ROUTINE)CompletedReadRoutine);
|
|
|
+ if (!fRead && ERROR_IO_PENDING != GetLastError()) {
|
|
|
+ printf("ReadFile: dwRead=%d,GLE=%d\n", dwRead, GetLastError());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Disconnect if an error occurred.
|
|
|
+ printf("%s: PipInst=%x,dwErr=%x,cbWritten=%d,fRead=%d.\n",
|
|
|
+ __func__, (int)lpPipeInst->hPipeInst, dwErr, cbWritten, fRead);
|
|
|
+
|
|
|
+ /*
|
|
|
+ if (!fRead) {
|
|
|
+ DisconnectAndClose(lpPipeInst);
|
|
|
+ }
|
|
|
+ */
|
|
|
+}
|
|
|
+
|
|
|
+// CompletedReadRoutine(DWORD, DWORD, LPOVERLAPPED)
|
|
|
+// This routine is called as an I/O completion routine after reading
|
|
|
+// a request from the client. It gets data and writes it to the pipe.
|
|
|
+
|
|
|
+VOID WINAPI CompletedReadRoutine(DWORD dwErr, DWORD cbBytesRead,LPOVERLAPPED lpOverLap)
|
|
|
+{
|
|
|
+ LPPIPEINST lpPipeInst;
|
|
|
+ BOOL fWrite = FALSE;
|
|
|
+
|
|
|
+ // lpOverlap points to storage for this instance.
|
|
|
+ /*
|
|
|
+ ERROR_BROKEN_PIPE
|
|
|
+ 109 (0x6D)
|
|
|
+ The pipe has been ended.
|
|
|
+ */
|
|
|
+ lpPipeInst = (LPPIPEINST)lpOverLap;
|
|
|
+ if (0x6d == dwErr) {
|
|
|
+ printf("%s: PipInst=%x, the pipe has been ended.\n",
|
|
|
+ __func__, (int)lpPipeInst->hPipeInst);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ printf("%s: PipInst=%x,dwErr=%x,cbBytesRead=%d.\n",
|
|
|
+ __func__, (int)lpPipeInst->hPipeInst, dwErr, cbBytesRead);
|
|
|
+ }
|
|
|
+
|
|
|
+ // The read operation has finished, so write a response (if no
|
|
|
+ // error occurred).
|
|
|
+
|
|
|
+ if ((dwErr == 0) && (cbBytesRead != 0))
|
|
|
+ {
|
|
|
+ DWORD dwWritten;
|
|
|
+ GetAnswerToRequest(lpPipeInst);
|
|
|
+ lpPipeInst->opType = OP_SEND;
|
|
|
+
|
|
|
+ fWrite = WriteFile(
|
|
|
+ lpPipeInst->hPipeInst,
|
|
|
+ lpPipeInst->chReply,
|
|
|
+ lpPipeInst->cbToWrite,
|
|
|
+ &dwWritten,
|
|
|
+ (LPOVERLAPPED)lpPipeInst);
|
|
|
+ // (LPOVERLAPPED_COMPLETION_ROUTINE)CompletedWriteRoutine);
|
|
|
+ if (!fWrite) {
|
|
|
+ printf("WriteFie: dwWritten=%d,GLE=%d\n", dwWritten, GetLastError());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Disconnect if an error occurred.
|
|
|
+
|
|
|
+ /*
|
|
|
+ if (!fWrite) {
|
|
|
+ DisconnectAndClose(lpPipeInst);
|
|
|
+ }
|
|
|
+ */
|
|
|
+}
|
|
|
+
|
|
|
+// DisconnectAndClose(LPPIPEINST)
|
|
|
+// This routine is called when an error occurs or the client closes
|
|
|
+// its handle to the pipe.
|
|
|
+
|
|
|
+VOID DisconnectAndClose(LPPIPEINST lpPipeInst)
|
|
|
+{
|
|
|
+ // Disconnect the pipe instance.
|
|
|
+
|
|
|
+ if (!DisconnectNamedPipe(lpPipeInst->hPipeInst))
|
|
|
+ {
|
|
|
+ printf("DisconnectNamedPipe failed with %d.\n", GetLastError());
|
|
|
+ }
|
|
|
+
|
|
|
+ // Close the handle to the pipe instance.
|
|
|
+
|
|
|
+ CloseHandle(lpPipeInst->hPipeInst);
|
|
|
+
|
|
|
+ // Release the storage for the pipe instance.
|
|
|
+
|
|
|
+ if (lpPipeInst != NULL)
|
|
|
+ GlobalFree(lpPipeInst);
|
|
|
+}
|
|
|
+
|
|
|
+// CreateAndConnectInstance(LPOVERLAPPED)
|
|
|
+// This function creates a pipe instance and connects to the client.
|
|
|
+// It returns TRUE if the connect operation is pending, and FALSE if
|
|
|
+// the connection has been completed.
|
|
|
+
|
|
|
+BOOL CreateAndConnectInstance()
|
|
|
+{
|
|
|
+ LPCWSTR lpszPipename = TEXT("\\\\.\\pipe\\mynamedpipe");
|
|
|
+
|
|
|
+ HANDLE hPipe = CreateNamedPipe(
|
|
|
+ lpszPipename, // pipe name
|
|
|
+ PIPE_ACCESS_DUPLEX | // read/write access
|
|
|
+ FILE_FLAG_OVERLAPPED, // overlapped mode
|
|
|
+ PIPE_TYPE_MESSAGE | // message-type pipe
|
|
|
+ PIPE_READMODE_MESSAGE | // message read mode
|
|
|
+ PIPE_WAIT, // blocking mode
|
|
|
+ PIPE_UNLIMITED_INSTANCES, // unlimited instances
|
|
|
+ BUFSIZE * sizeof(TCHAR), // output buffer size
|
|
|
+ BUFSIZE * sizeof(TCHAR), // input buffer size
|
|
|
+ PIPE_TIMEOUT, // client time-out
|
|
|
+ NULL); // default security attributes
|
|
|
+
|
|
|
+ printf("CreateNamedPipe, hPipe=%llx.\n", (INT64)hPipe);
|
|
|
+ if (hPipe == INVALID_HANDLE_VALUE)
|
|
|
+ {
|
|
|
+ printf("CreateNamedPipe failed with %d.\n", GetLastError());
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ HANDLE hRet = CreateIoCompletionPort(hPipe, hIocp, NULL, 0);
|
|
|
+ // Call a subroutine to connect to the new client.
|
|
|
+
|
|
|
+ return ConnectToNewClient(hPipe);
|
|
|
+}
|
|
|
+
|
|
|
+BOOL ConnectToNewClient(HANDLE hPipe)
|
|
|
+{
|
|
|
+ BOOL fConnected, fPendingIO = FALSE;
|
|
|
+
|
|
|
+ LPPIPEINST lpPipeInst = (LPPIPEINST)GlobalAlloc(GPTR, sizeof(PIPEINST));
|
|
|
+ if (lpPipeInst == NULL)
|
|
|
+ {
|
|
|
+ printf("GlobalAlloc failed (%d)\n", GetLastError());
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ ZeroMemory(&lpPipeInst->oOverlap, sizeof(OVERLAPPED));
|
|
|
+ lpPipeInst->hPipeInst = hPipe;
|
|
|
+ lpPipeInst->opType = OP_ACCEPT;
|
|
|
+
|
|
|
+ // Start an overlapped connection for this pipe instance.
|
|
|
+ fConnected = ConnectNamedPipe(hPipe, &lpPipeInst->oOverlap);
|
|
|
+
|
|
|
+ // Overlapped ConnectNamedPipe should return zero.
|
|
|
+ if (fConnected)
|
|
|
+ {
|
|
|
+ printf("ConnectNamedPipe failed with %d.\n", GetLastError());
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (GetLastError())
|
|
|
+ {
|
|
|
+ // The overlapped connection in progress.
|
|
|
+ case ERROR_IO_PENDING:
|
|
|
+ fPendingIO = TRUE;
|
|
|
+ break;
|
|
|
+
|
|
|
+ // Client is already connected, so signal an event.
|
|
|
+
|
|
|
+ case ERROR_PIPE_CONNECTED:
|
|
|
+ {
|
|
|
+ CreateAndConnectInstance();
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ // If an error occurs during the connect operation...
|
|
|
+ default:
|
|
|
+ {
|
|
|
+ printf("ConnectNamedPipe failed with %d.\n", GetLastError());
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return fPendingIO;
|
|
|
+}
|
|
|
+
|
|
|
+VOID GetAnswerToRequest(LPPIPEINST pipe)
|
|
|
+{
|
|
|
+ _tprintf(TEXT("[%llx] %s\n"), (INT64)pipe->hPipeInst, pipe->chRequest);
|
|
|
+ StringCchCopy(pipe->chReply, BUFSIZE, TEXT("Default answer from server"));
|
|
|
+ pipe->cbToWrite = (lstrlen(pipe->chReply) + 1) * sizeof(TCHAR);
|
|
|
+}
|