/* gcc -g -Wall -o server.exe server5.c */
#include <stdio.h>
#include <windows.h>
#include <process.h>
#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;
}