Skip to content

Commit 3449428

Browse files
cppguruGitHub Enterprise
authored andcommitted
Drqs 184194259 balb pipecontrolchannel configure permissions (#5932)
* balb_pipecontrolchannel: add 'permissions' to c'tor
1 parent 8f1854a commit 3449428

7 files changed

Lines changed: 1241 additions & 27 deletions

File tree

groups/bal/balb/balb_pipecontrolchannel.cpp

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
BSLS_IDENT_RCSID(balb_pipecontrolchannel_cpp,"$Id$ $CSID$")
66

77
#include <bdlf_bind.h>
8+
#include <bdls_filepermissions.h>
89
#include <bdls_filesystemutil.h>
910
#include <bdls_pathutil.h>
1011
#include <bdls_pipeutil.h>
@@ -45,6 +46,9 @@ BSLS_IDENT_RCSID(balb_pipecontrolchannel_cpp,"$Id$ $CSID$")
4546
#endif
4647

4748
namespace {
49+
namespace u {
50+
51+
using namespace BloombergLP;
4852

4953
#ifdef BSLS_PLATFORM_OS_WINDOWS
5054
bsl::string describeWin32Error(DWORD lastError)
@@ -63,6 +67,7 @@ bsl::string describeWin32Error(DWORD lastError)
6367
}
6468
#endif
6569

70+
} // close namespace u
6671
} // close unnamed namespace
6772

6873
namespace BloombergLP {
@@ -150,7 +155,7 @@ int PipeControlChannel::readNamedPipe()
150155
if (!ConnectNamedPipe(d_impl.d_windows.d_handle, NULL)) {
151156
BSLS_LOG_TRACE("Connecting to named pipe '%s': %s",
152157
d_pipeName.c_str(),
153-
describeWin32Error(GetLastError()).c_str());
158+
u::describeWin32Error(GetLastError()).c_str());
154159

155160
DWORD lastError = GetLastError();
156161
if (lastError != ERROR_PIPE_CONNECTED && lastError != ERROR_NO_DATA) {
@@ -204,7 +209,7 @@ int PipeControlChannel::readNamedPipe()
204209
if (ERROR_BROKEN_PIPE != err) {
205210
BSLS_LOG_TRACE("Failed read from named pipe '%s': %s",
206211
d_pipeName.c_str(),
207-
describeWin32Error(err).c_str());
212+
u::describeWin32Error(err).c_str());
208213
} else {
209214
// The 'ERROR_BROKEN_PIPE' case simply means that the client
210215
// closed the connection but did not tell us to shut down; we
@@ -254,7 +259,7 @@ PipeControlChannel::createNamedPipe(const char *pipeName)
254259
}
255260
BSLS_LOG_TRACE("Failed to create named pipe '%s': %s",
256261
d_pipeName.c_str(),
257-
describeWin32Error(GetLastError()).c_str());
262+
u::describeWin32Error(GetLastError()).c_str());
258263
return -1; // RETURN
259264
}
260265

@@ -469,7 +474,7 @@ PipeControlChannel::createNamedPipe(const char *pipeName)
469474
}
470475
}
471476

