aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/higet/higet.cc74
-rw-r--r--apps/http-proxy/src/ATSConnector.cc92
-rw-r--r--apps/http-proxy/src/ATSConnector.h13
-rw-r--r--apps/http-proxy/src/HTTP1.xMessageFastParser.cc19
-rw-r--r--apps/http-proxy/src/HTTP1.xMessageFastParser.h8
-rw-r--r--docs/README.md2
-rw-r--r--docs/source/apps.md133
-rw-r--r--docs/source/index.rst10
-rw-r--r--docs/source/interface.md42
-rw-r--r--docs/source/started.md25
-rw-r--r--docs/source/telemetry.md10
-rw-r--r--libtransport/src/hicn/transport/http/response.cc46
-rw-r--r--libtransport/src/hicn/transport/http/response.h6
13 files changed, 333 insertions, 147 deletions
diff --git a/apps/higet/higet.cc b/apps/higet/higet.cc
index df34d5c14..fcb0cc540 100644
--- a/apps/higet/higet.cc
+++ b/apps/higet/higet.cc
@@ -17,6 +17,9 @@
#include <fstream>
#include <map>
+#include <experimental/algorithm>
+#include <experimental/functional>
+
#ifndef ASIO_STANDALONE
#define ASIO_STANDALONE
#include <asio.hpp>
@@ -41,12 +44,16 @@ typedef struct {
class ReadBytesCallbackImplementation
: public transport::http::HTTPClientConnection::ReadBytesCallback {
+ static std::string chunk_separator;
+
public:
ReadBytesCallbackImplementation(std::string file_name, long yet_downloaded)
: file_name_(file_name),
temp_file_name_(file_name_ + ".temp"),
yet_downloaded_(yet_downloaded),
byte_downloaded_(yet_downloaded),
+ chunked_(false),
+ chunk_size_(0),
work_(std::make_unique<asio::io_service::work>(io_service_)),
thread_(
std::make_unique<std::thread>([this]() { io_service_.run(); })) {
@@ -71,21 +78,72 @@ class ReadBytesCallbackImplementation
auto buffer_ptr = buffer.release();
io_service_.post([this, buffer_ptr]() {
auto buffer = std::unique_ptr<utils::MemBuf>(buffer_ptr);
+ std::unique_ptr<utils::MemBuf> payload;
if (!first_chunk_read_) {
transport::http::HTTPResponse http_response(std::move(buffer));
- auto payload = http_response.getPayload();
+ payload = http_response.getPayload();
auto header = http_response.getHeaders();
+ content_size_ = yet_downloaded_;
std::map<std::string, std::string>::iterator it =
header.find("Content-Length");
if (it != header.end()) {
- content_size_ = yet_downloaded_ + std::stol(it->second);
+ content_size_ += std::stol(it->second);
+ } else {
+ it = header.find("Transfer-Encoding");
+ if (it != header.end() && it->second.compare("chunked") == 0) {
+ chunked_ = true;
+ }
}
- out_->write((char *)payload->data(), payload->length());
first_chunk_read_ = true;
- byte_downloaded_ += payload->length();
} else {
- out_->write((char *)buffer->data(), buffer->length());
- byte_downloaded_ += buffer->length();
+ payload = std::move(buffer);
+ }
+
+ if (chunked_) {
+ if (chunk_size_ > 0) {
+ out_->write((char *)payload->data(), chunk_size_);
+ payload->trimStart(chunk_size_);
+
+ if (payload->length() >= chunk_separator.size()) {
+ payload->trimStart(chunk_separator.size());
+ }
+ }
+
+ while (payload->length() > 0) {
+ // read next chunk size
+ const char *begin = (const char *)payload->data();
+ const char *end = (const char *)payload->tail();
+
+ using std::experimental::make_boyer_moore_searcher;
+ auto it = std::experimental::search(
+ begin, end,
+ make_boyer_moore_searcher(chunk_separator.begin(),
+ chunk_separator.end()));
+ if (it != end) {
+ chunk_size_ = std::stoul(begin, 0, 16);
+ content_size_ += chunk_size_;
+ payload->trimStart(it + chunk_separator.size() - begin);
+
+ std::size_t to_write;
+ if (payload->length() >= chunk_size_) {
+ to_write = chunk_size_;
+ } else {
+ to_write = payload->length();
+ chunk_size_ -= payload->length();
+ }
+
+ out_->write((char *)payload->data(), to_write);
+ byte_downloaded_ += to_write;
+ payload->trimStart(to_write);
+
+ if (payload->length() >= chunk_separator.size()) {
+ payload->trimStart(chunk_separator.size());
+ }
+ }
+ }
+ } else {
+ out_->write((char *)payload->data(), payload->length());
+ byte_downloaded_ += payload->length();
}
if (file_name_ != "-") {
@@ -174,11 +232,15 @@ class ReadBytesCallbackImplementation
long content_size_;
bool first_chunk_read_ = false;
long byte_downloaded_ = 0;
+ bool chunked_;
+ std::size_t chunk_size_;
asio::io_service io_service_;
std::unique_ptr<asio::io_service::work> work_;
std::unique_ptr<std::thread> thread_;
};
+std::string ReadBytesCallbackImplementation::chunk_separator = "\r\n";
+
long checkFileStatus(std::string file_name) {
struct stat stat_buf;
std::string temp_file_name_ = file_name + ".temp";
diff --git a/apps/http-proxy/src/ATSConnector.cc b/apps/http-proxy/src/ATSConnector.cc
index f656a68cb..a9b889941 100644
--- a/apps/http-proxy/src/ATSConnector.cc
+++ b/apps/http-proxy/src/ATSConnector.cc
@@ -33,6 +33,9 @@ ATSConnector::ATSConnector(asio::io_service &io_service,
timer_(io_service),
is_reconnection_(false),
data_available_(false),
+ content_length_(0),
+ is_last_chunk_(false),
+ chunked_(false),
receive_callback_(receive_callback),
on_reconnect_callback_(on_reconnect_callback) {
input_buffer_.prepare(buffer_size + 2048);
@@ -96,23 +99,26 @@ void ATSConnector::doWrite() {
});
} // namespace transport
-void ATSConnector::handleRead(std::error_code ec, std::size_t length,
- std::size_t size) {
+void ATSConnector::handleRead(std::error_code ec, std::size_t length) {
if (TRANSPORT_EXPECT_TRUE(!ec)) {
- size -= length;
+ content_length_ -= length;
const uint8_t *buffer =
asio::buffer_cast<const uint8_t *>(input_buffer_.data());
- receive_callback_(buffer, input_buffer_.size(), !size, false);
+ receive_callback_(buffer, input_buffer_.size(), !content_length_, false);
input_buffer_.consume(input_buffer_.size());
- if (!size) {
- doReadHeader();
+ if (!content_length_) {
+ if (!chunked_ || is_last_chunk_) {
+ doReadHeader();
+ } else {
+ doReadChunkedHeader();
+ }
} else {
- auto to_read = size >= buffer_size ? buffer_size : size;
- asio::async_read(
- socket_, input_buffer_, asio::transfer_exactly(to_read),
- std::bind(&ATSConnector::handleRead, this, std::placeholders::_1,
- std::placeholders::_2, size));
+ auto to_read =
+ content_length_ >= buffer_size ? buffer_size : content_length_;
+ asio::async_read(socket_, input_buffer_, asio::transfer_exactly(to_read),
+ std::bind(&ATSConnector::handleRead, this,
+ std::placeholders::_1, std::placeholders::_2));
}
} else if (ec == asio::error::eof) {
input_buffer_.consume(input_buffer_.size());
@@ -129,20 +135,47 @@ void ATSConnector::doReadBody(std::size_t body_size,
? (buffer_size - input_buffer_.size())
: bytes_to_read;
+ is_last_chunk_ = chunked_ && body_size == 5;
+
if (to_read > 0) {
- asio::async_read(
- socket_, input_buffer_, asio::transfer_exactly(to_read),
- std::bind(&ATSConnector::handleRead, this, std::placeholders::_1,
- std::placeholders::_2, bytes_to_read));
+ content_length_ = bytes_to_read;
+ asio::async_read(socket_, input_buffer_, asio::transfer_exactly(to_read),
+ std::bind(&ATSConnector::handleRead, this,
+ std::placeholders::_1, std::placeholders::_2));
} else {
const uint8_t *buffer =
asio::buffer_cast<const uint8_t *>(input_buffer_.data());
- receive_callback_(buffer, body_size, !to_read, false);
+ receive_callback_(buffer, body_size, chunked_ ? is_last_chunk_ : !to_read,
+ false);
input_buffer_.consume(body_size);
- doReadHeader();
+
+ if (!chunked_ || is_last_chunk_) {
+ doReadHeader();
+ } else {
+ doReadChunkedHeader();
+ }
}
}
+void ATSConnector::doReadChunkedHeader() {
+ asio::async_read_until(
+ socket_, input_buffer_, "\r\n",
+ [this](std::error_code ec, std::size_t length) {
+ if (TRANSPORT_EXPECT_TRUE(!ec)) {
+ const uint8_t *buffer =
+ asio::buffer_cast<const uint8_t *>(input_buffer_.data());
+ std::size_t chunk_size =
+ std::stoul(reinterpret_cast<const char *>(buffer), 0, 16) + 2 +
+ length;
+ auto additional_bytes = input_buffer_.size();
+ doReadBody(chunk_size, additional_bytes);
+ } else {
+ input_buffer_.consume(input_buffer_.size());
+ tryReconnection();
+ }
+ });
+}
+
void ATSConnector::doReadHeader() {
asio::async_read_until(
socket_, input_buffer_, "\r\n\r\n",
@@ -150,14 +183,31 @@ void ATSConnector::doReadHeader() {
if (TRANSPORT_EXPECT_TRUE(!ec)) {
const uint8_t *buffer =
asio::buffer_cast<const uint8_t *>(input_buffer_.data());
- std::size_t size = HTTPMessageFastParser::hasBody(buffer, length);
+ auto headers = HTTPMessageFastParser::getHeaders(buffer, length);
- auto additional_bytes = input_buffer_.size() - length;
+ // Try to get content length, if available
+ auto it = headers.find(HTTPMessageFastParser::content_length);
+ std::size_t size = 0;
+ if (it != headers.end()) {
+ size = std::stoull(it->second);
+ chunked_ = false;
+ } else {
+ it = headers.find(HTTPMessageFastParser::transfer_encoding);
+ if (it != headers.end() &&
+ it->second.compare(HTTPMessageFastParser::chunked) == 0) {
+ chunked_ = true;
+ }
+ }
- receive_callback_(buffer, length, !size, true);
+ receive_callback_(buffer, length, !size && !chunked_, true);
+ auto additional_bytes = input_buffer_.size() - length;
input_buffer_.consume(length);
- doReadBody(size, additional_bytes);
+ if (!chunked_) {
+ doReadBody(size, additional_bytes);
+ } else {
+ doReadChunkedHeader();
+ }
} else {
input_buffer_.consume(input_buffer_.size());
tryReconnection();
diff --git a/apps/http-proxy/src/ATSConnector.h b/apps/http-proxy/src/ATSConnector.h
index dbec30353..8d91b7b7b 100644
--- a/apps/http-proxy/src/ATSConnector.h
+++ b/apps/http-proxy/src/ATSConnector.h
@@ -65,12 +65,17 @@ class ATSConnector {
void doReadBody(std::size_t body_size, std::size_t additional_bytes);
+ // void handleReadChunked(std::error_code ec, std::size_t length,
+ // std::size_t size);
+
+ void doReadChunkedHeader();
+
void doWrite();
bool checkConnected();
private:
- void handleRead(std::error_code ec, std::size_t length, std::size_t bytes);
+ void handleRead(std::error_code ec, std::size_t length);
void tryReconnection();
void startConnectionTimer();
void handleDeadline(const std::error_code &ec);
@@ -88,6 +93,12 @@ class ATSConnector {
bool is_reconnection_;
bool data_available_;
+ std::size_t content_length_;
+
+ // Chunked encoding
+ bool is_last_chunk_;
+ bool chunked_;
+
ContentReceivedCallback receive_callback_;
OnReconnect on_reconnect_callback_;
diff --git a/apps/http-proxy/src/HTTP1.xMessageFastParser.cc b/apps/http-proxy/src/HTTP1.xMessageFastParser.cc
index a03871649..729eb3aeb 100644
--- a/apps/http-proxy/src/HTTP1.xMessageFastParser.cc
+++ b/apps/http-proxy/src/HTTP1.xMessageFastParser.cc
@@ -15,17 +15,36 @@
#include "HTTP1.xMessageFastParser.h"
+#include <hicn/transport/http/response.h>
+
#include <experimental/algorithm>
#include <experimental/functional>
#include <iostream>
std::string HTTPMessageFastParser::numbers = "0123456789";
std::string HTTPMessageFastParser::content_length = "Content-Length";
+std::string HTTPMessageFastParser::transfer_encoding = "Transfer-Encoding";
+std::string HTTPMessageFastParser::chunked = "chunked";
std::string HTTPMessageFastParser::cache_control = "Cache-Control";
std::string HTTPMessageFastParser::mpd = "mpd";
std::string HTTPMessageFastParser::connection = "Connection";
std::string HTTPMessageFastParser::separator = "\r\n\r\n";
+HTTPHeaders HTTPMessageFastParser::getHeaders(const uint8_t *headers,
+ std::size_t length) {
+ HTTPHeaders ret;
+ std::string http_version;
+ std::string status_code;
+ std::string status_string;
+
+ if (transport::http::HTTPResponse::parseHeaders(headers, length, ret, http_version,
+ status_code, status_string)) {
+ return ret;
+ }
+
+ throw std::runtime_error("Error parsing response headers.");
+}
+
std::size_t HTTPMessageFastParser::hasBody(const uint8_t *headers,
std::size_t length) {
const char *buffer = reinterpret_cast<const char *>(headers);
diff --git a/apps/http-proxy/src/HTTP1.xMessageFastParser.h b/apps/http-proxy/src/HTTP1.xMessageFastParser.h
index 10a70c3e9..79dbce19d 100644
--- a/apps/http-proxy/src/HTTP1.xMessageFastParser.h
+++ b/apps/http-proxy/src/HTTP1.xMessageFastParser.h
@@ -18,15 +18,21 @@
#include <algorithm>
#include <string>
+#include <hicn/transport/http/message.h>
+
+using transport::http::HTTPHeaders;
+
class HTTPMessageFastParser {
public:
+ static HTTPHeaders getHeaders(const uint8_t* headers, std::size_t length);
static std::size_t hasBody(const uint8_t* headers, std::size_t length);
static bool isMpdRequest(const uint8_t* headers, std::size_t length);
static uint32_t parseCacheControl(const uint8_t* headers, std::size_t length);
- private:
static std::string numbers;
static std::string content_length;
+ static std::string transfer_encoding;
+ static std::string chunked;
static std::string cache_control;
static std::string connection;
static std::string mpd;
diff --git a/docs/README.md b/docs/README.md
index d7a6c6cc8..be7f4e6df 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -26,7 +26,7 @@ $ source env/bin/activate
$ pip install -r docs/etc/requirements.txt
$ cd docs
-Which installs all the required applications into it's own, isolated,
+Which installs all the required applications into its own, isolated,
virtual environment, so as to not interfere with other builds that may
use different versions of software.
diff --git a/docs/source/apps.md b/docs/source/apps.md
index 1c44a8ca9..0a1d6eb20 100644
--- a/docs/source/apps.md
+++ b/docs/source/apps.md
@@ -3,7 +3,7 @@
The open source distribution provides a few application examples:
one MPEG-DASH video player, and an HTTP reverse proxy a command line
HTTP GET client.
-hICN sockets have been succesfully used to serve HTTP, RTP and
+hICN sockets have been successfully used to serve HTTP, RTP and
RSockets application protocols.
## Dependencies
@@ -94,7 +94,7 @@ For running the hicn-plugin at the server there are two main alternatives:
- Use a docker container
- Run the hicn-plugin directly in a VM or Bare Metal Server
-### Docker
+### Docker VPP hICN proxy
Install docker in the server VM:
@@ -102,86 +102,77 @@ Install docker in the server VM:
server$ curl get.docker.com | bash
```
-Run the hicn-http-proxy container. Here we use a public server "example.com" as origin:
+Run the hicn-http-proxy container. Here we use a public server at "localhost" as origin and
+HTTP traffic is server with an IPv6 name prefix b001.
```bash
-server$ docker run -e ORIGIN_ADDRESS=example.com \
- -e ORIGIN_PORT=80 \
- -e CACHE_SIZE=10000 \
- -e HICN_MTU=1200 \
- -e FIRST_IPV6_WORD=c001 \
- -e HICN_PREFIX=http://webserver \
- --privileged \
- --name vhttpproxy \
- -d icnteam/vhttpproxy
+#!/bin/bash
+
+#Http proxy options
+ORIGIN_ADDRESS=${ORIGIN_ADDRESS:-"localhost"}
+ORIGIN_PORT=${ORIGIN_PORT:-"80"}
+CACHE_SIZE=${CACHE_SIZE:-"10000"}
+DEFAULT_CONTENT_LIFETIME=${DEFAULT_CONTENT_LIFETIME:-"7200"}
+HICN_MTU=${HICN_MTU:-"1300"}
+FIRST_IPV6_WORD=${FIRST_IPV6_WORD:-"b001"}
+USE_MANIFEST=${USE_MANIFEST:-"true"}
+HICN_PREFIX=${HICN_PREFIX:-"http://webserver"}
+
+# UDP Punting
+HICN_LISTENER_PORT=${HICN_LISTENER_PORT:-33567}
+TAP_ADDRESS_VPP=192.168.0.2
+TAP_ADDRESS_KER=192.168.0.1
+TAP_ADDRESS_NET=192.168.0.0/24
+TAP_ID=0
+TAP_NAME=tap${TAP_ID}
+
+vppctl create tap id ${TAP_ID}
+vppctl set int state ${TAP_NAME} up
+vppctl set interface ip address tap0 ${TAP_ADDRESS_VPP}/24
+ip addr add ${TAP_ADDRESS_KER}/24 brd + dev ${TAP_NAME}
+
+# Redirect the udp traffic on port 33567 (The one used for hicn) to VPP
+iptables -t nat -A PREROUTING -p udp --dport ${HICN_LISTENER_PORT} -j DNAT \
+ --to-destination ${TAP_ADDRESS_VPP}:${HICN_LISTENER_PORT}
+# Masquerade all the traffic coming from VPP
+iptables -t nat -A POSTROUTING -j MASQUERADE --src ${TAP_ADDRESS_NET} ! \
+ --dst ${TAP_ADDRESS_NET} -o eth0
+# Add default route to vpp
+vppctl ip route add 0.0.0.0/0 via ${TAP_ADDRESS_KER} ${TAP_NAME}
+# Set UDP punting
+vppctl hicn punting add prefix ${FIRST_IPV6_WORD}::/16 intfc ${TAP_NAME}\
+ type udp4 dst_port ${HICN_LISTENER_PORT}
+
+# Run the http proxy
+PARAMS="-a ${ORIGIN_ADDRESS} "
+PARAMS+="-p ${ORIGIN_PORT} "
+PARAMS+="-c ${CACHE_SIZE} "
+PARAMS+="-m ${HICN_MTU} "
+PARAMS+="-P ${FIRST_IPV6_WORD} "
+PARAMS+="-l ${DEFAULT_CONTENT_LIFETIME} "
+if [ "${USE_MANIFEST}" = "true" ]; then
+ PARAMS+="-M "
+fi
+
+hicn-http-proxy ${PARAMS} ${HICN_PREFIX}
```
-Create a hicn private network:
+Docker images of the example above are available at
+<https://hub.docker.com/r/icnteam/vhttpproxy>.
+Images can be pulled using the following tags.
-```bash
-server$ GATEWAY=192.168.0.254
-server$ docker network create --subnet 192.168.0.0/24 --gateway ${GATEWAY} hicn-network
-```
-
-Connect the proxy container to the hicn network:
-
-```bash
-server$ docker network connect hicn-network vhttpproxy
+```shell
+docker pull icnteam/vhttpproxy:amd64
+docker pull icnteam/vhttpproxy:arm64
```
-Connect the hicn network to the vpp forwarder:
-
-```bash
-server$ IP_ADDRESS=$(docker inspect -f "{{with index .NetworkSettings.Networks \"hicn-network\"}}{{.IPAddress}}{{end}}" vhttpproxy)
-server$ INTERFACE=$(docker exec -it vhttpproxy ifconfig | grep -B 1 ${IP_ADDRESS} | awk 'NR==1 {gsub(":","",$1); print $1}')
-server$ docker exec -it vhttpproxy ip addr flush dev ${INTERFACE}
-server$ docker exec -it vhttpproxy ethtool -K ${INTERFACE} tx off rx off ufo off gso off gro off tso off
-server$ docker exec -it vhttpproxy vppctl create host-interface name ${INTERFACE}
-server$ docker exec -it vhttpproxy vppctl set interface state host-${INTERFACE} up
-server$ docker exec -it vhttpproxy vppctl set interface ip address host-${INTERFACE} ${IP_ADDRESS}/24
-server$ docker exec -it vhttpproxy vppctl ip route add 10.0.0.0/24 via ${GATEWAY} host-eth1
-```
-
-Set the punting:
-
-```bash
-server$ PORT=12345
-server$ docker exec -it vhttpproxy vppctl hicn punting add prefix c001::/16 intfc host-${INTERFACE} type udp4 src_port ${PORT} dst_port ${PORT}
-```
-
-Docker containers are cool, but sometimes they do not allow you to do simple operations like expose ports while the container is already running. But we have a workaround for this :)
-
-```bash
-server$ sudo iptables -t nat -A DOCKER -p udp --dport ${PORT} -j DNAT --to-destination ${IP_ADDRESS}:${PORT}
-server$ sudo iptables -t nat -A POSTROUTING -j MASQUERADE -p udp --source ${IP_ADDRESS} --destination ${IP_ADDRESS} --dport ${PORT}
-server$ sudo iptables -A DOCKER -j ACCEPT -p udp --destination ${IP_ADDRESS} --dport ${PORT}
-```
-
-In the client, install the hicn stack:
-
-```bash
-client$ sudo apt-get install -y hicn-light hicn-apps
-```
-
-Create a configuration file for the hicn-light forwarder. Here we are configuring UDP faces:
-
-```bash
-client$ mkdir -p ${HOME}/etc
-client$ LOCAL_IP="10.0.0.2" # Put here the actual IPv4 of the local interface
-client$ LOCAL_PORT="12345"
-client$ REMOTE_IP="10.0.0.1" # Put here the actual IPv4 of the remote interface
-client$ REMOTE_PORT="12345"
-client$ cat << EOF > ${HOME}/etc/hicn-light.conf
-add listener udp list0 ${LOCAL_IP} ${LOCAL_PORT}
-add connection udp conn0 ${REMOTE_IP} ${REMOTE_PORT} ${LOCAL_IP} ${LOCAL_PORT}
-add route conn0 c001::/16 1
-EOF
-```
+#### Client side
Run the hicn-light forwarder
```bash
-client$ sudo /usr/bin/hicn-light-daemon --daemon --capacity 1000 --log-file ${HOME}/hicn-light.log --config ${HOME}/etc/hicn-light.conf
+client$ sudo /usr/bin/hicn-light-daemon --daemon --capacity 1000 --log-file \
+ ${HOME}/hicn-light.log --config ${HOME}/etc/hicn-light.conf
```
Run the http client [higet](#higet) and print the http response on stdout:
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 17aeb3a1c..99ea39afa 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -1,6 +1,16 @@
Hybrid Information-Centric Networking
=====================================
+Hybrid Information-Centric Networking (hICN) is a network architecture that makes
+use of IPv6 or IPv4 to realize location-independent communications. It is largely
+inspired by the pioneer work of Van Jacobson on Content-Centric Networking, that was
+a clean-slate architecture whereas hICN is based on the Internet protocol and easy to
+deploy in today networks and applications. hICN brings many-to-many communications,
+multi-homing, multi-path, multi-source, group communications to the Internet protocol
+without replicated unicast. The project implements novel transport protocols, with a socket API,
+for real-time and capacity seeking applications. A scalable stack is available based
+on VPP and a client stack is provided to support any mobile and desktop operating system.
+
.. toctree::
started
diff --git a/docs/source/interface.md b/docs/source/interface.md
index 13f1007a3..9e6b6f383 100644
--- a/docs/source/interface.md
+++ b/docs/source/interface.md
@@ -38,7 +38,7 @@ interfaces:
protocol to discover a remote hICN forwarder that might be needed to
establish overlay faces.
-- network\_framework [MacOS, iOS]
+- network_framework [MacOS, iOS]
This component uses the recommended Network framework on Apple devices,
which provided all required information to query faces in a unified API:
@@ -82,11 +82,11 @@ The face manager source code includes a template that can be used as a skeleton
to develop new faces. It can be found in `src/interface/dummy/dummy.{h,c}`. Both
include guard and specific interface functions are prefixed by a (short)
identifier which acts as a namespace for interface specific code (in our case
-the string 'dummy\_').
+the string 'dummy_').
-Registration and instanciation of the different interfaces is currently done at
+Registration and instantiation of the different interfaces is currently done at
compile time in the file `src/api.c`, and the appropriate hooks to use the dummy
-interface are avaialble in the code between `#if 0/#endif` tags.
+interface are available in the code between `#if 0/#endif` tags.
#### Interface template header; configuration parameters
@@ -96,7 +96,7 @@ the interface, if any.
In the template, these configuration options are empty:
-```C#
+```C
/*
* Configuration data
*/
@@ -124,7 +124,7 @@ interface.
Each interface can hold a pointer to an internal data structure, which is
declared as follows:
-```C#
+```C
/*
* Internal data
*/
@@ -142,7 +142,7 @@ typedef struct {
```
We find here a copy of the configuration settings (which allows the called to
-instanciate the structure on the stack), as well as a file descriptor
+instantiate the structure on the stack), as well as a file descriptor
(assuming most interfaces will react on events on a file descriptor).
The rest of the file consists in the implementation of the interface, in
@@ -150,8 +150,8 @@ particular the different function required by the registration of a new
interface to the system. They are grouped as part of the `interface_ops_t` data
structure declared at the end of the file:
-```C#
-interface\_ops\_t dummy\_ops = {
+```C
+interface_ops_t dummy_ops = {
.type = "dummy",
.initialize = dummy_initialize,
.finalize = dummy_finalize,
@@ -170,14 +170,14 @@ typedef struct {
/** The type given to the interfaces */
char * type;
/* Constructor */
- int (*initialize)(struct interface\_s * interface, void * cfg);
+ int (*initialize)(struct interface_s * interface, void * cfg);
/* Destructor */
int (*finalize)(struct interface_s * interface);
/* Callback upon file descriptor event (iif previously registered) */
int (*callback)(struct interface_s * interface);
/* Callback upon facelet events coming from the face manager */
int (*on_event)(struct interface_s * interface, const struct facelet_s * facelet);
-} interface\_ops\_t;
+} interface_ops_t;
```
Such an interface has to be registered first, then one (or multiple) instance(s)
@@ -196,9 +196,9 @@ if (rc < 0)
goto ERR_REGISTER;
```
-- interface instanciation:
+- interface instantiation:
-```C++
+```C
#include "interfaces/dummy/dummy.h"
/* [...] */
@@ -219,7 +219,7 @@ In the template, the constructor is the most involved as it need to:
- initialize the internal data structure:
-```C#
+```C
dummy_data_t * data = malloc(sizeof(dummy_data_t));
if (!data)
goto ERR_MALLOC;
@@ -228,7 +228,7 @@ In the template, the constructor is the most involved as it need to:
- process configuration parameters, eventually setting some default values:
-```C#
+```C
/* Use default values for unspecified configuration parameters */
if (cfg) {
data->cfg = *(dummy_cfg_t *)cfg;
@@ -246,7 +246,7 @@ event loop for read events. A return value of 0 means the interface does not
require any file descriptor. As usual, a negative return value indicates an
error.
-```C#
+```C
data->fd = 0;
/* ... */
@@ -273,14 +273,14 @@ In order to retrieve the internal data structure, that should in particular
store such a file descriptor, all other function but the constructor can
dereference it from the interface pointer they receive as parameter:
-```C++
-dummy\_data\_t * data = (dummy\_data\_t*)interface->data;
+```C
+dummy_data_t * data = (dummy_data_t*)interface->data;
```
#### Raising and Receiving Events
An interface will receive events in the form of a facelet through the `*_on_event`
-function. It can then use the facelet API we have describe above to read
+function. It can then use the facelet API we have described above to read
information about the face.
As this information is declared const, the interface can either create a new
@@ -290,7 +290,7 @@ clone it.
The facelet event can then be defined and raised to the face maanger for further
processing through the following code:
-```C++
+```C
facelet_set_event(facelet, EVENT_TYPE_CREATE);
interface_raise_event(interface, facelet);
```
@@ -361,5 +361,5 @@ An example illustrating how to connect to the dummy service from `updownsrv` is
provided as the `updown` interface in the facemgr source code.
This interface periodically swaps the status of the LTE interface up and down.
-It is instanciated as part of the facemgr codebase when the code is compiled
+It is instantiated as part of the facemgr codebase when the code is compiled
with the ``-DWITH_EXAMPLE_UPDOWN` cmake option.
diff --git a/docs/source/started.md b/docs/source/started.md
index 168ce1272..3c5181297 100644
--- a/docs/source/started.md
+++ b/docs/source/started.md
@@ -90,13 +90,30 @@ Coming soon.
### Docker
-Several docker images are nightly built with the latest software for Ubuntu 18 LTS (amd64/arm64), and available on docker hub
-at <https://hub.docker.com/u/icnteam>.
+Several docker images are nightly built with the latest software for Ubuntu 18 LTS (amd64/arm64), and available on docker hub at <https://hub.docker.com/u/icnteam>.
+
+The following images are nightly built and maintained.
+
+```shell
+docker pull icnteam/vswitch:amd64
+docker pull icnteam/vswitch:arm64
+
+docker pull icnteam/vserver:amd64
+docker pull icnteam/vserver:arm64
+
+docker pull icnteam/vhttpproxy:amd64
+docker pull icnteam/vhttpproxy:arm64
+```
### Vagrant
-Vagrant boxes for a virtual switch are available at <https://app.vagrantup.com/icnteam/boxes/vswitch>.
-Supported providers are kvm, vmware and virtualbox.
+Vagrant boxes for a virtual switch are available at
+<https://app.vagrantup.com/icnteam>
+
+```shell
+vagrant box add icnteam/vswitch
+```
+Supported providers are libvirt, vmware and virtualbox.
## License
diff --git a/docs/source/telemetry.md b/docs/source/telemetry.md
index 0af3b0e02..868958f2b 100644
--- a/docs/source/telemetry.md
+++ b/docs/source/telemetry.md
@@ -27,9 +27,9 @@ $ make
$ sudo make install
```
-## Using hICN collectd plugins ##
+## Using hICN collectd plugins
-### Platforms ###
+### Platforms
hICN collectd plugins have been tested in:
@@ -40,7 +40,7 @@ hICN collectd plugins have been tested in:
- CentOS 7
-### Dependencies ###
+### Dependencies
Build dependencies:
@@ -51,7 +51,7 @@ Build dependencies:
- vpp-dev
- hicn-plugin-dev
-## Getting started ##
+## Getting started
Collectd needs to be configured in order to use the hICN collectd plugins.
The configuration can be achieved editing the file '/etc/collectd/collectd.conf' and adding the following lines:
@@ -67,7 +67,7 @@ Before running collectd, a vpp forwarder must be started. If the vpp-hicn plugin
Edit the configuration file as the following:
-```
+```html
######################################################################
# Global #
######################################################################
diff --git a/libtransport/src/hicn/transport/http/response.cc b/libtransport/src/hicn/transport/http/response.cc
index a2bc47e6b..ba0acd1ac 100644
--- a/libtransport/src/hicn/transport/http/response.cc
+++ b/libtransport/src/hicn/transport/http/response.cc
@@ -41,16 +41,33 @@ void HTTPResponse::appendResponseChunk(
}
bool HTTPResponse::parseHeaders(std::unique_ptr<utils::MemBuf> &&buffer) {
+ auto ret =
+ HTTPResponse::parseHeaders(buffer->data(), buffer->length(), headers_,
+ http_version_, status_code_, status_string_);
+
+ if (ret) {
+ buffer->trimStart(ret);
+ payload_ = std::move(buffer);
+ return true;
+ }
+
+ return false;
+}
+
+std::size_t HTTPResponse::parseHeaders(const uint8_t *buffer, std::size_t size,
+ HTTPHeaders &headers,
+ std::string &http_version,
+ std::string &status_code,
+ std::string &status_string) {
const char *crlf2 = "\r\n\r\n";
- const char *begin = (const char *)buffer->data();
- const char *end = begin + buffer->length();
+ const char *begin = (const char *)buffer;
+ const char *end = begin + size;
auto it =
std::experimental::search(begin, end,
std::experimental::make_boyer_moore_searcher(
crlf2, crlf2 + strlen(crlf2)));
if (it != end) {
- buffer->trimStart(it + strlen(crlf2) - begin);
std::stringstream ss;
ss.str(std::string(begin, it));
@@ -58,29 +75,28 @@ bool HTTPResponse::parseHeaders(std::unique_ptr<utils::MemBuf> &&buffer) {
getline(ss, line);
std::istringstream line_s(line);
std::string _http_version;
- std::string http_version;
line_s >> _http_version;
std::size_t separator;
if ((separator = _http_version.find('/')) != std::string::npos) {
if (_http_version.substr(0, separator) != "HTTP") {
- return false;
+ return 0;
}
- http_version_ =
+ http_version =
line.substr(separator + 1, _http_version.length() - separator - 1);
} else {
- return false;
+ return 0;
}
- std::string status_code, status_string;
+ std::string _status_string;
- line_s >> status_code_;
- line_s >> status_string;
+ line_s >> status_code;
+ line_s >> _status_string;
auto _it = std::search(line.begin(), line.end(), status_string.begin(),
status_string.end());
- status_string_ = std::string(_it, line.end() - 1);
+ status_string = std::string(_it, line.end() - 1);
std::size_t param_end;
std::size_t value_start;
@@ -92,19 +108,17 @@ bool HTTPResponse::parseHeaders(std::unique_ptr<utils::MemBuf> &&buffer) {
value_start++;
}
if (value_start < line.size()) {
- headers_[line.substr(0, param_end)] =
+ headers[line.substr(0, param_end)] =
line.substr(value_start, line.size() - value_start - 1);
}
}
} else {
- return false;
+ return 0;
}
}
}
- payload_ = std::move(buffer);
-
- return true;
+ return it + strlen(crlf2) - begin;
}
void HTTPResponse::parse(std::unique_ptr<utils::MemBuf> &&response) {
diff --git a/libtransport/src/hicn/transport/http/response.h b/libtransport/src/hicn/transport/http/response.h
index 7ef655059..bab41acb8 100644
--- a/libtransport/src/hicn/transport/http/response.h
+++ b/libtransport/src/hicn/transport/http/response.h
@@ -42,6 +42,12 @@ class HTTPResponse : public HTTPMessage {
bool parseHeaders(std::unique_ptr<utils::MemBuf> &&buffer);
+ static std::size_t parseHeaders(const uint8_t *buffer, std::size_t size,
+ HTTPHeaders &headers,
+ std::string &http_version,
+ std::string &status_code,
+ std::string &status_string);
+
private:
std::string status_code_;
std::string status_string_;