<commit_before>#include <cstdio>
#include <cstring>
#include <davix.hpp>
#include <sstream>
#include <unistd.h>
#include "copy_internal.hpp"
#include "delegation/delegation.hpp"
#include <utils/davix_logger_internal.hpp>

using namespace Davix;

const std::string COPY_SCOPE = "Davix::HttpThirdPartyCopy";

// Gets the real location of uri respect to ref
// uri can be absolute or relative to ref
static std::string _full_url(const std::string ref,
        const std::string& uri)
{
    std::string final;

    if (uri.find("://") != std::string::npos) {
        final = uri;
    }
    else if (uri[0] == '/') {
        size_t colon = ref.find(':');
        size_t slash = std::string::npos;
        if (colon != std::string::npos)
            slash = ref.find('/', colon + 3);
        if (slash != std::string::npos) {
            std::string base = ref.substr(0, slash);
            final = base + uri;
        }
    }
    else {
        final = ref + uri;
    }

    return final;
}

// Same as _full_url, but it makes sure
// that the destination is https
static std::string _full_delegation_endpoint(const std::string& ref,
        const std::string& uri, DavixError** err)
{
    std::string final = _full_url(ref, uri);
    if (final.substr(7).compare("http://") == 0) {
        DavixError::setupError(err, COPY_SCOPE, StatusCode::OperationNonSupported,
                               std::string("Plain http can not be used for delegation: ") + uri);
        final.clear();
    }
    return final;
}

DavixCopy::DavixCopy(Context &c, const RequestParams *params): d_ptr(NULL)
{
    d_ptr = new DavixCopyInternal(c, params);
}

DavixCopy::~DavixCopy()
{
    delete d_ptr;
}

void DavixCopy::copy(const Uri &source, const Uri &destination,
        unsigned nstreams, DavixError **error)
{
    d_ptr->copy(source, destination, nstreams, error);
}

void DavixCopy::setPerformanceCallback(PerformanceCallback callback, void *udata)
{
    d_ptr->setPerformanceCallback(callback, udata);
}

void DavixCopyInternal::setPerformanceCallback(DavixCopy::PerformanceCallback callback,
        void *udata)
{
    perfCallback = callback;
    perfCallbackUdata = udata;
}

void DavixCopyInternal::copy(const Uri &src, const Uri &dst,
        unsigned nstreams, DavixError **error)
{
    std::string nextSrc(src.getString()), prevSrc(src.getString());
    std::string destination(dst.getString());
    std::string delegationEndpoint;
    DavixError *internalError = NULL;

    // nstreams as string
    char nstreamsStr[16];
    snprintf(nstreamsStr, sizeof(nstreamsStr), "%u", nstreams);

    // Need a copy so we can modify it
    Davix::RequestParams requestParams(parameters);
    requestParams.setTransparentRedirectionSupport(false);

    // Perform COPY hopping through redirections
    HttpRequest* request = NULL;
    do {
        nextSrc = _full_url(prevSrc, nextSrc);
        prevSrc = nextSrc;
        if (request) {
            request->discardBody(&internalError);
            if (!internalError)
                request->endRequest(&internalError);
            if (internalError) {
                DavixError::propagatePrefixedError(error, internalError, __func__);
                break;
            }
        }
        delete request;

        DAVIX_SLOG(DAVIX_LOG_VERBOSE, DAVIX_LOG_GRID, "Hop: {}",
                     nextSrc);

        request = context.createRequest(nextSrc, &internalError);
        if (internalError) {
            DavixError::propagatePrefixedError(error, internalError, __func__);
            break;
        }

        request->setRequestMethod("COPY");
        request->addHeaderField("Destination", destination);
        request->addHeaderField("X-Number-Of-Streams", nstreamsStr);
        request->setParameters(requestParams);
        request->beginRequest(&internalError);
        if (internalError) {
            DavixError::propagatePrefixedError(error, internalError, __func__);
            break;
        }

        // If we get a X-Delegate-To, before continuing, delegate
        if (request->getAnswerHeader("X-Delegate-To", delegationEndpoint)) {
            delegationEndpoint = _full_delegation_endpoint(nextSrc,
                                                           delegationEndpoint,
                                                           &internalError);
            if (internalError) {
                DavixError::propagatePrefixedError(error, internalError, __func__);
                break;
            }

            DAVIX_SLOG(DAVIX_LOG_VERBOSE, DAVIX_LOG_GRID, "Got delegation endpoint: {}",
                         delegationEndpoint.c_str());

            std::string dlg_id = DavixDelegation::delegate(context, delegationEndpoint,
                    parameters, &internalError);
            if (internalError) {
                DavixError::propagatePrefixedError(error, internalError, __func__);
                break;
            }

            DAVIX_SLOG(DAVIX_LOG_VERBOSE, DAVIX_LOG_GRID, "Got delegation ID {}",
                         dlg_id.c_str());

            dlg_id.clear();
        }

    } while (request->getAnswerHeader("Location", nextSrc));

    if (!*error) {
        int responseStatus = request->getRequestCode();
        if (responseStatus == 404) {
            DavixError::setupError(error, COPY_SCOPE, StatusCode::FileNotFound,
                                   "Could not COPY. File not found");
        }
        else if (responseStatus == 403) {
            DavixError::setupError(error, COPY_SCOPE, StatusCode::PermissionRefused,
                                   "Could not COPY. Permission denied.");
        }
        else if (responseStatus == 501) {
            DavixError::setupError(error, COPY_SCOPE, StatusCode::OperationNonSupported,
                                   "Could not COPY. The source service does not support it");
        }
        else if (responseStatus >= 405) {
            DavixError::setupError(error, COPY_SCOPE, StatusCode::OperationNonSupported,
                                   "Could not COPY. The source service does not allow it");
        }
        else if (responseStatus == 400) {
            std::string err_msg(request->getAnswerContentVec().begin(), request->getAnswerContentVec().end());
        	DavixError::setupError(error, COPY_SCOPE, StatusCode::InvalidArgument,
                                   fmt::format("Could not COPY. The server rejected the request: {}", err_msg));
        }
        else if (responseStatus >= 300) {
            std::ostringstream msg;
            msg << "Could not COPY. Unknown error code: " << responseStatus;
            DavixError::setupError(error, COPY_SCOPE, StatusCode::UnknowError,
                                   msg.str());
        }
    }

    // Did we fail?
    if (*error)
        return;

    // Finished hopping
    std::string finalSource = nextSrc;

    // Just wait for it to finish
    monitorPerformanceMarkers(request, error);
    request->endRequest(error);
    delete request;
}

void DavixCopyInternal::monitorPerformanceMarkers(Davix::HttpRequest *request,
        Davix::DavixError **error)
{
    Davix::DavixError* daverr = NULL;
    char buffer[1024], *p;
    dav_ssize_t line_len;

    PerformanceMarker holder;
    PerformanceData performance;
    time_t lastPerfCallback = time(NULL);

    while ((line_len = request->readLine(buffer, sizeof(buffer), &daverr)) >= 0 && !daverr)
    {
        buffer[line_len] = '\0';

        if (line_len > 0)
            DAVIX_SLOG(DAVIX_LOG_VERBOSE, DAVIX_LOG_GRID, "Received: {}", buffer);

        // Skip heading whitespaces
        p = buffer;
        while (*p && p < buffer + sizeof(buffer) && isspace(*p))
            ++p;

        if (strncasecmp("Perf Marker", p, 11) == 0)
        {
            memset(&holder, 0, sizeof(holder));
        }
        else if (strncasecmp("Timestamp:", p, 10) == 0)
        {
            holder.latest = atol(p + 10);
        }
        else if (strncasecmp("Stripe Index:", p, 13) == 0)
        {
            holder.index = atoi(p + 13);
        }
        else if (strncasecmp("Stripe Bytes Transferred:", p, 25) == 0)
        {
            holder.transferred = atol(p + 26);
        }
        else if (strncasecmp("Total Stripe Count:", p, 19) == 0)
        {
            holder.count = atoi(p + 20);
        }
        else if (strncasecmp("End", p, 3) == 0)
        {
            performance.update(holder);
            time_t now = time(NULL);
            if (now - lastPerfCallback >= 1)
            {
                if (this->perfCallback)
                    this->perfCallback(performance, this->perfCallbackUdata);
                lastPerfCallback = now;
            }
        }
        else if (strncasecmp("success", p, 7) == 0)
        {
            break;
        }
        else if (strncasecmp("aborted", p, 7) == 0)
        {
            Davix::DavixError::setupError(error, COPY_SCOPE, StatusCode::Canceled,
                    "Transfer aborted in the remote end");
            break;
        }
        else if (strncasecmp("failed", p, 6) == 0 || strncasecmp("failure", p, 7) == 0)
        {
            Davix::DavixError::setupError(error, COPY_SCOPE, StatusCode::RemoteError,
                    std::string("Transfer failed: ") + p);
            break;
        }
        else if(line_len> 0)
        {
            DAVIX_SLOG(DAVIX_LOG_WARNING, DAVIX_LOG_GRID, "Unknown performance marker, ignoring: {}", buffer);
        }
    }
}

<commit_msg>DMC-665 - Add support for 3rd party copy from dav to s3 storage<commit_after>#include <cstdio>
#include <cstring>
#include <davix.hpp>
#include <sstream>
#include <unistd.h>
#include "copy_internal.hpp"
#include "delegation/delegation.hpp"
#include <utils/davix_logger_internal.hpp>

using namespace Davix;

const std::string COPY_SCOPE = "Davix::HttpThirdPartyCopy";

// Gets the real location of uri respect to ref
// uri can be absolute or relative to ref
static std::string _full_url(const std::string ref,
        const std::string& uri)
{
    std::string final;

    if (uri.find("://") != std::string::npos) {
        final = uri;
    }
    else if (uri[0] == '/') {
        size_t colon = ref.find(':');
        size_t slash = std::string::npos;
        if (colon != std::string::npos)
            slash = ref.find('/', colon + 3);
        if (slash != std::string::npos) {
            std::string base = ref.substr(0, slash);
            final = base + uri;
        }
    }
    else {
        final = ref + uri;
    }

    return final;
}

// Same as _full_url, but it makes sure
// that the destination is https
static std::string _full_delegation_endpoint(const std::string& ref,
        const std::string& uri, DavixError** err)
{
    std::string final = _full_url(ref, uri);
    if (final.substr(7).compare("http://") == 0) {
        DavixError::setupError(err, COPY_SCOPE, StatusCode::OperationNonSupported,
                               std::string("Plain http can not be used for delegation: ") + uri);
        final.clear();
    }
    return final;
}

DavixCopy::DavixCopy(Context &c, const RequestParams *params): d_ptr(NULL)
{
    d_ptr = new DavixCopyInternal(c, params);
}

DavixCopy::~DavixCopy()
{
    delete d_ptr;
}

void DavixCopy::copy(const Uri &source, const Uri &destination,
        unsigned nstreams, DavixError **error)
{
    d_ptr->copy(source, destination, nstreams, error);
}

void DavixCopy::setPerformanceCallback(PerformanceCallback callback, void *udata)
{
    d_ptr->setPerformanceCallback(callback, udata);
}

void DavixCopyInternal::setPerformanceCallback(DavixCopy::PerformanceCallback callback,
        void *udata)
{
    perfCallback = callback;
    perfCallbackUdata = udata;
}

