blob: 6f2f73db34e5f5537385438f9e1e78a2b8ad23fe [file] [log] [blame]
Roger Meierd1bf5d02012-04-11 21:38:56 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20#ifdef _WIN32
21
22#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
25#include <cstring>
26
27#include "TPipe.h"
28#include "TPipeServer.h"
29#include <boost/shared_ptr.hpp>
30#include <AccCtrl.h>
31#include <Aclapi.h>
32
33namespace apache { namespace thrift { namespace transport {
34
35using namespace std;
36using boost::shared_ptr;
37
38//---- Constructors ----
39TPipeServer::TPipeServer(string pipename, uint32_t bufsize) :
40 pipename_(pipename),
41 bufsize_(bufsize),
42 hPipe_(INVALID_HANDLE_VALUE),
43 isAnonymous(false),
44 maxconns_(TPIPE_SERVER_MAX_CONNS_DEFAULT)
45 {}
46
47TPipeServer::TPipeServer(string pipename, uint32_t bufsize, uint32_t maxconnections) :
48 pipename_(pipename),
49 bufsize_(bufsize),
50 hPipe_(INVALID_HANDLE_VALUE),
51 isAnonymous(false)
52 { //Restrict maxconns_ to 1-255
53 if(maxconnections == 0)
54 maxconns_ = 1;
55 else if (maxconnections > 255)
56 maxconns_ = 255;
57 else
58 maxconns_ = maxconnections;
59 }
60
61TPipeServer::TPipeServer(string pipename) :
62 pipename_(pipename),
63 bufsize_(1024),
64 hPipe_(INVALID_HANDLE_VALUE),
65 isAnonymous(false),
66 maxconns_(TPIPE_SERVER_MAX_CONNS_DEFAULT)
67 {}
68
69TPipeServer::TPipeServer(int bufsize) :
70 pipename_(""),
71 bufsize_(bufsize),
72 hPipe_(INVALID_HANDLE_VALUE),
73 isAnonymous(true),
74 maxconns_(1)
75 {
76 //The anonymous pipe needs to be created first so that the server can
77 //pass the handles on to the client before the serve (acceptImpl)
78 //blocking call.
79 if (!TCreateAnonPipe()) {
80 GlobalOutput.perror("TPipeServer Create(Anon)Pipe failed, GLE=", GetLastError());
81 throw TTransportException(TTransportException::NOT_OPEN, " TPipeServer Create(Anon)Pipe failed");
82 }
83}
84
85TPipeServer::TPipeServer() :
86 pipename_(""),
87 bufsize_(1024),
88 hPipe_(INVALID_HANDLE_VALUE),
89 isAnonymous(true),
90 maxconns_(1)
91{
92 if (!TCreateAnonPipe()) {
93 GlobalOutput.perror("TPipeServer Create(Anon)Pipe failed, GLE=", GetLastError());
94 throw TTransportException(TTransportException::NOT_OPEN, " TPipeServer Create(Anon)Pipe failed");
95 }
96}
97
98//---- Destructor ----
99TPipeServer::~TPipeServer() {
100 close();
101}
102
103//---------------------------------------------------------
104// Transport callbacks
105//---------------------------------------------------------
106
107shared_ptr<TTransport> TPipeServer::acceptImpl() {
108 shared_ptr<TPipe> client;
109
110 if(isAnonymous)
111 { //Anonymous Pipe
112 //This 0-byte read serves merely as a blocking call.
113 byte buf;
114 DWORD br;
115 int fSuccess = ReadFile(
116 hPipe_, // pipe handle
117 &buf, // buffer to receive reply
118 0, // size of buffer
119 &br, // number of bytes read
120 NULL); // not overlapped
121
122 if ( !fSuccess && GetLastError() != ERROR_MORE_DATA ) {
123 GlobalOutput.perror("TPipeServer unable to initiate pipe comms, GLE=", GetLastError());
124 throw TTransportException(TTransportException::NOT_OPEN, " TPipeServer unable to initiate pipe comms");
125 }
126 client.reset(new TPipe(hPipe_, hPipeW_));
127 }
128 else
129 { //Named Pipe
130 int ConnectRet;
131 while (true)
132 {
133 if (!TCreateNamedPipe()) {
134 GlobalOutput.perror("TPipeServer CreateNamedPipe failed, GLE=", GetLastError());
135 throw TTransportException(TTransportException::NOT_OPEN, " TPipeServer CreateNamedPipe failed");
136 }
137
138 // Wait for the client to connect; if it succeeds, the
139 // function returns a nonzero value. If the function returns
140 // zero, GetLastError should return ERROR_PIPE_CONNECTED.
141 ConnectRet = ConnectNamedPipe(hPipe_, NULL) ?
142 TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
143
144 if (ConnectRet == TRUE)
145 {
146 GlobalOutput.printf("Client connected.");
147 break;
148 }
149 else
150 {
151 close();
152 GlobalOutput.perror("TPipeServer ConnectNamedPipe GLE=", GetLastError());
153 throw TTransportException(TTransportException::NOT_OPEN, "TPipeServer: client connection failed");
154 }
155 }
156 client.reset(new TPipe(hPipe_));
157 }
158
159 return client;
160}
161
162void TPipeServer::interrupt() {
163 if(hPipe_ != INVALID_HANDLE_VALUE) {
164 CancelIo(hPipe_);
165 }
166}
167
168void TPipeServer::close() {
169 if(!isAnonymous)
170 {
171 if(hPipe_ != INVALID_HANDLE_VALUE) {
172 DisconnectNamedPipe(hPipe_);
173 CloseHandle(hPipe_);
174 hPipe_ = INVALID_HANDLE_VALUE;
175 }
176 }
177 else
178 {
179 try {
180 CloseHandle(hPipe_);
181 CloseHandle(hPipeW_);
182 CloseHandle(ClientAnonRead);
183 CloseHandle(ClientAnonWrite);
184 }
185 catch(...) {
186 GlobalOutput.perror("TPipeServer anon close GLE=", GetLastError());
187 }
188 }
189}
190
191
192bool TPipeServer::TCreateNamedPipe() {
193
194 //Windows - set security to allow non-elevated apps
195 //to access pipes created by elevated apps.
196 SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
197 PSID everyone_sid = NULL;
198 AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &everyone_sid);
199
200 EXPLICIT_ACCESS ea;
201 ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
202 ea.grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL;
203 ea.grfAccessMode = SET_ACCESS;
204 ea.grfInheritance = NO_INHERITANCE;
205 ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
206 ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
207 ea.Trustee.ptstrName = (LPSTR)everyone_sid;
208
209 PACL acl = NULL;
210 SetEntriesInAcl(1, &ea, NULL, &acl);
211
212 PSECURITY_DESCRIPTOR sd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,SECURITY_DESCRIPTOR_MIN_LENGTH);
213 InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION);
214 SetSecurityDescriptorDacl(sd, TRUE, acl, FALSE);
215
216 SECURITY_ATTRIBUTES sa;
217 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
218 sa.lpSecurityDescriptor = sd;
219 sa.bInheritHandle = FALSE;
220
221 // Create an instance of the named pipe
222 hPipe_ = CreateNamedPipe(
223 pipename_.c_str(), // pipe name
224 PIPE_ACCESS_DUPLEX, // read/write access
225 PIPE_TYPE_MESSAGE | // message type pipe
226 PIPE_READMODE_MESSAGE, // message-read mode
227 maxconns_, // max. instances
228 bufsize_, // output buffer size
229 bufsize_, // input buffer size
230 0, // client time-out
231 &sa); // default security attribute
232
233 return (hPipe_ != INVALID_HANDLE_VALUE);
234}
235
236bool TPipeServer::TCreateAnonPipe() {
237 SECURITY_ATTRIBUTES sa;
238 SECURITY_DESCRIPTOR sd; //security information for pipes
239
240 InitializeSecurityDescriptor(&sd,SECURITY_DESCRIPTOR_REVISION);
241 SetSecurityDescriptorDacl(&sd, true, NULL, false);
242 sa.lpSecurityDescriptor = &sd;
243 sa.lpSecurityDescriptor = NULL;
244 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
245 sa.bInheritHandle = true; //allow passing handle to child
246
247 if (!CreatePipe(&ClientAnonRead,&hPipeW_,&sa,0)) //create stdin pipe
248 {
249 GlobalOutput.perror("TPipeServer CreatePipe (anon) failed, GLE=", GetLastError());
250 return false;
251 }
252 if (!CreatePipe(&hPipe_,&ClientAnonWrite,&sa,0)) //create stdout pipe
253 {
254 GlobalOutput.perror("TPipeServer CreatePipe (anon) failed, GLE=", GetLastError());
255 CloseHandle(ClientAnonRead);
256 CloseHandle(hPipeW_);
257 return false;
258 }
259
260 return true;
261}
262
263
264//---------------------------------------------------------
265// Accessors
266//---------------------------------------------------------
267
268string TPipeServer::getPipename() {
269 return pipename_;
270}
271
272void TPipeServer::setPipename(std::string pipename) {
273 pipename_ = pipename;
274}
275
276int TPipeServer::getBufferSize() {
277 return bufsize_;
278}
279
280void TPipeServer::setBufferSize(int bufsize) {
281 bufsize_ = bufsize;
282}
283
284HANDLE TPipeServer::getPipeHandle() {
285 return hPipe_;
286}
287
288HANDLE TPipeServer::getWrtPipeHandle()
289{
290 return hPipeW_;
291}
292
293HANDLE TPipeServer::getClientRdPipeHandle()
294{
295 return ClientAnonRead;
296}
297
298HANDLE TPipeServer::getClientWrtPipeHandle()
299{
300 return ClientAnonWrite;
301}
302
303bool TPipeServer::getAnonymous() {
304 return isAnonymous;
305}
306
307void TPipeServer::setAnonymous(bool anon) {
308 isAnonymous = anon;
309}
310
311}}} // apache::thrift::transport
312
313#endif //_WIN32