• No results found

The ACE File Wrapper Facades

In document C++ Network Programming Vol 1 (Page 100-104)

Implementing the Networked Logging Service

Sidebar 8: The ACE File Wrapper Facades

ACE encapsulates platform mechanisms for unbuffered file operations in accordance with the Wrapper Facade pattern. Like most of the ACE

wrapper facades families, the ACE File classes decouple the

• Initialization factories, such as which open and/or create from

• Data transfer classes, such as the ACE_FILE_IO, which applica-tions use to read and write data to a file opened by

Connector,

The symmetry of the ACE IPC and file wrapper facades demonstrates the generality of ACE's design and provides the basis for strategizing IPC mechanisms into the higher-level ACE frameworks described in

The Logging Method

This helper method can be used by the hook methods to initialize a log file using the ACE File wrapper facades outlined in Sidebar 8.

(ACE_FILE_IO

char + sizeof

if 0) { // Use client host name as f i l e ACE_INET_Addr

(filename, strcat (filename,

else}

strcpy (filename,

connector;

return

// No time-out.

// Ignored.

0, // try to reuse the addr.

ACE DEFAULT FILE

86 CHAPTER 4 Implementing the Networked Logging Service

We name the log file by default. name can

be overridden by using the host name of the connected client, as we show on page 156 in Section 7.4.

Sidebar 9: The Logging Service Message Framing Protocol

Since TCP is a bytestream protocol, we need an application-level mes-sage framing protocol to delimit log records in the data stream, We use an 8-byte, CDR-encoded header that contains the byte-order indica-tion and payload followed by the log record contents, as shown below:

4.4.2 The Logging Class

This class is used in logging servers to encapsulate the I/O and processing of log records in accordance with the message framing protocol described in Sidebar 9. The sender side of this protocol implementation is shown

in the method on page 96, and the receiver

side is shown in the : recv_log_record method on page 88.

The class definition is placed in a header file called

ttinclude

#include

class // Forward declaration.

Section 4.4 The Initial Logging Server 87

class Logging_Handler {

// Reference to a log file.

// Connected to the client.

// Initialization and termination methods.

Logging_Handler

: log_file_ logging_peer_ {}

(const

: log_file_ {}

int close () { return }

// Receive one log record from a connected client. Returns // length of record on success and contains the // hostname, contains the log record header // (the byte order and the length) and the data. Returns -1 on // failure or connection close.

int recv_log_record

// Write one record to the log file. The contains the // hostname and the <mblk->cont> contains the log record.

// Returns length of record written on success; -1 on int write_log_record

// Log one record by calling and

// Returns 0 on success and -1 on failure.

int log_record

ACE SOCK_Stream () { return logging peer } // Accessor.

Below, we show the implementation of the recv_log_record and log_record methods.

Logging record(). This method implements the receiv-ing side of the networked loggreceiv-ing service's message framreceiv-ing protocol (see Sidebar 9, page 86). It uses the ACE_SOCK_Stream,

and classes along with the extraction

88 CHAPTER 4 Implementing the Networked Logging Service

on page 79 to read one complete log record from a connected client. This code is portable and interoperable since we demarshal the contents re-ceived from the network using the class.

1 int (ACE_Message_Block

11 // Align Message Block for a CDR stream.

12

20 // Use helper method to disambiguate booleans from 21 cdr

30 // Reflect additional

31

32 return length; // Return length of the log record.

33 }

Lines We allocate a new in which to store the host name. We're careful to NUL-terminate the host

Section 4.4 The Initial Logging Server 89

name and to ensure that only the host name is included in the current length of the message block, which is defined as

-Lines We create a separate ACE_Message_Block to hold the log record. The size of the header is known (8 bytes), so we receive that first.

Since we'll use the CDR facility to the header after it's received, we take some precautions with the new message block. CDR's ability to demarshal data requires the marshaled data start on

an alignment boundary. doesn't provide any

alignment guarantees, so we call to force proper alignment before using () to receive the header. The alignment may result in some unused bytes at the start of the block's in-ternal buffer, so we must initially size load larger than the 8 bytes it will receive has a default value of 512).

Lines Following a successful call to recv_n to obtain the fixed-sized header, payload's write pointer is advanced to reflect the addition of 8 bytes to the message block.

Lines 17-25 We create a CDR object to demarshal the 8-byte header lo-cated in the payload message block. The CDR object copies the header, avoiding any alteration of the payload message block as the header is de-marshaled. Since the byte order indicator is a Boolean, it can be extracted regardless of the client's byte order. The byte order of the CDR stream is then set according to the order indicated by the input, and the length of the variable-sized log record payload is extracted.

Lines 27-32 Now that we know the length of the log record the payload message block is resized to hold the complete record. The second call appends the remainder of the log record to the payload message block, immediately following the header. If all goes well, we update the write pointer in payload to reflect the added data, chain payload to

via its continuation field, and return the length of the log

Lines 35-38 Error cases end up here, so we need to release the memory

In document C++ Network Programming Vol 1 (Page 100-104)