Пример #1
0
/*
 * Decode the DMP header. If data is null we're expected to use the last
 * header we got.
 * @param headers the HeaderSet to add to
 * @param data a pointer to the data
 * @param length length of the data
 * @returns true if successful, false otherwise
 */
bool DMPInflator::DecodeHeader(HeaderSet &headers,
                                const uint8_t *data,
                                unsigned int length,
                                unsigned int &bytes_used) {
  if (data) {
    // the header bit was set, decode it
    if (length >= DMPHeader::DMP_HEADER_SIZE) {
      DMPHeader header(*data);
      m_last_header = header;
      m_last_header_valid = true;
      headers.SetDMPHeader(header);
      bytes_used = DMPHeader::DMP_HEADER_SIZE;
      return true;
    }
    bytes_used = 0;
    return false;
  }

  // use the last header if it exists
  bytes_used = 0;
  if (!m_last_header_valid) {
    OLA_WARN << "Missing DMP Header data";
    return false;
  }
  headers.SetDMPHeader(m_last_header);
  return true;
}
Пример #2
0
/**
 * Tries to construct an HTTP request object from the given string.
 * @return Returns the object representing the request on success, or NULL if
 * the string could not be parsed. If set, consumed will be filled with
 * the amount of data that was consumed from the string to parse the request.
 */
Request* Request::fromString(const string &str, unsigned int *consumed)
{
	unsigned int cons = 0;

	//Parse the first line which consists of the request type.
	size_t firstCRLF = str.find("\r\n");
	if (firstCRLF == string::npos) return NULL;
	string firstLine = str.substr(0, firstCRLF);
	cons = firstCRLF + 2;

	size_t methodPos = firstLine.find(" ");
	if (methodPos == string::npos) return NULL;
	string method = firstLine.substr(0, methodPos);
	Type type;
	if (method == "GET") type = kGET;
	else if (method == "POST") type = kPOST;
	else if (method == "DELETE") type = kDELETE;
	else if (method == "PUT") type = kPUT;
	else {
		throw new GenericError(string("Received HTTP request with unknown method '") + method + "'.");
	}

	size_t pathPos = firstLine.find(" ", methodPos + 1);
	if (pathPos == string::npos) return NULL;
	string path = firstLine.substr(methodPos + 1, pathPos - methodPos - 1);

	//Parse the header.
	unsigned int hsConsumed = 0;
	HeaderSet *hs = HeaderSet::fromString(str.substr(firstCRLF + 2), &hsConsumed);
	cons += hsConsumed;
	if (!hs) return NULL;

	//Read the content.
	int expectedLength = 0;
	if (hs->has("Content-Length")) {
		expectedLength = atoi(hs->get("Content-Length").c_str());
		if (expectedLength > str.size() - cons) {
			return NULL;
		}
	}

	//Create the request object.
	Request *req = new Request;
	req->type = type;
	req->path = path;
	req->headers = *hs;
	req->content = str.substr(cons, expectedLength);

	cons += expectedLength;
	if (consumed) *consumed = cons;

	return req;
}
Пример #3
0
/*
 * Handle a E1.33 Status PDU.
 */
bool E133StatusInflator::HandlePDUData(uint32_t vector,
                                       const HeaderSet &headers,
                                       const uint8_t *data,
                                       unsigned int pdu_len) {
  unsigned int size = std::min(
      pdu_len,
      static_cast<unsigned int>(ola::e133::MAX_E133_STATUS_STRING_SIZE));
  string description(reinterpret_cast<const char*>(&data[0]), size);

  m_handler->Run(&headers.GetTransportHeader(),
                 &headers.GetE133Header(),
                 static_cast<uint16_t>(vector),
                 description);
  return true;
}
Пример #4
0
/*
 * Handle a DMP PDU for E1.33.
 */