472-
int rc = mkfifo(pipeName, 0666);
477+
int rc = mkfifo(pipeName, d_permissions);
473478
if (0 != rc) {
474479
int savedErrno = errno;
475480
BSLS_LOG_ERROR("Unable to create pipe '%s'. errno = %d (%s)",
@@ -538,6 +543,9 @@ PipeControlChannel::createNamedPipe(const char *pipeName)
538543

539544
namespace balb {
540545

546+
// CONSTANTS
547+
const int PipeControlChannel::k_DEFAULT_PERMISSIONS;
548+
541549
// CREATORS
542550
PipeControlChannel::PipeControlChannel(const ControlCallback& callback,
543551
bslma::Allocator *basicAllocator)
@@ -548,8 +556,32 @@ PipeControlChannel::PipeControlChannel(const ControlCallback& callback,
548556
, d_buffer(bslma::Default::allocator(basicAllocator))
549557
, d_thread(bslmt::ThreadUtil::invalidHandle())
550558
, d_backgroundState(e_STOPPED)
559+
, d_permissions(k_DEFAULT_PERMISSIONS)
560+
, d_isPipeOpen(false)
561+
{
562+
#ifdef BSLS_PLATFORM_OS_WINDOWS
563+
d_impl.d_windows.d_handle = INVALID_HANDLE_VALUE;
564+
#else
565+
d_impl.d_unix.d_readFd = -1;
566+
d_impl.d_unix.d_writeFd = -1;
567+
#endif
568+
}
569+
570+
PipeControlChannel::PipeControlChannel(const ControlCallback& callback,
571+
int permissions,
572+
bslma::Allocator *basicAllocator)
573+
: d_callback(bsl::allocator_arg_t(),
574+
bsl::allocator<ControlCallback>(basicAllocator),
575+
callback)
576+
, d_pipeName(bslma::Default::allocator(basicAllocator))
577+
, d_buffer(bslma::Default::allocator(basicAllocator))
578+
, d_thread(bslmt::ThreadUtil::invalidHandle())
579+
, d_backgroundState(e_STOPPED)
580+
, d_permissions(permissions)
551581
, d_isPipeOpen(false)
552582
{
583+
BSLS_ASSERT(bdls::FilePermissions::isValidBaseBits(permissions));
584+
553585
#ifdef BSLS_PLATFORM_OS_WINDOWS
554586
d_impl.d_windows.d_handle = INVALID_HANDLE_VALUE;
555587
#else
@@ -565,6 +597,14 @@ PipeControlChannel::~PipeControlChannel()
565597
}
566598

567599
// MANIPULATORS
600+
void PipeControlChannel::setPermissions(int permissions)
601+
{
602+
BSLS_ASSERT(e_STOPPED == d_backgroundState);
603+
BSLS_ASSERT(bdls::FilePermissions::isValidBaseBits(permissions));
604+
605+
d_permissions = permissions;
606+
}
607+
568608
void PipeControlChannel::backgroundProcessor()
569609
{
570610
while (d_backgroundState == e_RUNNING) {

groups/bal/balb/balb_pipecontrolchannel.h

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,27 @@ BSLS_IDENT("$Id: $")
6565
// each message. This trailing newline is stripped from the message before
6666
// the message is passed to the control callback.
6767
//
68+
///Pipe Permissions
69+
///----------------
70+
// This component creates its underlying named pipe with a permission bit
71+
// mask that defaults to `k_DEFAULT_PERMISSIONS` (`0666`, i.e., read and write
72+
// for owner, group, and others). A different permission bit mask may be
73+
// supplied at construction time via the constructor overload taking an
74+
// `int permissions` argument, or may be changed after construction (but before
75+
// `start`) by calling `setPermissions`. The bit-mask semantics follow the
76+
// conventional Unix mode-bit layout enumerated by `bdls::FilePermissions`;
77+
// callers may express the desired permissions either as an octal literal
78+
// (e.g., `0640`) or by OR-ing together `bdls::FilePermissions` enumerators
79+
// (e.g., `bdls::FilePermissions::k_OWNER_READ | ...`). Only the nine
80+
// owner/group/others read/write/execute bits are accepted (see
81+
// `bdls::FilePermissions::isValidBaseBits`); `k_SET_UID`, `k_SET_GID`, and
82+
// `k_STICKY_BIT` are not meaningful for a control pipe and result in
83+
// undefined behavior.
84+
//
85+
// On operating systems that do not support Unix-style permission bits
86+
// (notably Windows) the requested permission bit mask is silently ignored
87+
// and the pipe is created with the operating-system default permissions.
88+
//
6889
///Platform-Specific Pipe Name Encoding Caveats
6990
///--------------------------------------------
7091
// Pipe-name encodings have the following caveats for the following operating
@@ -209,6 +230,8 @@ BSLS_IDENT("$Id: $")
209230

210231
#include <balscm_version.h>
211232

233+
#include <bdls_filepermissions.h>
234+
212235
#include <bslmt_threadattributes.h>
213236
#include <bslmt_threadutil.h>
214237

@@ -247,6 +270,17 @@ class PipeControlChannel {
247270
typedef bsl::function<void(const bslstl::StringRef& message)>
248271
ControlCallback;
249272

273+
// CONSTANTS
274+
275+
/// The default permission bit mask for the underlying named pipe
276+
/// (read/write for owner, group, and others).
277+
static const int k_DEFAULT_PERMISSIONS =
278+
bdls::FilePermissions::k_OWNER_READ |
279+
bdls::FilePermissions::k_OWNER_WRITE |
280+
bdls::FilePermissions::k_GROUP_READ |
281+
bdls::FilePermissions::k_GROUP_WRITE |
282+
bdls::FilePermissions::k_OTHERS_READ |
283+
bdls::FilePermissions::k_OTHERS_WRITE;
250284
private:
251285
// TYPES
252286
enum BackgroundThreadState {
@@ -261,6 +295,10 @@ class PipeControlChannel {
261295
bsl::vector<char> d_buffer; // message buffer
262296
bslmt::ThreadUtil::Handle d_thread; // background processing thread
263297
bsls::AtomicInt d_backgroundState; // the background thread state
298+
int d_permissions; // permission bit mask for the
299+
// created named pipe (see
300+
// `bdls_filepermissions`);
301+
// ignored on Windows
264302
bool d_isPipeOpen; // true if the pipe is still open
265303

266304
union {
@@ -320,19 +358,50 @@ class PipeControlChannel {
320358

321359
/// Create a pipe control mechanism that dispatches messages to the
322360
/// specified `callback`. Optionally specify `basicAllocator` to supply
323-
/// memory. If `basicAllocator` is zero, the currently installed
324-
/// default allocator is used.
361+
/// memory. If `basicAllocator` is zero, the currently installed default
362+
/// allocator is used. The permission bit mask of the underlying named
363+
/// pipe defaults to `k_DEFAULT_PERMISSIONS` (0666, i.e., read/write for
364+
/// everyone) and may be changed by calling `setPermissions` before
365+
/// `start`.
325366
explicit
326367
PipeControlChannel(const ControlCallback& callback,
327368
bslma::Allocator *basicAllocator = 0);
328369

370+
/// Create a pipe control mechanism that dispatches messages to the
371+
/// specified `callback` and creates its underlying named pipe with the
372+
/// specified `permissions` bit mask. Optionally specify
373+
/// `basicAllocator` to supply memory. If `basicAllocator` is zero, the
374+
/// currently installed default allocator is used. The behavior is
375+
/// undefined unless `bdls::FilePermissions::isValidBaseBits(permissions)`
376+
/// (i.e., unless `permissions` is a combination of the nine
377+
/// owner/group/others read/write/execute bits defined by
378+
/// `bdls::FilePermissions`; note that `k_SET_UID`, `k_SET_GID`, and
379+
/// `k_STICKY_BIT` are not accepted). On operating systems that do not
380+
/// support Unix-style permission bits (notably Windows) the value is
381+
/// ignored and falls back to the operating-system default (see the
382+
/// component-level documentation for details).
383+
PipeControlChannel(const ControlCallback& callback,
384+
int permissions,
385+
bslma::Allocator *basicAllocator = 0);
386+
329387
/// Destroy this object. Shut down the processing thread if it is still
330388
/// running and block until it terminates. Close the named pipe and
331389
/// clean up any associated system resources.
332390
~PipeControlChannel();
333391

334392
// MANIPULATORS
335393

394+
/// Set the permission bit mask for the underlying named pipe to the
395+
/// specified `permissions` value. The behavior is undefined unless
396+
/// `bdls::FilePermissions::isValidBaseBits(permissions)`. This setting
397+
/// only takes effect on the next call to `start`; calling this method
398+
/// has no effect on a pipe that has already been opened. See the
399+
/// class-level documentation for a description of the cross-platform
400+
/// semantics. The behavior is undefined if this method is called while
401+
/// the background thread is running (i.e., after `start` and before
402+
/// `shutdown`), or if the `permissions` value is not valid.
403+
void setPermissions(int permissions);
404+
336405
/// Open a named pipe having the specified `pipeName`, and start a
337406
/// thread to read messages and dispatch them to the callback specified
338407
/// at construction. Optionally specify `attributes` of the background
@@ -363,6 +432,10 @@ class PipeControlChannel {
363432

364433
// ACCESSORS
365434

435+
/// Return the permission bit mask that will be applied to the named
436+
/// pipe on the next call to `start`.
437+
int permissions() const;
438+
366439
/// Return the fully qualified system name of the pipe.
367440
const bsl::string& pipeName() const;
368441

@@ -458,6 +531,12 @@ int PipeControlChannel::start(const STRING_TYPE& pipeName,
458531
}
459532

460533
// ACCESSORS
534+
inline
535+
int PipeControlChannel::permissions() const
536+
{
537+
return d_permissions;
538+
}
539+
461540
inline
462541
const bsl::string& PipeControlChannel::pipeName() const
463542
{

0 commit comments

Comments
 (0)