void DavixCopyInternal::copy(const Uri &src, const Uri &dst,
        unsigned nstreams, DavixError **error)
{
    std::string nextSrc(src.getString()), prevSrc(src.getString());
    std::string destination(dst.getString());
    std::string delegationEndpoint;
    DavixError *internalError = NULL;
    bool isS3endpoint = false;

    // nstreams as string
    char nstreamsStr[16];
    snprintf(nstreamsStr, sizeof(nstreamsStr), "%u", nstreams);

    // Need a copy so we can modify it
    Davix::RequestParams requestParams(parameters);
    requestParams.setTransparentRedirectionSupport(false);

    size_t start_pos;

    // if destination is s3 endpoint, change prefix to http(s) and pre-sign the request as a PUT
    if(destination.compare(0,2,"s3") == 0){
        destination.replace(0, 2, "http");
        time_t expiration_time = time(NULL) +3600;
        Davix::HeaderVec vec;
        Uri tmp = Davix::S3::tokenizeRequest(requestParams, "PUT", destination, vec, expiration_time);
        destination = tmp.getString();
        isS3endpoint = true;
    }

    // Perform COPY hopping through redirections
    HttpRequest* request = NULL;
    do {
        nextSrc = _full_url(prevSrc, nextSrc);
        prevSrc = nextSrc;
        if (request) {
            request->discardBody(&internalError);
            if (!internalError)
                request->endRequest(&internalError);
            if (internalError) {
                DavixError::propagatePrefixedError(error, internalError, __func__);
                break;
            }
        }
        delete request;

        DAVIX_SLOG(DAVIX_LOG_VERBOSE, DAVIX_LOG_GRID, "Hop: {}",
                     nextSrc);

        request = context.createRequest(nextSrc, &internalError);
        if (internalError) {
            DavixError::propagatePrefixedError(error, internalError, __func__);
            break;
        }

        request->setRequestMethod("COPY");
        request->addHeaderField("Destination", destination);
        request->addHeaderField("X-Number-Of-Streams", nstreamsStr);
        // for lcgdm-dav -> S3, add NoHead flag to suppress final head-to-close request
        if(isS3endpoint)
            request->addHeaderField("Copy-Flags", "NoHead");
        request->setParameters(requestParams);
        request->beginRequest(&internalError);
        if (internalError) {
            DavixError::propagatePrefixedError(error, internalError, __func__);
            break;
        }

        // If we get a X-Delegate-To, before continuing, delegate
        if (request->getAnswerHeader("X-Delegate-To", delegationEndpoint)) {
            delegationEndpoint = _full_delegation_endpoint(nextSrc,
                                                           delegationEndpoint,
                                                           &internalError);
            if (internalError) {
                DavixError::propagatePrefixedError(error, internalError, __func__);
                break;
            }

            DAVIX_SLOG(DAVIX_LOG_VERBOSE, DAVIX_LOG_GRID, "Got delegation endpoint: {}",
                         delegationEndpoint.c_str());

            std::string dlg_id = DavixDelegation::delegate(context, delegationEndpoint,
                    parameters, &internalError);
            if (internalError) {
                DavixError::propagatePrefixedError(error, internalError, __func__);
                break;
            }

            DAVIX_SLOG(DAVIX_LOG_VERBOSE, DAVIX_LOG_GRID, "Got delegation ID {}",
                         dlg_id.c_str());

            dlg_id.clear();
        }

    } while (request->getAnswerHeader("Location", nextSrc));

    if (!*error) {
        int responseStatus = request->getRequestCode();
        if (responseStatus == 404) {
            DavixError::setupError(error, COPY_SCOPE, StatusCode::FileNotFound,
                                   "Could not COPY. File not found");
        }
        else if (responseStatus == 403) {
            DavixError::setupError(error, COPY_SCOPE, StatusCode::PermissionRefused,
                                   "Could not COPY. Permission denied.");
        }
        else if (responseStatus == 501) {
            DavixError::setupError(error, COPY_SCOPE, StatusCode::OperationNonSupported,
                                   "Could not COPY. The source service does not support it");
        }
        else if (responseStatus >= 405) {
            DavixError::setupError(error, COPY_SCOPE, StatusCode::OperationNonSupported,
                                   "Could not COPY. The source service does not allow it");
        }
        else if (responseStatus == 400) {
            std::string err_msg(request->getAnswerContentVec().begin(), request->getAnswerContentVec().end());
        	DavixError::setupError(error, COPY_SCOPE, StatusCode::InvalidArgument,
                                   fmt::format("Could not COPY. The server rejected the request: {}", err_msg));
        }
        else if (responseStatus >= 300) {
            std::ostringstream msg;
            msg << "Could not COPY. Unknown error code: " << responseStatus;
            DavixError::setupError(error, COPY_SCOPE, StatusCode::UnknowError,
                                   msg.str());
        }
    }

    // Did we fail?
    if (*error)
        return;

    // Finished hopping
    std::string finalSource = nextSrc;

    // Just wait for it to finish
    monitorPerformanceMarkers(request, error);
    request->endRequest(error);
    delete request;
}

void DavixCopyInternal::monitorPerformanceMarkers(Davix::HttpRequest *request,
        Davix::DavixError **error)
{
    Davix::DavixError* daverr = NULL;
    char buffer[1024], *p;
    dav_ssize_t line_len;

    PerformanceMarker holder;
    PerformanceData performance;
    time_t lastPerfCallback = time(NULL);

    while ((line_len = request->readLine(buffer, sizeof(buffer), &daverr)) >= 0 && !daverr)
    {
        buffer[line_len] = '\0';

        if (line_len > 0)
            DAVIX_SLOG(DAVIX_LOG_VERBOSE, DAVIX_LOG_GRID, "Received: {}", buffer);

        // Skip heading whitespaces
        p = buffer;
        while (*p && p < buffer + sizeof(buffer) && isspace(*p))
            ++p;

        if (strncasecmp("Perf Marker", p, 11) == 0)
        {
            memset(&holder, 0, sizeof(holder));
        }
        else if (strncasecmp("Timestamp:", p, 10) == 0)
        {
            holder.latest = atol(p + 10);
        }
        else if (strncasecmp("Stripe Index:", p, 13) == 0)
        {
            holder.index = atoi(p + 13);
        }
        else if (strncasecmp("Stripe Bytes Transferred:", p, 25) == 0)
        {
            holder.transferred = atol(p + 26);
        }
        else if (strncasecmp("Total Stripe Count:", p, 19) == 0)
        {
            holder.count = atoi(p + 20);
        }
        else if (strncasecmp("End", p, 3) == 0)
        {
            performance.update(holder);
            time_t now = time(NULL);
            if (now - lastPerfCallback >= 1)
            {
                if (this->perfCallback)
                    this->perfCallback(performance, this->perfCallbackUdata);
                lastPerfCallback = now;
            }
        }
        else if (strncasecmp("success", p, 7) == 0)
        {
            break;
        }
        else if (strncasecmp("aborted", p, 7) == 0)
        {
            Davix::DavixError::setupError(error, COPY_SCOPE, StatusCode::Canceled,
                    "Transfer aborted in the remote end");
            break;
        }
        else if (strncasecmp("failed", p, 6) == 0 || strncasecmp("failure", p, 7) == 0)
        {
            Davix::DavixError::setupError(error, COPY_SCOPE, StatusCode::RemoteError,
                    std::string("Transfer failed: ") + p);
            break;
        }
        else if(line_len> 0)
        {
            DAVIX_SLOG(DAVIX_LOG_WARNING, DAVIX_LOG_GRID, "Unknown performance marker, ignoring: {}", buffer);
        }
    }
}

<|endoftext|>


<commit_before>#include "crange_arch.hh"
#include "radix.hh"

enum { crange_debug = 0 };

#define dprintf(...) do { if (crange_debug) cprintf(__VA_ARGS__); } while(0)

// Returns the index needed to reach |level| from |level+1|.
static u32
index(u64 key, u32 level)
{
  u64 idx = key >> (bits_per_level * level);
  idx &= (1 << bits_per_level) - 1;
  return idx;
}

// Returns the level we stopped at.
template<class CB>
u32
descend(u64 key, markptr<void> *n, u32 level, CB cb, bool create)
{
  static_assert(key_bits == bits_per_level * radix_levels,
                "for now, we only support exact multiples of bits_per_level");
  assert(n);

  void *v = n->ptr();
  if (v == 0 && create) {
    radix_node *new_rn = new radix_node();
    if (n->ptr().cmpxch_update(&v, (void*) new_rn))
      v = new_rn;
    else
      delete new_rn;
  }
  // Node isn't there. Just return.
  if (v == 0) {
    return level+1;
  }

  radix_node *rn = (radix_node*) v;

  markptr<void> *vptr = &rn->ptr[index(key, level)];
  if (level == 0) {
    cb(vptr);
    return level;
  } else {
    return descend(key, vptr, level-1, cb, create);
  }
}

radix_elem*
radix::search(u64 key)
{
  radix_elem *result = 0;
  descend(key >> shift_, &root_, radix_levels-1, [&result](markptr<void> *v) {
      result = (radix_elem*) v->ptr().load();
    }, false);
  dprintf("%p: search(%lu) -> %p\n", this, key >> shift_, result);
  return result;
}

radix_range
radix::search_lock(u64 start, u64 size)
{
  return radix_range(this, start >> shift_, size >> shift_);
}

u64
radix::skip_empty(u64 k) const
{
  u64 next_k = k;
  while (next_k < (1UL<<key_bits)) {
    // Does next_k exist?
    // FIXME: evil evil const_cast
    u32 level = descend(next_k, const_cast<markptr<void>*>(&root_),
                        radix_levels-1, [](markptr<void> *v){}, false);
    if (level == 0) {
      return next_k;
    }
    u64 mask = 1UL<<(bits_per_level * level);
    // Skip past everything we know is missing.
    next_k = (next_k & ~(mask-1)) + mask;
  }
  // Nope, no successor.
  return ~0ULL;
}

radix_range::radix_range(radix *r, u64 start, u64 size)
  : r_(r), start_(start), size_(size)
{
  for (u64 k = start_; k != start_ + size_; k++) {
    if (descend(k, &r_->root_, radix_levels-1, [](markptr<void> *v) {
          while (!v->mark().xchg(true))
            ; // spin
        }, true) != 0) {
      panic("radix_range");
    }
  }
}

radix_range::~radix_range()
{
  if (!r_)
    return;

  for (u64 k = start_; k != start_ + size_; k++) {
    if (descend(k, &r_->root_, radix_levels-1, [](markptr<void> *v) {
          v->mark() = false;
        }, true) != 0) {
      panic("~radix_range");
    }
  }
}

void
radix_range::replace(u64 start, u64 size, radix_elem *val)
{
  start = start >> r_->shift_;
  size = size >> r_->shift_;
  dprintf("%p: replace: [%lu, %lu) with %p\n", r_, start, start + size, val);

  assert(start >= start_);
  assert(start + size <= start_ + size_);

  for (u64 k = start; k != start + size; k++) {
    if (descend(k, &r_->root_, radix_levels-1, [val](markptr<void> *v) {
          void* cur = v->ptr().load();
          while (!v->ptr().cmpxch_update(&cur, val))
            ; // spin
          if (val)
            val->incref();
          if (cur)
            ((radix_elem*) cur)->decref();
        }, true)) {
      panic("radix_range::replace");
    }
  }
}

radix_elem*
radix_iterator::operator*()
{
  radix_elem *result = 0;
  descend(k_, (markptr<void>*) &r_->root_, radix_levels-1, [&result](markptr<void> *v) {
      result = (radix_elem*) v->ptr().load();
    }, false);
  return result;
}

radix_iterator2::radix_iterator2(const radix* r, u64 k)
  : r_(r), k_(k) {
  dprintf("%p: Made iterator with k = %lu\n", r_, k_);
  if (k_ != ~0ULL) {
    path_[radix_levels] = r_->root_.ptr().load();
    if (!find_first_leaf(radix_levels - 1))
      k_ = ~0ULL;
  }
  dprintf("%p: Adjusted: k = %lu\n", r_, k_);
}

bool
radix_iterator2::advance(u32 level)
{
  // First, see if we can advance a lower level.
  if (level > 0 && advance(level-1)) {
    // Nothing more to do.
    return true;
  }

  // Try to advance this level.
  for (u32 idx = index(k_, level) + 1;
       idx < (1<<bits_per_level);
       idx++) {
    void *next = node(level+1)->ptr[idx].ptr().load();
    if (next != nullptr) {
      // Clear everything this level and under and set this one.
      k_ &= ~((1ULL<<((level+1) * bits_per_level)) - 1);
      k_ |= (u64(idx) << (level * bits_per_level));
      path_[level] = next;

      // Try to find a leaf.
      if (level == 0 || find_first_leaf(level-1))
        return true;
    }
  }
  // Failed to advance. Abort.
  return false;
}