bool RDMInflator::HandlePDUData(uint32_t vector,
                                const HeaderSet &headers,
                                const uint8_t *data,
                                unsigned int pdu_len) {
  if (vector != VECTOR_RDMNET_DATA) {
    OLA_INFO << "Not a RDM message, vector was " << vector;
    return true;
  }

  string rdm_message(reinterpret_cast<const char*>(&data[0]), pdu_len);

  E133Header e133_header = headers.GetE133Header();

  if (m_rdm_handler.get()) {
    m_rdm_handler->Run(&headers.GetTransportHeader(), &e133_header,
                       rdm_message);
  } else {
    OLA_WARN << "No RDM handler defined!";
  }
  return true;
}
Пример #5
0
/*
 * Check that the header set works
 */
void HeaderSetTest::testHeaderSet() {
  HeaderSet headers;
  RootHeader root_header;
  E131Header e131_header("e131", 1, 2, 6001);
  E133Header e133_header("foo", 1, 2050);
  DMPHeader dmp_header(false, false, NON_RANGE, ONE_BYTES);

  // test the root header component
  CID cid = CID::Generate();
  root_header.SetCid(cid);
  headers.SetRootHeader(root_header);
  OLA_ASSERT(root_header == headers.GetRootHeader());

  // test the E1.31 header component
  headers.SetE131Header(e131_header);
  OLA_ASSERT(e131_header == headers.GetE131Header());

  // test the E1.33 header component
  headers.SetE133Header(e133_header);
  OLA_ASSERT(e133_header == headers.GetE133Header());

  // test the DMP headers component
  headers.SetDMPHeader(dmp_header);
  OLA_ASSERT(dmp_header == headers.GetDMPHeader());

  // test assign
  HeaderSet headers2 = headers;
  OLA_ASSERT(root_header == headers2.GetRootHeader());
  OLA_ASSERT(e131_header == headers2.GetE131Header());
  OLA_ASSERT(e133_header == headers2.GetE133Header());
  OLA_ASSERT(dmp_header == headers2.GetDMPHeader());
  OLA_ASSERT(headers2 == headers);

  // test copy
  HeaderSet headers3(headers);
  OLA_ASSERT(root_header == headers3.GetRootHeader());
  OLA_ASSERT(e131_header == headers3.GetE131Header());
  OLA_ASSERT(e133_header == headers3.GetE133Header());
  OLA_ASSERT(dmp_header == headers3.GetDMPHeader());
  OLA_ASSERT(headers3 == headers);
}
Пример #6
0
/*
 * Verify a PDU is what we expected
 */
bool MockDMPInflator::HandlePDUData(uint32_t vector,
                                    HeaderSet &headers,
                                    const uint8_t *data,
                                    unsigned int pdu_len) {
  DMPHeader header = headers.GetDMPHeader();
  CPPUNIT_ASSERT_EQUAL(expected_vector, vector);
  CPPUNIT_ASSERT_EQUAL(expected_virtual, header.IsVirtual());
  CPPUNIT_ASSERT_EQUAL(expected_relative, header.IsRelative());
  CPPUNIT_ASSERT(expected_type == header.Type());
  CPPUNIT_ASSERT(expected_size == header.Size());

  if (vector == DMP_GET_PROPERTY_VECTOR ||
      vector == DMP_SET_PROPERTY_VECTOR) {
    unsigned int length = pdu_len;
    const BaseDMPAddress *addr = DecodeAddress(header.Size(), header.Type(),
                                               data, length);
    CPPUNIT_ASSERT(addr);
    CPPUNIT_ASSERT_EQUAL(expected_start, addr->Start());
    CPPUNIT_ASSERT_EQUAL(expected_increment, addr->Increment());
    CPPUNIT_ASSERT_EQUAL(expected_number, addr->Number());
    delete addr;
  }
  return true;
}
Пример #7
0
/*
 * Handle a DMP PDU for E1.31.
 */
