diff options
46 files changed, 2573 insertions, 160 deletions
diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 0f7a5c289..8907dfe5b 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -25,34 +25,36 @@ set(CMAKE_MODULE_PATH include(BuildMacros) include(WindowsMacros) +find_package(Asio REQUIRED) +find_package(CURL REQUIRED) + if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) find_package(Libtransport REQUIRED) + include_directories(${LIBTRANSPORT_INCLUDE_DIRS}) set(HICN_APPS hicn-apps) else() set(LIBTRANSPORT_LIBRARIES ${LIBTRANSPORT_SHARED}) + list(APPEND DEPENDENCIES + ${LIBHICN} + ${LIBHICN_SHARED} + ${LIBTRANSPORT_LIBRARIES} + ) endif() +list(APPEND LIBRARIES + ${LIBTRANSPORT_LIBRARIES} + ${CURL_LIBRARY} + ${CMAKE_THREAD_LIBS_INIT} +) + include(Packaging) set (COMPILER_DEFINITIONS "") -list(APPEND APPS_SRC - src/higet.cc -) if (WIN32) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4200 /wd4996") endif () -foreach(app ${APPS_SRC}) - get_filename_component(_app_name ${app} NAME) - string(REGEX REPLACE ".cc" "" app_name ${_app_name}) - - build_executable(${app_name} - SOURCES ${app} - LINK_LIBRARIES ${LIBTRANSPORT_LIBRARIES} ${WSOCK32_LIBRARY} ${WS2_32_LIBRARY} - DEPENDS ${LIBTRANSPORT} - COMPONENT ${HICN_APPS} - DEFINITIONS ${COMPILER_DEFINITIONS} - ) -endforeach() +add_subdirectory(src/http-server) +add_subdirectory(src/higet)
\ No newline at end of file diff --git a/apps/src/higet/CMakeLists.txt b/apps/src/higet/CMakeLists.txt new file mode 100644 index 000000000..a144d4c08 --- /dev/null +++ b/apps/src/higet/CMakeLists.txt @@ -0,0 +1,41 @@ +# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) +set(CMAKE_CXX_STANDARD 14) + +project(utils) + +set(CMAKE_MODULE_PATH + ${CMAKE_MODULE_PATH} + "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/Modules" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules" +) + +list(APPEND APPS_SRC + higet.cc +) + + +foreach(app ${APPS_SRC}) + get_filename_component(_app_name ${app} NAME) + string(REGEX REPLACE ".cc" "" app_name ${_app_name}) + + build_executable(${app_name} + SOURCES ${app} + LINK_LIBRARIES ${LIBTRANSPORT_LIBRARIES} ${WSOCK32_LIBRARY} ${WS2_32_LIBRARY} + DEPENDS ${LIBTRANSPORT} + COMPONENT ${HICN_APPS} + DEFINITIONS ${COMPILER_DEFINITIONS} + ) +endforeach() diff --git a/apps/src/higet.cc b/apps/src/higet/higet.cc index d2ef818cb..58b582a9d 100755..100644 --- a/apps/src/higet.cc +++ b/apps/src/higet/higet.cc @@ -35,12 +35,14 @@ typedef struct { std::string producer_certificate; } Configuration; -void processResponse(Configuration &conf, transport::http::HTTPResponse &&response) { +void processResponse(Configuration &conf, + transport::http::HTTPResponse &&response) { auto &payload = response.getPayload(); if (conf.file_name != "-") { - std::cerr << "Saving to: " << conf.file_name << " " << payload.size() << "kB" << std::endl; + std::cerr << "Saving to: " << conf.file_name << " " << payload.size() + << "kB" << std::endl; } Time t3 = std::chrono::system_clock::now(); @@ -59,7 +61,8 @@ void processResponse(Configuration &conf, transport::http::HTTPResponse &&respon if (conf.print_headers) { auto &headers = response.getHeaders(); - out << "HTTP/" << response.getHttpVersion() << " " << response.getStatusCode() << " " << response.getStatusString() + out << "HTTP/" << response.getHttpVersion() << " " + << response.getStatusCode() << " " << response.getStatusString() << "\n"; for (auto &h : headers) { out << h.first << ": " << h.second << "\n"; @@ -70,31 +73,37 @@ void processResponse(Configuration &conf, transport::http::HTTPResponse &&respon out.write((char *)payload.data(), payload.size()); of.close(); - Time t2 = std::chrono::system_clock::now();; - TimeDuration dt = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1); - TimeDuration dt3 = std::chrono::duration_cast<std::chrono::milliseconds>(t3 - t1); + Time t2 = std::chrono::system_clock::now(); + ; + TimeDuration dt = + std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1); + TimeDuration dt3 = + std::chrono::duration_cast<std::chrono::milliseconds>(t3 - t1); long msec = (long)dt.count(); long msec3 = (long)dt3.count(); - std::cerr << "Elapsed Time: " << msec / 1000.0 << " seconds -- " << payload.size() * 8 / msec / 1000.0 - << "[Mbps] -- " << payload.size() * 8 / msec3 / 1000.0 << "[Mbps]" << std::endl; - + std::cerr << "Elapsed Time: " << msec / 1000.0 << " seconds -- " + << payload.size() * 8 / msec / 1000.0 << "[Mbps] -- " + << payload.size() * 8 / msec3 / 1000.0 << "[Mbps]" << std::endl; } void usage(char *program_name) { std::cerr << "USAGE:" << std::endl; std::cerr << "\t" << program_name << " [OPTION]... [URL]..." << std::endl; std::cerr << "OPTIONS:" << std::endl; - std::cerr << "\t" << "-O filename write documents to FILE" << std::endl; - std::cerr << "\t" << "-S print server response" << std::endl; + std::cerr << "\t" + << "-O filename write documents to FILE" << std::endl; + std::cerr << "\t" + << "-S print server response" << std::endl; std::cerr << "EXAMPLE:" << std::endl; - std::cerr << "\t" << program_name << " -O - http://origin/index.html" << std::endl; + std::cerr << "\t" << program_name << " -O - http://origin/index.html" + << std::endl; exit(EXIT_FAILURE); } int main(int argc, char **argv) { #ifdef _WIN32 - WSADATA wsaData = { 0 }; + WSADATA wsaData = {0}; WSAStartup(MAKEWORD(2, 2), &wsaData); #endif @@ -108,19 +117,19 @@ int main(int argc, char **argv) { int opt; while ((opt = getopt(argc, argv, "O:Sc:")) != -1) { switch (opt) { - case 'O': - conf.file_name = optarg; - break; - case 'S': - conf.print_headers = true; - break; - case 'c': - conf.producer_certificate = optarg; - break; - case 'h': - default: - usage(argv[0]); - break; + case 'O': + conf.file_name = optarg; + break; + case 'S': + conf.print_headers = true; + break; + case 'c': + conf.producer_certificate = optarg; + break; + case 'h': + default: + usage(argv[0]); + break; } } @@ -134,10 +143,8 @@ int main(int argc, char **argv) { conf.file_name = name.substr(1 + name.find_last_of("/")); } - std::map<std::string, std::string> headers = { - {"Host", "localhost"}, - {"User-Agent", "higet/1.0"} - }; + std::map<std::string, std::string> headers = {{"Host", "localhost"}, + {"User-Agent", "higet/1.0"}}; transport::http::HTTPClientConnection connection; if (!conf.producer_certificate.empty()) { @@ -160,6 +167,4 @@ int main(int argc, char **argv) { } // end namespace hicnet -int main(int argc, char **argv) { - return hicnet::http::main(argc, argv); -} +int main(int argc, char **argv) { return hicnet::http::main(argc, argv); } diff --git a/apps/src/http-server/CMakeLists.txt b/apps/src/http-server/CMakeLists.txt new file mode 100644 index 000000000..a005f1a8f --- /dev/null +++ b/apps/src/http-server/CMakeLists.txt @@ -0,0 +1,79 @@ +# Copyright (c) 2017 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.2) + +set(CMAKE_CXX_STANDARD 14) + +option(HICNET "Link against Libhicnet." ON) + +configure_file("${PROJECT_SOURCE_DIR}/src/http-server/config.h.in" + "${CMAKE_BINARY_DIR}/apps/http-server/config.h") + +set(LIB_SOURCE_FILES + http-server/http_server.cc + http-server/response.cc + http-server/socket_response.cc + http-server/icn_response.cc + http-server/content.cc + http-server/request.cc + http-server/icn_request.cc + http-server/socket_request.cc + http-server/configuration.cc + http-client/http_client_tcp.cc + http-client/http_client_icn.cc) + +set(LIB_SERVER_HEADER_FILES + http-server/http_server.h + http-server/response.h + http-server/common.h + http-server/socket_response.h + http-server/content.h + http-server/request.h + http-server/icn_request.h + http-server/socket_request.h + http-server/configuration.h + ${CMAKE_BINARY_DIR}/apps/http-server/config.h + http-server/icn_response.h) + +set(LIB_CLIENT_HEADER_FILES + http-client/http_client_tcp.h + http-client/http_client_icn.h + http-client/http_client.h) + +set(APP_SOURCE_FILES + http-server.cc) + +include_directories(${CMAKE_BINARY_DIR}/apps/http-server http-server http-client) + +build_library(hicn-httpserver + STATIC + SOURCES ${LIB_SOURCE_FILES} ${LIB_SERVER_HEADER_FILES} ${LIB_CLIENT_HEADER_FILES} + INSTALL_HEADERS ${HEADER_FILES} + LINK_LIBRARIES ${LIBRARIES} + DEPENDS ${DEPENDENCIES} + COMPONENT lib${LIBTRANSPORT} + INCLUDE_DIRS ${LIBTRANSPORT_INCLUDE_DIRS} + INSTALL_ROOT_DIR hicn/transport + DEFINITIONS ${COMPILER_DEFINITIONS} +) + + +build_executable(hicn-http-server + SOURCES ${APP_SOURCE_FILES} + LINK_LIBRARIES hicn-httpserver ${WSOCK32_LIBRARY} ${WS2_32_LIBRARY} + DEPENDS hicn-httpserver + COMPONENT ${HICN_APPS} + DEFINITIONS ${COMPILER_DEFINITIONS} +) + diff --git a/apps/src/http-server/config.h.in b/apps/src/http-server/config.h.in new file mode 100644 index 000000000..d10e62ee2 --- /dev/null +++ b/apps/src/http-server/config.h.in @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#cmakedefine ICNET +#cmakedefine HICNET diff --git a/apps/src/http-server/http-client/http_client.h b/apps/src/http-server/http-client/http_client.h new file mode 100644 index 000000000..b2dbd1ffd --- /dev/null +++ b/apps/src/http-server/http-client/http_client.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "config.h" + +#include <string> + +#if defined(HICNET) +#include <hicn/transport/http/facade.h> +#elif defined(ICNET) +#include <icnet/icnet_http_facade.h> +#else +#error "No ICN tranport library to which link against." +#endif + +class HTTPClient { +public: + virtual ~HTTPClient() = default; + + virtual void setTcp() = 0; + + virtual bool download(const std::string &url, std::ostream &out) = 0; +}; diff --git a/apps/src/http-server/http-client/http_client_icn.cc b/apps/src/http-server/http-client/http_client_icn.cc new file mode 100644 index 000000000..862741bd9 --- /dev/null +++ b/apps/src/http-server/http-client/http_client_icn.cc @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "http_client_icn.h" +#include "response.h" + +#include <curl/curl.h> + +using namespace std; + +HTTPClientIcn::HTTPClientIcn(uint32_t timeout) { + std::chrono::seconds _timeout(timeout); + connection_.setTimeout(_timeout); +} + +void HTTPClientIcn::setTcp() {} + +HTTPClientIcn::~HTTPClientIcn() {} + +bool HTTPClientIcn::download(const std::string &url, std::ostream &out) { + connection_.get(url); + libl4::http::HTTPResponse r = connection_.response(); + out.write(reinterpret_cast<const char *>(r.data()), r.size()); + return true; +} diff --git a/apps/src/http-server/http-client/http_client_icn.h b/apps/src/http-server/http-client/http_client_icn.h new file mode 100644 index 000000000..8f5e9ae44 --- /dev/null +++ b/apps/src/http-server/http-client/http_client_icn.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "http_client.h" + +#include <string> + +class HTTPClientIcn : public HTTPClient { +public: + HTTPClientIcn(uint32_t timeout); + + void setTcp(); + + ~HTTPClientIcn(); + + bool download(const std::string &url, std::ostream &out); + +private: + libl4::http::HTTPClientConnection connection_; +}; diff --git a/apps/src/http-server/http-client/http_client_tcp.cc b/apps/src/http-server/http-client/http_client_tcp.cc new file mode 100644 index 000000000..08474d71c --- /dev/null +++ b/apps/src/http-server/http-client/http_client_tcp.cc @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "http_client_tcp.h" +#include "response.h" + +#include <curl/curl.h> +#include <iostream> +#include <sstream> +#include <stdio.h> +#include <string.h> + +using namespace std; + +struct UserData { + void *out; + void *curl; + bool tcp; + bool first_time; +}; + +typedef struct UserData UserData; + +size_t write_data(void *ptr, size_t size, size_t nmemb, void *user_data) { + + UserData *data = (UserData *)user_data; + + if (data->first_time) { + double cl; + + int res = + curl_easy_getinfo(data->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &cl); + + if (res >= 0) { + *(ostream *)data->out + << "HTTP/1.0 200 OK\r\nContent-Length: " << std::size_t(cl) + << "\r\n\r\n"; + } + + data->first_time = false; + } + + ((icn_httpserver::Response *)data->out) + ->write((const char *)ptr, size * nmemb); + // ((icn_httpserver::Response*) data->out)->send(); + return size * nmemb; +} + +HTTPClientTcp::HTTPClientTcp() { + tcp_ = false; + first_time = true; + curl_ = curl_easy_init(); +} + +void HTTPClientTcp::setTcp() { tcp_ = true; } + +HTTPClientTcp::~HTTPClientTcp() { curl_easy_cleanup(curl_); } + +bool HTTPClientTcp::download(const std::string &url, std::ostream &out) { + curl_easy_setopt(curl_, CURLOPT_URL, url.c_str()); + + /* example.com is redirected, so we tell libcurl to follow redirection */ + curl_easy_setopt(curl_, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl_, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt(curl_, CURLOPT_ACCEPT_ENCODING, "deflate"); + + curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, write_data); + UserData data; + data.out = &out; + data.curl = curl_; + data.tcp = tcp_; + data.first_time = first_time; + + curl_easy_setopt(curl_, CURLOPT_WRITEDATA, &data); + + /* Perform the request, res will get the return code */ + CURLcode res = curl_easy_perform(curl_); + + /* Check for errors */ + if (res != CURLE_OK) { + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + return false; + } + + return true; +} diff --git a/apps/src/http-server/http-client/http_client_tcp.h b/apps/src/http-server/http-client/http_client_tcp.h new file mode 100644 index 000000000..e1d81ada0 --- /dev/null +++ b/apps/src/http-server/http-client/http_client_tcp.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "http_client.h" + +#include <string> + +class HTTPClientTcp : public HTTPClient { +public: + HTTPClientTcp(); + + void setTcp(); + + ~HTTPClientTcp(); + + bool download(const std::string &url, std::ostream &out); + +private: + bool first_time; + bool tcp_; + void *curl_; +}; diff --git a/apps/src/http-server/http-server.cc b/apps/src/http-server/http-server.cc new file mode 100644 index 000000000..f65734bae --- /dev/null +++ b/apps/src/http-server/http-server.cc @@ -0,0 +1,400 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2016 Ole Christian Eidheim + * + * 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 <fstream> +#include <iostream> +#include <stdio.h> +#include <sys/stat.h> +#include <sys/types.h> + +#ifndef _WIN32 +#include <unistd.h> +#endif + +#include "http-server/http_server.h" +#include "http_client_icn.h" +#include "http_client_tcp.h" + +#ifdef _WIN32 +#include <shlobj.h> +#endif + +typedef icn_httpserver::HttpServer HttpServer; +typedef icn_httpserver::Response Response; +typedef icn_httpserver::Request Request; + +namespace std { + +int _isDirectory(const char *path) { + struct stat statbuf; + if (stat(path, &statbuf) != 0) + return -1; + return S_ISDIR(statbuf.st_mode); +} + +int _isRegularFile(const char *path) { + struct stat statbuf; + if (stat(path, &statbuf) != 0) + return 0; + return S_ISREG(statbuf.st_mode); +} + +string _getFileName(const string &strPath) { + size_t iLastSeparator = 0; +#ifdef _WIN32 + return strPath.substr((iLastSeparator = strPath.find_last_of("\\")) != + std::string::npos + ? iLastSeparator + 1 + : 0, + strPath.size() - strPath.find_last_of(".")); +#else + return strPath.substr((iLastSeparator = strPath.find_last_of("/")) != + std::string::npos + ? iLastSeparator + 1 + : 0, + strPath.size() - strPath.find_last_of(".")); +#endif +} + +int _mkdir(const char *dir) { + std::cout << dir << std::endl; +#ifdef _WIN32 + char sepChar = '\\'; + char tmp[MAX_PATH]; +#else + char sepChar = '/'; + char tmp[PATH_MAX]; +#endif + char *p = NULL; + size_t len; + + snprintf(tmp, sizeof(tmp), "%s", dir); + len = strlen(tmp); + + if (tmp[len - 1] == sepChar) + tmp[len - 1] = 0; + for (p = tmp + 1; *p; p++) { + if (*p == sepChar) { + *p = 0; + if (_isDirectory(tmp) != 1) { +#ifdef _WIN32 + if (!CreateDirectory(tmp, NULL)) { +#else + if (mkdir(tmp, S_IRWXU) == -1) { +#endif + return -1; + } + } + *p = sepChar; + } + } + + if (_isDirectory(tmp) != 1) { +#ifdef _WIN32 + if (!CreateDirectory(tmp, NULL)) { +#else + if (mkdir(tmp, S_IRWXU) == -1) { +#endif + return -1; + } + } + + return 0; +} + +string _getExtension(const string &strPath) { + size_t iLastSeparator = 0; + return strPath.substr((iLastSeparator = strPath.find_last_of(".")) != + std::string::npos + ? iLastSeparator + 1 + : 0, + strPath.size()); +} + +void default_resource_send(const HttpServer &server, + shared_ptr<Response> response, + shared_ptr<ifstream> ifs, + shared_ptr<vector<char>> buffer, + std::size_t bytes_to_read) { + streamsize read_length; + + if ((read_length = ifs->read(&(*buffer)[0], buffer->size()).gcount()) > 0) { + response->write(&(*buffer)[0], read_length); + + if (bytes_to_read <= static_cast<std::size_t>(buffer->size())) { + // If this is the last part of the response, send it at the pointer + // deletion! + return; + } + + std::size_t to_read = bytes_to_read - read_length; + server.send(response, [&server, response, ifs, buffer, + to_read](const std::error_code &ec) { + if (!ec) { + default_resource_send(server, response, ifs, buffer, to_read); + } else { + cerr << "Connection interrupted" << endl; + } + }); + } +} + +void afterSignal(HttpServer *webServer, const std::error_code &errorCode) { + cout << "\nGracefully terminating http-server... wait." << endl; + webServer->stop(); +} + +void usage(const char *programName) { + cerr << programName + << " [-p PATH_TO_ROOT_FOOT_FOLDER] [-f CONFIGURATION_FILE] [-o " + "TCP_LISTEN_PORT] [-l WEBSERVER_PREFIX] [-x TCP_PROXY_ADDRESS] [-z " + "ICN_PROXY_PREFIX]\n" + << "Web server able to publish content and generate http responses over " + "TCP/ICN\n" + << endl; + + exit(1); +} + +int main(int argc, char **argv) { + // Parse command line arguments + +#ifndef _WIN32 + string root_folder = "/var/www/html"; +#else + char path[MAX_PATH]; + SHGetFolderPathA(NULL, CSIDL_PROFILE, NULL, 0, path); + string root_folder(path); + root_folder += "\\www\\html"; +#endif + string webserver_prefix = "http://webserver"; + string tcp_proxy_address; + string icn_proxy_prefix; + int port = 8080; + int opt = 0; + + while ((opt = getopt(argc, argv, "p:l:o:hx:z:")) != -1) { + switch (opt) { + case 'p': + root_folder = optarg; + break; + case 'l': + webserver_prefix = optarg; + break; + case 'x': + tcp_proxy_address = optarg; + break; + case 'o': + port = atoi(optarg); + break; + case 'z': + icn_proxy_prefix = optarg; + break; + case 'h': + default: + usage(argv[0]); + break; + } + } + + if (_isDirectory(root_folder.c_str()) != 1) { + if (_mkdir(root_folder.c_str()) == -1) { + std::cerr << "The web root folder " << root_folder + << " does not exist and its creation failed. Exiting.." + << std::endl; + return (EXIT_FAILURE); + } + } + + std::cout << "Using web root folder: [" << root_folder << "]" << std::endl; + std::cout << "Using locator: [" << webserver_prefix << "]" << std::endl; + if (!tcp_proxy_address.empty()) { + std::cout << "Using TCP proxy: [" << tcp_proxy_address << "]" << std::endl; + } + if (!icn_proxy_prefix.empty()) { + std::cout << "Using ICN proxy: [" << icn_proxy_prefix << "]" << std::endl; + } + + asio::io_service io_service; + HttpServer server(port, webserver_prefix, 50, 5, 300, io_service); + + // GET for the path /info + // Responds with some server info + server.resource["^/info$"]["GET"] = [](shared_ptr<Response> response, + shared_ptr<Request> request) { + stringstream content_stream; + content_stream + << "<h1>This webserver is able to reply to HTTP over TCP/ICN</h1>"; + content_stream << request->getMethod() << " " << request->getPath() + << " HTTP/" << request->getHttp_version() << "<br>"; + + for (auto &header : request->getHeader()) { + content_stream << header.first << ": " << header.second << "<br>"; + } + + // find length of content_stream (length received using + // content_stream.tellp()) + content_stream.seekp(0, ios::end); + + *response << "HTTP/1.1 200 OK\r\nContent-Length: " << content_stream.tellp() + << "\r\n\r\n" + << content_stream.rdbuf(); + }; + + // Default GET-example. If no other matches, this anonymous function will be + // called. Will respond with content in the web/-directory, and its + // subdirectories. Default file: index.html Can for instance be used to + // retrieve an HTML 5 client that uses REST-resources on this server + server.default_resource["GET"] = + [&server, &root_folder, &tcp_proxy_address, &icn_proxy_prefix]( + shared_ptr<Response> response, shared_ptr<Request> request) { + const auto web_root_path = root_folder; + std::string path = web_root_path; + + // check if there is "/" + path = path + request->getPath(); + std::cout << "path:" << path << std::endl; + auto socket_request = + dynamic_cast<icn_httpserver::SocketRequest *>(request.get()); + + std::chrono::milliseconds response_lifetime; + std::string stem = _getFileName(path); + std::string extension = _getExtension(path); + if (extension == "mpd" || stem == "latest") { + std::cout << "1 second" << std::endl; + std::cout << "Setting lifetime to 1 second" << std::endl; + response_lifetime = std::chrono::milliseconds(1000); + } else { + std::cout << "5 second" << std::endl; + std::cout << "Setting lifetime to 5 second" << std::endl; + response_lifetime = std::chrono::milliseconds(5000); + } + + response->setResponseLifetime(response_lifetime); + + if (_isDirectory(path.c_str())) { + // Check if path is within web_root_path + if (distance(web_root_path.begin(), web_root_path.end()) <= + distance(path.begin(), path.end()) && + equal(web_root_path.begin(), web_root_path.end(), path.begin())) { + path += "index.html"; + if (_isRegularFile(path.c_str())) { + + auto ifs = make_shared<ifstream>(); + ifs->open(path, ifstream::in | ios::binary); + + if (*ifs) { + // read and send 15 MB at a time + streamsize buffer_size = 15 * 1024 * 1024; + auto buffer = make_shared<vector<char>>(buffer_size); + + ifs->seekg(0, ios::end); + auto length = ifs->tellg(); + ifs->seekg(0, ios::beg); + + response->setResponseLength(length); + *response << "HTTP/1.0 200 OK\r\nContent-Length: " << length + << "\r\n\r\n"; + + default_resource_send(server, response, ifs, buffer, length); + + return; + } + } + } + } + + string proxy; + HTTPClient *client = nullptr; + + if (tcp_proxy_address.empty() && !icn_proxy_prefix.empty()) { + proxy = icn_proxy_prefix; + client = new HTTPClientIcn(20); + } else if (!tcp_proxy_address.empty() && icn_proxy_prefix.empty()) { + proxy = tcp_proxy_address; + client = new HTTPClientTcp; + } else if (!tcp_proxy_address.empty() && !icn_proxy_prefix.empty()) { + if (socket_request) { + proxy = icn_proxy_prefix; + client = new HTTPClientIcn(20); + } else { + proxy = tcp_proxy_address; + client = new HTTPClientTcp; + } + } + + if (!proxy.empty()) { + // Fetch content from remote origin + std::stringstream ss; + + if (strncmp("http://", proxy.c_str(), 7) != 0) { + if (strncmp("https://", proxy.c_str(), 8) != 0) { + ss << "https://"; + } else { + ss << "http://"; + } + } + + ss << proxy; + ss << request->getPath(); + + std::cout << "Forwarding request to " << ss.str() << std::endl; + + client->download(ss.str(), *response); + + delete client; + + if (response->size() == 0) { + *response << "HTTP/1.1 504 Gateway Timeout\r\n\r\n"; + } + + return; + } + + string content = "Could not open path " + request->getPath() + "\n"; + + *response << "HTTP/1.1 404 Not found\r\nContent-Length: " + << content.length() << "\r\n\r\n" + << content; + }; + + // Let the main thread to catch SIGINT + asio::signal_set signals(io_service, SIGINT); + signals.async_wait(bind(afterSignal, &server, placeholders::_1)); + + thread server_thread([&server]() { + // Start server + server.start(); + }); + + if (server_thread.joinable()) { + server_thread.join(); + } + + return 0; +} + +} // end namespace std + +int main(int argc, char **argv) { return std::main(argc, argv); } diff --git a/apps/src/http-server/http-server/common.h b/apps/src/http-server/http-server/common.h new file mode 100644 index 000000000..81f6757c7 --- /dev/null +++ b/apps/src/http-server/http-server/common.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "config.h" + +#if defined(HICNET) +#include <hicn/transport/http/facade.h> +#include <hicn/transport/utils/hash.h> +#elif defined(ICNET) +#include <icnet/icnet_http_facade.h> +#include <icnet/icnet_utils_hash.h> +#else +#error "No ICN tranport library to which link against." +#endif + +#include <algorithm> +#include <asio.hpp> +#include <functional> +#include <future> +#include <iostream> +#include <memory> +#include <regex> +#include <sstream> +#include <string> +#include <thread> +#include <unordered_map> + +typedef asio::ip::tcp::socket socket_type; +typedef std::function<void(const std::error_code &)> SendCallback; diff --git a/apps/src/http-server/http-server/configuration.cc b/apps/src/http-server/http-server/configuration.cc new file mode 100644 index 000000000..603396b44 --- /dev/null +++ b/apps/src/http-server/http-server/configuration.cc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "configuration.h" + +namespace icn_httpserver { + +Configuration::Configuration(unsigned short port, size_t num_threads) + : num_threads_(num_threads), port_(port), reuse_address_(true) {} + +size_t Configuration::getNum_threads() const { return num_threads_; } + +void Configuration::setNum_threads(size_t num_threads) { + Configuration::num_threads_ = num_threads; +} + +unsigned short Configuration::getPort() const { return port_; } + +void Configuration::setPort(unsigned short port) { + Configuration::port_ = port; +} + +const std::string &Configuration::getAddress() const { return address_; } + +void Configuration::setAddress(const std::string &address) { + Configuration::address_ = address; +} + +bool Configuration::isReuse_address() const { return reuse_address_; } + +void Configuration::setReuse_address(bool reuse_address) { + Configuration::reuse_address_ = reuse_address; +} + +} // end namespace icn_httpserver
\ No newline at end of file diff --git a/apps/src/http-server/http-server/configuration.h b/apps/src/http-server/http-server/configuration.h new file mode 100644 index 000000000..b87558f91 --- /dev/null +++ b/apps/src/http-server/http-server/configuration.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "common.h" + +namespace icn_httpserver { + +class Configuration { +public: + Configuration(unsigned short port, size_t num_threads); + + size_t getNum_threads() const; + + void setNum_threads(size_t num_threads); + + unsigned short getPort() const; + + void setPort(unsigned short port); + + const std::string &getAddress() const; + + void setAddress(const std::string &address); + + bool isReuse_address() const; + + void setReuse_address(bool reuse_address); + +private: + size_t num_threads_; + unsigned short port_; + std::string address_; + bool reuse_address_; +}; + +} // end namespace icn_httpserver diff --git a/apps/src/http-server/http-server/content.cc b/apps/src/http-server/http-server/content.cc new file mode 100644 index 000000000..8ad16f904 --- /dev/null +++ b/apps/src/http-server/http-server/content.cc @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "content.h" + +namespace icn_httpserver { + +Content::Content(asio::streambuf &streambuf) + : std::istream(&streambuf), streambuf_(streambuf) {} + +std::size_t Content::size() { return streambuf_.size(); } + +std::string Content::string() { + std::stringstream ss; + ss << rdbuf(); + return ss.str(); +} + +} // end namespace icn_httpserver
\ No newline at end of file diff --git a/apps/src/http-server/http-server/content.h b/apps/src/http-server/http-server/content.h new file mode 100644 index 000000000..ebf2f7f32 --- /dev/null +++ b/apps/src/http-server/http-server/content.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "common.h" + +#pragma once + +namespace icn_httpserver { + +class Content : public std::istream { +public: + Content(asio::streambuf &streambuf); + + size_t size(); + + std::string string(); + +private: + asio::streambuf &streambuf_; +}; + +} // end namespace icn_httpserver diff --git a/apps/src/http-server/http-server/http_server.cc b/apps/src/http-server/http-server/http_server.cc new file mode 100644 index 000000000..8c8bea60a --- /dev/null +++ b/apps/src/http-server/http-server/http_server.cc @@ -0,0 +1,416 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2016 Ole Christian Eidheim + * + * 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 "http_server.h" + +#include <asio.hpp> +#include <fstream> +#include <istream> + +namespace icn_httpserver { + +HttpServer::HttpServer(unsigned short port, std::string icn_name, + size_t num_threads, long timeout_request, + long timeout_send_or_receive) + : config_(port, num_threads), + internal_io_service_(std::make_shared<asio::io_service>()), + io_service_(*internal_io_service_), acceptor_(io_service_), + icn_name_(icn_name), timeout_request_(timeout_request), + timeout_content_(timeout_send_or_receive) {} + +HttpServer::HttpServer(unsigned short port, std::string icn_name, + size_t num_threads, long timeout_request, + long timeout_send_or_receive, + asio::io_service &ioService) + : config_(port, num_threads), io_service_(ioService), + acceptor_(io_service_), icn_name_(icn_name), + timeout_request_(timeout_request), + timeout_content_(timeout_send_or_receive) {} + +void HttpServer::onIcnRequest( + std::shared_ptr<libl4::http::HTTPServerPublisher> &publisher, + const uint8_t *buffer, std::size_t size, int request_id) { + std::shared_ptr<Request> request = std::make_shared<IcnRequest>(publisher); + request->getContent().rdbuf()->sputn((char *)buffer, size); + + if (!parse_request(request, request->getContent())) { + return; + } + + std::map<int, std::shared_ptr<libl4::http::HTTPServerPublisher>> + &icn_publishers = icn_acceptor_->getPublishers(); + + std::unique_lock<std::mutex> lock(thread_list_mtx_); + if (icn_publishers.size() < config_.getNum_threads()) { + std::cout << "Received request for: " << request->getPath() << std::endl; + + publisher->attachPublisher(); + std::cout << "Starting new thread" << std::endl; + io_service_.dispatch([this, request, request_id]() { + std::map<int, std::shared_ptr<libl4::http::HTTPServerPublisher>> + &icn_publishers = icn_acceptor_->getPublishers(); + find_resource(nullptr, request); + icn_publishers[request_id]->serveClients(); + std::unique_lock<std::mutex> lock(thread_list_mtx_); + icn_publishers.erase(request_id); + }); + } +} + +void HttpServer::setIcnAcceptor() { + icn_acceptor_ = std::make_shared<libl4::http::HTTPServerAcceptor>( + icn_name_, std::bind(&HttpServer::onIcnRequest, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4)); + icn_acceptor_->listen(true); +} + +void HttpServer::spawnThreads() { + if (io_service_.stopped()) { + io_service_.reset(); + } + + asio::ip::tcp::endpoint endpoint; + + if (config_.getAddress().size() > 0) { + endpoint = asio::ip::tcp::endpoint( + asio::ip::address::from_string(config_.getAddress()), + config_.getPort()); + } else { + endpoint = asio::ip::tcp::endpoint(asio::ip::tcp::v4(), config_.getPort()); + } + + acceptor_.open(endpoint.protocol()); + acceptor_.set_option( + asio::socket_base::reuse_address(config_.isReuse_address())); + acceptor_.bind(endpoint); + acceptor_.listen(); + + accept(); + + // If num_threads>1, start m_io_service.run() in (num_threads-1) threads for + // thread-pooling + socket_threads_.clear(); + for (size_t c = 1; c < config_.getNum_threads(); c++) { + socket_threads_.emplace_back([this]() { io_service_.run(); }); + } +} + +void HttpServer::start() { + // Copy the resources to opt_resource for more efficient request processing + opt_resource_.clear(); + for (auto &res : resource) { + for (auto &res_method : res.second) { + auto it = opt_resource_.end(); + for (auto opt_it = opt_resource_.begin(); opt_it != opt_resource_.end(); + opt_it++) { + if (res_method.first == opt_it->first) { + it = opt_it; + break; + } + } + if (it == opt_resource_.end()) { + opt_resource_.emplace_back(); + it = opt_resource_.begin() + (opt_resource_.size() - 1); + it->first = res_method.first; + } + it->second.emplace_back(std::regex(res.first), res_method.second); + } + } + + spawnThreads(); + + setIcnAcceptor(); + + // Wait for the rest of the threads, if any, to finish as well + for (auto &t : socket_threads_) { + t.join(); + } + // for (auto &t : icn_threads) { + // t.second.get(); + // } +} + +void HttpServer::stop() { + acceptor_.close(); + + io_service_.stop(); + + std::map<int, std::shared_ptr<libl4::http::HTTPServerPublisher>> + &icn_publishers = icn_acceptor_->getPublishers(); + + for (auto &p : icn_publishers) { + p.second->stop(); + } +} + +void HttpServer::accept() { + // Create new socket for this connection + // Shared_ptr is used to pass temporary objects to the asynchronous functions + std::shared_ptr<socket_type> socket = + std::make_shared<socket_type>(io_service_); + + acceptor_.async_accept(*socket, [this, socket](const std::error_code &ec) { + // Immediately start accepting a new connection + accept(); + + if (!ec) { + asio::ip::tcp::no_delay option(true); + socket->set_option(option); + read_request_and_content(socket); + } + }); +} + +void HttpServer::send(std::shared_ptr<Response> response, + SendCallback callback) const { + response->send(callback); +} + +std::shared_ptr<asio::steady_timer> +HttpServer::set_timeout_on_socket(std::shared_ptr<socket_type> socket, + long seconds) { + std::shared_ptr<asio::steady_timer> timer = + std::make_shared<asio::steady_timer>(io_service_); + timer->expires_from_now(std::chrono::seconds(seconds)); + timer->async_wait([socket](const std::error_code &ec) { + if (!ec) { + std::error_code ec; + socket->lowest_layer().shutdown(asio::ip::tcp::socket::shutdown_both, ec); + socket->lowest_layer().close(); + } + }); + return timer; +} + +void HttpServer::read_request_and_content(std::shared_ptr<socket_type> socket) { + // Create new streambuf (Request::streambuf) for async_read_until() + // shared_ptr is used to pass temporary objects to the asynchronous functions + std::shared_ptr<Request> request = std::make_shared<SocketRequest>(); + request->read_remote_endpoint_data(*socket); + + // Set timeout on the following asio::async-read or write function + std::shared_ptr<asio::steady_timer> timer; + if (timeout_request_ > 0) { + timer = set_timeout_on_socket(socket, timeout_request_); + } + + asio::async_read_until( + *socket, request->getStreambuf(), "\r\n\r\n", + [this, socket, request, timer](const std::error_code &ec, + size_t bytes_transferred) { + if (timeout_request_ > 0) { + timer->cancel(); + } + if (!ec) { + // request->streambuf.size() is not necessarily the same as + // bytes_transferred, from Asio-docs: "After a successful + // async_read_until operation, the streambuf may contain additional + // data beyond the delimiter" The chosen solution is to extract lines + // from the stream directly when parsing the header. What is left of + // the streambuf (maybe some bytes of the content) is appended to in + // the async_read-function below (for retrieving content). + size_t num_additional_bytes = + request->getStreambuf().in_avail() - bytes_transferred; + + if (!parse_request(request, request->getContent())) { + return; + } + + // If content, read that as well + auto it = request->getHeader().find("Content-Length"); + if (it != request->getHeader().end()) { + // Set timeout on the following asio::async-read or write function + std::shared_ptr<asio::steady_timer> timer; + if (timeout_content_ > 0) { + timer = set_timeout_on_socket(socket, timeout_content_); + } + unsigned long long content_length; + try { + content_length = atol(it->second.c_str()); + } catch (const std::exception &) { + return; + } + if (content_length > num_additional_bytes) { + asio::async_read( + *socket, request->getStreambuf(), + asio::transfer_exactly(content_length - num_additional_bytes), + [this, socket, request, timer](const std::error_code &ec, + size_t /*bytes_transferred*/) { + if (timeout_content_ > 0) { + timer->cancel(); + } + if (!ec) { + find_resource(socket, request); + } + }); + } else { + + if (timeout_content_ > 0) { + timer->cancel(); + } + + find_resource(socket, request); + } + } else { + find_resource(socket, request); + } + } + }); +} + +bool HttpServer::parse_request(std::shared_ptr<Request> request, + std::istream &stream) const { + std::string line; + getline(stream, line); + size_t method_end; + if ((method_end = line.find(' ')) != std::string::npos) { + size_t path_end; + if ((path_end = line.find(' ', method_end + 1)) != std::string::npos) { + request->setMethod(line.substr(0, method_end)); + request->setPath(line.substr(method_end + 1, path_end - method_end - 1)); + + size_t protocol_end; + if ((protocol_end = line.find('/', path_end + 1)) != std::string::npos) { + if (line.substr(path_end + 1, protocol_end - path_end - 1) != "HTTP") { + return false; + } + request->setHttp_version( + line.substr(protocol_end + 1, line.size() - protocol_end - 2)); + } else { + return false; + } + + getline(stream, line); + size_t param_end; + while ((param_end = line.find(':')) != std::string::npos) { + size_t value_start = param_end + 1; + if ((value_start) < line.size()) { + if (line[value_start] == ' ') { + value_start++; + } + if (value_start < line.size()) { + request->getHeader().insert(std::make_pair( + line.substr(0, param_end), + line.substr(value_start, line.size() - value_start - 1))); + } + } + + getline(stream, line); + } + } else { + return false; + } + } else { + return false; + } + return true; +} + +void HttpServer::find_resource(std::shared_ptr<socket_type> socket, + std::shared_ptr<Request> request) { + // Find path- and method-match, and call write_response + for (auto &res : opt_resource_) { + if (request->getMethod() == res.first) { + for (auto &res_path : res.second) { + std::smatch sm_res; + if (std::regex_match(request->getPath(), sm_res, res_path.first)) { + request->setPath_match(std::move(sm_res)); + write_response(socket, request, res_path.second); + return; + } + } + } + } + auto it_method = default_resource.find(request->getMethod()); + if (it_method != default_resource.end()) { + write_response(socket, request, it_method->second); + return; + } + + std::cout << "resource not found" << std::endl; +} + +void HttpServer::write_response(std::shared_ptr<socket_type> socket, + std::shared_ptr<Request> request, + ResourceCallback &resource_function) { + // Set timeout on the following asio::async-read or write function + std::shared_ptr<asio::steady_timer> timer; + if (timeout_content_ > 0 && socket) { + timer = set_timeout_on_socket(socket, timeout_content_); + } + + Response *resp; + + if (socket) { + resp = new SocketResponse(socket); + } else { + resp = new IcnResponse( + std::static_pointer_cast<IcnRequest>(request)->getHttpPublisher(), + std::static_pointer_cast<IcnRequest>(request)->getName(), + std::static_pointer_cast<IcnRequest>(request)->getPath()); + } + + auto response = std::shared_ptr<Response>(resp, [this, request, timer, + socket]( + Response *response_ptr) { + auto response = std::shared_ptr<Response>(response_ptr); + response->setIsLast(true); + + send(response, [this, response, request, timer, + socket](const std::error_code &ec) { + if (!ec) { + if (socket && timeout_content_ > 0) { + timer->cancel(); + } + + float http_version; + try { + http_version = atof(request->getHttp_version().c_str()); + } catch (const std::exception &) { + return; + } + + auto range = request->getHeader().equal_range("Connection"); + for (auto it = range.first; it != range.second; it++) { + if (caseInsCompare(it->second, "close")) { + return; + } + } + if (http_version > 1.05 && socket) { + read_request_and_content( + std::static_pointer_cast<SocketResponse>(response)->getSocket()); + } + } + }); + }); + + try { + resource_function(response, request); + } catch (const std::exception &) { + return; + } +} + +} // end namespace icn_httpserver diff --git a/apps/src/http-server/http-server/http_server.h b/apps/src/http-server/http-server/http_server.h new file mode 100644 index 000000000..3468b438a --- /dev/null +++ b/apps/src/http-server/http-server/http_server.h @@ -0,0 +1,118 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2016 Ole Christian Eidheim + * + * 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. + */ + +#pragma once + +#include "common.h" +#include "configuration.h" +#include "icn_request.h" +#include "icn_response.h" +#include "socket_request.h" +#include "socket_response.h" + +typedef std::function<void(std::shared_ptr<icn_httpserver::Response>, + std::shared_ptr<icn_httpserver::Request>)> + ResourceCallback; + +#define SERVER_NAME "/webserver" +#define PACKET_SIZE 1500 +#define SEND_BUFFER_SIZE 30000 + +#define GET "GET" +#define POST "POST" +#define PUT "PUT" +#define DELETE "DELETE" +#define PATCH "PATCH" + +namespace icn_httpserver { + +class HttpServer { +public: + explicit HttpServer(unsigned short port, std::string icn_name, + size_t num_threads, long timeout_request, + long timeout_send_or_receive); + + explicit HttpServer(unsigned short port, std::string icn_name, + size_t num_threads, long timeout_request, + long timeout_send_or_receive, + asio::io_service &ioService); + + void start(); + + void stop(); + + void accept(); + + void send(std::shared_ptr<Response> response, + SendCallback callback = nullptr) const; + + std::unordered_map<std::string, + std::unordered_map<std::string, ResourceCallback>> + resource; + + std::unordered_map<std::string, ResourceCallback> default_resource; + + void + onIcnRequest(std::shared_ptr<libl4::http::HTTPServerPublisher> &publisher, + const uint8_t *buffer, std::size_t size, int request_id); + +private: + void spawnThreads(); + + void setIcnAcceptor(); + + std::shared_ptr<asio::steady_timer> + set_timeout_on_socket(std::shared_ptr<socket_type> socket, long seconds); + + void read_request_and_content(std::shared_ptr<socket_type> socket); + + bool parse_request(std::shared_ptr<Request> request, + std::istream &stream) const; + + void find_resource(std::shared_ptr<socket_type> socket, + std::shared_ptr<Request> request); + + void write_response(std::shared_ptr<socket_type> socket, + std::shared_ptr<Request> request, + ResourceCallback &resource_function); + + Configuration config_; + + std::vector<std::pair<std::string, + std::vector<std::pair<std::regex, ResourceCallback>>>> + opt_resource_; + + std::shared_ptr<asio::io_service> internal_io_service_; + asio::io_service &io_service_; + asio::ip::tcp::acceptor acceptor_; + std::vector<std::thread> socket_threads_; + std::string icn_name_; + std::shared_ptr<libl4::http::HTTPServerAcceptor> icn_acceptor_; + std::mutex thread_list_mtx_; + + long timeout_request_; + long timeout_content_; +}; + +} // end namespace icn_httpserver diff --git a/apps/src/http-server/http-server/icn_request.cc b/apps/src/http-server/http-server/icn_request.cc new file mode 100644 index 000000000..7871d908d --- /dev/null +++ b/apps/src/http-server/http-server/icn_request.cc @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "icn_request.h" + +namespace icn_httpserver { + +IcnRequest::IcnRequest( + std::shared_ptr<libl4::http::HTTPServerPublisher> &publisher) + : publisher_(publisher) { + time_t t; + time(&t); + srand((unsigned int)t); + request_id_ = rand(); +} + +IcnRequest::IcnRequest( + std::shared_ptr<libl4::http::HTTPServerPublisher> &publisher, + std::string name, std::string path, std::string method, + std::string http_version) + : IcnRequest(publisher) { + this->name_ = name; + this->path_ = path; + this->method_ = method; + this->http_version_ = http_version; +} + +const std::string &IcnRequest::getName() const { return name_; } + +void IcnRequest::setName(const std::string &name) { IcnRequest::name_ = name; } + +int IcnRequest::getRequest_id() const { return request_id_; } + +void IcnRequest::setRequest_id(int request_id) { + IcnRequest::request_id_ = request_id; +} + +const std::shared_ptr<libl4::http::HTTPServerPublisher> & +IcnRequest::getHttpPublisher() const { + return publisher_; +} + +void IcnRequest::setProducer( + const std::shared_ptr<libl4::http::HTTPServerPublisher> &producer) { + IcnRequest::publisher_ = producer; +} + +} // end namespace icn_httpserver diff --git a/apps/src/http-server/http-server/icn_request.h b/apps/src/http-server/http-server/icn_request.h new file mode 100644 index 000000000..adf36d129 --- /dev/null +++ b/apps/src/http-server/http-server/icn_request.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "common.h" +#include "request.h" + +namespace icn_httpserver { + +class IcnRequest : public Request { +public: + IcnRequest(std::shared_ptr<libl4::http::HTTPServerPublisher> &publisher); + + IcnRequest(std::shared_ptr<libl4::http::HTTPServerPublisher> &publisher, + std::string name, std::string path, std::string method, + std::string http_version); + + ~IcnRequest() = default; + + const std::string &getName() const; + + void setName(const std::string &name); + + int getRequest_id() const; + + void setRequest_id(int request_id); + + const std::shared_ptr<libl4::http::HTTPServerPublisher> & + getHttpPublisher() const; + + void setProducer( + const std::shared_ptr<libl4::http::HTTPServerPublisher> &producer); + +private: + std::string name_; + int request_id_; + std::shared_ptr<libl4::http::HTTPServerPublisher> publisher_; +}; + +} // end namespace icn_httpserver
\ No newline at end of file diff --git a/apps/src/http-server/http-server/icn_response.cc b/apps/src/http-server/http-server/icn_response.cc new file mode 100644 index 000000000..11d0faf6b --- /dev/null +++ b/apps/src/http-server/http-server/icn_response.cc @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "icn_response.h" + +namespace icn_httpserver { + +IcnResponse::IcnResponse( + std::shared_ptr<libl4::http::HTTPServerPublisher> publisher, + std::string ndn_name, + std::string ndn_path) //, + // int response_id) + : ndn_name_(ndn_name), ndn_path_(ndn_path), publisher_(publisher) {} + +void IcnResponse::send(const SendCallback &callback) { + + std::size_t buffer_size = this->streambuf_.size(); + this->streambuf_.commit(this->streambuf_.size()); + + this->publisher_->publishContent( + asio::buffer_cast<const uint8_t *>(this->streambuf_.data()), buffer_size, + response_lifetime_, this->is_last_); + + this->streambuf_.consume(buffer_size); + + if (callback) { + callback(std::error_code()); + } +} + +void IcnResponse::setResponseLifetime( + const std::chrono::milliseconds &response_lifetime) { + this->publisher_->setTimeout(response_lifetime, true); + Response::setResponseLifetime(response_lifetime); +} + +} // end namespace icn_httpserver diff --git a/apps/src/http-server/http-server/icn_response.h b/apps/src/http-server/http-server/icn_response.h new file mode 100644 index 000000000..2194a5a7f --- /dev/null +++ b/apps/src/http-server/http-server/icn_response.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "response.h" + +namespace icn_httpserver { + +class IcnResponse : public Response { + +public: + IcnResponse(std::shared_ptr<libl4::http::HTTPServerPublisher> producer, + std::string ndn_name, std::string ndn_path); + + void send(const SendCallback &callback = nullptr) override; + + void setResponseLifetime( + const std::chrono::milliseconds &response_lifetime) override; + +private: + std::string ndn_name_; + std::string ndn_path_; + std::shared_ptr<libl4::http::HTTPServerPublisher> publisher_; +}; + +} // end namespace icn_httpserver diff --git a/apps/src/http-server/http-server/request.cc b/apps/src/http-server/http-server/request.cc new file mode 100644 index 000000000..e754d645b --- /dev/null +++ b/apps/src/http-server/http-server/request.cc @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "request.h" + +using namespace std; + +inline bool caseInsCharCompareN(char a, char b) { + return (toupper(a) == toupper(b)); +} + +inline bool caseInsCharCompareW(wchar_t a, wchar_t b) { + return (towupper(a) == towupper(b)); +} + +bool caseInsCompare(const string &s1, const string &s2) { + return ((s1.size() == s2.size()) && + equal(s1.begin(), s1.end(), s2.begin(), caseInsCharCompareN)); +} + +bool caseInsCompare(const wstring &s1, const wstring &s2) { + return ((s1.size() == s2.size()) && + equal(s1.begin(), s1.end(), s2.begin(), caseInsCharCompareW)); +} + +namespace icn_httpserver { + +Request::Request() : content_(streambuf_) {} + +const std::string &Request::getMethod() const { return method_; } + +void Request::setMethod(const std::string &method) { + Request::method_ = method; +} + +const std::string &Request::getPath() const { return path_; } + +void Request::setPath(const std::string &path) { Request::path_ = path; } + +const std::string &Request::getHttp_version() const { return http_version_; } + +void Request::setHttp_version(const std::string &http_version) { + Request::http_version_ = http_version; +} + +std::unordered_multimap<std::string, std::string, ihash, iequal_to> & +Request::getHeader() { + return header_; +} + +Content &Request::getContent() { return content_; } + +const std::smatch &Request::getPath_match() const { return path_match_; } + +void Request::setPath_match(const std::smatch &path_match) { + Request::path_match_ = path_match; +} + +} // end namespace icn_httpserver diff --git a/apps/src/http-server/http-server/request.h b/apps/src/http-server/http-server/request.h new file mode 100644 index 000000000..f9b2a73df --- /dev/null +++ b/apps/src/http-server/http-server/request.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "common.h" +#include "content.h" + +using namespace std; + +inline bool caseInsCharCompareN(char a, char b); + +inline bool caseInsCharCompareW(wchar_t a, wchar_t b); + +bool caseInsCompare(const string &s1, const string &s2); + +bool caseInsCompare(const wstring &s1, const wstring &s2); + +namespace icn_httpserver { + +class iequal_to { +public: + bool operator()(const std::string &key1, const std::string &key2) const { + return caseInsCompare(key1, key2); + } +}; + +class ihash { +public: + size_t operator()(const std::string &key) const { + std::size_t seed = 0; + for (auto &c : key) { + std::hash<char> hasher; + seed ^= hasher(c) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + } + return seed; + } +}; + +class Request { +public: + Request(); + + virtual void read_remote_endpoint_data(socket_type &socket){}; + + virtual ~Request() = default; + + const std::string &getMethod() const; + + void setMethod(const std::string &method); + + const std::string &getPath() const; + + void setPath(const std::string &path); + + const std::string &getHttp_version() const; + + void setHttp_version(const std::string &http_version); + + std::unordered_multimap<std::string, std::string, ihash, iequal_to> & + getHeader(); + + asio::streambuf &getStreambuf() { return streambuf_; } + + Content &getContent(); + + const std::smatch &getPath_match() const; + + void setPath_match(const std::smatch &path_match); + +protected: + std::string method_, path_, http_version_; + Content content_; + std::unordered_multimap<std::string, std::string, ihash, iequal_to> header_; + std::smatch path_match_; + asio::streambuf streambuf_; +}; + +} // end namespace icn_httpserver diff --git a/apps/src/http-server/http-server/response.cc b/apps/src/http-server/http-server/response.cc new file mode 100644 index 000000000..ccb249e4a --- /dev/null +++ b/apps/src/http-server/http-server/response.cc @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "response.h" +#include "common.h" + +#define DEFAULT_LIFETIME 1000 * 1000 + +namespace icn_httpserver { + +Response::Response() + : std::ostream(&streambuf_), is_last_(false), response_length_(0), + response_lifetime_(DEFAULT_LIFETIME) {} + +Response::~Response() {} + +std::size_t Response::size() { return streambuf_.size(); } + +bool Response::isIsLast() const { return is_last_; } + +void Response::setIsLast(bool is_last) { Response::is_last_ = is_last; } + +const std::chrono::milliseconds &Response::getResponseLifetime() const { + return response_lifetime_; +} + +void Response::setResponseLifetime( + const std::chrono::milliseconds &response_lifetime) { + Response::response_lifetime_ = response_lifetime; +} + +void Response::setResponseLength(std::size_t length) { + response_length_ = length; +} + +} // end namespace icn_httpserver diff --git a/apps/src/http-server/http-server/response.h b/apps/src/http-server/http-server/response.h new file mode 100644 index 000000000..9cc2e61ab --- /dev/null +++ b/apps/src/http-server/http-server/response.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "common.h" + +namespace icn_httpserver { + +class Response : public std::ostream { +public: + Response(); + + virtual ~Response(); + + size_t size(); + + virtual void send(const SendCallback &callback = nullptr){}; + + bool isIsLast() const; + + void setIsLast(bool is_last); + + void setResponseLength(std::size_t length); + + const std::chrono::milliseconds &getResponseLifetime() const; + + virtual void + setResponseLifetime(const std::chrono::milliseconds &response_lifetime); + +protected: + asio::streambuf streambuf_; + bool is_last_; + std::size_t response_length_; + std::chrono::milliseconds response_lifetime_; +}; + +} // end namespace icn_httpserver
\ No newline at end of file diff --git a/apps/src/http-server/http-server/socket_request.cc b/apps/src/http-server/http-server/socket_request.cc new file mode 100644 index 000000000..321d9c61a --- /dev/null +++ b/apps/src/http-server/http-server/socket_request.cc @@ -0,0 +1,38 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2016 Ole Christian Eidheim + * + * 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 "socket_request.h" + +namespace icn_httpserver { + +void SocketRequest::read_remote_endpoint_data(socket_type &socket) { + try { + remote_endpoint_address_ = + socket.lowest_layer().remote_endpoint().address().to_string(); + remote_endpoint_port_ = socket.lowest_layer().remote_endpoint().port(); + } catch (const std::exception &) { + } +} + +} // end namespace icn_httpserver diff --git a/apps/src/http-server/http-server/socket_request.h b/apps/src/http-server/http-server/socket_request.h new file mode 100644 index 000000000..c6566a207 --- /dev/null +++ b/apps/src/http-server/http-server/socket_request.h @@ -0,0 +1,40 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2016 Ole Christian Eidheim + * + * 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. + */ + +#pragma once + +#include "request.h" + +namespace icn_httpserver { + +class SocketRequest : public Request { +public: + void read_remote_endpoint_data(socket_type &socket); + +private: + std::string remote_endpoint_address_; + unsigned short remote_endpoint_port_; +}; + +} // end namespace icn_httpserver diff --git a/apps/src/http-server/http-server/socket_response.cc b/apps/src/http-server/http-server/socket_response.cc new file mode 100644 index 000000000..5095c614f --- /dev/null +++ b/apps/src/http-server/http-server/socket_response.cc @@ -0,0 +1,52 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2016 Ole Christian Eidheim + * + * 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 "socket_response.h" + +namespace icn_httpserver { + +SocketResponse::SocketResponse(std::shared_ptr<asio::ip::tcp::socket> socket) + : socket_(socket) {} + +SocketResponse::~SocketResponse(){}; + +void SocketResponse::send(const SendCallback &callback) { + asio::async_write( + *this->socket_, this->streambuf_, + [callback](const std::error_code &ec, size_t /*bytes_transferred*/) { + if (callback) { + callback(ec); + } + }); +} + +const std::shared_ptr<socket_type> &SocketResponse::getSocket() const { + return socket_; +} + +void SocketResponse::setSocket(const std::shared_ptr<socket_type> &socket) { + SocketResponse::socket_ = socket; +} + +} // end namespace icn_httpserver diff --git a/apps/src/http-server/http-server/socket_response.h b/apps/src/http-server/http-server/socket_response.h new file mode 100644 index 000000000..b582809dc --- /dev/null +++ b/apps/src/http-server/http-server/socket_response.h @@ -0,0 +1,47 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2016 Ole Christian Eidheim + * + * 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. + */ + +#pragma once + +#include "response.h" + +namespace icn_httpserver { + +class SocketResponse : public Response { +public: + SocketResponse(std::shared_ptr<socket_type> socket); + + ~SocketResponse(); + + void send(const SendCallback &callback = nullptr); + + const std::shared_ptr<socket_type> &getSocket() const; + + void setSocket(const std::shared_ptr<socket_type> &socket); + +private: + std::shared_ptr<socket_type> socket_; +}; + +} // end namespace icn_httpserver diff --git a/cmake/Modules/FindCURL.cmake b/cmake/Modules/FindCURL.cmake new file mode 100644 index 000000000..239b0e505 --- /dev/null +++ b/cmake/Modules/FindCURL.cmake @@ -0,0 +1,69 @@ +#.rst: +# FindCURL +# -------- +# +# Find curl +# +# Find the native CURL headers and libraries. +# +# :: +# +# CURL_INCLUDE_DIRS - where to find curl_/curl_.h, etc. +# CURL_LIBRARIES - List of libraries when using curl. +# CURL_FOUND - True if curl found. +# CURL_VERSION_STRING - the version of curl found (since CMake 2.8.8) + +#============================================================================= +# Copyright 2006-2009 Kitware, Inc. +# Copyright 2012 Rolf Eike Beer <eike@sf-mail.de> +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +# Look for the header file. +find_path(CURL_INCLUDE_DIR NAMES curl/curl.h) +mark_as_advanced(CURL_INCLUDE_DIR) + +# Look for the library (sorted from most current/relevant entry to least). +find_library(CURL_LIBRARY NAMES + curl + # Windows MSVC prebuilts: + curllib + libcurl_imp + curllib_static + # Windows older "Win32 - MSVC" prebuilts (libcurl.lib, e.g. libcurl-7.15.5-win32-msvc.zip): + libcurl + ) +mark_as_advanced(CURL_LIBRARY) + +if(CURL_INCLUDE_DIR) + foreach(_curl_version_header curlver.h curl.h) + if(EXISTS "${CURL_INCLUDE_DIR}/curl/${_curl_version_header}") + file(STRINGS "${CURL_INCLUDE_DIR}/curl/${_curl_version_header}" curl_version_str REGEX "^#define[\t ]+LIBCURL_VERSION[\t ]+\".*\"") + + string(REGEX REPLACE "^#define[\t ]+LIBCURL_VERSION[\t ]+\"([^\"]*)\".*" "\\1" CURL_VERSION_STRING "${curl_version_str}") + unset(curl_version_str) + break() + endif() + endforeach() +endif() + +# handle the QUIETLY and REQUIRED arguments and set CURL_FOUND to TRUE if +# all listed variables are TRUE +include(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(CURL + REQUIRED_VARS CURL_LIBRARY CURL_INCLUDE_DIR + VERSION_VAR CURL_VERSION_STRING) + +if(CURL_FOUND) + set(CURL_LIBRARIES ${CURL_LIBRARY}) + set(CURL_INCLUDE_DIRS ${CURL_INCLUDE_DIR}) +endif() diff --git a/cmake/Modules/FindJsoncpp.cmake b/cmake/Modules/FindJsoncpp.cmake new file mode 100644 index 000000000..acde7b95b --- /dev/null +++ b/cmake/Modules/FindJsoncpp.cmake @@ -0,0 +1,47 @@ +# Find jsoncpp +# +# Find the jsoncpp includes and library +# +# if you nee to add a custom library search path, do it via via CMAKE_PREFIX_PATH +# +# This module defines +# JSONCPP_INCLUDE_DIRS, where to find header, etc. +# JSONCPP_LIBRARIES, the libraries needed to use jsoncpp. +# JSONCPP_FOUND, If false, do not try to use jsoncpp. +# JSONCPP_INCLUDE_PREFIX, include prefix for jsoncpp + +# only look in default directories +find_path( + JSONCPP_INCLUDE_DIR + NAMES jsoncpp/json/json.h json/json.h + DOC "jsoncpp include dir" +) + +find_library( + JSONCPP_LIBRARY + NAMES jsoncpp + DOC "jsoncpp library" +) + +set(JSONCPP_INCLUDE_DIRS ${JSONCPP_INCLUDE_DIR}) +set(JSONCPP_LIBRARIES ${JSONCPP_LIBRARY}) + +# find JSONCPP_INCLUDE_PREFIX +find_path( + JSONCPP_INCLUDE_PREFIX + NAMES json.h + PATH_SUFFIXES jsoncpp/json json +) + +if (${JSONCPP_INCLUDE_PREFIX} MATCHES "jsoncpp") + set(JSONCPP_INCLUDE_PREFIX "jsoncpp/json") +else() + set(JSONCPP_INCLUDE_PREFIX "json") +endif() + +# handle the QUIETLY and REQUIRED arguments and set JSONCPP_FOUND to TRUE +# if all listed variables are TRUE, hide their existence from configuration view +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(jsoncpp DEFAULT_MSG + JSONCPP_INCLUDE_DIR JSONCPP_LIBRARY) +mark_as_advanced (JSONCPP_INCLUDE_DIR JSONCPP_LIBRARY)
\ No newline at end of file diff --git a/cmake/Modules/Packager.cmake b/cmake/Modules/Packager.cmake index b19145025..b4849963d 100644 --- a/cmake/Modules/Packager.cmake +++ b/cmake/Modules/Packager.cmake @@ -19,7 +19,23 @@ set(CONTACT "hicn-dev@lists.fd.io" CACHE STRING "Contact") set(PACKAGE_MAINTAINER "ICN Team" CACHE STRING "Maintainer") set(PACKAGE_VENDOR "fd.io" CACHE STRING "Vendor") -# macro(set) +function(get_next_version VERSION NEXT_VERSION) + string(REGEX REPLACE "([0-9]+).([0-9]+)" "\\1;\\2" VER_NUMBERS ${VERSION}) + + # Increment version for getting next version value + list(GET VER_NUMBERS 0 major) + list(GET VER_NUMBERS 1 minor) + + math(EXPR minor "${minor} + 3") + + if (minor GREATER 12) + set(minor "1") + math(EXPR major "${major} + 1") + endif() + + set(minor "0${minor}") + set(${NEXT_VERSION} "${major}.${minor}" PARENT_SCOPE) +endfunction() macro(make_packages) if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") @@ -68,6 +84,8 @@ macro(make_packages) set(rpm_ver "${tag}-${commit_num}-release") endif() + get_next_version(${tag}, next_version) + get_cmake_property(components COMPONENTS) if(OS_ID_LIKE MATCHES "debian") @@ -92,6 +110,7 @@ macro(make_packages) set(DEB_DEPS) if (NOT ${${lc}_DEB_DEPENDENCIES} STREQUAL "") string(REPLACE "stable_version" ${tag} DEB_DEPS ${${lc}_DEB_DEPENDENCIES}) + string(REPLACE "next_version" ${next_version} DEB_DEPS ${DEB_DEPS}) endif() set(CPACK_${type}_${uc}_PACKAGE_DEPENDS "${DEB_DEPS}") @@ -120,6 +139,7 @@ macro(make_packages) set(RPM_DEPS) if (NOT ${${lc}_DEB_DEPENDENCIES} STREQUAL "") string(REPLACE "stable_version" ${tag} RPM_DEPS ${${lc}_RPM_DEPENDENCIES}) + string(REPLACE "next_version" ${next_version} RPM_DEPS ${RPM_DEPS}) endif() set(CPACK_${type}_${uc}_PACKAGE_REQUIRES "${RPM_DEPS}") diff --git a/hicn-plugin/cmake/Modules/Packaging.cmake b/hicn-plugin/cmake/Modules/Packaging.cmake index 9ba34aeca..98996981f 100644 --- a/hicn-plugin/cmake/Modules/Packaging.cmake +++ b/hicn-plugin/cmake/Modules/Packaging.cmake @@ -21,11 +21,11 @@ set(${HICN_PLUGIN}_DESCRIPTION ) set(${HICN_PLUGIN}_DEB_DEPENDENCIES - "vpp (= stable_version-release), vpp-plugins (= stable_version-release)" + "vpp (>= stable_version-release), vpp (< next_version-release), vpp-plugins (>= stable_version-release), vpp-plugins (< next_version-release)" CACHE STRING "Dependencies for deb/rpm package." ) set(${HICN_PLUGIN}_RPM_DEPENDENCIES - "vpp = stable_version-release, vpp-plugins = stable_version-release" + "vpp >= stable_version-release, vpp < next_version-release, vpp-plugins >= stable_version-release, vpp-plugins < next_version-release" CACHE STRING "Dependencies for deb/rpm package." ) diff --git a/libtransport/.clang-format b/libtransport/.clang-format new file mode 100644 index 000000000..513da4d69 --- /dev/null +++ b/libtransport/.clang-format @@ -0,0 +1,14 @@ +# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +BasedOnStyle: Google
\ No newline at end of file diff --git a/libtransport/cmake/Modules/Packaging.cmake b/libtransport/cmake/Modules/Packaging.cmake index 4112d3844..99dccbec4 100644 --- a/libtransport/cmake/Modules/Packaging.cmake +++ b/libtransport/cmake/Modules/Packaging.cmake @@ -32,22 +32,22 @@ set(lib${LIBTRANSPORT}-devel_DESCRIPTION ${lib${LIBTRANSPORT}_DESCRIPTION} if ((BUILD_MEMIF_CONNECTOR OR BUILD_HICNPLUGIN) AND "${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") set(lib${LIBTRANSPORT}_DEB_DEPENDENCIES - "lib${LIBHICN} (>= stable_version), libparc (>= 1.0), vpp-lib (= stable_version-release)" + "lib${LIBHICN} (>= stable_version), libparc (>= 1.0), vpp-lib (>= stable_version-release), vpp-lib (< next_version-release)" CACHE STRING "Dependencies for deb/rpm package." ) set(lib${LIBTRANSPORT}_RPM_DEPENDENCIES - "lib${LIBHICN} >= stable_version, libparc >= 1.0, vpp-lib = stable_version-release" + "lib${LIBHICN} >= stable_version, libparc >= 1.0, vpp-lib >= stable_version-release, vpp-lib < next_version-release" CACHE STRING "Dependencies for deb/rpm package." ) set(lib${LIBTRANSPORT}-dev_DEB_DEPENDENCIES - "lib${LIBTRANSPORT} (>= stable_version), libasio-dev (>= 1.10), libhicn-dev (>= stable_version), libparc-dev (>= 1.0), vpp-dev (= stable_version-release)" + "lib${LIBTRANSPORT} (>= stable_version), libasio-dev (>= 1.10), libhicn-dev (>= stable_version), libparc-dev (>= 1.0), vpp-dev (>= stable_version-release), vpp-dev (< next_version-release)" CACHE STRING "Dependencies for deb/rpm package." ) set(lib${LIBTRANSPORT}-dev_RPM_DEPENDENCIES - "lib${LIBTRANSPORT} >= stable_version, asio-devel >= 1.10, lib${LIBHICN}-devel >= stable_version, libparc-devel >= 1.0, vpp-devel = stable_version-release" + "lib${LIBTRANSPORT} >= stable_version, asio-devel >= 1.10, lib${LIBHICN}-devel >= stable_version, libparc-devel >= 1.0, vpp-devel >= stable_version-release, vpp-devel < next_version-release" CACHE STRING "Dependencies for deb/rpm package." ) diff --git a/libtransport/format_all.sh b/libtransport/format_all.sh new file mode 100644 index 000000000..0591413e0 --- /dev/null +++ b/libtransport/format_all.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -xue + +SCRIPT_PATH=$( cd "$(dirname "${BASH_SOURCE}")" ; pwd -P ) + +pushd ${SCRIPT_PATH} +find src/ -type f '(' -name '*.c' -o -name '*.cc' -o -name '*.h' ')' -exec clang-format -style=file -i {} \; +popd
\ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/portal.h b/libtransport/src/hicn/transport/core/portal.h index d9051c23c..07f84075e 100644 --- a/libtransport/src/hicn/transport/core/portal.h +++ b/libtransport/src/hicn/transport/core/portal.h @@ -407,7 +407,9 @@ class Portal { } } - TRANSPORT_ALWAYS_INLINE void killConnection() { connector_.close(); } + TRANSPORT_ALWAYS_INLINE void killConnection() { + forwarder_interface_.closeConnection(); + } TRANSPORT_ALWAYS_INLINE void clear() { for (auto &pend_interest : pending_interest_hash_table_) { diff --git a/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.cc b/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.cc index c07ca7989..87cf27b75 100644 --- a/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.cc +++ b/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.cc @@ -74,22 +74,22 @@ RTCProducerSocket::RTCProducerSocket() RTCProducerSocket::~RTCProducerSocket() {} -void RTCProducerSocket::registerName(Prefix &producer_namespace) { +void RTCProducerSocket::registerPrefix(const Prefix &producer_namespace) { ProducerSocket::registerPrefix(producer_namespace); flowName_ = producer_namespace.getName(); - - if (flowName_.getType() == HNT_CONTIGUOUS_V4 || - flowName_.getType() == HNT_IOV_V4) { - headerSize_ = sizeof(hicn_v6_hdr_t::ip); - } else if (flowName_.getType() == HNT_CONTIGUOUS_V6 || - flowName_.getType() == HNT_IOV_V6) { - headerSize_ = sizeof(hicn_v4_hdr_t::ip); - } else { - throw errors::RuntimeException("Unknown name format."); + auto family = flowName_.getAddressFamily(); + + switch (family) { + case AF_INET6: + headerSize_ = (uint32_t)Packet::getHeaderSizeFromFormat(HF_INET6_TCP); + break; + case AF_INET: + headerSize_ = (uint32_t)Packet::getHeaderSizeFromFormat(HF_INET_TCP); + break; + default: + throw errors::RuntimeException("Unknown name format."); } - - headerSize_ += TCP_HEADER_SIZE; } void RTCProducerSocket::updateStats(uint32_t packet_size) { diff --git a/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.h b/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.h index f1bcaa9e8..bc54be4bb 100644 --- a/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.h +++ b/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.h @@ -33,9 +33,9 @@ class RTCProducerSocket : public ProducerSocket { ~RTCProducerSocket(); - void registerName(Prefix &producer_namespace); + void registerPrefix(const Prefix &producer_namespace) override; - void produce(const uint8_t *buffer, size_t buffer_size); + void produce(const uint8_t *buffer, size_t buffer_size) override; void onInterest(Interest::Ptr &&interest) override; diff --git a/libtransport/src/hicn/transport/interfaces/socket_options_default_values.h b/libtransport/src/hicn/transport/interfaces/socket_options_default_values.h index 046fea892..13029e83a 100644 --- a/libtransport/src/hicn/transport/interfaces/socket_options_default_values.h +++ b/libtransport/src/hicn/transport/interfaces/socket_options_default_values.h @@ -61,8 +61,8 @@ static constexpr uint32_t rate_choice = 0; static constexpr uint32_t transport_protocol_min_retransmissions = 0; static constexpr uint32_t transport_protocol_max_retransmissions = 128; static constexpr uint32_t max_content_object_size = 8096; -static constexpr uint32_t min_window_size = 1; // Interests -static constexpr uint32_t max_window_size = 256 * 2; // Interests +static constexpr uint32_t min_window_size = 1; // Interests +static constexpr uint32_t max_window_size = 256 * 2; // Interests } // namespace default_values diff --git a/libtransport/src/hicn/transport/interfaces/socket_producer.h b/libtransport/src/hicn/transport/interfaces/socket_producer.h index d3738dc59..6ba5671cc 100644 --- a/libtransport/src/hicn/transport/interfaces/socket_producer.h +++ b/libtransport/src/hicn/transport/interfaces/socket_producer.h @@ -51,13 +51,19 @@ class ProducerSocket : public Socket<BasePortal>, void produce(ContentObject &content_object); + virtual void produce(const uint8_t *buffer, size_t buffer_size) { + // This API is meant to be used just with the RTC producer. + // Here it cannot be used since no name for the content is specified. + throw errors::NotImplementedException(); + } + void asyncProduce(const Name &suffix, const uint8_t *buf, size_t buffer_size); void asyncProduce(const Name &suffix, ContentBuffer &&output_buffer); void asyncProduce(ContentObject &content_object); - void registerPrefix(const Prefix &producer_namespace); + virtual void registerPrefix(const Prefix &producer_namespace); void serveForever(); diff --git a/libtransport/src/hicn/transport/utils/fd_deadline_timer.h b/libtransport/src/hicn/transport/utils/fd_deadline_timer.h index 6fb823a05..1c14513c9 100644 --- a/libtransport/src/hicn/transport/utils/fd_deadline_timer.h +++ b/libtransport/src/hicn/transport/utils/fd_deadline_timer.h @@ -53,7 +53,8 @@ class FdDeadlineTimer : public DeadlineTimer<FdDeadlineTimer> { reactor_.addFileDescriptor( timer_fd_, events, - [callback = std::forward<WaitHandler &&>(callback)](const Event &event) -> int { + [callback = std::forward<WaitHandler &&>(callback)]( + const Event &event) -> int { uint64_t s = 0; std::error_code ec; diff --git a/pom.xml b/pom.xml deleted file mode 100644 index 63d26cc80..000000000 --- a/pom.xml +++ /dev/null @@ -1,43 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - Copyright (c) 2019 Cisco and/or its affiliates. - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at: - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - - <parent> - <groupId>io.fd.hicn.common</groupId> - <artifactId>hicn-parent</artifactId> - <version>1.19.01-SNAPSHOT</version> - <relativePath>common/hicn-parent</relativePath> - </parent> - - <groupId>io.fd.hicn</groupId> - <artifactId>hicn-aggregator</artifactId> - <version>1.19.01-SNAPSHOT</version> - <name>hicn</name> - <packaging>pom</packaging> - <modelVersion>4.0.0</modelVersion> - - <description>hicn project root aggregator</description> - - <scm> - <url>https://git.fd.io/hicn/tree/</url> - </scm> - - <modules> - <module>lib</module> - <module>hicn-light</module> - <module>hicn-plugin</module> - <module>libtransport</module> - </modules> -</project>
\ No newline at end of file diff --git a/scripts/build-packages.sh b/scripts/build-packages.sh index 67adb39e9..ed8a95a55 100644 --- a/scripts/build-packages.sh +++ b/scripts/build-packages.sh @@ -24,15 +24,15 @@ PACKAGECLOUD_RELEASE_REPO_RPM="https://packagecloud.io/install/repositories/fdio VPP_GIT_REPO="https://git.fd.io/vpp" VPP_BRANCH="stable/1901" -VPP_VERSION_DEB="19.01-release" -VPP_VERSION_RPM="19.01-release.x86_64" +VPP_VERSION_DEB="19.01.1-release" +VPP_VERSION_RPM="19.01.1-release.x86_64" BUILD_TOOLS_UBUNTU="build-essential doxygen" LIBSSL_LIBEVENT_UBUNTU="libevent-dev libssl-dev" -DEPS_UBUNTU="libparc-dev libasio-dev vpp-dev=${VPP_VERSION_DEB} vpp-lib=${VPP_VERSION_DEB}" +DEPS_UBUNTU="libparc-dev libasio-dev libcurl4-openssl-dev vpp-dev=${VPP_VERSION_DEB} vpp-lib=${VPP_VERSION_DEB}" # BUILD_TOOLS_GROUP_CENTOS="'Development Tools'" -DEPS_CENTOS="vpp-devel-${VPP_VERSION_RPM} vpp-lib-${VPP_VERSION_RPM} libparc-devel asio-devel centos-release-scl devtoolset-7" +DEPS_CENTOS="vpp-devel-${VPP_VERSION_RPM} vpp-lib-${VPP_VERSION_RPM} libparc-devel libcurl-devel asio-devel centos-release-scl devtoolset-7" LATEST_EPEL_REPO="http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm" install_cmake() { @@ -112,7 +112,6 @@ setup() { # echo ${BUILD_TOOLS_GROUP_CENTOS} | xargs sudo yum groupinstall -y --nogpgcheck echo ${DEPS_CENTOS} | xargs sudo yum install -y --nogpgcheck sudo yum install devtoolset-7 - scl enable devtoolset-7 bash c++ --version diff --git a/utils/src/hiperf.cc b/utils/src/hiperf.cc index 860e7a000..e10907ccc 100644 --- a/utils/src/hiperf.cc +++ b/utils/src/hiperf.cc @@ -13,6 +13,7 @@ * limitations under the License. */ +#include <hicn/transport/interfaces/rtc_socket_producer.h> #include <hicn/transport/interfaces/socket_consumer.h> #include <hicn/transport/interfaces/socket_producer.h> #ifndef _WIN32 @@ -71,6 +72,41 @@ struct ClientConfiguration { bool rtc_; }; +class Rate { + public: + Rate() : rate_kbps_(0) {} + + Rate(const std::string &rate) { + std::size_t found = rate.find("kbps"); + if (found != std::string::npos) { + rate_kbps_ = std::stof(rate.substr(0, found)); + } else { + throw std::runtime_error("Format " + rate + " not correct"); + } + } + + Rate(const Rate &other) : rate_kbps_(other.rate_kbps_) {} + + Rate &operator=(const std::string &rate) { + std::size_t found = rate.find("kbps"); + if (found != std::string::npos) { + rate_kbps_ = std::stof(rate.substr(0, found)); + } else { + throw std::runtime_error("Format " + rate + " not correct"); + } + + return *this; + } + + std::chrono::microseconds getMicrosecondsForPacket(std::size_t packet_size) { + return std::chrono::microseconds( + packet_size * long(std::round(1000.0 * 8.0 / rate_kbps_))); + } + + private: + float rate_kbps_; +}; + struct ServerConfiguration { ServerConfiguration() : name("b001::abcd/64"), @@ -84,7 +120,10 @@ struct ServerConfiguration { hash_algorithm(HashAlgorithm::SHA_256), keystore_name("/tmp/rsa_crypto_material.p12"), keystore_password("cisco"), - multiphase_produce_(false) {} + multiphase_produce_(false), + rtc_(false), + production_rate_(std::string("2048kbps")), + payload_size_(1400) {} Prefix name; bool virtual_producer; @@ -98,6 +137,9 @@ struct ServerConfiguration { std::string keystore_name; std::string keystore_password; bool multiphase_produce_; + bool rtc_; + Rate production_rate_; + std::size_t payload_size_; }; class HIperfClient { @@ -338,10 +380,11 @@ class HIperfServer { HIperfServer(ServerConfiguration &conf) : configuration_(conf), signals_(io_service_, SIGINT), + rtc_timer_(io_service_), content_objects_((std::uint16_t)(1 << log2_content_object_buffer_size)), content_objects_index_(0), mask_((std::uint16_t)(1 << log2_content_object_buffer_size) - 1) { - std::string buffer(1440, 'X'); + std::string buffer(configuration_.payload_size_, 'X'); std::cout << "Producing contents under name " << conf.name.getName() << std::endl; @@ -357,16 +400,6 @@ class HIperfServer { void processInterest(ProducerSocket &p, const Interest &interest) { content_objects_[content_objects_index_ & mask_]->setName( interest.getName()); - - // if (final_chunk_number_ > 0 && interest.getName().getSuffix() == 0) { - // auto name = interest.getName(); - // manifest_ = std::make_shared<ContentObjectManifest>(name); - // // manifest_->setFinalChunkNumber(final_chunk_number_); - // manifest_->encode(); - // p.produce(*manifest_); - // return; - // } - producer_socket_->produce( *content_objects_[content_objects_index_++ & mask_]); } @@ -414,7 +447,11 @@ class HIperfServer { int setup() { int ret; - producer_socket_ = std::make_unique<ProducerSocket>(); + if (configuration_.rtc_) { + producer_socket_ = std::make_unique<RTCProducerSocket>(); + } else { + producer_socket_ = std::make_unique<ProducerSocket>(); + } if (configuration_.sign) { auto identity = setProducerIdentity(configuration_.keystore_name, @@ -431,6 +468,13 @@ class HIperfServer { producer_socket_->registerPrefix(configuration_.name); producer_socket_->connect(); + if (configuration_.rtc_) { + std::cout << "Running RTC producer: all other options (with the " + "exception of the bitrate) will be ignored." + << std::endl; + return ERROR_SUCCESS; + } + if (!configuration_.virtual_producer) { if (producer_socket_->setSocketOption( GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME, @@ -485,6 +529,20 @@ class HIperfServer { return ERROR_SUCCESS; } + void sendRTCContentObjectCallback(std::error_code ec) { + if (!ec) { + auto payload = + content_objects_[content_objects_index_++ & mask_]->getPayload(); + producer_socket_->produce(payload.data(), payload.length()); + rtc_timer_.expires_from_now( + configuration_.production_rate_.getMicrosecondsForPacket( + configuration_.payload_size_)); + rtc_timer_.async_wait( + std::bind(&HIperfServer::sendRTCContentObjectCallback, this, + std::placeholders::_1)); + } + } + int run() { std::cerr << "Starting to serve consumers" << std::endl; @@ -494,6 +552,15 @@ class HIperfServer { io_service_.stop(); }); + if (configuration_.rtc_) { + rtc_timer_.expires_from_now( + configuration_.production_rate_.getMicrosecondsForPacket( + configuration_.payload_size_)); + rtc_timer_.async_wait( + std::bind(&HIperfServer::sendRTCContentObjectCallback, this, + std::placeholders::_1)); + } + io_service_.run(); return ERROR_SUCCESS; @@ -503,6 +570,7 @@ class HIperfServer { ServerConfiguration configuration_; asio::io_service io_service_; asio::signal_set signals_; + asio::steady_timer rtc_timer_; std::vector<std::shared_ptr<ContentObject>> content_objects_; std::uint16_t content_objects_index_; std::uint16_t mask_; @@ -519,10 +587,17 @@ void usage() { #ifndef _WIN32 std::cerr << "-D\t\t\t\t\t" << "Run as a daemon" << std::endl; + std::cerr << "-R\t\t\t\t\t" + << "Run RTC protocol (client or server)" << std::endl; + std::cerr << "-f\t<filename>\t\t\t" + << "Log file" << std::endl; #endif std::cerr << std::endl; std::cerr << "Server specific:" << std::endl; - std::cerr << "-s\t<content_size>\t\t\tSize of the content to publish" + std::cerr << "-A\t<download_size>\t\t\tSize of the content to publish. This " + "is not the size of the packet (see -s for it)." + << std::endl; + std::cerr << "-s\t<packet_size>\t\t\tSize of the payload of each data packet." << std::endl; std::cerr << "-r\t\t\t\t\t" << "Produce real content of content_size bytes" << std::endl; @@ -542,6 +617,15 @@ void usage() { << std::endl; std::cerr << "-p\t<password>\t\t\t" << "Password for p12 keystore" << std::endl; + std::cerr << "-x\t\t\t\t\t" + << "Produce a content of <download_size>, then after downloading " + "it produce a new content of" + << std::endl + << "\t\t\t\t\t<download_size> without resetting " + "the suffix to 0." + << std::endl; + std::cerr << "-B\t<bitrate>\t\t\t" + << "Bitrate for RTC producer, to be used with the -R option." << std::endl; std::cerr << std::endl; std::cerr << "Client specific:" << std::endl; std::cerr << "-b\t<beta_parameter>\t\t" @@ -561,6 +645,9 @@ void usage() { "to be used for verifying the " "origin of the packets received" << std::endl; + std::cerr << "-i\t<stats_interval>\t\t" + << "Show the statistics every <stats_interval> milliseconds." + << std::endl; std::cout << "-v\t\t\t\t\t" << "Enable verification of received data" << std::endl; } @@ -588,84 +675,109 @@ int main(int argc, char *argv[]) { int opt; #ifndef _WIN32 - while ((opt = getopt(argc, argv, "DSCf:b:d:W:RMc:vs:rmlk:y:p:hi:x")) != -1) { + while ((opt = getopt(argc, argv, "DSCf:b:d:W:RMc:vA:s:rmlk:y:p:hi:xB:")) != + -1) { switch (opt) { // Common - case 'D': + case 'D': { daemon = true; break; + } #else - while ((opt = getopt(argc, argv, "SCf:b:d:W:RMc:vs:rmlk:y:p:hi:x")) != -1) { + while ((opt = getopt(argc, argv, "SCf:b:d:W:RMc:vA:s:rmlk:y:p:hi:xB:")) != + -1) { switch (opt) { #endif - case 'f': + case 'f': { log_file = optarg; break; + } + case 'R': { + client_configuration.rtc_ = true; + server_configuration.rtc_ = true; + break; + } // Server or Client - case 'S': + case 'S': { role -= 1; break; - case 'C': + } + case 'C': { role += 1; break; + } // Client specifc - case 'b': + case 'b': { client_configuration.beta = std::stod(optarg); options = 1; break; - case 'd': + } + case 'd': { client_configuration.drop_factor = std::stod(optarg); options = 1; break; - case 'W': + } + case 'W': { client_configuration.window = std::stod(optarg); options = 1; break; - case 'M': + } + case 'M': { client_configuration.virtual_download = false; options = 1; break; - case 'c': + } + case 'c': { client_configuration.producer_certificate = std::string(optarg); options = 1; break; - case 'v': + } + case 'v': { client_configuration.verify = true; options = 1; break; - case 'i': + } + case 'i': { client_configuration.report_interval_milliseconds_ = std::stoul(optarg); options = 1; break; - case 'R': - client_configuration.rtc_ = true; - break; + } // Server specific - case 's': + case 'A': { server_configuration.download_size = std::stoul(optarg); options = -1; break; - case 'r': + } + case 's': { + server_configuration.payload_size_ = std::stoul(optarg); + options = -1; + break; + } + case 'r': { server_configuration.virtual_producer = false; options = -1; break; - case 'm': + } + case 'm': { server_configuration.manifest = true; options = -1; break; - case 'l': + } + case 'l': { server_configuration.live_production = true; options = -1; break; - case 'k': + } + case 'k': { server_configuration.keystore_name = std::string(optarg); server_configuration.sign = true; options = -1; break; - case 'y': + } + case 'y': { if (strncasecmp(optarg, "sha256", 6) == 0) { server_configuration.hash_algorithm = HashAlgorithm::SHA_256; } else if (strncasecmp(optarg, "sha512", 6) == 0) { @@ -678,14 +790,27 @@ int main(int argc, char *argv[]) { } options = -1; break; - case 'p': + } + case 'p': { server_configuration.keystore_password = std::string(optarg); options = -1; break; - case 'x': + } + case 'x': { server_configuration.multiphase_produce_ = true; options = -1; break; + } + case 'B': { + auto str = std::string(optarg); + std::transform(str.begin(), str.end(), str.begin(), ::tolower); + std::cout << "---------------------------------------------------------" + "---------------------->" + << str << std::endl; + server_configuration.production_rate_ = str; + options = -1; + break; + } case 'h': default: usage(); |