bool
radix_iterator2::find_first_leaf(u32 level)
{
  // Find the first non-empty node after k_ on this level.
  for (u32 idx = index(k_, level); idx < (1<<bits_per_level); idx++) {
    void *next = node(level+1)->ptr[idx].ptr().load();
    if (next != nullptr) {
      if (index(k_, level) != idx) {
        // We had to advance; clear everything this level and under
        // and set this one.
        k_ &= ~((1ULL<<((level+1) * bits_per_level)) - 1);
        k_ |= (u64(idx) << (level * bits_per_level));
      }
      path_[level] = next;

      if (level == 0 || find_first_leaf(level-1))
        return true;
    }
  }

  // Failed to find a leaf. Abort.
  return false;
}
<commit_msg>Simplify advance a bit<commit_after>#include "crange_arch.hh"
#include "radix.hh"

enum { crange_debug = 0 };

#define dprintf(...) do { if (crange_debug) cprintf(__VA_ARGS__); } while(0)

// Returns the index needed to reach |level| from |level+1|.
static u32
index(u64 key, u32 level)
{
  u64 idx = key >> (bits_per_level * level);
  idx &= (1 << bits_per_level) - 1;
  return idx;
}

// Returns the level we stopped at.
template<class CB>
u32
descend(u64 key, markptr<void> *n, u32 level, CB cb, bool create)
{
  static_assert(key_bits == bits_per_level * radix_levels,
                "for now, we only support exact multiples of bits_per_level");
  assert(n);

  void *v = n->ptr();
  if (v == 0 && create) {
    radix_node *new_rn = new radix_node();
    if (n->ptr().cmpxch_update(&v, (void*) new_rn))
      v = new_rn;
    else
      delete new_rn;
  }
  // Node isn't there. Just return.
  if (v == 0) {
    return level+1;
  }

  radix_node *rn = (radix_node*) v;

  markptr<void> *vptr = &rn->ptr[index(key, level)];
  if (level == 0) {
    cb(vptr);
    return level;
  } else {
    return descend(key, vptr, level-1, cb, create);
  }
}

radix_elem*
radix::search(u64 key)
{
  radix_elem *result = 0;
  descend(key >> shift_, &root_, radix_levels-1, [&result](markptr<void> *v) {
      result = (radix_elem*) v->ptr().load();
    }, false);
  dprintf("%p: search(%lu) -> %p\n", this, key >> shift_, result);
  return result;
}

radix_range
radix::search_lock(u64 start, u64 size)
{
  return radix_range(this, start >> shift_, size >> shift_);
}

u64
radix::skip_empty(u64 k) const
{
  u64 next_k = k;
  while (next_k < (1UL<<key_bits)) {
    // Does next_k exist?
    // FIXME: evil evil const_cast
    u32 level = descend(next_k, const_cast<markptr<void>*>(&root_),
                        radix_levels-1, [](markptr<void> *v){}, false);
    if (level == 0) {
      return next_k;
    }
    u64 mask = 1UL<<(bits_per_level * level);
    // Skip past everything we know is missing.
    next_k = (next_k & ~(mask-1)) + mask;
  }
  // Nope, no successor.
  return ~0ULL;
}

radix_range::radix_range(radix *r, u64 start, u64 size)
  : r_(r), start_(start), size_(size)
{
  for (u64 k = start_; k != start_ + size_; k++) {
    if (descend(k, &r_->root_, radix_levels-1, [](markptr<void> *v) {
          while (!v->mark().xchg(true))
            ; // spin
        }, true) != 0) {
      panic("radix_range");
    }
  }
}

radix_range::~radix_range()
{
  if (!r_)
    return;

  for (u64 k = start_; k != start_ + size_; k++) {
    if (descend(k, &r_->root_, radix_levels-1, [](markptr<void> *v) {
          v->mark() = false;
        }, true) != 0) {
      panic("~radix_range");
    }
  }
}

void
radix_range::replace(u64 start, u64 size, radix_elem *val)
{
  start = start >> r_->shift_;
  size = size >> r_->shift_;
  dprintf("%p: replace: [%lu, %lu) with %p\n", r_, start, start + size, val);

  assert(start >= start_);
  assert(start + size <= start_ + size_);

  for (u64 k = start; k != start + size; k++) {
    if (descend(k, &r_->root_, radix_levels-1, [val](markptr<void> *v) {
          void* cur = v->ptr().load();
          while (!v->ptr().cmpxch_update(&cur, val))
            ; // spin
          if (val)
            val->incref();
          if (cur)
            ((radix_elem*) cur)->decref();
        }, true)) {
      panic("radix_range::replace");
    }
  }
}

radix_elem*
radix_iterator::operator*()
{
  radix_elem *result = 0;
  descend(k_, (markptr<void>*) &r_->root_, radix_levels-1, [&result](markptr<void> *v) {
      result = (radix_elem*) v->ptr().load();
    }, false);
  return result;
}

radix_iterator2::radix_iterator2(const radix* r, u64 k)
  : r_(r), k_(k) {
  dprintf("%p: Made iterator with k = %lu\n", r_, k_);
  if (k_ != ~0ULL) {
    path_[radix_levels] = r_->root_.ptr().load();
    if (!find_first_leaf(radix_levels - 1))
      k_ = ~0ULL;
  }
  dprintf("%p: Adjusted: k = %lu\n", r_, k_);
}

bool
radix_iterator2::advance(u32 level)
{
  // First, see if we can advance a lower level.
  if (level > 0 && advance(level-1)) {
    // Nothing more to do.
    return true;
  }

  // Try to advance this level, if we can.
  u32 start_idx = index(k_, level)+1;
  if (start_idx < (1<<bits_per_level)) {
    // Find the first leaf starting at our sibling node.
    k_ &= ~((1ULL<<((level+1) * bits_per_level)) - 1);
    k_ |= (u64(start_idx) << (level * bits_per_level));
    return find_first_leaf(level);
  } else {
    return false;
  }
}

bool
radix_iterator2::find_first_leaf(u32 level)
{
  // Find the first non-empty node after k_ on this level.
  for (u32 idx = index(k_, level); idx < (1<<bits_per_level); idx++) {
    void *next = node(level+1)->ptr[idx].ptr().load();
    if (next != nullptr) {
      if (index(k_, level) != idx) {
        // We had to advance; clear everything this level and under
        // and set this one.
        k_ &= ~((1ULL<<((level+1) * bits_per_level)) - 1);
        k_ |= (u64(idx) << (level * bits_per_level));
      }
      path_[level] = next;

      if (level == 0 || find_first_leaf(level-1))
        return true;
    }
  }

  // Failed to find a leaf. Abort.
  return false;
}
<|endoftext|>


<commit_before>// The local APIC manages internal (non-I/O) interrupts.
// See Chapter 8 & Appendix C of Intel processor manual volume 3.

#include "types.h"
#include "amd64.h"
#include "kernel.hh"
#include "traps.h"
#include "bits.hh"
#include "cpu.hh"
#include "apic.hh"

// Local APIC registers, divided by 4 for use as uint[] indices.
#define ID      (0x0020/4)   // ID
#define VER     (0x0030/4)   // Version
#define TPR     (0x0080/4)   // Task Priority
#define EOI     (0x00B0/4)   // EOI
#define SVR     (0x00F0/4)   // Spurious Interrupt Vector
  #define ENABLE     0x00000100   // Unit Enable
#define ESR     (0x0280/4)   // Error Status
#define ICRLO   (0x0300/4)   // Interrupt Command
  #define INIT       0x00000500   // INIT/RESET
  #define STARTUP    0x00000600   // Startup IPI
  #define DELIVS     0x00001000   // Delivery status
  #define ASSERT     0x00004000   // Assert interrupt (vs deassert)
  #define DEASSERT   0x00000000
  #define LEVEL      0x00008000   // Level triggered
  #define BCAST      0x00080000   // Send to all APICs, including self.
  #define FIXED      0x00000000
#define ICRHI   (0x0310/4)   // Interrupt Command [63:32]
#define TIMER   (0x0320/4)   // Local Vector Table 0 (TIMER)
  #define X1         0x0000000B   // divide counts by 1
  #define PERIODIC   0x00020000   // Periodic
#define PCINT   (0x0340/4)   // Performance Counter LVT
#define LINT0   (0x0350/4)   // Local Vector Table 1 (LINT0)
#define LINT1   (0x0360/4)   // Local Vector Table 2 (LINT1)
#define ERROR   (0x0370/4)   // Local Vector Table 3 (ERROR)
  #define MASKED     0x00010000   // Interrupt masked
  #define MT_NMI     0x00000400   // NMI message type
  #define MT_FIX     0x00000000   // Fixed message type
#define TICR    (0x0380/4)   // Timer Initial Count
#define TCCR    (0x0390/4)   // Timer Current Count
#define TDCR    (0x03E0/4)   // Timer Divide Configuration

#define IO_RTC  0x70

static volatile u32 *xapic = (u32 *)(KBASE + 0xfee00000);
static u64 xapichz;

static void
xapicw(int index, int value)
{
  xapic[index] = value;
  xapic[ID];  // wait for write to finish, by reading
}

static u32
xapicr(u32 off)
{
  return xapic[off];
}

static int
xapicwait()
{
  int i = 100000;
  while ((xapicr(ICRLO) & DELIVS) != 0) {
    nop_pause();
    i--;
    if (i == 0) {
      cprintf("xapicwait: wedged?\n");
      return -1;
    }
  }
  return 0;
}

void
initxapic(void)
{
  u64 count;

  u32 edx;
  cpuid(CPUID_FEATURES, nullptr, nullptr, nullptr, &edx);
  if (!(edx & FEATURE_EDX_APIC))
    panic("No LAPIC");

  // Enable local APIC; set spurious interrupt vector.
  xapicw(SVR, ENABLE | (T_IRQ0 + IRQ_SPURIOUS));

  if (xapichz == 0) {
    // Measure the TICR frequency
    xapicw(TDCR, X1);
    xapicw(TICR, 0xffffffff);
    u64 ccr0 = xapicr(TCCR);
    microdelay(10 * 1000);    // 1/100th of a second
    u64 ccr1 = xapicr(TCCR);
    xapichz = 100 * (ccr0 - ccr1);
  }

  count = (QUANTUM*xapichz) / 1000;
  if (count > 0xffffffff)
    panic("initxapic: QUANTUM too large");

  // The timer repeatedly counts down at bus frequency
  // from xapic[TICR] and then issues an interrupt.
  xapicw(TDCR, X1);
  xapicw(TIMER, PERIODIC | (T_IRQ0 + IRQ_TIMER));
  xapicw(TICR, count);

  // Disable logical interrupt lines.
  xapicw(LINT0, MASKED);
  xapicw(LINT1, MASKED);

  // Disable performance counter overflow interrupts
  // on machines that provide that interrupt entry.
  if(((xapic[VER]>>16) & 0xFF) >= 4)
    xapicpc(0);

  // Map error interrupt to IRQ_ERROR.
  xapicw(ERROR, T_IRQ0 + IRQ_ERROR);

  // Clear error status register (requires back-to-back writes).
  xapicw(ESR, 0);
  xapicw(ESR, 0);

  // Ack any outstanding interrupts.
  xapicw(EOI, 0);

  // Send an Init Level De-Assert to synchronise arbitration ID's.
  xapicw(ICRHI, 0);
  xapicw(ICRLO, BCAST | INIT | LEVEL);
  while(xapic[ICRLO] & DELIVS)
    ;

  // Enable interrupts on the APIC (but not on the processor).
  xapicw(TPR, 0);
}

void
xapicpc(char mask)
{
  xapicw(PCINT, mask ? MASKED : MT_NMI);
}