bool DMPE131Inflator::HandlePDUData(uint32_t vector,
                                    const HeaderSet &headers,
                                    const uint8_t *data,
                                    unsigned int pdu_len) {
  if (vector != ola::acn::DMP_SET_PROPERTY_VECTOR) {
    OLA_INFO << "not a set property msg: " << vector;
    return true;
  }

  E131Header e131_header = headers.GetE131Header();
  UniverseHandlers::iterator universe_iter =
      m_handlers.find(e131_header.Universe());

  if (e131_header.PreviewData() && m_ignore_preview) {
    OLA_DEBUG << "Ignoring preview data";
    return true;
  }

  if (universe_iter == m_handlers.end())
    return true;

  DMPHeader dmp_header = headers.GetDMPHeader();

  if (!dmp_header.IsVirtual() || dmp_header.IsRelative() ||
      dmp_header.Size() != TWO_BYTES ||
      dmp_header.Type() != RANGE_EQUAL) {
    OLA_INFO << "malformed E1.31 dmp header " << dmp_header.Header();
    return true;
  }

  if (e131_header.Priority() > MAX_PRIORITY) {
    OLA_INFO << "Priority " << static_cast<int>(e131_header.Priority()) <<
      " is greater than the max priority (" << static_cast<int>(MAX_PRIORITY) <<
      "), ignoring data";
    return true;
  }

  unsigned int available_length = pdu_len;
  std::auto_ptr<const BaseDMPAddress> address(
      DecodeAddress(dmp_header.Size(),
                    dmp_header.Type(),
                    data,
                    &available_length));

  if (!address.get()) {
    OLA_INFO << "DMP address parsing failed, the length is probably too small";
    return true;
  }

  if (address->Increment() != 1) {
    OLA_INFO << "E1.31 DMP packet with increment " << address->Increment()
      << ", disarding";
    return true;
  }

  unsigned int length_remaining = pdu_len - available_length;
  int start_code = -1;
  if (e131_header.UsingRev2())
    start_code = static_cast<int>(address->Start());
  else if (length_remaining && address->Number())
    start_code = *(data + available_length);

  // The only time we want to continue processing a non-0 start code is if it
  // contains a Terminate message.
  if (start_code && !e131_header.StreamTerminated()) {
    OLA_INFO << "Skipping packet with non-0 start code: " << start_code;
    return true;
  }

  DmxBuffer *target_buffer;
  if (!TrackSourceIfRequired(&universe_iter->second, headers,
                             &target_buffer)) {
    // no need to continue processing
    return true;
  }

  // Reaching here means that we actually have new data and we should merge.
  if (target_buffer && start_code == 0) {
    unsigned int channels = std::min(length_remaining, address->Number());
    if (e131_header.UsingRev2())
      target_buffer->Set(data + available_length, channels);
    else
     target_buffer->Set(data + available_length + 1, channels - 1);
  }

  if (universe_iter->second.priority)
    *universe_iter->second.priority = universe_iter->second.active_priority;

  // merge the sources
  switch (universe_iter->second.sources.size()) {
    case 0:
      universe_iter->second.buffer->Reset();
      break;
    case 1:
      universe_iter->second.buffer->Set(
          universe_iter->second.sources[0].buffer);
      universe_iter->second.closure->Run();
      break;
    default:
      // HTP Merge
      universe_iter->second.buffer->Reset();
      std::vector<dmx_source>::const_iterator source_iter =
        universe_iter->second.sources.begin();
      for (; source_iter != universe_iter->second.sources.end(); ++source_iter)
        universe_iter->second.buffer->HTPMerge(source_iter->buffer);
      universe_iter->second.closure->Run();
  }
  return true;
}
Пример #8
0
/*
 * Check if this source is operating at the highest priority for this universe.
 * This takes care of tracking all sources for a universe at the active
 * priority.
 * @param universe_data the universe_handler struct for this universe,
 * @param HeaderSet the set of headers in this packet
 * @param buffer, if set to a non-NULL pointer, the caller should copy the data
 * in the buffer.
 * @returns true if we should remerge the data, false otherwise.
 */
