1 |
|
|
/** |
2 |
|
|
* This file is part of the CernVM File System. |
3 |
|
|
*/ |
4 |
|
|
#ifndef CVMFS_CACHE_TRANSPORT_H_ |
5 |
|
|
#define CVMFS_CACHE_TRANSPORT_H_ |
6 |
|
|
|
7 |
|
|
#include <stdint.h> |
8 |
|
|
|
9 |
|
|
#include <cstdlib> |
10 |
|
|
|
11 |
|
|
#include "cache.h" |
12 |
|
|
#include "cache.pb.h" |
13 |
|
|
#include "util/single_copy.h" |
14 |
|
|
|
15 |
|
|
namespace shash { |
16 |
|
|
struct Any; |
17 |
|
|
} |
18 |
|
|
|
19 |
|
3 |
inline const char *CacheTransportCode2Ascii(const cvmfs::EnumStatus code) { |
20 |
✗✗✗✗ ✗✗✓✗ ✗✗✗✓ ✗✗ |
3 |
switch (code) { |
21 |
|
|
case cvmfs::STATUS_UNKNOWN: return "unknown cache protocol error"; |
22 |
|
|
case cvmfs::STATUS_OK: return "OK"; |
23 |
|
|
case cvmfs::STATUS_NOSUPPORT: |
24 |
|
|
return "operation not implemented by cache plugin"; |
25 |
|
|
case cvmfs::STATUS_FORBIDDEN: return "cache plugin denied the operation"; |
26 |
|
|
case cvmfs::STATUS_NOSPACE: return "no space in cache"; |
27 |
|
|
case cvmfs::STATUS_NOENTRY: return "object not found in cache"; |
28 |
|
2 |
case cvmfs::STATUS_MALFORMED: return "malformed cache protocol message"; |
29 |
|
|
case cvmfs::STATUS_IOERR: return "I/O error"; |
30 |
|
|
case cvmfs::STATUS_CORRUPTED: return "corrupted data detected"; |
31 |
|
|
case cvmfs::STATUS_TIMEOUT: return "multipart request timed out"; |
32 |
|
|
case cvmfs::STATUS_BADCOUNT: |
33 |
|
|
return "invalid attempt to set negative reference count"; |
34 |
|
1 |
case cvmfs::STATUS_OUTOFBOUNDS: return "out of bounds"; |
35 |
|
|
case cvmfs::STATUS_PARTIAL: |
36 |
|
|
return "cache could not be cleaned up to the given limit"; |
37 |
|
|
default: return "unexpected cache protocol error"; |
38 |
|
|
} |
39 |
|
|
} |
40 |
|
|
|
41 |
|
|
/** |
42 |
|
|
* Sending and receiving with a file descriptor. Does _not_ take the ownership |
43 |
|
|
* of the file descriptor. |
44 |
|
|
*/ |
45 |
|
|
class CacheTransport { |
46 |
|
|
public: |
47 |
|
|
/** |
48 |
|
|
* When this environment variable is set, the plugin will notify a cvmfs |
49 |
|
|
* client once it is ready to accept connections. |
50 |
|
|
*/ |
51 |
|
|
static const char *kEnvReadyNotifyFd; // __CVMFS_CACHE_EXTERNAL_PIPE_READY__ |
52 |
|
|
static const char kReadyNotification = 'C'; |
53 |
|
|
static const char kFailureNotification = 'F'; |
54 |
|
|
/** |
55 |
|
|
* Version of the wire protocol. The effective protocol version is negotiated |
56 |
|
|
* through the handshake. |
57 |
|
|
*/ |
58 |
|
|
static const unsigned char kWireProtocolVersion = 0x01; |
59 |
|
|
/** |
60 |
|
|
* This is or-ed to the version number if the message has an attachment. In |
61 |
|
|
* this case, the 2 bytes after the header specify the size of the protobuf |
62 |
|
|
* message alone. |
63 |
|
|
*/ |
64 |
|
|
static const unsigned char kFlagHasAttachment = 0x80; |
65 |
|
|
/** |
66 |
|
|
* Maximum size of the protobuf message _and_ the attachment, should it exist. |
67 |
|
|
*/ |
68 |
|
|
static const uint32_t kMaxMsgSize = (2 << 24) - 1; // 24MB (3 bytes) |
69 |
|
|
/** |
70 |
|
|
* The first byte has the wire protocol version, optinally or-ed with the |
71 |
|
|
* "has attachment" flag. The other three bytes encode the overall message |
72 |
|
|
* size in little-endian. |
73 |
|
|
*/ |
74 |
|
|
static const unsigned kHeaderSize = 4; |
75 |
|
|
/** |
76 |
|
|
* The "inner header" are two byte following the header. The two bytes encode |
77 |
|
|
* in little-endian the size of the protobuf message alone, if there is an |
78 |
|
|
* attachment. The inner header is only present if there is an attachment. |
79 |
|
|
*/ |
80 |
|
|
static const unsigned kInnerHeaderSize = 2; |
81 |
|
|
|
82 |
|
|
static const uint32_t kFlagSendIgnoreFailure = 0x01; |
83 |
|
|
static const uint32_t kFlagSendNonBlocking = 0x02; |
84 |
|
|
|
85 |
|
|
|
86 |
|
|
/** |
87 |
|
|
* A single unit of data transfer contains a "typed" Msg... protobuf message |
88 |
|
|
* inside a MsgRpc message. Optionally, there can be an "attachment", which |
89 |
|
|
* is a byte stream following the protobuf message. The typed message and the |
90 |
|
|
* attachment buffer are (stack)-allocated by users of CacheTransport. The |
91 |
|
|
* Frame subclass takes care of wrapping and unwrapping into/from MsgRpc |
92 |
|
|
* message. |
93 |
|
|
*/ |
94 |
|
|
class Frame : SingleCopy { |
95 |
|
|
public: |
96 |
|
|
Frame(); |
97 |
|
|
explicit Frame(google::protobuf::MessageLite *m); |
98 |
|
|
~Frame(); |
99 |
|
|
void MergeFrom(const Frame &other); |
100 |
|
|
void Reset(uint32_t original_att_size); |
101 |
|
|
|
102 |
|
17745 |
void *attachment() const { return attachment_; } |
103 |
|
32477 |
uint32_t att_size() const { return att_size_; } |
104 |
|
13594 |
void set_att_size(uint32_t size) { att_size_ = size; } |
105 |
|
14628 |
void set_attachment(void *attachment, uint32_t att_size) { |
106 |
|
14628 |
attachment_ = attachment; |
107 |
|
14628 |
att_size_ = att_size; |
108 |
|
14628 |
} |
109 |
|
|
|
110 |
|
|
bool ParseMsgRpc(void *buffer, uint32_t size); |
111 |
|
|
cvmfs::MsgRpc *GetMsgRpc(); |
112 |
|
|
google::protobuf::MessageLite *GetMsgTyped(); |
113 |
|
|
// The Detach message does not follow the command-reply pattern |
114 |
|
|
bool IsMsgOutOfBand(); |
115 |
|
|
|
116 |
|
|
private: |
117 |
|
|
void WrapMsg(); |
118 |
|
|
void UnwrapMsg(); |
119 |
|
|
void Release(); |
120 |
|
|
|
121 |
|
|
cvmfs::MsgRpc msg_rpc_; |
122 |
|
|
bool owns_msg_typed_; |
123 |
|
|
/** |
124 |
|
|
* Can either point to a user-provided message (sender side) or to a message |
125 |
|
|
* inside msg_rpc_ (receiving end) |
126 |
|
|
*/ |
127 |
|
|
google::protobuf::MessageLite *msg_typed_; |
128 |
|
|
void *attachment_; |
129 |
|
|
uint32_t att_size_; |
130 |
|
|
bool is_wrapped_; |
131 |
|
|
bool is_msg_out_of_band_; |
132 |
|
|
}; // class CacheTransport::Frame |
133 |
|
|
|
134 |
|
|
|
135 |
|
|
explicit CacheTransport(int fd_connection); |
136 |
|
|
CacheTransport(int fd_connection, uint32_t flags); |
137 |
|
4488 |
~CacheTransport() { } |
138 |
|
|
|
139 |
|
|
void SendFrame(Frame *frame); |
140 |
|
|
bool RecvFrame(Frame *frame); |
141 |
|
|
|
142 |
|
|
void FillMsgHash(const shash::Any &hash, cvmfs::MsgHash *msg_hash); |
143 |
|
|
bool ParseMsgHash(const cvmfs::MsgHash &msg_hash, shash::Any *hash); |
144 |
|
|
void FillObjectType(CacheManager::ObjectType object_type, |
145 |
|
|
cvmfs::EnumObjectType *wire_type); |
146 |
|
|
bool ParseObjectType(cvmfs::EnumObjectType wire_type, |
147 |
|
|
CacheManager::ObjectType *object_type); |
148 |
|
|
|
149 |
|
78 |
int fd_connection() const { return fd_connection_; } |
150 |
|
|
|
151 |
|
|
private: |
152 |
|
|
static const unsigned kMaxStackAlloc = 256 * 1024; // 256 kB |
153 |
|
|
|
154 |
|
|
void SendData(void *message, |
155 |
|
|
uint32_t msg_size, |
156 |
|
|
void *attachment = NULL, |
157 |
|
|
uint32_t att_size = 0); |
158 |
|
|
void SendNonBlocking(struct iovec *iov, unsigned iovcnt); |
159 |
|
|
bool RecvHeader(uint32_t *size, bool *has_attachment); |
160 |
|
|
|
161 |
|
|
int fd_connection_; |
162 |
|
|
uint32_t flags_; |
163 |
|
|
}; // class CacheTransport |
164 |
|
|
|
165 |
|
|
#endif // CVMFS_CACHE_TRANSPORT_H_ |