-
Notifications
You must be signed in to change notification settings - Fork 18
/
WinNamedPipe.cpp
197 lines (177 loc) · 4.74 KB
/
WinNamedPipe.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
#include "WinNamedPipe.h"
#include <sstream>
#ifdef _WIN32
#define THROW_LAST_ERROR(e) \
{ \
int error=GetLastError(); \
std::stringstream err; \
err<<e<<", GLE="<<error; \
throw std::runtime_error(err.str().data()); \
err.clear(); \
}
WinNamedPipe::WinNamedPipe(HANDLE pipe):_hPipe(pipe),_server_with_client(true)
{
_server=false;
}
WinNamedPipe::WinNamedPipe(const std::string& name, bool server) : _hPipe(NULL),_server_with_client(false),INamedPipe("\\\\.\\pipe\\",name,server)
{
}
void WinNamedPipe::open()
{
_hPipe = CreateNamedPipe(
(LPSTR)_name.data(), // pipe name
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access
PIPE_TYPE_BYTE |
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
BUFFER_PIPE_SIZE, // output buffer size
BUFFER_PIPE_SIZE, // input buffer size
0, // client time-out
NULL); // default security attribute
if (_hPipe == INVALID_HANDLE_VALUE)
{
THROW_LAST_ERROR("CreateNamedPipe failed");
}
}
void WinNamedPipe::connect()
{
for(;;)
{
WaitNamedPipe((LPSTR)_name.data(), NMPWAIT_WAIT_FOREVER);
_hPipe = CreateFile(
(LPSTR)_name.data(), // pipe name
GENERIC_READ | // read and write access
GENERIC_WRITE,
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING, // opens existing pipe
0, // default attributes
NULL); // no template file
// Break if the pipe handle is valid or error!=232
if (_hPipe != INVALID_HANDLE_VALUE||GetLastError() != ERROR_PIPE_BUSY)
break;
}
if (_hPipe == INVALID_HANDLE_VALUE)
THROW_LAST_ERROR("Could not open pipe");
// The pipe connected; change to message-read mode.
DWORD dwMode = PIPE_TYPE_BYTE;
BOOL fSuccess = SetNamedPipeHandleState(
_hPipe, // pipe handle
&dwMode, // new pipe mode
NULL, // don't set maximum bytes
NULL); // don't set maximum time
if ( ! fSuccess)
{
THROW_LAST_ERROR("SetNamedPipeHandleState failed");
}
}
WinNamedPipe* WinNamedPipe::WaitForConnection()
{
if(_server)
{
DWORD error;
if (ConnectNamedPipe(_hPipe, NULL)||(error=GetLastError())==ERROR_PIPE_CONNECTED)
{
HANDLE client=_hPipe;
open();
return new WinNamedPipe(client);
}
else
{
THROW_LAST_ERROR("WaitForConnection failed");
}
}
else
{
throw std::runtime_error("WaitForConnection is not supported on server pipe\n");
}
}
void WinNamedPipe::Close()
{
if(_server||_server_with_client)
{
DisconnectNamedPipe(_hPipe);
CloseHandle(_hPipe); //May throw an exception if a debugger is attached to the process!
_hPipe=NULL;
}
}
void WinNamedPipe::internalReadBytes(void* buf,size_t size)
{
DWORD cbBytesRead = 0;
BOOL fSuccess = FALSE;
// Read from the pipe.
fSuccess = ReadFile(
_hPipe, // handle to pipe
buf, // buffer to receive data
size, // size of buffer
&cbBytesRead, // number of bytes read
NULL); // not overlapped I/O
if (!fSuccess || cbBytesRead == 0 ||cbBytesRead!=size)
{
if (GetLastError() == ERROR_BROKEN_PIPE)
{
THROW_LAST_ERROR("pipe disconnected");
}
else
{
THROW_LAST_ERROR("read failed");
}
}
}
void WinNamedPipe::internalFlush()
{
FlushFileBuffers(_hPipe);
}
void WinNamedPipe::internalWriteBytes(const void* buf,size_t size)
{
DWORD cbWritten;
BOOL fSuccess = FALSE;
fSuccess = WriteFile(
_hPipe, // handle to pipe
buf, // buffer to write from
size, // number of bytes to write
&cbWritten, // number of bytes written
NULL); // not overlapped I/O
if (!fSuccess || size != cbWritten)
{
THROW_LAST_ERROR("WriteFile failed");
}
}
WinNamedPipe::~WinNamedPipe(void)
{
Close();
}
WinNamedPipe* WinNamedPipe::WaitForConnection(unsigned int timeout)
{
if(_server)
{
OVERLAPPED lpOverlapped = {0};
lpOverlapped.hEvent = CreateEvent(0,1,1,0);
if(ConnectNamedPipe(_hPipe, &lpOverlapped)==0)
{
if(GetLastError()==ERROR_PIPE_CONNECTED)
if (!SetEvent(lpOverlapped.hEvent))
THROW_LAST_ERROR("AsyncWaitForConnection failed");
int result = WaitForSingleObject(lpOverlapped.hEvent,timeout);
if (WAIT_OBJECT_0 == result)
{
HANDLE client=_hPipe;
open();
return new WinNamedPipe(client);
}
else
{
return NULL;
}
}
else
{
THROW_LAST_ERROR("AsyncWaitForConnection failed");
}
}
else
{
throw std::runtime_error("WaitForConnection is not supported on client pipe\n");
}
}
#endif