hwid_t
xapicid(void)
{
  if (readrflags() & FL_IF) {
    cli();
    panic("cpunum() called from %p with interrupts enabled\n",
      __builtin_return_address(0));
  }

  if (xapic == nullptr)
    panic("xapicid");
  return HWID(xapic[ID]>>24);
}

// Acknowledge interrupt.
void
xapiceoi(void)
{
  if(xapic)
    xapicw(EOI, 0);
}

// Send IPI
void
xapic_ipi(hwid_t hwid, int ino)
{
  xapicw(ICRHI, hwid.num << 24);
  xapicw(ICRLO, FIXED | DEASSERT | ino);
  if (xapicwait() < 0)
    panic("xapic_ipi: xapicwait failure");
}

void
xapic_tlbflush(hwid_t hwid)
{
  xapic_ipi(hwid, T_TLBFLUSH);
}

void
xapic_sampconf(hwid_t hwid)
{
  xapic_ipi(hwid, T_SAMPCONF);
}

// Start additional processor running bootstrap code at addr.
// See Appendix B of MultiProcessor Specification.
void
xapicstartap(hwid hwid, u32 addr)
{
  int i;

  // "Universal startup algorithm."
  // Send INIT (level-triggered) interrupt to reset other CPU.

  xapicw(ICRHI, hwid.num<<24);
  xapicw(ICRLO, INIT | LEVEL | ASSERT);
  xapicwait();
  microdelay(10000);
  xapicw(ICRLO, INIT | LEVEL);
  xapicwait();
  microdelay(10000);    // should be 10ms, but too slow in Bochs!

  // Send startup IPI (twice!) to enter bootstrap code.
  // Regular hardware is supposed to only accept a STARTUP
  // when it is in the halted state due to an INIT.  So the second
  // should be ignored, but it is part of the official Intel algorithm.
  // Bochs complains about the second one.  Too bad for Bochs.
  for(i = 0; i < 2; i++){
    xapicw(ICRHI, hwid.num<<24);
    xapicw(ICRLO, STARTUP | (addr>>12));
    microdelay(200);
  }
}
<commit_msg>xapic: More detailed init comment<commit_after>// The local APIC manages internal (non-I/O) interrupts.
// See Chapter 8 & Appendix C of Intel processor manual volume 3.

#include "types.h"
#include "amd64.h"
#include "kernel.hh"
#include "traps.h"
#include "bits.hh"
#include "cpu.hh"
#include "apic.hh"

// Local APIC registers, divided by 4 for use as uint[] indices.
#define ID      (0x0020/4)   // ID
#define VER     (0x0030/4)   // Version
#define TPR     (0x0080/4)   // Task Priority
#define EOI     (0x00B0/4)   // EOI
#define SVR     (0x00F0/4)   // Spurious Interrupt Vector
  #define ENABLE     0x00000100   // Unit Enable
#define ESR     (0x0280/4)   // Error Status
#define ICRLO   (0x0300/4)   // Interrupt Command
  #define INIT       0x00000500   // INIT/RESET
  #define STARTUP    0x00000600   // Startup IPI
  #define DELIVS     0x00001000   // Delivery status
  #define ASSERT     0x00004000   // Assert interrupt (vs deassert)
  #define DEASSERT   0x00000000
  #define LEVEL      0x00008000   // Level triggered
  #define BCAST      0x00080000   // Send to all APICs, including self.
  #define FIXED      0x00000000
#define ICRHI   (0x0310/4)   // Interrupt Command [63:32]
#define TIMER   (0x0320/4)   // Local Vector Table 0 (TIMER)
  #define X1         0x0000000B   // divide counts by 1
  #define PERIODIC   0x00020000   // Periodic
#define PCINT   (0x0340/4)   // Performance Counter LVT
#define LINT0   (0x0350/4)   // Local Vector Table 1 (LINT0)
#define LINT1   (0x0360/4)   // Local Vector Table 2 (LINT1)
#define ERROR   (0x0370/4)   // Local Vector Table 3 (ERROR)
  #define MASKED     0x00010000   // Interrupt masked
  #define MT_NMI     0x00000400   // NMI message type
  #define MT_FIX     0x00000000   // Fixed message type
#define TICR    (0x0380/4)   // Timer Initial Count
#define TCCR    (0x0390/4)   // Timer Current Count
#define TDCR    (0x03E0/4)   // Timer Divide Configuration

#define IO_RTC  0x70

static volatile u32 *xapic = (u32 *)(KBASE + 0xfee00000);
static u64 xapichz;

static void
xapicw(int index, int value)
{
  xapic[index] = value;
  xapic[ID];  // wait for write to finish, by reading
}

static u32
xapicr(u32 off)
{
  return xapic[off];
}

static int
xapicwait()
{
  int i = 100000;
  while ((xapicr(ICRLO) & DELIVS) != 0) {
    nop_pause();
    i--;
    if (i == 0) {
      cprintf("xapicwait: wedged?\n");
      return -1;
    }
  }
  return 0;
}

void
initxapic(void)
{
  u64 count;

  u32 edx;
  cpuid(CPUID_FEATURES, nullptr, nullptr, nullptr, &edx);
  if (!(edx & FEATURE_EDX_APIC))
    panic("No LAPIC");

  // Enable local APIC, do not suppress EOI broadcast, set spurious
  // interrupt vector.
  xapicw(SVR, ENABLE | (T_IRQ0 + IRQ_SPURIOUS));

  if (xapichz == 0) {
    // Measure the TICR frequency
    xapicw(TDCR, X1);
    xapicw(TICR, 0xffffffff);
    u64 ccr0 = xapicr(TCCR);
    microdelay(10 * 1000);    // 1/100th of a second
    u64 ccr1 = xapicr(TCCR);
    xapichz = 100 * (ccr0 - ccr1);
  }

  count = (QUANTUM*xapichz) / 1000;
  if (count > 0xffffffff)
    panic("initxapic: QUANTUM too large");

  // The timer repeatedly counts down at bus frequency
  // from xapic[TICR] and then issues an interrupt.
  xapicw(TDCR, X1);
  xapicw(TIMER, PERIODIC | (T_IRQ0 + IRQ_TIMER));
  xapicw(TICR, count);

  // Disable logical interrupt lines.
  xapicw(LINT0, MASKED);
  xapicw(LINT1, MASKED);

  // Disable performance counter overflow interrupts
  // on machines that provide that interrupt entry.
  if(((xapic[VER]>>16) & 0xFF) >= 4)
    xapicpc(0);

  // Map error interrupt to IRQ_ERROR.
  xapicw(ERROR, T_IRQ0 + IRQ_ERROR);

  // Clear error status register (requires back-to-back writes).
  xapicw(ESR, 0);
  xapicw(ESR, 0);

  // Ack any outstanding interrupts.
  xapicw(EOI, 0);

  // Send an Init Level De-Assert to synchronise arbitration ID's.
  xapicw(ICRHI, 0);
  xapicw(ICRLO, BCAST | INIT | LEVEL);
  while(xapic[ICRLO] & DELIVS)
    ;

  // Enable interrupts on the APIC (but not on the processor).
  xapicw(TPR, 0);
}

void
xapicpc(char mask)
{
  xapicw(PCINT, mask ? MASKED : MT_NMI);
}

hwid_t
xapicid(void)
{
  if (readrflags() & FL_IF) {
    cli();
    panic("cpunum() called from %p with interrupts enabled\n",
      __builtin_return_address(0));
  }

  if (xapic == nullptr)
    panic("xapicid");
  return HWID(xapic[ID]>>24);
}

// Acknowledge interrupt.
void
xapiceoi(void)
{
  if(xapic)
    xapicw(EOI, 0);
}

// Send IPI
void
xapic_ipi(hwid_t hwid, int ino)
{
  xapicw(ICRHI, hwid.num << 24);
  xapicw(ICRLO, FIXED | DEASSERT | ino);
  if (xapicwait() < 0)
    panic("xapic_ipi: xapicwait failure");
}

void
xapic_tlbflush(hwid_t hwid)
{
  xapic_ipi(hwid, T_TLBFLUSH);
}

void
xapic_sampconf(hwid_t hwid)
{
  xapic_ipi(hwid, T_SAMPCONF);
}

// Start additional processor running bootstrap code at addr.
// See Appendix B of MultiProcessor Specification.
void
xapicstartap(hwid hwid, u32 addr)
{
  int i;

  // "Universal startup algorithm."
  // Send INIT (level-triggered) interrupt to reset other CPU.

  xapicw(ICRHI, hwid.num<<24);
  xapicw(ICRLO, INIT | LEVEL | ASSERT);
  xapicwait();
  microdelay(10000);
  xapicw(ICRLO, INIT | LEVEL);
  xapicwait();
  microdelay(10000);    // should be 10ms, but too slow in Bochs!

  // Send startup IPI (twice!) to enter bootstrap code.
  // Regular hardware is supposed to only accept a STARTUP
  // when it is in the halted state due to an INIT.  So the second
  // should be ignored, but it is part of the official Intel algorithm.
  // Bochs complains about the second one.  Too bad for Bochs.
  for(i = 0; i < 2; i++){
    xapicw(ICRHI, hwid.num<<24);
    xapicw(ICRLO, STARTUP | (addr>>12));
    microdelay(200);
  }
}
<|endoftext|>


<commit_before>/**
 * @file	src/DemoModuleForwarder.cpp
 * @date	Mar 2016
 * @author	PhRG - opticalp.fr
 */

/*
 Copyright (c) 2016 Ph. Renaud-Goud / Opticalp

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 */

#include "DemoModuleForwarder.h"

#include "DataAttributeIn.h"
#include "DataAttribute.h"

#include "InDataPort.h"
#include "OutPort.h"

#include "Poco/NumberFormatter.h"

size_t DemoModuleForwarder::refCount = 0;

DemoModuleForwarder::DemoModuleForwarder(ModuleFactory* parent, std::string customName):
        Module(parent, customName)
{
    // poco_information(logger(),"Creating a new DemoModuleForwarder");

    setInternalName("DemoModuleForwarder" + Poco::NumberFormatter::format(refCount));
    setCustomName(customName);
    setLogger("module." + name());

    // ports
    setInPortCount(inPortCnt);
    setOutPortCount(outPortCnt);

    addInPort("inPortA", "data in", DataItem::typeInteger, inPortA);

    addOutPort("outPortA", "forwarded data as is", DataItem::typeInteger, outPortA);

    notifyCreation();

    // if nothing failed
    refCount++;
}

void DemoModuleForwarder::process(int startCond)
{
	if (startCond != allDataStartState)
	{
		poco_information(logger(), name() + ": no input data. Exiting. ");
		return;
	}
	else
	{
		poco_information(logger(),"Input data locked");
	}

    DataAttributeIn attr;
    int* pData;

	readLockInPort(inPortA);
    readInPortData<int>(inPortA, pData);
    readInPortDataAttribute(inPortA, &attr);

    DataAttributeOut outAttr = attr;

    int tmpData;

//    // buffered mode
//    tmpData = *pData;
//    releaseInPort(inPortA);

    reserveOutPort(outPortA);

    int* pOutData;
    getDataToWrite<int>(outPortA, pOutData);

//    // buffered mode
//  	*pOutData = tmpData;
//    else

    *pOutData = *pData;

    // not mandatory
    releaseInPort(inPortA);

    notifyOutPortReady(outPortA, outAttr);

    poco_information(logger(), "DemoModuleForwarder::runTask(): "
            + Poco::NumberFormatter::format(tmpData) + " was forwarded.");
}
<commit_msg>Remove un-initialized variable<commit_after>/**
 * @file	src/DemoModuleForwarder.cpp
 * @date	Mar 2016
 * @author	PhRG - opticalp.fr
 */

/*
 Copyright (c) 2016 Ph. Renaud-Goud / Opticalp

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 */

#include "DemoModuleForwarder.h"

#include "DataAttributeIn.h"
#include "DataAttribute.h"

#include "InDataPort.h"
#include "OutPort.h"

#include "Poco/NumberFormatter.h"

size_t DemoModuleForwarder::refCount = 0;

