Exemple #1
0
// atomically decrement the refcount using __sync_add_and_fetch
// to get the value after the decrement. If the value drops
// to zero free the msg
void mc_msg_decref(mc_msg_t* msg) {
  FBI_ASSERT(msg != NULL);
  if (msg->_refcount != MSG_NOT_REFCOUNTED) {
    FBI_ASSERT(msg->_refcount > 0);

    int new_refcount;
    if (_mc_msg_use_atomic_refcounts) {
      new_refcount = __sync_add_and_fetch(&msg->_refcount, -1);
    } else {
#ifndef FBCODE_OPT_BUILD
      FBI_ASSERT(__sync_bool_compare_and_swap(&msg->_refcount, msg->_refcount,
                                              msg->_refcount - 1) == 1);
      new_refcount = msg->_refcount;
#else
      new_refcount = --msg->_refcount;
#endif
    }

    if (new_refcount == 0) {
      if (_mc_msg_track_num_outstanding) {
        __sync_fetch_and_add(&_mc_msg_num_outstanding, -1);
      }
#ifndef LIBMC_FBTRACE_DISABLE
      mc_fbtrace_info_decref(msg->fbtrace_info);
#endif
#ifndef FBCODE_OPT_BUILD
      memset(msg, 'P', sizeof(*msg));
#endif
      free(msg);
    }
  }
}
Exemple #2
0
int mc_msg_grow(mc_msg_t **msg_ptr, size_t len, void **field_ptr) {
  FBI_ASSERT(msg_ptr != NULL && field_ptr != NULL);
  mc_msg_t *msg = *msg_ptr;

  // assert that the field_ptr refers to something within the *msg
  FBI_ASSERT(_in_msg(msg, field_ptr, sizeof(*field_ptr)));

  size_t field_ptr_offset = (void*)field_ptr - (void*)msg;
  size_t field_offset = sizeof(*msg) + msg->_extra_size;

  mc_msg_t *new_msg = mc_msg_realloc(msg, msg->_extra_size + len);
  if (new_msg == NULL) {
    return -1;
  }

  msg = new_msg;

  void **new_field_ptr = (void**) ((void*)msg + field_ptr_offset);


  FBI_ASSERT((void*)field_ptr-(void*)(*msg_ptr) == (void*)new_field_ptr-(void*)msg);

  *new_field_ptr = ((void*)msg) + field_offset;
  *msg_ptr = msg;

  return 0;
}
Exemple #3
0
static void mc_fbtrace_decref(mc_fbtrace_t* fbt) {
  FBI_ASSERT(fbt);
  int newrefcount = __sync_add_and_fetch(&fbt->_refcount, -1);
  FBI_ASSERT(newrefcount >= 0);
  if (newrefcount == 0) {
    free(fbt);
  }
}
Exemple #4
0
ssize_t um_consume_one_message(um_parser_t* um_parser,
                               const uint8_t* buf, size_t nbuf,
                               uint64_t* reqid_out,
                               mc_msg_t** msg_out) {
  FBI_ASSERT(um_parser && buf && nbuf > 0 && reqid_out && msg_out);
  *msg_out = NULL;

  ssize_t consumed = entry_list_preparer_read(&um_parser->prep,
                                              (const char*)buf,
                                              nbuf);
  if (consumed <= 0) {
    goto error;
  }

  /* Because the rank of the unsigned integer is equal to the rank of the
   * signed integer, the signed integer is converted to the type of the
   * unsigned integer, and this assertion triggers on error.  To get around
   * this, we do the cast ourselves.
   */
  FBI_ASSERT(consumed <= (ssize_t)nbuf);

  if (entry_list_preparer_finished(&um_parser->prep)) {
    entry_list_t elist;
    if (entry_list_consume_preparer(&elist, &um_parser->prep) < 0) {
      goto error;
    }
    mc_msg_t base;
    mc_msg_init_not_refcounted(&base);
    _parse_info_t parse_info;
    if (_fill_base_msg(&elist, &base, &parse_info) != 0) {
      goto error;
    }
    *reqid_out = parse_info.reqid;

    *msg_out = _msg_create(&base, &elist, &parse_info);
    if (*msg_out == NULL) {
      dbg_error("msg_create failed");
      goto error;
    }

    FBI_ASSERT((*msg_out)->op != mc_op_end);

    entry_list_cleanup(&elist);
  } else {
    FBI_ASSERT(consumed == nbuf);
  }

  return consumed;

error:
  entry_list_preparer_reset_after_failure(&um_parser->prep);

  // Function that return an error must have not left any messages around
  FBI_ASSERT(*msg_out == NULL);
  return -1;
}
Exemple #5
0
mc_msg_t* mc_msg_dup(const mc_msg_t *msg) {
  FBI_ASSERT(msg);
  FBI_ASSERT(msg->_refcount > 0 || msg->_refcount == MSG_NOT_REFCOUNTED);
  mc_msg_t *msg_copy = mc_msg_new(msg->_extra_size);
  if (msg_copy == NULL) {
    return NULL;
  }
  _msgcpy(msg_copy, msg);
  return msg_copy;
}
Exemple #6
0
/* Return 1 if pointer p lies within mc_msg_t msg's body
 *        0 if pointer p to p + len does not overlap at all
 * assert that p <-> p + len does not partially overlap
 */
