CernVM-FS  2.12.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
cache_transport.cc
Go to the documentation of this file.
1 
4 #include "cvmfs_config.h"
5 #include "cache_transport.h"
6 
7 #include <alloca.h>
8 #include <errno.h>
9 #include <sys/socket.h>
10 
11 #include <cassert>
12 #include <cstdlib>
13 #include <cstring>
14 
15 #include "crypto/hash.h"
16 #include "util/exception.h"
17 #include "util/logging.h"
18 #include "util/posix.h"
19 #include "util/smalloc.h"
20 
21 // TODO(jblomer): Check for possible starvation of plugin by dying clients
22 // (blocking read). Probably only relevant for TCP sockets.
23 
24 using namespace std; // NOLINT
25 
27  "__CVMFS_CACHE_EXTERNAL_PIPE_READY__";
28 
34  assert(msg_typed_ != NULL);
35  if (!is_wrapped_)
36  WrapMsg();
37  return &msg_rpc_;
38 }
39 
40 
45 google::protobuf::MessageLite *CacheTransport::Frame::GetMsgTyped() {
46  assert(msg_rpc_.IsInitialized());
47  if (msg_typed_ == NULL)
48  UnwrapMsg();
49  return msg_typed_;
50 }
51 
52 
54  : owns_msg_typed_(false)
55  , msg_typed_(NULL)
56  , attachment_(NULL)
57  , att_size_(0)
58  , is_wrapped_(false)
59  , is_msg_out_of_band_(false)
60 { }
61 
62 
63 CacheTransport::Frame::Frame(google::protobuf::MessageLite *m)
64  : owns_msg_typed_(false)
65  , msg_typed_(m)
66  , attachment_(NULL)
67  , att_size_(0)
68  , is_wrapped_(false)
69  , is_msg_out_of_band_(false)
70 { }
71 
72 
74  Reset(0);
75 }
76 
77 
79  assert(msg_rpc_.IsInitialized());
80  if (msg_typed_ == NULL)
81  UnwrapMsg();
82  return is_msg_out_of_band_;
83 }
84 
85 
87  msg_rpc_.CheckTypeAndMergeFrom(other.msg_rpc_);
88  owns_msg_typed_ = true;
89  if (other.att_size_ > 0) {
90  assert(att_size_ >= other.att_size_);
91  memcpy(attachment_, other.attachment_, other.att_size_);
92  att_size_ = other.att_size_;
93  }
94 }
95 
96 
97 bool CacheTransport::Frame::ParseMsgRpc(void *buffer, uint32_t size) {
98  bool retval = msg_rpc_.ParseFromArray(buffer, size);
99  if (!retval)
100  return false;
101 
102  // Cleanup typed message when Frame leaves scope
103  owns_msg_typed_ = true;
104  return true;
105 }
106 
107 
109  if (owns_msg_typed_)
110  return;
111 
112  msg_rpc_.release_msg_refcount_req();
113  msg_rpc_.release_msg_refcount_reply();
114  msg_rpc_.release_msg_read_req();
115  msg_rpc_.release_msg_read_reply();
116  msg_rpc_.release_msg_object_info_req();
117  msg_rpc_.release_msg_object_info_reply();
118  msg_rpc_.release_msg_store_req();
119  msg_rpc_.release_msg_store_abort_req();
120  msg_rpc_.release_msg_store_reply();
121  msg_rpc_.release_msg_handshake();
122  msg_rpc_.release_msg_handshake_ack();
123  msg_rpc_.release_msg_quit();
124  msg_rpc_.release_msg_ioctl();
125  msg_rpc_.release_msg_info_req();
126  msg_rpc_.release_msg_info_reply();
127  msg_rpc_.release_msg_shrink_req();
128  msg_rpc_.release_msg_shrink_reply();
129  msg_rpc_.release_msg_list_req();
130  msg_rpc_.release_msg_list_reply();
131  msg_rpc_.release_msg_detach();
132  msg_rpc_.release_msg_breadcrumb_store_req();
133  msg_rpc_.release_msg_breadcrumb_load_req();
134  msg_rpc_.release_msg_breadcrumb_reply();
135 }
136 
137 
138 void CacheTransport::Frame::Reset(uint32_t original_att_size) {
139  msg_typed_ = NULL;
140  att_size_ = original_att_size;
141  is_wrapped_ = false;
142  is_msg_out_of_band_ = false;
143  Release();
144  msg_rpc_.Clear();
145  owns_msg_typed_ = false;
146 }
147 
148 
150  if (msg_typed_->GetTypeName() == "cvmfs.MsgHandshake") {
151  msg_rpc_.set_allocated_msg_handshake(
152  reinterpret_cast<cvmfs::MsgHandshake *>(msg_typed_));
153  } else if (msg_typed_->GetTypeName() == "cvmfs.MsgHandshakeAck") {
154  msg_rpc_.set_allocated_msg_handshake_ack(
155  reinterpret_cast<cvmfs::MsgHandshakeAck *>(msg_typed_));
156  } else if (msg_typed_->GetTypeName() == "cvmfs.MsgQuit") {
157  msg_rpc_.set_allocated_msg_quit(
158  reinterpret_cast<cvmfs::MsgQuit *>(msg_typed_));
159  } else if (msg_typed_->GetTypeName() == "cvmfs.MsgIoctl") {
160  msg_rpc_.set_allocated_msg_ioctl(
161  reinterpret_cast<cvmfs::MsgIoctl *>(msg_typed_));
162  } else if (msg_typed_->GetTypeName() == "cvmfs.MsgRefcountReq") {
163  msg_rpc_.set_allocated_msg_refcount_req(
164  reinterpret_cast<cvmfs::MsgRefcountReq *>(msg_typed_));
165  } else if (msg_typed_->GetTypeName() == "cvmfs.MsgRefcountReply") {
166  msg_rpc_.set_allocated_msg_refcount_reply(
167  reinterpret_cast<cvmfs::MsgRefcountReply *>(msg_typed_));
168  } else if (msg_typed_->GetTypeName() == "cvmfs.MsgObjectInfoReq") {
169  msg_rpc_.set_allocated_msg_object_info_req(
170  reinterpret_cast<cvmfs::MsgObjectInfoReq *>(msg_typed_));
171  } else if (msg_typed_->GetTypeName() == "cvmfs.MsgObjectInfoReply") {
172  msg_rpc_.set_allocated_msg_object_info_reply(
173  reinterpret_cast<cvmfs::MsgObjectInfoReply *>(msg_typed_));
174  } else if (msg_typed_->GetTypeName() == "cvmfs.MsgReadReq") {
175  msg_rpc_.set_allocated_msg_read_req(
176  reinterpret_cast<cvmfs::MsgReadReq *>(msg_typed_));
177  } else if (msg_typed_->GetTypeName() == "cvmfs.MsgReadReply") {
178  msg_rpc_.set_allocated_msg_read_reply(
179  reinterpret_cast<cvmfs::MsgReadReply *>(msg_typed_));
180  } else if (msg_typed_->GetTypeName() == "cvmfs.MsgStoreReq") {
181  msg_rpc_.set_allocated_msg_store_req(
182  reinterpret_cast<cvmfs::MsgStoreReq *>(msg_typed_));
183  } else if (msg_typed_->GetTypeName() == "cvmfs.MsgStoreAbortReq") {
184  msg_rpc_.set_allocated_msg_store_abort_req(
185  reinterpret_cast<cvmfs::MsgStoreAbortReq *>(msg_typed_));
186  } else if (msg_typed_->GetTypeName() == "cvmfs.MsgStoreReply") {
187  msg_rpc_.set_allocated_msg_store_reply(
188  reinterpret_cast<cvmfs::MsgStoreReply *>(msg_typed_));
189  } else if (msg_typed_->GetTypeName() == "cvmfs.MsgInfoReq") {
190  msg_rpc_.set_allocated_msg_info_req(
191  reinterpret_cast<cvmfs::MsgInfoReq *>(msg_typed_));
192  } else if (msg_typed_->GetTypeName() == "cvmfs.MsgInfoReply") {
193  msg_rpc_.set_allocated_msg_info_reply(
194  reinterpret_cast<cvmfs::MsgInfoReply *>(msg_typed_));
195  } else if (msg_typed_->GetTypeName() == "cvmfs.MsgShrinkReq") {
196  msg_rpc_.set_allocated_msg_shrink_req(
197  reinterpret_cast<cvmfs::MsgShrinkReq *>(msg_typed_));
198  } else if (msg_typed_->GetTypeName() == "cvmfs.MsgShrinkReply") {
199  msg_rpc_.set_allocated_msg_shrink_reply(
200  reinterpret_cast<cvmfs::MsgShrinkReply *>(msg_typed_));
201  } else if (msg_typed_->GetTypeName() == "cvmfs.MsgListReq") {
202  msg_rpc_.set_allocated_msg_list_req(
203  reinterpret_cast<cvmfs::MsgListReq *>(msg_typed_));
204  } else if (msg_typed_->GetTypeName() == "cvmfs.MsgListReply") {
205  msg_rpc_.set_allocated_msg_list_reply(
206  reinterpret_cast<cvmfs::MsgListReply *>(msg_typed_));
207  } else if (msg_typed_->GetTypeName() == "cvmfs.MsgBreadcrumbStoreReq") {
208  msg_rpc_.set_allocated_msg_breadcrumb_store_req(
209  reinterpret_cast<cvmfs::MsgBreadcrumbStoreReq *>(msg_typed_));
210  } else if (msg_typed_->GetTypeName() == "cvmfs.MsgBreadcrumbLoadReq") {
211  msg_rpc_.set_allocated_msg_breadcrumb_load_req(
212  reinterpret_cast<cvmfs::MsgBreadcrumbLoadReq *>(msg_typed_));
213  } else if (msg_typed_->GetTypeName() == "cvmfs.MsgBreadcrumbReply") {
214  msg_rpc_.set_allocated_msg_breadcrumb_reply(
215  reinterpret_cast<cvmfs::MsgBreadcrumbReply *>(msg_typed_));
216  } else if (msg_typed_->GetTypeName() == "cvmfs.MsgDetach") {
217  msg_rpc_.set_allocated_msg_detach(
218  reinterpret_cast<cvmfs::MsgDetach *>(msg_typed_));
219  is_msg_out_of_band_ = true;
220  } else {
221  // Unexpected message type, should never happen
222  PANIC(NULL);
223  }
224  is_wrapped_ = true;
225 }
226 
227 
229  if (msg_rpc_.has_msg_handshake()) {
230  msg_typed_ = msg_rpc_.mutable_msg_handshake();
231  } else if (msg_rpc_.has_msg_handshake_ack()) {
232  msg_typed_ = msg_rpc_.mutable_msg_handshake_ack();
233  } else if (msg_rpc_.has_msg_quit()) {
234  msg_typed_ = msg_rpc_.mutable_msg_quit();
235  } else if (msg_rpc_.has_msg_ioctl()) {
236  msg_typed_ = msg_rpc_.mutable_msg_ioctl();
237  } else if (msg_rpc_.has_msg_refcount_req()) {
238  msg_typed_ = msg_rpc_.mutable_msg_refcount_req();
239  } else if (msg_rpc_.has_msg_refcount_reply()) {
240  msg_typed_ = msg_rpc_.mutable_msg_refcount_reply();
241  } else if (msg_rpc_.has_msg_object_info_req()) {
242  msg_typed_ = msg_rpc_.mutable_msg_object_info_req();
243  } else if (msg_rpc_.has_msg_object_info_reply()) {
244  msg_typed_ = msg_rpc_.mutable_msg_object_info_reply();
245  } else if (msg_rpc_.has_msg_read_req()) {
246  msg_typed_ = msg_rpc_.mutable_msg_read_req();
247  } else if (msg_rpc_.has_msg_read_reply()) {
248  msg_typed_ = msg_rpc_.mutable_msg_read_reply();
249  } else if (msg_rpc_.has_msg_store_req()) {
250  msg_typed_ = msg_rpc_.mutable_msg_store_req();
251  } else if (msg_rpc_.has_msg_store_abort_req()) {
252  msg_typed_ = msg_rpc_.mutable_msg_store_abort_req();
253  } else if (msg_rpc_.has_msg_store_reply()) {
254  msg_typed_ = msg_rpc_.mutable_msg_store_reply();
255  } else if (msg_rpc_.has_msg_info_req()) {
256  msg_typed_ = msg_rpc_.mutable_msg_info_req();
257  } else if (msg_rpc_.has_msg_info_reply()) {
258  msg_typed_ = msg_rpc_.mutable_msg_info_reply();
259  } else if (msg_rpc_.has_msg_shrink_req()) {
260  msg_typed_ = msg_rpc_.mutable_msg_shrink_req();
261  } else if (msg_rpc_.has_msg_shrink_reply()) {
262  msg_typed_ = msg_rpc_.mutable_msg_shrink_reply();
263  } else if (msg_rpc_.has_msg_list_req()) {
264  msg_typed_ = msg_rpc_.mutable_msg_list_req();
265  } else if (msg_rpc_.has_msg_list_reply()) {
266  msg_typed_ = msg_rpc_.mutable_msg_list_reply();
267  } else if (msg_rpc_.has_msg_breadcrumb_store_req()) {
268  msg_typed_ = msg_rpc_.mutable_msg_breadcrumb_store_req();
269  } else if (msg_rpc_.has_msg_breadcrumb_load_req()) {
270  msg_typed_ = msg_rpc_.mutable_msg_breadcrumb_load_req();
271  } else if (msg_rpc_.has_msg_breadcrumb_reply()) {
272  msg_typed_ = msg_rpc_.mutable_msg_breadcrumb_reply();
273  } else if (msg_rpc_.has_msg_detach()) {
274  msg_typed_ = msg_rpc_.mutable_msg_detach();
275  is_msg_out_of_band_ = true;
276  } else {
277  // Unexpected message type, should never happen
278  PANIC(NULL);
279  }
280 }
281 
282 
283 //------------------------------------------------------------------------------
284 
285 
287  : fd_connection_(fd_connection)
288  , flags_(0)
289 {
290  assert(fd_connection_ >= 0);
291 }
292 
293 
294 CacheTransport::CacheTransport(int fd_connection, uint32_t flags)
295  : fd_connection_(fd_connection)
296  , flags_(flags)
297 {
298  assert(fd_connection_ >= 0);
299 }
300 
301 
303  const shash::Any &hash,
304  cvmfs::MsgHash *msg_hash)
305 {
306  switch (hash.algorithm) {
307  case shash::kSha1:
308  msg_hash->set_algorithm(cvmfs::HASH_SHA1);
309  break;
310  case shash::kRmd160:
311  msg_hash->set_algorithm(cvmfs::HASH_RIPEMD160);
312  break;
313  case shash::kShake128:
314  msg_hash->set_algorithm(cvmfs::HASH_SHAKE128);
315  break;
316  default:
317  PANIC(NULL);
318  }
319  msg_hash->set_digest(hash.digest, shash::kDigestSizes[hash.algorithm]);
320 }
321 
322 
324  int object_flags, cvmfs::EnumObjectType *wire_type)
325 {
326  *wire_type = cvmfs::OBJECT_REGULAR;
327  if (object_flags & CacheManager::kLabelCatalog)
328  *wire_type = cvmfs::OBJECT_CATALOG;
329  if (object_flags & CacheManager::kLabelVolatile)
330  *wire_type = cvmfs::OBJECT_VOLATILE;
331 }
332 
333 
335  const cvmfs::MsgHash &msg_hash,
336  shash::Any *hash)
337 {
338  switch (msg_hash.algorithm()) {
339  case cvmfs::HASH_SHA1:
340  hash->algorithm = shash::kSha1;
341  break;
342  case cvmfs::HASH_RIPEMD160:
343  hash->algorithm = shash::kRmd160;
344  break;
345  case cvmfs::HASH_SHAKE128:
346  hash->algorithm = shash::kShake128;
347  break;
348  default:
349  return false;
350  }
351  const unsigned digest_size = shash::kDigestSizes[hash->algorithm];
352  if (msg_hash.digest().length() != digest_size)
353  return false;
354  memcpy(hash->digest, msg_hash.digest().data(), digest_size);
355  return true;
356 }
357 
358 
360  cvmfs::EnumObjectType wire_type, int *object_flags)
361 {
362  *object_flags = 0;
363  switch (wire_type) {
364  case cvmfs::OBJECT_REGULAR:
365  return true;
366  case cvmfs::OBJECT_CATALOG:
367  *object_flags |= CacheManager::kLabelCatalog;
368  return true;
369  case cvmfs::OBJECT_VOLATILE:
370  *object_flags |= CacheManager::kLabelVolatile;
371  return true;
372  default:
373  return false;
374  }
375 }
376 
377 
379  uint32_t size;
380  bool has_attachment;
381  bool retval = RecvHeader(&size, &has_attachment);
382  if (!retval)
383  return false;
384 
385  void *buffer;
386  if (size <= kMaxStackAlloc)
387  buffer = alloca(size);
388  else
389  buffer = smalloc(size);
390  ssize_t nbytes = SafeRead(fd_connection_, buffer, size);
391  if ((nbytes < 0) || (static_cast<uint32_t>(nbytes) != size)) {
392  if (size > kMaxStackAlloc) { free(buffer); }
393  return false;
394  }
395 
396  uint32_t msg_size = size;
397  if (has_attachment) {
398  if (size < 2) {
399  // kMaxStackAlloc is > 2 (of course!) but we'll leave the condition here
400  // for consistency.
401  if (size > kMaxStackAlloc) { free(buffer); }
402  return false;
403  }
404  msg_size = (*reinterpret_cast<unsigned char *>(buffer)) +
405  ((*(reinterpret_cast<unsigned char *>(buffer) + 1)) << 8);
406  if ((msg_size + kInnerHeaderSize) > size) {
407  if (size > kMaxStackAlloc) { free(buffer); }
408  return false;
409  }
410  }
411 
412  void *ptr_msg = has_attachment
413  ? (reinterpret_cast<char *>(buffer) + kInnerHeaderSize)
414  : buffer;
415  retval = frame->ParseMsgRpc(ptr_msg, msg_size);
416  if (!retval) {
417  if (size > kMaxStackAlloc) { free(buffer); }
418  return false;
419  }
420 
421  if (has_attachment) {
422  uint32_t attachment_size = size - (msg_size + kInnerHeaderSize);
423  if (frame->att_size() < attachment_size) {
424  if (size > kMaxStackAlloc) { free(buffer); }
425  return false;
426  }
427  void *ptr_attachment =
428  reinterpret_cast<char *>(buffer) + kInnerHeaderSize + msg_size;
429  memcpy(frame->attachment(), ptr_attachment, attachment_size);
430  frame->set_att_size(attachment_size);
431  } else {
432  frame->set_att_size(0);
433  }
434  if (size > kMaxStackAlloc) { free(buffer); }
435  return true;
436 }
437 
438 
439 bool CacheTransport::RecvHeader(uint32_t *size, bool *has_attachment) {
440  unsigned char header[kHeaderSize];
441  ssize_t nbytes = SafeRead(fd_connection_, header, kHeaderSize);
442  if ((nbytes < 0) || (static_cast<unsigned>(nbytes) != kHeaderSize))
443  return false;
444  if ((header[0] & (~kFlagHasAttachment)) != kWireProtocolVersion)
445  return false;
446  *has_attachment = header[0] & kFlagHasAttachment;
447  *size = header[1] + (header[2] << 8) + (header[3] << 16);
448  return (*size > 0) && (*size <= kMaxMsgSize);
449 }
450 
451 
453  void *message,
454  uint32_t msg_size,
455  void *attachment,
456  uint32_t att_size)
457 {
458  uint32_t total_size =
459  msg_size + att_size + ((att_size > 0) ? kInnerHeaderSize : 0);
460 
461  assert(total_size > 0);
462  assert(total_size <= kMaxMsgSize);
464  "sending message of size %u to cache transport", total_size);
465 
466  unsigned char header[kHeaderSize];
467  header[0] = kWireProtocolVersion | ((att_size == 0) ? 0 : kFlagHasAttachment);
468  header[1] = (total_size & 0x000000FF);
469  header[2] = (total_size & 0x0000FF00) >> 8;
470  header[3] = (total_size & 0x00FF0000) >> 16;
471  // Only transferred if an attachment is present. Otherwise the overall size
472  // is also the size of the protobuf message.
473  unsigned char inner_header[kInnerHeaderSize];
474 
475  struct iovec iov[4];
476  iov[0].iov_base = header;
477  iov[0].iov_len = kHeaderSize;
478 
479  if (att_size > 0) {
480  inner_header[0] = (msg_size & 0x000000FF);
481  inner_header[1] = (msg_size & 0x0000FF00) >> 8;
482  iov[1].iov_base = inner_header;
483  iov[1].iov_len = kInnerHeaderSize;
484  iov[2].iov_base = message;
485  iov[2].iov_len = msg_size;
486  iov[3].iov_base = attachment;
487  iov[3].iov_len = att_size;
488  } else {
489  iov[1].iov_base = message;
490  iov[1].iov_len = msg_size;
491  }
493  SendNonBlocking(iov, (att_size == 0) ? 2 : 4);
494  return;
495  }
496  bool retval = SafeWriteV(fd_connection_, iov, (att_size == 0) ? 2 : 4);
497 
498  if (!retval && !(flags_ & kFlagSendIgnoreFailure)) {
500  "failed to write to external cache transport (%d), aborting", errno);
501  }
502 }
503 
504 void CacheTransport::SendNonBlocking(struct iovec *iov, unsigned iovcnt) {
505  assert(iovcnt > 0);
506  unsigned total_size = 0;
507  for (unsigned i = 0; i < iovcnt; ++i)
508  total_size += iov[i].iov_len;
509  unsigned char *buffer = reinterpret_cast<unsigned char *>(alloca(total_size));
510 
511  unsigned pos = 0;
512  for (unsigned i = 0; i < iovcnt; ++i) {
513  memcpy(buffer + pos, iov[i].iov_base, iov[i].iov_len);
514  pos += iov[i].iov_len;
515  }
516 
517  int retval = send(fd_connection_, buffer, total_size, MSG_DONTWAIT);
518  if (retval < 0) {
519  assert(errno != EMSGSIZE);
520  if (!(flags_ & kFlagSendIgnoreFailure)) {
522  "failed to write to external cache transport (%d), aborting",
523  errno);
524  }
525  }
526 }
527 
528 
530  cvmfs::MsgRpc *msg_rpc = frame->GetMsgRpc();
531  int32_t size = msg_rpc->ByteSize();
532  assert(size > 0);
533 #ifdef __APPLE__
534  void *buffer = smalloc(size);
535 #else
536  void *buffer = alloca(size);
537 #endif
538  bool retval = msg_rpc->SerializeToArray(buffer, size);
539  assert(retval);
540  SendData(buffer, size, frame->attachment(), frame->att_size());
541 #ifdef __APPLE__
542  free(buffer);
543 #endif
544 }
static const unsigned kMaxStackAlloc
static const int kLabelCatalog
Definition: cache.h:80
#define PANIC(...)
Definition: exception.h:29
static const unsigned char kWireProtocolVersion
void SendNonBlocking(struct iovec *iov, unsigned iovcnt)
assert((mem||(size==0))&&"Out Of Memory")
void SendFrame(Frame *frame)
void FillObjectType(int object_flags, cvmfs::EnumObjectType *wire_type)
Algorithms algorithm
Definition: hash.h:125
unsigned char digest[digest_size_]
Definition: hash.h:124
static const uint32_t kFlagSendIgnoreFailure
void FillMsgHash(const shash::Any &hash, cvmfs::MsgHash *msg_hash)
void MergeFrom(const Frame &other)
static const uint32_t kMaxMsgSize
ssize_t SafeRead(int fd, void *buf, size_t nbyte)
Definition: posix.cc:2045
void * attachment() const
bool ParseMsgHash(const cvmfs::MsgHash &msg_hash, shash::Any *hash)
cvmfs::MsgRpc * GetMsgRpc()
uint32_t att_size() const
void set_att_size(uint32_t size)
static const unsigned char kFlagHasAttachment
google::protobuf::MessageLite * GetMsgTyped()
void SendData(void *message, uint32_t msg_size, void *attachment=NULL, uint32_t att_size=0)
static const int kLabelVolatile
Definition: cache.h:82
bool ParseMsgRpc(void *buffer, uint32_t size)
bool RecvFrame(Frame *frame)
static const unsigned kInnerHeaderSize
void Reset(uint32_t original_att_size)
static void size_t size
Definition: smalloc.h:54
const unsigned kDigestSizes[]
Definition: hash.h:69
static const unsigned kHeaderSize
int fd_connection() const
bool SafeWriteV(int fd, struct iovec *iov, unsigned iovcnt)
Definition: posix.cc:2004
static const char * kEnvReadyNotifyFd
static const uint32_t kFlagSendNonBlocking
bool ParseObjectType(cvmfs::EnumObjectType wire_type, int *object_flags)
CacheTransport(int fd_connection)
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)
Definition: logging.cc:528
bool RecvHeader(uint32_t *size, bool *has_attachment)