DemoModuleForwarder::DemoModuleForwarder(ModuleFactory* parent, std::string customName):
        Module(parent, customName)
{
    // poco_information(logger(),"Creating a new DemoModuleForwarder");

    setInternalName("DemoModuleForwarder" + Poco::NumberFormatter::format(refCount));
    setCustomName(customName);
    setLogger("module." + name());

    // ports
    setInPortCount(inPortCnt);
    setOutPortCount(outPortCnt);

    addInPort("inPortA", "data in", DataItem::typeInteger, inPortA);

    addOutPort("outPortA", "forwarded data as is", DataItem::typeInteger, outPortA);

    notifyCreation();

    // if nothing failed
    refCount++;
}

void DemoModuleForwarder::process(int startCond)
{
	if (startCond != allDataStartState)
	{
		poco_information(logger(), name() + ": no input data. Exiting. ");
		return;
	}
	else
	{
		poco_information(logger(),"Input data locked");
	}

    DataAttributeIn attr;
    int* pData;

	readLockInPort(inPortA);
    readInPortData<int>(inPortA, pData);
    readInPortDataAttribute(inPortA, &attr);

    DataAttributeOut outAttr = attr;

    int tmpData; // for verbosity purpose

//    // buffered mode
    tmpData = *pData;
//    releaseInPort(inPortA);

    reserveOutPort(outPortA);

    int* pOutData;
    getDataToWrite<int>(outPortA, pOutData);

//    // buffered mode
//  	*pOutData = tmpData;
//    else

    *pOutData = *pData;

    // not mandatory
    releaseInPort(inPortA);

    notifyOutPortReady(outPortA, outAttr);

    poco_information(logger(), "DemoModuleForwarder::runTask(): "
            + Poco::NumberFormatter::format(tmpData) + " was forwarded.");
}
<|endoftext|>


<commit_before>#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <irrlicht/Keycodes.h>
#include <stdio.h>
#include <unistd.h>

#define RETURN 13
#define BS 8
#define SPACE 32

XKeyEvent createKeyEvent(Display *display,
                         Window &win,
                         Window &winRoot,
                         bool press,
                         int keycode,
                         int modifiers)
{
  // Largely lifted from
  // http://www.doctort.org/adam/nerd-notes/x11-fake-keypress-event.html
  XKeyEvent event;
  event.display = display;
  event.window = win;
  event.root = winRoot;
  event.subwindow = None;
  event.time = CurrentTime;
  event.x = 1;
  event.y = 1;
  event.x_root = 1;
  event.y_root = 1;
  event.same_screen = True;
  event.keycode = XKeysymToKeycode(display, keycode);
  event.state = modifiers;

  if(press)
    event.type = KeyPress;
  else
    event.type = KeyRelease;

  return event;
}

class X11Display {
  public:
    Display *display;
    X11Display(const char* dispName);
    ~X11Display();
};

X11Display::X11Display(const char* dispName) :
  display(XOpenDisplay(dispName)){}

X11Display::~X11Display() { XCloseDisplay(display); }

int mapKeyCode(int irrcode){
  switch(irrcode){
    //FIXME: only to get rid of arrow spam
    case 37 ... 40:
      return -1;
    case irr::KEY_BACK :
      return XK_BackSpace;
    case irr::KEY_TAB :
      return XK_Tab;
    case irr::KEY_RETURN :
      return XK_Return;
    case irr::KEY_MINUS :
      return XK_minus;
    case irr::KEY_OEM_7 :
      return XK_apostrophe;
    default:
      return irrcode;
  }
}

int sendKeyEvent(const char* disp, int keycode)
{
  if(-1==keycode)
    return 0;
  printf("sendKeyEvent keycode: %d\n", keycode);
  Window winFocus;
  int revert;

  X11Display X11Display(disp);

  Display *display = XOpenDisplay(disp);
  if(NULL == display)
    return -1;
  Window winRoot = XDefaultRootWindow(display);
  //XSetInputFocus(display, 1, revert, CurrentTime);
  XGetInputFocus(display, &winFocus, &revert);
  XKeyEvent event = createKeyEvent(display, winFocus, winRoot, true, keycode, 0);
  XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent*)&event);
  event = createKeyEvent(display, winFocus, winRoot, false, keycode, 0);
  XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent*)&event);
  XCloseDisplay(display);
  return 0;
}
<commit_msg>Works using object<commit_after>#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <irrlicht/Keycodes.h>
#include <stdio.h>
#include <unistd.h>

#define RETURN 13
#define BS 8
#define SPACE 32

XKeyEvent createKeyEvent(Display *display,
                         Window &win,
                         Window &winRoot,
                         bool press,
                         int keycode,
                         int modifiers)
{
  // Largely lifted from
  // http://www.doctort.org/adam/nerd-notes/x11-fake-keypress-event.html
  XKeyEvent event;
  event.display = display;
  event.window = win;
  event.root = winRoot;
  event.subwindow = None;
  event.time = CurrentTime;
  event.x = 1;
  event.y = 1;
  event.x_root = 1;
  event.y_root = 1;
  event.same_screen = True;
  event.keycode = XKeysymToKeycode(display, keycode);
  event.state = modifiers;

  if(press)
    event.type = KeyPress;
  else
    event.type = KeyRelease;

  return event;
}

class X11Display {
  public:
    Display *display;
    X11Display(const char* dispName);
    ~X11Display();
};

X11Display::X11Display(const char* dispName) :
  display(XOpenDisplay(dispName)){}

X11Display::~X11Display() { XCloseDisplay(display); }

int mapKeyCode(int irrcode){
  switch(irrcode){
    //FIXME: only to get rid of arrow spam
    case 37 ... 40:
      return -1;
    case irr::KEY_BACK :
      return XK_BackSpace;
    case irr::KEY_TAB :
      return XK_Tab;
    case irr::KEY_RETURN :
      return XK_Return;
    case irr::KEY_MINUS :
      return XK_minus;
    case irr::KEY_OEM_7 :
      return XK_apostrophe;
    default:
      return irrcode;
  }
}

int sendKeyEvent(const char* disp, int keycode)
{
  if(-1==keycode)
    return 0;
  printf("sendKeyEvent keycode: %d\n", keycode);
  Window winFocus;
  int revert;

  X11Display xdisp(disp);

  //Display *display = XOpenDisplay(disp);
  //if(NULL == display)
  //  return -1;
  Window winRoot = XDefaultRootWindow(xdisp.display);
  //XSetInputFocus(display, 1, revert, CurrentTime);
  XGetInputFocus(xdisp.display, &winFocus, &revert);
  XKeyEvent event = createKeyEvent(xdisp.display, winFocus, winRoot, true, keycode, 0);
  XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent*)&event);
  event = createKeyEvent(xdisp.display, winFocus, winRoot, false, keycode, 0);
  XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent*)&event);
  //XCloseDisplay(display);
  return 0;
}
<|endoftext|>


<commit_before>/*
 * Website:
 *      https://github.com/wo3kie/dojo
 *
 * Author:
 *      Lukasz Czerwinski
 *
 * Compilation:
 *      g++ --std=c++11 generateAllSubsets.cpp -o generateAllSubsets
 *
 * Usage:
 *      $ ./generateAllSubsets
 */

#include <cassert>
#include <iostream>
#include <set>
#include <vector>

std::set<std::set<int>> getAllSubsetsImpl(
    std::set<std::set<int>> & sets1,
    std::set<int> set
){
    if(set.empty()){
        return sets1;
    }

    int item = * set.begin();
    set.erase(set.begin());

    std::set<std::set<int>> sets2;

    for(std::set<int> s : sets1){
        s.insert(item);
        sets2.insert(s);
    }

    std::set<std::set<int>> subsets1 = getAllSubsetsImpl(sets1, set);
    std::set<std::set<int>> subsets2 = getAllSubsetsImpl(sets2, set);

    subsets1.insert(
        subsets2.begin(),
        subsets2.end()
    );

    return subsets1;
}

std::set<std::set<int>> getAllSubsets(std::set<int> const & set){
    std::set<std::set<int>> sets;
    sets.insert(std::set<int>());
    return getAllSubsetsImpl(sets, set);
}

int main()
{
    std::set<std::set<int>> actual = getAllSubsets(std::set<int>{ 1, 2, 3 });

    std::set<std::set<int>> expected = std::set<std::set<int>>{
        std::set<int>(),
        {1}, {2}, {3},
        {1, 2}, {1, 3}, {2, 3},
        {1, 2, 3}
    };

    assert(actual == expected);
}

<commit_msg>generateAllSubsets<commit_after>/*
 * Website:
 *      https://github.com/wo3kie/dojo
 *
 * Author:
 *      Lukasz Czerwinski
 *
 * Compilation:
 *      g++ --std=c++11 generateAllSubsets.cpp -o generateAllSubsets
 *
 * Usage:
 *      $ ./generateAllSubsets
 */

#include <cassert>
#include <iostream>
#include <set>
#include <vector>

#include "./output.hpp"

std::set<std::set<int>> getAllSubsets(
    std::set<int> set
){
    std::set<std::set<int>> result;
    result.insert(std::set<int>());

    if(set.size() == 0){
        return result;
    }

    int item = * set.begin();
    set.erase(set.begin());
    std::set<std::set<int>> subsets = getAllSubsets(set);

    for(std::set<int> subset : subsets){
        result.insert(subset);
        subset.insert(item);
        result.insert(subset);
    }

    return result;
}

int main()
{
    std::set<std::set<int>> actual = getAllSubsets(std::set<int>{ 1, 2, 3 });

    std::set<std::set<int>> expected = std::set<std::set<int>>{
        std::set<int>(),
        {1}, {2}, {3},
        {1, 2}, {1, 3}, {2, 3},
        {1, 2, 3}
    };

    assert(actual == expected);
}

<|endoftext|>


<commit_before>// Copyright 2014, Yahoo! Inc.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Some portions of this file:
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/metrics/statistics_recorder.h"
#include "base/run_loop.h"
#include "base/test/launcher/unit_test_launcher.h"
#include "net/http/http_response_headers.h"
#include "net/socket/client_socket_pool_base.h"
#include "net/socket/ssl_server_socket.h"
#include "net/test/net_test_suite.h"
#include "net/test/spawned_test_server/spawned_test_server.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
#include "yahoo/cnet/cnet.h"
#include "yahoo/cnet/cnet_fetcher.h"
#include "yahoo/cnet/cnet_pool.h"
#include "yahoo/cnet/cnet_response.h"

using net::internal::ClientSocketPoolBaseHelper;

// Copied from url_request_unittest.cc
class LocalHttpTestServer : public net::SpawnedTestServer {
 public:
  explicit LocalHttpTestServer(const base::FilePath& document_root)
      : net::SpawnedTestServer(net::SpawnedTestServer::TYPE_HTTPS,
            "127.0.0.1", document_root) {}
  LocalHttpTestServer()
      : net::SpawnedTestServer(net::SpawnedTestServer::TYPE_HTTPS,
            "127.0.0.1", base::FilePath()) {}
};

class PoolTest : public PlatformTest {
 public:
  PoolTest()
      : quit_event_(false, false) {
    base::Thread::Options options;
    options.message_loop_type = base::MessageLoop::TYPE_UI;
    ui_thread_ = new base::Thread("cnet-ui");
    ui_thread_->StartWithOptions(options);

    cnet::Pool::Config config;
    config.user_agent = "cnet-unittest";
    pool_ = new cnet::Pool(ui_thread_->task_runner(), config);
  }

  virtual ~PoolTest() { }

  virtual void TearDown() override {
    StartDelete();
    quit_event_.Wait();
    ui_thread_->Stop();
  }

