Belle II Software development
StreamInterceptor Class Reference

Base class with all necessary features to intercept output to a file descriptor. More...

#include <IOIntercept.h>

Inheritance diagram for StreamInterceptor:
CaptureStream DiscardStream

Public Member Functions

 StreamInterceptor (std::ostream &stream, FILE *fileObject)
 Construct keeping a reference to the std::ostream and the file descriptor which are associated with this stream as well as a file descriptor for the replacement.
 
 ~StreamInterceptor ()
 close file descriptors
 
bool start ()
 start intercepting the stream.
 
bool finish ()
 stop intercepting the stream.
 

Protected Member Functions

void setReplacementFD (int fd)
 set the replacement file descriptor, should be called in the constructor of derived classes
 
bool replaceFD (int fileDescriptor)
 Replace the file descriptor of m_fileObject with the one passed.
 

Static Protected Member Functions

static void readFD (int fd, std::string &out)
 Read the contents of a file descriptor until there is no more input and place them in out.
 

Protected Attributes

std::ostream & m_stream
 C++ stream object, only needed to flush before replacement.
 
FILE * m_fileObject
 File object of the file we want to replace, needed to obtain file descriptor and to flush.
 
int m_savedFD { -1}
 Saved file descriptor: a duplicate of the file descriptor of m_fileObject.
 
int m_replacementFD { -1}
 Replacement file descriptor to be used while capturing.
 
bool m_capturing {false}
 Check whether we are already capturing.
 

Detailed Description

Base class with all necessary features to intercept output to a file descriptor.

Definition at line 23 of file IOIntercept.h.

Constructor & Destructor Documentation

◆ StreamInterceptor()

StreamInterceptor ( std::ostream &  stream,
FILE *  fileObject 
)

Construct keeping a reference to the std::ostream and the file descriptor which are associated with this stream as well as a file descriptor for the replacement.

Parameters
streamC++ ostream which is associated with the file descriptor we want to intercept
fileObjectfile object which is associated with the file descriptor we want to intercept

Definition at line 88 of file IOIntercept.cc.

88 :
89 m_stream(stream), m_fileObject(fileObject), m_savedFD(dup(fileno(m_fileObject)))
90 {
91 if (m_savedFD < 0) {
92 B2ERROR("Error duplicating file descriptor: " << std::strerror(errno));
93 }
94 }
std::ostream & m_stream
C++ stream object, only needed to flush before replacement.
Definition: IOIntercept.h:65
FILE * m_fileObject
File object of the file we want to replace, needed to obtain file descriptor and to flush.
Definition: IOIntercept.h:67
int m_savedFD
Saved file descriptor: a duplicate of the file descriptor of m_fileObject.
Definition: IOIntercept.h:69

◆ ~StreamInterceptor()

close file descriptors

Definition at line 95 of file IOIntercept.cc.

96 {
97 finish();
98 if (m_savedFD >= 0) close(m_savedFD);
99 if (m_replacementFD >= 0) close(m_replacementFD);
100 }
int m_replacementFD
Replacement file descriptor to be used while capturing.
Definition: IOIntercept.h:71
bool finish()
stop intercepting the stream.
Definition: IOIntercept.h:46

Member Function Documentation

◆ finish()

bool finish ( )
inline

stop intercepting the stream.

Returns
true if the object was capturing and stream could be restored

Definition at line 46 of file IOIntercept.h.

47 {
48 if (!m_capturing) return false;
49 m_capturing = false;
50 return replaceFD(m_savedFD);
51 }
bool replaceFD(int fileDescriptor)
Replace the file descriptor of m_fileObject with the one passed.
Definition: IOIntercept.cc:120
bool m_capturing
Check whether we are already capturing.
Definition: IOIntercept.h:73

◆ readFD()

void readFD ( int  fd,
std::string &  out 
)
staticprotected

Read the contents of a file descriptor until there is no more input and place them in out.

Parameters
fdfile descriptor to read, should be opened in non blocking mode O_NOBLOCK
outstring to be replaced with all the bytes read from fd

Definition at line 102 of file IOIntercept.cc.

103 {
104 out.clear();
105 if (fd <= 0) return;
106 // need a buffer to read
107 static std::unique_ptr<char[]> buffer(new char[1024]);
108 // so then, read everything
109 while (true) {
110 ssize_t size = read(fd, buffer.get(), 1024);
111 if (size <= 0) {
112 // in case we get interrupted by signal, try again
113 if (size < 0 && errno == EINTR) continue;
114 break;
115 }
116 out.append(buffer.get(), static_cast<size_t>(size));
117 }
118 }

◆ replaceFD()

bool replaceFD ( int  fileDescriptor)
protected

Replace the file descriptor of m_fileObject with the one passed.

Parameters
fileDescriptorfile descriptor to be set for m_fileObject using dup2()

Definition at line 120 of file IOIntercept.cc.

121 {
122 // obviously we don't want to replace invalid descriptors
123 if (fileDescriptor < 0) return false;
124 // flush existing stream
125 m_stream << std::flush;
126 std::fflush(m_fileObject);
127 // and clear the bad bits we might have gotten when pipe capacity is reached
128 m_stream.clear();
129 // and then replace the file descriptor
130 const int currentFD = fileno(m_fileObject);
131 if (currentFD < 0) {
132 B2ERROR("Error obtaining file descriptor: " << std::strerror(errno));
133 return false;
134 }
135 while (dup2(fileDescriptor, currentFD) < 0) {
136 if (errno != EINTR && errno != EBUSY) {
137 B2ERROR("Error in dup2(), cannot replace file descriptor: " << std::strerror(errno));
138 return false;
139 }
140 // interrupted or busy, let's try again
141 }
142 return true;
143 }

◆ setReplacementFD()

void setReplacementFD ( int  fd)
inlineprotected

set the replacement file descriptor, should be called in the constructor of derived classes

Definition at line 54 of file IOIntercept.h.

54{ m_replacementFD = fd; }

◆ start()

bool start ( )
inline

start intercepting the stream.

Returns
true on success, false on any error

Definition at line 38 of file IOIntercept.h.

39 {
40 // only start if we are not already running
42 return m_capturing;
43 }

Member Data Documentation

◆ m_capturing

bool m_capturing {false}
protected

Check whether we are already capturing.

Definition at line 73 of file IOIntercept.h.

◆ m_fileObject

FILE* m_fileObject
protected

File object of the file we want to replace, needed to obtain file descriptor and to flush.

Definition at line 67 of file IOIntercept.h.

◆ m_replacementFD

int m_replacementFD { -1}
protected

Replacement file descriptor to be used while capturing.

Definition at line 71 of file IOIntercept.h.

◆ m_savedFD

int m_savedFD { -1}
protected

Saved file descriptor: a duplicate of the file descriptor of m_fileObject.

Definition at line 69 of file IOIntercept.h.

◆ m_stream

std::ostream& m_stream
protected

C++ stream object, only needed to flush before replacement.

Definition at line 65 of file IOIntercept.h.


The documentation for this class was generated from the following files: