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