 protected:
  void StartDelete() {
    if (!pool_->GetNetworkTaskRunner()->RunsTasksOnCurrentThread()) {
      pool_->GetNetworkTaskRunner()->PostTask(FROM_HERE,
         base::Bind(&PoolTest::StartDelete, base::Unretained(this)));
      return;
    }

    // This should post a task to the UI thread to delete the pool's threads.
    // We want to do this from the network thread so that we know that
    // it will post a task to the UI thread before us.
    // This works only if the retain count is currently 1.
    pool_ = NULL;

    // Now we post a task to the UI thread to follow the cleanup of the pool.
    ui_thread_->message_loop()->PostTask(FROM_HERE,
        base::Bind(&PoolTest::OnPoolDeleted, base::Unretained(this)));
  }

  void OnPoolDeleted() {
    ASSERT_TRUE(ui_thread_->task_runner()->RunsTasksOnCurrentThread());
    quit_event_.Signal();
  }

  base::Thread* ui_thread_;
  base::WaitableEvent quit_event_;
  scoped_refptr<cnet::Pool> pool_;
};

TEST_F(PoolTest, InitShutdown) {
}

class FetcherTest : public PoolTest {
 public:
  FetcherTest()
      : completed_event_(false, false),
        test_server_(base::FilePath(FILE_PATH_LITERAL(
            "yahoo/cnet/data/cnet_unittest"))),
        download_progress_(0), upload_progress_(0) {
  }

  void OnFetcherCompleted(scoped_refptr<cnet::Fetcher> fetcher,
      scoped_refptr<cnet::Response> response) {
    // On work thread.
    response_ = response;
    completed_event_.Signal();
  }

  void OnFetcherDownloadProgress(scoped_refptr<cnet::Fetcher> fetcher,
      int64_t current, int64_t total) {
    // On work thread.
    download_progress_ = current;
  }

  void OnFetcherUploadProgress(scoped_refptr<cnet::Fetcher> fetcher,
      int64_t current, int64_t total) {
    // On work thread.
    upload_progress_ = current;
  }

 protected:
  scoped_refptr<cnet::Response> WaitForCompletion() {
    completed_event_.Wait();
    return response_;
  }

  base::WaitableEvent completed_event_;
  LocalHttpTestServer test_server_;
  scoped_refptr<cnet::Response> response_;
  int64 download_progress_;
  int64 upload_progress_;
};

TEST_F(FetcherTest, SimpleFetch) {
  ASSERT_TRUE(test_server_.Start());

  std::string url(test_server_.GetURL("files/hello.html").spec());
  scoped_refptr<cnet::Fetcher> fetcher(new cnet::Fetcher(
      pool_, url, "GET",
      base::Bind(&FetcherTest::OnFetcherCompleted, base::Unretained(this)),
      base::Bind(&FetcherTest::OnFetcherDownloadProgress,
          base::Unretained(this)),
      base::Bind(&FetcherTest::OnFetcherUploadProgress,
          base::Unretained(this))));
  fetcher->Start();

  scoped_refptr<cnet::Response> response = WaitForCompletion();
  ASSERT_EQ(response->status().status(), net::URLRequestStatus::SUCCESS);
  ASSERT_EQ(response->http_response_code(), 200);
  EXPECT_EQ(response->initial_url(), url);
  EXPECT_EQ(response->original_url(), GURL(url));
  EXPECT_EQ(response->final_url(), GURL(url));

  scoped_refptr<net::HttpResponseHeaders> response_headers(
      response->response_headers());
  EXPECT_TRUE(response_headers->HasHeaderValue("Content-Type", "text/html"));

  std::string expected_body("Hello!\n\n");
  ASSERT_EQ((int)expected_body.length(), response->response_length());
  std::string response_body(response->response_body(),
      response->response_length());
  ASSERT_EQ(expected_body, response_body);

  EXPECT_EQ(upload_progress_, 0);
  EXPECT_EQ(download_progress_, response->response_length());
}

TEST_F(FetcherTest, FetchError) {
  ASSERT_TRUE(test_server_.Start());

  std::string url(test_server_.GetURL("close-socket").spec());
  scoped_refptr<cnet::Fetcher> fetcher(new cnet::Fetcher(
      pool_, url, "GET",
      base::Bind(&FetcherTest::OnFetcherCompleted, base::Unretained(this)),
      base::Bind(&FetcherTest::OnFetcherDownloadProgress,
          base::Unretained(this)),
      base::Bind(&FetcherTest::OnFetcherUploadProgress,
          base::Unretained(this))));
  fetcher->Start();

  scoped_refptr<cnet::Response> response = WaitForCompletion();
  ASSERT_NE(response->status().status(), net::URLRequestStatus::SUCCESS);
  ASSERT_EQ(response->status().status(), net::URLRequestStatus::FAILED);
  ASSERT_EQ(response->http_response_code(), -1);
}

int main(int argc, char** argv) {
  base::StatisticsRecorder::Initialize();

  NetTestSuite test_suite(argc, argv);
  ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(false);

#if defined(OS_WIN)
  // We want to be sure to init NSPR on the main thread.
  crypto::EnsureNSPRInit();
#endif

  // Enable support for SSL server sockets, which must be done while
  // single-threaded.
  net::EnableSSLServerSockets();

  return base::LaunchUnitTests(argc, argv,
      base::Bind(&NetTestSuite::Run, base::Unretained(&test_suite)));
}
<commit_msg>Added links to test documentation.<commit_after>// Copyright 2014, Yahoo! Inc.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Some portions of this file:
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Testing documentation:
//   https://code.google.com/p/googletest/wiki/Primer
//   https://www.chromium.org/developers/testing

#include "base/metrics/statistics_recorder.h"
#include "base/run_loop.h"
#include "base/test/launcher/unit_test_launcher.h"
#include "net/http/http_response_headers.h"
#include "net/socket/client_socket_pool_base.h"
#include "net/socket/ssl_server_socket.h"
#include "net/test/net_test_suite.h"
#include "net/test/spawned_test_server/spawned_test_server.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
#include "yahoo/cnet/cnet.h"
#include "yahoo/cnet/cnet_fetcher.h"
#include "yahoo/cnet/cnet_pool.h"
#include "yahoo/cnet/cnet_response.h"

using net::internal::ClientSocketPoolBaseHelper;

// Copied from url_request_unittest.cc
class LocalHttpTestServer : public net::SpawnedTestServer {
 public:
  explicit LocalHttpTestServer(const base::FilePath& document_root)
      : net::SpawnedTestServer(net::SpawnedTestServer::TYPE_HTTPS,
            "127.0.0.1", document_root) {}
  LocalHttpTestServer()
      : net::SpawnedTestServer(net::SpawnedTestServer::TYPE_HTTPS,
            "127.0.0.1", base::FilePath()) {}
};

class PoolTest : public PlatformTest {
 public:
  PoolTest()
      : quit_event_(false, false) {
    base::Thread::Options options;
    options.message_loop_type = base::MessageLoop::TYPE_UI;
    ui_thread_ = new base::Thread("cnet-ui");
    ui_thread_->StartWithOptions(options);

    cnet::Pool::Config config;
    config.user_agent = "cnet-unittest";
    pool_ = new cnet::Pool(ui_thread_->task_runner(), config);
  }

  virtual ~PoolTest() { }

  virtual void TearDown() override {
    StartDelete();
    quit_event_.Wait();
    ui_thread_->Stop();
  }

 protected:
  void StartDelete() {
    if (!pool_->GetNetworkTaskRunner()->RunsTasksOnCurrentThread()) {
      pool_->GetNetworkTaskRunner()->PostTask(FROM_HERE,
         base::Bind(&PoolTest::StartDelete, base::Unretained(this)));
      return;
    }

    // This should post a task to the UI thread to delete the pool's threads.
    // We want to do this from the network thread so that we know that
    // it will post a task to the UI thread before us.
    // This works only if the retain count is currently 1.
    pool_ = NULL;

    // Now we post a task to the UI thread to follow the cleanup of the pool.
    ui_thread_->message_loop()->PostTask(FROM_HERE,
        base::Bind(&PoolTest::OnPoolDeleted, base::Unretained(this)));
  }

  void OnPoolDeleted() {
    ASSERT_TRUE(ui_thread_->task_runner()->RunsTasksOnCurrentThread());
    quit_event_.Signal();
  }

  base::Thread* ui_thread_;
  base::WaitableEvent quit_event_;
  scoped_refptr<cnet::Pool> pool_;
};

TEST_F(PoolTest, InitShutdown) {
}

class FetcherTest : public PoolTest {
 public:
  FetcherTest()
      : completed_event_(false, false),
        test_server_(base::FilePath(FILE_PATH_LITERAL(
            "yahoo/cnet/data/cnet_unittest"))),
        download_progress_(0), upload_progress_(0) {
  }

  void OnFetcherCompleted(scoped_refptr<cnet::Fetcher> fetcher,
      scoped_refptr<cnet::Response> response) {
    // On work thread.
    response_ = response;
    completed_event_.Signal();
  }

  void OnFetcherDownloadProgress(scoped_refptr<cnet::Fetcher> fetcher,
      int64_t current, int64_t total) {
    // On work thread.
    download_progress_ = current;
  }

  void OnFetcherUploadProgress(scoped_refptr<cnet::Fetcher> fetcher,
      int64_t current, int64_t total) {
    // On work thread.
    upload_progress_ = current;
  }

 protected:
  scoped_refptr<cnet::Response> WaitForCompletion() {
    completed_event_.Wait();
    return response_;
  }

  base::WaitableEvent completed_event_;
  LocalHttpTestServer test_server_;
  scoped_refptr<cnet::Response> response_;
  int64 download_progress_;
  int64 upload_progress_;
};

TEST_F(FetcherTest, SimpleFetch) {
  ASSERT_TRUE(test_server_.Start());

  std::string url(test_server_.GetURL("files/hello.html").spec());
  scoped_refptr<cnet::Fetcher> fetcher(new cnet::Fetcher(
      pool_, url, "GET",
      base::Bind(&FetcherTest::OnFetcherCompleted, base::Unretained(this)),
      base::Bind(&FetcherTest::OnFetcherDownloadProgress,
          base::Unretained(this)),
      base::Bind(&FetcherTest::OnFetcherUploadProgress,
          base::Unretained(this))));
  fetcher->Start();

  scoped_refptr<cnet::Response> response = WaitForCompletion();
  ASSERT_EQ(response->status().status(), net::URLRequestStatus::SUCCESS);
  ASSERT_EQ(response->http_response_code(), 200);
  EXPECT_EQ(response->initial_url(), url);
  EXPECT_EQ(response->original_url(), GURL(url));
  EXPECT_EQ(response->final_url(), GURL(url));

  scoped_refptr<net::HttpResponseHeaders> response_headers(
      response->response_headers());
  EXPECT_TRUE(response_headers->HasHeaderValue("Content-Type", "text/html"));

  std::string expected_body("Hello!\n\n");
  ASSERT_EQ((int)expected_body.length(), response->response_length());
  std::string response_body(response->response_body(),
      response->response_length());
  ASSERT_EQ(expected_body, response_body);

  EXPECT_EQ(upload_progress_, 0);
  EXPECT_EQ(download_progress_, response->response_length());
}

TEST_F(FetcherTest, FetchError) {
  ASSERT_TRUE(test_server_.Start());

  std::string url(test_server_.GetURL("close-socket").spec());
  scoped_refptr<cnet::Fetcher> fetcher(new cnet::Fetcher(
      pool_, url, "GET",
      base::Bind(&FetcherTest::OnFetcherCompleted, base::Unretained(this)),
      base::Bind(&FetcherTest::OnFetcherDownloadProgress,
          base::Unretained(this)),
      base::Bind(&FetcherTest::OnFetcherUploadProgress,
          base::Unretained(this))));
  fetcher->Start();

  scoped_refptr<cnet::Response> response = WaitForCompletion();
  ASSERT_NE(response->status().status(), net::URLRequestStatus::SUCCESS);
  ASSERT_EQ(response->status().status(), net::URLRequestStatus::FAILED);
  ASSERT_EQ(response->http_response_code(), -1);
}

