-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathPipe.cpp
144 lines (125 loc) · 3.39 KB
/
Pipe.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
#include "stdafx.h"
#include "Pipe.h"
#include "Exception.h"
#include "Common.h"
#include <winnt.h>
#include <vector>
#define MAX_PORTION_SIZE (512 * 1024)
//////////////////////////////////////////////////////////////////////////////////////////////////
size_t Pipe::readByHandle(void *buffer, size_t len, HANDLE pipeHandle)
{
DWORD result = 0;
OVERLAPPED overlapped;
memset(&overlapped, 0, sizeof(OVERLAPPED));
overlapped.hEvent = readEvent_.getHandle();
bool success;
DWORD length = (DWORD)len;
_ASSERT(length == len);
checkPipeHandle(pipeHandle);
success = (ReadFile(pipeHandle, buffer, length, &result, &overlapped) != 0);
if (!success) {
DWORD errCode = GetLastError();
if (errCode == ERROR_IO_PENDING) {
readEvent_.waitForEvent();
DWORD cbRet = 0;
checkPipeHandle(pipeHandle);
if (GetOverlappedResult(pipeHandle, &overlapped, &cbRet, FALSE) && cbRet != 0) {
result = cbRet;
} else {
std::string errString = "the pipe's read failed after GetOverlappedResult, " + Common::getErrString();
throw IOException(errString);
}
} else {
std::string errString = "the pipe's read failed after ReadFile, " + Common::getErrString();
throw IOException(errString);
}
}
if (0 == result) {
throw IOException("Unknown pipe error");
}
return result;
}
size_t Pipe::writeByHandle(const void *buffer, size_t len, HANDLE pipeHandle)
{
DWORD result;
OVERLAPPED overlapped;
memset(&overlapped, 0, sizeof(OVERLAPPED));
overlapped.hEvent = writeEvent_.getHandle();
bool success;
checkPipeHandle(pipeHandle);
DWORD length = (DWORD)len;
_ASSERT(length == len);
success = (WriteFile(pipeHandle, buffer, length, &result, &overlapped) != 0);
if (!success) {
int errCode = GetLastError();
if (errCode == ERROR_IO_PENDING) {
writeEvent_.waitForEvent();
DWORD cbRet;
checkPipeHandle(pipeHandle);
if (GetOverlappedResult(pipeHandle, &overlapped, &cbRet, FALSE) || cbRet == 0) {
result = cbRet;
} else {
std::string errString = "the pipe's write failed after GetOverlappedResult, " + Common::getErrString();
throw IOException(errString);
}
} else {
std::string errString = "the pipe's write failed after WriteFile, " + Common::getErrString();
throw IOException(errString);
}
}
if (0 == result) {
throw IOException("Unknown pip error");
}
return result;
}
void Pipe::checkPipeHandle(HANDLE pipeHandle)
{
if (pipeHandle == INVALID_HANDLE_VALUE) {
throw IOException("Invalid pipe handle");
}
}
////////////////////////////////////////////////////////////////
NamedPipe::NamedPipe(HANDLE hPipe, bool isServer)
: pipe_(hPipe), isServer_(isServer)
{
}
NamedPipe::~NamedPipe()
{
try {
close();
} catch (...) {
}
}
void NamedPipe::close()
{
if (isServer_) {
if (DisconnectNamedPipe(pipe_) == 0) {
std::string errString = "DisconnectNamedPipe failed, " + Common::getErrString();
throw Exception(errString);
}
}
if (pipe_ != INVALID_HANDLE_VALUE) {
CloseHandle(pipe_);
pipe_ = INVALID_HANDLE_VALUE;
}
readEvent_.notify();
writeEvent_.notify();
}
size_t NamedPipe::read(void *buffer, size_t len)
{
return readByHandle(buffer, len, pipe_);
}
size_t NamedPipe::write(const void *buffer, size_t len)
{
return writeByHandle(buffer, len, pipe_);
}
HANDLE NamedPipe::getHandle() const
{
return pipe_;
}
void NamedPipe::checkPipeHandle(HANDLE pipeHandle)
{
if (pipe_ == INVALID_HANDLE_VALUE) {
throw IOException("Invalid pipe handle");
}
}