/* gcc -g -Wall -o server.exe server5.c */ #include #include #include #define BUFSIZE 512 HANDLE objects[2]; typedef struct { HANDLE pipe; HANDLE event_exit; OVERLAPPED ol; OVERLAPPED ol_read; DWORD read_count; int exit_thread; HANDLE iocp_read; /* in normal struct */ void *data; int size; } Server; void print_last_error(const char *fct); static void _svr_data_append(Server *svr, void *data, size_t size) { if (!svr->data) { svr->data = malloc(size); if (!svr->data) return; memcpy(svr->data, data, size); svr->size = size; } else { void *tmp; tmp = realloc(svr->data, svr->size + size); if (tmp) { svr->data = tmp; memcpy(svr->data + svr->size, data, size); svr->size += size; } } { char *buf; buf = malloc(svr->size + 1); memcpy(buf, svr->data, svr->size); buf[svr->size] = 0; printf("msg (%d -> %02d) : %s\n", (int)size, (int)svr->size, buf); free(buf); } } static unsigned int __stdcall _read_data_cb(void *data) { #define READ_BUFSIZE 5 char buf[READ_BUFSIZE]; Server *svr; DWORD nbr_bytes = 0; BOOL res; BOOL pending = FALSE; ULONG_PTR key; LPOVERLAPPED lpol; svr = (Server *)data; while (!svr->exit_thread) { res = ReadFile(svr->pipe, buf, sizeof(buf), &nbr_bytes, &svr->ol_read); if (res) { printf("ReadFile 1\n"); _svr_data_append(svr, buf, nbr_bytes); do { res = ReadFile(svr->pipe, buf, sizeof(buf), &nbr_bytes, &svr->ol_read); if (res) { printf("ReadFile 2\n"); _svr_data_append(svr, buf, nbr_bytes); } else { DWORD err = GetLastError(); if (err == ERROR_IO_PENDING) { printf("ReadFile2: ERROR_IO_PENDING\n"); pending = TRUE; } else if (err == ERROR_SUCCESS) { printf(" * success\n"); continue; } else if (err == ERROR_BROKEN_PIPE) { printf(" * broken pipe\n"); SetEvent(svr->event_exit); } else { printf(" * unexpected error %ld\n", err); SetEvent(svr->event_exit); } break; } } while (1); } else { DWORD err = GetLastError(); if (err == ERROR_IO_PENDING) { printf("ReadFile1: ERROR_IO_PENDING\n"); pending = TRUE; } else if (err == ERROR_SUCCESS) { printf(" * success\n"); continue; } else if (err == ERROR_BROKEN_PIPE) { printf(" * broken pipe\n"); SetEvent(svr->event_exit); } else { printf(" * unexpected error %ld\n", err); SetEvent(svr->event_exit); } } if (pending) { res = GetQueuedCompletionStatus(svr->iocp_read, &nbr_bytes, &key, &lpol, INFINITE); printf("GQCIOS %d %d %p\n", (int)nbr_bytes, (int)key, lpol); if (res && lpol) { res = ReadFile(svr->pipe, buf, sizeof(buf), &nbr_bytes, &svr->ol_read); if (res) { pending = FALSE; printf("ReadFile 3\n"); _svr_data_append(svr, buf, nbr_bytes); } else { DWORD err = GetLastError(); if (err == ERROR_IO_PENDING) { printf("ReadFile3: ERROR_IO_PENDING\n"); } } } else { DWORD err = GetLastError(); print_last_error("GetQueuedCompletionStatus"); if (err == ERROR_IO_PENDING) { pending = TRUE; } } } } printf("ending thread...\n"); _endthreadex(0); return 0; } void print_last_error(const char *fct) { char *buf; DWORD dw = GetLastError(); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buf, 0, NULL ); // Display the error message and exit the process printf("%s failed with error %ld: %s\n", fct, dw, buf); LocalFree(buf); } Server * server_new(const char *name) { char buf[256]; Server *svr; HANDLE event; BOOL res; HANDLE iocp; ULONG_PTR key = 0xff; if (!name) return NULL; svr = (Server *)calloc(1,sizeof(Server)); if (!svr) return NULL; snprintf(buf, sizeof(buf), "\\\\.\\pipe\\%s", name); /* * Asynchronuous * block mode */ svr->pipe = CreateNamedPipe(buf, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 512, 512, 5000, NULL); if (!svr->pipe) { print_last_error("CreateNamedPipe"); goto free_svr; } /* * ConnectNamedPipe() event * Manual reset * Initial state : non signaled */ event = CreateEvent(NULL, TRUE, FALSE, NULL); if (!event) { print_last_error("CreateEvent"); goto close_pipe; } memset(&svr->ol, 0, sizeof(svr->ol)); svr->ol.hEvent = event; objects[0] = svr->ol.hEvent; res = ConnectNamedPipe(svr->pipe, &svr->ol); if (res) { print_last_error("ConnectNamedPipe"); goto close_event; } else { DWORD err = GetLastError(); if (err == ERROR_PIPE_CONNECTED) { SetEvent(svr->ol.hEvent); printf("client connected\n"); } else if (err != ERROR_IO_PENDING) { print_last_error("ConnectNamedPipe"); goto close_event; } /* else, we have ERROR_IO_PENDING, so a connection link is pending */ } /* * Exit event * Manual reset * Initial state : non signaled */ event = CreateEvent(NULL, TRUE, FALSE, NULL); if (!event) { print_last_error("CreateEvent (event exit)"); goto close_event; } svr->event_exit = event; objects[1] = svr->event_exit; /* * ReadFile() event * Manual reset * Initial state : non signaled */ event = CreateEvent(NULL, TRUE, FALSE, NULL); if (!event) { print_last_error("CreateEvent (event exit)"); goto close_event_exit; } memset(&svr->ol_read, 0, sizeof(svr->ol_read)); svr->ol_read.hEvent = event; iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); if (!iocp) { print_last_error("CreateIoCompletionPort"); goto close_event_exit; } svr->iocp_read = CreateIoCompletionPort(svr->pipe, iocp, key, 1); if (!svr->iocp_read) { print_last_error("CreateIoCompletionPort"); goto close_event_exit; } return svr; close_event_exit: CloseHandle(svr->event_exit); close_event: CloseHandle(event); close_pipe: CloseHandle(svr->pipe); free_svr: free(svr); return NULL; } void server_del(Server *svr) { if (!svr) return; CloseHandle(svr->event_exit); if (!FlushFileBuffers(svr->pipe)) { print_last_error("FlushFileBuffers"); } if (!DisconnectNamedPipe(svr->pipe)) { print_last_error("DisconnectNamedPipe"); } CloseHandle(svr->ol.hEvent); CloseHandle(svr->pipe); free(svr); } int main() { Server *svr; DWORD ret; DWORD nbr_bytes; BOOL res; svr = server_new("toto"); if (!svr) return -1; printf("waiting for client...\n"); while (1) { ret = WaitForMultipleObjects(2, objects, FALSE, INFINITE); if (ret == WAIT_FAILED) { print_last_error("WaitForMultipleObjects"); goto beach; } printf("WaitForMultipleObjects : %ld\n", ret); if (ret == WAIT_OBJECT_0) { ResetEvent(svr->ol.hEvent); res = GetOverlappedResult(svr->pipe, &svr->ol, &nbr_bytes, FALSE); if (!res) { print_last_error("GetOverlappedResult"); if (!DisconnectNamedPipe(svr->pipe)) { print_last_error("DisconnectNamedPipe"); goto beach; } res = ConnectNamedPipe(svr->pipe, &svr->ol); if (res) { print_last_error("ConnectNamedPipe"); goto beach; } else { DWORD err = GetLastError(); if (err == ERROR_PIPE_CONNECTED) { SetEvent(svr->ol.hEvent); } else if (err != ERROR_IO_PENDING) { print_last_error("ConnectNamedPipe"); goto beach; } /* else, we have ERROR_IO_PENDING, so a connection link is pending */ } } else { printf("client connected (%d)\n", res); /* read pipe */ _beginthreadex(NULL, 0, _read_data_cb, svr, 0, NULL); } } if (ret == (WAIT_OBJECT_0 + 1)) { printf("client connection closed\n"); svr->exit_thread = 1; goto beach; } if (ret == (WAIT_OBJECT_0 + 2)) { } } beach: server_del(svr); return 0; }