int main(int argc, char** argv) {
  base::StatisticsRecorder::Initialize();

  NetTestSuite test_suite(argc, argv);
  ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(false);

#if defined(OS_WIN)
  // We want to be sure to init NSPR on the main thread.
  crypto::EnsureNSPRInit();
#endif

  // Enable support for SSL server sockets, which must be done while
  // single-threaded.
  net::EnableSSLServerSockets();

  return base::LaunchUnitTests(argc, argv,
      base::Bind(&NetTestSuite::Run, base::Unretained(&test_suite)));
}
<|endoftext|>


<commit_before>#ifndef CWRAPPER_HPP_INCLUDED
#define CWRAPPER_HPP_INCLUDED

#define HAS_STATIC_MEMBER_DETECTOR(member)                                  \
template<typename T>                                                        \
class HAS_STATIC_MEMBER_DETECTOR_CLASS_ ## member                           \
{                                                                           \
    struct two_ints_type { int two_ints_1, two_ints_2; };                   \
    template<typename U>                                                    \
    static two_ints_type has_func_helper(...) { }                           \
    template<typename U>                                                    \
    static int has_func_helper(int, decltype(U::member)* func = nullptr)    \
    { return 0; }                                                           \
public:                                                                     \
    static constexpr bool value =                                           \
        sizeof(decltype(has_func_helper<T>(0))) == sizeof(int);             \
}

