/* gcc -g -Wall -o server.exe server4.c */
#include <stdio.h>
#include <windows.h>
#include <process.h>
#define BUFSIZE 512
HANDLE objects[3];
typedef struct
{
HANDLE pipe;
HANDLE event_exit;
OVERLAPPED ol;
OVERLAPPED ol_read;
DWORD read_count;
int exit_thread;
/* in normal struct */
void *data;
int size;
} Server;
void print_last_error(const char *fct);
static __stdcall unsigned int
_read_data_cb(void *data)
{
#define READ_BUFSIZE 5
char buf[READ_BUFSIZE];
Server *svr;
DWORD ret;
DWORD nbr_bytes;
BOOL res;
svr = (Server *)data;
while (!svr->exit_thread)
{
ret = ReadFile(svr->pipe, buf, sizeof(buf), &nbr_bytes, &svr->ol_read);
if (!ret)
{
DWORD err = GetLastError();
if (err == ERROR_IO_PENDING)
{
/* Let's wait for the event to be signaled ?? */
/* Call GetOverlappedResult ?? */
}
else if (ret == ERROR_BROKEN_PIPE)
{
printf(" * broken pipe\n");
SetEvent(svr->event_exit);
}
else
{
printf(" * unexpected error %ld\n", ret);
SetEvent(svr->event_exit);
}
}
else
{
printf(" * ReadFile : %ld\n", nbr_bytes);
}
}
_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;
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;
}
/*
* 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;
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 */
}
/*
* Manual reset
* Initial state : non signaled
*/
svr->event_exit = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!svr->event_exit)
{
print_last_error("CreateEvent (event exit)");
goto close_event;
}
/*
* Manual reset
* Initial state : non signaled
*/
memset(&svr->ol_read, 0, sizeof(svr->ol_read));
svr->ol_read.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!svr->ol_read.hEvent)
{
print_last_error("CreateEvent (event exit)");
goto close_event_exit;
}
/* start reading the pipe */
objects[0] = event;
objects[1] = svr->event_exit;
objects[2] = svr->ol_read.hEvent;
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(3, 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))
{
ResetEvent(svr->ol_read.hEvent);
/* res = GetOverlappedResult(svr->pipe, &svr->ol_read, */
/* &nbr_bytes, TRUE); */
/* if (res) printf(" nbr bytes : %ld\n", nbr_bytes); */
/* else */
/* print_last_error("GetOverlappedResult"); */
}
}
beach:
server_del(svr);
return 0;
}