-
Notifications
You must be signed in to change notification settings - Fork 574
/
Copy pathPipeChannel.cpp
125 lines (109 loc) · 3.22 KB
/
PipeChannel.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
#include "stdafx.h"
#include <PipeChannel.h>
using namespace weasel;
using namespace std;
using namespace boost;
#define _ThrowLastError throw ::GetLastError()
#define _ThrowCode(__c) throw __c
#define _ThrowIfNot(__c) \
{ \
DWORD err; \
if ((err = ::GetLastError()) != __c) \
throw err; \
}
PipeChannelBase::PipeChannelBase(std::wstring&& pn_cmd,
size_t bs = 4 * 1024,
SECURITY_ATTRIBUTES* s = NULL)
: pname(pn_cmd),
write_stream(nullptr),
buff_size(bs),
buffer(std::make_unique<char[]>(bs)),
hpipe(INVALID_HANDLE_VALUE),
has_body(false),
sa(s) {};
PipeChannelBase::PipeChannelBase(PipeChannelBase&& r)
: write_stream(std::move(r.write_stream)),
pname(std::move(r.pname)),
buff_size(r.buff_size),
buffer(std::move(r.buffer)),
hpipe(r.hpipe),
has_body(r.has_body),
sa(r.sa) {};
PipeChannelBase::~PipeChannelBase() {
_FinalizePipe(hpipe);
}
bool PipeChannelBase::_Ensure() {
try {
if (_Invalid(hpipe)) {
hpipe = _Connect(pname.c_str());
return !_Invalid(hpipe);
}
} catch (...) {
return false;
}
return true;
}
HANDLE PipeChannelBase::_Connect(const wchar_t* name) {
HANDLE pipe = INVALID_HANDLE_VALUE;
while (_Invalid(pipe = _TryConnect()))
::WaitNamedPipe(name, 500);
DWORD mode = PIPE_READMODE_MESSAGE;
if (!SetNamedPipeHandleState(pipe, &mode, NULL, NULL)) {
_ThrowLastError;
}
return pipe;
}
void PipeChannelBase::_Reconnect() {
_FinalizePipe(hpipe);
_Ensure();
}
HANDLE PipeChannelBase::_TryConnect() {
auto pipe = ::CreateFile(pname.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, 0, NULL);
if (!_Invalid(pipe)) {
// connected to the pipe
return pipe;
}
// being busy is not really an error since we just need to wait.
_ThrowIfNot(ERROR_PIPE_BUSY);
// All pipe instances are busy
return INVALID_HANDLE_VALUE;
}
size_t PipeChannelBase::_WritePipe(HANDLE pipe, size_t s, char* b) {
DWORD lwritten;
if (!::WriteFile(pipe, b, s, &lwritten, NULL) || lwritten <= 0) {
_ThrowLastError;
}
::FlushFileBuffers(pipe);
return lwritten;
}
void PipeChannelBase::_FinalizePipe(HANDLE& p) {
if (!_Invalid(p)) {
DisconnectNamedPipe(p);
CloseHandle(p);
}
p = INVALID_HANDLE_VALUE;
}
void PipeChannelBase::_Receive(HANDLE pipe, LPVOID msg, size_t rec_len) {
DWORD lread;
BOOL success = ::ReadFile(pipe, msg, rec_len, &lread, NULL);
if (!success) {
_ThrowIfNot(ERROR_MORE_DATA);
memset(buffer.get(), 0, buff_size);
success = ::ReadFile(pipe, buffer.get(), buff_size, &lread, NULL);
if (!success) {
_ThrowLastError;
}
}
has_body = false;
}
HANDLE PipeChannelBase::_ConnectServerPipe(std::wstring& pn) {
HANDLE pipe =
CreateNamedPipe(pn.c_str(), PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, buff_size, buff_size, 0, sa);
if (pipe == INVALID_HANDLE_VALUE || !::ConnectNamedPipe(pipe, NULL)) {
_ThrowLastError;
}
return pipe;
}