#define HAS_STATIC_MEMBER(type, member)                                     \
    (HAS_STATIC_MEMBER_DETECTOR_CLASS_ ## member<type>::value)

#define HAS_NESTED_TYPE_DETECTOR(member)                                    \
template<typename T>                                                        \
class HAS_NESTED_TYPE_DETECTOR_CLASS_ ## member                             \
{                                                                           \
    struct two_ints_type { int two_ints_1, two_ints_2; };                   \
    template<typename U>                                                    \
    static two_ints_type has_func_helper(...) { }                           \
    template<typename U>                                                    \
    static int has_func_helper(int, typename U::member* ty = nullptr)       \
    { return 0; }                                                           \
public:                                                                     \
    static constexpr bool value =                                           \
        sizeof(decltype(has_func_helper<T>(0))) == sizeof(int);             \
}

#define HAS_NESTED_TYPE(type, member)                                       \
    (HAS_NESTED_TYPE_DETECTOR_CLASS_ ## member<type>::value)

enum class CWrapperType
{
    Implicit,
    Explicit,
    Get,
};

template<
    typename H,
    typename F,
    CWrapperType TY,
    bool C>
class __CWrapperHelper__
{

template<
    typename HANDLE_T,
    typename BASE,
    bool CONSTSAFE>
struct ArrowHandler
{ };

template<
    typename PTR_T,
    typename BASE>
struct ArrowHandler<PTR_T*, BASE, false>
{
    PTR_T* operator->() const
    {   return static_cast<BASE*>(this)->ptr; }
};

template<
    typename PTR_T,
    typename BASE>
struct ArrowHandler<PTR_T*, BASE, true>
{
    PTR_T* operator->()
    {   return static_cast<BASE*>(this)->ptr; }
    PTR_T const* operator->() const
    {   return static_cast<BASE*>(this)->ptr; }
};

template<
    typename HANDLE_T,
    typename BASE,
    CWrapperType TYPE,
    bool CONSTSAFE>
struct ConversionHandler : public ArrowHandler<HANDLE_T, BASE, CONSTSAFE>
{ };

template<
    typename HANDLE_T,
    typename BASE,
    bool CONSTSAFE>
struct ConversionHandler<HANDLE_T, BASE, CWrapperType::Implicit, CONSTSAFE>
    : public ArrowHandler<HANDLE_T, BASE, CONSTSAFE>
{
    operator HANDLE_T() const
    {   return static_cast<BASE*>(this)->ptr; }
};
template<
    typename HANDLE_T,
    typename BASE,
    bool CONSTSAFE>
struct ConversionHandler<HANDLE_T, BASE, CWrapperType::Explicit, CONSTSAFE>
    : public ArrowHandler<HANDLE_T, BASE, CONSTSAFE>
{
    explicit operator HANDLE_T() const
    {   return static_cast<BASE*>(this)->ptr; }
};
template<
    typename HANDLE_T,
    typename BASE,
    bool CONSTSAFE>
struct ConversionHandler<HANDLE_T, BASE, CWrapperType::Get, CONSTSAFE>
    : public ArrowHandler<HANDLE_T, BASE, CONSTSAFE>
{
    HANDLE_T get() const
    {   return static_cast<BASE*>(this)->ptr; }
};

template<
    typename PTR_T,
    typename BASE>
struct ConversionHandler<PTR_T*, BASE, CWrapperType::Implicit, true>
    : public ArrowHandler<PTR_T*, BASE, true>
{
    operator PTR_T*()
    {   return static_cast<BASE*>(this)->ptr; }
    operator PTR_T const*() const
    {   return static_cast<BASE*>(this)->ptr; }
};
template<
    typename PTR_T,
    typename BASE>
struct ConversionHandler<PTR_T*, BASE, CWrapperType::Explicit, true>
    : public ArrowHandler<PTR_T*, BASE, true>
{
    explicit operator PTR_T*()
    {   return static_cast<BASE*>(this)->ptr; }
    explicit operator PTR_T const*() const
    {   return static_cast<BASE*>(this)->ptr; }
};
template<
    typename PTR_T,
    typename BASE>
struct ConversionHandler<PTR_T*, BASE, CWrapperType::Get, true>
    : public ArrowHandler<PTR_T*, BASE, true>
{
    PTR_T* get()
    {   return static_cast<BASE*>(this)->ptr; }
    PTR_T const* get() const
    {   return static_cast<BASE*>(this)->ptr; }
};

template<
    typename HANDLE_T,
    typename FUNCTIONS,
    CWrapperType TYPE,
    bool CONSTSAFE,
    typename EXCEPTION_T,
    typename INVALID_T>
class CWrapperBase
    : public ConversionHandler<
        HANDLE_T,
        CWrapperBase<HANDLE_T, FUNCTIONS, TYPE, CONSTSAFE, EXCEPTION_T, INVALID_T>,
        TYPE,
        CONSTSAFE>
{
    friend class ConversionHandler<
        HANDLE_T,
        CWrapperBase<HANDLE_T, FUNCTIONS, TYPE, CONSTSAFE, EXCEPTION_T, INVALID_T>,
        TYPE,
        CONSTSAFE>;
protected:
    HANDLE_T ptr;

public:

    explicit CWrapperBase(HANDLE_T ptr) :
        ptr{ptr}
    {
        if(ptr == INVALID_T::invalid_value)
            throw EXCEPTION_T{};
    }

    CWrapperBase(CWrapperBase const& other) :
        CWrapperBase{FUNCTIONS::copy_func(other.ptr)}
    { }

    // This one is needed to prevent variadic ctor to be called
    // when you want to copy a non-const object.
    CWrapperBase(CWrapperBase& other) :
        CWrapperBase{FUNCTIONS::copy_func(other.ptr)}
    { }

    template<typename... ARGS>
    explicit CWrapperBase(ARGS&&... args) :
        CWrapperBase{FUNCTIONS::ctor_func(std::forward<ARGS>(args)...)}
    { }

    CWrapperBase(CWrapperBase&& old) :
        CWrapperBase{old.ptr}
    {
        old.ptr = INVALID_T::invalid_value;
    }

    CWrapperBase& operator=(CWrapperBase&& old)
    {
        if(this != &old)
        {
            FUNCTIONS::dtor_func(ptr);
            ptr = old.ptr;
            old.ptr = INVALID_T::invalid_value;
        }
        return *this;
    }

    ~CWrapperBase()
    {
        FUNCTIONS::dtor_func(ptr);
    }

    CWrapperBase& operator=(CWrapperBase const& other)
    {
        if(this != &other)
        {
            HANDLE_T new_ptr = FUNCTIONS::copy_func(other.ptr);
            if(new_ptr == INVALID_T::invalid_value)
                throw EXCEPTION_T{};

            FUNCTIONS::dtor_func(ptr);
            ptr = new_ptr;
        }
        return *this;
    }
};

template<
    typename HANDLE_T,
    typename FUNCTIONS,
    CWrapperType TYPE,
    bool CONSTSAFE,
    typename EXCEPTION_T,
    typename INVALID_T>
class CWrapperNonCopiable
    : public ConversionHandler<
        HANDLE_T,
        CWrapperNonCopiable<HANDLE_T, FUNCTIONS, TYPE, CONSTSAFE, EXCEPTION_T, INVALID_T>,
        TYPE,
        CONSTSAFE>
{
    friend class ConversionHandler<
        HANDLE_T,
        CWrapperNonCopiable<HANDLE_T, FUNCTIONS, TYPE, CONSTSAFE, EXCEPTION_T, INVALID_T>,
        TYPE,
        CONSTSAFE>;

protected:
    HANDLE_T ptr;

public:

    explicit CWrapperNonCopiable(HANDLE_T ptr) :
        ptr{ptr}
    {
        if(ptr == INVALID_T::invalid_value)
            throw EXCEPTION_T{};
    }

    template<typename... ARGS>
    explicit CWrapperNonCopiable(ARGS&&... args) :
        CWrapperNonCopiable{FUNCTIONS::ctor_func(std::forward<ARGS>(args)...)}
    { }

    CWrapperNonCopiable(CWrapperNonCopiable&& old) :
        CWrapperNonCopiable{old.ptr}
    {
        old.ptr = INVALID_T::invalid_value;
    }

    CWrapperNonCopiable& operator=(CWrapperNonCopiable&& old)
    {
        if(this != &old)
        {
            FUNCTIONS::dtor_func(ptr);
            ptr = old.ptr;
            old.ptr = INVALID_T::invalid_value;
        }
        return *this;
    }

    ~CWrapperNonCopiable()
    {
        FUNCTIONS::dtor_func(ptr);
    }

    // This one is needed to prevent variadic ctor to be called
    // when you want to copy a non-const object.
    CWrapperNonCopiable(CWrapperNonCopiable& other) = delete;
    CWrapperNonCopiable(CWrapperNonCopiable const& other) = delete;
    CWrapperNonCopiable& operator=(CWrapperNonCopiable const& other) = delete;
};

template<bool condition, typename TRUE_TYPE, typename FALSE_TYPE>
struct COND
{
    using type = TRUE_TYPE;
};

template<typename TRUE_TYPE, typename FALSE_TYPE>
struct COND<false, TRUE_TYPE, FALSE_TYPE>
{
    using type = FALSE_TYPE;
};

HAS_NESTED_TYPE_DETECTOR(exception);
HAS_STATIC_MEMBER_DETECTOR(copy_func);
HAS_STATIC_MEMBER_DETECTOR(invalid_value);

template<typename TYPE, typename DEFTYPE, bool>
struct default_exception_type
{
    using type = DEFTYPE;
};

template<typename TYPE, typename DEFTYPE>
struct default_exception_type<TYPE, DEFTYPE, true>
{
    using type = typename TYPE::exception;
};

template<typename T>
struct default_invalid_value
{
    static constexpr T invalid_value = 0;
};
template<typename T>
struct default_invalid_value<T*>
{
    static constexpr T* invalid_value = nullptr;
};

using E = typename default_exception_type<F, std::bad_alloc, HAS_NESTED_TYPE(F, exception)>::type;
using D = typename COND< HAS_STATIC_MEMBER(F, invalid_value),
    F, default_invalid_value<H>>::type;

public:

    using type = typename COND< HAS_STATIC_MEMBER(F, copy_func),
        CWrapperBase<H, F, TY, C, E, D>,
        CWrapperNonCopiable<H, F, TY, C, E, D>>::type;
};

template<
    typename HANDLE_T,
    typename FUNCTIONS,
    CWrapperType TYPE = CWrapperType::Get,
    bool CONSTSAFE = true>
using CWrapper = typename __CWrapperHelper__<HANDLE_T, FUNCTIONS, TYPE, CONSTSAFE>::type;

#endif // CWRAPPER_HPP_INCLUDED
<commit_msg>Validating added<commit_after>#ifndef CWRAPPER_HPP_INCLUDED
#define CWRAPPER_HPP_INCLUDED

#define HAS_STATIC_MEMBER_DETECTOR(member)                                  \
template<typename T>                                                        \
class HAS_STATIC_MEMBER_DETECTOR_CLASS_ ## member                           \
{                                                                           \
    struct two_ints_type { int two_ints_1, two_ints_2; };                   \
    template<typename U>                                                    \
    static two_ints_type has_func_helper(...) { }                           \
    template<typename U>                                                    \
    static int has_func_helper(int, decltype(U::member)* func = nullptr)    \
    { return 0; }                                                           \
public:                                                                     \
    static constexpr bool value =                                           \
        sizeof(decltype(has_func_helper<T>(0))) == sizeof(int);             \
}

#define HAS_STATIC_MEMBER(type, member)                                     \
    (HAS_STATIC_MEMBER_DETECTOR_CLASS_ ## member<type>::value)

#define HAS_NESTED_TYPE_DETECTOR(member)                                    \
template<typename T>                                                        \
class HAS_NESTED_TYPE_DETECTOR_CLASS_ ## member                             \
{                                                                           \
    struct two_ints_type { int two_ints_1, two_ints_2; };                   \
    template<typename U>                                                    \
    static two_ints_type has_func_helper(...) { }                           \
    template<typename U>                                                    \
    static int has_func_helper(int, typename U::member* ty = nullptr)       \
    { return 0; }                                                           \
public:                                                                     \
    static constexpr bool value =                                           \
        sizeof(decltype(has_func_helper<T>(0))) == sizeof(int);             \
}

#define HAS_NESTED_TYPE(type, member)                                       \
    (HAS_NESTED_TYPE_DETECTOR_CLASS_ ## member<type>::value)

enum class CWrapperType
{
    Implicit,
    Explicit,
    Get,
};

template<
    typename H,
    typename F,
    CWrapperType TY,
    bool C>
class __CWrapperHelper__
{

template<
    typename HANDLE_T,
    typename BASE,
    bool CONSTSAFE>
struct ArrowHandler
{ };

template<
    typename PTR_T,
    typename BASE>
struct ArrowHandler<PTR_T*, BASE, false>
{
    PTR_T* operator->() const
    {   return static_cast<BASE*>(this)->ptr; }
};

template<
    typename PTR_T,
    typename BASE>
struct ArrowHandler<PTR_T*, BASE, true>
{
    PTR_T* operator->()
    {   return static_cast<BASE*>(this)->ptr; }
    PTR_T const* operator->() const
    {   return static_cast<BASE*>(this)->ptr; }
};

template<
    typename HANDLE_T,
    typename BASE,
    CWrapperType TYPE,
    bool CONSTSAFE>
struct ConversionHandler : public ArrowHandler<HANDLE_T, BASE, CONSTSAFE>
{ };

template<
    typename HANDLE_T,
    typename BASE,
    bool CONSTSAFE>
struct ConversionHandler<HANDLE_T, BASE, CWrapperType::Implicit, CONSTSAFE>
    : public ArrowHandler<HANDLE_T, BASE, CONSTSAFE>
{
    operator HANDLE_T() const
    {   return static_cast<BASE*>(this)->ptr; }
};
template<
    typename HANDLE_T,
    typename BASE,
    bool CONSTSAFE>
struct ConversionHandler<HANDLE_T, BASE, CWrapperType::Explicit, CONSTSAFE>
    : public ArrowHandler<HANDLE_T, BASE, CONSTSAFE>
{
    explicit operator HANDLE_T() const
    {   return static_cast<BASE*>(this)->ptr; }
};
template<
    typename HANDLE_T,
    typename BASE,
    bool CONSTSAFE>
struct ConversionHandler<HANDLE_T, BASE, CWrapperType::Get, CONSTSAFE>
    : public ArrowHandler<HANDLE_T, BASE, CONSTSAFE>
{
    HANDLE_T get() const
    {   return static_cast<BASE*>(this)->ptr; }
};

template<
    typename PTR_T,
    typename BASE>
struct ConversionHandler<PTR_T*, BASE, CWrapperType::Implicit, true>
    : public ArrowHandler<PTR_T*, BASE, true>
{
    operator PTR_T*()
    {   return static_cast<BASE*>(this)->ptr; }
    operator PTR_T const*() const
    {   return static_cast<BASE*>(this)->ptr; }
};
template<
    typename PTR_T,
    typename BASE>
struct ConversionHandler<PTR_T*, BASE, CWrapperType::Explicit, true>
    : public ArrowHandler<PTR_T*, BASE, true>
{
    explicit operator PTR_T*()
    {   return static_cast<BASE*>(this)->ptr; }
    explicit operator PTR_T const*() const
    {   return static_cast<BASE*>(this)->ptr; }
};
template<
    typename PTR_T,
    typename BASE>
struct ConversionHandler<PTR_T*, BASE, CWrapperType::Get, true>
    : public ArrowHandler<PTR_T*, BASE, true>
{
    PTR_T* get()
    {   return static_cast<BASE*>(this)->ptr; }
    PTR_T const* get() const
    {   return static_cast<BASE*>(this)->ptr; }
};

template<
    typename HANDLE_T,
    typename FUNCTIONS,
    CWrapperType TYPE,
    bool CONSTSAFE,
    typename EXCEPTION_T,
    typename INVALID_T,
    typename VALIDATE_T>
class CWrapperBase
    : public ConversionHandler<
        HANDLE_T,
        CWrapperBase<HANDLE_T, FUNCTIONS, TYPE, CONSTSAFE, EXCEPTION_T, INVALID_T, VALIDATE_T>,
        TYPE,
        CONSTSAFE>
{
    friend class ConversionHandler<
        HANDLE_T,
        CWrapperBase<HANDLE_T, FUNCTIONS, TYPE, CONSTSAFE, EXCEPTION_T, INVALID_T, VALIDATE_T>,
        TYPE,
        CONSTSAFE>;
protected:
    HANDLE_T ptr;

public:

    explicit CWrapperBase(HANDLE_T ptr) :
        ptr{ptr}
    {
        if(!VALIDATE_T::validate_func(ptr))
            throw EXCEPTION_T{};
    }

    CWrapperBase(CWrapperBase const& other) :
        CWrapperBase{FUNCTIONS::copy_func(other.ptr)}
    { }

    // This one is needed to prevent variadic ctor to be called
    // when you want to copy a non-const object.
    CWrapperBase(CWrapperBase& other) :
        CWrapperBase{FUNCTIONS::copy_func(other.ptr)}
    { }

    template<typename... ARGS>
    explicit CWrapperBase(ARGS&&... args) :
        CWrapperBase{FUNCTIONS::ctor_func(std::forward<ARGS>(args)...)}
    { }

    CWrapperBase(CWrapperBase&& old) :
        CWrapperBase{old.ptr}
    {
        old.ptr = INVALID_T::invalid_value;
    }

    CWrapperBase& operator=(CWrapperBase&& old)
    {
        if(this != &old)
        {
            FUNCTIONS::dtor_func(ptr);
            ptr = old.ptr;
            old.ptr = INVALID_T::invalid_value;
        }
        return *this;
    }

    ~CWrapperBase()
    {
        FUNCTIONS::dtor_func(ptr);
    }

    CWrapperBase& operator=(CWrapperBase const& other)
    {
        if(this != &other)
        {
            HANDLE_T new_ptr = FUNCTIONS::copy_func(other.ptr);
            if(!VALIDATE_T::validate_func(new_ptr))
                throw EXCEPTION_T{};

            FUNCTIONS::dtor_func(ptr);
            ptr = new_ptr;
        }
        return *this;
    }
};

template<
    typename HANDLE_T,
    typename FUNCTIONS,
    CWrapperType TYPE,
    bool CONSTSAFE,
    typename EXCEPTION_T,
    typename INVALID_T,
    typename VALIDATE_T>
class CWrapperNonCopiable
    : public ConversionHandler<
        HANDLE_T,
        CWrapperNonCopiable<HANDLE_T, FUNCTIONS, TYPE, CONSTSAFE, EXCEPTION_T, INVALID_T, VALIDATE_T>,
        TYPE,
        CONSTSAFE>
{
    friend class ConversionHandler<
        HANDLE_T,
        CWrapperNonCopiable<HANDLE_T, FUNCTIONS, TYPE, CONSTSAFE, EXCEPTION_T, INVALID_T, VALIDATE_T>,
        TYPE,
        CONSTSAFE>;

protected:
    HANDLE_T ptr;

public:

    explicit CWrapperNonCopiable(HANDLE_T ptr) :
        ptr{ptr}
    {
        if(!VALIDATE_T::validate_func(ptr))
            throw EXCEPTION_T{};
    }

    template<typename... ARGS>
    explicit CWrapperNonCopiable(ARGS&&... args) :
        CWrapperNonCopiable{FUNCTIONS::ctor_func(std::forward<ARGS>(args)...)}
    { }

    CWrapperNonCopiable(CWrapperNonCopiable&& old) :
        CWrapperNonCopiable{old.ptr}
    {
        old.ptr = INVALID_T::invalid_value;
    }

    CWrapperNonCopiable& operator=(CWrapperNonCopiable&& old)
    {
        if(this != &old)
        {
            FUNCTIONS::dtor_func(ptr);
            ptr = old.ptr;
            old.ptr = INVALID_T::invalid_value;
        }
        return *this;
    }

    ~CWrapperNonCopiable()
    {
        FUNCTIONS::dtor_func(ptr);
    }

    // This one is needed to prevent variadic ctor to be called
    // when you want to copy a non-const object.
    CWrapperNonCopiable(CWrapperNonCopiable& other) = delete;
    CWrapperNonCopiable(CWrapperNonCopiable const& other) = delete;
    CWrapperNonCopiable& operator=(CWrapperNonCopiable const& other) = delete;
};

template<bool condition, typename TRUE_TYPE, typename FALSE_TYPE>
struct COND
{
    using type = TRUE_TYPE;
};

template<typename TRUE_TYPE, typename FALSE_TYPE>
struct COND<false, TRUE_TYPE, FALSE_TYPE>
{
    using type = FALSE_TYPE;
};

HAS_NESTED_TYPE_DETECTOR(exception);
HAS_STATIC_MEMBER_DETECTOR(copy_func);
HAS_STATIC_MEMBER_DETECTOR(invalid_value);
HAS_STATIC_MEMBER_DETECTOR(validate_func);

template<typename TYPE, typename DEFTYPE, bool>
struct default_exception_type
{
    using type = DEFTYPE;
};

template<typename TYPE, typename DEFTYPE>
struct default_exception_type<TYPE, DEFTYPE, true>
{
    using type = typename TYPE::exception;
};

template<typename T>
struct default_invalid_value
{
    static constexpr T invalid_value = 0;
};
template<typename T>
struct default_invalid_value<T*>
{
    static constexpr T* invalid_value = nullptr;
};

template<typename T, typename INVALID_T>
struct default_validate_func
{
    static constexpr bool validate_func(T ptr)
    {
        return ptr != INVALID_T::invalid_value;
    }
};

using E = typename default_exception_type<F, std::bad_alloc, HAS_NESTED_TYPE(F, exception)>::type;
using D = typename COND< HAS_STATIC_MEMBER(F, invalid_value),
    F, default_invalid_value<H>>::type;
using V = typename COND< HAS_STATIC_MEMBER(F, validate_func),
    F, default_validate_func<H, D>>::type;

public:

    using type = typename COND< HAS_STATIC_MEMBER(F, copy_func),
        CWrapperBase<H, F, TY, C, E, D, V>,
        CWrapperNonCopiable<H, F, TY, C, E, D, V>>::type;
};

template<
    typename HANDLE_T,
    typename FUNCTIONS,
    CWrapperType TYPE = CWrapperType::Get,
    bool CONSTSAFE = true>
using CWrapper = typename __CWrapperHelper__<HANDLE_T, FUNCTIONS, TYPE, CONSTSAFE>::type;

#endif // CWRAPPER_HPP_INCLUDED
<|endoftext|>