static inline int _in_msg(const mc_msg_t *msg, void *p, size_t n) {
  FBI_ASSERT(msg);
  void *end = (void*)msg + sizeof(mc_msg_t) + msg->_extra_size;
  if (p >= (void*)msg && p < end) {
    FBI_ASSERT(p + n <= end);
    return 1;
  }
  FBI_ASSERT(p + n <= (void*)msg || p > end); // No partial overlap
  return 0;
}
Exemple #7
0
/* copy src's contents into dst
 * dst->_extra_size must be greater than or equal to src->_extra_size
 * If any string fields occur within src's whole message, they will be
 * deep copied into dst's deep message.  External strings will be shallow
 * copied
 */
static void _msgcpy(mc_msg_t *dst, const mc_msg_t *src) {
  FBI_ASSERT(dst && (dst->_refcount > 0 || dst->_refcount == MSG_NOT_REFCOUNTED));
  FBI_ASSERT(src && (src->_refcount > 0 || src->_refcount == MSG_NOT_REFCOUNTED));
  FBI_ASSERT(dst->_extra_size >= src->_extra_size);

  // The difference between the old msg and the new message
  // By adding this to void*'s we can shift the pointer forward pretty easily
  //
  // Example:
  //  ________(delta)_________
  // |                        |
  // v                        v
  // |   src  ...  |          |   dst  ...   |
  //            ^                        ^
  //            ptr                      ptr
  //            |________(delta)_________|
  //
  // dst->ptr = (void*)src->ptr + delta
  ssize_t delta = (void*)dst - (void*)src;

  int _refcount = dst->_refcount;
  size_t _extra_size = dst->_extra_size;
  memcpy(dst, src, sizeof(mc_msg_t) + src->_extra_size);
  dst->_refcount = _refcount; // restore
  dst->_extra_size = _extra_size; // restore
#ifndef LIBMC_FBTRACE_DISABLE
  if (src->fbtrace_info) {
    dst->fbtrace_info = mc_fbtrace_info_deep_copy(src->fbtrace_info);
  }
#endif

  if (src->stats != NULL) {
    int i, stats_count = src->number * 2;
    FBI_ASSERT(stats_count > 0);
    if (_in_msg(src, src->stats, sizeof(src->stats[0]) * stats_count)) {
      dst->stats = (void*)(src->stats) + delta;
      for (i = 0; i < stats_count; i++) {
        if (_in_msg(src, src->stats[i].str, src->stats[i].len)) {
          dst->stats[i].str = (void*)(src->stats[i].str) + delta;
        }
      }
    }
  }
  if (_in_msg(src, src->key.str, src->key.len)) {
    dst->key.str = (void*)(src->key.str) + delta;
  }
  if (_in_msg(src, src->value.str, src->value.len)) {
    dst->value.str = (void*)(src->value.str) + delta;
  }
}
Exemple #8
0
static char* stats_reply_to_string(nstring_t *stats,
                                   size_t num_stats,
                                   size_t *len) {
    uint64_t i;
    size_t slen = 0;
    size_t off = 0;
    char *s = NULL;

    for (i = 0; i < num_stats; i++) {
        nstring_t *name = &stats[2 * i];
        nstring_t *value = &stats[2 * i + 1];
        // At least one of them should have non-zero length
        FBI_ASSERT(name->len || value->len);

        // Not as naive as it looks, the compiler precomputes strlen for constants
        slen += strlen("STAT " /* name\s?value */ ASCII_TERM);
        slen += name->len;
        slen += value->len;
        if (name->len > 0 && value->len > 0) slen++; // space between them
    }
    slen += strlen("END\r\n");
    slen += 1; // '\0'

    s = malloc(slen);
    if (s == NULL) {
        return s;
    }

    for (i = 0; i < num_stats; i++) {
        nstring_t *name = &stats[2 * i];
        nstring_t *value = &stats[2 * i + 1];
        off += snprintf(s + off, slen - off, "STAT");
        if (name->len) {
            off += snprintf(s+off, slen-off, " %.*s", (int) name->len, name->str);
        }
        if (value->len) {
            off += snprintf(s+off, slen-off, " %.*s", (int) value->len, value->str);
        }
        memcpy(s+off, ASCII_TERM, strlen(ASCII_TERM));
        off += strlen(ASCII_TERM);
        FBI_ASSERT(off < slen);
    }

    FBI_ASSERT(slen - off == strlen("END\r\n") + 1);
    snprintf(s + off, slen - off, "END\r\n");

    *len = slen - 1;
    return s;
}
Exemple #9
0
void ProxyThread::proxyThreadRun() {
  FBI_ASSERT(proxy->router != nullptr);
  mcrouter_set_thread_name(pthread_self(), proxy->router->opts, "mcrpxy");

  while(!proxy->router->shutdownStarted()) {
    mcrouterLoopOnce(proxy->eventBase);
  }

  while (proxy->fiberManager.hasTasks()) {
    mcrouterLoopOnce(proxy->eventBase);
  }

  proxy->stopAwriterThreads();
  // Delete the proxy from the proxy thread so that the clients get
  // deleted from the same thread where they were created.
  folly::EventBase *eventBase = proxy->eventBase;
  std::unique_lock<std::mutex> lk(mux);
  // This is to avoid a race condition where proxy is deleted
  // before the call to stopAndJoin is made.
  cv.wait(lk,
    [this]() {
      return this->isSafeToDeleteProxy;
    });
  delete proxy;
  if (eventBase != nullptr) {
    delete eventBase;
  }
}
Exemple #10
0
int dynamic_stats_unregister(dynamic_stat_t* stat_ptr) {
  FBI_ASSERT(stat_ptr);
  FBI_ASSERT(dynamic_stats_initialized);

  {
    std::lock_guard<std::mutex> guard(dynamic_stats_mutex());
    TAILQ_REMOVE(&all_dynamic_stats, stat_ptr, entry);
  }

  if (stat_ptr->stat.type == stat_string) {
    free(stat_ptr->stat.data.string);
  }
  free(stat_ptr);

  return 0;
}
ProxyRequestContext::ProxyRequestContext(
  proxy_request_t* preq,
  std::shared_ptr<const ProxyConfigIf> config)
    : preq_(proxy_request_incref(preq)),
      config_(std::move(config)) {
  FBI_ASSERT(preq_);
}
Exemple #12
0
// atomically increment the refcount using __sync_fetch_and_add
mc_msg_t* mc_msg_incref(mc_msg_t* msg) {
  FBI_ASSERT(msg != NULL);
  if (msg->_refcount != MSG_NOT_REFCOUNTED) {
    FBI_ASSERT(msg->_refcount >= 0);
    if (_mc_msg_use_atomic_refcounts) {
      __sync_fetch_and_add(&msg->_refcount, 1);
    } else {
#ifndef FBCODE_OPT_BUILD
      FBI_ASSERT(__sync_bool_compare_and_swap(&msg->_refcount, msg->_refcount,
                                              msg->_refcount + 1) == 1);
#else
      msg->_refcount++;
#endif
    }
  }
  return msg;
}
Exemple #13
0
mc_fbtrace_info_t* mc_fbtrace_info_incref(mc_fbtrace_info_t* fbt_i) {
  if (!fbt_i) {
    return NULL;
  }
  int newrefcount = __sync_add_and_fetch(&fbt_i->_refcount, 1);
  FBI_ASSERT(newrefcount > 0);
  return fbt_i;
}
void DestinationClient::initializeAsyncMcClient() {
  FBI_ASSERT(proxy_->eventBase);

  auto pdstn = pdstn_.lock();
  assert(pdstn != nullptr);

  ConnectionOptions options(pdstn->accessPoint);
  options.noNetwork = proxy_->opts.no_network;
  options.tcpKeepAliveCount = proxy_->opts.keepalive_cnt;
  options.tcpKeepAliveIdle = proxy_->opts.keepalive_idle_s;
  options.tcpKeepAliveInterval = proxy_->opts.keepalive_interval_s;
  options.timeout = std::chrono::duration_cast<std::chrono::milliseconds>(
    std::chrono::seconds(pdstn->server_timeout.tv_sec) +
    std::chrono::microseconds(pdstn->server_timeout.tv_usec));
  if (proxy_->opts.enable_qos) {
    options.enableQoS = true;
    options.qos = pdstn->qos;
  }

  if (pdstn->use_ssl) {
    auto& opts = proxy_->opts;
    checkLogic(!opts.pem_cert_path.empty() &&
               !opts.pem_key_path.empty() &&
               !opts.pem_ca_path.empty(),
               "Some of ssl key paths are not set!");
    options.sslContextProvider = [&opts] {
      return getSSLContext(opts.pem_cert_path, opts.pem_key_path,
                           opts.pem_ca_path);
    };
  }

  asyncMcClient_ = folly::make_unique<AsyncMcClient>(*proxy_->eventBase,
                                                     std::move(options));

  auto pdstnWeakPtr = pdstn_;
  asyncMcClient_->setStatusCallbacks(
    [pdstnWeakPtr] () {
      auto pdstnPtr = pdstnWeakPtr.lock();
      if (!pdstnPtr) {
        return;
      }
      pdstnPtr->on_up();
    },
    [pdstnWeakPtr] (const apache::thrift::transport::TTransportException&) {
      auto pdstnPtr = pdstnWeakPtr.lock();
      if (!pdstnPtr) {
        return;
      }
      pdstnPtr->on_down();
    });

  if (proxy_->opts.target_max_inflight_requests > 0) {
    asyncMcClient_->setThrottle(proxy_->opts.target_max_inflight_requests,
                                proxy_->opts.target_max_pending_requests);
  }
}
Exemple #15
0
mc_msg_t* mc_msg_dup_append_key_full(const mc_msg_t *msg,
                                     const char* key_append,
                                     size_t nkey_append) {
  FBI_ASSERT(msg);
  FBI_ASSERT(msg->_refcount > 0 || msg->_refcount == MSG_NOT_REFCOUNTED);
  FBI_ASSERT(key_append);

  // Stats are not supported.
  if (msg->stats) {
    return NULL;
  }

  if (!nkey_append) {
    return mc_msg_dup(msg);
  }

  size_t new_extra_size = msg->_extra_size + nkey_append;
  if (!_in_msg(msg, msg->key.str, msg->key.len)) {
    new_extra_size += msg->key.len + 1; // +1 for null terminator
  }
  mc_msg_t* const msg_copy = mc_msg_new(new_extra_size);
  if (msg_copy == NULL) {
    return NULL;
  }
  mc_msg_shallow_copy(msg_copy, msg);

  // The new message's key is always embedded.
  msg_copy->key.len = msg->key.len + nkey_append;
  msg_copy->key.str = (void*) msg_copy + sizeof(*msg_copy);
  memcpy(msg_copy->key.str, msg->key.str, msg->key.len);
  memcpy(msg_copy->key.str + msg->key.len, key_append, nkey_append);
  msg_copy->key.str[msg_copy->key.len] = 0;

  if (_in_msg(msg, msg->value.str, msg->value.len)) {
    // The value starts after the key, including the null terminator.
    msg_copy->value.str = msg_copy->key.str + msg_copy->key.len + 1;
    memcpy(msg_copy->value.str, msg->value.str, msg_copy->value.len);
  }
  return msg_copy;
}
Exemple #16
0
void mc_msg_nzlib_compress(mc_msg_t **msgP) {
  FBI_ASSERT(msgP && *msgP);
  mc_msg_t *msg = *msgP;
  nzlib_format_t *format = NULL;
  size_t len = 0;
  int rc;

  if (msg->value.str == NULL
      || msg->value.len <= 0
      || (msg->flags & MC_MSG_FLAG_NZLIB_COMPRESSED)) {
    goto epilogue;
  }


  // Get the upper bound on the deflated value length
  len = compressBound(msg->value.len);
  format = malloc(sizeof(*format) + len);
  if (format == NULL) {
    goto epilogue;
  }
  format->magic = htonl(NZLIB_MAGIC);
  format->decompressed_sz = htonl(msg->value.len);

  rc = compress(format->buf, &len, (uint8_t*)msg->value.str, msg->value.len);
  if (rc != Z_OK) {
    goto epilogue;
  }

  len += sizeof(*format);
  if (len >= msg->value.len) {
    goto epilogue;
  }

  // If msg->value is not in the msg, grow the msg so we don't trample
  // someone else's value buffer
  if (!_in_msg(msg, msg->value.str, msg->value.len)
      && mc_msg_grow(&msg, len + 1, (void**) &msg->value.str) != 0) {
    goto epilogue;
  }

  msg->value.len = len;
  memcpy(msg->value.str, format, len);
  msg->value.str[len] = '\0';
  msg->flags |= MC_MSG_FLAG_NZLIB_COMPRESSED;

  *msgP = msg;

epilogue:
  if (format) {
    free(format);
  }
}
Exemple #17
0
static void _backing_msg_fill(um_backing_msg_t* bmsg,
                              uint64_t reqid, mc_msg_t* msg,
                              struct iovec* value_iovs,
                              size_t n_value_iovs) {
  FBI_ASSERT(bmsg->msg == NULL);
  if (msg->_refcount != MSG_NOT_REFCOUNTED) {
    bmsg->msg = mc_msg_incref(msg);
  } else {
    bmsg->msg = NULL;
  }
  _msg_to_elist(&bmsg->elist, reqid, msg, value_iovs, n_value_iovs);
  bmsg->inuse = 1;
}
Exemple #18
0
void mc_fbtrace_info_decref(mc_fbtrace_info_t* fbt_i) {
  if (!fbt_i) {
    return;
  }
  int newrefcount = __sync_add_and_fetch(&fbt_i->_refcount, -1);
  FBI_ASSERT(newrefcount >= 0);
  if (newrefcount == 0) {
    if (fbt_i->fbtrace) {
      mc_fbtrace_decref(fbt_i->fbtrace);
    }
    free(fbt_i);
  }
}
Exemple #19
0
void mc_msg_shallow_copy(mc_msg_t *dst, const mc_msg_t *src) {
  FBI_ASSERT(dst && src);
  int _refcount = dst->_refcount;
  size_t _extra_size = dst->_extra_size;
  *dst = *src;
  dst->_refcount = _refcount;
  dst->_extra_size = _extra_size;
#ifndef LIBMC_FBTRACE_DISABLE
  if (src->fbtrace_info) {
    dst->fbtrace_info = mc_fbtrace_info_deep_copy(src->fbtrace_info);
  }
#endif
}
Exemple #20
0
dynamic_stat_t* dynamic_stats_register(const stat_t* stat, void* ptr) {
  // Check for unique name?
  FBI_ASSERT(dynamic_stats_initialized);
  dynamic_stat_t* ret = (dynamic_stat_t*) malloc(sizeof(dynamic_stat_t));
  if (ret != nullptr) {
    memcpy(&ret->stat, stat, sizeof(stat_t));
    ret->entity_ptr = ptr;

    {
      std::lock_guard<std::mutex> guard(dynamic_stats_mutex());
      TAILQ_INSERT_TAIL(&all_dynamic_stats, ret, entry);
    }
  }
  return ret;
}
Exemple #21
0
int um_consume_buffer(um_parser_t* um_parser,
                      const uint8_t* buf, size_t nbuf,
                      msg_ready_cb* msg_ready,
                      void* context) {
  while (nbuf > 0) {
    uint64_t reqid;
    mc_msg_t* msg;
    ssize_t consumed = um_consume_one_message(um_parser,
                                              buf, nbuf, &reqid, &msg);
    if (consumed <= 0) {
      return -1;
    }
    FBI_ASSERT(consumed <= nbuf);
    if (msg != NULL) {
      msg_ready(context, reqid, msg);
      buf += consumed;
      nbuf -= consumed;
    } else {
      FBI_ASSERT(consumed == nbuf);
      break;
    }
  }
  return 0;
}
Exemple #22
0
int mc_msg_decompress(mc_msg_t **msgP) {
  FBI_ASSERT(msgP && *msgP);
  mc_msg_t *msg = *msgP;

  if (msg->value.str == NULL
      || msg->value.len == 0) {
    return 0;
  }

  if (msg->flags & MC_MSG_FLAG_NZLIB_COMPRESSED) {
    return mc_msg_nzlib_decompress(msgP);
  }

  // Not compressed
  return 0;
}
Exemple #23
0
um_status_t um_consume_no_copy(const uint8_t* header, size_t nheader,
                               const uint8_t* body, size_t nbody,
                               uint64_t* reqid_out,
                               mc_msg_t* msg_out) {
  FBI_ASSERT(header && body && reqid_out && msg_out);
  um_message_info_t info;
  um_status_t header_rv = um_parse_header(header, nheader, &info);
  if (header_rv != um_ok) {
    return header_rv;
  }
  if (!(nheader == info.header_size &&
        nbody == info.body_size &&
        nheader + nbody == info.message_size)) {
    return um_invalid_range;
  }

  entry_list_t elist;
  entry_list_init(&elist);
  /* We know that header/body won't be modified here,
     but the interface is messed up */
  ssize_t rv = entry_list_read_from_buf(&elist,
                                        (char*)header, nheader,
                                        (char*)body, nbody,
                                        /*free_buf_when_done=*/0);
  if (rv < 0 || rv != info.message_size) {
    return um_message_parse_error;
  }

  _parse_info_t parse_info;
  if (_fill_base_msg(&elist, msg_out, &parse_info) != 0) {
    return um_message_parse_error;
  }

  /* TODO: support stats with no_copy API */
  if (parse_info.stats_count > 0) {
    return um_message_parse_error;
  }

  if (_fill_msg_strs(msg_out, &elist, body, &parse_info) != 0) {
    return um_message_parse_error;
  }

  *reqid_out = parse_info.reqid;

  return um_ok;
}
Exemple #24
0
int um_emit_iovs_extended(um_backing_msg_t* bmsg,
                          uint64_t reqid,
                          mc_msg_t* msg,
                          struct iovec* value_iovs,
                          size_t n_value_iovs,
                          emit_iov_cb* emit_iov,
                          void* context) {

  FBI_ASSERT(bmsg && !bmsg->inuse && msg && msg->op != mc_op_end && emit_iov);
  _backing_msg_fill(bmsg, reqid, msg, value_iovs, n_value_iovs);

  if (entry_list_emit_iovs(&bmsg->elist, emit_iov, context)) {
    um_backing_msg_cleanup(bmsg);
    return -1;
  }

  return 0;
}
Exemple #25
0
ssize_t um_write_iovs_extended(um_backing_msg_t* bmsg,
                               uint64_t reqid,
                               mc_msg_t* msg,
                               struct iovec* value_iovs,
                               size_t n_value_iovs,
                               struct iovec* iovs,
                               size_t n_iovs) {

  FBI_ASSERT(bmsg && !bmsg->inuse && msg && msg->op != mc_op_end && iovs);
  _backing_msg_fill(bmsg, reqid, msg, value_iovs, n_value_iovs);

  int iovs_used = entry_list_to_iovecs(&bmsg->elist, iovs, n_iovs);
  if (iovs_used <= 0) {
    um_backing_msg_cleanup(bmsg);
    return -1;
  }

  return iovs_used;
}
Exemple #26
0
void ProxyThread::stopAndJoin() {
  if (thread_handle && proxy->router->pid == getpid()) {
    FBI_ASSERT(proxy->request_queue != nullptr);
    asox_queue_entry_t entry;
    entry.type = request_type_router_shutdown;
    entry.priority = 0;
    entry.data = nullptr;
    entry.nbytes = 0;
    asox_queue_enqueue(proxy->request_queue, &entry);
    {
      std::unique_lock<std::mutex> lk(mux);
      isSafeToDeleteProxy = true;
    }
    cv.notify_all();
    pthread_join(thread_handle, nullptr);
  }
  if (thread_stack) {
    free(thread_stack);
  }
}
Exemple #27
0
um_status_t um_parse_header(const uint8_t* buf, size_t nbuf,
                            um_message_info_t* info_out) {
  FBI_ASSERT(info_out);
  if (nbuf < sizeof(entry_list_msg_t)) {
    return um_not_enough_data;
  }

  entry_list_msg_t* header = (entry_list_msg_t*) buf;
  if (header->msg_header.magic_byte != ENTRY_LIST_MAGIC_BYTE) {
    return um_not_umbrella_message;
  }

  info_out->message_size = ntoh32(header->total_size);
  uint16_t nentries = ntoh16(header->nentries);

  info_out->header_size = sizeof(entry_list_msg_t) +
    sizeof(um_elist_entry_t) * nentries;
  if (info_out->header_size > info_out->message_size) {
    return um_header_parse_error;
  }
  info_out->body_size = info_out->message_size - info_out->header_size;

  return um_ok;
}
Exemple #28
0
int um_parser_init(um_parser_t* um_parser) {
  FBI_ASSERT(um_parser);
  entry_list_preparer_init(&um_parser->prep);
  return 0;
}
Exemple #29
0
size_t mc_ascii_response_write_iovs(mc_ascii_response_buf_t* buf,
                                    const mc_msg_t* req,
                                    const mc_msg_t* reply,
                                    struct iovec* iovs,
                                    size_t max_niovs) {
    size_t niovs = 0;
    buf->offset = 0;

    if (mc_res_is_err(reply->result)) {
        if (reply->value.len > 0) {
            if (reply->result == mc_res_client_error) {
                IOV_WRITE_CONST_STR("CLIENT_ERROR ");
            } else {
                IOV_WRITE_CONST_STR("SERVER_ERROR ");
            }
            if (reply->err_code != 0) {
                IOV_FORMAT(buf, "%" PRIu32 " ", reply->err_code);
            }
            IOV_WRITE_NSTRING(reply->value);
            IOV_WRITE_CONST_STR("\r\n");
        } else {
            IOV_WRITE_STR(mc_res_to_response_string(reply->result));
        }
        return niovs;
    }

    switch (req->op) {
    case mc_op_incr:
    case mc_op_decr:
        switch (reply->result) {
        case mc_res_stored:
            IOV_FORMAT(buf, "%" PRIu64 "\r\n", reply->delta);
            break;
        case mc_res_notfound:
            IOV_WRITE_CONST_STR("NOT_FOUND\r\n");
            break;
        default:
            goto UNEXPECTED;
        }
        break;

    case mc_op_set:
    case mc_op_lease_set:
    case mc_op_add:
    case mc_op_replace:
    case mc_op_append:
    case mc_op_prepend:
    case mc_op_cas:
        switch (reply->result) {
        case mc_res_ok:
            IOV_WRITE_STR(mc_res_to_response_string(mc_res_stored));
            break;

        case mc_res_stored:
        case mc_res_stalestored:
        case mc_res_found:
        case mc_res_notstored:
        case mc_res_notfound:
        case mc_res_exists:
            IOV_WRITE_STR(mc_res_to_response_string(reply->result));
            break;

        default:
            goto UNEXPECTED;
        }
        break;

    case mc_op_delete:
        switch (reply->result) {
        case mc_res_deleted:
        case mc_res_notfound:
            IOV_WRITE_STR(mc_res_to_response_string(reply->result));
            break;
        default:
            goto UNEXPECTED;
        }

        break;

    case mc_op_get:
    case mc_op_lease_get:
    case mc_op_gets:
        switch (reply->result) {
        case mc_res_found:
            IOV_WRITE_CONST_STR("VALUE ");
            IOV_WRITE_NSTRING(req->key);
            IOV_FORMAT(buf, " %" PRIu64 " %lu", reply->flags,
                       reply->value.len);
            if (req->op == mc_op_gets) {
                IOV_FORMAT(buf, " %" PRIu64, reply->cas);
            }
            IOV_WRITE_CONST_STR("\r\n");
            IOV_WRITE_NSTRING(reply->value);
            IOV_WRITE_CONST_STR("\r\n");
            break;

        case mc_res_notfound:
            if (req->op != mc_op_lease_get) {
                // misses should have been suppressed!
                goto UNEXPECTED;
            }
            // but lease-get always has a response
            IOV_WRITE_CONST_STR("LVALUE ");
            IOV_WRITE_NSTRING(req->key);
            IOV_FORMAT(buf, " %" PRIu64 " %"PRIu64 " %zu\r\n",
                       reply->lease_id,
                       reply->flags,
                       reply->value.len);
            IOV_WRITE_NSTRING(reply->value);
            IOV_WRITE_CONST_STR("\r\n");
            break;

        default:
            goto UNEXPECTED;
        }
        break;

    case mc_op_metaget:
        switch (reply->result) {
        case mc_res_found:
            /* (META key age: (unknown|\d+); exptime: \d+;
               from: (\d+\.\d+\.\d+\.\d+|unknown); is_transient: (1|0)\r\n) */
            IOV_WRITE_CONST_STR("META ");
            IOV_WRITE_NSTRING(req->key);
            IOV_WRITE_CONST_STR(" age: ");
            if (reply->number == (uint32_t) -1) {
                IOV_WRITE_CONST_STR("unknown");
            }
            else {
                IOV_FORMAT(buf, "%d", reply->number);
            }
            IOV_WRITE_CONST_STR("; exptime: ");
            IOV_FORMAT(buf, "%d", reply->exptime);
            IOV_WRITE_CONST_STR("; from: ");
            if (reply->ipv == 0) {
                IOV_WRITE_CONST_STR("unknown");
            }
            else {
                IOV_WRITE_IP(buf, reply->ipv, &(reply->ip_addr));
            }
            IOV_WRITE_CONST_STR("; is_transient: ");
            IOV_FORMAT(buf, "%" PRIu64, reply->flags);
            IOV_WRITE_CONST_STR("\r\n");
            break;
        case mc_res_notfound:
            break;
        default:
            goto UNEXPECTED;
        }
        break;

    case mc_op_end:
        if (reply->result == mc_res_found) {
            IOV_WRITE_CONST_STR("END\r\n");
        }
        else {
            IOV_WRITE_STR(mc_res_to_response_string(reply->result));
        }
        break;

    case mc_op_stats:
        switch (reply->result) {
        case mc_res_ok:
        {
            size_t length = 0;
            char* stats;
            if (reply->stats) {
                /* TODO(agartrell) assert(!reply->value.str)
                 *
                 * The assert here can't be turned on until
                 * mcrouter/stats.c:560 has been fixed to not set both
                 * value and stats on the libmc reply
                 */
                stats = stats_reply_to_string(reply->stats, reply->number, &length);
                buf->stats = stats;
            } else {
                stats = reply->value.str;
                length = reply->value.len;
            }

            if (!stats) {
                return 0;
            }

            IOV_WRITE(stats, length);
            break;
        }
        default:
            goto UNEXPECTED;
        }
        break;

    case mc_op_flushall:
    case mc_op_flushre:
        IOV_WRITE_CONST_STR("OK\r\n");
        break;

    case mc_op_version:
        IOV_WRITE_CONST_STR("VERSION ");
        IOV_WRITE_NSTRING(reply->value);
        IOV_WRITE_CONST_STR("\r\n");
        break;

    case mc_op_shutdown:
        if (reply->result == mc_res_ok) {
            IOV_WRITE_CONST_STR("OK\r\n");
        }
        else {
            goto UNEXPECTED;
        }
        break;

    case mc_op_exec:
        switch (reply->result) {
        case mc_res_ok:
            IOV_WRITE_NSTRING(reply->value);
            IOV_WRITE_CONST_STR("\r\n");
            break;
        default:
            goto UNEXPECTED;
        }
        break;

    default:
        IOV_WRITE_CONST_STR("SERVER_ERROR unhandled token ");
        IOV_WRITE_STR(mc_op_to_string(req->op));
        IOV_FORMAT(buf, " (%d)\r\n", (int)req->op);
        break;
    }

    return niovs;

UNEXPECTED:
    FBI_ASSERT(niovs == 0);
    IOV_WRITE_CONST_STR("SERVER_ERROR unexpected result ");
    IOV_WRITE_STR(mc_res_to_string(reply->result));
    IOV_FORMAT(buf, " (%d) for ", (int)reply->result);
    IOV_WRITE_STR(mc_op_to_string(req->op));
    IOV_FORMAT(buf, " (%d)\r\n", (int)req->op);
    return niovs;
}
Exemple #30
0
static int _fill_base_msg(entry_list_t *elist,
                          mc_msg_t* base,
                          _parse_info_t* parse_info) {
  FBI_ASSERT(elist && base && parse_info);
  uint64_t i;
  int numDoubles = 0;
  parse_info->reqid = 0;
  parse_info->key_idx = -1;
  parse_info->value_idx = -1;

#ifndef LIBMC_FBTRACE_DISABLE

  parse_info->fbtrace_idx = -1;

#endif

  parse_info->stats_count = 0;
  uint64_t field_mask = 0;

  for (i = 0; i < elist->nentries; i++) {
    uint16_t tag = ntoh16(elist->entries[i].tag);
    uint64_t val = ntoh64(elist->entries[i].data.val);

    // No dup fields (except for stats and double)
    if ((tag & field_mask) && (tag != msg_stats && tag != msg_double)) {
      dbg_error("Duplicate field: field_mask = 0x%lX, field = 0x%X\n",
                field_mask, tag);
      return -1;
    }
    field_mask |= tag;
    switch (tag) {
      case msg_op:
        if (val >= UM_NOPS) {
          return -1;
        }
        base->op = umbrella_op_to_mc[val];
        if (base->op == mc_nops) {
          return -1;
        }
        break;
      case msg_result:
        if (val >= mc_nres) {
          return -1;
        }
        base->result = umbrella_res_to_mc[val];
        break;
      case msg_reqid:
        if (val == 0) {
          return -1;
        }
        parse_info->reqid = val;
        break;
      case msg_err_code:
        base->err_code = val;
        break;
      case msg_flags:
        base->flags = val;
        break;
      case msg_exptime:
        base->exptime = val;
        break;
      case msg_number:
        base->number = val;
        break;
      case msg_delta:
        base->delta = val;
        break;
      case msg_lease_id:
        base->lease_id = val;
        break;
      case msg_cas:
        base->cas = val;
        break;
      case msg_double:
        if (numDoubles == 0 ) {
          memcpy(&base->lowval, &val, sizeof(double));
        } else if (numDoubles == 1) {
          memcpy(&base->highval, &val, sizeof(double));
        } else {
          return -1;
        }
        numDoubles++;
        break;
      case msg_key:
        if (parse_info->key_idx == -1) {
          parse_info->key_idx = i;
        }
        break;
      case msg_value:
        if (parse_info->value_idx != -1) {
          return -1;
        }
        parse_info->value_idx = i;
        break;
      case msg_stats:
        parse_info->stats_count++;
        break;

#ifndef LIBMC_FBTRACE_DISABLE

      case msg_fbtrace:
        if (parse_info->fbtrace_idx != -1) {
          return -1;
        }
        parse_info->fbtrace_idx = i;
        break;

#endif

      default:
        return -1;
    }
  }

  if (parse_info->reqid == 0) {
    return -1;
  }
  if (parse_info->key_idx >= (int64_t)elist->nentries) {
    return -1;
  }
  if (parse_info->value_idx >= (int64_t)elist->nentries) {
    return -1;
  }

  if (!valid_msg(base->op, field_mask)) {
    dbg_error("Invalid message");
    return -1;
  }

  return 0;
}