bool DMPE131Inflator::TrackSourceIfRequired(
    universe_handler *universe_data,
    const HeaderSet &headers,
    DmxBuffer **buffer) {

  *buffer = NULL;  // default the buffer to NULL
  ola::TimeStamp now;
  m_clock.CurrentTime(&now);
  const E131Header &e131_header = headers.GetE131Header();
  uint8_t priority = e131_header.Priority();
  vector<dmx_source> &sources = universe_data->sources;
  vector<dmx_source>::iterator iter = sources.begin();

  while (iter != sources.end()) {
    if (iter->cid != headers.GetRootHeader().GetCid()) {
      TimeStamp expiry_time = iter->last_heard_from + EXPIRY_INTERVAL;
      if (now > expiry_time) {
        OLA_INFO << "source " << iter->cid.ToString() << " has expired";
        iter = sources.erase(iter);
        continue;
      }
    }
    iter++;
  }

  if (sources.empty())
    universe_data->active_priority = 0;

  for (iter = sources.begin(); iter != sources.end(); ++iter) {
    if (iter->cid == headers.GetRootHeader().GetCid())
      break;
  }

  if (iter == sources.end()) {
    // This is an untracked source
    if (e131_header.StreamTerminated() ||
        priority < universe_data->active_priority)
      return false;

    if (priority > universe_data->active_priority) {
      OLA_INFO << "Raising priority for universe " <<
        e131_header.Universe() << " from " <<
        static_cast<int>(universe_data->active_priority) << " to " <<
        static_cast<int>(priority);
      sources.clear();
      universe_data->active_priority = priority;
    }

    if (sources.size() == MAX_MERGE_SOURCES) {
      // TODO(simon): flag this in the export map
      OLA_WARN << "Max merge sources reached for universe " <<
        e131_header.Universe() << ", " <<
        headers.GetRootHeader().GetCid().ToString() << " won't be tracked";
        return false;
    } else {
      OLA_INFO << "Added new E1.31 source: " <<
        headers.GetRootHeader().GetCid().ToString();
      dmx_source new_source;
      new_source.cid = headers.GetRootHeader().GetCid();
      new_source.sequence = e131_header.Sequence();
      new_source.last_heard_from = now;
      iter = sources.insert(sources.end(), new_source);
      *buffer = &iter->buffer;
      return true;
    }

  } else {
    // We already know about this one, check the seq #
    int8_t seq_diff = static_cast<int8_t>(e131_header.Sequence() -
                                          iter->sequence);
    if (seq_diff <= 0 && seq_diff > SEQUENCE_DIFF_THRESHOLD) {
      OLA_INFO << "Old packet received, ignoring, this # " <<
        static_cast<int>(e131_header.Sequence()) << ", last " <<
        static_cast<int>(iter->sequence);
      return false;
    }
    iter->sequence = e131_header.Sequence();

    if (e131_header.StreamTerminated()) {
      OLA_INFO << "CID " << headers.GetRootHeader().GetCid().ToString() <<
        " sent a termination for universe " << e131_header.Universe();
      sources.erase(iter);
      if (sources.empty())
        universe_data->active_priority = 0;
      // We need to trigger a merge here else the buffer will be stale, we keep
      // the buffer as NULL though so we don't use the data.
      return true;
    }

    iter->last_heard_from = now;
    if (priority < universe_data->active_priority) {
      if (sources.size() == 1) {
        universe_data->active_priority = priority;
      } else {
        sources.erase(iter);
        return true;
      }
    } else if (priority > universe_data->active_priority) {
      // new active priority
      universe_data->active_priority = priority;
      if (sources.size() != 1) {
        // clear all sources other than this one
        dmx_source this_source = *iter;
        sources.clear();
        iter = sources.insert(sources.end(), this_source);
      }
    }
    *buffer = &iter->buffer;
    return true;
  }
}
Пример #9
0
/**
 * This runs the on_data callback if we have one
 */
bool RootInflator::PostHeader(uint32_t, const HeaderSet &headers) {
  if (m_on_data.get())
    m_on_data->Run(headers.GetTransportHeader());
  return true;
}