blob: 6f2f73db34e5f5537385438f9e1e78a2b8ad23fe [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifdef _WIN32
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <cstring>
#include "TPipe.h"
#include "TPipeServer.h"
#include <boost/shared_ptr.hpp>
#include <AccCtrl.h>
#include <Aclapi.h>
namespace apache { namespace thrift { namespace transport {
using namespace std;
using boost::shared_ptr;
//---- Constructors ----
TPipeServer::TPipeServer(string pipename, uint32_t bufsize) :
pipename_(pipename),
bufsize_(bufsize),
hPipe_(INVALID_HANDLE_VALUE),
isAnonymous(false),
maxconns_(TPIPE_SERVER_MAX_CONNS_DEFAULT)
{}
TPipeServer::TPipeServer(string pipename, uint32_t bufsize, uint32_t maxconnections) :
pipename_(pipename),
bufsize_(bufsize),
hPipe_(INVALID_HANDLE_VALUE),
isAnonymous(false)
{ //Restrict maxconns_ to 1-255
if(maxconnections == 0)
maxconns_ = 1;
else if (maxconnections > 255)
maxconns_ = 255;
else
maxconns_ = maxconnections;
}
TPipeServer::TPipeServer(string pipename) :
pipename_(pipename),
bufsize_(1024),
hPipe_(INVALID_HANDLE_VALUE),
isAnonymous(false),
maxconns_(TPIPE_SERVER_MAX_CONNS_DEFAULT)
{}
TPipeServer::TPipeServer(int bufsize) :
pipename_(""),
bufsize_(bufsize),
hPipe_(INVALID_HANDLE_VALUE),
isAnonymous(true),
maxconns_(1)
{
//The anonymous pipe needs to be created first so that the server can
//pass the handles on to the client before the serve (acceptImpl)
//blocking call.
if (!TCreateAnonPipe()) {
GlobalOutput.perror("TPipeServer Create(Anon)Pipe failed, GLE=", GetLastError());
throw TTransportException(TTransportException::NOT_OPEN, " TPipeServer Create(Anon)Pipe failed");
}
}
TPipeServer::TPipeServer() :
pipename_(""),
bufsize_(1024),
hPipe_(INVALID_HANDLE_VALUE),
isAnonymous(true),
maxconns_(1)
{
if (!TCreateAnonPipe()) {
GlobalOutput.perror("TPipeServer Create(Anon)Pipe failed, GLE=", GetLastError());
throw TTransportException(TTransportException::NOT_OPEN, " TPipeServer Create(Anon)Pipe failed");
}
}
//---- Destructor ----
TPipeServer::~TPipeServer() {
close();
}
//---------------------------------------------------------
// Transport callbacks
//---------------------------------------------------------
shared_ptr<TTransport> TPipeServer::acceptImpl() {
shared_ptr<TPipe> client;
if(isAnonymous)
{ //Anonymous Pipe
//This 0-byte read serves merely as a blocking call.
byte buf;
DWORD br;
int fSuccess = ReadFile(
hPipe_, // pipe handle
&buf, // buffer to receive reply
0, // size of buffer
&br, // number of bytes read
NULL); // not overlapped
if ( !fSuccess && GetLastError() != ERROR_MORE_DATA ) {
GlobalOutput.perror("TPipeServer unable to initiate pipe comms, GLE=", GetLastError());
throw TTransportException(TTransportException::NOT_OPEN, " TPipeServer unable to initiate pipe comms");
}
client.reset(new TPipe(hPipe_, hPipeW_));
}
else
{ //Named Pipe
int ConnectRet;
while (true)
{
if (!TCreateNamedPipe()) {
GlobalOutput.perror("TPipeServer CreateNamedPipe failed, GLE=", GetLastError());
throw TTransportException(TTransportException::NOT_OPEN, " TPipeServer CreateNamedPipe failed");
}
// Wait for the client to connect; if it succeeds, the
// function returns a nonzero value. If the function returns
// zero, GetLastError should return ERROR_PIPE_CONNECTED.
ConnectRet = ConnectNamedPipe(hPipe_, NULL) ?
TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
if (ConnectRet == TRUE)
{
GlobalOutput.printf("Client connected.");
break;
}
else
{
close();
GlobalOutput.perror("TPipeServer ConnectNamedPipe GLE=", GetLastError());
throw TTransportException(TTransportException::NOT_OPEN, "TPipeServer: client connection failed");
}
}
client.reset(new TPipe(hPipe_));
}
return client;
}
void TPipeServer::interrupt() {
if(hPipe_ != INVALID_HANDLE_VALUE) {
CancelIo(hPipe_);
}
}
void TPipeServer::close() {
if(!isAnonymous)
{
if(hPipe_ != INVALID_HANDLE_VALUE) {
DisconnectNamedPipe(hPipe_);
CloseHandle(hPipe_);
hPipe_ = INVALID_HANDLE_VALUE;
}
}
else
{
try {
CloseHandle(hPipe_);
CloseHandle(hPipeW_);
CloseHandle(ClientAnonRead);
CloseHandle(ClientAnonWrite);
}
catch(...) {
GlobalOutput.perror("TPipeServer anon close GLE=", GetLastError());
}
}
}
bool TPipeServer::TCreateNamedPipe() {
//Windows - set security to allow non-elevated apps
//to access pipes created by elevated apps.
SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
PSID everyone_sid = NULL;
AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &everyone_sid);
EXPLICIT_ACCESS ea;
ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
ea.grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL;
ea.grfAccessMode = SET_ACCESS;
ea.grfInheritance = NO_INHERITANCE;
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
ea.Trustee.ptstrName = (LPSTR)everyone_sid;
PACL acl = NULL;
SetEntriesInAcl(1, &ea, NULL, &acl);
PSECURITY_DESCRIPTOR sd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,SECURITY_DESCRIPTOR_MIN_LENGTH);
InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(sd, TRUE, acl, FALSE);
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = sd;
sa.bInheritHandle = FALSE;
// Create an instance of the named pipe
hPipe_ = CreateNamedPipe(
pipename_.c_str(), // pipe name
PIPE_ACCESS_DUPLEX, // read/write access
PIPE_TYPE_MESSAGE | // message type pipe
PIPE_READMODE_MESSAGE, // message-read mode
maxconns_, // max. instances
bufsize_, // output buffer size
bufsize_, // input buffer size
0, // client time-out
&sa); // default security attribute
return (hPipe_ != INVALID_HANDLE_VALUE);
}
bool TPipeServer::TCreateAnonPipe() {
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd; //security information for pipes
InitializeSecurityDescriptor(&sd,SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, true, NULL, false);
sa.lpSecurityDescriptor = &sd;
sa.lpSecurityDescriptor = NULL;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = true; //allow passing handle to child
if (!CreatePipe(&ClientAnonRead,&hPipeW_,&sa,0)) //create stdin pipe
{
GlobalOutput.perror("TPipeServer CreatePipe (anon) failed, GLE=", GetLastError());
return false;
}
if (!CreatePipe(&hPipe_,&ClientAnonWrite,&sa,0)) //create stdout pipe
{
GlobalOutput.perror("TPipeServer CreatePipe (anon) failed, GLE=", GetLastError());
CloseHandle(ClientAnonRead);
CloseHandle(hPipeW_);
return false;
}
return true;
}
//---------------------------------------------------------
// Accessors
//---------------------------------------------------------
string TPipeServer::getPipename() {
return pipename_;
}
void TPipeServer::setPipename(std::string pipename) {
pipename_ = pipename;
}
int TPipeServer::getBufferSize() {
return bufsize_;
}
void TPipeServer::setBufferSize(int bufsize) {
bufsize_ = bufsize;
}
HANDLE TPipeServer::getPipeHandle() {
return hPipe_;
}
HANDLE TPipeServer::getWrtPipeHandle()
{
return hPipeW_;
}
HANDLE TPipeServer::getClientRdPipeHandle()
{
return ClientAnonRead;
}
HANDLE TPipeServer::getClientWrtPipeHandle()
{
return ClientAnonWrite;
}
bool TPipeServer::getAnonymous() {
return isAnonymous;
}
void TPipeServer::setAnonymous(bool anon) {
isAnonymous = anon;
}
}}} // apache::thrift::transport
#endif //_WIN32