From f4433f28b509a9f67ca85d79000ccf9c2f4b7a24 Mon Sep 17 00:00:00 2001 From: Mauro Sardara Date: Fri, 21 Feb 2020 11:52:28 +0100 Subject: [HICN-534] Major rework on libtransport organization Change-Id: I361b83a18b4fd59be136d5f0817fc28e17e89884 Signed-off-by: Mauro Sardara --- apps/higet/higet.cc | 5 +- apps/http-proxy/src/IcnReceiver.cc | 2 + libtransport/CMakeLists.txt | 3 +- .../includes/hicn/transport/CMakeLists.txt | 38 + .../includes/hicn/transport/core/CMakeLists.txt | 25 + .../includes/hicn/transport/core/content_object.h | 77 ++ .../includes/hicn/transport/core/interest.h | 71 + libtransport/includes/hicn/transport/core/name.h | 142 ++ libtransport/includes/hicn/transport/core/packet.h | 203 +++ .../includes/hicn/transport/core/payload_type.h | 29 + libtransport/includes/hicn/transport/core/prefix.h | 80 ++ .../includes/hicn/transport/errors/CMakeLists.txt | 30 + .../includes/hicn/transport/errors/errors.h | 24 + .../hicn/transport/errors/indexing_exception.h | 31 + .../errors/invalid_ip_address_exception.h | 31 + .../errors/malformed_ahpacket_exception.h | 31 + .../transport/errors/malformed_name_exception.h | 31 + .../transport/errors/malformed_packet_exception.h | 29 + .../transport/errors/not_implemented_exception.h | 30 + .../hicn/transport/errors/null_pointer_exception.h | 31 + .../hicn/transport/errors/runtime_exception.h | 32 + .../hicn/transport/errors/tokenizer_exception.h | 31 + .../errors/unexpected_manifest_exception.h | 31 + .../includes/hicn/transport/http/CMakeLists.txt | 25 + .../hicn/transport/http/client_connection.h | 80 ++ .../includes/hicn/transport/http/default_values.h | 32 + libtransport/includes/hicn/transport/http/facade.h | 20 + .../includes/hicn/transport/http/message.h | 70 + .../includes/hicn/transport/http/request.h | 56 + .../includes/hicn/transport/http/response.h | 58 + .../hicn/transport/interfaces/CMakeLists.txt | 35 + .../includes/hicn/transport/interfaces/callbacks.h | 116 ++ .../interfaces/p2psecure_socket_consumer.h | 32 + .../interfaces/p2psecure_socket_producer.h | 36 + .../transport/interfaces/publication_options.h | 43 + .../transport/interfaces/rtc_socket_producer.h | 32 + .../hicn/transport/interfaces/socket_consumer.h | 298 +++++ .../interfaces/socket_options_default_values.h | 69 + .../transport/interfaces/socket_options_keys.h | 118 ++ .../hicn/transport/interfaces/socket_producer.h | 149 +++ .../hicn/transport/interfaces/statistics.h | 121 ++ .../transport/interfaces/verification_policy.h | 33 + .../hicn/transport/portability/CMakeLists.txt | 31 + .../hicn/transport/portability/c_portability.h | 36 + .../hicn/transport/portability/portability.h | 50 + .../hicn/transport/portability/win_portability.h | 42 + .../hicn/transport/security/CMakeLists.txt | 27 + .../includes/hicn/transport/security/crypto_hash.h | 119 ++ .../hicn/transport/security/crypto_hash_type.h | 31 + .../hicn/transport/security/crypto_hasher.h | 68 + .../hicn/transport/security/crypto_suite.h | 36 + .../includes/hicn/transport/security/identity.h | 63 + .../includes/hicn/transport/security/key_id.h | 25 + .../includes/hicn/transport/security/signer.h | 90 ++ .../includes/hicn/transport/security/verifier.h | 103 ++ .../includes/hicn/transport/utils/CMakeLists.txt | 39 + libtransport/includes/hicn/transport/utils/array.h | 62 + .../hicn/transport/utils/branch_prediction.h | 27 + .../hicn/transport/utils/chrono_typedefs.h | 27 + .../includes/hicn/transport/utils/conversions.h | 37 + .../includes/hicn/transport/utils/daemonizator.h | 30 + libtransport/includes/hicn/transport/utils/hash.h | 101 ++ libtransport/includes/hicn/transport/utils/linux.h | 64 + .../includes/hicn/transport/utils/literals.h | 55 + libtransport/includes/hicn/transport/utils/log.h | 1057 +++++++++++++++ .../includes/hicn/transport/utils/membuf.h | 921 +++++++++++++ .../includes/hicn/transport/utils/object_pool.h | 90 ++ .../includes/hicn/transport/utils/ring_buffer.h | 129 ++ .../includes/hicn/transport/utils/spinlock.h | 53 + .../hicn/transport/utils/string_tokenizer.h | 35 + libtransport/includes/hicn/transport/utils/uri.h | 47 + libtransport/src/CMakeLists.txt | 92 ++ libtransport/src/config.h.in | 34 + libtransport/src/core/CMakeLists.txt | 76 ++ libtransport/src/core/connector.cc | 51 + libtransport/src/core/connector.h | 109 ++ libtransport/src/core/content_object.cc | 201 +++ libtransport/src/core/facade.h | 53 + libtransport/src/core/forwarder_interface.h | 147 ++ libtransport/src/core/hicn_forwarder_interface.cc | 135 ++ libtransport/src/core/hicn_forwarder_interface.h | 86 ++ libtransport/src/core/hicn_vapi.c | 216 +++ libtransport/src/core/hicn_vapi.h | 86 ++ libtransport/src/core/interest.cc | 166 +++ libtransport/src/core/manifest.cc | 33 + libtransport/src/core/manifest.h | 150 +++ libtransport/src/core/manifest_format.h | 210 +++ libtransport/src/core/manifest_format_fixed.cc | 227 ++++ libtransport/src/core/manifest_format_fixed.h | 172 +++ libtransport/src/core/manifest_inline.h | 115 ++ libtransport/src/core/memif_connector.cc | 494 +++++++ libtransport/src/core/memif_connector.h | 134 ++ libtransport/src/core/memif_vapi.c | 133 ++ libtransport/src/core/memif_vapi.h | 60 + libtransport/src/core/name.cc | 231 ++++ libtransport/src/core/packet.cc | 607 +++++++++ libtransport/src/core/pending_interest.cc | 74 ++ libtransport/src/core/pending_interest.h | 93 ++ libtransport/src/core/portal.h | 696 ++++++++++ libtransport/src/core/prefix.cc | 338 +++++ libtransport/src/core/raw_socket_connector.cc | 203 +++ libtransport/src/core/raw_socket_connector.h | 81 ++ libtransport/src/core/raw_socket_interface.cc | 57 + libtransport/src/core/raw_socket_interface.h | 62 + libtransport/src/core/tcp_socket_connector.cc | 282 ++++ libtransport/src/core/tcp_socket_connector.h | 87 ++ libtransport/src/core/test/CMakeLists.txt | 10 + libtransport/src/core/test/test_core_manifest.cc | 296 +++++ libtransport/src/core/udp_socket_connector.cc | 224 ++++ libtransport/src/core/udp_socket_connector.h | 85 ++ libtransport/src/core/vpp_forwarder_interface.cc | 213 +++ libtransport/src/core/vpp_forwarder_interface.h | 88 ++ libtransport/src/hicn/transport/CMakeLists.txt | 92 -- libtransport/src/hicn/transport/config.h.in | 34 - .../src/hicn/transport/core/CMakeLists.txt | 82 -- libtransport/src/hicn/transport/core/connector.cc | 51 - libtransport/src/hicn/transport/core/connector.h | 109 -- .../src/hicn/transport/core/content_object.cc | 201 --- .../src/hicn/transport/core/content_object.h | 77 -- libtransport/src/hicn/transport/core/facade.h | 53 - .../src/hicn/transport/core/forwarder_interface.h | 149 --- .../transport/core/hicn_forwarder_interface.cc | 135 -- .../hicn/transport/core/hicn_forwarder_interface.h | 85 -- libtransport/src/hicn/transport/core/hicn_vapi.c | 224 ---- libtransport/src/hicn/transport/core/hicn_vapi.h | 86 -- libtransport/src/hicn/transport/core/interest.cc | 166 --- libtransport/src/hicn/transport/core/interest.h | 72 - libtransport/src/hicn/transport/core/manifest.cc | 33 - libtransport/src/hicn/transport/core/manifest.h | 149 --- .../src/hicn/transport/core/manifest_format.h | 210 --- .../hicn/transport/core/manifest_format_fixed.cc | 226 ---- .../hicn/transport/core/manifest_format_fixed.h | 171 --- .../src/hicn/transport/core/manifest_inline.h | 114 -- .../src/hicn/transport/core/memif_connector.cc | 493 ------- .../src/hicn/transport/core/memif_connector.h | 133 -- libtransport/src/hicn/transport/core/memif_vapi.c | 144 -- libtransport/src/hicn/transport/core/memif_vapi.h | 60 - libtransport/src/hicn/transport/core/name.cc | 230 ---- libtransport/src/hicn/transport/core/name.h | 142 -- libtransport/src/hicn/transport/core/packet.cc | 607 --------- libtransport/src/hicn/transport/core/packet.h | 203 --- .../src/hicn/transport/core/payload_type.h | 29 - .../src/hicn/transport/core/pending_interest.cc | 74 -- .../src/hicn/transport/core/pending_interest.h | 92 -- libtransport/src/hicn/transport/core/portal.h | 695 ---------- libtransport/src/hicn/transport/core/prefix.cc | 338 ----- libtransport/src/hicn/transport/core/prefix.h | 79 -- .../hicn/transport/core/raw_socket_connector.cc | 202 --- .../src/hicn/transport/core/raw_socket_connector.h | 80 -- .../hicn/transport/core/raw_socket_interface.cc | 56 - .../src/hicn/transport/core/raw_socket_interface.h | 61 - .../hicn/transport/core/tcp_socket_connector.cc | 281 ---- .../src/hicn/transport/core/tcp_socket_connector.h | 86 -- .../src/hicn/transport/core/test/CMakeLists.txt | 10 - .../hicn/transport/core/test/test_core_manifest.cc | 296 ----- .../hicn/transport/core/udp_socket_connector.cc | 222 ---- .../src/hicn/transport/core/udp_socket_connector.h | 84 -- .../hicn/transport/core/vpp_forwarder_interface.cc | 220 --- .../hicn/transport/core/vpp_forwarder_interface.h | 87 -- .../src/hicn/transport/errors/CMakeLists.txt | 31 - libtransport/src/hicn/transport/errors/errors.h | 24 - .../src/hicn/transport/errors/indexing_exception.h | 31 - .../errors/invalid_ip_address_exception.h | 31 - .../errors/malformed_ahpacket_exception.h | 31 - .../transport/errors/malformed_name_exception.h | 31 - .../transport/errors/malformed_packet_exception.h | 29 - .../transport/errors/not_implemented_exception.h | 30 - .../hicn/transport/errors/null_pointer_exception.h | 31 - .../src/hicn/transport/errors/runtime_exception.h | 32 - .../hicn/transport/errors/tokenizer_exception.h | 31 - .../errors/unexpected_manifest_exception.h | 31 - .../src/hicn/transport/http/CMakeLists.txt | 35 - .../src/hicn/transport/http/client_connection.cc | 220 --- .../src/hicn/transport/http/client_connection.h | 121 -- .../src/hicn/transport/http/default_values.h | 32 - libtransport/src/hicn/transport/http/facade.h | 22 - libtransport/src/hicn/transport/http/message.h | 70 - libtransport/src/hicn/transport/http/request.cc | 74 -- libtransport/src/hicn/transport/http/request.h | 56 - libtransport/src/hicn/transport/http/response.cc | 138 -- libtransport/src/hicn/transport/http/response.h | 58 - .../src/hicn/transport/http/server_acceptor.cc | 110 -- .../src/hicn/transport/http/server_acceptor.h | 63 - .../src/hicn/transport/http/server_publisher.cc | 173 --- .../src/hicn/transport/http/server_publisher.h | 69 - .../src/hicn/transport/interfaces/CMakeLists.txt | 59 - .../src/hicn/transport/interfaces/callbacks.cc | 26 - .../src/hicn/transport/interfaces/callbacks.h | 125 -- .../interfaces/p2psecure_socket_consumer.cc | 382 ------ .../interfaces/p2psecure_socket_consumer.h | 147 -- .../interfaces/p2psecure_socket_producer.cc | 380 ------ .../interfaces/p2psecure_socket_producer.h | 129 -- .../transport/interfaces/publication_options.h | 43 - .../transport/interfaces/rtc_socket_producer.cc | 368 ----- .../transport/interfaces/rtc_socket_producer.h | 79 -- .../src/hicn/transport/interfaces/socket.h | 92 -- .../hicn/transport/interfaces/socket_consumer.cc | 862 ------------ .../hicn/transport/interfaces/socket_consumer.h | 412 ------ .../interfaces/socket_options_default_values.h | 69 - .../transport/interfaces/socket_options_keys.h | 113 -- .../hicn/transport/interfaces/socket_producer.cc | 909 ------------- .../hicn/transport/interfaces/socket_producer.h | 295 ---- .../interfaces/tls_rtc_socket_producer.cc | 178 --- .../transport/interfaces/tls_rtc_socket_producer.h | 58 - .../transport/interfaces/tls_socket_consumer.cc | 364 ----- .../transport/interfaces/tls_socket_consumer.h | 132 -- .../transport/interfaces/tls_socket_producer.cc | 587 -------- .../transport/interfaces/tls_socket_producer.h | 163 --- .../transport/interfaces/verification_policy.h | 33 - .../src/hicn/transport/portability/CMakeLists.txt | 32 - .../src/hicn/transport/portability/c_portability.h | 36 - .../src/hicn/transport/portability/portability.h | 50 - .../hicn/transport/portability/win_portability.h | 42 - .../src/hicn/transport/protocols/CMakeLists.txt | 77 -- .../transport/protocols/byte_stream_reassembly.cc | 121 -- .../transport/protocols/byte_stream_reassembly.h | 54 - libtransport/src/hicn/transport/protocols/cbr.cc | 51 - libtransport/src/hicn/transport/protocols/cbr.h | 40 - .../protocols/congestion_window_protocol.h | 30 - .../src/hicn/transport/protocols/consumer.conf | 21 - .../transport/protocols/data_processing_events.h | 33 - .../transport/protocols/datagram_reassembly.cc | 35 - .../hicn/transport/protocols/datagram_reassembly.h | 39 - .../hicn/transport/protocols/download_observer.h | 32 - .../src/hicn/transport/protocols/errors.cc | 60 - libtransport/src/hicn/transport/protocols/errors.h | 91 -- .../transport/protocols/incremental_indexer.cc | 52 - .../hicn/transport/protocols/incremental_indexer.h | 143 -- .../src/hicn/transport/protocols/indexer.cc | 78 -- .../src/hicn/transport/protocols/indexer.h | 106 -- .../protocols/manifest_incremental_indexer.cc | 232 ---- .../protocols/manifest_incremental_indexer.h | 91 -- .../protocols/manifest_indexing_manager.cc | 297 ----- .../src/hicn/transport/protocols/packet_manager.h | 67 - .../src/hicn/transport/protocols/protocol.cc | 105 -- .../src/hicn/transport/protocols/protocol.h | 91 -- libtransport/src/hicn/transport/protocols/raaqm.cc | 712 ---------- libtransport/src/hicn/transport/protocols/raaqm.h | 141 -- .../hicn/transport/protocols/raaqm_data_path.cc | 157 --- .../src/hicn/transport/protocols/raaqm_data_path.h | 225 ---- .../hicn/transport/protocols/rate_estimation.cc | 355 ----- .../src/hicn/transport/protocols/rate_estimation.h | 173 --- .../src/hicn/transport/protocols/reassembly.cc | 70 - .../src/hicn/transport/protocols/reassembly.h | 67 - libtransport/src/hicn/transport/protocols/rtc.cc | 1016 -------------- libtransport/src/hicn/transport/protocols/rtc.h | 227 ---- .../src/hicn/transport/protocols/rtc_data_path.cc | 160 --- .../src/hicn/transport/protocols/rtc_data_path.h | 79 -- .../src/hicn/transport/protocols/statistics.h | 113 -- .../hicn/transport/protocols/test/CMakeLists.txt | 10 - .../protocols/test/test_transport_producer.cc | 80 -- .../transport/protocols/verification_manager.cc | 96 -- .../transport/protocols/verification_manager.h | 67 - .../src/hicn/transport/utils/CMakeLists.txt | 82 -- libtransport/src/hicn/transport/utils/array.h | 62 - .../src/hicn/transport/utils/branch_prediction.h | 27 - .../src/hicn/transport/utils/chrono_typedefs.h | 27 - .../src/hicn/transport/utils/content_store.cc | 122 -- .../src/hicn/transport/utils/content_store.h | 77 -- .../src/hicn/transport/utils/conversions.h | 37 - .../src/hicn/transport/utils/crypto_hash.h | 119 -- .../src/hicn/transport/utils/crypto_hash_type.h | 31 - .../src/hicn/transport/utils/crypto_hasher.h | 68 - .../src/hicn/transport/utils/crypto_suite.h | 35 - .../src/hicn/transport/utils/daemonizator.cc | 76 -- .../src/hicn/transport/utils/daemonizator.h | 30 - .../src/hicn/transport/utils/deadline_timer.h | 114 -- .../hicn/transport/utils/epoll_event_reactor.cc | 186 --- .../src/hicn/transport/utils/epoll_event_reactor.h | 80 -- .../src/hicn/transport/utils/event_reactor.h | 37 - .../src/hicn/transport/utils/event_thread.h | 99 -- .../src/hicn/transport/utils/fd_deadline_timer.h | 128 -- libtransport/src/hicn/transport/utils/hash.h | 101 -- libtransport/src/hicn/transport/utils/identity.cc | 115 -- libtransport/src/hicn/transport/utils/identity.h | 62 - libtransport/src/hicn/transport/utils/key_id.h | 25 - libtransport/src/hicn/transport/utils/linux.h | 64 - libtransport/src/hicn/transport/utils/literals.h | 55 - libtransport/src/hicn/transport/utils/log.cc | 1403 -------------------- libtransport/src/hicn/transport/utils/log.h | 1057 --------------- libtransport/src/hicn/transport/utils/membuf.cc | 867 ------------ libtransport/src/hicn/transport/utils/membuf.h | 921 ------------- libtransport/src/hicn/transport/utils/min_filter.h | 56 - .../src/hicn/transport/utils/object_pool.h | 89 -- .../src/hicn/transport/utils/ring_buffer.h | 129 -- libtransport/src/hicn/transport/utils/signer.cc | 187 --- libtransport/src/hicn/transport/utils/signer.h | 90 -- libtransport/src/hicn/transport/utils/spinlock.h | 53 - .../src/hicn/transport/utils/stream_buffer.h | 31 - .../src/hicn/transport/utils/string_tokenizer.cc | 47 - .../src/hicn/transport/utils/string_tokenizer.h | 35 - .../src/hicn/transport/utils/suffix_strategy.h | 166 --- libtransport/src/hicn/transport/utils/test.h | 46 - libtransport/src/hicn/transport/utils/uri.cc | 122 -- libtransport/src/hicn/transport/utils/uri.h | 47 - libtransport/src/hicn/transport/utils/verifier.cc | 234 ---- libtransport/src/hicn/transport/utils/verifier.h | 103 -- libtransport/src/http/CMakeLists.txt | 21 + libtransport/src/http/client_connection.cc | 317 +++++ libtransport/src/http/request.cc | 74 ++ libtransport/src/http/response.cc | 138 ++ libtransport/src/implementation/CMakeLists.txt | 46 + .../implementation/p2psecure_socket_consumer.cc | 403 ++++++ .../src/implementation/p2psecure_socket_consumer.h | 148 +++ .../implementation/p2psecure_socket_producer.cc | 404 ++++++ .../src/implementation/p2psecure_socket_producer.h | 130 ++ .../src/implementation/rtc_socket_producer.cc | 352 +++++ .../src/implementation/rtc_socket_producer.h | 74 ++ libtransport/src/implementation/socket.h | 89 ++ libtransport/src/implementation/socket_consumer.h | 950 +++++++++++++ libtransport/src/implementation/socket_producer.h | 1061 +++++++++++++++ .../src/implementation/tls_rtc_socket_producer.cc | 201 +++ .../src/implementation/tls_rtc_socket_producer.h | 58 + .../src/implementation/tls_socket_consumer.cc | 384 ++++++ .../src/implementation/tls_socket_consumer.h | 133 ++ .../src/implementation/tls_socket_producer.cc | 611 +++++++++ .../src/implementation/tls_socket_producer.h | 163 +++ libtransport/src/interfaces/CMakeLists.txt | 39 + libtransport/src/interfaces/callbacks.cc | 26 + .../src/interfaces/p2psecure_socket_consumer.cc | 32 + .../src/interfaces/p2psecure_socket_producer.cc | 34 + libtransport/src/interfaces/rtc_socket_producer.cc | 29 + libtransport/src/interfaces/socket_consumer.cc | 196 +++ libtransport/src/interfaces/socket_producer.cc | 198 +++ .../src/interfaces/tls_rtc_socket_producer.cc | 32 + .../src/interfaces/tls_rtc_socket_producer.h | 36 + libtransport/src/interfaces/tls_socket_consumer.cc | 31 + libtransport/src/interfaces/tls_socket_consumer.h | 36 + libtransport/src/interfaces/tls_socket_producer.cc | 31 + libtransport/src/interfaces/tls_socket_producer.h | 36 + libtransport/src/protocols/CMakeLists.txt | 75 ++ .../src/protocols/byte_stream_reassembly.cc | 126 ++ .../src/protocols/byte_stream_reassembly.h | 54 + libtransport/src/protocols/cbr.cc | 52 + libtransport/src/protocols/cbr.h | 40 + .../src/protocols/congestion_window_protocol.h | 30 + libtransport/src/protocols/consumer.conf | 21 + .../src/protocols/data_processing_events.h | 33 + libtransport/src/protocols/datagram_reassembly.cc | 36 + libtransport/src/protocols/datagram_reassembly.h | 39 + libtransport/src/protocols/errors.cc | 60 + libtransport/src/protocols/errors.h | 91 ++ libtransport/src/protocols/incremental_indexer.cc | 53 + libtransport/src/protocols/incremental_indexer.h | 143 ++ libtransport/src/protocols/indexer.cc | 79 ++ libtransport/src/protocols/indexer.h | 106 ++ .../src/protocols/manifest_incremental_indexer.cc | 234 ++++ .../src/protocols/manifest_incremental_indexer.h | 92 ++ libtransport/src/protocols/packet_manager.h | 65 + libtransport/src/protocols/protocol.cc | 105 ++ libtransport/src/protocols/protocol.h | 92 ++ libtransport/src/protocols/raaqm.cc | 714 ++++++++++ libtransport/src/protocols/raaqm.h | 142 ++ libtransport/src/protocols/raaqm_data_path.cc | 158 +++ libtransport/src/protocols/raaqm_data_path.h | 226 ++++ libtransport/src/protocols/rate_estimation.cc | 356 +++++ libtransport/src/protocols/rate_estimation.h | 174 +++ libtransport/src/protocols/reassembly.cc | 72 + libtransport/src/protocols/reassembly.h | 67 + libtransport/src/protocols/rtc.cc | 1017 ++++++++++++++ libtransport/src/protocols/rtc.h | 227 ++++ libtransport/src/protocols/rtc_data_path.cc | 156 +++ libtransport/src/protocols/rtc_data_path.h | 80 ++ libtransport/src/protocols/test/CMakeLists.txt | 10 + .../src/protocols/test/test_transport_producer.cc | 80 ++ libtransport/src/protocols/verification_manager.cc | 101 ++ libtransport/src/protocols/verification_manager.h | 71 + libtransport/src/security/CMakeLists.txt | 22 + libtransport/src/security/identity.cc | 115 ++ libtransport/src/security/signer.cc | 187 +++ libtransport/src/security/verifier.cc | 241 ++++ libtransport/src/utils/CMakeLists.txt | 53 + libtransport/src/utils/content_store.cc | 122 ++ libtransport/src/utils/content_store.h | 76 ++ libtransport/src/utils/daemonizator.cc | 76 ++ libtransport/src/utils/deadline_timer.h | 114 ++ libtransport/src/utils/epoll_event_reactor.cc | 187 +++ libtransport/src/utils/epoll_event_reactor.h | 80 ++ libtransport/src/utils/event_reactor.h | 37 + libtransport/src/utils/event_thread.h | 99 ++ libtransport/src/utils/fd_deadline_timer.h | 129 ++ libtransport/src/utils/log.cc | 1403 ++++++++++++++++++++ libtransport/src/utils/membuf.cc | 867 ++++++++++++ libtransport/src/utils/memory_pool_allocator.h | 152 +++ libtransport/src/utils/min_filter.h | 56 + libtransport/src/utils/stream_buffer.h | 31 + libtransport/src/utils/string_tokenizer.cc | 47 + libtransport/src/utils/suffix_strategy.h | 165 +++ libtransport/src/utils/test.h | 46 + libtransport/src/utils/uri.cc | 122 ++ utils/CMakeLists.txt | 3 + utils/src/hiperf.cc | 18 +- utils/src/ping_client.cc | 10 +- utils/src/ping_server.cc | 26 +- 394 files changed, 29112 insertions(+), 28552 deletions(-) create mode 100644 libtransport/includes/hicn/transport/CMakeLists.txt create mode 100644 libtransport/includes/hicn/transport/core/CMakeLists.txt create mode 100644 libtransport/includes/hicn/transport/core/content_object.h create mode 100644 libtransport/includes/hicn/transport/core/interest.h create mode 100644 libtransport/includes/hicn/transport/core/name.h create mode 100644 libtransport/includes/hicn/transport/core/packet.h create mode 100644 libtransport/includes/hicn/transport/core/payload_type.h create mode 100644 libtransport/includes/hicn/transport/core/prefix.h create mode 100644 libtransport/includes/hicn/transport/errors/CMakeLists.txt create mode 100644 libtransport/includes/hicn/transport/errors/errors.h create mode 100644 libtransport/includes/hicn/transport/errors/indexing_exception.h create mode 100644 libtransport/includes/hicn/transport/errors/invalid_ip_address_exception.h create mode 100644 libtransport/includes/hicn/transport/errors/malformed_ahpacket_exception.h create mode 100644 libtransport/includes/hicn/transport/errors/malformed_name_exception.h create mode 100644 libtransport/includes/hicn/transport/errors/malformed_packet_exception.h create mode 100644 libtransport/includes/hicn/transport/errors/not_implemented_exception.h create mode 100644 libtransport/includes/hicn/transport/errors/null_pointer_exception.h create mode 100644 libtransport/includes/hicn/transport/errors/runtime_exception.h create mode 100644 libtransport/includes/hicn/transport/errors/tokenizer_exception.h create mode 100644 libtransport/includes/hicn/transport/errors/unexpected_manifest_exception.h create mode 100644 libtransport/includes/hicn/transport/http/CMakeLists.txt create mode 100644 libtransport/includes/hicn/transport/http/client_connection.h create mode 100644 libtransport/includes/hicn/transport/http/default_values.h create mode 100644 libtransport/includes/hicn/transport/http/facade.h create mode 100644 libtransport/includes/hicn/transport/http/message.h create mode 100644 libtransport/includes/hicn/transport/http/request.h create mode 100644 libtransport/includes/hicn/transport/http/response.h create mode 100644 libtransport/includes/hicn/transport/interfaces/CMakeLists.txt create mode 100644 libtransport/includes/hicn/transport/interfaces/callbacks.h create mode 100644 libtransport/includes/hicn/transport/interfaces/p2psecure_socket_consumer.h create mode 100644 libtransport/includes/hicn/transport/interfaces/p2psecure_socket_producer.h create mode 100644 libtransport/includes/hicn/transport/interfaces/publication_options.h create mode 100644 libtransport/includes/hicn/transport/interfaces/rtc_socket_producer.h create mode 100644 libtransport/includes/hicn/transport/interfaces/socket_consumer.h create mode 100644 libtransport/includes/hicn/transport/interfaces/socket_options_default_values.h create mode 100644 libtransport/includes/hicn/transport/interfaces/socket_options_keys.h create mode 100644 libtransport/includes/hicn/transport/interfaces/socket_producer.h create mode 100644 libtransport/includes/hicn/transport/interfaces/statistics.h create mode 100644 libtransport/includes/hicn/transport/interfaces/verification_policy.h create mode 100644 libtransport/includes/hicn/transport/portability/CMakeLists.txt create mode 100644 libtransport/includes/hicn/transport/portability/c_portability.h create mode 100644 libtransport/includes/hicn/transport/portability/portability.h create mode 100644 libtransport/includes/hicn/transport/portability/win_portability.h create mode 100644 libtransport/includes/hicn/transport/security/CMakeLists.txt create mode 100644 libtransport/includes/hicn/transport/security/crypto_hash.h create mode 100644 libtransport/includes/hicn/transport/security/crypto_hash_type.h create mode 100644 libtransport/includes/hicn/transport/security/crypto_hasher.h create mode 100644 libtransport/includes/hicn/transport/security/crypto_suite.h create mode 100644 libtransport/includes/hicn/transport/security/identity.h create mode 100644 libtransport/includes/hicn/transport/security/key_id.h create mode 100644 libtransport/includes/hicn/transport/security/signer.h create mode 100644 libtransport/includes/hicn/transport/security/verifier.h create mode 100644 libtransport/includes/hicn/transport/utils/CMakeLists.txt create mode 100644 libtransport/includes/hicn/transport/utils/array.h create mode 100644 libtransport/includes/hicn/transport/utils/branch_prediction.h create mode 100644 libtransport/includes/hicn/transport/utils/chrono_typedefs.h create mode 100644 libtransport/includes/hicn/transport/utils/conversions.h create mode 100644 libtransport/includes/hicn/transport/utils/daemonizator.h create mode 100644 libtransport/includes/hicn/transport/utils/hash.h create mode 100644 libtransport/includes/hicn/transport/utils/linux.h create mode 100644 libtransport/includes/hicn/transport/utils/literals.h create mode 100644 libtransport/includes/hicn/transport/utils/log.h create mode 100644 libtransport/includes/hicn/transport/utils/membuf.h create mode 100644 libtransport/includes/hicn/transport/utils/object_pool.h create mode 100644 libtransport/includes/hicn/transport/utils/ring_buffer.h create mode 100644 libtransport/includes/hicn/transport/utils/spinlock.h create mode 100644 libtransport/includes/hicn/transport/utils/string_tokenizer.h create mode 100644 libtransport/includes/hicn/transport/utils/uri.h create mode 100644 libtransport/src/CMakeLists.txt create mode 100644 libtransport/src/config.h.in create mode 100644 libtransport/src/core/CMakeLists.txt create mode 100644 libtransport/src/core/connector.cc create mode 100644 libtransport/src/core/connector.h create mode 100644 libtransport/src/core/content_object.cc create mode 100644 libtransport/src/core/facade.h create mode 100644 libtransport/src/core/forwarder_interface.h create mode 100644 libtransport/src/core/hicn_forwarder_interface.cc create mode 100644 libtransport/src/core/hicn_forwarder_interface.h create mode 100644 libtransport/src/core/hicn_vapi.c create mode 100644 libtransport/src/core/hicn_vapi.h create mode 100644 libtransport/src/core/interest.cc create mode 100644 libtransport/src/core/manifest.cc create mode 100644 libtransport/src/core/manifest.h create mode 100644 libtransport/src/core/manifest_format.h create mode 100644 libtransport/src/core/manifest_format_fixed.cc create mode 100644 libtransport/src/core/manifest_format_fixed.h create mode 100644 libtransport/src/core/manifest_inline.h create mode 100644 libtransport/src/core/memif_connector.cc create mode 100644 libtransport/src/core/memif_connector.h create mode 100644 libtransport/src/core/memif_vapi.c create mode 100644 libtransport/src/core/memif_vapi.h create mode 100644 libtransport/src/core/name.cc create mode 100644 libtransport/src/core/packet.cc create mode 100644 libtransport/src/core/pending_interest.cc create mode 100644 libtransport/src/core/pending_interest.h create mode 100644 libtransport/src/core/portal.h create mode 100644 libtransport/src/core/prefix.cc create mode 100644 libtransport/src/core/raw_socket_connector.cc create mode 100644 libtransport/src/core/raw_socket_connector.h create mode 100644 libtransport/src/core/raw_socket_interface.cc create mode 100644 libtransport/src/core/raw_socket_interface.h create mode 100644 libtransport/src/core/tcp_socket_connector.cc create mode 100644 libtransport/src/core/tcp_socket_connector.h create mode 100644 libtransport/src/core/test/CMakeLists.txt create mode 100644 libtransport/src/core/test/test_core_manifest.cc create mode 100644 libtransport/src/core/udp_socket_connector.cc create mode 100644 libtransport/src/core/udp_socket_connector.h create mode 100644 libtransport/src/core/vpp_forwarder_interface.cc create mode 100644 libtransport/src/core/vpp_forwarder_interface.h delete mode 100644 libtransport/src/hicn/transport/CMakeLists.txt delete mode 100644 libtransport/src/hicn/transport/config.h.in delete mode 100644 libtransport/src/hicn/transport/core/CMakeLists.txt delete mode 100644 libtransport/src/hicn/transport/core/connector.cc delete mode 100644 libtransport/src/hicn/transport/core/connector.h delete mode 100644 libtransport/src/hicn/transport/core/content_object.cc delete mode 100644 libtransport/src/hicn/transport/core/content_object.h delete mode 100644 libtransport/src/hicn/transport/core/facade.h delete mode 100644 libtransport/src/hicn/transport/core/forwarder_interface.h delete mode 100644 libtransport/src/hicn/transport/core/hicn_forwarder_interface.cc delete mode 100644 libtransport/src/hicn/transport/core/hicn_forwarder_interface.h delete mode 100644 libtransport/src/hicn/transport/core/hicn_vapi.c delete mode 100644 libtransport/src/hicn/transport/core/hicn_vapi.h delete mode 100644 libtransport/src/hicn/transport/core/interest.cc delete mode 100644 libtransport/src/hicn/transport/core/interest.h delete mode 100644 libtransport/src/hicn/transport/core/manifest.cc delete mode 100644 libtransport/src/hicn/transport/core/manifest.h delete mode 100644 libtransport/src/hicn/transport/core/manifest_format.h delete mode 100644 libtransport/src/hicn/transport/core/manifest_format_fixed.cc delete mode 100644 libtransport/src/hicn/transport/core/manifest_format_fixed.h delete mode 100644 libtransport/src/hicn/transport/core/manifest_inline.h delete mode 100644 libtransport/src/hicn/transport/core/memif_connector.cc delete mode 100644 libtransport/src/hicn/transport/core/memif_connector.h delete mode 100644 libtransport/src/hicn/transport/core/memif_vapi.c delete mode 100644 libtransport/src/hicn/transport/core/memif_vapi.h delete mode 100644 libtransport/src/hicn/transport/core/name.cc delete mode 100644 libtransport/src/hicn/transport/core/name.h delete mode 100644 libtransport/src/hicn/transport/core/packet.cc delete mode 100644 libtransport/src/hicn/transport/core/packet.h delete mode 100644 libtransport/src/hicn/transport/core/payload_type.h delete mode 100644 libtransport/src/hicn/transport/core/pending_interest.cc delete mode 100644 libtransport/src/hicn/transport/core/pending_interest.h delete mode 100644 libtransport/src/hicn/transport/core/portal.h delete mode 100644 libtransport/src/hicn/transport/core/prefix.cc delete mode 100644 libtransport/src/hicn/transport/core/prefix.h delete mode 100644 libtransport/src/hicn/transport/core/raw_socket_connector.cc delete mode 100644 libtransport/src/hicn/transport/core/raw_socket_connector.h delete mode 100644 libtransport/src/hicn/transport/core/raw_socket_interface.cc delete mode 100644 libtransport/src/hicn/transport/core/raw_socket_interface.h delete mode 100644 libtransport/src/hicn/transport/core/tcp_socket_connector.cc delete mode 100644 libtransport/src/hicn/transport/core/tcp_socket_connector.h delete mode 100644 libtransport/src/hicn/transport/core/test/CMakeLists.txt delete mode 100644 libtransport/src/hicn/transport/core/test/test_core_manifest.cc delete mode 100644 libtransport/src/hicn/transport/core/udp_socket_connector.cc delete mode 100644 libtransport/src/hicn/transport/core/udp_socket_connector.h delete mode 100644 libtransport/src/hicn/transport/core/vpp_forwarder_interface.cc delete mode 100644 libtransport/src/hicn/transport/core/vpp_forwarder_interface.h delete mode 100644 libtransport/src/hicn/transport/errors/CMakeLists.txt delete mode 100644 libtransport/src/hicn/transport/errors/errors.h delete mode 100644 libtransport/src/hicn/transport/errors/indexing_exception.h delete mode 100644 libtransport/src/hicn/transport/errors/invalid_ip_address_exception.h delete mode 100644 libtransport/src/hicn/transport/errors/malformed_ahpacket_exception.h delete mode 100644 libtransport/src/hicn/transport/errors/malformed_name_exception.h delete mode 100644 libtransport/src/hicn/transport/errors/malformed_packet_exception.h delete mode 100644 libtransport/src/hicn/transport/errors/not_implemented_exception.h delete mode 100644 libtransport/src/hicn/transport/errors/null_pointer_exception.h delete mode 100644 libtransport/src/hicn/transport/errors/runtime_exception.h delete mode 100644 libtransport/src/hicn/transport/errors/tokenizer_exception.h delete mode 100644 libtransport/src/hicn/transport/errors/unexpected_manifest_exception.h delete mode 100644 libtransport/src/hicn/transport/http/CMakeLists.txt delete mode 100644 libtransport/src/hicn/transport/http/client_connection.cc delete mode 100644 libtransport/src/hicn/transport/http/client_connection.h delete mode 100644 libtransport/src/hicn/transport/http/default_values.h delete mode 100644 libtransport/src/hicn/transport/http/facade.h delete mode 100644 libtransport/src/hicn/transport/http/message.h delete mode 100644 libtransport/src/hicn/transport/http/request.cc delete mode 100644 libtransport/src/hicn/transport/http/request.h delete mode 100644 libtransport/src/hicn/transport/http/response.cc delete mode 100644 libtransport/src/hicn/transport/http/response.h delete mode 100644 libtransport/src/hicn/transport/http/server_acceptor.cc delete mode 100644 libtransport/src/hicn/transport/http/server_acceptor.h delete mode 100644 libtransport/src/hicn/transport/http/server_publisher.cc delete mode 100644 libtransport/src/hicn/transport/http/server_publisher.h delete mode 100644 libtransport/src/hicn/transport/interfaces/CMakeLists.txt delete mode 100644 libtransport/src/hicn/transport/interfaces/callbacks.cc delete mode 100644 libtransport/src/hicn/transport/interfaces/callbacks.h delete mode 100644 libtransport/src/hicn/transport/interfaces/p2psecure_socket_consumer.cc delete mode 100644 libtransport/src/hicn/transport/interfaces/p2psecure_socket_consumer.h delete mode 100644 libtransport/src/hicn/transport/interfaces/p2psecure_socket_producer.cc delete mode 100644 libtransport/src/hicn/transport/interfaces/p2psecure_socket_producer.h delete mode 100644 libtransport/src/hicn/transport/interfaces/publication_options.h delete mode 100644 libtransport/src/hicn/transport/interfaces/rtc_socket_producer.cc delete mode 100644 libtransport/src/hicn/transport/interfaces/rtc_socket_producer.h delete mode 100644 libtransport/src/hicn/transport/interfaces/socket.h delete mode 100644 libtransport/src/hicn/transport/interfaces/socket_consumer.cc delete mode 100644 libtransport/src/hicn/transport/interfaces/socket_consumer.h delete mode 100644 libtransport/src/hicn/transport/interfaces/socket_options_default_values.h delete mode 100644 libtransport/src/hicn/transport/interfaces/socket_options_keys.h delete mode 100644 libtransport/src/hicn/transport/interfaces/socket_producer.cc delete mode 100644 libtransport/src/hicn/transport/interfaces/socket_producer.h delete mode 100644 libtransport/src/hicn/transport/interfaces/tls_rtc_socket_producer.cc delete mode 100644 libtransport/src/hicn/transport/interfaces/tls_rtc_socket_producer.h delete mode 100644 libtransport/src/hicn/transport/interfaces/tls_socket_consumer.cc delete mode 100644 libtransport/src/hicn/transport/interfaces/tls_socket_consumer.h delete mode 100644 libtransport/src/hicn/transport/interfaces/tls_socket_producer.cc delete mode 100644 libtransport/src/hicn/transport/interfaces/tls_socket_producer.h delete mode 100644 libtransport/src/hicn/transport/interfaces/verification_policy.h delete mode 100644 libtransport/src/hicn/transport/portability/CMakeLists.txt delete mode 100644 libtransport/src/hicn/transport/portability/c_portability.h delete mode 100644 libtransport/src/hicn/transport/portability/portability.h delete mode 100644 libtransport/src/hicn/transport/portability/win_portability.h delete mode 100644 libtransport/src/hicn/transport/protocols/CMakeLists.txt delete mode 100644 libtransport/src/hicn/transport/protocols/byte_stream_reassembly.cc delete mode 100644 libtransport/src/hicn/transport/protocols/byte_stream_reassembly.h delete mode 100644 libtransport/src/hicn/transport/protocols/cbr.cc delete mode 100644 libtransport/src/hicn/transport/protocols/cbr.h delete mode 100644 libtransport/src/hicn/transport/protocols/congestion_window_protocol.h delete mode 100644 libtransport/src/hicn/transport/protocols/consumer.conf delete mode 100644 libtransport/src/hicn/transport/protocols/data_processing_events.h delete mode 100644 libtransport/src/hicn/transport/protocols/datagram_reassembly.cc delete mode 100644 libtransport/src/hicn/transport/protocols/datagram_reassembly.h delete mode 100644 libtransport/src/hicn/transport/protocols/download_observer.h delete mode 100644 libtransport/src/hicn/transport/protocols/errors.cc delete mode 100644 libtransport/src/hicn/transport/protocols/errors.h delete mode 100644 libtransport/src/hicn/transport/protocols/incremental_indexer.cc delete mode 100644 libtransport/src/hicn/transport/protocols/incremental_indexer.h delete mode 100644 libtransport/src/hicn/transport/protocols/indexer.cc delete mode 100644 libtransport/src/hicn/transport/protocols/indexer.h delete mode 100644 libtransport/src/hicn/transport/protocols/manifest_incremental_indexer.cc delete mode 100644 libtransport/src/hicn/transport/protocols/manifest_incremental_indexer.h delete mode 100644 libtransport/src/hicn/transport/protocols/manifest_indexing_manager.cc delete mode 100644 libtransport/src/hicn/transport/protocols/packet_manager.h delete mode 100644 libtransport/src/hicn/transport/protocols/protocol.cc delete mode 100644 libtransport/src/hicn/transport/protocols/protocol.h delete mode 100644 libtransport/src/hicn/transport/protocols/raaqm.cc delete mode 100644 libtransport/src/hicn/transport/protocols/raaqm.h delete mode 100644 libtransport/src/hicn/transport/protocols/raaqm_data_path.cc delete mode 100644 libtransport/src/hicn/transport/protocols/raaqm_data_path.h delete mode 100644 libtransport/src/hicn/transport/protocols/rate_estimation.cc delete mode 100644 libtransport/src/hicn/transport/protocols/rate_estimation.h delete mode 100644 libtransport/src/hicn/transport/protocols/reassembly.cc delete mode 100644 libtransport/src/hicn/transport/protocols/reassembly.h delete mode 100644 libtransport/src/hicn/transport/protocols/rtc.cc delete mode 100644 libtransport/src/hicn/transport/protocols/rtc.h delete mode 100644 libtransport/src/hicn/transport/protocols/rtc_data_path.cc delete mode 100644 libtransport/src/hicn/transport/protocols/rtc_data_path.h delete mode 100644 libtransport/src/hicn/transport/protocols/statistics.h delete mode 100644 libtransport/src/hicn/transport/protocols/test/CMakeLists.txt delete mode 100644 libtransport/src/hicn/transport/protocols/test/test_transport_producer.cc delete mode 100644 libtransport/src/hicn/transport/protocols/verification_manager.cc delete mode 100644 libtransport/src/hicn/transport/protocols/verification_manager.h delete mode 100644 libtransport/src/hicn/transport/utils/CMakeLists.txt delete mode 100644 libtransport/src/hicn/transport/utils/array.h delete mode 100644 libtransport/src/hicn/transport/utils/branch_prediction.h delete mode 100644 libtransport/src/hicn/transport/utils/chrono_typedefs.h delete mode 100644 libtransport/src/hicn/transport/utils/content_store.cc delete mode 100644 libtransport/src/hicn/transport/utils/content_store.h delete mode 100644 libtransport/src/hicn/transport/utils/conversions.h delete mode 100644 libtransport/src/hicn/transport/utils/crypto_hash.h delete mode 100644 libtransport/src/hicn/transport/utils/crypto_hash_type.h delete mode 100644 libtransport/src/hicn/transport/utils/crypto_hasher.h delete mode 100644 libtransport/src/hicn/transport/utils/crypto_suite.h delete mode 100644 libtransport/src/hicn/transport/utils/daemonizator.cc delete mode 100644 libtransport/src/hicn/transport/utils/daemonizator.h delete mode 100644 libtransport/src/hicn/transport/utils/deadline_timer.h delete mode 100644 libtransport/src/hicn/transport/utils/epoll_event_reactor.cc delete mode 100644 libtransport/src/hicn/transport/utils/epoll_event_reactor.h delete mode 100644 libtransport/src/hicn/transport/utils/event_reactor.h delete mode 100644 libtransport/src/hicn/transport/utils/event_thread.h delete mode 100644 libtransport/src/hicn/transport/utils/fd_deadline_timer.h delete mode 100644 libtransport/src/hicn/transport/utils/hash.h delete mode 100644 libtransport/src/hicn/transport/utils/identity.cc delete mode 100644 libtransport/src/hicn/transport/utils/identity.h delete mode 100644 libtransport/src/hicn/transport/utils/key_id.h delete mode 100644 libtransport/src/hicn/transport/utils/linux.h delete mode 100644 libtransport/src/hicn/transport/utils/literals.h delete mode 100644 libtransport/src/hicn/transport/utils/log.cc delete mode 100644 libtransport/src/hicn/transport/utils/log.h delete mode 100644 libtransport/src/hicn/transport/utils/membuf.cc delete mode 100644 libtransport/src/hicn/transport/utils/membuf.h delete mode 100644 libtransport/src/hicn/transport/utils/min_filter.h delete mode 100644 libtransport/src/hicn/transport/utils/object_pool.h delete mode 100644 libtransport/src/hicn/transport/utils/ring_buffer.h delete mode 100644 libtransport/src/hicn/transport/utils/signer.cc delete mode 100644 libtransport/src/hicn/transport/utils/signer.h delete mode 100644 libtransport/src/hicn/transport/utils/spinlock.h delete mode 100644 libtransport/src/hicn/transport/utils/stream_buffer.h delete mode 100644 libtransport/src/hicn/transport/utils/string_tokenizer.cc delete mode 100644 libtransport/src/hicn/transport/utils/string_tokenizer.h delete mode 100644 libtransport/src/hicn/transport/utils/suffix_strategy.h delete mode 100644 libtransport/src/hicn/transport/utils/test.h delete mode 100644 libtransport/src/hicn/transport/utils/uri.cc delete mode 100644 libtransport/src/hicn/transport/utils/uri.h delete mode 100644 libtransport/src/hicn/transport/utils/verifier.cc delete mode 100644 libtransport/src/hicn/transport/utils/verifier.h create mode 100644 libtransport/src/http/CMakeLists.txt create mode 100644 libtransport/src/http/client_connection.cc create mode 100644 libtransport/src/http/request.cc create mode 100644 libtransport/src/http/response.cc create mode 100644 libtransport/src/implementation/CMakeLists.txt create mode 100644 libtransport/src/implementation/p2psecure_socket_consumer.cc create mode 100644 libtransport/src/implementation/p2psecure_socket_consumer.h create mode 100644 libtransport/src/implementation/p2psecure_socket_producer.cc create mode 100644 libtransport/src/implementation/p2psecure_socket_producer.h create mode 100644 libtransport/src/implementation/rtc_socket_producer.cc create mode 100644 libtransport/src/implementation/rtc_socket_producer.h create mode 100644 libtransport/src/implementation/socket.h create mode 100644 libtransport/src/implementation/socket_consumer.h create mode 100644 libtransport/src/implementation/socket_producer.h create mode 100644 libtransport/src/implementation/tls_rtc_socket_producer.cc create mode 100644 libtransport/src/implementation/tls_rtc_socket_producer.h create mode 100644 libtransport/src/implementation/tls_socket_consumer.cc create mode 100644 libtransport/src/implementation/tls_socket_consumer.h create mode 100644 libtransport/src/implementation/tls_socket_producer.cc create mode 100644 libtransport/src/implementation/tls_socket_producer.h create mode 100644 libtransport/src/interfaces/CMakeLists.txt create mode 100644 libtransport/src/interfaces/callbacks.cc create mode 100644 libtransport/src/interfaces/p2psecure_socket_consumer.cc create mode 100644 libtransport/src/interfaces/p2psecure_socket_producer.cc create mode 100644 libtransport/src/interfaces/rtc_socket_producer.cc create mode 100644 libtransport/src/interfaces/socket_consumer.cc create mode 100644 libtransport/src/interfaces/socket_producer.cc create mode 100644 libtransport/src/interfaces/tls_rtc_socket_producer.cc create mode 100644 libtransport/src/interfaces/tls_rtc_socket_producer.h create mode 100644 libtransport/src/interfaces/tls_socket_consumer.cc create mode 100644 libtransport/src/interfaces/tls_socket_consumer.h create mode 100644 libtransport/src/interfaces/tls_socket_producer.cc create mode 100644 libtransport/src/interfaces/tls_socket_producer.h create mode 100644 libtransport/src/protocols/CMakeLists.txt create mode 100644 libtransport/src/protocols/byte_stream_reassembly.cc create mode 100644 libtransport/src/protocols/byte_stream_reassembly.h create mode 100644 libtransport/src/protocols/cbr.cc create mode 100644 libtransport/src/protocols/cbr.h create mode 100644 libtransport/src/protocols/congestion_window_protocol.h create mode 100644 libtransport/src/protocols/consumer.conf create mode 100644 libtransport/src/protocols/data_processing_events.h create mode 100644 libtransport/src/protocols/datagram_reassembly.cc create mode 100644 libtransport/src/protocols/datagram_reassembly.h create mode 100644 libtransport/src/protocols/errors.cc create mode 100644 libtransport/src/protocols/errors.h create mode 100644 libtransport/src/protocols/incremental_indexer.cc create mode 100644 libtransport/src/protocols/incremental_indexer.h create mode 100644 libtransport/src/protocols/indexer.cc create mode 100644 libtransport/src/protocols/indexer.h create mode 100644 libtransport/src/protocols/manifest_incremental_indexer.cc create mode 100644 libtransport/src/protocols/manifest_incremental_indexer.h create mode 100644 libtransport/src/protocols/packet_manager.h create mode 100644 libtransport/src/protocols/protocol.cc create mode 100644 libtransport/src/protocols/protocol.h create mode 100644 libtransport/src/protocols/raaqm.cc create mode 100644 libtransport/src/protocols/raaqm.h create mode 100644 libtransport/src/protocols/raaqm_data_path.cc create mode 100644 libtransport/src/protocols/raaqm_data_path.h create mode 100644 libtransport/src/protocols/rate_estimation.cc create mode 100644 libtransport/src/protocols/rate_estimation.h create mode 100644 libtransport/src/protocols/reassembly.cc create mode 100644 libtransport/src/protocols/reassembly.h create mode 100644 libtransport/src/protocols/rtc.cc create mode 100644 libtransport/src/protocols/rtc.h create mode 100644 libtransport/src/protocols/rtc_data_path.cc create mode 100644 libtransport/src/protocols/rtc_data_path.h create mode 100644 libtransport/src/protocols/test/CMakeLists.txt create mode 100644 libtransport/src/protocols/test/test_transport_producer.cc create mode 100644 libtransport/src/protocols/verification_manager.cc create mode 100644 libtransport/src/protocols/verification_manager.h create mode 100644 libtransport/src/security/CMakeLists.txt create mode 100644 libtransport/src/security/identity.cc create mode 100644 libtransport/src/security/signer.cc create mode 100644 libtransport/src/security/verifier.cc create mode 100644 libtransport/src/utils/CMakeLists.txt create mode 100644 libtransport/src/utils/content_store.cc create mode 100644 libtransport/src/utils/content_store.h create mode 100644 libtransport/src/utils/daemonizator.cc create mode 100644 libtransport/src/utils/deadline_timer.h create mode 100644 libtransport/src/utils/epoll_event_reactor.cc create mode 100644 libtransport/src/utils/epoll_event_reactor.h create mode 100644 libtransport/src/utils/event_reactor.h create mode 100644 libtransport/src/utils/event_thread.h create mode 100644 libtransport/src/utils/fd_deadline_timer.h create mode 100644 libtransport/src/utils/log.cc create mode 100644 libtransport/src/utils/membuf.cc create mode 100644 libtransport/src/utils/memory_pool_allocator.h create mode 100644 libtransport/src/utils/min_filter.h create mode 100644 libtransport/src/utils/stream_buffer.h create mode 100644 libtransport/src/utils/string_tokenizer.cc create mode 100644 libtransport/src/utils/suffix_strategy.h create mode 100644 libtransport/src/utils/test.h create mode 100644 libtransport/src/utils/uri.cc diff --git a/apps/higet/higet.cc b/apps/higet/higet.cc index fcb0cc540..2aa42e460 100644 --- a/apps/higet/higet.cc +++ b/apps/higet/higet.cc @@ -20,10 +20,11 @@ #include #include -#ifndef ASIO_STANDALONE #define ASIO_STANDALONE #include -#endif +#undef ASIO_STANDALONE + +#include typedef std::chrono::time_point Time; typedef std::chrono::milliseconds TimeDuration; diff --git a/apps/http-proxy/src/IcnReceiver.cc b/apps/http-proxy/src/IcnReceiver.cc index cc47e2ed4..24b0eb5dc 100644 --- a/apps/http-proxy/src/IcnReceiver.cc +++ b/apps/http-proxy/src/IcnReceiver.cc @@ -16,8 +16,10 @@ #include "IcnReceiver.h" #include "HTTP1.xMessageFastParser.h" +#include #include #include +#include #include #include diff --git a/libtransport/CMakeLists.txt b/libtransport/CMakeLists.txt index 881e9810a..973dbaf35 100644 --- a/libtransport/CMakeLists.txt +++ b/libtransport/CMakeLists.txt @@ -42,7 +42,7 @@ endif () # Default: INFO set(TRANSPORT_LOG_LEVEL "INFO" CACHE STRING "Set log level") -set(TRANSPORT_ROOT_PATH "src/hicn/transport") +set(TRANSPORT_ROOT_PATH "src") set(TRANSPORT_CORE ${TRANSPORT_ROOT_PATH}/core) set(TRANSPORT_TRANSPORT ${TRANSPORT_ROOT_PATH}/transport) @@ -168,4 +168,5 @@ list(APPEND LIBTRANSPORT_INTERNAL_INCLUDE_DIRS ${OPENSSL_INCLUDE_DIR} ) +add_subdirectory(includes/hicn/transport) add_subdirectory(${TRANSPORT_ROOT_PATH}) diff --git a/libtransport/includes/hicn/transport/CMakeLists.txt b/libtransport/includes/hicn/transport/CMakeLists.txt new file mode 100644 index 000000000..1099e701d --- /dev/null +++ b/libtransport/includes/hicn/transport/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright (c) 2017-2020 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) + +include(GNUInstallDirs) + +set(ASIO_STANDALONE 1) + +add_subdirectory(core) +add_subdirectory(errors) +add_subdirectory(http) +add_subdirectory(interfaces) +add_subdirectory(portability) +add_subdirectory(security) +add_subdirectory(utils) + +set(LIBTRANSPORT_INCLUDE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR}/../.. "" + CACHE INTERNAL + "" FORCE +) + +set(LIBHICNTRANSPORT_TO_INSTALL_HEADER_FILES + ${HEADER_FILES} "" + CACHE INTERNAL + "" FORCE +) \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/core/CMakeLists.txt b/libtransport/includes/hicn/transport/core/CMakeLists.txt new file mode 100644 index 000000000..cb10745ff --- /dev/null +++ b/libtransport/includes/hicn/transport/core/CMakeLists.txt @@ -0,0 +1,25 @@ +# 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) + +list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/content_object.h + ${CMAKE_CURRENT_SOURCE_DIR}/interest.h + ${CMAKE_CURRENT_SOURCE_DIR}/name.h + ${CMAKE_CURRENT_SOURCE_DIR}/packet.h + ${CMAKE_CURRENT_SOURCE_DIR}/payload_type.h + ${CMAKE_CURRENT_SOURCE_DIR}/prefix.h +) + +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/core/content_object.h b/libtransport/includes/hicn/transport/core/content_object.h new file mode 100644 index 000000000..5af548fe4 --- /dev/null +++ b/libtransport/includes/hicn/transport/core/content_object.h @@ -0,0 +1,77 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +namespace transport { + +namespace core { + +// This class is used just to transfer buffer pointers +// without making a copy, as std::vector<> would do + +class ContentObject : public Packet { + public: + using Ptr = utils::ObjectPool::Ptr; + using HICNContentObject = hicn_header_t; + + ContentObject(Packet::Format format = HF_INET6_TCP); + + ContentObject(const Name &name, Packet::Format format = HF_INET6_TCP); + + ContentObject(const Name &name, hicn_format_t format, const uint8_t *payload, + std::size_t payload_size); + + ContentObject(const uint8_t *buffer, std::size_t size); + ContentObject(MemBufPtr &&buffer); + + ContentObject(const ContentObject &content_object) = delete; + + ContentObject(ContentObject &&content_object); + + ~ContentObject() override; + + void replace(MemBufPtr &&buffer) override; + + const Name &getName() const override; + + Name &getWritableName() override; + + void setName(const Name &name) override; + + void setName(Name &&name) override; + + uint32_t getPathLabel() const; + + ContentObject &setPathLabel(uint32_t path_label); + + void setLocator(const ip_address_t &ip_address) override; + + ip_address_t getLocator() const override; + + void setLifetime(uint32_t lifetime) override; + + uint32_t getLifetime() const override; + + private: + void resetForHash() override; +}; + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/includes/hicn/transport/core/interest.h b/libtransport/includes/hicn/transport/core/interest.h new file mode 100644 index 000000000..f0c546a8e --- /dev/null +++ b/libtransport/includes/hicn/transport/core/interest.h @@ -0,0 +1,71 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +namespace transport { + +namespace core { + +class Interest + : public Packet /*, public std::enable_shared_from_this*/ { + public: + using Ptr = utils::ObjectPool::Ptr; + + Interest(Packet::Format format = HF_INET6_TCP); + + Interest(const Name &interest_name, Packet::Format format = HF_INET6_TCP); + + Interest(const uint8_t *buffer, std::size_t size); + Interest(MemBufPtr &&buffer); + + /* + * Enforce zero-copy. + */ + Interest(const Interest &other_interest) = delete; + Interest &operator=(const Interest &other_interest) = delete; + + Interest(Interest &&other_interest); + + ~Interest() override; + + void replace(MemBufPtr &&buffer) override; + + const Name &getName() const override; + + Name &getWritableName() override; + + void setName(const Name &name) override; + + void setName(Name &&name) override; + + void setLocator(const ip_address_t &ip_address) override; + + ip_address_t getLocator() const override; + + void setLifetime(uint32_t lifetime) override; + + uint32_t getLifetime() const override; + + private: + void resetForHash() override; +}; + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/includes/hicn/transport/core/name.h b/libtransport/includes/hicn/transport/core/name.h new file mode 100644 index 000000000..ea72797ad --- /dev/null +++ b/libtransport/includes/hicn/transport/core/name.h @@ -0,0 +1,142 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include + +extern "C" { +#ifndef _WIN32 +TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat") +#endif +#include +}; + +#include + +namespace transport { + +namespace core { + +typedef struct sockaddr_in6 Sockaddr6; +typedef struct sockaddr_in Sockaddr4; +typedef struct sockaddr Sockaddr; + +enum class HashAlgorithm : uint8_t; + +class Name { + friend class Packet; + friend class ContentObject; + friend class Interest; + + static const uint32_t standard_name_string_length = 100; + + public: + using NameStruct = hicn_name_t; + using Type = hicn_name_type_t; + + Name(); + + /** + * @brief Create name + * @param name The null-terminated URI string + */ + Name(const char *name, uint32_t segment); + + Name(int family, const uint8_t *ip_address, std::uint32_t suffix = 0); + + Name(const std::string &uri, uint32_t segment); + + Name(const std::string &uri); + + Name(const Name &name); + + Name &operator=(const Name &name); + + bool operator==(const Name &name) const; + + bool operator!=(const Name &name) const; + + operator bool() const; + + std::string toString() const; + + bool equals(const Name &name, bool consider_segment = true) const; + + uint32_t getHash32(bool consider_suffix = true) const; + + void clear(); + + Type getType() const; + + uint32_t getSuffix() const; + + std::shared_ptr getAddress() const; + + Name &setSuffix(uint32_t seq_number); + + ip_prefix_t toIpAddress() const; + + void copyToDestination(uint8_t *destination, + bool include_suffix = false) const; + + int getAddressFamily() const; + + private: + TRANSPORT_ALWAYS_INLINE const NameStruct *getConstStructReference() const { + return &name_; + } + + TRANSPORT_ALWAYS_INLINE NameStruct *getStructReference() { return &name_; } + + NameStruct name_; +}; + +std::ostream &operator<<(std::ostream &os, const Name &name); + +template +struct hash {}; + +template <> +struct hash { + size_t operator()(const transport::core::Name &name) const; +}; + +template +struct compare2 {}; + +template <> +struct compare2 { + size_t operator()(const transport::core::Name &name1, const transport::core::Name &name2) const; +}; + +} // end namespace core + +} // end namespace transport + + +namespace std { +template <> +struct hash { + size_t operator()(const transport::core::Name &name) const; +}; + +} // end namespace std diff --git a/libtransport/includes/hicn/transport/core/packet.h b/libtransport/includes/hicn/transport/core/packet.h new file mode 100644 index 000000000..e80912cbe --- /dev/null +++ b/libtransport/includes/hicn/transport/core/packet.h @@ -0,0 +1,203 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace utils { +class Signer; +class Verifier; +} // namespace utils + +namespace transport { + +namespace core { + +/* + * Basic IP packet, modelled as circular chain of buffers: + * Header = H + * Payload = P + * + * H_0 --> H_1 --> H_2 --> P_0 --> P_1 --> P_2 + * \_______________________________________| + */ + +class Packet : public std::enable_shared_from_this { + friend class utils::Signer; + friend class utils::Verifier; + + public: + using MemBufPtr = std::shared_ptr; + using Format = hicn_format_t; + static constexpr size_t default_mtu = 1500; + + /** + * Create new IP packet. Here we allocate just the header, + * the eventual payload will be added by prepending the payload buffer + * to the buffer chain whose the fist buffer is the header itself. + */ + Packet(Format format = HF_UNSPEC); + + /** + * Create new IP packet using raw buffer. + */ + Packet(const uint8_t *buffer, std::size_t size); + Packet(MemBufPtr &&buffer); + + /* + * Enforce zero-copy lifestyle. + */ + Packet(const Packet &other) = delete; + Packet &operator=(const Packet &other) = delete; + + /* + * Move constructor. + */ + Packet(Packet &&other); + + friend bool operator==(const Packet &l_packet, const Packet &r_packet); + + virtual ~Packet(); + + static std::size_t getHeaderSizeFromFormat(Format format, + std::size_t signature_size = 0); + + static std::size_t getHeaderSizeFromBuffer(Format format, + const uint8_t *buffer); + + static std::size_t getPayloadSizeFromBuffer(Format format, + const uint8_t *buffer); + + static bool isInterest(const uint8_t *buffer); + + static Format getFormatFromBuffer(const uint8_t *buffer); + + virtual void replace(MemBufPtr &&buffer); + + std::size_t payloadSize() const; + + std::size_t headerSize() const; + + const std::shared_ptr acquireMemBufReference() const; + + virtual const Name &getName() const = 0; + + virtual Name &getWritableName() = 0; + + virtual void setName(const Name &name) = 0; + + virtual void setName(Name &&name) = 0; + + virtual void setLifetime(uint32_t lifetime) = 0; + + virtual uint32_t getLifetime() const = 0; + + Packet &appendPayload(const uint8_t *buffer, std::size_t length); + + Packet &appendPayload(std::unique_ptr &&payload); + + Packet &appendHeader(std::unique_ptr &&header); + + Packet &appendHeader(const uint8_t *buffer, std::size_t length); + + std::unique_ptr getPayload() const; + + Packet &updateLength(std::size_t length = 0); + + PayloadType getPayloadType() const; + + Packet &setPayloadType(PayloadType payload_type); + + Format getFormat() const; + + void dump() const; + + virtual void setLocator(const ip_address_t &locator) = 0; + + virtual ip_address_t getLocator() const = 0; + + void setSignatureTimestamp(const uint64_t ×tamp); + + uint64_t getSignatureTimestamp() const; + + void setValidationAlgorithm(const utils::CryptoSuite &validation_algorithm); + + utils::CryptoSuite getValidationAlgorithm() const; + + void setKeyId(const utils::KeyId &key_id); + + utils::KeyId getKeyId() const; + + virtual utils::CryptoHash computeDigest(HashAlgorithm algorithm) const; + + void setChecksum(); + + bool checkIntegrity() const; + + Packet &setSyn(); + Packet &resetSyn(); + bool testSyn() const; + Packet &setAck(); + Packet &resetAck(); + bool testAck() const; + Packet &setRst(); + Packet &resetRst(); + bool testRst() const; + Packet &setFin(); + Packet &resetFin(); + bool testFin() const; + Packet &resetFlags(); + std::string printFlags() const; + + Packet &setSrcPort(uint16_t srcPort); + Packet &setDstPort(uint16_t dstPort); + uint16_t getSrcPort() const; + uint16_t getDstPort() const; + + Packet &setTTL(uint8_t hops); + uint8_t getTTL() const; + + void resetPayload(); + + private: + virtual void resetForHash() = 0; + void setSignatureSize(std::size_t size_bytes); + std::size_t getSignatureSize() const; + uint8_t *getSignature() const; + void separateHeaderPayload(); + + protected: + Name name_; + MemBufPtr packet_; + hicn_header_t *packet_start_; + utils::MemBuf *header_head_; + utils::MemBuf *payload_head_; + mutable Format format_; + + static const core::Name base_name; +}; + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/includes/hicn/transport/core/payload_type.h b/libtransport/includes/hicn/transport/core/payload_type.h new file mode 100644 index 000000000..fa79db35a --- /dev/null +++ b/libtransport/includes/hicn/transport/core/payload_type.h @@ -0,0 +1,29 @@ +/* + * 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. + */ + +#pragma once + +namespace transport { + +namespace core { + +enum class PayloadType : uint16_t { + CONTENT_OBJECT = HPT_DATA, + MANIFEST = HPT_MANIFEST, +}; + +} // end namespace core + +} // end namespace transport \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/core/prefix.h b/libtransport/includes/hicn/transport/core/prefix.h new file mode 100644 index 000000000..c3805f13f --- /dev/null +++ b/libtransport/includes/hicn/transport/core/prefix.h @@ -0,0 +1,80 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace transport { + +namespace core { + +class Prefix { + public: + Prefix(); + + Prefix(const char *prefix); + + Prefix(const std::string &prefix); + + Prefix(std::string &&prefix); + + Prefix(std::string &prefix, uint16_t prefix_length); + + Prefix(const core::Name &content_name, uint16_t prefix_length); + + std::unique_ptr toSockaddr(); + + uint16_t getPrefixLength(); + + Prefix &setPrefixLength(uint16_t prefix_length); + + std::string getNetwork() const; + + int contains(const ip_address_t &content_name) const; + + int contains(const core::Name &content_name) const; + + Name getName() const; + + Name getRandomName() const; + + Name getName(const core::Name &mask, const core::Name &components, + const core::Name &content_name) const; + + Name mapName(const core::Name &content_name) const; + + Prefix &setNetwork(std::string &network); + + int getAddressFamily(); + + Prefix &setAddressFamily(int address_family); + + Name makeRandomName() const; + + ip_prefix_t &toIpPrefixStruct(); + + private: + static bool checkPrefixLengthAndAddressFamily(uint16_t prefix_length, + int family); + + void buildPrefix(std::string &prefix, uint16_t prefix_length, int family); + + ip_prefix_t ip_prefix_; +}; + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/includes/hicn/transport/errors/CMakeLists.txt b/libtransport/includes/hicn/transport/errors/CMakeLists.txt new file mode 100644 index 000000000..5b04ace10 --- /dev/null +++ b/libtransport/includes/hicn/transport/errors/CMakeLists.txt @@ -0,0 +1,30 @@ +# 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) + +list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/not_implemented_exception.h + ${CMAKE_CURRENT_SOURCE_DIR}/invalid_ip_address_exception.h + ${CMAKE_CURRENT_SOURCE_DIR}/malformed_name_exception.h + ${CMAKE_CURRENT_SOURCE_DIR}/errors.h + ${CMAKE_CURRENT_SOURCE_DIR}/malformed_packet_exception.h + ${CMAKE_CURRENT_SOURCE_DIR}/runtime_exception.h + ${CMAKE_CURRENT_SOURCE_DIR}/tokenizer_exception.h + ${CMAKE_CURRENT_SOURCE_DIR}/null_pointer_exception.h + ${CMAKE_CURRENT_SOURCE_DIR}/malformed_ahpacket_exception.h + ${CMAKE_CURRENT_SOURCE_DIR}/unexpected_manifest_exception.h + ${CMAKE_CURRENT_SOURCE_DIR}/indexing_exception.h +) + +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/errors/errors.h b/libtransport/includes/hicn/transport/errors/errors.h new file mode 100644 index 000000000..512e35736 --- /dev/null +++ b/libtransport/includes/hicn/transport/errors/errors.h @@ -0,0 +1,24 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/errors/indexing_exception.h b/libtransport/includes/hicn/transport/errors/indexing_exception.h new file mode 100644 index 000000000..731314f0e --- /dev/null +++ b/libtransport/includes/hicn/transport/errors/indexing_exception.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace errors { + +class IndexingException : public std::logic_error { + public: + IndexingException() : std::logic_error("") {} + + virtual char const *what() const noexcept override { + return "Impossible to retrieve next index to download."; + } +}; + +} // end namespace errors diff --git a/libtransport/includes/hicn/transport/errors/invalid_ip_address_exception.h b/libtransport/includes/hicn/transport/errors/invalid_ip_address_exception.h new file mode 100644 index 000000000..60226f576 --- /dev/null +++ b/libtransport/includes/hicn/transport/errors/invalid_ip_address_exception.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace errors { + +class InvalidIpAddressException : public std::runtime_error { + public: + InvalidIpAddressException() : std::runtime_error("") {} + + virtual char const *what() const noexcept override { + return "Malformed IP address."; + } +}; + +} // end namespace errors \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/errors/malformed_ahpacket_exception.h b/libtransport/includes/hicn/transport/errors/malformed_ahpacket_exception.h new file mode 100644 index 000000000..f0cfe0b82 --- /dev/null +++ b/libtransport/includes/hicn/transport/errors/malformed_ahpacket_exception.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace errors { + +class MalformedAHPacketException : public std::runtime_error { + public: + MalformedAHPacketException() : std::runtime_error("") {} + + virtual char const *what() const noexcept override { + return "Malformed AH packet."; + } +}; + +} // end namespace errors diff --git a/libtransport/includes/hicn/transport/errors/malformed_name_exception.h b/libtransport/includes/hicn/transport/errors/malformed_name_exception.h new file mode 100644 index 000000000..4ef45d2e8 --- /dev/null +++ b/libtransport/includes/hicn/transport/errors/malformed_name_exception.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace errors { + +class MalformedNameException : public std::runtime_error { + public: + MalformedNameException() : std::runtime_error("") {} + + virtual char const *what() const noexcept override { + return "Malformed IP address."; + } +}; + +} // end namespace errors diff --git a/libtransport/includes/hicn/transport/errors/malformed_packet_exception.h b/libtransport/includes/hicn/transport/errors/malformed_packet_exception.h new file mode 100644 index 000000000..ec5c97e6e --- /dev/null +++ b/libtransport/includes/hicn/transport/errors/malformed_packet_exception.h @@ -0,0 +1,29 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace errors { + +class MalformedPacketException : public std::runtime_error { + public: + MalformedPacketException() : std::runtime_error("") {} + + char const *what() const noexcept override { return "Malformed IP packet."; } +}; + +} // end namespace errors diff --git a/libtransport/includes/hicn/transport/errors/not_implemented_exception.h b/libtransport/includes/hicn/transport/errors/not_implemented_exception.h new file mode 100644 index 000000000..e9869163d --- /dev/null +++ b/libtransport/includes/hicn/transport/errors/not_implemented_exception.h @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace errors { + +class NotImplementedException : public std::logic_error { + public: + NotImplementedException() : std::logic_error("") {} + virtual char const *what() const noexcept override { + return "Function not yet implemented."; + } +}; + +} // end namespace errors diff --git a/libtransport/includes/hicn/transport/errors/null_pointer_exception.h b/libtransport/includes/hicn/transport/errors/null_pointer_exception.h new file mode 100644 index 000000000..bd06485ed --- /dev/null +++ b/libtransport/includes/hicn/transport/errors/null_pointer_exception.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace errors { + +class NullPointerException : public std::runtime_error { + public: + NullPointerException() : std::runtime_error("") {} + + char const *what() const noexcept override { + return "Null pointer exception."; + } +}; + +} // end namespace errors diff --git a/libtransport/includes/hicn/transport/errors/runtime_exception.h b/libtransport/includes/hicn/transport/errors/runtime_exception.h new file mode 100644 index 000000000..ba5128a7e --- /dev/null +++ b/libtransport/includes/hicn/transport/errors/runtime_exception.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include + +namespace errors { + +class RuntimeException : public std::runtime_error { + public: + RuntimeException() : std::runtime_error("") {} + + RuntimeException(std::string what) : runtime_error(what){}; +}; + +} // end namespace errors \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/errors/tokenizer_exception.h b/libtransport/includes/hicn/transport/errors/tokenizer_exception.h new file mode 100644 index 000000000..76eda838e --- /dev/null +++ b/libtransport/includes/hicn/transport/errors/tokenizer_exception.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace errors { + +class TokenizerException : public std::logic_error { + public: + TokenizerException() : std::logic_error("") {} + + virtual char const *what() const noexcept override { + return "No more tokens available."; + } +}; + +} // end namespace errors diff --git a/libtransport/includes/hicn/transport/errors/unexpected_manifest_exception.h b/libtransport/includes/hicn/transport/errors/unexpected_manifest_exception.h new file mode 100644 index 000000000..6f71471e4 --- /dev/null +++ b/libtransport/includes/hicn/transport/errors/unexpected_manifest_exception.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace errors { + +class UnexpectedManifestException : public std::logic_error { + public: + UnexpectedManifestException() : std::logic_error("") {} + + virtual char const *what() const noexcept override { + return "Received unexpected manifest."; + } +}; + +} // end namespace errors diff --git a/libtransport/includes/hicn/transport/http/CMakeLists.txt b/libtransport/includes/hicn/transport/http/CMakeLists.txt new file mode 100644 index 000000000..9cf618c21 --- /dev/null +++ b/libtransport/includes/hicn/transport/http/CMakeLists.txt @@ -0,0 +1,25 @@ +# Copyright (c) 2017-2020 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) + +list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/client_connection.h + ${CMAKE_CURRENT_SOURCE_DIR}/request.h + ${CMAKE_CURRENT_SOURCE_DIR}/default_values.h + ${CMAKE_CURRENT_SOURCE_DIR}/facade.h + ${CMAKE_CURRENT_SOURCE_DIR}/response.h + ${CMAKE_CURRENT_SOURCE_DIR}/message.h +) + +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/http/client_connection.h b/libtransport/includes/hicn/transport/http/client_connection.h new file mode 100644 index 000000000..262756a09 --- /dev/null +++ b/libtransport/includes/hicn/transport/http/client_connection.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2017-2020 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 +#include +#include +#include +#include +#include + +#include + +namespace transport { + +namespace http { + +using namespace interface; +using namespace core; + +class HTTPClientConnection { + static constexpr uint32_t max_buffer_capacity = 64 * 1024; + + public: + class ReadBytesCallback { + public: + virtual void onBytesReceived(std::unique_ptr &&buffer) = 0; + virtual void onSuccess(std::size_t bytes) = 0; + virtual void onError(const std::error_code ec) = 0; + }; + + enum class RC : uint32_t { DOWNLOAD_FAILED, DOWNLOAD_SUCCESS }; + + HTTPClientConnection(); + + ~HTTPClientConnection(); + + RC get(const std::string &url, HTTPHeaders headers = {}, + HTTPPayload &&payload = nullptr, + std::shared_ptr response = nullptr, + ReadBytesCallback *callback = nullptr, + std::string ipv6_first_word = "b001"); + + RC sendRequest(const std::string &url, HTTPMethod method, + HTTPHeaders headers = {}, HTTPPayload &&payload = nullptr, + std::shared_ptr response = nullptr, + ReadBytesCallback *callback = nullptr, + std::string ipv6_first_word = "b001"); + + std::shared_ptr response(); + + HTTPClientConnection &stop(); + + interface::ConsumerSocket &getConsumer(); + + HTTPClientConnection &setTimeout(const std::chrono::seconds &timeout); + + HTTPClientConnection &setCertificate(const std::string &cert_path); + + private: + class Implementation; + Implementation *implementation_; +}; + +} // end namespace http + +} // end namespace transport \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/http/default_values.h b/libtransport/includes/hicn/transport/http/default_values.h new file mode 100644 index 000000000..2d5a6b821 --- /dev/null +++ b/libtransport/includes/hicn/transport/http/default_values.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace transport { + +namespace http { + +namespace default_values { + +const uint16_t ipv6_first_word = 0xb001; // Network byte order + +} // namespace default_values + +} // namespace http + +} // end namespace transport diff --git a/libtransport/includes/hicn/transport/http/facade.h b/libtransport/includes/hicn/transport/http/facade.h new file mode 100644 index 000000000..8a465ce94 --- /dev/null +++ b/libtransport/includes/hicn/transport/http/facade.h @@ -0,0 +1,20 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace libl4 = transport; \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/http/message.h b/libtransport/includes/hicn/transport/http/message.h new file mode 100644 index 000000000..b8756224f --- /dev/null +++ b/libtransport/includes/hicn/transport/http/message.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2017-2020 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 + +#ifdef _WIN32 +#include +#endif + +#include + +#include +#include +#include + +#define HTTP_VERSION "1.1" + +namespace transport { + +namespace http { + +typedef enum { GET, POST, PUT, PATCH, DELETE } HTTPMethod; + +static std::map method_map = { + {GET, "GET"}, {POST, "POST"}, {PUT, "PUT"}, + {PATCH, "PATCH"}, {DELETE, "DELETE"}, +}; + +typedef std::map HTTPHeaders; +typedef std::unique_ptr HTTPPayload; + +class HTTPMessage { + public: + virtual ~HTTPMessage() = default; + + const HTTPHeaders getHeaders() { return headers_; }; + + void coalescePayloadBuffer() { + auto it = headers_.find("Content-Length"); + if (it != headers_.end()) { + auto content_length = std::stoul(it->second); + payload_->gather(content_length); + } + } + + HTTPPayload &&getPayload() { return std::move(payload_); } + + std::string getHttpVersion() const { return http_version_; }; + + protected: + HTTPHeaders headers_; + HTTPPayload payload_; + std::string http_version_; +}; + +} // end namespace http + +} // end namespace transport \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/http/request.h b/libtransport/includes/hicn/transport/http/request.h new file mode 100644 index 000000000..54904d696 --- /dev/null +++ b/libtransport/includes/hicn/transport/http/request.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2017-2020 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 + +#include +#include +#include + +namespace transport { + +namespace http { + +class HTTPRequest : public HTTPMessage { + public: + HTTPRequest(); + HTTPRequest(HTTPMethod method, const std::string &url, + const HTTPHeaders &headers, HTTPPayload &&payload); + + void init(HTTPMethod method, const std::string &url, + const HTTPHeaders &headers, HTTPPayload &&payload); + + std::string getQueryString() const; + + std::string getPath() const; + + std::string getProtocol() const; + + std::string getLocator() const; + + std::string getPort() const; + + std::string getRequestString() const; + + private: + std::string query_string_, path_, protocol_, locator_, port_; + std::string request_string_; +}; + +} // end namespace http + +} // end namespace transport \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/http/response.h b/libtransport/includes/hicn/transport/http/response.h new file mode 100644 index 000000000..bab41acb8 --- /dev/null +++ b/libtransport/includes/hicn/transport/http/response.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017-2020 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 +#include + +#include +#include +#include + +namespace transport { + +namespace http { + +class HTTPResponse : public HTTPMessage { + public: + HTTPResponse(); + + HTTPResponse(std::unique_ptr &&response); + + void appendResponseChunk(std::unique_ptr &&response_chunk); + + const std::string &getStatusCode() const; + + const std::string &getStatusString() const; + + void parse(std::unique_ptr &&response); + + bool parseHeaders(std::unique_ptr &&buffer); + + static std::size_t parseHeaders(const uint8_t *buffer, std::size_t size, + HTTPHeaders &headers, + std::string &http_version, + std::string &status_code, + std::string &status_string); + + private: + std::string status_code_; + std::string status_string_; +}; + +} // end namespace http + +} // end namespace transport \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/interfaces/CMakeLists.txt b/libtransport/includes/hicn/transport/interfaces/CMakeLists.txt new file mode 100644 index 000000000..38e6143f0 --- /dev/null +++ b/libtransport/includes/hicn/transport/interfaces/CMakeLists.txt @@ -0,0 +1,35 @@ +# 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) + +list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/socket_consumer.h + ${CMAKE_CURRENT_SOURCE_DIR}/socket_producer.h + ${CMAKE_CURRENT_SOURCE_DIR}/rtc_socket_producer.h + ${CMAKE_CURRENT_SOURCE_DIR}/publication_options.h + ${CMAKE_CURRENT_SOURCE_DIR}/socket_options_default_values.h + ${CMAKE_CURRENT_SOURCE_DIR}/socket_options_keys.h + ${CMAKE_CURRENT_SOURCE_DIR}/callbacks.h + ${CMAKE_CURRENT_SOURCE_DIR}/verification_policy.h + ${CMAKE_CURRENT_SOURCE_DIR}/statistics.h +) + +if (${OPENSSL_VERSION} VERSION_EQUAL "1.1.1a" OR ${OPENSSL_VERSION} VERSION_GREATER "1.1.1a") + list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_producer.h + ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_consumer.h + ) +endif() + +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) diff --git a/libtransport/includes/hicn/transport/interfaces/callbacks.h b/libtransport/includes/hicn/transport/interfaces/callbacks.h new file mode 100644 index 000000000..6ae07797e --- /dev/null +++ b/libtransport/includes/hicn/transport/interfaces/callbacks.h @@ -0,0 +1,116 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +#include +#include + +namespace utils { +class MemBuf; +} + +namespace transport { + +namespace protocol { + +class IcnObserver; + +} // namespace protocol + +namespace core { +class ContentObject; +class Interest; +} // namespace core + +namespace interface { + +// Forward declarations +class ConsumerSocket; +class ProducerSocket; + +/** + * The ConsumerInterestCallback will be called in different parts of the + * consumer socket processing pipeline, with a ConsumerSocket and an Interest as + * parameters. + */ +using ConsumerInterestCallback = + std::function; + +/** + * The ConsumerTimerCallback is called periodically for exposing to applications + * a summary of the statistics of the transport protocol in use. + */ +using ConsumerTimerCallback = + std::function; + +/** + * The ProducerContentCallback will be called by the producer socket right after + * a content has been segmented and published. + */ +using ProducerContentCallback = std::function; + +/** + * The ConsumerContentObjectCallback will be called in different parts of the + * consumer socket processing pipeline, with a ConsumerSocket and an + * ContentObject as parameters. + */ +using ConsumerContentObjectCallback = + std::function; + +/** + * The ConsumerContentObjectVerificationCallback will be called by the transport + * if an application is willing to verify each content object. Note that a + * better alternative is to instrument the transport to perform the verification + * autonomously, without requiring the intervention of the application. + */ +using ConsumerContentObjectVerificationCallback = + std::function; + +/** + * The ConsumerContentObjectVerificationFailedCallback will be caled by the + * transport if a data packet (either manifest or content object) cannot be + * verified. The application here decides what to do by returning a + * VerificationFailedPolicy object. + */ +using ConsumerContentObjectVerificationFailedCallback = + std::function; + +/** + * The ProducerContentObjectCallback will be called in different parts of the + * consumer socket processing pipeline, with a ProducerSocket and an + * ContentObject as parameters. + */ +using ProducerContentObjectCallback = + std::function; + +/** + * The ProducerContentObjectCallback will be called in different parts of the + * consumer socket processing pipeline, with a ProducerSocket and an + * Interest as parameters. + */ +using ProducerInterestCallback = + std::function; + +extern std::nullptr_t VOID_HANDLER; + +} // namespace interface + +} // namespace transport diff --git a/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_consumer.h b/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_consumer.h new file mode 100644 index 000000000..097b0a8c0 --- /dev/null +++ b/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_consumer.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 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 + +namespace transport { + +namespace interface { + +class P2PSecureConsumerSocket : public ConsumerSocket { + public: + P2PSecureConsumerSocket(int handshake_protocol, int protocol); + ~P2PSecureConsumerSocket() = default; +}; + +} // namespace interface + +} // end namespace transport diff --git a/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_producer.h b/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_producer.h new file mode 100644 index 000000000..6f0d48bb9 --- /dev/null +++ b/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_producer.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 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 + +#include + +namespace transport { + +namespace interface { + +class P2PSecureProducerSocket : public ProducerSocket { + public: + P2PSecureProducerSocket(); + P2PSecureProducerSocket(bool rtc, + const std::shared_ptr &identity); + ~P2PSecureProducerSocket() = default; +}; + +} // namespace interface + +} // end namespace transport diff --git a/libtransport/includes/hicn/transport/interfaces/publication_options.h b/libtransport/includes/hicn/transport/interfaces/publication_options.h new file mode 100644 index 000000000..6910e5371 --- /dev/null +++ b/libtransport/includes/hicn/transport/interfaces/publication_options.h @@ -0,0 +1,43 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace transport { + +namespace interface { + +class PublicationOptions { + public: + template + PublicationOptions(T&& name, uint32_t lifetime) + : name_(std::forward(name)), + content_lifetime_milliseconds_(lifetime) {} + + TRANSPORT_ALWAYS_INLINE const core::Name& getName() const { return name_; } + TRANSPORT_ALWAYS_INLINE uint32_t getLifetime() const { + return content_lifetime_milliseconds_; + } + + private: + core::Name name_; + uint32_t content_lifetime_milliseconds_; + // TODO Signature +}; +} // namespace interface + +} // namespace transport \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/interfaces/rtc_socket_producer.h b/libtransport/includes/hicn/transport/interfaces/rtc_socket_producer.h new file mode 100644 index 000000000..218240f83 --- /dev/null +++ b/libtransport/includes/hicn/transport/interfaces/rtc_socket_producer.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 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 + +namespace transport { + +namespace interface { + +class RTCProducerSocket : public ProducerSocket { + public: + RTCProducerSocket(); + ~RTCProducerSocket() = default; +}; + +} // namespace interface + +} // end namespace transport diff --git a/libtransport/includes/hicn/transport/interfaces/socket_consumer.h b/libtransport/includes/hicn/transport/interfaces/socket_consumer.h new file mode 100644 index 000000000..e9e671edd --- /dev/null +++ b/libtransport/includes/hicn/transport/interfaces/socket_consumer.h @@ -0,0 +1,298 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define CONSUMER_FINISHED 0 +#define CONSUMER_BUSY 1 +#define CONSUMER_RUNNING 2 + +namespace transport { + +namespace implementation { +class ConsumerSocket; +} + +namespace interface { + +using namespace core; + +/** + * @brief Main interface for consumer applications. + * + * The consumer socket is the main interface for a consumer application. + * It allows to retrieve an application data from one/many producers, by + * hiding all the complexity of the transport protocol used underneath. + */ +class ConsumerSocket { + public: + /** + * The ReadCallback is a class which can be used by the transport for both + * querying the application needs and notifying events. + * + * Beware that the methods of this class will be called synchronously while + * the transport is working, so the operations the application is performing + * on the data retrieved should be executed in another thread in an + * asynchronous manner. Blocking one of these callbacks means blocking the + * transport. + */ + class ReadCallback { + public: + virtual ~ReadCallback() = default; + + /** + * This API will specify to the transport whether the buffer should be + * allocated by the application (and then the retrieved content will be + * copied there) or the transport should allocate the buffer and "move" it + * to the application. In other words, if isBufferMovable return true, the + * transport will transfer the ownership of the read buffer to the + * application, without performing an additional copy, while if it returns + * false the transport will use the getReadBuffer API. + * + * By default this method returns true. + * + */ + virtual bool isBufferMovable() noexcept { return true; } + + /** + * This method will be called by the transport when the content is + * available. The application can then allocate its own buffer and provide + * the address to the transport, which will use it for writing the data. + * Note that if the application won't allocate enough memory this method + * will be called several times, until the internal read buffer will be + * emptied. For ensuring this method will be called once, applications + * should allocate at least maxBufferSize() bytes. + * + * @param application_buffer - Pointer to the application's buffer. + * @param max_length - The length of the application buffer. + */ + virtual void getReadBuffer(uint8_t **application_buffer, + size_t *max_length) = 0; + + /** + * This method will be called by the transport after calling getReadBuffer, + * in order to notify the application that length bytes are available in the + * buffer. The max_length size of the buffer could be larger than the actual + * amount of bytes written. + * + * @param length - The number of bytes placed in the buffer. + */ + virtual void readDataAvailable(size_t length) noexcept = 0; + + /** + * This method will be called by the transport for understanding how many + * bytes it should read (at most) before notifying the application. + * + * By default it reads 64 KB. + */ + virtual size_t maxBufferSize() const { return 64 * 1024; } + + /** + * This method will be called by the transport iff (isBufferMovable == + * true). The unique_ptr underlines the fact that the ownership of the + * buffer is being transferred to the application. + * + * @param buffer - The buffer + */ + virtual void readBufferAvailable( + std::unique_ptr &&buffer) noexcept {} + + /** + * readError() will be invoked if an error occurs reading from the + * transport. + * + * @param ec - An error code describing the error. + */ + virtual void readError(const std::error_code ec) noexcept = 0; + + /** + * This callback will be invoked when the whole content is retrieved. The + * transport itself knows when a content is retrieved (since it is not an + * opaque bytestream like TCP), and the transport itself is able to tell + * the application when the transfer is done. + */ + virtual void readSuccess(std::size_t total_size) noexcept = 0; + }; + + /** + * @brief Create a new consumer socket. + * + * @param protocol - The transport protocol to use. So far the following + * transport are supported: + * - CBR: Constant bitrate + * - Raaqm: Based on paper: Optimal multipath congestion control and request + * forwarding in information-centric networks: Protocol design and + * experimentation. G Carofiglio, M Gallo, L Muscariello. Computer Networks + * 110, 104-117 + * - RTC: Real time communication + */ + explicit ConsumerSocket(int protocol); + + /** + * @brief Destroy the consumer socket. + */ + ~ConsumerSocket(); + + /** + * @brief Connect the consumer socket to the underlying hICN forwarder. + */ + void connect(); + + /** + * @brief Check whether consumer socket is active or not. + */ + bool isRunning(); + + /** + * Retrieve a content using the protocol specified in the constructor. + * This function blocks until the whole content is downloaded. + * For monitoring the status of the download, the application MUST set the + * ConsumerRead callback. This callback will be called periodically (depending + * on the needs of the application), allowing the application to save the + * retrieved data. + * + * @param name - The name of the content to retrieve. + * + * @return CONSUMER_BUSY if a pending download exists + * @return CONSUMER_FINISHED when the download finishes + * + * Notice that the fact consume() returns CONSUMER_FINISHED does not imply the + * content retrieval succeeded. This information can be obtained from the + * error code in CONTENT_RETRIEVED callback. + */ + int consume(const Name &name); + int asyncConsume(const Name &name); + + /** + * Verify the packets containing a key after the origin of the key has been + * validated by the client. + * + * @return true if all packets are valid, false otherwise + */ + bool verifyKeyPackets(); + + /** + * Stops the consumer socket. If several downloads are queued (using + * asyncConsume), this call stops just the current one. + */ + void stop(); + + /** + * Resume the download from the same exact point it stopped. + */ + void resume(); + + /** + * Get the io_service which is running the transport protocol event loop. + * + * @return A reference to the internal io_service where the transport protocol + * is running. + */ + asio::io_service &getIoService(); + + int setSocketOption(int socket_option_key, ReadCallback *socket_option_value); + + int getSocketOption(int socket_option_key, + ReadCallback **socket_option_value); + + int setSocketOption(int socket_option_key, double socket_option_value); + + int setSocketOption(int socket_option_key, uint32_t socket_option_value); + + int setSocketOption(int socket_option_key, + std::nullptr_t socket_option_value); + + int setSocketOption(int socket_option_key, bool socket_option_value); + + int setSocketOption(int socket_option_key, + ConsumerContentObjectCallback socket_option_value); + + int setSocketOption( + int socket_option_key, + ConsumerContentObjectVerificationFailedCallback socket_option_value); + + int setSocketOption( + int socket_option_key, + ConsumerContentObjectVerificationCallback socket_option_value); + + int setSocketOption(int socket_option_key, + ConsumerInterestCallback socket_option_value); + + int setSocketOption(int socket_option_key, + interface::IcnObserver *socket_option_value); + + int setSocketOption( + int socket_option_key, + const std::shared_ptr &socket_option_value); + + int setSocketOption(int socket_option_key, + const std::string &socket_option_value); + + int setSocketOption(int socket_option_key, + ConsumerTimerCallback socket_option_value); + + int getSocketOption(int socket_option_key, double &socket_option_value); + + int getSocketOption(int socket_option_key, uint32_t &socket_option_value); + + int getSocketOption(int socket_option_key, bool &socket_option_value); + + int getSocketOption(int socket_option_key, Name **socket_option_value); + + int getSocketOption(int socket_option_key, + ConsumerContentObjectCallback **socket_option_value); + + int getSocketOption( + int socket_option_key, + ConsumerContentObjectVerificationFailedCallback **socket_option_value); + + int getSocketOption( + int socket_option_key, + ConsumerContentObjectVerificationCallback **socket_option_value); + + int getSocketOption(int socket_option_key, + ConsumerInterestCallback **socket_option_value); + + int getSocketOption(int socket_option_key, IcnObserver **socket_option_value); + + int getSocketOption(int socket_option_key, + std::shared_ptr &socket_option_value); + + int getSocketOption(int socket_option_key, std::string &socket_option_value); + + int getSocketOption(int socket_option_key, + ConsumerTimerCallback **socket_option_value); + + int getSocketOption(int socket_option_key, + interface::TransportStatistics **socket_option_value); + + protected: + ConsumerSocket(); + std::unique_ptr socket_; +}; + +} // namespace interface + +} // end namespace transport diff --git a/libtransport/includes/hicn/transport/interfaces/socket_options_default_values.h b/libtransport/includes/hicn/transport/interfaces/socket_options_default_values.h new file mode 100644 index 000000000..bcf103b8c --- /dev/null +++ b/libtransport/includes/hicn/transport/interfaces/socket_options_default_values.h @@ -0,0 +1,69 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include + +namespace transport { + +namespace interface { + +namespace default_values { + +static constexpr uint32_t interest_lifetime = 1001; // milliseconds +static constexpr uint32_t never_expire_time = HICN_MAX_LIFETIME; +static constexpr uint32_t content_object_expiry_time = + never_expire_time; // milliseconds -> 50 seconds +static constexpr uint32_t content_object_packet_size = + 1500; // The ethernet MTU +static constexpr uint32_t producer_socket_output_buffer_size = + 150000; // Content Object +static constexpr uint32_t log_2_default_buffer_size = 12; +static constexpr uint32_t signature_size = 260; // bytes +static constexpr uint32_t key_locator_size = 60; // bytes +static constexpr uint32_t limit_guard = 80; // bytes +static constexpr uint32_t digest_size = 34; // bytes +static constexpr uint32_t max_out_of_order_segments = 3; // content object + +// RAAQM +static constexpr int sample_number = 30; +static constexpr double gamma_value = 1; +static constexpr double beta_value = 0.8; +static constexpr double drop_factor = 0.2; +static constexpr double minimum_drop_probability = 0.00001; +static constexpr int path_id = 0; +static constexpr double rate_alpha = 0.8; + +// Rate estimation +static constexpr uint32_t batch = 50; +static constexpr uint32_t kv = 20; +static constexpr double alpha = 0.8; +static constexpr uint32_t rate_choice = 0; + +// maximum allowed values +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 + +} // namespace default_values + +} // namespace interface + +} // end namespace transport diff --git a/libtransport/includes/hicn/transport/interfaces/socket_options_keys.h b/libtransport/includes/hicn/transport/interfaces/socket_options_keys.h new file mode 100644 index 000000000..7910a4422 --- /dev/null +++ b/libtransport/includes/hicn/transport/interfaces/socket_options_keys.h @@ -0,0 +1,118 @@ +/* + * 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. + */ + +#pragma once + +#define SOCKET_OPTION_GET 0 +#define SOCKET_OPTION_NOT_GET 1 +#define SOCKET_OPTION_SET 2 +#define SOCKET_OPTION_NOT_SET 3 +#define SOCKET_OPTION_DEFAULT 12345 + +namespace transport { + +namespace interface { + +typedef enum { + RAAQM = 0, + CBR = 1, + RTC = 2, +} TransportProtocolAlgorithms; + +typedef enum { + INPUT_BUFFER_SIZE = 101, + OUTPUT_BUFFER_SIZE = 102, + NETWORK_NAME = 103, + NAME_SUFFIX = 104, + MAX_INTEREST_RETX = 105, + DATA_PACKET_SIZE = 106, + INTEREST_LIFETIME = 107, + CONTENT_OBJECT_EXPIRY_TIME = 108, + KEY_CONTENT = 110, + MIN_WINDOW_SIZE = 111, + MAX_WINDOW_SIZE = 112, + CURRENT_WINDOW_SIZE = 113, + ASYNC_MODE = 114, + MAKE_MANIFEST = 115, + PORTAL = 116, + RUNNING = 117, + APPLICATION_BUFFER = 118, + HASH_ALGORITHM = 119, + CRYPTO_SUITE = 120, + SIGNER = 121, + VERIFIER = 122, + CERTIFICATE = 123, + VERIFY_SIGNATURE = 124, + STATS_INTERVAL = 125, +} GeneralTransportOptions; + +typedef enum { + SAMPLE_NUMBER = 201, + GAMMA_VALUE = 202, + BETA_VALUE = 203, + DROP_FACTOR = 204, + MINIMUM_DROP_PROBABILITY = 205, + PATH_ID = 206, + RTT_STATS = 207, +} RaaqmTransportOptions; + +typedef enum { + RATE_ESTIMATION_ALPHA = 301, + RATE_ESTIMATION_OBSERVER = 302, + RATE_ESTIMATION_BATCH_PARAMETER = 303, + RATE_ESTIMATION_CHOICE = 304, +} RateEstimationOptions; + +typedef enum { + INTEREST_OUTPUT = 401, + INTEREST_RETRANSMISSION = 402, + INTEREST_EXPIRED = 403, + INTEREST_SATISFIED = 404, + CONTENT_OBJECT_INPUT = 411, + CONTENT_OBJECT_TO_VERIFY = 413, + VERIFICATION_FAILED = 414, + READ_CALLBACK = 415, + STATS_SUMMARY = 416 +} ConsumerCallbacksOptions; + +typedef enum { + INTEREST_INPUT = 501, + INTEREST_DROP = 502, + INTEREST_PASS = 503, + CACHE_HIT = 506, + CACHE_MISS = 508, + NEW_CONTENT_OBJECT = 509, + CONTENT_OBJECT_SIGN = 513, + CONTENT_OBJECT_READY = 510, + CONTENT_OBJECT_OUTPUT = 511, + CONTENT_PRODUCED = 512, +} ProducerCallbacksOptions; + +typedef enum { OUTPUT_INTERFACE = 601 } DataLinkOptions; + +typedef enum { + VIRTUAL_DOWNLOAD = 701, + USE_CFG_FILE = 702, + STATISTICS +} OtherOptions; + +typedef enum { + SHA_256 = 801, + RSA_256 = 802, +} SignatureType; + +} // namespace interface + +} // end namespace transport diff --git a/libtransport/includes/hicn/transport/interfaces/socket_producer.h b/libtransport/includes/hicn/transport/interfaces/socket_producer.h new file mode 100644 index 000000000..3fe99fbd4 --- /dev/null +++ b/libtransport/includes/hicn/transport/interfaces/socket_producer.h @@ -0,0 +1,149 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace transport { + +namespace implementation { +class ProducerSocket; +} + +namespace interface { + +using namespace core; + +class ProducerSocket { + public: + explicit ProducerSocket(int protocol = 0); + + virtual ~ProducerSocket(); + + void connect(); + + bool isRunning(); + + uint32_t produce(Name content_name, const uint8_t *buffer, size_t buffer_size, + bool is_last = true, uint32_t start_offset = 0) { + return produce(content_name, utils::MemBuf::copyBuffer(buffer, buffer_size), + is_last, start_offset); + } + + uint32_t produce(Name content_name, std::unique_ptr &&buffer, + bool is_last = true, uint32_t start_offset = 0); + + void produce(ContentObject &content_object); + + void produce(const uint8_t *buffer, size_t buffer_size) { + produce(utils::MemBuf::copyBuffer(buffer, buffer_size)); + } + + void produce(std::unique_ptr &&buffer); + + void asyncProduce(const Name &suffix, const uint8_t *buf, size_t buffer_size, + bool is_last = true, uint32_t *start_offset = nullptr); + + void asyncProduce(Name content_name, std::unique_ptr &&buffer, + bool is_last, uint32_t offset, + uint32_t **last_segment = nullptr); + + void asyncProduce(ContentObject &content_object); + + void registerPrefix(const Prefix &producer_namespace); + + void serveForever(); + + void stop(); + + asio::io_service &getIoService(); + + int setSocketOption(int socket_option_key, uint32_t socket_option_value); + + int setSocketOption(int socket_option_key, + std::nullptr_t socket_option_value); + + int setSocketOption(int socket_option_key, bool socket_option_value); + + int setSocketOption(int socket_option_key, Name *socket_option_value); + + int setSocketOption(int socket_option_key, + std::list socket_option_value); + + int setSocketOption(int socket_option_key, + ProducerContentObjectCallback socket_option_value); + + int setSocketOption(int socket_option_key, + ProducerInterestCallback socket_option_value); + + int setSocketOption(int socket_option_key, + ProducerContentCallback socket_option_value); + + int setSocketOption(int socket_option_key, HashAlgorithm socket_option_value); + + int setSocketOption(int socket_option_key, + utils::CryptoSuite socket_option_value); + + int setSocketOption( + int socket_option_key, + const std::shared_ptr &socket_option_value); + + int setSocketOption(int socket_option_key, + const std::string &socket_option_value); + + int getSocketOption(int socket_option_key, uint32_t &socket_option_value); + + int getSocketOption(int socket_option_key, bool &socket_option_value); + + int getSocketOption(int socket_option_key, + std::list &socket_option_value); + + int getSocketOption(int socket_option_key, + ProducerContentObjectCallback **socket_option_value); + + int getSocketOption(int socket_option_key, + ProducerContentCallback **socket_option_value); + + int getSocketOption(int socket_option_key, + ProducerInterestCallback **socket_option_value); + + int getSocketOption(int socket_option_key, + HashAlgorithm &socket_option_value); + + int getSocketOption(int socket_option_key, + utils::CryptoSuite &socket_option_value); + + int getSocketOption(int socket_option_key, + std::shared_ptr &socket_option_value); + + int getSocketOption(int socket_option_key, std::string &socket_option_value); + + protected: + ProducerSocket(bool); + std::unique_ptr socket_; +}; + +} // namespace interface + +} // namespace transport diff --git a/libtransport/includes/hicn/transport/interfaces/statistics.h b/libtransport/includes/hicn/transport/interfaces/statistics.h new file mode 100644 index 000000000..26831fbf1 --- /dev/null +++ b/libtransport/includes/hicn/transport/interfaces/statistics.h @@ -0,0 +1,121 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include + +namespace transport { + +namespace interface { + +class IcnObserver { + public: + virtual ~IcnObserver(){}; + + virtual void notifyStats(double throughput) = 0; + virtual void notifyDownloadTime(double downloadTime) = 0; +}; + +class TransportStatistics { + static constexpr double default_alpha = 0.7; + + public: + TransportStatistics(double alpha = default_alpha) + : retx_count_(0), + bytes_received_(0), + average_rtt_(0), + avg_window_size_(0), + interest_tx_(0), + alpha_(alpha), + loss_ratio_(0.0), + queuing_delay_(0.0) {} + + TRANSPORT_ALWAYS_INLINE void updateRetxCount(uint64_t retx) { + retx_count_ += retx; + } + + TRANSPORT_ALWAYS_INLINE void updateBytesRecv(uint64_t bytes) { + bytes_received_ += bytes; + } + + TRANSPORT_ALWAYS_INLINE void updateAverageRtt(uint64_t rtt) { + average_rtt_ = (alpha_ * average_rtt_) + ((1. - alpha_) * double(rtt)); + } + + TRANSPORT_ALWAYS_INLINE void updateAverageWindowSize(double current_window) { + avg_window_size_ = + (alpha_ * avg_window_size_) + ((1. - alpha_) * current_window); + } + + TRANSPORT_ALWAYS_INLINE void updateInterestTx(uint64_t int_tx) { + interest_tx_ += int_tx; + } + + TRANSPORT_ALWAYS_INLINE void updateLossRatio(double loss_ratio) { + loss_ratio_ = loss_ratio; + } + + TRANSPORT_ALWAYS_INLINE void updateQueuingDelay(double queuing_delay) { + queuing_delay_ = queuing_delay; + } + + TRANSPORT_ALWAYS_INLINE uint64_t getRetxCount() const { return retx_count_; } + + TRANSPORT_ALWAYS_INLINE uint64_t getBytesRecv() const { + return bytes_received_; + } + + TRANSPORT_ALWAYS_INLINE double getAverageRtt() const { return average_rtt_; } + + TRANSPORT_ALWAYS_INLINE double getAverageWindowSize() const { + return avg_window_size_; + } + + TRANSPORT_ALWAYS_INLINE uint64_t getInterestTx() const { + return interest_tx_; + } + + TRANSPORT_ALWAYS_INLINE double getLossRatio() const { return loss_ratio_; } + + TRANSPORT_ALWAYS_INLINE double getQueuingDelay() const { + return queuing_delay_; + } + + TRANSPORT_ALWAYS_INLINE void reset() { + retx_count_ = 0; + bytes_received_ = 0; + average_rtt_ = 0; + avg_window_size_ = 0; + interest_tx_ = 0; + loss_ratio_ = 0; + } + + private: + uint64_t retx_count_; + uint64_t bytes_received_; + double average_rtt_; + double avg_window_size_; + uint64_t interest_tx_; + double alpha_; + double loss_ratio_; + double queuing_delay_; +}; + +} // namespace interface + +} // end namespace transport diff --git a/libtransport/includes/hicn/transport/interfaces/verification_policy.h b/libtransport/includes/hicn/transport/interfaces/verification_policy.h new file mode 100644 index 000000000..cb5140ac1 --- /dev/null +++ b/libtransport/includes/hicn/transport/interfaces/verification_policy.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020 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 + +namespace transport { +namespace interface { + +/** + * This policy allows the application to tell the transport what to do in case + * the verification of a content object fails. + */ +enum class VerificationPolicy : std::uint8_t { + DROP_PACKET, + ACCEPT_PACKET, + ABORT_SESSION +}; +} // namespace interface +} // namespace transport \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/portability/CMakeLists.txt b/libtransport/includes/hicn/transport/portability/CMakeLists.txt new file mode 100644 index 000000000..469b11192 --- /dev/null +++ b/libtransport/includes/hicn/transport/portability/CMakeLists.txt @@ -0,0 +1,31 @@ +# 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) + +list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/c_portability.h + ${CMAKE_CURRENT_SOURCE_DIR}/portability.h +) + +list(APPEND SOURCE_FILES + "" +) + +if(WIN32) + list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/win_portability.h + ) +endif() + +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/portability/c_portability.h b/libtransport/includes/hicn/transport/portability/c_portability.h new file mode 100644 index 000000000..71e976a81 --- /dev/null +++ b/libtransport/includes/hicn/transport/portability/c_portability.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright 2017 Facebook, Inc. + * + * 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 + +// noinline +#ifdef _MSC_VER +#define TRANSPORT_NOINLINE __declspec(noinline) +#elif defined(__clang__) || defined(__GNUC__) +#define TRANSPORT_NOINLINE __attribute__((__noinline__)) +#else +#define TRANSPORT_NOINLINE +#endif + +// always inline +#ifdef _MSC_VER +#define TRANSPORT_ALWAYS_INLINE __forceinline +#elif defined(__clang__) || defined(__GNUC__) +#define TRANSPORT_ALWAYS_INLINE inline __attribute__((__always_inline__)) +#else +#define TRANSPORT_ALWAYS_INLINE inline +#endif \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/portability/portability.h b/libtransport/includes/hicn/transport/portability/portability.h new file mode 100644 index 000000000..1d97a346e --- /dev/null +++ b/libtransport/includes/hicn/transport/portability/portability.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright 2017 Facebook, Inc. + * + * 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 + +#ifdef _WIN32 +#include +#endif + +#include + +#include +#include + +namespace portability { + +constexpr bool little_endian_arch = __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__; +constexpr bool big_endian_arch = !little_endian_arch; + +#if defined(__GNUC__) +#define _TRANSPORT_GNU_DISABLE_WARNING(warning) #warning +#define TRANSPORT_GNU_DISABLE_WARNING(warning) \ + _Pragma(_TRANSPORT_GNU_DISABLE_WARNING(GCC diagnostic ignored warning)) + +#ifdef __clang__ +#define TRANSPORT_CLANG_DISABLE_WARNING(warning) \ + TRANSPORT_GNU_DISABLE_WARNING(warning) +#define TRANSPORT_GCC_DISABLE_WARNING(warning) +#else +#define TRANSPORT_CLANG_DISABLE_WARNING(warning) +#define TRANSPORT_GCC_DISABLE_WARNING(warning) \ + TRANSPORT_GNU_DISABLE_WARNING(warning) +#endif +#endif + +} // namespace portability diff --git a/libtransport/includes/hicn/transport/portability/win_portability.h b/libtransport/includes/hicn/transport/portability/win_portability.h new file mode 100644 index 000000000..65d949291 --- /dev/null +++ b/libtransport/includes/hicn/transport/portability/win_portability.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright 2017 Facebook, Inc. + * + * 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 +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define __ORDER_LITTLE_ENDIAN__ 0x41424344UL +#define __ORDER_BIG_ENDIAN__ 0x44434241UL +#define __BYTE_ORDER__ ('ABCD') +#undef DELETE + +#define HAVE_STRUCT_TIMESPEC +#include \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/security/CMakeLists.txt b/libtransport/includes/hicn/transport/security/CMakeLists.txt new file mode 100644 index 000000000..58a96780b --- /dev/null +++ b/libtransport/includes/hicn/transport/security/CMakeLists.txt @@ -0,0 +1,27 @@ +# 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) + +list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/signer.h + ${CMAKE_CURRENT_SOURCE_DIR}/verifier.h + ${CMAKE_CURRENT_SOURCE_DIR}/crypto_hasher.h + ${CMAKE_CURRENT_SOURCE_DIR}/crypto_suite.h + ${CMAKE_CURRENT_SOURCE_DIR}/crypto_hash.h + ${CMAKE_CURRENT_SOURCE_DIR}/crypto_hash_type.h + ${CMAKE_CURRENT_SOURCE_DIR}/identity.h + ${CMAKE_CURRENT_SOURCE_DIR}/key_id.h +) + +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/security/crypto_hash.h b/libtransport/includes/hicn/transport/security/crypto_hash.h new file mode 100644 index 000000000..5a58f258b --- /dev/null +++ b/libtransport/includes/hicn/transport/security/crypto_hash.h @@ -0,0 +1,119 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include + +extern "C" { +#include +}; + +#include +#include + +namespace utils { + +class CryptoHasher; + +struct EnumClassHash { + template + std::size_t operator()(T t) const { + return static_cast(t); + } +}; + +static std::unordered_map + hash_size_map = {{CryptoHashType::SHA_256, 32}, + {CryptoHashType::CRC32C, 4}, + {CryptoHashType::SHA_512, 64}}; + +class Signer; +class Verifier; + +class CryptoHash { + friend class CryptoHasher; + friend class Signer; + friend class Verifier; + + public: + CryptoHash() : hash_(nullptr) {} + + CryptoHash(const CryptoHash& other) { + if (other.hash_) { + hash_ = parcCryptoHash_Acquire(other.hash_); + } + } + + CryptoHash(CryptoHash&& other) { + if (other.hash_) { + hash_ = parcCryptoHash_Acquire(other.hash_); + } + } + + template + CryptoHash(const T* buffer, std::size_t length, CryptoHashType hash_type) { + hash_ = parcCryptoHash_CreateFromArray( + static_cast(hash_type), buffer, length); + } + + ~CryptoHash() { + if (hash_) { + parcCryptoHash_Release(&hash_); + } + } + + CryptoHash& operator=(const CryptoHash& other) { + if (other.hash_) { + hash_ = parcCryptoHash_Acquire(other.hash_); + } + + return *this; + } + + template + utils::Array getDigest() const { + return utils::Array( + static_cast(parcBuffer_Overlay(parcCryptoHash_GetDigest(hash_), 0)), + parcBuffer_Remaining(parcCryptoHash_GetDigest(hash_))); + } + + CryptoHashType getType() { + return static_cast(parcCryptoHash_GetDigestType(hash_)); + } + + template + static bool compareBinaryDigest(const T* digest1, const T* digest2, + CryptoHashType hash_type) { + if (hash_size_map.find(hash_type) == hash_size_map.end()) { + return false; + } + + return !static_cast( + std::memcmp(digest1, digest2, hash_size_map[hash_type])); + } + + TRANSPORT_ALWAYS_INLINE void display() { + parcBuffer_Display(parcCryptoHash_GetDigest(hash_), 2); + } + + private: + PARCCryptoHash* hash_; +}; + +} // namespace utils \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/security/crypto_hash_type.h b/libtransport/includes/hicn/transport/security/crypto_hash_type.h new file mode 100644 index 000000000..b7597e208 --- /dev/null +++ b/libtransport/includes/hicn/transport/security/crypto_hash_type.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#pragma once + +extern "C" { +#include +}; + +namespace utils { + +enum class CryptoHashType : uint8_t { + SHA_256 = PARCCryptoHashType_SHA256, + SHA_512 = PARCCryptoHashType_SHA512, + CRC32C = PARCCryptoHashType_CRC32C, + NULL_HASH = PARCCryptoHashType_NULL +}; + +} \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/security/crypto_hasher.h b/libtransport/includes/hicn/transport/security/crypto_hasher.h new file mode 100644 index 000000000..9367c3bc8 --- /dev/null +++ b/libtransport/includes/hicn/transport/security/crypto_hasher.h @@ -0,0 +1,68 @@ +/* + * 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. + */ + +#pragma once + +#include + +extern "C" { +#include +}; + +namespace utils { + +class CryptoHasher { + public: + CryptoHasher(CryptoHashType hash_type) + : hasher_(parcCryptoHasher_Create( + static_cast(hash_type))), + managed_(true) {} + + CryptoHasher(PARCCryptoHasher* hasher) : hasher_(hasher), managed_(false) {} + + ~CryptoHasher() { + if (managed_) { + parcCryptoHasher_Release(&hasher_); + } + } + + CryptoHasher& init() { + if (parcCryptoHasher_Init(hasher_) == -1) { + throw errors::RuntimeException("Cryptohash init failed."); + } + + return *this; + } + + template + CryptoHasher& updateBytes(const T* buffer, std::size_t length) { + if (parcCryptoHasher_UpdateBytes(hasher_, buffer, length) == -1) { + throw errors::RuntimeException("Cryptohash updateBytes failed."); + } + return *this; + } + + CryptoHash finalize() { + CryptoHash hash; + hash.hash_ = parcCryptoHasher_Finalize(hasher_); + return hash; + } + + private: + PARCCryptoHasher* hasher_; + bool managed_; +}; + +} // namespace utils \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/security/crypto_suite.h b/libtransport/includes/hicn/transport/security/crypto_suite.h new file mode 100644 index 000000000..017938f8f --- /dev/null +++ b/libtransport/includes/hicn/transport/security/crypto_suite.h @@ -0,0 +1,36 @@ +/* + * 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. + */ + +#pragma once + +extern "C" { +#include +}; + +#include + +namespace utils { + +enum class CryptoSuite : uint8_t { + RSA_SHA256 = PARCCryptoSuite_RSA_SHA256, + DSA_SHA256 = PARCCryptoSuite_DSA_SHA256, + RSA_SHA512 = PARCCryptoSuite_RSA_SHA512, + HMAC_SHA256 = PARCCryptoSuite_HMAC_SHA256, + HMAC_SHA512 = PARCCryptoSuite_HMAC_SHA512, + NULL_CRC32C = PARCCryptoSuite_NULL_CRC32C, + ECDSA_256K1 = PARCCryptoSuite_ECDSA_SHA256, + UNKNOWN = PARCCryptoSuite_UNKNOWN +}; +} diff --git a/libtransport/includes/hicn/transport/security/identity.h b/libtransport/includes/hicn/transport/security/identity.h new file mode 100644 index 000000000..c5d4b975d --- /dev/null +++ b/libtransport/includes/hicn/transport/security/identity.h @@ -0,0 +1,63 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +#include + +extern "C" { +#include +#include +#include +}; + +#include + +namespace utils { + +class Identity { + public: + Identity(const std::string &keystore_name, + const std::string &keystore_password, CryptoSuite suite, + unsigned int signature_length, unsigned int validity_days, + const std::string &subject_name); + + Identity(const Identity &other); + + Identity(std::string &file_name, std::string &password, + transport::core::HashAlgorithm hash_algorithm); + + ~Identity(); + + static Identity generateIdentity(const std::string &subject_name); + + std::string getFileName(); + + std::string getPassword(); + + std::shared_ptr getSigner(); + + size_t getSignatureLength() const; + + private: + PARCIdentity *identity_; + std::shared_ptr signer_; + transport::core::HashAlgorithm hash_algorithm_; +}; + +} // namespace utils diff --git a/libtransport/includes/hicn/transport/security/key_id.h b/libtransport/includes/hicn/transport/security/key_id.h new file mode 100644 index 000000000..d67b73d7a --- /dev/null +++ b/libtransport/includes/hicn/transport/security/key_id.h @@ -0,0 +1,25 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +namespace utils { + +using KeyId = std::pair; + +} diff --git a/libtransport/includes/hicn/transport/security/signer.h b/libtransport/includes/hicn/transport/security/signer.h new file mode 100644 index 000000000..31b21462b --- /dev/null +++ b/libtransport/includes/hicn/transport/security/signer.h @@ -0,0 +1,90 @@ +/* + * 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. + */ + +#pragma once + +#include + +extern "C" { +#include +#include +#include +#include +#include +} + +namespace utils { + +using Packet = transport::core::Packet; + +/** + * A signer can use a single key (asymmetric or symmetric) to sign a packet. + */ +class Signer { + friend class Identity; + + public: + /** + * Create a Signer + * + * @param keyStore A keystore containing a private key or simmetric key to + * use to sign packet with this Signer. + * @param suite CryptoSuite to use to verify the signature + */ + Signer(PARCKeyStore *keyStore, CryptoSuite suite); + + /** + * Create a Signer + * + * @param passphrase A string from which the symmetric key will be derived + * @param suite CryptoSuite to use to verify the signature + */ + Signer(const std::string &passphrase, CryptoSuite suite); + + Signer(const PARCSigner *signer, CryptoSuite suite); + + Signer(const PARCSigner *signer); + + ~Signer(); + + /** + * @brief Sign a packet + * + * This method is general and must be used for Public-private key signature, + * HMAC and CRC. + * + * @param packet A pointer to the header of the packet to sign. Mutable + * field in the packet must be set to 0. + * @param key_id Indentifier of the key to use to generate the signature. + */ + void sign(Packet &packet); + + size_t getSignatureLength(); + + PARCKeyStore *getKeyStore(); + + private: + PARCBufferComposer *composer_ = nullptr; + PARCBuffer *key_buffer_ = nullptr; + PARCSymmetricKeyStore *symmetricKeyStore_ = nullptr; + PARCSigner *signer_ = nullptr; + PARCSignature *signature_ = nullptr; + PARCKeyId *key_id_ = nullptr; + CryptoSuite suite_; + size_t signature_length_; + static uint8_t zeros[200]; +}; + +} // namespace utils diff --git a/libtransport/includes/hicn/transport/security/verifier.h b/libtransport/includes/hicn/transport/security/verifier.h new file mode 100644 index 000000000..7ec6e7eda --- /dev/null +++ b/libtransport/includes/hicn/transport/security/verifier.h @@ -0,0 +1,103 @@ +/* + * 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. + */ + +#pragma once + +#include + +extern "C" { +#include +#include +#include +#include +#include +#include +} + +namespace utils { + +using Packet = transport::core::Packet; + +/** + * A verifier holds a crypto cache that contains all the keys to use for + * verify signatures/hmacs. + */ +class Verifier { + public: + Verifier(); + + ~Verifier(); + + /** + * @brief Check if a key is already in this Verifier. + * + * A PARCVerifier contains a CryptoCache with a set of key to use for + * verification purposes. + * + * @param keyId Identifier of the key to match in the CryptoCache of the + * Verifier. + * @return true if the key is found, false otherwise. + */ + bool hasKey(PARCKeyId *keyId); + + /** + * @brief Add a key to this Verifier + * + * @param key to add + * @return true if the key was added successfully, false otherwise. + */ + bool addKey(PARCKey *key); + + PARCKeyId *addKeyFromPassphrase(const std::string &passphrase, + CryptoSuite suite); + + PARCKeyId *addKeyFromCertificate(const std::string &file_name); + + /** + * @brief Verify a Signature + * + * This method is general and must be used for Public-private key signature, + * HMAC and CRC. + * + * @param signature A pointer to the buffer holding the signature + * @param sign_len Lenght of the signature (must be consistent with the type + * of the key) + * @param bufferSigned A pointer to the packet header signed with + * signature. Mutable fields and the signature field in the packet must be + * set to 0 + * @param buf_len Lenght of bufferSigned + * @param suite CryptoSuite to use to verify the signature + * @param key_id Indentifier of the key to use to verify the signature. The + * key must be already present in the Verifier. + */ + int verify(const Packet &packet); + + CryptoHash getPacketHash(const Packet &packet, + std::shared_ptr hasher); + + private: + PARCVerifier *verifier_ = nullptr; + PARCCertificateFactory *factory_ = nullptr; + PARCCertificate *certificate_ = nullptr; + PARCKeyId *keyId_ = nullptr; + PARCKey *key_ = nullptr; + PARCBuffer *key_buffer_ = nullptr; + PARCSymmetricKeyStore *symmetricKeyStore_ = nullptr; + PARCSigner *signer_ = nullptr; + PARCBufferComposer *composer_ = nullptr; + static uint8_t zeros[200]; +}; + +} // namespace utils diff --git a/libtransport/includes/hicn/transport/utils/CMakeLists.txt b/libtransport/includes/hicn/transport/utils/CMakeLists.txt new file mode 100644 index 000000000..396bd06d6 --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/CMakeLists.txt @@ -0,0 +1,39 @@ +# 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) + +list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/array.h + ${CMAKE_CURRENT_SOURCE_DIR}/string_tokenizer.h + ${CMAKE_CURRENT_SOURCE_DIR}/hash.h + ${CMAKE_CURRENT_SOURCE_DIR}/uri.h + ${CMAKE_CURRENT_SOURCE_DIR}/chrono_typedefs.h + ${CMAKE_CURRENT_SOURCE_DIR}/branch_prediction.h + ${CMAKE_CURRENT_SOURCE_DIR}/ring_buffer.h + ${CMAKE_CURRENT_SOURCE_DIR}/literals.h + ${CMAKE_CURRENT_SOURCE_DIR}/conversions.h + ${CMAKE_CURRENT_SOURCE_DIR}/linux.h + ${CMAKE_CURRENT_SOURCE_DIR}/log.h + ${CMAKE_CURRENT_SOURCE_DIR}/object_pool.h + ${CMAKE_CURRENT_SOURCE_DIR}/membuf.h + ${CMAKE_CURRENT_SOURCE_DIR}/spinlock.h +) + +if(NOT WIN32) + list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/daemonizator.h + ) +endif() + +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/utils/array.h b/libtransport/includes/hicn/transport/utils/array.h new file mode 100644 index 000000000..7c0ed65d8 --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/array.h @@ -0,0 +1,62 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include + +namespace utils { + +template +class Array { + public: + explicit Array(const T *array, size_t size) : array_(array), size_(size) { + this->array_ = array; + this->size_ = size; + } + + Array() : array_(nullptr), size_(0) { + this->array_ = nullptr; + this->size_ = 0; + } + + TRANSPORT_ALWAYS_INLINE const T *data() const { return array_; } + + TRANSPORT_ALWAYS_INLINE T *writableData() const { + return const_cast(array_); + } + + TRANSPORT_ALWAYS_INLINE std::size_t length() const { return size_; } + + TRANSPORT_ALWAYS_INLINE Array &setData(const T *data) { + array_ = data; + return *this; + } + + TRANSPORT_ALWAYS_INLINE Array &setSize(std::size_t size) { + size_ = size; + return *this; + } + + TRANSPORT_ALWAYS_INLINE bool empty() { return !size_; } + + private: + const T *array_; + std::size_t size_; +}; + +} // namespace utils diff --git a/libtransport/includes/hicn/transport/utils/branch_prediction.h b/libtransport/includes/hicn/transport/utils/branch_prediction.h new file mode 100644 index 000000000..8cbfaca76 --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/branch_prediction.h @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#pragma once + +#undef TRANSPORT_EXPECT_TRUE +#undef TRANSPORT_EXPECT_FALSE + +#ifndef _WIN32 +#define TRANSPORT_EXPECT_TRUE(x) __builtin_expect((x), 1) +#define TRANSPORT_EXPECT_FALSE(x) __builtin_expect((x), 0) +#else +#define TRANSPORT_EXPECT_TRUE(x) (x) +#define TRANSPORT_EXPECT_FALSE(x) (x) +#endif \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/utils/chrono_typedefs.h b/libtransport/includes/hicn/transport/utils/chrono_typedefs.h new file mode 100644 index 000000000..8f28e763c --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/chrono_typedefs.h @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace utils { + +using SteadyClock = std::chrono::steady_clock; +using TimePoint = SteadyClock::time_point; +using Milliseconds = std::chrono::milliseconds; +using Microseconds = std::chrono::microseconds; + +} // namespace utils diff --git a/libtransport/includes/hicn/transport/utils/conversions.h b/libtransport/includes/hicn/transport/utils/conversions.h new file mode 100644 index 000000000..24b529206 --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/conversions.h @@ -0,0 +1,37 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include +#include +#include + +namespace utils { + +static TRANSPORT_ALWAYS_INLINE int convertStringToMacAddress( + const std::string& mac_address, uint8_t* mac_byte_array) { + const char* mac = mac_address.c_str(); + + sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mac_byte_array[0], + &mac_byte_array[1], &mac_byte_array[2], &mac_byte_array[3], + &mac_byte_array[4], &mac_byte_array[5]); + + return 0; +} + +} // namespace utils \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/utils/daemonizator.h b/libtransport/includes/hicn/transport/utils/daemonizator.h new file mode 100644 index 000000000..028d74865 --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/daemonizator.h @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#pragma once + +#ifndef _WIN32 + +#include +namespace utils { + +class Daemonizator { + public: + static void daemonize(bool close_fds = true); +}; + +} // namespace utils + +#endif \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/utils/hash.h b/libtransport/includes/hicn/transport/utils/hash.h new file mode 100644 index 000000000..6815ca4bf --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/hash.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright 2017 Facebook, Inc. + * + * 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 + +#include +#include +#include +#include +#include +#include +#include + +namespace utils { + +namespace hash { + +/* + * Fowler / Noll / Vo (FNV) Hash + * http://www.isthe.com/chongo/tech/comp/fnv/ + */ + +const uint32_t FNV_32_HASH_START = 2166136261UL; +const uint64_t FNV_64_HASH_START = 14695981039346656037ULL; + +TRANSPORT_ALWAYS_INLINE uint32_t fnv32(const char *s, + uint32_t hash = FNV_32_HASH_START) { + for (; *s; ++s) { + hash += + (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24); + hash ^= *s; + } + return hash; +} + +TRANSPORT_ALWAYS_INLINE uint32_t fnv32_buf(const void *buf, size_t n, + uint32_t hash = FNV_32_HASH_START) { + // forcing signed char, since other platforms can use unsigned + const signed char *char_buf = reinterpret_cast(buf); + + for (size_t i = 0; i < n; ++i) { + hash += + (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24); + hash ^= char_buf[i]; + } + + return hash; +} + +TRANSPORT_ALWAYS_INLINE uint32_t fnv32(const std::string &str, + uint32_t hash = FNV_32_HASH_START) { + return fnv32_buf(str.data(), str.size(), hash); +} + +TRANSPORT_ALWAYS_INLINE uint64_t fnv64(const char *s, + uint64_t hash = FNV_64_HASH_START) { + for (; *s; ++s) { + hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + + (hash << 8) + (hash << 40); + hash ^= *s; + } + return hash; +} + +TRANSPORT_ALWAYS_INLINE uint64_t fnv64_buf(const void *buf, size_t n, + uint64_t hash = FNV_64_HASH_START) { + // forcing signed char, since other platforms can use unsigned + const signed char *char_buf = reinterpret_cast(buf); + + for (size_t i = 0; i < n; ++i) { + hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + + (hash << 8) + (hash << 40); + hash ^= char_buf[i]; + } + return hash; +} + +TRANSPORT_ALWAYS_INLINE uint64_t fnv64(const std::string &str, + uint64_t hash = FNV_64_HASH_START) { + return fnv64_buf(str.data(), str.size(), hash); +} + +} // namespace hash + +} // namespace utils diff --git a/libtransport/includes/hicn/transport/utils/linux.h b/libtransport/includes/hicn/transport/utils/linux.h new file mode 100644 index 000000000..5820528e1 --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/linux.h @@ -0,0 +1,64 @@ +/* + * 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. + */ + +#pragma once + +#ifdef __linux__ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#define LINK_LOCAL_PREFIX 0xfe80 + +namespace utils { + +static TRANSPORT_ALWAYS_INLINE int retrieveInterfaceAddress( + const std::string &interface_name, struct sockaddr_in6 *address) { + struct ifaddrs *ifap, *ifa; + char addr[INET6_ADDRSTRLEN]; + + getifaddrs(&ifap); + + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (ifa->ifa_addr->sa_family == AF_INET6 && + strcmp(ifa->ifa_name, interface_name.c_str()) == 0) { + struct sockaddr_in6 *tmp = (struct sockaddr_in6 *)ifa->ifa_addr; + uint16_t prefix = 0; + memcpy(&prefix, tmp->sin6_addr.s6_addr, sizeof(uint16_t)); + + if (htons(LINK_LOCAL_PREFIX) != prefix) { + *address = *(struct sockaddr_in6 *)ifa->ifa_addr; + getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6), addr, + sizeof(addr), NULL, 0, NI_NUMERICHOST); + TRANSPORT_LOGI("Interface: %s\tAddress: %s", ifa->ifa_name, addr); + } + } + } + + freeifaddrs(ifap); + + return 0; +} + +} // namespace utils + +#endif // __linux__ \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/utils/literals.h b/libtransport/includes/hicn/transport/utils/literals.h new file mode 100644 index 000000000..bd00e0a58 --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/literals.h @@ -0,0 +1,55 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include + +TRANSPORT_ALWAYS_INLINE std::uint8_t operator"" _U8(unsigned long long value) { + return static_cast(value); +} + +TRANSPORT_ALWAYS_INLINE std::uint16_t operator"" _U16( + unsigned long long value) { + return static_cast(value); +} + +TRANSPORT_ALWAYS_INLINE std::uint32_t operator"" _U32( + unsigned long long value) { + return static_cast(value); +} + +TRANSPORT_ALWAYS_INLINE std::uint64_t operator"" _U64( + unsigned long long value) { + return static_cast(value); +} + +TRANSPORT_ALWAYS_INLINE std::int8_t operator"" _I8(unsigned long long value) { + return static_cast(value); +} + +TRANSPORT_ALWAYS_INLINE std::int16_t operator"" _I16(unsigned long long value) { + return static_cast(value); +} + +TRANSPORT_ALWAYS_INLINE std::int32_t operator"" _I32(unsigned long long value) { + return static_cast(value); +} + +TRANSPORT_ALWAYS_INLINE std::int64_t operator"" _I64(unsigned long long value) { + return static_cast(value); +} \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/utils/log.h b/libtransport/includes/hicn/transport/utils/log.h new file mode 100644 index 000000000..3c4f1277a --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/log.h @@ -0,0 +1,1057 @@ +/* + * 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. + */ + +/* + * The MIT License (MIT) + * + * Copyright (c) 2017 wonder-mice + * + * 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 + +/* To detect incompatible changes you can define TRANSPORT_LOG_VERSION_REQUIRED + * to be the current value of TRANSPORT_LOG_VERSION before including this file + * (or via compiler command line): + * + * #define TRANSPORT_LOG_VERSION_REQUIRED 4 + * #include + * + * Compilation will fail when included file has different version. + */ +#define TRANSPORT_LOG_VERSION 4 +#if defined(TRANSPORT_LOG_VERSION_REQUIRED) +#if TRANSPORT_LOG_VERSION_REQUIRED != TRANSPORT_LOG_VERSION +#error different transport_log version required +#endif +#endif + +/* Log level guideline: + * - TRANSPORT_LOG_FATAL - happened something impossible and absolutely + * unexpected. Process can't continue and must be terminated. Example: division + * by zero, unexpected modifications from other thread. + * - TRANSPORT_LOG_ERROR - happened something possible, but highly unexpected. + * The process is able to recover and continue execution. Example: out of memory + * (could also be FATAL if not handled properly). + * - TRANSPORT_LOG_WARN - happened something that *usually* should not happen + * and significantly changes application behavior for some period of time. + * Example: configuration file not found, auth error. + * - TRANSPORT_LOG_INFO - happened significant life cycle event or major state + * transition. + * Example: app started, user logged in. + * - TRANSPORT_LOG_DEBUG - minimal set of events that could help to reconstruct + * the execution path. Usually disabled in release builds. + * - TRANSPORT_LOG_VERBOSE - all other events. Usually disabled in release + * builds. + * + * *Ideally*, log file of debugged, well tested, production ready application + * should be empty or very small. Choosing a right log level is as important as + * providing short and self descriptive log message. + */ +#define TRANSPORT_LOG_VERBOSE 1 +#define TRANSPORT_LOG_DEBUG 2 +#define TRANSPORT_LOG_INFO 3 +#define TRANSPORT_LOG_WARN 4 +#define TRANSPORT_LOG_ERROR 5 +#define TRANSPORT_LOG_FATAL 6 +#define TRANSPORT_LOG_NONE 0xFF + +/* "Current" log level is a compile time check and has no runtime overhead. Log + * level that is below current log level it said to be "disabled". Otherwise, + * it's "enabled". Log messages that are disabled has no runtime overhead - they + * are converted to no-op by preprocessor and then eliminated by compiler. + * Current log level is configured per compilation module (.c/.cpp/.m file) by + * defining TRANSPORT_LOG_DEF_LEVEL or TRANSPORT_LOG_LEVEL. TRANSPORT_LOG_LEVEL + * has higer priority and when defined overrides value provided by + * TRANSPORT_LOG_DEF_LEVEL. + * + * Common practice is to define default current log level with + * TRANSPORT_LOG_DEF_LEVEL in build script (e.g. Makefile, CMakeLists.txt, gyp, + * etc.) for the entire project or target: + * + * CC_ARGS := -DTRANSPORT_LOG_DEF_LEVEL=TRANSPORT_LOG_INFO + * + * And when necessary to override it with TRANSPORT_LOG_LEVEL in .c/.cpp/.m + * files before including transport_log.h: + * + * #define TRANSPORT_LOG_LEVEL TRANSPORT_LOG_VERBOSE + * #include + * + * If both TRANSPORT_LOG_DEF_LEVEL and TRANSPORT_LOG_LEVEL are undefined, then + * TRANSPORT_LOG_INFO will be used for release builds (NDEBUG is defined) and + * TRANSPORT_LOG_DEBUG otherwise (NDEBUG is not defined). + */ +#if defined(TRANSPORT_LOG_LEVEL) +#define _TRANSPORT_LOG_LEVEL TRANSPORT_LOG_LEVEL +#elif defined(TRANSPORT_LOG_DEF_LEVEL) +#define _TRANSPORT_LOG_LEVEL TRANSPORT_LOG_DEF_LEVEL +#else +#ifdef NDEBUG +#define _TRANSPORT_LOG_LEVEL TRANSPORT_LOG_INFO +#else +#define _TRANSPORT_LOG_LEVEL TRANSPORT_LOG_DEBUG +#endif +#endif + +/* "Output" log level is a runtime check. When log level is below output log + * level it said to be "turned off" (or just "off" for short). Otherwise it's + * "turned on" (or just "on"). Log levels that were "disabled" (see + * TRANSPORT_LOG_LEVEL and TRANSPORT_LOG_DEF_LEVEL) can't be "turned on", but + * "enabled" log levels could be "turned off". Only messages with log level + * which is "turned on" will reach output facility. All other messages will be + * ignored (and their arguments will not be evaluated). Output log level is a + * global property and configured per process using + * transport_log_set_output_level() function which can be called at any time. + * + * Though in some cases it could be useful to configure output log level per + * compilation module or per library. There are two ways to achieve that: + * - Define TRANSPORT_LOG_OUTPUT_LEVEL to expresion that evaluates to desired + * output log level. + * - Copy transport_log.h and transport_log.c files into your library and build + * it with TRANSPORT_LOG_LIBRARY_PREFIX defined to library specific prefix. See + * TRANSPORT_LOG_LIBRARY_PREFIX for more details. + * + * When defined, TRANSPORT_LOG_OUTPUT_LEVEL must evaluate to integral value that + * corresponds to desired output log level. Use it only when compilation module + * is required to have output log level which is different from global output + * log level set by transport_log_set_output_level() function. For other cases, + * consider defining TRANSPORT_LOG_LEVEL or using + * transport_log_set_output_level() function. + * + * Example: + * + * #define TRANSPORT_LOG_OUTPUT_LEVEL g_module_log_level + * #include + * static int g_module_log_level = TRANSPORT_LOG_INFO; + * static void foo() { + * TRANSPORT_LOGI("Will check g_module_log_level for output log level"); + * } + * void debug_log(bool on) { + * g_module_log_level = on? TRANSPORT_LOG_DEBUG: TRANSPORT_LOG_INFO; + * } + * + * Note on performance. This expression will be evaluated each time message is + * logged (except when message log level is "disabled" - see TRANSPORT_LOG_LEVEL + * for details). Keep this expression as simple as possible, otherwise it will + * not only add runtime overhead, but also will increase size of call site + * (which will result in larger executable). The prefered way is to use integer + * variable (as in example above). If structure must be used, log_level field + * must be the first field in this structure: + * + * #define TRANSPORT_LOG_OUTPUT_LEVEL (g_config.log_level) + * #include + * struct config { + * int log_level; + * unsigned other_field; + * [...] + * }; + * static config g_config = {TRANSPORT_LOG_INFO, 0, ...}; + * + * This allows compiler to generate more compact load instruction (no need to + * specify offset since it's zero). Calling a function to get output log level + * is generaly a bad idea, since it will increase call site size and runtime + * overhead even further. + */ +#if defined(TRANSPORT_LOG_OUTPUT_LEVEL) +#define _TRANSPORT_LOG_OUTPUT_LEVEL TRANSPORT_LOG_OUTPUT_LEVEL +#else +#define _TRANSPORT_LOG_OUTPUT_LEVEL _transport_log_global_output_lvl +#endif + +/* "Tag" is a compound string that could be associated with a log message. It + * consists of tag prefix and tag (both are optional). + * + * Tag prefix is a global property and configured per process using + * transport_log_set_tag_prefix() function. Tag prefix identifies context in + * which component or module is running (e.g. process name). For example, the + * same library could be used in both client and server processes that work on + * the same machine. Tag prefix could be used to easily distinguish between + * them. For more details about tag prefix see transport_log_set_tag_prefix() + * function. Tag prefix + * + * Tag identifies component or module. It is configured per compilation module + * (.c/.cpp/.m file) by defining TRANSPORT_LOG_TAG or TRANSPORT_LOG_DEF_TAG. + * TRANSPORT_LOG_TAG has higer priority and when defined overrides value + * provided by TRANSPORT_LOG_DEF_TAG. When defined, value must evaluate to + * (const char *), so for strings double quotes must be used. + * + * Default tag could be defined with TRANSPORT_LOG_DEF_TAG in build script (e.g. + * Makefile, CMakeLists.txt, gyp, etc.) for the entire project or target: + * + * CC_ARGS := -DTRANSPORT_LOG_DEF_TAG=\"MISC\" + * + * And when necessary could be overriden with TRANSPORT_LOG_TAG in .c/.cpp/.m + * files before including transport_log.h: + * + * #define TRANSPORT_LOG_TAG "MAIN" + * #include + * + * If both TRANSPORT_LOG_DEF_TAG and TRANSPORT_LOG_TAG are undefined no tag will + * be added to the log message (tag prefix still could be added though). + * + * Output example: + * + * 04-29 22:43:20.244 40059 1299 I hello.MAIN Number of arguments: 1 + * | | + * | +- tag (e.g. module) + * +- tag prefix (e.g. process name) + */ +#if defined(TRANSPORT_LOG_TAG) +#define _TRANSPORT_LOG_TAG TRANSPORT_LOG_TAG +#elif defined(TRANSPORT_LOG_DEF_TAG) +#define _TRANSPORT_LOG_TAG TRANSPORT_LOG_DEF_TAG +#else +#define _TRANSPORT_LOG_TAG 0 +#endif + +/* Source location is part of a log line that describes location (function or + * method name, file name and line number, e.g. "runloop@main.cpp:68") of a + * log statement that produced it. + * Source location formats are: + * - TRANSPORT_LOG_SRCLOC_NONE - don't add source location to log line. + * - TRANSPORT_LOG_SRCLOC_SHORT - add source location in short form (file and + * line number, e.g. "@main.cpp:68"). + * - TRANSPORT_LOG_SRCLOC_LONG - add source location in long form (function or + * method name, file and line number, e.g. "runloop@main.cpp:68"). + */ +#define TRANSPORT_LOG_SRCLOC_NONE 0 +#define TRANSPORT_LOG_SRCLOC_SHORT 1 +#define TRANSPORT_LOG_SRCLOC_LONG 2 + +/* Source location format is configured per compilation module (.c/.cpp/.m + * file) by defining TRANSPORT_LOG_DEF_SRCLOC or TRANSPORT_LOG_SRCLOC. + * TRANSPORT_LOG_SRCLOC has higer priority and when defined overrides value + * provided by TRANSPORT_LOG_DEF_SRCLOC. + * + * Common practice is to define default format with TRANSPORT_LOG_DEF_SRCLOC in + * build script (e.g. Makefile, CMakeLists.txt, gyp, etc.) for the entire + * project or target: + * + * CC_ARGS := -DTRANSPORT_LOG_DEF_SRCLOC=TRANSPORT_LOG_SRCLOC_LONG + * + * And when necessary to override it with TRANSPORT_LOG_SRCLOC in .c/.cpp/.m + * files before including transport_log.h: + * + * #define TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_SRCLOC_NONE + * #include + * + * If both TRANSPORT_LOG_DEF_SRCLOC and TRANSPORT_LOG_SRCLOC are undefined, then + * TRANSPORT_LOG_SRCLOC_NONE will be used for release builds (NDEBUG is defined) + * and TRANSPORT_LOG_SRCLOC_LONG otherwise (NDEBUG is not defined). + */ +#if defined(TRANSPORT_LOG_SRCLOC) +#define _TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_SRCLOC +#elif defined(TRANSPORT_LOG_DEF_SRCLOC) +#define _TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_DEF_SRCLOC +#else +#ifdef NDEBUG +#define _TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_SRCLOC_NONE +#else +#define _TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_SRCLOC_LONG +#endif +#endif +#if TRANSPORT_LOG_SRCLOC_LONG == _TRANSPORT_LOG_SRCLOC +#define _TRANSPORT_LOG_SRCLOC_FUNCTION _TRANSPORT_LOG_FUNCTION +#else +#define _TRANSPORT_LOG_SRCLOC_FUNCTION 0 +#endif + +/* Censoring provides conditional logging of secret information, also known as + * Personally Identifiable Information (PII) or Sensitive Personal Information + * (SPI). Censoring can be either enabled (TRANSPORT_LOG_CENSORED) or disabled + * (TRANSPORT_LOG_UNCENSORED). When censoring is enabled, log statements marked + * as "secrets" will be ignored and will have zero overhead (arguments also will + * not be evaluated). + */ +#define TRANSPORT_LOG_CENSORED 1 +#define TRANSPORT_LOG_UNCENSORED 0 + +/* Censoring is configured per compilation module (.c/.cpp/.m file) by defining + * TRANSPORT_LOG_DEF_CENSORING or TRANSPORT_LOG_CENSORING. + * TRANSPORT_LOG_CENSORING has higer priority and when defined overrides value + * provided by TRANSPORT_LOG_DEF_CENSORING. + * + * Common practice is to define default censoring with + * TRANSPORT_LOG_DEF_CENSORING in build script (e.g. Makefile, CMakeLists.txt, + * gyp, etc.) for the entire project or target: + * + * CC_ARGS := -DTRANSPORT_LOG_DEF_CENSORING=TRANSPORT_LOG_CENSORED + * + * And when necessary to override it with TRANSPORT_LOG_CENSORING in .c/.cpp/.m + * files before including transport_log.h (consider doing it only for debug + * purposes and be very careful not to push such temporary changes to source + * control): + * + * #define TRANSPORT_LOG_CENSORING TRANSPORT_LOG_UNCENSORED + * #include + * + * If both TRANSPORT_LOG_DEF_CENSORING and TRANSPORT_LOG_CENSORING are + * undefined, then TRANSPORT_LOG_CENSORED will be used for release builds + * (NDEBUG is defined) and TRANSPORT_LOG_UNCENSORED otherwise (NDEBUG is not + * defined). + */ +#if defined(TRANSPORT_LOG_CENSORING) +#define _TRANSPORT_LOG_CENSORING TRANSPORT_LOG_CENSORING +#elif defined(TRANSPORT_LOG_DEF_CENSORING) +#define _TRANSPORT_LOG_CENSORING TRANSPORT_LOG_DEF_CENSORING +#else +#ifdef NDEBUG +#define _TRANSPORT_LOG_CENSORING TRANSPORT_LOG_CENSORED +#else +#define _TRANSPORT_LOG_CENSORING TRANSPORT_LOG_UNCENSORED +#endif +#endif + +/* Check censoring at compile time. Evaluates to true when censoring is disabled + * (i.e. when secrets will be logged). For example: + * + * #if TRANSPORT_LOG_SECRETS + * char ssn[16]; + * getSocialSecurityNumber(ssn); + * TRANSPORT_LOGI("Customer ssn: %s", ssn); + * #endif + * + * See TRANSPORT_LOG_SECRET() macro for a more convenient way of guarding single + * log statement. + */ +#define TRANSPORT_LOG_SECRETS \ + (TRANSPORT_LOG_UNCENSORED == _TRANSPORT_LOG_CENSORING) + +/* Static (compile-time) initialization support allows to configure logging + * before entering main() function. This mostly useful in C++ where functions + * and methods could be called during initialization of global objects. Those + * functions and methods could record log messages too and for that reason + * static initialization of logging configuration is customizable. + * + * Macros below allow to specify values to use for initial configuration: + * - TRANSPORT_LOG_EXTERN_TAG_PREFIX - tag prefix (default: none) + * - TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT - global format options (default: see + * TRANSPORT_LOG_MEM_WIDTH in transport_log.c) + * - TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT - global output facility (default: + * stderr or platform specific, see TRANSPORT_LOG_USE_XXX macros in + * transport_log.c) + * - TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL - global output log level + * (default: 0 - all levals are "turned on") + * + * For example, in log_config.c: + * + * #include + * TRANSPORT_LOG_DEFINE_TAG_PREFIX = "MyApp"; + * TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT = {CUSTOM_MEM_WIDTH}; + * TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {TRANSPORT_LOG_PUT_STD, + * custom_output_callback, 0}; TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = + * TRANSPORT_LOG_INFO; + * + * However, to use any of those macros transport_log library must be compiled + * with following macros defined: + * - to use TRANSPORT_LOG_DEFINE_TAG_PREFIX define + * TRANSPORT_LOG_EXTERN_TAG_PREFIX + * - to use TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT define + * TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT + * - to use TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT define + * TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT + * - to use TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL define + * TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL + * + * When transport_log library compiled with one of TRANSPORT_LOG_EXTERN_XXX + * macros defined, corresponding TRANSPORT_LOG_DEFINE_XXX macro MUST be used + * exactly once somewhere. Otherwise build will fail with link error (undefined + * symbol). + */ +#define TRANSPORT_LOG_DEFINE_TAG_PREFIX const char *_transport_log_tag_prefix +#define TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT \ + transport_log_format _transport_log_global_format +#define TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT \ + transport_log_output _transport_log_global_output +#define TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL \ + int _transport_log_global_output_lvl + +/* Pointer to global format options. Direct modification is not allowed. Use + * transport_log_set_mem_width() instead. Could be used to initialize + * transport_log_spec structure: + * + * const transport_log_output g_output = {TRANSPORT_LOG_PUT_STD, + * output_callback, 0}; const transport_log_spec g_spec = + * {TRANSPORT_LOG_GLOBAL_FORMAT, &g_output}; TRANSPORT_LOGI_AUX(&g_spec, + * "Hello"); + */ +#define TRANSPORT_LOG_GLOBAL_FORMAT \ + ((const transport_log_format *)&_transport_log_global_format) + +/* Pointer to global output variable. Direct modification is not allowed. Use + * transport_log_set_output_v() or transport_log_set_output_p() instead. Could + * be used to initialize transport_log_spec structure: + * + * const transport_log_format g_format = {40}; + * const transport_log_spec g_spec = {g_format, TRANSPORT_LOG_GLOBAL_OUTPUT}; + * TRANSPORT_LOGI_AUX(&g_spec, "Hello"); + */ +#define TRANSPORT_LOG_GLOBAL_OUTPUT \ + ((const transport_log_output *)&_transport_log_global_output) + +/* When defined, all library symbols produced by linker will be prefixed with + * provided value. That allows to use transport_log library privately in another + * libraries without exposing transport_log symbols in their original form (to + * avoid possible conflicts with other libraries / components that also could + * use transport_log for logging). Value must be without quotes, for example: + * + * CC_ARGS := -DTRANSPORT_LOG_LIBRARY_PREFIX=my_lib_ + * + * Note, that in this mode TRANSPORT_LOG_LIBRARY_PREFIX must be defined when + * building transport_log library AND it also must be defined to the same value + * when building a library that uses it. For example, consider fictional + * KittyHttp library that wants to use transport_log for logging. First approach + * that could be taken is to add transport_log.h and transport_log.c to the + * KittyHttp's source code tree directly. In that case it will be enough just to + * define TRANSPORT_LOG_LIBRARY_PREFIX in KittyHttp's build script: + * + * // KittyHttp/CMakeLists.txt + * target_compile_definitions(KittyHttp PRIVATE + * "TRANSPORT_LOG_LIBRARY_PREFIX=KittyHttp_") + * + * If KittyHttp doesn't want to include transport_log source code in its source + * tree and wants to build transport_log as a separate library than + * transport_log library must be built with TRANSPORT_LOG_LIBRARY_PREFIX defined + * to KittyHttp_ AND KittyHttp library itself also needs to define + * TRANSPORT_LOG_LIBRARY_PREFIX to KittyHttp_. It can do so either in its build + * script, as in example above, or by providing a wrapper header that KittyHttp + * library will need to use instead of transport_log.h: + * + * // KittyHttpLogging.h + * #define TRANSPORT_LOG_LIBRARY_PREFIX KittyHttp_ + * #include + * + * Regardless of the method chosen, the end result is that transport_log symbols + * will be prefixed with "KittyHttp_", so if a user of KittyHttp (say + * DogeBrowser) also uses transport_log for logging, they will not interferer + * with each other. Both will have their own log level, output facility, format + * options etc. + */ +#ifdef TRANSPORT_LOG_LIBRARY_PREFIX +#define _TRANSPORT_LOG_DECOR__(prefix, name) prefix##name +#define _TRANSPORT_LOG_DECOR_(prefix, name) _TRANSPORT_LOG_DECOR__(prefix, name) +#define _TRANSPORT_LOG_DECOR(name) \ + _TRANSPORT_LOG_DECOR_(TRANSPORT_LOG_LIBRARY_PREFIX, name) + +#define transport_log_set_tag_prefix \ + _TRANSPORT_LOG_DECOR(transport_log_set_tag_prefix) +#define transport_log_set_mem_width \ + _TRANSPORT_LOG_DECOR(transport_log_set_mem_width) +#define transport_log_set_output_level \ + _TRANSPORT_LOG_DECOR(transport_log_set_output_level) +#define transport_log_set_output_v \ + _TRANSPORT_LOG_DECOR(transport_log_set_output_v) +#define transport_log_set_output_p \ + _TRANSPORT_LOG_DECOR(transport_log_set_output_p) +#define transport_log_out_stderr_callback \ + _TRANSPORT_LOG_DECOR(transport_log_out_stderr_callback) +#define _transport_log_tag_prefix \ + _TRANSPORT_LOG_DECOR(_transport_log_tag_prefix) +#define _transport_log_global_format \ + _TRANSPORT_LOG_DECOR(_transport_log_global_format) +#define _transport_log_global_output \ + _TRANSPORT_LOG_DECOR(_transport_log_global_output) +#define _transport_log_global_output_lvl \ + _TRANSPORT_LOG_DECOR(_transport_log_global_output_lvl) +#define _transport_log_write_d _TRANSPORT_LOG_DECOR(_transport_log_write_d) +#define _transport_log_write_aux_d \ + _TRANSPORT_LOG_DECOR(_transport_log_write_aux_d) +#define _transport_log_write _TRANSPORT_LOG_DECOR(_transport_log_write) +#define _transport_log_write_aux _TRANSPORT_LOG_DECOR(_transport_log_write_aux) +#define _transport_log_write_mem_d \ + _TRANSPORT_LOG_DECOR(_transport_log_write_mem_d) +#define _transport_log_write_mem_aux_d \ + _TRANSPORT_LOG_DECOR(_transport_log_write_mem_aux_d) +#define _transport_log_write_mem _TRANSPORT_LOG_DECOR(_transport_log_write_mem) +#define _transport_log_write_mem_aux \ + _TRANSPORT_LOG_DECOR(_transport_log_write_mem_aux) +#define _transport_log_stderr_spec \ + _TRANSPORT_LOG_DECOR(_transport_log_stderr_spec) +#endif + +#if defined(__printflike) +#define _TRANSPORT_LOG_PRINTFLIKE(str_index, first_to_check) \ + __printflike(str_index, first_to_check) +#elif defined(__GNUC__) +#define _TRANSPORT_LOG_PRINTFLIKE(str_index, first_to_check) \ + __attribute__((format(__printf__, str_index, first_to_check))) +#else +#define _TRANSPORT_LOG_PRINTFLIKE(str_index, first_to_check) +#endif + +#if (defined(_WIN32) || defined(_WIN64)) && !defined(__GNUC__) +#define _TRANSPORT_LOG_FUNCTION __FUNCTION__ +#else +#define _TRANSPORT_LOG_FUNCTION __func__ +#endif + +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) +#define _TRANSPORT_LOG_INLINE __inline +#define _TRANSPORT_LOG_IF(cond) \ + __pragma(warning(push)) __pragma(warning(disable : 4127)) if (cond) \ + __pragma(warning(pop)) +#define _TRANSPORT_LOG_WHILE(cond) \ + __pragma(warning(push)) __pragma(warning(disable : 4127)) while (cond) \ + __pragma(warning(pop)) +#else +#define _TRANSPORT_LOG_INLINE inline +#define _TRANSPORT_LOG_IF(cond) if (cond) +#define _TRANSPORT_LOG_WHILE(cond) while (cond) +#endif +#define _TRANSPORT_LOG_NEVER _TRANSPORT_LOG_IF(0) +#define _TRANSPORT_LOG_ONCE _TRANSPORT_LOG_WHILE(0) + +#ifdef __cplusplus +extern "C" { +#endif + +/* Set tag prefix. Prefix will be separated from the tag with dot ('.'). + * Use 0 or empty string to disable (default). Common use is to set it to + * the process (or build target) name (e.g. to separate client and server + * processes). Function will NOT copy provided prefix string, but will store the + * pointer. Hence specified prefix string must remain valid. See + * TRANSPORT_LOG_DEFINE_TAG_PREFIX for a way to set it before entering main() + * function. See TRANSPORT_LOG_TAG for more information about tag and tag + * prefix. + */ +void transport_log_set_tag_prefix(const char *const prefix); + +/* Set number of bytes per log line in memory (ASCII-HEX) output. Example: + * + * I hello.MAIN 4c6f72656d20697073756d20646f6c6f Lorem ipsum dolo + * |<- w bytes ->| |<- w chars ->| + * + * See TRANSPORT_LOGF_MEM and TRANSPORT_LOGF_MEM_AUX for more details. + */ +void transport_log_set_mem_width(const unsigned w); + +/* Set "output" log level. See TRANSPORT_LOG_LEVEL and + * TRANSPORT_LOG_OUTPUT_LEVEL for more info about log levels. + */ +void transport_log_set_output_level(const int lvl); + +/* Put mask is a set of flags that define what fields will be added to each + * log message. Default value is TRANSPORT_LOG_PUT_STD and other flags could be + * used to alter its behavior. See transport_log_set_output_v() for more + * details. + * + * Note about TRANSPORT_LOG_PUT_SRC: it will be added only in debug builds + * (NDEBUG is not defined). + */ +enum { + TRANSPORT_LOG_PUT_CTX = 1 << 0, /* context (time, pid, tid, log level) */ + TRANSPORT_LOG_PUT_TAG = 1 << 1, /* tag (including tag prefix) */ + TRANSPORT_LOG_PUT_SRC = 1 << 2, /* source location (file, line, function) */ + TRANSPORT_LOG_PUT_MSG = 1 << 3, /* message text (formatted string) */ + TRANSPORT_LOG_PUT_STD = 0xffff, /* everything (default) */ +}; + +typedef struct transport_log_message { + int lvl; /* Log level of the message */ + const char *tag; /* Associated tag (without tag prefix) */ + char *buf; /* Buffer start */ + char *e; /* Buffer end (last position where EOL with 0 could be written) */ + char *p; /* Buffer content end (append position) */ + char *tag_b; /* Prefixed tag start */ + char *tag_e; /* Prefixed tag end (if != tag_b, points to msg separator) */ + char *msg_b; /* Message start (expanded format string) */ +} transport_log_message; + +/* Type of output callback function. It will be called for each log line allowed + * by both "current" and "output" log levels ("enabled" and "turned on"). + * Callback function is allowed to modify content of the buffers pointed by the + * msg, but it's not allowed to modify any of msg fields. Buffer pointed by msg + * is UTF-8 encoded (no BOM mark). + */ +typedef void (*transport_log_output_cb)(const transport_log_message *msg, + void *arg); + +/* Format options. For more details see transport_log_set_mem_width(). + */ +typedef struct transport_log_format { + unsigned mem_width; /* Bytes per line in memory (ASCII-HEX) dump */ +} transport_log_format; + +/* Output facility. + */ +typedef struct transport_log_output { + unsigned + mask; /* What to put into log line buffer (see TRANSPORT_LOG_PUT_XXX) */ + void *arg; /* User provided output callback argument */ + transport_log_output_cb callback; /* Output callback function */ +} transport_log_output; + +/* Set output callback function. + * + * Mask allows to control what information will be added to the log line buffer + * before callback function is invoked. Default mask value is + * TRANSPORT_LOG_PUT_STD. + */ +void transport_log_set_output_v(const unsigned mask, void *const arg, + const transport_log_output_cb callback); +static _TRANSPORT_LOG_INLINE void transport_log_set_output_p( + const transport_log_output *const output) { + transport_log_set_output_v(output->mask, output->arg, output->callback); +} + +/* Used with _AUX macros and allows to override global format and output + * facility. Use TRANSPORT_LOG_GLOBAL_FORMAT and TRANSPORT_LOG_GLOBAL_OUTPUT for + * values from global configuration. Example: + * + * static const transport_log_output module_output = { + * TRANSPORT_LOG_PUT_STD, 0, custom_output_callback + * }; + * static const transport_log_spec module_spec = { + * TRANSPORT_LOG_GLOBAL_FORMAT, &module_output + * }; + * TRANSPORT_LOGI_AUX(&module_spec, "Position: %ix%i", x, y); + * + * See TRANSPORT_LOGF_AUX and TRANSPORT_LOGF_MEM_AUX for details. + */ +typedef struct transport_log_spec { + const transport_log_format *format; + const transport_log_output *output; +} transport_log_spec; + +#ifdef __cplusplus +} +#endif + +/* Execute log statement if condition is true. Example: + * + * TRANSPORT_LOG_IF(1 < 2, TRANSPORT_LOGI("Log this")); + * TRANSPORT_LOG_IF(1 > 2, TRANSPORT_LOGI("Don't log this")); + * + * Keep in mind though, that if condition can't be evaluated at compile time, + * then it will be evaluated at run time. This will increase exectuable size + * and can have noticeable performance overhead. Try to limit conditions to + * expressions that can be evaluated at compile time. + */ +#define TRANSPORT_LOG_IF(cond, f) \ + do { \ + _TRANSPORT_LOG_IF((cond)) { f; } \ + } \ + _TRANSPORT_LOG_ONCE + +/* Mark log statement as "secret". Log statements that are marked as secrets + * will NOT be executed when censoring is enabled (see TRANSPORT_LOG_CENSORED). + * Example: + * + * TRANSPORT_LOG_SECRET(TRANSPORT_LOGI("Credit card: %s", credit_card)); + * TRANSPORT_LOG_SECRET(TRANSPORT_LOGD_MEM(cipher, cipher_sz, "Cipher + * bytes:")); + */ +#define TRANSPORT_LOG_SECRET(f) TRANSPORT_LOG_IF(TRANSPORT_LOG_SECRETS, f) + +/* Check "current" log level at compile time (ignoring "output" log level). + * Evaluates to true when specified log level is enabled. For example: + * + * #if TRANSPORT_LOG_ENABLED_DEBUG + * const char *const g_enum_strings[] = { + * "enum_value_0", "enum_value_1", "enum_value_2" + * }; + * #endif + * // ... + * #if TRANSPORT_LOG_ENABLED_DEBUG + * TRANSPORT_LOGD("enum value: %s", g_enum_strings[v]); + * #endif + * + * See TRANSPORT_LOG_LEVEL for details. + */ +#define TRANSPORT_LOG_ENABLED(lvl) ((lvl) >= _TRANSPORT_LOG_LEVEL) +#define TRANSPORT_LOG_ENABLED_VERBOSE \ + TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_VERBOSE) +#define TRANSPORT_LOG_ENABLED_DEBUG TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_DEBUG) +#define TRANSPORT_LOG_ENABLED_INFO TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_INFO) +#define TRANSPORT_LOG_ENABLED_WARN TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_WARN) +#define TRANSPORT_LOG_ENABLED_ERROR TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_ERROR) +#define TRANSPORT_LOG_ENABLED_FATAL TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_FATAL) + +/* Check "output" log level at run time (taking into account "current" log + * level as well). Evaluates to true when specified log level is turned on AND + * enabled. For example: + * + * if (TRANSPORT_LOG_ON_DEBUG) + * { + * char hash[65]; + * sha256(data_ptr, data_sz, hash); + * TRANSPORT_LOGD("data: len=%u, sha256=%s", data_sz, hash); + * } + * + * See TRANSPORT_LOG_OUTPUT_LEVEL for details. + */ +#define TRANSPORT_LOG_ON(lvl) \ + (TRANSPORT_LOG_ENABLED((lvl)) && (lvl) >= _TRANSPORT_LOG_OUTPUT_LEVEL) +#define TRANSPORT_LOG_ON_VERBOSE TRANSPORT_LOG_ON(TRANSPORT_LOG_VERBOSE) +#define TRANSPORT_LOG_ON_DEBUG TRANSPORT_LOG_ON(TRANSPORT_LOG_DEBUG) +#define TRANSPORT_LOG_ON_INFO TRANSPORT_LOG_ON(TRANSPORT_LOG_INFO) +#define TRANSPORT_LOG_ON_WARN TRANSPORT_LOG_ON(TRANSPORT_LOG_WARN) +#define TRANSPORT_LOG_ON_ERROR TRANSPORT_LOG_ON(TRANSPORT_LOG_ERROR) +#define TRANSPORT_LOG_ON_FATAL TRANSPORT_LOG_ON(TRANSPORT_LOG_FATAL) + +#ifdef __cplusplus +extern "C" { +#endif + +extern const char *_transport_log_tag_prefix; +extern transport_log_format _transport_log_global_format; +extern transport_log_output _transport_log_global_output; +extern int _transport_log_global_output_lvl; +extern const transport_log_spec _transport_log_stderr_spec; + +void _transport_log_write_d(const char *const func, const char *const file, + const unsigned line, const int lvl, + const char *const tag, const char *const fmt, ...) + _TRANSPORT_LOG_PRINTFLIKE(6, 7); +void _transport_log_write_aux_d(const char *const func, const char *const file, + const unsigned line, + const transport_log_spec *const log, + const int lvl, const char *const tag, + const char *const fmt, ...) + _TRANSPORT_LOG_PRINTFLIKE(7, 8); +void _transport_log_write(const int lvl, const char *const tag, + const char *const fmt, ...) + _TRANSPORT_LOG_PRINTFLIKE(3, 4); +void _transport_log_write_aux(const transport_log_spec *const log, + const int lvl, const char *const tag, + const char *const fmt, ...) + _TRANSPORT_LOG_PRINTFLIKE(4, 5); +void _transport_log_write_mem_d(const char *const func, const char *const file, + const unsigned line, const int lvl, + const char *const tag, const void *const d, + const unsigned d_sz, const char *const fmt, ...) + _TRANSPORT_LOG_PRINTFLIKE(8, 9); +void _transport_log_write_mem_aux_d(const char *const func, + const char *const file, const unsigned line, + const transport_log_spec *const log, + const int lvl, const char *const tag, + const void *const d, const unsigned d_sz, + const char *const fmt, ...) + _TRANSPORT_LOG_PRINTFLIKE(9, 10); +void _transport_log_write_mem(const int lvl, const char *const tag, + const void *const d, const unsigned d_sz, + const char *const fmt, ...) + _TRANSPORT_LOG_PRINTFLIKE(5, 6); +void _transport_log_write_mem_aux(const transport_log_spec *const log, + const int lvl, const char *const tag, + const void *const d, const unsigned d_sz, + const char *const fmt, ...) + _TRANSPORT_LOG_PRINTFLIKE(6, 7); + +#ifdef __cplusplus +} +#endif + +/* Message logging macros: + * - TRANSPORT_LOGV("format string", args, ...) + * - TRANSPORT_LOGD("format string", args, ...) + * - TRANSPORT_LOGI("format string", args, ...) + * - TRANSPORT_LOGW("format string", args, ...) + * - TRANSPORT_LOGE("format string", args, ...) + * - TRANSPORT_LOGF("format string", args, ...) + * + * Memory logging macros: + * - TRANSPORT_LOGV_MEM(data_ptr, data_sz, "format string", args, ...) + * - TRANSPORT_LOGD_MEM(data_ptr, data_sz, "format string", args, ...) + * - TRANSPORT_LOGI_MEM(data_ptr, data_sz, "format string", args, ...) + * - TRANSPORT_LOGW_MEM(data_ptr, data_sz, "format string", args, ...) + * - TRANSPORT_LOGE_MEM(data_ptr, data_sz, "format string", args, ...) + * - TRANSPORT_LOGF_MEM(data_ptr, data_sz, "format string", args, ...) + * + * Auxiliary logging macros: + * - TRANSPORT_LOGV_AUX(&log_instance, "format string", args, ...) + * - TRANSPORT_LOGD_AUX(&log_instance, "format string", args, ...) + * - TRANSPORT_LOGI_AUX(&log_instance, "format string", args, ...) + * - TRANSPORT_LOGW_AUX(&log_instance, "format string", args, ...) + * - TRANSPORT_LOGE_AUX(&log_instance, "format string", args, ...) + * - TRANSPORT_LOGF_AUX(&log_instance, "format string", args, ...) + * + * Auxiliary memory logging macros: + * - TRANSPORT_LOGV_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", + * args, ...) + * - TRANSPORT_LOGD_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", + * args, ...) + * - TRANSPORT_LOGI_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", + * args, ...) + * - TRANSPORT_LOGW_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", + * args, ...) + * - TRANSPORT_LOGE_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", + * args, ...) + * - TRANSPORT_LOGF_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", + * args, ...) + * + * Preformatted string logging macros: + * - TRANSPORT_LOGV_STR("preformatted string"); + * - TRANSPORT_LOGD_STR("preformatted string"); + * - TRANSPORT_LOGI_STR("preformatted string"); + * - TRANSPORT_LOGW_STR("preformatted string"); + * - TRANSPORT_LOGE_STR("preformatted string"); + * - TRANSPORT_LOGF_STR("preformatted string"); + * + * Explicit log level and tag macros: + * - TRANSPORT_LOG_WRITE(level, tag, "format string", args, ...) + * - TRANSPORT_LOG_WRITE_MEM(level, tag, data_ptr, data_sz, "format string", + * args, ...) + * - TRANSPORT_LOG_WRITE_AUX(&log_instance, level, tag, "format string", args, + * ...) + * - TRANSPORT_LOG_WRITE_MEM_AUX(&log_instance, level, tag, data_ptr, data_sz, + * "format string", args, ...) + * + * Format string follows printf() conventions. Both data_ptr and data_sz could + * be 0. Tag can be 0 as well. Most compilers will verify that type of arguments + * match format specifiers in format string. + * + * Library assuming UTF-8 encoding for all strings (char *), including format + * string itself. + */ +#if TRANSPORT_LOG_SRCLOC_NONE == _TRANSPORT_LOG_SRCLOC +#define TRANSPORT_LOG_WRITE(lvl, tag, ...) \ + do { \ + if (TRANSPORT_LOG_ON(lvl)) _transport_log_write(lvl, tag, __VA_ARGS__); \ + } \ + _TRANSPORT_LOG_ONCE +#define TRANSPORT_LOG_WRITE_MEM(lvl, tag, d, d_sz, ...) \ + do { \ + if (TRANSPORT_LOG_ON(lvl)) \ + _transport_log_write_mem(lvl, tag, d, d_sz, __VA_ARGS__); \ + } \ + _TRANSPORT_LOG_ONCE +#define TRANSPORT_LOG_WRITE_AUX(log, lvl, tag, ...) \ + do { \ + if (TRANSPORT_LOG_ON(lvl)) \ + _transport_log_write_aux(log, lvl, tag, __VA_ARGS__); \ + } \ + _TRANSPORT_LOG_ONCE +#define TRANSPORT_LOG_WRITE_MEM_AUX(log, lvl, tag, d, d_sz, ...) \ + do { \ + if (TRANSPORT_LOG_ON(lvl)) \ + _transport_log_write_mem_aux(log, lvl, tag, d, d_sz, __VA_ARGS__); \ + } \ + _TRANSPORT_LOG_ONCE +#else +#define TRANSPORT_LOG_WRITE(lvl, tag, ...) \ + do { \ + if (TRANSPORT_LOG_ON(lvl)) \ + _transport_log_write_d(_TRANSPORT_LOG_SRCLOC_FUNCTION, __FILE__, \ + __LINE__, lvl, tag, __VA_ARGS__); \ + } \ + _TRANSPORT_LOG_ONCE +#define TRANSPORT_LOG_WRITE_MEM(lvl, tag, d, d_sz, ...) \ + do { \ + if (TRANSPORT_LOG_ON(lvl)) \ + _transport_log_write_mem_d(_TRANSPORT_LOG_SRCLOC_FUNCTION, __FILE__, \ + __LINE__, lvl, tag, d, d_sz, __VA_ARGS__); \ + } \ + _TRANSPORT_LOG_ONCE +#define TRANSPORT_LOG_WRITE_AUX(log, lvl, tag, ...) \ + do { \ + if (TRANSPORT_LOG_ON(lvl)) \ + _transport_log_write_aux_d(_TRANSPORT_LOG_SRCLOC_FUNCTION, __FILE__, \ + __LINE__, log, lvl, tag, __VA_ARGS__); \ + } \ + _TRANSPORT_LOG_ONCE +#define TRANSPORT_LOG_WRITE_MEM_AUX(log, lvl, tag, d, d_sz, ...) \ + do { \ + if (TRANSPORT_LOG_ON(lvl)) \ + _transport_log_write_mem_aux_d(_TRANSPORT_LOG_SRCLOC_FUNCTION, __FILE__, \ + __LINE__, log, lvl, tag, d, d_sz, \ + __VA_ARGS__); \ + } \ + _TRANSPORT_LOG_ONCE +#endif + +static _TRANSPORT_LOG_INLINE void _transport_log_unused(const int dummy, ...) { + (void)dummy; +} + +#define _TRANSPORT_LOG_UNUSED(...) \ + do { \ + _TRANSPORT_LOG_NEVER _transport_log_unused(0, __VA_ARGS__); \ + } \ + _TRANSPORT_LOG_ONCE + +#if TRANSPORT_LOG_ENABLED_VERBOSE +#define TRANSPORT_LOGV(...) \ + TRANSPORT_LOG_WRITE(TRANSPORT_LOG_VERBOSE, _TRANSPORT_LOG_TAG, __VA_ARGS__) +#define TRANSPORT_LOGV_AUX(log, ...) \ + TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_VERBOSE, _TRANSPORT_LOG_TAG, \ + __VA_ARGS__) +#define TRANSPORT_LOGV_MEM(d, d_sz, ...) \ + TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_VERBOSE, _TRANSPORT_LOG_TAG, d, d_sz, \ + __VA_ARGS__) +#define TRANSPORT_LOGV_MEM_AUX(log, d, d_sz, ...) \ + TRANSPORT_LOG_WRITE_MEM(log, TRANSPORT_LOG_VERBOSE, _TRANSPORT_LOG_TAG, d, \ + d_sz, __VA_ARGS__) +#else +#define TRANSPORT_LOGV(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGV_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGV_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGV_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#endif + +#if TRANSPORT_LOG_ENABLED_DEBUG +#define TRANSPORT_LOGD(...) \ + TRANSPORT_LOG_WRITE(TRANSPORT_LOG_DEBUG, _TRANSPORT_LOG_TAG, __VA_ARGS__) +#define TRANSPORT_LOGD_AUX(log, ...) \ + TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_DEBUG, _TRANSPORT_LOG_TAG, \ + __VA_ARGS__) +#define TRANSPORT_LOGD_MEM(d, d_sz, ...) \ + TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_DEBUG, _TRANSPORT_LOG_TAG, d, d_sz, \ + __VA_ARGS__) +#define TRANSPORT_LOGD_MEM_AUX(log, d, d_sz, ...) \ + TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_DEBUG, _TRANSPORT_LOG_TAG, d, \ + d_sz, __VA_ARGS__) +#else +#define TRANSPORT_LOGD(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGD_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGD_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGD_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#endif + +#if TRANSPORT_LOG_ENABLED_INFO +#define TRANSPORT_LOGI(...) \ + TRANSPORT_LOG_WRITE(TRANSPORT_LOG_INFO, _TRANSPORT_LOG_TAG, __VA_ARGS__) +#define TRANSPORT_LOGI_AUX(log, ...) \ + TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_INFO, _TRANSPORT_LOG_TAG, \ + __VA_ARGS__) +#define TRANSPORT_LOGI_MEM(d, d_sz, ...) \ + TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_INFO, _TRANSPORT_LOG_TAG, d, d_sz, \ + __VA_ARGS__) +#define TRANSPORT_LOGI_MEM_AUX(log, d, d_sz, ...) \ + TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_INFO, _TRANSPORT_LOG_TAG, d, \ + d_sz, __VA_ARGS__) +#else +#define TRANSPORT_LOGI(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGI_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGI_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGI_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#endif + +#if TRANSPORT_LOG_ENABLED_WARN +#define TRANSPORT_LOGW(...) \ + TRANSPORT_LOG_WRITE(TRANSPORT_LOG_WARN, _TRANSPORT_LOG_TAG, __VA_ARGS__) +#define TRANSPORT_LOGW_AUX(log, ...) \ + TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_WARN, _TRANSPORT_LOG_TAG, \ + __VA_ARGS__) +#define TRANSPORT_LOGW_MEM(d, d_sz, ...) \ + TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_WARN, _TRANSPORT_LOG_TAG, d, d_sz, \ + __VA_ARGS__) +#define TRANSPORT_LOGW_MEM_AUX(log, d, d_sz, ...) \ + TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_WARN, _TRANSPORT_LOG_TAG, d, \ + d_sz, __VA_ARGS__) +#else +#define TRANSPORT_LOGW(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGW_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGW_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGW_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#endif + +#if TRANSPORT_LOG_ENABLED_ERROR +#define TRANSPORT_LOGE(...) \ + TRANSPORT_LOG_WRITE(TRANSPORT_LOG_ERROR, _TRANSPORT_LOG_TAG, __VA_ARGS__) +#define TRANSPORT_LOGE_AUX(log, ...) \ + TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_ERROR, _TRANSPORT_LOG_TAG, \ + __VA_ARGS__) +#define TRANSPORT_LOGE_MEM(d, d_sz, ...) \ + TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_ERROR, _TRANSPORT_LOG_TAG, d, d_sz, \ + __VA_ARGS__) +#define TRANSPORT_LOGE_MEM_AUX(log, d, d_sz, ...) \ + TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_ERROR, _TRANSPORT_LOG_TAG, d, \ + d_sz, __VA_ARGS__) +#else +#define TRANSPORT_LOGE(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGE_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGE_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGE_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#endif + +#if TRANSPORT_LOG_ENABLED_FATAL +#define TRANSPORT_LOGF(...) \ + TRANSPORT_LOG_WRITE(TRANSPORT_LOG_FATAL, _TRANSPORT_LOG_TAG, __VA_ARGS__) +#define TRANSPORT_LOGF_AUX(log, ...) \ + TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_FATAL, _TRANSPORT_LOG_TAG, \ + __VA_ARGS__) +#define TRANSPORT_LOGF_MEM(d, d_sz, ...) \ + TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_FATAL, _TRANSPORT_LOG_TAG, d, d_sz, \ + __VA_ARGS__) +#define TRANSPORT_LOGF_MEM_AUX(log, d, d_sz, ...) \ + TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_FATAL, _TRANSPORT_LOG_TAG, d, \ + d_sz, __VA_ARGS__) +#else +#define TRANSPORT_LOGF(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGF_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGF_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGF_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#endif + +#define TRANSPORT_LOGV_STR(s) TRANSPORT_LOGV("%s", (s)) +#define TRANSPORT_LOGD_STR(s) TRANSPORT_LOGD("%s", (s)) +#define TRANSPORT_LOGI_STR(s) TRANSPORT_LOGI("%s", (s)) +#define TRANSPORT_LOGW_STR(s) TRANSPORT_LOGW("%s", (s)) +#define TRANSPORT_LOGE_STR(s) TRANSPORT_LOGE("%s", (s)) +#define TRANSPORT_LOGF_STR(s) TRANSPORT_LOGF("%s", (s)) + +#ifdef __cplusplus +extern "C" { +#endif + +/* Output to standard error stream. Library uses it by default, though in few + * cases it could be necessary to specify it explicitly. For example, when + * transport_log library is compiled with TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT, + * application must define and initialize global output variable: + * + * TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {TRANSPORT_LOG_OUT_STDERR}; + * + * Another example is when using custom output, stderr could be used as a + * fallback when custom output facility failed to initialize: + * + * transport_log_set_output_v(TRANSPORT_LOG_OUT_STDERR); + */ +enum { TRANSPORT_LOG_OUT_STDERR_MASK = TRANSPORT_LOG_PUT_STD }; +void transport_log_out_stderr_callback(const transport_log_message *const msg, + void *arg); +#define TRANSPORT_LOG_OUT_STDERR \ + TRANSPORT_LOG_OUT_STDERR_MASK, 0, transport_log_out_stderr_callback + +/* Predefined spec for stderr. Uses global format options + * (TRANSPORT_LOG_GLOBAL_FORMAT) and TRANSPORT_LOG_OUT_STDERR. Could be used to + * force output to stderr for a particular message. Example: + * + * f = fopen("foo.log", "w"); + * if (!f) + * TRANSPORT_LOGE_AUX(TRANSPORT_LOG_STDERR, "Failed to open log file"); + */ +#define TRANSPORT_LOG_STDERR (&_transport_log_stderr_spec) + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/utils/membuf.h b/libtransport/includes/hicn/transport/utils/membuf.h new file mode 100644 index 000000000..9fc37dd25 --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/membuf.h @@ -0,0 +1,921 @@ +/* + * Copyright 2013-present Facebook, Inc. + * + * 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. + */ + +/* + * The code in this file if adapated from the IOBuf of folly: + * https://github.com/facebook/folly/blob/master/folly/io/IOBuf.h + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifndef _WIN32 +TRANSPORT_GNU_DISABLE_WARNING("-Wshadow") +#endif + +namespace utils { + +class MemBuf { + public: + enum CreateOp { CREATE }; + enum WrapBufferOp { WRAP_BUFFER }; + enum TakeOwnershipOp { TAKE_OWNERSHIP }; + enum CopyBufferOp { COPY_BUFFER }; + + typedef void (*FreeFunction)(void* buf, void* userData); + + static std::unique_ptr create(std::size_t capacity); + MemBuf(CreateOp, std::size_t capacity); + + /** + * Create a new MemBuf, using a single memory allocation to allocate space + * for both the MemBuf object and the data storage space. + * + * This saves one memory allocation. However, it can be wasteful if you + * later need to grow the buffer using reserve(). If the buffer needs to be + * reallocated, the space originally allocated will not be freed() until the + * MemBuf object itself is also freed. (It can also be slightly wasteful in + * some cases where you clone this MemBuf and then free the original MemBuf.) + */ + static std::unique_ptr createCombined(std::size_t capacity); + + /** + * Create a new IOBuf, using separate memory allocations for the IOBuf object + * for the IOBuf and the data storage space. + * + * This requires two memory allocations, but saves space in the long run + * if you know that you will need to reallocate the data buffer later. + */ + static std::unique_ptr createSeparate(std::size_t capacity); + + /** + * Allocate a new MemBuf chain with the requested total capacity, allocating + * no more than maxBufCapacity to each buffer. + */ + static std::unique_ptr createChain(size_t totalCapacity, + std::size_t maxBufCapacity); + + static std::unique_ptr takeOwnership(void* buf, std::size_t capacity, + FreeFunction freeFn = nullptr, + void* userData = nullptr, + bool freeOnError = true) { + return takeOwnership(buf, capacity, capacity, freeFn, userData, + freeOnError); + } + + MemBuf(TakeOwnershipOp op, void* buf, std::size_t capacity, + FreeFunction freeFn = nullptr, void* userData = nullptr, + bool freeOnError = true) + : MemBuf(op, buf, capacity, capacity, freeFn, userData, freeOnError) {} + + static std::unique_ptr takeOwnership(void* buf, std::size_t capacity, + std::size_t length, + FreeFunction freeFn = nullptr, + void* userData = nullptr, + bool freeOnError = true); + + MemBuf(TakeOwnershipOp, void* buf, std::size_t capacity, std::size_t length, + FreeFunction freeFn = nullptr, void* userData = nullptr, + bool freeOnError = true); + + static std::unique_ptr wrapBuffer(const void* buf, + std::size_t capacity); + + static MemBuf wrapBufferAsValue(const void* buf, + std::size_t capacity) noexcept; + + MemBuf(WrapBufferOp op, const void* buf, std::size_t capacity) noexcept; + + /** + * Convenience function to create a new MemBuf object that copies data from a + * user-supplied buffer, optionally allocating a given amount of + * headroom and tailroom. + */ + static std::unique_ptr copyBuffer(const void* buf, std::size_t size, + std::size_t headroom = 0, + std::size_t minTailroom = 0); + + MemBuf(CopyBufferOp op, const void* buf, std::size_t size, + std::size_t headroom = 0, std::size_t minTailroom = 0); + + /** + * Convenience function to free a chain of MemBufs held by a unique_ptr. + */ + static void destroy(std::unique_ptr&& data) { + auto destroyer = std::move(data); + } + + ~MemBuf(); + + bool empty() const; + + const uint8_t* data() const { return data_; } + + uint8_t* writableData() { return data_; } + + const uint8_t* tail() const { return data_ + length_; } + + uint8_t* writableTail() { return data_ + length_; } + + std::size_t length() const { return length_; } + + std::size_t headroom() const { return std::size_t(data_ - buffer()); } + + std::size_t tailroom() const { return std::size_t(bufferEnd() - tail()); } + + const uint8_t* buffer() const { return buf_; } + + uint8_t* writableBuffer() { return buf_; } + + const uint8_t* bufferEnd() const { return buf_ + capacity_; } + + std::size_t capacity() const { return capacity_; } + + MemBuf* next() { return next_; } + + const MemBuf* next() const { return next_; } + + MemBuf* prev() { return prev_; } + + const MemBuf* prev() const { return prev_; } + + /** + * Shift the data forwards in the buffer. + * + * This shifts the data pointer forwards in the buffer to increase the + * headroom. This is commonly used to increase the headroom in a newly + * allocated buffer. + * + * The caller is responsible for ensuring that there is sufficient + * tailroom in the buffer before calling advance(). + * + * If there is a non-zero data length, advance() will use memmove() to shift + * the data forwards in the buffer. In this case, the caller is responsible + * for making sure the buffer is unshared, so it will not affect other MemBufs + * that may be sharing the same underlying buffer. + */ + void advance(std::size_t amount) { + // In debug builds, assert if there is a problem. + assert(amount <= tailroom()); + + if (length_ > 0) { + memmove(data_ + amount, data_, length_); + } + data_ += amount; + } + + /** + * Shift the data backwards in the buffer. + * + * The caller is responsible for ensuring that there is sufficient headroom + * in the buffer before calling retreat(). + * + * If there is a non-zero data length, retreat() will use memmove() to shift + * the data backwards in the buffer. In this case, the caller is responsible + * for making sure the buffer is unshared, so it will not affect other MemBufs + * that may be sharing the same underlying buffer. + */ + void retreat(std::size_t amount) { + // In debug builds, assert if there is a problem. + assert(amount <= headroom()); + + if (length_ > 0) { + memmove(data_ - amount, data_, length_); + } + data_ -= amount; + } + + void prepend(std::size_t amount) { + data_ -= amount; + length_ += amount; + } + + void append(std::size_t amount) { length_ += amount; } + + void trimStart(std::size_t amount) { + data_ += amount; + length_ -= amount; + } + + void trimEnd(std::size_t amount) { length_ -= amount; } + + // Never call clear on cloned membuf sharing different + // portions of the same underlying buffer. + // Use the trim functions instead. + void clear() { + data_ = writableBuffer(); + length_ = 0; + } + + void reserve(std::size_t minHeadroom, std::size_t minTailroom) { + // Maybe we don't need to do anything. + if (headroom() >= minHeadroom && tailroom() >= minTailroom) { + return; + } + // If the buffer is empty but we have enough total room (head + tail), + // move the data_ pointer around. + if (length() == 0 && headroom() + tailroom() >= minHeadroom + minTailroom) { + data_ = writableBuffer() + minHeadroom; + return; + } + // Bah, we have to do actual work. + reserveSlow(minHeadroom, minTailroom); + } + + bool isChained() const { + assert((next_ == this) == (prev_ == this)); + return next_ != this; + } + + size_t countChainElements() const; + + std::size_t computeChainDataLength() const; + + void prependChain(std::unique_ptr&& iobuf); + + void appendChain(std::unique_ptr&& iobuf) { + // Just use prependChain() on the next element in our chain + next_->prependChain(std::move(iobuf)); + } + + std::unique_ptr unlink() { + next_->prev_ = prev_; + prev_->next_ = next_; + prev_ = this; + next_ = this; + return std::unique_ptr(this); + } + + /** + * Remove this MemBuf from its current chain and return a unique_ptr to + * the MemBuf that formerly followed it in the chain. + */ + std::unique_ptr pop() { + MemBuf* next = next_; + next_->prev_ = prev_; + prev_->next_ = next_; + prev_ = this; + next_ = this; + return std::unique_ptr((next == this) ? nullptr : next); + } + + /** + * Remove a subchain from this chain. + * + * Remove the subchain starting at head and ending at tail from this chain. + * + * Returns a unique_ptr pointing to head. (In other words, ownership of the + * head of the subchain is transferred to the caller.) If the caller ignores + * the return value and lets the unique_ptr be destroyed, the subchain will + * be immediately destroyed. + * + * The subchain referenced by the specified head and tail must be part of the + * same chain as the current MemBuf, but must not contain the current MemBuf. + * However, the specified head and tail may be equal to each other (i.e., + * they may be a subchain of length 1). + */ + std::unique_ptr separateChain(MemBuf* head, MemBuf* tail) { + assert(head != this); + assert(tail != this); + + head->prev_->next_ = tail->next_; + tail->next_->prev_ = head->prev_; + + head->prev_ = tail; + tail->next_ = head; + + return std::unique_ptr(head); + } + + /** + * Return true if at least one of the MemBufs in this chain are shared, + * or false if all of the MemBufs point to unique buffers. + * + * Use isSharedOne() to only check this MemBuf rather than the entire chain. + */ + bool isShared() const { + const MemBuf* current = this; + while (true) { + if (current->isSharedOne()) { + return true; + } + current = current->next_; + if (current == this) { + return false; + } + } + } + + /** + * Return true if all MemBufs in this chain are managed by the usual + * refcounting mechanism (and so the lifetime of the underlying memory + * can be extended by clone()). + */ + bool isManaged() const { + const MemBuf* current = this; + while (true) { + if (!current->isManagedOne()) { + return false; + } + current = current->next_; + if (current == this) { + return true; + } + } + } + + /** + * Return true if this MemBuf is managed by the usual refcounting mechanism + * (and so the lifetime of the underlying memory can be extended by + * cloneOne()). + */ + bool isManagedOne() const { return sharedInfo(); } + + /** + * Return true if other MemBufs are also pointing to the buffer used by this + * MemBuf, and false otherwise. + * + * If this MemBuf points at a buffer owned by another (non-MemBuf) part of the + * code (i.e., if the MemBuf was created using wrapBuffer(), or was cloned + * from such an MemBuf), it is always considered shared. + * + * This only checks the current MemBuf, and not other MemBufs in the chain. + */ + bool isSharedOne() const { + // If this is a user-owned buffer, it is always considered shared + if ((TRANSPORT_EXPECT_FALSE(!sharedInfo()))) { + return true; + } + + if ((TRANSPORT_EXPECT_FALSE(sharedInfo()->externallyShared))) { + return true; + } + + if ((TRANSPORT_EXPECT_TRUE(!(flags() & flag_maybe_shared)))) { + return false; + } + + // flag_maybe_shared is set, so we need to check the reference count. + // (Checking the reference count requires an atomic operation, which is why + // we prefer to only check flag_maybe_shared if possible.) + bool shared = sharedInfo()->refcount.load(std::memory_order_acquire) > 1; + if (!shared) { + // we're the last one left + clearFlags(flag_maybe_shared); + } + return shared; + } + + /** + * Ensure that this MemBuf has a unique buffer that is not shared by other + * MemBufs. + * + * unshare() operates on an entire chain of MemBuf objects. If the chain is + * shared, it may also coalesce the chain when making it unique. If the + * chain is coalesced, subsequent MemBuf objects in the current chain will be + * automatically deleted. + * + * Note that buffers owned by other (non-MemBuf) users are automatically + * considered shared. + * + * Throws std::bad_alloc on error. On error the MemBuf chain will be + * unmodified. + * + * Currently unshare may also throw std::overflow_error if it tries to + * coalesce. (TODO: In the future it would be nice if unshare() were smart + * enough not to coalesce the entire buffer if the data is too large. + * However, in practice this seems unlikely to become an issue.) + */ + void unshare() { + if (isChained()) { + unshareChained(); + } else { + unshareOne(); + } + } + + /** + * Ensure that this MemBuf has a unique buffer that is not shared by other + * MemBufs. + * + * unshareOne() operates on a single MemBuf object. This MemBuf will have a + * unique buffer after unshareOne() returns, but other MemBufs in the chain + * may still be shared after unshareOne() returns. + * + * Throws std::bad_alloc on error. On error the MemBuf will be unmodified. + */ + void unshareOne() { + if (isSharedOne()) { + unshareOneSlow(); + } + } + + /** + * Mark the underlying buffers in this chain as shared with external memory + * management mechanism. This will make isShared() always returns true. + * + * This function is not thread-safe, and only safe to call immediately after + * creating an MemBuf, before it has been shared with other threads. + */ + void markExternallyShared(); + + /** + * Mark the underlying buffer that this MemBuf refers to as shared with + * external memory management mechanism. This will make isSharedOne() always + * returns true. + * + * This function is not thread-safe, and only safe to call immediately after + * creating an MemBuf, before it has been shared with other threads. + */ + void markExternallySharedOne() { + SharedInfo* info = sharedInfo(); + if (info) { + info->externallyShared = true; + } + } + + /** + * Ensure that the memory that MemBufs in this chain refer to will continue to + * be allocated for as long as the MemBufs of the chain (or any clone()s + * created from this point onwards) is alive. + * + * This only has an effect for user-owned buffers (created with the + * WRAP_BUFFER constructor or wrapBuffer factory function), in which case + * those buffers are unshared. + */ + void makeManaged() { + if (isChained()) { + makeManagedChained(); + } else { + makeManagedOne(); + } + } + + /** + * Ensure that the memory that this MemBuf refers to will continue to be + * allocated for as long as this MemBuf (or any clone()s created from this + * point onwards) is alive. + * + * This only has an effect for user-owned buffers (created with the + * WRAP_BUFFER constructor or wrapBuffer factory function), in which case + * those buffers are unshared. + */ + void makeManagedOne() { + if (!isManagedOne()) { + // We can call the internal function directly; unmanaged implies shared. + unshareOneSlow(); + } + } + + // /** + // * Coalesce this MemBuf chain into a single buffer. + // * + // * This method moves all of the data in this MemBuf chain into a single + // * contiguous buffer, if it is not already in one buffer. After coalesce() + // * returns, this MemBuf will be a chain of length one. Other MemBufs in + // the + // * chain will be automatically deleted. + // * + // * After coalescing, the MemBuf will have at least as much headroom as the + // * first MemBuf in the chain, and at least as much tailroom as the last + // MemBuf + // * in the chain. + // * + // * Throws std::bad_alloc on error. On error the MemBuf chain will be + // * unmodified. + // * + // * Returns ByteRange that points to the data MemBuf stores. + // */ + // ByteRange coalesce() { + // const std::size_t newHeadroom = headroom(); + // const std::size_t newTailroom = prev()->tailroom(); + // return coalesceWithHeadroomTailroom(newHeadroom, newTailroom); + // } + + // /** + // * This is similar to the coalesce() method, except this allows to set a + // * headroom and tailroom after coalescing. + // * + // * Returns ByteRange that points to the data MemBuf stores. + // */ + // ByteRange coalesceWithHeadroomTailroom(std::size_t newHeadroom, + // std::size_t newTailroom) { + // if (isChained()) { + // coalesceAndReallocate(newHeadroom, computeChainDataLength(), this, + // newTailroom); + // } + // return ByteRange(data_, length_); + // } + + /** + * Ensure that this chain has at least maxLength bytes available as a + * contiguous memory range. + * + * This method coalesces whole buffers in the chain into this buffer as + * necessary until this buffer's length() is at least maxLength. + * + * After coalescing, the MemBuf will have at least as much headroom as the + * first MemBuf in the chain, and at least as much tailroom as the last MemBuf + * that was coalesced. + * + * Throws std::bad_alloc or std::overflow_error on error. On error the MemBuf + * chain will be unmodified. Throws std::overflow_error if maxLength is + * longer than the total chain length. + * + * Upon return, either enough of the chain was coalesced into a contiguous + * region, or the entire chain was coalesced. That is, + * length() >= maxLength || !isChained() is true. + */ + void gather(std::size_t maxLength) { + if (!isChained() || length_ >= maxLength) { + return; + } + coalesceSlow(maxLength); + } + + /** + * Return a new MemBuf chain sharing the same data as this chain. + * + * The new MemBuf chain will normally point to the same underlying data + * buffers as the original chain. (The one exception to this is if some of + * the MemBufs in this chain contain small internal data buffers which cannot + * be shared.) + */ + std::unique_ptr clone() const; + + /** + * Similar to clone(). But returns MemBuf by value rather than heap-allocating + * it. + */ + MemBuf cloneAsValue() const; + + /** + * Return a new MemBuf with the same data as this MemBuf. + * + * The new MemBuf returned will not be part of a chain (even if this MemBuf is + * part of a larger chain). + */ + std::unique_ptr cloneOne() const; + + /** + * Similar to cloneOne(). But returns MemBuf by value rather than + * heap-allocating it. + */ + MemBuf cloneOneAsValue() const; + + /** + * Return a new unchained MemBuf that may share the same data as this chain. + * + * If the MemBuf chain is not chained then the new MemBuf will point to the + * same underlying data buffer as the original chain. Otherwise, it will clone + * and coalesce the MemBuf chain. + * + * The new MemBuf will have at least as much headroom as the first MemBuf in + * the chain, and at least as much tailroom as the last MemBuf in the chain. + * + * Throws std::bad_alloc on error. + */ + std::unique_ptr cloneCoalesced() const; + + /** + * This is similar to the cloneCoalesced() method, except this allows to set a + * headroom and tailroom for the new MemBuf. + */ + std::unique_ptr cloneCoalescedWithHeadroomTailroom( + std::size_t newHeadroom, std::size_t newTailroom) const; + + /** + * Similar to cloneCoalesced(). But returns MemBuf by value rather than + * heap-allocating it. + */ + MemBuf cloneCoalescedAsValue() const; + + /** + * This is similar to the cloneCoalescedAsValue() method, except this allows + * to set a headroom and tailroom for the new MemBuf. + */ + MemBuf cloneCoalescedAsValueWithHeadroomTailroom( + std::size_t newHeadroom, std::size_t newTailroom) const; + + /** + * Similar to Clone(). But use other as the head node. Other nodes in the + * chain (if any) will be allocted on heap. + */ + void cloneInto(MemBuf& other) const { other = cloneAsValue(); } + + /** + * Similar to CloneOne(). But to fill an existing MemBuf instead of a new + * MemBuf. + */ + void cloneOneInto(MemBuf& other) const { other = cloneOneAsValue(); } + + /** + * Return an iovector suitable for e.g. writev() + * + * auto iov = buf->getIov(); + * auto xfer = writev(fd, iov.data(), iov.size()); + * + * Naturally, the returned iovector is invalid if you modify the buffer + * chain. + */ + std::vector getIov() const; + + /** + * Update an existing iovec array with the MemBuf data. + * + * New iovecs will be appended to the existing vector; anything already + * present in the vector will be left unchanged. + * + * Naturally, the returned iovec data will be invalid if you modify the + * buffer chain. + */ + void appendToIov(std::vector* iov) const; + + /** + * Fill an iovec array with the MemBuf data. + * + * Returns the number of iovec filled. If there are more buffer than + * iovec, returns 0. This version is suitable to use with stack iovec + * arrays. + * + * Naturally, the filled iovec data will be invalid if you modify the + * buffer chain. + */ + size_t fillIov(struct iovec* iov, size_t len) const; + + /** + * A helper that wraps a number of iovecs into an MemBuf chain. If count == + * 0, then a zero length buf is returned. This function never returns + * nullptr. + */ + static std::unique_ptr wrapIov(const iovec* vec, size_t count); + + /** + * A helper that takes ownerships a number of iovecs into an MemBuf chain. If + * count == 0, then a zero length buf is returned. This function never + * returns nullptr. + */ + static std::unique_ptr takeOwnershipIov(const iovec* vec, + size_t count, + FreeFunction freeFn = nullptr, + void* userData = nullptr, + bool freeOnError = true); + + /* + * Overridden operator new and delete. + * These perform specialized memory management to help support + * createCombined(), which allocates MemBuf objects together with the buffer + * data. + */ + void* operator new(size_t size); + void* operator new(size_t size, void* ptr); + void operator delete(void* ptr); + void operator delete(void* ptr, void* placement); + + // /** + // * Iteration support: a chain of MemBufs may be iterated through using + // * STL-style iterators over const ByteRanges. Iterators are only + // invalidated + // * if the MemBuf that they currently point to is removed. + // */ + // Iterator cbegin() const; + // Iterator cend() const; + // Iterator begin() const; + // Iterator end() const; + + /** + * Allocate a new null buffer. + * + * This can be used to allocate an empty MemBuf on the stack. It will have no + * space allocated for it. This is generally useful only to later use move + * assignment to fill out the MemBuf. + */ + MemBuf() noexcept; + + /** + * Move constructor and assignment operator. + * + * In general, you should only ever move the head of an MemBuf chain. + * Internal nodes in an MemBuf chain are owned by the head of the chain, and + * should not be moved from. (Technically, nothing prevents you from moving + * a non-head node, but the moved-to node will replace the moved-from node in + * the chain. This has implications for ownership, since non-head nodes are + * owned by the chain head. You are then responsible for relinquishing + * ownership of the moved-to node, and manually deleting the moved-from + * node.) + * + * With the move assignment operator, the destination of the move should be + * the head of an MemBuf chain or a solitary MemBuf not part of a chain. If + * the move destination is part of a chain, all other MemBufs in the chain + * will be deleted. + */ + MemBuf(MemBuf&& other) noexcept; + MemBuf& operator=(MemBuf&& other) noexcept; + + MemBuf(const MemBuf& other); + MemBuf& operator=(const MemBuf& other); + + private: + enum FlagsEnum : uintptr_t { + // Adding any more flags would not work on 32-bit architectures, + // as these flags are stashed in the least significant 2 bits of a + // max-align-aligned pointer. + flag_free_shared_info = 0x1, + flag_maybe_shared = 0x2, + flag_mask = flag_free_shared_info | flag_maybe_shared + }; + + struct SharedInfo { + SharedInfo(); + SharedInfo(FreeFunction fn, void* arg); + + // A pointer to a function to call to free the buffer when the refcount + // hits 0. If this is null, free() will be used instead. + FreeFunction freeFn; + void* userData; + std::atomic refcount; + bool externallyShared{false}; + }; + // Helper structs for use by operator new and delete + struct HeapPrefix; + struct HeapStorage; + struct HeapFullStorage; + + /** + * Create a new MemBuf pointing to an external buffer. + * + * The caller is responsible for holding a reference count for this new + * MemBuf. The MemBuf constructor does not automatically increment the + * reference count. + */ + struct InternalConstructor {}; // avoid conflicts + MemBuf(InternalConstructor, uintptr_t flagsAndSharedInfo, uint8_t* buf, + std::size_t capacity, uint8_t* data, std::size_t length) noexcept; + + void unshareOneSlow(); + void unshareChained(); + void makeManagedChained(); + void coalesceSlow(); + void coalesceSlow(size_t maxLength); + // newLength must be the entire length of the buffers between this and + // end (no truncation) + void coalesceAndReallocate(size_t newHeadroom, size_t newLength, MemBuf* end, + size_t newTailroom); + void coalesceAndReallocate(size_t newLength, MemBuf* end) { + coalesceAndReallocate(headroom(), newLength, end, end->prev_->tailroom()); + } + void decrementRefcount(); + void reserveSlow(std::size_t minHeadroom, std::size_t minTailroom); + void freeExtBuffer(); + + static size_t goodExtBufferSize(std::size_t minCapacity); + static void initExtBuffer(uint8_t* buf, size_t mallocSize, + SharedInfo** infoReturn, + std::size_t* capacityReturn); + static void allocExtBuffer(std::size_t minCapacity, uint8_t** bufReturn, + SharedInfo** infoReturn, + std::size_t* capacityReturn); + static void releaseStorage(HeapStorage* storage, uint16_t freeFlags); + static void freeInternalBuf(void* buf, void* userData); + + /* + * Member variables + */ + + /* + * Links to the next and the previous MemBuf in this chain. + * + * The chain is circularly linked (the last element in the chain points back + * at the head), and next_ and prev_ can never be null. If this MemBuf is the + * only element in the chain, next_ and prev_ will both point to this. + */ + MemBuf* next_{this}; + MemBuf* prev_{this}; + + /* + * A pointer to the start of the data referenced by this MemBuf, and the + * length of the data. + * + * This may refer to any subsection of the actual buffer capacity. + */ + uint8_t* data_{nullptr}; + uint8_t* buf_{nullptr}; + std::size_t length_{0}; + std::size_t capacity_{0}; + + // Pack flags in least significant 2 bits, sharedInfo in the rest + mutable uintptr_t flags_and_shared_info_{0}; + + static inline uintptr_t packFlagsAndSharedInfo(uintptr_t flags, + SharedInfo* info) { + uintptr_t uinfo = reinterpret_cast(info); + return flags | uinfo; + } + + inline SharedInfo* sharedInfo() const { + return reinterpret_cast(flags_and_shared_info_ & ~flag_mask); + } + + inline void setSharedInfo(SharedInfo* info) { + uintptr_t uinfo = reinterpret_cast(info); + flags_and_shared_info_ = (flags_and_shared_info_ & flag_mask) | uinfo; + } + + inline uintptr_t flags() const { return flags_and_shared_info_ & flag_mask; } + + // flags_ are changed from const methods + inline void setFlags(uintptr_t flags) const { + flags_and_shared_info_ |= flags; + } + + inline void clearFlags(uintptr_t flags) const { + flags_and_shared_info_ &= ~flags; + } + + inline void setFlagsAndSharedInfo(uintptr_t flags, SharedInfo* info) { + flags_and_shared_info_ = packFlagsAndSharedInfo(flags, info); + } + + struct DeleterBase { + virtual ~DeleterBase() {} + virtual void dispose(void* p) = 0; + }; + + template + struct UniquePtrDeleter : public DeleterBase { + typedef typename UniquePtr::pointer Pointer; + typedef typename UniquePtr::deleter_type Deleter; + + explicit UniquePtrDeleter(Deleter deleter) : deleter_(std::move(deleter)) {} + void dispose(void* p) override { + try { + deleter_(static_cast(p)); + delete this; + } catch (...) { + abort(); + } + } + + private: + Deleter deleter_; + }; + + static void freeUniquePtrBuffer(void* ptr, void* userData) { + static_cast(userData)->dispose(ptr); + } +}; + +// template +// typename std::enable_if< +// detail::IsUniquePtrToSL::value, +// std::unique_ptr>::type +// MemBuf::takeOwnership(UniquePtr&& buf, size_t count) { +// size_t size = count * sizeof(typename UniquePtr::element_type); +// auto deleter = new UniquePtrDeleter(buf.get_deleter()); +// return takeOwnership( +// buf.release(), size, &MemBuf::freeUniquePtrBuffer, deleter); +// } + +inline std::unique_ptr MemBuf::copyBuffer(const void* data, + std::size_t size, + std::size_t headroom, + std::size_t minTailroom) { + std::size_t capacity = headroom + size + minTailroom; + std::unique_ptr buf = MemBuf::create(capacity); + buf->advance(headroom); + if (size != 0) { + memcpy(buf->writableData(), data, size); + } + buf->append(size); + return buf; +} + +} // namespace utils diff --git a/libtransport/includes/hicn/transport/utils/object_pool.h b/libtransport/includes/hicn/transport/utils/object_pool.h new file mode 100644 index 000000000..f78bd2aa2 --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/object_pool.h @@ -0,0 +1,90 @@ +/* + * 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. + */ + +#pragma once + +// TODO +#include +#include + +#include +#include +#include + +namespace utils { + +template +class ObjectPool { + class ObjectDeleter { + public: + ObjectDeleter(ObjectPool *pool = nullptr) : pool_(pool) {} + + void operator()(T *t) { + if (pool_) { + pool_->add(t); + } else { + delete t; + } + } + + private: + ObjectPool *pool_; + }; + + public: + using Ptr = std::unique_ptr; + + ObjectPool() : destructor_(false) {} + + ~ObjectPool() { + destructor_ = true; + for (auto &ptr : object_pool_) { + ptr.reset(); + } + } + + std::pair get() { + if (object_pool_.empty()) { + return std::make_pair(false, makePtr(nullptr)); + } + + utils::SpinLock::Acquire locked(object_pool_lock_); + auto ret = std::move(object_pool_.front()); + object_pool_.pop_front(); + return std::make_pair(true, std::move(ret)); + } + + void add(T *object) { + utils::SpinLock::Acquire locked(object_pool_lock_); + + if (TRANSPORT_EXPECT_TRUE(!destructor_)) { + object_pool_.emplace_back(makePtr(object)); + } else { + delete object; + } + } + + Ptr makePtr(T *object) { return Ptr(object, ObjectDeleter(this)); } + + private: + // No copies + ObjectPool(const ObjectPool &other) = delete; + + utils::SpinLock object_pool_lock_; + std::deque object_pool_; + bool destructor_; +}; + +} // namespace utils \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/utils/ring_buffer.h b/libtransport/includes/hicn/transport/utils/ring_buffer.h new file mode 100644 index 000000000..9babe56bd --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/ring_buffer.h @@ -0,0 +1,129 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +namespace utils { + +/** + * NOTE: Single consumer single producer ring buffer + */ +template +class CircularFifo { + public: + enum { Capacity = Size + 1 }; + + CircularFifo() : tail_(0), head_(0), size_(0) {} + virtual ~CircularFifo() {} + + bool push(const Element& item); + bool push(Element&& item); + bool pop(Element& item); + + bool wasEmpty() const; + bool wasFull() const; + bool isLockFree() const; + std::size_t size() const; + + private: + std::size_t increment(std::size_t idx) const; + std::atomic tail_; // tail(input) index + Element array_[Capacity]; + std::atomic head_; // head(output) index + std::atomic size_; +}; + +template +bool CircularFifo::push(const Element& item) { + const auto current_tail = tail_.load(std::memory_order_relaxed); + const auto next_tail = increment(current_tail); + if (next_tail != head_.load(std::memory_order_acquire)) { + array_[current_tail] = item; + tail_.store(next_tail, std::memory_order_release); + size_++; + return true; + } + + // full queue + return false; +} + +/** + * Push by move + */ +template +bool CircularFifo::push(Element&& item) { + const auto current_tail = tail_.load(std::memory_order_relaxed); + const auto next_tail = increment(current_tail); + if (next_tail != head_.load(std::memory_order_acquire)) { + array_[current_tail] = std::move(item); + tail_.store(next_tail, std::memory_order_release); + size_++; + return true; + } + + // full queue + return false; +} + +// Pop by Consumer can only update the head +// (load with relaxed, store with release) +// the tail must be accessed with at least acquire +template +bool CircularFifo::pop(Element& item) { + const size_t current_head = head_.load(std::memory_order_relaxed); + if (current_head == tail_.load(std::memory_order_acquire)) { + return false; // empty queue + } + + item = std::move(array_[current_head]); + head_.store(increment(current_head), std::memory_order_release); + size_--; + return true; +} + +template +bool CircularFifo::wasEmpty() const { + // snapshot with acceptance of that this comparison operation is not atomic + return (head_.load() == tail_.load()); +} + +// snapshot with acceptance that this comparison is not atomic +template +bool CircularFifo::wasFull() const { + const auto next_tail = + increment(tail_.load()); // acquire, we dont know who call + return (next_tail == head_.load()); +} + +template +bool CircularFifo::isLockFree() const { + return (tail_.is_lock_free() && head_.is_lock_free()); +} + +template +std::size_t CircularFifo::increment(std::size_t idx) const { + return (idx + 1) % Capacity; +} + +template +std::size_t CircularFifo::size() const { + return size_.load(std::memory_order_relaxed); +} + +} // namespace utils \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/utils/spinlock.h b/libtransport/includes/hicn/transport/utils/spinlock.h new file mode 100644 index 000000000..009a94454 --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/spinlock.h @@ -0,0 +1,53 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace utils { + +class SpinLock : private std::atomic_flag { + public: + class Acquire { + public: + Acquire(SpinLock& spin_lock) : spin_lock_(spin_lock) { spin_lock_.lock(); } + + ~Acquire() { spin_lock_.unlock(); } + + // No copies + Acquire& operator=(const Acquire&) = delete; + Acquire(const Acquire&) = delete; + + private: + SpinLock& spin_lock_; + }; + + SpinLock() { clear(); } + + void lock() { + // busy-wait + while (std::atomic_flag::test_and_set(std::memory_order_acquire)) + ; + } + + void unlock() { clear(std::memory_order_release); } + + bool tryLock() { + return std::atomic_flag::test_and_set(std::memory_order_acquire); + } +}; + +} // namespace utils \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/utils/string_tokenizer.h b/libtransport/includes/hicn/transport/utils/string_tokenizer.h new file mode 100644 index 000000000..36630eb58 --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/string_tokenizer.h @@ -0,0 +1,35 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace utils { + +class StringTokenizer { + public: + StringTokenizer(const std::string &str); + StringTokenizer(const std::string &str, const std::string &delim); + + bool hasMoreTokens(); + std::string nextToken(); + + private: + std::string str_; + std::string delimiter_; +}; + +} // namespace utils diff --git a/libtransport/includes/hicn/transport/utils/uri.h b/libtransport/includes/hicn/transport/utils/uri.h new file mode 100644 index 000000000..7c28e8552 --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/uri.h @@ -0,0 +1,47 @@ +/* + * 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. + */ + +#pragma once + +#include // find +#include + +namespace utils { + +class Uri { + typedef std::string::const_iterator iterator_t; + + public: + Uri(); + + Uri &parse(const std::string &uri); + + Uri &parseProtocolAndLocator(const std::string &locator); + + std::string getQueryString(); + + std::string getPath(); + + std::string getProtocol(); + + std::string getLocator(); + + std::string getPort(); + + private: + std::string query_string_, path_, protocol_, locator_, port_; +}; // uri + +} // namespace utils diff --git a/libtransport/src/CMakeLists.txt b/libtransport/src/CMakeLists.txt new file mode 100644 index 000000000..a182998e3 --- /dev/null +++ b/libtransport/src/CMakeLists.txt @@ -0,0 +1,92 @@ +# 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) + +include(GNUInstallDirs) + +set(ASIO_STANDALONE 1) + +add_subdirectory(core) +add_subdirectory(interfaces) +add_subdirectory(protocols) +add_subdirectory(security) +add_subdirectory(implementation) +add_subdirectory(utils) +add_subdirectory(http) + +include(Packager) +extract_version() +configure_file("config.h.in" "hicn/transport/config.h" @ONLY) +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/hicn/transport/config.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hicn/transport + COMPONENT lib${LIBTRANSPORT}-dev +) + +set (COMPILER_DEFINITIONS "-DTRANSPORT_LOG_DEF_LEVEL=TRANSPORT_LOG_${TRANSPORT_LOG_LEVEL}") + +list(INSERT LIBTRANSPORT_INTERNAL_INCLUDE_DIRS 0 + ${CMAKE_CURRENT_SOURCE_DIR}/ + ${CMAKE_CURRENT_BINARY_DIR}/ +) + +set(LIBTRANSPORT_INCLUDE_DIRS + ${CMAKE_CURRENT_BINARY_DIR} + ${LIBTRANSPORT_INCLUDE_DIRS} + "" CACHE INTERNAL + "" FORCE +) + +if (NOT WIN32) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") +else () + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4200") + if (CMAKE_BUILD_TYPE EQUAL "RELEASE") + set(CMAKE_SHARED_LINKER_FLAGS "/NODEFAULTLIB:\"MSVCRTD\"" ) + endif () +endif () +if (${CMAKE_SYSTEM_NAME} STREQUAL "Android") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -isystem -lm") +endif() + +if (DISABLE_SHARED_LIBRARIES) + build_library(${LIBTRANSPORT} + STATIC + SOURCES ${SOURCE_FILES} ${HEADER_FILES} + INSTALL_HEADERS ${LIBHICNTRANSPORT_TO_INSTALL_HEADER_FILES} + LINK_LIBRARIES ${LIBRARIES} + DEPENDS ${DEPENDENCIES} + COMPONENT lib${LIBTRANSPORT} + INCLUDE_DIRS ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS} ${LIBTRANSPORT_INCLUDE_DIRS} + INSTALL_ROOT_DIR hicn/transport + DEFINITIONS ${COMPILER_DEFINITIONS} + ) +else () + build_library(${LIBTRANSPORT} + STATIC SHARED + SOURCES ${SOURCE_FILES} ${HEADER_FILES} + INSTALL_HEADERS ${LIBHICNTRANSPORT_TO_INSTALL_HEADER_FILES} + LINK_LIBRARIES ${LIBRARIES} + DEPENDS ${DEPENDENCIES} + COMPONENT lib${LIBTRANSPORT} + INCLUDE_DIRS ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS} ${LIBTRANSPORT_INCLUDE_DIRS} + INSTALL_ROOT_DIR hicn/transport + DEFINITIONS ${COMPILER_DEFINITIONS} + ) +endif () + +if (${COMPILE_TESTS}) + add_subdirectory(core/test) + add_subdirectory(transport/test) +endif() diff --git a/libtransport/src/config.h.in b/libtransport/src/config.h.in new file mode 100644 index 000000000..4e9a0f262 --- /dev/null +++ b/libtransport/src/config.h.in @@ -0,0 +1,34 @@ +/* + * 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. + */ + +#pragma once + +#cmakedefine TRANSPORT_HAVE_PTHREAD 1 + +#define HICNTRANSPORT_VERSION_MAJOR "@VERSION_MAJOR@" +#define HICNTRANSPORT_VERSION_MINOR "@VERSION_MINOR@" +#define HICNTRANSPORT_VERSION_REVISION "@VERSION_REVISION@" + +#ifndef ASIO_STANDALONE +#cmakedefine ASIO_STANDALONE +#endif + +#ifndef SECURE_HICNTRANSPORT +#cmakedefine SECURE_HICNTRANSPORT +#endif + +#define RAAQM_CONFIG_PATH "@raaqm_config_path@" + +#cmakedefine __vpp__ diff --git a/libtransport/src/core/CMakeLists.txt b/libtransport/src/core/CMakeLists.txt new file mode 100644 index 000000000..12ef9cfe4 --- /dev/null +++ b/libtransport/src/core/CMakeLists.txt @@ -0,0 +1,76 @@ +# 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) + +list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/facade.h + ${CMAKE_CURRENT_SOURCE_DIR}/manifest.h + ${CMAKE_CURRENT_SOURCE_DIR}/manifest_inline.h + ${CMAKE_CURRENT_SOURCE_DIR}/manifest_format_fixed.h + ${CMAKE_CURRENT_SOURCE_DIR}/manifest_format.h + ${CMAKE_CURRENT_SOURCE_DIR}/pending_interest.h + ${CMAKE_CURRENT_SOURCE_DIR}/portal.h + ${CMAKE_CURRENT_SOURCE_DIR}/connector.h + ${CMAKE_CURRENT_SOURCE_DIR}/tcp_socket_connector.h + ${CMAKE_CURRENT_SOURCE_DIR}/udp_socket_connector.h + ${CMAKE_CURRENT_SOURCE_DIR}/forwarder_interface.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn_forwarder_interface.h + ${CMAKE_CURRENT_SOURCE_DIR}/vpp_forwarder_interface.h + ${CMAKE_CURRENT_SOURCE_DIR}/memif_connector.h +) + +list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/content_object.cc + ${CMAKE_CURRENT_SOURCE_DIR}/interest.cc + ${CMAKE_CURRENT_SOURCE_DIR}/pending_interest.cc + ${CMAKE_CURRENT_SOURCE_DIR}/packet.cc + ${CMAKE_CURRENT_SOURCE_DIR}/name.cc + ${CMAKE_CURRENT_SOURCE_DIR}/prefix.cc + ${CMAKE_CURRENT_SOURCE_DIR}/tcp_socket_connector.cc + ${CMAKE_CURRENT_SOURCE_DIR}/udp_socket_connector.cc + ${CMAKE_CURRENT_SOURCE_DIR}/hicn_forwarder_interface.cc + ${CMAKE_CURRENT_SOURCE_DIR}/manifest_format_fixed.cc + ${CMAKE_CURRENT_SOURCE_DIR}/connector.cc +) + +if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") + if (BUILD_WITH_VPP OR BUILD_HICNPLUGIN) + list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/vpp_forwarder_interface.h + ${CMAKE_CURRENT_SOURCE_DIR}/memif_connector.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn_vapi.h + ${CMAKE_CURRENT_SOURCE_DIR}/memif_vapi.h + ) + + list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/vpp_forwarder_interface.cc + ${CMAKE_CURRENT_SOURCE_DIR}/memif_connector.cc + ${CMAKE_CURRENT_SOURCE_DIR}/hicn_vapi.c + ${CMAKE_CURRENT_SOURCE_DIR}/memif_vapi.c + ) + endif() + + list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/raw_socket_connector.h + ${CMAKE_CURRENT_SOURCE_DIR}/raw_socket_interface.h + ) + + list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/raw_socket_connector.cc + ${CMAKE_CURRENT_SOURCE_DIR}/raw_socket_interface.cc + ) +endif() + +set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file diff --git a/libtransport/src/core/connector.cc b/libtransport/src/core/connector.cc new file mode 100644 index 000000000..63919537d --- /dev/null +++ b/libtransport/src/core/connector.cc @@ -0,0 +1,51 @@ +/* + * 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. + */ + +#include + +namespace transport { + +namespace core { + +std::once_flag Connector::init_flag_; + +Connector::Connector(PacketReceivedCallback &&receive_callback, + OnReconnect &&reconnect_callback) + : packet_pool_(), + receive_callback_(std::move(receive_callback)), + on_reconnect_callback_(std::move(reconnect_callback)), + state_(ConnectorState::CLOSED) { + init(); +} + +void Connector::init() { increasePoolSize(); } + +void Connector::increasePoolSize(std::size_t size) { + // Allocate space for receiving packets + const auto capacity = packet_size * size; + uint8_t *buffer = static_cast(malloc(capacity)); + std::unique_ptr buffer0 = + utils::MemBuf::takeOwnership(buffer, capacity, 0, nullptr, nullptr, true); + + for (std::size_t i = 1; i < size; i++) { + auto b = buffer0->cloneOne(); + b->advance(i * packet_size); + packet_pool_.add(b.release()); + } +} + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/core/connector.h b/libtransport/src/core/connector.h new file mode 100644 index 000000000..f2bbe5dcd --- /dev/null +++ b/libtransport/src/core/connector.h @@ -0,0 +1,109 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace transport { + +namespace core { + +enum class ConnectorType : uint8_t { + SOCKET_CONNECTOR, + RAW_SOCKET_CONNECTOR, + VPP_CONNECTOR, +}; + +class Connector { + protected: + enum class ConnectorState { + CLOSED, + CONNECTING, + CONNECTED, + }; + + public: + static constexpr std::size_t packet_size = 2048; + static constexpr std::size_t queue_size = 4096; + static constexpr std::size_t packet_pool_size = 4096; + + using PacketRing = utils::CircularFifo; + using PacketQueue = std::deque; + using PacketReceivedCallback = std::function; + using OnReconnect = std::function; + using PacketSentCallback = std::function; + + Connector(PacketReceivedCallback &&receive_callback, + OnReconnect &&reconnect_callback); + + virtual ~Connector(){}; + + virtual void send(const Packet::MemBufPtr &packet) = 0; + + virtual void send(const uint8_t *packet, std::size_t len, + const PacketSentCallback &packet_sent = 0) = 0; + + virtual void close() = 0; + + virtual ConnectorState state() { return state_; }; + + virtual bool isConnected() { return state_ == ConnectorState::CONNECTED; } + + protected: + void increasePoolSize(std::size_t size = packet_pool_size); + + TRANSPORT_ALWAYS_INLINE utils::ObjectPool::Ptr getPacket() { + auto result = packet_pool_.get(); + + while (TRANSPORT_EXPECT_FALSE(!result.first)) { + // Add packets to the pool + increasePoolSize(); + result = packet_pool_.get(); + } + + if (result.second->isChained()) { + result.second->separateChain(result.second->next(), + result.second->prev()); + } + + result.second->trimEnd(result.second->length()); + return std::move(result.second); + } + + private: + void init(); + + protected: + static std::once_flag init_flag_; + utils::ObjectPool packet_pool_; + PacketQueue output_buffer_; + + // Connector events + PacketReceivedCallback receive_callback_; + OnReconnect on_reconnect_callback_; + + // Connector state + ConnectorState state_; +}; +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/core/content_object.cc b/libtransport/src/core/content_object.cc new file mode 100644 index 000000000..6cbcdb29e --- /dev/null +++ b/libtransport/src/core/content_object.cc @@ -0,0 +1,201 @@ +/* + * 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. + */ + +#include +#include +#include + +extern "C" { +#ifndef _WIN32 +TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat") +#endif +#include +#include +} + +#include +#include + +namespace transport { + +namespace core { + +ContentObject::ContentObject(const Name &name, Packet::Format format) + : Packet(format) { + if (TRANSPORT_EXPECT_FALSE( + hicn_data_set_name(format, packet_start_, &name.name_) < 0)) { + throw errors::RuntimeException("Error filling the packet name."); + } + + if (TRANSPORT_EXPECT_FALSE(hicn_data_get_name(format_, packet_start_, + name_.getStructReference()) < + 0)) { + throw errors::MalformedPacketException(); + } +} + +#ifdef __ANDROID__ +ContentObject::ContentObject(hicn_format_t format) + : ContentObject(Name("0::0|0"), format) {} +#else +ContentObject::ContentObject(hicn_format_t format) + : ContentObject(Packet::base_name, format) {} +#endif + +ContentObject::ContentObject(const Name &name, hicn_format_t format, + const uint8_t *payload, std::size_t size) + : ContentObject(name, format) { + appendPayload(payload, size); +} + +ContentObject::ContentObject(const uint8_t *buffer, std::size_t size) + : Packet(buffer, size) { + if (hicn_data_get_name(format_, packet_start_, name_.getStructReference()) < + 0) { + throw errors::RuntimeException("Error getting name from content object."); + } +} + +ContentObject::ContentObject(MemBufPtr &&buffer) : Packet(std::move(buffer)) { + if (hicn_data_get_name(format_, packet_start_, name_.getStructReference()) < + 0) { + throw errors::RuntimeException("Error getting name from content object."); + } +} + +ContentObject::ContentObject(ContentObject &&other) : Packet(std::move(other)) { + name_ = std::move(other.name_); + + if (hicn_data_get_name(format_, packet_start_, name_.getStructReference()) < + 0) { + throw errors::MalformedPacketException(); + } +} + +ContentObject::~ContentObject() {} + +void ContentObject::replace(MemBufPtr &&buffer) { + Packet::replace(std::move(buffer)); + + if (hicn_data_get_name(format_, packet_start_, name_.getStructReference()) < + 0) { + throw errors::RuntimeException("Error getting name from content object."); + } +} + +const Name &ContentObject::getName() const { + if (!name_) { + if (hicn_data_get_name(format_, packet_start_, + (hicn_name_t *)name_.getConstStructReference()) < + 0) { + throw errors::MalformedPacketException(); + } + } + + return name_; +} + +Name &ContentObject::getWritableName() { return const_cast(getName()); } + +void ContentObject::setName(const Name &name) { + if (hicn_data_set_name(format_, packet_start_, + name.getConstStructReference()) < 0) { + throw errors::RuntimeException("Error setting content object name."); + } + + if (hicn_data_get_name(format_, packet_start_, name_.getStructReference()) < + 0) { + throw errors::MalformedPacketException(); + } +} + +void ContentObject::setName(Name &&name) { + if (hicn_data_set_name(format_, packet_start_, name.getStructReference()) < + 0) { + throw errors::RuntimeException( + "Error getting the payload length from content object."); + } + + if (hicn_data_get_name(format_, packet_start_, name_.getStructReference()) < + 0) { + throw errors::MalformedPacketException(); + } +} + +uint32_t ContentObject::getPathLabel() const { + uint32_t path_label; + if (hicn_data_get_path_label(packet_start_, &path_label) < 0) { + throw errors::RuntimeException( + "Error retrieving the path label from content object"); + } + + return path_label; +} + +ContentObject &ContentObject::setPathLabel(uint32_t path_label) { + if (hicn_data_set_path_label((hicn_header_t *)packet_start_, path_label) < + 0) { + throw errors::RuntimeException( + "Error setting the path label from content object"); + } + + return *this; +} + +void ContentObject::setLocator(const ip_address_t &ip_address) { + if (hicn_data_set_locator(format_, packet_start_, &ip_address) < 0) { + throw errors::RuntimeException("Error setting content object locator"); + } + + return; +} + +ip_address_t ContentObject::getLocator() const { + ip_address_t ip; + + if (hicn_data_get_locator(format_, packet_start_, &ip) < 0) { + throw errors::RuntimeException("Error getting content object locator."); + } + + return ip; +} + +void ContentObject::setLifetime(uint32_t lifetime) { + if (hicn_data_set_expiry_time(packet_start_, lifetime) < 0) { + throw errors::MalformedPacketException(); + } +} + +uint32_t ContentObject::getLifetime() const { + uint32_t lifetime = 0; + + if (hicn_data_get_expiry_time(packet_start_, &lifetime) < 0) { + throw errors::MalformedPacketException(); + } + + return lifetime; +} + +void ContentObject::resetForHash() { + if (hicn_data_reset_for_hash( + format_, reinterpret_cast(packet_start_)) < 0) { + throw errors::RuntimeException( + "Error resetting content object fields for hash computation."); + } +} + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/core/facade.h b/libtransport/src/core/facade.h new file mode 100644 index 000000000..04f643f63 --- /dev/null +++ b/libtransport/src/core/facade.h @@ -0,0 +1,53 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#ifdef __linux__ +#ifndef __ANDROID__ +#include +#ifdef __vpp__ +#include +#endif +#endif +#endif + +namespace transport { + +namespace core { + +using HicnForwarderPortal = Portal; + +#ifdef __linux__ +#ifndef __ANDROID__ +using RawSocketPortal = Portal; +#endif +#ifdef __vpp__ +using VPPForwarderPortal = Portal; +#endif +#endif + +using ContentObjectManifest = core::ManifestInline; +using InterestManifest = core::ManifestInline; + +} // namespace core + +} // namespace transport diff --git a/libtransport/src/core/forwarder_interface.h b/libtransport/src/core/forwarder_interface.h new file mode 100644 index 000000000..3e70e221d --- /dev/null +++ b/libtransport/src/core/forwarder_interface.h @@ -0,0 +1,147 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include + +#include + +namespace transport { + +namespace core { + +typedef struct { + uint64_t rx_packets; + uint64_t tx_packets; + uint64_t rx_bytes; + uint64_t tx_bytes; + uint64_t rx_errors; + uint64_t tx_errors; +} Counters; + +template +class ForwarderInterface { + static_assert(std::is_base_of::value, + "T must inherit from connector!"); + + static constexpr uint32_t standard_cs_reserved = 5000; + + protected: + ForwarderInterface(ConnectorType &c) + : connector_(c), + inet_address_({}), + inet6_address_({}), + mtu_(1500), + output_interface_(""), + content_store_reserved_(standard_cs_reserved) {} + + public: + virtual ~ForwarderInterface() {} + + TRANSPORT_ALWAYS_INLINE void connect(bool is_consumer = true) { + static_cast(*this).connect(is_consumer); + } + + TRANSPORT_ALWAYS_INLINE void registerRoute(Prefix &prefix) { + static_cast(*this).registerRoute(); + } + + TRANSPORT_ALWAYS_INLINE std::uint32_t getMtu() { + return static_cast(*this).getMtu(); + } + + TRANSPORT_ALWAYS_INLINE static bool isControlMessage(const uint8_t *message) { + return Implementation::isControlMessageImpl(message); + } + + template + TRANSPORT_ALWAYS_INLINE void processControlMessageReply(R &&packet_buffer) { + return static_cast(*this).processControlMessageReplyImpl( + std::forward(packet_buffer)); + } + + TRANSPORT_ALWAYS_INLINE void closeConnection() { + return static_cast(*this).closeConnection(); + } + + template < + typename R, + typename = std::enable_if_t< + std::is_base_of>::value, + R>> + TRANSPORT_ALWAYS_INLINE void send(R &&packet) { + counters_.tx_packets++; + counters_.tx_bytes += packet.payloadSize() + packet.headerSize(); + + if (_is_ipv4(packet.getFormat())) { + packet.setLocator(inet_address_); + } else { + packet.setLocator(inet6_address_); + } + + // TRANSPORT_LOGI("Sending packet %s at %lu", + // packet.getName().toString().c_str(), + // utils::SteadyClock::now().time_since_epoch().count()); + packet.setChecksum(); + connector_.send(packet.acquireMemBufReference()); + } + + TRANSPORT_ALWAYS_INLINE void send(const uint8_t *packet, std::size_t len) { + // ASIO_COMPLETION_HANDLER_CHECK(Handler, packet_sent) type_check; + counters_.tx_packets++; + counters_.tx_bytes += len; + + // Perfect forwarding + connector_.send(packet, len); + } + + TRANSPORT_ALWAYS_INLINE void shutdown() { connector_.close(); } + + TRANSPORT_ALWAYS_INLINE Connector &getConnector() { return connector_; } + + TRANSPORT_ALWAYS_INLINE void setContentStoreSize(uint32_t cs_size) { + content_store_reserved_ = cs_size; + } + + TRANSPORT_ALWAYS_INLINE uint32_t getContentStoreSize() const { + return content_store_reserved_; + } + + TRANSPORT_ALWAYS_INLINE void setOutputInterface( + const std::string &interface) { + output_interface_ = interface; + } + + TRANSPORT_ALWAYS_INLINE std::string &getOutputInterface() { + return output_interface_; + } + + protected: + ConnectorType &connector_; + ip_address_t inet_address_; + ip_address_t inet6_address_; + uint16_t mtu_; + std::string output_interface_; + uint32_t content_store_reserved_; + Counters counters_; +}; + +} // namespace core + +} // namespace transport diff --git a/libtransport/src/core/hicn_forwarder_interface.cc b/libtransport/src/core/hicn_forwarder_interface.cc new file mode 100644 index 000000000..810daba3a --- /dev/null +++ b/libtransport/src/core/hicn_forwarder_interface.cc @@ -0,0 +1,135 @@ +/* + * 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. + */ + +#include + +union AddressLight { + uint32_t ipv4; + struct in6_addr ipv6; +}; + +typedef struct { + uint8_t message_type; + uint8_t command_id; + uint16_t length; + uint32_t seq_num; +} CommandHeader; + +typedef struct { + uint8_t message_type; + uint8_t command_id; + uint16_t length; + uint32_t seq_num; + char symbolic_or_connid[16]; + union AddressLight address; + uint16_t cost; + uint8_t address_type; + uint8_t len; +} RouteToSelfCommand; + +typedef struct { + uint8_t message_type; + uint8_t command_id; + uint16_t length; + uint32_t seq_num; + char symbolic_or_connid[16]; +} DeleteSelfConnectionCommand; + +namespace { +static constexpr uint8_t addr_inet = 1; +static constexpr uint8_t addr_inet6 = 2; +static constexpr uint8_t add_route_command = 3; +static constexpr uint8_t delete_connection_command = 5; +static constexpr uint8_t request_light = 0xc0; +static constexpr char identifier[] = "SELF"; + +void fillCommandHeader(CommandHeader *header) { + // Allocate and fill the header + header->message_type = request_light; + header->length = 1; +} + +RouteToSelfCommand createCommandRoute(std::unique_ptr &&addr, + uint8_t prefix_length) { + RouteToSelfCommand command = {0}; + + // check and set IP address + if (addr->sa_family == AF_INET) { + command.address_type = addr_inet; + command.address.ipv4 = ((sockaddr_in *)addr.get())->sin_addr.s_addr; + } else if (addr->sa_family == AF_INET6) { + command.address_type = addr_inet6; + command.address.ipv6 = ((sockaddr_in6 *)addr.get())->sin6_addr; + } + + // Fill remaining payload fields +#ifndef _WIN32 + strcpy(command.symbolic_or_connid, identifier); +#else + strcpy_s(command.symbolic_or_connid, 16, identifier); +#endif + command.cost = 1; + command.len = (uint8_t)prefix_length; + + // Allocate and fill the header + command.command_id = add_route_command; + fillCommandHeader((CommandHeader *)&command); + + return command; +} + +DeleteSelfConnectionCommand createCommandDeleteConnection() { + DeleteSelfConnectionCommand command = {0}; + fillCommandHeader((CommandHeader *)&command); + command.command_id = delete_connection_command; + +#ifndef _WIN32 + strcpy(command.symbolic_or_connid, identifier); +#else + strcpy_s(command.symbolic_or_connid, 16, identifier); +#endif + + return command; +} + +} // namespace + +namespace transport { + +namespace core { + +HicnForwarderInterface::HicnForwarderInterface(UdpSocketConnector &connector) + : ForwarderInterface( + connector) {} + +HicnForwarderInterface::~HicnForwarderInterface() {} + +void HicnForwarderInterface::connect(bool is_consumer) { connector_.connect(); } + +void HicnForwarderInterface::registerRoute(Prefix &prefix) { + auto command = createCommandRoute(prefix.toSockaddr(), + (uint8_t)prefix.getPrefixLength()); + send((uint8_t *)&command, sizeof(RouteToSelfCommand)); +} + +void HicnForwarderInterface::closeConnection() { + auto command = createCommandDeleteConnection(); + send((uint8_t *)&command, sizeof(DeleteSelfConnectionCommand)); + connector_.close(); +} + +} // namespace core + +} // namespace transport diff --git a/libtransport/src/core/hicn_forwarder_interface.h b/libtransport/src/core/hicn_forwarder_interface.h new file mode 100644 index 000000000..6969f4a6b --- /dev/null +++ b/libtransport/src/core/hicn_forwarder_interface.h @@ -0,0 +1,86 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include +#include + +#include + +namespace transport { + +namespace core { + +class HicnForwarderInterface + : public ForwarderInterface { + static constexpr uint8_t ack_code = 0xc2; + static constexpr uint8_t nack_code = 0xc3; + + public: + union addressLight { + uint32_t ipv4; + struct in6_addr ipv6; + }; + + struct route_to_self_command { + uint8_t messageType; + uint8_t commandID; + uint16_t length; + uint32_t seqNum; + char symbolicOrConnid[16]; + union addressLight address; + uint16_t cost; + uint8_t addressType; + uint8_t len; + }; + + using route_to_self_command = struct route_to_self_command; + using ConnectorType = UdpSocketConnector; + + HicnForwarderInterface(UdpSocketConnector &connector); + + ~HicnForwarderInterface(); + + void connect(bool is_consumer); + + void registerRoute(Prefix &prefix); + + std::uint16_t getMtu() { return interface_mtu; } + + TRANSPORT_ALWAYS_INLINE static bool isControlMessageImpl( + const uint8_t *message) { + return message[0] == ack_code || message[0] == nack_code; + } + + TRANSPORT_ALWAYS_INLINE void processControlMessageReplyImpl( + Packet::MemBufPtr &&packet_buffer) { + if (packet_buffer->data()[0] == nack_code) { + throw errors::RuntimeException( + "Received Nack message from hicn light forwarder."); + } + } + + void closeConnection(); + + private: + static constexpr std::uint16_t interface_mtu = 1500; +}; + +} // namespace core + +} // namespace transport diff --git a/libtransport/src/core/hicn_vapi.c b/libtransport/src/core/hicn_vapi.c new file mode 100644 index 000000000..d19e36346 --- /dev/null +++ b/libtransport/src/core/hicn_vapi.c @@ -0,0 +1,216 @@ +/* + * 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. + */ + +#include + +#ifdef __vpp__ + +#include + +#include + +#define HICN_VPP_PLUGIN +#include +#undef HICN_VPP_PLUGIN + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +///////////////////////////////////////////////////// +const char *HICN_ERROR_STRING[] = { +#define _(a, b, c) c, + foreach_hicn_error +#undef _ +}; +///////////////////////////////////////////////////// + +/*********************** Missing Symbol in vpp libraries + * *************************/ +u8 *format_vl_api_address_union(u8 *s, va_list *args) { return NULL; } + +/*********************************************************************************/ + +DEFINE_VAPI_MSG_IDS_HICN_API_JSON + +static vapi_error_e register_prod_app_cb( + vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last, + vapi_payload_hicn_api_register_prod_app_reply *reply) { + hicn_producer_output_params *output_params = + (hicn_producer_output_params *)callback_ctx; + + if (reply == NULL) return rv; + + output_params->cs_reserved = reply->cs_reserved; + output_params->prod_addr = (ip_address_t *)malloc(sizeof(ip_address_t)); + memset(output_params->prod_addr, 0, sizeof(ip_address_t)); + if (reply->prod_addr.af == ADDRESS_IP6) + memcpy(&output_params->prod_addr->v6, reply->prod_addr.un.ip6, + sizeof(ip6_address_t)); + else + memcpy(&output_params->prod_addr->v4, reply->prod_addr.un.ip4, + sizeof(ip4_address_t)); + output_params->face_id = reply->faceid; + + return reply->retval; +} + +int hicn_vapi_register_prod_app(vapi_ctx_t ctx, + hicn_producer_input_params *input_params, + hicn_producer_output_params *output_params) { + vapi_lock(); + vapi_msg_hicn_api_register_prod_app *msg = + vapi_alloc_hicn_api_register_prod_app(ctx); + + if (ip46_address_is_ip4((ip46_address_t *)&input_params->prefix->address)) { + memcpy(&msg->payload.prefix.address.un.ip4, &input_params->prefix->address, + sizeof(ip4_address_t)); + msg->payload.prefix.address.af = ADDRESS_IP4; + } else { + memcpy(&msg->payload.prefix.address.un.ip6, &input_params->prefix->address, + sizeof(ip6_address_t)); + msg->payload.prefix.address.af = ADDRESS_IP6; + } + msg->payload.prefix.len = input_params->prefix->len; + + msg->payload.swif = input_params->swif; + msg->payload.cs_reserved = input_params->cs_reserved; + + int ret = vapi_hicn_api_register_prod_app(ctx, msg, register_prod_app_cb, + output_params); + vapi_unlock(); + return ret; +} + +static vapi_error_e face_prod_del_cb( + vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last, + vapi_payload_hicn_api_face_prod_del_reply *reply) { + if (reply == NULL) return rv; + + return reply->retval; +} + +int hicn_vapi_face_prod_del(vapi_ctx_t ctx, + hicn_del_face_app_input_params *input_params) { + vapi_lock(); + vapi_msg_hicn_api_face_prod_del *msg = vapi_alloc_hicn_api_face_prod_del(ctx); + + msg->payload.faceid = input_params->face_id; + + int ret = vapi_hicn_api_face_prod_del(ctx, msg, face_prod_del_cb, NULL); + vapi_unlock(); + return ret; +} + +static vapi_error_e register_cons_app_cb( + vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last, + vapi_payload_hicn_api_register_cons_app_reply *reply) { + hicn_consumer_output_params *output_params = + (hicn_consumer_output_params *)callback_ctx; + + if (reply == NULL) return rv; + + output_params->src6 = (ip_address_t *)malloc(sizeof(ip_address_t)); + output_params->src4 = (ip_address_t *)malloc(sizeof(ip_address_t)); + memset(output_params->src6, 0, sizeof(ip_address_t)); + memset(output_params->src4, 0, sizeof(ip_address_t)); + memcpy(&output_params->src6->v6, &reply->src_addr6.un.ip6, + sizeof(ip6_address_t)); + memcpy(&output_params->src4->v4, &reply->src_addr4.un.ip4, + sizeof(ip4_address_t)); + + output_params->face_id1 = reply->faceid1; + output_params->face_id2 = reply->faceid2; + + return reply->retval; +} + +int hicn_vapi_register_cons_app(vapi_ctx_t ctx, + hicn_consumer_input_params *input_params, + hicn_consumer_output_params *output_params) { + vapi_lock(); + vapi_msg_hicn_api_register_cons_app *msg = + vapi_alloc_hicn_api_register_cons_app(ctx); + + msg->payload.swif = input_params->swif; + + int ret = vapi_hicn_api_register_cons_app(ctx, msg, register_cons_app_cb, + output_params); + vapi_unlock(); + return ret; +} + +static vapi_error_e face_cons_del_cb( + vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last, + vapi_payload_hicn_api_face_cons_del_reply *reply) { + if (reply == NULL) return rv; + + return reply->retval; +} + +int hicn_vapi_face_cons_del(vapi_ctx_t ctx, + hicn_del_face_app_input_params *input_params) { + vapi_lock(); + vapi_msg_hicn_api_face_cons_del *msg = vapi_alloc_hicn_api_face_cons_del(ctx); + + msg->payload.faceid = input_params->face_id; + + int ret = vapi_hicn_api_face_cons_del(ctx, msg, face_cons_del_cb, NULL); + vapi_unlock(); + return ret; +} + +static vapi_error_e reigster_route_cb( + vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last, + vapi_payload_hicn_api_route_nhops_add_reply *reply) { + if (reply == NULL) return rv; + + return reply->retval; +} + +int hicn_vapi_register_route(vapi_ctx_t ctx, + hicn_producer_set_route_params *input_params) { + vapi_lock(); + vapi_msg_hicn_api_route_nhops_add *msg = + vapi_alloc_hicn_api_route_nhops_add(ctx); + + fib_prefix_t prefix; + memcpy(&prefix.fp_addr, &input_params->prefix->address, + sizeof(ip46_address_t)); + prefix.fp_len = input_params->prefix->len; + msg->payload.face_ids[0] = input_params->face_id; + msg->payload.n_faces = 1; + + int ret = vapi_hicn_api_route_nhops_add(ctx, msg, reigster_route_cb, NULL); + + vapi_unlock(); + return ret; +} + +char *hicn_vapi_get_error_string(int ret_val) { + return get_error_string(ret_val); +} + +#endif // __vpp__ diff --git a/libtransport/src/core/hicn_vapi.h b/libtransport/src/core/hicn_vapi.h new file mode 100644 index 000000000..f2718e6f5 --- /dev/null +++ b/libtransport/src/core/hicn_vapi.h @@ -0,0 +1,86 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +#ifdef __vpp__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "stdint.h" + +typedef struct { + ip_prefix_t* prefix; + uint32_t swif; + uint32_t cs_reserved; +} hicn_producer_input_params; + +typedef struct { + uint32_t swif; +} hicn_consumer_input_params; + +typedef struct { + uint32_t face_id; +} hicn_del_face_app_input_params; + +typedef struct { + uint32_t cs_reserved; + ip_address_t* prod_addr; + uint32_t face_id; +} hicn_producer_output_params; + +typedef struct { + ip_address_t* src4; + ip_address_t* src6; + uint32_t face_id1; + uint32_t face_id2; +} hicn_consumer_output_params; + +typedef struct { + ip_prefix_t* prefix; + uint32_t face_id; +} hicn_producer_set_route_params; + +int hicn_vapi_register_prod_app( + vapi_ctx_t ctx, hicn_producer_input_params* input_params, + hicn_producer_output_params* output_params); + +int hicn_vapi_register_cons_app( + vapi_ctx_t ctx, hicn_consumer_input_params* input_params, + hicn_consumer_output_params* output_params); + +int hicn_vapi_register_route( + vapi_ctx_t ctx, hicn_producer_set_route_params* input_params); + +int hicn_vapi_face_cons_del( + vapi_ctx_t ctx, hicn_del_face_app_input_params *input_params); + +int hicn_vapi_face_prod_del( + vapi_ctx_t ctx, hicn_del_face_app_input_params *input_params); + +char* hicn_vapi_get_error_string(int ret_val); + +#ifdef __cplusplus +} +#endif + +#endif // __vpp__ diff --git a/libtransport/src/core/interest.cc b/libtransport/src/core/interest.cc new file mode 100644 index 000000000..166632f0a --- /dev/null +++ b/libtransport/src/core/interest.cc @@ -0,0 +1,166 @@ +/* + * 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. + */ + +#include +#include +#include + +extern "C" { +#ifndef _WIN32 +TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat") +#endif +#include +} + +#include +#include + +namespace transport { + +namespace core { + +Interest::Interest(const Name &interest_name, Packet::Format format) + : Packet(format) { + if (hicn_interest_set_name(format_, packet_start_, + interest_name.getConstStructReference()) < 0) { + throw errors::MalformedPacketException(); + } + + if (hicn_interest_get_name(format_, packet_start_, + name_.getStructReference()) < 0) { + throw errors::MalformedPacketException(); + } +} + +#ifdef __ANDROID__ +Interest::Interest(hicn_format_t format) : Interest(Name("0::0|0"), format) {} +#else +Interest::Interest(hicn_format_t format) : Interest(base_name, format) {} +#endif + +Interest::Interest(const uint8_t *buffer, std::size_t size) + : Packet(buffer, size) { + if (hicn_interest_get_name(format_, packet_start_, + name_.getStructReference()) < 0) { + throw errors::MalformedPacketException(); + } +} + +Interest::Interest(MemBufPtr &&buffer) : Packet(std::move(buffer)) { + if (hicn_interest_get_name(format_, packet_start_, + name_.getStructReference()) < 0) { + throw errors::MalformedPacketException(); + } +} + +Interest::Interest(Interest &&other_interest) + : Packet(std::move(other_interest)) { + name_ = std::move(other_interest.name_); +} + +Interest::~Interest() {} + +void Interest::replace(MemBufPtr &&buffer) { + Packet::replace(std::move(buffer)); + + if (hicn_interest_get_name(format_, packet_start_, + name_.getStructReference()) < 0) { + throw errors::MalformedPacketException(); + } +} + +const Name &Interest::getName() const { + if (!name_) { + if (hicn_interest_get_name(format_, packet_start_, + (hicn_name_t *)name_.getConstStructReference()) < + 0) { + throw errors::MalformedPacketException(); + } + } + + return name_; +} + +Name &Interest::getWritableName() { return const_cast(getName()); } + +void Interest::setName(const Name &name) { + if (hicn_interest_set_name(format_, packet_start_, + name.getConstStructReference()) < 0) { + throw errors::RuntimeException("Error setting interest name."); + } + + if (hicn_interest_get_name(format_, packet_start_, + name_.getStructReference()) < 0) { + throw errors::MalformedPacketException(); + } +} + +void Interest::setName(Name &&name) { + if (hicn_interest_set_name(format_, packet_start_, + name.getStructReference()) < 0) { + throw errors::RuntimeException("Error setting interest name."); + } + + if (hicn_interest_get_name(format_, packet_start_, + name_.getStructReference()) < 0) { + throw errors::MalformedPacketException(); + } +} + +void Interest::setLocator(const ip_address_t &ip_address) { + if (hicn_interest_set_locator(format_, packet_start_, &ip_address) < 0) { + throw errors::RuntimeException("Error setting interest locator."); + } + + return; +} + +ip_address_t Interest::getLocator() const { + ip_address_t ip; + + if (hicn_interest_get_locator(format_, packet_start_, &ip) < 0) { + throw errors::RuntimeException("Error getting interest locator."); + } + + return ip; +} + +void Interest::setLifetime(uint32_t lifetime) { + if (hicn_interest_set_lifetime(packet_start_, lifetime) < 0) { + throw errors::MalformedPacketException(); + } +} + +uint32_t Interest::getLifetime() const { + uint32_t lifetime = 0; + + if (hicn_interest_get_lifetime(packet_start_, &lifetime) < 0) { + throw errors::MalformedPacketException(); + } + + return lifetime; +} + +void Interest::resetForHash() { + if (hicn_interest_reset_for_hash( + format_, reinterpret_cast(packet_start_)) < 0) { + throw errors::RuntimeException( + "Error resetting interest fields for hash computation."); + } +} + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/core/manifest.cc b/libtransport/src/core/manifest.cc new file mode 100644 index 000000000..3f890f3d0 --- /dev/null +++ b/libtransport/src/core/manifest.cc @@ -0,0 +1,33 @@ +/* + * 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. + */ + +#include + +namespace transport { + +namespace core { + +std::string ManifestEncoding::manifest_type = std::string("manifest_type"); + +std::map ManifestEncoding::manifest_types = { + {FINAL_CHUNK_NUMBER, "FinalChunkNumber"}, {NAME_LIST, "NameList"}}; + +std::string ManifestEncoding::final_chunk_number = + std::string("final_chunk_number"); +std::string ManifestEncoding::content_name = std::string("content_name"); + +} // end namespace core + +} // end namespace transport \ No newline at end of file diff --git a/libtransport/src/core/manifest.h b/libtransport/src/core/manifest.h new file mode 100644 index 000000000..b4875bf22 --- /dev/null +++ b/libtransport/src/core/manifest.h @@ -0,0 +1,150 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +#include + +#include + +namespace transport { + +namespace core { + +using typename core::Name; +using typename core::Packet; +using typename core::PayloadType; + +template +class Manifest : public Base { + static_assert(std::is_base_of::value, + "Base must inherit from packet!"); + + public: + using Encoder = typename FormatTraits::Encoder; + using Decoder = typename FormatTraits::Decoder; + + Manifest(std::size_t signature_size = 0) + : Base(HF_INET6_TCP_AH), + encoder_(*this, signature_size), + decoder_(*this) { + Base::setPayloadType(PayloadType::MANIFEST); + } + + Manifest(const core::Name &name, std::size_t signature_size = 0) + : Base(name, HF_INET6_TCP_AH), + encoder_(*this, signature_size), + decoder_(*this) { + Base::setPayloadType(PayloadType::MANIFEST); + } + + template + Manifest(T &&base) + : Base(std::forward(base)), encoder_(*this), decoder_(*this) { + Base::setPayloadType(PayloadType::MANIFEST); + } + + virtual ~Manifest() = default; + + std::size_t estimateManifestSize(std::size_t additional_entries = 0) { + return static_cast(*this).estimateManifestSizeImpl( + additional_entries); + } + + /* + * After the call to encode, users MUST call clear before adding data + * to the manifest. + */ + Manifest &encode() { return static_cast(*this).encodeImpl(); } + + Manifest &decode() { + Manifest::decoder_.decode(); + + manifest_type_ = decoder_.getManifestType(); + hash_algorithm_ = decoder_.getHashAlgorithm(); + is_last_ = decoder_.getIsFinalManifest(); + + return static_cast(*this).decodeImpl(); + } + + static std::size_t getManifestHeaderSize() { + return Encoder::getManifestHeaderSize(); + } + + static std::size_t getManifestEntrySize() { + return Encoder::getManifestEntrySize(); + } + + Manifest &setManifestType(ManifestType type) { + manifest_type_ = type; + encoder_.setManifestType(manifest_type_); + return *this; + } + + Manifest &setHashAlgorithm(HashAlgorithm hash_algorithm) { + hash_algorithm_ = hash_algorithm; + encoder_.setHashAlgorithm(hash_algorithm_); + return *this; + } + + HashAlgorithm getHashAlgorithm() { return hash_algorithm_; } + + ManifestType getManifestType() const { return manifest_type_; } + + bool isFinalManifest() const { return is_last_; } + + Manifest &setVersion(ManifestVersion version) { + encoder_.setVersion(version); + return *this; + } + + Manifest &setFinalBlockNumber(std::uint32_t final_block_number) { + encoder_.setFinalBlockNumber(final_block_number); + return *this; + } + + uint32_t getFinalBlockNumber() const { + return decoder_.getFinalBlockNumber(); + } + + ManifestVersion getVersion() const { return decoder_.getVersion(); } + + Manifest &setFinalManifest(bool is_final_manifest) { + encoder_.setIsFinalManifest(is_final_manifest); + is_last_ = is_final_manifest; + return *this; + } + + Manifest &clear() { + encoder_.clear(); + decoder_.clear(); + return *this; + } + + protected: + ManifestType manifest_type_; + HashAlgorithm hash_algorithm_; + bool is_last_; + + Encoder encoder_; + Decoder decoder_; +}; + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/core/manifest_format.h b/libtransport/src/core/manifest_format.h new file mode 100644 index 000000000..f95d19aa8 --- /dev/null +++ b/libtransport/src/core/manifest_format.h @@ -0,0 +1,210 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +#include +#include +#include + +namespace transport { + +namespace core { + +enum class ManifestFields : uint8_t { + VERSION, + HASH_ALGORITHM, + SEGMENT_CALCULATION_STRATEGY, + FINAL_MANIFEST, + NAME_HASH_LIST, + BASE_NAME +}; + +enum class ManifestVersion : uint8_t { + VERSION_1 = 1, +}; + +enum class ManifestType : uint8_t { + INLINE_MANIFEST = 1, + FINAL_CHUNK_NUMBER = 2, + FLIC_MANIFEST = 3, +}; + +enum class HashAlgorithm : uint8_t { + SHA_256 = static_cast(utils::CryptoHashType::SHA_256), + SHA_512 = static_cast(utils::CryptoHashType::SHA_512), + CRC32C = static_cast(utils::CryptoHashType::CRC32C), +}; + +/** + * INCREMENTAL: Manifests will be received inline with the data with no specific + * assumption regarding the manifest capacity. Consumers can send interests + * using a +1 heuristic. + * + * MANIFEST_CAPACITY_BASED: manifests with capacity N have a suffix multiple of + * N+1: 0, N+1, 2(N+1) etc. Contents have a suffix incremented by 1 except when + * it conflicts with a manifest: 1, 2, ..., N, N+2, N+3, ..., 2N+1, 2N+3 + */ +enum class NextSegmentCalculationStrategy : uint8_t { + INCREMENTAL = 1, + MANIFEST_CAPACITY_BASED = 2, +}; + +template +struct format_traits { + using Encoder = typename T::Encoder; + using Decoder = typename T::Decoder; + using HashType = typename T::HashType; + using HashList = typename T::HashList; +}; + +class Packet; + +template +class ManifestEncoder { + public: + virtual ~ManifestEncoder() = default; + + ManifestEncoder encode() { + return static_cast(*this).encodeImpl(); + } + + ManifestEncoder &clear() { + return static_cast(*this).clearImpl(); + } + + ManifestEncoder &setManifestType(ManifestType type) { + return static_cast(*this).setManifestTypeImpl(type); + } + + ManifestEncoder &setHashAlgorithm(HashAlgorithm hash) { + return static_cast(*this).setHashAlgorithmImpl(hash); + } + + ManifestEncoder &setFinalChunkNumber(uint32_t final_chunk) { + return static_cast(*this).setFinalChunkImpl(final_chunk); + } + + ManifestEncoder &setNextSegmentCalculationStrategy( + NextSegmentCalculationStrategy strategy) { + return static_cast(*this) + .setNextSegmentCalculationStrategyImpl(strategy); + } + + template < + typename T, + typename = std::enable_if_t>, core::Name>::value>> + ManifestEncoder &setBaseName(T &&name) { + return static_cast(*this).setBaseNameImpl(name); + } + + template + ManifestEncoder &addSuffixAndHash(uint32_t suffix, Hash &&hash) { + return static_cast(*this).addSuffixAndHashImpl( + suffix, std::forward(hash)); + } + + ManifestEncoder &setIsFinalManifest(bool is_last) { + return static_cast(*this).setIsFinalManifestImpl(is_last); + } + + ManifestEncoder &setVersion(ManifestVersion version) { + return static_cast(*this).setVersionImpl(version); + } + + std::size_t estimateSerializedLength(std::size_t number_of_entries) { + return static_cast(*this).estimateSerializedLengthImpl( + number_of_entries); + } + + ManifestEncoder &update() { + return static_cast(*this).updateImpl(); + } + + ManifestEncoder &setFinalBlockNumber(std::uint32_t final_block_number) { + return static_cast(*this).setFinalBlockNumberImpl( + final_block_number); + } + + static std::size_t getManifestHeaderSize() { + return Implementation::getManifestHeaderSizeImpl(); + } + + static std::size_t getManifestEntrySize() { + return Implementation::getManifestEntrySizeImpl(); + } +}; + +template +class ManifestDecoder { + public: + virtual ~ManifestDecoder() = default; + + ManifestDecoder &clear() { + return static_cast(*this).clearImpl(); + } + + void decode() { static_cast(*this).decodeImpl(); } + + ManifestType getManifestType() const { + return static_cast(*this).getManifestTypeImpl(); + } + + HashAlgorithm getHashAlgorithm() const { + return static_cast(*this).getHashAlgorithmImpl(); + } + + uint32_t getFinalChunkNumber() const { + return static_cast(*this).getFinalChunkImpl(); + } + + NextSegmentCalculationStrategy getNextSegmentCalculationStrategy() const { + return static_cast(*this) + .getNextSegmentCalculationStrategyImpl(); + } + + core::Name getBaseName() const { + return static_cast(*this).getBaseNameImpl(); + } + + auto getSuffixHashList() { + return static_cast(*this).getSuffixHashListImpl(); + } + + bool getIsFinalManifest() const { + return static_cast(*this).getIsFinalManifestImpl(); + } + + ManifestVersion getVersion() const { + return static_cast(*this).getVersionImpl(); + } + + std::size_t estimateSerializedLength(std::size_t number_of_entries) const { + return static_cast(*this) + .estimateSerializedLengthImpl(number_of_entries); + } + + uint32_t getFinalBlockNumber() const { + return static_cast(*this).getFinalBlockNumberImpl(); + } +}; + +} // namespace core + +} // namespace transport diff --git a/libtransport/src/core/manifest_format_fixed.cc b/libtransport/src/core/manifest_format_fixed.cc new file mode 100644 index 000000000..4073a5d26 --- /dev/null +++ b/libtransport/src/core/manifest_format_fixed.cc @@ -0,0 +1,227 @@ +/* + * 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. + */ + +#include +#include + +#include + +namespace transport { + +namespace core { + +// TODO use preallocated pool of membufs +FixedManifestEncoder::FixedManifestEncoder(Packet &packet, + std::size_t signature_size) + : packet_(packet), + max_size_(Packet::default_mtu - packet_.headerSize() - signature_size), + manifest_( + utils::MemBuf::create(Packet::default_mtu - packet_.headerSize())), + manifest_header_( + reinterpret_cast(manifest_->writableData())), + manifest_entries_(reinterpret_cast( + manifest_->writableData() + sizeof(ManifestHeader))), + current_entry_(0), + signature_size_(signature_size) { + *manifest_header_ = {0}; +} + +FixedManifestEncoder::~FixedManifestEncoder() {} + +FixedManifestEncoder &FixedManifestEncoder::encodeImpl() { + manifest_->append(sizeof(ManifestHeader) + + manifest_header_->number_of_entries * + sizeof(ManifestEntry)); + packet_.appendPayload(std::move(manifest_)); + return *this; +} + +FixedManifestEncoder &FixedManifestEncoder::clearImpl() { + manifest_ = utils::MemBuf::create(Packet::default_mtu - packet_.headerSize() - + signature_size_); + return *this; +} + +FixedManifestEncoder &FixedManifestEncoder::setHashAlgorithmImpl( + HashAlgorithm algorithm) { + manifest_header_->hash_algorithm = static_cast(algorithm); + return *this; +} + +FixedManifestEncoder &FixedManifestEncoder::setManifestTypeImpl( + ManifestType manifest_type) { + manifest_header_->manifest_type = static_cast(manifest_type); + return *this; +} + +FixedManifestEncoder & +FixedManifestEncoder::setNextSegmentCalculationStrategyImpl( + NextSegmentCalculationStrategy strategy) { + manifest_header_->next_segment_strategy = static_cast(strategy); + return *this; +} + +FixedManifestEncoder &FixedManifestEncoder::setBaseNameImpl( + const core::Name &base_name) { + base_name.copyToDestination( + reinterpret_cast(&manifest_header_->prefix[0]), false); + manifest_header_->flags.ipv6 = + base_name.getAddressFamily() == AF_INET6 ? 1_U8 : 0_U8; + return *this; +} + +FixedManifestEncoder &FixedManifestEncoder::addSuffixAndHashImpl( + uint32_t suffix, const utils::CryptoHash &hash) { + auto _hash = hash.getDigest(); + addSuffixHashBytes(suffix, _hash.data(), _hash.length()); + return *this; +} + +void FixedManifestEncoder::addSuffixHashBytes(uint32_t suffix, + const uint8_t *hash, + std::size_t length) { + manifest_entries_[current_entry_].suffix = htonl(suffix); + // std::copy(hash, hash + length, + // manifest_entries_[current_entry_].hash); + std::memcpy( + reinterpret_cast(manifest_entries_[current_entry_].hash), hash, + length); + + manifest_header_->number_of_entries++; + current_entry_++; + + if (TRANSPORT_EXPECT_FALSE(estimateSerializedLengthImpl() > max_size_)) { + throw errors::RuntimeException("Manifest size exceeded the packet MTU!"); + } +} + +FixedManifestEncoder &FixedManifestEncoder::setIsFinalManifestImpl( + bool is_last) { + manifest_header_->flags.is_last = static_cast(is_last); + return *this; +} + +FixedManifestEncoder &FixedManifestEncoder::setVersionImpl( + ManifestVersion version) { + manifest_header_->version = static_cast(version); + return *this; +} + +std::size_t FixedManifestEncoder::estimateSerializedLengthImpl( + std::size_t additional_entries) { + return sizeof(ManifestHeader) + + (manifest_header_->number_of_entries + additional_entries) * + sizeof(ManifestEntry); +} + +FixedManifestEncoder &FixedManifestEncoder::updateImpl() { + max_size_ = Packet::default_mtu - packet_.headerSize() - signature_size_; + return *this; +} + +FixedManifestEncoder &FixedManifestEncoder::setFinalBlockNumberImpl( + std::uint32_t final_block_number) { + manifest_header_->final_block_number = htonl(final_block_number); + return *this; +} + +std::size_t FixedManifestEncoder::getManifestHeaderSizeImpl() { + return sizeof(ManifestHeader); +} + +std::size_t FixedManifestEncoder::getManifestEntrySizeImpl() { + return sizeof(ManifestEntry); +} + +FixedManifestDecoder::FixedManifestDecoder(Packet &packet) + : packet_(packet), + manifest_header_(reinterpret_cast( + packet_.getPayload()->writableData())), + manifest_entries_(reinterpret_cast( + packet_.getPayload()->writableData() + sizeof(ManifestHeader))) {} + +FixedManifestDecoder::~FixedManifestDecoder() {} + +void FixedManifestDecoder::decodeImpl() { + std::size_t packet_size = packet_.payloadSize(); + + if (packet_size < sizeof(ManifestHeader) || + packet_size < estimateSerializedLengthImpl()) { + throw errors::RuntimeException( + "The packet does not match expected manifest size."); + } +} + +FixedManifestDecoder &FixedManifestDecoder::clearImpl() { return *this; } + +ManifestType FixedManifestDecoder::getManifestTypeImpl() const { + return static_cast(manifest_header_->manifest_type); +} + +HashAlgorithm FixedManifestDecoder::getHashAlgorithmImpl() const { + return static_cast(manifest_header_->hash_algorithm); +} + +NextSegmentCalculationStrategy +FixedManifestDecoder::getNextSegmentCalculationStrategyImpl() const { + return static_cast( + manifest_header_->next_segment_strategy); +} + +typename Fixed::SuffixList FixedManifestDecoder::getSuffixHashListImpl() { + typename Fixed::SuffixList hash_list; + + for (int i = 0; i < manifest_header_->number_of_entries; i++) { + hash_list.insert(hash_list.end(), + std::make_pair(ntohl(manifest_entries_[i].suffix), + reinterpret_cast( + &manifest_entries_[i].hash[0]))); + } + + return hash_list; +} + +core::Name FixedManifestDecoder::getBaseNameImpl() const { + if (static_cast(manifest_header_->flags.ipv6)) { + return core::Name(AF_INET6, + reinterpret_cast(&manifest_header_->prefix)); + } else { + return core::Name(AF_INET, + reinterpret_cast(&manifest_header_->prefix)); + } +} + +bool FixedManifestDecoder::getIsFinalManifestImpl() const { + return static_cast(manifest_header_->flags.is_last); +} + +ManifestVersion FixedManifestDecoder::getVersionImpl() const { + return static_cast(manifest_header_->version); +} + +std::size_t FixedManifestDecoder::estimateSerializedLengthImpl( + std::size_t additional_entries) const { + return sizeof(ManifestHeader) + + (additional_entries + manifest_header_->number_of_entries) * + sizeof(ManifestEntry); +} + +uint32_t FixedManifestDecoder::getFinalBlockNumberImpl() const { + return ntohl(manifest_header_->final_block_number); +} + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/core/manifest_format_fixed.h b/libtransport/src/core/manifest_format_fixed.h new file mode 100644 index 000000000..9cacb3bc2 --- /dev/null +++ b/libtransport/src/core/manifest_format_fixed.h @@ -0,0 +1,172 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include + +#include + +namespace transport { + +namespace core { + +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |Version| MType |HashAlg|NextStr| Flags |NumberOfEntries| +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Final Block Number | +// +---------------------------------------------------------------| +// | | +// + + +// | | +// + Prefix + +// | | +// + + +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Suffix | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Hash Value | +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +class FixedManifestEncoder; +class FixedManifestDecoder; +class Packet; + +struct Fixed { + using Encoder = FixedManifestEncoder; + using Decoder = FixedManifestDecoder; + using HashType = utils::CryptoHash; + using SuffixList = std::list>; +}; + +struct Flags { + std::uint8_t ipv6 : 1; + std::uint8_t is_last : 1; + std::uint8_t unused : 6; +}; + +struct ManifestEntry { + std::uint32_t suffix; + std::uint32_t hash[8]; +}; + +struct ManifestHeader { + std::uint8_t version : 4; + std::uint8_t manifest_type : 4; + std::uint8_t hash_algorithm : 4; + std::uint8_t next_segment_strategy : 4; + Flags flags; + std::uint8_t number_of_entries; + std::uint32_t final_block_number; + std::uint32_t prefix[4]; + ManifestEntry entries[0]; +}; + +static const constexpr std::uint8_t manifest_version = 1; + +class FixedManifestEncoder : public ManifestEncoder { + public: + FixedManifestEncoder(Packet &packet, std::size_t signature_size = 0); + + ~FixedManifestEncoder(); + + FixedManifestEncoder &encodeImpl(); + + FixedManifestEncoder &clearImpl(); + + FixedManifestEncoder &setManifestTypeImpl(ManifestType manifest_type); + + FixedManifestEncoder &setHashAlgorithmImpl(HashAlgorithm algorithm); + + FixedManifestEncoder &setNextSegmentCalculationStrategyImpl( + NextSegmentCalculationStrategy strategy); + + FixedManifestEncoder &setBaseNameImpl(const core::Name &base_name); + + FixedManifestEncoder &addSuffixAndHashImpl(uint32_t suffix, + const utils::CryptoHash &hash); + + FixedManifestEncoder &setIsFinalManifestImpl(bool is_last); + + FixedManifestEncoder &setVersionImpl(ManifestVersion version); + + std::size_t estimateSerializedLengthImpl(std::size_t additional_entries = 0); + + FixedManifestEncoder &updateImpl(); + + FixedManifestEncoder &setFinalBlockNumberImpl( + std::uint32_t final_block_number); + + static std::size_t getManifestHeaderSizeImpl(); + + static std::size_t getManifestEntrySizeImpl(); + + private: + void addSuffixHashBytes(uint32_t suffix, const uint8_t *hash, + std::size_t length); + + Packet &packet_; + std::size_t max_size_; + std::unique_ptr manifest_; + ManifestHeader *manifest_header_; + ManifestEntry *manifest_entries_; + std::size_t current_entry_; + std::size_t signature_size_; +}; + +class FixedManifestDecoder : public ManifestDecoder { + public: + FixedManifestDecoder(Packet &packet); + + ~FixedManifestDecoder(); + + void decodeImpl(); + + FixedManifestDecoder &clearImpl(); + + ManifestType getManifestTypeImpl() const; + + HashAlgorithm getHashAlgorithmImpl() const; + + NextSegmentCalculationStrategy getNextSegmentCalculationStrategyImpl() const; + + typename Fixed::SuffixList getSuffixHashListImpl(); + + core::Name getBaseNameImpl() const; + + bool getIsFinalManifestImpl() const; + + std::size_t estimateSerializedLengthImpl( + std::size_t additional_entries = 0) const; + + ManifestVersion getVersionImpl() const; + + uint32_t getFinalBlockNumberImpl() const; + + private: + Packet &packet_; + ManifestHeader *manifest_header_; + ManifestEntry *manifest_entries_; +}; + +} // namespace core + +} // namespace transport diff --git a/libtransport/src/core/manifest_inline.h b/libtransport/src/core/manifest_inline.h new file mode 100644 index 000000000..235c6f3a0 --- /dev/null +++ b/libtransport/src/core/manifest_inline.h @@ -0,0 +1,115 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include +#include +#include + +namespace transport { + +namespace core { + +template +class ManifestInline + : public Manifest> { + using ManifestBase = + Manifest>; + using HashType = typename FormatTraits::HashType; + using SuffixList = typename FormatTraits::SuffixList; + + public: + ManifestInline() : ManifestBase() {} + + ManifestInline(const core::Name &name, std::size_t signature_size = 0) + : ManifestBase(name, signature_size) {} + + template + ManifestInline(T &&base) : ManifestBase(std::forward(base)) {} + + static TRANSPORT_ALWAYS_INLINE ManifestInline *createManifest( + const core::Name &manifest_name, ManifestVersion version, + ManifestType type, HashAlgorithm algorithm, bool is_last, + const Name &base_name, NextSegmentCalculationStrategy strategy, + std::size_t signature_size) { + auto manifest = new ManifestInline(manifest_name, signature_size); + manifest->setVersion(version); + manifest->setManifestType(type); + manifest->setHashAlgorithm(algorithm); + manifest->setFinalManifest(is_last); + manifest->setBaseName(base_name); + manifest->setNextSegmentCalculationStrategy(strategy); + + return manifest; + } + + ManifestInline &encodeImpl() { + ManifestBase::encoder_.encode(); + return *this; + } + + ManifestInline &decodeImpl() { + base_name_ = ManifestBase::decoder_.getBaseName(); + next_segment_strategy_ = + ManifestBase::decoder_.getNextSegmentCalculationStrategy(); + suffix_hash_map_ = ManifestBase::decoder_.getSuffixHashList(); + + return *this; + } + + std::size_t estimateManifestSizeImpl(std::size_t additional_entries = 0) { + return ManifestBase::encoder_.estimateSerializedLength(additional_entries); + } + + ManifestInline &setBaseName(const Name &name) { + base_name_ = name; + ManifestBase::encoder_.setBaseName(base_name_); + return *this; + } + + const Name &getBaseName() { return base_name_; } + + ManifestInline &addSuffixHash(uint32_t suffix, const HashType &hash) { + ManifestBase::encoder_.addSuffixAndHash(suffix, hash); + return *this; + } + + // Call this function only after the decode function! + const SuffixList &getSuffixList() { return suffix_hash_map_; } + + ManifestInline &setNextSegmentCalculationStrategy( + NextSegmentCalculationStrategy strategy) { + next_segment_strategy_ = strategy; + ManifestBase::encoder_.setNextSegmentCalculationStrategy( + next_segment_strategy_); + return *this; + } + + NextSegmentCalculationStrategy getNextSegmentCalculationStrategy() { + return next_segment_strategy_; + } + + private: + core::Name base_name_; + NextSegmentCalculationStrategy next_segment_strategy_; + SuffixList suffix_hash_map_; +}; + +} // end namespace core + +} // end namespace transport \ No newline at end of file diff --git a/libtransport/src/core/memif_connector.cc b/libtransport/src/core/memif_connector.cc new file mode 100644 index 000000000..2292e9b41 --- /dev/null +++ b/libtransport/src/core/memif_connector.cc @@ -0,0 +1,494 @@ +/* + * 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. + */ + +#include + +#include + +#ifdef __vpp__ + +#include +#include + +extern "C" { +#include +}; + +#define CANCEL_TIMER 1 + +namespace transport { + +namespace core { + +struct memif_connection { + uint16_t index; + /* memif conenction handle */ + memif_conn_handle_t conn; + /* transmit queue id */ + uint16_t tx_qid; + /* tx buffers */ + memif_buffer_t *tx_bufs; + /* allocated tx buffers counter */ + /* number of tx buffers pointing to shared memory */ + uint16_t tx_buf_num; + /* rx buffers */ + memif_buffer_t *rx_bufs; + /* allcoated rx buffers counter */ + /* number of rx buffers pointing to shared memory */ + uint16_t rx_buf_num; + /* interface ip address */ + uint8_t ip_addr[4]; +}; + +std::once_flag MemifConnector::flag_; +utils::EpollEventReactor MemifConnector::main_event_reactor_; + +MemifConnector::MemifConnector(PacketReceivedCallback &&receive_callback, + OnReconnect &&on_reconnect_callback, + asio::io_service &io_service, + std::string app_name) + : Connector(std::move(receive_callback), std::move(on_reconnect_callback)), + memif_worker_(nullptr), + timer_set_(false), + send_timer_(std::make_unique(event_reactor_)), + disconnect_timer_( + std::make_unique(event_reactor_)), + io_service_(io_service), + packet_counter_(0), + memif_connection_(std::make_unique()), + tx_buf_counter_(0), + is_reconnection_(false), + data_available_(false), + app_name_(app_name), + socket_filename_("") { + std::call_once(MemifConnector::flag_, &MemifConnector::init, this); +} + +MemifConnector::~MemifConnector() { close(); } + +void MemifConnector::init() { + /* initialize memory interface */ + int err = memif_init(controlFdUpdate, const_cast(app_name_.c_str()), + nullptr, nullptr, nullptr); + + if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { + TRANSPORT_LOGE("memif_init: %s", memif_strerror(err)); + } +} + +void MemifConnector::connect(uint32_t memif_id, long memif_mode) { + state_ = ConnectorState::CONNECTING; + + memif_id_ = memif_id; + socket_filename_ = "/run/vpp/memif.sock"; + + createMemif(memif_id, memif_mode, nullptr); + + work_ = std::make_unique(io_service_); + + while (state_ != ConnectorState::CONNECTED) { + MemifConnector::main_event_reactor_.runOneEvent(); + } + + int err; + + /* get interrupt queue id */ + int fd = -1; + err = memif_get_queue_efd(memif_connection_->conn, 0, &fd); + if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { + TRANSPORT_LOGE("memif_get_queue_efd: %s", memif_strerror(err)); + return; + } + + // Remove fd from main epoll + main_event_reactor_.delFileDescriptor(fd); + + // Add fd to epoll of instance + event_reactor_.addFileDescriptor( + fd, EPOLLIN, [this](const utils::Event &evt) -> int { + return onInterrupt(memif_connection_->conn, this, 0); + }); + + memif_worker_ = std::make_unique( + std::bind(&MemifConnector::threadMain, this)); +} + +int MemifConnector::createMemif(uint32_t index, uint8_t mode, char *s) { + memif_connection_t *c = memif_connection_.get(); + + /* setting memif connection arguments */ + memif_conn_args_t args; + memset(&args, 0, sizeof(args)); + + args.is_master = mode; + args.log2_ring_size = MEMIF_LOG2_RING_SIZE; + args.buffer_size = MEMIF_BUF_SIZE; + args.num_s2m_rings = 1; + args.num_m2s_rings = 1; + strncpy((char *)args.interface_name, IF_NAME, strlen(IF_NAME) + 1); + args.mode = memif_interface_mode_t::MEMIF_INTERFACE_MODE_IP; + + int err; + + err = memif_create_socket(&args.socket, socket_filename_.c_str(), nullptr); + + if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { + throw errors::RuntimeException(memif_strerror(err)); + } + + args.interface_id = index; + /* last argument for memif_create (void * private_ctx) is used by user + to identify connection. this context is returned with callbacks */ + + /* default interrupt */ + if (s == nullptr) { + err = memif_create(&c->conn, &args, onConnect, onDisconnect, onInterrupt, + this); + + if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { + throw errors::RuntimeException(memif_strerror(err)); + } + } + + c->index = (uint16_t)index; + c->tx_qid = 0; + /* alloc memif buffers */ + c->rx_buf_num = 0; + c->rx_bufs = static_cast( + malloc(sizeof(memif_buffer_t) * MAX_MEMIF_BUFS)); + c->tx_buf_num = 0; + c->tx_bufs = static_cast( + malloc(sizeof(memif_buffer_t) * MAX_MEMIF_BUFS)); + + // memif_set_rx_mode (c->conn, MEMIF_RX_MODE_POLLING, 0); + + return 0; +} + +int MemifConnector::deleteMemif() { + memif_connection_t *c = memif_connection_.get(); + + if (c->rx_bufs) { + free(c->rx_bufs); + } + + c->rx_bufs = nullptr; + c->rx_buf_num = 0; + + if (c->tx_bufs) { + free(c->tx_bufs); + } + + c->tx_bufs = nullptr; + c->tx_buf_num = 0; + + int err; + /* disconenct then delete memif connection */ + err = memif_delete(&c->conn); + + if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { + TRANSPORT_LOGE("memif_delete: %s", memif_strerror(err)); + } + + if (TRANSPORT_EXPECT_FALSE(c->conn != nullptr)) { + TRANSPORT_LOGE("memif delete fail"); + } + + return 0; +} + +int MemifConnector::controlFdUpdate(int fd, uint8_t events, void *private_ctx) { + /* convert memif event definitions to epoll events */ + if (events & MEMIF_FD_EVENT_DEL) { + return MemifConnector::main_event_reactor_.delFileDescriptor(fd); + } + + uint32_t evt = 0; + + if (events & MEMIF_FD_EVENT_READ) { + evt |= EPOLLIN; + } + + if (events & MEMIF_FD_EVENT_WRITE) { + evt |= EPOLLOUT; + } + + if (events & MEMIF_FD_EVENT_MOD) { + return MemifConnector::main_event_reactor_.modFileDescriptor(fd, evt); + } + + return MemifConnector::main_event_reactor_.addFileDescriptor( + fd, evt, [](const utils::Event &evt) -> int { + uint32_t event = 0; + int memif_err = 0; + + if (evt.events & EPOLLIN) { + event |= MEMIF_FD_EVENT_READ; + } + + if (evt.events & EPOLLOUT) { + event |= MEMIF_FD_EVENT_WRITE; + } + + if (evt.events & EPOLLERR) { + event |= MEMIF_FD_EVENT_ERROR; + } + + memif_err = memif_control_fd_handler(evt.data.fd, event); + + if (TRANSPORT_EXPECT_FALSE(memif_err != MEMIF_ERR_SUCCESS)) { + TRANSPORT_LOGE("memif_control_fd_handler: %s", + memif_strerror(memif_err)); + } + + return 0; + }); +} + +int MemifConnector::bufferAlloc(long n, uint16_t qid) { + memif_connection_t *c = memif_connection_.get(); + int err; + uint16_t r; + /* set data pointer to shared memory and set buffer_len to shared mmeory + * buffer len */ + err = memif_buffer_alloc(c->conn, qid, c->tx_bufs, n, &r, 2000); + + if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { + TRANSPORT_LOGE("memif_buffer_alloc: %s", memif_strerror(err)); + } + + c->tx_buf_num += r; + return r; +} + +int MemifConnector::txBurst(uint16_t qid) { + memif_connection_t *c = memif_connection_.get(); + int err; + uint16_t r; + /* inform peer memif interface about data in shared memory buffers */ + /* mark memif buffers as free */ + err = memif_tx_burst(c->conn, qid, c->tx_bufs, c->tx_buf_num, &r); + + if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { + TRANSPORT_LOGE("memif_tx_burst: %s", memif_strerror(err)); + } + + // err = memif_refill_queue(c->conn, qid, r, 0); + + if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { + TRANSPORT_LOGE("memif_tx_burst: %s", memif_strerror(err)); + c->tx_buf_num -= r; + return -1; + } + + c->tx_buf_num -= r; + return 0; +} + +void MemifConnector::sendCallback(const std::error_code &ec) { + timer_set_ = false; + + if (TRANSPORT_EXPECT_TRUE(!ec && state_ == ConnectorState::CONNECTED)) { + doSend(); + } +} + +void MemifConnector::processInputBuffer() { + Packet::MemBufPtr ptr; + + while (input_buffer_.pop(ptr)) { + receive_callback_(std::move(ptr)); + } +} + +/* informs user about connected status. private_ctx is used by user to identify + connection (multiple connections WIP) */ +int MemifConnector::onConnect(memif_conn_handle_t conn, void *private_ctx) { + MemifConnector *connector = (MemifConnector *)private_ctx; + connector->state_ = ConnectorState::CONNECTED; + memif_refill_queue(conn, 0, -1, 0); + + return 0; +} + +/* informs user about disconnected status. private_ctx is used by user to + identify connection (multiple connections WIP) */ +int MemifConnector::onDisconnect(memif_conn_handle_t conn, void *private_ctx) { + MemifConnector *connector = (MemifConnector *)private_ctx; + connector->state_ = ConnectorState::CLOSED; + return 0; +} + +void MemifConnector::threadMain() { event_reactor_.runEventLoop(1000); } + +int MemifConnector::onInterrupt(memif_conn_handle_t conn, void *private_ctx, + uint16_t qid) { + MemifConnector *connector = (MemifConnector *)private_ctx; + + memif_connection_t *c = connector->memif_connection_.get(); + int err = MEMIF_ERR_SUCCESS, ret_val; + uint16_t rx; + + do { + err = memif_rx_burst(conn, qid, c->rx_bufs, MAX_MEMIF_BUFS, &rx); + ret_val = err; + + if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS && + err != MEMIF_ERR_NOBUF)) { + TRANSPORT_LOGE("memif_rx_burst: %s", memif_strerror(err)); + goto error; + } + + c->rx_buf_num += rx; + + if (TRANSPORT_EXPECT_TRUE(connector->io_service_.stopped())) { + TRANSPORT_LOGE("socket stopped: ignoring %u packets", rx); + goto error; + } + + std::size_t packet_length; + for (int i = 0; i < rx; i++) { + auto packet = connector->getPacket(); + packet_length = (c->rx_bufs + i)->len; + std::memcpy(packet->writableData(), + reinterpret_cast((c->rx_bufs + i)->data), + packet_length); + packet->append(packet_length); + + if (!connector->input_buffer_.push(std::move(packet))) { + TRANSPORT_LOGE("Error pushing packet. Ring buffer full."); + + // TODO Here we should consider the possibility to signal the congestion + // to the application, that would react properly (e.g. slow down + // message) + } + } + + /* mark memif buffers and shared memory buffers as free */ + /* free processed buffers */ + + err = memif_refill_queue(conn, qid, rx, 0); + + if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { + TRANSPORT_LOGE("memif_buffer_free: %s", memif_strerror(err)); + } + + c->rx_buf_num -= rx; + + } while (ret_val == MEMIF_ERR_NOBUF); + + connector->io_service_.post( + std::bind(&MemifConnector::processInputBuffer, connector)); + + return 0; + +error: + err = memif_refill_queue(c->conn, qid, rx, 0); + + if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { + TRANSPORT_LOGE("memif_buffer_free: %s", memif_strerror(err)); + } + c->rx_buf_num -= rx; + + return 0; +} + +void MemifConnector::close() { + if (state_ != ConnectorState::CLOSED) { + disconnect_timer_->expiresFromNow(std::chrono::microseconds(50)); + disconnect_timer_->asyncWait([this](const std::error_code &ec) { + deleteMemif(); + event_reactor_.stop(); + work_.reset(); + }); + + if (memif_worker_ && memif_worker_->joinable()) { + memif_worker_->join(); + } + } +} + +void MemifConnector::send(const Packet::MemBufPtr &packet) { + { + utils::SpinLock::Acquire locked(write_msgs_lock_); + output_buffer_.push_back(packet); + } +#if CANCEL_TIMER + if (!timer_set_) { + timer_set_ = true; + send_timer_->expiresFromNow(std::chrono::microseconds(50)); + send_timer_->asyncWait( + std::bind(&MemifConnector::sendCallback, this, std::placeholders::_1)); + } +#endif +} + +int MemifConnector::doSend() { + std::size_t max = 0; + uint16_t n = 0; + std::size_t size = 0; + + { + utils::SpinLock::Acquire locked(write_msgs_lock_); + size = output_buffer_.size(); + } + + do { + max = size < MAX_MEMIF_BUFS ? size : MAX_MEMIF_BUFS; + + if (TRANSPORT_EXPECT_FALSE( + (n = bufferAlloc(max, memif_connection_->tx_qid)) < 0)) { + TRANSPORT_LOGE("Error allocating buffers."); + return -1; + } + + for (uint16_t i = 0; i < n; i++) { + utils::SpinLock::Acquire locked(write_msgs_lock_); + + auto packet = output_buffer_.front().get(); + const utils::MemBuf *current = packet; + std::size_t offset = 0; + uint8_t *shared_buffer = + reinterpret_cast(memif_connection_->tx_bufs[i].data); + do { + std::memcpy(shared_buffer + offset, current->data(), current->length()); + offset += current->length(); + current = current->next(); + } while (current != packet); + + memif_connection_->tx_bufs[i].len = uint32_t(offset); + + output_buffer_.pop_front(); + } + + txBurst(memif_connection_->tx_qid); + + utils::SpinLock::Acquire locked(write_msgs_lock_); + size = output_buffer_.size(); + } while (size > 0); + + return 0; +} + +void MemifConnector::send(const uint8_t *packet, std::size_t len, + const PacketSentCallback &packet_sent) { + throw errors::NotImplementedException(); +} + +} // end namespace core + +} // end namespace transport + +#endif // __vpp__ diff --git a/libtransport/src/core/memif_connector.h b/libtransport/src/core/memif_connector.h new file mode 100644 index 000000000..aafef1e56 --- /dev/null +++ b/libtransport/src/core/memif_connector.h @@ -0,0 +1,134 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include + +#include +//#include +#include +#include + +#include +#include +#include +#include + +#ifdef __vpp__ + +#define _Static_assert static_assert + +namespace transport { + +namespace core { + +typedef struct memif_connection memif_connection_t; + +#define APP_NAME "libtransport" +#define IF_NAME "vpp_connection" + +#define MEMIF_BUF_SIZE 2048 +#define MEMIF_LOG2_RING_SIZE 11 +#define MAX_MEMIF_BUFS (1 << MEMIF_LOG2_RING_SIZE) + +class MemifConnector : public Connector { + typedef void *memif_conn_handle_t; + + public: + MemifConnector(PacketReceivedCallback &&receive_callback, + OnReconnect &&on_reconnect_callback, + asio::io_service &io_service, + std::string app_name = "Libtransport"); + + ~MemifConnector() override; + + void send(const Packet::MemBufPtr &packet) override; + + void send(const uint8_t *packet, std::size_t len, + const PacketSentCallback &packet_sent = 0) override; + + void close() override; + + void connect(uint32_t memif_id, long memif_mode); + + TRANSPORT_ALWAYS_INLINE uint32_t getMemifId() { return memif_id_; }; + + private: + void init(); + + int doSend(); + + int createMemif(uint32_t index, uint8_t mode, char *s); + + uint32_t getMemifConfiguration(); + + int deleteMemif(); + + static int controlFdUpdate(int fd, uint8_t events, void *private_ctx); + + static int onConnect(memif_conn_handle_t conn, void *private_ctx); + + static int onDisconnect(memif_conn_handle_t conn, void *private_ctx); + + static int onInterrupt(memif_conn_handle_t conn, void *private_ctx, + uint16_t qid); + + void threadMain(); + + int txBurst(uint16_t qid); + + int bufferAlloc(long n, uint16_t qid); + + void sendCallback(const std::error_code &ec); + + void processInputBuffer(); + + private: + static utils::EpollEventReactor main_event_reactor_; + static std::unique_ptr main_worker_; + + int epfd; + std::unique_ptr memif_worker_; + utils::EpollEventReactor event_reactor_; + std::atomic_bool timer_set_; + std::unique_ptr send_timer_; + std::unique_ptr disconnect_timer_; + asio::io_service &io_service_; + std::unique_ptr work_; + uint32_t packet_counter_; + std::unique_ptr memif_connection_; + uint16_t tx_buf_counter_; + + PacketRing input_buffer_; + bool is_reconnection_; + bool data_available_; + uint32_t memif_id_; + uint8_t memif_mode_; + std::string app_name_; + uint16_t transmission_index_; + utils::SpinLock write_msgs_lock_; + std::string socket_filename_; + + static std::once_flag flag_; +}; + +} // end namespace core + +} // end namespace transport + +#endif // __vpp__ \ No newline at end of file diff --git a/libtransport/src/core/memif_vapi.c b/libtransport/src/core/memif_vapi.c new file mode 100644 index 000000000..ea3513306 --- /dev/null +++ b/libtransport/src/core/memif_vapi.c @@ -0,0 +1,133 @@ +/* + * 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. + */ +#include + +#ifdef __vpp__ + +#include + +#include +#include +#include +#include +#include +#include +#include + +DEFINE_VAPI_MSG_IDS_MEMIF_API_JSON + +static vapi_error_e memif_details_cb(vapi_ctx_t ctx, void *callback_ctx, + vapi_error_e rv, bool is_last, + vapi_payload_memif_details *reply) { + uint32_t *last_memif_id = (uint32_t *)callback_ctx; + uint32_t current_memif_id = 0; + if (reply != NULL) { + current_memif_id = reply->id; + } else { + return rv; + } + + if (current_memif_id >= *last_memif_id) { + *last_memif_id = current_memif_id + 1; + } + + return rv; +} + +int memif_vapi_get_next_memif_id(vapi_ctx_t ctx, uint32_t *memif_id) { + vapi_lock(); + vapi_msg_memif_dump *msg = vapi_alloc_memif_dump(ctx); + int ret = vapi_memif_dump(ctx, msg, memif_details_cb, memif_id); + vapi_unlock(); + return ret; +} + +static vapi_error_e memif_create_cb(vapi_ctx_t ctx, void *callback_ctx, + vapi_error_e rv, bool is_last, + vapi_payload_memif_create_reply *reply) { + memif_output_params_t *output_params = (memif_output_params_t *)callback_ctx; + + if (reply == NULL) return rv; + + output_params->sw_if_index = reply->sw_if_index; + + return rv; +} + +int memif_vapi_create_memif(vapi_ctx_t ctx, memif_create_params_t *input_params, + memif_output_params_t *output_params) { + vapi_lock(); + vapi_msg_memif_create *msg = vapi_alloc_memif_create(ctx); + + int ret = 0; + if (input_params->socket_id == ~0) { + // invalid socket-id + ret = -1; + goto END; + } + + if (!is_pow2(input_params->ring_size)) { + // ring size must be power of 2 + ret = -1; + goto END; + } + + if (input_params->rx_queues > 255 || input_params->rx_queues < 1) { + // rx queue must be between 1 - 255 + ret = -1; + goto END; + } + + if (input_params->tx_queues > 255 || input_params->tx_queues < 1) { + // tx queue must be between 1 - 255 + ret = -1; + goto END; + } + + msg->payload.role = input_params->role; + msg->payload.mode = input_params->mode; + msg->payload.rx_queues = input_params->rx_queues; + msg->payload.tx_queues = input_params->tx_queues; + msg->payload.id = input_params->id; + msg->payload.socket_id = input_params->socket_id; + msg->payload.ring_size = input_params->ring_size; + msg->payload.buffer_size = input_params->buffer_size; + + ret = vapi_memif_create(ctx, msg, memif_create_cb, output_params); +END: + vapi_unlock(); + return ret; +} + +static vapi_error_e memif_delete_cb(vapi_ctx_t ctx, void *callback_ctx, + vapi_error_e rv, bool is_last, + vapi_payload_memif_delete_reply *reply) { + if (reply == NULL) return rv; + + return reply->retval; +} + +int memif_vapi_delete_memif(vapi_ctx_t ctx, uint32_t sw_if_index) { + vapi_lock(); + vapi_msg_memif_delete *msg = vapi_alloc_memif_delete(ctx); + + msg->payload.sw_if_index = sw_if_index; + + int ret = vapi_memif_delete(ctx, msg, memif_delete_cb, NULL); + vapi_unlock(); + return ret; +} + +#endif // __vpp__ diff --git a/libtransport/src/core/memif_vapi.h b/libtransport/src/core/memif_vapi.h new file mode 100644 index 000000000..c045cf093 --- /dev/null +++ b/libtransport/src/core/memif_vapi.h @@ -0,0 +1,60 @@ +/* + * 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. + */ + +#pragma once + +#include + +#ifdef __vpp__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "stdint.h" + +typedef struct memif_create_params_s { + uint8_t role; + uint8_t mode; + uint8_t rx_queues; + uint8_t tx_queues; + uint32_t id; + uint32_t socket_id; + uint8_t secret[24]; + uint32_t ring_size; + uint16_t buffer_size; + uint8_t hw_addr[6]; +} memif_create_params_t; + +typedef struct memif_output_params_s { + uint32_t sw_if_index; +} memif_output_params_t; + +int memif_vapi_get_next_memif_id(vapi_ctx_t ctx, + uint32_t *memif_id); + +int memif_vapi_create_memif(vapi_ctx_t ctx, + memif_create_params_t *input_params, + memif_output_params_t *output_params); + +int memif_vapi_delete_memif(vapi_ctx_t ctx, + uint32_t sw_if_index); + +#ifdef __cplusplus +} +#endif + +#endif // __vpp__ \ No newline at end of file diff --git a/libtransport/src/core/name.cc b/libtransport/src/core/name.cc new file mode 100644 index 000000000..811e93b87 --- /dev/null +++ b/libtransport/src/core/name.cc @@ -0,0 +1,231 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include + +#include + +namespace transport { + +namespace core { + +Name::Name() { name_ = {}; } + +Name::Name(int family, const uint8_t *ip_address, std::uint32_t suffix) + : name_({}) { + name_.type = HNT_UNSPEC; + std::size_t length; + uint8_t *dst = NULL; + + if (family == AF_INET) { + dst = name_.ip4.prefix_as_u8; + length = IPV4_ADDR_LEN; + name_.type = HNT_CONTIGUOUS_V4; + } else if (family == AF_INET6) { + dst = name_.ip6.prefix_as_u8; + length = IPV6_ADDR_LEN; + name_.type = HNT_CONTIGUOUS_V6; + } else { + throw errors::RuntimeException("Specified name family does not exist."); + } + + std::memcpy(dst, ip_address, length); + *reinterpret_cast(dst + length) = suffix; +} + +Name::Name(const char *name, uint32_t segment) { + name_.type = HNT_UNSPEC; + if (hicn_name_create(name, segment, &name_) < 0) { + throw errors::InvalidIpAddressException(); + } +} + +Name::Name(const std::string &uri, uint32_t segment) + : Name(uri.c_str(), segment) {} + +Name::Name(const std::string &uri) { + name_.type = HNT_UNSPEC; + utils::StringTokenizer tokenizer(uri, "|"); + std::string ip_address; + std::string seq_number; + + ip_address = tokenizer.nextToken(); + + try { + seq_number = tokenizer.nextToken(); + } catch (errors::TokenizerException &) { + seq_number = "0"; + } + + if (hicn_name_create(ip_address.c_str(), (uint32_t)atoi(seq_number.c_str()), + &name_) < 0) { + throw errors::InvalidIpAddressException(); + } +} + +Name::Name(const Name &name) { this->name_ = name.name_; } + +Name &Name::operator=(const Name &name) { + if (hicn_name_copy(&this->name_, &name.name_) < 0) { + throw errors::MalformedNameException(); + } + + return *this; +} + +bool Name::operator==(const Name &name) const { + return this->equals(name, true); +} + +bool Name::operator!=(const Name &name) const { + return !this->operator==(name); +} + +Name::operator bool() const { + return bool(hicn_name_empty((hicn_name_t *)&name_)); +} + +bool Name::equals(const Name &name, bool consider_segment) const { + return !hicn_name_compare(&name_, &name.name_, consider_segment); +} + +std::string Name::toString() const { + char *name = new char[100]; + int ret = hicn_name_ntop(&name_, name, standard_name_string_length); + if (ret < 0) { + throw errors::MalformedNameException(); + } + std::string name_string(name); + delete[] name; + + return name_string; +} + +uint32_t Name::getHash32(bool consider_suffix) const { + uint32_t hash; + if (hicn_name_hash(&name_, &hash, consider_suffix) < 0) { + throw errors::RuntimeException("Error computing the hash of the name!"); + } + return hash; +} + +void Name::clear() { name_.type = HNT_UNSPEC; }; + +Name::Type Name::getType() const { return name_.type; } + +uint32_t Name::getSuffix() const { + uint32_t ret = 0; + if (hicn_name_get_seq_number((hicn_name_t *)&name_, &ret) < 0) { + throw errors::RuntimeException( + "Impossible to retrieve the sequence number from the name."); + } + return ret; +} + +Name &Name::setSuffix(uint32_t seq_number) { + if (hicn_name_set_seq_number(&name_, seq_number) < 0) { + throw errors::RuntimeException( + "Impossible to set the sequence number to the name."); + } + + return *this; +} + +std::shared_ptr Name::getAddress() const { + Sockaddr *ret = nullptr; + + switch (name_.type) { + case HNT_CONTIGUOUS_V4: + case HNT_IOV_V4: + ret = (Sockaddr *)new Sockaddr4; + break; + case HNT_CONTIGUOUS_V6: + case HNT_IOV_V6: + ret = (Sockaddr *)new Sockaddr6; + break; + default: + throw errors::MalformedNameException(); + } + + if (hicn_name_to_sockaddr_address((hicn_name_t *)&name_, ret) < 0) { + throw errors::MalformedNameException(); + } + + return std::shared_ptr(ret); +} + +ip_prefix_t Name::toIpAddress() const { + ip_prefix_t ret; + std::memset(&ret, 0, sizeof(ret)); + + if (hicn_name_to_ip_prefix(&name_, &ret) < 0) { + throw errors::InvalidIpAddressException(); + } + + return ret; +} + +int Name::getAddressFamily() const { + int ret = 0; + + if (hicn_name_get_family(&name_, &ret) < 0) { + throw errors::InvalidIpAddressException(); + } + + return ret; +} + +void Name::copyToDestination(uint8_t *destination, bool include_suffix) const { + if (hicn_name_copy_to_destination(destination, &name_, include_suffix) < 0) { + throw errors::RuntimeException( + "Impossibe to copy the name into the " + "provided destination"); + } +} + +std::ostream &operator<<(std::ostream &os, const Name &name) { + const std::string &str = name.toString(); + // os << "core:/"; + os << str; + + return os; +} + +size_t hash::operator()( + const transport::core::Name &name) const { + return name.getHash32(false); +} + +size_t compare2::operator()( + const transport::core::Name &name1, + const transport::core::Name &name2) const { + return name1.equals(name2, false); +} + +} // end namespace core + +} // end namespace transport + +namespace std { +size_t hash::operator()( + const transport::core::Name &name) const { + return name.getHash32(); +} + +} // end namespace std diff --git a/libtransport/src/core/packet.cc b/libtransport/src/core/packet.cc new file mode 100644 index 000000000..817f8de66 --- /dev/null +++ b/libtransport/src/core/packet.cc @@ -0,0 +1,607 @@ +/* + * 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. + */ + +#include +#include +#include +#include + +extern "C" { +#ifndef _WIN32 +TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat") +#endif +#include +} + +namespace transport { + +namespace core { + +const core::Name Packet::base_name("0::0|0"); + +Packet::Packet(Format format) + : packet_(utils::MemBuf::create(getHeaderSizeFromFormat(format, 256)) + .release()), + packet_start_(reinterpret_cast(packet_->writableData())), + header_head_(packet_.get()), + payload_head_(nullptr), + format_(format) { + if (hicn_packet_init_header(format, packet_start_) < 0) { + throw errors::RuntimeException("Unexpected error initializing the packet."); + } + + packet_->append(getHeaderSizeFromFormat(format_)); +} + +Packet::Packet(MemBufPtr &&buffer) + : packet_(std::move(buffer)), + packet_start_(reinterpret_cast(packet_->writableData())), + header_head_(packet_.get()), + payload_head_(nullptr), + format_(getFormatFromBuffer(packet_->writableData())) {} + +Packet::Packet(const uint8_t *buffer, std::size_t size) + : Packet(MemBufPtr(utils::MemBuf::copyBuffer(buffer, size).release())) {} + +Packet::Packet(Packet &&other) + : packet_(std::move(other.packet_)), + packet_start_(other.packet_start_), + header_head_(other.header_head_), + payload_head_(other.payload_head_), + format_(other.format_) { + other.packet_start_ = nullptr; + other.header_head_ = nullptr; + other.payload_head_ = nullptr; + other.format_ = HF_UNSPEC; +} + +Packet::~Packet() {} + +std::size_t Packet::getHeaderSizeFromFormat(Format format, + size_t signature_size) { + std::size_t header_length; + hicn_packet_get_header_length_from_format(format, &header_length); + int is_ah = _is_ah(format); + return is_ah * (header_length + signature_size) + (!is_ah) * header_length; +} + +std::size_t Packet::getHeaderSizeFromBuffer(Format format, + const uint8_t *buffer) { + size_t header_length; + if (hicn_packet_get_header_length(format, (hicn_header_t *)buffer, + &header_length) < 0) { + throw errors::MalformedPacketException(); + } + return header_length; +} + +bool Packet::isInterest(const uint8_t *buffer) { + bool is_interest = false; + + if (TRANSPORT_EXPECT_FALSE(hicn_packet_test_ece((const hicn_header_t *)buffer, + &is_interest) < 0)) { + throw errors::RuntimeException( + "Impossible to retrieve ece flag from packet"); + } + + return !is_interest; +} + +Packet::Format Packet::getFormatFromBuffer(const uint8_t *buffer) { + Format format = HF_UNSPEC; + + if (TRANSPORT_EXPECT_FALSE( + hicn_packet_get_format((const hicn_header_t *)buffer, &format) < 0)) { + throw errors::MalformedPacketException(); + } + + return format; +} + +std::size_t Packet::getPayloadSizeFromBuffer(Format format, + const uint8_t *buffer) { + std::size_t payload_length; + if (TRANSPORT_EXPECT_FALSE( + hicn_packet_get_payload_length(format, (hicn_header_t *)buffer, + &payload_length) < 0)) { + throw errors::MalformedPacketException(); + } + + return payload_length; +} + +void Packet::replace(MemBufPtr &&buffer) { + packet_ = std::move(buffer); + packet_start_ = reinterpret_cast(packet_->writableData()); + header_head_ = packet_.get(); + payload_head_ = nullptr; + format_ = getFormatFromBuffer(reinterpret_cast(packet_start_)); +} + +std::size_t Packet::payloadSize() const { + return getPayloadSizeFromBuffer(format_, + reinterpret_cast(packet_start_)); +} + +std::size_t Packet::headerSize() const { + return getHeaderSizeFromBuffer(format_, + reinterpret_cast(packet_start_)); +} + +Packet &Packet::appendPayload(std::unique_ptr &&payload) { + separateHeaderPayload(); + + if (!payload_head_) { + payload_head_ = payload.get(); + } + + header_head_->prependChain(std::move(payload)); + updateLength(); + return *this; +} + +Packet &Packet::appendPayload(const uint8_t *buffer, std::size_t length) { + return appendPayload(utils::MemBuf::copyBuffer(buffer, length)); +} + +Packet &Packet::appendHeader(std::unique_ptr &&header) { + separateHeaderPayload(); + + if (!payload_head_) { + header_head_->prependChain(std::move(header)); + } else { + payload_head_->prependChain(std::move(header)); + } + + updateLength(); + return *this; +} + +Packet &Packet::appendHeader(const uint8_t *buffer, std::size_t length) { + return appendHeader(utils::MemBuf::copyBuffer(buffer, length)); +} + +std::unique_ptr Packet::getPayload() const { + const_cast(this)->separateHeaderPayload(); + + // Hopefully the payload is contiguous + if (TRANSPORT_EXPECT_FALSE(payload_head_ && + payload_head_->next() != header_head_)) { + payload_head_->gather(payloadSize()); + } + + return payload_head_->cloneOne(); +} + +Packet &Packet::updateLength(std::size_t length) { + std::size_t total_length = length; + + for (utils::MemBuf *current = payload_head_; + current && current != header_head_; current = current->next()) { + total_length += current->length(); + } + + if (hicn_packet_set_payload_length(format_, packet_start_, total_length) < + 0) { + throw errors::RuntimeException("Error setting the packet payload."); + } + + return *this; +} + +PayloadType Packet::getPayloadType() const { + hicn_payload_type_t ret = HPT_UNSPEC; + + if (hicn_packet_get_payload_type(packet_start_, &ret) < 0) { + throw errors::RuntimeException("Impossible to retrieve payload type."); + } + + return PayloadType(ret); +} + +Packet &Packet::setPayloadType(PayloadType payload_type) { + if (hicn_packet_set_payload_type(packet_start_, + hicn_payload_type_t(payload_type)) < 0) { + throw errors::RuntimeException("Error setting payload type of the packet."); + } + + return *this; +} + +Packet::Format Packet::getFormat() const { + if (format_ == HF_UNSPEC) { + if (hicn_packet_get_format(packet_start_, &format_) < 0) { + throw errors::MalformedPacketException(); + } + } + + return format_; +} + +const std::shared_ptr Packet::acquireMemBufReference() const { + return packet_; +} + +void Packet::dump() const { + const_cast(this)->separateHeaderPayload(); + + std::cout << "HEADER -- Length: " << headerSize() << std::endl; + hicn_packet_dump((uint8_t *)header_head_->data(), headerSize()); + + std::cout << std::endl << "PAYLOAD -- Length: " << payloadSize() << std::endl; + for (utils::MemBuf *current = payload_head_; + current && current != header_head_; current = current->next()) { + std::cout << "MemBuf Length: " << current->length() << std::endl; + hicn_packet_dump((uint8_t *)current->data(), current->length()); + } +} + +void Packet::setSignatureSize(std::size_t size_bytes) { + int ret = hicn_packet_set_signature_size(format_, packet_start_, size_bytes); + + if (ret < 0) { + throw errors::RuntimeException("Packet without Authentication Header."); + } + + packet_->append(size_bytes); + updateLength(); +} + +uint8_t *Packet::getSignature() const { + uint8_t *signature; + int ret = hicn_packet_get_signature(format_, packet_start_, &signature); + + if (ret < 0) { + throw errors::RuntimeException("Packet without Authentication Header."); + } + + return signature; +} + +std::size_t Packet::getSignatureSize() const { + size_t size_bytes; + int ret = hicn_packet_get_signature_size(format_, packet_start_, &size_bytes); + + if (ret < 0) { + throw errors::RuntimeException("Packet without Authentication Header."); + } + + return size_bytes; +} + +void Packet::setSignatureTimestamp(const uint64_t ×tamp) { + int ret = + hicn_packet_set_signature_timestamp(format_, packet_start_, timestamp); + + if (ret < 0) { + throw errors::RuntimeException("Error setting the signature timestamp."); + } +} + +uint64_t Packet::getSignatureTimestamp() const { + uint64_t return_value; + int ret = hicn_packet_get_signature_timestamp(format_, packet_start_, + &return_value); + + if (ret < 0) { + throw errors::RuntimeException("Error getting the signature timestamp."); + } + + return return_value; +} + +void Packet::setValidationAlgorithm( + const utils::CryptoSuite &validation_algorithm) { + int ret = hicn_packet_set_validation_algorithm(format_, packet_start_, + uint8_t(validation_algorithm)); + + if (ret < 0) { + throw errors::RuntimeException("Error setting the validation algorithm."); + } +} + +utils::CryptoSuite Packet::getValidationAlgorithm() const { + uint8_t return_value; + int ret = hicn_packet_get_validation_algorithm(format_, packet_start_, + &return_value); + + if (ret < 0) { + throw errors::RuntimeException("Error getting the validation algorithm."); + } + + return utils::CryptoSuite(return_value); +} + +void Packet::setKeyId(const utils::KeyId &key_id) { + int ret = hicn_packet_set_key_id(format_, packet_start_, key_id.first); + + if (ret < 0) { + throw errors::RuntimeException("Error setting the key id."); + } +} + +utils::KeyId Packet::getKeyId() const { + utils::KeyId return_value; + int ret = hicn_packet_get_key_id(format_, packet_start_, &return_value.first, + &return_value.second); + + if (ret < 0) { + throw errors::RuntimeException("Error getting the validation algorithm."); + } + + return return_value; +} + +utils::CryptoHash Packet::computeDigest(HashAlgorithm algorithm) const { + utils::CryptoHasher hasher(static_cast(algorithm)); + hasher.init(); + + // Copy IP+TCP/ICMP header before zeroing them + hicn_header_t header_copy; + + hicn_packet_copy_header(format_, packet_start_, &header_copy, false); + + const_cast(this)->resetForHash(); + + auto current = header_head_; + do { + hasher.updateBytes(current->data(), current->length()); + current = current->next(); + } while (current != header_head_); + + hicn_packet_copy_header(format_, &header_copy, packet_start_, false); + + return hasher.finalize(); +} + +void Packet::setChecksum() { + uint16_t partial_csum = 0; + + for (utils::MemBuf *current = header_head_->next(); + current && current != header_head_; current = current->next()) { + if (partial_csum != 0) { + partial_csum = ~partial_csum; + } + partial_csum = csum(current->data(), current->length(), partial_csum); + } + if (hicn_packet_compute_header_checksum(format_, packet_start_, + partial_csum) < 0) { + throw errors::MalformedPacketException(); + } +} + +bool Packet::checkIntegrity() const { + if (hicn_packet_check_integrity(format_, packet_start_) < 0) { + return false; + } + + return true; +} + +Packet &Packet::setSyn() { + if (hicn_packet_set_syn(packet_start_) < 0) { + throw errors::RuntimeException("Error setting syn bit in the packet."); + } + + return *this; +} + +Packet &Packet::resetSyn() { + if (hicn_packet_reset_syn(packet_start_) < 0) { + throw errors::RuntimeException("Error resetting syn bit in the packet."); + } + + return *this; +} + +bool Packet::testSyn() const { + bool res = false; + if (hicn_packet_test_syn(packet_start_, &res) < 0) { + throw errors::RuntimeException("Error testing syn bit in the packet."); + } + + return res; +} + +Packet &Packet::setAck() { + if (hicn_packet_set_ack(packet_start_) < 0) { + throw errors::RuntimeException("Error setting ack bit in the packet."); + } + + return *this; +} + +Packet &Packet::resetAck() { + if (hicn_packet_reset_ack(packet_start_) < 0) { + throw errors::RuntimeException("Error resetting ack bit in the packet."); + } + + return *this; +} + +bool Packet::testAck() const { + bool res = false; + if (hicn_packet_test_ack(packet_start_, &res) < 0) { + throw errors::RuntimeException("Error testing ack bit in the packet."); + } + + return res; +} + +Packet &Packet::setRst() { + if (hicn_packet_set_rst(packet_start_) < 0) { + throw errors::RuntimeException("Error setting rst bit in the packet."); + } + + return *this; +} + +Packet &Packet::resetRst() { + if (hicn_packet_reset_rst(packet_start_) < 0) { + throw errors::RuntimeException("Error resetting rst bit in the packet."); + } + + return *this; +} + +bool Packet::testRst() const { + bool res = false; + if (hicn_packet_test_rst(packet_start_, &res) < 0) { + throw errors::RuntimeException("Error testing rst bit in the packet."); + } + + return res; +} + +Packet &Packet::setFin() { + if (hicn_packet_set_fin(packet_start_) < 0) { + throw errors::RuntimeException("Error setting fin bit in the packet."); + } + + return *this; +} + +Packet &Packet::resetFin() { + if (hicn_packet_reset_fin(packet_start_) < 0) { + throw errors::RuntimeException("Error resetting fin bit in the packet."); + } + + return *this; +} + +bool Packet::testFin() const { + bool res = false; + if (hicn_packet_test_fin(packet_start_, &res) < 0) { + throw errors::RuntimeException("Error testing fin bit in the packet."); + } + + return res; +} + +Packet &Packet::resetFlags() { + resetSyn(); + resetAck(); + resetRst(); + resetFin(); + + return *this; +} + +std::string Packet::printFlags() const { + std::string flags = ""; + if (testSyn()) { + flags += "S"; + } + if (testAck()) { + flags += "A"; + } + if (testRst()) { + flags += "R"; + } + if (testFin()) { + flags += "F"; + } + return flags; +} + +Packet &Packet::setSrcPort(uint16_t srcPort) { + if (hicn_packet_set_src_port(packet_start_, srcPort) < 0) { + throw errors::RuntimeException("Error setting source port in the packet."); + } + + return *this; +} + +Packet &Packet::setDstPort(uint16_t dstPort) { + if (hicn_packet_set_dst_port(packet_start_, dstPort) < 0) { + throw errors::RuntimeException( + "Error setting destination port in the packet."); + } + + return *this; +} + +uint16_t Packet::getSrcPort() const { + uint16_t port = 0; + + if (hicn_packet_get_src_port(packet_start_, &port) < 0) { + throw errors::RuntimeException("Error reading source port in the packet."); + } + + return port; +} + +uint16_t Packet::getDstPort() const { + uint16_t port = 0; + + if (hicn_packet_get_dst_port(packet_start_, &port) < 0) { + throw errors::RuntimeException( + "Error reading destination port in the packet."); + } + + return port; +} + +Packet &Packet::setTTL(uint8_t hops) { + if (hicn_packet_set_hoplimit(packet_start_, hops) < 0) { + throw errors::RuntimeException("Error setting TTL."); + } + + return *this; +} + +uint8_t Packet::getTTL() const { + uint8_t hops = 0; + if (hicn_packet_get_hoplimit(packet_start_, &hops) < 0) { + throw errors::RuntimeException("Error reading TTL."); + } + + return hops; +} + +void Packet::separateHeaderPayload() { + if (payload_head_) { + return; + } + + int signature_size = 0; + if (_is_ah(format_)) { + signature_size = (uint32_t)getSignatureSize(); + } + + auto header_size = getHeaderSizeFromFormat(format_, signature_size); + auto payload_length = packet_->length() - header_size; + + packet_->trimEnd(packet_->length()); + + auto payload = packet_->cloneOne(); + payload_head_ = payload.get(); + payload_head_->advance(header_size); + payload_head_->append(payload_length); + packet_->prependChain(std::move(payload)); + packet_->append(header_size); +} + +void Packet::resetPayload() { + if (packet_->isChained()) { + packet_->separateChain(packet_->next(), packet_->prev()); + payload_head_ = nullptr; + updateLength(); + } +} + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/core/pending_interest.cc b/libtransport/src/core/pending_interest.cc new file mode 100644 index 000000000..fbe98cab5 --- /dev/null +++ b/libtransport/src/core/pending_interest.cc @@ -0,0 +1,74 @@ +/* + * 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. + */ + +#include + +namespace transport { + +namespace core { + +PendingInterest::PendingInterest() + : interest_(nullptr, nullptr), + timer_(), + on_content_object_callback_(), + on_interest_timeout_callback_() {} + +PendingInterest::PendingInterest(Interest::Ptr &&interest, + std::unique_ptr &&timer) + : interest_(std::move(interest)), + timer_(std::move(timer)), + on_content_object_callback_(), + on_interest_timeout_callback_() {} + +PendingInterest::PendingInterest( + Interest::Ptr &&interest, OnContentObjectCallback &&on_content_object, + OnInterestTimeoutCallback &&on_interest_timeout, + std::unique_ptr &&timer) + : interest_(std::move(interest)), + timer_(std::move(timer)), + on_content_object_callback_(std::move(on_content_object)), + on_interest_timeout_callback_(std::move(on_interest_timeout)) {} + +PendingInterest::~PendingInterest() {} + +void PendingInterest::cancelTimer() { timer_->cancel(); } + +void PendingInterest::setInterest(Interest::Ptr &&interest) { + interest_ = std::move(interest); +} + +Interest::Ptr &&PendingInterest::getInterest() { return std::move(interest_); } + +const OnContentObjectCallback &PendingInterest::getOnDataCallback() const { + return on_content_object_callback_; +} + +void PendingInterest::setOnContentObjectCallback( + OnContentObjectCallback &&on_content_object) { + PendingInterest::on_content_object_callback_ = on_content_object; +} + +const OnInterestTimeoutCallback &PendingInterest::getOnTimeoutCallback() const { + return on_interest_timeout_callback_; +} + +void PendingInterest::setOnTimeoutCallback( + OnInterestTimeoutCallback &&on_interest_timeout) { + PendingInterest::on_interest_timeout_callback_ = on_interest_timeout; +} + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/core/pending_interest.h b/libtransport/src/core/pending_interest.h new file mode 100644 index 000000000..87fed5073 --- /dev/null +++ b/libtransport/src/core/pending_interest.h @@ -0,0 +1,93 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include + +#include + +namespace transport { + +namespace core { + +class HicnForwarderInterface; +class VPPForwarderInterface; +class RawSocketInterface; + +template +class Portal; + +typedef std::function + OnContentObjectCallback; +typedef std::function OnInterestTimeoutCallback; +typedef std::function TimerCallback; + +class PendingInterest { + friend class Portal; + friend class Portal; + friend class Portal; + + public: + using Ptr = utils::ObjectPool::Ptr; + PendingInterest(); + + PendingInterest(Interest::Ptr &&interest, + std::unique_ptr &&timer); + + PendingInterest(Interest::Ptr &&interest, + OnContentObjectCallback &&on_content_object, + OnInterestTimeoutCallback &&on_interest_timeout, + std::unique_ptr &&timer); + + ~PendingInterest(); + + template + TRANSPORT_ALWAYS_INLINE void startCountdown(Handler &&cb) { + timer_->expires_from_now( + std::chrono::milliseconds(interest_->getLifetime())); + timer_->async_wait(std::forward(cb)); + } + + void cancelTimer(); + + Interest::Ptr &&getInterest(); + + void setInterest(Interest::Ptr &&interest); + + const OnContentObjectCallback &getOnDataCallback() const; + + void setOnContentObjectCallback(OnContentObjectCallback &&on_content_object); + + const OnInterestTimeoutCallback &getOnTimeoutCallback() const; + + void setOnTimeoutCallback(OnInterestTimeoutCallback &&on_interest_timeout); + + private: + Interest::Ptr interest_; + std::unique_ptr timer_; + OnContentObjectCallback on_content_object_callback_; + OnInterestTimeoutCallback on_interest_timeout_callback_; +}; + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/core/portal.h b/libtransport/src/core/portal.h new file mode 100644 index 000000000..d7c463dfd --- /dev/null +++ b/libtransport/src/core/portal.h @@ -0,0 +1,696 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef __vpp__ +#include +#endif + +#include +#include +#include +#include +#include +#include + +#define UNSET_CALLBACK 0 + +namespace transport { +namespace core { + +namespace portal_details { + +static constexpr uint32_t pool_size = 2048; + +class HandlerMemory { +#ifdef __vpp__ + static constexpr std::size_t memory_size = 1024 * 1024; + + public: + HandlerMemory() : index_(0) {} + + HandlerMemory(const HandlerMemory &) = delete; + HandlerMemory &operator=(const HandlerMemory &) = delete; + + TRANSPORT_ALWAYS_INLINE void *allocate(std::size_t size) { + return &storage_[index_++ % memory_size]; + } + + TRANSPORT_ALWAYS_INLINE void deallocate(void *pointer) {} + + private: + // Storage space used for handler-based custom memory allocation. + typename std::aligned_storage<128>::type storage_[memory_size]; + uint32_t index_; +#else + public: + HandlerMemory() {} + + HandlerMemory(const HandlerMemory &) = delete; + HandlerMemory &operator=(const HandlerMemory &) = delete; + + TRANSPORT_ALWAYS_INLINE void *allocate(std::size_t size) { + return ::operator new(size); + } + + TRANSPORT_ALWAYS_INLINE void deallocate(void *pointer) { + ::operator delete(pointer); + } +#endif +}; + +// The allocator to be associated with the handler objects. This allocator only +// needs to satisfy the C++11 minimal allocator requirements. +template +class HandlerAllocator { + public: + using value_type = T; + + explicit HandlerAllocator(HandlerMemory &mem) : memory_(mem) {} + + template + HandlerAllocator(const HandlerAllocator &other) noexcept + : memory_(other.memory_) {} + + TRANSPORT_ALWAYS_INLINE bool operator==(const HandlerAllocator &other) const + noexcept { + return &memory_ == &other.memory_; + } + + TRANSPORT_ALWAYS_INLINE bool operator!=(const HandlerAllocator &other) const + noexcept { + return &memory_ != &other.memory_; + } + + TRANSPORT_ALWAYS_INLINE T *allocate(std::size_t n) const { + return static_cast(memory_.allocate(sizeof(T) * n)); + } + + TRANSPORT_ALWAYS_INLINE void deallocate(T *p, std::size_t /*n*/) const { + return memory_.deallocate(p); + } + + private: + template + friend class HandlerAllocator; + + // The underlying memory. + HandlerMemory &memory_; +}; + +// Wrapper class template for handler objects to allow handler memory +// allocation to be customised. The allocator_type type and get_allocator() +// member function are used by the asynchronous operations to obtain the +// allocator. Calls to operator() are forwarded to the encapsulated handler. +template +class CustomAllocatorHandler { + public: + using allocator_type = HandlerAllocator; + + CustomAllocatorHandler(HandlerMemory &m, Handler h) + : memory_(m), handler_(h) {} + + allocator_type get_allocator() const noexcept { + return allocator_type(memory_); + } + + template + void operator()(Args &&... args) { + handler_(std::forward(args)...); + } + + private: + HandlerMemory &memory_; + Handler handler_; +}; + +// Helper function to wrap a handler object to add custom allocation. +template +inline CustomAllocatorHandler makeCustomAllocatorHandler( + HandlerMemory &m, Handler h) { + return CustomAllocatorHandler(m, h); +} + +class Pool { + public: + Pool(asio::io_service &io_service) : io_service_(io_service) { + increasePendingInterestPool(); + increaseInterestPool(); + increaseContentObjectPool(); + } + + TRANSPORT_ALWAYS_INLINE void increasePendingInterestPool() { + // Create pool of pending interests to reuse + for (uint32_t i = 0; i < pool_size; i++) { + pending_interests_pool_.add(new PendingInterest( + Interest::Ptr(nullptr), + std::make_unique(io_service_))); + } + } + + TRANSPORT_ALWAYS_INLINE void increaseInterestPool() { + // Create pool of interests to reuse + for (uint32_t i = 0; i < pool_size; i++) { + interest_pool_.add(new Interest()); + } + } + + TRANSPORT_ALWAYS_INLINE void increaseContentObjectPool() { + // Create pool of content object to reuse + for (uint32_t i = 0; i < pool_size; i++) { + content_object_pool_.add(new ContentObject()); + } + } + + PendingInterest::Ptr getPendingInterest() { + auto res = pending_interests_pool_.get(); + while (TRANSPORT_EXPECT_FALSE(!res.first)) { + increasePendingInterestPool(); + res = pending_interests_pool_.get(); + } + + return std::move(res.second); + } + + TRANSPORT_ALWAYS_INLINE ContentObject::Ptr getContentObject() { + auto res = content_object_pool_.get(); + while (TRANSPORT_EXPECT_FALSE(!res.first)) { + increaseContentObjectPool(); + res = content_object_pool_.get(); + } + + return std::move(res.second); + } + + TRANSPORT_ALWAYS_INLINE Interest::Ptr getInterest() { + auto res = interest_pool_.get(); + while (TRANSPORT_EXPECT_FALSE(!res.first)) { + increaseInterestPool(); + res = interest_pool_.get(); + } + + return std::move(res.second); + } + + private: + utils::ObjectPool pending_interests_pool_; + utils::ObjectPool content_object_pool_; + utils::ObjectPool interest_pool_; + asio::io_service &io_service_; +}; + +} // namespace portal_details + +using PendingInterestHashTable = + std::unordered_map; + +template +class BasicBindConfig { + static_assert(std::is_same::value, + "Prefix must be a Prefix type."); + + const uint32_t standard_cs_reserved = 5000; + + public: + template + BasicBindConfig(T &&prefix) + : prefix_(std::forward(prefix)), + content_store_reserved_(standard_cs_reserved) {} + + template + BasicBindConfig(T &&prefix, uint32_t cs_reserved) + : prefix_(std::forward(prefix)), + content_store_reserved_(cs_reserved) {} + + TRANSPORT_ALWAYS_INLINE const PrefixType &prefix() const { return prefix_; } + + TRANSPORT_ALWAYS_INLINE uint32_t csReserved() const { + return content_store_reserved_; + } + + private: + PrefixType prefix_; + uint32_t content_store_reserved_; +}; + +using BindConfig = BasicBindConfig; + +/** + * Portal is a opaque class which is used for sending/receiving interest/data + * packets over multiple kind of connector. The connector itself is defined by + * the template ForwarderInt, which is resolved at compile time. It is then not + * possible to decide at runtime what the connector will be. + * + * The tasks performed by portal are the following: + * - Sending/Receiving Interest packets + * - Sending/Receiving Data packets + * - Set timers (one per interest), in order to trigger events if an interest is + * not satisfied + * - Register a producer prefix to the local forwarder + * + * The way of working of portal is event-based, which means that data and + * interests are sent/received in a asynchronous manner, and the notifications + * are performed through callbacks. + * + * The portal class is not thread safe, appropriate locking is required by the + * users of this class. + */ +template +class Portal { + static_assert( + std::is_base_of, + ForwarderInt>::value, + "ForwarderInt must inherit from ForwarderInterface!"); + + public: + /** + * Consumer callback is an abstract class containing two methods to be + * implemented by a consumer application. + */ + class ConsumerCallback { + public: + virtual void onContentObject(Interest::Ptr &&i, ContentObject::Ptr &&c) = 0; + virtual void onTimeout(Interest::Ptr &&i) = 0; + }; + + /** + * Producer callback is an abstract class containing two methods to be + * implemented by a producer application. + */ + class ProducerCallback { + public: + virtual void onInterest(Interest::Ptr &&i) = 0; + }; + + Portal() : Portal(internal_io_service_) {} + + Portal(asio::io_service &io_service) + : io_service_(io_service), + packet_pool_(io_service), + app_name_("libtransport_application"), + consumer_callback_(nullptr), + producer_callback_(nullptr), + connector_(std::bind(&Portal::processIncomingMessages, this, + std::placeholders::_1), + std::bind(&Portal::setLocalRoutes, this), io_service_, + app_name_), + forwarder_interface_(connector_) {} + + /** + * Set the consumer callback. + * + * @param consumer_callback - The pointer to the ConsumerCallback object. + */ + void setConsumerCallback(ConsumerCallback *consumer_callback) { + consumer_callback_ = consumer_callback; + } + + /** + * Set the producer callback. + * + * @param producer_callback - The pointer to the ProducerCallback object. + */ + void setProducerCallback(ProducerCallback *producer_callback) { + producer_callback_ = producer_callback; + } + + /** + * Specify the output interface to use. This method will be useful in a future + * scenario where the library will be able to forward packets without + * connecting to a local forwarder. Now it is not used. + * + * @param output_interface - The output interface to use for + * forwarding/receiving packets. + */ + TRANSPORT_ALWAYS_INLINE void setOutputInterface( + const std::string &output_interface) { + forwarder_interface_.setOutputInterface(output_interface); + } + + /** + * Connect the transport to the local hicn forwarder. + * + * @param is_consumer - Boolean specifying if the application on top of portal + * is a consumer or a producer. + */ + TRANSPORT_ALWAYS_INLINE void connect(bool is_consumer = true) { + pending_interest_hash_table_.reserve(portal_details::pool_size); + forwarder_interface_.connect(is_consumer); + } + + /** + * Destructor. + */ + ~Portal() { killConnection(); } + + /** + * Check if there is already a pending interest for a given name. + * + * @param name - The interest name. + */ + TRANSPORT_ALWAYS_INLINE bool interestIsPending(const Name &name) { + auto it = + pending_interest_hash_table_.find(name.getHash32() + name.getSuffix()); + if (it != pending_interest_hash_table_.end()) { + return true; + } + + return false; + } + + /** + * Send an interest through to the local forwarder. + * + * @param interest - The pointer to the interest. The ownership of the + * interest is transferred by the caller to portal. + * + * @param on_content_object_callback - If the caller wishes to use a different + * callback to be called for this interest, it can set this parameter. + * Otherwise ConsumerCallback::onContentObject will be used. + * + * @param on_interest_timeout_callback - If the caller wishes to use a + * different callback to be called for this interest, it can set this + * parameter. Otherwise ConsumerCallback::onTimeout will be used. + */ + TRANSPORT_ALWAYS_INLINE void sendInterest( + Interest::Ptr &&interest, + OnContentObjectCallback &&on_content_object_callback = UNSET_CALLBACK, + OnInterestTimeoutCallback &&on_interest_timeout_callback = + UNSET_CALLBACK) { + uint32_t hash = + interest->getName().getHash32() + interest->getName().getSuffix(); + // Send it + forwarder_interface_.send(*interest); + + auto pending_interest = packet_pool_.getPendingInterest(); + pending_interest->setInterest(std::move(interest)); + pending_interest->setOnContentObjectCallback( + std::move(on_content_object_callback)); + pending_interest->setOnTimeoutCallback( + std::move(on_interest_timeout_callback)); + pending_interest->startCountdown(portal_details::makeCustomAllocatorHandler( + async_callback_memory_, std::bind(&Portal::timerHandler, + this, std::placeholders::_1, hash))); + + auto it = pending_interest_hash_table_.find(hash); + if (it != pending_interest_hash_table_.end()) { + it->second->cancelTimer(); + + // Get reference to interest packet in order to have it destroyed. + auto _int = it->second->getInterest(); + it->second = std::move(pending_interest); + } else { + pending_interest_hash_table_[hash] = std::move(pending_interest); + } + } + + /** + * Handler fot the timer set when the interest is sent. + * + * @param ec - Error code which says whether the timer expired or has been + * canceled upon data packet reception. + * + * @param hash - The index of the interest in the pending interest hash table. + */ + TRANSPORT_ALWAYS_INLINE void timerHandler(const std::error_code &ec, + uint32_t hash) { + bool is_stopped = io_service_.stopped(); + if (TRANSPORT_EXPECT_FALSE(is_stopped)) { + return; + } + + if (TRANSPORT_EXPECT_TRUE(!ec)) { + PendingInterestHashTable::iterator it = + pending_interest_hash_table_.find(hash); + if (it != pending_interest_hash_table_.end()) { + PendingInterest::Ptr ptr = std::move(it->second); + pending_interest_hash_table_.erase(it); + auto _int = ptr->getInterest(); + + if (ptr->getOnTimeoutCallback() != UNSET_CALLBACK) { + ptr->on_interest_timeout_callback_(std::move(_int)); + } else if (consumer_callback_) { + consumer_callback_->onTimeout(std::move(_int)); + } + } + } + } + + /** + * Register a producer name to the local forwarder and optionally set the + * content store size in a per-face manner. + * + * @param config - The configuration for the local forwarder binding. + */ + TRANSPORT_ALWAYS_INLINE void bind(const BindConfig &config) { + forwarder_interface_.setContentStoreSize(config.csReserved()); + served_namespaces_.push_back(config.prefix()); + + setLocalRoutes(); + } + + /** + * Start the event loop. This function blocks here and calls the callback set + * by the application upon interest/data received or timeout. + */ + TRANSPORT_ALWAYS_INLINE void runEventsLoop() { + if (io_service_.stopped()) { + io_service_.reset(); // ensure that run()/poll() will do some work + } + + io_service_.run(); + } + + /** + * Run one event and return. + */ + TRANSPORT_ALWAYS_INLINE void runOneEvent() { + if (io_service_.stopped()) { + io_service_.reset(); // ensure that run()/poll() will do some work + } + + io_service_.run_one(); + } + + /** + * Send a data packet to the local forwarder. As opposite to sendInterest, the + * ownership of the content object is not transferred to the portal. + * + * @param content_object - The data packet. + */ + TRANSPORT_ALWAYS_INLINE void sendContentObject( + ContentObject &content_object) { + forwarder_interface_.send(content_object); + } + + /** + * Stop the event loop, canceling all the pending events in the event queue. + * + * Beware that stopping the event loop DOES NOT disconnect the transport from + * the local forwarder, the connector underneath will stay connected. + */ + TRANSPORT_ALWAYS_INLINE void stopEventsLoop() { + if (!io_service_.stopped()) { + io_service_.dispatch([this]() { + clear(); + io_service_.stop(); + }); + } + } + + /** + * Disconnect the transport from the local forwarder. + */ + TRANSPORT_ALWAYS_INLINE void killConnection() { + forwarder_interface_.closeConnection(); + } + + /** + * Clear the pending interest hash table. + */ + TRANSPORT_ALWAYS_INLINE void clear() { + if (!io_service_.stopped()) { + io_service_.dispatch(std::bind(&Portal::doClear, this)); + } else { + doClear(); + } + } + + /** + * Get a reference to the io_service object. + */ + TRANSPORT_ALWAYS_INLINE asio::io_service &getIoService() { + return io_service_; + } + + /** + * Register a route to the local forwarder. + */ + TRANSPORT_ALWAYS_INLINE void registerRoute(Prefix &prefix) { + served_namespaces_.push_back(prefix); + if (connector_.isConnected()) { + forwarder_interface_.registerRoute(prefix); + } + } + + private: + /** + * Clear the pending interest hash table. + */ + TRANSPORT_ALWAYS_INLINE void doClear() { + for (auto &pend_interest : pending_interest_hash_table_) { + pend_interest.second->cancelTimer(); + + // Get interest packet from pending interest and do nothing with it. It + // will get destroyed as it goes out of scope. + auto _int = pend_interest.second->getInterest(); + } + + pending_interest_hash_table_.clear(); + } + + /** + * Callback called by the underlying connector upon reception of a packet from + * the local forwarder. + * + * @param packet_buffer - The bytes of the packet. + */ + TRANSPORT_ALWAYS_INLINE void processIncomingMessages( + Packet::MemBufPtr &&packet_buffer) { + bool is_stopped = io_service_.stopped(); + if (TRANSPORT_EXPECT_FALSE(is_stopped)) { + return; + } + + if (TRANSPORT_EXPECT_FALSE( + ForwarderInt::isControlMessage(packet_buffer->data()))) { + processControlMessage(std::move(packet_buffer)); + return; + } + + Packet::Format format = Packet::getFormatFromBuffer(packet_buffer->data()); + + if (TRANSPORT_EXPECT_TRUE(_is_tcp(format))) { + if (!Packet::isInterest(packet_buffer->data())) { + auto content_object = packet_pool_.getContentObject(); + content_object->replace(std::move(packet_buffer)); + processContentObject(std::move(content_object)); + } else { + auto interest = packet_pool_.getInterest(); + interest->replace(std::move(packet_buffer)); + processInterest(std::move(interest)); + } + } else { + TRANSPORT_LOGE("Received not supported packet. Ignoring it."); + } + } + + /** + * Callback called by the transport upon connection to the local forwarder. + * It register the prefixes in the served_namespaces_ list to the local + * forwarder. + */ + TRANSPORT_ALWAYS_INLINE void setLocalRoutes() { + for (auto &prefix : served_namespaces_) { + if (connector_.isConnected()) { + forwarder_interface_.registerRoute(prefix); + } + } + } + + TRANSPORT_ALWAYS_INLINE void processInterest(Interest::Ptr &&interest) { + // Interest for a producer + if (TRANSPORT_EXPECT_TRUE(producer_callback_ != nullptr)) { + producer_callback_->onInterest(std::move(interest)); + } + } + + /** + * Process a content object: + * - Check if the data packet was effectively requested by portal + * - Delete its timer + * - Pass packet to application + * + * @param content_object - The data packet + */ + TRANSPORT_ALWAYS_INLINE void processContentObject( + ContentObject::Ptr &&content_object) { + uint32_t hash = content_object->getName().getHash32() + + content_object->getName().getSuffix(); + + auto it = pending_interest_hash_table_.find(hash); + if (it != pending_interest_hash_table_.end()) { + PendingInterest::Ptr interest_ptr = std::move(it->second); + pending_interest_hash_table_.erase(it); + interest_ptr->cancelTimer(); + auto _int = interest_ptr->getInterest(); + + if (interest_ptr->getOnDataCallback() != UNSET_CALLBACK) { + interest_ptr->on_content_object_callback_(std::move(_int), + std::move(content_object)); + } else if (consumer_callback_) { + consumer_callback_->onContentObject(std::move(_int), + std::move(content_object)); + } + } + } + + /** + * Process a control message. Control messages are different depending on the + * connector, then the forwarder_interface will do the job of understanding + * them. + */ + TRANSPORT_ALWAYS_INLINE void processControlMessage( + Packet::MemBufPtr &&packet_buffer) { + forwarder_interface_.processControlMessageReply(std::move(packet_buffer)); + } + + private: + asio::io_service &io_service_; + asio::io_service internal_io_service_; + portal_details::Pool packet_pool_; + + std::string app_name_; + + PendingInterestHashTable pending_interest_hash_table_; + std::list served_namespaces_; + + ConsumerCallback *consumer_callback_; + ProducerCallback *producer_callback_; + + portal_details::HandlerMemory async_callback_memory_; + + typename ForwarderInt::ConnectorType connector_; + ForwarderInt forwarder_interface_; +}; + +} // namespace core + +} // end namespace transport diff --git a/libtransport/src/core/prefix.cc b/libtransport/src/core/prefix.cc new file mode 100644 index 000000000..59898ab70 --- /dev/null +++ b/libtransport/src/core/prefix.cc @@ -0,0 +1,338 @@ +/* + * 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. + */ + +#include +#include +#include + +#ifndef _WIN32 +extern "C" { +#include +} +#else +#include +#endif + +#include +#include +#include + +#include + +namespace transport { + +namespace core { + +Prefix::Prefix() { std::memset(&ip_prefix_, 0, sizeof(ip_prefix_t)); } + +Prefix::Prefix(const char *prefix) : Prefix(std::string(prefix)) {} + +Prefix::Prefix(std::string &&prefix) : Prefix(prefix) {} + +Prefix::Prefix(const std::string &prefix) { + utils::StringTokenizer st(prefix, "/"); + + std::string ip_address = st.nextToken(); + int family = get_addr_family(ip_address.c_str()); + + std::string prefix_length = family == AF_INET6 ? "128" : "32"; + + if (st.hasMoreTokens()) { + prefix_length = st.nextToken(); + } + + buildPrefix(ip_address, uint16_t(atoi(prefix_length.c_str())), family); +} + +Prefix::Prefix(std::string &prefix, uint16_t prefix_length) { + int family = get_addr_family(prefix.c_str()); + buildPrefix(prefix, prefix_length, family); +} + +Prefix::Prefix(const core::Name &content_name, uint16_t prefix_length) { + int family = content_name.getAddressFamily(); + + if (!checkPrefixLengthAndAddressFamily(prefix_length, family)) { + throw errors::InvalidIpAddressException(); + } + + ip_prefix_ = content_name.toIpAddress(); + ip_prefix_.len = prefix_length; + ip_prefix_.family = family; +} + +void Prefix::buildPrefix(std::string &prefix, uint16_t prefix_length, + int family) { + if (!checkPrefixLengthAndAddressFamily(prefix_length, family)) { + throw errors::InvalidIpAddressException(); + } + + int ret; + switch (family) { + case AF_INET: + ret = inet_pton(AF_INET, prefix.c_str(), ip_prefix_.address.v4.buffer); + break; + case AF_INET6: + ret = inet_pton(AF_INET6, prefix.c_str(), ip_prefix_.address.v6.buffer); + break; + default: + throw errors::InvalidIpAddressException(); + } + + if (ret != 1) { + throw errors::InvalidIpAddressException(); + } + + ip_prefix_.len = prefix_length; + ip_prefix_.family = family; +} + +std::unique_ptr Prefix::toSockaddr() { + Sockaddr *ret = nullptr; + + switch (ip_prefix_.family) { + case AF_INET6: + ret = (Sockaddr *)new Sockaddr6; + break; + case AF_INET: + ret = (Sockaddr *)new Sockaddr4; + break; + default: + throw errors::InvalidIpAddressException(); + } + + if (ip_prefix_to_sockaddr(&ip_prefix_, ret) < 0) { + throw errors::InvalidIpAddressException(); + } + + return std::unique_ptr(ret); +} + +uint16_t Prefix::getPrefixLength() { return ip_prefix_.len; } + +Prefix &Prefix::setPrefixLength(uint16_t prefix_length) { + ip_prefix_.len = prefix_length; + return *this; +} + +int Prefix::getAddressFamily() { return ip_prefix_.family; } + +Prefix &Prefix::setAddressFamily(int address_family) { + ip_prefix_.family = address_family; + return *this; +} + +std::string Prefix::getNetwork() const { + if (!checkPrefixLengthAndAddressFamily(ip_prefix_.len, ip_prefix_.family)) { + throw errors::InvalidIpAddressException(); + } + + std::size_t size = + ip_prefix_.family == 4 + AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN; + + std::string network(size, 0); + + if (ip_prefix_ntop_short(&ip_prefix_, (char *)network.c_str(), size) < 0) { + throw errors::RuntimeException( + "Impossible to retrieve network from ip address."); + } + + return network; +} + +int Prefix::contains(const ip_address_t &content_name) const { + int res = + ip_address_cmp(&content_name, &(ip_prefix_.address), ip_prefix_.family); + + if (ip_prefix_.len != (ip_prefix_.family == AF_INET6 ? IPV6_ADDR_LEN_BITS + : IPV4_ADDR_LEN_BITS)) { + const u8 *ip_prefix_buffer = + ip_address_get_buffer(&(ip_prefix_.address), ip_prefix_.family); + const u8 *content_name_buffer = + ip_address_get_buffer(&content_name, ip_prefix_.family); + uint8_t mask = 0xFF >> (ip_prefix_.len % 8); + mask = ~mask; + + res += (ip_prefix_buffer[ip_prefix_.len] & mask) == + (content_name_buffer[ip_prefix_.len] & mask); + } + + return res; +} + +int Prefix::contains(const core::Name &content_name) const { + return contains(content_name.toIpAddress().address); +} + +Name Prefix::getName() const { + std::string s(getNetwork()); + return Name(s); +} + +/* + * Mask is used to apply the components to a content name that belong to this + * prefix + */ +Name Prefix::getName(const core::Name &mask, const core::Name &components, + const core::Name &content_name) const { + if (ip_prefix_.family != mask.getAddressFamily() || + ip_prefix_.family != components.getAddressFamily() || + ip_prefix_.family != content_name.getAddressFamily()) + throw errors::RuntimeException( + "Prefix, mask, components and content name are not of the same address " + "family"); + + ip_address_t mask_ip = mask.toIpAddress().address; + ip_address_t component_ip = components.toIpAddress().address; + ip_address_t name_ip = content_name.toIpAddress().address; + const u8 *mask_ip_buffer = ip_address_get_buffer(&mask_ip, ip_prefix_.family); + const u8 *component_ip_buffer = + ip_address_get_buffer(&component_ip, ip_prefix_.family); + u8 *name_ip_buffer = + const_cast(ip_address_get_buffer(&name_ip, ip_prefix_.family)); + + int addr_len = ip_prefix_.family == AF_INET6 ? IPV6_ADDR_LEN : IPV4_ADDR_LEN; + + for (int i = 0; i < addr_len; i++) { + if (mask_ip_buffer[i]) { + name_ip_buffer[i] = component_ip_buffer[i] & mask_ip_buffer[i]; + } + } + + if (this->contains(name_ip)) + throw errors::RuntimeException("Mask overrides the prefix"); + return Name(ip_prefix_.family, (uint8_t *)&name_ip); +} + +Name Prefix::getRandomName() const { + ip_address_t name_ip = ip_prefix_.address; + u8 *name_ip_buffer = + const_cast(ip_address_get_buffer(&name_ip, ip_prefix_.family)); + + int addr_len = + (ip_prefix_.family == AF_INET6 ? IPV6_ADDR_LEN * 8 : IPV4_ADDR_LEN * 8) - + ip_prefix_.len; + + size_t size = (size_t)ceil((float)addr_len / 8.0); + uint8_t buffer[size]; + + RAND_bytes(buffer, size); + + int j = 0; + for (uint8_t i = (uint8_t)ceil((float)ip_prefix_.len / 8.0); + i < (ip_prefix_.family == AF_INET6 ? IPV6_ADDR_LEN : IPV4_ADDR_LEN); + i++) { + name_ip_buffer[i] = buffer[j]; + j++; + } + + return Name(ip_prefix_.family, (uint8_t *)&name_ip); +} + +/* + * Map a name in a different name prefix to this name prefix + */ +Name Prefix::mapName(const core::Name &content_name) const { + if (ip_prefix_.family != content_name.getAddressFamily()) + throw errors::RuntimeException( + "Prefix content name are not of the same address " + "family"); + + ip_address_t name_ip = content_name.toIpAddress().address; + const u8 *ip_prefix_buffer = + ip_address_get_buffer(&(ip_prefix_.address), ip_prefix_.family); + u8 *name_ip_buffer = + const_cast(ip_address_get_buffer(&name_ip, ip_prefix_.family)); + + memcpy(name_ip_buffer, ip_prefix_buffer, ip_prefix_.len / 8); + + if (ip_prefix_.len != (ip_prefix_.family == AF_INET6 ? IPV6_ADDR_LEN_BITS + : IPV4_ADDR_LEN_BITS)) { + uint8_t mask = 0xFF >> (ip_prefix_.len % 8); + name_ip_buffer[ip_prefix_.len / 8 + 1] = + (name_ip_buffer[ip_prefix_.len / 8 + 1] & mask) | + (ip_prefix_buffer[ip_prefix_.len / 8 + 1] & ~mask); + } + + return Name(ip_prefix_.family, (uint8_t *)&name_ip); +} + +Prefix &Prefix::setNetwork(std::string &network) { + if (!inet_pton(AF_INET6, network.c_str(), ip_prefix_.address.v6.buffer)) { + throw errors::RuntimeException("The network name is not valid."); + } + + return *this; +} + +Name Prefix::makeRandomName() const { + srand((unsigned int)time(nullptr)); + + if (ip_prefix_.family == AF_INET6) { + std::default_random_engine eng((std::random_device())()); + std::uniform_int_distribution idis( + 0, std::numeric_limits::max()); + uint64_t random_number = idis(eng); + + uint32_t hash_size_bits = IPV6_ADDR_LEN_BITS - ip_prefix_.len; + uint64_t ip_address[2]; + memcpy(ip_address, ip_prefix_.address.v6.buffer, sizeof(uint64_t)); + memcpy(ip_address + 1, ip_prefix_.address.v6.buffer + 8, sizeof(uint64_t)); + std::string network(IPV6_ADDR_LEN * 3, 0); + + // Let's do the magic ;) + int shift_size = hash_size_bits > sizeof(random_number) * 8 + ? sizeof(random_number) * 8 + : hash_size_bits; + + ip_address[1] >>= shift_size; + ip_address[1] <<= shift_size; + + ip_address[1] |= random_number >> (sizeof(uint64_t) * 8 - shift_size); + + if (!inet_ntop(ip_prefix_.family, ip_address, (char *)network.c_str(), + IPV6_ADDR_LEN * 3)) { + throw errors::RuntimeException( + "Impossible to retrieve network from ip address."); + } + + return Name(network); + } + + return Name(); +} + +bool Prefix::checkPrefixLengthAndAddressFamily(uint16_t prefix_length, + int family) { + // First check the family + if (family != AF_INET6 && family != AF_INET) { + return false; + } + + int max_addr_len_bits = + family == AF_INET6 ? IPV6_ADDR_LEN_BITS : IPV4_ADDR_LEN_BITS; + + if (prefix_length > max_addr_len_bits) { + return false; + } + + return true; +} + +ip_prefix_t &Prefix::toIpPrefixStruct() { return ip_prefix_; } + +} // namespace core + +} // namespace transport diff --git a/libtransport/src/core/raw_socket_connector.cc b/libtransport/src/core/raw_socket_connector.cc new file mode 100644 index 000000000..4d780959b --- /dev/null +++ b/libtransport/src/core/raw_socket_connector.cc @@ -0,0 +1,203 @@ +/* + * 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. + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#define MY_DEST_MAC0 0x0a +#define MY_DEST_MAC1 0x7b +#define MY_DEST_MAC2 0x7c +#define MY_DEST_MAC3 0x1c +#define MY_DEST_MAC4 0x4a +#define MY_DEST_MAC5 0x14 + +namespace transport { + +namespace core { + +RawSocketConnector::RawSocketConnector( + PacketReceivedCallback &&receive_callback, + OnReconnect &&on_reconnect_callback, asio::io_service &io_service, + std::string app_name) + : Connector(std::move(receive_callback), std::move(on_reconnect_callback)), + io_service_(io_service), + socket_(io_service_, raw_protocol(PF_PACKET, SOCK_RAW)), + // resolver_(io_service_), + timer_(io_service_), + read_msg_(packet_pool_.makePtr(nullptr)), + data_available_(false), + app_name_(app_name) { + memset(&link_layer_address_, 0, sizeof(link_layer_address_)); +} + +RawSocketConnector::~RawSocketConnector() {} + +void RawSocketConnector::connect(const std::string &interface_name, + const std::string &mac_address_str) { + state_ = ConnectorState::CONNECTING; + memset(ðernet_header_, 0, sizeof(ethernet_header_)); + struct ifreq ifr; + struct ifreq if_mac; + uint8_t mac_address[6]; + + utils::convertStringToMacAddress(mac_address_str, mac_address); + + // Get interface mac address + int fd = static_cast(socket_.native_handle()); + + /* Get the index of the interface to send on */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_name, interface_name.c_str(), interface_name.size()); + + // if (ioctl(fd, SIOCGIFINDEX, &if_idx) < 0) { + // perror("SIOCGIFINDEX"); + // } + + /* Get the MAC address of the interface to send on */ + memset(&if_mac, 0, sizeof(struct ifreq)); + strncpy(if_mac.ifr_name, interface_name.c_str(), interface_name.size()); + if (ioctl(fd, SIOCGIFHWADDR, &if_mac) < 0) { + perror("SIOCGIFHWADDR"); + throw errors::RuntimeException("Interface does not exist"); + } + + /* Ethernet header */ + for (int i = 0; i < 6; i++) { + ethernet_header_.ether_shost[i] = + ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[i]; + ethernet_header_.ether_dhost[i] = mac_address[i]; + } + + /* Ethertype field */ + ethernet_header_.ether_type = htons(ETH_P_IPV6); + + strcpy(ifr.ifr_name, interface_name.c_str()); + + if (0 == ioctl(fd, SIOCGIFHWADDR, &ifr)) { + memcpy(link_layer_address_.sll_addr, ifr.ifr_hwaddr.sa_data, 6); + } + + // memset(&ifr, 0, sizeof(ifr)); + // ioctl(fd, SIOCGIFFLAGS, &ifr); + // ifr.ifr_flags |= IFF_PROMISC; + // ioctl(fd, SIOCSIFFLAGS, &ifr); + + link_layer_address_.sll_family = AF_PACKET; + link_layer_address_.sll_protocol = htons(ETH_P_ALL); + link_layer_address_.sll_ifindex = if_nametoindex(interface_name.c_str()); + link_layer_address_.sll_hatype = 1; + link_layer_address_.sll_halen = 6; + + // startConnectionTimer(); + doConnect(); + doRecvPacket(); +} + +void RawSocketConnector::send(const uint8_t *packet, std::size_t len, + const PacketSentCallback &packet_sent) { + if (packet_sent != 0) { + socket_.async_send( + asio::buffer(packet, len), + [packet_sent](std::error_code ec, std::size_t /*length*/) { + packet_sent(); + }); + } else { + if (state_ == ConnectorState::CONNECTED) { + socket_.send(asio::buffer(packet, len)); + } + } +} + +void RawSocketConnector::send(const Packet::MemBufPtr &packet) { + io_service_.post([this, packet]() { + bool write_in_progress = !output_buffer_.empty(); + output_buffer_.push_back(std::move(packet)); + if (TRANSPORT_EXPECT_TRUE(state_ == ConnectorState::CONNECTED)) { + if (!write_in_progress) { + doSendPacket(); + } else { + // Tell the handle connect it has data to write + data_available_ = true; + } + } + }); +} + +void RawSocketConnector::close() { + io_service_.post([this]() { socket_.close(); }); +} + +void RawSocketConnector::doSendPacket() { + auto packet = output_buffer_.front().get(); + auto array = std::vector(); + + const utils::MemBuf *current = packet; + do { + array.push_back(asio::const_buffer(current->data(), current->length())); + current = current->next(); + } while (current != packet); + + socket_.async_send( + std::move(array), + [this /*, packet*/](std::error_code ec, std::size_t bytes_transferred) { + if (TRANSPORT_EXPECT_TRUE(!ec)) { + output_buffer_.pop_front(); + if (!output_buffer_.empty()) { + doSendPacket(); + } + } else { + TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str()); + } + }); +} + +void RawSocketConnector::doRecvPacket() { + read_msg_ = getPacket(); + socket_.async_receive( + asio::buffer(read_msg_->writableData(), packet_size), + [this](std::error_code ec, std::size_t bytes_transferred) mutable { + if (!ec) { + // Ignore packets that are not for us + uint8_t *dst_mac_address = const_cast(read_msg_->data()); + if (!std::memcmp(dst_mac_address, ethernet_header_.ether_shost, + ETHER_ADDR_LEN)) { + read_msg_->append(bytes_transferred); + read_msg_->trimStart(sizeof(struct ether_header)); + receive_callback_(std::move(read_msg_)); + } + } else { + TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str()); + } + doRecvPacket(); + }); +} + +void RawSocketConnector::doConnect() { + state_ = ConnectorState::CONNECTED; + socket_.bind(raw_endpoint(&link_layer_address_, sizeof(link_layer_address_))); +} + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/core/raw_socket_connector.h b/libtransport/src/core/raw_socket_connector.h new file mode 100644 index 000000000..1d4e9cb39 --- /dev/null +++ b/libtransport/src/core/raw_socket_connector.h @@ -0,0 +1,81 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +namespace transport { + +namespace core { + +using asio::generic::raw_protocol; +using raw_endpoint = asio::generic::basic_endpoint; + +class RawSocketConnector : public Connector { + public: + RawSocketConnector(PacketReceivedCallback &&receive_callback, + OnReconnect &&reconnect_callback, + asio::io_service &io_service, + std::string app_name = "Libtransport"); + + ~RawSocketConnector() override; + + void send(const Packet::MemBufPtr &packet) override; + + void send(const uint8_t *packet, std::size_t len, + const PacketSentCallback &packet_sent = 0) override; + + void close() override; + + void connect(const std::string &interface_name, + const std::string &mac_address_str); + + private: + void doConnect(); + + void doRecvPacket(); + + void doSendPacket(); + + private: + asio::io_service &io_service_; + raw_protocol::socket socket_; + + struct ether_header ethernet_header_; + + struct sockaddr_ll link_layer_address_; + + asio::steady_timer timer_; + + utils::ObjectPool::Ptr read_msg_; + + bool data_available_; + std::string app_name_; +}; + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/core/raw_socket_interface.cc b/libtransport/src/core/raw_socket_interface.cc new file mode 100644 index 000000000..7ee2a844d --- /dev/null +++ b/libtransport/src/core/raw_socket_interface.cc @@ -0,0 +1,57 @@ +/* + * 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. + */ + +#include + +#include + +#include + +namespace transport { + +namespace core { + +static std::string config_folder_path = "/etc/transport/interface.conf.d"; + +RawSocketInterface::RawSocketInterface(RawSocketConnector &connector) + : ForwarderInterface(connector) {} + +RawSocketInterface::~RawSocketInterface() {} + +void RawSocketInterface::connect(bool is_consumer) { + std::string complete_filename = + config_folder_path + std::string("/") + output_interface_; + + std::ifstream is(complete_filename); + std::string interface; + + if (is) { + is >> remote_mac_address_; + } + + // Get interface ip address + struct sockaddr_in6 address = {0}; + utils::retrieveInterfaceAddress(output_interface_, &address); + + std::memcpy(&inet6_address_.v6.as_u8, &address.sin6_addr, + sizeof(address.sin6_addr)); + connector_.connect(output_interface_, remote_mac_address_); +} + +void RawSocketInterface::registerRoute(Prefix &prefix) { return; } + +} // namespace core + +} // namespace transport diff --git a/libtransport/src/core/raw_socket_interface.h b/libtransport/src/core/raw_socket_interface.h new file mode 100644 index 000000000..c06d14637 --- /dev/null +++ b/libtransport/src/core/raw_socket_interface.h @@ -0,0 +1,62 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include +#include + +#include +#include + +namespace transport { + +namespace core { + +class RawSocketInterface + : public ForwarderInterface { + public: + typedef RawSocketConnector ConnectorType; + + RawSocketInterface(RawSocketConnector &connector); + + ~RawSocketInterface(); + + void connect(bool is_consumer); + + void registerRoute(Prefix &prefix); + + std::uint16_t getMtu() { return interface_mtu; } + + TRANSPORT_ALWAYS_INLINE static bool isControlMessageImpl( + const uint8_t *message) { + return false; + } + + TRANSPORT_ALWAYS_INLINE void processControlMessageReplyImpl( + Packet::MemBufPtr &&packet_buffer) {} + + TRANSPORT_ALWAYS_INLINE void closeConnection(){}; + + private: + static constexpr std::uint16_t interface_mtu = 1500; + std::string remote_mac_address_; +}; + +} // namespace core + +} // namespace transport diff --git a/libtransport/src/core/tcp_socket_connector.cc b/libtransport/src/core/tcp_socket_connector.cc new file mode 100644 index 000000000..58df8fb08 --- /dev/null +++ b/libtransport/src/core/tcp_socket_connector.cc @@ -0,0 +1,282 @@ +/* + * 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. + */ + +#include +#ifdef _WIN32 +#include +#endif + +#include +#include +#include + +#include +#include + +namespace transport { + +namespace core { + +namespace { +class NetworkMessage { + public: + static constexpr std::size_t fixed_header_length = 10; + + static std::size_t decodeHeader(const uint8_t *packet) { + // General checks + // CCNX Control packet format + uint8_t first_byte = packet[0]; + uint8_t ip_format = (packet[0] & 0xf0) >> 4; + + if (TRANSPORT_EXPECT_FALSE(first_byte == 102)) { + // Get packet length + return 44; + } else if (TRANSPORT_EXPECT_TRUE(ip_format == 6 || ip_format == 4)) { + Packet::Format format = Packet::getFormatFromBuffer(packet); + return Packet::getHeaderSizeFromBuffer(format, packet) + + Packet::getPayloadSizeFromBuffer(format, packet); + } + + return 0; + } +}; +} // namespace + +TcpSocketConnector::TcpSocketConnector( + PacketReceivedCallback &&receive_callback, + OnReconnect &&on_reconnect_callback, asio::io_service &io_service, + std::string app_name) + : Connector(std::move(receive_callback), std::move(on_reconnect_callback)), + io_service_(io_service), + socket_(io_service_), + resolver_(io_service_), + timer_(io_service_), + read_msg_(packet_pool_.makePtr(nullptr)), + is_reconnection_(false), + data_available_(false), + app_name_(app_name) {} + +TcpSocketConnector::~TcpSocketConnector() {} + +void TcpSocketConnector::connect(std::string ip_address, std::string port) { + endpoint_iterator_ = resolver_.resolve( + {ip_address, port, asio::ip::resolver_query_base::numeric_service}); + + state_ = ConnectorState::CONNECTING; + doConnect(); +} + +void TcpSocketConnector::send(const uint8_t *packet, std::size_t len, + const PacketSentCallback &packet_sent) { + if (packet_sent != 0) { + asio::async_write(socket_, asio::buffer(packet, len), + [packet_sent](std::error_code ec, + std::size_t /*length*/) { packet_sent(); }); + } else { + if (state_ == ConnectorState::CONNECTED) { + asio::write(socket_, asio::buffer(packet, len)); + } + } +} + +void TcpSocketConnector::send(const Packet::MemBufPtr &packet) { + io_service_.post([this, packet]() { + bool write_in_progress = !output_buffer_.empty(); + output_buffer_.push_back(std::move(packet)); + if (TRANSPORT_EXPECT_TRUE(state_ == ConnectorState::CONNECTED)) { + if (!write_in_progress) { + doWrite(); + } + } else { + // Tell the handle connect it has data to write + data_available_ = true; + } + }); +} + +void TcpSocketConnector::close() { + if (state_ != ConnectorState::CLOSED) { + state_ = ConnectorState::CLOSED; + if (socket_.is_open()) { + socket_.shutdown(asio::ip::tcp::socket::shutdown_type::shutdown_both); + socket_.close(); + } + } +} + +void TcpSocketConnector::doWrite() { +#if 1 + auto array = std::vector(); + std::vector packet_store(packet_store_size); + uint8_t i = 0; + + utils::MemBuf *packet = nullptr; + const utils::MemBuf *current = nullptr; + // Send vectors of 32 packets + while (!output_buffer_.empty() && i++ < packet_store_size) { + packet_store[i] = output_buffer_.front(); + output_buffer_.pop_front(); + packet = packet_store[i].get(); + current = packet; + do { + array.push_back(asio::const_buffer(current->data(), current->length())); + current = current->next(); + } while (current != packet); + } +#else + auto packet = output_buffer_.front().get(); + auto array = std::vector(); + + const utils::MemBuf *current = packet; + do { + array.push_back(asio::const_buffer(current->data(), current->length())); + current = current->next(); + } while (current != packet); +#endif + + asio::async_write( + socket_, std::move(array), + [this, packet_store = std::move(packet_store)](std::error_code ec, + std::size_t length) { + if (TRANSPORT_EXPECT_TRUE(!ec)) { + if (!output_buffer_.empty()) { + doWrite(); + } + } else if (ec.value() == + static_cast(std::errc::operation_canceled)) { + // The connection has been closed by the application. + return; + } else { + TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str()); + tryReconnect(); + } + }); +} + +void TcpSocketConnector::doReadBody(std::size_t body_length) { + asio::async_read( + socket_, asio::buffer(read_msg_->writableTail(), body_length), + asio::transfer_exactly(body_length), + [this](std::error_code ec, std::size_t length) { + read_msg_->append(length); + if (TRANSPORT_EXPECT_TRUE(!ec)) { + receive_callback_(std::move(read_msg_)); + doReadHeader(); + } else if (ec.value() == + static_cast(std::errc::operation_canceled)) { + // The connection has been closed by the application. + return; + } else { + TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str()); + tryReconnect(); + } + }); +} + +void TcpSocketConnector::doReadHeader() { + read_msg_ = getPacket(); + asio::async_read( + socket_, + asio::buffer(read_msg_->writableData(), + NetworkMessage::fixed_header_length), + asio::transfer_exactly(NetworkMessage::fixed_header_length), + [this](std::error_code ec, std::size_t length) { + if (TRANSPORT_EXPECT_TRUE(!ec)) { + read_msg_->append(NetworkMessage::fixed_header_length); + std::size_t body_length = 0; + if ((body_length = NetworkMessage::decodeHeader(read_msg_->data())) > + 0) { + doReadBody(body_length - length); + } else { + TRANSPORT_LOGE("Decoding error. Ignoring packet."); + } + } else if (ec.value() == + static_cast(std::errc::operation_canceled)) { + // The connection has been closed by the application. + return; + } else { + TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str()); + tryReconnect(); + } + }); +} + +void TcpSocketConnector::tryReconnect() { + if (state_ == ConnectorState::CONNECTED) { + TRANSPORT_LOGE("Connection lost. Trying to reconnect...\n"); + state_ = ConnectorState::CONNECTING; + is_reconnection_ = true; + io_service_.post([this]() { + if (socket_.is_open()) { + socket_.shutdown(asio::ip::tcp::socket::shutdown_type::shutdown_both); + socket_.close(); + } + startConnectionTimer(); + doConnect(); + }); + } +} + +void TcpSocketConnector::doConnect() { + asio::async_connect( + socket_, endpoint_iterator_, + [this](std::error_code ec, tcp::resolver::iterator) { + if (!ec) { + timer_.cancel(); + state_ = ConnectorState::CONNECTED; + asio::ip::tcp::no_delay noDelayOption(true); + socket_.set_option(noDelayOption); + doReadHeader(); + + if (data_available_) { + data_available_ = false; + doWrite(); + } + + if (is_reconnection_) { + is_reconnection_ = false; + TRANSPORT_LOGI("Connection recovered!\n"); + on_reconnect_callback_(); + } + } else { + doConnect(); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + }); +} + +bool TcpSocketConnector::checkConnected() { + return state_ == ConnectorState::CONNECTED; +} + +void TcpSocketConnector::startConnectionTimer() { + timer_.expires_from_now(std::chrono::seconds(60)); + timer_.async_wait(std::bind(&TcpSocketConnector::handleDeadline, this, + std::placeholders::_1)); +} + +void TcpSocketConnector::handleDeadline(const std::error_code &ec) { + if (!ec) { + io_service_.post([this]() { + socket_.close(); + TRANSPORT_LOGE("Error connecting. Is the forwarder running?\n"); + io_service_.stop(); + }); + } +} + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/core/tcp_socket_connector.h b/libtransport/src/core/tcp_socket_connector.h new file mode 100644 index 000000000..c57123e9f --- /dev/null +++ b/libtransport/src/core/tcp_socket_connector.h @@ -0,0 +1,87 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include + +#include + +#include +#include +#include + +namespace transport { +namespace core { + +using asio::ip::tcp; + +class TcpSocketConnector : public Connector { + static constexpr uint16_t packet_store_size = 32; + + public: + TcpSocketConnector(PacketReceivedCallback &&receive_callback, + OnReconnect &&reconnect_callback, + asio::io_service &io_service, + std::string app_name = "Libtransport"); + + ~TcpSocketConnector() override; + + void send(const Packet::MemBufPtr &packet) override; + + void send(const uint8_t *packet, std::size_t len, + const PacketSentCallback &packet_sent = 0) override; + + void close() override; + + void connect(std::string ip_address = "127.0.0.1", std::string port = "9695"); + + private: + void doConnect(); + + void doReadHeader(); + + void doReadBody(std::size_t body_length); + + void doWrite(); + + bool checkConnected(); + + private: + void handleDeadline(const std::error_code &ec); + + void startConnectionTimer(); + + void tryReconnect(); + + asio::io_service &io_service_; + asio::ip::tcp::socket socket_; + asio::ip::tcp::resolver resolver_; + asio::ip::tcp::resolver::iterator endpoint_iterator_; + asio::steady_timer timer_; + + utils::ObjectPool::Ptr read_msg_; + + bool is_reconnection_; + bool data_available_; + + std::string app_name_; +}; + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/core/test/CMakeLists.txt b/libtransport/src/core/test/CMakeLists.txt new file mode 100644 index 000000000..48c50e9b0 --- /dev/null +++ b/libtransport/src/core/test/CMakeLists.txt @@ -0,0 +1,10 @@ +# Enable gcov output for the tests +add_definitions(--coverage) +set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage") + +set(TestsExpectedToPass + test_core_manifest) + +foreach(test ${TestsExpectedToPass}) + AddTest(${test}) +endforeach() \ No newline at end of file diff --git a/libtransport/src/core/test/test_core_manifest.cc b/libtransport/src/core/test/test_core_manifest.cc new file mode 100644 index 000000000..58563d8f9 --- /dev/null +++ b/libtransport/src/core/test/test_core_manifest.cc @@ -0,0 +1,296 @@ +/* + * 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. + */ + +#include + +#include "../manifest_format_fixed.h" +#include "../manifest_inline.h" + +#include +#include +#include + +namespace transport { + +namespace core { + +namespace { +// The fixture for testing class Foo. +class ManifestTest : public ::testing::Test { + protected: + using ContentObjectManifest = ManifestInline; + + ManifestTest() : name_("b001::123|321"), manifest1_(name_) { + // You can do set-up work for each test here. + } + + virtual ~ManifestTest() { + // You can do clean-up work that doesn't throw exceptions here. + } + + // If the constructor and destructor are not enough for setting up + // and cleaning up each test, you can define the following methods: + + virtual void SetUp() { + // Code here will be called immediately after the constructor (right + // before each test). + } + + virtual void TearDown() { + // Code here will be called immediately after each test (right + // before the destructor). + } + + Name name_; + ContentObjectManifest manifest1_; + + std::vector manifest_payload = { + 0x11, 0x11, 0x01, 0x00, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad // , 0x00, 0x00, + // 0x00, 0x45, 0xa3, + // 0xd1, 0xf2, 0x2b, + // 0x94, 0x41, 0x22, + // 0xc9, 0x00, 0x00, + // 0x00, 0x44, 0xa3, + // 0xd1, 0xf2, 0x2b, + // 0x94, 0x41, 0x22, + // 0xc8 + }; +}; + +} // namespace + +TEST_F(ManifestTest, ManifestCreate) { + ContentObjectManifest manifest2(name_); + ContentObjectManifest manifest3 = manifest2; + + EXPECT_EQ(manifest1_, manifest2); + EXPECT_EQ(manifest1_, manifest3); +} + +TEST_F(ManifestTest, ManifestCreateFromBase) { + ContentObject content_object(name_); + content_object.setPayload(manifest_payload.data(), manifest_payload.size()); + ContentObjectManifest manifest(std::move(content_object)); + + auto manifest4 = ContentObjectManifest::createManifest( + name_, core::ManifestVersion::VERSION_1, + core::ManifestType::INLINE_MANIFEST, HashAlgorithm::SHA_256, true, + core::Name("b001::dead"), + core::NextSegmentCalculationStrategy::INCREMENTAL, 128); + + manifest4->encode(); + manifest4->dump(); + manifest.dump(); + + EXPECT_EQ(manifest1_, manifest); + // EXPECT_EQ(manifest1_, manifest3); +} + +TEST_F(ManifestTest, SetLastManifest) { + manifest1_.clear(); + + manifest1_.setFinalManifest(true); + manifest1_.encode(); + manifest1_.decode(); + bool fcn = manifest1_.isFinalManifest(); + + ASSERT_TRUE(fcn); +} + +TEST_F(ManifestTest, SetManifestType) { + manifest1_.clear(); + + ManifestType type1 = ManifestType::INLINE_MANIFEST; + ManifestType type2 = ManifestType::FLIC_MANIFEST; + + manifest1_.setManifestType(type1); + manifest1_.encode(); + manifest1_.decode(); + ManifestType type_returned1 = manifest1_.getManifestType(); + + manifest1_.clear(); + + manifest1_.setManifestType(type2); + manifest1_.encode(); + manifest1_.decode(); + ManifestType type_returned2 = manifest1_.getManifestType(); + + ASSERT_EQ(type1, type_returned1); + ASSERT_EQ(type2, type_returned2); +} + +TEST_F(ManifestTest, SetHashAlgorithm) { + manifest1_.clear(); + + HashAlgorithm hash1 = HashAlgorithm::SHA_512; + HashAlgorithm hash2 = HashAlgorithm::CRC32C; + HashAlgorithm hash3 = HashAlgorithm::SHA_256; + + manifest1_.setHashAlgorithm(hash1); + manifest1_.encode(); + manifest1_.decode(); + HashAlgorithm type_returned1 = manifest1_.getHashAlgorithm(); + + manifest1_.clear(); + + manifest1_.setHashAlgorithm(hash2); + manifest1_.encode(); + manifest1_.decode(); + HashAlgorithm type_returned2 = manifest1_.getHashAlgorithm(); + + manifest1_.clear(); + + manifest1_.setHashAlgorithm(hash3); + manifest1_.encode(); + manifest1_.decode(); + HashAlgorithm type_returned3 = manifest1_.getHashAlgorithm(); + + ASSERT_EQ(hash1, type_returned1); + ASSERT_EQ(hash2, type_returned2); + ASSERT_EQ(hash3, type_returned3); +} + +TEST_F(ManifestTest, SetNextSegmentCalculationStrategy) { + manifest1_.clear(); + + NextSegmentCalculationStrategy strategy1 = + NextSegmentCalculationStrategy::INCREMENTAL; + + manifest1_.setNextSegmentCalculationStrategy(strategy1); + manifest1_.encode(); + manifest1_.decode(); + NextSegmentCalculationStrategy type_returned1 = + manifest1_.getNextSegmentCalculationStrategy(); + + ASSERT_EQ(strategy1, type_returned1); +} + +TEST_F(ManifestTest, SetBaseName) { + manifest1_.clear(); + + core::Name base_name("b001::dead"); + manifest1_.setBaseName(base_name); + manifest1_.encode(); + manifest1_.decode(); + core::Name ret_name = manifest1_.getBaseName(); + + ASSERT_EQ(base_name, ret_name); +} + +TEST_F(ManifestTest, SetSuffixList) { + manifest1_.clear(); + + core::Name base_name("b001::dead"); + + using random_bytes_engine = + std::independent_bits_engine; + random_bytes_engine rbe; + + std::default_random_engine eng((std::random_device())()); + std::uniform_int_distribution idis( + 0, std::numeric_limits::max()); + + auto entries = new std::pair[3]; + uint32_t suffixes[3]; + std::vector data[3]; + + for (int i = 0; i < 3; i++) { + data[i].resize(32); + std::generate(std::begin(data[i]), std::end(data[i]), std::ref(rbe)); + suffixes[i] = idis(eng); + entries[i] = std::make_pair( + suffixes[i], utils::CryptoHash(data[i].data(), data[i].size(), + utils::CryptoHashType::SHA_256)); + manifest1_.addSuffixHash(entries[i].first, entries[i].second); + } + + manifest1_.setBaseName(base_name); + + manifest1_.encode(); + manifest1_.decode(); + + core::Name ret_name = manifest1_.getBaseName(); + + // auto & hash_list = manifest1_.getSuffixHashList(); + + bool cond; + int i = 0; + + // for (auto & item : manifest1_.getSuffixList()) { + // auto hash = manifest1_.getHash(suffixes[i]); + // cond = utils::CryptoHash::compareBinaryDigest(hash, + // entries[i].second.getDigest().data(), + // entries[i].second.getType()); + // ASSERT_TRUE(cond); + // i++; + // } + + ASSERT_EQ(base_name, ret_name); + + delete[] entries; +} + +TEST_F(ManifestTest, EstimateSize) { + manifest1_.clear(); + + HashAlgorithm hash1 = HashAlgorithm::SHA_256; + NextSegmentCalculationStrategy strategy1 = + NextSegmentCalculationStrategy::INCREMENTAL; + ManifestType type1 = ManifestType::INLINE_MANIFEST; + core::Name base_name1("b001:abcd:fede:baba:cece:d0d0:face:dead"); + + manifest1_.setFinalManifest(true); + manifest1_.setBaseName(base_name1); + manifest1_.setNextSegmentCalculationStrategy(strategy1); + manifest1_.setHashAlgorithm(hash1); + manifest1_.setManifestType(type1); + + std::default_random_engine eng((std::random_device())()); + std::uniform_int_distribution idis( + 0, std::numeric_limits::max()); + + using random_bytes_engine = + std::independent_bits_engine; + random_bytes_engine rbe; + + while (manifest1_.estimateManifestSize(1) < 1440) { + uint32_t suffix = static_cast(idis(eng)); + std::vector data(32); + std::generate(std::begin(data), std::end(data), std::ref(rbe)); + auto hash = utils::CryptoHash(data.data(), data.size(), + utils::CryptoHashType::SHA_256); + manifest1_.addSuffixHash(suffix, hash); + } + + manifest1_.encode(); + manifest1_.decode(); + + manifest1_.dump(); + + ASSERT_GT(manifest1_.estimateManifestSize(), 0); + ASSERT_LT(manifest1_.estimateManifestSize(), 1500); +} + +} // namespace core + +} // namespace transport + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/libtransport/src/core/udp_socket_connector.cc b/libtransport/src/core/udp_socket_connector.cc new file mode 100644 index 000000000..ec59c2e64 --- /dev/null +++ b/libtransport/src/core/udp_socket_connector.cc @@ -0,0 +1,224 @@ +/* + * 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. + */ + +#ifdef _WIN32 +#include +#endif + +#include +#include +#include + +#include + +#include +#include + +namespace transport { + +namespace core { + +UdpSocketConnector::UdpSocketConnector( + PacketReceivedCallback &&receive_callback, + OnReconnect &&on_reconnect_callback, asio::io_service &io_service, + std::string app_name) + : Connector(std::move(receive_callback), std::move(on_reconnect_callback)), + io_service_(io_service), + socket_(io_service_), + resolver_(io_service_), + connection_timer_(io_service_), + read_msg_(packet_pool_.makePtr(nullptr)), + is_reconnection_(false), + data_available_(false), + app_name_(app_name) {} + +UdpSocketConnector::~UdpSocketConnector() {} + +void UdpSocketConnector::connect(std::string ip_address, std::string port) { + endpoint_iterator_ = resolver_.resolve( + {ip_address, port, asio::ip::resolver_query_base::numeric_service}); + + state_ = ConnectorState::CONNECTING; + doConnect(); +} + +void UdpSocketConnector::send(const uint8_t *packet, std::size_t len, + const PacketSentCallback &packet_sent) { + if (packet_sent != 0) { + socket_.async_send( + asio::buffer(packet, len), + [packet_sent](std::error_code ec, std::size_t /*length*/) { + packet_sent(); + }); + } else { + if (state_ == ConnectorState::CONNECTED) { + try { + socket_.send(asio::buffer(packet, len)); + } catch (std::system_error &err) { + TRANSPORT_LOGE( + "Sending of disconnect message to forwarder failed. Reason: %s", + err.what()); + } + } + } +} + +void UdpSocketConnector::send(const Packet::MemBufPtr &packet) { + io_service_.post([this, packet]() { + bool write_in_progress = !output_buffer_.empty(); + output_buffer_.push_back(std::move(packet)); + if (TRANSPORT_EXPECT_TRUE(state_ == ConnectorState::CONNECTED)) { + if (!write_in_progress) { + doWrite(); + } + } else { + // Tell the handle connect it has data to write + data_available_ = true; + } + }); +} + +void UdpSocketConnector::close() { + if (io_service_.stopped()) { + doClose(); + } else { + io_service_.dispatch(std::bind(&UdpSocketConnector::doClose, this)); + } +} + +void UdpSocketConnector::doClose() { + if (state_ != ConnectorState::CLOSED) { + state_ = ConnectorState::CLOSED; + if (socket_.is_open()) { + socket_.shutdown(asio::ip::tcp::socket::shutdown_type::shutdown_both); + socket_.close(); + } + } +} + +void UdpSocketConnector::doWrite() { + auto packet = output_buffer_.front().get(); + auto array = std::vector(); + + const utils::MemBuf *current = packet; + do { + array.push_back(asio::const_buffer(current->data(), current->length())); + current = current->next(); + } while (current != packet); + + socket_.async_send(std::move(array), [this](std::error_code ec, + std::size_t length) { + if (TRANSPORT_EXPECT_TRUE(!ec)) { + output_buffer_.pop_front(); + if (!output_buffer_.empty()) { + doWrite(); + } + } else if (ec.value() == static_cast(std::errc::operation_canceled)) { + // The connection has been closed by the application. + return; + } else { + TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str()); + tryReconnect(); + } + }); +} + +void UdpSocketConnector::doRead() { + read_msg_ = getPacket(); + socket_.async_receive( + asio::buffer(read_msg_->writableData(), Connector::packet_size), + [this](std::error_code ec, std::size_t length) { + if (TRANSPORT_EXPECT_TRUE(!ec)) { + read_msg_->append(length); + receive_callback_(std::move(read_msg_)); + doRead(); + } else if (ec.value() == + static_cast(std::errc::operation_canceled)) { + // The connection has been closed by the application. + return; + } else { + TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str()); + tryReconnect(); + } + }); +} + +void UdpSocketConnector::tryReconnect() { + if (state_ == ConnectorState::CONNECTED) { + TRANSPORT_LOGE("Connection lost. Trying to reconnect...\n"); + state_ = ConnectorState::CONNECTING; + is_reconnection_ = true; + io_service_.post([this]() { + if (socket_.is_open()) { + socket_.shutdown(asio::ip::tcp::socket::shutdown_type::shutdown_both); + socket_.close(); + } + + doConnect(); + startConnectionTimer(); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + }); + } +} + +void UdpSocketConnector::doConnect() { + asio::async_connect( + socket_, endpoint_iterator_, + [this](std::error_code ec, udp::resolver::iterator) { + if (!ec) { + connection_timer_.cancel(); + state_ = ConnectorState::CONNECTED; + doRead(); + + if (data_available_) { + data_available_ = false; + doWrite(); + } + + if (is_reconnection_) { + is_reconnection_ = false; + } + + on_reconnect_callback_(); + } else { + doConnect(); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + }); +} + +bool UdpSocketConnector::checkConnected() { + return state_ == ConnectorState::CONNECTED; +} + +void UdpSocketConnector::startConnectionTimer() { + connection_timer_.expires_from_now(std::chrono::seconds(60)); + connection_timer_.async_wait(std::bind(&UdpSocketConnector::handleDeadline, + this, std::placeholders::_1)); +} + +void UdpSocketConnector::handleDeadline(const std::error_code &ec) { + if (!ec) { + io_service_.post([this]() { + socket_.close(); + TRANSPORT_LOGE("Error connecting. Is the forwarder running?\n"); + io_service_.stop(); + }); + } +} + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/core/udp_socket_connector.h b/libtransport/src/core/udp_socket_connector.h new file mode 100644 index 000000000..5fdb6aeec --- /dev/null +++ b/libtransport/src/core/udp_socket_connector.h @@ -0,0 +1,85 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include + +#include + +#include +#include +#include + +namespace transport { +namespace core { + +using asio::ip::udp; + +class UdpSocketConnector : public Connector { + public: + UdpSocketConnector(PacketReceivedCallback &&receive_callback, + OnReconnect &&reconnect_callback, + asio::io_service &io_service, + std::string app_name = "Libtransport"); + + ~UdpSocketConnector() override; + + void send(const Packet::MemBufPtr &packet) override; + + void send(const uint8_t *packet, std::size_t len, + const PacketSentCallback &packet_sent = 0) override; + + void close() override; + + void connect(std::string ip_address = "127.0.0.1", std::string port = "9695"); + + private: + void doConnect(); + + void doRead(); + + void doWrite(); + + void doClose(); + + bool checkConnected(); + + private: + void handleDeadline(const std::error_code &ec); + + void startConnectionTimer(); + + void tryReconnect(); + + asio::io_service &io_service_; + asio::ip::udp::socket socket_; + asio::ip::udp::resolver resolver_; + asio::ip::udp::resolver::iterator endpoint_iterator_; + asio::steady_timer connection_timer_; + + utils::ObjectPool::Ptr read_msg_; + + bool is_reconnection_; + bool data_available_; + + std::string app_name_; +}; + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/core/vpp_forwarder_interface.cc b/libtransport/src/core/vpp_forwarder_interface.cc new file mode 100644 index 000000000..7b4298592 --- /dev/null +++ b/libtransport/src/core/vpp_forwarder_interface.cc @@ -0,0 +1,213 @@ +/* + * 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. + */ + +#include + +#ifdef __vpp__ + +#include +#include +#include + +extern "C" { +#include +}; + +typedef enum { MASTER = 0, SLAVE = 1 } memif_role_t; + +#define MEMIF_DEFAULT_RING_SIZE 2048 +#define MEMIF_DEFAULT_RX_QUEUES 1 +#define MEMIF_DEFAULT_TX_QUEUES 1 +#define MEMIF_DEFAULT_BUFFER_SIZE 2048 + +namespace transport { + +namespace core { + +std::mutex VPPForwarderInterface::global_lock_; + +VPPForwarderInterface::VPPForwarderInterface(MemifConnector &connector) + : ForwarderInterface(connector), + sw_if_index_(~0), + face_id1_(~0), + face_id2_(~0), + is_consumer_(false) {} + +VPPForwarderInterface::~VPPForwarderInterface() {} + +/** + * @brief Create a memif interface in the local VPP forwarder. + */ +uint32_t VPPForwarderInterface::getMemifConfiguration() { + memif_create_params_t input_params = {0}; + + int ret = + memif_vapi_get_next_memif_id(VPPForwarderInterface::sock_, &memif_id_); + + if (ret < 0) { + throw errors::RuntimeException( + "Error getting next memif id. Could not create memif interface."); + } + + input_params.id = memif_id_; + input_params.role = memif_role_t::MASTER; + input_params.mode = memif_interface_mode_t::MEMIF_INTERFACE_MODE_IP; + input_params.rx_queues = MEMIF_DEFAULT_RX_QUEUES; + input_params.tx_queues = MEMIF_DEFAULT_TX_QUEUES; + input_params.ring_size = MEMIF_DEFAULT_RING_SIZE; + input_params.buffer_size = MEMIF_DEFAULT_BUFFER_SIZE; + + memif_output_params_t output_params = {0}; + + ret = memif_vapi_create_memif(VPPForwarderInterface::sock_, &input_params, + &output_params); + + if (ret < 0) { + throw errors::RuntimeException( + "Error creating memif interface in the local VPP forwarder."); + } + + return output_params.sw_if_index; +} + +void VPPForwarderInterface::consumerConnection() { + hicn_consumer_input_params input = {0}; + hicn_consumer_output_params output = {0}; + ip_address_t ip4_address; + ip_address_t ip6_address; + + output.src4 = &ip4_address; + output.src6 = &ip6_address; + input.swif = sw_if_index_; + + int ret = hicn_vapi_register_cons_app(VPPForwarderInterface::sock_, &input, + &output); + + if (ret < 0) { + throw errors::RuntimeException(hicn_vapi_get_error_string(ret)); + } + + face_id1_ = output.face_id1; + face_id2_ = output.face_id2; + + std::memcpy(inet_address_.v4.as_u8, output.src4->v4.as_u8, IPV4_ADDR_LEN); + + std::memcpy(inet6_address_.v6.as_u8, output.src6->v6.as_u8, IPV6_ADDR_LEN); +} + +void VPPForwarderInterface::producerConnection() { + // Producer connection will be set when we set the first route. +} + +void VPPForwarderInterface::connect(bool is_consumer) { + std::lock_guard connection_lock(global_lock_); + + vapi_connect_safe(&sock_, 0); + + sw_if_index_ = getMemifConfiguration(); + + is_consumer_ = is_consumer; + if (is_consumer_) { + consumerConnection(); + } + + connector_.connect(memif_id_, 0); +} + +void VPPForwarderInterface::registerRoute(Prefix &prefix) { + ip_prefix_t &addr = prefix.toIpPrefixStruct(); + + ip_prefix_t producer_prefix; + ip_address_t producer_locator; + + if (face_id1_ == uint32_t(~0)) { + hicn_producer_input_params input; + std::memset(&input, 0, sizeof(input)); + + hicn_producer_output_params output; + std::memset(&output, 0, sizeof(output)); + + input.prefix = &producer_prefix; + output.prod_addr = &producer_locator; + + // Here we have to ask to the actual connector what is the + // memif_id, since this function should be called after the + // memif creation. + input.swif = sw_if_index_; + input.prefix->address = addr.address; + input.prefix->family = addr.family; + input.prefix->len = addr.len; + input.cs_reserved = content_store_reserved_; + + int ret = hicn_vapi_register_prod_app(VPPForwarderInterface::sock_, &input, + &output); + + if (ret < 0) { + throw errors::RuntimeException(hicn_vapi_get_error_string(ret)); + } + + inet6_address_ = *output.prod_addr; + + face_id1_ = output.face_id; + } else { + hicn_producer_set_route_params params; + params.prefix = &producer_prefix; + params.prefix->address = addr.address; + params.prefix->family = addr.family; + params.prefix->len = addr.len; + params.face_id = face_id1_; + + int ret = hicn_vapi_register_route(VPPForwarderInterface::sock_, ¶ms); + + if (ret < 0) { + throw errors::RuntimeException(hicn_vapi_get_error_string(ret)); + } + } +} + +void VPPForwarderInterface::closeConnection() { + if (VPPForwarderInterface::sock_) { + connector_.close(); + + if (is_consumer_) { + hicn_del_face_app_input_params params; + params.face_id = face_id1_; + hicn_vapi_face_cons_del(VPPForwarderInterface::sock_, ¶ms); + params.face_id = face_id2_; + hicn_vapi_face_cons_del(VPPForwarderInterface::sock_, ¶ms); + } else { + hicn_del_face_app_input_params params; + params.face_id = face_id1_; + hicn_vapi_face_prod_del(VPPForwarderInterface::sock_, ¶ms); + } + + if (sw_if_index_ != uint32_t(~0)) { + int ret = + memif_vapi_delete_memif(VPPForwarderInterface::sock_, sw_if_index_); + if (ret < 0) { + TRANSPORT_LOGE("Error deleting memif with sw idx %u.", sw_if_index_); + } + } + + vapi_disconnect_safe(); + VPPForwarderInterface::sock_ = nullptr; + } +} + +} // namespace core + +} // namespace transport + +#endif diff --git a/libtransport/src/core/vpp_forwarder_interface.h b/libtransport/src/core/vpp_forwarder_interface.h new file mode 100644 index 000000000..eb759f8bc --- /dev/null +++ b/libtransport/src/core/vpp_forwarder_interface.h @@ -0,0 +1,88 @@ +/* + * 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. + */ + +#pragma once + +#include + +#ifdef __vpp__ + +#include + +#ifdef always_inline +#undef always_inline +#endif +extern "C" { +#include +}; + +#include +#include + +#include + +namespace transport { + +namespace core { + +class VPPForwarderInterface + : public ForwarderInterface { + static constexpr std::uint16_t interface_mtu = 1500; + + public: + VPPForwarderInterface(MemifConnector &connector); + + typedef MemifConnector ConnectorType; + + ~VPPForwarderInterface(); + + void connect(bool is_consumer); + + void registerRoute(Prefix &prefix); + + TRANSPORT_ALWAYS_INLINE std::uint16_t getMtu() { return interface_mtu; } + + TRANSPORT_ALWAYS_INLINE static bool isControlMessageImpl( + const uint8_t *message) { + return false; + } + + TRANSPORT_ALWAYS_INLINE void processControlMessageReplyImpl( + Packet::MemBufPtr &&packet_buffer) {} + + void closeConnection(); + + private: + uint32_t getMemifConfiguration(); + + void consumerConnection(); + + void producerConnection(); + + uint32_t memif_id_; + uint32_t sw_if_index_; + // A consumer socket in vpp has two faces (ipv4 and ipv6) + uint32_t face_id1_; + uint32_t face_id2_; + bool is_consumer_; + vapi_ctx_t sock_; + static std::mutex global_lock_; +}; + +} // namespace core + +} // namespace transport + +#endif diff --git a/libtransport/src/hicn/transport/CMakeLists.txt b/libtransport/src/hicn/transport/CMakeLists.txt deleted file mode 100644 index 4bdb3c1e7..000000000 --- a/libtransport/src/hicn/transport/CMakeLists.txt +++ /dev/null @@ -1,92 +0,0 @@ -# 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) - -include(GNUInstallDirs) - -set(ASIO_STANDALONE 1) - -add_subdirectory(core) -add_subdirectory(errors) -add_subdirectory(http) -add_subdirectory(interfaces) -add_subdirectory(portability) -add_subdirectory(protocols) -add_subdirectory(utils) - -include(Packager) -extract_version() -configure_file("config.h.in" "config.h" @ONLY) -install( - FILES ${CMAKE_CURRENT_BINARY_DIR}/config.h - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hicn/transport - COMPONENT lib${LIBTRANSPORT}-dev -) - -set (COMPILER_DEFINITIONS "-DTRANSPORT_LOG_DEF_LEVEL=TRANSPORT_LOG_${TRANSPORT_LOG_LEVEL}") - -list(INSERT LIBTRANSPORT_INTERNAL_INCLUDE_DIRS 0 - ${CMAKE_CURRENT_SOURCE_DIR}/../.. - ${CMAKE_CURRENT_BINARY_DIR}/../.. -) - -set(LIBTRANSPORT_INCLUDE_DIRS - ${CMAKE_CURRENT_SOURCE_DIR}/../../ - ${CMAKE_CURRENT_BINARY_DIR}/../../ - "" CACHE INTERNAL - "" FORCE -) - -if (NOT WIN32) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") -else () - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4200") - if (CMAKE_BUILD_TYPE EQUAL "RELEASE") - set(CMAKE_SHARED_LINKER_FLAGS "/NODEFAULTLIB:\"MSVCRTD\"" ) - endif () -endif () -if (${CMAKE_SYSTEM_NAME} STREQUAL "Android") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -isystem -lm") -endif() - -if (DISABLE_SHARED_LIBRARIES) - build_library(${LIBTRANSPORT} - STATIC - SOURCES ${SOURCE_FILES} ${HEADER_FILES} - INSTALL_HEADERS ${HEADER_FILES} - LINK_LIBRARIES ${LIBRARIES} - DEPENDS ${DEPENDENCIES} - COMPONENT lib${LIBTRANSPORT} - INCLUDE_DIRS ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS} - INSTALL_ROOT_DIR hicn/transport - DEFINITIONS ${COMPILER_DEFINITIONS} - ) -else () - build_library(${LIBTRANSPORT} - STATIC SHARED - SOURCES ${SOURCE_FILES} ${HEADER_FILES} - INSTALL_HEADERS ${HEADER_FILES} - LINK_LIBRARIES ${LIBRARIES} - DEPENDS ${DEPENDENCIES} - COMPONENT lib${LIBTRANSPORT} - INCLUDE_DIRS ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS} - INSTALL_ROOT_DIR hicn/transport - DEFINITIONS ${COMPILER_DEFINITIONS} - ) -endif () - -if (${COMPILE_TESTS}) - add_subdirectory(core/test) - add_subdirectory(transport/test) -endif() diff --git a/libtransport/src/hicn/transport/config.h.in b/libtransport/src/hicn/transport/config.h.in deleted file mode 100644 index 4e9a0f262..000000000 --- a/libtransport/src/hicn/transport/config.h.in +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#cmakedefine TRANSPORT_HAVE_PTHREAD 1 - -#define HICNTRANSPORT_VERSION_MAJOR "@VERSION_MAJOR@" -#define HICNTRANSPORT_VERSION_MINOR "@VERSION_MINOR@" -#define HICNTRANSPORT_VERSION_REVISION "@VERSION_REVISION@" - -#ifndef ASIO_STANDALONE -#cmakedefine ASIO_STANDALONE -#endif - -#ifndef SECURE_HICNTRANSPORT -#cmakedefine SECURE_HICNTRANSPORT -#endif - -#define RAAQM_CONFIG_PATH "@raaqm_config_path@" - -#cmakedefine __vpp__ diff --git a/libtransport/src/hicn/transport/core/CMakeLists.txt b/libtransport/src/hicn/transport/core/CMakeLists.txt deleted file mode 100644 index 8439fdf45..000000000 --- a/libtransport/src/hicn/transport/core/CMakeLists.txt +++ /dev/null @@ -1,82 +0,0 @@ -# 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) - -list(APPEND HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/content_object.h - ${CMAKE_CURRENT_SOURCE_DIR}/facade.h - ${CMAKE_CURRENT_SOURCE_DIR}/interest.h - ${CMAKE_CURRENT_SOURCE_DIR}/manifest.h - ${CMAKE_CURRENT_SOURCE_DIR}/manifest_inline.h - ${CMAKE_CURRENT_SOURCE_DIR}/manifest_format_fixed.h - ${CMAKE_CURRENT_SOURCE_DIR}/manifest_format.h - ${CMAKE_CURRENT_SOURCE_DIR}/name.h - ${CMAKE_CURRENT_SOURCE_DIR}/packet.h - ${CMAKE_CURRENT_SOURCE_DIR}/payload_type.h - ${CMAKE_CURRENT_SOURCE_DIR}/pending_interest.h - ${CMAKE_CURRENT_SOURCE_DIR}/portal.h - ${CMAKE_CURRENT_SOURCE_DIR}/prefix.h - ${CMAKE_CURRENT_SOURCE_DIR}/connector.h - ${CMAKE_CURRENT_SOURCE_DIR}/tcp_socket_connector.h - ${CMAKE_CURRENT_SOURCE_DIR}/udp_socket_connector.h - ${CMAKE_CURRENT_SOURCE_DIR}/forwarder_interface.h - ${CMAKE_CURRENT_SOURCE_DIR}/hicn_forwarder_interface.h - ${CMAKE_CURRENT_SOURCE_DIR}/vpp_forwarder_interface.h - ${CMAKE_CURRENT_SOURCE_DIR}/memif_connector.h -) - -list(APPEND SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/content_object.cc - ${CMAKE_CURRENT_SOURCE_DIR}/interest.cc - ${CMAKE_CURRENT_SOURCE_DIR}/pending_interest.cc - ${CMAKE_CURRENT_SOURCE_DIR}/packet.cc - ${CMAKE_CURRENT_SOURCE_DIR}/name.cc - ${CMAKE_CURRENT_SOURCE_DIR}/prefix.cc - ${CMAKE_CURRENT_SOURCE_DIR}/tcp_socket_connector.cc - ${CMAKE_CURRENT_SOURCE_DIR}/udp_socket_connector.cc - ${CMAKE_CURRENT_SOURCE_DIR}/hicn_forwarder_interface.cc - ${CMAKE_CURRENT_SOURCE_DIR}/manifest_format_fixed.cc - ${CMAKE_CURRENT_SOURCE_DIR}/connector.cc -) - -if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") - if (BUILD_WITH_VPP OR BUILD_HICNPLUGIN) - list(APPEND HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/vpp_forwarder_interface.h - ${CMAKE_CURRENT_SOURCE_DIR}/memif_connector.h - ${CMAKE_CURRENT_SOURCE_DIR}/hicn_vapi.h - ${CMAKE_CURRENT_SOURCE_DIR}/memif_vapi.h - ) - - list(APPEND SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/vpp_forwarder_interface.cc - ${CMAKE_CURRENT_SOURCE_DIR}/memif_connector.cc - ${CMAKE_CURRENT_SOURCE_DIR}/hicn_vapi.c - ${CMAKE_CURRENT_SOURCE_DIR}/memif_vapi.c - ) - endif() - - list(APPEND HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/raw_socket_connector.h - ${CMAKE_CURRENT_SOURCE_DIR}/raw_socket_interface.h - ) - - list(APPEND SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/raw_socket_connector.cc - ${CMAKE_CURRENT_SOURCE_DIR}/raw_socket_interface.cc - ) -endif() - -set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) -set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/connector.cc b/libtransport/src/hicn/transport/core/connector.cc deleted file mode 100644 index fc271574c..000000000 --- a/libtransport/src/hicn/transport/core/connector.cc +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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. - */ - -#include - -namespace transport { - -namespace core { - -std::once_flag Connector::init_flag_; - -Connector::Connector(PacketReceivedCallback &&receive_callback, - OnReconnect &&reconnect_callback) - : packet_pool_(), - receive_callback_(std::move(receive_callback)), - on_reconnect_callback_(std::move(reconnect_callback)), - state_(ConnectorState::CLOSED) { - init(); -} - -void Connector::init() { increasePoolSize(); } - -void Connector::increasePoolSize(std::size_t size) { - // Allocate space for receiving packets - const auto capacity = packet_size * size; - uint8_t *buffer = static_cast(malloc(capacity)); - std::unique_ptr buffer0 = - utils::MemBuf::takeOwnership(buffer, capacity, 0, nullptr, nullptr, true); - - for (std::size_t i = 1; i < size; i++) { - auto b = buffer0->cloneOne(); - b->advance(i * packet_size); - packet_pool_.add(b.release()); - } -} - -} // end namespace core - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/connector.h b/libtransport/src/hicn/transport/core/connector.h deleted file mode 100644 index f2bbe5dcd..000000000 --- a/libtransport/src/hicn/transport/core/connector.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include -#include - -#include -#include - -namespace transport { - -namespace core { - -enum class ConnectorType : uint8_t { - SOCKET_CONNECTOR, - RAW_SOCKET_CONNECTOR, - VPP_CONNECTOR, -}; - -class Connector { - protected: - enum class ConnectorState { - CLOSED, - CONNECTING, - CONNECTED, - }; - - public: - static constexpr std::size_t packet_size = 2048; - static constexpr std::size_t queue_size = 4096; - static constexpr std::size_t packet_pool_size = 4096; - - using PacketRing = utils::CircularFifo; - using PacketQueue = std::deque; - using PacketReceivedCallback = std::function; - using OnReconnect = std::function; - using PacketSentCallback = std::function; - - Connector(PacketReceivedCallback &&receive_callback, - OnReconnect &&reconnect_callback); - - virtual ~Connector(){}; - - virtual void send(const Packet::MemBufPtr &packet) = 0; - - virtual void send(const uint8_t *packet, std::size_t len, - const PacketSentCallback &packet_sent = 0) = 0; - - virtual void close() = 0; - - virtual ConnectorState state() { return state_; }; - - virtual bool isConnected() { return state_ == ConnectorState::CONNECTED; } - - protected: - void increasePoolSize(std::size_t size = packet_pool_size); - - TRANSPORT_ALWAYS_INLINE utils::ObjectPool::Ptr getPacket() { - auto result = packet_pool_.get(); - - while (TRANSPORT_EXPECT_FALSE(!result.first)) { - // Add packets to the pool - increasePoolSize(); - result = packet_pool_.get(); - } - - if (result.second->isChained()) { - result.second->separateChain(result.second->next(), - result.second->prev()); - } - - result.second->trimEnd(result.second->length()); - return std::move(result.second); - } - - private: - void init(); - - protected: - static std::once_flag init_flag_; - utils::ObjectPool packet_pool_; - PacketQueue output_buffer_; - - // Connector events - PacketReceivedCallback receive_callback_; - OnReconnect on_reconnect_callback_; - - // Connector state - ConnectorState state_; -}; -} // end namespace core - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/content_object.cc b/libtransport/src/hicn/transport/core/content_object.cc deleted file mode 100644 index 6cbcdb29e..000000000 --- a/libtransport/src/hicn/transport/core/content_object.cc +++ /dev/null @@ -1,201 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include - -extern "C" { -#ifndef _WIN32 -TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat") -#endif -#include -#include -} - -#include -#include - -namespace transport { - -namespace core { - -ContentObject::ContentObject(const Name &name, Packet::Format format) - : Packet(format) { - if (TRANSPORT_EXPECT_FALSE( - hicn_data_set_name(format, packet_start_, &name.name_) < 0)) { - throw errors::RuntimeException("Error filling the packet name."); - } - - if (TRANSPORT_EXPECT_FALSE(hicn_data_get_name(format_, packet_start_, - name_.getStructReference()) < - 0)) { - throw errors::MalformedPacketException(); - } -} - -#ifdef __ANDROID__ -ContentObject::ContentObject(hicn_format_t format) - : ContentObject(Name("0::0|0"), format) {} -#else -ContentObject::ContentObject(hicn_format_t format) - : ContentObject(Packet::base_name, format) {} -#endif - -ContentObject::ContentObject(const Name &name, hicn_format_t format, - const uint8_t *payload, std::size_t size) - : ContentObject(name, format) { - appendPayload(payload, size); -} - -ContentObject::ContentObject(const uint8_t *buffer, std::size_t size) - : Packet(buffer, size) { - if (hicn_data_get_name(format_, packet_start_, name_.getStructReference()) < - 0) { - throw errors::RuntimeException("Error getting name from content object."); - } -} - -ContentObject::ContentObject(MemBufPtr &&buffer) : Packet(std::move(buffer)) { - if (hicn_data_get_name(format_, packet_start_, name_.getStructReference()) < - 0) { - throw errors::RuntimeException("Error getting name from content object."); - } -} - -ContentObject::ContentObject(ContentObject &&other) : Packet(std::move(other)) { - name_ = std::move(other.name_); - - if (hicn_data_get_name(format_, packet_start_, name_.getStructReference()) < - 0) { - throw errors::MalformedPacketException(); - } -} - -ContentObject::~ContentObject() {} - -void ContentObject::replace(MemBufPtr &&buffer) { - Packet::replace(std::move(buffer)); - - if (hicn_data_get_name(format_, packet_start_, name_.getStructReference()) < - 0) { - throw errors::RuntimeException("Error getting name from content object."); - } -} - -const Name &ContentObject::getName() const { - if (!name_) { - if (hicn_data_get_name(format_, packet_start_, - (hicn_name_t *)name_.getConstStructReference()) < - 0) { - throw errors::MalformedPacketException(); - } - } - - return name_; -} - -Name &ContentObject::getWritableName() { return const_cast(getName()); } - -void ContentObject::setName(const Name &name) { - if (hicn_data_set_name(format_, packet_start_, - name.getConstStructReference()) < 0) { - throw errors::RuntimeException("Error setting content object name."); - } - - if (hicn_data_get_name(format_, packet_start_, name_.getStructReference()) < - 0) { - throw errors::MalformedPacketException(); - } -} - -void ContentObject::setName(Name &&name) { - if (hicn_data_set_name(format_, packet_start_, name.getStructReference()) < - 0) { - throw errors::RuntimeException( - "Error getting the payload length from content object."); - } - - if (hicn_data_get_name(format_, packet_start_, name_.getStructReference()) < - 0) { - throw errors::MalformedPacketException(); - } -} - -uint32_t ContentObject::getPathLabel() const { - uint32_t path_label; - if (hicn_data_get_path_label(packet_start_, &path_label) < 0) { - throw errors::RuntimeException( - "Error retrieving the path label from content object"); - } - - return path_label; -} - -ContentObject &ContentObject::setPathLabel(uint32_t path_label) { - if (hicn_data_set_path_label((hicn_header_t *)packet_start_, path_label) < - 0) { - throw errors::RuntimeException( - "Error setting the path label from content object"); - } - - return *this; -} - -void ContentObject::setLocator(const ip_address_t &ip_address) { - if (hicn_data_set_locator(format_, packet_start_, &ip_address) < 0) { - throw errors::RuntimeException("Error setting content object locator"); - } - - return; -} - -ip_address_t ContentObject::getLocator() const { - ip_address_t ip; - - if (hicn_data_get_locator(format_, packet_start_, &ip) < 0) { - throw errors::RuntimeException("Error getting content object locator."); - } - - return ip; -} - -void ContentObject::setLifetime(uint32_t lifetime) { - if (hicn_data_set_expiry_time(packet_start_, lifetime) < 0) { - throw errors::MalformedPacketException(); - } -} - -uint32_t ContentObject::getLifetime() const { - uint32_t lifetime = 0; - - if (hicn_data_get_expiry_time(packet_start_, &lifetime) < 0) { - throw errors::MalformedPacketException(); - } - - return lifetime; -} - -void ContentObject::resetForHash() { - if (hicn_data_reset_for_hash( - format_, reinterpret_cast(packet_start_)) < 0) { - throw errors::RuntimeException( - "Error resetting content object fields for hash computation."); - } -} - -} // end namespace core - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/content_object.h b/libtransport/src/hicn/transport/core/content_object.h deleted file mode 100644 index 5af548fe4..000000000 --- a/libtransport/src/hicn/transport/core/content_object.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include - -namespace transport { - -namespace core { - -// This class is used just to transfer buffer pointers -// without making a copy, as std::vector<> would do - -class ContentObject : public Packet { - public: - using Ptr = utils::ObjectPool::Ptr; - using HICNContentObject = hicn_header_t; - - ContentObject(Packet::Format format = HF_INET6_TCP); - - ContentObject(const Name &name, Packet::Format format = HF_INET6_TCP); - - ContentObject(const Name &name, hicn_format_t format, const uint8_t *payload, - std::size_t payload_size); - - ContentObject(const uint8_t *buffer, std::size_t size); - ContentObject(MemBufPtr &&buffer); - - ContentObject(const ContentObject &content_object) = delete; - - ContentObject(ContentObject &&content_object); - - ~ContentObject() override; - - void replace(MemBufPtr &&buffer) override; - - const Name &getName() const override; - - Name &getWritableName() override; - - void setName(const Name &name) override; - - void setName(Name &&name) override; - - uint32_t getPathLabel() const; - - ContentObject &setPathLabel(uint32_t path_label); - - void setLocator(const ip_address_t &ip_address) override; - - ip_address_t getLocator() const override; - - void setLifetime(uint32_t lifetime) override; - - uint32_t getLifetime() const override; - - private: - void resetForHash() override; -}; - -} // end namespace core - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/facade.h b/libtransport/src/hicn/transport/core/facade.h deleted file mode 100644 index 27e738e62..000000000 --- a/libtransport/src/hicn/transport/core/facade.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include -#include -#include - -#ifdef __linux__ -#ifndef __ANDROID__ -#include -#ifdef __vpp__ -#include -#endif -#endif -#endif - -namespace transport { - -namespace core { - -using HicnForwarderPortal = Portal; - -#ifdef __linux__ -#ifndef __ANDROID__ -using RawSocketPortal = Portal; -#endif -#ifdef __vpp__ -using VPPForwarderPortal = Portal; -#endif -#endif - -using ContentObjectManifest = core::ManifestInline; -using InterestManifest = core::ManifestInline; - -} // namespace core - -} // namespace transport diff --git a/libtransport/src/hicn/transport/core/forwarder_interface.h b/libtransport/src/hicn/transport/core/forwarder_interface.h deleted file mode 100644 index 63b4a2eda..000000000 --- a/libtransport/src/hicn/transport/core/forwarder_interface.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include -#include -#include - -#include - -namespace transport { - -namespace core { - -typedef struct { - uint64_t rx_packets; - uint64_t tx_packets; - uint64_t rx_bytes; - uint64_t tx_bytes; - uint64_t rx_errors; - uint64_t tx_errors; -} Counters; - -template -class ForwarderInterface { - static_assert(std::is_base_of::value, - "T must inherit from connector!"); - - static constexpr uint32_t standard_cs_reserved = 5000; - - protected: - ForwarderInterface(ConnectorType &c) - : connector_(c), - inet_address_({}), - inet6_address_({}), - mtu_(1500), - output_interface_(""), - content_store_reserved_(standard_cs_reserved) { - } - - public: - virtual ~ForwarderInterface() {} - - TRANSPORT_ALWAYS_INLINE void connect(bool is_consumer = true) { - static_cast(*this).connect(is_consumer); - } - - TRANSPORT_ALWAYS_INLINE void registerRoute(Prefix &prefix) { - static_cast(*this).registerRoute(); - } - - TRANSPORT_ALWAYS_INLINE std::uint32_t getMtu() { - return static_cast(*this).getMtu(); - } - - TRANSPORT_ALWAYS_INLINE static bool isControlMessage(const uint8_t *message) { - return Implementation::isControlMessageImpl(message); - } - - template - TRANSPORT_ALWAYS_INLINE void processControlMessageReply(R &&packet_buffer) { - return static_cast(*this).processControlMessageReplyImpl( - std::forward(packet_buffer)); - } - - TRANSPORT_ALWAYS_INLINE void closeConnection() { - return static_cast(*this).closeConnection(); - } - - template < - typename R, - typename = std::enable_if_t< - std::is_base_of>::value, - R>> - TRANSPORT_ALWAYS_INLINE void send(R &&packet) { - counters_.tx_packets++; - counters_.tx_bytes += packet.payloadSize() + packet.headerSize(); - - if (_is_ipv4(packet.getFormat())) { - packet.setLocator(inet_address_); - } else { - packet.setLocator(inet6_address_); - } - - // TRANSPORT_LOGI("Sending packet %s at %lu", - // packet.getName().toString().c_str(), - // utils::SteadyClock::now().time_since_epoch().count()); - packet.setChecksum(); - connector_.send(packet.acquireMemBufReference()); - } - - TRANSPORT_ALWAYS_INLINE void send(const uint8_t *packet, std::size_t len) { - // ASIO_COMPLETION_HANDLER_CHECK(Handler, packet_sent) type_check; - counters_.tx_packets++; - counters_.tx_bytes += len; - - // Perfect forwarding - connector_.send(packet, len); - } - - TRANSPORT_ALWAYS_INLINE void shutdown() { connector_.close(); } - - TRANSPORT_ALWAYS_INLINE Connector &getConnector() { return connector_; } - - TRANSPORT_ALWAYS_INLINE void setContentStoreSize(uint32_t cs_size) { - content_store_reserved_ = cs_size; - } - - TRANSPORT_ALWAYS_INLINE uint32_t getContentStoreSize() const { - return content_store_reserved_; - } - - TRANSPORT_ALWAYS_INLINE void setOutputInterface( - const std::string &interface) { - output_interface_ = interface; - } - - TRANSPORT_ALWAYS_INLINE std::string &getOutputInterface() { - return output_interface_; - } - - protected: - ConnectorType &connector_; - ip_address_t inet_address_; - ip_address_t inet6_address_; - uint16_t mtu_; - std::string output_interface_; - uint32_t content_store_reserved_; - Counters counters_; -}; - -} // namespace core - -} // namespace transport diff --git a/libtransport/src/hicn/transport/core/hicn_forwarder_interface.cc b/libtransport/src/hicn/transport/core/hicn_forwarder_interface.cc deleted file mode 100644 index 2a02a2ba8..000000000 --- a/libtransport/src/hicn/transport/core/hicn_forwarder_interface.cc +++ /dev/null @@ -1,135 +0,0 @@ -/* - * 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. - */ - -#include - -union AddressLight { - uint32_t ipv4; - struct in6_addr ipv6; -}; - -typedef struct { - uint8_t message_type; - uint8_t command_id; - uint16_t length; - uint32_t seq_num; -} CommandHeader; - -typedef struct { - uint8_t message_type; - uint8_t command_id; - uint16_t length; - uint32_t seq_num; - char symbolic_or_connid[16]; - union AddressLight address; - uint16_t cost; - uint8_t address_type; - uint8_t len; -} RouteToSelfCommand; - -typedef struct { - uint8_t message_type; - uint8_t command_id; - uint16_t length; - uint32_t seq_num; - char symbolic_or_connid[16]; -} DeleteSelfConnectionCommand; - -namespace { -static constexpr uint8_t addr_inet = 1; -static constexpr uint8_t addr_inet6 = 2; -static constexpr uint8_t add_route_command = 3; -static constexpr uint8_t delete_connection_command = 5; -static constexpr uint8_t request_light = 0xc0; -static constexpr char identifier[] = "SELF"; - -void fillCommandHeader(CommandHeader *header) { - // Allocate and fill the header - header->message_type = request_light; - header->length = 1; -} - -RouteToSelfCommand createCommandRoute(std::unique_ptr &&addr, - uint8_t prefix_length) { - RouteToSelfCommand command = {0}; - - // check and set IP address - if (addr->sa_family == AF_INET) { - command.address_type = addr_inet; - command.address.ipv4 = ((sockaddr_in *)addr.get())->sin_addr.s_addr; - } else if (addr->sa_family == AF_INET6) { - command.address_type = addr_inet6; - command.address.ipv6 = ((sockaddr_in6 *)addr.get())->sin6_addr; - } - - // Fill remaining payload fields -#ifndef _WIN32 - strcpy(command.symbolic_or_connid, identifier); -#else - strcpy_s(command.symbolic_or_connid, 16, identifier); -#endif - command.cost = 1; - command.len = (uint8_t)prefix_length; - - // Allocate and fill the header - command.command_id = add_route_command; - fillCommandHeader((CommandHeader *)&command); - - return command; -} - -DeleteSelfConnectionCommand createCommandDeleteConnection() { - DeleteSelfConnectionCommand command = {0}; - fillCommandHeader((CommandHeader *)&command); - command.command_id = delete_connection_command; - -#ifndef _WIN32 - strcpy(command.symbolic_or_connid, identifier); -#else - strcpy_s(command.symbolic_or_connid, 16, identifier); -#endif - - return command; -} - -} // namespace - -namespace transport { - -namespace core { - -HicnForwarderInterface::HicnForwarderInterface(UdpSocketConnector &connector) - : ForwarderInterface( - connector) {} - -HicnForwarderInterface::~HicnForwarderInterface() {} - -void HicnForwarderInterface::connect(bool is_consumer) { connector_.connect(); } - -void HicnForwarderInterface::registerRoute(Prefix &prefix) { - auto command = createCommandRoute(prefix.toSockaddr(), - (uint8_t)prefix.getPrefixLength()); - send((uint8_t *)&command, sizeof(RouteToSelfCommand)); -} - -void HicnForwarderInterface::closeConnection() { - auto command = createCommandDeleteConnection(); - send((uint8_t *)&command, sizeof(DeleteSelfConnectionCommand)); - connector_.close(); -} - -} // namespace core - -} // namespace transport diff --git a/libtransport/src/hicn/transport/core/hicn_forwarder_interface.h b/libtransport/src/hicn/transport/core/hicn_forwarder_interface.h deleted file mode 100644 index b11841b69..000000000 --- a/libtransport/src/hicn/transport/core/hicn_forwarder_interface.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include - -#include - -namespace transport { - -namespace core { - -class HicnForwarderInterface - : public ForwarderInterface { - static constexpr uint8_t ack_code = 0xc2; - static constexpr uint8_t nack_code = 0xc3; - - public: - union addressLight { - uint32_t ipv4; - struct in6_addr ipv6; - }; - - struct route_to_self_command { - uint8_t messageType; - uint8_t commandID; - uint16_t length; - uint32_t seqNum; - char symbolicOrConnid[16]; - union addressLight address; - uint16_t cost; - uint8_t addressType; - uint8_t len; - }; - - using route_to_self_command = struct route_to_self_command; - using ConnectorType = UdpSocketConnector; - - HicnForwarderInterface(UdpSocketConnector &connector); - - ~HicnForwarderInterface(); - - void connect(bool is_consumer); - - void registerRoute(Prefix &prefix); - - std::uint16_t getMtu() { return interface_mtu; } - - TRANSPORT_ALWAYS_INLINE static bool isControlMessageImpl( - const uint8_t *message) { - return message[0] == ack_code || message[0] == nack_code; - } - - TRANSPORT_ALWAYS_INLINE void processControlMessageReplyImpl( - Packet::MemBufPtr &&packet_buffer) { - if (packet_buffer->data()[0] == nack_code) { - throw errors::RuntimeException( - "Received Nack message from hicn light forwarder."); - } - } - - void closeConnection(); - - private: - static constexpr std::uint16_t interface_mtu = 1500; -}; - -} // namespace core - -} // namespace transport diff --git a/libtransport/src/hicn/transport/core/hicn_vapi.c b/libtransport/src/hicn/transport/core/hicn_vapi.c deleted file mode 100644 index aea08f31c..000000000 --- a/libtransport/src/hicn/transport/core/hicn_vapi.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * 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. - */ - -#include - -#ifdef __vpp__ - -#include -#include - -#define HICN_VPP_PLUGIN -#include -#undef HICN_VPP_PLUGIN - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -///////////////////////////////////////////////////// -const char *HICN_ERROR_STRING[] = { -#define _(a, b, c) c, - foreach_hicn_error -#undef _ -}; -///////////////////////////////////////////////////// - -/*********************** Missing Symbol in vpp libraries *************************/ -u8 * -format_vl_api_address_union (u8 * s, va_list * args) -{ - return NULL; -} - -/*********************************************************************************/ - -DEFINE_VAPI_MSG_IDS_HICN_API_JSON - -static vapi_error_e register_prod_app_cb(vapi_ctx_t ctx, - void *callback_ctx, - vapi_error_e rv, - bool is_last, - vapi_payload_hicn_api_register_prod_app_reply *reply) { - hicn_producer_output_params * output_params = (hicn_producer_output_params *)callback_ctx; - - if(reply == NULL) - return rv; - - output_params->cs_reserved = reply->cs_reserved; - output_params->prod_addr = (ip_address_t *)malloc(sizeof(ip_address_t)); - memset(output_params->prod_addr, 0, sizeof(ip_address_t)); - if(reply->prod_addr.af == ADDRESS_IP6) - memcpy(&output_params->prod_addr->v6, reply->prod_addr.un.ip6, sizeof(ip6_address_t)); - else - memcpy(&output_params->prod_addr->v4, reply->prod_addr.un.ip4, sizeof(ip4_address_t)); - output_params->face_id = reply->faceid; - - return reply->retval; -} - -int hicn_vapi_register_prod_app( - vapi_ctx_t ctx, hicn_producer_input_params *input_params, - hicn_producer_output_params *output_params) { - - vapi_lock(); - vapi_msg_hicn_api_register_prod_app * msg = vapi_alloc_hicn_api_register_prod_app(ctx); - - if(ip46_address_is_ip4((ip46_address_t *)&input_params->prefix->address)) { - memcpy(&msg->payload.prefix.address.un.ip4, &input_params->prefix->address, sizeof(ip4_address_t)); - msg->payload.prefix.address.af = ADDRESS_IP4; - } else { - memcpy(&msg->payload.prefix.address.un.ip6, &input_params->prefix->address, sizeof(ip6_address_t)); - msg->payload.prefix.address.af = ADDRESS_IP6; - } - msg->payload.prefix.len = input_params->prefix->len; - - msg->payload.swif = input_params->swif; - msg->payload.cs_reserved = input_params->cs_reserved; - - int ret = vapi_hicn_api_register_prod_app(ctx, msg, register_prod_app_cb, output_params); - vapi_unlock(); - return ret; -} - -static vapi_error_e face_prod_del_cb(vapi_ctx_t ctx, - void *callback_ctx, - vapi_error_e rv, - bool is_last, - vapi_payload_hicn_api_face_prod_del_reply *reply) { - if(reply == NULL) - return rv; - - return reply->retval; -} - -int hicn_vapi_face_prod_del( - vapi_ctx_t ctx, hicn_del_face_app_input_params *input_params) { - vapi_lock(); - vapi_msg_hicn_api_face_prod_del * msg = vapi_alloc_hicn_api_face_prod_del(ctx); - - msg->payload.faceid = input_params->face_id; - - int ret = vapi_hicn_api_face_prod_del(ctx, msg, face_prod_del_cb, NULL); - vapi_unlock(); - return ret; -} - -static vapi_error_e register_cons_app_cb(vapi_ctx_t ctx, - void *callback_ctx, - vapi_error_e rv, - bool is_last, - vapi_payload_hicn_api_register_cons_app_reply *reply) { - hicn_consumer_output_params * output_params = (hicn_consumer_output_params *)callback_ctx; - - if(reply == NULL) - return rv; - - output_params->src6 = (ip_address_t *)malloc(sizeof(ip_address_t)); - output_params->src4 = (ip_address_t *)malloc(sizeof(ip_address_t)); - memset(output_params->src6, 0, sizeof(ip_address_t)); - memset(output_params->src4, 0, sizeof(ip_address_t)); - memcpy(&output_params->src6->v6, &reply->src_addr6.un.ip6, sizeof(ip6_address_t)); - memcpy(&output_params->src4->v4, &reply->src_addr4.un.ip4, sizeof(ip4_address_t)); - - output_params->face_id1 = reply->faceid1; - output_params->face_id2 = reply->faceid2; - - return reply->retval; -} - -int hicn_vapi_register_cons_app( - vapi_ctx_t ctx, hicn_consumer_input_params *input_params, - hicn_consumer_output_params *output_params) { - - vapi_lock(); - vapi_msg_hicn_api_register_cons_app * msg = vapi_alloc_hicn_api_register_cons_app(ctx); - - msg->payload.swif = input_params->swif; - - int ret = vapi_hicn_api_register_cons_app(ctx, msg, register_cons_app_cb, output_params); - vapi_unlock(); - return ret; -} - -static vapi_error_e face_cons_del_cb(vapi_ctx_t ctx, - void *callback_ctx, - vapi_error_e rv, - bool is_last, - vapi_payload_hicn_api_face_cons_del_reply *reply) { - if(reply == NULL) - return rv; - - return reply->retval; -} - -int hicn_vapi_face_cons_del( - vapi_ctx_t ctx, hicn_del_face_app_input_params *input_params) { - - vapi_lock(); - vapi_msg_hicn_api_face_cons_del * msg = vapi_alloc_hicn_api_face_cons_del(ctx); - - msg->payload.faceid = input_params->face_id; - - int ret = vapi_hicn_api_face_cons_del(ctx, msg, face_cons_del_cb, NULL); - vapi_unlock(); - return ret; -} - -static vapi_error_e reigster_route_cb(vapi_ctx_t ctx, - void *callback_ctx, - vapi_error_e rv, - bool is_last, - vapi_payload_hicn_api_route_nhops_add_reply *reply) { - if(reply == NULL) - return rv; - - return reply->retval; -} - -int hicn_vapi_register_route( - vapi_ctx_t ctx, - hicn_producer_set_route_params *input_params) { - - vapi_lock(); - vapi_msg_hicn_api_route_nhops_add * msg = vapi_alloc_hicn_api_route_nhops_add(ctx); - - fib_prefix_t prefix; - memcpy(&prefix.fp_addr, &input_params->prefix->address, sizeof(ip46_address_t)); - prefix.fp_len = input_params->prefix->len; - msg->payload.face_ids[0] = input_params->face_id; - msg->payload.n_faces = 1; - - int ret = vapi_hicn_api_route_nhops_add(ctx, msg, reigster_route_cb, NULL); - - vapi_unlock(); - return ret; -} - -char *hicn_vapi_get_error_string(int ret_val) { - return get_error_string(ret_val); -} - -#endif // __vpp__ diff --git a/libtransport/src/hicn/transport/core/hicn_vapi.h b/libtransport/src/hicn/transport/core/hicn_vapi.h deleted file mode 100644 index f2718e6f5..000000000 --- a/libtransport/src/hicn/transport/core/hicn_vapi.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include - -#ifdef __vpp__ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#include "stdint.h" - -typedef struct { - ip_prefix_t* prefix; - uint32_t swif; - uint32_t cs_reserved; -} hicn_producer_input_params; - -typedef struct { - uint32_t swif; -} hicn_consumer_input_params; - -typedef struct { - uint32_t face_id; -} hicn_del_face_app_input_params; - -typedef struct { - uint32_t cs_reserved; - ip_address_t* prod_addr; - uint32_t face_id; -} hicn_producer_output_params; - -typedef struct { - ip_address_t* src4; - ip_address_t* src6; - uint32_t face_id1; - uint32_t face_id2; -} hicn_consumer_output_params; - -typedef struct { - ip_prefix_t* prefix; - uint32_t face_id; -} hicn_producer_set_route_params; - -int hicn_vapi_register_prod_app( - vapi_ctx_t ctx, hicn_producer_input_params* input_params, - hicn_producer_output_params* output_params); - -int hicn_vapi_register_cons_app( - vapi_ctx_t ctx, hicn_consumer_input_params* input_params, - hicn_consumer_output_params* output_params); - -int hicn_vapi_register_route( - vapi_ctx_t ctx, hicn_producer_set_route_params* input_params); - -int hicn_vapi_face_cons_del( - vapi_ctx_t ctx, hicn_del_face_app_input_params *input_params); - -int hicn_vapi_face_prod_del( - vapi_ctx_t ctx, hicn_del_face_app_input_params *input_params); - -char* hicn_vapi_get_error_string(int ret_val); - -#ifdef __cplusplus -} -#endif - -#endif // __vpp__ diff --git a/libtransport/src/hicn/transport/core/interest.cc b/libtransport/src/hicn/transport/core/interest.cc deleted file mode 100644 index 166632f0a..000000000 --- a/libtransport/src/hicn/transport/core/interest.cc +++ /dev/null @@ -1,166 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include - -extern "C" { -#ifndef _WIN32 -TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat") -#endif -#include -} - -#include -#include - -namespace transport { - -namespace core { - -Interest::Interest(const Name &interest_name, Packet::Format format) - : Packet(format) { - if (hicn_interest_set_name(format_, packet_start_, - interest_name.getConstStructReference()) < 0) { - throw errors::MalformedPacketException(); - } - - if (hicn_interest_get_name(format_, packet_start_, - name_.getStructReference()) < 0) { - throw errors::MalformedPacketException(); - } -} - -#ifdef __ANDROID__ -Interest::Interest(hicn_format_t format) : Interest(Name("0::0|0"), format) {} -#else -Interest::Interest(hicn_format_t format) : Interest(base_name, format) {} -#endif - -Interest::Interest(const uint8_t *buffer, std::size_t size) - : Packet(buffer, size) { - if (hicn_interest_get_name(format_, packet_start_, - name_.getStructReference()) < 0) { - throw errors::MalformedPacketException(); - } -} - -Interest::Interest(MemBufPtr &&buffer) : Packet(std::move(buffer)) { - if (hicn_interest_get_name(format_, packet_start_, - name_.getStructReference()) < 0) { - throw errors::MalformedPacketException(); - } -} - -Interest::Interest(Interest &&other_interest) - : Packet(std::move(other_interest)) { - name_ = std::move(other_interest.name_); -} - -Interest::~Interest() {} - -void Interest::replace(MemBufPtr &&buffer) { - Packet::replace(std::move(buffer)); - - if (hicn_interest_get_name(format_, packet_start_, - name_.getStructReference()) < 0) { - throw errors::MalformedPacketException(); - } -} - -const Name &Interest::getName() const { - if (!name_) { - if (hicn_interest_get_name(format_, packet_start_, - (hicn_name_t *)name_.getConstStructReference()) < - 0) { - throw errors::MalformedPacketException(); - } - } - - return name_; -} - -Name &Interest::getWritableName() { return const_cast(getName()); } - -void Interest::setName(const Name &name) { - if (hicn_interest_set_name(format_, packet_start_, - name.getConstStructReference()) < 0) { - throw errors::RuntimeException("Error setting interest name."); - } - - if (hicn_interest_get_name(format_, packet_start_, - name_.getStructReference()) < 0) { - throw errors::MalformedPacketException(); - } -} - -void Interest::setName(Name &&name) { - if (hicn_interest_set_name(format_, packet_start_, - name.getStructReference()) < 0) { - throw errors::RuntimeException("Error setting interest name."); - } - - if (hicn_interest_get_name(format_, packet_start_, - name_.getStructReference()) < 0) { - throw errors::MalformedPacketException(); - } -} - -void Interest::setLocator(const ip_address_t &ip_address) { - if (hicn_interest_set_locator(format_, packet_start_, &ip_address) < 0) { - throw errors::RuntimeException("Error setting interest locator."); - } - - return; -} - -ip_address_t Interest::getLocator() const { - ip_address_t ip; - - if (hicn_interest_get_locator(format_, packet_start_, &ip) < 0) { - throw errors::RuntimeException("Error getting interest locator."); - } - - return ip; -} - -void Interest::setLifetime(uint32_t lifetime) { - if (hicn_interest_set_lifetime(packet_start_, lifetime) < 0) { - throw errors::MalformedPacketException(); - } -} - -uint32_t Interest::getLifetime() const { - uint32_t lifetime = 0; - - if (hicn_interest_get_lifetime(packet_start_, &lifetime) < 0) { - throw errors::MalformedPacketException(); - } - - return lifetime; -} - -void Interest::resetForHash() { - if (hicn_interest_reset_for_hash( - format_, reinterpret_cast(packet_start_)) < 0) { - throw errors::RuntimeException( - "Error resetting interest fields for hash computation."); - } -} - -} // end namespace core - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/interest.h b/libtransport/src/hicn/transport/core/interest.h deleted file mode 100644 index 48c833a73..000000000 --- a/libtransport/src/hicn/transport/core/interest.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include - -namespace transport { - -namespace core { - -class Interest - : public Packet /*, public std::enable_shared_from_this*/ { - public: - using Ptr = utils::ObjectPool::Ptr; - - Interest(Packet::Format format = HF_INET6_TCP); - - Interest(const Name &interest_name, Packet::Format format = HF_INET6_TCP); - - Interest(const uint8_t *buffer, std::size_t size); - Interest(MemBufPtr &&buffer); - - /* - * Enforce zero-copy. - */ - Interest(const Interest &other_interest) = delete; - Interest &operator=(const Interest &other_interest) = delete; - - Interest(Interest &&other_interest); - - ~Interest() override; - - void replace(MemBufPtr &&buffer) override; - - const Name &getName() const override; - - Name &getWritableName() override; - - void setName(const Name &name) override; - - void setName(Name &&name) override; - - void setLocator(const ip_address_t &ip_address) override; - - ip_address_t getLocator() const override; - - void setLifetime(uint32_t lifetime) override; - - uint32_t getLifetime() const override; - - private: - void resetForHash() override; -}; - -} // end namespace core - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/manifest.cc b/libtransport/src/hicn/transport/core/manifest.cc deleted file mode 100644 index 3f890f3d0..000000000 --- a/libtransport/src/hicn/transport/core/manifest.cc +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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. - */ - -#include - -namespace transport { - -namespace core { - -std::string ManifestEncoding::manifest_type = std::string("manifest_type"); - -std::map ManifestEncoding::manifest_types = { - {FINAL_CHUNK_NUMBER, "FinalChunkNumber"}, {NAME_LIST, "NameList"}}; - -std::string ManifestEncoding::final_chunk_number = - std::string("final_chunk_number"); -std::string ManifestEncoding::content_name = std::string("content_name"); - -} // end namespace core - -} // end namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/manifest.h b/libtransport/src/hicn/transport/core/manifest.h deleted file mode 100644 index 9650de94d..000000000 --- a/libtransport/src/hicn/transport/core/manifest.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include - -#include - -namespace transport { - -namespace core { - -using typename core::Name; -using typename core::Packet; -using typename core::PayloadType; - -template -class Manifest : public Base { - static_assert(std::is_base_of::value, - "Base must inherit from packet!"); - - public: - using Encoder = typename FormatTraits::Encoder; - using Decoder = typename FormatTraits::Decoder; - - Manifest(std::size_t signature_size = 0) - : Base(HF_INET6_TCP_AH), - encoder_(*this, signature_size), - decoder_(*this) { - Base::setPayloadType(PayloadType::MANIFEST); - } - - Manifest(const core::Name &name, std::size_t signature_size = 0) - : Base(name, HF_INET6_TCP_AH), - encoder_(*this, signature_size), - decoder_(*this) { - Base::setPayloadType(PayloadType::MANIFEST); - } - - template - Manifest(T &&base) - : Base(std::forward(base)), encoder_(*this), decoder_(*this) { - Base::setPayloadType(PayloadType::MANIFEST); - } - - virtual ~Manifest() = default; - - std::size_t estimateManifestSize(std::size_t additional_entries = 0) { - return static_cast(*this).estimateManifestSizeImpl( - additional_entries); - } - - /* - * After the call to encode, users MUST call clear before adding data - * to the manifest. - */ - Manifest &encode() { return static_cast(*this).encodeImpl(); } - - Manifest &decode() { - Manifest::decoder_.decode(); - - manifest_type_ = decoder_.getManifestType(); - hash_algorithm_ = decoder_.getHashAlgorithm(); - is_last_ = decoder_.getIsFinalManifest(); - - return static_cast(*this).decodeImpl(); - } - - static std::size_t getManifestHeaderSize() { - return Encoder::getManifestHeaderSize(); - } - - static std::size_t getManifestEntrySize() { - return Encoder::getManifestEntrySize(); - } - - Manifest &setManifestType(ManifestType type) { - manifest_type_ = type; - encoder_.setManifestType(manifest_type_); - return *this; - } - - Manifest &setHashAlgorithm(HashAlgorithm hash_algorithm) { - hash_algorithm_ = hash_algorithm; - encoder_.setHashAlgorithm(hash_algorithm_); - return *this; - } - - HashAlgorithm getHashAlgorithm() { return hash_algorithm_; } - - ManifestType getManifestType() const { return manifest_type_; } - - bool isFinalManifest() const { return is_last_; } - - Manifest &setVersion(ManifestVersion version) { - encoder_.setVersion(version); - return *this; - } - - Manifest &setFinalBlockNumber(std::uint32_t final_block_number) { - encoder_.setFinalBlockNumber(final_block_number); - return *this; - } - - uint32_t getFinalBlockNumber() const { - return decoder_.getFinalBlockNumber(); - } - - ManifestVersion getVersion() const { return decoder_.getVersion(); } - - Manifest &setFinalManifest(bool is_final_manifest) { - encoder_.setIsFinalManifest(is_final_manifest); - is_last_ = is_final_manifest; - return *this; - } - - Manifest &clear() { - encoder_.clear(); - decoder_.clear(); - return *this; - } - - protected: - ManifestType manifest_type_; - HashAlgorithm hash_algorithm_; - bool is_last_; - - Encoder encoder_; - Decoder decoder_; -}; - -} // end namespace core - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/manifest_format.h b/libtransport/src/hicn/transport/core/manifest_format.h deleted file mode 100644 index 9b6777270..000000000 --- a/libtransport/src/hicn/transport/core/manifest_format.h +++ /dev/null @@ -1,210 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include - -#include -#include -#include - -namespace transport { - -namespace core { - -enum class ManifestFields : uint8_t { - VERSION, - HASH_ALGORITHM, - SEGMENT_CALCULATION_STRATEGY, - FINAL_MANIFEST, - NAME_HASH_LIST, - BASE_NAME -}; - -enum class ManifestVersion : uint8_t { - VERSION_1 = 1, -}; - -enum class ManifestType : uint8_t { - INLINE_MANIFEST = 1, - FINAL_CHUNK_NUMBER = 2, - FLIC_MANIFEST = 3, -}; - -enum class HashAlgorithm : uint8_t { - SHA_256 = static_cast(utils::CryptoHashType::SHA_256), - SHA_512 = static_cast(utils::CryptoHashType::SHA_512), - CRC32C = static_cast(utils::CryptoHashType::CRC32C), -}; - -/** - * INCREMENTAL: Manifests will be received inline with the data with no specific - * assumption regarding the manifest capacity. Consumers can send interests - * using a +1 heuristic. - * - * MANIFEST_CAPACITY_BASED: manifests with capacity N have a suffix multiple of - * N+1: 0, N+1, 2(N+1) etc. Contents have a suffix incremented by 1 except when - * it conflicts with a manifest: 1, 2, ..., N, N+2, N+3, ..., 2N+1, 2N+3 - */ -enum class NextSegmentCalculationStrategy : uint8_t { - INCREMENTAL = 1, - MANIFEST_CAPACITY_BASED = 2, -}; - -template -struct format_traits { - using Encoder = typename T::Encoder; - using Decoder = typename T::Decoder; - using HashType = typename T::HashType; - using HashList = typename T::HashList; -}; - -class Packet; - -template -class ManifestEncoder { - public: - virtual ~ManifestEncoder() = default; - - ManifestEncoder encode() { - return static_cast(*this).encodeImpl(); - } - - ManifestEncoder &clear() { - return static_cast(*this).clearImpl(); - } - - ManifestEncoder &setManifestType(ManifestType type) { - return static_cast(*this).setManifestTypeImpl(type); - } - - ManifestEncoder &setHashAlgorithm(HashAlgorithm hash) { - return static_cast(*this).setHashAlgorithmImpl(hash); - } - - ManifestEncoder &setFinalChunkNumber(uint32_t final_chunk) { - return static_cast(*this).setFinalChunkImpl(final_chunk); - } - - ManifestEncoder &setNextSegmentCalculationStrategy( - NextSegmentCalculationStrategy strategy) { - return static_cast(*this) - .setNextSegmentCalculationStrategyImpl(strategy); - } - - template < - typename T, - typename = std::enable_if_t>, core::Name>::value>> - ManifestEncoder &setBaseName(T &&name) { - return static_cast(*this).setBaseNameImpl(name); - } - - template - ManifestEncoder &addSuffixAndHash(uint32_t suffix, Hash &&hash) { - return static_cast(*this).addSuffixAndHashImpl( - suffix, std::forward(hash)); - } - - ManifestEncoder &setIsFinalManifest(bool is_last) { - return static_cast(*this).setIsFinalManifestImpl(is_last); - } - - ManifestEncoder &setVersion(ManifestVersion version) { - return static_cast(*this).setVersionImpl(version); - } - - std::size_t estimateSerializedLength(std::size_t number_of_entries) { - return static_cast(*this).estimateSerializedLengthImpl( - number_of_entries); - } - - ManifestEncoder &update() { - return static_cast(*this).updateImpl(); - } - - ManifestEncoder &setFinalBlockNumber(std::uint32_t final_block_number) { - return static_cast(*this).setFinalBlockNumberImpl( - final_block_number); - } - - static std::size_t getManifestHeaderSize() { - return Implementation::getManifestHeaderSizeImpl(); - } - - static std::size_t getManifestEntrySize() { - return Implementation::getManifestEntrySizeImpl(); - } -}; - -template -class ManifestDecoder { - public: - virtual ~ManifestDecoder() = default; - - ManifestDecoder &clear() { - return static_cast(*this).clearImpl(); - } - - void decode() { static_cast(*this).decodeImpl(); } - - ManifestType getManifestType() const { - return static_cast(*this).getManifestTypeImpl(); - } - - HashAlgorithm getHashAlgorithm() const { - return static_cast(*this).getHashAlgorithmImpl(); - } - - uint32_t getFinalChunkNumber() const { - return static_cast(*this).getFinalChunkImpl(); - } - - NextSegmentCalculationStrategy getNextSegmentCalculationStrategy() const { - return static_cast(*this) - .getNextSegmentCalculationStrategyImpl(); - } - - core::Name getBaseName() const { - return static_cast(*this).getBaseNameImpl(); - } - - auto getSuffixHashList() { - return static_cast(*this).getSuffixHashListImpl(); - } - - bool getIsFinalManifest() const { - return static_cast(*this).getIsFinalManifestImpl(); - } - - ManifestVersion getVersion() const { - return static_cast(*this).getVersionImpl(); - } - - std::size_t estimateSerializedLength(std::size_t number_of_entries) const { - return static_cast(*this) - .estimateSerializedLengthImpl(number_of_entries); - } - - uint32_t getFinalBlockNumber() const { - return static_cast(*this).getFinalBlockNumberImpl(); - } -}; - -} // namespace core - -} // namespace transport diff --git a/libtransport/src/hicn/transport/core/manifest_format_fixed.cc b/libtransport/src/hicn/transport/core/manifest_format_fixed.cc deleted file mode 100644 index f5e31d784..000000000 --- a/libtransport/src/hicn/transport/core/manifest_format_fixed.cc +++ /dev/null @@ -1,226 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include - -namespace transport { - -namespace core { - -// TODO use preallocated pool of membufs -FixedManifestEncoder::FixedManifestEncoder(Packet &packet, - std::size_t signature_size) - : packet_(packet), - max_size_(Packet::default_mtu - packet_.headerSize() - signature_size), - manifest_( - utils::MemBuf::create(Packet::default_mtu - packet_.headerSize())), - manifest_header_( - reinterpret_cast(manifest_->writableData())), - manifest_entries_(reinterpret_cast( - manifest_->writableData() + sizeof(ManifestHeader))), - current_entry_(0), - signature_size_(signature_size) { - *manifest_header_ = {0}; -} - -FixedManifestEncoder::~FixedManifestEncoder() {} - -FixedManifestEncoder &FixedManifestEncoder::encodeImpl() { - manifest_->append(sizeof(ManifestHeader) + - manifest_header_->number_of_entries * - sizeof(ManifestEntry)); - packet_.appendPayload(std::move(manifest_)); - return *this; -} - -FixedManifestEncoder &FixedManifestEncoder::clearImpl() { - manifest_ = utils::MemBuf::create(Packet::default_mtu - packet_.headerSize() - - signature_size_); - return *this; -} - -FixedManifestEncoder &FixedManifestEncoder::setHashAlgorithmImpl( - HashAlgorithm algorithm) { - manifest_header_->hash_algorithm = static_cast(algorithm); - return *this; -} - -FixedManifestEncoder &FixedManifestEncoder::setManifestTypeImpl( - ManifestType manifest_type) { - manifest_header_->manifest_type = static_cast(manifest_type); - return *this; -} - -FixedManifestEncoder & -FixedManifestEncoder::setNextSegmentCalculationStrategyImpl( - NextSegmentCalculationStrategy strategy) { - manifest_header_->next_segment_strategy = static_cast(strategy); - return *this; -} - -FixedManifestEncoder &FixedManifestEncoder::setBaseNameImpl( - const core::Name &base_name) { - base_name.copyToDestination( - reinterpret_cast(&manifest_header_->prefix[0]), false); - manifest_header_->flags.ipv6 = - base_name.getAddressFamily() == AF_INET6 ? 1_U8 : 0_U8; - return *this; -} - -FixedManifestEncoder &FixedManifestEncoder::addSuffixAndHashImpl( - uint32_t suffix, const utils::CryptoHash &hash) { - auto _hash = hash.getDigest(); - addSuffixHashBytes(suffix, _hash.data(), _hash.length()); - return *this; -} - -void FixedManifestEncoder::addSuffixHashBytes(uint32_t suffix, - const uint8_t *hash, - std::size_t length) { - manifest_entries_[current_entry_].suffix = htonl(suffix); - // std::copy(hash, hash + length, - // manifest_entries_[current_entry_].hash); - std::memcpy( - reinterpret_cast(manifest_entries_[current_entry_].hash), hash, - length); - - manifest_header_->number_of_entries++; - current_entry_++; - - if (TRANSPORT_EXPECT_FALSE(estimateSerializedLengthImpl() > max_size_)) { - throw errors::RuntimeException("Manifest size exceeded the packet MTU!"); - } -} - -FixedManifestEncoder &FixedManifestEncoder::setIsFinalManifestImpl( - bool is_last) { - manifest_header_->flags.is_last = static_cast(is_last); - return *this; -} - -FixedManifestEncoder &FixedManifestEncoder::setVersionImpl( - ManifestVersion version) { - manifest_header_->version = static_cast(version); - return *this; -} - -std::size_t FixedManifestEncoder::estimateSerializedLengthImpl( - std::size_t additional_entries) { - return sizeof(ManifestHeader) + - (manifest_header_->number_of_entries + additional_entries) * - sizeof(ManifestEntry); -} - -FixedManifestEncoder &FixedManifestEncoder::updateImpl() { - max_size_ = Packet::default_mtu - packet_.headerSize() - signature_size_; - return *this; -} - -FixedManifestEncoder &FixedManifestEncoder::setFinalBlockNumberImpl( - std::uint32_t final_block_number) { - manifest_header_->final_block_number = htonl(final_block_number); - return *this; -} - -std::size_t FixedManifestEncoder::getManifestHeaderSizeImpl() { - return sizeof(ManifestHeader); -} - -std::size_t FixedManifestEncoder::getManifestEntrySizeImpl() { - return sizeof(ManifestEntry); -} - -FixedManifestDecoder::FixedManifestDecoder(Packet &packet) - : packet_(packet), - manifest_header_(reinterpret_cast( - packet_.getPayload()->writableData())), - manifest_entries_(reinterpret_cast( - packet_.getPayload()->writableData() + sizeof(ManifestHeader))) {} - -FixedManifestDecoder::~FixedManifestDecoder() {} - -void FixedManifestDecoder::decodeImpl() { - std::size_t packet_size = packet_.payloadSize(); - - if (packet_size < sizeof(ManifestHeader) || - packet_size < estimateSerializedLengthImpl()) { - throw errors::RuntimeException( - "The packet does not match expected manifest size."); - } -} - -FixedManifestDecoder &FixedManifestDecoder::clearImpl() { return *this; } - -ManifestType FixedManifestDecoder::getManifestTypeImpl() const { - return static_cast(manifest_header_->manifest_type); -} - -HashAlgorithm FixedManifestDecoder::getHashAlgorithmImpl() const { - return static_cast(manifest_header_->hash_algorithm); -} - -NextSegmentCalculationStrategy -FixedManifestDecoder::getNextSegmentCalculationStrategyImpl() const { - return static_cast( - manifest_header_->next_segment_strategy); -} - -typename Fixed::SuffixList FixedManifestDecoder::getSuffixHashListImpl() { - typename Fixed::SuffixList hash_list; - - for (int i = 0; i < manifest_header_->number_of_entries; i++) { - hash_list.insert(hash_list.end(), - std::make_pair(ntohl(manifest_entries_[i].suffix), - reinterpret_cast( - &manifest_entries_[i].hash[0]))); - } - - return hash_list; -} - -core::Name FixedManifestDecoder::getBaseNameImpl() const { - if (static_cast(manifest_header_->flags.ipv6)) { - return core::Name(AF_INET6, - reinterpret_cast(&manifest_header_->prefix)); - } else { - return core::Name(AF_INET, - reinterpret_cast(&manifest_header_->prefix)); - } -} - -bool FixedManifestDecoder::getIsFinalManifestImpl() const { - return static_cast(manifest_header_->flags.is_last); -} - -ManifestVersion FixedManifestDecoder::getVersionImpl() const { - return static_cast(manifest_header_->version); -} - -std::size_t FixedManifestDecoder::estimateSerializedLengthImpl( - std::size_t additional_entries) const { - return sizeof(ManifestHeader) + - (additional_entries + manifest_header_->number_of_entries) * - sizeof(ManifestEntry); -} - -uint32_t FixedManifestDecoder::getFinalBlockNumberImpl() const { - return ntohl(manifest_header_->final_block_number); -} - -} // end namespace core - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/manifest_format_fixed.h b/libtransport/src/hicn/transport/core/manifest_format_fixed.h deleted file mode 100644 index 2c6e2bced..000000000 --- a/libtransport/src/hicn/transport/core/manifest_format_fixed.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include - -#include - -namespace transport { - -namespace core { - -// 0 1 2 3 -// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// |Version| MType |HashAlg|NextStr| Flags |NumberOfEntries| -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | Final Block Number | -// +---------------------------------------------------------------| -// | | -// + + -// | | -// + Prefix + -// | | -// + + -// | | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | Suffix | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | Hash Value | -// | | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -class FixedManifestEncoder; -class FixedManifestDecoder; -class Packet; - -struct Fixed { - using Encoder = FixedManifestEncoder; - using Decoder = FixedManifestDecoder; - using HashType = utils::CryptoHash; - using SuffixList = std::list>; -}; - -struct Flags { - std::uint8_t ipv6 : 1; - std::uint8_t is_last : 1; - std::uint8_t unused : 6; -}; - -struct ManifestEntry { - std::uint32_t suffix; - std::uint32_t hash[8]; -}; - -struct ManifestHeader { - std::uint8_t version : 4; - std::uint8_t manifest_type : 4; - std::uint8_t hash_algorithm : 4; - std::uint8_t next_segment_strategy : 4; - Flags flags; - std::uint8_t number_of_entries; - std::uint32_t final_block_number; - std::uint32_t prefix[4]; - ManifestEntry entries[0]; -}; - -static const constexpr std::uint8_t manifest_version = 1; - -class FixedManifestEncoder : public ManifestEncoder { - public: - FixedManifestEncoder(Packet &packet, std::size_t signature_size = 0); - - ~FixedManifestEncoder(); - - FixedManifestEncoder &encodeImpl(); - - FixedManifestEncoder &clearImpl(); - - FixedManifestEncoder &setManifestTypeImpl(ManifestType manifest_type); - - FixedManifestEncoder &setHashAlgorithmImpl(HashAlgorithm algorithm); - - FixedManifestEncoder &setNextSegmentCalculationStrategyImpl( - NextSegmentCalculationStrategy strategy); - - FixedManifestEncoder &setBaseNameImpl(const core::Name &base_name); - - FixedManifestEncoder &addSuffixAndHashImpl(uint32_t suffix, - const utils::CryptoHash &hash); - - FixedManifestEncoder &setIsFinalManifestImpl(bool is_last); - - FixedManifestEncoder &setVersionImpl(ManifestVersion version); - - std::size_t estimateSerializedLengthImpl(std::size_t additional_entries = 0); - - FixedManifestEncoder &updateImpl(); - - FixedManifestEncoder &setFinalBlockNumberImpl( - std::uint32_t final_block_number); - - static std::size_t getManifestHeaderSizeImpl(); - - static std::size_t getManifestEntrySizeImpl(); - - private: - void addSuffixHashBytes(uint32_t suffix, const uint8_t *hash, - std::size_t length); - - Packet &packet_; - std::size_t max_size_; - std::unique_ptr manifest_; - ManifestHeader *manifest_header_; - ManifestEntry *manifest_entries_; - std::size_t current_entry_; - std::size_t signature_size_; -}; - -class FixedManifestDecoder : public ManifestDecoder { - public: - FixedManifestDecoder(Packet &packet); - - ~FixedManifestDecoder(); - - void decodeImpl(); - - FixedManifestDecoder &clearImpl(); - - ManifestType getManifestTypeImpl() const; - - HashAlgorithm getHashAlgorithmImpl() const; - - NextSegmentCalculationStrategy getNextSegmentCalculationStrategyImpl() const; - - typename Fixed::SuffixList getSuffixHashListImpl(); - - core::Name getBaseNameImpl() const; - - bool getIsFinalManifestImpl() const; - - std::size_t estimateSerializedLengthImpl( - std::size_t additional_entries = 0) const; - - ManifestVersion getVersionImpl() const; - - uint32_t getFinalBlockNumberImpl() const; - - private: - Packet &packet_; - ManifestHeader *manifest_header_; - ManifestEntry *manifest_entries_; -}; - -} // namespace core - -} // namespace transport diff --git a/libtransport/src/hicn/transport/core/manifest_inline.h b/libtransport/src/hicn/transport/core/manifest_inline.h deleted file mode 100644 index 385e43af3..000000000 --- a/libtransport/src/hicn/transport/core/manifest_inline.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include -#include - -namespace transport { - -namespace core { - -template -class ManifestInline - : public Manifest> { - using ManifestBase = - Manifest>; - using HashType = typename FormatTraits::HashType; - using SuffixList = typename FormatTraits::SuffixList; - - public: - ManifestInline() : ManifestBase() {} - - ManifestInline(const core::Name &name, std::size_t signature_size = 0) - : ManifestBase(name, signature_size) {} - - template - ManifestInline(T &&base) : ManifestBase(std::forward(base)) {} - - static TRANSPORT_ALWAYS_INLINE ManifestInline *createManifest( - const core::Name &manifest_name, ManifestVersion version, - ManifestType type, HashAlgorithm algorithm, bool is_last, - const Name &base_name, NextSegmentCalculationStrategy strategy, - std::size_t signature_size) { - auto manifest = new ManifestInline(manifest_name, signature_size); - manifest->setVersion(version); - manifest->setManifestType(type); - manifest->setHashAlgorithm(algorithm); - manifest->setFinalManifest(is_last); - manifest->setBaseName(base_name); - manifest->setNextSegmentCalculationStrategy(strategy); - - return manifest; - } - - ManifestInline &encodeImpl() { - ManifestBase::encoder_.encode(); - return *this; - } - - ManifestInline &decodeImpl() { - base_name_ = ManifestBase::decoder_.getBaseName(); - next_segment_strategy_ = - ManifestBase::decoder_.getNextSegmentCalculationStrategy(); - suffix_hash_map_ = ManifestBase::decoder_.getSuffixHashList(); - - return *this; - } - - std::size_t estimateManifestSizeImpl(std::size_t additional_entries = 0) { - return ManifestBase::encoder_.estimateSerializedLength(additional_entries); - } - - ManifestInline &setBaseName(const Name &name) { - base_name_ = name; - ManifestBase::encoder_.setBaseName(base_name_); - return *this; - } - - const Name &getBaseName() { return base_name_; } - - ManifestInline &addSuffixHash(uint32_t suffix, const HashType &hash) { - ManifestBase::encoder_.addSuffixAndHash(suffix, hash); - return *this; - } - - // Call this function only after the decode function! - const SuffixList &getSuffixList() { return suffix_hash_map_; } - - ManifestInline &setNextSegmentCalculationStrategy( - NextSegmentCalculationStrategy strategy) { - next_segment_strategy_ = strategy; - ManifestBase::encoder_.setNextSegmentCalculationStrategy( - next_segment_strategy_); - return *this; - } - - NextSegmentCalculationStrategy getNextSegmentCalculationStrategy() { - return next_segment_strategy_; - } - - private: - core::Name base_name_; - NextSegmentCalculationStrategy next_segment_strategy_; - SuffixList suffix_hash_map_; -}; - -} // end namespace core - -} // end namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/memif_connector.cc b/libtransport/src/hicn/transport/core/memif_connector.cc deleted file mode 100644 index 5e37c882a..000000000 --- a/libtransport/src/hicn/transport/core/memif_connector.cc +++ /dev/null @@ -1,493 +0,0 @@ -/* - * 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. - */ - -#include -#include - -#ifdef __vpp__ - -#include -#include - -extern "C" { -#include -}; - -#define CANCEL_TIMER 1 - -namespace transport { - -namespace core { - -struct memif_connection { - uint16_t index; - /* memif conenction handle */ - memif_conn_handle_t conn; - /* transmit queue id */ - uint16_t tx_qid; - /* tx buffers */ - memif_buffer_t *tx_bufs; - /* allocated tx buffers counter */ - /* number of tx buffers pointing to shared memory */ - uint16_t tx_buf_num; - /* rx buffers */ - memif_buffer_t *rx_bufs; - /* allcoated rx buffers counter */ - /* number of rx buffers pointing to shared memory */ - uint16_t rx_buf_num; - /* interface ip address */ - uint8_t ip_addr[4]; -}; - -std::once_flag MemifConnector::flag_; -utils::EpollEventReactor MemifConnector::main_event_reactor_; - -MemifConnector::MemifConnector(PacketReceivedCallback &&receive_callback, - OnReconnect &&on_reconnect_callback, - asio::io_service &io_service, - std::string app_name) - : Connector(std::move(receive_callback), std::move(on_reconnect_callback)), - memif_worker_(nullptr), - timer_set_(false), - send_timer_(std::make_unique(event_reactor_)), - disconnect_timer_( - std::make_unique(event_reactor_)), - io_service_(io_service), - packet_counter_(0), - memif_connection_(std::make_unique()), - tx_buf_counter_(0), - is_reconnection_(false), - data_available_(false), - app_name_(app_name), - socket_filename_("") { - std::call_once(MemifConnector::flag_, &MemifConnector::init, this); -} - -MemifConnector::~MemifConnector() { close(); } - -void MemifConnector::init() { - /* initialize memory interface */ - int err = memif_init(controlFdUpdate, const_cast(app_name_.c_str()), - nullptr, nullptr, nullptr); - - if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { - TRANSPORT_LOGE("memif_init: %s", memif_strerror(err)); - } -} - -void MemifConnector::connect(uint32_t memif_id, long memif_mode) { - state_ = ConnectorState::CONNECTING; - - memif_id_ = memif_id; - socket_filename_ = "/run/vpp/memif.sock"; - - createMemif(memif_id, memif_mode, nullptr); - - work_ = std::make_unique(io_service_); - - while (state_ != ConnectorState::CONNECTED) { - MemifConnector::main_event_reactor_.runOneEvent(); - } - - int err; - - /* get interrupt queue id */ - int fd = -1; - err = memif_get_queue_efd(memif_connection_->conn, 0, &fd); - if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { - TRANSPORT_LOGE("memif_get_queue_efd: %s", memif_strerror(err)); - return; - } - - // Remove fd from main epoll - main_event_reactor_.delFileDescriptor(fd); - - // Add fd to epoll of instance - event_reactor_.addFileDescriptor( - fd, EPOLLIN, [this](const utils::Event &evt) -> int { - return onInterrupt(memif_connection_->conn, this, 0); - }); - - memif_worker_ = std::make_unique( - std::bind(&MemifConnector::threadMain, this)); -} - -int MemifConnector::createMemif(uint32_t index, uint8_t mode, char *s) { - memif_connection_t *c = memif_connection_.get(); - - /* setting memif connection arguments */ - memif_conn_args_t args; - memset(&args, 0, sizeof(args)); - - args.is_master = mode; - args.log2_ring_size = MEMIF_LOG2_RING_SIZE; - args.buffer_size = MEMIF_BUF_SIZE; - args.num_s2m_rings = 1; - args.num_m2s_rings = 1; - strncpy((char *)args.interface_name, IF_NAME, strlen(IF_NAME) + 1); - args.mode = memif_interface_mode_t::MEMIF_INTERFACE_MODE_IP; - - int err; - - err = memif_create_socket(&args.socket, socket_filename_.c_str(), nullptr); - - if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { - throw errors::RuntimeException(memif_strerror(err)); - } - - args.interface_id = index; - /* last argument for memif_create (void * private_ctx) is used by user - to identify connection. this context is returned with callbacks */ - - /* default interrupt */ - if (s == nullptr) { - err = memif_create(&c->conn, &args, onConnect, onDisconnect, onInterrupt, - this); - - if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { - throw errors::RuntimeException(memif_strerror(err)); - } - } - - c->index = (uint16_t)index; - c->tx_qid = 0; - /* alloc memif buffers */ - c->rx_buf_num = 0; - c->rx_bufs = static_cast( - malloc(sizeof(memif_buffer_t) * MAX_MEMIF_BUFS)); - c->tx_buf_num = 0; - c->tx_bufs = static_cast( - malloc(sizeof(memif_buffer_t) * MAX_MEMIF_BUFS)); - - // memif_set_rx_mode (c->conn, MEMIF_RX_MODE_POLLING, 0); - - return 0; -} - -int MemifConnector::deleteMemif() { - memif_connection_t *c = memif_connection_.get(); - - if (c->rx_bufs) { - free(c->rx_bufs); - } - - c->rx_bufs = nullptr; - c->rx_buf_num = 0; - - if (c->tx_bufs) { - free(c->tx_bufs); - } - - c->tx_bufs = nullptr; - c->tx_buf_num = 0; - - int err; - /* disconenct then delete memif connection */ - err = memif_delete(&c->conn); - - if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { - TRANSPORT_LOGE("memif_delete: %s", memif_strerror(err)); - } - - if (TRANSPORT_EXPECT_FALSE(c->conn != nullptr)) { - TRANSPORT_LOGE("memif delete fail"); - } - - return 0; -} - -int MemifConnector::controlFdUpdate(int fd, uint8_t events, void *private_ctx) { - /* convert memif event definitions to epoll events */ - if (events & MEMIF_FD_EVENT_DEL) { - return MemifConnector::main_event_reactor_.delFileDescriptor(fd); - } - - uint32_t evt = 0; - - if (events & MEMIF_FD_EVENT_READ) { - evt |= EPOLLIN; - } - - if (events & MEMIF_FD_EVENT_WRITE) { - evt |= EPOLLOUT; - } - - if (events & MEMIF_FD_EVENT_MOD) { - return MemifConnector::main_event_reactor_.modFileDescriptor(fd, evt); - } - - return MemifConnector::main_event_reactor_.addFileDescriptor( - fd, evt, [](const utils::Event &evt) -> int { - uint32_t event = 0; - int memif_err = 0; - - if (evt.events & EPOLLIN) { - event |= MEMIF_FD_EVENT_READ; - } - - if (evt.events & EPOLLOUT) { - event |= MEMIF_FD_EVENT_WRITE; - } - - if (evt.events & EPOLLERR) { - event |= MEMIF_FD_EVENT_ERROR; - } - - memif_err = memif_control_fd_handler(evt.data.fd, event); - - if (TRANSPORT_EXPECT_FALSE(memif_err != MEMIF_ERR_SUCCESS)) { - TRANSPORT_LOGE("memif_control_fd_handler: %s", - memif_strerror(memif_err)); - } - - return 0; - }); -} - -int MemifConnector::bufferAlloc(long n, uint16_t qid) { - memif_connection_t *c = memif_connection_.get(); - int err; - uint16_t r; - /* set data pointer to shared memory and set buffer_len to shared mmeory - * buffer len */ - err = memif_buffer_alloc(c->conn, qid, c->tx_bufs, n, &r, 2000); - - if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { - TRANSPORT_LOGE("memif_buffer_alloc: %s", memif_strerror(err)); - } - - c->tx_buf_num += r; - return r; -} - -int MemifConnector::txBurst(uint16_t qid) { - memif_connection_t *c = memif_connection_.get(); - int err; - uint16_t r; - /* inform peer memif interface about data in shared memory buffers */ - /* mark memif buffers as free */ - err = memif_tx_burst(c->conn, qid, c->tx_bufs, c->tx_buf_num, &r); - - if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { - TRANSPORT_LOGE("memif_tx_burst: %s", memif_strerror(err)); - } - - // err = memif_refill_queue(c->conn, qid, r, 0); - - if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { - TRANSPORT_LOGE("memif_tx_burst: %s", memif_strerror(err)); - c->tx_buf_num -= r; - return -1; - } - - c->tx_buf_num -= r; - return 0; -} - -void MemifConnector::sendCallback(const std::error_code &ec) { - timer_set_ = false; - - if (TRANSPORT_EXPECT_TRUE(!ec && state_ == ConnectorState::CONNECTED)) { - doSend(); - } -} - -void MemifConnector::processInputBuffer() { - Packet::MemBufPtr ptr; - - while (input_buffer_.pop(ptr)) { - receive_callback_(std::move(ptr)); - } -} - -/* informs user about connected status. private_ctx is used by user to identify - connection (multiple connections WIP) */ -int MemifConnector::onConnect(memif_conn_handle_t conn, void *private_ctx) { - MemifConnector *connector = (MemifConnector *)private_ctx; - connector->state_ = ConnectorState::CONNECTED; - memif_refill_queue(conn, 0, -1, 0); - - return 0; -} - -/* informs user about disconnected status. private_ctx is used by user to - identify connection (multiple connections WIP) */ -int MemifConnector::onDisconnect(memif_conn_handle_t conn, void *private_ctx) { - MemifConnector *connector = (MemifConnector *)private_ctx; - connector->state_ = ConnectorState::CLOSED; - return 0; -} - -void MemifConnector::threadMain() { event_reactor_.runEventLoop(1000); } - -int MemifConnector::onInterrupt(memif_conn_handle_t conn, void *private_ctx, - uint16_t qid) { - MemifConnector *connector = (MemifConnector *)private_ctx; - - memif_connection_t *c = connector->memif_connection_.get(); - int err = MEMIF_ERR_SUCCESS, ret_val; - uint16_t rx; - - do { - err = memif_rx_burst(conn, qid, c->rx_bufs, MAX_MEMIF_BUFS, &rx); - ret_val = err; - - if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS && - err != MEMIF_ERR_NOBUF)) { - TRANSPORT_LOGE("memif_rx_burst: %s", memif_strerror(err)); - goto error; - } - - c->rx_buf_num += rx; - - if (TRANSPORT_EXPECT_TRUE(connector->io_service_.stopped())) { - TRANSPORT_LOGE("socket stopped: ignoring %u packets", rx); - goto error; - } - - std::size_t packet_length; - for (int i = 0; i < rx; i++) { - auto packet = connector->getPacket(); - packet_length = (c->rx_bufs + i)->len; - std::memcpy(packet->writableData(), - reinterpret_cast((c->rx_bufs + i)->data), - packet_length); - packet->append(packet_length); - - if (!connector->input_buffer_.push(std::move(packet))) { - TRANSPORT_LOGE("Error pushing packet. Ring buffer full."); - - // TODO Here we should consider the possibility to signal the congestion - // to the application, that would react properly (e.g. slow down - // message) - } - } - - /* mark memif buffers and shared memory buffers as free */ - /* free processed buffers */ - - err = memif_refill_queue(conn, qid, rx, 0); - - if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { - TRANSPORT_LOGE("memif_buffer_free: %s", memif_strerror(err)); - } - - c->rx_buf_num -= rx; - - } while (ret_val == MEMIF_ERR_NOBUF); - - connector->io_service_.post( - std::bind(&MemifConnector::processInputBuffer, connector)); - - return 0; - -error: - err = memif_refill_queue(c->conn, qid, rx, 0); - - if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { - TRANSPORT_LOGE("memif_buffer_free: %s", memif_strerror(err)); - } - c->rx_buf_num -= rx; - - return 0; -} - -void MemifConnector::close() { - if (state_ != ConnectorState::CLOSED) { - disconnect_timer_->expiresFromNow(std::chrono::microseconds(50)); - disconnect_timer_->asyncWait([this](const std::error_code &ec) { - deleteMemif(); - event_reactor_.stop(); - work_.reset(); - }); - - if (memif_worker_ && memif_worker_->joinable()) { - memif_worker_->join(); - } - } -} - -void MemifConnector::send(const Packet::MemBufPtr &packet) { - { - utils::SpinLock::Acquire locked(write_msgs_lock_); - output_buffer_.push_back(packet); - } -#if CANCEL_TIMER - if (!timer_set_) { - timer_set_ = true; - send_timer_->expiresFromNow(std::chrono::microseconds(50)); - send_timer_->asyncWait( - std::bind(&MemifConnector::sendCallback, this, std::placeholders::_1)); - } -#endif -} - -int MemifConnector::doSend() { - std::size_t max = 0; - uint16_t n = 0; - std::size_t size = 0; - - { - utils::SpinLock::Acquire locked(write_msgs_lock_); - size = output_buffer_.size(); - } - - do { - max = size < MAX_MEMIF_BUFS ? size : MAX_MEMIF_BUFS; - - if (TRANSPORT_EXPECT_FALSE( - (n = bufferAlloc(max, memif_connection_->tx_qid)) < 0)) { - TRANSPORT_LOGE("Error allocating buffers."); - return -1; - } - - for (uint16_t i = 0; i < n; i++) { - utils::SpinLock::Acquire locked(write_msgs_lock_); - - auto packet = output_buffer_.front().get(); - const utils::MemBuf *current = packet; - std::size_t offset = 0; - uint8_t *shared_buffer = - reinterpret_cast(memif_connection_->tx_bufs[i].data); - do { - std::memcpy(shared_buffer + offset, current->data(), current->length()); - offset += current->length(); - current = current->next(); - } while (current != packet); - - memif_connection_->tx_bufs[i].len = uint32_t(offset); - - output_buffer_.pop_front(); - } - - txBurst(memif_connection_->tx_qid); - - utils::SpinLock::Acquire locked(write_msgs_lock_); - size = output_buffer_.size(); - } while (size > 0); - - return 0; -} - -void MemifConnector::send(const uint8_t *packet, std::size_t len, - const PacketSentCallback &packet_sent) { - throw errors::NotImplementedException(); -} - -} // end namespace core - -} // end namespace transport - -#endif // __vpp__ diff --git a/libtransport/src/hicn/transport/core/memif_connector.h b/libtransport/src/hicn/transport/core/memif_connector.h deleted file mode 100644 index bf4e2d56c..000000000 --- a/libtransport/src/hicn/transport/core/memif_connector.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -//#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#ifdef __vpp__ - -#define _Static_assert static_assert - -namespace transport { - -namespace core { - -typedef struct memif_connection memif_connection_t; - -#define APP_NAME "libtransport" -#define IF_NAME "vpp_connection" - -#define MEMIF_BUF_SIZE 2048 -#define MEMIF_LOG2_RING_SIZE 11 -#define MAX_MEMIF_BUFS (1 << MEMIF_LOG2_RING_SIZE) - -class MemifConnector : public Connector { - typedef void *memif_conn_handle_t; - - public: - MemifConnector(PacketReceivedCallback &&receive_callback, - OnReconnect &&on_reconnect_callback, - asio::io_service &io_service, - std::string app_name = "Libtransport"); - - ~MemifConnector() override; - - void send(const Packet::MemBufPtr &packet) override; - - void send(const uint8_t *packet, std::size_t len, - const PacketSentCallback &packet_sent = 0) override; - - void close() override; - - void connect(uint32_t memif_id, long memif_mode); - - TRANSPORT_ALWAYS_INLINE uint32_t getMemifId() { return memif_id_; }; - - private: - void init(); - - int doSend(); - - int createMemif(uint32_t index, uint8_t mode, char *s); - - uint32_t getMemifConfiguration(); - - int deleteMemif(); - - static int controlFdUpdate(int fd, uint8_t events, void *private_ctx); - - static int onConnect(memif_conn_handle_t conn, void *private_ctx); - - static int onDisconnect(memif_conn_handle_t conn, void *private_ctx); - - static int onInterrupt(memif_conn_handle_t conn, void *private_ctx, - uint16_t qid); - - void threadMain(); - - int txBurst(uint16_t qid); - - int bufferAlloc(long n, uint16_t qid); - - void sendCallback(const std::error_code &ec); - - void processInputBuffer(); - - private: - static utils::EpollEventReactor main_event_reactor_; - static std::unique_ptr main_worker_; - - int epfd; - std::unique_ptr memif_worker_; - utils::EpollEventReactor event_reactor_; - std::atomic_bool timer_set_; - std::unique_ptr send_timer_; - std::unique_ptr disconnect_timer_; - asio::io_service &io_service_; - std::unique_ptr work_; - uint32_t packet_counter_; - std::unique_ptr memif_connection_; - uint16_t tx_buf_counter_; - - PacketRing input_buffer_; - bool is_reconnection_; - bool data_available_; - uint32_t memif_id_; - uint8_t memif_mode_; - std::string app_name_; - uint16_t transmission_index_; - utils::SpinLock write_msgs_lock_; - std::string socket_filename_; - - static std::once_flag flag_; -}; - -} // end namespace core - -} // end namespace transport - -#endif // __vpp__ \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/memif_vapi.c b/libtransport/src/hicn/transport/core/memif_vapi.c deleted file mode 100644 index 11cf42441..000000000 --- a/libtransport/src/hicn/transport/core/memif_vapi.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * 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. - */ -#include - -#ifdef __vpp__ - -#include -#include -#include -#include -#include -#include -#include -#include - -DEFINE_VAPI_MSG_IDS_MEMIF_API_JSON - -static vapi_error_e memif_details_cb(vapi_ctx_t ctx, - void *callback_ctx, - vapi_error_e rv, - bool is_last, - vapi_payload_memif_details *reply) { - uint32_t *last_memif_id = (uint32_t *)callback_ctx; - uint32_t current_memif_id = 0; - if (reply != NULL) { - current_memif_id = reply->id; - } - else { - return rv; - } - - if (current_memif_id >= *last_memif_id) { - *last_memif_id = current_memif_id + 1; - } - - return rv; -} - -int memif_vapi_get_next_memif_id(vapi_ctx_t ctx, - uint32_t *memif_id) { - vapi_lock(); - vapi_msg_memif_dump * msg = vapi_alloc_memif_dump(ctx); - int ret = vapi_memif_dump(ctx, msg, memif_details_cb, memif_id); - vapi_unlock(); - return ret; -} - -static vapi_error_e memif_create_cb(vapi_ctx_t ctx, - void *callback_ctx, - vapi_error_e rv, - bool is_last, - vapi_payload_memif_create_reply *reply) { - memif_output_params_t *output_params = (memif_output_params_t *)callback_ctx; - - if (reply == NULL) - return rv; - - output_params->sw_if_index = reply->sw_if_index; - - return rv; -} - -int memif_vapi_create_memif(vapi_ctx_t ctx, - memif_create_params_t *input_params, - memif_output_params_t *output_params) { - vapi_lock(); - vapi_msg_memif_create * msg = vapi_alloc_memif_create(ctx); - - int ret = 0; - if (input_params->socket_id == ~0) { - // invalid socket-id - ret = -1; - goto END; - } - - if (!is_pow2(input_params->ring_size)) { - // ring size must be power of 2 - ret = -1; - goto END; - } - - if (input_params->rx_queues > 255 || input_params->rx_queues < 1) { - // rx queue must be between 1 - 255 - ret = -1; - goto END; - } - - if (input_params->tx_queues > 255 || input_params->tx_queues < 1) { - // tx queue must be between 1 - 255 - ret = -1; - goto END; - } - - msg->payload.role = input_params->role; - msg->payload.mode = input_params->mode; - msg->payload.rx_queues = input_params->rx_queues; - msg->payload.tx_queues = input_params->tx_queues; - msg->payload.id = input_params->id; - msg->payload.socket_id = input_params->socket_id; - msg->payload.ring_size = input_params->ring_size; - msg->payload.buffer_size = input_params->buffer_size; - - ret = vapi_memif_create(ctx, msg, memif_create_cb, output_params); - END: - vapi_unlock(); - return ret; -} - -static vapi_error_e memif_delete_cb(vapi_ctx_t ctx, - void *callback_ctx, - vapi_error_e rv, - bool is_last, - vapi_payload_memif_delete_reply *reply) { - if(reply == NULL) - return rv; - - return reply->retval; -} - -int memif_vapi_delete_memif(vapi_ctx_t ctx, - uint32_t sw_if_index) { - vapi_lock(); - vapi_msg_memif_delete * msg = vapi_alloc_memif_delete(ctx); - - msg->payload.sw_if_index = sw_if_index; - - int ret = vapi_memif_delete(ctx, msg, memif_delete_cb, NULL); - vapi_unlock(); - return ret; -} - -#endif // __vpp__ diff --git a/libtransport/src/hicn/transport/core/memif_vapi.h b/libtransport/src/hicn/transport/core/memif_vapi.h deleted file mode 100644 index c045cf093..000000000 --- a/libtransport/src/hicn/transport/core/memif_vapi.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -#ifdef __vpp__ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include "stdint.h" - -typedef struct memif_create_params_s { - uint8_t role; - uint8_t mode; - uint8_t rx_queues; - uint8_t tx_queues; - uint32_t id; - uint32_t socket_id; - uint8_t secret[24]; - uint32_t ring_size; - uint16_t buffer_size; - uint8_t hw_addr[6]; -} memif_create_params_t; - -typedef struct memif_output_params_s { - uint32_t sw_if_index; -} memif_output_params_t; - -int memif_vapi_get_next_memif_id(vapi_ctx_t ctx, - uint32_t *memif_id); - -int memif_vapi_create_memif(vapi_ctx_t ctx, - memif_create_params_t *input_params, - memif_output_params_t *output_params); - -int memif_vapi_delete_memif(vapi_ctx_t ctx, - uint32_t sw_if_index); - -#ifdef __cplusplus -} -#endif - -#endif // __vpp__ \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/name.cc b/libtransport/src/hicn/transport/core/name.cc deleted file mode 100644 index 85e2b8565..000000000 --- a/libtransport/src/hicn/transport/core/name.cc +++ /dev/null @@ -1,230 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include -#include -#include -#include - -namespace transport { - -namespace core { - -Name::Name() { name_ = {}; } - -Name::Name(int family, const uint8_t *ip_address, std::uint32_t suffix) - : name_({}) { - name_.type = HNT_UNSPEC; - std::size_t length; - uint8_t *dst = NULL; - - if (family == AF_INET) { - dst = name_.ip4.prefix_as_u8; - length = IPV4_ADDR_LEN; - name_.type = HNT_CONTIGUOUS_V4; - } else if (family == AF_INET6) { - dst = name_.ip6.prefix_as_u8; - length = IPV6_ADDR_LEN; - name_.type = HNT_CONTIGUOUS_V6; - } else { - throw errors::RuntimeException("Specified name family does not exist."); - } - - std::memcpy(dst, ip_address, length); - *reinterpret_cast(dst + length) = suffix; -} - -Name::Name(const char *name, uint32_t segment) { - name_.type = HNT_UNSPEC; - if (hicn_name_create(name, segment, &name_) < 0) { - throw errors::InvalidIpAddressException(); - } -} - -Name::Name(const std::string &uri, uint32_t segment) - : Name(uri.c_str(), segment) {} - -Name::Name(const std::string &uri) { - name_.type = HNT_UNSPEC; - utils::StringTokenizer tokenizer(uri, "|"); - std::string ip_address; - std::string seq_number; - - ip_address = tokenizer.nextToken(); - - try { - seq_number = tokenizer.nextToken(); - } catch (errors::TokenizerException &) { - seq_number = "0"; - } - - if (hicn_name_create(ip_address.c_str(), (uint32_t)atoi(seq_number.c_str()), - &name_) < 0) { - throw errors::InvalidIpAddressException(); - } -} - -Name::Name(const Name &name) { this->name_ = name.name_; } - -Name &Name::operator=(const Name &name) { - if (hicn_name_copy(&this->name_, &name.name_) < 0) { - throw errors::MalformedNameException(); - } - - return *this; -} - -bool Name::operator==(const Name &name) const { - return this->equals(name, true); -} - -bool Name::operator!=(const Name &name) const { - return !this->operator==(name); -} - -Name::operator bool() const { - return bool(hicn_name_empty((hicn_name_t *)&name_)); -} - -bool Name::equals(const Name &name, bool consider_segment) const { - return !hicn_name_compare(&name_, &name.name_, consider_segment); -} - -std::string Name::toString() const { - char *name = new char[100]; - int ret = hicn_name_ntop(&name_, name, standard_name_string_length); - if (ret < 0) { - throw errors::MalformedNameException(); - } - std::string name_string(name); - delete[] name; - - return name_string; -} - -uint32_t Name::getHash32(bool consider_suffix) const { - uint32_t hash; - if (hicn_name_hash(&name_, &hash, consider_suffix) < 0) { - throw errors::RuntimeException("Error computing the hash of the name!"); - } - return hash; -} - -void Name::clear() { name_.type = HNT_UNSPEC; }; - -Name::Type Name::getType() const { return name_.type; } - -uint32_t Name::getSuffix() const { - uint32_t ret = 0; - if (hicn_name_get_seq_number((hicn_name_t *)&name_, &ret) < 0) { - throw errors::RuntimeException( - "Impossible to retrieve the sequence number from the name."); - } - return ret; -} - -Name &Name::setSuffix(uint32_t seq_number) { - if (hicn_name_set_seq_number(&name_, seq_number) < 0) { - throw errors::RuntimeException( - "Impossible to set the sequence number to the name."); - } - - return *this; -} - -std::shared_ptr Name::getAddress() const { - Sockaddr *ret = nullptr; - - switch (name_.type) { - case HNT_CONTIGUOUS_V4: - case HNT_IOV_V4: - ret = (Sockaddr *)new Sockaddr4; - break; - case HNT_CONTIGUOUS_V6: - case HNT_IOV_V6: - ret = (Sockaddr *)new Sockaddr6; - break; - default: - throw errors::MalformedNameException(); - } - - if (hicn_name_to_sockaddr_address((hicn_name_t *)&name_, ret) < 0) { - throw errors::MalformedNameException(); - } - - return std::shared_ptr(ret); -} - -ip_prefix_t Name::toIpAddress() const { - ip_prefix_t ret; - std::memset(&ret, 0, sizeof(ret)); - - if (hicn_name_to_ip_prefix(&name_, &ret) < 0) { - throw errors::InvalidIpAddressException(); - } - - return ret; -} - -int Name::getAddressFamily() const { - int ret = 0; - - if (hicn_name_get_family(&name_, &ret) < 0) { - throw errors::InvalidIpAddressException(); - } - - return ret; -} - -void Name::copyToDestination(uint8_t *destination, bool include_suffix) const { - if (hicn_name_copy_to_destination(destination, &name_, include_suffix) < 0) { - throw errors::RuntimeException( - "Impossibe to copy the name into the " - "provided destination"); - } -} - -std::ostream &operator<<(std::ostream &os, const Name &name) { - const std::string &str = name.toString(); - // os << "core:/"; - os << str; - - return os; -} - -size_t hash::operator()( - const transport::core::Name &name) const { - return name.getHash32(false); -} - -size_t compare2::operator()( - const transport::core::Name &name1, - const transport::core::Name &name2) const { - return name1.equals(name2, false); -} - -} // end namespace core - -} // end namespace transport - -namespace std { -size_t hash::operator()( - const transport::core::Name &name) const { - return name.getHash32(); -} - -} // end namespace std diff --git a/libtransport/src/hicn/transport/core/name.h b/libtransport/src/hicn/transport/core/name.h deleted file mode 100644 index ea72797ad..000000000 --- a/libtransport/src/hicn/transport/core/name.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include - -#include -#include -#include -#include - -extern "C" { -#ifndef _WIN32 -TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat") -#endif -#include -}; - -#include - -namespace transport { - -namespace core { - -typedef struct sockaddr_in6 Sockaddr6; -typedef struct sockaddr_in Sockaddr4; -typedef struct sockaddr Sockaddr; - -enum class HashAlgorithm : uint8_t; - -class Name { - friend class Packet; - friend class ContentObject; - friend class Interest; - - static const uint32_t standard_name_string_length = 100; - - public: - using NameStruct = hicn_name_t; - using Type = hicn_name_type_t; - - Name(); - - /** - * @brief Create name - * @param name The null-terminated URI string - */ - Name(const char *name, uint32_t segment); - - Name(int family, const uint8_t *ip_address, std::uint32_t suffix = 0); - - Name(const std::string &uri, uint32_t segment); - - Name(const std::string &uri); - - Name(const Name &name); - - Name &operator=(const Name &name); - - bool operator==(const Name &name) const; - - bool operator!=(const Name &name) const; - - operator bool() const; - - std::string toString() const; - - bool equals(const Name &name, bool consider_segment = true) const; - - uint32_t getHash32(bool consider_suffix = true) const; - - void clear(); - - Type getType() const; - - uint32_t getSuffix() const; - - std::shared_ptr getAddress() const; - - Name &setSuffix(uint32_t seq_number); - - ip_prefix_t toIpAddress() const; - - void copyToDestination(uint8_t *destination, - bool include_suffix = false) const; - - int getAddressFamily() const; - - private: - TRANSPORT_ALWAYS_INLINE const NameStruct *getConstStructReference() const { - return &name_; - } - - TRANSPORT_ALWAYS_INLINE NameStruct *getStructReference() { return &name_; } - - NameStruct name_; -}; - -std::ostream &operator<<(std::ostream &os, const Name &name); - -template -struct hash {}; - -template <> -struct hash { - size_t operator()(const transport::core::Name &name) const; -}; - -template -struct compare2 {}; - -template <> -struct compare2 { - size_t operator()(const transport::core::Name &name1, const transport::core::Name &name2) const; -}; - -} // end namespace core - -} // end namespace transport - - -namespace std { -template <> -struct hash { - size_t operator()(const transport::core::Name &name) const; -}; - -} // end namespace std diff --git a/libtransport/src/hicn/transport/core/packet.cc b/libtransport/src/hicn/transport/core/packet.cc deleted file mode 100644 index 817f8de66..000000000 --- a/libtransport/src/hicn/transport/core/packet.cc +++ /dev/null @@ -1,607 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include -#include - -extern "C" { -#ifndef _WIN32 -TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat") -#endif -#include -} - -namespace transport { - -namespace core { - -const core::Name Packet::base_name("0::0|0"); - -Packet::Packet(Format format) - : packet_(utils::MemBuf::create(getHeaderSizeFromFormat(format, 256)) - .release()), - packet_start_(reinterpret_cast(packet_->writableData())), - header_head_(packet_.get()), - payload_head_(nullptr), - format_(format) { - if (hicn_packet_init_header(format, packet_start_) < 0) { - throw errors::RuntimeException("Unexpected error initializing the packet."); - } - - packet_->append(getHeaderSizeFromFormat(format_)); -} - -Packet::Packet(MemBufPtr &&buffer) - : packet_(std::move(buffer)), - packet_start_(reinterpret_cast(packet_->writableData())), - header_head_(packet_.get()), - payload_head_(nullptr), - format_(getFormatFromBuffer(packet_->writableData())) {} - -Packet::Packet(const uint8_t *buffer, std::size_t size) - : Packet(MemBufPtr(utils::MemBuf::copyBuffer(buffer, size).release())) {} - -Packet::Packet(Packet &&other) - : packet_(std::move(other.packet_)), - packet_start_(other.packet_start_), - header_head_(other.header_head_), - payload_head_(other.payload_head_), - format_(other.format_) { - other.packet_start_ = nullptr; - other.header_head_ = nullptr; - other.payload_head_ = nullptr; - other.format_ = HF_UNSPEC; -} - -Packet::~Packet() {} - -std::size_t Packet::getHeaderSizeFromFormat(Format format, - size_t signature_size) { - std::size_t header_length; - hicn_packet_get_header_length_from_format(format, &header_length); - int is_ah = _is_ah(format); - return is_ah * (header_length + signature_size) + (!is_ah) * header_length; -} - -std::size_t Packet::getHeaderSizeFromBuffer(Format format, - const uint8_t *buffer) { - size_t header_length; - if (hicn_packet_get_header_length(format, (hicn_header_t *)buffer, - &header_length) < 0) { - throw errors::MalformedPacketException(); - } - return header_length; -} - -bool Packet::isInterest(const uint8_t *buffer) { - bool is_interest = false; - - if (TRANSPORT_EXPECT_FALSE(hicn_packet_test_ece((const hicn_header_t *)buffer, - &is_interest) < 0)) { - throw errors::RuntimeException( - "Impossible to retrieve ece flag from packet"); - } - - return !is_interest; -} - -Packet::Format Packet::getFormatFromBuffer(const uint8_t *buffer) { - Format format = HF_UNSPEC; - - if (TRANSPORT_EXPECT_FALSE( - hicn_packet_get_format((const hicn_header_t *)buffer, &format) < 0)) { - throw errors::MalformedPacketException(); - } - - return format; -} - -std::size_t Packet::getPayloadSizeFromBuffer(Format format, - const uint8_t *buffer) { - std::size_t payload_length; - if (TRANSPORT_EXPECT_FALSE( - hicn_packet_get_payload_length(format, (hicn_header_t *)buffer, - &payload_length) < 0)) { - throw errors::MalformedPacketException(); - } - - return payload_length; -} - -void Packet::replace(MemBufPtr &&buffer) { - packet_ = std::move(buffer); - packet_start_ = reinterpret_cast(packet_->writableData()); - header_head_ = packet_.get(); - payload_head_ = nullptr; - format_ = getFormatFromBuffer(reinterpret_cast(packet_start_)); -} - -std::size_t Packet::payloadSize() const { - return getPayloadSizeFromBuffer(format_, - reinterpret_cast(packet_start_)); -} - -std::size_t Packet::headerSize() const { - return getHeaderSizeFromBuffer(format_, - reinterpret_cast(packet_start_)); -} - -Packet &Packet::appendPayload(std::unique_ptr &&payload) { - separateHeaderPayload(); - - if (!payload_head_) { - payload_head_ = payload.get(); - } - - header_head_->prependChain(std::move(payload)); - updateLength(); - return *this; -} - -Packet &Packet::appendPayload(const uint8_t *buffer, std::size_t length) { - return appendPayload(utils::MemBuf::copyBuffer(buffer, length)); -} - -Packet &Packet::appendHeader(std::unique_ptr &&header) { - separateHeaderPayload(); - - if (!payload_head_) { - header_head_->prependChain(std::move(header)); - } else { - payload_head_->prependChain(std::move(header)); - } - - updateLength(); - return *this; -} - -Packet &Packet::appendHeader(const uint8_t *buffer, std::size_t length) { - return appendHeader(utils::MemBuf::copyBuffer(buffer, length)); -} - -std::unique_ptr Packet::getPayload() const { - const_cast(this)->separateHeaderPayload(); - - // Hopefully the payload is contiguous - if (TRANSPORT_EXPECT_FALSE(payload_head_ && - payload_head_->next() != header_head_)) { - payload_head_->gather(payloadSize()); - } - - return payload_head_->cloneOne(); -} - -Packet &Packet::updateLength(std::size_t length) { - std::size_t total_length = length; - - for (utils::MemBuf *current = payload_head_; - current && current != header_head_; current = current->next()) { - total_length += current->length(); - } - - if (hicn_packet_set_payload_length(format_, packet_start_, total_length) < - 0) { - throw errors::RuntimeException("Error setting the packet payload."); - } - - return *this; -} - -PayloadType Packet::getPayloadType() const { - hicn_payload_type_t ret = HPT_UNSPEC; - - if (hicn_packet_get_payload_type(packet_start_, &ret) < 0) { - throw errors::RuntimeException("Impossible to retrieve payload type."); - } - - return PayloadType(ret); -} - -Packet &Packet::setPayloadType(PayloadType payload_type) { - if (hicn_packet_set_payload_type(packet_start_, - hicn_payload_type_t(payload_type)) < 0) { - throw errors::RuntimeException("Error setting payload type of the packet."); - } - - return *this; -} - -Packet::Format Packet::getFormat() const { - if (format_ == HF_UNSPEC) { - if (hicn_packet_get_format(packet_start_, &format_) < 0) { - throw errors::MalformedPacketException(); - } - } - - return format_; -} - -const std::shared_ptr Packet::acquireMemBufReference() const { - return packet_; -} - -void Packet::dump() const { - const_cast(this)->separateHeaderPayload(); - - std::cout << "HEADER -- Length: " << headerSize() << std::endl; - hicn_packet_dump((uint8_t *)header_head_->data(), headerSize()); - - std::cout << std::endl << "PAYLOAD -- Length: " << payloadSize() << std::endl; - for (utils::MemBuf *current = payload_head_; - current && current != header_head_; current = current->next()) { - std::cout << "MemBuf Length: " << current->length() << std::endl; - hicn_packet_dump((uint8_t *)current->data(), current->length()); - } -} - -void Packet::setSignatureSize(std::size_t size_bytes) { - int ret = hicn_packet_set_signature_size(format_, packet_start_, size_bytes); - - if (ret < 0) { - throw errors::RuntimeException("Packet without Authentication Header."); - } - - packet_->append(size_bytes); - updateLength(); -} - -uint8_t *Packet::getSignature() const { - uint8_t *signature; - int ret = hicn_packet_get_signature(format_, packet_start_, &signature); - - if (ret < 0) { - throw errors::RuntimeException("Packet without Authentication Header."); - } - - return signature; -} - -std::size_t Packet::getSignatureSize() const { - size_t size_bytes; - int ret = hicn_packet_get_signature_size(format_, packet_start_, &size_bytes); - - if (ret < 0) { - throw errors::RuntimeException("Packet without Authentication Header."); - } - - return size_bytes; -} - -void Packet::setSignatureTimestamp(const uint64_t ×tamp) { - int ret = - hicn_packet_set_signature_timestamp(format_, packet_start_, timestamp); - - if (ret < 0) { - throw errors::RuntimeException("Error setting the signature timestamp."); - } -} - -uint64_t Packet::getSignatureTimestamp() const { - uint64_t return_value; - int ret = hicn_packet_get_signature_timestamp(format_, packet_start_, - &return_value); - - if (ret < 0) { - throw errors::RuntimeException("Error getting the signature timestamp."); - } - - return return_value; -} - -void Packet::setValidationAlgorithm( - const utils::CryptoSuite &validation_algorithm) { - int ret = hicn_packet_set_validation_algorithm(format_, packet_start_, - uint8_t(validation_algorithm)); - - if (ret < 0) { - throw errors::RuntimeException("Error setting the validation algorithm."); - } -} - -utils::CryptoSuite Packet::getValidationAlgorithm() const { - uint8_t return_value; - int ret = hicn_packet_get_validation_algorithm(format_, packet_start_, - &return_value); - - if (ret < 0) { - throw errors::RuntimeException("Error getting the validation algorithm."); - } - - return utils::CryptoSuite(return_value); -} - -void Packet::setKeyId(const utils::KeyId &key_id) { - int ret = hicn_packet_set_key_id(format_, packet_start_, key_id.first); - - if (ret < 0) { - throw errors::RuntimeException("Error setting the key id."); - } -} - -utils::KeyId Packet::getKeyId() const { - utils::KeyId return_value; - int ret = hicn_packet_get_key_id(format_, packet_start_, &return_value.first, - &return_value.second); - - if (ret < 0) { - throw errors::RuntimeException("Error getting the validation algorithm."); - } - - return return_value; -} - -utils::CryptoHash Packet::computeDigest(HashAlgorithm algorithm) const { - utils::CryptoHasher hasher(static_cast(algorithm)); - hasher.init(); - - // Copy IP+TCP/ICMP header before zeroing them - hicn_header_t header_copy; - - hicn_packet_copy_header(format_, packet_start_, &header_copy, false); - - const_cast(this)->resetForHash(); - - auto current = header_head_; - do { - hasher.updateBytes(current->data(), current->length()); - current = current->next(); - } while (current != header_head_); - - hicn_packet_copy_header(format_, &header_copy, packet_start_, false); - - return hasher.finalize(); -} - -void Packet::setChecksum() { - uint16_t partial_csum = 0; - - for (utils::MemBuf *current = header_head_->next(); - current && current != header_head_; current = current->next()) { - if (partial_csum != 0) { - partial_csum = ~partial_csum; - } - partial_csum = csum(current->data(), current->length(), partial_csum); - } - if (hicn_packet_compute_header_checksum(format_, packet_start_, - partial_csum) < 0) { - throw errors::MalformedPacketException(); - } -} - -bool Packet::checkIntegrity() const { - if (hicn_packet_check_integrity(format_, packet_start_) < 0) { - return false; - } - - return true; -} - -Packet &Packet::setSyn() { - if (hicn_packet_set_syn(packet_start_) < 0) { - throw errors::RuntimeException("Error setting syn bit in the packet."); - } - - return *this; -} - -Packet &Packet::resetSyn() { - if (hicn_packet_reset_syn(packet_start_) < 0) { - throw errors::RuntimeException("Error resetting syn bit in the packet."); - } - - return *this; -} - -bool Packet::testSyn() const { - bool res = false; - if (hicn_packet_test_syn(packet_start_, &res) < 0) { - throw errors::RuntimeException("Error testing syn bit in the packet."); - } - - return res; -} - -Packet &Packet::setAck() { - if (hicn_packet_set_ack(packet_start_) < 0) { - throw errors::RuntimeException("Error setting ack bit in the packet."); - } - - return *this; -} - -Packet &Packet::resetAck() { - if (hicn_packet_reset_ack(packet_start_) < 0) { - throw errors::RuntimeException("Error resetting ack bit in the packet."); - } - - return *this; -} - -bool Packet::testAck() const { - bool res = false; - if (hicn_packet_test_ack(packet_start_, &res) < 0) { - throw errors::RuntimeException("Error testing ack bit in the packet."); - } - - return res; -} - -Packet &Packet::setRst() { - if (hicn_packet_set_rst(packet_start_) < 0) { - throw errors::RuntimeException("Error setting rst bit in the packet."); - } - - return *this; -} - -Packet &Packet::resetRst() { - if (hicn_packet_reset_rst(packet_start_) < 0) { - throw errors::RuntimeException("Error resetting rst bit in the packet."); - } - - return *this; -} - -bool Packet::testRst() const { - bool res = false; - if (hicn_packet_test_rst(packet_start_, &res) < 0) { - throw errors::RuntimeException("Error testing rst bit in the packet."); - } - - return res; -} - -Packet &Packet::setFin() { - if (hicn_packet_set_fin(packet_start_) < 0) { - throw errors::RuntimeException("Error setting fin bit in the packet."); - } - - return *this; -} - -Packet &Packet::resetFin() { - if (hicn_packet_reset_fin(packet_start_) < 0) { - throw errors::RuntimeException("Error resetting fin bit in the packet."); - } - - return *this; -} - -bool Packet::testFin() const { - bool res = false; - if (hicn_packet_test_fin(packet_start_, &res) < 0) { - throw errors::RuntimeException("Error testing fin bit in the packet."); - } - - return res; -} - -Packet &Packet::resetFlags() { - resetSyn(); - resetAck(); - resetRst(); - resetFin(); - - return *this; -} - -std::string Packet::printFlags() const { - std::string flags = ""; - if (testSyn()) { - flags += "S"; - } - if (testAck()) { - flags += "A"; - } - if (testRst()) { - flags += "R"; - } - if (testFin()) { - flags += "F"; - } - return flags; -} - -Packet &Packet::setSrcPort(uint16_t srcPort) { - if (hicn_packet_set_src_port(packet_start_, srcPort) < 0) { - throw errors::RuntimeException("Error setting source port in the packet."); - } - - return *this; -} - -Packet &Packet::setDstPort(uint16_t dstPort) { - if (hicn_packet_set_dst_port(packet_start_, dstPort) < 0) { - throw errors::RuntimeException( - "Error setting destination port in the packet."); - } - - return *this; -} - -uint16_t Packet::getSrcPort() const { - uint16_t port = 0; - - if (hicn_packet_get_src_port(packet_start_, &port) < 0) { - throw errors::RuntimeException("Error reading source port in the packet."); - } - - return port; -} - -uint16_t Packet::getDstPort() const { - uint16_t port = 0; - - if (hicn_packet_get_dst_port(packet_start_, &port) < 0) { - throw errors::RuntimeException( - "Error reading destination port in the packet."); - } - - return port; -} - -Packet &Packet::setTTL(uint8_t hops) { - if (hicn_packet_set_hoplimit(packet_start_, hops) < 0) { - throw errors::RuntimeException("Error setting TTL."); - } - - return *this; -} - -uint8_t Packet::getTTL() const { - uint8_t hops = 0; - if (hicn_packet_get_hoplimit(packet_start_, &hops) < 0) { - throw errors::RuntimeException("Error reading TTL."); - } - - return hops; -} - -void Packet::separateHeaderPayload() { - if (payload_head_) { - return; - } - - int signature_size = 0; - if (_is_ah(format_)) { - signature_size = (uint32_t)getSignatureSize(); - } - - auto header_size = getHeaderSizeFromFormat(format_, signature_size); - auto payload_length = packet_->length() - header_size; - - packet_->trimEnd(packet_->length()); - - auto payload = packet_->cloneOne(); - payload_head_ = payload.get(); - payload_head_->advance(header_size); - payload_head_->append(payload_length); - packet_->prependChain(std::move(payload)); - packet_->append(header_size); -} - -void Packet::resetPayload() { - if (packet_->isChained()) { - packet_->separateChain(packet_->next(), packet_->prev()); - payload_head_ = nullptr; - updateLength(); - } -} - -} // end namespace core - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/packet.h b/libtransport/src/hicn/transport/core/packet.h deleted file mode 100644 index 35c8606c9..000000000 --- a/libtransport/src/hicn/transport/core/packet.h +++ /dev/null @@ -1,203 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace utils { -class Signer; -class Verifier; -} // namespace utils - -namespace transport { - -namespace core { - -/* - * Basic IP packet, modelled as circular chain of buffers: - * Header = H - * Payload = P - * - * H_0 --> H_1 --> H_2 --> P_0 --> P_1 --> P_2 - * \_______________________________________| - */ - -class Packet : public std::enable_shared_from_this { - friend class utils::Signer; - friend class utils::Verifier; - - public: - using MemBufPtr = std::shared_ptr; - using Format = hicn_format_t; - static constexpr size_t default_mtu = 1500; - - /** - * Create new IP packet. Here we allocate just the header, - * the eventual payload will be added by prepending the payload buffer - * to the buffer chain whose the fist buffer is the header itself. - */ - Packet(Format format = HF_UNSPEC); - - /** - * Create new IP packet using raw buffer. - */ - Packet(const uint8_t *buffer, std::size_t size); - Packet(MemBufPtr &&buffer); - - /* - * Enforce zero-copy lifestyle. - */ - Packet(const Packet &other) = delete; - Packet &operator=(const Packet &other) = delete; - - /* - * Move constructor. - */ - Packet(Packet &&other); - - friend bool operator==(const Packet &l_packet, const Packet &r_packet); - - virtual ~Packet(); - - static std::size_t getHeaderSizeFromFormat(Format format, - std::size_t signature_size = 0); - - static std::size_t getHeaderSizeFromBuffer(Format format, - const uint8_t *buffer); - - static std::size_t getPayloadSizeFromBuffer(Format format, - const uint8_t *buffer); - - static bool isInterest(const uint8_t *buffer); - - static Format getFormatFromBuffer(const uint8_t *buffer); - - virtual void replace(MemBufPtr &&buffer); - - std::size_t payloadSize() const; - - std::size_t headerSize() const; - - const std::shared_ptr acquireMemBufReference() const; - - virtual const Name &getName() const = 0; - - virtual Name &getWritableName() = 0; - - virtual void setName(const Name &name) = 0; - - virtual void setName(Name &&name) = 0; - - virtual void setLifetime(uint32_t lifetime) = 0; - - virtual uint32_t getLifetime() const = 0; - - Packet &appendPayload(const uint8_t *buffer, std::size_t length); - - Packet &appendPayload(std::unique_ptr &&payload); - - Packet &appendHeader(std::unique_ptr &&header); - - Packet &appendHeader(const uint8_t *buffer, std::size_t length); - - std::unique_ptr getPayload() const; - - Packet &updateLength(std::size_t length = 0); - - PayloadType getPayloadType() const; - - Packet &setPayloadType(PayloadType payload_type); - - Format getFormat() const; - - void dump() const; - - virtual void setLocator(const ip_address_t &locator) = 0; - - virtual ip_address_t getLocator() const = 0; - - void setSignatureTimestamp(const uint64_t ×tamp); - - uint64_t getSignatureTimestamp() const; - - void setValidationAlgorithm(const utils::CryptoSuite &validation_algorithm); - - utils::CryptoSuite getValidationAlgorithm() const; - - void setKeyId(const utils::KeyId &key_id); - - utils::KeyId getKeyId() const; - - virtual utils::CryptoHash computeDigest(HashAlgorithm algorithm) const; - - void setChecksum(); - - bool checkIntegrity() const; - - Packet &setSyn(); - Packet &resetSyn(); - bool testSyn() const; - Packet &setAck(); - Packet &resetAck(); - bool testAck() const; - Packet &setRst(); - Packet &resetRst(); - bool testRst() const; - Packet &setFin(); - Packet &resetFin(); - bool testFin() const; - Packet &resetFlags(); - std::string printFlags() const; - - Packet &setSrcPort(uint16_t srcPort); - Packet &setDstPort(uint16_t dstPort); - uint16_t getSrcPort() const; - uint16_t getDstPort() const; - - Packet &setTTL(uint8_t hops); - uint8_t getTTL() const; - - void resetPayload(); - - private: - virtual void resetForHash() = 0; - void setSignatureSize(std::size_t size_bytes); - std::size_t getSignatureSize() const; - uint8_t *getSignature() const; - void separateHeaderPayload(); - - protected: - Name name_; - MemBufPtr packet_; - hicn_header_t *packet_start_; - utils::MemBuf *header_head_; - utils::MemBuf *payload_head_; - mutable Format format_; - - static const core::Name base_name; -}; - -} // end namespace core - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/payload_type.h b/libtransport/src/hicn/transport/core/payload_type.h deleted file mode 100644 index fa79db35a..000000000 --- a/libtransport/src/hicn/transport/core/payload_type.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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. - */ - -#pragma once - -namespace transport { - -namespace core { - -enum class PayloadType : uint16_t { - CONTENT_OBJECT = HPT_DATA, - MANIFEST = HPT_MANIFEST, -}; - -} // end namespace core - -} // end namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/pending_interest.cc b/libtransport/src/hicn/transport/core/pending_interest.cc deleted file mode 100644 index dbbd2c83e..000000000 --- a/libtransport/src/hicn/transport/core/pending_interest.cc +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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. - */ - -#include - -namespace transport { - -namespace core { - -PendingInterest::PendingInterest() - : interest_(nullptr, nullptr), - timer_(), - on_content_object_callback_(), - on_interest_timeout_callback_() {} - -PendingInterest::PendingInterest(Interest::Ptr &&interest, - std::unique_ptr &&timer) - : interest_(std::move(interest)), - timer_(std::move(timer)), - on_content_object_callback_(), - on_interest_timeout_callback_() {} - -PendingInterest::PendingInterest( - Interest::Ptr &&interest, OnContentObjectCallback &&on_content_object, - OnInterestTimeoutCallback &&on_interest_timeout, - std::unique_ptr &&timer) - : interest_(std::move(interest)), - timer_(std::move(timer)), - on_content_object_callback_(std::move(on_content_object)), - on_interest_timeout_callback_(std::move(on_interest_timeout)) {} - -PendingInterest::~PendingInterest() {} - -void PendingInterest::cancelTimer() { timer_->cancel(); } - -void PendingInterest::setInterest(Interest::Ptr &&interest) { - interest_ = std::move(interest); -} - -Interest::Ptr &&PendingInterest::getInterest() { return std::move(interest_); } - -const OnContentObjectCallback &PendingInterest::getOnDataCallback() const { - return on_content_object_callback_; -} - -void PendingInterest::setOnContentObjectCallback( - OnContentObjectCallback &&on_content_object) { - PendingInterest::on_content_object_callback_ = on_content_object; -} - -const OnInterestTimeoutCallback &PendingInterest::getOnTimeoutCallback() const { - return on_interest_timeout_callback_; -} - -void PendingInterest::setOnTimeoutCallback( - OnInterestTimeoutCallback &&on_interest_timeout) { - PendingInterest::on_interest_timeout_callback_ = on_interest_timeout; -} - -} // end namespace core - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/pending_interest.h b/libtransport/src/hicn/transport/core/pending_interest.h deleted file mode 100644 index c481cc200..000000000 --- a/libtransport/src/hicn/transport/core/pending_interest.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include - -namespace transport { - -namespace core { - -class HicnForwarderInterface; -class VPPForwarderInterface; -class RawSocketInterface; - -template -class Portal; - -typedef std::function - OnContentObjectCallback; -typedef std::function OnInterestTimeoutCallback; -typedef std::function TimerCallback; - -class PendingInterest { - friend class Portal; - friend class Portal; - friend class Portal; - - public: - using Ptr = utils::ObjectPool::Ptr; - PendingInterest(); - - PendingInterest(Interest::Ptr &&interest, - std::unique_ptr &&timer); - - PendingInterest(Interest::Ptr &&interest, - OnContentObjectCallback &&on_content_object, - OnInterestTimeoutCallback &&on_interest_timeout, - std::unique_ptr &&timer); - - ~PendingInterest(); - - template - TRANSPORT_ALWAYS_INLINE void startCountdown(Handler &&cb) { - timer_->expires_from_now( - std::chrono::milliseconds(interest_->getLifetime())); - timer_->async_wait(std::forward(cb)); - } - - void cancelTimer(); - - Interest::Ptr &&getInterest(); - - void setInterest(Interest::Ptr &&interest); - - const OnContentObjectCallback &getOnDataCallback() const; - - void setOnContentObjectCallback(OnContentObjectCallback &&on_content_object); - - const OnInterestTimeoutCallback &getOnTimeoutCallback() const; - - void setOnTimeoutCallback(OnInterestTimeoutCallback &&on_interest_timeout); - - private: - Interest::Ptr interest_; - std::unique_ptr timer_; - OnContentObjectCallback on_content_object_callback_; - OnInterestTimeoutCallback on_interest_timeout_callback_; -}; - -} // end namespace core - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/portal.h b/libtransport/src/hicn/transport/core/portal.h deleted file mode 100644 index c6e11ada6..000000000 --- a/libtransport/src/hicn/transport/core/portal.h +++ /dev/null @@ -1,695 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __vpp__ -#include -#endif - -#include -#include -#include -#include -#include -#include - -#define UNSET_CALLBACK 0 - -namespace transport { -namespace core { - -namespace portal_details { - -static constexpr uint32_t pool_size = 2048; - -class HandlerMemory { -#ifdef __vpp__ - static constexpr std::size_t memory_size = 1024 * 1024; - - public: - HandlerMemory() : index_(0) {} - - HandlerMemory(const HandlerMemory &) = delete; - HandlerMemory &operator=(const HandlerMemory &) = delete; - - TRANSPORT_ALWAYS_INLINE void *allocate(std::size_t size) { - return &storage_[index_++ % memory_size]; - } - - TRANSPORT_ALWAYS_INLINE void deallocate(void *pointer) {} - - private: - // Storage space used for handler-based custom memory allocation. - typename std::aligned_storage<128>::type storage_[memory_size]; - uint32_t index_; -#else - public: - HandlerMemory() {} - - HandlerMemory(const HandlerMemory &) = delete; - HandlerMemory &operator=(const HandlerMemory &) = delete; - - TRANSPORT_ALWAYS_INLINE void *allocate(std::size_t size) { - return ::operator new(size); - } - - TRANSPORT_ALWAYS_INLINE void deallocate(void *pointer) { - ::operator delete(pointer); - } -#endif -}; - -// The allocator to be associated with the handler objects. This allocator only -// needs to satisfy the C++11 minimal allocator requirements. -template -class HandlerAllocator { - public: - using value_type = T; - - explicit HandlerAllocator(HandlerMemory &mem) : memory_(mem) {} - - template - HandlerAllocator(const HandlerAllocator &other) noexcept - : memory_(other.memory_) {} - - TRANSPORT_ALWAYS_INLINE bool operator==(const HandlerAllocator &other) const - noexcept { - return &memory_ == &other.memory_; - } - - TRANSPORT_ALWAYS_INLINE bool operator!=(const HandlerAllocator &other) const - noexcept { - return &memory_ != &other.memory_; - } - - TRANSPORT_ALWAYS_INLINE T *allocate(std::size_t n) const { - return static_cast(memory_.allocate(sizeof(T) * n)); - } - - TRANSPORT_ALWAYS_INLINE void deallocate(T *p, std::size_t /*n*/) const { - return memory_.deallocate(p); - } - - private: - template - friend class HandlerAllocator; - - // The underlying memory. - HandlerMemory &memory_; -}; - -// Wrapper class template for handler objects to allow handler memory -// allocation to be customised. The allocator_type type and get_allocator() -// member function are used by the asynchronous operations to obtain the -// allocator. Calls to operator() are forwarded to the encapsulated handler. -template -class CustomAllocatorHandler { - public: - using allocator_type = HandlerAllocator; - - CustomAllocatorHandler(HandlerMemory &m, Handler h) - : memory_(m), handler_(h) {} - - allocator_type get_allocator() const noexcept { - return allocator_type(memory_); - } - - template - void operator()(Args &&... args) { - handler_(std::forward(args)...); - } - - private: - HandlerMemory &memory_; - Handler handler_; -}; - -// Helper function to wrap a handler object to add custom allocation. -template -inline CustomAllocatorHandler makeCustomAllocatorHandler( - HandlerMemory &m, Handler h) { - return CustomAllocatorHandler(m, h); -} - -class Pool { - public: - Pool(asio::io_service &io_service) : io_service_(io_service) { - increasePendingInterestPool(); - increaseInterestPool(); - increaseContentObjectPool(); - } - - TRANSPORT_ALWAYS_INLINE void increasePendingInterestPool() { - // Create pool of pending interests to reuse - for (uint32_t i = 0; i < pool_size; i++) { - pending_interests_pool_.add(new PendingInterest( - Interest::Ptr(nullptr), - std::make_unique(io_service_))); - } - } - - TRANSPORT_ALWAYS_INLINE void increaseInterestPool() { - // Create pool of interests to reuse - for (uint32_t i = 0; i < pool_size; i++) { - interest_pool_.add(new Interest()); - } - } - - TRANSPORT_ALWAYS_INLINE void increaseContentObjectPool() { - // Create pool of content object to reuse - for (uint32_t i = 0; i < pool_size; i++) { - content_object_pool_.add(new ContentObject()); - } - } - - PendingInterest::Ptr getPendingInterest() { - auto res = pending_interests_pool_.get(); - while (TRANSPORT_EXPECT_FALSE(!res.first)) { - increasePendingInterestPool(); - res = pending_interests_pool_.get(); - } - - return std::move(res.second); - } - - TRANSPORT_ALWAYS_INLINE ContentObject::Ptr getContentObject() { - auto res = content_object_pool_.get(); - while (TRANSPORT_EXPECT_FALSE(!res.first)) { - increaseContentObjectPool(); - res = content_object_pool_.get(); - } - - return std::move(res.second); - } - - TRANSPORT_ALWAYS_INLINE Interest::Ptr getInterest() { - auto res = interest_pool_.get(); - while (TRANSPORT_EXPECT_FALSE(!res.first)) { - increaseInterestPool(); - res = interest_pool_.get(); - } - - return std::move(res.second); - } - - private: - utils::ObjectPool pending_interests_pool_; - utils::ObjectPool content_object_pool_; - utils::ObjectPool interest_pool_; - asio::io_service &io_service_; -}; - -} // namespace portal_details - -using PendingInterestHashTable = - std::unordered_map; - -template -class BasicBindConfig { - static_assert(std::is_same::value, - "Prefix must be a Prefix type."); - - const uint32_t standard_cs_reserved = 5000; - - public: - template - BasicBindConfig(T &&prefix) - : prefix_(std::forward(prefix)), - content_store_reserved_(standard_cs_reserved) {} - - template - BasicBindConfig(T &&prefix, uint32_t cs_reserved) - : prefix_(std::forward(prefix)), - content_store_reserved_(cs_reserved) {} - - TRANSPORT_ALWAYS_INLINE const PrefixType &prefix() const { return prefix_; } - - TRANSPORT_ALWAYS_INLINE uint32_t csReserved() const { - return content_store_reserved_; - } - - private: - PrefixType prefix_; - uint32_t content_store_reserved_; -}; - -using BindConfig = BasicBindConfig; - -/** - * Portal is a opaque class which is used for sending/receiving interest/data - * packets over multiple kind of connector. The connector itself is defined by - * the template ForwarderInt, which is resolved at compile time. It is then not - * possible to decide at runtime what the connector will be. - * - * The tasks performed by portal are the following: - * - Sending/Receiving Interest packets - * - Sending/Receiving Data packets - * - Set timers (one per interest), in order to trigger events if an interest is - * not satisfied - * - Register a producer prefix to the local forwarder - * - * The way of working of portal is event-based, which means that data and - * interests are sent/received in a asynchronous manner, and the notifications - * are performed through callbacks. - * - * The portal class is not thread safe, appropriate locking is required by the - * users of this class. - */ -template -class Portal { - static_assert( - std::is_base_of, - ForwarderInt>::value, - "ForwarderInt must inherit from ForwarderInterface!"); - - public: - /** - * Consumer callback is an abstract class containing two methods to be - * implemented by a consumer application. - */ - class ConsumerCallback { - public: - virtual void onContentObject(Interest::Ptr &&i, ContentObject::Ptr &&c) = 0; - virtual void onTimeout(Interest::Ptr &&i) = 0; - }; - - /** - * Producer callback is an abstract class containing two methods to be - * implemented by a producer application. - */ - class ProducerCallback { - public: - virtual void onInterest(Interest::Ptr &&i) = 0; - }; - - Portal() : Portal(internal_io_service_) {} - - Portal(asio::io_service &io_service) - : io_service_(io_service), - packet_pool_(io_service), - app_name_("libtransport_application"), - consumer_callback_(nullptr), - producer_callback_(nullptr), - connector_(std::bind(&Portal::processIncomingMessages, this, - std::placeholders::_1), - std::bind(&Portal::setLocalRoutes, this), io_service_, - app_name_), - forwarder_interface_(connector_) {} - - /** - * Set the consumer callback. - * - * @param consumer_callback - The pointer to the ConsumerCallback object. - */ - void setConsumerCallback(ConsumerCallback *consumer_callback) { - consumer_callback_ = consumer_callback; - } - - /** - * Set the producer callback. - * - * @param producer_callback - The pointer to the ProducerCallback object. - */ - void setProducerCallback(ProducerCallback *producer_callback) { - producer_callback_ = producer_callback; - } - - /** - * Specify the output interface to use. This method will be useful in a future - * scenario where the library will be able to forward packets without - * connecting to a local forwarder. Now it is not used. - * - * @param output_interface - The output interface to use for - * forwarding/receiving packets. - */ - TRANSPORT_ALWAYS_INLINE void setOutputInterface( - const std::string &output_interface) { - forwarder_interface_.setOutputInterface(output_interface); - } - - /** - * Connect the transport to the local hicn forwarder. - * - * @param is_consumer - Boolean specifying if the application on top of portal - * is a consumer or a producer. - */ - TRANSPORT_ALWAYS_INLINE void connect(bool is_consumer = true) { - pending_interest_hash_table_.reserve(portal_details::pool_size); - forwarder_interface_.connect(is_consumer); - } - - /** - * Destructor. - */ - ~Portal() { killConnection(); } - - /** - * Check if there is already a pending interest for a given name. - * - * @param name - The interest name. - */ - TRANSPORT_ALWAYS_INLINE bool interestIsPending(const Name &name) { - auto it = - pending_interest_hash_table_.find(name.getHash32() + name.getSuffix()); - if (it != pending_interest_hash_table_.end()) { - return true; - } - - return false; - } - - /** - * Send an interest through to the local forwarder. - * - * @param interest - The pointer to the interest. The ownership of the - * interest is transferred by the caller to portal. - * - * @param on_content_object_callback - If the caller wishes to use a different - * callback to be called for this interest, it can set this parameter. - * Otherwise ConsumerCallback::onContentObject will be used. - * - * @param on_interest_timeout_callback - If the caller wishes to use a - * different callback to be called for this interest, it can set this - * parameter. Otherwise ConsumerCallback::onTimeout will be used. - */ - TRANSPORT_ALWAYS_INLINE void sendInterest( - Interest::Ptr &&interest, - OnContentObjectCallback &&on_content_object_callback = UNSET_CALLBACK, - OnInterestTimeoutCallback &&on_interest_timeout_callback = - UNSET_CALLBACK) { - uint32_t hash = - interest->getName().getHash32() + interest->getName().getSuffix(); - // Send it - forwarder_interface_.send(*interest); - - auto pending_interest = packet_pool_.getPendingInterest(); - pending_interest->setInterest(std::move(interest)); - pending_interest->setOnContentObjectCallback( - std::move(on_content_object_callback)); - pending_interest->setOnTimeoutCallback( - std::move(on_interest_timeout_callback)); - pending_interest->startCountdown(portal_details::makeCustomAllocatorHandler( - async_callback_memory_, std::bind(&Portal::timerHandler, - this, std::placeholders::_1, hash))); - - auto it = pending_interest_hash_table_.find(hash); - if (it != pending_interest_hash_table_.end()) { - it->second->cancelTimer(); - - // Get reference to interest packet in order to have it destroyed. - auto _int = it->second->getInterest(); - it->second = std::move(pending_interest); - } else { - pending_interest_hash_table_[hash] = std::move(pending_interest); - } - } - - /** - * Handler fot the timer set when the interest is sent. - * - * @param ec - Error code which says whether the timer expired or has been - * canceled upon data packet reception. - * - * @param hash - The index of the interest in the pending interest hash table. - */ - TRANSPORT_ALWAYS_INLINE void timerHandler(const std::error_code &ec, - uint32_t hash) { - bool is_stopped = io_service_.stopped(); - if (TRANSPORT_EXPECT_FALSE(is_stopped)) { - return; - } - - if (TRANSPORT_EXPECT_TRUE(!ec)) { - PendingInterestHashTable::iterator it = - pending_interest_hash_table_.find(hash); - if (it != pending_interest_hash_table_.end()) { - PendingInterest::Ptr ptr = std::move(it->second); - pending_interest_hash_table_.erase(it); - auto _int = ptr->getInterest(); - - if (ptr->getOnTimeoutCallback() != UNSET_CALLBACK) { - ptr->on_interest_timeout_callback_(std::move(_int)); - } else if (consumer_callback_) { - consumer_callback_->onTimeout(std::move(_int)); - } - } - } - } - - /** - * Register a producer name to the local forwarder and optionally set the - * content store size in a per-face manner. - * - * @param config - The configuration for the local forwarder binding. - */ - TRANSPORT_ALWAYS_INLINE void bind(const BindConfig &config) { - forwarder_interface_.setContentStoreSize(config.csReserved()); - served_namespaces_.push_back(config.prefix()); - - setLocalRoutes(); - } - - /** - * Start the event loop. This function blocks here and calls the callback set - * by the application upon interest/data received or timeout. - */ - TRANSPORT_ALWAYS_INLINE void runEventsLoop() { - if (io_service_.stopped()) { - io_service_.reset(); // ensure that run()/poll() will do some work - } - - io_service_.run(); - } - - /** - * Run one event and return. - */ - TRANSPORT_ALWAYS_INLINE void runOneEvent() { - if (io_service_.stopped()) { - io_service_.reset(); // ensure that run()/poll() will do some work - } - - io_service_.run_one(); - } - - /** - * Send a data packet to the local forwarder. As opposite to sendInterest, the - * ownership of the content object is not transferred to the portal. - * - * @param content_object - The data packet. - */ - TRANSPORT_ALWAYS_INLINE void sendContentObject( - ContentObject &content_object) { - forwarder_interface_.send(content_object); - } - - /** - * Stop the event loop, canceling all the pending events in the event queue. - * - * Beware that stopping the event loop DOES NOT disconnect the transport from - * the local forwarder, the connector underneath will stay connected. - */ - TRANSPORT_ALWAYS_INLINE void stopEventsLoop() { - if (!io_service_.stopped()) { - io_service_.dispatch([this]() { - clear(); - io_service_.stop(); - }); - } - } - - /** - * Disconnect the transport from the local forwarder. - */ - TRANSPORT_ALWAYS_INLINE void killConnection() { - forwarder_interface_.closeConnection(); - } - - /** - * Clear the pending interest hash table. - */ - TRANSPORT_ALWAYS_INLINE void clear() { - if (!io_service_.stopped()) { - io_service_.dispatch(std::bind(&Portal::doClear, this)); - } else { - doClear(); - } - } - - /** - * Get a reference to the io_service object. - */ - TRANSPORT_ALWAYS_INLINE asio::io_service &getIoService() { - return io_service_; - } - - /** - * Register a route to the local forwarder. - */ - TRANSPORT_ALWAYS_INLINE void registerRoute(Prefix &prefix) { - served_namespaces_.push_back(prefix); - if (connector_.isConnected()) { - forwarder_interface_.registerRoute(prefix); - } - } - - private: - /** - * Clear the pending interest hash table. - */ - TRANSPORT_ALWAYS_INLINE void doClear() { - for (auto &pend_interest : pending_interest_hash_table_) { - pend_interest.second->cancelTimer(); - - // Get interest packet from pending interest and do nothing with it. It - // will get destroyed as it goes out of scope. - auto _int = pend_interest.second->getInterest(); - } - - pending_interest_hash_table_.clear(); - } - - /** - * Callback called by the underlying connector upon reception of a packet from - * the local forwarder. - * - * @param packet_buffer - The bytes of the packet. - */ - TRANSPORT_ALWAYS_INLINE void processIncomingMessages( - Packet::MemBufPtr &&packet_buffer) { - bool is_stopped = io_service_.stopped(); - if (TRANSPORT_EXPECT_FALSE(is_stopped)) { - return; - } - - if (TRANSPORT_EXPECT_FALSE( - ForwarderInt::isControlMessage(packet_buffer->data()))) { - processControlMessage(std::move(packet_buffer)); - return; - } - - Packet::Format format = Packet::getFormatFromBuffer(packet_buffer->data()); - - if (TRANSPORT_EXPECT_TRUE(_is_tcp(format))) { - if (!Packet::isInterest(packet_buffer->data())) { - auto content_object = packet_pool_.getContentObject(); - content_object->replace(std::move(packet_buffer)); - processContentObject(std::move(content_object)); - } else { - auto interest = packet_pool_.getInterest(); - interest->replace(std::move(packet_buffer)); - processInterest(std::move(interest)); - } - } else { - TRANSPORT_LOGE("Received not supported packet. Ignoring it."); - } - } - - /** - * Callback called by the transport upon connection to the local forwarder. - * It register the prefixes in the served_namespaces_ list to the local - * forwarder. - */ - TRANSPORT_ALWAYS_INLINE void setLocalRoutes() { - for (auto &prefix : served_namespaces_) { - if (connector_.isConnected()) { - forwarder_interface_.registerRoute(prefix); - } - } - } - - TRANSPORT_ALWAYS_INLINE void processInterest(Interest::Ptr &&interest) { - // Interest for a producer - if (TRANSPORT_EXPECT_TRUE(producer_callback_ != nullptr)) { - producer_callback_->onInterest(std::move(interest)); - } - } - - /** - * Process a content object: - * - Check if the data packet was effectively requested by portal - * - Delete its timer - * - Pass packet to application - * - * @param content_object - The data packet - */ - TRANSPORT_ALWAYS_INLINE void processContentObject( - ContentObject::Ptr &&content_object) { - uint32_t hash = content_object->getName().getHash32() + - content_object->getName().getSuffix(); - - auto it = pending_interest_hash_table_.find(hash); - if (it != pending_interest_hash_table_.end()) { - PendingInterest::Ptr interest_ptr = std::move(it->second); - pending_interest_hash_table_.erase(it); - interest_ptr->cancelTimer(); - auto _int = interest_ptr->getInterest(); - - if (interest_ptr->getOnDataCallback() != UNSET_CALLBACK) { - interest_ptr->on_content_object_callback_(std::move(_int), - std::move(content_object)); - } else if (consumer_callback_) { - consumer_callback_->onContentObject(std::move(_int), - std::move(content_object)); - } - } - } - - /** - * Process a control message. Control messages are different depending on the - * connector, then the forwarder_interface will do the job of understanding - * them. - */ - TRANSPORT_ALWAYS_INLINE void processControlMessage( - Packet::MemBufPtr &&packet_buffer) { - forwarder_interface_.processControlMessageReply(std::move(packet_buffer)); - } - - private: - asio::io_service &io_service_; - asio::io_service internal_io_service_; - portal_details::Pool packet_pool_; - - std::string app_name_; - - PendingInterestHashTable pending_interest_hash_table_; - std::list served_namespaces_; - - ConsumerCallback *consumer_callback_; - ProducerCallback *producer_callback_; - - portal_details::HandlerMemory async_callback_memory_; - - typename ForwarderInt::ConnectorType connector_; - ForwarderInt forwarder_interface_; -}; - -} // namespace core - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/prefix.cc b/libtransport/src/hicn/transport/core/prefix.cc deleted file mode 100644 index 59898ab70..000000000 --- a/libtransport/src/hicn/transport/core/prefix.cc +++ /dev/null @@ -1,338 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include - -#ifndef _WIN32 -extern "C" { -#include -} -#else -#include -#endif - -#include -#include -#include - -#include - -namespace transport { - -namespace core { - -Prefix::Prefix() { std::memset(&ip_prefix_, 0, sizeof(ip_prefix_t)); } - -Prefix::Prefix(const char *prefix) : Prefix(std::string(prefix)) {} - -Prefix::Prefix(std::string &&prefix) : Prefix(prefix) {} - -Prefix::Prefix(const std::string &prefix) { - utils::StringTokenizer st(prefix, "/"); - - std::string ip_address = st.nextToken(); - int family = get_addr_family(ip_address.c_str()); - - std::string prefix_length = family == AF_INET6 ? "128" : "32"; - - if (st.hasMoreTokens()) { - prefix_length = st.nextToken(); - } - - buildPrefix(ip_address, uint16_t(atoi(prefix_length.c_str())), family); -} - -Prefix::Prefix(std::string &prefix, uint16_t prefix_length) { - int family = get_addr_family(prefix.c_str()); - buildPrefix(prefix, prefix_length, family); -} - -Prefix::Prefix(const core::Name &content_name, uint16_t prefix_length) { - int family = content_name.getAddressFamily(); - - if (!checkPrefixLengthAndAddressFamily(prefix_length, family)) { - throw errors::InvalidIpAddressException(); - } - - ip_prefix_ = content_name.toIpAddress(); - ip_prefix_.len = prefix_length; - ip_prefix_.family = family; -} - -void Prefix::buildPrefix(std::string &prefix, uint16_t prefix_length, - int family) { - if (!checkPrefixLengthAndAddressFamily(prefix_length, family)) { - throw errors::InvalidIpAddressException(); - } - - int ret; - switch (family) { - case AF_INET: - ret = inet_pton(AF_INET, prefix.c_str(), ip_prefix_.address.v4.buffer); - break; - case AF_INET6: - ret = inet_pton(AF_INET6, prefix.c_str(), ip_prefix_.address.v6.buffer); - break; - default: - throw errors::InvalidIpAddressException(); - } - - if (ret != 1) { - throw errors::InvalidIpAddressException(); - } - - ip_prefix_.len = prefix_length; - ip_prefix_.family = family; -} - -std::unique_ptr Prefix::toSockaddr() { - Sockaddr *ret = nullptr; - - switch (ip_prefix_.family) { - case AF_INET6: - ret = (Sockaddr *)new Sockaddr6; - break; - case AF_INET: - ret = (Sockaddr *)new Sockaddr4; - break; - default: - throw errors::InvalidIpAddressException(); - } - - if (ip_prefix_to_sockaddr(&ip_prefix_, ret) < 0) { - throw errors::InvalidIpAddressException(); - } - - return std::unique_ptr(ret); -} - -uint16_t Prefix::getPrefixLength() { return ip_prefix_.len; } - -Prefix &Prefix::setPrefixLength(uint16_t prefix_length) { - ip_prefix_.len = prefix_length; - return *this; -} - -int Prefix::getAddressFamily() { return ip_prefix_.family; } - -Prefix &Prefix::setAddressFamily(int address_family) { - ip_prefix_.family = address_family; - return *this; -} - -std::string Prefix::getNetwork() const { - if (!checkPrefixLengthAndAddressFamily(ip_prefix_.len, ip_prefix_.family)) { - throw errors::InvalidIpAddressException(); - } - - std::size_t size = - ip_prefix_.family == 4 + AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN; - - std::string network(size, 0); - - if (ip_prefix_ntop_short(&ip_prefix_, (char *)network.c_str(), size) < 0) { - throw errors::RuntimeException( - "Impossible to retrieve network from ip address."); - } - - return network; -} - -int Prefix::contains(const ip_address_t &content_name) const { - int res = - ip_address_cmp(&content_name, &(ip_prefix_.address), ip_prefix_.family); - - if (ip_prefix_.len != (ip_prefix_.family == AF_INET6 ? IPV6_ADDR_LEN_BITS - : IPV4_ADDR_LEN_BITS)) { - const u8 *ip_prefix_buffer = - ip_address_get_buffer(&(ip_prefix_.address), ip_prefix_.family); - const u8 *content_name_buffer = - ip_address_get_buffer(&content_name, ip_prefix_.family); - uint8_t mask = 0xFF >> (ip_prefix_.len % 8); - mask = ~mask; - - res += (ip_prefix_buffer[ip_prefix_.len] & mask) == - (content_name_buffer[ip_prefix_.len] & mask); - } - - return res; -} - -int Prefix::contains(const core::Name &content_name) const { - return contains(content_name.toIpAddress().address); -} - -Name Prefix::getName() const { - std::string s(getNetwork()); - return Name(s); -} - -/* - * Mask is used to apply the components to a content name that belong to this - * prefix - */ -Name Prefix::getName(const core::Name &mask, const core::Name &components, - const core::Name &content_name) const { - if (ip_prefix_.family != mask.getAddressFamily() || - ip_prefix_.family != components.getAddressFamily() || - ip_prefix_.family != content_name.getAddressFamily()) - throw errors::RuntimeException( - "Prefix, mask, components and content name are not of the same address " - "family"); - - ip_address_t mask_ip = mask.toIpAddress().address; - ip_address_t component_ip = components.toIpAddress().address; - ip_address_t name_ip = content_name.toIpAddress().address; - const u8 *mask_ip_buffer = ip_address_get_buffer(&mask_ip, ip_prefix_.family); - const u8 *component_ip_buffer = - ip_address_get_buffer(&component_ip, ip_prefix_.family); - u8 *name_ip_buffer = - const_cast(ip_address_get_buffer(&name_ip, ip_prefix_.family)); - - int addr_len = ip_prefix_.family == AF_INET6 ? IPV6_ADDR_LEN : IPV4_ADDR_LEN; - - for (int i = 0; i < addr_len; i++) { - if (mask_ip_buffer[i]) { - name_ip_buffer[i] = component_ip_buffer[i] & mask_ip_buffer[i]; - } - } - - if (this->contains(name_ip)) - throw errors::RuntimeException("Mask overrides the prefix"); - return Name(ip_prefix_.family, (uint8_t *)&name_ip); -} - -Name Prefix::getRandomName() const { - ip_address_t name_ip = ip_prefix_.address; - u8 *name_ip_buffer = - const_cast(ip_address_get_buffer(&name_ip, ip_prefix_.family)); - - int addr_len = - (ip_prefix_.family == AF_INET6 ? IPV6_ADDR_LEN * 8 : IPV4_ADDR_LEN * 8) - - ip_prefix_.len; - - size_t size = (size_t)ceil((float)addr_len / 8.0); - uint8_t buffer[size]; - - RAND_bytes(buffer, size); - - int j = 0; - for (uint8_t i = (uint8_t)ceil((float)ip_prefix_.len / 8.0); - i < (ip_prefix_.family == AF_INET6 ? IPV6_ADDR_LEN : IPV4_ADDR_LEN); - i++) { - name_ip_buffer[i] = buffer[j]; - j++; - } - - return Name(ip_prefix_.family, (uint8_t *)&name_ip); -} - -/* - * Map a name in a different name prefix to this name prefix - */ -Name Prefix::mapName(const core::Name &content_name) const { - if (ip_prefix_.family != content_name.getAddressFamily()) - throw errors::RuntimeException( - "Prefix content name are not of the same address " - "family"); - - ip_address_t name_ip = content_name.toIpAddress().address; - const u8 *ip_prefix_buffer = - ip_address_get_buffer(&(ip_prefix_.address), ip_prefix_.family); - u8 *name_ip_buffer = - const_cast(ip_address_get_buffer(&name_ip, ip_prefix_.family)); - - memcpy(name_ip_buffer, ip_prefix_buffer, ip_prefix_.len / 8); - - if (ip_prefix_.len != (ip_prefix_.family == AF_INET6 ? IPV6_ADDR_LEN_BITS - : IPV4_ADDR_LEN_BITS)) { - uint8_t mask = 0xFF >> (ip_prefix_.len % 8); - name_ip_buffer[ip_prefix_.len / 8 + 1] = - (name_ip_buffer[ip_prefix_.len / 8 + 1] & mask) | - (ip_prefix_buffer[ip_prefix_.len / 8 + 1] & ~mask); - } - - return Name(ip_prefix_.family, (uint8_t *)&name_ip); -} - -Prefix &Prefix::setNetwork(std::string &network) { - if (!inet_pton(AF_INET6, network.c_str(), ip_prefix_.address.v6.buffer)) { - throw errors::RuntimeException("The network name is not valid."); - } - - return *this; -} - -Name Prefix::makeRandomName() const { - srand((unsigned int)time(nullptr)); - - if (ip_prefix_.family == AF_INET6) { - std::default_random_engine eng((std::random_device())()); - std::uniform_int_distribution idis( - 0, std::numeric_limits::max()); - uint64_t random_number = idis(eng); - - uint32_t hash_size_bits = IPV6_ADDR_LEN_BITS - ip_prefix_.len; - uint64_t ip_address[2]; - memcpy(ip_address, ip_prefix_.address.v6.buffer, sizeof(uint64_t)); - memcpy(ip_address + 1, ip_prefix_.address.v6.buffer + 8, sizeof(uint64_t)); - std::string network(IPV6_ADDR_LEN * 3, 0); - - // Let's do the magic ;) - int shift_size = hash_size_bits > sizeof(random_number) * 8 - ? sizeof(random_number) * 8 - : hash_size_bits; - - ip_address[1] >>= shift_size; - ip_address[1] <<= shift_size; - - ip_address[1] |= random_number >> (sizeof(uint64_t) * 8 - shift_size); - - if (!inet_ntop(ip_prefix_.family, ip_address, (char *)network.c_str(), - IPV6_ADDR_LEN * 3)) { - throw errors::RuntimeException( - "Impossible to retrieve network from ip address."); - } - - return Name(network); - } - - return Name(); -} - -bool Prefix::checkPrefixLengthAndAddressFamily(uint16_t prefix_length, - int family) { - // First check the family - if (family != AF_INET6 && family != AF_INET) { - return false; - } - - int max_addr_len_bits = - family == AF_INET6 ? IPV6_ADDR_LEN_BITS : IPV4_ADDR_LEN_BITS; - - if (prefix_length > max_addr_len_bits) { - return false; - } - - return true; -} - -ip_prefix_t &Prefix::toIpPrefixStruct() { return ip_prefix_; } - -} // namespace core - -} // namespace transport diff --git a/libtransport/src/hicn/transport/core/prefix.h b/libtransport/src/hicn/transport/core/prefix.h deleted file mode 100644 index 47971acaf..000000000 --- a/libtransport/src/hicn/transport/core/prefix.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -namespace transport { - -namespace core { - -class Prefix { - public: - Prefix(); - - Prefix(const char *prefix); - - Prefix(const std::string &prefix); - - Prefix(std::string &&prefix); - - Prefix(std::string &prefix, uint16_t prefix_length); - - Prefix(const core::Name &content_name, uint16_t prefix_length); - - std::unique_ptr toSockaddr(); - - uint16_t getPrefixLength(); - - Prefix &setPrefixLength(uint16_t prefix_length); - - std::string getNetwork() const; - - int contains(const ip_address_t &content_name) const; - - int contains(const core::Name &content_name) const; - - Name getName() const; - - Name getRandomName() const; - - Name getName(const core::Name &mask, const core::Name &components, - const core::Name &content_name) const; - - Name mapName(const core::Name &content_name) const; - - Prefix &setNetwork(std::string &network); - - int getAddressFamily(); - - Prefix &setAddressFamily(int address_family); - - Name makeRandomName() const; - - ip_prefix_t &toIpPrefixStruct(); - - private: - static bool checkPrefixLengthAndAddressFamily(uint16_t prefix_length, - int family); - - void buildPrefix(std::string &prefix, uint16_t prefix_length, int family); - - ip_prefix_t ip_prefix_; -}; - -} // end namespace core - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/raw_socket_connector.cc b/libtransport/src/hicn/transport/core/raw_socket_connector.cc deleted file mode 100644 index 0e1743671..000000000 --- a/libtransport/src/hicn/transport/core/raw_socket_connector.cc +++ /dev/null @@ -1,202 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#define MY_DEST_MAC0 0x0a -#define MY_DEST_MAC1 0x7b -#define MY_DEST_MAC2 0x7c -#define MY_DEST_MAC3 0x1c -#define MY_DEST_MAC4 0x4a -#define MY_DEST_MAC5 0x14 - -namespace transport { - -namespace core { - -RawSocketConnector::RawSocketConnector( - PacketReceivedCallback &&receive_callback, - OnReconnect &&on_reconnect_callback, asio::io_service &io_service, - std::string app_name) - : Connector(std::move(receive_callback), std::move(on_reconnect_callback)), - io_service_(io_service), - socket_(io_service_, raw_protocol(PF_PACKET, SOCK_RAW)), - // resolver_(io_service_), - timer_(io_service_), - read_msg_(packet_pool_.makePtr(nullptr)), - data_available_(false), - app_name_(app_name) { - memset(&link_layer_address_, 0, sizeof(link_layer_address_)); -} - -RawSocketConnector::~RawSocketConnector() {} - -void RawSocketConnector::connect(const std::string &interface_name, - const std::string &mac_address_str) { - state_ = ConnectorState::CONNECTING; - memset(ðernet_header_, 0, sizeof(ethernet_header_)); - struct ifreq ifr; - struct ifreq if_mac; - uint8_t mac_address[6]; - - utils::convertStringToMacAddress(mac_address_str, mac_address); - - // Get interface mac address - int fd = static_cast(socket_.native_handle()); - - /* Get the index of the interface to send on */ - memset(&ifr, 0, sizeof(struct ifreq)); - strncpy(ifr.ifr_name, interface_name.c_str(), interface_name.size()); - - // if (ioctl(fd, SIOCGIFINDEX, &if_idx) < 0) { - // perror("SIOCGIFINDEX"); - // } - - /* Get the MAC address of the interface to send on */ - memset(&if_mac, 0, sizeof(struct ifreq)); - strncpy(if_mac.ifr_name, interface_name.c_str(), interface_name.size()); - if (ioctl(fd, SIOCGIFHWADDR, &if_mac) < 0) { - perror("SIOCGIFHWADDR"); - throw errors::RuntimeException("Interface does not exist"); - } - - /* Ethernet header */ - for (int i = 0; i < 6; i++) { - ethernet_header_.ether_shost[i] = - ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[i]; - ethernet_header_.ether_dhost[i] = mac_address[i]; - } - - /* Ethertype field */ - ethernet_header_.ether_type = htons(ETH_P_IPV6); - - strcpy(ifr.ifr_name, interface_name.c_str()); - - if (0 == ioctl(fd, SIOCGIFHWADDR, &ifr)) { - memcpy(link_layer_address_.sll_addr, ifr.ifr_hwaddr.sa_data, 6); - } - - // memset(&ifr, 0, sizeof(ifr)); - // ioctl(fd, SIOCGIFFLAGS, &ifr); - // ifr.ifr_flags |= IFF_PROMISC; - // ioctl(fd, SIOCSIFFLAGS, &ifr); - - link_layer_address_.sll_family = AF_PACKET; - link_layer_address_.sll_protocol = htons(ETH_P_ALL); - link_layer_address_.sll_ifindex = if_nametoindex(interface_name.c_str()); - link_layer_address_.sll_hatype = 1; - link_layer_address_.sll_halen = 6; - - // startConnectionTimer(); - doConnect(); - doRecvPacket(); -} - -void RawSocketConnector::send(const uint8_t *packet, std::size_t len, - const PacketSentCallback &packet_sent) { - if (packet_sent != 0) { - socket_.async_send( - asio::buffer(packet, len), - [packet_sent](std::error_code ec, std::size_t /*length*/) { - packet_sent(); - }); - } else { - if (state_ == ConnectorState::CONNECTED) { - socket_.send(asio::buffer(packet, len)); - } - } -} - -void RawSocketConnector::send(const Packet::MemBufPtr &packet) { - io_service_.post([this, packet]() { - bool write_in_progress = !output_buffer_.empty(); - output_buffer_.push_back(std::move(packet)); - if (TRANSPORT_EXPECT_TRUE(state_ == ConnectorState::CONNECTED)) { - if (!write_in_progress) { - doSendPacket(); - } else { - // Tell the handle connect it has data to write - data_available_ = true; - } - } - }); -} - -void RawSocketConnector::close() { - io_service_.post([this]() { socket_.close(); }); -} - -void RawSocketConnector::doSendPacket() { - auto packet = output_buffer_.front().get(); - auto array = std::vector(); - - const utils::MemBuf *current = packet; - do { - array.push_back(asio::const_buffer(current->data(), current->length())); - current = current->next(); - } while (current != packet); - - socket_.async_send( - std::move(array), - [this /*, packet*/](std::error_code ec, std::size_t bytes_transferred) { - if (TRANSPORT_EXPECT_TRUE(!ec)) { - output_buffer_.pop_front(); - if (!output_buffer_.empty()) { - doSendPacket(); - } - } else { - TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str()); - } - }); -} - -void RawSocketConnector::doRecvPacket() { - read_msg_ = getPacket(); - socket_.async_receive( - asio::buffer(read_msg_->writableData(), packet_size), - [this](std::error_code ec, std::size_t bytes_transferred) mutable { - if (!ec) { - // Ignore packets that are not for us - uint8_t *dst_mac_address = const_cast(read_msg_->data()); - if (!std::memcmp(dst_mac_address, ethernet_header_.ether_shost, - ETHER_ADDR_LEN)) { - read_msg_->append(bytes_transferred); - read_msg_->trimStart(sizeof(struct ether_header)); - receive_callback_(std::move(read_msg_)); - } - } else { - TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str()); - } - doRecvPacket(); - }); -} - -void RawSocketConnector::doConnect() { - state_ = ConnectorState::CONNECTED; - socket_.bind(raw_endpoint(&link_layer_address_, sizeof(link_layer_address_))); -} - -} // end namespace core - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/raw_socket_connector.h b/libtransport/src/hicn/transport/core/raw_socket_connector.h deleted file mode 100644 index fe9ceb227..000000000 --- a/libtransport/src/hicn/transport/core/raw_socket_connector.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace transport { - -namespace core { - -using asio::generic::raw_protocol; -using raw_endpoint = asio::generic::basic_endpoint; - -class RawSocketConnector : public Connector { - public: - RawSocketConnector(PacketReceivedCallback &&receive_callback, - OnReconnect &&reconnect_callback, - asio::io_service &io_service, - std::string app_name = "Libtransport"); - - ~RawSocketConnector() override; - - void send(const Packet::MemBufPtr &packet) override; - - void send(const uint8_t *packet, std::size_t len, - const PacketSentCallback &packet_sent = 0) override; - - void close() override; - - void connect(const std::string &interface_name, - const std::string &mac_address_str); - - private: - void doConnect(); - - void doRecvPacket(); - - void doSendPacket(); - - private: - asio::io_service &io_service_; - raw_protocol::socket socket_; - - struct ether_header ethernet_header_; - - struct sockaddr_ll link_layer_address_; - - asio::steady_timer timer_; - - utils::ObjectPool::Ptr read_msg_; - - bool data_available_; - std::string app_name_; -}; - -} // end namespace core - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/raw_socket_interface.cc b/libtransport/src/hicn/transport/core/raw_socket_interface.cc deleted file mode 100644 index bb4e083e1..000000000 --- a/libtransport/src/hicn/transport/core/raw_socket_interface.cc +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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. - */ - -#include -#include - -#include - -namespace transport { - -namespace core { - -static std::string config_folder_path = "/etc/transport/interface.conf.d"; - -RawSocketInterface::RawSocketInterface(RawSocketConnector &connector) - : ForwarderInterface(connector) {} - -RawSocketInterface::~RawSocketInterface() {} - -void RawSocketInterface::connect(bool is_consumer) { - std::string complete_filename = - config_folder_path + std::string("/") + output_interface_; - - std::ifstream is(complete_filename); - std::string interface; - - if (is) { - is >> remote_mac_address_; - } - - // Get interface ip address - struct sockaddr_in6 address = {0}; - utils::retrieveInterfaceAddress(output_interface_, &address); - - std::memcpy(&inet6_address_.v6.as_u8, &address.sin6_addr, - sizeof(address.sin6_addr)); - connector_.connect(output_interface_, remote_mac_address_); -} - -void RawSocketInterface::registerRoute(Prefix &prefix) { return; } - -} // namespace core - -} // namespace transport diff --git a/libtransport/src/hicn/transport/core/raw_socket_interface.h b/libtransport/src/hicn/transport/core/raw_socket_interface.h deleted file mode 100644 index ac48e5874..000000000 --- a/libtransport/src/hicn/transport/core/raw_socket_interface.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include - -#include -#include - -namespace transport { - -namespace core { - -class RawSocketInterface - : public ForwarderInterface { - public: - typedef RawSocketConnector ConnectorType; - - RawSocketInterface(RawSocketConnector &connector); - - ~RawSocketInterface(); - - void connect(bool is_consumer); - - void registerRoute(Prefix &prefix); - - std::uint16_t getMtu() { return interface_mtu; } - - TRANSPORT_ALWAYS_INLINE static bool isControlMessageImpl( - const uint8_t *message) { - return false; - } - - TRANSPORT_ALWAYS_INLINE void processControlMessageReplyImpl( - Packet::MemBufPtr &&packet_buffer) {} - - TRANSPORT_ALWAYS_INLINE void closeConnection(){}; - - private: - static constexpr std::uint16_t interface_mtu = 1500; - std::string remote_mac_address_; -}; - -} // namespace core - -} // namespace transport diff --git a/libtransport/src/hicn/transport/core/tcp_socket_connector.cc b/libtransport/src/hicn/transport/core/tcp_socket_connector.cc deleted file mode 100644 index c82373ae1..000000000 --- a/libtransport/src/hicn/transport/core/tcp_socket_connector.cc +++ /dev/null @@ -1,281 +0,0 @@ -/* - * 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. - */ - -#ifdef _WIN32 -#include -#endif -#include -#include -#include -#include - -#include -#include - -namespace transport { - -namespace core { - -namespace { -class NetworkMessage { - public: - static constexpr std::size_t fixed_header_length = 10; - - static std::size_t decodeHeader(const uint8_t *packet) { - // General checks - // CCNX Control packet format - uint8_t first_byte = packet[0]; - uint8_t ip_format = (packet[0] & 0xf0) >> 4; - - if (TRANSPORT_EXPECT_FALSE(first_byte == 102)) { - // Get packet length - return 44; - } else if (TRANSPORT_EXPECT_TRUE(ip_format == 6 || ip_format == 4)) { - Packet::Format format = Packet::getFormatFromBuffer(packet); - return Packet::getHeaderSizeFromBuffer(format, packet) + - Packet::getPayloadSizeFromBuffer(format, packet); - } - - return 0; - } -}; -} // namespace - -TcpSocketConnector::TcpSocketConnector( - PacketReceivedCallback &&receive_callback, - OnReconnect &&on_reconnect_callback, asio::io_service &io_service, - std::string app_name) - : Connector(std::move(receive_callback), std::move(on_reconnect_callback)), - io_service_(io_service), - socket_(io_service_), - resolver_(io_service_), - timer_(io_service_), - read_msg_(packet_pool_.makePtr(nullptr)), - is_reconnection_(false), - data_available_(false), - app_name_(app_name) {} - -TcpSocketConnector::~TcpSocketConnector() {} - -void TcpSocketConnector::connect(std::string ip_address, std::string port) { - endpoint_iterator_ = resolver_.resolve( - {ip_address, port, asio::ip::resolver_query_base::numeric_service}); - - state_ = ConnectorState::CONNECTING; - doConnect(); -} - -void TcpSocketConnector::send(const uint8_t *packet, std::size_t len, - const PacketSentCallback &packet_sent) { - if (packet_sent != 0) { - asio::async_write(socket_, asio::buffer(packet, len), - [packet_sent](std::error_code ec, - std::size_t /*length*/) { packet_sent(); }); - } else { - if (state_ == ConnectorState::CONNECTED) { - asio::write(socket_, asio::buffer(packet, len)); - } - } -} - -void TcpSocketConnector::send(const Packet::MemBufPtr &packet) { - io_service_.post([this, packet]() { - bool write_in_progress = !output_buffer_.empty(); - output_buffer_.push_back(std::move(packet)); - if (TRANSPORT_EXPECT_TRUE(state_ == ConnectorState::CONNECTED)) { - if (!write_in_progress) { - doWrite(); - } - } else { - // Tell the handle connect it has data to write - data_available_ = true; - } - }); -} - -void TcpSocketConnector::close() { - if (state_ != ConnectorState::CLOSED) { - state_ = ConnectorState::CLOSED; - if (socket_.is_open()) { - socket_.shutdown(asio::ip::tcp::socket::shutdown_type::shutdown_both); - socket_.close(); - } - } -} - -void TcpSocketConnector::doWrite() { -#if 1 - auto array = std::vector(); - std::vector packet_store(packet_store_size); - uint8_t i = 0; - - utils::MemBuf *packet = nullptr; - const utils::MemBuf *current = nullptr; - // Send vectors of 32 packets - while (!output_buffer_.empty() && i++ < packet_store_size) { - packet_store[i] = output_buffer_.front(); - output_buffer_.pop_front(); - packet = packet_store[i].get(); - current = packet; - do { - array.push_back(asio::const_buffer(current->data(), current->length())); - current = current->next(); - } while (current != packet); - } -#else - auto packet = output_buffer_.front().get(); - auto array = std::vector(); - - const utils::MemBuf *current = packet; - do { - array.push_back(asio::const_buffer(current->data(), current->length())); - current = current->next(); - } while (current != packet); -#endif - - asio::async_write( - socket_, std::move(array), - [this, packet_store = std::move(packet_store)](std::error_code ec, - std::size_t length) { - if (TRANSPORT_EXPECT_TRUE(!ec)) { - if (!output_buffer_.empty()) { - doWrite(); - } - } else if (ec.value() == - static_cast(std::errc::operation_canceled)) { - // The connection has been closed by the application. - return; - } else { - TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str()); - tryReconnect(); - } - }); -} - -void TcpSocketConnector::doReadBody(std::size_t body_length) { - asio::async_read( - socket_, asio::buffer(read_msg_->writableTail(), body_length), - asio::transfer_exactly(body_length), - [this](std::error_code ec, std::size_t length) { - read_msg_->append(length); - if (TRANSPORT_EXPECT_TRUE(!ec)) { - receive_callback_(std::move(read_msg_)); - doReadHeader(); - } else if (ec.value() == - static_cast(std::errc::operation_canceled)) { - // The connection has been closed by the application. - return; - } else { - TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str()); - tryReconnect(); - } - }); -} - -void TcpSocketConnector::doReadHeader() { - read_msg_ = getPacket(); - asio::async_read( - socket_, - asio::buffer(read_msg_->writableData(), - NetworkMessage::fixed_header_length), - asio::transfer_exactly(NetworkMessage::fixed_header_length), - [this](std::error_code ec, std::size_t length) { - if (TRANSPORT_EXPECT_TRUE(!ec)) { - read_msg_->append(NetworkMessage::fixed_header_length); - std::size_t body_length = 0; - if ((body_length = NetworkMessage::decodeHeader(read_msg_->data())) > - 0) { - doReadBody(body_length - length); - } else { - TRANSPORT_LOGE("Decoding error. Ignoring packet."); - } - } else if (ec.value() == - static_cast(std::errc::operation_canceled)) { - // The connection has been closed by the application. - return; - } else { - TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str()); - tryReconnect(); - } - }); -} - -void TcpSocketConnector::tryReconnect() { - if (state_ == ConnectorState::CONNECTED) { - TRANSPORT_LOGE("Connection lost. Trying to reconnect...\n"); - state_ = ConnectorState::CONNECTING; - is_reconnection_ = true; - io_service_.post([this]() { - if (socket_.is_open()) { - socket_.shutdown(asio::ip::tcp::socket::shutdown_type::shutdown_both); - socket_.close(); - } - startConnectionTimer(); - doConnect(); - }); - } -} - -void TcpSocketConnector::doConnect() { - asio::async_connect( - socket_, endpoint_iterator_, - [this](std::error_code ec, tcp::resolver::iterator) { - if (!ec) { - timer_.cancel(); - state_ = ConnectorState::CONNECTED; - asio::ip::tcp::no_delay noDelayOption(true); - socket_.set_option(noDelayOption); - doReadHeader(); - - if (data_available_) { - data_available_ = false; - doWrite(); - } - - if (is_reconnection_) { - is_reconnection_ = false; - TRANSPORT_LOGI("Connection recovered!\n"); - on_reconnect_callback_(); - } - } else { - doConnect(); - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - } - }); -} - -bool TcpSocketConnector::checkConnected() { - return state_ == ConnectorState::CONNECTED; -} - -void TcpSocketConnector::startConnectionTimer() { - timer_.expires_from_now(std::chrono::seconds(60)); - timer_.async_wait(std::bind(&TcpSocketConnector::handleDeadline, this, - std::placeholders::_1)); -} - -void TcpSocketConnector::handleDeadline(const std::error_code &ec) { - if (!ec) { - io_service_.post([this]() { - socket_.close(); - TRANSPORT_LOGE("Error connecting. Is the forwarder running?\n"); - io_service_.stop(); - }); - } -} - -} // end namespace core - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/tcp_socket_connector.h b/libtransport/src/hicn/transport/core/tcp_socket_connector.h deleted file mode 100644 index d755b5e86..000000000 --- a/libtransport/src/hicn/transport/core/tcp_socket_connector.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include -#include - -#include -#include -#include - -namespace transport { -namespace core { - -using asio::ip::tcp; - -class TcpSocketConnector : public Connector { - static constexpr uint16_t packet_store_size = 32; - - public: - TcpSocketConnector(PacketReceivedCallback &&receive_callback, - OnReconnect &&reconnect_callback, - asio::io_service &io_service, - std::string app_name = "Libtransport"); - - ~TcpSocketConnector() override; - - void send(const Packet::MemBufPtr &packet) override; - - void send(const uint8_t *packet, std::size_t len, - const PacketSentCallback &packet_sent = 0) override; - - void close() override; - - void connect(std::string ip_address = "127.0.0.1", std::string port = "9695"); - - private: - void doConnect(); - - void doReadHeader(); - - void doReadBody(std::size_t body_length); - - void doWrite(); - - bool checkConnected(); - - private: - void handleDeadline(const std::error_code &ec); - - void startConnectionTimer(); - - void tryReconnect(); - - asio::io_service &io_service_; - asio::ip::tcp::socket socket_; - asio::ip::tcp::resolver resolver_; - asio::ip::tcp::resolver::iterator endpoint_iterator_; - asio::steady_timer timer_; - - utils::ObjectPool::Ptr read_msg_; - - bool is_reconnection_; - bool data_available_; - - std::string app_name_; -}; - -} // end namespace core - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/test/CMakeLists.txt b/libtransport/src/hicn/transport/core/test/CMakeLists.txt deleted file mode 100644 index 48c50e9b0..000000000 --- a/libtransport/src/hicn/transport/core/test/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -# Enable gcov output for the tests -add_definitions(--coverage) -set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage") - -set(TestsExpectedToPass - test_core_manifest) - -foreach(test ${TestsExpectedToPass}) - AddTest(${test}) -endforeach() \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/test/test_core_manifest.cc b/libtransport/src/hicn/transport/core/test/test_core_manifest.cc deleted file mode 100644 index 58563d8f9..000000000 --- a/libtransport/src/hicn/transport/core/test/test_core_manifest.cc +++ /dev/null @@ -1,296 +0,0 @@ -/* - * 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. - */ - -#include - -#include "../manifest_format_fixed.h" -#include "../manifest_inline.h" - -#include -#include -#include - -namespace transport { - -namespace core { - -namespace { -// The fixture for testing class Foo. -class ManifestTest : public ::testing::Test { - protected: - using ContentObjectManifest = ManifestInline; - - ManifestTest() : name_("b001::123|321"), manifest1_(name_) { - // You can do set-up work for each test here. - } - - virtual ~ManifestTest() { - // You can do clean-up work that doesn't throw exceptions here. - } - - // If the constructor and destructor are not enough for setting up - // and cleaning up each test, you can define the following methods: - - virtual void SetUp() { - // Code here will be called immediately after the constructor (right - // before each test). - } - - virtual void TearDown() { - // Code here will be called immediately after each test (right - // before the destructor). - } - - Name name_; - ContentObjectManifest manifest1_; - - std::vector manifest_payload = { - 0x11, 0x11, 0x01, 0x00, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad // , 0x00, 0x00, - // 0x00, 0x45, 0xa3, - // 0xd1, 0xf2, 0x2b, - // 0x94, 0x41, 0x22, - // 0xc9, 0x00, 0x00, - // 0x00, 0x44, 0xa3, - // 0xd1, 0xf2, 0x2b, - // 0x94, 0x41, 0x22, - // 0xc8 - }; -}; - -} // namespace - -TEST_F(ManifestTest, ManifestCreate) { - ContentObjectManifest manifest2(name_); - ContentObjectManifest manifest3 = manifest2; - - EXPECT_EQ(manifest1_, manifest2); - EXPECT_EQ(manifest1_, manifest3); -} - -TEST_F(ManifestTest, ManifestCreateFromBase) { - ContentObject content_object(name_); - content_object.setPayload(manifest_payload.data(), manifest_payload.size()); - ContentObjectManifest manifest(std::move(content_object)); - - auto manifest4 = ContentObjectManifest::createManifest( - name_, core::ManifestVersion::VERSION_1, - core::ManifestType::INLINE_MANIFEST, HashAlgorithm::SHA_256, true, - core::Name("b001::dead"), - core::NextSegmentCalculationStrategy::INCREMENTAL, 128); - - manifest4->encode(); - manifest4->dump(); - manifest.dump(); - - EXPECT_EQ(manifest1_, manifest); - // EXPECT_EQ(manifest1_, manifest3); -} - -TEST_F(ManifestTest, SetLastManifest) { - manifest1_.clear(); - - manifest1_.setFinalManifest(true); - manifest1_.encode(); - manifest1_.decode(); - bool fcn = manifest1_.isFinalManifest(); - - ASSERT_TRUE(fcn); -} - -TEST_F(ManifestTest, SetManifestType) { - manifest1_.clear(); - - ManifestType type1 = ManifestType::INLINE_MANIFEST; - ManifestType type2 = ManifestType::FLIC_MANIFEST; - - manifest1_.setManifestType(type1); - manifest1_.encode(); - manifest1_.decode(); - ManifestType type_returned1 = manifest1_.getManifestType(); - - manifest1_.clear(); - - manifest1_.setManifestType(type2); - manifest1_.encode(); - manifest1_.decode(); - ManifestType type_returned2 = manifest1_.getManifestType(); - - ASSERT_EQ(type1, type_returned1); - ASSERT_EQ(type2, type_returned2); -} - -TEST_F(ManifestTest, SetHashAlgorithm) { - manifest1_.clear(); - - HashAlgorithm hash1 = HashAlgorithm::SHA_512; - HashAlgorithm hash2 = HashAlgorithm::CRC32C; - HashAlgorithm hash3 = HashAlgorithm::SHA_256; - - manifest1_.setHashAlgorithm(hash1); - manifest1_.encode(); - manifest1_.decode(); - HashAlgorithm type_returned1 = manifest1_.getHashAlgorithm(); - - manifest1_.clear(); - - manifest1_.setHashAlgorithm(hash2); - manifest1_.encode(); - manifest1_.decode(); - HashAlgorithm type_returned2 = manifest1_.getHashAlgorithm(); - - manifest1_.clear(); - - manifest1_.setHashAlgorithm(hash3); - manifest1_.encode(); - manifest1_.decode(); - HashAlgorithm type_returned3 = manifest1_.getHashAlgorithm(); - - ASSERT_EQ(hash1, type_returned1); - ASSERT_EQ(hash2, type_returned2); - ASSERT_EQ(hash3, type_returned3); -} - -TEST_F(ManifestTest, SetNextSegmentCalculationStrategy) { - manifest1_.clear(); - - NextSegmentCalculationStrategy strategy1 = - NextSegmentCalculationStrategy::INCREMENTAL; - - manifest1_.setNextSegmentCalculationStrategy(strategy1); - manifest1_.encode(); - manifest1_.decode(); - NextSegmentCalculationStrategy type_returned1 = - manifest1_.getNextSegmentCalculationStrategy(); - - ASSERT_EQ(strategy1, type_returned1); -} - -TEST_F(ManifestTest, SetBaseName) { - manifest1_.clear(); - - core::Name base_name("b001::dead"); - manifest1_.setBaseName(base_name); - manifest1_.encode(); - manifest1_.decode(); - core::Name ret_name = manifest1_.getBaseName(); - - ASSERT_EQ(base_name, ret_name); -} - -TEST_F(ManifestTest, SetSuffixList) { - manifest1_.clear(); - - core::Name base_name("b001::dead"); - - using random_bytes_engine = - std::independent_bits_engine; - random_bytes_engine rbe; - - std::default_random_engine eng((std::random_device())()); - std::uniform_int_distribution idis( - 0, std::numeric_limits::max()); - - auto entries = new std::pair[3]; - uint32_t suffixes[3]; - std::vector data[3]; - - for (int i = 0; i < 3; i++) { - data[i].resize(32); - std::generate(std::begin(data[i]), std::end(data[i]), std::ref(rbe)); - suffixes[i] = idis(eng); - entries[i] = std::make_pair( - suffixes[i], utils::CryptoHash(data[i].data(), data[i].size(), - utils::CryptoHashType::SHA_256)); - manifest1_.addSuffixHash(entries[i].first, entries[i].second); - } - - manifest1_.setBaseName(base_name); - - manifest1_.encode(); - manifest1_.decode(); - - core::Name ret_name = manifest1_.getBaseName(); - - // auto & hash_list = manifest1_.getSuffixHashList(); - - bool cond; - int i = 0; - - // for (auto & item : manifest1_.getSuffixList()) { - // auto hash = manifest1_.getHash(suffixes[i]); - // cond = utils::CryptoHash::compareBinaryDigest(hash, - // entries[i].second.getDigest().data(), - // entries[i].second.getType()); - // ASSERT_TRUE(cond); - // i++; - // } - - ASSERT_EQ(base_name, ret_name); - - delete[] entries; -} - -TEST_F(ManifestTest, EstimateSize) { - manifest1_.clear(); - - HashAlgorithm hash1 = HashAlgorithm::SHA_256; - NextSegmentCalculationStrategy strategy1 = - NextSegmentCalculationStrategy::INCREMENTAL; - ManifestType type1 = ManifestType::INLINE_MANIFEST; - core::Name base_name1("b001:abcd:fede:baba:cece:d0d0:face:dead"); - - manifest1_.setFinalManifest(true); - manifest1_.setBaseName(base_name1); - manifest1_.setNextSegmentCalculationStrategy(strategy1); - manifest1_.setHashAlgorithm(hash1); - manifest1_.setManifestType(type1); - - std::default_random_engine eng((std::random_device())()); - std::uniform_int_distribution idis( - 0, std::numeric_limits::max()); - - using random_bytes_engine = - std::independent_bits_engine; - random_bytes_engine rbe; - - while (manifest1_.estimateManifestSize(1) < 1440) { - uint32_t suffix = static_cast(idis(eng)); - std::vector data(32); - std::generate(std::begin(data), std::end(data), std::ref(rbe)); - auto hash = utils::CryptoHash(data.data(), data.size(), - utils::CryptoHashType::SHA_256); - manifest1_.addSuffixHash(suffix, hash); - } - - manifest1_.encode(); - manifest1_.decode(); - - manifest1_.dump(); - - ASSERT_GT(manifest1_.estimateManifestSize(), 0); - ASSERT_LT(manifest1_.estimateManifestSize(), 1500); -} - -} // namespace core - -} // namespace transport - -int main(int argc, char **argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/udp_socket_connector.cc b/libtransport/src/hicn/transport/core/udp_socket_connector.cc deleted file mode 100644 index 99f47fedf..000000000 --- a/libtransport/src/hicn/transport/core/udp_socket_connector.cc +++ /dev/null @@ -1,222 +0,0 @@ -/* - * 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. - */ - -#ifdef _WIN32 -#include -#endif -#include -#include -#include -#include - -#include -#include - -namespace transport { - -namespace core { - -UdpSocketConnector::UdpSocketConnector( - PacketReceivedCallback &&receive_callback, - OnReconnect &&on_reconnect_callback, asio::io_service &io_service, - std::string app_name) - : Connector(std::move(receive_callback), std::move(on_reconnect_callback)), - io_service_(io_service), - socket_(io_service_), - resolver_(io_service_), - connection_timer_(io_service_), - read_msg_(packet_pool_.makePtr(nullptr)), - is_reconnection_(false), - data_available_(false), - app_name_(app_name) {} - -UdpSocketConnector::~UdpSocketConnector() {} - -void UdpSocketConnector::connect(std::string ip_address, std::string port) { - endpoint_iterator_ = resolver_.resolve( - {ip_address, port, asio::ip::resolver_query_base::numeric_service}); - - state_ = ConnectorState::CONNECTING; - doConnect(); -} - -void UdpSocketConnector::send(const uint8_t *packet, std::size_t len, - const PacketSentCallback &packet_sent) { - if (packet_sent != 0) { - socket_.async_send( - asio::buffer(packet, len), - [packet_sent](std::error_code ec, std::size_t /*length*/) { - packet_sent(); - }); - } else { - if (state_ == ConnectorState::CONNECTED) { - try { - socket_.send(asio::buffer(packet, len)); - } catch (std::system_error &err) { - TRANSPORT_LOGE( - "Sending of disconnect message to forwarder failed. Reason: %s", - err.what()); - } - } - } -} - -void UdpSocketConnector::send(const Packet::MemBufPtr &packet) { - io_service_.post([this, packet]() { - bool write_in_progress = !output_buffer_.empty(); - output_buffer_.push_back(std::move(packet)); - if (TRANSPORT_EXPECT_TRUE(state_ == ConnectorState::CONNECTED)) { - if (!write_in_progress) { - doWrite(); - } - } else { - // Tell the handle connect it has data to write - data_available_ = true; - } - }); -} - -void UdpSocketConnector::close() { - if (io_service_.stopped()) { - doClose(); - } else { - io_service_.dispatch(std::bind(&UdpSocketConnector::doClose, this)); - } -} - -void UdpSocketConnector::doClose() { - if (state_ != ConnectorState::CLOSED) { - state_ = ConnectorState::CLOSED; - if (socket_.is_open()) { - socket_.shutdown(asio::ip::tcp::socket::shutdown_type::shutdown_both); - socket_.close(); - } - } -} - -void UdpSocketConnector::doWrite() { - auto packet = output_buffer_.front().get(); - auto array = std::vector(); - - const utils::MemBuf *current = packet; - do { - array.push_back(asio::const_buffer(current->data(), current->length())); - current = current->next(); - } while (current != packet); - - socket_.async_send(std::move(array), [this](std::error_code ec, - std::size_t length) { - if (TRANSPORT_EXPECT_TRUE(!ec)) { - output_buffer_.pop_front(); - if (!output_buffer_.empty()) { - doWrite(); - } - } else if (ec.value() == static_cast(std::errc::operation_canceled)) { - // The connection has been closed by the application. - return; - } else { - TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str()); - tryReconnect(); - } - }); -} - -void UdpSocketConnector::doRead() { - read_msg_ = getPacket(); - socket_.async_receive( - asio::buffer(read_msg_->writableData(), Connector::packet_size), - [this](std::error_code ec, std::size_t length) { - if (TRANSPORT_EXPECT_TRUE(!ec)) { - read_msg_->append(length); - receive_callback_(std::move(read_msg_)); - doRead(); - } else if (ec.value() == - static_cast(std::errc::operation_canceled)) { - // The connection has been closed by the application. - return; - } else { - TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str()); - tryReconnect(); - } - }); -} - -void UdpSocketConnector::tryReconnect() { - if (state_ == ConnectorState::CONNECTED) { - TRANSPORT_LOGE("Connection lost. Trying to reconnect...\n"); - state_ = ConnectorState::CONNECTING; - is_reconnection_ = true; - io_service_.post([this]() { - if (socket_.is_open()) { - socket_.shutdown(asio::ip::tcp::socket::shutdown_type::shutdown_both); - socket_.close(); - } - - doConnect(); - startConnectionTimer(); - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - }); - } -} - -void UdpSocketConnector::doConnect() { - asio::async_connect( - socket_, endpoint_iterator_, - [this](std::error_code ec, udp::resolver::iterator) { - if (!ec) { - connection_timer_.cancel(); - state_ = ConnectorState::CONNECTED; - doRead(); - - if (data_available_) { - data_available_ = false; - doWrite(); - } - - if (is_reconnection_) { - is_reconnection_ = false; - } - - on_reconnect_callback_(); - } else { - doConnect(); - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - } - }); -} - -bool UdpSocketConnector::checkConnected() { - return state_ == ConnectorState::CONNECTED; -} - -void UdpSocketConnector::startConnectionTimer() { - connection_timer_.expires_from_now(std::chrono::seconds(60)); - connection_timer_.async_wait(std::bind(&UdpSocketConnector::handleDeadline, - this, std::placeholders::_1)); -} - -void UdpSocketConnector::handleDeadline(const std::error_code &ec) { - if (!ec) { - io_service_.post([this]() { - socket_.close(); - TRANSPORT_LOGE("Error connecting. Is the forwarder running?\n"); - io_service_.stop(); - }); - } -} - -} // end namespace core - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/udp_socket_connector.h b/libtransport/src/hicn/transport/core/udp_socket_connector.h deleted file mode 100644 index 7c5dbaf10..000000000 --- a/libtransport/src/hicn/transport/core/udp_socket_connector.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include -#include - -#include -#include -#include - -namespace transport { -namespace core { - -using asio::ip::udp; - -class UdpSocketConnector : public Connector { - public: - UdpSocketConnector(PacketReceivedCallback &&receive_callback, - OnReconnect &&reconnect_callback, - asio::io_service &io_service, - std::string app_name = "Libtransport"); - - ~UdpSocketConnector() override; - - void send(const Packet::MemBufPtr &packet) override; - - void send(const uint8_t *packet, std::size_t len, - const PacketSentCallback &packet_sent = 0) override; - - void close() override; - - void connect(std::string ip_address = "127.0.0.1", std::string port = "9695"); - - private: - void doConnect(); - - void doRead(); - - void doWrite(); - - void doClose(); - - bool checkConnected(); - - private: - void handleDeadline(const std::error_code &ec); - - void startConnectionTimer(); - - void tryReconnect(); - - asio::io_service &io_service_; - asio::ip::udp::socket socket_; - asio::ip::udp::resolver resolver_; - asio::ip::udp::resolver::iterator endpoint_iterator_; - asio::steady_timer connection_timer_; - - utils::ObjectPool::Ptr read_msg_; - - bool is_reconnection_; - bool data_available_; - - std::string app_name_; -}; - -} // end namespace core - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/vpp_forwarder_interface.cc b/libtransport/src/hicn/transport/core/vpp_forwarder_interface.cc deleted file mode 100644 index 9e701bf80..000000000 --- a/libtransport/src/hicn/transport/core/vpp_forwarder_interface.cc +++ /dev/null @@ -1,220 +0,0 @@ -/* - * 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. - */ - -#include - -#ifdef __vpp__ - -#include -#include -#include -#include - -extern "C" { -#include -}; - -typedef enum { MASTER = 0, SLAVE = 1 } memif_role_t; - -#define MEMIF_DEFAULT_RING_SIZE 2048 -#define MEMIF_DEFAULT_RX_QUEUES 1 -#define MEMIF_DEFAULT_TX_QUEUES 1 -#define MEMIF_DEFAULT_BUFFER_SIZE 2048 - -namespace transport { - -namespace core { - -std::mutex VPPForwarderInterface::global_lock_; - -VPPForwarderInterface::VPPForwarderInterface(MemifConnector &connector) - : ForwarderInterface(connector), - sw_if_index_(~0), - face_id1_(~0), - face_id2_(~0), - is_consumer_(false){ - } - -VPPForwarderInterface::~VPPForwarderInterface() {} - -/** - * @brief Create a memif interface in the local VPP forwarder. - */ -uint32_t VPPForwarderInterface::getMemifConfiguration() { - memif_create_params_t input_params = {0}; - - int ret = memif_vapi_get_next_memif_id( - VPPForwarderInterface::sock_, &memif_id_); - - if (ret < 0) { - throw errors::RuntimeException( - "Error getting next memif id. Could not create memif interface."); - } - - input_params.id = memif_id_; - input_params.role = memif_role_t::MASTER; - input_params.mode = memif_interface_mode_t::MEMIF_INTERFACE_MODE_IP; - input_params.rx_queues = MEMIF_DEFAULT_RX_QUEUES; - input_params.tx_queues = MEMIF_DEFAULT_TX_QUEUES; - input_params.ring_size = MEMIF_DEFAULT_RING_SIZE; - input_params.buffer_size = MEMIF_DEFAULT_BUFFER_SIZE; - - memif_output_params_t output_params = {0}; - - ret = memif_vapi_create_memif(VPPForwarderInterface::sock_, - &input_params, &output_params); - - if (ret < 0) { - throw errors::RuntimeException( - "Error creating memif interface in the local VPP forwarder."); - } - - return output_params.sw_if_index; -} - -void VPPForwarderInterface::consumerConnection() { - hicn_consumer_input_params input = {0}; - hicn_consumer_output_params output = {0}; - ip_address_t ip4_address; - ip_address_t ip6_address; - - output.src4 = &ip4_address; - output.src6 = &ip6_address; - input.swif = sw_if_index_; - - - - int ret = hicn_vapi_register_cons_app(VPPForwarderInterface::sock_, - &input, &output); - - if (ret < 0) { - throw errors::RuntimeException(hicn_vapi_get_error_string(ret)); - } - - face_id1_ = output.face_id1; - face_id2_ = output.face_id2; - - - std::memcpy(inet_address_.v4.as_u8, output.src4->v4.as_u8, IPV4_ADDR_LEN); - - std::memcpy(inet6_address_.v6.as_u8, output.src6->v6.as_u8, IPV6_ADDR_LEN); -} - -void VPPForwarderInterface::producerConnection() { - // Producer connection will be set when we set the first route. -} - -void VPPForwarderInterface::connect(bool is_consumer) { - std::lock_guard connection_lock(global_lock_); - - vapi_connect_safe(&sock_, 0); - - sw_if_index_ = getMemifConfiguration(); - - is_consumer_ = is_consumer; - if (is_consumer_) { - consumerConnection(); - } - - connector_.connect(memif_id_, 0); -} - -void VPPForwarderInterface::registerRoute(Prefix &prefix) { - ip_prefix_t &addr = prefix.toIpPrefixStruct(); - - ip_prefix_t producer_prefix; - ip_address_t producer_locator; - - if (face_id1_ == uint32_t(~0)) { - hicn_producer_input_params input; - std::memset(&input, 0, sizeof(input)); - - hicn_producer_output_params output; - std::memset(&output, 0, sizeof(output)); - - input.prefix = &producer_prefix; - output.prod_addr = &producer_locator; - - // Here we have to ask to the actual connector what is the - // memif_id, since this function should be called after the - // memif creation. - input.swif = sw_if_index_; - input.prefix->address = addr.address; - input.prefix->family = addr.family; - input.prefix->len = addr.len; - input.cs_reserved = content_store_reserved_; - - int ret = hicn_vapi_register_prod_app( - VPPForwarderInterface::sock_, &input, &output); - - if (ret < 0) { - throw errors::RuntimeException(hicn_vapi_get_error_string(ret)); - } - - inet6_address_ = *output.prod_addr; - - face_id1_ = output.face_id; - } else { - hicn_producer_set_route_params params; - params.prefix = &producer_prefix; - params.prefix->address = addr.address; - params.prefix->family = addr.family; - params.prefix->len = addr.len; - params.face_id = face_id1_; - - int ret = hicn_vapi_register_route(VPPForwarderInterface::sock_, - ¶ms); - - if (ret < 0) { - throw errors::RuntimeException(hicn_vapi_get_error_string(ret)); - } - } -} - -void VPPForwarderInterface::closeConnection() { - if (VPPForwarderInterface::sock_) { - connector_.close(); - - if (is_consumer_) { - hicn_del_face_app_input_params params; - params.face_id = face_id1_; - hicn_vapi_face_cons_del(VPPForwarderInterface::sock_, ¶ms); - params.face_id = face_id2_; - hicn_vapi_face_cons_del(VPPForwarderInterface::sock_, ¶ms); - } - else { - hicn_del_face_app_input_params params; - params.face_id = face_id1_; - hicn_vapi_face_prod_del(VPPForwarderInterface::sock_, ¶ms); - } - - if (sw_if_index_ != uint32_t(~0)) { - int ret = memif_vapi_delete_memif(VPPForwarderInterface::sock_, - sw_if_index_); - if (ret < 0) { - TRANSPORT_LOGE("Error deleting memif with sw idx %u.", sw_if_index_); - } - } - - vapi_disconnect_safe(); - VPPForwarderInterface::sock_ = nullptr; - } -} - -} // namespace core - -} // namespace transport - -#endif diff --git a/libtransport/src/hicn/transport/core/vpp_forwarder_interface.h b/libtransport/src/hicn/transport/core/vpp_forwarder_interface.h deleted file mode 100644 index 9f8000828..000000000 --- a/libtransport/src/hicn/transport/core/vpp_forwarder_interface.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -#ifdef __vpp__ - -#ifdef always_inline -#undef always_inline -#endif -extern "C" { -#include -}; - -#include -#include -#include - -#include - -namespace transport { - -namespace core { - -class VPPForwarderInterface - : public ForwarderInterface { - static constexpr std::uint16_t interface_mtu = 1500; - - public: - VPPForwarderInterface(MemifConnector &connector); - - typedef MemifConnector ConnectorType; - - ~VPPForwarderInterface(); - - void connect(bool is_consumer); - - void registerRoute(Prefix &prefix); - - TRANSPORT_ALWAYS_INLINE std::uint16_t getMtu() { return interface_mtu; } - - TRANSPORT_ALWAYS_INLINE static bool isControlMessageImpl( - const uint8_t *message) { - return false; - } - - TRANSPORT_ALWAYS_INLINE void processControlMessageReplyImpl( - Packet::MemBufPtr &&packet_buffer) {} - - void closeConnection(); - - private: - uint32_t getMemifConfiguration(); - - void consumerConnection(); - - void producerConnection(); - - uint32_t memif_id_; - uint32_t sw_if_index_; - //A consumer socket in vpp has two faces (ipv4 and ipv6) - uint32_t face_id1_; - uint32_t face_id2_; - bool is_consumer_; - vapi_ctx_t sock_; - static std::mutex global_lock_; -}; - -} // namespace core - -} // namespace transport - -#endif diff --git a/libtransport/src/hicn/transport/errors/CMakeLists.txt b/libtransport/src/hicn/transport/errors/CMakeLists.txt deleted file mode 100644 index 7b0d1332d..000000000 --- a/libtransport/src/hicn/transport/errors/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -# 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) - -list(APPEND HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/not_implemented_exception.h - ${CMAKE_CURRENT_SOURCE_DIR}/invalid_ip_address_exception.h - ${CMAKE_CURRENT_SOURCE_DIR}/malformed_name_exception.h - ${CMAKE_CURRENT_SOURCE_DIR}/errors.h - ${CMAKE_CURRENT_SOURCE_DIR}/malformed_packet_exception.h - ${CMAKE_CURRENT_SOURCE_DIR}/runtime_exception.h - ${CMAKE_CURRENT_SOURCE_DIR}/tokenizer_exception.h - ${CMAKE_CURRENT_SOURCE_DIR}/null_pointer_exception.h - ${CMAKE_CURRENT_SOURCE_DIR}/malformed_ahpacket_exception.h - ${CMAKE_CURRENT_SOURCE_DIR}/unexpected_manifest_exception.h - ${CMAKE_CURRENT_SOURCE_DIR}/indexing_exception.h -) - -set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) -set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file diff --git a/libtransport/src/hicn/transport/errors/errors.h b/libtransport/src/hicn/transport/errors/errors.h deleted file mode 100644 index 512e35736..000000000 --- a/libtransport/src/hicn/transport/errors/errors.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include \ No newline at end of file diff --git a/libtransport/src/hicn/transport/errors/indexing_exception.h b/libtransport/src/hicn/transport/errors/indexing_exception.h deleted file mode 100644 index 731314f0e..000000000 --- a/libtransport/src/hicn/transport/errors/indexing_exception.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -namespace errors { - -class IndexingException : public std::logic_error { - public: - IndexingException() : std::logic_error("") {} - - virtual char const *what() const noexcept override { - return "Impossible to retrieve next index to download."; - } -}; - -} // end namespace errors diff --git a/libtransport/src/hicn/transport/errors/invalid_ip_address_exception.h b/libtransport/src/hicn/transport/errors/invalid_ip_address_exception.h deleted file mode 100644 index 60226f576..000000000 --- a/libtransport/src/hicn/transport/errors/invalid_ip_address_exception.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -namespace errors { - -class InvalidIpAddressException : public std::runtime_error { - public: - InvalidIpAddressException() : std::runtime_error("") {} - - virtual char const *what() const noexcept override { - return "Malformed IP address."; - } -}; - -} // end namespace errors \ No newline at end of file diff --git a/libtransport/src/hicn/transport/errors/malformed_ahpacket_exception.h b/libtransport/src/hicn/transport/errors/malformed_ahpacket_exception.h deleted file mode 100644 index f0cfe0b82..000000000 --- a/libtransport/src/hicn/transport/errors/malformed_ahpacket_exception.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -namespace errors { - -class MalformedAHPacketException : public std::runtime_error { - public: - MalformedAHPacketException() : std::runtime_error("") {} - - virtual char const *what() const noexcept override { - return "Malformed AH packet."; - } -}; - -} // end namespace errors diff --git a/libtransport/src/hicn/transport/errors/malformed_name_exception.h b/libtransport/src/hicn/transport/errors/malformed_name_exception.h deleted file mode 100644 index 4ef45d2e8..000000000 --- a/libtransport/src/hicn/transport/errors/malformed_name_exception.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -namespace errors { - -class MalformedNameException : public std::runtime_error { - public: - MalformedNameException() : std::runtime_error("") {} - - virtual char const *what() const noexcept override { - return "Malformed IP address."; - } -}; - -} // end namespace errors diff --git a/libtransport/src/hicn/transport/errors/malformed_packet_exception.h b/libtransport/src/hicn/transport/errors/malformed_packet_exception.h deleted file mode 100644 index ec5c97e6e..000000000 --- a/libtransport/src/hicn/transport/errors/malformed_packet_exception.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -namespace errors { - -class MalformedPacketException : public std::runtime_error { - public: - MalformedPacketException() : std::runtime_error("") {} - - char const *what() const noexcept override { return "Malformed IP packet."; } -}; - -} // end namespace errors diff --git a/libtransport/src/hicn/transport/errors/not_implemented_exception.h b/libtransport/src/hicn/transport/errors/not_implemented_exception.h deleted file mode 100644 index e9869163d..000000000 --- a/libtransport/src/hicn/transport/errors/not_implemented_exception.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -namespace errors { - -class NotImplementedException : public std::logic_error { - public: - NotImplementedException() : std::logic_error("") {} - virtual char const *what() const noexcept override { - return "Function not yet implemented."; - } -}; - -} // end namespace errors diff --git a/libtransport/src/hicn/transport/errors/null_pointer_exception.h b/libtransport/src/hicn/transport/errors/null_pointer_exception.h deleted file mode 100644 index bd06485ed..000000000 --- a/libtransport/src/hicn/transport/errors/null_pointer_exception.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -namespace errors { - -class NullPointerException : public std::runtime_error { - public: - NullPointerException() : std::runtime_error("") {} - - char const *what() const noexcept override { - return "Null pointer exception."; - } -}; - -} // end namespace errors diff --git a/libtransport/src/hicn/transport/errors/runtime_exception.h b/libtransport/src/hicn/transport/errors/runtime_exception.h deleted file mode 100644 index ba5128a7e..000000000 --- a/libtransport/src/hicn/transport/errors/runtime_exception.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include -#include - -namespace errors { - -class RuntimeException : public std::runtime_error { - public: - RuntimeException() : std::runtime_error("") {} - - RuntimeException(std::string what) : runtime_error(what){}; -}; - -} // end namespace errors \ No newline at end of file diff --git a/libtransport/src/hicn/transport/errors/tokenizer_exception.h b/libtransport/src/hicn/transport/errors/tokenizer_exception.h deleted file mode 100644 index 76eda838e..000000000 --- a/libtransport/src/hicn/transport/errors/tokenizer_exception.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -namespace errors { - -class TokenizerException : public std::logic_error { - public: - TokenizerException() : std::logic_error("") {} - - virtual char const *what() const noexcept override { - return "No more tokens available."; - } -}; - -} // end namespace errors diff --git a/libtransport/src/hicn/transport/errors/unexpected_manifest_exception.h b/libtransport/src/hicn/transport/errors/unexpected_manifest_exception.h deleted file mode 100644 index 6f71471e4..000000000 --- a/libtransport/src/hicn/transport/errors/unexpected_manifest_exception.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -namespace errors { - -class UnexpectedManifestException : public std::logic_error { - public: - UnexpectedManifestException() : std::logic_error("") {} - - virtual char const *what() const noexcept override { - return "Received unexpected manifest."; - } -}; - -} // end namespace errors diff --git a/libtransport/src/hicn/transport/http/CMakeLists.txt b/libtransport/src/hicn/transport/http/CMakeLists.txt deleted file mode 100644 index b24c80195..000000000 --- a/libtransport/src/hicn/transport/http/CMakeLists.txt +++ /dev/null @@ -1,35 +0,0 @@ -# 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) - -list(APPEND SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/client_connection.cc - ${CMAKE_CURRENT_SOURCE_DIR}/request.cc - ${CMAKE_CURRENT_SOURCE_DIR}/server_publisher.cc - ${CMAKE_CURRENT_SOURCE_DIR}/server_acceptor.cc - ${CMAKE_CURRENT_SOURCE_DIR}/response.cc) - -list(APPEND HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/client_connection.h - ${CMAKE_CURRENT_SOURCE_DIR}/request.h - ${CMAKE_CURRENT_SOURCE_DIR}/server_publisher.h - ${CMAKE_CURRENT_SOURCE_DIR}/server_acceptor.h - ${CMAKE_CURRENT_SOURCE_DIR}/default_values.h - ${CMAKE_CURRENT_SOURCE_DIR}/facade.h - ${CMAKE_CURRENT_SOURCE_DIR}/response.h - ${CMAKE_CURRENT_SOURCE_DIR}/message.h -) - -set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) -set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file diff --git a/libtransport/src/hicn/transport/http/client_connection.cc b/libtransport/src/hicn/transport/http/client_connection.cc deleted file mode 100644 index bd21bc448..000000000 --- a/libtransport/src/hicn/transport/http/client_connection.cc +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (c) 2017-2020 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 -#include - -#define DEFAULT_BETA 0.99 -#define DEFAULT_GAMMA 0.07 - -namespace transport { - -namespace http { - -using namespace transport; - -HTTPClientConnection::HTTPClientConnection() - : consumer_(TransportProtocolAlgorithms::RAAQM), - read_bytes_callback_(nullptr), - read_buffer_(nullptr), - response_(std::make_shared()), - timer_(nullptr) { - consumer_.setSocketOption( - ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY, - (ConsumerContentObjectVerificationCallback)std::bind( - &HTTPClientConnection::verifyData, this, std::placeholders::_1, - std::placeholders::_2)); - - consumer_.setSocketOption(ConsumerCallbacksOptions::READ_CALLBACK, this); - - consumer_.connect(); - std::shared_ptr portal; - consumer_.getSocketOption(GeneralTransportOptions::PORTAL, portal); - timer_ = std::make_unique(portal->getIoService()); -} - -HTTPClientConnection::RC HTTPClientConnection::get( - const std::string &url, HTTPHeaders headers, HTTPPayload &&payload, - std::shared_ptr response, ReadBytesCallback *callback, - std::string ipv6_first_word) { - return sendRequest(url, HTTPMethod::GET, headers, std::move(payload), - response, callback, ipv6_first_word); -} - -HTTPClientConnection::RC HTTPClientConnection::sendRequest( - const std::string &url, HTTPMethod method, HTTPHeaders headers, - HTTPPayload &&payload, std::shared_ptr response, - ReadBytesCallback *callback, std::string ipv6_first_word) { - current_url_ = url; - read_bytes_callback_ = callback; - if (!response) { - response_ = std::make_shared(); - } else { - response_ = response; - } - - auto start = std::chrono::steady_clock::now(); - request_.init(method, url, headers, std::move(payload)); - - success_callback_ = [this, method = std::move(method), url = std::move(url), - start = std::move(start)](std::size_t size) -> void { - auto end = std::chrono::steady_clock::now(); - TRANSPORT_LOGI( - "%s %s [%s] duration: %llu [usec] %zu [bytes]\n", - method_map[method].c_str(), url.c_str(), name_.str().c_str(), - (unsigned long long) - std::chrono::duration_cast(end - start) - .count(), - size); - }; - - sendRequestGetReply(ipv6_first_word); - return return_code_; -} - -void HTTPClientConnection::sendRequestGetReply(std::string &ipv6_first_word) { - const std::string &request_string = request_.getRequestString(); - const std::string &locator = request_.getLocator(); - - // Hash it - - uint32_t locator_hash = - utils::hash::fnv32_buf(locator.c_str(), locator.size()); - uint64_t request_hash = - utils::hash::fnv64_buf(request_string.c_str(), request_string.size()); - - consumer_.setSocketOption( - ConsumerCallbacksOptions::INTEREST_OUTPUT, - (ConsumerInterestCallback)std::bind( - &HTTPClientConnection::processLeavingInterest, this, - std::placeholders::_1, std::placeholders::_2)); - - // Factor hicn name using hash - name_.str(""); - - name_ << ipv6_first_word << ":"; - - for (uint16_t *word = (uint16_t *)&locator_hash; - std::size_t(word) < (std::size_t(&locator_hash) + sizeof(locator_hash)); - word++) { - name_ << ":" << std::hex << *word; - } - - for (uint16_t *word = (uint16_t *)&request_hash; - std::size_t(word) < (std::size_t(&request_hash) + sizeof(request_hash)); - word++) { - name_ << ":" << std::hex << *word; - } - - name_ << "|0"; - - consumer_.consume(Name(name_.str())); - - consumer_.stop(); -} - -std::shared_ptr HTTPClientConnection::response() { - response_->coalescePayloadBuffer(); - return response_; -} - -bool HTTPClientConnection::verifyData( - ConsumerSocket &c, const core::ContentObject &contentObject) { - if (contentObject.getPayloadType() == PayloadType::CONTENT_OBJECT) { - TRANSPORT_LOGI("VERIFY CONTENT\n"); - } else if (contentObject.getPayloadType() == PayloadType::MANIFEST) { - TRANSPORT_LOGI("VERIFY MANIFEST\n"); - } - - return true; -} - -void HTTPClientConnection::processLeavingInterest( - ConsumerSocket &c, const core::Interest &interest) { - if (interest.payloadSize() == 0) { - Interest &int2 = const_cast(interest); - auto payload = request_.getRequestString(); - auto payload2 = request_.getPayload(); - int2.appendPayload((uint8_t *)payload.data(), payload.size()); - if (payload2) - int2.appendPayload((uint8_t *)payload2->data(), payload2->length()); - } -} - -ConsumerSocket &HTTPClientConnection::getConsumer() { return consumer_; } - -HTTPClientConnection &HTTPClientConnection::stop() { - // This is thread safe and can be called from another thread - consumer_.stop(); - - return *this; -} - -HTTPClientConnection &HTTPClientConnection::setTimeout( - const std::chrono::seconds &timeout) { - timer_->cancel(); - timer_->expires_from_now(timeout); - timer_->async_wait([this](std::error_code ec) { - if (!ec) { - consumer_.stop(); - } - }); - - return *this; -} - -HTTPClientConnection &HTTPClientConnection::setCertificate( - const std::string &cert_path) { - if (consumer_.setSocketOption(GeneralTransportOptions::CERTIFICATE, - cert_path) == SOCKET_OPTION_NOT_SET) { - throw errors::RuntimeException("Error setting the certificate."); - } - - return *this; -} - -// Read buffer management -void HTTPClientConnection::readBufferAvailable( - std::unique_ptr &&buffer) noexcept { - if (!read_bytes_callback_) { - response_->appendResponseChunk(std::move(buffer)); - } else { - read_bytes_callback_->onBytesReceived(std::move(buffer)); - } -} - -// Read buffer management -void HTTPClientConnection::readError(const std::error_code ec) noexcept { - TRANSPORT_LOGE("Error %s during download of %s", ec.message().c_str(), - current_url_.c_str()); - if (read_bytes_callback_) { - read_bytes_callback_->onError(ec); - } - - return_code_ = HTTPClientConnection::RC::DOWNLOAD_FAILED; -} - -void HTTPClientConnection::readSuccess(std::size_t total_size) noexcept { - success_callback_(total_size); - if (read_bytes_callback_) { - read_bytes_callback_->onSuccess(total_size); - } - - return_code_ = HTTPClientConnection::RC::DOWNLOAD_SUCCESS; -} - -} // namespace http - -} // namespace transport diff --git a/libtransport/src/hicn/transport/http/client_connection.h b/libtransport/src/hicn/transport/http/client_connection.h deleted file mode 100644 index e93a37111..000000000 --- a/libtransport/src/hicn/transport/http/client_connection.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2017-2020 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 -#include -#include -#include -#include -#include - -#include - -namespace transport { - -namespace http { - -using namespace interface; -using namespace core; - -class HTTPClientConnection : public ConsumerSocket::ReadCallback { - static constexpr uint32_t max_buffer_capacity = 64 * 1024; - - public: - class ReadBytesCallback { - public: - virtual void onBytesReceived(std::unique_ptr &&buffer) = 0; - virtual void onSuccess(std::size_t bytes) = 0; - virtual void onError(const std::error_code ec) = 0; - }; - - enum class RC : uint32_t { DOWNLOAD_FAILED, DOWNLOAD_SUCCESS }; - - HTTPClientConnection(); - - RC get(const std::string &url, HTTPHeaders headers = {}, - HTTPPayload &&payload = nullptr, - std::shared_ptr response = nullptr, - ReadBytesCallback *callback = nullptr, - std::string ipv6_first_word = "b001"); - - RC sendRequest(const std::string &url, HTTPMethod method, - HTTPHeaders headers = {}, HTTPPayload &&payload = nullptr, - std::shared_ptr response = nullptr, - ReadBytesCallback *callback = nullptr, - std::string ipv6_first_word = "b001"); - - std::shared_ptr response(); - - HTTPClientConnection &stop(); - - interface::ConsumerSocket &getConsumer(); - - HTTPClientConnection &setTimeout(const std::chrono::seconds &timeout); - - HTTPClientConnection &setCertificate(const std::string &cert_path); - - private: - void sendRequestGetReply(std::string &ipv6_first_word); - - bool verifyData(interface::ConsumerSocket &c, - const core::ContentObject &contentObject); - - void processLeavingInterest(interface::ConsumerSocket &c, - const core::Interest &interest); - - // Read callback - bool isBufferMovable() noexcept override { return true; } - void getReadBuffer(uint8_t **application_buffer, - size_t *max_length) override {} - void readDataAvailable(size_t length) noexcept override {} - size_t maxBufferSize() const override { return max_buffer_capacity; } - void readBufferAvailable( - std::unique_ptr &&buffer) noexcept override; - void readError(const std::error_code ec) noexcept override; - void readSuccess(std::size_t total_size) noexcept override; - - // The consumer socket - ConsumerSocket consumer_; - - // The current url provided by the application - std::string current_url_; - // The current hICN name used for downloading - std::stringstream name_; - // Function to be called when the read is successful - std::function success_callback_; - // Return code for current download - RC return_code_; - - // Application provided callback for saving the received content during - // the download. If this callback is used, the HTTPClient will NOT save - // any byte internally. - ReadBytesCallback *read_bytes_callback_; - - HTTPRequest request_; - - // Internal read buffer and HTTP response, to be used if the application does - // not provide any read_bytes_callback - std::unique_ptr read_buffer_; - std::shared_ptr response_; - - // Timer - std::unique_ptr timer_; -}; - -} // end namespace http - -} // end namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/http/default_values.h b/libtransport/src/hicn/transport/http/default_values.h deleted file mode 100644 index 2d5a6b821..000000000 --- a/libtransport/src/hicn/transport/http/default_values.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -namespace transport { - -namespace http { - -namespace default_values { - -const uint16_t ipv6_first_word = 0xb001; // Network byte order - -} // namespace default_values - -} // namespace http - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/http/facade.h b/libtransport/src/hicn/transport/http/facade.h deleted file mode 100644 index 1551ede3a..000000000 --- a/libtransport/src/hicn/transport/http/facade.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include - -namespace libl4 = transport; \ No newline at end of file diff --git a/libtransport/src/hicn/transport/http/message.h b/libtransport/src/hicn/transport/http/message.h deleted file mode 100644 index b8756224f..000000000 --- a/libtransport/src/hicn/transport/http/message.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2017-2020 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 - -#ifdef _WIN32 -#include -#endif - -#include - -#include -#include -#include - -#define HTTP_VERSION "1.1" - -namespace transport { - -namespace http { - -typedef enum { GET, POST, PUT, PATCH, DELETE } HTTPMethod; - -static std::map method_map = { - {GET, "GET"}, {POST, "POST"}, {PUT, "PUT"}, - {PATCH, "PATCH"}, {DELETE, "DELETE"}, -}; - -typedef std::map HTTPHeaders; -typedef std::unique_ptr HTTPPayload; - -class HTTPMessage { - public: - virtual ~HTTPMessage() = default; - - const HTTPHeaders getHeaders() { return headers_; }; - - void coalescePayloadBuffer() { - auto it = headers_.find("Content-Length"); - if (it != headers_.end()) { - auto content_length = std::stoul(it->second); - payload_->gather(content_length); - } - } - - HTTPPayload &&getPayload() { return std::move(payload_); } - - std::string getHttpVersion() const { return http_version_; }; - - protected: - HTTPHeaders headers_; - HTTPPayload payload_; - std::string http_version_; -}; - -} // end namespace http - -} // end namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/http/request.cc b/libtransport/src/hicn/transport/http/request.cc deleted file mode 100644 index 09f709642..000000000 --- a/libtransport/src/hicn/transport/http/request.cc +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2017-2020 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 -#include - -namespace transport { - -namespace http { - -HTTPRequest::HTTPRequest() {} - -HTTPRequest::HTTPRequest(HTTPMethod method, const std::string &url, - const HTTPHeaders &headers, HTTPPayload &&payload) { - init(method, url, headers, std::move(payload)); -} - -void HTTPRequest::init(HTTPMethod method, const std::string &url, - const HTTPHeaders &headers, HTTPPayload &&payload) { - utils::Uri uri; - uri.parse(url); - - path_ = uri.getPath(); - query_string_ = uri.getQueryString(); - protocol_ = uri.getProtocol(); - locator_ = uri.getLocator(); - port_ = uri.getPort(); - http_version_ = HTTP_VERSION; - - headers_ = headers; - payload_ = std::move(payload); - - std::transform(locator_.begin(), locator_.end(), locator_.begin(), ::tolower); - - std::transform(protocol_.begin(), protocol_.end(), protocol_.begin(), - ::tolower); - - std::stringstream stream; - stream << method_map[method] << " " << uri.getPath() << " HTTP/" - << HTTP_VERSION << "\r\n"; - for (auto &item : headers) { - stream << item.first << ": " << item.second << "\r\n"; - } - stream << "\r\n"; - request_string_ = stream.str(); -} - -std::string HTTPRequest::getPort() const { return port_; } - -std::string HTTPRequest::getLocator() const { return locator_; } - -std::string HTTPRequest::getProtocol() const { return protocol_; } - -std::string HTTPRequest::getPath() const { return path_; } - -std::string HTTPRequest::getQueryString() const { return query_string_; } - -std::string HTTPRequest::getRequestString() const { return request_string_; } - -} // namespace http - -} // namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/http/request.h b/libtransport/src/hicn/transport/http/request.h deleted file mode 100644 index 54904d696..000000000 --- a/libtransport/src/hicn/transport/http/request.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2017-2020 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 - -#include -#include -#include - -namespace transport { - -namespace http { - -class HTTPRequest : public HTTPMessage { - public: - HTTPRequest(); - HTTPRequest(HTTPMethod method, const std::string &url, - const HTTPHeaders &headers, HTTPPayload &&payload); - - void init(HTTPMethod method, const std::string &url, - const HTTPHeaders &headers, HTTPPayload &&payload); - - std::string getQueryString() const; - - std::string getPath() const; - - std::string getProtocol() const; - - std::string getLocator() const; - - std::string getPort() const; - - std::string getRequestString() const; - - private: - std::string query_string_, path_, protocol_, locator_, port_; - std::string request_string_; -}; - -} // end namespace http - -} // end namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/http/response.cc b/libtransport/src/hicn/transport/http/response.cc deleted file mode 100644 index ba0acd1ac..000000000 --- a/libtransport/src/hicn/transport/http/response.cc +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 2017-2020 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 -#include - -#include -#include - -#include - -namespace transport { - -namespace http { - -HTTPResponse::HTTPResponse() {} - -HTTPResponse::HTTPResponse(std::unique_ptr &&response) { - parse(std::move(response)); -} - -void HTTPResponse::appendResponseChunk( - std::unique_ptr &&response_chunk) { - if (headers_.empty()) { - parse(std::move(response_chunk)); - } else { - payload_->prependChain(std::move(response_chunk)); - } -} - -bool HTTPResponse::parseHeaders(std::unique_ptr &&buffer) { - auto ret = - HTTPResponse::parseHeaders(buffer->data(), buffer->length(), headers_, - http_version_, status_code_, status_string_); - - if (ret) { - buffer->trimStart(ret); - payload_ = std::move(buffer); - return true; - } - - return false; -} - -std::size_t HTTPResponse::parseHeaders(const uint8_t *buffer, std::size_t size, - HTTPHeaders &headers, - std::string &http_version, - std::string &status_code, - std::string &status_string) { - const char *crlf2 = "\r\n\r\n"; - const char *begin = (const char *)buffer; - const char *end = begin + size; - auto it = - std::experimental::search(begin, end, - std::experimental::make_boyer_moore_searcher( - crlf2, crlf2 + strlen(crlf2))); - - if (it != end) { - std::stringstream ss; - ss.str(std::string(begin, it)); - - std::string line; - getline(ss, line); - std::istringstream line_s(line); - std::string _http_version; - - line_s >> _http_version; - std::size_t separator; - if ((separator = _http_version.find('/')) != std::string::npos) { - if (_http_version.substr(0, separator) != "HTTP") { - return 0; - } - http_version = - line.substr(separator + 1, _http_version.length() - separator - 1); - } else { - return 0; - } - - std::string _status_string; - - line_s >> status_code; - line_s >> _status_string; - - auto _it = std::search(line.begin(), line.end(), status_string.begin(), - status_string.end()); - - status_string = std::string(_it, line.end() - 1); - - std::size_t param_end; - std::size_t value_start; - while (getline(ss, line)) { - if ((param_end = line.find(':')) != std::string::npos) { - value_start = param_end + 1; - if ((value_start) < line.size()) { - if (line[value_start] == ' ') { - value_start++; - } - if (value_start < line.size()) { - headers[line.substr(0, param_end)] = - line.substr(value_start, line.size() - value_start - 1); - } - } - } else { - return 0; - } - } - } - - return it + strlen(crlf2) - begin; -} - -void HTTPResponse::parse(std::unique_ptr &&response) { - if (!parseHeaders(std::move(response))) { - throw errors::RuntimeException("Malformed HTTP response"); - } -} - -const std::string &HTTPResponse::getStatusCode() const { return status_code_; } - -const std::string &HTTPResponse::getStatusString() const { - return status_string_; -} - -} // namespace http - -} // namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/http/response.h b/libtransport/src/hicn/transport/http/response.h deleted file mode 100644 index bab41acb8..000000000 --- a/libtransport/src/hicn/transport/http/response.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2017-2020 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 -#include - -#include -#include -#include - -namespace transport { - -namespace http { - -class HTTPResponse : public HTTPMessage { - public: - HTTPResponse(); - - HTTPResponse(std::unique_ptr &&response); - - void appendResponseChunk(std::unique_ptr &&response_chunk); - - const std::string &getStatusCode() const; - - const std::string &getStatusString() const; - - void parse(std::unique_ptr &&response); - - bool parseHeaders(std::unique_ptr &&buffer); - - static std::size_t parseHeaders(const uint8_t *buffer, std::size_t size, - HTTPHeaders &headers, - std::string &http_version, - std::string &status_code, - std::string &status_string); - - private: - std::string status_code_; - std::string status_string_; -}; - -} // end namespace http - -} // end namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/http/server_acceptor.cc b/libtransport/src/hicn/transport/http/server_acceptor.cc deleted file mode 100644 index e478dfcd4..000000000 --- a/libtransport/src/hicn/transport/http/server_acceptor.cc +++ /dev/null @@ -1,110 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include - -namespace transport { - -namespace http { - -HTTPServerAcceptor::HTTPServerAcceptor(std::string &&server_locator, - OnHttpRequest callback) - : HTTPServerAcceptor(server_locator, callback) {} - -HTTPServerAcceptor::HTTPServerAcceptor(std::string &server_locator, - OnHttpRequest callback) - : callback_(callback) { - utils::Uri uri; - - uri.parseProtocolAndLocator(server_locator); - std::string protocol = uri.getProtocol(); - std::string locator = uri.getLocator(); - - std::transform(locator.begin(), locator.end(), locator.begin(), ::tolower); - - std::transform(protocol.begin(), protocol.end(), protocol.begin(), ::tolower); - - if (protocol != "http") { - throw errors::RuntimeException( - "Malformed server_locator. The locator format should be in the form " - "http://locator"); - } - - uint32_t locator_hash = - utils::hash::fnv32_buf(locator.c_str(), locator.size()); - - std::stringstream stream; - stream << std::hex << http::default_values::ipv6_first_word << ":0000"; - - for (uint16_t *word = (uint16_t *)&locator_hash; - std::size_t(word) < (std::size_t(&locator_hash) + sizeof(locator_hash)); - word++) { - stream << ":" << std::hex << *word; - } - - stream << "::0"; - - std::string network = stream.str(); - - core::Prefix acceptor_namespace(network, 64); - - std::string producer_identity = "acceptor_producer"; - acceptor_producer_ = std::make_shared(); - acceptor_producer_->registerPrefix(acceptor_namespace); -} - -void HTTPServerAcceptor::listen(bool async) { - acceptor_producer_->setSocketOption( - ProducerCallbacksOptions::INTEREST_INPUT, - (ProducerInterestCallback)bind( - &HTTPServerAcceptor::processIncomingInterest, this, - std::placeholders::_1, std::placeholders::_2)); - acceptor_producer_->connect(); - - if (!async) { - acceptor_producer_->serveForever(); - } -} - -void HTTPServerAcceptor::processIncomingInterest(ProducerSocket &p, - Interest &interest) { - // Temporary solution. With - auto payload = interest.getPayload(); - - int request_id = utils::hash::fnv32_buf(payload->data(), payload->length()); - - if (publishers_.find(request_id) != publishers_.end()) { - if (publishers_[request_id]) { - publishers_[request_id]->getProducer().onInterest(interest); - return; - } - } - - publishers_[request_id] = - std::make_shared(interest.getName()); - callback_(publishers_[request_id], (uint8_t *)payload->data(), - payload->length(), request_id); -} - -std::map> - &HTTPServerAcceptor::getPublishers() { - return publishers_; -} - -} // namespace http - -} // namespace transport diff --git a/libtransport/src/hicn/transport/http/server_acceptor.h b/libtransport/src/hicn/transport/http/server_acceptor.h deleted file mode 100644 index 6ed58f70e..000000000 --- a/libtransport/src/hicn/transport/http/server_acceptor.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include -#include -#include - -#include -#include - -namespace transport { - -namespace http { - -class HTTPServerAcceptor { - friend class HTTPServerPublisher; - using OnHttpRequest = - std::function &, - const uint8_t *, std::size_t, int request_id)>; - - public: - HTTPServerAcceptor(std::string &&server_locator, OnHttpRequest callback); - HTTPServerAcceptor(std::string &server_locator, OnHttpRequest callback); - - void listen(bool async); - - std::map> &getPublishers(); - - // void asyncSendResponse(); - - // HTTPClientConnection& get(std::string &url, HTTPHeaders headers = {}, - // HTTPPayload payload = {}); - // - // HTTPResponse&& response(); - - private: - void processIncomingInterest(ProducerSocket &p, Interest &interest); - - OnHttpRequest callback_; - std::shared_ptr acceptor_producer_; - - std::map> publishers_; -}; - -} // end namespace http - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/http/server_publisher.cc b/libtransport/src/hicn/transport/http/server_publisher.cc deleted file mode 100644 index b4deb5333..000000000 --- a/libtransport/src/hicn/transport/http/server_publisher.cc +++ /dev/null @@ -1,173 +0,0 @@ -/* - * 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. - */ - -#include -#include - -namespace transport { - -namespace http { - -HTTPServerPublisher::HTTPServerPublisher(const core::Name &content_name) - : content_name_(content_name) { - std::string identity = "acceptor_producer"; - producer_ = std::make_unique(); - // utils::Identity::generateIdentity(identity)); - core::Prefix publisher_prefix(content_name_, 128); - producer_->registerPrefix(publisher_prefix); -} - -HTTPServerPublisher::~HTTPServerPublisher() { - if (timer_) { - this->timer_->cancel(); - } -} - -HTTPServerPublisher &HTTPServerPublisher::attachPublisher() { - // Create a new publisher - producer_->setSocketOption(GeneralTransportOptions::DATA_PACKET_SIZE, - 1410_U32); - producer_->connect(); - return *this; -} - -HTTPServerPublisher &HTTPServerPublisher::setTimeout( - const std::chrono::milliseconds &timeout, bool timeout_renewal) { - std::shared_ptr portal; - producer_->getSocketOption(GeneralTransportOptions::PORTAL, portal); - timer_ = - std::make_unique(portal->getIoService(), timeout); - - wait_callback_ = [this](const std::error_code &e) { - if (!e) { - producer_->stop(); - } - }; - - if (timeout_renewal) { - interest_enter_callback_ = [this, timeout](ProducerSocket &p, - const Interest &interest) { - this->timer_->cancel(); - this->timer_->expires_from_now(timeout); - this->timer_->async_wait(wait_callback_); - }; - - producer_->setSocketOption( - ProducerCallbacksOptions::CACHE_HIT, - (ProducerInterestCallback)interest_enter_callback_); - } - - timer_->async_wait(wait_callback_); - - return *this; -} - -void HTTPServerPublisher::publishContent( - const uint8_t *buf, size_t buffer_size, - std::chrono::milliseconds content_lifetime, bool is_last) { - if (producer_) { - producer_->setSocketOption( - GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME, - static_cast(content_lifetime.count())); - producer_->produce(content_name_, buf, buffer_size, is_last); - // producer_->setSocketOption(ProducerCallbacksOptions::CACHE_MISS, - // [this](ProducerSocket &p, const - // core::Interest &interest){ - // producer_->stop(); - // }); - } -} - -template -void HTTPServerPublisher::asyncPublishContent( - const uint8_t *buf, size_t buffer_size, - std::chrono::milliseconds content_lifetime, Handler &&handler, - bool is_last) { - if (producer_) { - producer_->setSocketOption( - GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME, - static_cast(content_lifetime.count())); - producer_->asyncProduce(content_name_, buf, buffer_size, - std::forward(handler), is_last); - } -} - -void HTTPServerPublisher::serveClients() { producer_->serveForever(); } - -void HTTPServerPublisher::stop() { - std::shared_ptr portal_ptr; - producer_->getSocketOption(GeneralTransportOptions::PORTAL, portal_ptr); - portal_ptr->getIoService().stop(); -} - -ProducerSocket &HTTPServerPublisher::getProducer() { return *producer_; } - -void HTTPServerPublisher::setPublisherName(std::string &name, - std::string &mask) { - // Name represents the last 64 bits of the ipv6 address. - // It is an ipv6 address with the first 64 bits set to 0 - uint16_t i; - std::string s = content_name_.toString(); - std::shared_ptr sockaddr = content_name_.getAddress(); - in6_addr name_ipv6 = ((core::Sockaddr6 *)sockaddr.get())->sin6_addr; - - in6_addr bitmask, new_address, _name; - - if (inet_pton(AF_INET6, mask.c_str(), &bitmask) != 1) { - throw errors::RuntimeException("Error during conversion to ipv6 address."); - } - - if (inet_pton(AF_INET6, name.c_str(), &_name) != 1) { - throw errors::RuntimeException("Error during conversion to ipv6 address."); - } - - for (i = 0; i < sizeof(new_address.s6_addr); i++) { - new_address.s6_addr[i] = name_ipv6.s6_addr[i] & bitmask.s6_addr[i]; - } - - for (i = 0; i < sizeof(new_address.s6_addr); i++) { - new_address.s6_addr[i] |= _name.s6_addr[i] & ~bitmask.s6_addr[i]; - } - - // Effectively change the name - char str[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, &new_address, str, INET6_ADDRSTRLEN); - std::string str2(str); - - core::Name new_name(str2, 0); - - // If the new name differs from the one required by the consumer part, send a - // manifest - if (!new_name.equals(content_name_, false)) { - // Publish manifest pointing to the new name - - auto manifest = - std::make_shared(content_name_.setSuffix(0)); - - content_name_ = core::Name(str2, 0); - - // manifest->setNameList(content_name_); - manifest->setLifetime(4000 * 1000); - manifest->encode(); - producer_->produce(*manifest); - - core::Prefix ns(content_name_, 128); - producer_->registerPrefix(ns); - } -} - -} // namespace http - -} // namespace transport diff --git a/libtransport/src/hicn/transport/http/server_publisher.h b/libtransport/src/hicn/transport/http/server_publisher.h deleted file mode 100644 index 33d596f63..000000000 --- a/libtransport/src/hicn/transport/http/server_publisher.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include - -#include -#include - -namespace transport { - -namespace http { - -using namespace interface; -using namespace core; - -class HTTPServerPublisher { - public: - HTTPServerPublisher(const core::Name &content_name); - - ~HTTPServerPublisher(); - - void publishContent(const uint8_t *buf, size_t buffer_size, - std::chrono::milliseconds content_lifetime, bool is_last); - - template - void asyncPublishContent(const uint8_t *buf, size_t buffer_size, - std::chrono::milliseconds content_lifetime, - Handler &&handler, bool is_last); - - void serveClients(); - - void stop(); - - ProducerSocket &getProducer(); - - HTTPServerPublisher &setTimeout(const std::chrono::milliseconds &timeout, - bool timeout_renewal); - - HTTPServerPublisher &attachPublisher(); - - void setPublisherName(std::string &name, std::string &mask); - - private: - Name content_name_; - std::unique_ptr timer_; - std::unique_ptr producer_; - ProducerInterestCallback interest_enter_callback_; - utils::UserCallback wait_callback_; -}; - -} // end namespace http - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/interfaces/CMakeLists.txt b/libtransport/src/hicn/transport/interfaces/CMakeLists.txt deleted file mode 100644 index 88b83e9d4..000000000 --- a/libtransport/src/hicn/transport/interfaces/CMakeLists.txt +++ /dev/null @@ -1,59 +0,0 @@ -# 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) - -list(APPEND HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/socket.h - ${CMAKE_CURRENT_SOURCE_DIR}/socket_consumer.h - ${CMAKE_CURRENT_SOURCE_DIR}/socket_producer.h - ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_producer.h - ${CMAKE_CURRENT_SOURCE_DIR}/tls_rtc_socket_producer.h - ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_producer.h - ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_consumer.h - ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_consumer.h - ${CMAKE_CURRENT_SOURCE_DIR}/rtc_socket_producer.h - ${CMAKE_CURRENT_SOURCE_DIR}/publication_options.h - ${CMAKE_CURRENT_SOURCE_DIR}/socket_options_default_values.h - ${CMAKE_CURRENT_SOURCE_DIR}/socket_options_keys.h - ${CMAKE_CURRENT_SOURCE_DIR}/callbacks.h - ${CMAKE_CURRENT_SOURCE_DIR}/verification_policy.h -) - -list(APPEND SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/socket_producer.cc - ${CMAKE_CURRENT_SOURCE_DIR}/rtc_socket_producer.cc - ${CMAKE_CURRENT_SOURCE_DIR}/socket_consumer.cc - ${CMAKE_CURRENT_SOURCE_DIR}/callbacks.cc -) - -if (${OPENSSL_VERSION} VERSION_EQUAL "1.1.1a" OR ${OPENSSL_VERSION} VERSION_GREATER "1.1.1a") - list(APPEND SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_producer.cc - ${CMAKE_CURRENT_SOURCE_DIR}/tls_rtc_socket_producer.cc - ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_producer.cc - ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_consumer.cc - ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_consumer.cc - ) - - list(APPEND HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_producer.h - ${CMAKE_CURRENT_SOURCE_DIR}/tls_rtc_socket_producer.h - ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_producer.h - ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_consumer.h - ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_consumer.h - ) -endif() - -set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) -set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) diff --git a/libtransport/src/hicn/transport/interfaces/callbacks.cc b/libtransport/src/hicn/transport/interfaces/callbacks.cc deleted file mode 100644 index 2574e7720..000000000 --- a/libtransport/src/hicn/transport/interfaces/callbacks.cc +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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. - */ - -#include "callbacks.h" - -namespace transport { - -namespace interface { - -std::nullptr_t VOID_HANDLER = nullptr; - -} // namespace interface - -} // namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/interfaces/callbacks.h b/libtransport/src/hicn/transport/interfaces/callbacks.h deleted file mode 100644 index 9d3d57992..000000000 --- a/libtransport/src/hicn/transport/interfaces/callbacks.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include - -#include -#include - -namespace utils { -class MemBuf; -} - -namespace transport { - -namespace protocol { - -class IcnObserver; -class TransportStatistics; - -} // namespace protocol - -namespace core { - -class ContentObject; -class Interest; -} // namespace core - -namespace interface { - -// Forward declarations -class ConsumerSocket; -class ProducerSocket; - -/** - * The ConsumerInterestCallback will be called in different parts of the - * consumer socket processing pipeline, with a ConsumerSocket and an Interest as - * parameters. - */ -using ConsumerInterestCallback = - std::function; - -/** - * The ConsumerTimerCallback is called periodically for exposing to applications - * a summary of the statistics of the transport protocol in use. - */ -using ConsumerTimerCallback = std::function; - -/** - * The ProducerContentCallback will be called by the producer socket right after - * a content has been segmented and published. - */ -using ProducerContentCallback = std::function; - -/** - * The ConsumerContentObjectCallback will be called in different parts of the - * consumer socket processing pipeline, with a ConsumerSocket and an - * ContentObject as parameters. - */ -using ConsumerContentObjectCallback = - std::function; - -/** - * The ConsumerContentObjectVerificationCallback will be called by the transport - * if an application is willing to verify each content object. Note that a - * better alternative is to instrument the transport to perform the verification - * autonomously, without requiring the intervention of the application. - */ -using ConsumerContentObjectVerificationCallback = - std::function; - -/** - * The ConsumerContentObjectVerificationFailedCallback will be caled by the - * transport if a data packet (either manifest or content object) cannot be - * verified. The application here decides what to do by returning a - * VerificationFailedPolicy object. - */ -using ConsumerContentObjectVerificationFailedCallback = - std::function; - -/** - * The ConsumerManifestCallback will be called by the consumer socket when a - * manifest is received. - */ -using ConsumerManifestCallback = - std::function; - -/** - * The ProducerContentObjectCallback will be called in different parts of the - * consumer socket processing pipeline, with a ProducerSocket and an - * ContentObject as parameters. - */ -using ProducerContentObjectCallback = - std::function; - -/** - * The ProducerContentObjectCallback will be called in different parts of the - * consumer socket processing pipeline, with a ProducerSocket and an - * Interest as parameters. - */ -using ProducerInterestCallback = - std::function; - -extern std::nullptr_t VOID_HANDLER; - -} // namespace interface - -} // namespace transport diff --git a/libtransport/src/hicn/transport/interfaces/p2psecure_socket_consumer.cc b/libtransport/src/hicn/transport/interfaces/p2psecure_socket_consumer.cc deleted file mode 100644 index ec966e509..000000000 --- a/libtransport/src/hicn/transport/interfaces/p2psecure_socket_consumer.cc +++ /dev/null @@ -1,382 +0,0 @@ -#include -#include -#include -#include - -#include - -namespace transport { - -namespace interface { - -void P2PSecureConsumerSocket::setInterestPayload( - ConsumerSocket &c, const core::Interest &interest) { - Interest &int2 = const_cast(interest); - random_suffix_ = int2.getName().getSuffix(); - - if (payload_ != NULL) int2.appendPayload(std::move(payload_)); -} - -// implement void readBufferAvailable(), size_t maxBufferSize() const override, -// void readError(), void readSuccess(). getReadBuffer() and readDataAvailable() -// must be implemented even if empty. - -/* Return the number of read bytes in the return param */ -int readOld(BIO *b, char *buf, int size) { - if (size < 0) return size; - - P2PSecureConsumerSocket *socket; - socket = (P2PSecureConsumerSocket *)BIO_get_data(b); - - std::unique_lock lck(socket->mtx_); - - if (!socket->something_to_read_) { - if (!socket->transport_protocol_->isRunning()) { - socket->network_name_.setSuffix(socket->random_suffix_); - socket->ConsumerSocket::asyncConsume(socket->network_name_); - } - if (!socket->something_to_read_) socket->cv_.wait(lck); - } - - size_t size_to_read, read; - size_t chain_size = socket->head_->length(); - if (socket->head_->isChained()) - chain_size = socket->head_->computeChainDataLength(); - - if (chain_size > (size_t)size) { - read = size_to_read = (size_t)size; - } else { - read = size_to_read = chain_size; - socket->something_to_read_ = false; - } - - while (size_to_read) { - if (socket->head_->length() < size_to_read) { - std::memcpy(buf, socket->head_->data(), socket->head_->length()); - size_to_read -= socket->head_->length(); - buf += socket->head_->length(); - socket->head_ = socket->head_->pop(); - } else { - std::memcpy(buf, socket->head_->data(), size_to_read); - socket->head_->trimStart(size_to_read); - size_to_read = 0; - } - } - - return read; -} - -/* Return the number of read bytes in readbytes */ -int read(BIO *b, char *buf, size_t size, size_t *readbytes) { - int ret; - - if (size > INT_MAX) size = INT_MAX; - - ret = transport::interface::readOld(b, buf, (int)size); - - if (ret <= 0) { - *readbytes = 0; - return ret; - } - - *readbytes = (size_t)ret; - - return 1; -} - -/* Return the number of written bytes in the return param */ -int writeOld(BIO *b, const char *buf, int num) { - P2PSecureConsumerSocket *socket; - socket = (P2PSecureConsumerSocket *)BIO_get_data(b); - - socket->payload_ = utils::MemBuf::copyBuffer(buf, num); - socket->ConsumerSocket::setSocketOption( - ConsumerCallbacksOptions::INTEREST_OUTPUT, - (ConsumerInterestCallback)std::bind( - &P2PSecureConsumerSocket::setInterestPayload, socket, - std::placeholders::_1, std::placeholders::_2)); - - return num; -} - -/* Return the number of written bytes in written */ -int write(BIO *b, const char *buf, size_t size, size_t *written) { - int ret; - - if (size > INT_MAX) size = INT_MAX; - - ret = transport::interface::writeOld(b, buf, (int)size); - - if (ret <= 0) { - *written = 0; - return ret; - } - - *written = (size_t)ret; - - return 1; -} - -long ctrl(BIO *b, int cmd, long num, void *ptr) { return 1; } - -int P2PSecureConsumerSocket::addHicnKeyIdCb(SSL *s, unsigned int ext_type, - unsigned int context, - const unsigned char **out, - size_t *outlen, X509 *x, - size_t chainidx, int *al, - void *add_arg) { - if (ext_type == 100) { - *out = (unsigned char *)malloc(4); - *(uint32_t *)*out = 10; - *outlen = 4; - } - return 1; -} - -void P2PSecureConsumerSocket::freeHicnKeyIdCb(SSL *s, unsigned int ext_type, - unsigned int context, - const unsigned char *out, - void *add_arg) { - free(const_cast(out)); -} - -int P2PSecureConsumerSocket::parseHicnKeyIdCb(SSL *s, unsigned int ext_type, - unsigned int context, - const unsigned char *in, - size_t inlen, X509 *x, - size_t chainidx, int *al, - void *add_arg) { - P2PSecureConsumerSocket *socket = - reinterpret_cast(add_arg); - if (ext_type == 100) { - memcpy(&socket->secure_prefix_, in, sizeof(ip_prefix_t)); - } - return 1; -} - -P2PSecureConsumerSocket::P2PSecureConsumerSocket(int handshake_protocol, int transport_protocol) - : ConsumerSocket(handshake_protocol), - name_(), - tls_consumer_(), - buf_pool_(), - decrypted_content_(), - payload_(), - head_(), - something_to_read_(false), - content_downloaded_(false), - random_suffix_(), - secure_prefix_(), - producer_namespace_(), - read_callback_decrypted_(), - mtx_(), - cv_(), - protocol_(transport_protocol) { - /* Create the (d)TLS state */ - const SSL_METHOD *meth = TLS_client_method(); - ctx_ = SSL_CTX_new(meth); - - int result = - SSL_CTX_set_ciphersuites(ctx_, - "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_" - "SHA256:TLS_AES_128_GCM_SHA256"); - if (result != 1) { - throw errors::RuntimeException( - "Unable to set cipher list on TLS subsystem. Aborting."); - } - - SSL_CTX_set_min_proto_version(ctx_, TLS1_3_VERSION); - SSL_CTX_set_max_proto_version(ctx_, TLS1_3_VERSION); - SSL_CTX_set_verify(ctx_, SSL_VERIFY_NONE, NULL); - SSL_CTX_set_ssl_version(ctx_, meth); - - result = SSL_CTX_add_custom_ext( - ctx_, 100, SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS, - P2PSecureConsumerSocket::addHicnKeyIdCb, - P2PSecureConsumerSocket::freeHicnKeyIdCb, NULL, - P2PSecureConsumerSocket::parseHicnKeyIdCb, this); - - ssl_ = SSL_new(ctx_); - - bio_meth_ = BIO_meth_new(BIO_TYPE_CONNECT, "secure consumer socket"); - BIO_meth_set_read(bio_meth_, transport::interface::readOld); - BIO_meth_set_write(bio_meth_, transport::interface::writeOld); - BIO_meth_set_ctrl(bio_meth_, transport::interface::ctrl); - BIO *bio = BIO_new(bio_meth_); - BIO_set_init(bio, 1); - BIO_set_data(bio, this); - SSL_set_bio(ssl_, bio, bio); - - ConsumerSocket::getSocketOption(MAX_WINDOW_SIZE, old_max_win_); - ConsumerSocket::setSocketOption(MAX_WINDOW_SIZE, (double)1.0); - - ConsumerSocket::getSocketOption(CURRENT_WINDOW_SIZE, old_current_win_); - ConsumerSocket::setSocketOption(CURRENT_WINDOW_SIZE, (double)1.0); - - std::default_random_engine generator; - std::uniform_int_distribution distribution( - 1, std::numeric_limits::max()); - random_suffix_ = 0; - - this->ConsumerSocket::setSocketOption(ConsumerCallbacksOptions::READ_CALLBACK, - this); -}; - -P2PSecureConsumerSocket::~P2PSecureConsumerSocket() { - BIO_meth_free(bio_meth_); - SSL_shutdown(ssl_); -} - -int P2PSecureConsumerSocket::consume(const Name &name) { - if (transport_protocol_->isRunning()) { - return CONSUMER_BUSY; - } - - if ((SSL_in_before(this->ssl_) || SSL_in_init(this->ssl_))) { - ConsumerSocket::setSocketOption(MAX_WINDOW_SIZE, (double)1.0); - network_name_ = producer_namespace_.getRandomName(); - network_name_.setSuffix(0); - int result = SSL_connect(this->ssl_); - ConsumerSocket::setSocketOption(MAX_WINDOW_SIZE, old_max_win_); - ConsumerSocket::setSocketOption(CURRENT_WINDOW_SIZE, old_current_win_); - if (result != 1) - throw errors::RuntimeException("Unable to perform client handshake"); - } - std::shared_ptr prefix_name = std::make_shared( - secure_prefix_.family, - ip_address_get_buffer(&(secure_prefix_.address), secure_prefix_.family)); - std::shared_ptr prefix = - std::make_shared(*prefix_name, secure_prefix_.len); - TLSConsumerSocket tls_consumer(this->protocol_, this->ssl_); - - ConsumerTimerCallback *stats_summary_callback = nullptr; - this->getSocketOption(ConsumerCallbacksOptions::STATS_SUMMARY, - &stats_summary_callback); - - uint32_t lifetime; - this->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, lifetime); - tls_consumer.setSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, - lifetime); - tls_consumer.setSocketOption(ConsumerCallbacksOptions::READ_CALLBACK, - read_callback_decrypted_); - tls_consumer.setSocketOption(ConsumerCallbacksOptions::STATS_SUMMARY, - *stats_summary_callback); - tls_consumer.setSocketOption(GeneralTransportOptions::STATS_INTERVAL, - this->timer_interval_milliseconds_); - tls_consumer.setSocketOption(MAX_WINDOW_SIZE, old_max_win_); - tls_consumer.setSocketOption(CURRENT_WINDOW_SIZE, old_current_win_); - tls_consumer.connect(); - - if (payload_ != NULL) - return tls_consumer.consume((prefix->mapName(name)), std::move(payload_)); - else - return tls_consumer.consume((prefix->mapName(name))); -} - -int P2PSecureConsumerSocket::asyncConsume(const Name &name) { - if ((SSL_in_before(this->ssl_) || SSL_in_init(this->ssl_))) { - ConsumerSocket::setSocketOption(CURRENT_WINDOW_SIZE, (double)1.0); - ConsumerSocket::setSocketOption(MAX_WINDOW_SIZE, (double)1.0); - network_name_ = producer_namespace_.getRandomName(); - network_name_.setSuffix(0); - TRANSPORT_LOGD("Start handshake at %s", network_name_.toString().c_str()); - interface::ConsumerSocket::ReadCallback *on_payload = VOID_HANDLER; - this->getSocketOption(ConsumerCallbacksOptions::READ_CALLBACK, &on_payload); - int result = SSL_connect(this->ssl_); - ConsumerSocket::setSocketOption(MAX_WINDOW_SIZE, old_max_win_); - ConsumerSocket::setSocketOption(CURRENT_WINDOW_SIZE, old_current_win_); - if (result != 1) - throw errors::RuntimeException("Unable to perform client handshake"); - TRANSPORT_LOGD("Handshake performed!"); - } - - std::shared_ptr prefix_name = std::make_shared( - secure_prefix_.family, - ip_address_get_buffer(&(secure_prefix_.address), secure_prefix_.family)); - std::shared_ptr prefix = - std::make_shared(*prefix_name, secure_prefix_.len); - tls_consumer_ = - std::make_shared(this->protocol_, this->ssl_); - - ConsumerTimerCallback *stats_summary_callback = nullptr; - this->getSocketOption(ConsumerCallbacksOptions::STATS_SUMMARY, - &stats_summary_callback); - - uint32_t lifetime; - this->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, lifetime); - tls_consumer_->setSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, - lifetime); - tls_consumer_->setSocketOption(ConsumerCallbacksOptions::READ_CALLBACK, - read_callback_decrypted_); - tls_consumer_->setSocketOption(ConsumerCallbacksOptions::STATS_SUMMARY, - *stats_summary_callback); - tls_consumer_->setSocketOption(GeneralTransportOptions::STATS_INTERVAL, - this->timer_interval_milliseconds_); - tls_consumer_->setSocketOption(MAX_WINDOW_SIZE, old_max_win_); - tls_consumer_->setSocketOption(CURRENT_WINDOW_SIZE, old_current_win_); - tls_consumer_->connect(); - - if (payload_ != NULL) - return tls_consumer_->asyncConsume((prefix->mapName(name)), - std::move(payload_)); - else - return tls_consumer_->asyncConsume((prefix->mapName(name))); -} - -void P2PSecureConsumerSocket::registerPrefix(const Prefix &producer_namespace) { - producer_namespace_ = producer_namespace; -} - -int P2PSecureConsumerSocket::setSocketOption( - int socket_option_key, ConsumerSocket::ReadCallback *socket_option_value) { - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ConsumerSocket::ReadCallback *socket_option_value) -> int { - switch (socket_option_key) { - case ConsumerCallbacksOptions::READ_CALLBACK: - read_callback_decrypted_ = socket_option_value; - break; - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; - }); -} - -void P2PSecureConsumerSocket::getReadBuffer(uint8_t **application_buffer, - size_t *max_length){}; - -void P2PSecureConsumerSocket::readDataAvailable(size_t length) noexcept {}; - -size_t P2PSecureConsumerSocket::maxBufferSize() const { - return SSL3_RT_MAX_PLAIN_LENGTH; -} - -void P2PSecureConsumerSocket::readBufferAvailable( - std::unique_ptr &&buffer) noexcept { - std::unique_lock lck(this->mtx_); - if (head_) { - head_->prependChain(std::move(buffer)); - } else { - head_ = std::move(buffer); - } - - something_to_read_ = true; - cv_.notify_one(); -} - -void P2PSecureConsumerSocket::readError(const std::error_code ec) noexcept {}; - -void P2PSecureConsumerSocket::readSuccess(std::size_t total_size) noexcept { - std::unique_lock lck(this->mtx_); - content_downloaded_ = true; - something_to_read_ = true; - cv_.notify_one(); -} - -bool P2PSecureConsumerSocket::isBufferMovable() noexcept { return true; } - -} // namespace interface - -} // namespace transport diff --git a/libtransport/src/hicn/transport/interfaces/p2psecure_socket_consumer.h b/libtransport/src/hicn/transport/interfaces/p2psecure_socket_consumer.h deleted file mode 100644 index ff867f07b..000000000 --- a/libtransport/src/hicn/transport/interfaces/p2psecure_socket_consumer.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include -#include - -namespace transport { - -namespace interface { - -class P2PSecureConsumerSocket : public ConsumerSocket, - public ConsumerSocket::ReadCallback { - /* Return the number of read bytes in readbytes */ - friend int read(BIO *b, char *buf, size_t size, size_t *readbytes); - - /* Return the number of read bytes in the return param */ - friend int readOld(BIO *h, char *buf, int size); - - /* Return the number of written bytes in written */ - friend int write(BIO *b, const char *buf, size_t size, size_t *written); - - /* Return the number of written bytes in the return param */ - friend int writeOld(BIO *h, const char *buf, int num); - - friend long ctrl(BIO *b, int cmd, long num, void *ptr); - - public: - explicit P2PSecureConsumerSocket(int handshake_protocol, int transport_protocol); - - ~P2PSecureConsumerSocket(); - - int consume(const Name &name) override; - - int asyncConsume(const Name &name) override; - - void registerPrefix(const Prefix &producer_namespace); - - int setSocketOption( - int socket_option_key, - ConsumerSocket::ReadCallback *socket_option_value) override; - - using ConsumerSocket::getSocketOption; - using ConsumerSocket::setSocketOption; - - protected: - /* Callback invoked once an interest has been received and its payload - * decrypted */ - ConsumerInterestCallback on_interest_input_decrypted_; - ConsumerInterestCallback on_interest_process_decrypted_; - - private: - Name name_; - std::shared_ptr tls_consumer_; - - /* SSL handle */ - SSL *ssl_; - SSL_CTX *ctx_; - BIO_METHOD *bio_meth_; - - /* Chain of MemBuf to be used as a temporary buffer to pass descypted data - * from the underlying layer to the application */ - utils::ObjectPool buf_pool_; - std::unique_ptr decrypted_content_; - - /* Chain of MemBuf holding the payload to be written into interest or data */ - std::unique_ptr payload_; - - /* Chain of MemBuf holding the data retrieved from the underlying layer */ - std::unique_ptr head_; - - bool something_to_read_; - - bool content_downloaded_; - - double old_max_win_; - - double old_current_win_; - - uint32_t random_suffix_; - - ip_prefix_t secure_prefix_; - - Prefix producer_namespace_; - - ConsumerSocket::ReadCallback *read_callback_decrypted_; - - std::mutex mtx_; - - /* Condition variable for the wait */ - std::condition_variable cv_; - - int protocol_; - - void setInterestPayload(ConsumerSocket &c, const core::Interest &interest); - void processPayload(ConsumerSocket &c, std::size_t bytes_transferred, - const std::error_code &ec); - - static int addHicnKeyIdCb(SSL *s, unsigned int ext_type, unsigned int context, - const unsigned char **out, size_t *outlen, X509 *x, - size_t chainidx, int *al, void *add_arg); - - static void freeHicnKeyIdCb(SSL *s, unsigned int ext_type, - unsigned int context, const unsigned char *out, - void *add_arg); - - static int parseHicnKeyIdCb(SSL *s, unsigned int ext_type, - unsigned int context, const unsigned char *in, - size_t inlen, X509 *x, size_t chainidx, int *al, - void *add_arg); - - virtual void getReadBuffer(uint8_t **application_buffer, - size_t *max_length) override; - - virtual void readDataAvailable(size_t length) noexcept override; - - virtual size_t maxBufferSize() const override; - - virtual void readBufferAvailable( - std::unique_ptr &&buffer) noexcept override; - - virtual void readError(const std::error_code ec) noexcept override; - - virtual void readSuccess(std::size_t total_size) noexcept override; - virtual bool isBufferMovable() noexcept override; - - int download_content(const Name &name); -}; - -} // namespace interface - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/interfaces/p2psecure_socket_producer.cc b/libtransport/src/hicn/transport/interfaces/p2psecure_socket_producer.cc deleted file mode 100644 index 8850bde8a..000000000 --- a/libtransport/src/hicn/transport/interfaces/p2psecure_socket_producer.cc +++ /dev/null @@ -1,380 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include - -namespace transport { - -namespace interface { - -/* Workaround to prevent content with expiry time equal to 0 to be lost when - * pushed in the forwarder */ -#define HICN_HANDSHAKE_CONTENT_EXPIRY_TIME 100; - -P2PSecureProducerSocket::P2PSecureProducerSocket() - : ProducerSocket(), - mtx_(), - cv_(), - map_secure_producers(), - map_secure_rtc_producers(), - list_secure_producers() {} - -P2PSecureProducerSocket::P2PSecureProducerSocket( - bool rtc, const std::shared_ptr &identity) - : ProducerSocket(), - rtc_(rtc), - mtx_(), - cv_(), - map_secure_producers(), - map_secure_rtc_producers(), - list_secure_producers() { - /* - * Setup SSL context (identity and parameter to use TLS 1.3) - */ - der_cert_ = parcKeyStore_GetDEREncodedCertificate( - (identity->getSigner()->getKeyStore())); - der_prk_ = parcKeyStore_GetDEREncodedPrivateKey( - (identity->getSigner()->getKeyStore())); - - int cert_size = parcBuffer_Limit(der_cert_); - int prk_size = parcBuffer_Limit(der_prk_); - const uint8_t *cert = - reinterpret_cast(parcBuffer_Overlay(der_cert_, cert_size)); - const uint8_t *prk = - reinterpret_cast(parcBuffer_Overlay(der_prk_, prk_size)); - cert_509_ = d2i_X509(NULL, &cert, cert_size); - pkey_rsa_ = d2i_AutoPrivateKey(NULL, &prk, prk_size); - - /* - * Set the callback so that when an interest is received we catch it and we - * decrypt the payload before passing it to the application. - */ - ProducerSocket::setSocketOption( - ProducerCallbacksOptions::INTEREST_INPUT, - (ProducerInterestCallback)std::bind( - &P2PSecureProducerSocket::onInterestCallback, this, - std::placeholders::_1, std::placeholders::_2)); -} - -P2PSecureProducerSocket::~P2PSecureProducerSocket() { - if (der_cert_) parcBuffer_Release(&der_cert_); - if (der_prk_) parcBuffer_Release(&der_prk_); -} - -void P2PSecureProducerSocket::onInterestCallback(ProducerSocket &p, - Interest &interest) { - std::unique_lock lck(mtx_); - - TRANSPORT_LOGD("Start handshake at %s", interest.getName().toString().c_str()); - if (!rtc_) { - auto it = map_secure_producers.find(interest.getName()); - if (it != map_secure_producers.end()) return; - TLSProducerSocket *tls_producer = - new TLSProducerSocket(this, interest.getName()); - tls_producer->on_content_produced_application_ = - this->on_content_produced_application_; - tls_producer->setSocketOption(CONTENT_OBJECT_EXPIRY_TIME, - this->content_object_expiry_time_); - tls_producer->setSocketOption(SIGNER, this->signer_); - tls_producer->setSocketOption(MAKE_MANIFEST, this->making_manifest_); - tls_producer->setSocketOption(DATA_PACKET_SIZE, - (uint32_t)(this->data_packet_size_)); - tls_producer->output_buffer_.setLimit(this->output_buffer_.getLimit()); - map_secure_producers.insert( - {interest.getName(), std::unique_ptr(tls_producer)}); - tls_producer->onInterest(*tls_producer, interest); - tls_producer->async_accept(); - } else { - auto it = map_secure_rtc_producers.find(interest.getName()); - if (it != map_secure_rtc_producers.end()) return; - TLSRTCProducerSocket *tls_producer = - new TLSRTCProducerSocket(this, interest.getName()); - tls_producer->on_content_produced_application_ = - this->on_content_produced_application_; - tls_producer->setSocketOption(CONTENT_OBJECT_EXPIRY_TIME, - this->content_object_expiry_time_); - tls_producer->setSocketOption(SIGNER, this->signer_); - tls_producer->setSocketOption(MAKE_MANIFEST, this->making_manifest_); - tls_producer->setSocketOption(DATA_PACKET_SIZE, - (uint32_t)(this->data_packet_size_)); - tls_producer->output_buffer_.setLimit(this->output_buffer_.getLimit()); - map_secure_rtc_producers.insert( - {interest.getName(), - std::unique_ptr(tls_producer)}); - tls_producer->onInterest(*tls_producer, interest); - tls_producer->async_accept(); - } -} - -void P2PSecureProducerSocket::produce(const uint8_t *buffer, - size_t buffer_size) { - if (!rtc_) { - throw errors::RuntimeException( - "RTC must be the transport protocol to start the production of current " - "data. Aborting."); - } - - std::unique_lock lck(mtx_); - if (list_secure_rtc_producers.empty()) cv_.wait(lck); - - for (auto it = list_secure_rtc_producers.cbegin(); - it != list_secure_rtc_producers.cend(); it++) { - (*it)->produce(utils::MemBuf::copyBuffer(buffer, buffer_size)); - } -} - -uint32_t P2PSecureProducerSocket::produce( - Name content_name, std::unique_ptr &&buffer, bool is_last, - uint32_t start_offset) { - if (rtc_) { - throw errors::RuntimeException( - "RTC transport protocol is not compatible with the production of " - "current data. Aborting."); - } - - std::unique_lock lck(mtx_); - uint32_t segments = 0; - if (list_secure_producers.empty()) cv_.wait(lck); - - for (auto it = list_secure_producers.cbegin(); - it != list_secure_producers.cend(); it++) - segments += - (*it)->produce(content_name, buffer->clone(), is_last, start_offset); - return segments; -} - -uint32_t P2PSecureProducerSocket::produce(Name content_name, - const uint8_t *buffer, - size_t buffer_size, bool is_last, - uint32_t start_offset) { - if (rtc_) { - throw errors::RuntimeException( - "RTC transport protocol is not compatible with the production of " - "current data. Aborting."); - } - - std::unique_lock lck(mtx_); - uint32_t segments = 0; - if (list_secure_producers.empty()) cv_.wait(lck); - - for (auto it = list_secure_producers.cbegin(); - it != list_secure_producers.cend(); it++) - segments += (*it)->produce(content_name, buffer, buffer_size, is_last, - start_offset); - return segments; -} - -void P2PSecureProducerSocket::asyncProduce(const Name &content_name, - const uint8_t *buf, - size_t buffer_size, bool is_last, - uint32_t *start_offset) { - if (rtc_) { - throw errors::RuntimeException( - "RTC transport protocol is not compatible with the production of " - "current data. Aborting."); - } - - std::unique_lock lck(mtx_); - if (list_secure_producers.empty()) cv_.wait(lck); - - for (auto it = list_secure_producers.cbegin(); - it != list_secure_producers.cend(); it++) { - (*it)->asyncProduce(content_name, buf, buffer_size, is_last, start_offset); - } -} - -void P2PSecureProducerSocket::asyncProduce( - Name content_name, std::unique_ptr &&buffer, bool is_last, - uint32_t offset, uint32_t **last_segment) { - if (rtc_) { - throw errors::RuntimeException( - "RTC transport protocol is not compatible with the production of " - "current data. Aborting."); - } - - std::unique_lock lck(mtx_); - if (list_secure_producers.empty()) cv_.wait(lck); - - for (auto it = list_secure_producers.cbegin(); - it != list_secure_producers.cend(); it++) { - (*it)->asyncProduce(content_name, buffer->clone(), is_last, offset, - last_segment); - } -} - -// Socket Option Redefinition to avoid name hiding - -int P2PSecureProducerSocket::setSocketOption( - int socket_option_key, ProducerInterestCallback socket_option_value) { - if (!list_secure_producers.empty()) { - for (auto it = list_secure_producers.cbegin(); - it != list_secure_producers.cend(); it++) - (*it)->setSocketOption(socket_option_key, socket_option_value); - } - - switch (socket_option_key) { - case ProducerCallbacksOptions::INTEREST_INPUT: - on_interest_input_decrypted_ = socket_option_value; - return SOCKET_OPTION_SET; - - case ProducerCallbacksOptions::INTEREST_DROP: - on_interest_dropped_input_buffer_ = socket_option_value; - return SOCKET_OPTION_SET; - - case ProducerCallbacksOptions::INTEREST_PASS: - on_interest_inserted_input_buffer_ = socket_option_value; - return SOCKET_OPTION_SET; - - case ProducerCallbacksOptions::CACHE_HIT: - on_interest_satisfied_output_buffer_ = socket_option_value; - return SOCKET_OPTION_SET; - - case ProducerCallbacksOptions::CACHE_MISS: - on_interest_process_decrypted_ = socket_option_value; - return SOCKET_OPTION_SET; - - default: - return SOCKET_OPTION_NOT_SET; - } -} - -int P2PSecureProducerSocket::setSocketOption( - int socket_option_key, - const std::shared_ptr &socket_option_value) { - if (!list_secure_producers.empty()) - for (auto it = list_secure_producers.cbegin(); - it != list_secure_producers.cend(); it++) - (*it)->setSocketOption(socket_option_key, socket_option_value); - - switch (socket_option_key) { - case GeneralTransportOptions::SIGNER: { - signer_.reset(); - signer_ = socket_option_value; - - return SOCKET_OPTION_SET; - } - default: - return SOCKET_OPTION_NOT_SET; - } -} - -int P2PSecureProducerSocket::setSocketOption(int socket_option_key, - uint32_t socket_option_value) { - if (!list_secure_producers.empty()) { - for (auto it = list_secure_producers.cbegin(); - it != list_secure_producers.cend(); it++) - (*it)->setSocketOption(socket_option_key, socket_option_value); - } - switch (socket_option_key) { - case GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME: - content_object_expiry_time_ = - socket_option_value; // HICN_HANDSHAKE_CONTENT_EXPIRY_TIME; - return SOCKET_OPTION_SET; - } - return ProducerSocket::setSocketOption(socket_option_key, - socket_option_value); -} - -int P2PSecureProducerSocket::setSocketOption(int socket_option_key, - bool socket_option_value) { - if (!list_secure_producers.empty()) - for (auto it = list_secure_producers.cbegin(); - it != list_secure_producers.cend(); it++) - (*it)->setSocketOption(socket_option_key, socket_option_value); - - return ProducerSocket::setSocketOption(socket_option_key, - socket_option_value); -} - -int P2PSecureProducerSocket::setSocketOption(int socket_option_key, - Name *socket_option_value) { - if (!list_secure_producers.empty()) - for (auto it = list_secure_producers.cbegin(); - it != list_secure_producers.cend(); it++) - (*it)->setSocketOption(socket_option_key, socket_option_value); - - return ProducerSocket::setSocketOption(socket_option_key, - socket_option_value); -} - -int P2PSecureProducerSocket::setSocketOption( - int socket_option_key, std::list socket_option_value) { - if (!list_secure_producers.empty()) - for (auto it = list_secure_producers.cbegin(); - it != list_secure_producers.cend(); it++) - (*it)->setSocketOption(socket_option_key, socket_option_value); - - return ProducerSocket::setSocketOption(socket_option_key, - socket_option_value); -} - -int P2PSecureProducerSocket::setSocketOption( - int socket_option_key, ProducerContentObjectCallback socket_option_value) { - if (!list_secure_producers.empty()) - for (auto it = list_secure_producers.cbegin(); - it != list_secure_producers.cend(); it++) - (*it)->setSocketOption(socket_option_key, socket_option_value); - - return ProducerSocket::setSocketOption(socket_option_key, - socket_option_value); -} - -int P2PSecureProducerSocket::setSocketOption( - int socket_option_key, ProducerContentCallback socket_option_value) { - if (!list_secure_producers.empty()) - for (auto it = list_secure_producers.cbegin(); - it != list_secure_producers.cend(); it++) - (*it)->setSocketOption(socket_option_key, socket_option_value); - - switch (socket_option_key) { - case ProducerCallbacksOptions::CONTENT_PRODUCED: - on_content_produced_application_ = socket_option_value; - break; - - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; -} - -int P2PSecureProducerSocket::setSocketOption( - int socket_option_key, HashAlgorithm socket_option_value) { - if (!list_secure_producers.empty()) - for (auto it = list_secure_producers.cbegin(); - it != list_secure_producers.cend(); it++) - (*it)->setSocketOption(socket_option_key, socket_option_value); - - return ProducerSocket::setSocketOption(socket_option_key, - socket_option_value); -} - -int P2PSecureProducerSocket::setSocketOption( - int socket_option_key, utils::CryptoSuite socket_option_value) { - if (!list_secure_producers.empty()) - for (auto it = list_secure_producers.cbegin(); - it != list_secure_producers.cend(); it++) - (*it)->setSocketOption(socket_option_key, socket_option_value); - - return ProducerSocket::setSocketOption(socket_option_key, - socket_option_value); -} - -int P2PSecureProducerSocket::setSocketOption( - int socket_option_key, const std::string &socket_option_value) { - if (!list_secure_producers.empty()) - for (auto it = list_secure_producers.cbegin(); - it != list_secure_producers.cend(); it++) - (*it)->setSocketOption(socket_option_key, socket_option_value); - - return ProducerSocket::setSocketOption(socket_option_key, - socket_option_value); -} - -} // namespace interface - -} // namespace transport diff --git a/libtransport/src/hicn/transport/interfaces/p2psecure_socket_producer.h b/libtransport/src/hicn/transport/interfaces/p2psecure_socket_producer.h deleted file mode 100644 index ba3fa0189..000000000 --- a/libtransport/src/hicn/transport/interfaces/p2psecure_socket_producer.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace transport { - -namespace interface { - -class P2PSecureProducerSocket : public ProducerSocket { - friend class TLSProducerSocket; - friend class TLSRTCProducerSocket; - - public: - explicit P2PSecureProducerSocket(); - explicit P2PSecureProducerSocket( - bool rtc, const std::shared_ptr &identity); - ~P2PSecureProducerSocket(); - - void produce(const uint8_t *buffer, size_t buffer_size) override; - - uint32_t produce(Name content_name, const uint8_t *buffer, size_t buffer_size, - bool is_last = true, uint32_t start_offset = 0) override; - - uint32_t produce(Name content_name, std::unique_ptr &&buffer, - bool is_last = true, uint32_t start_offset = 0) override; - - void asyncProduce(const Name &suffix, const uint8_t *buf, size_t buffer_size, - bool is_last = true, - uint32_t *start_offset = nullptr) override; - - void asyncProduce(Name content_name, std::unique_ptr &&buffer, - bool is_last, uint32_t offset, - uint32_t **last_segment = nullptr) override; - - int setSocketOption(int socket_option_key, - ProducerInterestCallback socket_option_value) override; - - int setSocketOption( - int socket_option_key, - const std::shared_ptr &socket_option_value) override; - - int setSocketOption(int socket_option_key, - uint32_t socket_option_value) override; - - int setSocketOption(int socket_option_key, bool socket_option_value) override; - - int setSocketOption(int socket_option_key, - Name *socket_option_value) override; - - int setSocketOption(int socket_option_key, - std::list socket_option_value) override; - - int setSocketOption( - int socket_option_key, - ProducerContentObjectCallback socket_option_value) override; - - int setSocketOption(int socket_option_key, - ProducerContentCallback socket_option_value) override; - - int setSocketOption(int socket_option_key, - HashAlgorithm socket_option_value) override; - - int setSocketOption(int socket_option_key, - utils::CryptoSuite socket_option_value) override; - - int setSocketOption(int socket_option_key, - const std::string &socket_option_value) override; - - using ProducerSocket::getSocketOption; - using ProducerSocket::onInterest; - - protected: - bool rtc_; - /* Callback invoked once an interest has been received and its payload - * decrypted */ - ProducerInterestCallback on_interest_input_decrypted_; - ProducerInterestCallback on_interest_process_decrypted_; - ProducerContentCallback on_content_produced_application_; - - private: - std::mutex mtx_; - - /* Condition variable for the wait */ - std::condition_variable cv_; - - PARCBuffer *der_cert_; - PARCBuffer *der_prk_; - X509 *cert_509_; - EVP_PKEY *pkey_rsa_; - std::unordered_map, - core::hash, core::compare2> - map_secure_producers; - std::unordered_map, - core::hash, core::compare2> - map_secure_rtc_producers; - std::list> list_secure_producers; - std::list> list_secure_rtc_producers; - - void onInterestCallback(ProducerSocket &p, Interest &interest); -}; - -} // namespace interface - -} // namespace transport diff --git a/libtransport/src/hicn/transport/interfaces/publication_options.h b/libtransport/src/hicn/transport/interfaces/publication_options.h deleted file mode 100644 index 6910e5371..000000000 --- a/libtransport/src/hicn/transport/interfaces/publication_options.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -namespace transport { - -namespace interface { - -class PublicationOptions { - public: - template - PublicationOptions(T&& name, uint32_t lifetime) - : name_(std::forward(name)), - content_lifetime_milliseconds_(lifetime) {} - - TRANSPORT_ALWAYS_INLINE const core::Name& getName() const { return name_; } - TRANSPORT_ALWAYS_INLINE uint32_t getLifetime() const { - return content_lifetime_milliseconds_; - } - - private: - core::Name name_; - uint32_t content_lifetime_milliseconds_; - // TODO Signature -}; -} // namespace interface - -} // namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.cc b/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.cc deleted file mode 100644 index fefa419a9..000000000 --- a/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.cc +++ /dev/null @@ -1,368 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include -#include - -#define NACK_HEADER_SIZE 8 // bytes -#define TIMESTAMP_LEN 8 // bytes -#define TCP_HEADER_SIZE 20 -#define IP6_HEADER_SIZE 40 -#define INIT_PACKET_PRODUCTION_RATE 100 // pps random value (almost 1Mbps) -#define STATS_INTERVAL_DURATION 500 // ms -#define INTEREST_LIFETIME_REDUCTION_FACTOR 0.8 -#define INACTIVE_TIME \ - 500 // ms without producing before the socket - // is considered inactive -#define MILLI_IN_A_SEC 1000 // ms in a second - -#define HICN_MAX_DATA_SEQ 0xefffffff - -// slow production rate param -#define MIN_PRODUCTION_RATE \ - 10 // in pacekts per sec. this value is computed - // through experiments -#define LIFETIME_FRACTION 0.5 - -// NACK HEADER -// +-----------------------------------------+ -// | 4 bytes: current segment in production | -// +-----------------------------------------+ -// | 4 bytes: production rate (bytes x sec) | -// +-----------------------------------------+ -// - -// PACKET HEADER -// +-----------------------------------------+ -// | 8 bytes: TIMESTAMP | -// +-----------------------------------------+ -// | packet | -// +-----------------------------------------+ - -namespace transport { - -namespace interface { - -RTCProducerSocket::RTCProducerSocket(asio::io_service &io_service) - : ProducerSocket(io_service), - currentSeg_(1), - producedBytes_(0), - producedPackets_(0), - bytesProductionRate_(INIT_PACKET_PRODUCTION_RATE * 1400), - packetsProductionRate_(INIT_PACKET_PRODUCTION_RATE), - perSecondFactor_(MILLI_IN_A_SEC / STATS_INTERVAL_DURATION), - timer_on_(false) { - srand((unsigned int)time(NULL)); - prodLabel_ = ((rand() % 255) << 24UL); - interests_cache_timer_ = - std::make_unique(this->getIoService()); - round_timer_ = std::make_unique(this->getIoService()); - setSocketOption(GeneralTransportOptions::OUTPUT_BUFFER_SIZE, 10000U); - scheduleRoundTimer(); -} - -RTCProducerSocket::RTCProducerSocket() - : ProducerSocket(), - currentSeg_(1), - producedBytes_(0), - producedPackets_(0), - bytesProductionRate_(INIT_PACKET_PRODUCTION_RATE * 1400), - packetsProductionRate_(INIT_PACKET_PRODUCTION_RATE), - perSecondFactor_(MILLI_IN_A_SEC / STATS_INTERVAL_DURATION), - timer_on_(false) { - srand((unsigned int)time(NULL)); - prodLabel_ = ((rand() % 255) << 24UL); - interests_cache_timer_ = - std::make_unique(this->getIoService()); - round_timer_ = std::make_unique(this->getIoService()); - setSocketOption(GeneralTransportOptions::OUTPUT_BUFFER_SIZE, 10000U); - scheduleRoundTimer(); -} - -RTCProducerSocket::~RTCProducerSocket() {} - -void RTCProducerSocket::registerPrefix(const Prefix &producer_namespace) { - ProducerSocket::registerPrefix(producer_namespace); - - flowName_ = producer_namespace.getName(); - 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."); - } -} - -void RTCProducerSocket::scheduleRoundTimer() { - round_timer_->expires_from_now( - std::chrono::milliseconds(STATS_INTERVAL_DURATION)); - round_timer_->async_wait([this](std::error_code ec) { - if (ec) return; - updateStats(); - }); -} - -void RTCProducerSocket::updateStats() { - bytesProductionRate_ = producedBytes_.load() * perSecondFactor_; - packetsProductionRate_ = producedPackets_.load() * perSecondFactor_; - if (packetsProductionRate_.load() == 0) packetsProductionRate_ = 1; - producedBytes_ = 0; - producedPackets_ = 0; - scheduleRoundTimer(); -} - -void RTCProducerSocket::produce(std::unique_ptr &&buffer) { - auto buffer_size = buffer->length(); - - if (TRANSPORT_EXPECT_FALSE(buffer_size == 0)) { - return; - } - - if (TRANSPORT_EXPECT_FALSE((buffer_size + headerSize_ + TIMESTAMP_LEN) > - data_packet_size_)) { - return; - } - - uint64_t now = std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()) - .count(); - - producedBytes_ += (uint32_t)(buffer_size + headerSize_ + TIMESTAMP_LEN); - producedPackets_++; - - Name n(flowName_); - auto content_object = - std::make_shared(n.setSuffix(currentSeg_.load())); - auto payload = utils::MemBuf::create(TIMESTAMP_LEN); - - memcpy(payload->writableData(), &now, TIMESTAMP_LEN); - payload->append(TIMESTAMP_LEN); - payload->prependChain(std::move(buffer)); - content_object->appendPayload(std::move(payload)); - - content_object->setLifetime(500); // XXX this should be set by the APP - - content_object->setPathLabel(prodLabel_); - - output_buffer_.insert(std::static_pointer_cast( - content_object->shared_from_this())); - - if (on_content_object_in_output_buffer_) { - on_content_object_in_output_buffer_(*this, *content_object); - } - - TRANSPORT_LOGD("Send content %u (produce)", content_object->getName().getSuffix()); - portal_->sendContentObject(*content_object); - - if (on_content_object_output_) { - on_content_object_output_(*this, *content_object); - } - - uint32_t old_curr = currentSeg_.load(); - currentSeg_ = (currentSeg_.load() + 1) % HICN_MAX_DATA_SEQ; - - // remove interests from the interest cache if it exists - // this generates nacks that will tell to the consumer - // that a new data packet was produced - utils::SpinLock::Acquire locked(interests_cache_lock_); - if (!seqs_map_.empty()) { - for (auto it = seqs_map_.begin(); it != seqs_map_.end(); it++) { - if (it->first != old_curr) sendNack(it->first); - } - seqs_map_.clear(); - timers_map_.clear(); - } -} - -void RTCProducerSocket::onInterest(Interest::Ptr &&interest) { - uint32_t interestSeg = interest->getName().getSuffix(); - uint32_t lifetime = interest->getLifetime(); - - if (on_interest_input_) { - on_interest_input_(*this, *interest); - } - - uint64_t now = std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()) - .count(); - - if (interestSeg > HICN_MAX_DATA_SEQ) { - sendNack(interestSeg); - return; - } - - const std::shared_ptr content_object = - output_buffer_.find(*interest); - - if (content_object) { - if (on_interest_satisfied_output_buffer_) { - on_interest_satisfied_output_buffer_(*this, *interest); - } - - if (on_content_object_output_) { - on_content_object_output_(*this, *content_object); - } - - TRANSPORT_LOGD("Send content %u (onInterest)", content_object->getName().getSuffix()); - portal_->sendContentObject(*content_object); - return; - } else { - if (on_interest_process_) { - on_interest_process_(*this, *interest); - } - } - - // if the production rate is less than MIN_PRODUCTION_RATE we put the - // interest in a queue, otherwise we handle it in the usual way - if (packetsProductionRate_.load() < MIN_PRODUCTION_RATE && - interestSeg >= currentSeg_.load()) { - utils::SpinLock::Acquire locked(interests_cache_lock_); - - uint64_t next_timer = ~0; - if (!timers_map_.empty()) { - next_timer = timers_map_.begin()->first; - } - - uint64_t expiration = now + (lifetime * LIFETIME_FRACTION); - // check if the seq number exists already - auto it_seqs = seqs_map_.find(interestSeg); - if (it_seqs != seqs_map_.end()) { - // the seq already exists - if (expiration < it_seqs->second) { - // we need to update the timer becasue we got a smaller one - // 1) remove the entry from the multimap - // 2) update this entry - auto range = timers_map_.equal_range(it_seqs->second); - for (auto it_timers = range.first; it_timers != range.second; - it_timers++) { - if (it_timers->second == it_seqs->first) { - timers_map_.erase(it_timers); - break; - } - } - timers_map_.insert( - std::pair(expiration, interestSeg)); - it_seqs->second = expiration; - } else { - // nothing to do here - return; - } - } else { - // add the new seq - timers_map_.insert( - std::pair(expiration, interestSeg)); - seqs_map_.insert(std::pair(interestSeg, expiration)); - } - - // here we have at least one interest in the queue, we need to start or - // update the timer - if (!timer_on_) { - // set timeout - timer_on_ = true; - scheduleCacheTimer(timers_map_.begin()->first - now); - } else { - // re-schedule the timer because a new interest will expires sooner - if (next_timer > timers_map_.begin()->first) { - interests_cache_timer_->cancel(); - scheduleCacheTimer(timers_map_.begin()->first - now); - } - } - return; - } - - uint32_t max_gap = (uint32_t)floor( - (double)((double)((double)lifetime * INTEREST_LIFETIME_REDUCTION_FACTOR / - 1000.0) * - (double)packetsProductionRate_.load())); - - if (interestSeg < currentSeg_.load() || - interestSeg > (max_gap + currentSeg_.load())) { - sendNack(interestSeg); - } - // else drop packet -} - -void RTCProducerSocket::scheduleCacheTimer(uint64_t wait) { - interests_cache_timer_->expires_from_now(std::chrono::milliseconds(wait)); - interests_cache_timer_->async_wait([this](std::error_code ec) { - if (ec) return; - interestCacheTimer(); - }); -} - -void RTCProducerSocket::interestCacheTimer() { - uint64_t now = std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()) - .count(); - - utils::SpinLock::Acquire locked(interests_cache_lock_); - - for (auto it_timers = timers_map_.begin(); it_timers != timers_map_.end();) { - uint64_t expire = it_timers->first; - if (expire <= now) { - uint32_t seq = it_timers->second; - sendNack(seq); - // remove the interest from the other map - seqs_map_.erase(seq); - it_timers = timers_map_.erase(it_timers); - } else { - // stop, we are done! - break; - } - } - if (timers_map_.empty()) { - timer_on_ = false; - } else { - timer_on_ = true; - scheduleCacheTimer(timers_map_.begin()->first - now); - } -} - -void RTCProducerSocket::sendNack(uint32_t sequence) { - auto nack_payload = utils::MemBuf::create(NACK_HEADER_SIZE); - nack_payload->append(NACK_HEADER_SIZE); - ContentObject nack; - - Name n(flowName_); - nack.appendPayload(std::move(nack_payload)); - nack.setName(n.setSuffix(sequence)); - - uint32_t *payload_ptr = (uint32_t *)nack.getPayload()->data(); - *payload_ptr = currentSeg_.load(); - - *(++payload_ptr) = bytesProductionRate_.load(); - - nack.setLifetime(0); - nack.setPathLabel(prodLabel_); - - if (on_content_object_output_) { - on_content_object_output_(*this, nack); - } - - TRANSPORT_LOGD("Send nack %u", sequence); - portal_->sendContentObject(nack); -} - -} // namespace interface - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.h b/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.h deleted file mode 100644 index d7917a8c0..000000000 --- a/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include - -#include -#include -#include - -namespace transport { - -namespace interface { - -class RTCProducerSocket : virtual public ProducerSocket { - public: - RTCProducerSocket(asio::io_service &io_service); - - RTCProducerSocket(); - - ~RTCProducerSocket(); - - void registerPrefix(const Prefix &producer_namespace) override; - - virtual void produce(std::unique_ptr &&buffer) override; - - void onInterest(Interest::Ptr &&interest) override; - - private: - void sendNack(uint32_t sequence); - void updateStats(); - void scheduleCacheTimer(uint64_t wait); - void scheduleRoundTimer(); - void interestCacheTimer(); - - std::atomic currentSeg_; - uint32_t prodLabel_; - uint16_t headerSize_; - Name flowName_; - std::atomic producedBytes_; - std::atomic producedPackets_; - std::atomic bytesProductionRate_; - std::atomic packetsProductionRate_; - uint32_t perSecondFactor_; - - std::unique_ptr round_timer_; - - // cache for the received interests - // this map maps the expiration time of an interest to - // its sequence number. the map is sorted by timeouts - // the same timeout may be used for multiple sequence numbers - // but for each sequence number we store only the smallest - // expiry time. In this way the mapping from seqs_map_ to - // timers_map_ is unique - std::multimap timers_map_; - // this map does the opposite, this map is not ordered - std::unordered_map seqs_map_; - bool timer_on_; - std::unique_ptr interests_cache_timer_; - utils::SpinLock interests_cache_lock_; -}; - -} // namespace interface - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/interfaces/socket.h b/libtransport/src/hicn/transport/interfaces/socket.h deleted file mode 100644 index 4c9bda7df..000000000 --- a/libtransport/src/hicn/transport/interfaces/socket.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include -#include -#include - -#define SOCKET_OPTION_GET 0 -#define SOCKET_OPTION_NOT_GET 1 -#define SOCKET_OPTION_SET 2 -#define SOCKET_OPTION_NOT_SET 3 -#define SOCKET_OPTION_DEFAULT 12345 - -namespace transport { - -namespace interface { - -// Forward Declarations -template -class Socket; - -// Define the portal and its connector, depending on the compilation options -// passed by the build tool. -using HicnForwarderPortal = core::HicnForwarderPortal; - -#ifdef __linux__ -#ifndef __ANDROID__ -using RawSocketPortal = core::RawSocketPortal; -#endif -#endif - -#ifdef __vpp__ -using VPPForwarderPortal = core::VPPForwarderPortal; -using BaseSocket = Socket; -using BasePortal = VPPForwarderPortal; -#else -using BaseSocket = Socket; -using BasePortal = HicnForwarderPortal; -#endif - -template -class Socket { - static_assert(std::is_same::value -#ifdef __linux__ -#ifndef __ANDROID__ - || std::is_same::value -#ifdef __vpp__ - || std::is_same::value -#endif -#endif - , -#else - , - -#endif - "This class is not allowed as Portal"); - - public: - using Portal = PortalType; - - virtual asio::io_service &getIoService() = 0; - - virtual void connect() = 0; - - virtual bool isRunning() = 0; - - protected: - virtual ~Socket(){}; - - protected: - std::string output_interface_; -}; - -} // namespace interface - -} // namespace transport diff --git a/libtransport/src/hicn/transport/interfaces/socket_consumer.cc b/libtransport/src/hicn/transport/interfaces/socket_consumer.cc deleted file mode 100644 index b2c054947..000000000 --- a/libtransport/src/hicn/transport/interfaces/socket_consumer.cc +++ /dev/null @@ -1,862 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include -#include - -namespace transport { - -namespace interface { - -ConsumerSocket::ConsumerSocket(int protocol) - : ConsumerSocket(protocol, internal_io_service_) {} - -ConsumerSocket::ConsumerSocket(int protocol, asio::io_service &io_service) - : io_service_(io_service), - portal_(std::make_shared(io_service_)), - async_downloader_(), - interest_lifetime_(default_values::interest_lifetime), - min_window_size_(default_values::min_window_size), - max_window_size_(default_values::max_window_size), - current_window_size_(-1), - max_retransmissions_( - default_values::transport_protocol_max_retransmissions), - /****** RAAQM Parameters ******/ - minimum_drop_probability_(default_values::minimum_drop_probability), - sample_number_(default_values::sample_number), - gamma_(default_values::gamma_value), - beta_(default_values::beta_value), - drop_factor_(default_values::drop_factor), - /****** END RAAQM Parameters ******/ - rate_estimation_alpha_(default_values::rate_alpha), - rate_estimation_observer_(nullptr), - rate_estimation_batching_parameter_(default_values::batch), - rate_estimation_choice_(0), - verifier_(std::make_shared()), - verify_signature_(false), - key_content_(false), - on_interest_output_(VOID_HANDLER), - on_interest_timeout_(VOID_HANDLER), - on_interest_satisfied_(VOID_HANDLER), - on_content_object_input_(VOID_HANDLER), - on_content_object_verification_(VOID_HANDLER), - on_content_object_(VOID_HANDLER), - on_manifest_(VOID_HANDLER), - stats_summary_(VOID_HANDLER), - read_callback_(nullptr), - virtual_download_(false), - timer_interval_milliseconds_(0), - guard_raaqm_params_() { - switch (protocol) { - case TransportProtocolAlgorithms::CBR: - transport_protocol_ = std::make_unique(this); - break; - case TransportProtocolAlgorithms::RTC: - transport_protocol_ = std::make_unique(this); - break; - case TransportProtocolAlgorithms::RAAQM: - default: - transport_protocol_ = std::make_unique(this); - break; - } -} - -ConsumerSocket::~ConsumerSocket() { - stop(); - async_downloader_.stop(); -} - -void ConsumerSocket::connect() { portal_->connect(); } - -int ConsumerSocket::consume(const Name &name) { - if (transport_protocol_->isRunning()) { - return CONSUMER_BUSY; - } - - network_name_ = name; - network_name_.setSuffix(0); - - transport_protocol_->start(); - - return CONSUMER_FINISHED; -} - -int ConsumerSocket::asyncConsume(const Name &name) { - if (!async_downloader_.stopped()) { - async_downloader_.add([this, name]() { - network_name_ = std::move(name); - network_name_.setSuffix(0); - transport_protocol_->start(); - }); - } - - return CONSUMER_RUNNING; -} - -bool ConsumerSocket::verifyKeyPackets() { - return transport_protocol_->verifyKeyPackets(); -} - -void ConsumerSocket::stop() { - if (transport_protocol_) { - if (transport_protocol_->isRunning()) transport_protocol_->stop(); - } -} - -void ConsumerSocket::resume() { - if (!transport_protocol_->isRunning()) { - transport_protocol_->resume(); - } -} - -asio::io_service &ConsumerSocket::getIoService() { - return portal_->getIoService(); -} - -int ConsumerSocket::setSocketOption(int socket_option_key, - ReadCallback *socket_option_value) { - // Reschedule the function on the io_service to avoid race condition in case - // setSocketOption is called while the io_service is running. - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, ReadCallback *socket_option_value) -> int { - switch (socket_option_key) { - case ConsumerCallbacksOptions::READ_CALLBACK: - read_callback_ = socket_option_value; - break; - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; - }); -} - -int ConsumerSocket::getSocketOption(int socket_option_key, - ReadCallback **socket_option_value) { - // Reschedule the function on the io_service to avoid race condition in case - // setSocketOption is called while the io_service is running. - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, ReadCallback **socket_option_value) -> int { - switch (socket_option_key) { - case ConsumerCallbacksOptions::READ_CALLBACK: - *socket_option_value = read_callback_; - break; - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; - }); -} - -int ConsumerSocket::setSocketOption(int socket_option_key, - double socket_option_value) { - utils::SpinLock::Acquire locked(guard_raaqm_params_); - switch (socket_option_key) { - case MIN_WINDOW_SIZE: - min_window_size_ = socket_option_value; - break; - - case MAX_WINDOW_SIZE: - max_window_size_ = socket_option_value; - break; - - case CURRENT_WINDOW_SIZE: - current_window_size_ = socket_option_value; - break; - - case GAMMA_VALUE: - gamma_ = socket_option_value; - break; - - case BETA_VALUE: - beta_ = socket_option_value; - break; - - case DROP_FACTOR: - drop_factor_ = socket_option_value; - break; - - case MINIMUM_DROP_PROBABILITY: - minimum_drop_probability_ = socket_option_value; - break; - - case RATE_ESTIMATION_ALPHA: - if (socket_option_value >= 0 && socket_option_value < 1) { - rate_estimation_alpha_ = socket_option_value; - } else { - rate_estimation_alpha_ = default_values::alpha; - } - break; - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; -} - -int ConsumerSocket::setSocketOption(int socket_option_key, - uint32_t socket_option_value) { - utils::SpinLock::Acquire locked(guard_raaqm_params_); - switch (socket_option_key) { - case GeneralTransportOptions::MAX_INTEREST_RETX: - max_retransmissions_ = socket_option_value; - break; - - case GeneralTransportOptions::INTEREST_LIFETIME: - interest_lifetime_ = socket_option_value; - break; - - case RateEstimationOptions::RATE_ESTIMATION_BATCH_PARAMETER: - if (socket_option_value > 0) { - rate_estimation_batching_parameter_ = socket_option_value; - } else { - rate_estimation_batching_parameter_ = default_values::batch; - } - break; - - case RateEstimationOptions::RATE_ESTIMATION_CHOICE: - if (socket_option_value > 0) { - rate_estimation_choice_ = socket_option_value; - } else { - rate_estimation_choice_ = default_values::rate_choice; - } - break; - - case GeneralTransportOptions::STATS_INTERVAL: - timer_interval_milliseconds_ = socket_option_value; - break; - - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; -} - -int ConsumerSocket::setSocketOption(int socket_option_key, - std::nullptr_t socket_option_value) { - // Reschedule the function on the io_service to avoid race condition in case - // setSocketOption is called while the io_service is running. - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, std::nullptr_t socket_option_value) -> int { - switch (socket_option_key) { - case ConsumerCallbacksOptions::INTEREST_RETRANSMISSION: - if (socket_option_value == VOID_HANDLER) { - on_interest_retransmission_ = VOID_HANDLER; - break; - } - - case ConsumerCallbacksOptions::INTEREST_EXPIRED: - if (socket_option_value == VOID_HANDLER) { - on_interest_timeout_ = VOID_HANDLER; - break; - } - - case ConsumerCallbacksOptions::INTEREST_SATISFIED: - if (socket_option_value == VOID_HANDLER) { - on_interest_satisfied_ = VOID_HANDLER; - break; - } - - case ConsumerCallbacksOptions::INTEREST_OUTPUT: - if (socket_option_value == VOID_HANDLER) { - on_interest_output_ = VOID_HANDLER; - break; - } - - case ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT: - if (socket_option_value == VOID_HANDLER) { - on_content_object_input_ = VOID_HANDLER; - break; - } - - case ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY: - if (socket_option_value == VOID_HANDLER) { - on_content_object_verification_ = VOID_HANDLER; - break; - } - - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; - }); -} - -int ConsumerSocket::setSocketOption(int socket_option_key, - bool socket_option_value) { - int result = SOCKET_OPTION_NOT_SET; - if (!transport_protocol_->isRunning()) { - switch (socket_option_key) { - case OtherOptions::VIRTUAL_DOWNLOAD: - virtual_download_ = socket_option_value; - result = SOCKET_OPTION_SET; - break; - - case GeneralTransportOptions::VERIFY_SIGNATURE: - verify_signature_ = socket_option_value; - result = SOCKET_OPTION_SET; - break; - - case GeneralTransportOptions::KEY_CONTENT: - key_content_ = socket_option_value; - result = SOCKET_OPTION_SET; - break; - - default: - return result; - } - } - return result; -} - -int ConsumerSocket::setSocketOption( - int socket_option_key, ConsumerContentObjectCallback socket_option_value) { - // Reschedule the function on the io_service to avoid race condition in case - // setSocketOption is called while the io_service is running. - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ConsumerContentObjectCallback socket_option_value) -> int { - switch (socket_option_key) { - case ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT: - on_content_object_input_ = socket_option_value; - break; - - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; - }); -} - -int ConsumerSocket::setSocketOption( - int socket_option_key, - ConsumerContentObjectVerificationCallback socket_option_value) { - // Reschedule the function on the io_service to avoid race condition in case - // setSocketOption is called while the io_service is running. - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ConsumerContentObjectVerificationCallback socket_option_value) - -> int { - switch (socket_option_key) { - case ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY: - on_content_object_verification_ = socket_option_value; - break; - - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; - }); -} - -int ConsumerSocket::setSocketOption( - int socket_option_key, ConsumerInterestCallback socket_option_value) { - // Reschedule the function on the io_service to avoid race condition in case - // setSocketOption is called while the io_service is running. - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ConsumerInterestCallback socket_option_value) -> int { - switch (socket_option_key) { - case ConsumerCallbacksOptions::INTEREST_RETRANSMISSION: - on_interest_retransmission_ = socket_option_value; - break; - - case ConsumerCallbacksOptions::INTEREST_OUTPUT: - on_interest_output_ = socket_option_value; - break; - - case ConsumerCallbacksOptions::INTEREST_EXPIRED: - on_interest_timeout_ = socket_option_value; - break; - - case ConsumerCallbacksOptions::INTEREST_SATISFIED: - on_interest_satisfied_ = socket_option_value; - break; - - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; - }); -} - -int ConsumerSocket::setSocketOption( - int socket_option_key, ConsumerManifestCallback socket_option_value) { - // Reschedule the function on the io_service to avoid race condition in case - // setSocketOption is called while the io_service is running. - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ConsumerManifestCallback socket_option_value) -> int { - switch (socket_option_key) { - case ConsumerCallbacksOptions::MANIFEST_INPUT: - on_manifest_ = socket_option_value; - break; - - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; - }); -} - -int ConsumerSocket::setSocketOption( - int socket_option_key, - ConsumerContentObjectVerificationFailedCallback socket_option_value) { - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this]( - int socket_option_key, - ConsumerContentObjectVerificationFailedCallback socket_option_value) - -> int { - switch (socket_option_key) { - case ConsumerCallbacksOptions::VERIFICATION_FAILED: - verification_failed_callback_ = socket_option_value; - break; - - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; - }); -} - -int ConsumerSocket::setSocketOption(int socket_option_key, - IcnObserver *socket_option_value) { - utils::SpinLock::Acquire locked(guard_raaqm_params_); - switch (socket_option_key) { - case RateEstimationOptions::RATE_ESTIMATION_OBSERVER: - rate_estimation_observer_ = socket_option_value; - break; - - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; -} - -int ConsumerSocket::setSocketOption( - int socket_option_key, - const std::shared_ptr &socket_option_value) { - int result = SOCKET_OPTION_NOT_SET; - if (!transport_protocol_->isRunning()) { - switch (socket_option_key) { - case GeneralTransportOptions::VERIFIER: - verifier_.reset(); - verifier_ = socket_option_value; - result = SOCKET_OPTION_SET; - break; - default: - return result; - } - } - - return result; -} - -int ConsumerSocket::setSocketOption(int socket_option_key, - const std::string &socket_option_value) { - int result = SOCKET_OPTION_NOT_SET; - if (!transport_protocol_->isRunning()) { - switch (socket_option_key) { - case GeneralTransportOptions::CERTIFICATE: - key_id_ = verifier_->addKeyFromCertificate(socket_option_value); - if (key_id_ != nullptr) result = SOCKET_OPTION_SET; - break; - - case DataLinkOptions::OUTPUT_INTERFACE: - output_interface_ = socket_option_value; - portal_->setOutputInterface(output_interface_); - result = SOCKET_OPTION_SET; - break; - - default: - return result; - } - } - return result; -} - -int ConsumerSocket::setSocketOption(int socket_option_key, - ConsumerTimerCallback socket_option_value) { - // Reschedule the function on the io_service to avoid race condition in case - // setSocketOption is called while the io_service is running. - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ConsumerTimerCallback socket_option_value) -> int { - switch (socket_option_key) { - case ConsumerCallbacksOptions::STATS_SUMMARY: - stats_summary_ = socket_option_value; - break; - - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; - }); -} - -int ConsumerSocket::getSocketOption(int socket_option_key, - double &socket_option_value) { - utils::SpinLock::Acquire locked(guard_raaqm_params_); - switch (socket_option_key) { - case GeneralTransportOptions::MIN_WINDOW_SIZE: - socket_option_value = min_window_size_; - break; - - case GeneralTransportOptions::MAX_WINDOW_SIZE: - socket_option_value = max_window_size_; - break; - - case GeneralTransportOptions::CURRENT_WINDOW_SIZE: - socket_option_value = current_window_size_; - break; - - // RAAQM parameters - - case RaaqmTransportOptions::GAMMA_VALUE: - socket_option_value = gamma_; - break; - - case RaaqmTransportOptions::BETA_VALUE: - socket_option_value = beta_; - break; - - case RaaqmTransportOptions::DROP_FACTOR: - socket_option_value = drop_factor_; - break; - - case RaaqmTransportOptions::MINIMUM_DROP_PROBABILITY: - socket_option_value = minimum_drop_probability_; - break; - - case RateEstimationOptions::RATE_ESTIMATION_ALPHA: - socket_option_value = rate_estimation_alpha_; - break; - - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; -} - -int ConsumerSocket::getSocketOption(int socket_option_key, - uint32_t &socket_option_value) { - utils::SpinLock::Acquire locked(guard_raaqm_params_); - switch (socket_option_key) { - case GeneralTransportOptions::MAX_INTEREST_RETX: - socket_option_value = max_retransmissions_; - break; - - case GeneralTransportOptions::INTEREST_LIFETIME: - socket_option_value = interest_lifetime_; - break; - - case RaaqmTransportOptions::SAMPLE_NUMBER: - socket_option_value = sample_number_; - break; - - case RateEstimationOptions::RATE_ESTIMATION_BATCH_PARAMETER: - socket_option_value = rate_estimation_batching_parameter_; - break; - - case RateEstimationOptions::RATE_ESTIMATION_CHOICE: - socket_option_value = rate_estimation_choice_; - break; - - case GeneralTransportOptions::STATS_INTERVAL: - socket_option_value = timer_interval_milliseconds_; - break; - - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; -} - -int ConsumerSocket::getSocketOption(int socket_option_key, - bool &socket_option_value) { - switch (socket_option_key) { - case GeneralTransportOptions::RUNNING: - socket_option_value = transport_protocol_->isRunning(); - break; - - case OtherOptions::VIRTUAL_DOWNLOAD: - socket_option_value = virtual_download_; - break; - - case GeneralTransportOptions::VERIFY_SIGNATURE: - socket_option_value = verify_signature_; - break; - - case GeneralTransportOptions::KEY_CONTENT: - socket_option_value = key_content_; - break; - - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; -} - -int ConsumerSocket::getSocketOption(int socket_option_key, - Name **socket_option_value) { - switch (socket_option_key) { - case GeneralTransportOptions::NETWORK_NAME: - *socket_option_value = &network_name_; - break; - - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; -} - -int ConsumerSocket::getSocketOption( - int socket_option_key, - ConsumerContentObjectCallback **socket_option_value) { - // Reschedule the function on the io_service to avoid race condition in case - // setSocketOption is called while the io_service is running. - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ConsumerContentObjectCallback **socket_option_value) -> int { - switch (socket_option_key) { - case ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT: - *socket_option_value = &on_content_object_input_; - break; - - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; - }); -} - -int ConsumerSocket::getSocketOption( - int socket_option_key, - ConsumerContentObjectVerificationCallback **socket_option_value) { - // Reschedule the function on the io_service to avoid race condition in case - // setSocketOption is called while the io_service is running. - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ConsumerContentObjectVerificationCallback **socket_option_value) - -> int { - switch (socket_option_key) { - case ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY: - *socket_option_value = &on_content_object_verification_; - break; - - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; - }); -} - -int ConsumerSocket::getSocketOption( - int socket_option_key, ConsumerInterestCallback **socket_option_value) { - // Reschedule the function on the io_service to avoid race condition in case - // setSocketOption is called while the io_service is running. - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ConsumerInterestCallback **socket_option_value) -> int { - switch (socket_option_key) { - case ConsumerCallbacksOptions::INTEREST_RETRANSMISSION: - *socket_option_value = &on_interest_retransmission_; - break; - - case ConsumerCallbacksOptions::INTEREST_OUTPUT: - *socket_option_value = &on_interest_output_; - break; - - case ConsumerCallbacksOptions::INTEREST_EXPIRED: - *socket_option_value = &on_interest_timeout_; - break; - - case ConsumerCallbacksOptions::INTEREST_SATISFIED: - *socket_option_value = &on_interest_satisfied_; - break; - - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; - }); -} - -int ConsumerSocket::getSocketOption( - int socket_option_key, ConsumerManifestCallback **socket_option_value) { - // Reschedule the function on the io_service to avoid race condition in case - // setSocketOption is called while the io_service is running. - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ConsumerManifestCallback **socket_option_value) -> int { - switch (socket_option_key) { - case ConsumerCallbacksOptions::MANIFEST_INPUT: - *socket_option_value = &on_manifest_; - break; - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; - }); -} - -int ConsumerSocket::getSocketOption( - int socket_option_key, - ConsumerContentObjectVerificationFailedCallback **socket_option_value) { - // Reschedule the function on the io_service to avoid race condition in case - // setSocketOption is called while the io_service is running. - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this]( - int socket_option_key, - ConsumerContentObjectVerificationFailedCallback **socket_option_value) - -> int { - switch (socket_option_key) { - case ConsumerCallbacksOptions::VERIFICATION_FAILED: - *socket_option_value = &verification_failed_callback_; - break; - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; - }); -} - -int ConsumerSocket::getSocketOption( - int socket_option_key, std::shared_ptr &socket_option_value) { - switch (socket_option_key) { - case PORTAL: - socket_option_value = portal_; - break; - - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; -} - -int ConsumerSocket::getSocketOption(int socket_option_key, - IcnObserver **socket_option_value) { - utils::SpinLock::Acquire locked(guard_raaqm_params_); - switch (socket_option_key) { - case RateEstimationOptions::RATE_ESTIMATION_OBSERVER: - *socket_option_value = (rate_estimation_observer_); - break; - - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; -} - -int ConsumerSocket::getSocketOption( - int socket_option_key, - std::shared_ptr &socket_option_value) { - switch (socket_option_key) { - case GeneralTransportOptions::VERIFIER: - socket_option_value = verifier_; - break; - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; -} - -int ConsumerSocket::getSocketOption(int socket_option_key, - std::string &socket_option_value) { - switch (socket_option_key) { - case DataLinkOptions::OUTPUT_INTERFACE: - socket_option_value = output_interface_; - break; - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; -} - -int ConsumerSocket::getSocketOption(int socket_option_key, - TransportStatistics **socket_option_value) { - switch (socket_option_key) { - case OtherOptions::STATISTICS: - *socket_option_value = &stats_; - break; - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; -} - -int ConsumerSocket::getSocketOption( - int socket_option_key, ConsumerTimerCallback **socket_option_value) { - // Reschedule the function on the io_service to avoid race condition in case - // setSocketOption is called while the io_service is running. - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ConsumerTimerCallback **socket_option_value) -> int { - switch (socket_option_key) { - case ConsumerCallbacksOptions::STATS_SUMMARY: - *socket_option_value = &stats_summary_; - break; - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; - }); -} - -} // namespace interface - -} // namespace transport diff --git a/libtransport/src/hicn/transport/interfaces/socket_consumer.h b/libtransport/src/hicn/transport/interfaces/socket_consumer.h deleted file mode 100644 index 48a594adf..000000000 --- a/libtransport/src/hicn/transport/interfaces/socket_consumer.h +++ /dev/null @@ -1,412 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -extern "C" { -#include -} - -#define CONSUMER_FINISHED 0 -#define CONSUMER_BUSY 1 -#define CONSUMER_RUNNING 2 - -namespace transport { - -namespace interface { - -using namespace core; -using namespace protocol; - -/** - * @brief Main interface for consumer applications. - * - * The consumer socket is the main interface for a consumer application. - * It allows to retrieve an application data from one/many producers, by - * hiding all the complexity of the transport protocol used underneath. - */ -class ConsumerSocket : public BaseSocket { - public: - /** - * The ReadCallback is a class which can be used by the transport for both - * querying the application needs and notifying events. - * - * Beware that the methods of this class will be called synchronously while - * the transport is working, so the operations the application is performing - * on the data retrieved should be executed in another thread in an - * asynchronous manner. Blocking one of these callbacks means blocking the - * transport. - */ - class ReadCallback { - public: - virtual ~ReadCallback() = default; - - /** - * This API will specify to the transport whether the buffer should be - * allocated by the application (and then the retrieved content will be - * copied there) or the transport should allocate the buffer and "move" it - * to the application. In other words, if isBufferMovable return true, the - * transport will transfer the ownership of the read buffer to the - * application, without performing an additional copy, while if it returns - * false the transport will use the getReadBuffer API. - * - * By default this method returns true. - * - */ - virtual bool isBufferMovable() noexcept { return true; } - - /** - * This method will be called by the transport when the content is - * available. The application can then allocate its own buffer and provide - * the address to the transport, which will use it for writing the data. - * Note that if the application won't allocate enough memory this method - * will be called several times, until the internal read buffer will be - * emptied. For ensuring this method will be called once, applications - * should allocate at least maxBufferSize() bytes. - * - * @param application_buffer - Pointer to the application's buffer. - * @param max_length - The length of the application buffer. - */ - virtual void getReadBuffer(uint8_t **application_buffer, - size_t *max_length) = 0; - - /** - * This method will be called by the transport after calling getReadBuffer, - * in order to notify the application that length bytes are available in the - * buffer. The max_length size of the buffer could be larger than the actual - * amount of bytes written. - * - * @param length - The number of bytes placed in the buffer. - */ - virtual void readDataAvailable(size_t length) noexcept = 0; - - /** - * This method will be called by the transport for understanding how many - * bytes it should read (at most) before notifying the application. - * - * By default it reads 64 KB. - */ - virtual size_t maxBufferSize() const { return 64 * 1024; } - - /** - * This method will be called by the transport iff (isBufferMovable == - * true). The unique_ptr underlines the fact that the ownership of the - * buffer is being transferred to the application. - * - * @param buffer - The buffer - */ - virtual void readBufferAvailable( - std::unique_ptr &&buffer) noexcept {} - - /** - * readError() will be invoked if an error occurs reading from the - * transport. - * - * @param ec - An error code describing the error. - */ - virtual void readError(const std::error_code ec) noexcept = 0; - - /** - * This callback will be invoked when the whole content is retrieved. The - * transport itself knows when a content is retrieved (since it is not an - * opaque bytestream like TCP), and the transport itself is able to tell - * the application when the transfer is done. - */ - virtual void readSuccess(std::size_t total_size) noexcept = 0; - - virtual void afterRead() {} - }; - - /** - * @brief Create a new consumer socket. - * - * @param protocol - The transport protocol to use. So far the following - * transport are supported: - * - CBR: Constant bitrate - * - Raaqm: Based on paper: Optimal multipath congestion control and request - * forwarding in information-centric networks: Protocol design and - * experimentation. G Carofiglio, M Gallo, L Muscariello. Computer Networks - * 110, 104-117 - * - RTC: Real time communication - */ - explicit ConsumerSocket(int protocol); - explicit ConsumerSocket(int protocol, asio::io_service &io_service); - - /** - * @brief Destroy the consumer socket. - */ - ~ConsumerSocket(); - - /** - * @brief Connect the consumer socket to the underlying hICN forwarder. - */ - void connect() override; - - /** - * @brief Check whether consumer socket is active or not. - */ - bool isRunning() override { return transport_protocol_->isRunning(); } - - /** - * Retrieve a content using the protocol specified in the constructor. - * This function blocks until the whole content is downloaded. - * For monitoring the status of the download, the application MUST set the - * ConsumerRead callback. This callback will be called periodically (depending - * on the needs of the application), allowing the application to save the - * retrieved data. - * - * @param name - The name of the content to retrieve. - * - * @return CONSUMER_BUSY if a pending download exists - * @return CONSUMER_FINISHED when the download finishes - * - * Notice that the fact consume() returns CONSUMER_FINISHED does not imply the - * content retrieval succeeded. This information can be obtained from the - * error code in CONTENT_RETRIEVED callback. - */ - virtual int consume(const Name &name); - virtual int asyncConsume(const Name &name); - - /** - * Verify the packets containing a key after the origin of the key has been - * validated by the client. - * - * @return true if all packets are valid, false otherwise - */ - virtual bool verifyKeyPackets(); - - /** - * Stops the consumer socket. If several downloads are queued (using - * asyncConsume), this call stops just the current one. - */ - void stop(); - - /** - * Resume the download from the same exact point it stopped. - */ - void resume(); - - /** - * Get the io_service which is running the transport protocol event loop. - * - * @return A reference to the internal io_service where the transport protocol - * is running. - */ - asio::io_service &getIoService() override; - - virtual int setSocketOption(int socket_option_key, - ReadCallback *socket_option_value); - - virtual int getSocketOption(int socket_option_key, - ReadCallback **socket_option_value); - - virtual int setSocketOption(int socket_option_key, - double socket_option_value); - - virtual int setSocketOption(int socket_option_key, - uint32_t socket_option_value); - - virtual int setSocketOption(int socket_option_key, - std::nullptr_t socket_option_value); - - virtual int setSocketOption(int socket_option_key, bool socket_option_value); - - virtual int setSocketOption( - int socket_option_key, ConsumerContentObjectCallback socket_option_value); - - virtual int setSocketOption( - int socket_option_key, - ConsumerContentObjectVerificationFailedCallback socket_option_value); - - virtual int setSocketOption( - int socket_option_key, - ConsumerContentObjectVerificationCallback socket_option_value); - - virtual int setSocketOption(int socket_option_key, - ConsumerInterestCallback socket_option_value); - - virtual int setSocketOption(int socket_option_key, - ConsumerManifestCallback socket_option_value); - - virtual int setSocketOption(int socket_option_key, - IcnObserver *socket_option_value); - - virtual int setSocketOption( - int socket_option_key, - const std::shared_ptr &socket_option_value); - - virtual int setSocketOption(int socket_option_key, - const std::string &socket_option_value); - - virtual int setSocketOption(int socket_option_key, - ConsumerTimerCallback socket_option_value); - - virtual int getSocketOption(int socket_option_key, - double &socket_option_value); - - virtual int getSocketOption(int socket_option_key, - uint32_t &socket_option_value); - - virtual int getSocketOption(int socket_option_key, bool &socket_option_value); - - virtual int getSocketOption(int socket_option_key, - Name **socket_option_value); - - virtual int getSocketOption( - int socket_option_key, - ConsumerContentObjectCallback **socket_option_value); - - virtual int getSocketOption( - int socket_option_key, - ConsumerContentObjectVerificationFailedCallback **socket_option_value); - - virtual int getSocketOption( - int socket_option_key, - ConsumerContentObjectVerificationCallback **socket_option_value); - - virtual int getSocketOption(int socket_option_key, - ConsumerInterestCallback **socket_option_value); - - virtual int getSocketOption(int socket_option_key, - ConsumerManifestCallback **socket_option_value); - - virtual int getSocketOption(int socket_option_key, - std::shared_ptr &socket_option_value); - - virtual int getSocketOption(int socket_option_key, - IcnObserver **socket_option_value); - - virtual int getSocketOption( - int socket_option_key, - std::shared_ptr &socket_option_value); - - virtual int getSocketOption(int socket_option_key, - std::string &socket_option_value); - - virtual int getSocketOption(int socket_option_key, - ConsumerTimerCallback **socket_option_value); - - virtual int getSocketOption(int socket_option_key, - TransportStatistics **socket_option_value); - - protected: - // If the thread calling lambda_func is not the same of io_service, this - // function reschedule the function on it - template - int rescheduleOnIOService(int socket_option_key, arg2 socket_option_value, - Lambda lambda_func) { - // To enforce type check - std::function func = lambda_func; - int result = SOCKET_OPTION_SET; - if (transport_protocol_->isRunning()) { - std::mutex mtx; - /* Condition variable for the wait */ - std::condition_variable cv; - bool done = false; - io_service_.dispatch([&socket_option_key, &socket_option_value, &mtx, &cv, - &result, &done, &func]() { - std::unique_lock lck(mtx); - done = true; - result = func(socket_option_key, socket_option_value); - cv.notify_all(); - }); - std::unique_lock lck(mtx); - if (!done) { - cv.wait(lck); - } - } else { - result = func(socket_option_key, socket_option_value); - } - - return result; - } - - // context inner state variables - asio::io_service internal_io_service_; - asio::io_service &io_service_; - - std::shared_ptr portal_; - - utils::EventThread async_downloader_; - - Name network_name_; - - int interest_lifetime_; - - double min_window_size_; - double max_window_size_; - double current_window_size_; - uint32_t max_retransmissions_; - - // RAAQM Parameters - double minimum_drop_probability_; - unsigned int sample_number_; - double gamma_; - double beta_; - double drop_factor_; - - // Rate estimation parameters - double rate_estimation_alpha_; - IcnObserver *rate_estimation_observer_; - int rate_estimation_batching_parameter_; - int rate_estimation_choice_; - - bool is_async_; - - // Verification parameters - std::shared_ptr verifier_; - PARCKeyId *key_id_; - std::atomic_bool verify_signature_; - std::atomic_bool key_content_; - - ConsumerInterestCallback on_interest_retransmission_; - ConsumerInterestCallback on_interest_output_; - ConsumerInterestCallback on_interest_timeout_; - ConsumerInterestCallback on_interest_satisfied_; - - ConsumerContentObjectCallback on_content_object_input_; - ConsumerContentObjectVerificationCallback on_content_object_verification_; - - ConsumerContentObjectCallback on_content_object_; - ConsumerManifestCallback on_manifest_; - ConsumerTimerCallback stats_summary_; - ConsumerContentObjectVerificationFailedCallback verification_failed_callback_; - - ReadCallback *read_callback_; - - // Virtual download for traffic generator - bool virtual_download_; - - uint32_t timer_interval_milliseconds_; - - // Transport protocol - std::unique_ptr transport_protocol_; - - // Statistic - TransportStatistics stats_; - - utils::SpinLock guard_raaqm_params_; -}; - -} // namespace interface - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/interfaces/socket_options_default_values.h b/libtransport/src/hicn/transport/interfaces/socket_options_default_values.h deleted file mode 100644 index bcf103b8c..000000000 --- a/libtransport/src/hicn/transport/interfaces/socket_options_default_values.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include - -namespace transport { - -namespace interface { - -namespace default_values { - -static constexpr uint32_t interest_lifetime = 1001; // milliseconds -static constexpr uint32_t never_expire_time = HICN_MAX_LIFETIME; -static constexpr uint32_t content_object_expiry_time = - never_expire_time; // milliseconds -> 50 seconds -static constexpr uint32_t content_object_packet_size = - 1500; // The ethernet MTU -static constexpr uint32_t producer_socket_output_buffer_size = - 150000; // Content Object -static constexpr uint32_t log_2_default_buffer_size = 12; -static constexpr uint32_t signature_size = 260; // bytes -static constexpr uint32_t key_locator_size = 60; // bytes -static constexpr uint32_t limit_guard = 80; // bytes -static constexpr uint32_t digest_size = 34; // bytes -static constexpr uint32_t max_out_of_order_segments = 3; // content object - -// RAAQM -static constexpr int sample_number = 30; -static constexpr double gamma_value = 1; -static constexpr double beta_value = 0.8; -static constexpr double drop_factor = 0.2; -static constexpr double minimum_drop_probability = 0.00001; -static constexpr int path_id = 0; -static constexpr double rate_alpha = 0.8; - -// Rate estimation -static constexpr uint32_t batch = 50; -static constexpr uint32_t kv = 20; -static constexpr double alpha = 0.8; -static constexpr uint32_t rate_choice = 0; - -// maximum allowed values -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 - -} // namespace default_values - -} // namespace interface - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/interfaces/socket_options_keys.h b/libtransport/src/hicn/transport/interfaces/socket_options_keys.h deleted file mode 100644 index a38131271..000000000 --- a/libtransport/src/hicn/transport/interfaces/socket_options_keys.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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. - */ - -#pragma once - -namespace transport { - -namespace interface { - -typedef enum { - RAAQM = 0, - CBR = 1, - RTC = 2, -} TransportProtocolAlgorithms; - -typedef enum { - INPUT_BUFFER_SIZE = 101, - OUTPUT_BUFFER_SIZE = 102, - NETWORK_NAME = 103, - NAME_SUFFIX = 104, - MAX_INTEREST_RETX = 105, - DATA_PACKET_SIZE = 106, - INTEREST_LIFETIME = 107, - CONTENT_OBJECT_EXPIRY_TIME = 108, - KEY_CONTENT = 110, - MIN_WINDOW_SIZE = 111, - MAX_WINDOW_SIZE = 112, - CURRENT_WINDOW_SIZE = 113, - ASYNC_MODE = 114, - MAKE_MANIFEST = 115, - PORTAL = 116, - RUNNING = 117, - APPLICATION_BUFFER = 118, - HASH_ALGORITHM = 119, - CRYPTO_SUITE = 120, - SIGNER = 121, - VERIFIER = 122, - CERTIFICATE = 123, - VERIFY_SIGNATURE = 124, - STATS_INTERVAL = 125, -} GeneralTransportOptions; - -typedef enum { - SAMPLE_NUMBER = 201, - GAMMA_VALUE = 202, - BETA_VALUE = 203, - DROP_FACTOR = 204, - MINIMUM_DROP_PROBABILITY = 205, - PATH_ID = 206, - RTT_STATS = 207, -} RaaqmTransportOptions; - -typedef enum { - RATE_ESTIMATION_ALPHA = 301, - RATE_ESTIMATION_OBSERVER = 302, - RATE_ESTIMATION_BATCH_PARAMETER = 303, - RATE_ESTIMATION_CHOICE = 304, -} RateEstimationOptions; - -typedef enum { - INTEREST_OUTPUT = 401, - INTEREST_RETRANSMISSION = 402, - INTEREST_EXPIRED = 403, - INTEREST_SATISFIED = 404, - CONTENT_OBJECT_INPUT = 411, - MANIFEST_INPUT = 412, - CONTENT_OBJECT_TO_VERIFY = 413, - VERIFICATION_FAILED = 414, - READ_CALLBACK = 415, - STATS_SUMMARY = 416 -} ConsumerCallbacksOptions; - -typedef enum { - INTEREST_INPUT = 501, - INTEREST_DROP = 502, - INTEREST_PASS = 503, - CACHE_HIT = 506, - CACHE_MISS = 508, - NEW_CONTENT_OBJECT = 509, - CONTENT_OBJECT_SIGN = 513, - CONTENT_OBJECT_READY = 510, - CONTENT_OBJECT_OUTPUT = 511, - CONTENT_PRODUCED = 512, -} ProducerCallbacksOptions; - -typedef enum { OUTPUT_INTERFACE = 601 } DataLinkOptions; - -typedef enum { - VIRTUAL_DOWNLOAD = 701, - USE_CFG_FILE = 702, - STATISTICS -} OtherOptions; - -typedef enum { - SHA_256 = 801, - RSA_256 = 802, -} SignatureType; - -} // namespace interface - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/interfaces/socket_producer.cc b/libtransport/src/hicn/transport/interfaces/socket_producer.cc deleted file mode 100644 index 26a7208b6..000000000 --- a/libtransport/src/hicn/transport/interfaces/socket_producer.cc +++ /dev/null @@ -1,909 +0,0 @@ -/* - * 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. - */ - -#include -#include - -#include - -namespace transport { - -namespace interface { - -namespace details {} - -typedef std::chrono::time_point Time; -typedef std::chrono::microseconds TimeDuration; - -ProducerSocket::ProducerSocket() : ProducerSocket(internal_io_service_) {} - -ProducerSocket::ProducerSocket(asio::io_service &io_service) - : io_service_(io_service), - portal_(std::make_shared(io_service_)), - data_packet_size_(default_values::content_object_packet_size), - content_object_expiry_time_(default_values::content_object_expiry_time), - output_buffer_(default_values::producer_socket_output_buffer_size), - async_thread_(), - registration_status_(REGISTRATION_NOT_ATTEMPTED), - making_manifest_(false), - hash_algorithm_(HashAlgorithm::SHA_256), - suffix_strategy_(core::NextSegmentCalculationStrategy::INCREMENTAL), - on_interest_input_(VOID_HANDLER), - on_interest_dropped_input_buffer_(VOID_HANDLER), - on_interest_inserted_input_buffer_(VOID_HANDLER), - on_interest_satisfied_output_buffer_(VOID_HANDLER), - on_interest_process_(VOID_HANDLER), - on_new_segment_(VOID_HANDLER), - on_content_object_to_sign_(VOID_HANDLER), - on_content_object_in_output_buffer_(VOID_HANDLER), - on_content_object_output_(VOID_HANDLER), - on_content_object_evicted_from_output_buffer_(VOID_HANDLER), - on_content_produced_(VOID_HANDLER) {} - -ProducerSocket::~ProducerSocket() { - stop(); - if (listening_thread_.joinable()) { - listening_thread_.join(); - } -} - -void ProducerSocket::connect() { - portal_->connect(false); - listening_thread_ = std::thread(std::bind(&ProducerSocket::listen, this)); -} - -void ProducerSocket::serveForever() { - if (listening_thread_.joinable()) { - listening_thread_.join(); - } -} - -void ProducerSocket::stop() { portal_->stopEventsLoop(); } - -void ProducerSocket::registerPrefix(const Prefix &producer_namespace) { - served_namespaces_.push_back(producer_namespace); -} - -void ProducerSocket::listen() { - registration_status_ = REGISTRATION_IN_PROGRESS; - bool first = true; - - for (core::Prefix &producer_namespace : served_namespaces_) { - if (first) { - core::BindConfig bind_config(producer_namespace, 1000); - portal_->bind(bind_config); - portal_->setProducerCallback(this); - first = !first; - } else { - portal_->registerRoute(producer_namespace); - } - } - - portal_->runEventsLoop(); -} - -void ProducerSocket::passContentObjectToCallbacks( - const std::shared_ptr &content_object) { - if (content_object) { - io_service_.dispatch([this, content_object]() { - if (on_new_segment_) { - on_new_segment_(*this, *content_object); - } - - if (on_content_object_to_sign_) { - on_content_object_to_sign_(*this, *content_object); - } - - if (on_content_object_in_output_buffer_) { - on_content_object_in_output_buffer_(*this, *content_object); - } - }); - - output_buffer_.insert(content_object); - - io_service_.dispatch([this, content_object]() { - if (on_content_object_output_) { - on_content_object_output_(*this, *content_object); - } - }); - - portal_->sendContentObject(*content_object); - } -} - -void ProducerSocket::produce(ContentObject &content_object) { - io_service_.dispatch([this, &content_object]() { - if (on_content_object_in_output_buffer_) { - on_content_object_in_output_buffer_(*this, content_object); - } - }); - - output_buffer_.insert(std::static_pointer_cast( - content_object.shared_from_this())); - - io_service_.dispatch([this, &content_object]() { - if (on_content_object_output_) { - on_content_object_output_(*this, content_object); - } - }); - - portal_->sendContentObject(content_object); -} - -uint32_t ProducerSocket::produce(Name content_name, - std::unique_ptr &&buffer, - bool is_last, uint32_t start_offset) { - if (TRANSPORT_EXPECT_FALSE(buffer->length() == 0)) { - return 0; - } - - // Copy the atomic variables to ensure they keep the same value - // during the production - std::size_t data_packet_size = data_packet_size_; - uint32_t content_object_expiry_time = content_object_expiry_time_; - HashAlgorithm hash_algo = hash_algorithm_; - bool making_manifest = making_manifest_; - auto suffix_strategy = utils::SuffixStrategyFactory::getSuffixStrategy( - suffix_strategy_, start_offset); - std::shared_ptr signer; - getSocketOption(GeneralTransportOptions::SIGNER, signer); - - auto buffer_size = buffer->length(); - int bytes_segmented = 0; - std::size_t header_size; - std::size_t manifest_header_size = 0; - std::size_t signature_length = 0; - std::uint32_t final_block_number = start_offset; - uint64_t free_space_for_content = 0; - - core::Packet::Format format; - std::shared_ptr manifest; - bool is_last_manifest = false; - - // TODO Manifest may still be used for indexing - if (making_manifest && !signer) { - TRANSPORT_LOGD("Making manifests without setting producer identity."); - } - - core::Packet::Format hf_format = core::Packet::Format::HF_UNSPEC; - core::Packet::Format hf_format_ah = core::Packet::Format::HF_UNSPEC; - if (content_name.getType() == HNT_CONTIGUOUS_V4 || - content_name.getType() == HNT_IOV_V4) { - hf_format = core::Packet::Format::HF_INET_TCP; - hf_format_ah = core::Packet::Format::HF_INET_TCP_AH; - } else if (content_name.getType() == HNT_CONTIGUOUS_V6 || - content_name.getType() == HNT_IOV_V6) { - hf_format = core::Packet::Format::HF_INET6_TCP; - hf_format_ah = core::Packet::Format::HF_INET6_TCP_AH; - } else { - throw errors::RuntimeException("Unknown name format."); - } - - format = hf_format; - if (making_manifest) { - manifest_header_size = core::Packet::getHeaderSizeFromFormat( - signer ? hf_format_ah : hf_format, - signer ? signer->getSignatureLength() : 0); - } else if (signer) { - format = hf_format_ah; - signature_length = signer->getSignatureLength(); - } - - header_size = core::Packet::getHeaderSizeFromFormat(format, signature_length); - free_space_for_content = data_packet_size - header_size; - uint32_t number_of_segments = - uint32_t(std::ceil(double(buffer_size) / double(free_space_for_content))); - if (free_space_for_content * number_of_segments < buffer_size) { - number_of_segments++; - } - - // TODO allocate space for all the headers - if (making_manifest) { - uint32_t segment_in_manifest = static_cast( - std::floor(double(data_packet_size - manifest_header_size - - ContentObjectManifest::getManifestHeaderSize()) / - ContentObjectManifest::getManifestEntrySize()) - - 1.0); - uint32_t number_of_manifests = static_cast( - std::ceil(float(number_of_segments) / segment_in_manifest)); - final_block_number += number_of_segments + number_of_manifests - 1; - - manifest.reset(ContentObjectManifest::createManifest( - content_name.setSuffix(suffix_strategy->getNextManifestSuffix()), - core::ManifestVersion::VERSION_1, core::ManifestType::INLINE_MANIFEST, - hash_algo, is_last_manifest, content_name, suffix_strategy_, - signer ? signer->getSignatureLength() : 0)); - manifest->setLifetime(content_object_expiry_time); - - if (is_last) { - manifest->setFinalBlockNumber(final_block_number); - } else { - manifest->setFinalBlockNumber(utils::SuffixStrategy::INVALID_SUFFIX); - } - } - - TRANSPORT_LOGD("--------- START PRODUCE ----------"); - for (unsigned int packaged_segments = 0; - packaged_segments < number_of_segments; packaged_segments++) { - if (making_manifest) { - if (manifest->estimateManifestSize(2) > - data_packet_size - manifest_header_size) { - // Send the current manifest - manifest->encode(); - - // If identity set, sign manifest - if (signer) { - signer->sign(*manifest); - } - - passContentObjectToCallbacks(manifest); - TRANSPORT_LOGD("Send manifest %u", manifest->getName().getSuffix()); - - // Send content objects stored in the queue - while (!content_queue_.empty()) { - passContentObjectToCallbacks(content_queue_.front()); - TRANSPORT_LOGD("Send content %u", - content_queue_.front()->getName().getSuffix()); - content_queue_.pop(); - } - - // Create new manifest. The reference to the last manifest has been - // acquired in the passContentObjectToCallbacks function, so we can - // safely release this reference - manifest.reset(ContentObjectManifest::createManifest( - content_name.setSuffix(suffix_strategy->getNextManifestSuffix()), - core::ManifestVersion::VERSION_1, - core::ManifestType::INLINE_MANIFEST, hash_algo, is_last_manifest, - content_name, suffix_strategy_, - signer ? signer->getSignatureLength() : 0)); - - manifest->setLifetime(content_object_expiry_time); - manifest->setFinalBlockNumber( - is_last ? final_block_number - : utils::SuffixStrategy::INVALID_SUFFIX); - } - } - - auto content_suffix = suffix_strategy->getNextContentSuffix(); - auto content_object = std::make_shared( - content_name.setSuffix(content_suffix), format); - content_object->setLifetime(content_object_expiry_time); - - auto b = buffer->cloneOne(); - b->trimStart(free_space_for_content * packaged_segments); - b->trimEnd(b->length()); - - if (TRANSPORT_EXPECT_FALSE(packaged_segments == number_of_segments - 1)) { - b->append(buffer_size - bytes_segmented); - bytes_segmented += (int)(buffer_size - bytes_segmented); - - if (is_last && making_manifest) { - is_last_manifest = true; - } else if (is_last) { - content_object->setRst(); - } - - } else { - b->append(free_space_for_content); - bytes_segmented += (int)(free_space_for_content); - } - - content_object->appendPayload(std::move(b)); - - if (making_manifest) { - using namespace std::chrono_literals; - utils::CryptoHash hash = content_object->computeDigest(hash_algo); - manifest->addSuffixHash(content_suffix, hash); - content_queue_.push(content_object); - } else { - if (signer) { - signer->sign(*content_object); - } - passContentObjectToCallbacks(content_object); - TRANSPORT_LOGD("Send content %u", content_object->getName().getSuffix()); - } - } - - if (making_manifest) { - if (is_last_manifest) { - manifest->setFinalManifest(is_last_manifest); - } - - manifest->encode(); - if (signer) { - signer->sign(*manifest); - } - - passContentObjectToCallbacks(manifest); - TRANSPORT_LOGD("Send manifest %u", manifest->getName().getSuffix()); - while (!content_queue_.empty()) { - passContentObjectToCallbacks(content_queue_.front()); - TRANSPORT_LOGD("Send content %u", - content_queue_.front()->getName().getSuffix()); - content_queue_.pop(); - } - } - - io_service_.dispatch([this, buffer_size]() { - if (on_content_produced_) { - on_content_produced_(*this, std::make_error_code(std::errc(0)), - buffer_size); - } - }); - - TRANSPORT_LOGD("--------- END PRODUCE ------------"); - return suffix_strategy->getTotalCount(); -} - -void ProducerSocket::asyncProduce(ContentObject &content_object) { - if (!async_thread_.stopped()) { - auto co_ptr = std::static_pointer_cast( - content_object.shared_from_this()); - async_thread_.add([this, content_object = std::move(co_ptr)]() { - ProducerSocket::produce(*content_object); - }); - } -} - -void ProducerSocket::asyncProduce(const Name &suffix, const uint8_t *buf, - size_t buffer_size, bool is_last, - uint32_t *start_offset) { - if (!async_thread_.stopped()) { - async_thread_.add([this, suffix, buffer = buf, size = buffer_size, is_last, - start_offset]() { - if (start_offset != NULL) { - *start_offset = ProducerSocket::produce(suffix, buffer, size, is_last, - *start_offset); - } else { - ProducerSocket::produce(suffix, buffer, size, is_last, 0); - } - }); - } -} - -void ProducerSocket::asyncProduce(Name content_name, - std::unique_ptr &&buffer, - bool is_last, uint32_t offset, - uint32_t **last_segment) { - if (!async_thread_.stopped()) { - auto a = buffer.release(); - async_thread_.add([this, content_name, a, is_last, offset, last_segment]() { - auto buf = std::unique_ptr(a); - if (last_segment != NULL) { - **last_segment = - offset + ProducerSocket::produce(content_name, std::move(buf), - is_last, offset); - } else { - ProducerSocket::produce(content_name, std::move(buf), is_last, offset); - } - }); - } -} - -void ProducerSocket::onInterest(Interest &interest) { - if (on_interest_input_) { - on_interest_input_(*this, interest); - } - - const std::shared_ptr content_object = - output_buffer_.find(interest); - - if (content_object) { - if (on_interest_satisfied_output_buffer_) { - on_interest_satisfied_output_buffer_(*this, interest); - } - - if (on_content_object_output_) { - on_content_object_output_(*this, *content_object); - } - - portal_->sendContentObject(*content_object); - } else { - if (on_interest_process_) { - on_interest_process_(*this, interest); - } - } -} - -int ProducerSocket::setSocketOption(int socket_option_key, - uint32_t socket_option_value) { - switch (socket_option_key) { - case GeneralTransportOptions::DATA_PACKET_SIZE: - if (socket_option_value < default_values::max_content_object_size && - socket_option_value > 0) { - data_packet_size_ = socket_option_value; - } - break; - - case GeneralTransportOptions::OUTPUT_BUFFER_SIZE: - output_buffer_.setLimit(socket_option_value); - break; - - case GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME: - content_object_expiry_time_ = socket_option_value; - break; - - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; -} - -int ProducerSocket::setSocketOption(int socket_option_key, - std::nullptr_t socket_option_value) { - // Reschedule the function on the io_service to avoid race condition in case - // setSocketOption is called while the io_service is running. - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ProducerContentObjectCallback socket_option_value) -> int { - switch (socket_option_key) { - case ProducerCallbacksOptions::INTEREST_INPUT: - if (socket_option_value == VOID_HANDLER) { - on_interest_input_ = VOID_HANDLER; - break; - } - - case ProducerCallbacksOptions::INTEREST_DROP: - if (socket_option_value == VOID_HANDLER) { - on_interest_dropped_input_buffer_ = VOID_HANDLER; - break; - } - - case ProducerCallbacksOptions::INTEREST_PASS: - if (socket_option_value == VOID_HANDLER) { - on_interest_inserted_input_buffer_ = VOID_HANDLER; - break; - } - - case ProducerCallbacksOptions::CACHE_HIT: - if (socket_option_value == VOID_HANDLER) { - on_interest_satisfied_output_buffer_ = VOID_HANDLER; - break; - } - - case ProducerCallbacksOptions::CACHE_MISS: - if (socket_option_value == VOID_HANDLER) { - on_interest_process_ = VOID_HANDLER; - break; - } - - case ProducerCallbacksOptions::NEW_CONTENT_OBJECT: - if (socket_option_value == VOID_HANDLER) { - on_new_segment_ = VOID_HANDLER; - break; - } - - case ProducerCallbacksOptions::CONTENT_OBJECT_SIGN: - if (socket_option_value == VOID_HANDLER) { - on_content_object_to_sign_ = VOID_HANDLER; - break; - } - - case ProducerCallbacksOptions::CONTENT_OBJECT_READY: - if (socket_option_value == VOID_HANDLER) { - on_content_object_in_output_buffer_ = VOID_HANDLER; - break; - } - - case ProducerCallbacksOptions::CONTENT_OBJECT_OUTPUT: - if (socket_option_value == VOID_HANDLER) { - on_content_object_output_ = VOID_HANDLER; - break; - } - - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; - }); -} - -int ProducerSocket::setSocketOption(int socket_option_key, - bool socket_option_value) { - switch (socket_option_key) { - case GeneralTransportOptions::MAKE_MANIFEST: - making_manifest_ = socket_option_value; - break; - - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; -} - -int ProducerSocket::setSocketOption(int socket_option_key, - Name *socket_option_value) { - return SOCKET_OPTION_NOT_SET; -} - -int ProducerSocket::setSocketOption(int socket_option_key, - std::list socket_option_value) { - switch (socket_option_key) { - case GeneralTransportOptions::NETWORK_NAME: - served_namespaces_ = socket_option_value; - break; - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; -} - -int ProducerSocket::setSocketOption( - int socket_option_key, ProducerContentObjectCallback socket_option_value) { - // Reschedule the function on the io_service to avoid race condition in case - // setSocketOption is called while the io_service is running. - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ProducerContentObjectCallback socket_option_value) -> int { - switch (socket_option_key) { - case ProducerCallbacksOptions::NEW_CONTENT_OBJECT: - on_new_segment_ = socket_option_value; - break; - - case ProducerCallbacksOptions::CONTENT_OBJECT_SIGN: - on_content_object_to_sign_ = socket_option_value; - break; - - case ProducerCallbacksOptions::CONTENT_OBJECT_READY: - on_content_object_in_output_buffer_ = socket_option_value; - break; - - case ProducerCallbacksOptions::CONTENT_OBJECT_OUTPUT: - on_content_object_output_ = socket_option_value; - break; - - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; - }); -} - -int ProducerSocket::setSocketOption( - int socket_option_key, ProducerInterestCallback socket_option_value) { - // Reschedule the function on the io_service to avoid race condition in case - // setSocketOption is called while the io_service is running. - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ProducerInterestCallback socket_option_value) -> int { - switch (socket_option_key) { - case ProducerCallbacksOptions::INTEREST_INPUT: - on_interest_input_ = socket_option_value; - break; - - case ProducerCallbacksOptions::INTEREST_DROP: - on_interest_dropped_input_buffer_ = socket_option_value; - break; - - case ProducerCallbacksOptions::INTEREST_PASS: - on_interest_inserted_input_buffer_ = socket_option_value; - break; - - case ProducerCallbacksOptions::CACHE_HIT: - on_interest_satisfied_output_buffer_ = socket_option_value; - break; - - case ProducerCallbacksOptions::CACHE_MISS: - on_interest_process_ = socket_option_value; - break; - - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; - }); -} - -int ProducerSocket::setSocketOption( - int socket_option_key, ProducerContentCallback socket_option_value) { - // Reschedule the function on the io_service to avoid race condition in case - // setSocketOption is called while the io_service is running. - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ProducerContentCallback socket_option_value) -> int { - switch (socket_option_key) { - case ProducerCallbacksOptions::CONTENT_PRODUCED: - on_content_produced_ = socket_option_value; - break; - - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; - }); -} - -int ProducerSocket::setSocketOption(int socket_option_key, - HashAlgorithm socket_option_value) { - switch (socket_option_key) { - case GeneralTransportOptions::HASH_ALGORITHM: - hash_algorithm_ = socket_option_value; - break; - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; -} - -int ProducerSocket::setSocketOption(int socket_option_key, - utils::CryptoSuite socket_option_value) { - switch (socket_option_key) { - case GeneralTransportOptions::CRYPTO_SUITE: - crypto_suite_ = socket_option_value; - break; - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; -} - -int ProducerSocket::setSocketOption( - int socket_option_key, - const std::shared_ptr &socket_option_value) { - switch (socket_option_key) { - case GeneralTransportOptions::SIGNER: { - utils::SpinLock::Acquire locked(signer_lock_); - signer_.reset(); - signer_ = socket_option_value; - } break; - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; -} - -int ProducerSocket::setSocketOption(int socket_option_key, - const std::string &socket_option_value) { - switch (socket_option_key) { - case DataLinkOptions::OUTPUT_INTERFACE: - output_interface_ = socket_option_value; - portal_->setOutputInterface(output_interface_); - break; - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; -} - -int ProducerSocket::getSocketOption(int socket_option_key, - uint32_t &socket_option_value) { - switch (socket_option_key) { - case GeneralTransportOptions::OUTPUT_BUFFER_SIZE: - socket_option_value = (uint32_t)output_buffer_.getLimit(); - break; - - case GeneralTransportOptions::DATA_PACKET_SIZE: - socket_option_value = (uint32_t)data_packet_size_; - break; - - case GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME: - socket_option_value = content_object_expiry_time_; - break; - - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_GET; -} - -int ProducerSocket::getSocketOption(int socket_option_key, - bool &socket_option_value) { - switch (socket_option_key) { - case GeneralTransportOptions::MAKE_MANIFEST: - socket_option_value = making_manifest_; - break; - - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; -} - -int ProducerSocket::getSocketOption(int socket_option_key, - std::list &socket_option_value) { - switch (socket_option_key) { - case GeneralTransportOptions::NETWORK_NAME: - socket_option_value = served_namespaces_; - break; - - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; -} - -int ProducerSocket::getSocketOption( - int socket_option_key, - ProducerContentObjectCallback **socket_option_value) { - // Reschedule the function on the io_service to avoid race condition in case - // setSocketOption is called while the io_service is running. - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ProducerContentObjectCallback **socket_option_value) -> int { - switch (socket_option_key) { - case ProducerCallbacksOptions::NEW_CONTENT_OBJECT: - *socket_option_value = &on_new_segment_; - break; - - case ProducerCallbacksOptions::CONTENT_OBJECT_SIGN: - *socket_option_value = &on_content_object_to_sign_; - break; - - case ProducerCallbacksOptions::CONTENT_OBJECT_READY: - *socket_option_value = &on_content_object_in_output_buffer_; - break; - - case ProducerCallbacksOptions::CONTENT_OBJECT_OUTPUT: - *socket_option_value = &on_content_object_output_; - break; - - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; - }); -} - -int ProducerSocket::getSocketOption( - int socket_option_key, ProducerContentCallback **socket_option_value) { - // Reschedule the function on the io_service to avoid race condition in case - // setSocketOption is called while the io_service is running. - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ProducerContentCallback **socket_option_value) -> int { - switch (socket_option_key) { - case ProducerCallbacksOptions::CONTENT_PRODUCED: - *socket_option_value = &on_content_produced_; - break; - - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; - }); -} - -int ProducerSocket::getSocketOption( - int socket_option_key, ProducerInterestCallback **socket_option_value) { - // Reschedule the function on the io_service to avoid race condition in case - // setSocketOption is called while the io_service is running. - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ProducerInterestCallback **socket_option_value) -> int { - switch (socket_option_key) { - case ProducerCallbacksOptions::INTEREST_INPUT: - *socket_option_value = &on_interest_input_; - break; - - case ProducerCallbacksOptions::INTEREST_DROP: - *socket_option_value = &on_interest_dropped_input_buffer_; - break; - - case ProducerCallbacksOptions::INTEREST_PASS: - *socket_option_value = &on_interest_inserted_input_buffer_; - break; - - case CACHE_HIT: - *socket_option_value = &on_interest_satisfied_output_buffer_; - break; - - case CACHE_MISS: - *socket_option_value = &on_interest_process_; - break; - - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; - }); -} - -int ProducerSocket::getSocketOption( - int socket_option_key, std::shared_ptr &socket_option_value) { - switch (socket_option_key) { - case PORTAL: - socket_option_value = portal_; - break; - default: - return SOCKET_OPTION_NOT_GET; - ; - } - - return SOCKET_OPTION_GET; -} - -int ProducerSocket::getSocketOption(int socket_option_key, - HashAlgorithm &socket_option_value) { - switch (socket_option_key) { - case GeneralTransportOptions::HASH_ALGORITHM: - socket_option_value = hash_algorithm_; - break; - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; -} - -int ProducerSocket::getSocketOption(int socket_option_key, - utils::CryptoSuite &socket_option_value) { - switch (socket_option_key) { - case GeneralTransportOptions::HASH_ALGORITHM: - socket_option_value = crypto_suite_; - break; - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; -} - -int ProducerSocket::getSocketOption( - int socket_option_key, - std::shared_ptr &socket_option_value) { - switch (socket_option_key) { - case GeneralTransportOptions::SIGNER: { - utils::SpinLock::Acquire locked(signer_lock_); - socket_option_value = signer_; - } break; - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; -} - -int ProducerSocket::getSocketOption(int socket_option_key, - std::string &socket_option_value) { - switch (socket_option_key) { - case DataLinkOptions::OUTPUT_INTERFACE: - socket_option_value = output_interface_; - break; - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; -} - -asio::io_service &ProducerSocket::getIoService() { return io_service_; } - -} // namespace interface - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/interfaces/socket_producer.h b/libtransport/src/hicn/transport/interfaces/socket_producer.h deleted file mode 100644 index 5f360f2ce..000000000 --- a/libtransport/src/hicn/transport/interfaces/socket_producer.h +++ /dev/null @@ -1,295 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#define REGISTRATION_NOT_ATTEMPTED 0 -#define REGISTRATION_SUCCESS 1 -#define REGISTRATION_FAILURE 2 -#define REGISTRATION_IN_PROGRESS 3 - -namespace transport { - -namespace interface { - -using namespace core; - -class ProducerSocket : public Socket, - public BasePortal::ProducerCallback { - public: - explicit ProducerSocket(); - explicit ProducerSocket(asio::io_service &io_service); - - ~ProducerSocket(); - - void connect() override; - - bool isRunning() override { return !io_service_.stopped(); }; - - virtual uint32_t produce(Name content_name, const uint8_t *buffer, - size_t buffer_size, bool is_last = true, - uint32_t start_offset = 0) { - return ProducerSocket::produce( - content_name, utils::MemBuf::copyBuffer(buffer, buffer_size), is_last, - start_offset); - } - - virtual uint32_t produce(Name content_name, - std::unique_ptr &&buffer, - bool is_last = true, uint32_t start_offset = 0); - - virtual void produce(ContentObject &content_object); - - virtual void produce(const uint8_t *buffer, size_t buffer_size) { - produce(utils::MemBuf::copyBuffer(buffer, buffer_size)); - } - - virtual void produce(std::unique_ptr &&buffer) { - // 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(); - } - - virtual void asyncProduce(const Name &suffix, const uint8_t *buf, - size_t buffer_size, bool is_last = true, - uint32_t *start_offset = nullptr); - - void asyncProduce(const Name &suffix); - - virtual void asyncProduce(Name content_name, - std::unique_ptr &&buffer, - bool is_last, uint32_t offset, - uint32_t **last_segment = nullptr); - - virtual void asyncProduce(ContentObject &content_object); - - virtual void registerPrefix(const Prefix &producer_namespace); - - void serveForever(); - - void stop(); - - asio::io_service &getIoService() override; - - virtual void onInterest(Interest &interest); - - virtual void onInterest(Interest::Ptr &&interest) override { - onInterest(*interest); - }; - - virtual int setSocketOption(int socket_option_key, - uint32_t socket_option_value); - - virtual int setSocketOption(int socket_option_key, - std::nullptr_t socket_option_value); - - virtual int setSocketOption(int socket_option_key, bool socket_option_value); - - virtual int setSocketOption(int socket_option_key, Name *socket_option_value); - - virtual int setSocketOption(int socket_option_key, - std::list socket_option_value); - - virtual int setSocketOption( - int socket_option_key, ProducerContentObjectCallback socket_option_value); - - virtual int setSocketOption(int socket_option_key, - ProducerInterestCallback socket_option_value); - - virtual int setSocketOption(int socket_option_key, - ProducerContentCallback socket_option_value); - - virtual int setSocketOption(int socket_option_key, - HashAlgorithm socket_option_value); - - virtual int setSocketOption(int socket_option_key, - utils::CryptoSuite socket_option_value); - - virtual int setSocketOption( - int socket_option_key, - const std::shared_ptr &socket_option_value); - - virtual int setSocketOption(int socket_option_key, - const std::string &socket_option_value); - - virtual int getSocketOption(int socket_option_key, - uint32_t &socket_option_value); - - virtual int getSocketOption(int socket_option_key, bool &socket_option_value); - - virtual int getSocketOption(int socket_option_key, - std::list &socket_option_value); - - virtual int getSocketOption( - int socket_option_key, - ProducerContentObjectCallback **socket_option_value); - - virtual int getSocketOption(int socket_option_key, - ProducerContentCallback **socket_option_value); - - virtual int getSocketOption(int socket_option_key, - ProducerInterestCallback **socket_option_value); - - virtual int getSocketOption(int socket_option_key, - std::shared_ptr &socket_option_value); - - virtual int getSocketOption(int socket_option_key, - HashAlgorithm &socket_option_value); - - virtual int getSocketOption(int socket_option_key, - utils::CryptoSuite &socket_option_value); - - virtual int getSocketOption( - int socket_option_key, - std::shared_ptr &socket_option_value); - - virtual int getSocketOption(int socket_option_key, - std::string &socket_option_value); - - // If the thread calling lambda_func is not the same of io_service, this - // function reschedule the function on it - template - int rescheduleOnIOService(int socket_option_key, arg2 socket_option_value, - Lambda lambda_func) { - // To enforce type check - std::function func = lambda_func; - int result = SOCKET_OPTION_SET; - if (listening_thread_.joinable() && - std::this_thread::get_id() != listening_thread_.get_id()) { - std::mutex mtx; - /* Condition variable for the wait */ - std::condition_variable cv; - bool done = false; - io_service_.dispatch([&socket_option_key, &socket_option_value, &mtx, &cv, - &result, &done, &func]() { - std::unique_lock lck(mtx); - done = true; - result = func(socket_option_key, socket_option_value); - cv.notify_all(); - }); - std::unique_lock lck(mtx); - if (!done) { - cv.wait(lck); - } - } else { - result = func(socket_option_key, socket_option_value); - } - - return result; - } - - template - int rescheduleOnIOServiceWithReference(int socket_option_key, - arg2 &socket_option_value, - Lambda lambda_func) { - // To enforce type check - std::function func = lambda_func; - int result = SOCKET_OPTION_SET; - if (listening_thread_.joinable() && - std::this_thread::get_id() != this->listening_thread_.get_id()) { - std::mutex mtx; - /* Condition variable for the wait */ - std::condition_variable cv; - - bool done = false; - io_service_.dispatch([&socket_option_key, &socket_option_value, &mtx, &cv, - &result, &done, &func]() { - std::unique_lock lck(mtx); - done = true; - result = func(socket_option_key, socket_option_value); - cv.notify_all(); - }); - std::unique_lock lck(mtx); - if (!done) { - cv.wait(lck); - } - } else { - result = func(socket_option_key, socket_option_value); - } - - return result; - } - // Threads - protected: - std::thread listening_thread_; - asio::io_service internal_io_service_; - asio::io_service &io_service_; - std::shared_ptr portal_; - std::atomic data_packet_size_; - std::list - served_namespaces_; // No need to be threadsafe, this is always modified - // by the application thread - std::atomic content_object_expiry_time_; - - // buffers - // ContentStore is thread-safe - utils::ContentStore output_buffer_; - - utils::EventThread async_thread_; - int registration_status_; - - std::atomic making_manifest_; - - // map for storing sequence numbers for several calls of the publish - // function - std::unordered_map> seq_number_map_; - - std::atomic hash_algorithm_; - std::atomic crypto_suite_; - utils::SpinLock signer_lock_; - std::shared_ptr signer_; - core::NextSegmentCalculationStrategy suffix_strategy_; - - // While manifests are being built, contents are stored in a queue - std::queue> content_queue_; - - // callbacks - ProducerInterestCallback on_interest_input_; - ProducerInterestCallback on_interest_dropped_input_buffer_; - ProducerInterestCallback on_interest_inserted_input_buffer_; - ProducerInterestCallback on_interest_satisfied_output_buffer_; - ProducerInterestCallback on_interest_process_; - - ProducerContentObjectCallback on_new_segment_; - ProducerContentObjectCallback on_content_object_to_sign_; - ProducerContentObjectCallback on_content_object_in_output_buffer_; - ProducerContentObjectCallback on_content_object_output_; - ProducerContentObjectCallback on_content_object_evicted_from_output_buffer_; - - ProducerContentCallback on_content_produced_; - - private: - void listen(); - - void passContentObjectToCallbacks( - const std::shared_ptr &content_object); -}; - -} // namespace interface - -} // namespace transport diff --git a/libtransport/src/hicn/transport/interfaces/tls_rtc_socket_producer.cc b/libtransport/src/hicn/transport/interfaces/tls_rtc_socket_producer.cc deleted file mode 100644 index 27c1e54bd..000000000 --- a/libtransport/src/hicn/transport/interfaces/tls_rtc_socket_producer.cc +++ /dev/null @@ -1,178 +0,0 @@ -#include -#include -#include - -#include -#include -#include - -namespace transport { - -namespace interface { -int TLSRTCProducerSocket::read(BIO *b, char *buf, size_t size, - size_t *readbytes) { - int ret; - - if (size > INT_MAX) size = INT_MAX; - - ret = TLSRTCProducerSocket::readOld(b, buf, (int)size); - - if (ret <= 0) { - *readbytes = 0; - return ret; - } - - *readbytes = (size_t)ret; - - return 1; -} - -int TLSRTCProducerSocket::readOld(BIO *b, char *buf, int size) { - TLSRTCProducerSocket *socket; - socket = (TLSRTCProducerSocket *)BIO_get_data(b); - - std::unique_lock lck(socket->mtx_); - if (!socket->something_to_read_) { - (socket->cv_).wait(lck); - } - - utils::MemBuf *membuf = socket->packet_->next(); - int size_to_read; - - if ((int)membuf->length() > size) { - size_to_read = size; - } else { - size_to_read = membuf->length(); - socket->something_to_read_ = false; - } - - std::memcpy(buf, membuf->data(), size_to_read); - membuf->trimStart(size_to_read); - - return size_to_read; -} - -int TLSRTCProducerSocket::write(BIO *b, const char *buf, size_t size, - size_t *written) { - int ret; - - if (size > INT_MAX) size = INT_MAX; - - ret = TLSRTCProducerSocket::writeOld(b, buf, (int)size); - - if (ret <= 0) { - *written = 0; - return ret; - } - - *written = (size_t)ret; - - return 1; -} - -int TLSRTCProducerSocket::writeOld(BIO *b, const char *buf, int num) { - TLSRTCProducerSocket *socket; - socket = (TLSRTCProducerSocket *)BIO_get_data(b); - - if ((SSL_in_before(socket->ssl_) || SSL_in_init(socket->ssl_)) && - socket->first_) { - socket->tls_chunks_--; - bool making_manifest = socket->parent_->making_manifest_; - socket->parent_->setSocketOption(GeneralTransportOptions::MAKE_MANIFEST, - false); - socket->parent_->ProducerSocket::produce( - socket->name_, (const uint8_t *)buf, num, socket->tls_chunks_ == 0, 0); - socket->parent_->setSocketOption(GeneralTransportOptions::MAKE_MANIFEST, - making_manifest); - socket->first_ = false; - - } else { - std::unique_ptr mbuf = - utils::MemBuf::copyBuffer(buf, (std::size_t)num, 0, 0); - auto a = mbuf.release(); - socket->async_thread_.add([socket = socket, a]() { - socket->to_call_oncontentproduced_--; - auto mbuf = std::unique_ptr(a); - socket->RTCProducerSocket::produce(std::move(mbuf)); - ProducerContentCallback on_content_produced_application; - socket->getSocketOption(ProducerCallbacksOptions::CONTENT_PRODUCED, - on_content_produced_application); - if (socket->to_call_oncontentproduced_ == 0 && - on_content_produced_application) { - on_content_produced_application(*socket, std::error_code(), 0); - } - }); - } - - return num; -} - -TLSRTCProducerSocket::TLSRTCProducerSocket(P2PSecureProducerSocket *parent, - const Name &handshake_name) - : RTCProducerSocket(), TLSProducerSocket(parent, handshake_name) { - BIO_METHOD *bio_meth = - BIO_meth_new(BIO_TYPE_ACCEPT, "secure rtc producer socket"); - BIO_meth_set_read(bio_meth, TLSRTCProducerSocket::readOld); - BIO_meth_set_write(bio_meth, TLSRTCProducerSocket::writeOld); - BIO_meth_set_ctrl(bio_meth, TLSProducerSocket::ctrl); - BIO *bio = BIO_new(bio_meth); - BIO_set_init(bio, 1); - BIO_set_data(bio, this); - SSL_set_bio(ssl_, bio, bio); -} - -void TLSRTCProducerSocket::accept() { - if (SSL_in_before(ssl_) || SSL_in_init(ssl_)) { - tls_chunks_ = 1; - int result = SSL_accept(ssl_); - if (result != 1) - throw errors::RuntimeException("Unable to perform client handshake"); - } - - TRANSPORT_LOGD("Handshake performed!"); - parent_->list_secure_rtc_producers.push_front( - std::move(parent_->map_secure_rtc_producers[handshake_name_])); - parent_->map_secure_rtc_producers.erase(handshake_name_); - - ProducerInterestCallback on_interest_process_decrypted; - getSocketOption(ProducerCallbacksOptions::CACHE_MISS, - on_interest_process_decrypted); - - if (on_interest_process_decrypted) { - Interest inter(std::move(packet_)); - on_interest_process_decrypted(*this, inter); - } - - parent_->cv_.notify_one(); -} - -int TLSRTCProducerSocket::async_accept() { - if (!async_thread_.stopped()) { - async_thread_.add([this]() { this->TLSRTCProducerSocket::accept(); }); - } else { - throw errors::RuntimeException( - "Async thread not running, impossible to perform handshake"); - } - - return 1; -} - -void TLSRTCProducerSocket::produce(std::unique_ptr &&buffer) { - if (SSL_in_before(ssl_) || SSL_in_init(ssl_)) { - throw errors::RuntimeException( - "New handshake on the same P2P secure producer socket not supported"); - } - - size_t buf_size = buffer->length(); - tls_chunks_ = ceil((float)buf_size / (float)SSL3_RT_MAX_PLAIN_LENGTH); - to_call_oncontentproduced_ = tls_chunks_; - - SSL_write(ssl_, buffer->data(), buf_size); - BIO *wbio = SSL_get_wbio(ssl_); - int i = BIO_flush(wbio); - (void)i; // To shut up gcc 5 -} - -} // namespace interface - -} // namespace transport diff --git a/libtransport/src/hicn/transport/interfaces/tls_rtc_socket_producer.h b/libtransport/src/hicn/transport/interfaces/tls_rtc_socket_producer.h deleted file mode 100644 index 16125f889..000000000 --- a/libtransport/src/hicn/transport/interfaces/tls_rtc_socket_producer.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include - -namespace transport { - -namespace interface { - -class P2PSecureProducerSocket; - -class TLSRTCProducerSocket : public RTCProducerSocket, - public TLSProducerSocket { - friend class P2PSecureProducerSocket; - - public: - explicit TLSRTCProducerSocket(P2PSecureProducerSocket *parent, - const Name &handshake_name); - - ~TLSRTCProducerSocket() = default; - - void produce(std::unique_ptr &&buffer) override; - - void accept() override; - - int async_accept() override; - - using TLSProducerSocket::produce; - using TLSProducerSocket::onInterest; - - protected: - static int read(BIO *b, char *buf, size_t size, size_t *readbytes); - - static int readOld(BIO *h, char *buf, int size); - - static int write(BIO *b, const char *buf, size_t size, size_t *written); - - static int writeOld(BIO *h, const char *buf, int num); -}; - -} // namespace interface - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/interfaces/tls_socket_consumer.cc b/libtransport/src/hicn/transport/interfaces/tls_socket_consumer.cc deleted file mode 100644 index 58b3c1d7d..000000000 --- a/libtransport/src/hicn/transport/interfaces/tls_socket_consumer.cc +++ /dev/null @@ -1,364 +0,0 @@ -#include -#include -#include -#include - -#include - -namespace transport { - -namespace interface { - -void TLSConsumerSocket::setInterestPayload(ConsumerSocket &c, - const core::Interest &interest) { - Interest &int2 = const_cast(interest); - random_suffix_ = int2.getName().getSuffix(); - - if (payload_ != NULL) int2.appendPayload(std::move(payload_)); -} - -/* Return the number of read bytes in the return param */ -int readOldTLS(BIO *b, char *buf, int size) { - if (size < 0) return size; - - TLSConsumerSocket *socket; - socket = (TLSConsumerSocket *)BIO_get_data(b); - - std::unique_lock lck(socket->mtx_); - - if (!socket->something_to_read_) { - if (!socket->transport_protocol_->isRunning()) { - socket->network_name_.setSuffix(socket->random_suffix_); - socket->ConsumerSocket::asyncConsume(socket->network_name_); - } - if (!socket->something_to_read_) socket->cv_.wait(lck); - } - - size_t size_to_read, read; - size_t chain_size = socket->head_->length(); - if (socket->head_->isChained()) - chain_size = socket->head_->computeChainDataLength(); - - if (chain_size > (size_t)size) { - read = size_to_read = (size_t)size; - } else { - read = size_to_read = chain_size; - socket->something_to_read_ = false; - } - - while (size_to_read) { - if (socket->head_->length() < size_to_read) { - std::memcpy(buf, socket->head_->data(), socket->head_->length()); - size_to_read -= socket->head_->length(); - buf += socket->head_->length(); - socket->head_ = socket->head_->pop(); - } else { - std::memcpy(buf, socket->head_->data(), size_to_read); - socket->head_->trimStart(size_to_read); - size_to_read = 0; - } - } - - return read; -} - -/* Return the number of read bytes in readbytes */ -int readTLS(BIO *b, char *buf, size_t size, size_t *readbytes) { - int ret; - - if (size > INT_MAX) size = INT_MAX; - - ret = transport::interface::readOldTLS(b, buf, (int)size); - - if (ret <= 0) { - *readbytes = 0; - return ret; - } - - *readbytes = (size_t)ret; - - return 1; -} - -/* Return the number of written bytes in the return param */ -int writeOldTLS(BIO *b, const char *buf, int num) { - TLSConsumerSocket *socket; - socket = (TLSConsumerSocket *)BIO_get_data(b); - - socket->payload_ = utils::MemBuf::copyBuffer(buf, num); - socket->ConsumerSocket::setSocketOption( - ConsumerCallbacksOptions::INTEREST_OUTPUT, - (ConsumerInterestCallback)std::bind( - &TLSConsumerSocket::setInterestPayload, socket, std::placeholders::_1, - std::placeholders::_2)); - - return num; -} - -/* Return the number of written bytes in written */ -int writeTLS(BIO *b, const char *buf, size_t size, size_t *written) { - int ret; - - if (size > INT_MAX) size = INT_MAX; - - ret = transport::interface::writeOldTLS(b, buf, (int)size); - - if (ret <= 0) { - *written = 0; - return ret; - } - - *written = (size_t)ret; - - return 1; -} - -long ctrlTLS(BIO *b, int cmd, long num, void *ptr) { return 1; } - -TLSConsumerSocket::TLSConsumerSocket(int protocol, SSL *ssl) - : ConsumerSocket(protocol), - name_(), - buf_pool_(), - decrypted_content_(), - payload_(), - head_(), - something_to_read_(false), - content_downloaded_(false), - random_suffix_(), - secure_prefix_(), - producer_namespace_(), - read_callback_decrypted_(), - mtx_(), - cv_(), - async_downloader_tls_() { - /* Create the (d)TLS state */ - const SSL_METHOD *meth = TLS_client_method(); - ctx_ = SSL_CTX_new(meth); - - int result = - SSL_CTX_set_ciphersuites(ctx_, - "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_" - "SHA256:TLS_AES_128_GCM_SHA256"); - if (result != 1) { - throw errors::RuntimeException( - "Unable to set cipher list on TLS subsystem. Aborting."); - } - - SSL_CTX_set_min_proto_version(ctx_, TLS1_3_VERSION); - SSL_CTX_set_max_proto_version(ctx_, TLS1_3_VERSION); - SSL_CTX_set_verify(ctx_, SSL_VERIFY_NONE, NULL); - SSL_CTX_set_ssl_version(ctx_, meth); - - ssl_ = ssl; - - BIO_METHOD *bio_meth = - BIO_meth_new(BIO_TYPE_CONNECT, "secure consumer socket"); - BIO_meth_set_read(bio_meth, transport::interface::readOldTLS); - BIO_meth_set_write(bio_meth, transport::interface::writeOldTLS); - BIO_meth_set_ctrl(bio_meth, transport::interface::ctrlTLS); - BIO *bio = BIO_new(bio_meth); - BIO_set_init(bio, 1); - BIO_set_data(bio, this); - SSL_set_bio(ssl_, bio, bio); - - ConsumerSocket::getSocketOption(MAX_WINDOW_SIZE, old_max_win_); - ConsumerSocket::setSocketOption(MAX_WINDOW_SIZE, (double)1.0); - - ConsumerSocket::getSocketOption(CURRENT_WINDOW_SIZE, old_current_win_); - ConsumerSocket::setSocketOption(CURRENT_WINDOW_SIZE, (double)1.0); - - std::default_random_engine generator; - std::uniform_int_distribution distribution( - 1, std::numeric_limits::max()); - random_suffix_ = 0; - - this->ConsumerSocket::setSocketOption(ConsumerCallbacksOptions::READ_CALLBACK, - this); -}; - -int TLSConsumerSocket::consume(const Name &name, - std::unique_ptr &&buffer) { - this->payload_ = std::move(buffer); - - this->ConsumerSocket::setSocketOption( - ConsumerCallbacksOptions::INTEREST_OUTPUT, - (ConsumerInterestCallback)std::bind( - &TLSConsumerSocket::setInterestPayload, this, std::placeholders::_1, - std::placeholders::_2)); - - return consume(name); -} - -int TLSConsumerSocket::consume(const Name &name) { - if (transport_protocol_->isRunning()) { - return CONSUMER_BUSY; - } - - if ((SSL_in_before(this->ssl_) || SSL_in_init(this->ssl_))) { - throw errors::RuntimeException("Handshake not performed"); - } - - return download_content(name); -} - -int TLSConsumerSocket::download_content(const Name &name) { - network_name_ = name; - network_name_.setSuffix(0); - something_to_read_ = false; - content_downloaded_ = false; - - decrypted_content_ = utils::MemBuf::createCombined(SSL3_RT_MAX_PLAIN_LENGTH); - uint8_t *buf = decrypted_content_->writableData(); - size_t size = 0; - int result = -1; - - while (!content_downloaded_ || something_to_read_) { - if (decrypted_content_->tailroom() < SSL3_RT_MAX_PLAIN_LENGTH) { - decrypted_content_->appendChain( - utils::MemBuf::createCombined(SSL3_RT_MAX_PLAIN_LENGTH)); - // decrypted_content_->computeChainDataLength(); - buf = decrypted_content_->prev()->writableData(); - } else { - buf = decrypted_content_->writableTail(); - } - - result = SSL_read(this->ssl_, buf, SSL3_RT_MAX_PLAIN_LENGTH); - - /* SSL_read returns the data only if there were SSL3_RT_MAX_PLAIN_LENGTH of - * the data has been fully downloaded */ - - /* ASSERT((result < SSL3_RT_MAX_PLAIN_LENGTH && content_downloaded_) || */ - /* result == SSL3_RT_MAX_PLAIN_LENGTH); */ - - if (result >= 0) { - size += result; - decrypted_content_->prepend(result); - } else - throw errors::RuntimeException("Unable to download content"); - - if (size >= read_callback_decrypted_->maxBufferSize()) { - if (read_callback_decrypted_->isBufferMovable()) { - // No need to perform an additional copy. The whole buffer will be - // tranferred to the application. - - read_callback_decrypted_->readBufferAvailable( - std::move(decrypted_content_)); - decrypted_content_ = utils::MemBuf::create(SSL3_RT_MAX_PLAIN_LENGTH); - } else { - // The buffer will be copied into the application-provided buffer - uint8_t *buffer; - std::size_t length; - std::size_t total_length = decrypted_content_->length(); - - while (decrypted_content_->length()) { - buffer = nullptr; - length = 0; - read_callback_decrypted_->getReadBuffer(&buffer, &length); - - if (!buffer || !length) { - throw errors::RuntimeException( - "Invalid buffer provided by the application."); - } - - auto to_copy = std::min(decrypted_content_->length(), length); - std::memcpy(buffer, decrypted_content_->data(), to_copy); - decrypted_content_->trimStart(to_copy); - } - - read_callback_decrypted_->readDataAvailable(total_length); - decrypted_content_->clear(); - } - } - } - - read_callback_decrypted_->readSuccess(size); - - return CONSUMER_FINISHED; -} - -int TLSConsumerSocket::asyncConsume(const Name &name, - std::unique_ptr &&buffer) { - this->payload_ = std::move(buffer); - - this->ConsumerSocket::setSocketOption( - ConsumerCallbacksOptions::INTEREST_OUTPUT, - (ConsumerInterestCallback)std::bind( - &TLSConsumerSocket::setInterestPayload, this, std::placeholders::_1, - std::placeholders::_2)); - - return asyncConsume(name); -} - -int TLSConsumerSocket::asyncConsume(const Name &name) { - if ((SSL_in_before(this->ssl_) || SSL_in_init(this->ssl_))) { - throw errors::RuntimeException("Handshake not performed"); - } - - if (!async_downloader_tls_.stopped()) { - async_downloader_tls_.add([this, name]() { - is_async_ = true; - download_content(name); - }); - } - - return CONSUMER_RUNNING; -} - -void TLSConsumerSocket::registerPrefix(const Prefix &producer_namespace) { - producer_namespace_ = producer_namespace; -} - -int TLSConsumerSocket::setSocketOption( - int socket_option_key, ConsumerSocket::ReadCallback *socket_option_value) { - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ConsumerSocket::ReadCallback *socket_option_value) -> int { - switch (socket_option_key) { - case ConsumerCallbacksOptions::READ_CALLBACK: - read_callback_decrypted_ = socket_option_value; - break; - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; - }); -} - -void TLSConsumerSocket::getReadBuffer(uint8_t **application_buffer, - size_t *max_length) {} - -void TLSConsumerSocket::readDataAvailable(size_t length) noexcept {} - -size_t TLSConsumerSocket::maxBufferSize() const { - return SSL3_RT_MAX_PLAIN_LENGTH; -} - -void TLSConsumerSocket::readBufferAvailable( - std::unique_ptr &&buffer) noexcept { - std::unique_lock lck(this->mtx_); - if (head_) { - head_->prependChain(std::move(buffer)); - } else { - head_ = std::move(buffer); - } - - something_to_read_ = true; - cv_.notify_one(); -} - -void TLSConsumerSocket::readError(const std::error_code ec) noexcept {} - -void TLSConsumerSocket::readSuccess(std::size_t total_size) noexcept { - std::unique_lock lck(this->mtx_); - content_downloaded_ = true; - something_to_read_ = true; - cv_.notify_one(); -} - -bool TLSConsumerSocket::isBufferMovable() noexcept { return true; } - -} // namespace interface - -} // namespace transport diff --git a/libtransport/src/hicn/transport/interfaces/tls_socket_consumer.h b/libtransport/src/hicn/transport/interfaces/tls_socket_consumer.h deleted file mode 100644 index 05f7fe6a5..000000000 --- a/libtransport/src/hicn/transport/interfaces/tls_socket_consumer.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include - -namespace transport { - -namespace interface { - -class TLSConsumerSocket : public ConsumerSocket, - public ConsumerSocket::ReadCallback { - /* Return the number of read bytes in readbytes */ - friend int readTLS(BIO *b, char *buf, size_t size, size_t *readbytes); - - /* Return the number of read bytes in the return param */ - friend int readOldTLS(BIO *h, char *buf, int size); - - /* Return the number of written bytes in written */ - friend int writeTLS(BIO *b, const char *buf, size_t size, size_t *written); - - /* Return the number of written bytes in the return param */ - friend int writeOldTLS(BIO *h, const char *buf, int num); - - friend long ctrlTLS(BIO *b, int cmd, long num, void *ptr); - - public: - explicit TLSConsumerSocket(int protocol, SSL *ssl_); - - ~TLSConsumerSocket() = default; - - int consume(const Name &name, std::unique_ptr &&buffer); - int consume(const Name &name) override; - - int asyncConsume(const Name &name, std::unique_ptr &&buffer); - int asyncConsume(const Name &name) override; - - void registerPrefix(const Prefix &producer_namespace); - - int setSocketOption( - int socket_option_key, - ConsumerSocket::ReadCallback *socket_option_value) override; - - using ConsumerSocket::getSocketOption; - using ConsumerSocket::setSocketOption; - - protected: - /* Callback invoked once an interest has been received and its payload - * decrypted */ - ConsumerInterestCallback on_interest_input_decrypted_; - ConsumerInterestCallback on_interest_process_decrypted_; - - private: - Name name_; - - /* SSL handle */ - SSL *ssl_; - SSL_CTX *ctx_; - - /* Chain of MemBuf to be used as a temporary buffer to pass descypted data - * from the underlying layer to the application */ - utils::ObjectPool buf_pool_; - std::unique_ptr decrypted_content_; - - /* Chain of MemBuf holding the payload to be written into interest or data */ - std::unique_ptr payload_; - - /* Chain of MemBuf holding the data retrieved from the underlying layer */ - std::unique_ptr head_; - - bool something_to_read_; - - bool content_downloaded_; - - double old_max_win_; - - double old_current_win_; - - uint32_t random_suffix_; - - ip_address_t secure_prefix_; - - Prefix producer_namespace_; - - ConsumerSocket::ReadCallback *read_callback_decrypted_; - - std::mutex mtx_; - - /* Condition variable for the wait */ - std::condition_variable cv_; - - utils::EventThread async_downloader_tls_; - - void setInterestPayload(ConsumerSocket &c, const core::Interest &interest); - void processPayload(ConsumerSocket &c, std::size_t bytes_transferred, - const std::error_code &ec); - - virtual void getReadBuffer(uint8_t **application_buffer, - size_t *max_length) override; - - virtual void readDataAvailable(size_t length) noexcept override; - - virtual size_t maxBufferSize() const override; - - virtual void readBufferAvailable( - std::unique_ptr &&buffer) noexcept override; - - virtual void readError(const std::error_code ec) noexcept override; - - virtual void readSuccess(std::size_t total_size) noexcept override; - virtual bool isBufferMovable() noexcept override; - - int download_content(const Name &name); -}; - -} // namespace interface - -} // end namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/interfaces/tls_socket_producer.cc b/libtransport/src/hicn/transport/interfaces/tls_socket_producer.cc deleted file mode 100644 index ad85ec6ea..000000000 --- a/libtransport/src/hicn/transport/interfaces/tls_socket_producer.cc +++ /dev/null @@ -1,587 +0,0 @@ -#include -#include -#include - -#include -#include -#include - -namespace transport { - -namespace interface { - -/* Return the number of read bytes in readbytes */ -int TLSProducerSocket::read(BIO *b, char *buf, size_t size, size_t *readbytes) { - int ret; - - if (size > INT_MAX) size = INT_MAX; - - ret = TLSProducerSocket::readOld(b, buf, (int)size); - - if (ret <= 0) { - *readbytes = 0; - return ret; - } - - *readbytes = (size_t)ret; - - return 1; -} - -/* Return the number of read bytes in the return param */ -int TLSProducerSocket::readOld(BIO *b, char *buf, int size) { - TLSProducerSocket *socket; - socket = (TLSProducerSocket *)BIO_get_data(b); - - /* take a lock on the mutex. It will be unlocked by */ - std::unique_lock lck(socket->mtx_); - if (!socket->something_to_read_) { - (socket->cv_).wait(lck); - } - - /* Either there already is something to read, or the thread has been waken up - */ - /* must return the payload in the interest */ - - utils::MemBuf *membuf = socket->packet_->next(); - int size_to_read; - if ((int)membuf->length() > size) { - size_to_read = size; - } else { - size_to_read = membuf->length(); - socket->something_to_read_ = false; - } - - std::memcpy(buf, membuf->data(), size_to_read); - membuf->trimStart(size_to_read); - - return size_to_read; -} - -/* Return the number of written bytes in written */ -int TLSProducerSocket::write(BIO *b, const char *buf, size_t size, - size_t *written) { - int ret; - - if (size > INT_MAX) size = INT_MAX; - - ret = TLSProducerSocket::writeOld(b, buf, (int)size); - - if (ret <= 0) { - *written = 0; - return ret; - } - - *written = (size_t)ret; - - return 1; -} - -/* Return the number of written bytes in the return param */ -int TLSProducerSocket::writeOld(BIO *b, const char *buf, int num) { - TLSProducerSocket *socket; - socket = (TLSProducerSocket *)BIO_get_data(b); - - if ((SSL_in_before(socket->ssl_) || SSL_in_init(socket->ssl_)) && - socket->first_) { - //! socket->tls_chunks_ corresponds to is_last - socket->tls_chunks_--; - bool making_manifest = socket->parent_->making_manifest_; - socket->parent_->setSocketOption(GeneralTransportOptions::MAKE_MANIFEST, - false); - socket->parent_->ProducerSocket::produce( - socket->name_, (const uint8_t *)buf, num, socket->tls_chunks_ == 0, - socket->last_segment_); - socket->parent_->setSocketOption(GeneralTransportOptions::MAKE_MANIFEST, - making_manifest); - socket->first_ = false; - } else { - socket->still_writing_ = true; - - std::unique_ptr mbuf = - utils::MemBuf::copyBuffer(buf, (std::size_t)num, 0, 0); - auto a = mbuf.release(); - socket->async_thread_.add([socket = socket, a]() { - socket->tls_chunks_--; - socket->to_call_oncontentproduced_--; - auto mbuf = std::unique_ptr(a); - socket->last_segment_ += socket->ProducerSocket::produce( - socket->name_, std::move(mbuf), socket->tls_chunks_ == 0, - socket->last_segment_); - ProducerContentCallback on_content_produced_application; - socket->getSocketOption(ProducerCallbacksOptions::CONTENT_PRODUCED, - on_content_produced_application); - if (socket->to_call_oncontentproduced_ == 0 && - on_content_produced_application) { - on_content_produced_application(*socket, std::error_code(), 0); - } - }); - } - - return num; -} - -TLSProducerSocket::TLSProducerSocket(P2PSecureProducerSocket *parent, - const Name &handshake_name) - : ProducerSocket(), - on_content_produced_application_(), - mtx_(), - cv_(), - something_to_read_(), - name_(), - last_segment_(0), - parent_(parent), - first_(true), - handshake_name_(handshake_name), - tls_chunks_(0), - to_call_oncontentproduced_(0), - still_writing_(false), - encryption_thread_() { - const SSL_METHOD *meth = TLS_server_method(); - ctx_ = SSL_CTX_new(meth); - - /* - * Setup SSL context (identity and parameter to use TLS 1.3) - */ - SSL_CTX_use_certificate(ctx_, parent->cert_509_); - SSL_CTX_use_PrivateKey(ctx_, parent->pkey_rsa_); - - int result = - SSL_CTX_set_ciphersuites(ctx_, - "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_" - "SHA256:TLS_AES_128_GCM_SHA256"); - if (result != 1) { - throw errors::RuntimeException( - "Unable to set cipher list on TLS subsystem. Aborting."); - } - - // We force it to be TLS 1.3 - SSL_CTX_set_min_proto_version(ctx_, TLS1_3_VERSION); - SSL_CTX_set_max_proto_version(ctx_, TLS1_3_VERSION); - SSL_CTX_set_verify(ctx_, SSL_VERIFY_NONE, NULL); - SSL_CTX_set_num_tickets(ctx_, 0); - - result = SSL_CTX_add_custom_ext( - ctx_, 100, SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS, - TLSProducerSocket::addHicnKeyIdCb, TLSProducerSocket::freeHicnKeyIdCb, - this, TLSProducerSocket::parseHicnKeyIdCb, NULL); - - ssl_ = SSL_new(ctx_); - /* - * Setup this producer socker as the bio that TLS will use to write and read - * data (in stream mode) - */ - BIO_METHOD *bio_meth = - BIO_meth_new(BIO_TYPE_ACCEPT, "secure producer socket"); - BIO_meth_set_read(bio_meth, TLSProducerSocket::readOld); - BIO_meth_set_write(bio_meth, TLSProducerSocket::writeOld); - BIO_meth_set_ctrl(bio_meth, TLSProducerSocket::ctrl); - BIO *bio = BIO_new(bio_meth); - BIO_set_init(bio, 1); - BIO_set_data(bio, this); - SSL_set_bio(ssl_, bio, bio); - /* - * Set the callback so that when an interest is received we catch it and we - * decrypt the payload before passing it to the application. - */ - this->ProducerSocket::setSocketOption( - ProducerCallbacksOptions::CACHE_MISS, - (ProducerInterestCallback)std::bind(&TLSProducerSocket::cacheMiss, this, - std::placeholders::_1, - std::placeholders::_2)); - this->ProducerSocket::setSocketOption( - ProducerCallbacksOptions::CONTENT_PRODUCED, - (ProducerContentCallback)bind( - &TLSProducerSocket::onContentProduced, this, std::placeholders::_1, - std::placeholders::_2, std::placeholders::_3)); -} - -void TLSProducerSocket::accept() { - if (SSL_in_before(ssl_) || SSL_in_init(ssl_)) { - tls_chunks_ = 1; - int result = SSL_accept(ssl_); - if (result != 1) - throw errors::RuntimeException("Unable to perform client handshake"); - } - TRANSPORT_LOGD("Handshake performed!"); - parent_->list_secure_producers.push_front( - std::move(parent_->map_secure_producers[handshake_name_])); - parent_->map_secure_producers.erase(handshake_name_); - - ProducerInterestCallback on_interest_process_decrypted; - getSocketOption(ProducerCallbacksOptions::CACHE_MISS, - on_interest_process_decrypted); - - if (on_interest_process_decrypted) { - Interest inter(std::move(packet_)); - on_interest_process_decrypted(*this, inter); - } else { - throw errors::RuntimeException( - "On interest process unset. Unable to perform handshake"); - } -} - -int TLSProducerSocket::async_accept() { - if (!async_thread_.stopped()) { - async_thread_.add([this]() { this->accept(); }); - } else { - throw errors::RuntimeException( - "Async thread not running, impossible to perform handshake"); - } - - return 1; -} - -void TLSProducerSocket::onInterest(ProducerSocket &p, Interest &interest) { - /* Based on the state machine of (D)TLS, we know what action to do */ - if (SSL_in_before(ssl_) || SSL_in_init(ssl_)) { - std::unique_lock lck(mtx_); - name_ = interest.getName(); - something_to_read_ = true; - packet_ = interest.acquireMemBufReference(); - if (head_) { - payload_->prependChain(interest.getPayload()); - } else { - payload_ = interest.getPayload(); // std::move(interest.getPayload()); - } - cv_.notify_one(); - } else { - name_ = interest.getName(); - packet_ = interest.acquireMemBufReference(); - payload_ = interest.getPayload(); - something_to_read_ = true; - - if (interest.getPayload()->length() > 0) - SSL_read( - ssl_, - const_cast(interest.getPayload()->writableData()), - interest.getPayload()->length()); - } - - ProducerInterestCallback on_interest_input_decrypted; - getSocketOption(ProducerCallbacksOptions::INTEREST_INPUT, - on_interest_input_decrypted); - if (on_interest_input_decrypted) - (on_interest_input_decrypted)(*this, interest); -} - -void TLSProducerSocket::cacheMiss(ProducerSocket &p, Interest &interest) { - if (SSL_in_before(ssl_) || SSL_in_init(ssl_)) { - std::unique_lock lck(mtx_); - name_ = interest.getName(); - something_to_read_ = true; - packet_ = interest.acquireMemBufReference(); - payload_ = interest.getPayload(); - cv_.notify_one(); - } else { - name_ = interest.getName(); - packet_ = interest.acquireMemBufReference(); - payload_ = interest.getPayload(); - something_to_read_ = true; - - if (interest.getPayload()->length() > 0) - SSL_read( - ssl_, - const_cast(interest.getPayload()->writableData()), - interest.getPayload()->length()); - - if (on_interest_process_decrypted_ != VOID_HANDLER) - on_interest_process_decrypted_(*this, interest); - } -} - -void TLSProducerSocket::onContentProduced(ProducerSocket &p, - const std::error_code &err, - uint64_t bytes_written) {} - -uint32_t TLSProducerSocket::produce(Name content_name, - std::unique_ptr &&buffer, - bool is_last, uint32_t start_offset) { - if (SSL_in_before(ssl_) || SSL_in_init(ssl_)) { - throw errors::RuntimeException( - "New handshake on the same P2P secure producer socket not supported"); - } - size_t buf_size = buffer->length(); - name_ = served_namespaces_.front().mapName(content_name); - - tls_chunks_ = to_call_oncontentproduced_ = - ceil((float)buf_size / (float)SSL3_RT_MAX_PLAIN_LENGTH); - - if (!is_last) { - tls_chunks_++; - } - - last_segment_ = start_offset; - - SSL_write(ssl_, buffer->data(), buf_size); - BIO *wbio = SSL_get_wbio(ssl_); - int i = BIO_flush(wbio); - (void)i; // To shut up gcc 5 - - return 0; -} - -void TLSProducerSocket::asyncProduce(const Name &content_name, - const uint8_t *buf, size_t buffer_size, - bool is_last, uint32_t *start_offset) { - if (!encryption_thread_.stopped()) { - encryption_thread_.add([this, content_name, buffer = buf, - size = buffer_size, is_last, start_offset]() { - if (start_offset != NULL) { - produce(content_name, buffer, size, is_last, *start_offset); - } else { - produce(content_name, buffer, size, is_last, 0); - } - }); - } -} - -void TLSProducerSocket::asyncProduce(Name content_name, - std::unique_ptr &&buffer, - bool is_last, uint32_t offset, - uint32_t **last_segment) { - if (!encryption_thread_.stopped()) { - auto a = buffer.release(); - encryption_thread_.add( - [this, content_name, a, is_last, offset, last_segment]() { - auto buf = std::unique_ptr(a); - if (last_segment != NULL) { - *last_segment = &last_segment_; - } - produce(content_name, std::move(buf), is_last, offset); - }); - } -} - -void TLSProducerSocket::asyncProduce(ContentObject &content_object) { - throw errors::RuntimeException("API not supported"); -} - -void TLSProducerSocket::produce(ContentObject &content_object) { - throw errors::RuntimeException("API not supported"); -} - -long TLSProducerSocket::ctrl(BIO *b, int cmd, long num, void *ptr) { - if (cmd == BIO_CTRL_FLUSH) { - } - return 1; -} - -int TLSProducerSocket::addHicnKeyIdCb(SSL *s, unsigned int ext_type, - unsigned int context, - const unsigned char **out, size_t *outlen, - X509 *x, size_t chainidx, int *al, - void *add_arg) { - TLSProducerSocket *socket = reinterpret_cast(add_arg); - if (ext_type == 100) { - ip_prefix_t ip_prefix = - socket->parent_->served_namespaces_.front().toIpPrefixStruct(); - int inet_family = - socket->parent_->served_namespaces_.front().getAddressFamily(); - uint16_t prefix_len_bits = - socket->parent_->served_namespaces_.front().getPrefixLength(); - uint8_t prefix_len_bytes = prefix_len_bits / 8; - uint8_t prefix_len_u32 = prefix_len_bits / 32; - - ip_prefix_t *out_ip = (ip_prefix_t *)malloc(sizeof(ip_prefix_t)); - out_ip->family = inet_family; - out_ip->len = prefix_len_bits + 32; - u8 *out_ip_buf = const_cast( - ip_address_get_buffer(&(out_ip->address), inet_family)); - *out = reinterpret_cast(out_ip); - - RAND_bytes((unsigned char *)&socket->key_id_, 4); - - memcpy(out_ip_buf, ip_address_get_buffer(&(ip_prefix.address), inet_family), - prefix_len_bytes); - memcpy((out_ip_buf + prefix_len_bytes), &socket->key_id_, 4); - *outlen = sizeof(ip_prefix_t); - - ip_address_t mask = {}; - ip_address_t keyId_component = {}; - u32 *mask_buf; - u32 *keyId_component_buf; - switch (inet_family) { - case AF_INET: - mask_buf = &(mask.v4.as_u32); - keyId_component_buf = &(keyId_component.v4.as_u32); - break; - case AF_INET6: - mask_buf = mask.v6.as_u32; - keyId_component_buf = keyId_component.v6.as_u32; - break; - default: - throw errors::RuntimeException("Unknown protocol"); - } - - if (prefix_len_bits > (inet_family == AF_INET6 ? IPV6_ADDR_LEN_BITS - 32 - : IPV4_ADDR_LEN_BITS - 32)) - throw errors::RuntimeException( - "Not enough space in the content name to add key_id"); - - mask_buf[prefix_len_u32] = 0xffffffff; - keyId_component_buf[prefix_len_u32] = socket->key_id_; - socket->last_segment_ = 0; - - socket->on_interest_process_decrypted_ = - socket->parent_->on_interest_process_decrypted_; - - socket->registerPrefix( - Prefix(socket->parent_->served_namespaces_.front().getName( - Name(inet_family, (uint8_t *)&mask), - Name(inet_family, (uint8_t *)&keyId_component), - socket->parent_->served_namespaces_.front().getName()), - out_ip->len)); - socket->connect(); - } - return 1; -} - -void TLSProducerSocket::freeHicnKeyIdCb(SSL *s, unsigned int ext_type, - unsigned int context, - const unsigned char *out, - void *add_arg) { - free(const_cast(out)); -} - -int TLSProducerSocket::parseHicnKeyIdCb(SSL *s, unsigned int ext_type, - unsigned int context, - const unsigned char *in, size_t inlen, - X509 *x, size_t chainidx, int *al, - void *add_arg) { - return 1; -} - -int TLSProducerSocket::setSocketOption( - int socket_option_key, ProducerInterestCallback socket_option_value) { - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ProducerInterestCallback socket_option_value) -> int { - int result = SOCKET_OPTION_SET; - switch (socket_option_key) { - case ProducerCallbacksOptions::INTEREST_INPUT: - on_interest_input_decrypted_ = socket_option_value; - break; - - case ProducerCallbacksOptions::INTEREST_DROP: - on_interest_dropped_input_buffer_ = socket_option_value; - break; - - case ProducerCallbacksOptions::INTEREST_PASS: - on_interest_inserted_input_buffer_ = socket_option_value; - break; - - case ProducerCallbacksOptions::CACHE_HIT: - on_interest_satisfied_output_buffer_ = socket_option_value; - break; - - case ProducerCallbacksOptions::CACHE_MISS: - on_interest_process_decrypted_ = socket_option_value; - break; - - default: - result = SOCKET_OPTION_NOT_SET; - break; - } - return result; - }); -} - -int TLSProducerSocket::setSocketOption( - int socket_option_key, ProducerContentCallback socket_option_value) { - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ProducerContentCallback socket_option_value) -> int { - switch (socket_option_key) { - case ProducerCallbacksOptions::CONTENT_PRODUCED: - on_content_produced_application_ = socket_option_value; - break; - - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; - }); -} - -int TLSProducerSocket::getSocketOption( - int socket_option_key, ProducerContentCallback **socket_option_value) { - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ProducerContentCallback **socket_option_value) -> int { - switch (socket_option_key) { - case ProducerCallbacksOptions::CONTENT_PRODUCED: - *socket_option_value = &on_content_produced_application_; - break; - - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; - }); -} - -int TLSProducerSocket::getSocketOption( - int socket_option_key, ProducerContentCallback &socket_option_value) { - return rescheduleOnIOServiceWithReference( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ProducerContentCallback &socket_option_value) -> int { - switch (socket_option_key) { - case ProducerCallbacksOptions::CONTENT_PRODUCED: - socket_option_value = on_content_produced_application_; - break; - - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; - }); -} - -int TLSProducerSocket::getSocketOption( - int socket_option_key, ProducerInterestCallback &socket_option_value) { - // Reschedule the function on the io_service to avoid race condition in case - // setSocketOption is called while the io_service is running. - return rescheduleOnIOServiceWithReference( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ProducerInterestCallback &socket_option_value) -> int { - switch (socket_option_key) { - case ProducerCallbacksOptions::INTEREST_INPUT: - socket_option_value = on_interest_input_decrypted_; - break; - - case ProducerCallbacksOptions::INTEREST_DROP: - socket_option_value = on_interest_dropped_input_buffer_; - break; - - case ProducerCallbacksOptions::INTEREST_PASS: - socket_option_value = on_interest_inserted_input_buffer_; - break; - - case ProducerCallbacksOptions::CACHE_HIT: - socket_option_value = on_interest_satisfied_output_buffer_; - break; - - case ProducerCallbacksOptions::CACHE_MISS: - socket_option_value = on_interest_process_decrypted_; - break; - - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; - }); -} - -} // namespace interface - -} // namespace transport diff --git a/libtransport/src/hicn/transport/interfaces/tls_socket_producer.h b/libtransport/src/hicn/transport/interfaces/tls_socket_producer.h deleted file mode 100644 index 4c09ddaa5..000000000 --- a/libtransport/src/hicn/transport/interfaces/tls_socket_producer.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include - -#include -#include -#include - -namespace transport { - -namespace interface { - -class P2PSecureProducerSocket; - -class TLSProducerSocket : virtual public ProducerSocket { - friend class P2PSecureProducerSocket; - - public: - explicit TLSProducerSocket(P2PSecureProducerSocket *parent, - const Name &handshake_name); - ~TLSProducerSocket() = default; - - uint32_t produce(Name content_name, const uint8_t *buffer, size_t buffer_size, - bool is_last = true, uint32_t start_offset = 0) override { - return produce(content_name, utils::MemBuf::copyBuffer(buffer, buffer_size), - is_last, start_offset); - } - - uint32_t produce(Name content_name, std::unique_ptr &&buffer, - bool is_last = true, uint32_t start_offset = 0) override; - - void produce(ContentObject &content_object) override; - - void asyncProduce(const Name &suffix, const uint8_t *buf, size_t buffer_size, - bool is_last = true, - uint32_t *start_offset = nullptr) override; - - void asyncProduce(Name content_name, std::unique_ptr &&buffer, - bool is_last, uint32_t offset, - uint32_t **last_segment = nullptr) override; - - void asyncProduce(ContentObject &content_object) override; - - virtual void accept(); - - virtual int async_accept(); - - virtual int setSocketOption( - int socket_option_key, - ProducerInterestCallback socket_option_value) override; - - virtual int setSocketOption( - int socket_option_key, - ProducerContentCallback socket_option_value) override; - - virtual int getSocketOption( - int socket_option_key, - ProducerContentCallback **socket_option_value) override; - - int getSocketOption(int socket_option_key, - ProducerContentCallback &socket_option_value); - - int getSocketOption(int socket_option_key, - ProducerInterestCallback &socket_option_value); - - using ProducerSocket::getSocketOption; - using ProducerSocket::onInterest; - using ProducerSocket::setSocketOption; - - protected: - /* Callback invoked once an interest has been received and its payload - * decrypted */ - ProducerInterestCallback on_interest_input_decrypted_; - ProducerInterestCallback on_interest_process_decrypted_; - ProducerContentCallback on_content_produced_application_; - - std::mutex mtx_; - - /* Condition variable for the wait */ - std::condition_variable cv_; - - /* Bool variable, true if there is something to read (an interest arrived) */ - bool something_to_read_; - - /* First interest that open a secure connection */ - transport::core::Name name_; - - /* SSL handle */ - SSL *ssl_; - SSL_CTX *ctx_; - - Packet::MemBufPtr packet_; - - std::unique_ptr head_; - std::uint32_t last_segment_; - std::shared_ptr payload_; - std::uint32_t key_id_; - - std::thread *handshake; - P2PSecureProducerSocket *parent_; - - bool first_; - Name handshake_name_; - int tls_chunks_; - int to_call_oncontentproduced_; - - bool still_writing_; - - utils::EventThread encryption_thread_; - - void onInterest(ProducerSocket &p, Interest &interest); - void cacheMiss(ProducerSocket &p, Interest &interest); - - /* Return the number of read bytes in readbytes */ - static int read(BIO *b, char *buf, size_t size, size_t *readbytes); - - /* Return the number of read bytes in the return param */ - static int readOld(BIO *h, char *buf, int size); - - /* Return the number of written bytes in written */ - static int write(BIO *b, const char *buf, size_t size, size_t *written); - - /* Return the number of written bytes in the return param */ - static int writeOld(BIO *h, const char *buf, int num); - - static long ctrl(BIO *b, int cmd, long num, void *ptr); - - static int addHicnKeyIdCb(SSL *s, unsigned int ext_type, unsigned int context, - const unsigned char **out, size_t *outlen, X509 *x, - size_t chainidx, int *al, void *add_arg); - - static void freeHicnKeyIdCb(SSL *s, unsigned int ext_type, - unsigned int context, const unsigned char *out, - void *add_arg); - - static int parseHicnKeyIdCb(SSL *s, unsigned int ext_type, - unsigned int context, const unsigned char *in, - size_t inlen, X509 *x, size_t chainidx, int *al, - void *add_arg); - - void onContentProduced(ProducerSocket &p, const std::error_code &err, - uint64_t bytes_written); -}; - -} // namespace interface - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/interfaces/verification_policy.h b/libtransport/src/hicn/transport/interfaces/verification_policy.h deleted file mode 100644 index cb5140ac1..000000000 --- a/libtransport/src/hicn/transport/interfaces/verification_policy.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2020 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 - -namespace transport { -namespace interface { - -/** - * This policy allows the application to tell the transport what to do in case - * the verification of a content object fails. - */ -enum class VerificationPolicy : std::uint8_t { - DROP_PACKET, - ACCEPT_PACKET, - ABORT_SESSION -}; -} // namespace interface -} // namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/portability/CMakeLists.txt b/libtransport/src/hicn/transport/portability/CMakeLists.txt deleted file mode 100644 index 5ad3c8207..000000000 --- a/libtransport/src/hicn/transport/portability/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -# 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) - -list(APPEND HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/c_portability.h - ${CMAKE_CURRENT_SOURCE_DIR}/portability.h -) - -list(APPEND SOURCE_FILES - "" -) - -if(WIN32) - list(APPEND HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/win_portability.h - ) -endif() - -set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) -set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file diff --git a/libtransport/src/hicn/transport/portability/c_portability.h b/libtransport/src/hicn/transport/portability/c_portability.h deleted file mode 100644 index 71e976a81..000000000 --- a/libtransport/src/hicn/transport/portability/c_portability.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Copyright 2017 Facebook, Inc. - * - * 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 - -// noinline -#ifdef _MSC_VER -#define TRANSPORT_NOINLINE __declspec(noinline) -#elif defined(__clang__) || defined(__GNUC__) -#define TRANSPORT_NOINLINE __attribute__((__noinline__)) -#else -#define TRANSPORT_NOINLINE -#endif - -// always inline -#ifdef _MSC_VER -#define TRANSPORT_ALWAYS_INLINE __forceinline -#elif defined(__clang__) || defined(__GNUC__) -#define TRANSPORT_ALWAYS_INLINE inline __attribute__((__always_inline__)) -#else -#define TRANSPORT_ALWAYS_INLINE inline -#endif \ No newline at end of file diff --git a/libtransport/src/hicn/transport/portability/portability.h b/libtransport/src/hicn/transport/portability/portability.h deleted file mode 100644 index 1d97a346e..000000000 --- a/libtransport/src/hicn/transport/portability/portability.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Copyright 2017 Facebook, Inc. - * - * 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 - -#ifdef _WIN32 -#include -#endif - -#include - -#include -#include - -namespace portability { - -constexpr bool little_endian_arch = __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__; -constexpr bool big_endian_arch = !little_endian_arch; - -#if defined(__GNUC__) -#define _TRANSPORT_GNU_DISABLE_WARNING(warning) #warning -#define TRANSPORT_GNU_DISABLE_WARNING(warning) \ - _Pragma(_TRANSPORT_GNU_DISABLE_WARNING(GCC diagnostic ignored warning)) - -#ifdef __clang__ -#define TRANSPORT_CLANG_DISABLE_WARNING(warning) \ - TRANSPORT_GNU_DISABLE_WARNING(warning) -#define TRANSPORT_GCC_DISABLE_WARNING(warning) -#else -#define TRANSPORT_CLANG_DISABLE_WARNING(warning) -#define TRANSPORT_GCC_DISABLE_WARNING(warning) \ - TRANSPORT_GNU_DISABLE_WARNING(warning) -#endif -#endif - -} // namespace portability diff --git a/libtransport/src/hicn/transport/portability/win_portability.h b/libtransport/src/hicn/transport/portability/win_portability.h deleted file mode 100644 index 65d949291..000000000 --- a/libtransport/src/hicn/transport/portability/win_portability.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Copyright 2017 Facebook, Inc. - * - * 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 -#define WIN32_LEAN_AND_MEAN -#define NOMINMAX -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define __ORDER_LITTLE_ENDIAN__ 0x41424344UL -#define __ORDER_BIG_ENDIAN__ 0x44434241UL -#define __BYTE_ORDER__ ('ABCD') -#undef DELETE - -#define HAVE_STRUCT_TIMESPEC -#include \ No newline at end of file diff --git a/libtransport/src/hicn/transport/protocols/CMakeLists.txt b/libtransport/src/hicn/transport/protocols/CMakeLists.txt deleted file mode 100644 index 06515e0e2..000000000 --- a/libtransport/src/hicn/transport/protocols/CMakeLists.txt +++ /dev/null @@ -1,77 +0,0 @@ -# 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) - -list(APPEND HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/indexer.h - ${CMAKE_CURRENT_SOURCE_DIR}/incremental_indexer.h - ${CMAKE_CURRENT_SOURCE_DIR}/manifest_incremental_indexer.h - ${CMAKE_CURRENT_SOURCE_DIR}/reassembly.h - ${CMAKE_CURRENT_SOURCE_DIR}/datagram_reassembly.h - ${CMAKE_CURRENT_SOURCE_DIR}/byte_stream_reassembly.h - ${CMAKE_CURRENT_SOURCE_DIR}/congestion_window_protocol.h - ${CMAKE_CURRENT_SOURCE_DIR}/packet_manager.h - ${CMAKE_CURRENT_SOURCE_DIR}/statistics.h - ${CMAKE_CURRENT_SOURCE_DIR}/rate_estimation.h - ${CMAKE_CURRENT_SOURCE_DIR}/download_observer.h - ${CMAKE_CURRENT_SOURCE_DIR}/protocol.h - ${CMAKE_CURRENT_SOURCE_DIR}/raaqm.h - ${CMAKE_CURRENT_SOURCE_DIR}/raaqm_data_path.h - ${CMAKE_CURRENT_SOURCE_DIR}/cbr.h - ${CMAKE_CURRENT_SOURCE_DIR}/rtc.h - ${CMAKE_CURRENT_SOURCE_DIR}/rtc_data_path.h - ${CMAKE_CURRENT_SOURCE_DIR}/errors.h - ${CMAKE_CURRENT_SOURCE_DIR}/verification_manager.h - ${CMAKE_CURRENT_SOURCE_DIR}/data_processing_events.h -) - -list(APPEND SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/indexer.cc - ${CMAKE_CURRENT_SOURCE_DIR}/incremental_indexer.cc - ${CMAKE_CURRENT_SOURCE_DIR}/manifest_incremental_indexer.cc - ${CMAKE_CURRENT_SOURCE_DIR}/reassembly.cc - ${CMAKE_CURRENT_SOURCE_DIR}/datagram_reassembly.cc - ${CMAKE_CURRENT_SOURCE_DIR}/byte_stream_reassembly.cc - ${CMAKE_CURRENT_SOURCE_DIR}/protocol.cc - ${CMAKE_CURRENT_SOURCE_DIR}/raaqm.cc - ${CMAKE_CURRENT_SOURCE_DIR}/rate_estimation.cc - ${CMAKE_CURRENT_SOURCE_DIR}/raaqm_data_path.cc - ${CMAKE_CURRENT_SOURCE_DIR}/cbr.cc - ${CMAKE_CURRENT_SOURCE_DIR}/rtc.cc - ${CMAKE_CURRENT_SOURCE_DIR}/rtc_data_path.cc - ${CMAKE_CURRENT_SOURCE_DIR}/errors.cc - ${CMAKE_CURRENT_SOURCE_DIR}/verification_manager.cc -) - -set(RAAQM_CONFIG_INSTALL_PREFIX -${CMAKE_INSTALL_PREFIX}/etc/hicn -) - -set(raaqm_config_path - ${RAAQM_CONFIG_INSTALL_PREFIX}/consumer.conf - PARENT_SCOPE -) - -set(TRANSPORT_CONFIG - ${CMAKE_CURRENT_SOURCE_DIR}/consumer.conf -) - -install( - FILES ${TRANSPORT_CONFIG} - DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/hicn - COMPONENT lib${LIBTRANSPORT} -) - -set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) -set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file diff --git a/libtransport/src/hicn/transport/protocols/byte_stream_reassembly.cc b/libtransport/src/hicn/transport/protocols/byte_stream_reassembly.cc deleted file mode 100644 index 2f1e5d8fd..000000000 --- a/libtransport/src/hicn/transport/protocols/byte_stream_reassembly.cc +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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. - */ - -#include - -#include -#include -#include -#include -#include - -namespace transport { - -namespace protocol { - -ByteStreamReassembly::ByteStreamReassembly( - interface::ConsumerSocket *icn_socket, - TransportProtocol *transport_protocol) - : Reassembly(icn_socket, transport_protocol), - index_(IndexManager::invalid_index), - download_complete_(false) {} - -void ByteStreamReassembly::reassemble( - std::unique_ptr &&manifest) { - if (TRANSPORT_EXPECT_TRUE(manifest != nullptr)) { - received_packets_.emplace( - std::make_pair(manifest->getName().getSuffix(), nullptr)); - assembleContent(); - } -} - -void ByteStreamReassembly::reassemble(ContentObject::Ptr &&content_object) { - if (TRANSPORT_EXPECT_TRUE(content_object != nullptr)) { - received_packets_.emplace(std::make_pair( - content_object->getName().getSuffix(), std::move(content_object))); - assembleContent(); - } -} - -void ByteStreamReassembly::assembleContent() { - if (TRANSPORT_EXPECT_FALSE(index_ == IndexManager::invalid_index)) { - index_ = index_manager_->getNextReassemblySegment(); - if (index_ == IndexManager::invalid_index) { - return; - } - } - - auto it = received_packets_.find((const unsigned int)index_); - while (it != received_packets_.end()) { - // Check if valid packet - if (it->second) { - copyContent(*it->second); - } - - received_packets_.erase(it); - index_ = index_manager_->getNextReassemblySegment(); - it = received_packets_.find((const unsigned int)index_); - } - - if (!download_complete_ && index_ != IndexManager::invalid_index) { - transport_protocol_->onReassemblyFailed(index_); - } -} - -void ByteStreamReassembly::copyContent(const ContentObject &content_object) { - auto a = content_object.getPayload(); - auto payload_length = a->length(); - auto write_size = std::min(payload_length, read_buffer_->tailroom()); - auto additional_bytes = payload_length > read_buffer_->tailroom() - ? payload_length - read_buffer_->tailroom() - : 0; - - std::memcpy(read_buffer_->writableTail(), a->data(), write_size); - read_buffer_->append(write_size); - - if (!read_buffer_->tailroom()) { - notifyApplication(); - std::memcpy(read_buffer_->writableTail(), a->data() + write_size, - additional_bytes); - read_buffer_->append(additional_bytes); - } - - download_complete_ = - index_manager_->getFinalSuffix() == content_object.getName().getSuffix(); - - if (TRANSPORT_EXPECT_FALSE(download_complete_)) { - notifyApplication(); - transport_protocol_->onContentReassembled( - make_error_code(protocol_error::success)); - } -} - -void ByteStreamReassembly::reInitialize() { - index_ = IndexManager::invalid_index; - download_complete_ = false; - - received_packets_.clear(); - - // reset read buffer - interface::ConsumerSocket::ReadCallback *read_callback; - reassembly_consumer_socket_->getSocketOption( - interface::ConsumerCallbacksOptions::READ_CALLBACK, &read_callback); - - read_buffer_ = utils::MemBuf::create(read_callback->maxBufferSize()); -} - -} // namespace protocol - -} // namespace transport diff --git a/libtransport/src/hicn/transport/protocols/byte_stream_reassembly.h b/libtransport/src/hicn/transport/protocols/byte_stream_reassembly.h deleted file mode 100644 index 7c77d486f..000000000 --- a/libtransport/src/hicn/transport/protocols/byte_stream_reassembly.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -namespace transport { - -namespace protocol { - -class ByteStreamReassembly : public Reassembly { - public: - ByteStreamReassembly(interface::ConsumerSocket *icn_socket, - TransportProtocol *transport_protocol); - - protected: - virtual void reassemble(core::ContentObject::Ptr &&content_object) override; - - virtual void reassemble( - std::unique_ptr &&manifest) override; - - virtual void copyContent(const core::ContentObject &content_object); - - virtual void reInitialize() override; - - private: - void assembleContent(); - - protected: - // The consumer socket - // std::unique_ptr incremental_index_manager_; - // std::unique_ptr manifest_index_manager_; - // IndexVerificationManager *index_manager_; - std::unordered_map received_packets_; - uint32_t index_; - bool download_complete_; -}; - -} // namespace protocol - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/protocols/cbr.cc b/libtransport/src/hicn/transport/protocols/cbr.cc deleted file mode 100644 index 02bc7b5e4..000000000 --- a/libtransport/src/hicn/transport/protocols/cbr.cc +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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. - */ - -#include -#include - -namespace transport { - -namespace protocol { - -using namespace interface; - -CbrTransportProtocol::CbrTransportProtocol( - interface::ConsumerSocket *icnet_socket) - : RaaqmTransportProtocol(icnet_socket) {} - -int CbrTransportProtocol::start() { return RaaqmTransportProtocol::start(); } - -void CbrTransportProtocol::reset() { - RaaqmTransportProtocol::reset(); - socket_->getSocketOption(GeneralTransportOptions::CURRENT_WINDOW_SIZE, - current_window_size_); -} - -void CbrTransportProtocol::afterDataUnsatisfied(uint64_t segment) {} - -void CbrTransportProtocol::afterContentReception( - const Interest &interest, const ContentObject &content_object) { - auto segment = content_object.getName().getSuffix(); - auto now = utils::SteadyClock::now(); - auto rtt = std::chrono::duration_cast( - now - interest_timepoints_[segment & mask]); - // Update stats - updateStats(segment, rtt.count(), now); -} - -} // end namespace protocol - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/protocols/cbr.h b/libtransport/src/hicn/transport/protocols/cbr.h deleted file mode 100644 index e80da14f5..000000000 --- a/libtransport/src/hicn/transport/protocols/cbr.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -namespace transport { - -namespace protocol { - -class CbrTransportProtocol : public RaaqmTransportProtocol { - public: - CbrTransportProtocol(interface::ConsumerSocket *icnet_socket); - - int start() override; - - void reset() override; - - private: - void afterContentReception(const Interest &interest, - const ContentObject &content_object) override; - void afterDataUnsatisfied(uint64_t segment) override; -}; - -} // end namespace protocol - -} // end namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/protocols/congestion_window_protocol.h b/libtransport/src/hicn/transport/protocols/congestion_window_protocol.h deleted file mode 100644 index 36ac6eb17..000000000 --- a/libtransport/src/hicn/transport/protocols/congestion_window_protocol.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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. - */ - -#pragma once - -namespace transport { - -namespace protocol { - -class CWindowProtocol { - protected: - virtual void increaseWindow() = 0; - virtual void decreaseWindow() = 0; -}; - -} // end namespace protocol - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/protocols/consumer.conf b/libtransport/src/hicn/transport/protocols/consumer.conf deleted file mode 100644 index 1a366f32f..000000000 --- a/libtransport/src/hicn/transport/protocols/consumer.conf +++ /dev/null @@ -1,21 +0,0 @@ -; this file contais the parameters for RAAQM -autotune = no -lifetime = 500 -retransmissions = 128 -beta = 0.99 -drop = 0.003 -beta_wifi_ = 0.99 -drop_wifi_ = 0.6 -beta_lte_ = 0.99 -drop_lte_ = 0.003 -wifi_delay_ = 200 -lte_delay_ = 9000 - -alpha = 0.95 -batching_parameter = 200 - -;Choice of rate estimator: -;0 --> an estimation each $(batching_parameter) packets -;1 --> an estimation "a la TCP", estimation at the end of the download of the segment - -rate_estimator = 0 diff --git a/libtransport/src/hicn/transport/protocols/data_processing_events.h b/libtransport/src/hicn/transport/protocols/data_processing_events.h deleted file mode 100644 index 8975c2b4a..000000000 --- a/libtransport/src/hicn/transport/protocols/data_processing_events.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include - -namespace transport { -namespace protocol { - -class ContentObjectProcessingEventCallback { - public: - virtual ~ContentObjectProcessingEventCallback() = default; - virtual void onPacketDropped(core::Interest::Ptr &&i, - core::ContentObject::Ptr &&c) = 0; - virtual void onReassemblyFailed(std::uint32_t missing_segment) = 0; -}; - -} // namespace protocol -} // namespace transport diff --git a/libtransport/src/hicn/transport/protocols/datagram_reassembly.cc b/libtransport/src/hicn/transport/protocols/datagram_reassembly.cc deleted file mode 100644 index 7b01ad4bc..000000000 --- a/libtransport/src/hicn/transport/protocols/datagram_reassembly.cc +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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. - */ - -#include - -namespace transport { - -namespace protocol { - -DatagramReassembly::DatagramReassembly(interface::ConsumerSocket* icn_socket, - TransportProtocol* transport_protocol) - : Reassembly(icn_socket, transport_protocol) {} - -void DatagramReassembly::reassemble(core::ContentObject::Ptr&& content_object) { - read_buffer_ = content_object->getPayload(); - Reassembly::notifyApplication(); -} - -void DatagramReassembly::reInitialize() {} - -} // namespace protocol - -} // namespace transport diff --git a/libtransport/src/hicn/transport/protocols/datagram_reassembly.h b/libtransport/src/hicn/transport/protocols/datagram_reassembly.h deleted file mode 100644 index 923b6f2c1..000000000 --- a/libtransport/src/hicn/transport/protocols/datagram_reassembly.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -namespace transport { - -namespace protocol { - -class DatagramReassembly : public Reassembly { - public: - DatagramReassembly(interface::ConsumerSocket *icn_socket, - TransportProtocol *transport_protocol); - - virtual void reassemble(core::ContentObject::Ptr &&content_object) override; - virtual void reInitialize() override; - virtual void reassemble( - std::unique_ptr &&manifest) override { - return; - } -}; - -} // namespace protocol - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/protocols/download_observer.h b/libtransport/src/hicn/transport/protocols/download_observer.h deleted file mode 100644 index 6d24fe6fd..000000000 --- a/libtransport/src/hicn/transport/protocols/download_observer.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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. - */ - -#pragma once - -namespace transport { - -namespace protocol { - -class IcnObserver { - public: - virtual ~IcnObserver(){}; - - virtual void notifyStats(double throughput) = 0; - virtual void notifyDownloadTime(double downloadTime) = 0; -}; - -} // end namespace protocol - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/protocols/errors.cc b/libtransport/src/hicn/transport/protocols/errors.cc deleted file mode 100644 index c2249ed4a..000000000 --- a/libtransport/src/hicn/transport/protocols/errors.cc +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2020 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 - -namespace transport { -namespace protocol { - -const std::error_category& protocol_category() { - static protocol_category_impl instance; - - return instance; -} - -const char* protocol_category_impl::name() const throw() { - return "transport::protocol::error"; -} - -std::string protocol_category_impl::message(int ev) const { - switch (static_cast(ev)) { - case protocol_error::success: { - return "Success"; - } - case protocol_error::signature_verification_failed: { - return "Signature verification failed."; - } - case protocol_error::integrity_verification_failed: { - return "Integrity verification failed"; - } - case protocol_error::no_verifier_provided: { - return "Transport cannot get any verifier for the given data."; - } - case protocol_error::io_error: { - return "Conectivity error between transport and local forwarder"; - } - case protocol_error::max_retransmissions_error: { - return "Transport protocol reached max number of retransmissions allowed " - "for the same interest."; - } - case protocol_error::session_aborted: { - return "The session has been aborted by the application."; - } - default: { return "Unknown protocol error"; } - } -} - -} // namespace protocol -} // namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/protocols/errors.h b/libtransport/src/hicn/transport/protocols/errors.h deleted file mode 100644 index cb3d3474e..000000000 --- a/libtransport/src/hicn/transport/protocols/errors.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2020 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 -#include - -namespace transport { -namespace protocol { - -/** - * @brief Get the default server error category. - * @return The default server error category instance. - * - * @warning The first call to this function is thread-safe only starting with - * C++11. - */ -const std::error_category& protocol_category(); - -/** - * The list of errors. - */ -enum class protocol_error { - success = 0, - signature_verification_failed, - integrity_verification_failed, - no_verifier_provided, - io_error, - max_retransmissions_error, - session_aborted, -}; - -/** - * @brief Create an error_code instance for the given error. - * @param error The error. - * @return The error_code instance. - */ -inline std::error_code make_error_code(protocol_error error) { - return std::error_code(static_cast(error), protocol_category()); -} - -/** - * @brief Create an error_condition instance for the given error. - * @param error The error. - * @return The error_condition instance. - */ -inline std::error_condition make_error_condition(protocol_error error) { - return std::error_condition(static_cast(error), protocol_category()); -} - -/** - * @brief A server error category. - */ -class protocol_category_impl : public std::error_category { - public: - /** - * @brief Get the name of the category. - * @return The name of the category. - */ - virtual const char* name() const throw(); - - /** - * @brief Get the error message for a given error. - * @param ev The error numeric value. - * @return The message associated to the error. - */ - virtual std::string message(int ev) const; -}; -} // namespace protocol -} // namespace transport - -namespace std { -// namespace system { -template <> -struct is_error_code_enum<::transport::protocol::protocol_error> - : public std::true_type {}; -// } // namespace system -} // namespace std \ No newline at end of file diff --git a/libtransport/src/hicn/transport/protocols/incremental_indexer.cc b/libtransport/src/hicn/transport/protocols/incremental_indexer.cc deleted file mode 100644 index 5a8046daa..000000000 --- a/libtransport/src/hicn/transport/protocols/incremental_indexer.cc +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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. - */ - -#include - -#include - -namespace transport { -namespace protocol { - -void IncrementalIndexer::onContentObject( - core::Interest::Ptr &&interest, core::ContentObject::Ptr &&content_object) { - using namespace interface; - - if (TRANSPORT_EXPECT_FALSE(content_object->testRst())) { - final_suffix_ = content_object->getName().getSuffix(); - } - - auto ret = verification_manager_->onPacketToVerify(*content_object); - - switch (ret) { - case VerificationPolicy::ACCEPT_PACKET: { - reassembly_->reassemble(std::move(content_object)); - break; - } - case VerificationPolicy::DROP_PACKET: { - transport_protocol_->onPacketDropped(std::move(interest), - std::move(content_object)); - break; - } - case VerificationPolicy::ABORT_SESSION: { - transport_protocol_->onContentReassembled( - make_error_code(protocol_error::session_aborted)); - break; - } - } -} - -} // namespace protocol -} // namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/protocols/incremental_indexer.h b/libtransport/src/hicn/transport/protocols/incremental_indexer.h deleted file mode 100644 index b587a8332..000000000 --- a/libtransport/src/hicn/transport/protocols/incremental_indexer.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -#include -#include -#include -#include -#include - -#include - -namespace transport { - -namespace interface { -class ConsumerSocket; -} - -namespace protocol { - -class Reassembly; -class TransportProtocol; - -class IncrementalIndexer : public Indexer { - public: - IncrementalIndexer(interface::ConsumerSocket *icn_socket, - TransportProtocol *transport, Reassembly *reassembly) - : socket_(icn_socket), - reassembly_(reassembly), - transport_protocol_(transport), - final_suffix_(std::numeric_limits::max()), - first_suffix_(0), - next_download_suffix_(0), - next_reassembly_suffix_(0), - verification_manager_( - std::make_unique(icn_socket)) { - if (reassembly_) { - reassembly_->setIndexer(this); - } - } - - IncrementalIndexer(const IncrementalIndexer &) = delete; - - IncrementalIndexer(IncrementalIndexer &&other) - : socket_(other.socket_), - reassembly_(other.reassembly_), - transport_protocol_(other.transport_protocol_), - final_suffix_(other.final_suffix_), - first_suffix_(other.first_suffix_), - next_download_suffix_(other.next_download_suffix_), - next_reassembly_suffix_(other.next_reassembly_suffix_), - verification_manager_(std::move(other.verification_manager_)) { - if (reassembly_) { - reassembly_->setIndexer(this); - } - } - - /** - * - */ - virtual ~IncrementalIndexer() {} - - TRANSPORT_ALWAYS_INLINE virtual void reset( - std::uint32_t offset = 0) override { - final_suffix_ = std::numeric_limits::max(); - next_download_suffix_ = offset; - next_reassembly_suffix_ = offset; - } - - /** - * Retrieve from the manifest the next suffix to retrieve. - */ - TRANSPORT_ALWAYS_INLINE virtual uint32_t getNextSuffix() override { - return next_download_suffix_ <= final_suffix_ ? next_download_suffix_++ - : IndexManager::invalid_index; - } - - TRANSPORT_ALWAYS_INLINE virtual void setFirstSuffix( - uint32_t suffix) override { - first_suffix_ = suffix; - } - - /** - * Retrive the next segment to be reassembled. - */ - TRANSPORT_ALWAYS_INLINE virtual uint32_t getNextReassemblySegment() override { - return next_reassembly_suffix_ <= final_suffix_ - ? next_reassembly_suffix_++ - : IndexManager::invalid_index; - } - - TRANSPORT_ALWAYS_INLINE virtual bool isFinalSuffixDiscovered() override { - return final_suffix_ != std::numeric_limits::max(); - } - - TRANSPORT_ALWAYS_INLINE virtual uint32_t getFinalSuffix() override { - return final_suffix_; - } - - void onContentObject(core::Interest::Ptr &&interest, - core::ContentObject::Ptr &&content_object) override; - - TRANSPORT_ALWAYS_INLINE void setReassembly(Reassembly *reassembly) { - reassembly_ = reassembly; - - if (reassembly_) { - reassembly_->setIndexer(this); - } - } - - TRANSPORT_ALWAYS_INLINE bool onKeyToVerify() override { - return verification_manager_->onKeyToVerify(); - } - - protected: - interface::ConsumerSocket *socket_; - Reassembly *reassembly_; - TransportProtocol *transport_protocol_; - uint32_t final_suffix_; - uint32_t first_suffix_; - uint32_t next_download_suffix_; - uint32_t next_reassembly_suffix_; - std::unique_ptr verification_manager_; -}; - -} // end namespace protocol - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/protocols/indexer.cc b/libtransport/src/hicn/transport/protocols/indexer.cc deleted file mode 100644 index d95c10ff9..000000000 --- a/libtransport/src/hicn/transport/protocols/indexer.cc +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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. - */ - -#include - -#include -#include -#include -#include - -namespace transport { -namespace protocol { - -IndexManager::IndexManager(interface::ConsumerSocket *icn_socket, - TransportProtocol *transport, Reassembly *reassembly) - : indexer_(std::make_unique(icn_socket, transport, - reassembly)), - first_segment_received_(false), - icn_socket_(icn_socket), - transport_(transport), - reassembly_(reassembly) {} - -void IndexManager::onContentObject(core::Interest::Ptr &&interest, - core::ContentObject::Ptr &&content_object) { - if (first_segment_received_) { - indexer_->onContentObject(std::move(interest), std::move(content_object)); - } else { - std::uint32_t segment_number = interest->getName().getSuffix(); - - if (segment_number == 0) { - // Check if manifest - if (content_object->getPayloadType() == PayloadType::MANIFEST) { - IncrementalIndexer *indexer = - static_cast(indexer_.release()); - indexer_ = - std::make_unique(std::move(*indexer)); - delete indexer; - } - - indexer_->onContentObject(std::move(interest), std::move(content_object)); - auto it = interest_data_set_.begin(); - while (it != interest_data_set_.end()) { - indexer_->onContentObject(std::move(const_cast(it->first)), std::move(const_cast(it->second))); - it = interest_data_set_.erase(it); - } - - first_segment_received_ = true; - } else { - interest_data_set_.emplace(std::move(interest), std::move(content_object)); - } - } -} - -bool IndexManager::onKeyToVerify() { - return indexer_->onKeyToVerify(); -} - -void IndexManager::reset(std::uint32_t offset) { - indexer_ = std::make_unique(icn_socket_, transport_, - reassembly_); - first_segment_received_ = false; - interest_data_set_.clear(); -} - -} // namespace protocol -} // namespace transport diff --git a/libtransport/src/hicn/transport/protocols/indexer.h b/libtransport/src/hicn/transport/protocols/indexer.h deleted file mode 100644 index 87cf9b307..000000000 --- a/libtransport/src/hicn/transport/protocols/indexer.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include - -#include - -namespace transport { - -namespace interface { -class ConsumerSocket; -} - -namespace protocol { - -class Reassembly; -class TransportProtocol; - -class Indexer { - public: - /** - * - */ - virtual ~Indexer() = default; - /** - * Retrieve from the manifest the next suffix to retrieve. - */ - virtual uint32_t getNextSuffix() = 0; - - virtual void setFirstSuffix(uint32_t suffix) = 0; - - /** - * Retrive the next segment to be reassembled. - */ - virtual uint32_t getNextReassemblySegment() = 0; - - virtual bool isFinalSuffixDiscovered() = 0; - - virtual uint32_t getFinalSuffix() = 0; - - virtual void reset(std::uint32_t offset = 0) = 0; - - virtual void onContentObject(core::Interest::Ptr &&interest, - core::ContentObject::Ptr &&content_object) = 0; - - virtual bool onKeyToVerify() = 0; -}; - -class IndexManager : Indexer { - public: - static constexpr uint32_t invalid_index = ~0; - - IndexManager(interface::ConsumerSocket *icn_socket, - TransportProtocol *transport, Reassembly *reassembly); - - uint32_t getNextSuffix() override { return indexer_->getNextSuffix(); } - - void setFirstSuffix(uint32_t suffix) override { - indexer_->setFirstSuffix(suffix); - } - - uint32_t getNextReassemblySegment() override { - return indexer_->getNextReassemblySegment(); - } - - bool isFinalSuffixDiscovered() override { - return indexer_->isFinalSuffixDiscovered(); - } - - uint32_t getFinalSuffix() override { return indexer_->getFinalSuffix(); } - - void reset(std::uint32_t offset = 0) override; - - void onContentObject(core::Interest::Ptr &&interest, - core::ContentObject::Ptr &&content_object) override; - - bool onKeyToVerify() override; - - private: - std::unique_ptr indexer_; - bool first_segment_received_; - std::set> - interest_data_set_; - interface::ConsumerSocket *icn_socket_; - TransportProtocol *transport_; - Reassembly *reassembly_; -}; - -} // end namespace protocol - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/protocols/manifest_incremental_indexer.cc b/libtransport/src/hicn/transport/protocols/manifest_incremental_indexer.cc deleted file mode 100644 index 592daa4d4..000000000 --- a/libtransport/src/hicn/transport/protocols/manifest_incremental_indexer.cc +++ /dev/null @@ -1,232 +0,0 @@ -/* - * 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. - */ - -#include -#include - -#include -#include - -namespace transport { - -namespace protocol { - -using namespace interface; - -ManifestIncrementalIndexer::ManifestIncrementalIndexer( - interface::ConsumerSocket *icn_socket, TransportProtocol *transport, - Reassembly *reassembly) - : IncrementalIndexer(icn_socket, transport, reassembly), - suffix_strategy_(utils::SuffixStrategyFactory::getSuffixStrategy( - NextSegmentCalculationStrategy::INCREMENTAL, - next_download_suffix_, 0)) {} - -void ManifestIncrementalIndexer::onContentObject( - core::Interest::Ptr &&interest, core::ContentObject::Ptr &&content_object) { - // Check if mainfiest or not - if (content_object->getPayloadType() == PayloadType::MANIFEST) { - onUntrustedManifest(std::move(interest), std::move(content_object)); - } else if (content_object->getPayloadType() == PayloadType::CONTENT_OBJECT) { - onUntrustedContentObject(std::move(interest), std::move(content_object)); - } -} - -void ManifestIncrementalIndexer::onUntrustedManifest( - core::Interest::Ptr &&interest, core::ContentObject::Ptr &&content_object) { - auto ret = verification_manager_->onPacketToVerify(*content_object); - - switch (ret) { - case VerificationPolicy::ACCEPT_PACKET: { - processTrustedManifest(std::move(content_object)); - break; - } - case VerificationPolicy::DROP_PACKET: - case VerificationPolicy::ABORT_SESSION: { - transport_protocol_->onContentReassembled( - make_error_code(protocol_error::session_aborted)); - break; - } - } -} - -void ManifestIncrementalIndexer::processTrustedManifest( - ContentObject::Ptr &&content_object) { - auto manifest = - std::make_unique(std::move(*content_object)); - manifest->decode(); - - if (TRANSPORT_EXPECT_FALSE(manifest->getVersion() != - core::ManifestVersion::VERSION_1)) { - throw errors::RuntimeException("Received manifest with unknown version."); - } - - switch (manifest->getManifestType()) { - case core::ManifestType::INLINE_MANIFEST: { - auto _it = manifest->getSuffixList().begin(); - auto _end = manifest->getSuffixList().end(); - - suffix_strategy_->setFinalSuffix(manifest->getFinalBlockNumber()); - - for (; _it != _end; _it++) { - auto hash = - std::make_pair(std::vector(_it->second, _it->second + 32), - manifest->getHashAlgorithm()); - - if (!checkUnverifiedSegments(_it->first, hash)) { - suffix_hash_map_[_it->first] = std::move(hash); - } - } - - reassembly_->reassemble(std::move(manifest)); - - break; - } - case core::ManifestType::FLIC_MANIFEST: { - throw errors::NotImplementedException(); - } - case core::ManifestType::FINAL_CHUNK_NUMBER: { - throw errors::NotImplementedException(); - } - } -} - -bool ManifestIncrementalIndexer::checkUnverifiedSegments( - std::uint32_t suffix, const HashEntry &hash) { - auto it = unverified_segments_.find(suffix); - - if (it != unverified_segments_.end()) { - auto ret = verifyContentObject(hash, *it->second.second); - - switch (ret) { - case VerificationPolicy::ACCEPT_PACKET: { - reassembly_->reassemble(std::move(it->second.second)); - break; - } - case VerificationPolicy::DROP_PACKET: { - transport_protocol_->onPacketDropped(std::move(it->second.first), - std::move(it->second.second)); - break; - } - case VerificationPolicy::ABORT_SESSION: { - transport_protocol_->onContentReassembled( - make_error_code(protocol_error::session_aborted)); - break; - } - } - - unverified_segments_.erase(it); - return true; - } - - return false; -} - -VerificationPolicy ManifestIncrementalIndexer::verifyContentObject( - const HashEntry &manifest_hash, const ContentObject &content_object) { - VerificationPolicy ret; - - auto hash_type = static_cast(manifest_hash.second); - auto data_packet_digest = content_object.computeDigest(manifest_hash.second); - auto data_packet_digest_bytes = - data_packet_digest.getDigest().data(); - const std::vector &manifest_digest_bytes = manifest_hash.first; - - if (utils::CryptoHash::compareBinaryDigest( - data_packet_digest_bytes, manifest_digest_bytes.data(), hash_type)) { - ret = VerificationPolicy::ACCEPT_PACKET; - } else { - ConsumerContentObjectVerificationFailedCallback - *verification_failed_callback = VOID_HANDLER; - socket_->getSocketOption(ConsumerCallbacksOptions::VERIFICATION_FAILED, - &verification_failed_callback); - ret = (*verification_failed_callback)( - *socket_, content_object, - make_error_code(protocol_error::integrity_verification_failed)); - } - - return ret; -} - -void ManifestIncrementalIndexer::onUntrustedContentObject( - Interest::Ptr &&i, ContentObject::Ptr &&c) { - auto suffix = c->getName().getSuffix(); - auto it = suffix_hash_map_.find(suffix); - - if (it != suffix_hash_map_.end()) { - auto ret = verifyContentObject(it->second, *c); - - switch (ret) { - case VerificationPolicy::ACCEPT_PACKET: { - suffix_hash_map_.erase(it); - reassembly_->reassemble(std::move(c)); - break; - } - case VerificationPolicy::DROP_PACKET: { - transport_protocol_->onPacketDropped(std::move(i), std::move(c)); - break; - } - case VerificationPolicy::ABORT_SESSION: { - transport_protocol_->onContentReassembled( - make_error_code(protocol_error::session_aborted)); - break; - } - } - } else { - unverified_segments_[suffix] = std::make_pair(std::move(i), std::move(c)); - } -} - -uint32_t ManifestIncrementalIndexer::getNextSuffix() { - auto ret = suffix_strategy_->getNextSuffix(); - - if (ret <= suffix_strategy_->getFinalSuffix() && - ret != utils::SuffixStrategy::INVALID_SUFFIX) { - suffix_queue_.push(ret); - return ret; - } - - return IndexManager::invalid_index; -} - -uint32_t ManifestIncrementalIndexer::getFinalSuffix() { - return suffix_strategy_->getFinalSuffix(); -} - -bool ManifestIncrementalIndexer::isFinalSuffixDiscovered() { - return IncrementalIndexer::isFinalSuffixDiscovered(); -} - -uint32_t ManifestIncrementalIndexer::getNextReassemblySegment() { - if (suffix_queue_.empty()) { - return IndexManager::invalid_index; - } - - auto ret = suffix_queue_.front(); - suffix_queue_.pop(); - return ret; -} - -void ManifestIncrementalIndexer::reset(std::uint32_t offset) { - IncrementalIndexer::reset(offset); - suffix_hash_map_.clear(); - unverified_segments_.clear(); - SuffixQueue empty; - std::swap(suffix_queue_, empty); - suffix_strategy_->reset(offset); -} - -} // namespace protocol - -} // namespace transport diff --git a/libtransport/src/hicn/transport/protocols/manifest_incremental_indexer.h b/libtransport/src/hicn/transport/protocols/manifest_incremental_indexer.h deleted file mode 100644 index 6e991f86f..000000000 --- a/libtransport/src/hicn/transport/protocols/manifest_incremental_indexer.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include - -#include - -namespace transport { - -namespace protocol { - -class ManifestIncrementalIndexer : public IncrementalIndexer { - static constexpr double alpha = 0.3; - - public: - using SuffixQueue = std::queue; - using HashEntry = std::pair, core::HashAlgorithm>; - - ManifestIncrementalIndexer(interface::ConsumerSocket *icn_socket, - TransportProtocol *transport, Reassembly *reassembly); - - ManifestIncrementalIndexer(IncrementalIndexer &&indexer) - : IncrementalIndexer(std::move(indexer)), - suffix_strategy_(utils::SuffixStrategyFactory::getSuffixStrategy( - core::NextSegmentCalculationStrategy::INCREMENTAL, - next_download_suffix_, 0)) { - for (uint32_t i = first_suffix_; i < next_download_suffix_; i++) { - suffix_queue_.push(i); - } - } - - virtual ~ManifestIncrementalIndexer() = default; - - void reset(std::uint32_t offset = 0) override; - - void onContentObject(core::Interest::Ptr &&interest, - core::ContentObject::Ptr &&content_object) override; - - uint32_t getNextSuffix() override; - - uint32_t getNextReassemblySegment() override; - - bool isFinalSuffixDiscovered() override; - - uint32_t getFinalSuffix() override; - - private: - void onUntrustedManifest(core::Interest::Ptr &&interest, - core::ContentObject::Ptr &&content_object); - void onUntrustedContentObject(core::Interest::Ptr &&interest, - core::ContentObject::Ptr &&content_object); - void processTrustedManifest(core::ContentObject::Ptr &&content_object); - void onManifestReceived(core::Interest::Ptr &&i, - core::ContentObject::Ptr &&c); - void onManifestTimeout(core::Interest::Ptr &&i); - VerificationPolicy verifyContentObject( - const HashEntry &manifest_hash, - const core::ContentObject &content_object); - bool checkUnverifiedSegments(std::uint32_t suffix, const HashEntry &hash); - - protected: - std::unique_ptr suffix_strategy_; - SuffixQueue suffix_queue_; - - // Hash verification - std::unordered_map suffix_hash_map_; - - std::unordered_map> - unverified_segments_; -}; - -} // end namespace protocol - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/protocols/manifest_indexing_manager.cc b/libtransport/src/hicn/transport/protocols/manifest_indexing_manager.cc deleted file mode 100644 index 5bf9c89f7..000000000 --- a/libtransport/src/hicn/transport/protocols/manifest_indexing_manager.cc +++ /dev/null @@ -1,297 +0,0 @@ -/* - * 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. - */ - -#include -#include - -#include -#include - -namespace transport { - -namespace protocol { - -using namespace interface; - -ManifestIndexManager::ManifestIndexManager( - interface::ConsumerSocket *icn_socket, TransportProtocol *next_interest) - : IncrementalIndexManager(icn_socket), - PacketManager(1024), - next_to_retrieve_segment_(suffix_queue_.end()), - suffix_manifest_(core::NextSegmentCalculationStrategy::INCREMENTAL, 0), - next_reassembly_segment_( - core::NextSegmentCalculationStrategy::INCREMENTAL, 1, true), - ignored_segments_(), - next_interest_(next_interest) {} - -bool ManifestIndexManager::onManifest( - core::ContentObject::Ptr &&content_object) { - auto manifest = - std::make_unique(std::move(*content_object)); - bool manifest_verified = verification_manager_->onPacketToVerify(*manifest); - - if (manifest_verified) { - manifest->decode(); - - if (TRANSPORT_EXPECT_FALSE(manifest->getVersion() != - core::ManifestVersion::VERSION_1)) { - throw errors::RuntimeException("Received manifest with unknown version."); - } - - switch (manifest->getManifestType()) { - case core::ManifestType::INLINE_MANIFEST: { - auto _it = manifest->getSuffixList().begin(); - auto _end = manifest->getSuffixList().end(); - size_t nb_segments = std::distance(_it, _end); - final_suffix_ = manifest->getFinalBlockNumber(); // final block number - - TRANSPORT_LOGD("Received manifest %u", - manifest->getWritableName().getSuffix()); - suffix_hash_map_[_it->first] = - std::make_pair(std::vector(_it->second, _it->second + 32), - manifest->getHashAlgorithm()); - suffix_queue_.push_back(_it->first); - - // If the transport protocol finished the list of segments to retrieve, - // reset the next_to_retrieve_segment_ iterator to the next segment - // provided by this manifest. - if (TRANSPORT_EXPECT_FALSE(next_to_retrieve_segment_ == - suffix_queue_.end())) { - next_to_retrieve_segment_ = --suffix_queue_.end(); - } - - std::advance(_it, 1); - for (; _it != _end; _it++) { - suffix_hash_map_[_it->first] = std::make_pair( - std::vector(_it->second, _it->second + 32), - manifest->getHashAlgorithm()); - suffix_queue_.push_back(_it->first); - } - - if (TRANSPORT_EXPECT_FALSE(manifest->getName().getSuffix()) == 0) { - core::NextSegmentCalculationStrategy strategy = - manifest->getNextSegmentCalculationStrategy(); - - suffix_manifest_.reset(0); - suffix_manifest_.setNbSegments(nb_segments); - suffix_manifest_.setSuffixStrategy(strategy); - TRANSPORT_LOGD("Capacity of 1st manifest %zu", - suffix_manifest_.getNbSegments()); - - next_reassembly_segment_.reset(*suffix_queue_.begin()); - next_reassembly_segment_.setNbSegments(nb_segments); - suffix_manifest_.setSuffixStrategy(strategy); - } - - // If the manifest is not full, we add the suffixes of missing segments - // to the list of segments to ignore when computing the next reassembly - // index. - if (TRANSPORT_EXPECT_FALSE( - suffix_manifest_.getNbSegments() - nb_segments > 0)) { - auto start = manifest->getSuffixList().begin(); - auto last = --_end; - for (uint32_t i = last->first + 1; - i < start->first + suffix_manifest_.getNbSegments(); i++) { - ignored_segments_.push_back(i); - } - } - - if (TRANSPORT_EXPECT_FALSE(manifest->isFinalManifest()) == 0) { - fillWindow(manifest->getWritableName(), - manifest->getName().getSuffix()); - } - - break; - } - case core::ManifestType::FLIC_MANIFEST: { - throw errors::NotImplementedException(); - } - case core::ManifestType::FINAL_CHUNK_NUMBER: { - throw errors::NotImplementedException(); - } - } - } - - return manifest_verified; -} - -void ManifestIndexManager::onManifestReceived(Interest::Ptr &&i, - ContentObject::Ptr &&c) { - onManifest(std::move(c)); - if (next_interest_) { - next_interest_->scheduleNextInterests(); - } -} - -void ManifestIndexManager::onManifestTimeout(Interest::Ptr &&i) { - const Name &n = i->getName(); - uint32_t segment = n.getSuffix(); - - if (segment > final_suffix_) { - return; - } - - TRANSPORT_LOGD("Timeout on manifest %u", segment); - // Get portal - std::shared_ptr portal; - socket_->getSocketOption(GeneralTransportOptions::PORTAL, portal); - - // Send requests for manifest out of the congestion window (no - // in_flight_interests++) - portal->sendInterest( - std::move(i), - std::bind(&ManifestIndexManager::onManifestReceived, this, - std::placeholders::_1, std::placeholders::_2), - std::bind(&ManifestIndexManager::onManifestTimeout, this, - std::placeholders::_1)); -} - -void ManifestIndexManager::fillWindow(Name &name, uint32_t current_manifest) { - /* Send as many manifest as required for filling window. */ - uint32_t interest_lifetime; - double window_size; - std::shared_ptr portal; - Interest::Ptr interest; - uint32_t current_segment = *next_to_retrieve_segment_; - // suffix_manifest_ now points to the next manifest to request - uint32_t last_requested_manifest = (suffix_manifest_++).getSuffix(); - - socket_->getSocketOption(GeneralTransportOptions::PORTAL, portal); - socket_->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, - interest_lifetime); - socket_->getSocketOption(GeneralTransportOptions::CURRENT_WINDOW_SIZE, - window_size); - - if (TRANSPORT_EXPECT_FALSE(suffix_manifest_.getSuffix() >= final_suffix_)) { - suffix_manifest_.updateSuffix(last_requested_manifest); - return; - } - - if (current_segment + window_size < suffix_manifest_.getSuffix() && - current_manifest != last_requested_manifest) { - suffix_manifest_.updateSuffix(last_requested_manifest); - return; - } - - do { - interest = getPacket(); - name.setSuffix(suffix_manifest_.getSuffix()); - interest->setName(name); - interest->setLifetime(interest_lifetime); - - // Send interests for manifest out of the congestion window (no - // in_flight_interests++) - portal->sendInterest( - std::move(interest), - std::bind(&ManifestIndexManager::onManifestReceived, this, - std::placeholders::_1, std::placeholders::_2), - std::bind(&ManifestIndexManager::onManifestTimeout, this, - std::placeholders::_1)); - TRANSPORT_LOGD("Send manifest interest %u", name.getSuffix()); - - last_requested_manifest = (suffix_manifest_++).getSuffix(); - } while (current_segment + window_size >= suffix_manifest_.getSuffix() && - suffix_manifest_.getSuffix() < final_suffix_); - - // suffix_manifest_ now points to the last requested manifest - suffix_manifest_.updateSuffix(last_requested_manifest); -} - -bool ManifestIndexManager::onContentObject( - const core::ContentObject &content_object) { - bool verify_signature; - socket_->getSocketOption(GeneralTransportOptions::VERIFY_SIGNATURE, - verify_signature); - - if (!verify_signature) { - return true; - } - - uint64_t segment = content_object.getName().getSuffix(); - - bool ret = false; - - auto it = suffix_hash_map_.find((const unsigned int)segment); - if (it != suffix_hash_map_.end()) { - auto hash_type = static_cast(it->second.second); - auto data_packet_digest = content_object.computeDigest(it->second.second); - auto data_packet_digest_bytes = - data_packet_digest.getDigest().data(); - std::vector &manifest_digest_bytes = it->second.first; - - if (utils::CryptoHash::compareBinaryDigest(data_packet_digest_bytes, - manifest_digest_bytes.data(), - hash_type)) { - suffix_hash_map_.erase(it); - ret = true; - } else { - throw errors::RuntimeException( - "Verification failure policy has to be implemented."); - } - } - - return ret; -} - -uint32_t ManifestIndexManager::getNextSuffix() { - if (TRANSPORT_EXPECT_FALSE(next_to_retrieve_segment_ == - suffix_queue_.end())) { - return invalid_index; - } - - return *next_to_retrieve_segment_++; -} - -uint32_t ManifestIndexManager::getFinalSuffix() { return final_suffix_; } - -bool ManifestIndexManager::isFinalSuffixDiscovered() { - return IncrementalIndexManager::isFinalSuffixDiscovered(); -} - -uint32_t ManifestIndexManager::getNextReassemblySegment() { - uint32_t current_reassembly_segment; - - while (true) { - current_reassembly_segment = next_reassembly_segment_.getSuffix(); - next_reassembly_segment_++; - - if (TRANSPORT_EXPECT_FALSE(current_reassembly_segment > final_suffix_)) { - return invalid_index; - } - - if (ignored_segments_.empty()) break; - - auto is_ignored = - std::find(ignored_segments_.begin(), ignored_segments_.end(), - current_reassembly_segment); - - if (is_ignored == ignored_segments_.end()) break; - - ignored_segments_.erase(is_ignored); - } - - return current_reassembly_segment; -} - -void ManifestIndexManager::reset() { - IncrementalIndexManager::reset(); - suffix_manifest_.reset(0); - suffix_queue_.clear(); - suffix_hash_map_.clear(); -} - -} // end namespace protocol - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/protocols/packet_manager.h b/libtransport/src/hicn/transport/protocols/packet_manager.h deleted file mode 100644 index 4d4011ecf..000000000 --- a/libtransport/src/hicn/transport/protocols/packet_manager.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -namespace transport { - -namespace protocol { - -using namespace core; - -template -class PacketManager { - static_assert(std::is_base_of::value, - "The packet manager support just Interest and Data."); - - static constexpr std::size_t packet_pool_size = 4096; - - public: - PacketManager(std::size_t size = packet_pool_size) : size_(0) { - // Create pool of interests - increasePoolSize(size); - } - - TRANSPORT_ALWAYS_INLINE void increasePoolSize(std::size_t size) { - for (std::size_t i = 0; i < size; i++) { - interest_pool_.add(new PacketType()); - } - - size_ += size; - } - - TRANSPORT_ALWAYS_INLINE typename PacketType::Ptr getPacket() { - auto result = interest_pool_.get(); - - while (TRANSPORT_EXPECT_FALSE(!result.first)) { - // Add packets to the pool - increasePoolSize(size_); - result = interest_pool_.get(); - } - - result.second->resetPayload(); - return std::move(result.second); - } - - private: - utils::ObjectPool interest_pool_; - std::size_t size_; -}; - -} // end namespace protocol - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/protocols/protocol.cc b/libtransport/src/hicn/transport/protocols/protocol.cc deleted file mode 100644 index db461a66f..000000000 --- a/libtransport/src/hicn/transport/protocols/protocol.cc +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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. - */ - -#include -#include - -namespace transport { - -namespace protocol { - -using namespace interface; - -TransportProtocol::TransportProtocol(interface::ConsumerSocket *icn_socket, - Reassembly *reassembly_protocol) - : socket_(icn_socket), - reassembly_protocol_(reassembly_protocol), - index_manager_( - std::make_unique(socket_, this, reassembly_protocol)), - is_running_(false), - is_first_(false) { - socket_->getSocketOption(GeneralTransportOptions::PORTAL, portal_); - socket_->getSocketOption(OtherOptions::STATISTICS, &stats_); -} - -int TransportProtocol::start() { - // If the protocol is already running, return otherwise set as running - if (is_running_) return -1; - - // Reset the protocol state machine - reset(); - - // Set it is the first time we schedule an interest - is_first_ = true; - - // Schedule next interests - scheduleNextInterests(); - - is_first_ = false; - - // Set the protocol as running - is_running_ = true; - - // Start Event loop - portal_->runEventsLoop(); - - // Not running anymore - is_running_ = false; - - return 0; -} - -void TransportProtocol::stop() { - is_running_ = false; - portal_->stopEventsLoop(); -} - -void TransportProtocol::resume() { - if (is_running_) return; - - is_running_ = true; - - scheduleNextInterests(); - - portal_->runEventsLoop(); - - is_running_ = false; -} - -void TransportProtocol::onContentReassembled(std::error_code ec) { - interface::ConsumerSocket::ReadCallback *on_payload = VOID_HANDLER; - socket_->getSocketOption(READ_CALLBACK, &on_payload); - - if (!on_payload) { - throw errors::RuntimeException( - "The read callback must be installed in the transport before " - "starting " - "the content retrieval."); - } - - if (!ec) { - on_payload->readSuccess(stats_->getBytesRecv()); - } else { - on_payload->readError(ec); - } - - stop(); - - on_payload->afterRead(); -} - -} // end namespace protocol - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/protocols/protocol.h b/libtransport/src/hicn/transport/protocols/protocol.h deleted file mode 100644 index 4897da902..000000000 --- a/libtransport/src/hicn/transport/protocols/protocol.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace transport { - -namespace protocol { - -using namespace core; - -class IndexVerificationManager; - -class TransportProtocolCallback { - virtual void onContentObject(const core::Interest &interest, - const core::ContentObject &content_object) = 0; - virtual void onTimeout(const core::Interest &interest) = 0; -}; - -class TransportProtocol : public interface::BasePortal::ConsumerCallback, - public PacketManager, - public ContentObjectProcessingEventCallback { - static constexpr std::size_t interest_pool_size = 4096; - - friend class ManifestIndexManager; - - public: - TransportProtocol(interface::ConsumerSocket *icn_socket, - Reassembly *reassembly_protocol); - - virtual ~TransportProtocol() = default; - - TRANSPORT_ALWAYS_INLINE bool isRunning() { return is_running_; } - - virtual int start(); - - virtual void stop(); - - virtual void resume(); - - virtual bool verifyKeyPackets() = 0; - - virtual void scheduleNextInterests() = 0; - - // Events generated by the indexing - virtual void onContentReassembled(std::error_code ec); - virtual void onPacketDropped(Interest::Ptr &&interest, - ContentObject::Ptr &&content_object) = 0; - virtual void onReassemblyFailed(std::uint32_t missing_segment) = 0; - - protected: - // Consumer Callback - virtual void reset() = 0; - virtual void onContentObject(Interest::Ptr &&i, ContentObject::Ptr &&c) = 0; - virtual void onTimeout(Interest::Ptr &&i) = 0; - - protected: - interface::ConsumerSocket *socket_; - std::unique_ptr reassembly_protocol_; - std::unique_ptr index_manager_; - std::shared_ptr portal_; - std::atomic is_running_; - // True if it si the first time we schedule an interest - std::atomic is_first_; - TransportStatistics *stats_; -}; - -} // end namespace protocol -} // end namespace transport diff --git a/libtransport/src/hicn/transport/protocols/raaqm.cc b/libtransport/src/hicn/transport/protocols/raaqm.cc deleted file mode 100644 index 984470edb..000000000 --- a/libtransport/src/hicn/transport/protocols/raaqm.cc +++ /dev/null @@ -1,712 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include -#include - -#include -#include - -namespace transport { - -namespace protocol { - -using namespace interface; - -RaaqmTransportProtocol::RaaqmTransportProtocol(ConsumerSocket *icn_socket) - : TransportProtocol(icn_socket, new ByteStreamReassembly(icn_socket, this)), - current_window_size_(1), - interests_in_flight_(0), - cur_path_(nullptr), - t0_(utils::SteadyClock::now()), - rate_estimator_(nullptr) { - init(); -} - -RaaqmTransportProtocol::~RaaqmTransportProtocol() { - if (rate_estimator_) { - delete rate_estimator_; - } -} - -int RaaqmTransportProtocol::start() { - if (rate_estimator_) { - rate_estimator_->onStart(); - } - - if (!cur_path_) { - // RAAQM - double drop_factor; - double minimum_drop_probability; - uint32_t sample_number; - uint32_t interest_lifetime; - - socket_->getSocketOption(RaaqmTransportOptions::DROP_FACTOR, drop_factor); - socket_->getSocketOption(RaaqmTransportOptions::MINIMUM_DROP_PROBABILITY, - minimum_drop_probability); - socket_->getSocketOption(RaaqmTransportOptions::SAMPLE_NUMBER, - sample_number); - socket_->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, - interest_lifetime); - - // Rate Estimation - double alpha = 0.0; - uint32_t batching_param = 0; - uint32_t choice_param = 0; - socket_->getSocketOption(RateEstimationOptions::RATE_ESTIMATION_ALPHA, - alpha); - socket_->getSocketOption( - RateEstimationOptions::RATE_ESTIMATION_BATCH_PARAMETER, batching_param); - socket_->getSocketOption(RateEstimationOptions::RATE_ESTIMATION_CHOICE, - choice_param); - - if (choice_param == 1) { - rate_estimator_ = new ALaTcpEstimator(); - } else { - rate_estimator_ = new SimpleEstimator(alpha, batching_param); - } - - socket_->getSocketOption(RateEstimationOptions::RATE_ESTIMATION_OBSERVER, - &rate_estimator_->observer_); - - // Current path - auto cur_path = std::make_unique( - drop_factor, minimum_drop_probability, interest_lifetime * 1000, - sample_number); - cur_path_ = cur_path.get(); - path_table_[default_values::path_id] = std::move(cur_path); - } - - portal_->setConsumerCallback(this); - return TransportProtocol::start(); -} - -void RaaqmTransportProtocol::resume() { return TransportProtocol::resume(); } - -void RaaqmTransportProtocol::reset() { - // Set first segment to retrieve - core::Name *name; - socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME, &name); - index_manager_->reset(); - index_manager_->setFirstSuffix(name->getSuffix()); - std::queue empty; - std::swap(interest_to_retransmit_, empty); - stats_->reset(); - - // Reset reassembly component - reassembly_protocol_->reInitialize(); - - // Reset protocol variables - interests_in_flight_ = 0; - t0_ = utils::SteadyClock::now(); -} - -bool RaaqmTransportProtocol::verifyKeyPackets() { - return index_manager_->onKeyToVerify(); -} - -void RaaqmTransportProtocol::increaseWindow() { - // return; - double max_window_size = 0.; - socket_->getSocketOption(GeneralTransportOptions::MAX_WINDOW_SIZE, - max_window_size); - if (current_window_size_ < max_window_size) { - double gamma = 0.; - socket_->getSocketOption(RaaqmTransportOptions::GAMMA_VALUE, gamma); - - current_window_size_ += gamma / current_window_size_; - socket_->setSocketOption(GeneralTransportOptions::CURRENT_WINDOW_SIZE, - current_window_size_); - } - rate_estimator_->onWindowIncrease(current_window_size_); -} - -void RaaqmTransportProtocol::decreaseWindow() { - // return; - double min_window_size = 0.; - socket_->getSocketOption(GeneralTransportOptions::MIN_WINDOW_SIZE, - min_window_size); - if (current_window_size_ > min_window_size) { - double beta = 0.; - socket_->getSocketOption(RaaqmTransportOptions::BETA_VALUE, beta); - - current_window_size_ = current_window_size_ * beta; - if (current_window_size_ < min_window_size) { - current_window_size_ = min_window_size; - } - - socket_->setSocketOption(GeneralTransportOptions::CURRENT_WINDOW_SIZE, - current_window_size_); - } - rate_estimator_->onWindowDecrease(current_window_size_); -} - -void RaaqmTransportProtocol::afterDataUnsatisfied(uint64_t segment) { - // Decrease the window because the timeout happened - decreaseWindow(); -} - -void RaaqmTransportProtocol::afterContentReception( - const Interest &interest, const ContentObject &content_object) { - updatePathTable(content_object); - increaseWindow(); - updateRtt(interest.getName().getSuffix()); - rate_estimator_->onDataReceived((int)content_object.payloadSize() + - (int)content_object.headerSize()); - // Set drop probablility and window size accordingly - RAAQM(); -} - -void RaaqmTransportProtocol::init() { - std::ifstream is(RAAQM_CONFIG_PATH); - - std::string line; - raaqm_autotune_ = false; - default_beta_ = default_values::beta_value; - default_drop_ = default_values::drop_factor; - beta_wifi_ = default_values::beta_value; - drop_wifi_ = default_values::drop_factor; - beta_lte_ = default_values::beta_value; - drop_lte_ = default_values::drop_factor; - wifi_delay_ = 1000; - lte_delay_ = 15000; - - if (!is) { - TRANSPORT_LOGW( - "WARNING: RAAQM parameters not found at %s, set default values", - RAAQM_CONFIG_PATH); - return; - } - - while (getline(is, line)) { - std::string command; - std::istringstream line_s(line); - - line_s >> command; - - if (command == ";") { - continue; - } - - if (command == "autotune") { - std::string tmp; - std::string val; - line_s >> tmp >> val; - if (val == "yes") { - raaqm_autotune_ = true; - } else { - raaqm_autotune_ = false; - } - continue; - } - - if (command == "lifetime") { - std::string tmp; - uint32_t lifetime; - line_s >> tmp >> lifetime; - socket_->setSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, - lifetime); - continue; - } - - if (command == "retransmissions") { - std::string tmp; - uint32_t rtx; - line_s >> tmp >> rtx; - socket_->setSocketOption(GeneralTransportOptions::MAX_INTEREST_RETX, rtx); - continue; - } - - if (command == "beta") { - std::string tmp; - line_s >> tmp >> default_beta_; - socket_->setSocketOption(RaaqmTransportOptions::BETA_VALUE, - default_beta_); - continue; - } - - if (command == "drop") { - std::string tmp; - line_s >> tmp >> default_drop_; - socket_->setSocketOption(RaaqmTransportOptions::DROP_FACTOR, - default_drop_); - continue; - } - - if (command == "beta_wifi_") { - std::string tmp; - line_s >> tmp >> beta_wifi_; - continue; - } - - if (command == "drop_wifi_") { - std::string tmp; - line_s >> tmp >> drop_wifi_; - continue; - } - - if (command == "beta_lte_") { - std::string tmp; - line_s >> tmp >> beta_lte_; - continue; - } - - if (command == "drop_lte_") { - std::string tmp; - line_s >> tmp >> drop_lte_; - continue; - } - - if (command == "wifi_delay_") { - std::string tmp; - line_s >> tmp >> wifi_delay_; - continue; - } - - if (command == "lte_delay_") { - std::string tmp; - line_s >> tmp >> lte_delay_; - continue; - } - if (command == "alpha") { - std::string tmp; - double rate_alpha = 0.0; - line_s >> tmp >> rate_alpha; - socket_->setSocketOption(RateEstimationOptions::RATE_ESTIMATION_ALPHA, - rate_alpha); - continue; - } - - if (command == "batching_parameter") { - std::string tmp; - uint32_t batching_param = 0; - line_s >> tmp >> batching_param; - socket_->setSocketOption( - RateEstimationOptions::RATE_ESTIMATION_BATCH_PARAMETER, - batching_param); - continue; - } - - if (command == "rate_estimator") { - std::string tmp; - uint32_t choice_param = 0; - line_s >> tmp >> choice_param; - socket_->setSocketOption(RateEstimationOptions::RATE_ESTIMATION_CHOICE, - choice_param); - continue; - } - } - - is.close(); -} - -void RaaqmTransportProtocol::onContentObject( - Interest::Ptr &&interest, ContentObject::Ptr &&content_object) { - // Check whether makes sense to continue - if (TRANSPORT_EXPECT_FALSE(!is_running_)) { - return; - } - - // Call application-defined callbacks - ConsumerContentObjectCallback *callback_content_object = VOID_HANDLER; - socket_->getSocketOption(ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT, - &callback_content_object); - if (*callback_content_object) { - (*callback_content_object)(*socket_, *content_object); - } - - ConsumerInterestCallback *callback_interest = VOID_HANDLER; - socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_SATISFIED, - &callback_interest); - if (*callback_interest) { - (*callback_interest)(*socket_, *interest); - } - - if (content_object->getPayloadType() == PayloadType::CONTENT_OBJECT) { - stats_->updateBytesRecv(content_object->payloadSize()); - } - - onContentSegment(std::move(interest), std::move(content_object)); - scheduleNextInterests(); -} - -void RaaqmTransportProtocol::onContentSegment( - Interest::Ptr &&interest, ContentObject::Ptr &&content_object) { - uint32_t incremental_suffix = content_object->getName().getSuffix(); - - // Decrease in-flight interests - interests_in_flight_--; - - // Update stats - if (!interest_retransmissions_[incremental_suffix & mask]) { - afterContentReception(*interest, *content_object); - } - - index_manager_->onContentObject(std::move(interest), - std::move(content_object)); -} - -void RaaqmTransportProtocol::onPacketDropped( - Interest::Ptr &&interest, ContentObject::Ptr &&content_object) { - uint32_t max_rtx = 0; - socket_->getSocketOption(GeneralTransportOptions::MAX_INTEREST_RETX, max_rtx); - - uint64_t segment = interest->getName().getSuffix(); - ConsumerInterestCallback *callback = VOID_HANDLER; - if (TRANSPORT_EXPECT_TRUE(interest_retransmissions_[segment & mask] < - max_rtx)) { - stats_->updateRetxCount(1); - - callback = VOID_HANDLER; - socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_RETRANSMISSION, - &callback); - if (*callback) { - (*callback)(*socket_, *interest); - } - - callback = VOID_HANDLER; - socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_OUTPUT, - &callback); - if (*callback) { - (*callback)(*socket_, *interest); - } - - if (!is_running_) { - return; - } - - interest_retransmissions_[segment & mask]++; - - interest_to_retransmit_.push(std::move(interest)); - } else { - TRANSPORT_LOGE( - "Stop: received not trusted packet %llu times", - (unsigned long long)interest_retransmissions_[segment & mask]); - onContentReassembled( - make_error_code(protocol_error::max_retransmissions_error)); - } -} - -void RaaqmTransportProtocol::onReassemblyFailed(std::uint32_t missing_segment) { - -} - -void RaaqmTransportProtocol::onTimeout(Interest::Ptr &&interest) { - checkForStalePaths(); - - const Name &n = interest->getName(); - - TRANSPORT_LOGW("Timeout on content %s", n.toString().c_str()); - - if (TRANSPORT_EXPECT_FALSE(!is_running_)) { - return; - } - - interests_in_flight_--; - - uint64_t segment = n.getSuffix(); - - // Do not retransmit interests asking contents that do not exist. - if (segment > index_manager_->getFinalSuffix()) { - return; - } - - ConsumerInterestCallback *callback = VOID_HANDLER; - socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_EXPIRED, - &callback); - if (*callback) { - (*callback)(*socket_, *interest); - } - - afterDataUnsatisfied(segment); - - uint32_t max_rtx = 0; - socket_->getSocketOption(GeneralTransportOptions::MAX_INTEREST_RETX, max_rtx); - - if (TRANSPORT_EXPECT_TRUE(interest_retransmissions_[segment & mask] < - max_rtx)) { - stats_->updateRetxCount(1); - - callback = VOID_HANDLER; - socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_RETRANSMISSION, - &callback); - if (*callback) { - (*callback)(*socket_, *interest); - } - - callback = VOID_HANDLER; - socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_OUTPUT, - &callback); - if (*callback) { - (*callback)(*socket_, *interest); - } - - if (!is_running_) { - return; - } - - interest_retransmissions_[segment & mask]++; - - interest_to_retransmit_.push(std::move(interest)); - - scheduleNextInterests(); - } else { - TRANSPORT_LOGE("Stop: reached max retx limit."); - onContentReassembled(std::make_error_code(std::errc(std::errc::io_error))); - } -} - -void RaaqmTransportProtocol::scheduleNextInterests() { - if (TRANSPORT_EXPECT_FALSE(!is_running_ && !is_first_)) { - return; - } - - if (TRANSPORT_EXPECT_FALSE(interests_in_flight_ >= current_window_size_ && - interest_to_retransmit_.size() > 0)) { - // send at least one interest if there are retransmissions to perform and - // there is no space left in the window - sendInterest(std::move(interest_to_retransmit_.front())); - TRANSPORT_LOGD("Window full, retransmit one content interest"); - interest_to_retransmit_.pop(); - } - - uint32_t index = IndexManager::invalid_index; - - // Send the interest needed for filling the window - while (interests_in_flight_ < current_window_size_) { - if (interest_to_retransmit_.size() > 0) { - sendInterest(std::move(interest_to_retransmit_.front())); - TRANSPORT_LOGD("Retransmit content interest"); - interest_to_retransmit_.pop(); - } else { - index = index_manager_->getNextSuffix(); - if (index == IndexManager::invalid_index) { - TRANSPORT_LOGE("INVALID INDEX %d", index); - break; - } - - sendInterest(index); - TRANSPORT_LOGD("Send content interest %u", index); - } - } -} - -void RaaqmTransportProtocol::sendInterest(std::uint64_t next_suffix) { - auto interest = getPacket(); - core::Name *name; - socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME, &name); - name->setSuffix((uint32_t)next_suffix); - interest->setName(*name); - - uint32_t interest_lifetime; - socket_->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, - interest_lifetime); - interest->setLifetime(interest_lifetime); - - ConsumerInterestCallback *callback = VOID_HANDLER; - socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_OUTPUT, - &callback); - if (*callback) { - callback->operator()(*socket_, *interest); - } - - if (TRANSPORT_EXPECT_FALSE(!is_running_ && !is_first_)) { - return; - } - - // This is set to ~0 so that the next interest_retransmissions_ + 1, - // performed by sendInterest, will result in 0 - interest_retransmissions_[next_suffix & mask] = ~0; - interest_timepoints_[next_suffix & mask] = utils::SteadyClock::now(); - sendInterest(std::move(interest)); -} - -void RaaqmTransportProtocol::sendInterest(Interest::Ptr &&interest) { - interests_in_flight_++; - interest_retransmissions_[interest->getName().getSuffix() & mask]++; - - portal_->sendInterest(std::move(interest)); -} - -void RaaqmTransportProtocol::onContentReassembled(std::error_code ec) { - rate_estimator_->onDownloadFinished(); - TransportProtocol::onContentReassembled(ec); -} - -void RaaqmTransportProtocol::updateRtt(uint64_t segment) { - if (TRANSPORT_EXPECT_FALSE(!cur_path_)) { - throw std::runtime_error("RAAQM ERROR: no current path found, exit"); - } else { - auto now = utils::SteadyClock::now(); - utils::Microseconds rtt = std::chrono::duration_cast( - now - interest_timepoints_[segment & mask]); - - // Update stats - updateStats((uint32_t)segment, rtt.count(), now); - - if (rate_estimator_) { - rate_estimator_->onRttUpdate((double)rtt.count()); - } - - cur_path_->insertNewRtt(rtt.count()); - cur_path_->smoothTimer(); - - if (cur_path_->newPropagationDelayAvailable()) { - checkDropProbability(); - } - } -} - -void RaaqmTransportProtocol::RAAQM() { - if (!cur_path_) { - throw errors::RuntimeException("ERROR: no current path found, exit"); - exit(EXIT_FAILURE); - } else { - // Change drop probability according to RTT statistics - cur_path_->updateDropProb(); - - double coin = ((double)rand() / (RAND_MAX)); - if (coin <= cur_path_->getDropProb()) { - decreaseWindow(); - } - } -} - -void RaaqmTransportProtocol::updateStats(uint32_t suffix, uint64_t rtt, - utils::TimePoint &now) { - // Update RTT statistics - stats_->updateAverageRtt(rtt); - stats_->updateAverageWindowSize(current_window_size_); - - // Call statistics callback - ConsumerTimerCallback *stats_callback = VOID_HANDLER; - socket_->getSocketOption(ConsumerCallbacksOptions::STATS_SUMMARY, - &stats_callback); - if (*stats_callback) { - auto dt = std::chrono::duration_cast(now - t0_); - - uint32_t timer_interval_milliseconds = 0; - socket_->getSocketOption(GeneralTransportOptions::STATS_INTERVAL, - timer_interval_milliseconds); - if (dt.count() > timer_interval_milliseconds) { - (*stats_callback)(*socket_, *stats_); - t0_ = utils::SteadyClock::now(); - } - } -} - -void RaaqmTransportProtocol::updatePathTable( - const ContentObject &content_object) { - uint32_t path_id = content_object.getPathLabel(); - - if (path_table_.find(path_id) == path_table_.end()) { - if (TRANSPORT_EXPECT_TRUE(cur_path_ != nullptr)) { - // Create a new path with some default param - - if (TRANSPORT_EXPECT_FALSE(path_table_.empty())) { - throw errors::RuntimeException( - "[RAAQM] No path initialized for path table, error could be in " - "default path initialization."); - } - - // Initiate the new path default param - auto new_path = std::make_unique( - *(path_table_.at(default_values::path_id))); - - // Insert the new path into hash table - path_table_[path_id] = std::move(new_path); - } else { - throw errors::RuntimeException( - "UNEXPECTED ERROR: when running,current path not found."); - } - } - - cur_path_ = path_table_[path_id].get(); - - size_t header_size = content_object.headerSize(); - size_t data_size = content_object.payloadSize(); - - // Update measurements for path - cur_path_->updateReceivedStats(header_size + data_size, data_size); -} - -void RaaqmTransportProtocol::checkDropProbability() { - if (!raaqm_autotune_) { - return; - } - - unsigned int max_pd = 0; - PathTable::iterator it; - for (auto it = path_table_.begin(); it != path_table_.end(); ++it) { - if (it->second->getPropagationDelay() > max_pd && - it->second->getPropagationDelay() != UINT_MAX && - !it->second->isStale()) { - max_pd = it->second->getPropagationDelay(); - } - } - - double drop_prob = 0; - double beta = 0; - if (max_pd < wifi_delay_) { // only ethernet paths - drop_prob = default_drop_; - beta = default_beta_; - } else if (max_pd < lte_delay_) { // at least one wifi path - drop_prob = drop_wifi_; - beta = beta_wifi_; - } else { // at least one lte path - drop_prob = drop_lte_; - beta = beta_lte_; - } - - double old_drop_prob = 0; - double old_beta = 0; - socket_->getSocketOption(RaaqmTransportOptions::BETA_VALUE, old_beta); - socket_->getSocketOption(RaaqmTransportOptions::DROP_FACTOR, old_drop_prob); - - if (drop_prob == old_drop_prob && beta == old_beta) { - return; - } - - socket_->setSocketOption(RaaqmTransportOptions::BETA_VALUE, beta); - socket_->setSocketOption(RaaqmTransportOptions::DROP_FACTOR, drop_prob); - - for (it = path_table_.begin(); it != path_table_.end(); it++) { - it->second->setDropProb(drop_prob); - } -} - -void RaaqmTransportProtocol::checkForStalePaths() { - if (!raaqm_autotune_) { - return; - } - - bool stale = false; - PathTable::iterator it; - for (it = path_table_.begin(); it != path_table_.end(); ++it) { - if (it->second->isStale()) { - stale = true; - break; - } - } - if (stale) { - checkDropProbability(); - } -} - -} // end namespace protocol - -} // namespace transport diff --git a/libtransport/src/hicn/transport/protocols/raaqm.h b/libtransport/src/hicn/transport/protocols/raaqm.h deleted file mode 100644 index f2d819ec5..000000000 --- a/libtransport/src/hicn/transport/protocols/raaqm.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace transport { - -namespace protocol { - -class RaaqmTransportProtocol : public TransportProtocol, - public CWindowProtocol { - public: - RaaqmTransportProtocol(interface::ConsumerSocket *icnet_socket); - - ~RaaqmTransportProtocol(); - - int start() override; - - void resume() override; - - void reset() override; - - virtual bool verifyKeyPackets() override; - - protected: - static constexpr uint32_t buffer_size = - 1 << interface::default_values::log_2_default_buffer_size; - static constexpr uint16_t mask = buffer_size - 1; - using PathTable = - std::unordered_map>; - - void increaseWindow() override; - void decreaseWindow() override; - - virtual void afterContentReception(const Interest &interest, - const ContentObject &content_object); - virtual void afterDataUnsatisfied(uint64_t segment); - - virtual void updateStats(uint32_t suffix, uint64_t rtt, - utils::TimePoint &now); - - private: - void init(); - - void onContentObject(Interest::Ptr &&i, ContentObject::Ptr &&c) override; - - void onContentSegment(Interest::Ptr &&interest, - ContentObject::Ptr &&content_object); - - void onPacketDropped(Interest::Ptr &&interest, - ContentObject::Ptr &&content_object) override; - - void onReassemblyFailed(std::uint32_t missing_segment) override; - - void onTimeout(Interest::Ptr &&i) override; - - virtual void scheduleNextInterests() override; - - void sendInterest(std::uint64_t next_suffix); - - void sendInterest(Interest::Ptr &&interest); - - void onContentReassembled(std::error_code ec) override; - - void updateRtt(uint64_t segment); - - void RAAQM(); - - void updatePathTable(const ContentObject &content_object); - - void checkDropProbability(); - - void checkForStalePaths(); - - void printRtt(); - - protected: - // Congestion window management - double current_window_size_; - // Protocol management - uint64_t interests_in_flight_; - std::array interest_retransmissions_; - std::array interest_timepoints_; - std::queue interest_to_retransmit_; - - private: - /** - * Current download path - */ - RaaqmDataPath *cur_path_; - - /** - * Hash table for path: each entry is a pair path ID(key) - path object - */ - PathTable path_table_; - - // TimePoints for statistic - utils::TimePoint t0_; - - bool set_interest_filter_; - - // for rate-estimation at packet level - IcnRateEstimator *rate_estimator_; - - // params for autotuning - bool raaqm_autotune_; - double default_beta_; - double default_drop_; - double beta_wifi_; - double drop_wifi_; - double beta_lte_; - double drop_lte_; - unsigned int wifi_delay_; - unsigned int lte_delay_; -}; - -} // end namespace protocol - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/protocols/raaqm_data_path.cc b/libtransport/src/hicn/transport/protocols/raaqm_data_path.cc deleted file mode 100644 index e25646205..000000000 --- a/libtransport/src/hicn/transport/protocols/raaqm_data_path.cc +++ /dev/null @@ -1,157 +0,0 @@ -/* - * 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. - */ - -#include -#include - -namespace transport { - -namespace protocol { - -RaaqmDataPath::RaaqmDataPath(double drop_factor, - double minimum_drop_probability, - unsigned new_timer, unsigned int samples, - uint64_t new_rtt, uint64_t new_rtt_min, - uint64_t new_rtt_max, unsigned new_pd) - - : drop_factor_(drop_factor), - minimum_drop_probability_(minimum_drop_probability), - timer_(new_timer), - samples_(samples), - rtt_(new_rtt), - rtt_min_(new_rtt_min), - rtt_max_(new_rtt_max), - prop_delay_(new_pd), - new_prop_delay_(false), - drop_prob_(0), - packets_received_(0), - last_packets_received_(0), - m_packets_bytes_received_(0), - last_packets_bytes_received_(0), - raw_data_bytes_received_(0), - last_raw_data_bytes_received_(0), - rtt_samples_(samples_), - last_received_pkt_(utils::SteadyClock::now()), - average_rtt_(0), - alpha_(ALPHA) {} - -RaaqmDataPath &RaaqmDataPath::insertNewRtt(uint64_t new_rtt) { - rtt_ = new_rtt; - rtt_samples_.pushBack(new_rtt); - - rtt_max_ = rtt_samples_.rBegin(); - rtt_min_ = rtt_samples_.begin(); - - if (rtt_min_ < prop_delay_) { - new_prop_delay_ = true; - prop_delay_ = rtt_min_; - } - - last_received_pkt_ = utils::SteadyClock::now(); - - return *this; -} - -RaaqmDataPath &RaaqmDataPath::updateReceivedStats(std::size_t packet_size, - std::size_t data_size) { - packets_received_++; - m_packets_bytes_received_ += packet_size; - raw_data_bytes_received_ += data_size; - - return *this; -} - -double RaaqmDataPath::getDropFactor() { return drop_factor_; } - -double RaaqmDataPath::getDropProb() { return drop_prob_; } - -RaaqmDataPath &RaaqmDataPath::setDropProb(double dropProb) { - drop_prob_ = dropProb; - - return *this; -} - -double RaaqmDataPath::getMinimumDropProbability() { - return minimum_drop_probability_; -} - -double RaaqmDataPath::getTimer() { return timer_; } - -RaaqmDataPath &RaaqmDataPath::smoothTimer() { - timer_ = (1 - TIMEOUT_SMOOTHER) * timer_ + - (TIMEOUT_SMOOTHER)*rtt_ * (TIMEOUT_RATIO); - - return *this; -} - -double RaaqmDataPath::getRtt() { return (double)rtt_; } - -double RaaqmDataPath::getAverageRtt() { return average_rtt_; } - -double RaaqmDataPath::getRttMax() { return (double)rtt_max_; } - -double RaaqmDataPath::getRttMin() { return (double)rtt_min_; } - -unsigned RaaqmDataPath::getSampleValue() { return samples_; } - -unsigned RaaqmDataPath::getRttQueueSize() { - return static_cast(rtt_samples_.size()); -} - -RaaqmDataPath &RaaqmDataPath::updateDropProb() { - drop_prob_ = 0.0; - - if (getSampleValue() == getRttQueueSize()) { - if (rtt_max_ == rtt_min_) { - drop_prob_ = minimum_drop_probability_; - } else { - drop_prob_ = minimum_drop_probability_ + - drop_factor_ * (rtt_ - rtt_min_) / (rtt_max_ - rtt_min_); - } - } - - return *this; -} - -void RaaqmDataPath::setAlpha(double alpha) { - if (alpha >= 0 && alpha <= 1) { - alpha_ = alpha; - } -} - -bool RaaqmDataPath::newPropagationDelayAvailable() { - bool r = new_prop_delay_; - new_prop_delay_ = false; - return r; -} - -unsigned int RaaqmDataPath::getPropagationDelay() { - return (unsigned int)prop_delay_; -} - -bool RaaqmDataPath::isStale() { - utils::TimePoint now = utils::SteadyClock::now(); - auto time = - std::chrono::duration_cast(now - last_received_pkt_) - .count(); - if (time > 2000000) { - return true; - } - return false; -} - -} // end namespace protocol - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/protocols/raaqm_data_path.h b/libtransport/src/hicn/transport/protocols/raaqm_data_path.h deleted file mode 100644 index 9e4accfa5..000000000 --- a/libtransport/src/hicn/transport/protocols/raaqm_data_path.h +++ /dev/null @@ -1,225 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include - -#include -#include -#include - -#define TIMEOUT_SMOOTHER 0.1 -#define TIMEOUT_RATIO 10 -#define ALPHA 0.8 - -namespace transport { - -namespace protocol { - -class RaaqmDataPath { - public: - RaaqmDataPath(double drop_factor, double minimum_drop_probability, - unsigned new_timer, unsigned int samples, - uint64_t new_rtt = 1000, uint64_t new_rtt_min = 1000, - uint64_t new_rtt_max = 1000, unsigned new_pd = UINT_MAX); - - public: - /* - * @brief Add a new RTT to the RTT queue of the path, check if RTT queue is - * full, and thus need overwrite. Also it maintains the validity of min and - * max of RTT. - * @param new_rtt is the value of the new RTT - */ - RaaqmDataPath &insertNewRtt(uint64_t new_rtt); - - /** - * @brief Update the path statistics - * @param packet_size the size of the packet received, including the ICN - * header - * @param data_size the size of the data received, without the ICN header - */ - RaaqmDataPath &updateReceivedStats(std::size_t packet_size, - std::size_t data_size); - - /** - * @brief Get the value of the drop factor parameter - */ - double getDropFactor(); - - /** - * @brief Get the value of the drop probability - */ - double getDropProb(); - - /** - * @brief Set the value pf the drop probability - * @param drop_prob is the value of the drop probability - */ - RaaqmDataPath &setDropProb(double drop_prob); - - /** - * @brief Get the minimum drop probability - */ - double getMinimumDropProbability(); - - /** - * @brief Get last RTT - */ - double getRtt(); - - /** - * @brief Get average RTT - */ - double getAverageRtt(); - - /** - * @brief Get the current m_timer value - */ - double getTimer(); - - /** - * @brief Smooth he value of the m_timer accordingly with the last RTT - * measured - */ - RaaqmDataPath &smoothTimer(); - - /** - * @brief Get the maximum RTT among the last samples - */ - double getRttMax(); - - /** - * @brief Get the minimum RTT among the last samples - */ - double getRttMin(); - - /** - * @brief Get the number of saved samples - */ - unsigned getSampleValue(); - - /** - * @brief Get the size og the RTT queue - */ - unsigned getRttQueueSize(); - - /* - * @brief Change drop probability according to RTT statistics - * Invoked in RAAQM(), before control window size update. - */ - RaaqmDataPath &updateDropProb(); - - void setAlpha(double alpha); - - /** - * @brief Returns the smallest RTT registered so far for this path - */ - - unsigned int getPropagationDelay(); - - bool newPropagationDelayAvailable(); - - bool isStale(); - - private: - /** - * The value of the drop factor - */ - double drop_factor_; - - /** - * The minumum drop probability - */ - double minimum_drop_probability_; - - /** - * The timer, expressed in milliseconds - */ - double timer_; - - /** - * The number of samples to store for computing the protocol measurements - */ - const unsigned int samples_; - - /** - * The last, the minimum and the maximum value of the RTT (among the last - * m_samples samples) - */ - uint64_t rtt_, rtt_min_, rtt_max_, prop_delay_; - - bool new_prop_delay_; - - /** - * The current drop probability - */ - double drop_prob_; - - /** - * The number of packets received in this path - */ - intmax_t packets_received_; - - /** - * The first packet received after the statistics print - */ - intmax_t last_packets_received_; - - /** - * Total number of bytes received including the ICN header - */ - intmax_t m_packets_bytes_received_; - - /** - * The amount of packet bytes received at the last path summary computation - */ - intmax_t last_packets_bytes_received_; - - /** - * Total number of bytes received without including the ICN header - */ - intmax_t raw_data_bytes_received_; - - /** - * The amount of raw dat bytes received at the last path summary computation - */ - intmax_t last_raw_data_bytes_received_; - - class byArrival; - - class byOrder; - - /** - * Double ended queue for the RTTs - */ - - typedef utils::MinFilter RTTQueue; - - RTTQueue rtt_samples_; - - /** - * Time of the last call to the path reporter method - */ - utils::TimePoint last_received_pkt_; - - double average_rtt_; - double alpha_; -}; - -} // end namespace protocol - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/protocols/rate_estimation.cc b/libtransport/src/hicn/transport/protocols/rate_estimation.cc deleted file mode 100644 index 50306e6e5..000000000 --- a/libtransport/src/hicn/transport/protocols/rate_estimation.cc +++ /dev/null @@ -1,355 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include - -#include - -namespace transport { - -namespace protocol { - -void *Timer(void *data) { - InterRttEstimator *estimator = (InterRttEstimator *)data; - - double dat_rtt, my_avg_win, my_avg_rtt; - int my_win_change, number_of_packets, max_packet_size; - - pthread_mutex_lock(&(estimator->mutex_)); - dat_rtt = estimator->rtt_; - pthread_mutex_unlock(&(estimator->mutex_)); - - while (estimator->is_running_) { - std::this_thread::sleep_for(std::chrono::microseconds( - (uint64_t)(interface::default_values::kv * dat_rtt))); - - pthread_mutex_lock(&(estimator->mutex_)); - - dat_rtt = estimator->rtt_; - my_avg_win = estimator->avg_win_; - my_avg_rtt = estimator->avg_rtt_; - my_win_change = (int)(estimator->win_change_); - number_of_packets = estimator->number_of_packets_; - max_packet_size = estimator->max_packet_size_; - estimator->avg_rtt_ = estimator->rtt_; - estimator->avg_win_ = 0; - estimator->win_change_ = 0; - estimator->number_of_packets_ = 1; - - pthread_mutex_unlock(&(estimator->mutex_)); - - if (number_of_packets == 0 || my_win_change == 0) { - continue; - } - if (estimator->estimation_ == 0) { - estimator->estimation_ = (my_avg_win * 8.0 * max_packet_size * 1000000.0 / - (1.0 * my_win_change)) / - (my_avg_rtt / (1.0 * number_of_packets)); - } - - estimator->estimation_ = - estimator->alpha_ * estimator->estimation_ + - (1 - estimator->alpha_) * ((my_avg_win * 8.0 * max_packet_size * - 1000000.0 / (1.0 * my_win_change)) / - (my_avg_rtt / (1.0 * number_of_packets))); - - if (estimator->observer_) { - estimator->observer_->notifyStats(estimator->estimation_); - } - } - - return nullptr; -} - -InterRttEstimator::InterRttEstimator(double alpha_arg) { - this->estimated_ = false; - this->observer_ = NULL; - this->alpha_ = alpha_arg; - this->thread_is_running_ = false; - this->my_th_ = NULL; - this->is_running_ = true; - this->avg_rtt_ = 0.0; - this->estimation_ = 0.0; - this->avg_win_ = 0.0; - this->rtt_ = 0.0; - this->win_change_ = 0; - this->number_of_packets_ = 0; - this->max_packet_size_ = 0; - this->win_current_ = 1.0; - - pthread_mutex_init(&(this->mutex_), NULL); - this->start_time_ = std::chrono::steady_clock::now(); - this->begin_batch_ = std::chrono::steady_clock::now(); -} - -InterRttEstimator::~InterRttEstimator() { - this->is_running_ = false; - if (this->my_th_) { - pthread_join(*(this->my_th_), NULL); - } - this->my_th_ = NULL; - pthread_mutex_destroy(&(this->mutex_)); -} - -void InterRttEstimator::onRttUpdate(double rtt) { - pthread_mutex_lock(&(this->mutex_)); - this->rtt_ = rtt; - this->number_of_packets_++; - this->avg_rtt_ += rtt; - pthread_mutex_unlock(&(this->mutex_)); - - if (!thread_is_running_) { - my_th_ = (pthread_t *)malloc(sizeof(pthread_t)); - if (!my_th_) { - TRANSPORT_LOGE("Error allocating thread."); - my_th_ = NULL; - } - if (/*int err = */ pthread_create(my_th_, NULL, transport::protocol::Timer, - (void *)this)) { - TRANSPORT_LOGE("Error creating the thread"); - my_th_ = NULL; - } - thread_is_running_ = true; - } -} - -void InterRttEstimator::onWindowIncrease(double win_current) { - TimePoint end = std::chrono::steady_clock::now(); - auto delay = - std::chrono::duration_cast(end - this->begin_batch_) - .count(); - - pthread_mutex_lock(&(this->mutex_)); - this->avg_win_ += this->win_current_ * delay; - this->win_current_ = win_current; - this->win_change_ += delay; - pthread_mutex_unlock(&(this->mutex_)); - - this->begin_batch_ = std::chrono::steady_clock::now(); -} - -void InterRttEstimator::onWindowDecrease(double win_current) { - TimePoint end = std::chrono::steady_clock::now(); - auto delay = - std::chrono::duration_cast(end - this->begin_batch_) - .count(); - - pthread_mutex_lock(&(this->mutex_)); - this->avg_win_ += this->win_current_ * delay; - this->win_current_ = win_current; - this->win_change_ += delay; - pthread_mutex_unlock(&(this->mutex_)); - - this->begin_batch_ = std::chrono::steady_clock::now(); -} - -ALaTcpEstimator::ALaTcpEstimator() { - this->estimation_ = 0.0; - this->observer_ = NULL; - this->start_time_ = std::chrono::steady_clock::now(); - this->totalSize_ = 0.0; -} - -void ALaTcpEstimator::onStart() { - this->totalSize_ = 0.0; - this->start_time_ = std::chrono::steady_clock::now(); -} - -void ALaTcpEstimator::onDownloadFinished() { - TimePoint end = std::chrono::steady_clock::now(); - auto delay = - std::chrono::duration_cast(end - this->start_time_).count(); - this->estimation_ = this->totalSize_ * 8 * 1000000 / delay; - if (observer_) { - observer_->notifyStats(this->estimation_); - } -} - -void ALaTcpEstimator::onDataReceived(int packet_size) { - this->totalSize_ += packet_size; -} - -SimpleEstimator::SimpleEstimator(double alphaArg, int batching_param) { - this->estimation_ = 0.0; - this->estimated_ = false; - this->observer_ = nullptr; - this->batching_param_ = batching_param; - this->total_size_ = 0.0; - this->number_of_packets_ = 0; - this->base_alpha_ = alphaArg; - this->alpha_ = alphaArg; - this->start_time_ = std::chrono::steady_clock::now(); - this->begin_batch_ = std::chrono::steady_clock::now(); -} - -void SimpleEstimator::onStart() { - this->estimated_ = false; - this->number_of_packets_ = 0; - this->total_size_ = 0.0; - this->start_time_ = std::chrono::steady_clock::now(); - this->begin_batch_ = std::chrono::steady_clock::now(); -} - -void SimpleEstimator::onDownloadFinished() { - TimePoint end = std::chrono::steady_clock::now(); - auto delay = - std::chrono::duration_cast(end - this->start_time_).count(); - if (observer_) { - observer_->notifyDownloadTime((double)delay); - } - if (!this->estimated_) { - // Assuming all packets carry max_packet_size_ bytes of data - // (8*max_packet_size_ bits); 1000000 factor to convert us to seconds - if (this->estimation_) { - this->estimation_ = - alpha_ * this->estimation_ + - (1 - alpha_) * (total_size_ * 8 * 1000000.0 / (delay)); - } else { - this->estimation_ = total_size_ * 8 * 1000000.0 / (delay); - } - if (observer_) { - observer_->notifyStats(this->estimation_); - } - this->alpha_ = this->base_alpha_ * (((double)this->number_of_packets_) / - ((double)this->batching_param_)); - } else { - if (this->number_of_packets_ >= - (int)(75.0 * (double)this->batching_param_ / 100.0)) { - delay = std::chrono::duration_cast(end - this->begin_batch_) - .count(); - // Assuming all packets carry max_packet_size_ bytes of data - // (8*max_packet_size_ bits); 1000000 factor to convert us to seconds - if (this->estimation_) { - this->estimation_ = - alpha_ * this->estimation_ + - (1 - alpha_) * (total_size_ * 8 * 1000000.0 / (delay)); - } else { - this->estimation_ = total_size_ * 8 * 1000000.0 / (delay); - } - if (observer_) { - observer_->notifyStats(this->estimation_); - } - this->alpha_ = this->base_alpha_ * (((double)this->number_of_packets_) / - ((double)this->batching_param_)); - } - } - this->number_of_packets_ = 0; - this->total_size_ = 0.0; - this->start_time_ = std::chrono::steady_clock::now(); - this->begin_batch_ = std::chrono::steady_clock::now(); -} - -void SimpleEstimator::onDataReceived(int packet_size) { - this->total_size_ += packet_size; -} - -void SimpleEstimator::onRttUpdate(double rtt) { - this->number_of_packets_++; - - if (this->number_of_packets_ == this->batching_param_) { - TimePoint end = std::chrono::steady_clock::now(); - auto delay = - std::chrono::duration_cast(end - this->begin_batch_) - .count(); - // Assuming all packets carry max_packet_size_ bytes of data - // (8*max_packet_size_ bits); 1000000 factor to convert us to seconds - if (this->estimation_) { - this->estimation_ = - alpha_ * this->estimation_ + - (1 - alpha_) * (total_size_ * 8 * 1000000.0 / (delay)); - } else { - this->estimation_ = total_size_ * 8 * 1000000.0 / (delay); - } - if (observer_) { - observer_->notifyStats(this->estimation_); - } - this->alpha_ = this->base_alpha_; - this->number_of_packets_ = 0; - this->total_size_ = 0.0; - this->begin_batch_ = std::chrono::steady_clock::now(); - } -} - -BatchingPacketsEstimator::BatchingPacketsEstimator(double alpha_arg, - int param) { - this->estimated_ = false; - this->observer_ = NULL; - this->alpha_ = alpha_arg; - this->batching_param_ = param; - this->number_of_packets_ = 0; - this->avg_win_ = 0.0; - this->avg_rtt_ = 0.0; - this->win_change_ = 0.0; - this->max_packet_size_ = 0; - this->estimation_ = 0.0; - this->win_current_ = 1.0; - this->begin_batch_ = std::chrono::steady_clock::now(); - this->start_time_ = std::chrono::steady_clock::now(); -} - -void BatchingPacketsEstimator::onRttUpdate(double rtt) { - this->number_of_packets_++; - this->avg_rtt_ += rtt; - - if (number_of_packets_ == this->batching_param_) { - if (estimation_ == 0) { - estimation_ = (avg_win_ * 8.0 * max_packet_size_ * 1000000.0 / - (1.0 * win_change_)) / - (avg_rtt_ / (1.0 * number_of_packets_)); - } else { - estimation_ = alpha_ * estimation_ + - (1 - alpha_) * ((avg_win_ * 8.0 * max_packet_size_ * - 1000000.0 / (1.0 * win_change_)) / - (avg_rtt_ / (1.0 * number_of_packets_))); - } - - if (observer_) { - observer_->notifyStats(estimation_); - } - - this->number_of_packets_ = 0; - this->avg_win_ = 0.0; - this->avg_rtt_ = 0.0; - this->win_change_ = 0.0; - } -} - -void BatchingPacketsEstimator::onWindowIncrease(double win_current) { - TimePoint end = std::chrono::steady_clock::now(); - auto delay = - std::chrono::duration_cast(end - this->begin_batch_) - .count(); - this->avg_win_ += this->win_current_ * delay; - this->win_current_ = win_current; - this->win_change_ += delay; - this->begin_batch_ = std::chrono::steady_clock::now(); -} - -void BatchingPacketsEstimator::onWindowDecrease(double win_current) { - TimePoint end = std::chrono::steady_clock::now(); - auto delay = - std::chrono::duration_cast(end - this->begin_batch_) - .count(); - this->avg_win_ += this->win_current_ * delay; - this->win_current_ = win_current; - this->win_change_ += delay; - this->begin_batch_ = std::chrono::steady_clock::now(); -} - -} // end namespace protocol - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/protocols/rate_estimation.h b/libtransport/src/hicn/transport/protocols/rate_estimation.h deleted file mode 100644 index 616501b24..000000000 --- a/libtransport/src/hicn/transport/protocols/rate_estimation.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include - -#include - -namespace transport { - -namespace protocol { - -class IcnRateEstimator { - public: - using TimePoint = std::chrono::steady_clock::time_point; - using Microseconds = std::chrono::microseconds; - - IcnRateEstimator(){}; - - virtual ~IcnRateEstimator(){}; - - virtual void onRttUpdate(double rtt){}; - - virtual void onDataReceived(int packetSize){}; - - virtual void onWindowIncrease(double winCurrent){}; - - virtual void onWindowDecrease(double winCurrent){}; - - virtual void onStart(){}; - - virtual void onDownloadFinished(){}; - - virtual void setObserver(IcnObserver *observer) { - this->observer_ = observer; - }; - IcnObserver *observer_; - TimePoint start_time_; - TimePoint begin_batch_; - double base_alpha_; - double alpha_; - double estimation_; - int number_of_packets_; - // this boolean is to make sure at least one estimation of the BW is done - bool estimated_; -}; - -// A rate estimator RTT-based. Computes EWMA(WinSize)/EWMA(RTT) - -class InterRttEstimator : public IcnRateEstimator { - public: - InterRttEstimator(double alpha_arg); - - ~InterRttEstimator(); - - void onRttUpdate(double rtt); - - void onDataReceived(int packet_size) { - if (packet_size > this->max_packet_size_) { - this->max_packet_size_ = packet_size; - } - }; - - void onWindowIncrease(double win_current); - - void onWindowDecrease(double win_current); - - void onStart(){}; - - void onDownloadFinished(){}; - - // private: should be done by using getters - pthread_t *my_th_; - bool thread_is_running_; - double rtt_; - bool is_running_; - pthread_mutex_t mutex_; - double avg_rtt_; - double avg_win_; - int max_packet_size_; - double win_change_; - double win_current_; -}; - -// A rate estimator, Batching Packets based. Computes EWMA(WinSize)/EWMA(RTT) - -class BatchingPacketsEstimator : public IcnRateEstimator { - public: - BatchingPacketsEstimator(double alpha_arg, int batchingParam); - - void onRttUpdate(double rtt); - - void onDataReceived(int packet_size) { - if (packet_size > this->max_packet_size_) { - this->max_packet_size_ = packet_size; - } - }; - - void onWindowIncrease(double win_current); - - void onWindowDecrease(double win_current); - - void onStart(){}; - - void onDownloadFinished(){}; - - private: - int batching_param_; - double avg_rtt_; - double avg_win_; - double win_change_; - int max_packet_size_; - double win_current_; -}; - -// Segment Estimator - -class ALaTcpEstimator : public IcnRateEstimator { - public: - ALaTcpEstimator(); - - void onDataReceived(int packet_size); - void onStart(); - void onDownloadFinished(); - - private: - double totalSize_; -}; - -// A Rate estimator, this one is the simplest: counting batching_param_ packets -// and then divide the sum of the size of these packets by the time taken to DL -// them. Should be the one used - -class SimpleEstimator : public IcnRateEstimator { - public: - SimpleEstimator(double alpha, int batching_param); - - void onRttUpdate(double rtt); - - void onDataReceived(int packet_size); - - void onWindowIncrease(double win_current){}; - - void onWindowDecrease(double win_current){}; - - void onStart(); - - void onDownloadFinished(); - - private: - int batching_param_; - double total_size_; -}; - -void *Timer(void *data); - -} // namespace protocol - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/protocols/reassembly.cc b/libtransport/src/hicn/transport/protocols/reassembly.cc deleted file mode 100644 index 9682d338d..000000000 --- a/libtransport/src/hicn/transport/protocols/reassembly.cc +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include -#include -#include -#include - -namespace transport { - -namespace protocol { - -void Reassembly::notifyApplication() { - interface::ConsumerSocket::ReadCallback *read_callback = nullptr; - reassembly_consumer_socket_->getSocketOption( - interface::ConsumerCallbacksOptions::READ_CALLBACK, &read_callback); - - if (TRANSPORT_EXPECT_FALSE(!read_callback)) { - TRANSPORT_LOGE("Read callback not installed!"); - return; - } - - if (read_callback->isBufferMovable()) { - // No need to perform an additional copy. The whole buffer will be - // tranferred to the application. - - read_callback->readBufferAvailable(std::move(read_buffer_)); - read_buffer_ = utils::MemBuf::create(read_callback->maxBufferSize()); - } else { - // The buffer will be copied into the application-provided buffer - uint8_t *buffer; - std::size_t length; - std::size_t total_length = read_buffer_->length(); - - while (read_buffer_->length()) { - buffer = nullptr; - length = 0; - read_callback->getReadBuffer(&buffer, &length); - - if (!buffer || !length) { - throw errors::RuntimeException( - "Invalid buffer provided by the application."); - } - - auto to_copy = std::min(read_buffer_->length(), length); - std::memcpy(buffer, read_buffer_->data(), to_copy); - read_buffer_->trimStart(to_copy); - } - - read_callback->readDataAvailable(total_length); - read_buffer_->clear(); - } -} - -} // namespace protocol -} // namespace transport diff --git a/libtransport/src/hicn/transport/protocols/reassembly.h b/libtransport/src/hicn/transport/protocols/reassembly.h deleted file mode 100644 index 34af2a70a..000000000 --- a/libtransport/src/hicn/transport/protocols/reassembly.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -namespace transport { - -namespace interface { -class ConsumerReadCallback; -class ConsumerSocket; -} // namespace interface - -namespace protocol { - -class TransportProtocol; -class Indexer; - -// Forward Declaration -class ManifestManager; - -class Reassembly { - public: - class ContentReassembledCallback { - public: - virtual void onContentReassembled(std::error_code ec) = 0; - }; - - Reassembly(interface::ConsumerSocket *icn_socket, - TransportProtocol *transport_protocol) - : reassembly_consumer_socket_(icn_socket), - transport_protocol_(transport_protocol) {} - - virtual ~Reassembly() = default; - - virtual void reassemble(core::ContentObject::Ptr &&content_object) = 0; - virtual void reassemble( - std::unique_ptr &&manifest) = 0; - virtual void reInitialize() = 0; - virtual void setIndexer(Indexer *indexer) { index_manager_ = indexer; } - - protected: - virtual void notifyApplication(); - - protected: - interface::ConsumerSocket *reassembly_consumer_socket_; - TransportProtocol *transport_protocol_; - Indexer *index_manager_; - std::unique_ptr read_buffer_; -}; - -} // namespace protocol - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/protocols/rtc.cc b/libtransport/src/hicn/transport/protocols/rtc.cc deleted file mode 100644 index fece95d03..000000000 --- a/libtransport/src/hicn/transport/protocols/rtc.cc +++ /dev/null @@ -1,1016 +0,0 @@ -/* - * 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. - */ - -#include - -#include - -#include -#include - -namespace transport { - -namespace protocol { - -using namespace interface; - -RTCTransportProtocol::RTCTransportProtocol( - interface::ConsumerSocket *icn_socket) - : TransportProtocol(icn_socket, nullptr), - DatagramReassembly(icn_socket, this), - inflightInterests_(1 << default_values::log_2_default_buffer_size), - modMask_((1 << default_values::log_2_default_buffer_size) - 1) { - icn_socket->getSocketOption(PORTAL, portal_); - rtx_timer_ = std::make_unique(portal_->getIoService()); - probe_timer_ = std::make_unique(portal_->getIoService()); - sentinel_timer_ = - std::make_unique(portal_->getIoService()); - round_timer_ = std::make_unique(portal_->getIoService()); - reset(); -} - -RTCTransportProtocol::~RTCTransportProtocol() { - if (is_running_) { - stop(); - } -} - -int RTCTransportProtocol::start() { - if (is_running_) return -1; - - reset(); - is_first_ = true; - - probeRtt(); - sentinelTimer(); - newRound(); - scheduleNextInterests(); - - is_first_ = false; - is_running_ = true; - portal_->runEventsLoop(); - is_running_ = false; - - return 0; -} - -void RTCTransportProtocol::stop() { - if (!is_running_) return; - - is_running_ = false; - portal_->stopEventsLoop(); -} - -void RTCTransportProtocol::resume() { - if (is_running_) return; - - is_running_ = true; - inflightInterestsCount_ = 0; - - probeRtt(); - sentinelTimer(); - newRound(); - scheduleNextInterests(); - - portal_->runEventsLoop(); - is_running_ = false; -} - -// private -void RTCTransportProtocol::reset() { - portal_->setConsumerCallback(this); - // controller var - currentState_ = HICN_RTC_SYNC_STATE; - - // cwin var - currentCWin_ = HICN_INITIAL_CWIN; - maxCWin_ = HICN_INITIAL_CWIN_MAX; - - // names/packets var - actualSegment_ = 0; - inflightInterestsCount_ = 0; - interestRetransmissions_.clear(); - lastSegNacked_ = 0; - lastReceived_ = 0; - lastReceivedTime_ = std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()) - .count(); - lastEvent_ = lastReceivedTime_; - highestReceived_ = 0; - firstSequenceInRound_ = 0; - - rtx_timer_used_ = false; - for (int i = 0; i < (1 << default_values::log_2_default_buffer_size); i++) { - inflightInterests_[i] = {0}; - } - - // stats - firstPckReceived_ = false; - receivedBytes_ = 0; - sentInterest_ = 0; - receivedData_ = 0; - packetLost_ = 0; - lossRecovered_ = 0; - avgPacketSize_ = HICN_INIT_PACKET_SIZE; - gotNack_ = false; - gotFutureNack_ = 0; - rounds_ = 0; - roundsWithoutNacks_ = 0; - pathTable_.clear(); - - // CC var - estimatedBw_ = 0.0; - lossRate_ = 0.0; - queuingDelay_ = 0.0; - protocolState_ = HICN_RTC_NORMAL_STATE; - - producerPathLabels_[0] = 0; - producerPathLabels_[1] = 0; - initied = false; - - socket_->setSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, - (uint32_t)HICN_RTC_INTEREST_LIFETIME); - // XXX this should be done by the application -} - -uint32_t max(uint32_t a, uint32_t b) { - if (a > b) - return a; - else - return b; -} - -uint32_t min(uint32_t a, uint32_t b) { - if (a < b) - return a; - else - return b; -} - -void RTCTransportProtocol::newRound() { - round_timer_->expires_from_now(std::chrono::milliseconds(HICN_ROUND_LEN)); - round_timer_->async_wait([this](std::error_code ec) { - if (ec) return; - updateStats(HICN_ROUND_LEN); - newRound(); - }); -} - -void RTCTransportProtocol::updateDelayStats( - const ContentObject &content_object) { - uint32_t segmentNumber = content_object.getName().getSuffix(); - uint32_t pkt = segmentNumber & modMask_; - - if (inflightInterests_[pkt].state != sent_) return; - - if (interestRetransmissions_.find(segmentNumber) != - interestRetransmissions_.end()) - // this packet was rtx at least once - return; - - uint32_t pathLabel = content_object.getPathLabel(); - - if (pathTable_.find(pathLabel) == pathTable_.end()) { - // found a new path - std::shared_ptr newPath = std::make_shared(); - pathTable_[pathLabel] = newPath; - } - - // RTT measurements are useful both from NACKs and data packets - uint64_t RTT = std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()) - .count() - - inflightInterests_[pkt].transmissionTime; - - pathTable_[pathLabel]->insertRttSample(RTT); - auto payload = content_object.getPayload(); - - // we collect OWD only for datapackets - if (payload->length() != HICN_NACK_HEADER_SIZE) { - uint64_t *senderTimeStamp = (uint64_t *)payload->data(); - int64_t OWD = std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()) - .count() - - *senderTimeStamp; - - pathTable_[pathLabel]->insertOwdSample(OWD); - pathTable_[pathLabel]->computeInterArrivalGap(segmentNumber); - } else { - pathTable_[pathLabel]->receivedNack(); - } -} - -void RTCTransportProtocol::updateStats(uint32_t round_duration) { - if (pathTable_.empty()) return; - - if (receivedBytes_ != 0) { - double bytesPerSec = - (double)(receivedBytes_ * - ((double)HICN_MILLI_IN_A_SEC / (double)round_duration)); - estimatedBw_ = (estimatedBw_ * HICN_ESTIMATED_BW_ALPHA) + - ((1 - HICN_ESTIMATED_BW_ALPHA) * bytesPerSec); - } - - uint64_t minRtt = UINT_MAX; - uint64_t maxRtt = 0; - - for (auto it = pathTable_.begin(); it != pathTable_.end(); it++) { - it->second->roundEnd(); - if (it->second->isActive()) { - if (it->second->getMinRtt() < minRtt) { - minRtt = it->second->getMinRtt(); - producerPathLabels_[0] = it->first; - } - if (it->second->getMinRtt() > maxRtt) { - maxRtt = it->second->getMinRtt(); - producerPathLabels_[1] = it->first; - } - } - } - - if (pathTable_.find(producerPathLabels_[0]) == pathTable_.end() || - pathTable_.find(producerPathLabels_[1]) == pathTable_.end()) - return; // this should not happen - - // as a queuing delay we keep the lowest one among the two paths - // if one path is congested the forwarder should decide to do not - // use it so it does not make sense to inform the application - // that maybe we have a problem - if (pathTable_[producerPathLabels_[0]]->getQueuingDealy() < - pathTable_[producerPathLabels_[1]]->getQueuingDealy()) - queuingDelay_ = pathTable_[producerPathLabels_[0]]->getQueuingDealy(); - else - queuingDelay_ = pathTable_[producerPathLabels_[1]]->getQueuingDealy(); - - if (sentInterest_ != 0 && currentState_ == HICN_RTC_NORMAL_STATE) { - uint32_t numberTheoricallyReceivedPackets_ = - highestReceived_ - firstSequenceInRound_; - double lossRate = 0; - if (numberTheoricallyReceivedPackets_ != 0) - lossRate = (double)((double)(packetLost_ - lossRecovered_) / - (double)numberTheoricallyReceivedPackets_); - - if (lossRate < 0) lossRate = 0; - - if (initied) { - lossRate_ = lossRate_ * HICN_ESTIMATED_LOSSES_ALPHA + - (lossRate * (1 - HICN_ESTIMATED_LOSSES_ALPHA)); - } else { - lossRate_ = lossRate; - initied = true; - } - } - - if (avgPacketSize_ == 0) avgPacketSize_ = HICN_INIT_PACKET_SIZE; - - // for the BDP we use the max rtt, so that we calibrate the window on the - // RTT of the slowest path. In this way we are sure that the window will - // never be too small - uint32_t BDP = (uint32_t)ceil( - (estimatedBw_ * - (double)((double)pathTable_[producerPathLabels_[1]]->getMinRtt() / - (double)HICN_MILLI_IN_A_SEC) * - HICN_BANDWIDTH_SLACK_FACTOR) / - avgPacketSize_); - uint32_t BW = (uint32_t)ceil(estimatedBw_); - computeMaxWindow(BW, BDP); - - ConsumerTimerCallback *stats_callback = nullptr; - socket_->getSocketOption(ConsumerCallbacksOptions::STATS_SUMMARY, - &stats_callback); - if (*stats_callback) { - // Send the stats to the app - stats_->updateQueuingDelay(queuingDelay_); - stats_->updateLossRatio(lossRate_); - stats_->updateAverageRtt(pathTable_[producerPathLabels_[1]]->getMinRtt()); - (*stats_callback)(*socket_, *stats_); - } - // bound also by interest lifitime* production rate - if (!gotNack_) { - roundsWithoutNacks_++; - if (currentState_ == HICN_RTC_SYNC_STATE && - roundsWithoutNacks_ >= HICN_ROUNDS_IN_SYNC_BEFORE_SWITCH) { - currentState_ = HICN_RTC_NORMAL_STATE; - } - } else { - roundsWithoutNacks_ = 0; - } - - updateCCState(); - updateWindow(); - - if (queuingDelay_ > 25.0) { - // this indicates that the client will go soon out of synch, - // switch to synch mode - if (currentState_ == HICN_RTC_NORMAL_STATE) { - currentState_ = HICN_RTC_SYNC_STATE; - } - computeMaxWindow(BW, 0); - increaseWindow(); - } - - // in any case we reset all the counters - - gotNack_ = false; - gotFutureNack_ = 0; - receivedBytes_ = 0; - sentInterest_ = 0; - receivedData_ = 0; - packetLost_ = 0; - lossRecovered_ = 0; - rounds_++; - firstSequenceInRound_ = highestReceived_; -} - -void RTCTransportProtocol::updateCCState() { - // TODO -} - -void RTCTransportProtocol::computeMaxWindow(uint32_t productionRate, - uint32_t BDPWin) { - if (productionRate == - 0) // we have no info about the producer, keep the previous maxCWin - return; - - uint32_t interestLifetime = default_values::interest_lifetime; - socket_->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, - interestLifetime); - uint32_t maxWaintingInterest = (uint32_t)ceil( - (productionRate / avgPacketSize_) * - (double)((double)(interestLifetime * - HICN_INTEREST_LIFETIME_REDUCTION_FACTOR) / - (double)HICN_MILLI_IN_A_SEC)); - - if (currentState_ == HICN_RTC_SYNC_STATE) { - // in this case we do not limit the window with the BDP, beacuse most - // likely it is wrong - maxCWin_ = maxWaintingInterest; - return; - } - - // currentState = RTC_NORMAL_STATE - if (BDPWin != 0) { - maxCWin_ = (uint32_t)ceil((double)BDPWin + - (((double)BDPWin * 30.0) / 100.0)); // BDP + 30% - } else { - maxCWin_ = min(maxWaintingInterest, maxCWin_); - } - - if (maxCWin_ < HICN_MIN_CWIN) maxCWin_ = HICN_MIN_CWIN; -} - -void RTCTransportProtocol::updateWindow() { - if (currentState_ == HICN_RTC_SYNC_STATE) return; - - if (currentCWin_ < maxCWin_ * 0.9) { - currentCWin_ = - min(maxCWin_, (uint32_t)(currentCWin_ * HICN_WIN_INCREASE_FACTOR)); - } else if (currentCWin_ > maxCWin_) { - currentCWin_ = - max((uint32_t)(currentCWin_ * HICN_WIN_DECREASE_FACTOR), HICN_MIN_CWIN); - } -} - -void RTCTransportProtocol::decreaseWindow() { - // this is used only in SYNC mode - if (currentState_ == HICN_RTC_NORMAL_STATE) return; - - if (gotFutureNack_ == 1) - currentCWin_ = min((currentCWin_ - 1), - (uint32_t)ceil((double)maxCWin_ * 0.66)); // 2/3 - else - currentCWin_--; - - currentCWin_ = max(currentCWin_, HICN_MIN_CWIN); -} - -void RTCTransportProtocol::increaseWindow() { - // this is used only in SYNC mode - if (currentState_ == HICN_RTC_NORMAL_STATE) return; - - // we need to be carefull to do not increase the window to much - if (currentCWin_ < ((double)maxCWin_ * 0.7)) { - currentCWin_ = currentCWin_ + 1; // exponential - } else { - currentCWin_ = min( - maxCWin_, - (uint32_t)ceil(currentCWin_ + (1.0 / (double)currentCWin_))); // linear - } -} - -void RTCTransportProtocol::probeRtt() { - probe_timer_->expires_from_now(std::chrono::milliseconds(1000)); - probe_timer_->async_wait([this](std::error_code ec) { - if (ec) return; - probeRtt(); - }); - - // To avoid sending the first probe, because the transport is not running yet - if (is_first_ && !is_running_) return; - - time_sent_probe_ = std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()) - .count(); - - Name *interest_name = nullptr; - socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME, - &interest_name); - // get a random numbe in the probe seq range - std::default_random_engine eng((std::random_device())()); - std::uniform_int_distribution idis(HICN_MIN_PROBE_SEQ, - HICN_MAX_PROBE_SEQ); - probe_seq_number_ = idis(eng); - interest_name->setSuffix(probe_seq_number_); - - // we considere the probe as a rtx so that we do not incresea inFlightInt - received_probe_ = false; - TRANSPORT_LOGD("Send content interest %u (probeRtt)", - interest_name->getSuffix()); - sendInterest(interest_name, true); -} - -void RTCTransportProtocol::sendInterest(Name *interest_name, bool rtx) { - auto interest = getPacket(); - interest->setName(*interest_name); - - uint32_t interestLifetime = default_values::interest_lifetime; - socket_->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, - interestLifetime); - interest->setLifetime(uint32_t(interestLifetime)); - - ConsumerInterestCallback *on_interest_output = nullptr; - - socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_OUTPUT, - &on_interest_output); - - if (*on_interest_output) { - (*on_interest_output)(*socket_, *interest); - } - - if (TRANSPORT_EXPECT_FALSE(!is_running_ && !is_first_)) { - return; - } - - portal_->sendInterest(std::move(interest)); - - sentInterest_++; - - if (!rtx) { - packets_in_window_[interest_name->getSuffix()] = 0; - inflightInterestsCount_++; - } -} - -void RTCTransportProtocol::scheduleNextInterests() { - if (!is_running_ && !is_first_) return; - - TRANSPORT_LOGD("----- [window %u - inflight_interests %u = %d] -----", - currentCWin_, inflightInterestsCount_, - currentCWin_ - inflightInterestsCount_); - - while (inflightInterestsCount_ < currentCWin_) { - Name *interest_name = nullptr; - socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME, - &interest_name); - - interest_name->setSuffix(actualSegment_); - - // if the producer socket is not stated (does not reply even with nacks) - // we keep asking for something without marking anything as lost (see - // timeout). In this way when the producer socket will start the - // consumer socket will not miss any packet - if (TRANSPORT_EXPECT_FALSE(!firstPckReceived_)) { - uint32_t pkt = actualSegment_ & modMask_; - inflightInterests_[pkt].state = sent_; - inflightInterests_[pkt].sequence = actualSegment_; - actualSegment_ = (actualSegment_ + 1) % HICN_MIN_PROBE_SEQ; - TRANSPORT_LOGD( - "Send content interest %u (scheduleNextInterests no replies)", - interest_name->getSuffix()); - sendInterest(interest_name, false); - return; - } - - // we send the packet only if it is not pending yet - // notice that this is not true for rtx packets - if (portal_->interestIsPending(*interest_name)) { - actualSegment_ = (actualSegment_ + 1) % HICN_MIN_PROBE_SEQ; - continue; - } - - uint32_t pkt = actualSegment_ & modMask_; - // if we already reacevied the content we don't ask it again - if (inflightInterests_[pkt].state == received_ && - inflightInterests_[pkt].sequence == actualSegment_) { - actualSegment_ = (actualSegment_ + 1) % HICN_MIN_PROBE_SEQ; - continue; - } - - // same if the packet is lost - if (inflightInterests_[pkt].state == lost_ && - inflightInterests_[pkt].sequence == actualSegment_) { - actualSegment_ = (actualSegment_ + 1) % HICN_MIN_PROBE_SEQ; - continue; - } - - inflightInterests_[pkt].transmissionTime = - std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()) - .count(); - - // here the packet can be in any state except for lost or recevied - inflightInterests_[pkt].state = sent_; - inflightInterests_[pkt].sequence = actualSegment_; - actualSegment_ = (actualSegment_ + 1) % HICN_MIN_PROBE_SEQ; - - TRANSPORT_LOGD("Send content interest %u (scheduleNextInterests)", - interest_name->getSuffix()); - sendInterest(interest_name, false); - } - - TRANSPORT_LOGD("----- end of scheduleNextInterest -----"); -} - -bool RTCTransportProtocol::verifyKeyPackets() { - // Not yet implemented - return false; -} - -void RTCTransportProtocol::sentinelTimer() { - uint32_t wait = 50; - - if (pathTable_.find(producerPathLabels_[0]) != pathTable_.end() && - pathTable_.find(producerPathLabels_[1]) != pathTable_.end()) { - // we have all the info to set the timers - wait = round(pathTable_[producerPathLabels_[0]]->getInterArrivalGap()); - if (wait == 0) wait = 1; - } - - sentinel_timer_->expires_from_now(std::chrono::milliseconds(wait)); - sentinel_timer_->async_wait([this](std::error_code ec) { - if (ec) return; - - uint64_t now = std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()) - .count(); - - if (pathTable_.find(producerPathLabels_[0]) == pathTable_.end() || - pathTable_.find(producerPathLabels_[1]) == pathTable_.end()) { - // we have no info, so we send again - - for (auto it = packets_in_window_.begin(); it != packets_in_window_.end(); - it++) { - uint32_t pkt = it->first & modMask_; - if (inflightInterests_[pkt].sequence == it->first) { - inflightInterests_[pkt].transmissionTime = now; - Name *interest_name = nullptr; - socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME, - &interest_name); - interest_name->setSuffix(it->first); - it->second++; - sendInterest(interest_name, true); - } - } - } else { - uint64_t max_waiting_time = // wait at least 50ms - (pathTable_[producerPathLabels_[1]]->getMinRtt() - - pathTable_[producerPathLabels_[0]]->getMinRtt()) + - (ceil(pathTable_[producerPathLabels_[0]]->getInterArrivalGap()) * 50); - - if ((currentState_ == HICN_RTC_NORMAL_STATE) && - (inflightInterestsCount_ >= currentCWin_) && - ((now - lastEvent_) > max_waiting_time) && (lossRate_ >= 0.05)) { - uint64_t RTT = pathTable_[producerPathLabels_[1]]->getMinRtt(); - - for (auto it = packets_in_window_.begin(); - it != packets_in_window_.end(); it++) { - uint32_t pkt = it->first & modMask_; - if (inflightInterests_[pkt].sequence == it->first && - ((now - inflightInterests_[pkt].transmissionTime) >= RTT)) { - inflightInterests_[pkt].transmissionTime = now; - Name *interest_name = nullptr; - socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME, - &interest_name); - interest_name->setSuffix(it->first); - it->second++; - sendInterest(interest_name, true); - } - } - } - } - - sentinelTimer(); - }); -} -void RTCTransportProtocol::addRetransmissions(uint32_t val) { - // add only val in the rtx list - addRetransmissions(val, val + 1); -} - -void RTCTransportProtocol::addRetransmissions(uint32_t start, uint32_t stop) { - uint64_t now = std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()) - .count(); - - bool new_rtx = false; - for (uint32_t i = start; i < stop; i++) { - auto it = interestRetransmissions_.find(i); - if (it == interestRetransmissions_.end()) { - uint32_t pkt = i & modMask_; - if (lastSegNacked_ <= i && inflightInterests_[pkt].state != received_) { - // it must be larger than the last past nack received - packetLost_++; - interestRetransmissions_[i] = 0; - uint32_t pkt = i & modMask_; - // we reset the transmission time setting to now, so that rtx will - // happne in one RTT on waint one inter arrival gap - inflightInterests_[pkt].transmissionTime = now; - new_rtx = true; - } - } // if the retransmission is already there the rtx timer will - // take care of it - } - - // in case a new rtx is added to the map we need to run checkRtx() - if (new_rtx) { - if (rtx_timer_used_) { - // if a timer is pending we need to delete it - rtx_timer_->cancel(); - rtx_timer_used_ = false; - } - checkRtx(); - } -} - -uint64_t RTCTransportProtocol::retransmit() { - auto it = interestRetransmissions_.begin(); - - // cut len to max HICN_MAX_RTX_SIZE - // since we use a map, the smaller (and so the older) sequence number are at - // the beginnin of the map - while (interestRetransmissions_.size() > HICN_MAX_RTX_SIZE) { - it = interestRetransmissions_.erase(it); - } - - it = interestRetransmissions_.begin(); - uint64_t smallest_timeout = ULONG_MAX; - uint64_t now = std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()) - .count(); - - while (it != interestRetransmissions_.end()) { - uint32_t pkt = it->first & modMask_; - - if (inflightInterests_[pkt].sequence != it->first) { - // this packet is not anymore in the inflight buffer, erase it - it = interestRetransmissions_.erase(it); - continue; - } - - // we retransmitted the packet too many times - if (it->second >= HICN_MAX_RTX) { - it = interestRetransmissions_.erase(it); - continue; - } - - // this packet is too old - if ((lastReceived_ > it->first) && - (lastReceived_ - it->first) > HICN_MAX_RTX_MAX_AGE) { - it = interestRetransmissions_.erase(it); - continue; - } - - uint64_t rtx_time = now; - - if (it->second == 0) { - // first rtx - if (producerPathLabels_[0] != producerPathLabels_[1]) { - // multipath - if (pathTable_.find(producerPathLabels_[0]) != pathTable_.end() && - pathTable_.find(producerPathLabels_[1]) != pathTable_.end() && - (pathTable_[producerPathLabels_[0]]->getInterArrivalGap() < - HICN_MIN_INTER_ARRIVAL_GAP)) { - rtx_time = lastReceivedTime_ + - (pathTable_[producerPathLabels_[1]]->getMinRtt() - - pathTable_[producerPathLabels_[0]]->getMinRtt()) + - pathTable_[producerPathLabels_[0]]->getInterArrivalGap(); - } // else low rate producer, send it immediatly - } else { - // single path - if (pathTable_.find(producerPathLabels_[0]) != pathTable_.end() && - (pathTable_[producerPathLabels_[0]]->getInterArrivalGap() < - HICN_MIN_INTER_ARRIVAL_GAP)) { - rtx_time = lastReceivedTime_ + - pathTable_[producerPathLabels_[0]]->getInterArrivalGap(); - } // else low rate producer send immediatly - } - } else { - // second or plus rtx, wait for the min rtt - if (pathTable_.find(producerPathLabels_[0]) != pathTable_.end()) { - uint64_t sent_time = inflightInterests_[pkt].transmissionTime; - rtx_time = sent_time + pathTable_[producerPathLabels_[0]]->getMinRtt(); - } // if we don't have info we send it immediatly - } - - if (now >= rtx_time) { - inflightInterests_[pkt].transmissionTime = now; - it->second++; - - Name *interest_name = nullptr; - socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME, - &interest_name); - interest_name->setSuffix(it->first); - TRANSPORT_LOGD("Send content interest %u (retransmit)", - interest_name->getSuffix()); - sendInterest(interest_name, true); - } else if (rtx_time < smallest_timeout) { - smallest_timeout = rtx_time; - } - - ++it; - } - return smallest_timeout; -} - -void RTCTransportProtocol::checkRtx() { - if (interestRetransmissions_.empty()) { - rtx_timer_used_ = false; - return; - } - - uint64_t next_timeout = retransmit(); - uint64_t wait = 1; - uint64_t now = std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()) - .count(); - if (next_timeout != ULONG_MAX && now < next_timeout) { - wait = next_timeout - now; - } - rtx_timer_used_ = true; - rtx_timer_->expires_from_now(std::chrono::milliseconds(wait)); - rtx_timer_->async_wait([this](std::error_code ec) { - if (ec) return; - rtx_timer_used_ = false; - checkRtx(); - }); -} - -void RTCTransportProtocol::onTimeout(Interest::Ptr &&interest) { - uint32_t segmentNumber = interest->getName().getSuffix(); - - if (segmentNumber >= HICN_MIN_PROBE_SEQ) { - // this is a timeout on a probe, do nothing - return; - } - - uint32_t pkt = segmentNumber & modMask_; - - if (TRANSPORT_EXPECT_FALSE(!firstPckReceived_)) { - // we do nothing, and we keep asking the same stuff over - // and over until we get at least a packet - inflightInterestsCount_--; - lastEvent_ = std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()) - .count(); - packets_in_window_.erase(segmentNumber); - scheduleNextInterests(); - return; - } - - if (inflightInterests_[pkt].state == sent_) { - lastEvent_ = std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()) - .count(); - packets_in_window_.erase(segmentNumber); - inflightInterestsCount_--; - } - - // check how many times we sent this packet - auto it = interestRetransmissions_.find(segmentNumber); - if (it != interestRetransmissions_.end() && it->second >= HICN_MAX_RTX) { - inflightInterests_[pkt].state = lost_; - } - - if (inflightInterests_[pkt].state == sent_) { - inflightInterests_[pkt].state = timeout1_; - } else if (inflightInterests_[pkt].state == timeout1_) { - inflightInterests_[pkt].state = timeout2_; - } else if (inflightInterests_[pkt].state == timeout2_) { - inflightInterests_[pkt].state = lost_; - } - - if (inflightInterests_[pkt].state == lost_) { - interestRetransmissions_.erase(segmentNumber); - } else { - addRetransmissions(segmentNumber); - } - - scheduleNextInterests(); -} - -bool RTCTransportProtocol::onNack(const ContentObject &content_object, - bool rtx) { - uint32_t *payload = (uint32_t *)content_object.getPayload()->data(); - uint32_t productionSeg = *payload; - uint32_t productionRate = *(++payload); - uint32_t nackSegment = content_object.getName().getSuffix(); - - bool old_nack = false; - - // if we did not received anything between lastReceived_ + 1 and productionSeg - // most likelly some packets got lost - if (lastReceived_ != 0) { - addRetransmissions(lastReceived_ + 1, productionSeg); - } - - if (!rtx) { - gotNack_ = true; - // we synch the estimated production rate with the actual one - estimatedBw_ = (double)productionRate; - } - - if (productionSeg > nackSegment) { - // we are asking for stuff produced in the past - actualSegment_ = max(productionSeg, actualSegment_) % HICN_MIN_PROBE_SEQ; - - if (!rtx) { - if (currentState_ == HICN_RTC_NORMAL_STATE) { - currentState_ = HICN_RTC_SYNC_STATE; - } - - computeMaxWindow(productionRate, 0); - increaseWindow(); - } - - lastSegNacked_ = productionSeg; - old_nack = true; - - } else if (productionSeg < nackSegment) { - actualSegment_ = productionSeg % HICN_MIN_PROBE_SEQ; - - if (!rtx) { - // we are asking stuff in the future - gotFutureNack_++; - computeMaxWindow(productionRate, 0); - decreaseWindow(); - - if (currentState_ == HICN_RTC_SYNC_STATE) { - currentState_ = HICN_RTC_NORMAL_STATE; - } - } - } else { - // we are asking the right thing, but the producer is slow - // keep doing the same until the packet is produced - actualSegment_ = productionSeg % HICN_MIN_PROBE_SEQ; - } - - return old_nack; -} - -void RTCTransportProtocol::onContentObject( - Interest::Ptr &&interest, ContentObject::Ptr &&content_object) { - // as soon as we get a packet firstPckReceived_ will never be false - firstPckReceived_ = true; - - auto payload = content_object->getPayload(); - uint32_t payload_size = (uint32_t)payload->length(); - uint32_t segmentNumber = content_object->getName().getSuffix(); - uint32_t pkt = segmentNumber & modMask_; - - ConsumerContentObjectCallback *callback_content_object = nullptr; - socket_->getSocketOption(ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT, - &callback_content_object); - if (*callback_content_object) { - (*callback_content_object)(*socket_, *content_object); - } - - if (segmentNumber >= HICN_MIN_PROBE_SEQ) { - TRANSPORT_LOGD("Received probe %u", segmentNumber); - if (segmentNumber == probe_seq_number_ && !received_probe_) { - received_probe_ = true; - - uint32_t pathLabel = content_object->getPathLabel(); - if (pathTable_.find(pathLabel) == pathTable_.end()) { - std::shared_ptr newPath = std::make_shared(); - pathTable_[pathLabel] = newPath; - } - - // this is the expected probe, update the RTT and drop the packet - uint64_t RTT = std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()) - .count() - - time_sent_probe_; - - pathTable_[pathLabel]->insertRttSample(RTT); - pathTable_[pathLabel]->receivedNack(); - } - return; - } - - // check if the packet is a rtx - bool is_rtx = false; - if (interestRetransmissions_.find(segmentNumber) != - interestRetransmissions_.end()) { - is_rtx = true; - } else { - auto it_win = packets_in_window_.find(segmentNumber); - if (it_win != packets_in_window_.end() && it_win->second != 0) - is_rtx = true; - } - - if (payload_size == HICN_NACK_HEADER_SIZE) { - TRANSPORT_LOGD("Received nack %u", segmentNumber); - - if (inflightInterests_[pkt].state == sent_) { - lastEvent_ = std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()) - .count(); - packets_in_window_.erase(segmentNumber); - inflightInterestsCount_--; - } - - bool old_nack = false; - - if (!is_rtx) { - // this is not a retransmitted packet - old_nack = onNack(*content_object, false); - updateDelayStats(*content_object); - } else { - old_nack = onNack(*content_object, true); - } - - // the nacked_ state is used only to avoid to decrease - // inflightInterestsCount_ multiple times. In fact, every time that we - // receive an event related to an interest (timeout, nacked, content) we - // cange the state. In this way we are sure that we do not decrease twice - // the counter - if (old_nack) { - inflightInterests_[pkt].state = lost_; - interestRetransmissions_.erase(segmentNumber); - } else { - inflightInterests_[pkt].state = nacked_; - } - - } else { - TRANSPORT_LOGD("Received content %u", segmentNumber); - - avgPacketSize_ = (HICN_ESTIMATED_PACKET_SIZE * avgPacketSize_) + - ((1 - HICN_ESTIMATED_PACKET_SIZE) * payload->length()); - - receivedBytes_ += (uint32_t)(content_object->headerSize() + - content_object->payloadSize()); - - if (inflightInterests_[pkt].state == sent_) { - lastEvent_ = std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()) - .count(); - packets_in_window_.erase(segmentNumber); - inflightInterestsCount_--; // packet sent without timeouts - } - - if (inflightInterests_[pkt].state == sent_ && !is_rtx) { - // delay stats are computed only for non retransmitted data - updateDelayStats(*content_object); - } - - addRetransmissions(lastReceived_ + 1, segmentNumber); - if (segmentNumber > highestReceived_) { - highestReceived_ = segmentNumber; - } - if (segmentNumber > lastReceived_) { - lastReceived_ = segmentNumber; - lastReceivedTime_ = - std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()) - .count(); - } - receivedData_++; - inflightInterests_[pkt].state = received_; - - auto it = interestRetransmissions_.find(segmentNumber); - if (it != interestRetransmissions_.end()) lossRecovered_++; - - interestRetransmissions_.erase(segmentNumber); - - reassemble(std::move(content_object)); - increaseWindow(); - } - - scheduleNextInterests(); -} - -} // end namespace protocol - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/protocols/rtc.h b/libtransport/src/hicn/transport/protocols/rtc.h deleted file mode 100644 index f34afbb5f..000000000 --- a/libtransport/src/hicn/transport/protocols/rtc.h +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiTC_SYNC_STATE - * 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 -#include -#include - -#include -#include -#include - -// algorithm state -#define HICN_RTC_SYNC_STATE 0 -#define HICN_RTC_NORMAL_STATE 1 -#define HICN_ROUNDS_IN_SYNC_BEFORE_SWITCH 3 - -// packet constants -#define HICN_INIT_PACKET_SIZE 1300 // bytes -#define HICN_PACKET_HEADER_SIZE 60 // bytes ipv6+tcp -#define HICN_NACK_HEADER_SIZE 8 // bytes -#define HICN_TIMESTAMP_SIZE 8 // bytes -#define HICN_RTC_INTEREST_LIFETIME 1000 // ms - -// rtt measurement -// normal interests for data goes from 0 to -// HICN_MIN_PROBE_SEQ, the rest is reserverd for -// probes -#define HICN_MIN_PROBE_SEQ 0xefffffff -#define HICN_MAX_PROBE_SEQ 0xffffffff - -// controller constant -#define HICN_ROUND_LEN \ - 200 // ms interval of time on which - // we take decisions / measurements -#define HICN_MAX_RTX 10 -#define HICN_MAX_RTX_SIZE 1024 -#define HICN_MAX_RTX_MAX_AGE 10000 -#define HICN_MIN_RTT_WIN 30 // rounds -#define HICN_MIN_INTER_ARRIVAL_GAP 100 // ms - -// cwin -#define HICN_INITIAL_CWIN 1 // packets -#define HICN_INITIAL_CWIN_MAX 100000 // packets -#define HICN_MIN_CWIN 10 // packets -#define HICN_WIN_INCREASE_FACTOR 1.5 -#define HICN_WIN_DECREASE_FACTOR 0.9 - -// statistics constants -#define HICN_BANDWIDTH_SLACK_FACTOR 1.8 -#define HICN_ESTIMATED_BW_ALPHA 0.7 -#define HICN_ESTIMATED_PACKET_SIZE 0.7 -#define HICN_ESTIMATED_LOSSES_ALPHA 0.8 -#define HICN_INTEREST_LIFETIME_REDUCTION_FACTOR 0.8 - -// other constants -#define HICN_NANO_IN_A_SEC 1000000000 -#define HICN_MICRO_IN_A_SEC 1000000 -#define HICN_MILLI_IN_A_SEC 1000 - -namespace transport { - -namespace protocol { - -enum packetState { sent_, nacked_, received_, timeout1_, timeout2_, lost_ }; - -typedef enum packetState packetState_t; - -struct sentInterest { - uint64_t transmissionTime; - uint32_t sequence; // sequence number of the interest sent - // to handle seq % buffer_size - packetState_t state; // see packet state -}; - -class RTCTransportProtocol : public TransportProtocol, - public DatagramReassembly { - public: - RTCTransportProtocol(interface::ConsumerSocket *icnet_socket); - - ~RTCTransportProtocol(); - - int start() override; - - void stop() override; - - void resume() override; - - bool verifyKeyPackets() override; - - private: - // algo functions - void reset() override; - - // CC functions - void updateDelayStats(const ContentObject &content_object); - void updateStats(uint32_t round_duration); - void updateCCState(); - void computeMaxWindow(uint32_t productionRate, uint32_t BDPWin); - void updateWindow(); - void decreaseWindow(); - void increaseWindow(); - void resetPreviousWindow(); - - // packet functions - void sendInterest(Name *interest_name, bool rtx); - void scheduleNextInterests() override; - void sentinelTimer(); - void addRetransmissions(uint32_t val); - void addRetransmissions(uint32_t start, uint32_t stop); - uint64_t retransmit(); - void checkRtx(); - void probeRtt(); - void newRound(); - void onTimeout(Interest::Ptr &&interest) override; - bool onNack(const ContentObject &content_object, bool rtx); - void onContentObject(Interest::Ptr &&interest, - ContentObject::Ptr &&content_object) override; - void onPacketDropped(Interest::Ptr &&interest, - ContentObject::Ptr &&content_object) override {} - void onReassemblyFailed(std::uint32_t missing_segment) override {} - - TRANSPORT_ALWAYS_INLINE virtual void reassemble( - ContentObject::Ptr &&content_object) override { - auto read_buffer = content_object->getPayload(); - read_buffer->trimStart(HICN_TIMESTAMP_SIZE); - Reassembly::read_buffer_ = std::move(read_buffer); - Reassembly::notifyApplication(); - } - - // controller var - std::unique_ptr round_timer_; - unsigned currentState_; - - // cwin var - uint32_t currentCWin_; - uint32_t maxCWin_; - - // names/packets var - uint32_t actualSegment_; - uint32_t inflightInterestsCount_; - // map seq to rtx - std::map interestRetransmissions_; - bool rtx_timer_used_; - std::unique_ptr rtx_timer_; - std::vector inflightInterests_; - uint32_t lastSegNacked_; // indicates the segment id in the last received - // past Nack. we do not ask for retransmissions - // for samething that is older than this value. - uint32_t lastReceived_; // segment of the last content object received - // indicates the base of the window on the client - uint64_t lastReceivedTime_; // time at which we recevied the - // lastReceived_ packet - - // sentinel - // if all packets in the window get lost we need something that - // wakes up our consumer socket. Interest timeouts set to 1 sec - // expire too late. This timers expire much sooner and if it - // detects that all the interest in the window may be lost - // it sends all of them again - std::unique_ptr sentinel_timer_; - uint64_t lastEvent_; // time at which we removed a pending - // interest from the window - std::unordered_map packets_in_window_; - - // rtt probes - // the RTC transport tends to overestimate the RTT - // du to the production time on the server side - // once per second we send an interest for wich we know - // we will get a nack. This nack will keep our estimation - // close to the reality - std::unique_ptr probe_timer_; - uint64_t time_sent_probe_; - uint32_t probe_seq_number_; - bool received_probe_; - - uint32_t modMask_; - - // stats - bool firstPckReceived_; - uint32_t receivedBytes_; - uint32_t sentInterest_; - uint32_t receivedData_; - int32_t packetLost_; - int32_t lossRecovered_; - uint32_t firstSequenceInRound_; - uint32_t highestReceived_; - double avgPacketSize_; - bool gotNack_; - uint32_t gotFutureNack_; - uint32_t rounds_; - uint32_t roundsWithoutNacks_; - - // we keep track of up two paths (if only one path is in use - // the two values in the vector will be the same) - // position 0 stores the path with minRTT - // position 1 stores the path with maxRTT - uint32_t producerPathLabels_[2]; - - std::unordered_map> pathTable_; - uint32_t roundCounter_; - - // CC var - double estimatedBw_; - double lossRate_; - double queuingDelay_; - unsigned protocolState_; - - bool initied; -}; - -} // namespace protocol - -} // namespace transport diff --git a/libtransport/src/hicn/transport/protocols/rtc_data_path.cc b/libtransport/src/hicn/transport/protocols/rtc_data_path.cc deleted file mode 100644 index 0cbff0e3c..000000000 --- a/libtransport/src/hicn/transport/protocols/rtc_data_path.cc +++ /dev/null @@ -1,160 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include - -#define MAX_ROUNDS_WITHOUT_PKTS 10 //2sec - -namespace transport { - -namespace protocol { - -RTCDataPath::RTCDataPath() - : min_rtt(UINT_MAX), - prev_min_rtt(UINT_MAX), - min_owd(INT_MAX), // this is computed like in LEDBAT, so it is not the - // real OWD, but the measured one, that depends on the - // clock of sender and receiver. the only meaningful - // value is is the queueing delay. for this reason we - // keep both RTT (for the windowd calculation) and OWD - // (for congestion/quality control) - prev_min_owd(INT_MAX), - avg_owd(0.0), - queuing_delay(DBL_MAX), - lastRecvSeq_(0), - lastRecvTime_(0), - avg_inter_arrival_(DBL_MAX), - received_nacks_(false), - received_packets_(false), - rounds_without_packets_(0), - RTThistory_(HISTORY_LEN), - OWDhistory_(HISTORY_LEN){}; - -void RTCDataPath::insertRttSample(uint64_t rtt) { - // for the rtt we only keep track of the min one - if (rtt < min_rtt) min_rtt = rtt; -} - -void RTCDataPath::insertOwdSample(int64_t owd) { - // for owd we use both min and avg - if (owd < min_owd) min_owd = owd; - - if(avg_owd != DBL_MAX) - avg_owd = (avg_owd * (1 - ALPHA_RTC)) + (owd * ALPHA_RTC); - else { - avg_owd = owd; - } - - //owd is computed only for valid data packets so we count only - //this for decide if we recevie traffic or not - received_packets_ = true; -} - -void RTCDataPath::computeInterArrivalGap(uint32_t segmentNumber){ - - //got packet in sequence, compute gap - if(lastRecvSeq_ == (segmentNumber - 1)){ - uint64_t now = std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()) - .count(); - uint64_t delta = now - lastRecvTime_; - lastRecvSeq_ = segmentNumber; - lastRecvTime_ = now; - if(avg_inter_arrival_ == DBL_MAX) - avg_inter_arrival_ = delta; - else - avg_inter_arrival_ = (avg_inter_arrival_ * (1 -ALPHA_RTC)) - + (delta * ALPHA_RTC); - return; - } - - //ooo packet, update the stasts if needed - if(lastRecvSeq_ <= segmentNumber){ - lastRecvSeq_ = segmentNumber; - lastRecvTime_ = std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()) - .count(); - } -} - -void RTCDataPath::receivedNack(){ - received_nacks_ = true; -} - -double RTCDataPath::getInterArrivalGap(){ - if(avg_inter_arrival_ == DBL_MAX) - return 0; - return avg_inter_arrival_; -} - -bool RTCDataPath::isActive(){ - if(received_nacks_ && rounds_without_packets_ < MAX_ROUNDS_WITHOUT_PKTS) - return true; - return false; -} - -void RTCDataPath::roundEnd() { - // reset min_rtt and add it to the history - if (min_rtt != UINT_MAX) { - prev_min_rtt = min_rtt; - } else { - // this may happen if we do not receive any packet - // from this path in the last round. in this case - // we use the measure from the previuos round - min_rtt = prev_min_rtt; - } - - if(min_rtt == 0) - min_rtt = 1; - - RTThistory_.pushBack(min_rtt); - min_rtt = UINT_MAX; - - // do the same for min owd - if (min_owd != INT_MAX) { - prev_min_owd = min_owd; - } else { - min_owd = prev_min_owd; - } - - if (min_owd != INT_MAX) { - OWDhistory_.pushBack(min_owd); - min_owd = INT_MAX; - - // compute queuing delay - queuing_delay = avg_owd - getMinOwd(); - - } else { - queuing_delay = 0.0; - } - - if(!received_packets_) - rounds_without_packets_++; - else - rounds_without_packets_ = 0; - received_packets_ = false; -} - -double RTCDataPath::getQueuingDealy() { return queuing_delay; } - -uint64_t RTCDataPath::getMinRtt() { return RTThistory_.begin(); } - -int64_t RTCDataPath::getMinOwd() { return OWDhistory_.begin(); } - -} // end namespace protocol - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/protocols/rtc_data_path.h b/libtransport/src/hicn/transport/protocols/rtc_data_path.h deleted file mode 100644 index 48a67c525..000000000 --- a/libtransport/src/hicn/transport/protocols/rtc_data_path.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include - -#define ALPHA_RTC 0.125 -#define HISTORY_LEN 20 //4 sec - -namespace transport { - -namespace protocol { - -class RTCDataPath { - public: - RTCDataPath(); - - public: - void insertRttSample(uint64_t rtt); - void insertOwdSample(int64_t owd); - void computeInterArrivalGap(uint32_t segmentNumber); - void receivedNack(); - - uint64_t getMinRtt(); - double getQueuingDealy(); - double getInterArrivalGap(); - bool isActive(); - - void roundEnd(); - - private: - int64_t getMinOwd(); - - uint64_t min_rtt; - uint64_t prev_min_rtt; - - int64_t min_owd; - int64_t prev_min_owd; - - double avg_owd; - - double queuing_delay; - - uint32_t lastRecvSeq_; - uint64_t lastRecvTime_; - double avg_inter_arrival_; - - //flags to check if a path is active - //we considere a path active if it reaches a producer - //(not a cache) --aka we got at least one nack on this path-- - //and if we receives packets - bool received_nacks_; - bool received_packets_; - uint8_t rounds_without_packets_; //if we don't get any packet - //for MAX_ROUNDS_WITHOUT_PKTS - //we consider the path inactive - - utils::MinFilter RTThistory_; - utils::MinFilter OWDhistory_; -}; - -} // namespace protocol - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/protocols/statistics.h b/libtransport/src/hicn/transport/protocols/statistics.h deleted file mode 100644 index c92940ab4..000000000 --- a/libtransport/src/hicn/transport/protocols/statistics.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -#include - -namespace transport { - -namespace protocol { - -class TransportStatistics { - static constexpr double default_alpha = 0.7; - - public: - TransportStatistics(double alpha = default_alpha) - : retx_count_(0), - bytes_received_(0), - average_rtt_(0), - avg_window_size_(0), - interest_tx_(0), - alpha_(alpha), - loss_ratio_(0.0), - queuing_delay_(0.0) {} - - TRANSPORT_ALWAYS_INLINE void updateRetxCount(uint64_t retx) { - retx_count_ += retx; - } - - TRANSPORT_ALWAYS_INLINE void updateBytesRecv(uint64_t bytes) { - bytes_received_ += bytes; - } - - TRANSPORT_ALWAYS_INLINE void updateAverageRtt(uint64_t rtt) { - average_rtt_ = (alpha_ * average_rtt_) + ((1. - alpha_) * double(rtt)); - } - - TRANSPORT_ALWAYS_INLINE void updateAverageWindowSize(double current_window) { - avg_window_size_ = - (alpha_ * avg_window_size_) + ((1. - alpha_) * current_window); - } - - TRANSPORT_ALWAYS_INLINE void updateInterestTx(uint64_t int_tx) { - interest_tx_ += int_tx; - } - - TRANSPORT_ALWAYS_INLINE void updateLossRatio(double loss_ratio) { - loss_ratio_ = loss_ratio; - } - - TRANSPORT_ALWAYS_INLINE void updateQueuingDelay(double queuing_delay) { - queuing_delay_ = queuing_delay; - } - - TRANSPORT_ALWAYS_INLINE uint64_t getRetxCount() const { return retx_count_; } - - TRANSPORT_ALWAYS_INLINE uint64_t getBytesRecv() const { - return bytes_received_; - } - - TRANSPORT_ALWAYS_INLINE double getAverageRtt() const { return average_rtt_; } - - TRANSPORT_ALWAYS_INLINE double getAverageWindowSize() const { - return avg_window_size_; - } - - TRANSPORT_ALWAYS_INLINE uint64_t getInterestTx() const { - return interest_tx_; - } - - TRANSPORT_ALWAYS_INLINE double getLossRatio() const { return loss_ratio_; } - - TRANSPORT_ALWAYS_INLINE double getQueuingDelay() const { - return queuing_delay_; - } - - TRANSPORT_ALWAYS_INLINE void reset() { - retx_count_ = 0; - bytes_received_ = 0; - average_rtt_ = 0; - avg_window_size_ = 0; - interest_tx_ = 0; - loss_ratio_ = 0; - } - - private: - uint64_t retx_count_; - uint64_t bytes_received_; - double average_rtt_; - double avg_window_size_; - uint64_t interest_tx_; - double alpha_; - double loss_ratio_; - double queuing_delay_; -}; - -} // end namespace protocol - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/protocols/test/CMakeLists.txt b/libtransport/src/hicn/transport/protocols/test/CMakeLists.txt deleted file mode 100644 index 6f9fdb9aa..000000000 --- a/libtransport/src/hicn/transport/protocols/test/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -# Enable gcov output for the tests -add_definitions(--coverage) -set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage") - -set(TestsExpectedToPass - test_transport_producer) - -foreach(test ${TestsExpectedToPass}) - AddTest(${test}) -endforeach() \ No newline at end of file diff --git a/libtransport/src/hicn/transport/protocols/test/test_transport_producer.cc b/libtransport/src/hicn/transport/protocols/test/test_transport_producer.cc deleted file mode 100644 index 204f2cbe2..000000000 --- a/libtransport/src/hicn/transport/protocols/test/test_transport_producer.cc +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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. - */ - -#include - -#include "../socket_producer.h" -#include "literals.h" - -#include -#include - -namespace transport { - -namespace protocol { - -namespace { -// The fixture for testing class Foo. -class ProducerTest : public ::testing::Test { - protected: - ProducerTest() : name_("b001::123|321"), producer_(io_service_) { - // You can do set-up work for each test here. - } - - virtual ~ProducerTest() { - // You can do clean-up work that doesn't throw exceptions here. - } - - // If the constructor and destructor are not enough for setting up - // and cleaning up each test, you can define the following methods: - - virtual void SetUp() { - // Code here will be called immediately after the constructor (right - // before each test). - } - - virtual void TearDown() { - // Code here will be called immediately after each test (right - // before the destructor). - } - - Name name_; - asio::io_service io_service_; - ProducerSocket producer_; -}; - -} // namespace - -// Tests that the Foo::Bar() method does Abc. -TEST_F(ProducerTest, ProduceContent) { - std::string content(250000, '?'); - - producer_.registerPrefix(Prefix("b001::/64")); - producer_.produce(name_, reinterpret_cast(content.data()), - content.size(), true); - producer_.setSocketOption(GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME, - 500000000_U32); - producer_.attach(); - producer_.serveForever(); -} - -} // namespace protocol - -} // namespace transport - -int main(int argc, char **argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} \ No newline at end of file diff --git a/libtransport/src/hicn/transport/protocols/verification_manager.cc b/libtransport/src/hicn/transport/protocols/verification_manager.cc deleted file mode 100644 index 74faf0521..000000000 --- a/libtransport/src/hicn/transport/protocols/verification_manager.cc +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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. - */ - -#include -#include - -namespace transport { - -namespace protocol { - -interface::VerificationPolicy SignatureVerificationManager::onPacketToVerify( - const Packet& packet) { - using namespace interface; - - bool verify_signature = false, key_content = false; - VerificationPolicy ret = VerificationPolicy::DROP_PACKET; - - icn_socket_->getSocketOption(GeneralTransportOptions::VERIFY_SIGNATURE, - verify_signature); - icn_socket_->getSocketOption(GeneralTransportOptions::KEY_CONTENT, - key_content); - - if (!verify_signature) { - return VerificationPolicy::ACCEPT_PACKET; - } - - if (key_content) { - key_packets_.push(copyPacket(packet)); - return VerificationPolicy::ACCEPT_PACKET; - } else if (!key_packets_.empty()) { - std::queue().swap(key_packets_); - } - - ConsumerContentObjectVerificationFailedCallback* - verification_failed_callback = VOID_HANDLER; - icn_socket_->getSocketOption(ConsumerCallbacksOptions::VERIFICATION_FAILED, - &verification_failed_callback); - - if (!verification_failed_callback) { - throw errors::RuntimeException( - "No verification failed callback provided by application. " - "Aborting."); - } - - std::shared_ptr verifier; - icn_socket_->getSocketOption(GeneralTransportOptions::VERIFIER, verifier); - - if (TRANSPORT_EXPECT_FALSE(!verifier)) { - ret = (*verification_failed_callback)( - *icn_socket_, dynamic_cast(packet), - make_error_code(protocol_error::no_verifier_provided)); - return ret; - } - - if (!verifier->verify(packet)) { - ret = (*verification_failed_callback)( - *icn_socket_, dynamic_cast(packet), - make_error_code(protocol_error::signature_verification_failed)); - } else { - ret = VerificationPolicy::ACCEPT_PACKET; - } - - return ret; -} - -bool SignatureVerificationManager::onKeyToVerify() { - if (TRANSPORT_EXPECT_FALSE(key_packets_.empty())) { - throw errors::RuntimeException("No key to verify."); - } - - while (!key_packets_.empty()) { - ContentObjectPtr packet_to_verify = key_packets_.front(); - key_packets_.pop(); - if (onPacketToVerify(*packet_to_verify) != - VerificationPolicy::ACCEPT_PACKET) - return false; - } - - return true; -} - -} // end namespace protocol - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/protocols/verification_manager.h b/libtransport/src/hicn/transport/protocols/verification_manager.h deleted file mode 100644 index 293e8103a..000000000 --- a/libtransport/src/hicn/transport/protocols/verification_manager.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include - -namespace transport { - -namespace interface { -class ConsumerSocket; -} - -namespace protocol { - -using Packet = core::Packet; -using interface::ConsumerSocket; -using interface::VerificationPolicy; -using ContentObjectPtr = std::shared_ptr; - -class VerificationManager { - public: - virtual ~VerificationManager() = default; - virtual VerificationPolicy onPacketToVerify(const Packet& packet) = 0; - virtual bool onKeyToVerify() { return false; } -}; - -class SignatureVerificationManager : public VerificationManager { - public: - SignatureVerificationManager(interface::ConsumerSocket* icn_socket) - : icn_socket_(icn_socket), key_packets_() {} - - interface::VerificationPolicy onPacketToVerify(const Packet& packet) override; - bool onKeyToVerify() override; - - private: - ConsumerSocket* icn_socket_; - std::queue key_packets_; - - ContentObjectPtr copyPacket(const Packet& packet) { - std::shared_ptr packet_copy = - packet.acquireMemBufReference(); - ContentObjectPtr content_object_copy = - std::make_shared(std::move(packet_copy)); - std::unique_ptr payload_copy = packet.getPayload(); - content_object_copy->appendPayload(std::move(payload_copy)); - return content_object_copy; - } -}; - -} // end namespace protocol - -} // end namespace transport diff --git a/libtransport/src/hicn/transport/utils/CMakeLists.txt b/libtransport/src/hicn/transport/utils/CMakeLists.txt deleted file mode 100644 index 5a7dbe9cc..000000000 --- a/libtransport/src/hicn/transport/utils/CMakeLists.txt +++ /dev/null @@ -1,82 +0,0 @@ -# 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) - -list(APPEND SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/string_tokenizer.cc - ${CMAKE_CURRENT_SOURCE_DIR}/uri.cc - ${CMAKE_CURRENT_SOURCE_DIR}/signer.cc - ${CMAKE_CURRENT_SOURCE_DIR}/verifier.cc - ${CMAKE_CURRENT_SOURCE_DIR}/identity.cc - ${CMAKE_CURRENT_SOURCE_DIR}/log.cc - ${CMAKE_CURRENT_SOURCE_DIR}/membuf.cc - ${CMAKE_CURRENT_SOURCE_DIR}/content_store.cc -) - - -list(APPEND HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/array.h - ${CMAKE_CURRENT_SOURCE_DIR}/string_tokenizer.h - ${CMAKE_CURRENT_SOURCE_DIR}/hash.h - ${CMAKE_CURRENT_SOURCE_DIR}/uri.h - ${CMAKE_CURRENT_SOURCE_DIR}/chrono_typedefs.h - ${CMAKE_CURRENT_SOURCE_DIR}/branch_prediction.h - ${CMAKE_CURRENT_SOURCE_DIR}/event_reactor.h - ${CMAKE_CURRENT_SOURCE_DIR}/deadline_timer.h - ${CMAKE_CURRENT_SOURCE_DIR}/ring_buffer.h - ${CMAKE_CURRENT_SOURCE_DIR}/event_reactor.h - ${CMAKE_CURRENT_SOURCE_DIR}/min_filter.h - ${CMAKE_CURRENT_SOURCE_DIR}/stream_buffer.h - ${CMAKE_CURRENT_SOURCE_DIR}/literals.h - ${CMAKE_CURRENT_SOURCE_DIR}/signer.h - ${CMAKE_CURRENT_SOURCE_DIR}/verifier.h - ${CMAKE_CURRENT_SOURCE_DIR}/crypto_hasher.h - ${CMAKE_CURRENT_SOURCE_DIR}/crypto_suite.h - ${CMAKE_CURRENT_SOURCE_DIR}/crypto_hash.h - ${CMAKE_CURRENT_SOURCE_DIR}/crypto_hash_type.h - ${CMAKE_CURRENT_SOURCE_DIR}/identity.h - ${CMAKE_CURRENT_SOURCE_DIR}/suffix_strategy.h - ${CMAKE_CURRENT_SOURCE_DIR}/conversions.h - ${CMAKE_CURRENT_SOURCE_DIR}/linux.h - ${CMAKE_CURRENT_SOURCE_DIR}/log.h - ${CMAKE_CURRENT_SOURCE_DIR}/event_thread.h - ${CMAKE_CURRENT_SOURCE_DIR}/object_pool.h - ${CMAKE_CURRENT_SOURCE_DIR}/membuf.h - ${CMAKE_CURRENT_SOURCE_DIR}/spinlock.h - ${CMAKE_CURRENT_SOURCE_DIR}/content_store.h - ${CMAKE_CURRENT_SOURCE_DIR}/key_id.h -) - -if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") - list(APPEND HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/epoll_event_reactor.h - ${CMAKE_CURRENT_SOURCE_DIR}/fd_deadline_timer.h - ) - - list(APPEND SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/epoll_event_reactor.cc - ) -endif() - -if(NOT WIN32) - list(APPEND HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/daemonizator.h - ) - list(APPEND SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/daemonizator.cc - ) -endif() - -set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) -set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) diff --git a/libtransport/src/hicn/transport/utils/array.h b/libtransport/src/hicn/transport/utils/array.h deleted file mode 100644 index 7c0ed65d8..000000000 --- a/libtransport/src/hicn/transport/utils/array.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -#include - -namespace utils { - -template -class Array { - public: - explicit Array(const T *array, size_t size) : array_(array), size_(size) { - this->array_ = array; - this->size_ = size; - } - - Array() : array_(nullptr), size_(0) { - this->array_ = nullptr; - this->size_ = 0; - } - - TRANSPORT_ALWAYS_INLINE const T *data() const { return array_; } - - TRANSPORT_ALWAYS_INLINE T *writableData() const { - return const_cast(array_); - } - - TRANSPORT_ALWAYS_INLINE std::size_t length() const { return size_; } - - TRANSPORT_ALWAYS_INLINE Array &setData(const T *data) { - array_ = data; - return *this; - } - - TRANSPORT_ALWAYS_INLINE Array &setSize(std::size_t size) { - size_ = size; - return *this; - } - - TRANSPORT_ALWAYS_INLINE bool empty() { return !size_; } - - private: - const T *array_; - std::size_t size_; -}; - -} // namespace utils diff --git a/libtransport/src/hicn/transport/utils/branch_prediction.h b/libtransport/src/hicn/transport/utils/branch_prediction.h deleted file mode 100644 index 8cbfaca76..000000000 --- a/libtransport/src/hicn/transport/utils/branch_prediction.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#undef TRANSPORT_EXPECT_TRUE -#undef TRANSPORT_EXPECT_FALSE - -#ifndef _WIN32 -#define TRANSPORT_EXPECT_TRUE(x) __builtin_expect((x), 1) -#define TRANSPORT_EXPECT_FALSE(x) __builtin_expect((x), 0) -#else -#define TRANSPORT_EXPECT_TRUE(x) (x) -#define TRANSPORT_EXPECT_FALSE(x) (x) -#endif \ No newline at end of file diff --git a/libtransport/src/hicn/transport/utils/chrono_typedefs.h b/libtransport/src/hicn/transport/utils/chrono_typedefs.h deleted file mode 100644 index 8f28e763c..000000000 --- a/libtransport/src/hicn/transport/utils/chrono_typedefs.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -namespace utils { - -using SteadyClock = std::chrono::steady_clock; -using TimePoint = SteadyClock::time_point; -using Milliseconds = std::chrono::milliseconds; -using Microseconds = std::chrono::microseconds; - -} // namespace utils diff --git a/libtransport/src/hicn/transport/utils/content_store.cc b/libtransport/src/hicn/transport/utils/content_store.cc deleted file mode 100644 index ba13bef41..000000000 --- a/libtransport/src/hicn/transport/utils/content_store.cc +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include -#include - -namespace utils { - -ContentStore::ContentStore(std::size_t max_packets) - : max_content_store_size_(max_packets) {} - -ContentStore::~ContentStore() {} - -void ContentStore::insert( - const std::shared_ptr &content_object) { - if (max_content_store_size_ == 0) { - return; - } - - utils::SpinLock::Acquire locked(cs_mutex_); - - if (TRANSPORT_EXPECT_FALSE(content_store_hash_table_.size() != - fifo_list_.size())) { - TRANSPORT_LOGW("Inconsistent size!!!!"); - TRANSPORT_LOGW("Hash Table: %zu |||| FIFO List: %zu", - content_store_hash_table_.size(), fifo_list_.size()); - } - - if (content_store_hash_table_.size() >= max_content_store_size_) { - content_store_hash_table_.erase(fifo_list_.back()); - fifo_list_.pop_back(); - } - - // Insert new item - auto it = content_store_hash_table_.find(content_object->getName()); - if (it != content_store_hash_table_.end()) { - fifo_list_.erase(it->second.second); - content_store_hash_table_.erase(content_object->getName()); - } - - fifo_list_.push_front(std::cref(content_object->getName())); - auto pos = fifo_list_.begin(); - content_store_hash_table_[content_object->getName()] = ContentStoreEntry( - ObjectTimeEntry(content_object, std::chrono::steady_clock::now()), pos); -} - -const std::shared_ptr ContentStore::find( - const Interest &interest) { - utils::SpinLock::Acquire locked(cs_mutex_); - - std::shared_ptr ret = empty_reference_; - auto it = content_store_hash_table_.find(interest.getName()); - if (it != content_store_hash_table_.end()) { - - auto content_lifetime = it->second.first.first->getLifetime(); - auto time_passed_since_creation = - std::chrono::duration_cast( - std::chrono::steady_clock::now() - it->second.first.second) - .count(); - - if (time_passed_since_creation > content_lifetime) { - fifo_list_.erase(it->second.second); - content_store_hash_table_.erase(it); - } - else { - ret = it->second.first.first; - } - } - - return ret; -} - -void ContentStore::erase(const Name &exact_name) { - utils::SpinLock::Acquire locked(cs_mutex_); - auto it = content_store_hash_table_.find(exact_name); - fifo_list_.erase(it->second.second); - content_store_hash_table_.erase(exact_name); -} - -void ContentStore::setLimit(size_t max_packets) { - utils::SpinLock::Acquire locked(cs_mutex_); - max_content_store_size_ = max_packets; -} - -std::size_t ContentStore::getLimit() const { - utils::SpinLock::Acquire locked(cs_mutex_); - return max_content_store_size_; -} - -std::size_t ContentStore::size() const { - utils::SpinLock::Acquire locked(cs_mutex_); - return content_store_hash_table_.size(); -} - -void ContentStore::printContent() { - for (auto &item : content_store_hash_table_) { - if (item.second.first.first->getPayloadType() == - transport::core::PayloadType::MANIFEST) { - TRANSPORT_LOGI("Manifest: %s", - item.second.first.first->getName().toString().c_str()); - } else { - TRANSPORT_LOGI("Data Packet: %s", - item.second.first.first->getName().toString().c_str()); - } - } -} - -} // end namespace utils \ No newline at end of file diff --git a/libtransport/src/hicn/transport/utils/content_store.h b/libtransport/src/hicn/transport/utils/content_store.h deleted file mode 100644 index 613ffcbc2..000000000 --- a/libtransport/src/hicn/transport/utils/content_store.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include - -#include - -namespace transport { - -namespace core { -class Name; -class ContentObject; -class Interest; -} // namespace core - -} // namespace transport - -namespace utils { - -using Name = transport::core::Name; -using ContentObject = transport::core::ContentObject; -using Interest = transport::core::Interest; - -typedef std::pair, - std::chrono::steady_clock::time_point> - ObjectTimeEntry; -typedef std::pair>::iterator> - ContentStoreEntry; -typedef std::list> FIFOList; -typedef std::unordered_map ContentStoreHashTable; - -class ContentStore { - public: - explicit ContentStore(std::size_t max_packets = (1 << 16)); - - ~ContentStore(); - - void insert(const std::shared_ptr &content_object); - - const std::shared_ptr find(const Interest &interest); - - void erase(const Name &exact_name); - - void setLimit(size_t max_packets); - - size_t getLimit() const; - - size_t size() const; - - void printContent(); - - private: - ContentStoreHashTable content_store_hash_table_; - FIFOList fifo_list_; - std::shared_ptr empty_reference_; - // Must be atomic - std::atomic_size_t max_content_store_size_; - mutable utils::SpinLock cs_mutex_; -}; - -} // end namespace utils \ No newline at end of file diff --git a/libtransport/src/hicn/transport/utils/conversions.h b/libtransport/src/hicn/transport/utils/conversions.h deleted file mode 100644 index 24b529206..000000000 --- a/libtransport/src/hicn/transport/utils/conversions.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -#include -#include -#include - -namespace utils { - -static TRANSPORT_ALWAYS_INLINE int convertStringToMacAddress( - const std::string& mac_address, uint8_t* mac_byte_array) { - const char* mac = mac_address.c_str(); - - sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mac_byte_array[0], - &mac_byte_array[1], &mac_byte_array[2], &mac_byte_array[3], - &mac_byte_array[4], &mac_byte_array[5]); - - return 0; -} - -} // namespace utils \ No newline at end of file diff --git a/libtransport/src/hicn/transport/utils/crypto_hash.h b/libtransport/src/hicn/transport/utils/crypto_hash.h deleted file mode 100644 index 945909d14..000000000 --- a/libtransport/src/hicn/transport/utils/crypto_hash.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include -#include - -extern "C" { -#include -}; - -#include -#include - -namespace utils { - -class CryptoHasher; - -struct EnumClassHash { - template - std::size_t operator()(T t) const { - return static_cast(t); - } -}; - -static std::unordered_map - hash_size_map = {{CryptoHashType::SHA_256, 32}, - {CryptoHashType::CRC32C, 4}, - {CryptoHashType::SHA_512, 64}}; - -class Signer; -class Verifier; - -class CryptoHash { - friend class CryptoHasher; - friend class Signer; - friend class Verifier; - - public: - CryptoHash() : hash_(nullptr) {} - - CryptoHash(const CryptoHash& other) { - if (other.hash_) { - hash_ = parcCryptoHash_Acquire(other.hash_); - } - } - - CryptoHash(CryptoHash&& other) { - if (other.hash_) { - hash_ = parcCryptoHash_Acquire(other.hash_); - } - } - - template - CryptoHash(const T* buffer, std::size_t length, CryptoHashType hash_type) { - hash_ = parcCryptoHash_CreateFromArray( - static_cast(hash_type), buffer, length); - } - - ~CryptoHash() { - if (hash_) { - parcCryptoHash_Release(&hash_); - } - } - - CryptoHash& operator=(const CryptoHash& other) { - if (other.hash_) { - hash_ = parcCryptoHash_Acquire(other.hash_); - } - - return *this; - } - - template - utils::Array getDigest() const { - return utils::Array( - static_cast(parcBuffer_Overlay(parcCryptoHash_GetDigest(hash_), 0)), - parcBuffer_Remaining(parcCryptoHash_GetDigest(hash_))); - } - - CryptoHashType getType() { - return static_cast(parcCryptoHash_GetDigestType(hash_)); - } - - template - static bool compareBinaryDigest(const T* digest1, const T* digest2, - CryptoHashType hash_type) { - if (hash_size_map.find(hash_type) == hash_size_map.end()) { - return false; - } - - return !static_cast( - std::memcmp(digest1, digest2, hash_size_map[hash_type])); - } - - TRANSPORT_ALWAYS_INLINE void display() { - parcBuffer_Display(parcCryptoHash_GetDigest(hash_), 2); - } - - private: - PARCCryptoHash* hash_; -}; - -} // namespace utils \ No newline at end of file diff --git a/libtransport/src/hicn/transport/utils/crypto_hash_type.h b/libtransport/src/hicn/transport/utils/crypto_hash_type.h deleted file mode 100644 index b7597e208..000000000 --- a/libtransport/src/hicn/transport/utils/crypto_hash_type.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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. - */ - -#pragma once - -extern "C" { -#include -}; - -namespace utils { - -enum class CryptoHashType : uint8_t { - SHA_256 = PARCCryptoHashType_SHA256, - SHA_512 = PARCCryptoHashType_SHA512, - CRC32C = PARCCryptoHashType_CRC32C, - NULL_HASH = PARCCryptoHashType_NULL -}; - -} \ No newline at end of file diff --git a/libtransport/src/hicn/transport/utils/crypto_hasher.h b/libtransport/src/hicn/transport/utils/crypto_hasher.h deleted file mode 100644 index c34a26fac..000000000 --- a/libtransport/src/hicn/transport/utils/crypto_hasher.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -extern "C" { -#include -}; - -namespace utils { - -class CryptoHasher { - public: - CryptoHasher(CryptoHashType hash_type) - : hasher_(parcCryptoHasher_Create( - static_cast(hash_type))), - managed_(true) {} - - CryptoHasher(PARCCryptoHasher* hasher) : hasher_(hasher), managed_(false) {} - - ~CryptoHasher() { - if (managed_) { - parcCryptoHasher_Release(&hasher_); - } - } - - CryptoHasher& init() { - if (parcCryptoHasher_Init(hasher_) == -1) { - throw errors::RuntimeException("Cryptohash init failed."); - } - - return *this; - } - - template - CryptoHasher& updateBytes(const T* buffer, std::size_t length) { - if (parcCryptoHasher_UpdateBytes(hasher_, buffer, length) == -1) { - throw errors::RuntimeException("Cryptohash updateBytes failed."); - } - return *this; - } - - CryptoHash finalize() { - CryptoHash hash; - hash.hash_ = parcCryptoHasher_Finalize(hasher_); - return hash; - } - - private: - PARCCryptoHasher* hasher_; - bool managed_; -}; - -} // namespace utils \ No newline at end of file diff --git a/libtransport/src/hicn/transport/utils/crypto_suite.h b/libtransport/src/hicn/transport/utils/crypto_suite.h deleted file mode 100644 index 8ae32b846..000000000 --- a/libtransport/src/hicn/transport/utils/crypto_suite.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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. - */ - -#pragma once - -extern "C" { -#include -}; - -namespace utils { - -enum class CryptoSuite : uint8_t { - RSA_SHA256 = PARCCryptoSuite_RSA_SHA256, - DSA_SHA256 = PARCCryptoSuite_DSA_SHA256, - RSA_SHA512 = PARCCryptoSuite_RSA_SHA512, - HMAC_SHA256 = PARCCryptoSuite_HMAC_SHA256, - HMAC_SHA512 = PARCCryptoSuite_HMAC_SHA512, - NULL_CRC32C = PARCCryptoSuite_NULL_CRC32C, - ECDSA_256K1 = PARCCryptoSuite_ECDSA_SHA256, - UNKNOWN = PARCCryptoSuite_UNKNOWN -}; - -} diff --git a/libtransport/src/hicn/transport/utils/daemonizator.cc b/libtransport/src/hicn/transport/utils/daemonizator.cc deleted file mode 100644 index c51a68d14..000000000 --- a/libtransport/src/hicn/transport/utils/daemonizator.cc +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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. - */ - -#ifndef _WIN32 -#include -#include -#include - -#include -#include - -namespace utils { - -void Daemonizator::daemonize(bool close_fds) { - pid_t process_id = 0; - pid_t sid = 0; - - // Create child process - process_id = fork(); - - // Indication of fork() failure - if (process_id < 0) { - throw errors::RuntimeException("Fork failed."); - } - - // PARENT PROCESS. Need to kill it. - if (process_id > 0) { - TRANSPORT_LOGE("Process id of child process %d", process_id); - // return success in exit status - exit(EXIT_SUCCESS); - } - - // unmask the file mode - umask(0); - - // set new session - sid = setsid(); - if (sid < 0) { - // Return failure - exit(EXIT_FAILURE); - } - - // Change the current working directory to root. - int ret = chdir("/"); - - if (ret < 0) { - throw errors::RuntimeException("Error changing working directory to root"); - } - - // Close stdin. Redirect stdout and stderr to file if possible - - if (close_fds) { - close(STDOUT_FILENO); - close(STDERR_FILENO); - } - - close(STDIN_FILENO); - - // Really start application -} - -} // namespace utils - -#endif diff --git a/libtransport/src/hicn/transport/utils/daemonizator.h b/libtransport/src/hicn/transport/utils/daemonizator.h deleted file mode 100644 index 028d74865..000000000 --- a/libtransport/src/hicn/transport/utils/daemonizator.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#ifndef _WIN32 - -#include -namespace utils { - -class Daemonizator { - public: - static void daemonize(bool close_fds = true); -}; - -} // namespace utils - -#endif \ No newline at end of file diff --git a/libtransport/src/hicn/transport/utils/deadline_timer.h b/libtransport/src/hicn/transport/utils/deadline_timer.h deleted file mode 100644 index 61f906141..000000000 --- a/libtransport/src/hicn/transport/utils/deadline_timer.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -#include -#include -#include -#include - -namespace std { -namespace chrono { -namespace detail { - -template -struct posix_duration_cast; - -// chrono -> timespec caster -template -struct posix_duration_cast, - struct timespec> { - static struct timespec cast(std::chrono::duration const &d) { - struct timespec tv; - - std::chrono::seconds const sec = - std::chrono::duration_cast(d); - - tv.tv_sec = sec.count(); - tv.tv_nsec = - std::chrono::duration_cast(d - sec).count(); - - return tv; - } -}; - -// timespec -> chrono caster -template -struct posix_duration_cast> { - static std::chrono::duration cast(struct timespec const &tv) { - return std::chrono::duration_cast>( - std::chrono::seconds(tv.tv_sec) + std::chrono::nanoseconds(tv.tv_nsec)); - } -}; - -} // namespace detail - -// chrono -> timespec -template -auto duration_cast(std::chrono::duration const &d) -> - typename std::enable_if::value, - struct timespec>::type { - return detail::posix_duration_cast, - timespec>::cast(d); -} - -// timespec -> chrono -template -Duration duration_cast(struct timespec const &tv) { - return detail::posix_duration_cast::cast(tv); -} - -} // namespace chrono -} // namespace std - -namespace utils { - -template -class DeadlineTimer { - public: - virtual ~DeadlineTimer() = default; - - template - void asyncWait(WaitHandler &&callback) { - static_cast(this)->asyncWaitImpl( - std::forward(callback)); - } - - void wait() { static_cast(this)->waitImpl(); } - - template - void expiresFromNow(std::chrono::duration &&duration) { - static_cast(this)->expiresFromNowImpl( - std::forward>(duration)); - } - - template , - std::chrono::steady_clock::time_point>::value, - TimePoint>::type> - void expiresAt(TimePoint &&time_point) { - static_cast(this)->expiresAtImpl( - std::forward(time_point)); - } - - void cancel() { static_cast(this)->cancelImpl(); } -}; - -} // namespace utils diff --git a/libtransport/src/hicn/transport/utils/epoll_event_reactor.cc b/libtransport/src/hicn/transport/utils/epoll_event_reactor.cc deleted file mode 100644 index a97e89500..000000000 --- a/libtransport/src/hicn/transport/utils/epoll_event_reactor.cc +++ /dev/null @@ -1,186 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include - -#include -#include -#include - -namespace utils { - -EpollEventReactor::EpollEventReactor() - : epoll_fd_(epoll_create(20000)), run_event_loop_(true) {} - -EpollEventReactor::~EpollEventReactor() { close(epoll_fd_); } - -int EpollEventReactor::addFileDescriptor(int fd, uint32_t events) { - if (TRANSPORT_EXPECT_FALSE(fd < 0)) { - TRANSPORT_LOGE("invalid fd %d", fd); - return -1; - } - - struct epoll_event evt; - std::memset(&evt, 0, sizeof(evt)); - evt.events = events; - evt.data.fd = fd; - - if (TRANSPORT_EXPECT_FALSE(epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &evt) < - 0)) { - TRANSPORT_LOGE("epoll_ctl: %s fd %d", strerror(errno), fd); - return -1; - } - - return 0; -} - -int EpollEventReactor::modFileDescriptor(int fd, uint32_t events) { - if (TRANSPORT_EXPECT_FALSE(fd < 0)) { - TRANSPORT_LOGE("invalid fd %d", fd); - return -1; - } - - struct epoll_event evt; - memset(&evt, 0, sizeof(evt)); - evt.events = events; - evt.data.fd = fd; - - if (TRANSPORT_EXPECT_FALSE(epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, fd, &evt) < - 0)) { - TRANSPORT_LOGE("epoll_ctl: %s fd %d", strerror(errno), fd); - return -1; - } - - return 0; -} - -std::size_t EpollEventReactor::mapSize() { return event_callback_map_.size(); } - -int EpollEventReactor::delFileDescriptor(int fd) { - if (TRANSPORT_EXPECT_FALSE(fd < 0)) { - TRANSPORT_LOGE("invalid fd %d", fd); - return -1; - } - - struct epoll_event evt; - memset(&evt, 0, sizeof(evt)); - - if (TRANSPORT_EXPECT_FALSE(epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, fd, &evt) < - 0)) { - TRANSPORT_LOGE("epoll_ctl: %s fd %d", strerror(errno), fd); - return -1; - } - - utils::SpinLock::Acquire locked(event_callback_map_lock_); - event_callback_map_.erase(fd); - - return 0; -} - -void EpollEventReactor::runEventLoop(int timeout) { - Event evt[128]; - int en = 0; - EventCallbackMap::iterator it; - EventCallback callback; - - // evt.events = EPOLLIN | EPOLLOUT; - sigset_t sigset; - sigemptyset(&sigset); - - while (run_event_loop_) { - memset(&evt, 0, sizeof(evt)); - - en = epoll_pwait(epoll_fd_, evt, 128, timeout, &sigset); - - if (TRANSPORT_EXPECT_FALSE(en < 0)) { - TRANSPORT_LOGE("epoll_pwait: %s", strerror(errno)); - return; - } - - for (int i = 0; i < en; i++) { - if (evt[i].data.fd > 0) { - { - utils::SpinLock::Acquire locked(event_callback_map_lock_); - it = event_callback_map_.find(evt[i].data.fd); - } - - if (TRANSPORT_EXPECT_FALSE(it == event_callback_map_.end())) { - TRANSPORT_LOGE("unexpected event. fd %d", evt[i].data.fd); - } else { - { - utils::SpinLock::Acquire locked(event_callback_map_lock_); - callback = event_callback_map_[evt[i].data.fd]; - } - - callback(evt[i]); - - // In the callback the epoll event reactor could have been stopped, - // then we need to check whether the event loop is still running. - if (TRANSPORT_EXPECT_FALSE(!run_event_loop_)) { - return; - } - } - } else { - TRANSPORT_LOGE("unexpected event. fd %d", evt[i].data.fd); - } - } - } -} - -void EpollEventReactor::runOneEvent() { - Event evt; - int en = 0; - EventCallbackMap::iterator it; - EventCallback callback; - - // evt.events = EPOLLIN | EPOLLOUT; - sigset_t sigset; - sigemptyset(&sigset); - - memset(&evt, 0, sizeof(evt)); - - en = epoll_pwait(epoll_fd_, &evt, 1, -1, &sigset); - - if (TRANSPORT_EXPECT_FALSE(en < 0)) { - TRANSPORT_LOGE("epoll_pwait: %s", strerror(errno)); - return; - } - - if (TRANSPORT_EXPECT_TRUE(evt.data.fd > 0)) { - { - utils::SpinLock::Acquire locked(event_callback_map_lock_); - it = event_callback_map_.find(evt.data.fd); - } - - if (TRANSPORT_EXPECT_FALSE(it == event_callback_map_.end())) { - TRANSPORT_LOGE("unexpected event. fd %d", evt.data.fd); - } else { - { - utils::SpinLock::Acquire locked(event_callback_map_lock_); - callback = event_callback_map_[evt.data.fd]; - } - - callback(evt); - } - } else { - TRANSPORT_LOGE("unexpected event. fd %d", evt.data.fd); - } -} - -void EpollEventReactor::stop() { run_event_loop_ = false; } - -} // namespace utils \ No newline at end of file diff --git a/libtransport/src/hicn/transport/utils/epoll_event_reactor.h b/libtransport/src/hicn/transport/utils/epoll_event_reactor.h deleted file mode 100644 index 04c10fc7e..000000000 --- a/libtransport/src/hicn/transport/utils/epoll_event_reactor.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include - -#include -#include -#include -#include -#include -#include - -#define FD_NUMBER 20000 - -namespace utils { - -typedef struct epoll_event Event; -typedef std::function EventCallback; -typedef std::unordered_map EventCallbackMap; - -class EpollEventReactor : public EventReactor { - public: - explicit EpollEventReactor(); - - ~EpollEventReactor(); - - template - int addFileDescriptor(int fd, uint32_t events, EventHandler &&callback) { - auto it = event_callback_map_.find(fd); - int ret = 0; - - if (it == event_callback_map_.end()) { - { - utils::SpinLock::Acquire locked(event_callback_map_lock_); - event_callback_map_[fd] = std::forward(callback); - } - - ret = addFileDescriptor(fd, events); - } - - return ret; - } - - int delFileDescriptor(int fd); - - int modFileDescriptor(int fd, uint32_t events); - - void runEventLoop(int timeout = -1) override; - - void runOneEvent() override; - - void stop() override; - - std::size_t mapSize(); - - private: - int addFileDescriptor(int fd, uint32_t events); - - int epoll_fd_; - std::atomic_bool run_event_loop_; - EventCallbackMap event_callback_map_; - utils::SpinLock event_callback_map_lock_; -}; - -} // namespace utils diff --git a/libtransport/src/hicn/transport/utils/event_reactor.h b/libtransport/src/hicn/transport/utils/event_reactor.h deleted file mode 100644 index 4f8b58296..000000000 --- a/libtransport/src/hicn/transport/utils/event_reactor.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include - -namespace utils { - -typedef std::function UserCallback; - -class EventReactor { - public: - virtual ~EventReactor() = default; - - virtual void runEventLoop(int timeout = -1) = 0; - - virtual void runOneEvent() = 0; - - virtual void stop() = 0; -}; - -} // namespace utils diff --git a/libtransport/src/hicn/transport/utils/event_thread.h b/libtransport/src/hicn/transport/utils/event_thread.h deleted file mode 100644 index e50ae9648..000000000 --- a/libtransport/src/hicn/transport/utils/event_thread.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include - -#include - -namespace utils { - -class EventThread { - private: - // No copies - EventThread(const EventThread&) = delete; // non construction-copyable - EventThread& operator=(const EventThread&) = delete; // non copyable - - public: - explicit EventThread(asio::io_service& io_service) - : internal_io_service_(nullptr), - io_service_(io_service), - work_(io_service_), - thread_(nullptr) { - run(); - } - - explicit EventThread() - : internal_io_service_(std::make_unique()), - io_service_(*internal_io_service_), - work_(io_service_), - thread_(nullptr) { - run(); - } - - ~EventThread() { stop(); } - - void run() { - if (stopped()) { - io_service_.reset(); - } - - thread_ = std::make_unique([this]() { io_service_.run(); }); - } - - std::thread::id getThreadId() const { - if (thread_) { - return thread_->get_id(); - } else { - throw errors::RuntimeException("Event thread is not running."); - } - } - - template - void add(Func&& f) { - // If the function f - // TODO USe post in mac os, asio->post in xenial - io_service_.post(std::forward(f)); - } - - template - void tryRunHandlerNow(Func&& f) { - io_service_.dispatch(std::forward(f)); - } - - void stop() { - io_service_.stop(); - - if (thread_ && thread_->joinable()) { - thread_->join(); - } - - thread_.reset(); - } - - bool stopped() { return io_service_.stopped(); } - - asio::io_service& getIoService() { return io_service_; } - - private: - std::unique_ptr internal_io_service_; - asio::io_service& io_service_; - asio::io_service::work work_; - std::unique_ptr thread_; -}; - -} // namespace utils \ No newline at end of file diff --git a/libtransport/src/hicn/transport/utils/fd_deadline_timer.h b/libtransport/src/hicn/transport/utils/fd_deadline_timer.h deleted file mode 100644 index 1c14513c9..000000000 --- a/libtransport/src/hicn/transport/utils/fd_deadline_timer.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include -#include - -#include -#include - -#include -#include - -namespace utils { - -class FdDeadlineTimer : public DeadlineTimer { - public: - explicit FdDeadlineTimer(EpollEventReactor &reactor) - : reactor_(reactor), - timer_fd_(timerfd_create(CLOCK_MONOTONIC, 0)), - flags_(0) { - if (timer_fd_ == -1) { - throw errors::RuntimeException("Impossible to create the timer!"); - } - } - - ~FdDeadlineTimer() { close(timer_fd_); } - - template - void asyncWaitImpl(WaitHandler &&callback) { - // ASIO_WAIT_HANDLER_CHECK(WaitHandler, callback) type_check; - - if (timerfd_settime(timer_fd_, flags_, &new_value_, NULL) == -1) { - throw errors::RuntimeException("Impossible to set the timer!"); - } - - uint32_t events = EPOLLIN; - - reactor_.addFileDescriptor( - timer_fd_, events, - [callback = std::forward(callback)]( - const Event &event) -> int { - uint64_t s = 0; - std::error_code ec; - - if (read(event.data.fd, &s, sizeof(s)) == -1) { - TRANSPORT_LOGE("Read error!!"); - } - - if (!(event.events & EPOLLIN)) { - ec = std::make_error_code(std::errc::operation_canceled); - } - - callback(ec); - - return 0; - }); - } - - void waitImpl() { - if (timerfd_settime(timer_fd_, flags_, &new_value_, NULL) == -1) { - throw errors::RuntimeException("Impossible to set the timer!"); - } - - uint64_t ret; - - if (read(timer_fd_, &ret, sizeof(ret)) == -1) { - throw errors::RuntimeException( - "Error while waiting for the timer expiration."); - } - } - - template - void expiresFromNowImpl(std::chrono::duration &&duration) { - std::memset(&new_value_, 0, sizeof(new_value_)); - new_value_.it_value = std::chrono::duration_cast( - std::forward>(duration)); - } - - template , - std::chrono::steady_clock::time_point>::value, - TimePoint>> - void expiresAtImpl(TimePoint &&time_point) { - std::memset(&new_value_, 0, sizeof(new_value_)); - - new_value_.it_value = std::chrono::duration_cast( - time_point.time_since_epoch()); - flags_ |= TFD_TIMER_ABSTIME; - } - - void cancelImpl() { - std::memset(&new_value_, 0, sizeof(new_value_)); - - if (timerfd_settime(timer_fd_, 0, &new_value_, NULL) == -1) { - throw errors::RuntimeException("Impossible to cancel the timer!"); - } - - // reactor_.delFileDescriptor(timer_fd_); - } - - EventReactor &getEventReactor() { return reactor_; } - - private: - EpollEventReactor &reactor_; - int timer_fd_; - EventCallback callback_; - struct itimerspec new_value_; - int flags_; -}; - -} // namespace utils diff --git a/libtransport/src/hicn/transport/utils/hash.h b/libtransport/src/hicn/transport/utils/hash.h deleted file mode 100644 index 6815ca4bf..000000000 --- a/libtransport/src/hicn/transport/utils/hash.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Copyright 2017 Facebook, Inc. - * - * 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 - -#include -#include -#include -#include -#include -#include -#include - -namespace utils { - -namespace hash { - -/* - * Fowler / Noll / Vo (FNV) Hash - * http://www.isthe.com/chongo/tech/comp/fnv/ - */ - -const uint32_t FNV_32_HASH_START = 2166136261UL; -const uint64_t FNV_64_HASH_START = 14695981039346656037ULL; - -TRANSPORT_ALWAYS_INLINE uint32_t fnv32(const char *s, - uint32_t hash = FNV_32_HASH_START) { - for (; *s; ++s) { - hash += - (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24); - hash ^= *s; - } - return hash; -} - -TRANSPORT_ALWAYS_INLINE uint32_t fnv32_buf(const void *buf, size_t n, - uint32_t hash = FNV_32_HASH_START) { - // forcing signed char, since other platforms can use unsigned - const signed char *char_buf = reinterpret_cast(buf); - - for (size_t i = 0; i < n; ++i) { - hash += - (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24); - hash ^= char_buf[i]; - } - - return hash; -} - -TRANSPORT_ALWAYS_INLINE uint32_t fnv32(const std::string &str, - uint32_t hash = FNV_32_HASH_START) { - return fnv32_buf(str.data(), str.size(), hash); -} - -TRANSPORT_ALWAYS_INLINE uint64_t fnv64(const char *s, - uint64_t hash = FNV_64_HASH_START) { - for (; *s; ++s) { - hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + - (hash << 8) + (hash << 40); - hash ^= *s; - } - return hash; -} - -TRANSPORT_ALWAYS_INLINE uint64_t fnv64_buf(const void *buf, size_t n, - uint64_t hash = FNV_64_HASH_START) { - // forcing signed char, since other platforms can use unsigned - const signed char *char_buf = reinterpret_cast(buf); - - for (size_t i = 0; i < n; ++i) { - hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + - (hash << 8) + (hash << 40); - hash ^= char_buf[i]; - } - return hash; -} - -TRANSPORT_ALWAYS_INLINE uint64_t fnv64(const std::string &str, - uint64_t hash = FNV_64_HASH_START) { - return fnv64_buf(str.data(), str.size(), hash); -} - -} // namespace hash - -} // namespace utils diff --git a/libtransport/src/hicn/transport/utils/identity.cc b/libtransport/src/hicn/transport/utils/identity.cc deleted file mode 100644 index c5ab03e44..000000000 --- a/libtransport/src/hicn/transport/utils/identity.cc +++ /dev/null @@ -1,115 +0,0 @@ -/* - * 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. - */ - -#include - -extern "C" { -#include -#include -} - -namespace utils { - -Identity::Identity(const std::string &keystore_name, - const std::string &keystore_password, CryptoSuite suite, - unsigned int key_length, unsigned int validity_days, - const std::string &subject_name) { - parcSecurity_Init(); - - bool success = parcPkcs12KeyStore_CreateFile( - keystore_name.c_str(), keystore_password.c_str(), subject_name.c_str(), - parcCryptoSuite_GetSigningAlgorithm(static_cast(suite)), - key_length, validity_days); - - parcAssertTrue( - success, - "parcPkcs12KeyStore_CreateFile('%s', '%s', '%s', %d, %d) failed.", - keystore_name.c_str(), keystore_password.c_str(), subject_name.c_str(), - static_cast(key_length), validity_days); - - PARCIdentityFile *identity_file = - parcIdentityFile_Create(keystore_name.c_str(), keystore_password.c_str()); - - identity_ = - parcIdentity_Create(identity_file, PARCIdentityFileAsPARCIdentity); - - PARCSigner *signer = parcIdentity_CreateSigner( - identity_, - parcCryptoSuite_GetCryptoHash(static_cast(suite))); - - signer_ = std::make_shared(signer, suite); - - parcSigner_Release(&signer); - parcIdentityFile_Release(&identity_file); -} - -Identity::Identity(const Identity &other) - : signer_(other.signer_), hash_algorithm_(other.hash_algorithm_) { - parcSecurity_Init(); - identity_ = parcIdentity_Acquire(other.identity_); -} - -Identity Identity::generateIdentity(const std::string &subject_name) { - std::string keystore_name = "keystore"; - std::string keystore_password = "password"; - std::size_t key_length = 1024; - unsigned int validity_days = 30; - CryptoSuite suite = CryptoSuite::RSA_SHA256; - - return utils::Identity(keystore_name, keystore_password, suite, - (unsigned int)key_length, validity_days, subject_name); -} - -Identity::Identity(std::string &file_name, std::string &password, - transport::core::HashAlgorithm hash_algorithm) - : hash_algorithm_(hash_algorithm) { - parcSecurity_Init(); - - PARCIdentityFile *identity_file = - parcIdentityFile_Create(file_name.c_str(), password.c_str()); - - identity_ = - parcIdentity_Create(identity_file, PARCIdentityFileAsPARCIdentity); - - PARCSigner *signer = parcIdentity_CreateSigner( - identity_, static_cast(hash_algorithm)); - - signer_ = std::make_shared( - signer, CryptoSuite(parcSigner_GetCryptoSuite(signer))); - - parcSigner_Release(&signer); - parcIdentityFile_Release(&identity_file); -} - -Identity::~Identity() { - parcIdentity_Release(&identity_); - parcSecurity_Fini(); -} - -std::string Identity::getFileName() { - return std::string(parcIdentity_GetFileName(identity_)); -} - -std::string Identity::getPassword() { - return std::string(parcIdentity_GetPassWord(identity_)); -} - -std::shared_ptr Identity::getSigner() { return signer_; } - -size_t Identity::getSignatureLength() const { - return signer_->getSignatureLength(); -} - -} // namespace utils diff --git a/libtransport/src/hicn/transport/utils/identity.h b/libtransport/src/hicn/transport/utils/identity.h deleted file mode 100644 index e9801a005..000000000 --- a/libtransport/src/hicn/transport/utils/identity.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include - -extern "C" { -#include -#include -#include -}; - -#include - -namespace utils { - -class Identity { - public: - Identity(const std::string &keystore_name, - const std::string &keystore_password, CryptoSuite suite, - unsigned int signature_length, unsigned int validity_days, - const std::string &subject_name); - - Identity(const Identity &other); - - Identity(std::string &file_name, std::string &password, - transport::core::HashAlgorithm hash_algorithm); - - ~Identity(); - - static Identity generateIdentity(const std::string &subject_name); - - std::string getFileName(); - - std::string getPassword(); - - std::shared_ptr getSigner(); - - size_t getSignatureLength() const; - - private: - PARCIdentity *identity_; - std::shared_ptr signer_; - transport::core::HashAlgorithm hash_algorithm_; -}; - -} // namespace utils diff --git a/libtransport/src/hicn/transport/utils/key_id.h b/libtransport/src/hicn/transport/utils/key_id.h deleted file mode 100644 index d67b73d7a..000000000 --- a/libtransport/src/hicn/transport/utils/key_id.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include - -namespace utils { - -using KeyId = std::pair; - -} diff --git a/libtransport/src/hicn/transport/utils/linux.h b/libtransport/src/hicn/transport/utils/linux.h deleted file mode 100644 index 5820528e1..000000000 --- a/libtransport/src/hicn/transport/utils/linux.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#ifdef __linux__ - -#include -#include - -#include -#include -#include -#include -#include -#include - -#define LINK_LOCAL_PREFIX 0xfe80 - -namespace utils { - -static TRANSPORT_ALWAYS_INLINE int retrieveInterfaceAddress( - const std::string &interface_name, struct sockaddr_in6 *address) { - struct ifaddrs *ifap, *ifa; - char addr[INET6_ADDRSTRLEN]; - - getifaddrs(&ifap); - - for (ifa = ifap; ifa; ifa = ifa->ifa_next) { - if (ifa->ifa_addr->sa_family == AF_INET6 && - strcmp(ifa->ifa_name, interface_name.c_str()) == 0) { - struct sockaddr_in6 *tmp = (struct sockaddr_in6 *)ifa->ifa_addr; - uint16_t prefix = 0; - memcpy(&prefix, tmp->sin6_addr.s6_addr, sizeof(uint16_t)); - - if (htons(LINK_LOCAL_PREFIX) != prefix) { - *address = *(struct sockaddr_in6 *)ifa->ifa_addr; - getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6), addr, - sizeof(addr), NULL, 0, NI_NUMERICHOST); - TRANSPORT_LOGI("Interface: %s\tAddress: %s", ifa->ifa_name, addr); - } - } - } - - freeifaddrs(ifap); - - return 0; -} - -} // namespace utils - -#endif // __linux__ \ No newline at end of file diff --git a/libtransport/src/hicn/transport/utils/literals.h b/libtransport/src/hicn/transport/utils/literals.h deleted file mode 100644 index bd00e0a58..000000000 --- a/libtransport/src/hicn/transport/utils/literals.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -#include - -TRANSPORT_ALWAYS_INLINE std::uint8_t operator"" _U8(unsigned long long value) { - return static_cast(value); -} - -TRANSPORT_ALWAYS_INLINE std::uint16_t operator"" _U16( - unsigned long long value) { - return static_cast(value); -} - -TRANSPORT_ALWAYS_INLINE std::uint32_t operator"" _U32( - unsigned long long value) { - return static_cast(value); -} - -TRANSPORT_ALWAYS_INLINE std::uint64_t operator"" _U64( - unsigned long long value) { - return static_cast(value); -} - -TRANSPORT_ALWAYS_INLINE std::int8_t operator"" _I8(unsigned long long value) { - return static_cast(value); -} - -TRANSPORT_ALWAYS_INLINE std::int16_t operator"" _I16(unsigned long long value) { - return static_cast(value); -} - -TRANSPORT_ALWAYS_INLINE std::int32_t operator"" _I32(unsigned long long value) { - return static_cast(value); -} - -TRANSPORT_ALWAYS_INLINE std::int64_t operator"" _I64(unsigned long long value) { - return static_cast(value); -} \ No newline at end of file diff --git a/libtransport/src/hicn/transport/utils/log.cc b/libtransport/src/hicn/transport/utils/log.cc deleted file mode 100644 index 27dd3f541..000000000 --- a/libtransport/src/hicn/transport/utils/log.cc +++ /dev/null @@ -1,1403 +0,0 @@ -/* - * 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. - */ - -/* - * The MIT License (MIT) - * - * Copyright (c) 2017 wonder-mice - * - * 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. - */ - -/* When defined, Android log (android/log.h) will be used by default instead of - * stderr (ignored on non-Android platforms). Date, time, pid and tid (context) - * will be provided by Android log. Android log features will be used to output - * log level and tag. - */ - -#if defined(__ANDROID__) -#define TRANSPORT_LOG_USE_ANDROID_LOG 1 -#define ANDROID_TAG "HicnTransport" -#else -#define TRANSPORT_LOG_USE_ANDROID_LOG 0 -#endif - -/* When defined, NSLog (uses Apple System Log) will be used instead of stderr - * (ignored on non-Apple platforms). Date, time, pid and tid (context) will be - * provided by NSLog. Curiously, doesn't use NSLog() directly, but piggybacks on - * non-public CFLog() function. Both use Apple System Log internally, but it's - * easier to call CFLog() from C than NSLog(). Current implementation doesn't - * support "%@" format specifier. - */ -#ifdef TRANSPORT_LOG_USE_NSLOG -#undef TRANSPORT_LOG_USE_NSLOG -#if defined(__APPLE__) && defined(__MACH__) -#define TRANSPORT_LOG_USE_NSLOG 1 -#else -#define TRANSPORT_LOG_USE_NSLOG 0 -#endif -#else -#define TRANSPORT_LOG_USE_NSLOG 0 -#endif -/* When defined, OutputDebugString() will be used instead of stderr (ignored on - * non-Windows platforms). Uses OutputDebugStringA() variant and feeds it with - * UTF-8 data. - */ -#ifdef TRANSPORT_LOG_USE_DEBUGSTRING -#undef TRANSPORT_LOG_USE_DEBUGSTRING -#if defined(_WIN32) || defined(_WIN64) -#define TRANSPORT_LOG_USE_DEBUGSTRING 1 -#else -#define TRANSPORT_LOG_USE_DEBUGSTRING 0 -#endif -#else -#define TRANSPORT_LOG_USE_DEBUGSTRING 0 -#endif -/* When defined, TRANSPORT_LOG library will not contain definition of tag prefix - * variable. In that case it must be defined elsewhere using - * TRANSPORT_LOG_DEFINE_TAG_PREFIX macro, for example: - * - * TRANSPORT_LOG_DEFINE_TAG_PREFIX = "ProcessName"; - * - * This allows to specify custom value for static initialization and avoid - * overhead of setting this value in runtime. - */ -#ifdef TRANSPORT_LOG_EXTERN_TAG_PREFIX -#undef TRANSPORT_LOG_EXTERN_TAG_PREFIX -#define TRANSPORT_LOG_EXTERN_TAG_PREFIX 1 -#else -#define TRANSPORT_LOG_EXTERN_TAG_PREFIX 0 -#endif -/* When defined, TRANSPORT_LOG library will not contain definition of global - * format variable. In that case it must be defined elsewhere using - * TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT macro, for example: - * - * TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT = {MEM_WIDTH}; - * - * This allows to specify custom value for static initialization and avoid - * overhead of setting this value in runtime. - */ -#ifdef TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT -#undef TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT -#define TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT 1 -#else -#define TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT 0 -#endif -/* When defined, transport_log library will not contain definition of global - * output variable. In that case it must be defined elsewhere using - * TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT macro, for example: - * - * TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {TRANSPORT_LOG_PUT_STD, - * custom_output_callback}; - * - * This allows to specify custom value for static initialization and avoid - * overhead of setting this value in runtime. - */ -#ifdef TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT -#undef TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT -#define TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT 1 -#else -#define TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT 0 -#endif -/* When defined, transport_log library will not contain definition of global - * output level variable. In that case it must be defined elsewhere using - * TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL macro, for example: - * - * TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = TRANSPORT_LOG_WARN; - * - * This allows to specify custom value for static initialization and avoid - * overhead of setting this value in runtime. - */ -#ifdef TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL -#undef TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL -#define TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL 1 -#else -#define TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL 0 -#endif -/* When defined, implementation will prefer smaller code size over speed. - * Very rough estimate is that code will be up to 2x smaller and up to 2x - * slower. Disabled by default. - */ -#ifdef TRANSPORT_LOG_OPTIMIZE_SIZE -#undef TRANSPORT_LOG_OPTIMIZE_SIZE -#define TRANSPORT_LOG_OPTIMIZE_SIZE 1 -#else -#define TRANSPORT_LOG_OPTIMIZE_SIZE 0 -#endif -/* Size of the log line buffer. The buffer is allocated on stack. It limits - * maximum length of a log line. - */ -#ifndef TRANSPORT_LOG_BUF_SZ -#define TRANSPORT_LOG_BUF_SZ 512 -#endif -/* Default number of bytes in one line of memory output. For large values - * TRANSPORT_LOG_BUF_SZ also must be increased. - */ -#ifndef TRANSPORT_LOG_MEM_WIDTH -#define TRANSPORT_LOG_MEM_WIDTH 32 -#endif -/* String to put in the end of each log line (can be empty). Its value used by - * stderr output callback. Its size used as a default value for - * TRANSPORT_LOG_EOL_SZ. - */ -#ifndef TRANSPORT_LOG_EOL -#define TRANSPORT_LOG_EOL "\n" -#endif -/* Default delimiter that separates parts of log message. Can NOT contain '%' - * or '\0'. - * - * Log message format specifications can override (or ignore) this value. For - * more details see TRANSPORT_LOG_MESSAGE_CTX_FORMAT, - * TRANSPORT_LOG_MESSAGE_SRC_FORMAT and TRANSPORT_LOG_MESSAGE_TAG_FORMAT. - */ -#ifndef TRANSPORT_LOG_DEF_DELIMITER -#define TRANSPORT_LOG_DEF_DELIMITER " " -#endif -/* Specifies log message context format. Log message context includes date, - * time, process id, thread id and message's log level. Custom information can - * be added as well. Supported fields: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, - * MILLISECOND, PID, TID, LEVEL, S(str), F_INIT(statements), - * F_UINT(width, value). - * - * Must be defined as a tuple, for example: - * - * #define TRANSPORT_LOG_MESSAGE_CTX_FORMAT (YEAR, S("."), MONTH, S("."), DAY, - * S(" > ")) - * - * In that case, resulting log message will be: - * - * 2016.12.22 > TAG function@filename.c:line Message text - * - * Note, that tag, source location and message text are not impacted by - * this setting. See TRANSPORT_LOG_MESSAGE_TAG_FORMAT and - * TRANSPORT_LOG_MESSAGE_SRC_FORMAT. - * - * If message context must be visually separated from the rest of the message, - * it must be reflected in context format (notice trailing S(" > ") in the - * example above). - * - * S(str) adds constant string str. String can NOT contain '%' or '\0'. - * - * F_INIT(statements) adds initialization statement(s) that will be evaluated - * once for each log message. All statements are evaluated in specified order. - * Several F_INIT() fields can be used in every log message format - * specification. Fields, like F_UINT(width, value), are allowed to use results - * of initialization statements. If statement introduces variables (or other - * names, like structures) they must be prefixed with "f_". Statements must be - * enclosed into additional "()". Example: - * - * #define TRANSPORT_LOG_MESSAGE_CTX_FORMAT \ - * (F_INIT(( struct rusage f_ru; getrusage(RUSAGE_SELF, &f_ru); )), \ - * YEAR, S("."), MONTH, S("."), DAY, S(" "), \ - * F_UINT(5, f_ru.ru_nsignals), \ - * S(" ")) - * - * F_UINT(width, value) adds unsigned integer value extended with up to width - * spaces (for alignment purposes). Value can be any expression that evaluates - * to unsigned integer. If expression contains non-standard functions, they - * must be declared with F_INIT(). Example: - * - * #define TRANSPORT_LOG_MESSAGE_CTX_FORMAT \ - * (YEAR, S("."), MONTH, S("."), DAY, S(" "), \ - * F_INIT(( unsigned tickcount(); )), \ - * F_UINT(5, tickcount()), \ - * S(" ")) - * - * Other log message format specifications follow same rules, but have a - * different set of supported fields. - */ -#ifndef TRANSPORT_LOG_MESSAGE_CTX_FORMAT -#define TRANSPORT_LOG_MESSAGE_CTX_FORMAT \ - (MONTH, S("-"), DAY, S(TRANSPORT_LOG_DEF_DELIMITER), HOUR, S(":"), MINUTE, \ - S(":"), SECOND, S("."), MILLISECOND, S(TRANSPORT_LOG_DEF_DELIMITER), PID, \ - S(TRANSPORT_LOG_DEF_DELIMITER), TID, S(TRANSPORT_LOG_DEF_DELIMITER), LEVEL, \ - S(TRANSPORT_LOG_DEF_DELIMITER)) -#endif -/* Example: - */ -/* Specifies log message tag format. It includes tag prefix and tag. Custom - * information can be added as well. Supported fields: - * TAG(prefix_delimiter, tag_delimiter), S(str), F_INIT(statements), - * F_UINT(width, value). - * - * TAG(prefix_delimiter, tag_delimiter) adds following string to log message: - * - * PREFIXTAG - * - * Prefix delimiter will be used only when prefix is not empty. Tag delimiter - * will be used only when prefixed tag is not empty. Example: - * - * #define TRANSPORT_LOG_TAG_FORMAT (S("["), TAG(".", ""), S("] ")) - * - * See TRANSPORT_LOG_MESSAGE_CTX_FORMAT for details. - */ -#ifndef TRANSPORT_LOG_MESSAGE_TAG_FORMAT -#define TRANSPORT_LOG_MESSAGE_TAG_FORMAT (TAG(".", TRANSPORT_LOG_DEF_DELIMITER)) -#endif -/* Specifies log message source location format. It includes function name, - * file name and file line. Custom information can be added as well. Supported - * fields: FUNCTION, FILENAME, FILELINE, S(str), F_INIT(statements), - * F_UINT(width, value). - * - * See TRANSPORT_LOG_MESSAGE_CTX_FORMAT for details. - */ -#ifndef TRANSPORT_LOG_MESSAGE_SRC_FORMAT -#define TRANSPORT_LOG_MESSAGE_SRC_FORMAT \ - (FUNCTION, S("@"), FILENAME, S(":"), FILELINE, S(TRANSPORT_LOG_DEF_DELIMITER)) -#endif -/* Fields that can be used in log message format specifications (see above). - * Mentioning them here explicitly, so we know that nobody else defined them - * before us. See TRANSPORT_LOG_MESSAGE_CTX_FORMAT for details. - */ -#define YEAR YEAR -#define MONTH MONTH -#define DAY DAY -#define MINUTE MINUTE -#define SECOND SECOND -#define MILLISECOND MILLISECOND -#define PID PID -#define TID TID -#define LEVEL LEVEL -#define TAG(prefix_delim, tag_delim) TAG(prefix_delim, tag_delim) -#define FUNCTION FUNCTION -#define FILENAME FILENAME -#define FILELINE FILELINE -#define S(str) S(str) -#define F_INIT(statements) F_INIT(statements) -#define F_UINT(width, value) F_UINT(width, value) -/* Number of bytes to reserve for EOL in the log line buffer (must be >0). - * Must be larger than or equal to length of TRANSPORT_LOG_EOL with terminating - * null. - */ -#ifndef TRANSPORT_LOG_EOL_SZ -#define TRANSPORT_LOG_EOL_SZ sizeof(TRANSPORT_LOG_EOL) -#endif -/* Compile instrumented version of the library to facilitate unit testing. - */ -#ifndef TRANSPORT_LOG_INSTRUMENTED -#define TRANSPORT_LOG_INSTRUMENTED 0 -#endif - -#if defined(__linux__) -#if !defined(__ANDROID__) && !defined(_GNU_SOURCE) -#define _GNU_SOURCE -#endif -#endif -#if defined(__MINGW32__) -#ifdef __STRICT_ANSI__ -#undef __STRICT_ANSI__ -#endif -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(_WIN32) || defined(_WIN64) -#include -#else -#include -#include -#if defined(__linux__) -#include -#else -#include -#endif -#endif - -#if defined(__linux__) -#include -#include -#if !defined(__ANDROID__) -#include -#endif -#endif -#if defined(__MACH__) -#include -#endif - -#define INLINE _TRANSPORT_LOG_INLINE -#define VAR_UNUSED(var) (void)var -#define RETVAL_UNUSED(expr) \ - do { \ - while (expr) break; \ - } while (0) -#define STATIC_ASSERT(name, cond) typedef char assert_##name[(cond) ? 1 : -1] -#define ASSERT_UNREACHABLE(why) assert(!sizeof(why)) -#ifndef _countof -#define _countof(xs) (sizeof(xs) / sizeof((xs)[0])) -#endif - -#if TRANSPORT_LOG_INSTRUMENTED -#define INSTRUMENTED_CONST -#else -#define INSTRUMENTED_CONST const -#endif - -#define _PP_PASTE_2(a, b) a##b -#define _PP_CONCAT_2(a, b) _PP_PASTE_2(a, b) - -#define _PP_PASTE_3(a, b, c) a##b##c -#define _PP_CONCAT_3(a, b, c) _PP_PASTE_3(a, b, c) - -/* Microsoft C preprocessor is a piece of shit. This moron treats __VA_ARGS__ - * as a single token and requires additional expansion to realize that it's - * actually a list. If not for it, there would be no need in this extra - * expansion. - */ -#define _PP_ID(x) x -#define _PP_NARGS_N(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, \ - _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, \ - _24, ...) \ - _24 -#define _PP_NARGS(...) \ - _PP_ID(_PP_NARGS_N(__VA_ARGS__, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, \ - 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)) - -/* There is a more efficient way to implement this, but it requires - * working C preprocessor. Unfortunately, Microsoft Visual Studio doesn't - * have one. - */ -#define _PP_HEAD__(x, ...) x -#define _PP_HEAD_(...) _PP_ID(_PP_HEAD__(__VA_ARGS__, ~)) -#define _PP_HEAD(xs) _PP_HEAD_ xs -#define _PP_TAIL_(x, ...) (__VA_ARGS__) -#define _PP_TAIL(xs) _PP_TAIL_ xs -#define _PP_UNTUPLE_(...) __VA_ARGS__ -#define _PP_UNTUPLE(xs) _PP_UNTUPLE_ xs - -/* Apply function macro to each element in tuple. Output is not - * enforced to be a tuple. - */ -#define _PP_MAP_1(f, xs) f(_PP_HEAD(xs)) -#define _PP_MAP_2(f, xs) f(_PP_HEAD(xs)) _PP_MAP_1(f, _PP_TAIL(xs)) -#define _PP_MAP_3(f, xs) f(_PP_HEAD(xs)) _PP_MAP_2(f, _PP_TAIL(xs)) -#define _PP_MAP_4(f, xs) f(_PP_HEAD(xs)) _PP_MAP_3(f, _PP_TAIL(xs)) -#define _PP_MAP_5(f, xs) f(_PP_HEAD(xs)) _PP_MAP_4(f, _PP_TAIL(xs)) -#define _PP_MAP_6(f, xs) f(_PP_HEAD(xs)) _PP_MAP_5(f, _PP_TAIL(xs)) -#define _PP_MAP_7(f, xs) f(_PP_HEAD(xs)) _PP_MAP_6(f, _PP_TAIL(xs)) -#define _PP_MAP_8(f, xs) f(_PP_HEAD(xs)) _PP_MAP_7(f, _PP_TAIL(xs)) -#define _PP_MAP_9(f, xs) f(_PP_HEAD(xs)) _PP_MAP_8(f, _PP_TAIL(xs)) -#define _PP_MAP_10(f, xs) f(_PP_HEAD(xs)) _PP_MAP_9(f, _PP_TAIL(xs)) -#define _PP_MAP_11(f, xs) f(_PP_HEAD(xs)) _PP_MAP_10(f, _PP_TAIL(xs)) -#define _PP_MAP_12(f, xs) f(_PP_HEAD(xs)) _PP_MAP_11(f, _PP_TAIL(xs)) -#define _PP_MAP_13(f, xs) f(_PP_HEAD(xs)) _PP_MAP_12(f, _PP_TAIL(xs)) -#define _PP_MAP_14(f, xs) f(_PP_HEAD(xs)) _PP_MAP_13(f, _PP_TAIL(xs)) -#define _PP_MAP_15(f, xs) f(_PP_HEAD(xs)) _PP_MAP_14(f, _PP_TAIL(xs)) -#define _PP_MAP_16(f, xs) f(_PP_HEAD(xs)) _PP_MAP_15(f, _PP_TAIL(xs)) -#define _PP_MAP_17(f, xs) f(_PP_HEAD(xs)) _PP_MAP_16(f, _PP_TAIL(xs)) -#define _PP_MAP_18(f, xs) f(_PP_HEAD(xs)) _PP_MAP_17(f, _PP_TAIL(xs)) -#define _PP_MAP_19(f, xs) f(_PP_HEAD(xs)) _PP_MAP_18(f, _PP_TAIL(xs)) -#define _PP_MAP_20(f, xs) f(_PP_HEAD(xs)) _PP_MAP_19(f, _PP_TAIL(xs)) -#define _PP_MAP_21(f, xs) f(_PP_HEAD(xs)) _PP_MAP_20(f, _PP_TAIL(xs)) -#define _PP_MAP_22(f, xs) f(_PP_HEAD(xs)) _PP_MAP_21(f, _PP_TAIL(xs)) -#define _PP_MAP_23(f, xs) f(_PP_HEAD(xs)) _PP_MAP_22(f, _PP_TAIL(xs)) -#define _PP_MAP_24(f, xs) f(_PP_HEAD(xs)) _PP_MAP_23(f, _PP_TAIL(xs)) -#define _PP_MAP(f, xs) _PP_CONCAT_2(_PP_MAP_, _PP_NARGS xs)(f, xs) - -/* Apply function macro to each element in tuple in reverse order. - * Output is not enforced to be a tuple. - */ -#define _PP_RMAP_1(f, xs) f(_PP_HEAD(xs)) -#define _PP_RMAP_2(f, xs) _PP_RMAP_1(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) -#define _PP_RMAP_3(f, xs) _PP_RMAP_2(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) -#define _PP_RMAP_4(f, xs) _PP_RMAP_3(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) -#define _PP_RMAP_5(f, xs) _PP_RMAP_4(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) -#define _PP_RMAP_6(f, xs) _PP_RMAP_5(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) -#define _PP_RMAP_7(f, xs) _PP_RMAP_6(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) -#define _PP_RMAP_8(f, xs) _PP_RMAP_7(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) -#define _PP_RMAP_9(f, xs) _PP_RMAP_8(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) -#define _PP_RMAP_10(f, xs) _PP_RMAP_9(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) -#define _PP_RMAP_11(f, xs) _PP_RMAP_10(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) -#define _PP_RMAP_12(f, xs) _PP_RMAP_11(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) -#define _PP_RMAP_13(f, xs) _PP_RMAP_12(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) -#define _PP_RMAP_14(f, xs) _PP_RMAP_13(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) -#define _PP_RMAP_15(f, xs) _PP_RMAP_14(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) -#define _PP_RMAP_16(f, xs) _PP_RMAP_15(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) -#define _PP_RMAP_17(f, xs) _PP_RMAP_16(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) -#define _PP_RMAP_18(f, xs) _PP_RMAP_17(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) -#define _PP_RMAP_19(f, xs) _PP_RMAP_18(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) -#define _PP_RMAP_20(f, xs) _PP_RMAP_19(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) -#define _PP_RMAP_21(f, xs) _PP_RMAP_20(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) -#define _PP_RMAP_22(f, xs) _PP_RMAP_21(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) -#define _PP_RMAP_23(f, xs) _PP_RMAP_22(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) -#define _PP_RMAP_24(f, xs) _PP_RMAP_23(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) -#define _PP_RMAP(f, xs) _PP_CONCAT_2(_PP_RMAP_, _PP_NARGS xs)(f, xs) - -/* Used to implement _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS() macro. All - * possible fields must be mentioned here. Not counting F_INIT() here because - * it's somewhat special and is handled spearatly (at least for now). - */ -#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__ (0 << 0) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__YEAR (1 << 1) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__MONTH (1 << 2) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__DAY (1 << 3) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__HOUR (1 << 4) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__MINUTE (1 << 5) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__SECOND (1 << 6) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__MILLISECOND (1 << 7) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__PID (1 << 8) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__TID (1 << 9) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__LEVEL (1 << 10) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__TAG(ps, ts) (1 << 11) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__FUNCTION (1 << 12) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__FILENAME (1 << 13) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__FILELINE (1 << 14) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__S(s) (1 << 15) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__F_INIT(expr) (0 << 16) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__F_UINT(w, v) (1 << 17) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK(field) \ - _PP_CONCAT_3(_TRANSPORT_LOG_MESSAGE_FORMAT_MASK_, _, field) - -/* Logical "or" of masks of fields used in specified format specification. - */ -#define _TRANSPORT_LOG_MESSAGE_FORMAT_FIELDS(format) \ - (0 _PP_MAP(| _TRANSPORT_LOG_MESSAGE_FORMAT_MASK, format)) - -/* Expands to expressions that evaluates to true if field is used in - * specified format specification. Example: - * - * #if _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(F_UINT, - * TRANSPORT_LOG_MESSAGE_CTX_FORMAT) - * ... - * #endif - */ -#define _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(field, format) \ - (_TRANSPORT_LOG_MESSAGE_FORMAT_MASK(field) & \ - _TRANSPORT_LOG_MESSAGE_FORMAT_FIELDS(format)) - -/* Same, but checks all supported format specifications. - */ -#define _TRANSPORT_LOG_MESSAGE_FORMAT_FIELD_USED(field) \ - (_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(field, \ - TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \ - _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(field, \ - TRANSPORT_LOG_MESSAGE_TAG_FORMAT) || \ - _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(field, \ - TRANSPORT_LOG_MESSAGE_SRC_FORMAT)) - -#define _TRANSPORT_LOG_MESSAGE_FORMAT_DATETIME_USED \ - (_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(YEAR, \ - TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \ - _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(MONTH, \ - TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \ - _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(DAY, \ - TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \ - _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(HOUR, \ - TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \ - _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(MINUTE, \ - TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \ - _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(SECOND, \ - TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \ - _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(MILLISECOND, \ - TRANSPORT_LOG_MESSAGE_CTX_FORMAT)) - -#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) -#pragma warning(disable : 4204) /* nonstandard extension used: non-constant \ - aggregate initializer */ -#define memccpy _memccpy -#endif - -#if (defined(_MSC_VER) && !defined(__INTEL_COMPILER)) || defined(__MINGW64__) -#define vsnprintf(s, sz, fmt, va) fake_vsnprintf(s, sz, fmt, va) -static int fake_vsnprintf(char *s, size_t sz, const char *fmt, va_list ap) { - const int n = vsnprintf_s(s, sz, _TRUNCATE, fmt, ap); - return 0 < n ? n : (int)sz + 1; /* no need in _vscprintf() for now */ -} -#if TRANSPORT_LOG_OPTIMIZE_SIZE -#define snprintf(s, sz, ...) fake_snprintf(s, sz, __VA_ARGS__) -static int fake_snprintf(char *s, size_t sz, const char *fmt, ...) { - va_list va; - va_start(va, fmt); - const int n = fake_vsnprintf(s, sz, fmt, va); - va_end(va); - return n; -} -#endif -#endif - -typedef void (*time_cb)(struct tm *const tm, unsigned *const usec); -typedef void (*pid_cb)(int *const pid, int *const tid); -typedef void (*buffer_cb)(transport_log_message *msg, char *buf); - -typedef struct src_location { - const char *const func; - const char *const file; - const unsigned line; -} src_location; - -typedef struct mem_block { - const void *const d; - const unsigned d_sz; -} mem_block; - -static void time_callback(struct tm *const tm, unsigned *const usec); -static void pid_callback(int *const pid, int *const tid); -static void buffer_callback(transport_log_message *msg, char *buf); - -STATIC_ASSERT(eol_fits_eol_sz, - sizeof(TRANSPORT_LOG_EOL) <= TRANSPORT_LOG_EOL_SZ); -STATIC_ASSERT(eol_sz_greater_than_zero, 0 < TRANSPORT_LOG_EOL_SZ); -STATIC_ASSERT(eol_sz_less_than_buf_sz, - TRANSPORT_LOG_EOL_SZ < TRANSPORT_LOG_BUF_SZ); -#if !defined(_WIN32) && !defined(_WIN64) -STATIC_ASSERT(buf_sz_less_than_pipe_buf, TRANSPORT_LOG_BUF_SZ <= PIPE_BUF); -#endif -static const char c_hex[] = "0123456789abcdef"; - -static INSTRUMENTED_CONST unsigned g_buf_sz = - TRANSPORT_LOG_BUF_SZ - TRANSPORT_LOG_EOL_SZ; -static INSTRUMENTED_CONST time_cb g_time_cb = time_callback; -static INSTRUMENTED_CONST pid_cb g_pid_cb = pid_callback; -static INSTRUMENTED_CONST buffer_cb g_buffer_cb = buffer_callback; - -#if TRANSPORT_LOG_USE_ANDROID_LOG -#include - -static INLINE int android_lvl(const int lvl) { - switch (lvl) { - case TRANSPORT_LOG_VERBOSE: - return ANDROID_LOG_VERBOSE; - case TRANSPORT_LOG_DEBUG: - return ANDROID_LOG_DEBUG; - case TRANSPORT_LOG_INFO: - return ANDROID_LOG_INFO; - case TRANSPORT_LOG_WARN: - return ANDROID_LOG_WARN; - case TRANSPORT_LOG_ERROR: - return ANDROID_LOG_ERROR; - case TRANSPORT_LOG_FATAL: - return ANDROID_LOG_FATAL; - default: - ASSERT_UNREACHABLE("Bad log level"); - return ANDROID_LOG_UNKNOWN; - } -} - -static void out_android_callback(const transport_log_message *const msg, - void *arg) { - VAR_UNUSED(arg); - *msg->p = 0; - const char *tag = msg->p; - if (msg->tag_e != msg->tag_b) { - tag = msg->tag_b; - *msg->tag_e = 0; - } - __android_log_print(android_lvl(msg->lvl), ANDROID_TAG, "%s", msg->msg_b); -} - -enum { OUT_ANDROID_MASK = TRANSPORT_LOG_PUT_STD & ~TRANSPORT_LOG_PUT_CTX }; -#define OUT_ANDROID OUT_ANDROID_MASK, 0, out_android_callback -#endif - -#if TRANSPORT_LOG_USE_NSLOG -#include -CF_EXPORT void CFLog(int32_t level, CFStringRef format, ...); - -static INLINE int apple_lvl(const int lvl) { - switch (lvl) { - case TRANSPORT_LOG_VERBOSE: - return 7; /* ASL_LEVEL_DEBUG / kCFLogLevelDebug */ - ; - case TRANSPORT_LOG_DEBUG: - return 7; /* ASL_LEVEL_DEBUG / kCFLogLevelDebug */ - ; - case TRANSPORT_LOG_INFO: - return 6; /* ASL_LEVEL_INFO / kCFLogLevelInfo */ - ; - case TRANSPORT_LOG_WARN: - return 4; /* ASL_LEVEL_WARNING / kCFLogLevelWarning */ - ; - case TRANSPORT_LOG_ERROR: - return 3; /* ASL_LEVEL_ERR / kCFLogLevelError */ - ; - case TRANSPORT_LOG_FATAL: - return 0; /* ASL_LEVEL_EMERG / kCFLogLevelEmergency */ - ; - default: - ASSERT_UNREACHABLE("Bad log level"); - return 0; /* ASL_LEVEL_EMERG / kCFLogLevelEmergency */ - ; - } -} - -static void out_nslog_callback(const transport_log_message *const msg, - void *arg) { - VAR_UNUSED(arg); - *msg->p = 0; - CFLog(apple_lvl(msg->lvl), CFSTR("%s"), msg->tag_b); -} - -enum { OUT_NSLOG_MASK = TRANSPORT_LOG_PUT_STD & ~TRANSPORT_LOG_PUT_CTX }; -#define OUT_NSLOG OUT_NSLOG_MASK, 0, out_nslog_callback -#endif - -#if TRANSPORT_LOG_USE_DEBUGSTRING -#include - -static void out_debugstring_callback(const transport_log_message *const msg, - void *arg) { - VAR_UNUSED(arg); - msg->p[0] = '\n'; - msg->p[1] = '\0'; - OutputDebugStringA(msg->buf); -} - -enum { OUT_DEBUGSTRING_MASK = TRANSPORT_LOG_PUT_STD }; -#define OUT_DEBUGSTRING OUT_DEBUGSTRING_MASK, 0, out_debugstring_callback -#endif - -void transport_log_out_stderr_callback(const transport_log_message *const msg, - void *arg) { - VAR_UNUSED(arg); - const size_t eol_len = sizeof(TRANSPORT_LOG_EOL) - 1; - memcpy(msg->p, TRANSPORT_LOG_EOL, eol_len); -#if defined(_WIN32) || defined(_WIN64) - /* WriteFile() is atomic for local files opened with FILE_APPEND_DATA and - without FILE_WRITE_DATA */ - DWORD written; - WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg->buf, - (DWORD)(msg->p - msg->buf + eol_len), &written, 0); -#else - /* write() is atomic for buffers less than or equal to PIPE_BUF. */ - RETVAL_UNUSED( - write(STDERR_FILENO, msg->buf, (size_t)(msg->p - msg->buf) + eol_len)); -#endif -} - -static const transport_log_output out_stderr = {TRANSPORT_LOG_OUT_STDERR}; - -#if !TRANSPORT_LOG_EXTERN_TAG_PREFIX -TRANSPORT_LOG_DEFINE_TAG_PREFIX = 0; -#endif - -#if !TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT -TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT = {TRANSPORT_LOG_MEM_WIDTH}; -#endif - -#if !TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT -#if TRANSPORT_LOG_USE_ANDROID_LOG -TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {OUT_ANDROID}; -#elif TRANSPORT_LOG_USE_NSLOG -TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {OUT_NSLOG}; -#elif TRANSPORT_LOG_USE_DEBUGSTRING -TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {OUT_DEBUGSTRING}; -#else -TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {TRANSPORT_LOG_OUT_STDERR}; -#endif -#endif - -#if !TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL -TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = 0; -#endif - -const transport_log_spec _transport_log_stderr_spec = { - TRANSPORT_LOG_GLOBAL_FORMAT, - &out_stderr, -}; - -static const transport_log_spec global_spec = { - TRANSPORT_LOG_GLOBAL_FORMAT, - TRANSPORT_LOG_GLOBAL_OUTPUT, -}; - -#if _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(LEVEL, \ - TRANSPORT_LOG_MESSAGE_CTX_FORMAT) -static char lvl_char(const int lvl) { - switch (lvl) { - case TRANSPORT_LOG_VERBOSE: - return 'V'; - case TRANSPORT_LOG_DEBUG: - return 'D'; - case TRANSPORT_LOG_INFO: - return 'I'; - case TRANSPORT_LOG_WARN: - return 'W'; - case TRANSPORT_LOG_ERROR: - return 'E'; - case TRANSPORT_LOG_FATAL: - return 'F'; - default: - ASSERT_UNREACHABLE("Bad log level"); - return '?'; - } -} -#endif - -#define GCCVER_LESS(MAJOR, MINOR, PATCH) \ - (__GNUC__ < MAJOR || (__GNUC__ == MAJOR && (__GNUC_MINOR__ < MINOR || \ - (__GNUC_MINOR__ == MINOR && \ - __GNUC_PATCHLEVEL__ < PATCH)))) - -#if !defined(__clang__) && defined(__GNUC__) && GCCVER_LESS(4, 7, 0) -#define __atomic_load_n(vp, model) __sync_fetch_and_add(vp, 0) -#define __atomic_fetch_add(vp, n, model) __sync_fetch_and_add(vp, n) -#define __atomic_sub_fetch(vp, n, model) __sync_sub_and_fetch(vp, n) -#define __atomic_or_fetch(vp, n, model) __sync_or_and_fetch(vp, n) -#define __atomic_and_fetch(vp, n, model) __sync_and_and_fetch(vp, n) -/* Note: will not store old value of *vp in *ep (non-standard behaviour) */ -#define __atomic_compare_exchange_n(vp, ep, d, weak, smodel, fmodel) \ - __sync_bool_compare_and_swap(vp, *(ep), d) -#endif - -#if !TRANSPORT_LOG_OPTIMIZE_SIZE && !defined(_WIN32) && !defined(_WIN64) -#define TCACHE -#define TCACHE_STALE (0x40000000) -#define TCACHE_FLUID (0x40000000 | 0x80000000) -static unsigned g_tcache_mode = TCACHE_STALE; -static struct timeval g_tcache_tv = {0, 0}; -static struct tm g_tcache_tm = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - -static INLINE int tcache_get(const struct timeval *const tv, - struct tm *const tm) { - unsigned mode; - mode = __atomic_load_n(&g_tcache_mode, __ATOMIC_RELAXED); - if (0 == (mode & TCACHE_FLUID)) { - mode = __atomic_fetch_add(&g_tcache_mode, 1, __ATOMIC_ACQUIRE); - if (0 == (mode & TCACHE_FLUID)) { - if (g_tcache_tv.tv_sec == tv->tv_sec) { - *tm = g_tcache_tm; - __atomic_sub_fetch(&g_tcache_mode, 1, __ATOMIC_RELEASE); - return !0; - } - __atomic_or_fetch(&g_tcache_mode, TCACHE_STALE, __ATOMIC_RELAXED); - } - __atomic_sub_fetch(&g_tcache_mode, 1, __ATOMIC_RELEASE); - } - return 0; -} - -static INLINE void tcache_set(const struct timeval *const tv, - struct tm *const tm) { - unsigned stale = TCACHE_STALE; - if (__atomic_compare_exchange_n(&g_tcache_mode, &stale, TCACHE_FLUID, 0, - __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) { - g_tcache_tv = *tv; - g_tcache_tm = *tm; - __atomic_and_fetch(&g_tcache_mode, ~TCACHE_FLUID, __ATOMIC_RELEASE); - } -} -#endif - -static void time_callback(struct tm *const tm, unsigned *const msec) { -#if !_TRANSPORT_LOG_MESSAGE_FORMAT_DATETIME_USED - VAR_UNUSED(tm); - VAR_UNUSED(msec); -#else -#if defined(_WIN32) || defined(_WIN64) - SYSTEMTIME st; - GetLocalTime(&st); - tm->tm_year = st.wYear; - tm->tm_mon = st.wMonth - 1; - tm->tm_mday = st.wDay; - tm->tm_wday = st.wDayOfWeek; - tm->tm_hour = st.wHour; - tm->tm_min = st.wMinute; - tm->tm_sec = st.wSecond; - *msec = st.wMilliseconds; -#else - struct timeval tv; - gettimeofday(&tv, 0); -#ifndef TCACHE - localtime_r(&tv.tv_sec, tm); -#else - if (!tcache_get(&tv, tm)) { - localtime_r(&tv.tv_sec, tm); - tcache_set(&tv, tm); - } -#endif - *msec = (unsigned)tv.tv_usec / 1000; -#endif -#endif -} - -static void pid_callback(int *const pid, int *const tid) { -#if !_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(PID, \ - TRANSPORT_LOG_MESSAGE_CTX_FORMAT) - VAR_UNUSED(pid); -#else -#if defined(_WIN32) || defined(_WIN64) - *pid = GetCurrentProcessId(); -#else - *pid = getpid(); -#endif -#endif - -#if !_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(TID, \ - TRANSPORT_LOG_MESSAGE_CTX_FORMAT) - VAR_UNUSED(tid); -#else -#if defined(_WIN32) || defined(_WIN64) - *tid = GetCurrentThreadId(); -#elif defined(__ANDROID__) - *tid = gettid(); -#elif defined(__linux__) - *tid = syscall(SYS_gettid); -#elif defined(__MACH__) - *tid = (int)pthread_mach_thread_np(pthread_self()); -#else -#define Platform not supported -#endif -#endif -} - -static void buffer_callback(transport_log_message *msg, char *buf) { - msg->e = (msg->p = msg->buf = buf) + g_buf_sz; -} - -#if _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(FUNCTION, \ - TRANSPORT_LOG_MESSAGE_SRC_FORMAT) -static const char *funcname(const char *func) { return func ? func : ""; } -#endif - -#if _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(FILENAME, \ - TRANSPORT_LOG_MESSAGE_SRC_FORMAT) -static const char *filename(const char *file) { - const char *f = file; - for (const char *p = file; 0 != *p; ++p) { - if ('/' == *p || '\\' == *p) { - f = p + 1; - } - } - return f; -} -#endif - -static INLINE size_t nprintf_size(transport_log_message *const msg) { - // *nprintf() always puts 0 in the end when input buffer is not empty. This - // 0 is not desired because its presence sets (ctx->p) to (ctx->e - 1) which - // leaves space for one more character. Some put_xxx() functions don't use - // *nprintf() and could use that last character. In that case log line will - // have multiple (two) half-written parts which is confusing. To workaround - // that we allow *nprintf() to write its 0 in the eol area (which is always - // not empty). - return (size_t)(msg->e - msg->p + 1); -} - -static INLINE void put_nprintf(transport_log_message *const msg, const int n) { - if (0 < n) { - msg->p = n < msg->e - msg->p ? msg->p + n : msg->e; - } -} - -static INLINE char *put_padding_r(const unsigned w, const char wc, char *p, - char *e) { - for (char *const b = e - w; b < p; *--p = wc) { - } - return p; -} - -static char *put_integer_r(unsigned v, const int sign, const unsigned w, - const char wc, char *const e) { - static const char _signs[] = {'-', '0', '+'}; - static const char *const signs = _signs + 1; - char *p = e; - do { - *--p = '0' + v % 10; - } while (0 != (v /= 10)); - if (0 == sign) return put_padding_r(w, wc, p, e); - if ('0' != wc) { - *--p = signs[sign]; - return put_padding_r(w, wc, p, e); - } - p = put_padding_r(w, wc, p, e + 1); - *--p = signs[sign]; - return p; -} - -static INLINE char *put_uint_r(const unsigned v, const unsigned w, - const char wc, char *const e) { - return put_integer_r(v, 0, w, wc, e); -} - -static INLINE char *put_int_r(const int v, const unsigned w, const char wc, - char *const e) { - return 0 <= v ? put_integer_r((unsigned)v, 0, w, wc, e) - : put_integer_r((unsigned)-v, -1, w, wc, e); -} - -static INLINE char *put_stringn(const char *const s_p, const char *const s_e, - char *const p, char *const e) { - const ptrdiff_t m = e - p; - ptrdiff_t n = s_e - s_p; - if (n > m) { - n = m; - } - memcpy(p, s_p, n); - return p + n; -} - -static INLINE char *put_string(const char *s, char *p, char *const e) { - const ptrdiff_t n = e - p; - char *const c = (char *)memccpy(p, s, '\0', n); - return 0 != c ? c - 1 : e; -} - -static INLINE char *put_uint(unsigned v, const unsigned w, const char wc, - char *const p, char *const e) { - char buf[16]; - char *const se = buf + _countof(buf); - char *sp = put_uint_r(v, w, wc, se); - return put_stringn(sp, se, p, e); -} - -#define PUT_CSTR_R(p, STR) \ - do { \ - for (unsigned i = sizeof(STR) - 1; 0 < i--;) { \ - *--(p) = (STR)[i]; \ - } \ - } \ - _TRANSPORT_LOG_ONCE - -#define PUT_CSTR_CHECKED(p, e, STR) \ - do { \ - for (unsigned i = 0; (e) > (p) && (sizeof(STR) - 1) > i; ++i) { \ - *(p)++ = (STR)[i]; \ - } \ - } \ - _TRANSPORT_LOG_ONCE - -/* F_INIT field support. - */ -#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__ -#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__YEAR -#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__MONTH -#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__DAY -#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__HOUR -#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__MINUTE -#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__SECOND -#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__MILLISECOND -#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__PID -#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__TID -#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__LEVEL -#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__TAG(ps, ts) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__FUNCTION -#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__FILENAME -#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__FILELINE -#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__S(s) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__F_INIT(expr) _PP_UNTUPLE(expr); -#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__F_UINT(w, v) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT(field) \ - _PP_CONCAT_3(_TRANSPORT_LOG_MESSAGE_FORMAT_INIT_, _, field) - -/* Implements generation of printf-like format string for log message - * format specification. - */ -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__ "" -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__YEAR "%04u" -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__MONTH "%02u" -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__DAY "%02u" -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__HOUR "%02u" -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__MINUTE "%02u" -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__SECOND "%02u" -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__MILLISECOND "%03u" -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__PID "%5i" -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__TID "%5i" -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__LEVEL "%c" -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__TAG UNDEFINED -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__FUNCTION "%s" -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__FILENAME "%s" -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__FILELINE "%u" -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__S(s) s -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__F_INIT(expr) "" -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__F_UINT(w, v) "%" #w "u" -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT(field) \ - _PP_CONCAT_3(_TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT_, _, field) - -/* Implements generation of printf-like format parameters for log message - * format specification. - */ -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__ -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__YEAR \ - , (unsigned)(tm.tm_year + 1900) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__MONTH \ - , (unsigned)(tm.tm_mon + 1) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__DAY , (unsigned)tm.tm_mday -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__HOUR , (unsigned)tm.tm_hour -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__MINUTE , (unsigned)tm.tm_min -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__SECOND , (unsigned)tm.tm_sec -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__MILLISECOND , (unsigned)msec -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__PID , pid -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__TID , tid -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__LEVEL \ - , (char)lvl_char(msg->lvl) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__TAG UNDEFINED -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__FUNCTION , funcname(src->func) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__FILENAME , filename(src->file) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__FILELINE , src->line -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__S(s) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__F_INIT(expr) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__F_UINT(w, v) , v -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL(field) \ - _PP_CONCAT_3(_TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL_, _, field) - -/* Implements generation of put_xxx_t statements for log message specification. - */ -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__ -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__YEAR \ - p = put_uint_r(tm.tm_year + 1900, 4, '0', p); -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__MONTH \ - p = put_uint_r((unsigned)tm.tm_mon + 1, 2, '0', p); -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__DAY \ - p = put_uint_r((unsigned)tm.tm_mday, 2, '0', p); -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__HOUR \ - p = put_uint_r((unsigned)tm.tm_hour, 2, '0', p); -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__MINUTE \ - p = put_uint_r((unsigned)tm.tm_min, 2, '0', p); -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__SECOND \ - p = put_uint_r((unsigned)tm.tm_sec, 2, '0', p); -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__MILLISECOND \ - p = put_uint_r(msec, 3, '0', p); -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__PID p = put_int_r(pid, 5, ' ', p); -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__TID p = put_int_r(tid, 5, ' ', p); -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__LEVEL *--p = lvl_char(msg->lvl); -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__TAG UNDEFINED -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__FUNCTION UNDEFINED -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__FILENAME UNDEFINED -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__FILELINE UNDEFINED -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__S(s) PUT_CSTR_R(p, s); -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__F_INIT(expr) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__F_UINT(w, v) \ - p = put_uint_r(v, w, ' ', p); -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R(field) \ - _PP_CONCAT_3(_TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R_, _, field) - -static void put_ctx(transport_log_message *const msg) { - _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_INIT, TRANSPORT_LOG_MESSAGE_CTX_FORMAT) -#if !_TRANSPORT_LOG_MESSAGE_FORMAT_FIELDS(TRANSPORT_LOG_MESSAGE_CTX_FORMAT) - VAR_UNUSED(msg); -#else -#if _TRANSPORT_LOG_MESSAGE_FORMAT_DATETIME_USED - struct tm tm; - unsigned msec; - g_time_cb(&tm, &msec); -#endif -#if _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS( \ - PID, TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \ - _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(TID, \ - TRANSPORT_LOG_MESSAGE_CTX_FORMAT) - int pid, tid; - g_pid_cb(&pid, &tid); -#endif - -#if TRANSPORT_LOG_OPTIMIZE_SIZE - int n; - n = snprintf(msg->p, nprintf_size(msg), - _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT, - TRANSPORT_LOG_MESSAGE_CTX_FORMAT) - _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL, - TRANSPORT_LOG_MESSAGE_CTX_FORMAT)); - put_nprintf(msg, n); -#else - char buf[64]; - char *const e = buf + sizeof(buf); - char *p = e; - _PP_RMAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R, - TRANSPORT_LOG_MESSAGE_CTX_FORMAT) - msg->p = put_stringn(p, e, msg->p, msg->e); -#endif -#endif -} - -#define PUT_TAG(msg, tag, prefix_delim, tag_delim) \ - do { \ - const char *ch; \ - msg->tag_b = msg->p; \ - if (0 != (ch = _transport_log_tag_prefix)) { \ - for (; msg->e != msg->p && 0 != (*msg->p = *ch); ++msg->p, ++ch) { \ - } \ - } \ - if (0 != (ch = tag) && 0 != tag[0]) { \ - if (msg->tag_b != msg->p) { \ - PUT_CSTR_CHECKED(msg->p, msg->e, prefix_delim); \ - } \ - for (; msg->e != msg->p && 0 != (*msg->p = *ch); ++msg->p, ++ch) { \ - } \ - } \ - msg->tag_e = msg->p; \ - if (msg->tag_b != msg->p) { \ - PUT_CSTR_CHECKED(msg->p, msg->e, tag_delim); \ - } \ - } \ - _TRANSPORT_LOG_ONCE - -/* Implements simple put statements for log message specification. - */ -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__ -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__YEAR UNDEFINED -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__MONTH UNDEFINED -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__DAY UNDEFINED -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__HOUR UNDEFINED -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__MINUTE UNDEFINED -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__SECOND UNDEFINED -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__MILLISECOND UNDEFINED -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__PID UNDEFINED -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__TID UNDEFINED -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__LEVEL UNDEFINED -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__TAG(pd, td) \ - PUT_TAG(msg, tag, pd, td); -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__FUNCTION \ - msg->p = put_string(funcname(src->func), msg->p, msg->e); -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__FILENAME \ - msg->p = put_string(filename(src->file), msg->p, msg->e); -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__FILELINE \ - msg->p = put_uint(src->line, 0, '\0', msg->p, msg->e); -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__S(s) \ - PUT_CSTR_CHECKED(msg->p, msg->e, s); -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__F_INIT(expr) -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__F_UINT(w, v) \ - msg->p = put_uint(v, w, ' ', msg->p, msg->e); -#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT(field) \ - _PP_CONCAT_3(_TRANSPORT_LOG_MESSAGE_FORMAT_PUT_, _, field) - -static void put_tag(transport_log_message *const msg, const char *const tag) { - _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_INIT, TRANSPORT_LOG_MESSAGE_TAG_FORMAT) -#if !_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(TAG, \ - TRANSPORT_LOG_MESSAGE_TAG_FORMAT) - VAR_UNUSED(tag); -#endif -#if !_TRANSPORT_LOG_MESSAGE_FORMAT_FIELDS(TRANSPORT_LOG_MESSAGE_TAG_FORMAT) - VAR_UNUSED(msg); -#else - _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PUT, TRANSPORT_LOG_MESSAGE_TAG_FORMAT) -#endif -} - -static void put_src(transport_log_message *const msg, - const src_location *const src) { - _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_INIT, TRANSPORT_LOG_MESSAGE_SRC_FORMAT) -#if !_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS( \ - FUNCTION, TRANSPORT_LOG_MESSAGE_SRC_FORMAT) && \ - !_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS( \ - FILENAME, TRANSPORT_LOG_MESSAGE_SRC_FORMAT) && \ - !_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(FILELINE, \ - TRANSPORT_LOG_MESSAGE_SRC_FORMAT) - VAR_UNUSED(src); -#endif -#if !_TRANSPORT_LOG_MESSAGE_FORMAT_FIELDS(TRANSPORT_LOG_MESSAGE_SRC_FORMAT) - VAR_UNUSED(msg); -#else -#if TRANSPORT_LOG_OPTIMIZE_SIZE - int n; - n = snprintf(msg->p, nprintf_size(msg), - _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT, - TRANSPORT_LOG_MESSAGE_SRC_FORMAT) - _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL, - TRANSPORT_LOG_MESSAGE_SRC_FORMAT)); - put_nprintf(msg, n); -#else - _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PUT, TRANSPORT_LOG_MESSAGE_SRC_FORMAT) -#endif -#endif -} - -static void put_msg(transport_log_message *const msg, const char *const fmt, - va_list va) { - int n; - msg->msg_b = msg->p; - n = vsnprintf(msg->p, nprintf_size(msg), fmt, va); - put_nprintf(msg, n); -} - -static void output_mem(const transport_log_spec *log, - transport_log_message *const msg, - const mem_block *const mem) { - if (0 == mem->d || 0 == mem->d_sz) { - return; - } - const unsigned char *mem_p = (const unsigned char *)mem->d; - const unsigned char *const mem_e = mem_p + mem->d_sz; - const unsigned char *mem_cut; - const ptrdiff_t mem_width = (ptrdiff_t)log->format->mem_width; - char *const hex_b = msg->msg_b; - char *const ascii_b = hex_b + 2 * mem_width + 2; - char *const ascii_e = ascii_b + mem_width; - if (msg->e < ascii_e) { - return; - } - while (mem_p != mem_e) { - char *hex = hex_b; - char *ascii = ascii_b; - for (mem_cut = mem_width < mem_e - mem_p ? mem_p + mem_width : mem_e; - mem_cut != mem_p; ++mem_p) { - const unsigned char ch = *mem_p; - *hex++ = c_hex[(0xf0 & ch) >> 4]; - *hex++ = c_hex[(0x0f & ch)]; - *ascii++ = isprint(ch) ? (char)ch : '?'; - } - while (hex != ascii_b) { - *hex++ = ' '; - } - msg->p = ascii; - log->output->callback(msg, log->output->arg); - } -} - -void transport_log_set_tag_prefix(const char *const prefix) { - _transport_log_tag_prefix = prefix; -} - -void transport_log_set_mem_width(const unsigned w) { - _transport_log_global_format.mem_width = w; -} - -void transport_log_set_output_level(const int lvl) { - _transport_log_global_output_lvl = lvl; -} - -void transport_log_set_output_v(const unsigned mask, void *const arg, - const transport_log_output_cb callback) { - _transport_log_global_output.mask = mask; - _transport_log_global_output.arg = arg; - _transport_log_global_output.callback = callback; -} - -static void _transport_log_write_imp(const transport_log_spec *log, - const src_location *const src, - const mem_block *const mem, const int lvl, - const char *const tag, - const char *const fmt, va_list va) { - transport_log_message msg; - char buf[TRANSPORT_LOG_BUF_SZ]; - const unsigned mask = log->output->mask; - msg.lvl = lvl; - msg.tag = tag; - g_buffer_cb(&msg, buf); - if (TRANSPORT_LOG_PUT_CTX & mask) { - put_ctx(&msg); - } - if (TRANSPORT_LOG_PUT_TAG & mask) { - put_tag(&msg, tag); - } - if (0 != src && TRANSPORT_LOG_PUT_SRC & mask) { - put_src(&msg, src); - } - if (TRANSPORT_LOG_PUT_MSG & mask) { - put_msg(&msg, fmt, va); - } - log->output->callback(&msg, log->output->arg); - if (0 != mem && TRANSPORT_LOG_PUT_MSG & mask) { - output_mem(log, &msg, mem); - } -} - -void _transport_log_write_d(const char *const func, const char *const file, - const unsigned line, const int lvl, - const char *const tag, const char *const fmt, ...) { - const src_location src = {func, file, line}; - va_list va; - va_start(va, fmt); - _transport_log_write_imp(&global_spec, &src, 0, lvl, tag, fmt, va); - va_end(va); -} - -void _transport_log_write_aux_d(const char *const func, const char *const file, - const unsigned line, - const transport_log_spec *const log, - const int lvl, const char *const tag, - const char *const fmt, ...) { - const src_location src = {func, file, line}; - va_list va; - va_start(va, fmt); - _transport_log_write_imp(log, &src, 0, lvl, tag, fmt, va); - va_end(va); -} - -void _transport_log_write(const int lvl, const char *const tag, - const char *const fmt, ...) { - va_list va; - va_start(va, fmt); - _transport_log_write_imp(&global_spec, 0, 0, lvl, tag, fmt, va); - va_end(va); -} - -void _transport_log_write_aux(const transport_log_spec *const log, - const int lvl, const char *const tag, - const char *const fmt, ...) { - va_list va; - va_start(va, fmt); - _transport_log_write_imp(log, 0, 0, lvl, tag, fmt, va); - va_end(va); -} - -void _transport_log_write_mem_d(const char *const func, const char *const file, - const unsigned line, const int lvl, - const char *const tag, const void *const d, - const unsigned d_sz, const char *const fmt, - ...) { - const src_location src = {func, file, line}; - const mem_block mem = {d, d_sz}; - va_list va; - va_start(va, fmt); - _transport_log_write_imp(&global_spec, &src, &mem, lvl, tag, fmt, va); - va_end(va); -} - -void _transport_log_write_mem_aux_d(const char *const func, - const char *const file, const unsigned line, - const transport_log_spec *const log, - const int lvl, const char *const tag, - const void *const d, const unsigned d_sz, - const char *const fmt, ...) { - const src_location src = {func, file, line}; - const mem_block mem = {d, d_sz}; - va_list va; - va_start(va, fmt); - _transport_log_write_imp(log, &src, &mem, lvl, tag, fmt, va); - va_end(va); -} - -void _transport_log_write_mem(const int lvl, const char *const tag, - const void *const d, const unsigned d_sz, - const char *const fmt, ...) { - const mem_block mem = {d, d_sz}; - va_list va; - va_start(va, fmt); - _transport_log_write_imp(&global_spec, 0, &mem, lvl, tag, fmt, va); - va_end(va); -} - -void _transport_log_write_mem_aux(const transport_log_spec *const log, - const int lvl, const char *const tag, - const void *const d, const unsigned d_sz, - const char *const fmt, ...) { - const mem_block mem = {d, d_sz}; - va_list va; - va_start(va, fmt); - _transport_log_write_imp(log, 0, &mem, lvl, tag, fmt, va); - va_end(va); -} \ No newline at end of file diff --git a/libtransport/src/hicn/transport/utils/log.h b/libtransport/src/hicn/transport/utils/log.h deleted file mode 100644 index 3c4f1277a..000000000 --- a/libtransport/src/hicn/transport/utils/log.h +++ /dev/null @@ -1,1057 +0,0 @@ -/* - * 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. - */ - -/* - * The MIT License (MIT) - * - * Copyright (c) 2017 wonder-mice - * - * 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 - -/* To detect incompatible changes you can define TRANSPORT_LOG_VERSION_REQUIRED - * to be the current value of TRANSPORT_LOG_VERSION before including this file - * (or via compiler command line): - * - * #define TRANSPORT_LOG_VERSION_REQUIRED 4 - * #include - * - * Compilation will fail when included file has different version. - */ -#define TRANSPORT_LOG_VERSION 4 -#if defined(TRANSPORT_LOG_VERSION_REQUIRED) -#if TRANSPORT_LOG_VERSION_REQUIRED != TRANSPORT_LOG_VERSION -#error different transport_log version required -#endif -#endif - -/* Log level guideline: - * - TRANSPORT_LOG_FATAL - happened something impossible and absolutely - * unexpected. Process can't continue and must be terminated. Example: division - * by zero, unexpected modifications from other thread. - * - TRANSPORT_LOG_ERROR - happened something possible, but highly unexpected. - * The process is able to recover and continue execution. Example: out of memory - * (could also be FATAL if not handled properly). - * - TRANSPORT_LOG_WARN - happened something that *usually* should not happen - * and significantly changes application behavior for some period of time. - * Example: configuration file not found, auth error. - * - TRANSPORT_LOG_INFO - happened significant life cycle event or major state - * transition. - * Example: app started, user logged in. - * - TRANSPORT_LOG_DEBUG - minimal set of events that could help to reconstruct - * the execution path. Usually disabled in release builds. - * - TRANSPORT_LOG_VERBOSE - all other events. Usually disabled in release - * builds. - * - * *Ideally*, log file of debugged, well tested, production ready application - * should be empty or very small. Choosing a right log level is as important as - * providing short and self descriptive log message. - */ -#define TRANSPORT_LOG_VERBOSE 1 -#define TRANSPORT_LOG_DEBUG 2 -#define TRANSPORT_LOG_INFO 3 -#define TRANSPORT_LOG_WARN 4 -#define TRANSPORT_LOG_ERROR 5 -#define TRANSPORT_LOG_FATAL 6 -#define TRANSPORT_LOG_NONE 0xFF - -/* "Current" log level is a compile time check and has no runtime overhead. Log - * level that is below current log level it said to be "disabled". Otherwise, - * it's "enabled". Log messages that are disabled has no runtime overhead - they - * are converted to no-op by preprocessor and then eliminated by compiler. - * Current log level is configured per compilation module (.c/.cpp/.m file) by - * defining TRANSPORT_LOG_DEF_LEVEL or TRANSPORT_LOG_LEVEL. TRANSPORT_LOG_LEVEL - * has higer priority and when defined overrides value provided by - * TRANSPORT_LOG_DEF_LEVEL. - * - * Common practice is to define default current log level with - * TRANSPORT_LOG_DEF_LEVEL in build script (e.g. Makefile, CMakeLists.txt, gyp, - * etc.) for the entire project or target: - * - * CC_ARGS := -DTRANSPORT_LOG_DEF_LEVEL=TRANSPORT_LOG_INFO - * - * And when necessary to override it with TRANSPORT_LOG_LEVEL in .c/.cpp/.m - * files before including transport_log.h: - * - * #define TRANSPORT_LOG_LEVEL TRANSPORT_LOG_VERBOSE - * #include - * - * If both TRANSPORT_LOG_DEF_LEVEL and TRANSPORT_LOG_LEVEL are undefined, then - * TRANSPORT_LOG_INFO will be used for release builds (NDEBUG is defined) and - * TRANSPORT_LOG_DEBUG otherwise (NDEBUG is not defined). - */ -#if defined(TRANSPORT_LOG_LEVEL) -#define _TRANSPORT_LOG_LEVEL TRANSPORT_LOG_LEVEL -#elif defined(TRANSPORT_LOG_DEF_LEVEL) -#define _TRANSPORT_LOG_LEVEL TRANSPORT_LOG_DEF_LEVEL -#else -#ifdef NDEBUG -#define _TRANSPORT_LOG_LEVEL TRANSPORT_LOG_INFO -#else -#define _TRANSPORT_LOG_LEVEL TRANSPORT_LOG_DEBUG -#endif -#endif - -/* "Output" log level is a runtime check. When log level is below output log - * level it said to be "turned off" (or just "off" for short). Otherwise it's - * "turned on" (or just "on"). Log levels that were "disabled" (see - * TRANSPORT_LOG_LEVEL and TRANSPORT_LOG_DEF_LEVEL) can't be "turned on", but - * "enabled" log levels could be "turned off". Only messages with log level - * which is "turned on" will reach output facility. All other messages will be - * ignored (and their arguments will not be evaluated). Output log level is a - * global property and configured per process using - * transport_log_set_output_level() function which can be called at any time. - * - * Though in some cases it could be useful to configure output log level per - * compilation module or per library. There are two ways to achieve that: - * - Define TRANSPORT_LOG_OUTPUT_LEVEL to expresion that evaluates to desired - * output log level. - * - Copy transport_log.h and transport_log.c files into your library and build - * it with TRANSPORT_LOG_LIBRARY_PREFIX defined to library specific prefix. See - * TRANSPORT_LOG_LIBRARY_PREFIX for more details. - * - * When defined, TRANSPORT_LOG_OUTPUT_LEVEL must evaluate to integral value that - * corresponds to desired output log level. Use it only when compilation module - * is required to have output log level which is different from global output - * log level set by transport_log_set_output_level() function. For other cases, - * consider defining TRANSPORT_LOG_LEVEL or using - * transport_log_set_output_level() function. - * - * Example: - * - * #define TRANSPORT_LOG_OUTPUT_LEVEL g_module_log_level - * #include - * static int g_module_log_level = TRANSPORT_LOG_INFO; - * static void foo() { - * TRANSPORT_LOGI("Will check g_module_log_level for output log level"); - * } - * void debug_log(bool on) { - * g_module_log_level = on? TRANSPORT_LOG_DEBUG: TRANSPORT_LOG_INFO; - * } - * - * Note on performance. This expression will be evaluated each time message is - * logged (except when message log level is "disabled" - see TRANSPORT_LOG_LEVEL - * for details). Keep this expression as simple as possible, otherwise it will - * not only add runtime overhead, but also will increase size of call site - * (which will result in larger executable). The prefered way is to use integer - * variable (as in example above). If structure must be used, log_level field - * must be the first field in this structure: - * - * #define TRANSPORT_LOG_OUTPUT_LEVEL (g_config.log_level) - * #include - * struct config { - * int log_level; - * unsigned other_field; - * [...] - * }; - * static config g_config = {TRANSPORT_LOG_INFO, 0, ...}; - * - * This allows compiler to generate more compact load instruction (no need to - * specify offset since it's zero). Calling a function to get output log level - * is generaly a bad idea, since it will increase call site size and runtime - * overhead even further. - */ -#if defined(TRANSPORT_LOG_OUTPUT_LEVEL) -#define _TRANSPORT_LOG_OUTPUT_LEVEL TRANSPORT_LOG_OUTPUT_LEVEL -#else -#define _TRANSPORT_LOG_OUTPUT_LEVEL _transport_log_global_output_lvl -#endif - -/* "Tag" is a compound string that could be associated with a log message. It - * consists of tag prefix and tag (both are optional). - * - * Tag prefix is a global property and configured per process using - * transport_log_set_tag_prefix() function. Tag prefix identifies context in - * which component or module is running (e.g. process name). For example, the - * same library could be used in both client and server processes that work on - * the same machine. Tag prefix could be used to easily distinguish between - * them. For more details about tag prefix see transport_log_set_tag_prefix() - * function. Tag prefix - * - * Tag identifies component or module. It is configured per compilation module - * (.c/.cpp/.m file) by defining TRANSPORT_LOG_TAG or TRANSPORT_LOG_DEF_TAG. - * TRANSPORT_LOG_TAG has higer priority and when defined overrides value - * provided by TRANSPORT_LOG_DEF_TAG. When defined, value must evaluate to - * (const char *), so for strings double quotes must be used. - * - * Default tag could be defined with TRANSPORT_LOG_DEF_TAG in build script (e.g. - * Makefile, CMakeLists.txt, gyp, etc.) for the entire project or target: - * - * CC_ARGS := -DTRANSPORT_LOG_DEF_TAG=\"MISC\" - * - * And when necessary could be overriden with TRANSPORT_LOG_TAG in .c/.cpp/.m - * files before including transport_log.h: - * - * #define TRANSPORT_LOG_TAG "MAIN" - * #include - * - * If both TRANSPORT_LOG_DEF_TAG and TRANSPORT_LOG_TAG are undefined no tag will - * be added to the log message (tag prefix still could be added though). - * - * Output example: - * - * 04-29 22:43:20.244 40059 1299 I hello.MAIN Number of arguments: 1 - * | | - * | +- tag (e.g. module) - * +- tag prefix (e.g. process name) - */ -#if defined(TRANSPORT_LOG_TAG) -#define _TRANSPORT_LOG_TAG TRANSPORT_LOG_TAG -#elif defined(TRANSPORT_LOG_DEF_TAG) -#define _TRANSPORT_LOG_TAG TRANSPORT_LOG_DEF_TAG -#else -#define _TRANSPORT_LOG_TAG 0 -#endif - -/* Source location is part of a log line that describes location (function or - * method name, file name and line number, e.g. "runloop@main.cpp:68") of a - * log statement that produced it. - * Source location formats are: - * - TRANSPORT_LOG_SRCLOC_NONE - don't add source location to log line. - * - TRANSPORT_LOG_SRCLOC_SHORT - add source location in short form (file and - * line number, e.g. "@main.cpp:68"). - * - TRANSPORT_LOG_SRCLOC_LONG - add source location in long form (function or - * method name, file and line number, e.g. "runloop@main.cpp:68"). - */ -#define TRANSPORT_LOG_SRCLOC_NONE 0 -#define TRANSPORT_LOG_SRCLOC_SHORT 1 -#define TRANSPORT_LOG_SRCLOC_LONG 2 - -/* Source location format is configured per compilation module (.c/.cpp/.m - * file) by defining TRANSPORT_LOG_DEF_SRCLOC or TRANSPORT_LOG_SRCLOC. - * TRANSPORT_LOG_SRCLOC has higer priority and when defined overrides value - * provided by TRANSPORT_LOG_DEF_SRCLOC. - * - * Common practice is to define default format with TRANSPORT_LOG_DEF_SRCLOC in - * build script (e.g. Makefile, CMakeLists.txt, gyp, etc.) for the entire - * project or target: - * - * CC_ARGS := -DTRANSPORT_LOG_DEF_SRCLOC=TRANSPORT_LOG_SRCLOC_LONG - * - * And when necessary to override it with TRANSPORT_LOG_SRCLOC in .c/.cpp/.m - * files before including transport_log.h: - * - * #define TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_SRCLOC_NONE - * #include - * - * If both TRANSPORT_LOG_DEF_SRCLOC and TRANSPORT_LOG_SRCLOC are undefined, then - * TRANSPORT_LOG_SRCLOC_NONE will be used for release builds (NDEBUG is defined) - * and TRANSPORT_LOG_SRCLOC_LONG otherwise (NDEBUG is not defined). - */ -#if defined(TRANSPORT_LOG_SRCLOC) -#define _TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_SRCLOC -#elif defined(TRANSPORT_LOG_DEF_SRCLOC) -#define _TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_DEF_SRCLOC -#else -#ifdef NDEBUG -#define _TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_SRCLOC_NONE -#else -#define _TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_SRCLOC_LONG -#endif -#endif -#if TRANSPORT_LOG_SRCLOC_LONG == _TRANSPORT_LOG_SRCLOC -#define _TRANSPORT_LOG_SRCLOC_FUNCTION _TRANSPORT_LOG_FUNCTION -#else -#define _TRANSPORT_LOG_SRCLOC_FUNCTION 0 -#endif - -/* Censoring provides conditional logging of secret information, also known as - * Personally Identifiable Information (PII) or Sensitive Personal Information - * (SPI). Censoring can be either enabled (TRANSPORT_LOG_CENSORED) or disabled - * (TRANSPORT_LOG_UNCENSORED). When censoring is enabled, log statements marked - * as "secrets" will be ignored and will have zero overhead (arguments also will - * not be evaluated). - */ -#define TRANSPORT_LOG_CENSORED 1 -#define TRANSPORT_LOG_UNCENSORED 0 - -/* Censoring is configured per compilation module (.c/.cpp/.m file) by defining - * TRANSPORT_LOG_DEF_CENSORING or TRANSPORT_LOG_CENSORING. - * TRANSPORT_LOG_CENSORING has higer priority and when defined overrides value - * provided by TRANSPORT_LOG_DEF_CENSORING. - * - * Common practice is to define default censoring with - * TRANSPORT_LOG_DEF_CENSORING in build script (e.g. Makefile, CMakeLists.txt, - * gyp, etc.) for the entire project or target: - * - * CC_ARGS := -DTRANSPORT_LOG_DEF_CENSORING=TRANSPORT_LOG_CENSORED - * - * And when necessary to override it with TRANSPORT_LOG_CENSORING in .c/.cpp/.m - * files before including transport_log.h (consider doing it only for debug - * purposes and be very careful not to push such temporary changes to source - * control): - * - * #define TRANSPORT_LOG_CENSORING TRANSPORT_LOG_UNCENSORED - * #include - * - * If both TRANSPORT_LOG_DEF_CENSORING and TRANSPORT_LOG_CENSORING are - * undefined, then TRANSPORT_LOG_CENSORED will be used for release builds - * (NDEBUG is defined) and TRANSPORT_LOG_UNCENSORED otherwise (NDEBUG is not - * defined). - */ -#if defined(TRANSPORT_LOG_CENSORING) -#define _TRANSPORT_LOG_CENSORING TRANSPORT_LOG_CENSORING -#elif defined(TRANSPORT_LOG_DEF_CENSORING) -#define _TRANSPORT_LOG_CENSORING TRANSPORT_LOG_DEF_CENSORING -#else -#ifdef NDEBUG -#define _TRANSPORT_LOG_CENSORING TRANSPORT_LOG_CENSORED -#else -#define _TRANSPORT_LOG_CENSORING TRANSPORT_LOG_UNCENSORED -#endif -#endif - -/* Check censoring at compile time. Evaluates to true when censoring is disabled - * (i.e. when secrets will be logged). For example: - * - * #if TRANSPORT_LOG_SECRETS - * char ssn[16]; - * getSocialSecurityNumber(ssn); - * TRANSPORT_LOGI("Customer ssn: %s", ssn); - * #endif - * - * See TRANSPORT_LOG_SECRET() macro for a more convenient way of guarding single - * log statement. - */ -#define TRANSPORT_LOG_SECRETS \ - (TRANSPORT_LOG_UNCENSORED == _TRANSPORT_LOG_CENSORING) - -/* Static (compile-time) initialization support allows to configure logging - * before entering main() function. This mostly useful in C++ where functions - * and methods could be called during initialization of global objects. Those - * functions and methods could record log messages too and for that reason - * static initialization of logging configuration is customizable. - * - * Macros below allow to specify values to use for initial configuration: - * - TRANSPORT_LOG_EXTERN_TAG_PREFIX - tag prefix (default: none) - * - TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT - global format options (default: see - * TRANSPORT_LOG_MEM_WIDTH in transport_log.c) - * - TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT - global output facility (default: - * stderr or platform specific, see TRANSPORT_LOG_USE_XXX macros in - * transport_log.c) - * - TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL - global output log level - * (default: 0 - all levals are "turned on") - * - * For example, in log_config.c: - * - * #include - * TRANSPORT_LOG_DEFINE_TAG_PREFIX = "MyApp"; - * TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT = {CUSTOM_MEM_WIDTH}; - * TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {TRANSPORT_LOG_PUT_STD, - * custom_output_callback, 0}; TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = - * TRANSPORT_LOG_INFO; - * - * However, to use any of those macros transport_log library must be compiled - * with following macros defined: - * - to use TRANSPORT_LOG_DEFINE_TAG_PREFIX define - * TRANSPORT_LOG_EXTERN_TAG_PREFIX - * - to use TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT define - * TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT - * - to use TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT define - * TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT - * - to use TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL define - * TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL - * - * When transport_log library compiled with one of TRANSPORT_LOG_EXTERN_XXX - * macros defined, corresponding TRANSPORT_LOG_DEFINE_XXX macro MUST be used - * exactly once somewhere. Otherwise build will fail with link error (undefined - * symbol). - */ -#define TRANSPORT_LOG_DEFINE_TAG_PREFIX const char *_transport_log_tag_prefix -#define TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT \ - transport_log_format _transport_log_global_format -#define TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT \ - transport_log_output _transport_log_global_output -#define TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL \ - int _transport_log_global_output_lvl - -/* Pointer to global format options. Direct modification is not allowed. Use - * transport_log_set_mem_width() instead. Could be used to initialize - * transport_log_spec structure: - * - * const transport_log_output g_output = {TRANSPORT_LOG_PUT_STD, - * output_callback, 0}; const transport_log_spec g_spec = - * {TRANSPORT_LOG_GLOBAL_FORMAT, &g_output}; TRANSPORT_LOGI_AUX(&g_spec, - * "Hello"); - */ -#define TRANSPORT_LOG_GLOBAL_FORMAT \ - ((const transport_log_format *)&_transport_log_global_format) - -/* Pointer to global output variable. Direct modification is not allowed. Use - * transport_log_set_output_v() or transport_log_set_output_p() instead. Could - * be used to initialize transport_log_spec structure: - * - * const transport_log_format g_format = {40}; - * const transport_log_spec g_spec = {g_format, TRANSPORT_LOG_GLOBAL_OUTPUT}; - * TRANSPORT_LOGI_AUX(&g_spec, "Hello"); - */ -#define TRANSPORT_LOG_GLOBAL_OUTPUT \ - ((const transport_log_output *)&_transport_log_global_output) - -/* When defined, all library symbols produced by linker will be prefixed with - * provided value. That allows to use transport_log library privately in another - * libraries without exposing transport_log symbols in their original form (to - * avoid possible conflicts with other libraries / components that also could - * use transport_log for logging). Value must be without quotes, for example: - * - * CC_ARGS := -DTRANSPORT_LOG_LIBRARY_PREFIX=my_lib_ - * - * Note, that in this mode TRANSPORT_LOG_LIBRARY_PREFIX must be defined when - * building transport_log library AND it also must be defined to the same value - * when building a library that uses it. For example, consider fictional - * KittyHttp library that wants to use transport_log for logging. First approach - * that could be taken is to add transport_log.h and transport_log.c to the - * KittyHttp's source code tree directly. In that case it will be enough just to - * define TRANSPORT_LOG_LIBRARY_PREFIX in KittyHttp's build script: - * - * // KittyHttp/CMakeLists.txt - * target_compile_definitions(KittyHttp PRIVATE - * "TRANSPORT_LOG_LIBRARY_PREFIX=KittyHttp_") - * - * If KittyHttp doesn't want to include transport_log source code in its source - * tree and wants to build transport_log as a separate library than - * transport_log library must be built with TRANSPORT_LOG_LIBRARY_PREFIX defined - * to KittyHttp_ AND KittyHttp library itself also needs to define - * TRANSPORT_LOG_LIBRARY_PREFIX to KittyHttp_. It can do so either in its build - * script, as in example above, or by providing a wrapper header that KittyHttp - * library will need to use instead of transport_log.h: - * - * // KittyHttpLogging.h - * #define TRANSPORT_LOG_LIBRARY_PREFIX KittyHttp_ - * #include - * - * Regardless of the method chosen, the end result is that transport_log symbols - * will be prefixed with "KittyHttp_", so if a user of KittyHttp (say - * DogeBrowser) also uses transport_log for logging, they will not interferer - * with each other. Both will have their own log level, output facility, format - * options etc. - */ -#ifdef TRANSPORT_LOG_LIBRARY_PREFIX -#define _TRANSPORT_LOG_DECOR__(prefix, name) prefix##name -#define _TRANSPORT_LOG_DECOR_(prefix, name) _TRANSPORT_LOG_DECOR__(prefix, name) -#define _TRANSPORT_LOG_DECOR(name) \ - _TRANSPORT_LOG_DECOR_(TRANSPORT_LOG_LIBRARY_PREFIX, name) - -#define transport_log_set_tag_prefix \ - _TRANSPORT_LOG_DECOR(transport_log_set_tag_prefix) -#define transport_log_set_mem_width \ - _TRANSPORT_LOG_DECOR(transport_log_set_mem_width) -#define transport_log_set_output_level \ - _TRANSPORT_LOG_DECOR(transport_log_set_output_level) -#define transport_log_set_output_v \ - _TRANSPORT_LOG_DECOR(transport_log_set_output_v) -#define transport_log_set_output_p \ - _TRANSPORT_LOG_DECOR(transport_log_set_output_p) -#define transport_log_out_stderr_callback \ - _TRANSPORT_LOG_DECOR(transport_log_out_stderr_callback) -#define _transport_log_tag_prefix \ - _TRANSPORT_LOG_DECOR(_transport_log_tag_prefix) -#define _transport_log_global_format \ - _TRANSPORT_LOG_DECOR(_transport_log_global_format) -#define _transport_log_global_output \ - _TRANSPORT_LOG_DECOR(_transport_log_global_output) -#define _transport_log_global_output_lvl \ - _TRANSPORT_LOG_DECOR(_transport_log_global_output_lvl) -#define _transport_log_write_d _TRANSPORT_LOG_DECOR(_transport_log_write_d) -#define _transport_log_write_aux_d \ - _TRANSPORT_LOG_DECOR(_transport_log_write_aux_d) -#define _transport_log_write _TRANSPORT_LOG_DECOR(_transport_log_write) -#define _transport_log_write_aux _TRANSPORT_LOG_DECOR(_transport_log_write_aux) -#define _transport_log_write_mem_d \ - _TRANSPORT_LOG_DECOR(_transport_log_write_mem_d) -#define _transport_log_write_mem_aux_d \ - _TRANSPORT_LOG_DECOR(_transport_log_write_mem_aux_d) -#define _transport_log_write_mem _TRANSPORT_LOG_DECOR(_transport_log_write_mem) -#define _transport_log_write_mem_aux \ - _TRANSPORT_LOG_DECOR(_transport_log_write_mem_aux) -#define _transport_log_stderr_spec \ - _TRANSPORT_LOG_DECOR(_transport_log_stderr_spec) -#endif - -#if defined(__printflike) -#define _TRANSPORT_LOG_PRINTFLIKE(str_index, first_to_check) \ - __printflike(str_index, first_to_check) -#elif defined(__GNUC__) -#define _TRANSPORT_LOG_PRINTFLIKE(str_index, first_to_check) \ - __attribute__((format(__printf__, str_index, first_to_check))) -#else -#define _TRANSPORT_LOG_PRINTFLIKE(str_index, first_to_check) -#endif - -#if (defined(_WIN32) || defined(_WIN64)) && !defined(__GNUC__) -#define _TRANSPORT_LOG_FUNCTION __FUNCTION__ -#else -#define _TRANSPORT_LOG_FUNCTION __func__ -#endif - -#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) -#define _TRANSPORT_LOG_INLINE __inline -#define _TRANSPORT_LOG_IF(cond) \ - __pragma(warning(push)) __pragma(warning(disable : 4127)) if (cond) \ - __pragma(warning(pop)) -#define _TRANSPORT_LOG_WHILE(cond) \ - __pragma(warning(push)) __pragma(warning(disable : 4127)) while (cond) \ - __pragma(warning(pop)) -#else -#define _TRANSPORT_LOG_INLINE inline -#define _TRANSPORT_LOG_IF(cond) if (cond) -#define _TRANSPORT_LOG_WHILE(cond) while (cond) -#endif -#define _TRANSPORT_LOG_NEVER _TRANSPORT_LOG_IF(0) -#define _TRANSPORT_LOG_ONCE _TRANSPORT_LOG_WHILE(0) - -#ifdef __cplusplus -extern "C" { -#endif - -/* Set tag prefix. Prefix will be separated from the tag with dot ('.'). - * Use 0 or empty string to disable (default). Common use is to set it to - * the process (or build target) name (e.g. to separate client and server - * processes). Function will NOT copy provided prefix string, but will store the - * pointer. Hence specified prefix string must remain valid. See - * TRANSPORT_LOG_DEFINE_TAG_PREFIX for a way to set it before entering main() - * function. See TRANSPORT_LOG_TAG for more information about tag and tag - * prefix. - */ -void transport_log_set_tag_prefix(const char *const prefix); - -/* Set number of bytes per log line in memory (ASCII-HEX) output. Example: - * - * I hello.MAIN 4c6f72656d20697073756d20646f6c6f Lorem ipsum dolo - * |<- w bytes ->| |<- w chars ->| - * - * See TRANSPORT_LOGF_MEM and TRANSPORT_LOGF_MEM_AUX for more details. - */ -void transport_log_set_mem_width(const unsigned w); - -/* Set "output" log level. See TRANSPORT_LOG_LEVEL and - * TRANSPORT_LOG_OUTPUT_LEVEL for more info about log levels. - */ -void transport_log_set_output_level(const int lvl); - -/* Put mask is a set of flags that define what fields will be added to each - * log message. Default value is TRANSPORT_LOG_PUT_STD and other flags could be - * used to alter its behavior. See transport_log_set_output_v() for more - * details. - * - * Note about TRANSPORT_LOG_PUT_SRC: it will be added only in debug builds - * (NDEBUG is not defined). - */ -enum { - TRANSPORT_LOG_PUT_CTX = 1 << 0, /* context (time, pid, tid, log level) */ - TRANSPORT_LOG_PUT_TAG = 1 << 1, /* tag (including tag prefix) */ - TRANSPORT_LOG_PUT_SRC = 1 << 2, /* source location (file, line, function) */ - TRANSPORT_LOG_PUT_MSG = 1 << 3, /* message text (formatted string) */ - TRANSPORT_LOG_PUT_STD = 0xffff, /* everything (default) */ -}; - -typedef struct transport_log_message { - int lvl; /* Log level of the message */ - const char *tag; /* Associated tag (without tag prefix) */ - char *buf; /* Buffer start */ - char *e; /* Buffer end (last position where EOL with 0 could be written) */ - char *p; /* Buffer content end (append position) */ - char *tag_b; /* Prefixed tag start */ - char *tag_e; /* Prefixed tag end (if != tag_b, points to msg separator) */ - char *msg_b; /* Message start (expanded format string) */ -} transport_log_message; - -/* Type of output callback function. It will be called for each log line allowed - * by both "current" and "output" log levels ("enabled" and "turned on"). - * Callback function is allowed to modify content of the buffers pointed by the - * msg, but it's not allowed to modify any of msg fields. Buffer pointed by msg - * is UTF-8 encoded (no BOM mark). - */ -typedef void (*transport_log_output_cb)(const transport_log_message *msg, - void *arg); - -/* Format options. For more details see transport_log_set_mem_width(). - */ -typedef struct transport_log_format { - unsigned mem_width; /* Bytes per line in memory (ASCII-HEX) dump */ -} transport_log_format; - -/* Output facility. - */ -typedef struct transport_log_output { - unsigned - mask; /* What to put into log line buffer (see TRANSPORT_LOG_PUT_XXX) */ - void *arg; /* User provided output callback argument */ - transport_log_output_cb callback; /* Output callback function */ -} transport_log_output; - -/* Set output callback function. - * - * Mask allows to control what information will be added to the log line buffer - * before callback function is invoked. Default mask value is - * TRANSPORT_LOG_PUT_STD. - */ -void transport_log_set_output_v(const unsigned mask, void *const arg, - const transport_log_output_cb callback); -static _TRANSPORT_LOG_INLINE void transport_log_set_output_p( - const transport_log_output *const output) { - transport_log_set_output_v(output->mask, output->arg, output->callback); -} - -/* Used with _AUX macros and allows to override global format and output - * facility. Use TRANSPORT_LOG_GLOBAL_FORMAT and TRANSPORT_LOG_GLOBAL_OUTPUT for - * values from global configuration. Example: - * - * static const transport_log_output module_output = { - * TRANSPORT_LOG_PUT_STD, 0, custom_output_callback - * }; - * static const transport_log_spec module_spec = { - * TRANSPORT_LOG_GLOBAL_FORMAT, &module_output - * }; - * TRANSPORT_LOGI_AUX(&module_spec, "Position: %ix%i", x, y); - * - * See TRANSPORT_LOGF_AUX and TRANSPORT_LOGF_MEM_AUX for details. - */ -typedef struct transport_log_spec { - const transport_log_format *format; - const transport_log_output *output; -} transport_log_spec; - -#ifdef __cplusplus -} -#endif - -/* Execute log statement if condition is true. Example: - * - * TRANSPORT_LOG_IF(1 < 2, TRANSPORT_LOGI("Log this")); - * TRANSPORT_LOG_IF(1 > 2, TRANSPORT_LOGI("Don't log this")); - * - * Keep in mind though, that if condition can't be evaluated at compile time, - * then it will be evaluated at run time. This will increase exectuable size - * and can have noticeable performance overhead. Try to limit conditions to - * expressions that can be evaluated at compile time. - */ -#define TRANSPORT_LOG_IF(cond, f) \ - do { \ - _TRANSPORT_LOG_IF((cond)) { f; } \ - } \ - _TRANSPORT_LOG_ONCE - -/* Mark log statement as "secret". Log statements that are marked as secrets - * will NOT be executed when censoring is enabled (see TRANSPORT_LOG_CENSORED). - * Example: - * - * TRANSPORT_LOG_SECRET(TRANSPORT_LOGI("Credit card: %s", credit_card)); - * TRANSPORT_LOG_SECRET(TRANSPORT_LOGD_MEM(cipher, cipher_sz, "Cipher - * bytes:")); - */ -#define TRANSPORT_LOG_SECRET(f) TRANSPORT_LOG_IF(TRANSPORT_LOG_SECRETS, f) - -/* Check "current" log level at compile time (ignoring "output" log level). - * Evaluates to true when specified log level is enabled. For example: - * - * #if TRANSPORT_LOG_ENABLED_DEBUG - * const char *const g_enum_strings[] = { - * "enum_value_0", "enum_value_1", "enum_value_2" - * }; - * #endif - * // ... - * #if TRANSPORT_LOG_ENABLED_DEBUG - * TRANSPORT_LOGD("enum value: %s", g_enum_strings[v]); - * #endif - * - * See TRANSPORT_LOG_LEVEL for details. - */ -#define TRANSPORT_LOG_ENABLED(lvl) ((lvl) >= _TRANSPORT_LOG_LEVEL) -#define TRANSPORT_LOG_ENABLED_VERBOSE \ - TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_VERBOSE) -#define TRANSPORT_LOG_ENABLED_DEBUG TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_DEBUG) -#define TRANSPORT_LOG_ENABLED_INFO TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_INFO) -#define TRANSPORT_LOG_ENABLED_WARN TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_WARN) -#define TRANSPORT_LOG_ENABLED_ERROR TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_ERROR) -#define TRANSPORT_LOG_ENABLED_FATAL TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_FATAL) - -/* Check "output" log level at run time (taking into account "current" log - * level as well). Evaluates to true when specified log level is turned on AND - * enabled. For example: - * - * if (TRANSPORT_LOG_ON_DEBUG) - * { - * char hash[65]; - * sha256(data_ptr, data_sz, hash); - * TRANSPORT_LOGD("data: len=%u, sha256=%s", data_sz, hash); - * } - * - * See TRANSPORT_LOG_OUTPUT_LEVEL for details. - */ -#define TRANSPORT_LOG_ON(lvl) \ - (TRANSPORT_LOG_ENABLED((lvl)) && (lvl) >= _TRANSPORT_LOG_OUTPUT_LEVEL) -#define TRANSPORT_LOG_ON_VERBOSE TRANSPORT_LOG_ON(TRANSPORT_LOG_VERBOSE) -#define TRANSPORT_LOG_ON_DEBUG TRANSPORT_LOG_ON(TRANSPORT_LOG_DEBUG) -#define TRANSPORT_LOG_ON_INFO TRANSPORT_LOG_ON(TRANSPORT_LOG_INFO) -#define TRANSPORT_LOG_ON_WARN TRANSPORT_LOG_ON(TRANSPORT_LOG_WARN) -#define TRANSPORT_LOG_ON_ERROR TRANSPORT_LOG_ON(TRANSPORT_LOG_ERROR) -#define TRANSPORT_LOG_ON_FATAL TRANSPORT_LOG_ON(TRANSPORT_LOG_FATAL) - -#ifdef __cplusplus -extern "C" { -#endif - -extern const char *_transport_log_tag_prefix; -extern transport_log_format _transport_log_global_format; -extern transport_log_output _transport_log_global_output; -extern int _transport_log_global_output_lvl; -extern const transport_log_spec _transport_log_stderr_spec; - -void _transport_log_write_d(const char *const func, const char *const file, - const unsigned line, const int lvl, - const char *const tag, const char *const fmt, ...) - _TRANSPORT_LOG_PRINTFLIKE(6, 7); -void _transport_log_write_aux_d(const char *const func, const char *const file, - const unsigned line, - const transport_log_spec *const log, - const int lvl, const char *const tag, - const char *const fmt, ...) - _TRANSPORT_LOG_PRINTFLIKE(7, 8); -void _transport_log_write(const int lvl, const char *const tag, - const char *const fmt, ...) - _TRANSPORT_LOG_PRINTFLIKE(3, 4); -void _transport_log_write_aux(const transport_log_spec *const log, - const int lvl, const char *const tag, - const char *const fmt, ...) - _TRANSPORT_LOG_PRINTFLIKE(4, 5); -void _transport_log_write_mem_d(const char *const func, const char *const file, - const unsigned line, const int lvl, - const char *const tag, const void *const d, - const unsigned d_sz, const char *const fmt, ...) - _TRANSPORT_LOG_PRINTFLIKE(8, 9); -void _transport_log_write_mem_aux_d(const char *const func, - const char *const file, const unsigned line, - const transport_log_spec *const log, - const int lvl, const char *const tag, - const void *const d, const unsigned d_sz, - const char *const fmt, ...) - _TRANSPORT_LOG_PRINTFLIKE(9, 10); -void _transport_log_write_mem(const int lvl, const char *const tag, - const void *const d, const unsigned d_sz, - const char *const fmt, ...) - _TRANSPORT_LOG_PRINTFLIKE(5, 6); -void _transport_log_write_mem_aux(const transport_log_spec *const log, - const int lvl, const char *const tag, - const void *const d, const unsigned d_sz, - const char *const fmt, ...) - _TRANSPORT_LOG_PRINTFLIKE(6, 7); - -#ifdef __cplusplus -} -#endif - -/* Message logging macros: - * - TRANSPORT_LOGV("format string", args, ...) - * - TRANSPORT_LOGD("format string", args, ...) - * - TRANSPORT_LOGI("format string", args, ...) - * - TRANSPORT_LOGW("format string", args, ...) - * - TRANSPORT_LOGE("format string", args, ...) - * - TRANSPORT_LOGF("format string", args, ...) - * - * Memory logging macros: - * - TRANSPORT_LOGV_MEM(data_ptr, data_sz, "format string", args, ...) - * - TRANSPORT_LOGD_MEM(data_ptr, data_sz, "format string", args, ...) - * - TRANSPORT_LOGI_MEM(data_ptr, data_sz, "format string", args, ...) - * - TRANSPORT_LOGW_MEM(data_ptr, data_sz, "format string", args, ...) - * - TRANSPORT_LOGE_MEM(data_ptr, data_sz, "format string", args, ...) - * - TRANSPORT_LOGF_MEM(data_ptr, data_sz, "format string", args, ...) - * - * Auxiliary logging macros: - * - TRANSPORT_LOGV_AUX(&log_instance, "format string", args, ...) - * - TRANSPORT_LOGD_AUX(&log_instance, "format string", args, ...) - * - TRANSPORT_LOGI_AUX(&log_instance, "format string", args, ...) - * - TRANSPORT_LOGW_AUX(&log_instance, "format string", args, ...) - * - TRANSPORT_LOGE_AUX(&log_instance, "format string", args, ...) - * - TRANSPORT_LOGF_AUX(&log_instance, "format string", args, ...) - * - * Auxiliary memory logging macros: - * - TRANSPORT_LOGV_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", - * args, ...) - * - TRANSPORT_LOGD_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", - * args, ...) - * - TRANSPORT_LOGI_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", - * args, ...) - * - TRANSPORT_LOGW_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", - * args, ...) - * - TRANSPORT_LOGE_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", - * args, ...) - * - TRANSPORT_LOGF_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", - * args, ...) - * - * Preformatted string logging macros: - * - TRANSPORT_LOGV_STR("preformatted string"); - * - TRANSPORT_LOGD_STR("preformatted string"); - * - TRANSPORT_LOGI_STR("preformatted string"); - * - TRANSPORT_LOGW_STR("preformatted string"); - * - TRANSPORT_LOGE_STR("preformatted string"); - * - TRANSPORT_LOGF_STR("preformatted string"); - * - * Explicit log level and tag macros: - * - TRANSPORT_LOG_WRITE(level, tag, "format string", args, ...) - * - TRANSPORT_LOG_WRITE_MEM(level, tag, data_ptr, data_sz, "format string", - * args, ...) - * - TRANSPORT_LOG_WRITE_AUX(&log_instance, level, tag, "format string", args, - * ...) - * - TRANSPORT_LOG_WRITE_MEM_AUX(&log_instance, level, tag, data_ptr, data_sz, - * "format string", args, ...) - * - * Format string follows printf() conventions. Both data_ptr and data_sz could - * be 0. Tag can be 0 as well. Most compilers will verify that type of arguments - * match format specifiers in format string. - * - * Library assuming UTF-8 encoding for all strings (char *), including format - * string itself. - */ -#if TRANSPORT_LOG_SRCLOC_NONE == _TRANSPORT_LOG_SRCLOC -#define TRANSPORT_LOG_WRITE(lvl, tag, ...) \ - do { \ - if (TRANSPORT_LOG_ON(lvl)) _transport_log_write(lvl, tag, __VA_ARGS__); \ - } \ - _TRANSPORT_LOG_ONCE -#define TRANSPORT_LOG_WRITE_MEM(lvl, tag, d, d_sz, ...) \ - do { \ - if (TRANSPORT_LOG_ON(lvl)) \ - _transport_log_write_mem(lvl, tag, d, d_sz, __VA_ARGS__); \ - } \ - _TRANSPORT_LOG_ONCE -#define TRANSPORT_LOG_WRITE_AUX(log, lvl, tag, ...) \ - do { \ - if (TRANSPORT_LOG_ON(lvl)) \ - _transport_log_write_aux(log, lvl, tag, __VA_ARGS__); \ - } \ - _TRANSPORT_LOG_ONCE -#define TRANSPORT_LOG_WRITE_MEM_AUX(log, lvl, tag, d, d_sz, ...) \ - do { \ - if (TRANSPORT_LOG_ON(lvl)) \ - _transport_log_write_mem_aux(log, lvl, tag, d, d_sz, __VA_ARGS__); \ - } \ - _TRANSPORT_LOG_ONCE -#else -#define TRANSPORT_LOG_WRITE(lvl, tag, ...) \ - do { \ - if (TRANSPORT_LOG_ON(lvl)) \ - _transport_log_write_d(_TRANSPORT_LOG_SRCLOC_FUNCTION, __FILE__, \ - __LINE__, lvl, tag, __VA_ARGS__); \ - } \ - _TRANSPORT_LOG_ONCE -#define TRANSPORT_LOG_WRITE_MEM(lvl, tag, d, d_sz, ...) \ - do { \ - if (TRANSPORT_LOG_ON(lvl)) \ - _transport_log_write_mem_d(_TRANSPORT_LOG_SRCLOC_FUNCTION, __FILE__, \ - __LINE__, lvl, tag, d, d_sz, __VA_ARGS__); \ - } \ - _TRANSPORT_LOG_ONCE -#define TRANSPORT_LOG_WRITE_AUX(log, lvl, tag, ...) \ - do { \ - if (TRANSPORT_LOG_ON(lvl)) \ - _transport_log_write_aux_d(_TRANSPORT_LOG_SRCLOC_FUNCTION, __FILE__, \ - __LINE__, log, lvl, tag, __VA_ARGS__); \ - } \ - _TRANSPORT_LOG_ONCE -#define TRANSPORT_LOG_WRITE_MEM_AUX(log, lvl, tag, d, d_sz, ...) \ - do { \ - if (TRANSPORT_LOG_ON(lvl)) \ - _transport_log_write_mem_aux_d(_TRANSPORT_LOG_SRCLOC_FUNCTION, __FILE__, \ - __LINE__, log, lvl, tag, d, d_sz, \ - __VA_ARGS__); \ - } \ - _TRANSPORT_LOG_ONCE -#endif - -static _TRANSPORT_LOG_INLINE void _transport_log_unused(const int dummy, ...) { - (void)dummy; -} - -#define _TRANSPORT_LOG_UNUSED(...) \ - do { \ - _TRANSPORT_LOG_NEVER _transport_log_unused(0, __VA_ARGS__); \ - } \ - _TRANSPORT_LOG_ONCE - -#if TRANSPORT_LOG_ENABLED_VERBOSE -#define TRANSPORT_LOGV(...) \ - TRANSPORT_LOG_WRITE(TRANSPORT_LOG_VERBOSE, _TRANSPORT_LOG_TAG, __VA_ARGS__) -#define TRANSPORT_LOGV_AUX(log, ...) \ - TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_VERBOSE, _TRANSPORT_LOG_TAG, \ - __VA_ARGS__) -#define TRANSPORT_LOGV_MEM(d, d_sz, ...) \ - TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_VERBOSE, _TRANSPORT_LOG_TAG, d, d_sz, \ - __VA_ARGS__) -#define TRANSPORT_LOGV_MEM_AUX(log, d, d_sz, ...) \ - TRANSPORT_LOG_WRITE_MEM(log, TRANSPORT_LOG_VERBOSE, _TRANSPORT_LOG_TAG, d, \ - d_sz, __VA_ARGS__) -#else -#define TRANSPORT_LOGV(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) -#define TRANSPORT_LOGV_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) -#define TRANSPORT_LOGV_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) -#define TRANSPORT_LOGV_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) -#endif - -#if TRANSPORT_LOG_ENABLED_DEBUG -#define TRANSPORT_LOGD(...) \ - TRANSPORT_LOG_WRITE(TRANSPORT_LOG_DEBUG, _TRANSPORT_LOG_TAG, __VA_ARGS__) -#define TRANSPORT_LOGD_AUX(log, ...) \ - TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_DEBUG, _TRANSPORT_LOG_TAG, \ - __VA_ARGS__) -#define TRANSPORT_LOGD_MEM(d, d_sz, ...) \ - TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_DEBUG, _TRANSPORT_LOG_TAG, d, d_sz, \ - __VA_ARGS__) -#define TRANSPORT_LOGD_MEM_AUX(log, d, d_sz, ...) \ - TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_DEBUG, _TRANSPORT_LOG_TAG, d, \ - d_sz, __VA_ARGS__) -#else -#define TRANSPORT_LOGD(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) -#define TRANSPORT_LOGD_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) -#define TRANSPORT_LOGD_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) -#define TRANSPORT_LOGD_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) -#endif - -#if TRANSPORT_LOG_ENABLED_INFO -#define TRANSPORT_LOGI(...) \ - TRANSPORT_LOG_WRITE(TRANSPORT_LOG_INFO, _TRANSPORT_LOG_TAG, __VA_ARGS__) -#define TRANSPORT_LOGI_AUX(log, ...) \ - TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_INFO, _TRANSPORT_LOG_TAG, \ - __VA_ARGS__) -#define TRANSPORT_LOGI_MEM(d, d_sz, ...) \ - TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_INFO, _TRANSPORT_LOG_TAG, d, d_sz, \ - __VA_ARGS__) -#define TRANSPORT_LOGI_MEM_AUX(log, d, d_sz, ...) \ - TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_INFO, _TRANSPORT_LOG_TAG, d, \ - d_sz, __VA_ARGS__) -#else -#define TRANSPORT_LOGI(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) -#define TRANSPORT_LOGI_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) -#define TRANSPORT_LOGI_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) -#define TRANSPORT_LOGI_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) -#endif - -#if TRANSPORT_LOG_ENABLED_WARN -#define TRANSPORT_LOGW(...) \ - TRANSPORT_LOG_WRITE(TRANSPORT_LOG_WARN, _TRANSPORT_LOG_TAG, __VA_ARGS__) -#define TRANSPORT_LOGW_AUX(log, ...) \ - TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_WARN, _TRANSPORT_LOG_TAG, \ - __VA_ARGS__) -#define TRANSPORT_LOGW_MEM(d, d_sz, ...) \ - TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_WARN, _TRANSPORT_LOG_TAG, d, d_sz, \ - __VA_ARGS__) -#define TRANSPORT_LOGW_MEM_AUX(log, d, d_sz, ...) \ - TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_WARN, _TRANSPORT_LOG_TAG, d, \ - d_sz, __VA_ARGS__) -#else -#define TRANSPORT_LOGW(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) -#define TRANSPORT_LOGW_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) -#define TRANSPORT_LOGW_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) -#define TRANSPORT_LOGW_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) -#endif - -#if TRANSPORT_LOG_ENABLED_ERROR -#define TRANSPORT_LOGE(...) \ - TRANSPORT_LOG_WRITE(TRANSPORT_LOG_ERROR, _TRANSPORT_LOG_TAG, __VA_ARGS__) -#define TRANSPORT_LOGE_AUX(log, ...) \ - TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_ERROR, _TRANSPORT_LOG_TAG, \ - __VA_ARGS__) -#define TRANSPORT_LOGE_MEM(d, d_sz, ...) \ - TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_ERROR, _TRANSPORT_LOG_TAG, d, d_sz, \ - __VA_ARGS__) -#define TRANSPORT_LOGE_MEM_AUX(log, d, d_sz, ...) \ - TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_ERROR, _TRANSPORT_LOG_TAG, d, \ - d_sz, __VA_ARGS__) -#else -#define TRANSPORT_LOGE(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) -#define TRANSPORT_LOGE_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) -#define TRANSPORT_LOGE_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) -#define TRANSPORT_LOGE_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) -#endif - -#if TRANSPORT_LOG_ENABLED_FATAL -#define TRANSPORT_LOGF(...) \ - TRANSPORT_LOG_WRITE(TRANSPORT_LOG_FATAL, _TRANSPORT_LOG_TAG, __VA_ARGS__) -#define TRANSPORT_LOGF_AUX(log, ...) \ - TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_FATAL, _TRANSPORT_LOG_TAG, \ - __VA_ARGS__) -#define TRANSPORT_LOGF_MEM(d, d_sz, ...) \ - TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_FATAL, _TRANSPORT_LOG_TAG, d, d_sz, \ - __VA_ARGS__) -#define TRANSPORT_LOGF_MEM_AUX(log, d, d_sz, ...) \ - TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_FATAL, _TRANSPORT_LOG_TAG, d, \ - d_sz, __VA_ARGS__) -#else -#define TRANSPORT_LOGF(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) -#define TRANSPORT_LOGF_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) -#define TRANSPORT_LOGF_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) -#define TRANSPORT_LOGF_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) -#endif - -#define TRANSPORT_LOGV_STR(s) TRANSPORT_LOGV("%s", (s)) -#define TRANSPORT_LOGD_STR(s) TRANSPORT_LOGD("%s", (s)) -#define TRANSPORT_LOGI_STR(s) TRANSPORT_LOGI("%s", (s)) -#define TRANSPORT_LOGW_STR(s) TRANSPORT_LOGW("%s", (s)) -#define TRANSPORT_LOGE_STR(s) TRANSPORT_LOGE("%s", (s)) -#define TRANSPORT_LOGF_STR(s) TRANSPORT_LOGF("%s", (s)) - -#ifdef __cplusplus -extern "C" { -#endif - -/* Output to standard error stream. Library uses it by default, though in few - * cases it could be necessary to specify it explicitly. For example, when - * transport_log library is compiled with TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT, - * application must define and initialize global output variable: - * - * TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {TRANSPORT_LOG_OUT_STDERR}; - * - * Another example is when using custom output, stderr could be used as a - * fallback when custom output facility failed to initialize: - * - * transport_log_set_output_v(TRANSPORT_LOG_OUT_STDERR); - */ -enum { TRANSPORT_LOG_OUT_STDERR_MASK = TRANSPORT_LOG_PUT_STD }; -void transport_log_out_stderr_callback(const transport_log_message *const msg, - void *arg); -#define TRANSPORT_LOG_OUT_STDERR \ - TRANSPORT_LOG_OUT_STDERR_MASK, 0, transport_log_out_stderr_callback - -/* Predefined spec for stderr. Uses global format options - * (TRANSPORT_LOG_GLOBAL_FORMAT) and TRANSPORT_LOG_OUT_STDERR. Could be used to - * force output to stderr for a particular message. Example: - * - * f = fopen("foo.log", "w"); - * if (!f) - * TRANSPORT_LOGE_AUX(TRANSPORT_LOG_STDERR, "Failed to open log file"); - */ -#define TRANSPORT_LOG_STDERR (&_transport_log_stderr_spec) - -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/libtransport/src/hicn/transport/utils/membuf.cc b/libtransport/src/hicn/transport/utils/membuf.cc deleted file mode 100644 index e75e85b35..000000000 --- a/libtransport/src/hicn/transport/utils/membuf.cc +++ /dev/null @@ -1,867 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Copyright 2013-present Facebook, Inc. - * 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. - */ - -/* - * The code in this file if adapated from the IOBuf of folly: - * https://github.com/facebook/folly/blob/master/folly/io/IOBuf.h - */ -#ifdef _WIN32 -#include -#endif - -#include - -#include -#include -#include -#include -#include -#include - -using std::unique_ptr; - -namespace { - -enum : uint16_t { - kHeapMagic = 0xa5a5, - // This memory segment contains an MemBuf that is still in use - kMemBufInUse = 0x01, - // This memory segment contains buffer data that is still in use - kDataInUse = 0x02, -}; - -enum : std::size_t { - // When create() is called for buffers less than kDefaultCombinedBufSize, - // we allocate a single combined memory segment for the MemBuf and the data - // together. See the comments for createCombined()/createSeparate() for more - // details. - // - // (The size of 1k is largely just a guess here. We could could probably do - // benchmarks of real applications to see if adjusting this number makes a - // difference. Callers that know their exact use case can also explicitly - // call createCombined() or createSeparate().) - kDefaultCombinedBufSize = 1024 -}; - -// Helper function for MemBuf::takeOwnership() -void takeOwnershipError(bool freeOnError, void* buf, - utils::MemBuf::FreeFunction freeFn, void* userData) { - if (!freeOnError) { - return; - } - if (!freeFn) { - free(buf); - return; - } - try { - freeFn(buf, userData); - } catch (...) { - // The user's free function is not allowed to throw. - // (We are already in the middle of throwing an exception, so - // we cannot let this exception go unhandled.) - abort(); - } -} - -} // namespace - -namespace utils { - -struct MemBuf::HeapPrefix { - explicit HeapPrefix(uint16_t flg) : magic(kHeapMagic), flags(flg) {} - ~HeapPrefix() { - // Reset magic to 0 on destruction. This is solely for debugging purposes - // to help catch bugs where someone tries to use HeapStorage after it has - // been deleted. - magic = 0; - } - - uint16_t magic; - std::atomic flags; -}; - -struct MemBuf::HeapStorage { - HeapPrefix prefix; - // The MemBuf is last in the HeapStorage object. - // This way operator new will work even if allocating a subclass of MemBuf - // that requires more space. - utils::MemBuf buf; -}; - -struct MemBuf::HeapFullStorage { - // Make sure jemalloc allocates from the 64-byte class. Putting this here - // because HeapStorage is private so it can't be at namespace level. - static_assert(sizeof(HeapStorage) <= 64, - "MemBuf may not grow over 56 bytes!"); - - HeapStorage hs; - SharedInfo shared; - std::max_align_t align; -}; - -MemBuf::SharedInfo::SharedInfo() : freeFn(nullptr), userData(nullptr) { - // Use relaxed memory ordering here. Since we are creating a new SharedInfo, - // no other threads should be referring to it yet. - refcount.store(1, std::memory_order_relaxed); -} - -MemBuf::SharedInfo::SharedInfo(FreeFunction fn, void* arg) - : freeFn(fn), userData(arg) { - // Use relaxed memory ordering here. Since we are creating a new SharedInfo, - // no other threads should be referring to it yet. - refcount.store(1, std::memory_order_relaxed); -} - -void* MemBuf::operator new(size_t size) { - size_t fullSize = offsetof(HeapStorage, buf) + size; - auto* storage = static_cast(malloc(fullSize)); - - new (&storage->prefix) HeapPrefix(kMemBufInUse); - return &(storage->buf); -} - -void* MemBuf::operator new(size_t /* size */, void* ptr) { return ptr; } - -void MemBuf::operator delete(void* ptr) { - auto* storageAddr = static_cast(ptr) - offsetof(HeapStorage, buf); - auto* storage = reinterpret_cast(storageAddr); - releaseStorage(storage, kMemBufInUse); -} - -void MemBuf::operator delete(void* /* ptr */, void* /* placement */) { - // Provide matching operator for `MemBuf::new` to avoid MSVC compilation - // warning (C4291) about memory leak when exception is thrown in the - // constructor. -} - -void MemBuf::releaseStorage(HeapStorage* storage, uint16_t freeFlags) { - // Use relaxed memory order here. If we are unlucky and happen to get - // out-of-date data the compare_exchange_weak() call below will catch - // it and load new data with memory_order_acq_rel. - auto flags = storage->prefix.flags.load(std::memory_order_acquire); - - while (true) { - uint16_t newFlags = uint16_t(flags & ~freeFlags); - if (newFlags == 0) { - // The storage space is now unused. Free it. - storage->prefix.HeapPrefix::~HeapPrefix(); - free(storage); - return; - } - - // This storage segment still contains portions that are in use. - // Just clear the flags specified in freeFlags for now. - auto ret = storage->prefix.flags.compare_exchange_weak( - flags, newFlags, std::memory_order_acq_rel); - if (ret) { - // We successfully updated the flags. - return; - } - - // We failed to update the flags. Some other thread probably updated them - // and cleared some of the other bits. Continue around the loop to see if - // we are the last user now, or if we need to try updating the flags again. - } -} - -void MemBuf::freeInternalBuf(void* /* buf */, void* userData) { - auto* storage = static_cast(userData); - releaseStorage(storage, kDataInUse); -} - -MemBuf::MemBuf(CreateOp, std::size_t capacity) - : next_(this), - prev_(this), - data_(nullptr), - length_(0), - flags_and_shared_info_(0) { - SharedInfo* info; - allocExtBuffer(capacity, &buf_, &info, &capacity_); - setSharedInfo(info); - data_ = buf_; -} - -MemBuf::MemBuf(CopyBufferOp /* op */, const void* buf, std::size_t size, - std::size_t headroom, std::size_t min_tailroom) - : MemBuf(CREATE, headroom + size + min_tailroom) { - advance(headroom); - if (size > 0) { - assert(buf != nullptr); - memcpy(writableData(), buf, size); - append(size); - } -} - -unique_ptr MemBuf::create(std::size_t capacity) { - // For smaller-sized buffers, allocate the MemBuf, SharedInfo, and the buffer - // all with a single allocation. - // - // We don't do this for larger buffers since it can be wasteful if the user - // needs to reallocate the buffer but keeps using the same MemBuf object. - // In this case we can't free the data space until the MemBuf is also - // destroyed. Callers can explicitly call createCombined() or - // createSeparate() if they know their use case better, and know if they are - // likely to reallocate the buffer later. - if (capacity <= kDefaultCombinedBufSize) { - return createCombined(capacity); - } - return createSeparate(capacity); -} - -unique_ptr MemBuf::createCombined(std::size_t capacity) { - // To save a memory allocation, allocate space for the MemBuf object, the - // SharedInfo struct, and the data itself all with a single call to malloc(). - size_t requiredStorage = offsetof(HeapFullStorage, align) + capacity; - size_t mallocSize = requiredStorage; - auto* storage = static_cast(malloc(mallocSize)); - - new (&storage->hs.prefix) HeapPrefix(kMemBufInUse | kDataInUse); - new (&storage->shared) SharedInfo(freeInternalBuf, storage); - - uint8_t* bufAddr = reinterpret_cast(&storage->align); - uint8_t* storageEnd = reinterpret_cast(storage) + mallocSize; - size_t actualCapacity = size_t(storageEnd - bufAddr); - unique_ptr ret(new (&storage->hs.buf) MemBuf( - InternalConstructor(), packFlagsAndSharedInfo(0, &storage->shared), - bufAddr, actualCapacity, bufAddr, 0)); - return ret; -} - -unique_ptr MemBuf::createSeparate(std::size_t capacity) { - return std::make_unique(CREATE, capacity); -} - -unique_ptr MemBuf::createChain(size_t totalCapacity, - std::size_t maxBufCapacity) { - unique_ptr out = - create(std::min(totalCapacity, size_t(maxBufCapacity))); - size_t allocatedCapacity = out->capacity(); - - while (allocatedCapacity < totalCapacity) { - unique_ptr newBuf = create( - std::min(totalCapacity - allocatedCapacity, size_t(maxBufCapacity))); - allocatedCapacity += newBuf->capacity(); - out->prependChain(std::move(newBuf)); - } - - return out; -} - -MemBuf::MemBuf(TakeOwnershipOp, void* buf, std::size_t capacity, - std::size_t length, FreeFunction freeFn, void* userData, - bool freeOnError) - : next_(this), - prev_(this), - data_(static_cast(buf)), - buf_(static_cast(buf)), - length_(length), - capacity_(capacity), - flags_and_shared_info_( - packFlagsAndSharedInfo(flag_free_shared_info, nullptr)) { - try { - setSharedInfo(new SharedInfo(freeFn, userData)); - } catch (...) { - takeOwnershipError(freeOnError, buf, freeFn, userData); - throw; - } -} - -unique_ptr MemBuf::takeOwnership(void* buf, std::size_t capacity, - std::size_t length, - FreeFunction freeFn, void* userData, - bool freeOnError) { - try { - // TODO: We could allocate the MemBuf object and SharedInfo all in a single - // memory allocation. We could use the existing HeapStorage class, and - // define a new kSharedInfoInUse flag. We could change our code to call - // releaseStorage(flag_free_shared_info) when this flag_free_shared_info, - // rather than directly calling delete. - // - // Note that we always pass freeOnError as false to the constructor. - // If the constructor throws we'll handle it below. (We have to handle - // allocation failures from std::make_unique too.) - return std::make_unique(TAKE_OWNERSHIP, buf, capacity, length, - freeFn, userData, false); - } catch (...) { - takeOwnershipError(freeOnError, buf, freeFn, userData); - throw; - } -} - -MemBuf::MemBuf(WrapBufferOp, const void* buf, std::size_t capacity) noexcept - : MemBuf(InternalConstructor(), 0, - // We cast away the const-ness of the buffer here. - // This is okay since MemBuf users must use unshare() to create a - // copy of this buffer before writing to the buffer. - static_cast(const_cast(buf)), capacity, - static_cast(const_cast(buf)), capacity) {} - -unique_ptr MemBuf::wrapBuffer(const void* buf, std::size_t capacity) { - return std::make_unique(WRAP_BUFFER, buf, capacity); -} - -MemBuf MemBuf::wrapBufferAsValue(const void* buf, - std::size_t capacity) noexcept { - return MemBuf(WrapBufferOp::WRAP_BUFFER, buf, capacity); -} - -MemBuf::MemBuf() noexcept {} - -MemBuf::MemBuf(MemBuf&& other) noexcept - : data_(other.data_), - buf_(other.buf_), - length_(other.length_), - capacity_(other.capacity_), - flags_and_shared_info_(other.flags_and_shared_info_) { - // Reset other so it is a clean state to be destroyed. - other.data_ = nullptr; - other.buf_ = nullptr; - other.length_ = 0; - other.capacity_ = 0; - other.flags_and_shared_info_ = 0; - - // If other was part of the chain, assume ownership of the rest of its chain. - // (It's only valid to perform move assignment on the head of a chain.) - if (other.next_ != &other) { - next_ = other.next_; - next_->prev_ = this; - other.next_ = &other; - - prev_ = other.prev_; - prev_->next_ = this; - other.prev_ = &other; - } -} - -MemBuf::MemBuf(const MemBuf& other) { *this = other.cloneAsValue(); } - -MemBuf::MemBuf(InternalConstructor, uintptr_t flagsAndSharedInfo, uint8_t* buf, - std::size_t capacity, uint8_t* data, std::size_t length) noexcept - : next_(this), - prev_(this), - data_(data), - buf_(buf), - length_(length), - capacity_(capacity), - flags_and_shared_info_(flagsAndSharedInfo) { - assert(data >= buf); - assert(data + length <= buf + capacity); -} - -MemBuf::~MemBuf() { - // Destroying an MemBuf destroys the entire chain. - // Users of MemBuf should only explicitly delete the head of any chain. - // The other elements in the chain will be automatically destroyed. - while (next_ != this) { - // Since unlink() returns unique_ptr() and we don't store it, - // it will automatically delete the unlinked element. - (void)next_->unlink(); - } - - decrementRefcount(); -} - -MemBuf& MemBuf::operator=(MemBuf&& other) noexcept { - if (this == &other) { - return *this; - } - - // If we are part of a chain, delete the rest of the chain. - while (next_ != this) { - // Since unlink() returns unique_ptr() and we don't store it, - // it will automatically delete the unlinked element. - (void)next_->unlink(); - } - - // Decrement our refcount on the current buffer - decrementRefcount(); - - // Take ownership of the other buffer's data - data_ = other.data_; - buf_ = other.buf_; - length_ = other.length_; - capacity_ = other.capacity_; - flags_and_shared_info_ = other.flags_and_shared_info_; - // Reset other so it is a clean state to be destroyed. - other.data_ = nullptr; - other.buf_ = nullptr; - other.length_ = 0; - other.capacity_ = 0; - other.flags_and_shared_info_ = 0; - - // If other was part of the chain, assume ownership of the rest of its chain. - // (It's only valid to perform move assignment on the head of a chain.) - if (other.next_ != &other) { - next_ = other.next_; - next_->prev_ = this; - other.next_ = &other; - - prev_ = other.prev_; - prev_->next_ = this; - other.prev_ = &other; - } - - return *this; -} - -MemBuf& MemBuf::operator=(const MemBuf& other) { - if (this != &other) { - *this = MemBuf(other); - } - return *this; -} - -bool MemBuf::empty() const { - const MemBuf* current = this; - do { - if (current->length() != 0) { - return false; - } - current = current->next_; - } while (current != this); - return true; -} - -size_t MemBuf::countChainElements() const { - size_t numElements = 1; - for (MemBuf* current = next_; current != this; current = current->next_) { - ++numElements; - } - return numElements; -} - -std::size_t MemBuf::computeChainDataLength() const { - std::size_t fullLength = length_; - for (MemBuf* current = next_; current != this; current = current->next_) { - fullLength += current->length_; - } - return fullLength; -} - -void MemBuf::prependChain(unique_ptr&& iobuf) { - // Take ownership of the specified MemBuf - MemBuf* other = iobuf.release(); - - // Remember the pointer to the tail of the other chain - MemBuf* otherTail = other->prev_; - - // Hook up prev_->next_ to point at the start of the other chain, - // and other->prev_ to point at prev_ - prev_->next_ = other; - other->prev_ = prev_; - - // Hook up otherTail->next_ to point at us, - // and prev_ to point back at otherTail, - otherTail->next_ = this; - prev_ = otherTail; -} - -unique_ptr MemBuf::clone() const { - return std::make_unique(cloneAsValue()); -} - -unique_ptr MemBuf::cloneOne() const { - return std::make_unique(cloneOneAsValue()); -} - -unique_ptr MemBuf::cloneCoalesced() const { - return std::make_unique(cloneCoalescedAsValue()); -} - -unique_ptr MemBuf::cloneCoalescedWithHeadroomTailroom( - std::size_t new_headroom, std::size_t new_tailroom) const { - return std::make_unique( - cloneCoalescedAsValueWithHeadroomTailroom(new_headroom, new_tailroom)); -} - -MemBuf MemBuf::cloneAsValue() const { - auto tmp = cloneOneAsValue(); - - for (MemBuf* current = next_; current != this; current = current->next_) { - tmp.prependChain(current->cloneOne()); - } - - return tmp; -} - -MemBuf MemBuf::cloneOneAsValue() const { - if (SharedInfo* info = sharedInfo()) { - setFlags(flag_maybe_shared); - info->refcount.fetch_add(1, std::memory_order_acq_rel); - } - return MemBuf(InternalConstructor(), flags_and_shared_info_, buf_, capacity_, - data_, length_); -} - -MemBuf MemBuf::cloneCoalescedAsValue() const { - const std::size_t new_headroom = headroom(); - const std::size_t new_tailroom = prev()->tailroom(); - return cloneCoalescedAsValueWithHeadroomTailroom(new_headroom, new_tailroom); -} - -MemBuf MemBuf::cloneCoalescedAsValueWithHeadroomTailroom( - std::size_t new_headroom, std::size_t new_tailroom) const { - if (!isChained()) { - return cloneOneAsValue(); - } - // Coalesce into newBuf - const std::size_t new_length = computeChainDataLength(); - const std::size_t new_capacity = new_length + new_headroom + new_tailroom; - MemBuf newBuf{CREATE, new_capacity}; - newBuf.advance(new_headroom); - - auto current = this; - do { - if (current->length() > 0) { - memcpy(newBuf.writableTail(), current->data(), current->length()); - newBuf.append(current->length()); - } - current = current->next(); - } while (current != this); - - return newBuf; -} - -void MemBuf::unshareOneSlow() { - // Allocate a new buffer for the data - uint8_t* buf; - SharedInfo* sharedInfo; - std::size_t actualCapacity; - allocExtBuffer(capacity_, &buf, &sharedInfo, &actualCapacity); - - // Copy the data - // Maintain the same amount of headroom. Since we maintained the same - // minimum capacity we also maintain at least the same amount of tailroom. - std::size_t headlen = headroom(); - if (length_ > 0) { - assert(data_ != nullptr); - memcpy(buf + headlen, data_, length_); - } - - // Release our reference on the old buffer - decrementRefcount(); - // Make sure flag_maybe_shared and flag_free_shared_info are all cleared. - setFlagsAndSharedInfo(0, sharedInfo); - - // Update the buffer pointers to point to the new buffer - data_ = buf + headlen; - buf_ = buf; -} - -void MemBuf::unshareChained() { - // unshareChained() should only be called if we are part of a chain of - // multiple MemBufs. The caller should have already verified this. - assert(isChained()); - - MemBuf* current = this; - while (true) { - if (current->isSharedOne()) { - // we have to unshare - break; - } - - current = current->next_; - if (current == this) { - // None of the MemBufs in the chain are shared, - // so return without doing anything - return; - } - } - - // We have to unshare. Let coalesceSlow() do the work. - coalesceSlow(); -} - -void MemBuf::markExternallyShared() { - MemBuf* current = this; - do { - current->markExternallySharedOne(); - current = current->next_; - } while (current != this); -} - -void MemBuf::makeManagedChained() { - assert(isChained()); - - MemBuf* current = this; - while (true) { - current->makeManagedOne(); - current = current->next_; - if (current == this) { - break; - } - } -} - -void MemBuf::coalesceSlow() { - // coalesceSlow() should only be called if we are part of a chain of multiple - // MemBufs. The caller should have already verified this. - - // Compute the length of the entire chain - std::size_t new_length = 0; - MemBuf* end = this; - do { - new_length += end->length_; - end = end->next_; - } while (end != this); - - coalesceAndReallocate(new_length, end); - // We should be only element left in the chain now -} - -void MemBuf::coalesceSlow(size_t max_length) { - // coalesceSlow() should only be called if we are part of a chain of multiple - // MemBufs. The caller should have already verified this. - - // Compute the length of the entire chain - std::size_t new_length = 0; - MemBuf* end = this; - while (true) { - new_length += end->length_; - end = end->next_; - if (new_length >= max_length) { - break; - } - if (end == this) { - throw std::overflow_error( - "attempted to coalesce more data than " - "available"); - } - } - - coalesceAndReallocate(new_length, end); - // We should have the requested length now -} - -void MemBuf::coalesceAndReallocate(size_t new_headroom, size_t new_length, - MemBuf* end, size_t new_tailroom) { - std::size_t new_capacity = new_length + new_headroom + new_tailroom; - - // Allocate space for the coalesced buffer. - // We always convert to an external buffer, even if we happened to be an - // internal buffer before. - uint8_t* newBuf; - SharedInfo* newInfo; - std::size_t actualCapacity; - allocExtBuffer(new_capacity, &newBuf, &newInfo, &actualCapacity); - - // Copy the data into the new buffer - uint8_t* new_data = newBuf + new_headroom; - uint8_t* p = new_data; - MemBuf* current = this; - size_t remaining = new_length; - do { - if (current->length_ > 0) { - assert(current->length_ <= remaining); - assert(current->data_ != nullptr); - remaining -= current->length_; - memcpy(p, current->data_, current->length_); - p += current->length_; - } - current = current->next_; - } while (current != end); - assert(remaining == 0); - - // Point at the new buffer - decrementRefcount(); - - // Make sure flag_maybe_shared and flag_free_shared_info are all cleared. - setFlagsAndSharedInfo(0, newInfo); - - capacity_ = actualCapacity; - buf_ = newBuf; - data_ = new_data; - length_ = new_length; - - // Separate from the rest of our chain. - // Since we don't store the unique_ptr returned by separateChain(), - // this will immediately delete the returned subchain. - if (isChained()) { - (void)separateChain(next_, current->prev_); - } -} - -void MemBuf::decrementRefcount() { - // Externally owned buffers don't have a SharedInfo object and aren't managed - // by the reference count - SharedInfo* info = sharedInfo(); - if (!info) { - return; - } - - // Decrement the refcount - uint32_t newcnt = info->refcount.fetch_sub(1, std::memory_order_acq_rel); - // Note that fetch_sub() returns the value before we decremented. - // If it is 1, we were the only remaining user; if it is greater there are - // still other users. - if (newcnt > 1) { - return; - } - - // We were the last user. Free the buffer - freeExtBuffer(); - - // Free the SharedInfo if it was allocated separately. - // - // This is only used by takeOwnership(). - // - // To avoid this special case handling in decrementRefcount(), we could have - // takeOwnership() set a custom freeFn() that calls the user's free function - // then frees the SharedInfo object. (This would require that - // takeOwnership() store the user's free function with its allocated - // SharedInfo object.) However, handling this specially with a flag seems - // like it shouldn't be problematic. - if (flags() & flag_free_shared_info) { - delete sharedInfo(); - } -} - -void MemBuf::reserveSlow(std::size_t min_headroom, std::size_t min_tailroom) { - size_t new_capacity = (size_t)length_ + min_headroom + min_tailroom; - - // // reserveSlow() is dangerous if anyone else is sharing the buffer, as we - // may - // // reallocate and free the original buffer. It should only ever be called - // if - // // we are the only user of the buffer. - - // We'll need to reallocate the buffer. - // There are a few options. - // - If we have enough total room, move the data around in the buffer - // and adjust the data_ pointer. - // - If we're using an internal buffer, we'll switch to an external - // buffer with enough headroom and tailroom. - // - If we have enough headroom (headroom() >= min_headroom) but not too much - // (so we don't waste memory), we can try: - // - If we don't have too much to copy, we'll use realloc() (note that - // realloc might have to copy - // headroom + data + tailroom) - // - Otherwise, bite the bullet and reallocate. - if (headroom() + tailroom() >= min_headroom + min_tailroom) { - uint8_t* new_data = writableBuffer() + min_headroom; - std::memmove(new_data, data_, length_); - data_ = new_data; - return; - } - - size_t new_allocated_capacity = 0; - uint8_t* new_buffer = nullptr; - std::size_t new_headroom = 0; - std::size_t old_headroom = headroom(); - - // If we have a buffer allocated with malloc and we just need more tailroom, - // try to use realloc()/xallocx() to grow the buffer in place. - SharedInfo* info = sharedInfo(); - if (info && (info->freeFn == nullptr) && length_ != 0 && - old_headroom >= min_headroom) { - size_t head_slack = old_headroom - min_headroom; - new_allocated_capacity = goodExtBufferSize(new_capacity + head_slack); - - size_t copySlack = capacity() - length_; - if (copySlack * 2 <= length_) { - void* p = realloc(buf_, new_allocated_capacity); - if (TRANSPORT_EXPECT_FALSE(p == nullptr)) { - throw std::bad_alloc(); - } - new_buffer = static_cast(p); - new_headroom = old_headroom; - } - } - - // None of the previous reallocation strategies worked (or we're using - // an internal buffer). malloc/copy/free. - if (new_buffer == nullptr) { - new_allocated_capacity = goodExtBufferSize(new_capacity); - new_buffer = static_cast(malloc(new_allocated_capacity)); - if (length_ > 0) { - assert(data_ != nullptr); - memcpy(new_buffer + min_headroom, data_, length_); - } - if (sharedInfo()) { - freeExtBuffer(); - } - new_headroom = min_headroom; - } - - std::size_t cap; - initExtBuffer(new_buffer, new_allocated_capacity, &info, &cap); - - if (flags() & flag_free_shared_info) { - delete sharedInfo(); - } - - setFlagsAndSharedInfo(0, info); - capacity_ = cap; - buf_ = new_buffer; - data_ = new_buffer + new_headroom; - // length_ is unchanged -} - -void MemBuf::freeExtBuffer() { - SharedInfo* info = sharedInfo(); - - if (info->freeFn) { - try { - info->freeFn(buf_, info->userData); - } catch (...) { - // The user's free function should never throw. Otherwise we might - // throw from the MemBuf destructor. Other code paths like coalesce() - // also assume that decrementRefcount() cannot throw. - abort(); - } - } else { - free(buf_); - } -} - -void MemBuf::allocExtBuffer(std::size_t minCapacity, uint8_t** bufReturn, - SharedInfo** infoReturn, - std::size_t* capacityReturn) { - size_t mallocSize = goodExtBufferSize(minCapacity); - uint8_t* buf = static_cast(malloc(mallocSize)); - initExtBuffer(buf, mallocSize, infoReturn, capacityReturn); - *bufReturn = buf; -} - -size_t MemBuf::goodExtBufferSize(std::size_t minCapacity) { - // Determine how much space we should allocate. We'll store the SharedInfo - // for the external buffer just after the buffer itself. (We store it just - // after the buffer rather than just before so that the code can still just - // use free(buf_) to free the buffer.) - size_t minSize = static_cast(minCapacity) + sizeof(SharedInfo); - // Add room for padding so that the SharedInfo will be aligned on an 8-byte - // boundary. - minSize = (minSize + 7) & ~7; - - // Use goodMallocSize() to bump up the capacity to a decent size to request - // from malloc, so we can use all of the space that malloc will probably give - // us anyway. - return minSize; -} - -void MemBuf::initExtBuffer(uint8_t* buf, size_t mallocSize, - SharedInfo** infoReturn, - std::size_t* capacityReturn) { - // Find the SharedInfo storage at the end of the buffer - // and construct the SharedInfo. - uint8_t* infoStart = (buf + mallocSize) - sizeof(SharedInfo); - SharedInfo* sharedInfo = new (infoStart) SharedInfo; - - *capacityReturn = std::size_t(infoStart - buf); - *infoReturn = sharedInfo; -} - -} // namespace utils \ No newline at end of file diff --git a/libtransport/src/hicn/transport/utils/membuf.h b/libtransport/src/hicn/transport/utils/membuf.h deleted file mode 100644 index 9fc37dd25..000000000 --- a/libtransport/src/hicn/transport/utils/membuf.h +++ /dev/null @@ -1,921 +0,0 @@ -/* - * Copyright 2013-present Facebook, Inc. - * - * 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. - */ - -/* - * The code in this file if adapated from the IOBuf of folly: - * https://github.com/facebook/folly/blob/master/folly/io/IOBuf.h - */ - -#pragma once - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifndef _WIN32 -TRANSPORT_GNU_DISABLE_WARNING("-Wshadow") -#endif - -namespace utils { - -class MemBuf { - public: - enum CreateOp { CREATE }; - enum WrapBufferOp { WRAP_BUFFER }; - enum TakeOwnershipOp { TAKE_OWNERSHIP }; - enum CopyBufferOp { COPY_BUFFER }; - - typedef void (*FreeFunction)(void* buf, void* userData); - - static std::unique_ptr create(std::size_t capacity); - MemBuf(CreateOp, std::size_t capacity); - - /** - * Create a new MemBuf, using a single memory allocation to allocate space - * for both the MemBuf object and the data storage space. - * - * This saves one memory allocation. However, it can be wasteful if you - * later need to grow the buffer using reserve(). If the buffer needs to be - * reallocated, the space originally allocated will not be freed() until the - * MemBuf object itself is also freed. (It can also be slightly wasteful in - * some cases where you clone this MemBuf and then free the original MemBuf.) - */ - static std::unique_ptr createCombined(std::size_t capacity); - - /** - * Create a new IOBuf, using separate memory allocations for the IOBuf object - * for the IOBuf and the data storage space. - * - * This requires two memory allocations, but saves space in the long run - * if you know that you will need to reallocate the data buffer later. - */ - static std::unique_ptr createSeparate(std::size_t capacity); - - /** - * Allocate a new MemBuf chain with the requested total capacity, allocating - * no more than maxBufCapacity to each buffer. - */ - static std::unique_ptr createChain(size_t totalCapacity, - std::size_t maxBufCapacity); - - static std::unique_ptr takeOwnership(void* buf, std::size_t capacity, - FreeFunction freeFn = nullptr, - void* userData = nullptr, - bool freeOnError = true) { - return takeOwnership(buf, capacity, capacity, freeFn, userData, - freeOnError); - } - - MemBuf(TakeOwnershipOp op, void* buf, std::size_t capacity, - FreeFunction freeFn = nullptr, void* userData = nullptr, - bool freeOnError = true) - : MemBuf(op, buf, capacity, capacity, freeFn, userData, freeOnError) {} - - static std::unique_ptr takeOwnership(void* buf, std::size_t capacity, - std::size_t length, - FreeFunction freeFn = nullptr, - void* userData = nullptr, - bool freeOnError = true); - - MemBuf(TakeOwnershipOp, void* buf, std::size_t capacity, std::size_t length, - FreeFunction freeFn = nullptr, void* userData = nullptr, - bool freeOnError = true); - - static std::unique_ptr wrapBuffer(const void* buf, - std::size_t capacity); - - static MemBuf wrapBufferAsValue(const void* buf, - std::size_t capacity) noexcept; - - MemBuf(WrapBufferOp op, const void* buf, std::size_t capacity) noexcept; - - /** - * Convenience function to create a new MemBuf object that copies data from a - * user-supplied buffer, optionally allocating a given amount of - * headroom and tailroom. - */ - static std::unique_ptr copyBuffer(const void* buf, std::size_t size, - std::size_t headroom = 0, - std::size_t minTailroom = 0); - - MemBuf(CopyBufferOp op, const void* buf, std::size_t size, - std::size_t headroom = 0, std::size_t minTailroom = 0); - - /** - * Convenience function to free a chain of MemBufs held by a unique_ptr. - */ - static void destroy(std::unique_ptr&& data) { - auto destroyer = std::move(data); - } - - ~MemBuf(); - - bool empty() const; - - const uint8_t* data() const { return data_; } - - uint8_t* writableData() { return data_; } - - const uint8_t* tail() const { return data_ + length_; } - - uint8_t* writableTail() { return data_ + length_; } - - std::size_t length() const { return length_; } - - std::size_t headroom() const { return std::size_t(data_ - buffer()); } - - std::size_t tailroom() const { return std::size_t(bufferEnd() - tail()); } - - const uint8_t* buffer() const { return buf_; } - - uint8_t* writableBuffer() { return buf_; } - - const uint8_t* bufferEnd() const { return buf_ + capacity_; } - - std::size_t capacity() const { return capacity_; } - - MemBuf* next() { return next_; } - - const MemBuf* next() const { return next_; } - - MemBuf* prev() { return prev_; } - - const MemBuf* prev() const { return prev_; } - - /** - * Shift the data forwards in the buffer. - * - * This shifts the data pointer forwards in the buffer to increase the - * headroom. This is commonly used to increase the headroom in a newly - * allocated buffer. - * - * The caller is responsible for ensuring that there is sufficient - * tailroom in the buffer before calling advance(). - * - * If there is a non-zero data length, advance() will use memmove() to shift - * the data forwards in the buffer. In this case, the caller is responsible - * for making sure the buffer is unshared, so it will not affect other MemBufs - * that may be sharing the same underlying buffer. - */ - void advance(std::size_t amount) { - // In debug builds, assert if there is a problem. - assert(amount <= tailroom()); - - if (length_ > 0) { - memmove(data_ + amount, data_, length_); - } - data_ += amount; - } - - /** - * Shift the data backwards in the buffer. - * - * The caller is responsible for ensuring that there is sufficient headroom - * in the buffer before calling retreat(). - * - * If there is a non-zero data length, retreat() will use memmove() to shift - * the data backwards in the buffer. In this case, the caller is responsible - * for making sure the buffer is unshared, so it will not affect other MemBufs - * that may be sharing the same underlying buffer. - */ - void retreat(std::size_t amount) { - // In debug builds, assert if there is a problem. - assert(amount <= headroom()); - - if (length_ > 0) { - memmove(data_ - amount, data_, length_); - } - data_ -= amount; - } - - void prepend(std::size_t amount) { - data_ -= amount; - length_ += amount; - } - - void append(std::size_t amount) { length_ += amount; } - - void trimStart(std::size_t amount) { - data_ += amount; - length_ -= amount; - } - - void trimEnd(std::size_t amount) { length_ -= amount; } - - // Never call clear on cloned membuf sharing different - // portions of the same underlying buffer. - // Use the trim functions instead. - void clear() { - data_ = writableBuffer(); - length_ = 0; - } - - void reserve(std::size_t minHeadroom, std::size_t minTailroom) { - // Maybe we don't need to do anything. - if (headroom() >= minHeadroom && tailroom() >= minTailroom) { - return; - } - // If the buffer is empty but we have enough total room (head + tail), - // move the data_ pointer around. - if (length() == 0 && headroom() + tailroom() >= minHeadroom + minTailroom) { - data_ = writableBuffer() + minHeadroom; - return; - } - // Bah, we have to do actual work. - reserveSlow(minHeadroom, minTailroom); - } - - bool isChained() const { - assert((next_ == this) == (prev_ == this)); - return next_ != this; - } - - size_t countChainElements() const; - - std::size_t computeChainDataLength() const; - - void prependChain(std::unique_ptr&& iobuf); - - void appendChain(std::unique_ptr&& iobuf) { - // Just use prependChain() on the next element in our chain - next_->prependChain(std::move(iobuf)); - } - - std::unique_ptr unlink() { - next_->prev_ = prev_; - prev_->next_ = next_; - prev_ = this; - next_ = this; - return std::unique_ptr(this); - } - - /** - * Remove this MemBuf from its current chain and return a unique_ptr to - * the MemBuf that formerly followed it in the chain. - */ - std::unique_ptr pop() { - MemBuf* next = next_; - next_->prev_ = prev_; - prev_->next_ = next_; - prev_ = this; - next_ = this; - return std::unique_ptr((next == this) ? nullptr : next); - } - - /** - * Remove a subchain from this chain. - * - * Remove the subchain starting at head and ending at tail from this chain. - * - * Returns a unique_ptr pointing to head. (In other words, ownership of the - * head of the subchain is transferred to the caller.) If the caller ignores - * the return value and lets the unique_ptr be destroyed, the subchain will - * be immediately destroyed. - * - * The subchain referenced by the specified head and tail must be part of the - * same chain as the current MemBuf, but must not contain the current MemBuf. - * However, the specified head and tail may be equal to each other (i.e., - * they may be a subchain of length 1). - */ - std::unique_ptr separateChain(MemBuf* head, MemBuf* tail) { - assert(head != this); - assert(tail != this); - - head->prev_->next_ = tail->next_; - tail->next_->prev_ = head->prev_; - - head->prev_ = tail; - tail->next_ = head; - - return std::unique_ptr(head); - } - - /** - * Return true if at least one of the MemBufs in this chain are shared, - * or false if all of the MemBufs point to unique buffers. - * - * Use isSharedOne() to only check this MemBuf rather than the entire chain. - */ - bool isShared() const { - const MemBuf* current = this; - while (true) { - if (current->isSharedOne()) { - return true; - } - current = current->next_; - if (current == this) { - return false; - } - } - } - - /** - * Return true if all MemBufs in this chain are managed by the usual - * refcounting mechanism (and so the lifetime of the underlying memory - * can be extended by clone()). - */ - bool isManaged() const { - const MemBuf* current = this; - while (true) { - if (!current->isManagedOne()) { - return false; - } - current = current->next_; - if (current == this) { - return true; - } - } - } - - /** - * Return true if this MemBuf is managed by the usual refcounting mechanism - * (and so the lifetime of the underlying memory can be extended by - * cloneOne()). - */ - bool isManagedOne() const { return sharedInfo(); } - - /** - * Return true if other MemBufs are also pointing to the buffer used by this - * MemBuf, and false otherwise. - * - * If this MemBuf points at a buffer owned by another (non-MemBuf) part of the - * code (i.e., if the MemBuf was created using wrapBuffer(), or was cloned - * from such an MemBuf), it is always considered shared. - * - * This only checks the current MemBuf, and not other MemBufs in the chain. - */ - bool isSharedOne() const { - // If this is a user-owned buffer, it is always considered shared - if ((TRANSPORT_EXPECT_FALSE(!sharedInfo()))) { - return true; - } - - if ((TRANSPORT_EXPECT_FALSE(sharedInfo()->externallyShared))) { - return true; - } - - if ((TRANSPORT_EXPECT_TRUE(!(flags() & flag_maybe_shared)))) { - return false; - } - - // flag_maybe_shared is set, so we need to check the reference count. - // (Checking the reference count requires an atomic operation, which is why - // we prefer to only check flag_maybe_shared if possible.) - bool shared = sharedInfo()->refcount.load(std::memory_order_acquire) > 1; - if (!shared) { - // we're the last one left - clearFlags(flag_maybe_shared); - } - return shared; - } - - /** - * Ensure that this MemBuf has a unique buffer that is not shared by other - * MemBufs. - * - * unshare() operates on an entire chain of MemBuf objects. If the chain is - * shared, it may also coalesce the chain when making it unique. If the - * chain is coalesced, subsequent MemBuf objects in the current chain will be - * automatically deleted. - * - * Note that buffers owned by other (non-MemBuf) users are automatically - * considered shared. - * - * Throws std::bad_alloc on error. On error the MemBuf chain will be - * unmodified. - * - * Currently unshare may also throw std::overflow_error if it tries to - * coalesce. (TODO: In the future it would be nice if unshare() were smart - * enough not to coalesce the entire buffer if the data is too large. - * However, in practice this seems unlikely to become an issue.) - */ - void unshare() { - if (isChained()) { - unshareChained(); - } else { - unshareOne(); - } - } - - /** - * Ensure that this MemBuf has a unique buffer that is not shared by other - * MemBufs. - * - * unshareOne() operates on a single MemBuf object. This MemBuf will have a - * unique buffer after unshareOne() returns, but other MemBufs in the chain - * may still be shared after unshareOne() returns. - * - * Throws std::bad_alloc on error. On error the MemBuf will be unmodified. - */ - void unshareOne() { - if (isSharedOne()) { - unshareOneSlow(); - } - } - - /** - * Mark the underlying buffers in this chain as shared with external memory - * management mechanism. This will make isShared() always returns true. - * - * This function is not thread-safe, and only safe to call immediately after - * creating an MemBuf, before it has been shared with other threads. - */ - void markExternallyShared(); - - /** - * Mark the underlying buffer that this MemBuf refers to as shared with - * external memory management mechanism. This will make isSharedOne() always - * returns true. - * - * This function is not thread-safe, and only safe to call immediately after - * creating an MemBuf, before it has been shared with other threads. - */ - void markExternallySharedOne() { - SharedInfo* info = sharedInfo(); - if (info) { - info->externallyShared = true; - } - } - - /** - * Ensure that the memory that MemBufs in this chain refer to will continue to - * be allocated for as long as the MemBufs of the chain (or any clone()s - * created from this point onwards) is alive. - * - * This only has an effect for user-owned buffers (created with the - * WRAP_BUFFER constructor or wrapBuffer factory function), in which case - * those buffers are unshared. - */ - void makeManaged() { - if (isChained()) { - makeManagedChained(); - } else { - makeManagedOne(); - } - } - - /** - * Ensure that the memory that this MemBuf refers to will continue to be - * allocated for as long as this MemBuf (or any clone()s created from this - * point onwards) is alive. - * - * This only has an effect for user-owned buffers (created with the - * WRAP_BUFFER constructor or wrapBuffer factory function), in which case - * those buffers are unshared. - */ - void makeManagedOne() { - if (!isManagedOne()) { - // We can call the internal function directly; unmanaged implies shared. - unshareOneSlow(); - } - } - - // /** - // * Coalesce this MemBuf chain into a single buffer. - // * - // * This method moves all of the data in this MemBuf chain into a single - // * contiguous buffer, if it is not already in one buffer. After coalesce() - // * returns, this MemBuf will be a chain of length one. Other MemBufs in - // the - // * chain will be automatically deleted. - // * - // * After coalescing, the MemBuf will have at least as much headroom as the - // * first MemBuf in the chain, and at least as much tailroom as the last - // MemBuf - // * in the chain. - // * - // * Throws std::bad_alloc on error. On error the MemBuf chain will be - // * unmodified. - // * - // * Returns ByteRange that points to the data MemBuf stores. - // */ - // ByteRange coalesce() { - // const std::size_t newHeadroom = headroom(); - // const std::size_t newTailroom = prev()->tailroom(); - // return coalesceWithHeadroomTailroom(newHeadroom, newTailroom); - // } - - // /** - // * This is similar to the coalesce() method, except this allows to set a - // * headroom and tailroom after coalescing. - // * - // * Returns ByteRange that points to the data MemBuf stores. - // */ - // ByteRange coalesceWithHeadroomTailroom(std::size_t newHeadroom, - // std::size_t newTailroom) { - // if (isChained()) { - // coalesceAndReallocate(newHeadroom, computeChainDataLength(), this, - // newTailroom); - // } - // return ByteRange(data_, length_); - // } - - /** - * Ensure that this chain has at least maxLength bytes available as a - * contiguous memory range. - * - * This method coalesces whole buffers in the chain into this buffer as - * necessary until this buffer's length() is at least maxLength. - * - * After coalescing, the MemBuf will have at least as much headroom as the - * first MemBuf in the chain, and at least as much tailroom as the last MemBuf - * that was coalesced. - * - * Throws std::bad_alloc or std::overflow_error on error. On error the MemBuf - * chain will be unmodified. Throws std::overflow_error if maxLength is - * longer than the total chain length. - * - * Upon return, either enough of the chain was coalesced into a contiguous - * region, or the entire chain was coalesced. That is, - * length() >= maxLength || !isChained() is true. - */ - void gather(std::size_t maxLength) { - if (!isChained() || length_ >= maxLength) { - return; - } - coalesceSlow(maxLength); - } - - /** - * Return a new MemBuf chain sharing the same data as this chain. - * - * The new MemBuf chain will normally point to the same underlying data - * buffers as the original chain. (The one exception to this is if some of - * the MemBufs in this chain contain small internal data buffers which cannot - * be shared.) - */ - std::unique_ptr clone() const; - - /** - * Similar to clone(). But returns MemBuf by value rather than heap-allocating - * it. - */ - MemBuf cloneAsValue() const; - - /** - * Return a new MemBuf with the same data as this MemBuf. - * - * The new MemBuf returned will not be part of a chain (even if this MemBuf is - * part of a larger chain). - */ - std::unique_ptr cloneOne() const; - - /** - * Similar to cloneOne(). But returns MemBuf by value rather than - * heap-allocating it. - */ - MemBuf cloneOneAsValue() const; - - /** - * Return a new unchained MemBuf that may share the same data as this chain. - * - * If the MemBuf chain is not chained then the new MemBuf will point to the - * same underlying data buffer as the original chain. Otherwise, it will clone - * and coalesce the MemBuf chain. - * - * The new MemBuf will have at least as much headroom as the first MemBuf in - * the chain, and at least as much tailroom as the last MemBuf in the chain. - * - * Throws std::bad_alloc on error. - */ - std::unique_ptr cloneCoalesced() const; - - /** - * This is similar to the cloneCoalesced() method, except this allows to set a - * headroom and tailroom for the new MemBuf. - */ - std::unique_ptr cloneCoalescedWithHeadroomTailroom( - std::size_t newHeadroom, std::size_t newTailroom) const; - - /** - * Similar to cloneCoalesced(). But returns MemBuf by value rather than - * heap-allocating it. - */ - MemBuf cloneCoalescedAsValue() const; - - /** - * This is similar to the cloneCoalescedAsValue() method, except this allows - * to set a headroom and tailroom for the new MemBuf. - */ - MemBuf cloneCoalescedAsValueWithHeadroomTailroom( - std::size_t newHeadroom, std::size_t newTailroom) const; - - /** - * Similar to Clone(). But use other as the head node. Other nodes in the - * chain (if any) will be allocted on heap. - */ - void cloneInto(MemBuf& other) const { other = cloneAsValue(); } - - /** - * Similar to CloneOne(). But to fill an existing MemBuf instead of a new - * MemBuf. - */ - void cloneOneInto(MemBuf& other) const { other = cloneOneAsValue(); } - - /** - * Return an iovector suitable for e.g. writev() - * - * auto iov = buf->getIov(); - * auto xfer = writev(fd, iov.data(), iov.size()); - * - * Naturally, the returned iovector is invalid if you modify the buffer - * chain. - */ - std::vector getIov() const; - - /** - * Update an existing iovec array with the MemBuf data. - * - * New iovecs will be appended to the existing vector; anything already - * present in the vector will be left unchanged. - * - * Naturally, the returned iovec data will be invalid if you modify the - * buffer chain. - */ - void appendToIov(std::vector* iov) const; - - /** - * Fill an iovec array with the MemBuf data. - * - * Returns the number of iovec filled. If there are more buffer than - * iovec, returns 0. This version is suitable to use with stack iovec - * arrays. - * - * Naturally, the filled iovec data will be invalid if you modify the - * buffer chain. - */ - size_t fillIov(struct iovec* iov, size_t len) const; - - /** - * A helper that wraps a number of iovecs into an MemBuf chain. If count == - * 0, then a zero length buf is returned. This function never returns - * nullptr. - */ - static std::unique_ptr wrapIov(const iovec* vec, size_t count); - - /** - * A helper that takes ownerships a number of iovecs into an MemBuf chain. If - * count == 0, then a zero length buf is returned. This function never - * returns nullptr. - */ - static std::unique_ptr takeOwnershipIov(const iovec* vec, - size_t count, - FreeFunction freeFn = nullptr, - void* userData = nullptr, - bool freeOnError = true); - - /* - * Overridden operator new and delete. - * These perform specialized memory management to help support - * createCombined(), which allocates MemBuf objects together with the buffer - * data. - */ - void* operator new(size_t size); - void* operator new(size_t size, void* ptr); - void operator delete(void* ptr); - void operator delete(void* ptr, void* placement); - - // /** - // * Iteration support: a chain of MemBufs may be iterated through using - // * STL-style iterators over const ByteRanges. Iterators are only - // invalidated - // * if the MemBuf that they currently point to is removed. - // */ - // Iterator cbegin() const; - // Iterator cend() const; - // Iterator begin() const; - // Iterator end() const; - - /** - * Allocate a new null buffer. - * - * This can be used to allocate an empty MemBuf on the stack. It will have no - * space allocated for it. This is generally useful only to later use move - * assignment to fill out the MemBuf. - */ - MemBuf() noexcept; - - /** - * Move constructor and assignment operator. - * - * In general, you should only ever move the head of an MemBuf chain. - * Internal nodes in an MemBuf chain are owned by the head of the chain, and - * should not be moved from. (Technically, nothing prevents you from moving - * a non-head node, but the moved-to node will replace the moved-from node in - * the chain. This has implications for ownership, since non-head nodes are - * owned by the chain head. You are then responsible for relinquishing - * ownership of the moved-to node, and manually deleting the moved-from - * node.) - * - * With the move assignment operator, the destination of the move should be - * the head of an MemBuf chain or a solitary MemBuf not part of a chain. If - * the move destination is part of a chain, all other MemBufs in the chain - * will be deleted. - */ - MemBuf(MemBuf&& other) noexcept; - MemBuf& operator=(MemBuf&& other) noexcept; - - MemBuf(const MemBuf& other); - MemBuf& operator=(const MemBuf& other); - - private: - enum FlagsEnum : uintptr_t { - // Adding any more flags would not work on 32-bit architectures, - // as these flags are stashed in the least significant 2 bits of a - // max-align-aligned pointer. - flag_free_shared_info = 0x1, - flag_maybe_shared = 0x2, - flag_mask = flag_free_shared_info | flag_maybe_shared - }; - - struct SharedInfo { - SharedInfo(); - SharedInfo(FreeFunction fn, void* arg); - - // A pointer to a function to call to free the buffer when the refcount - // hits 0. If this is null, free() will be used instead. - FreeFunction freeFn; - void* userData; - std::atomic refcount; - bool externallyShared{false}; - }; - // Helper structs for use by operator new and delete - struct HeapPrefix; - struct HeapStorage; - struct HeapFullStorage; - - /** - * Create a new MemBuf pointing to an external buffer. - * - * The caller is responsible for holding a reference count for this new - * MemBuf. The MemBuf constructor does not automatically increment the - * reference count. - */ - struct InternalConstructor {}; // avoid conflicts - MemBuf(InternalConstructor, uintptr_t flagsAndSharedInfo, uint8_t* buf, - std::size_t capacity, uint8_t* data, std::size_t length) noexcept; - - void unshareOneSlow(); - void unshareChained(); - void makeManagedChained(); - void coalesceSlow(); - void coalesceSlow(size_t maxLength); - // newLength must be the entire length of the buffers between this and - // end (no truncation) - void coalesceAndReallocate(size_t newHeadroom, size_t newLength, MemBuf* end, - size_t newTailroom); - void coalesceAndReallocate(size_t newLength, MemBuf* end) { - coalesceAndReallocate(headroom(), newLength, end, end->prev_->tailroom()); - } - void decrementRefcount(); - void reserveSlow(std::size_t minHeadroom, std::size_t minTailroom); - void freeExtBuffer(); - - static size_t goodExtBufferSize(std::size_t minCapacity); - static void initExtBuffer(uint8_t* buf, size_t mallocSize, - SharedInfo** infoReturn, - std::size_t* capacityReturn); - static void allocExtBuffer(std::size_t minCapacity, uint8_t** bufReturn, - SharedInfo** infoReturn, - std::size_t* capacityReturn); - static void releaseStorage(HeapStorage* storage, uint16_t freeFlags); - static void freeInternalBuf(void* buf, void* userData); - - /* - * Member variables - */ - - /* - * Links to the next and the previous MemBuf in this chain. - * - * The chain is circularly linked (the last element in the chain points back - * at the head), and next_ and prev_ can never be null. If this MemBuf is the - * only element in the chain, next_ and prev_ will both point to this. - */ - MemBuf* next_{this}; - MemBuf* prev_{this}; - - /* - * A pointer to the start of the data referenced by this MemBuf, and the - * length of the data. - * - * This may refer to any subsection of the actual buffer capacity. - */ - uint8_t* data_{nullptr}; - uint8_t* buf_{nullptr}; - std::size_t length_{0}; - std::size_t capacity_{0}; - - // Pack flags in least significant 2 bits, sharedInfo in the rest - mutable uintptr_t flags_and_shared_info_{0}; - - static inline uintptr_t packFlagsAndSharedInfo(uintptr_t flags, - SharedInfo* info) { - uintptr_t uinfo = reinterpret_cast(info); - return flags | uinfo; - } - - inline SharedInfo* sharedInfo() const { - return reinterpret_cast(flags_and_shared_info_ & ~flag_mask); - } - - inline void setSharedInfo(SharedInfo* info) { - uintptr_t uinfo = reinterpret_cast(info); - flags_and_shared_info_ = (flags_and_shared_info_ & flag_mask) | uinfo; - } - - inline uintptr_t flags() const { return flags_and_shared_info_ & flag_mask; } - - // flags_ are changed from const methods - inline void setFlags(uintptr_t flags) const { - flags_and_shared_info_ |= flags; - } - - inline void clearFlags(uintptr_t flags) const { - flags_and_shared_info_ &= ~flags; - } - - inline void setFlagsAndSharedInfo(uintptr_t flags, SharedInfo* info) { - flags_and_shared_info_ = packFlagsAndSharedInfo(flags, info); - } - - struct DeleterBase { - virtual ~DeleterBase() {} - virtual void dispose(void* p) = 0; - }; - - template - struct UniquePtrDeleter : public DeleterBase { - typedef typename UniquePtr::pointer Pointer; - typedef typename UniquePtr::deleter_type Deleter; - - explicit UniquePtrDeleter(Deleter deleter) : deleter_(std::move(deleter)) {} - void dispose(void* p) override { - try { - deleter_(static_cast(p)); - delete this; - } catch (...) { - abort(); - } - } - - private: - Deleter deleter_; - }; - - static void freeUniquePtrBuffer(void* ptr, void* userData) { - static_cast(userData)->dispose(ptr); - } -}; - -// template -// typename std::enable_if< -// detail::IsUniquePtrToSL::value, -// std::unique_ptr>::type -// MemBuf::takeOwnership(UniquePtr&& buf, size_t count) { -// size_t size = count * sizeof(typename UniquePtr::element_type); -// auto deleter = new UniquePtrDeleter(buf.get_deleter()); -// return takeOwnership( -// buf.release(), size, &MemBuf::freeUniquePtrBuffer, deleter); -// } - -inline std::unique_ptr MemBuf::copyBuffer(const void* data, - std::size_t size, - std::size_t headroom, - std::size_t minTailroom) { - std::size_t capacity = headroom + size + minTailroom; - std::unique_ptr buf = MemBuf::create(capacity); - buf->advance(headroom); - if (size != 0) { - memcpy(buf->writableData(), data, size); - } - buf->append(size); - return buf; -} - -} // namespace utils diff --git a/libtransport/src/hicn/transport/utils/min_filter.h b/libtransport/src/hicn/transport/utils/min_filter.h deleted file mode 100644 index dcfd5652d..000000000 --- a/libtransport/src/hicn/transport/utils/min_filter.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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.sudo make instamake install - */ - -#pragma once - -#include -#include - -#include -#include -#include -#include -#include - -namespace utils { - -template -class MinFilter { - public: - MinFilter(std::size_t size) : size_(size) {} - - std::size_t size() { return by_arrival_.size(); } - - template - TRANSPORT_ALWAYS_INLINE void pushBack(R&& value) { - if (by_arrival_.size() >= size_) { - by_order_.erase(by_arrival_.back()); - by_arrival_.pop_back(); - } - - by_arrival_.push_front(by_order_.insert(std::forward(value))); - } - - TRANSPORT_ALWAYS_INLINE const T& begin() { return *by_order_.cbegin(); } - - TRANSPORT_ALWAYS_INLINE const T& rBegin() { return *by_order_.crbegin(); } - - private: - std::multiset by_order_; - std::deque::const_iterator> by_arrival_; - std::size_t size_; -}; - -} // namespace utils diff --git a/libtransport/src/hicn/transport/utils/object_pool.h b/libtransport/src/hicn/transport/utils/object_pool.h deleted file mode 100644 index e8f837753..000000000 --- a/libtransport/src/hicn/transport/utils/object_pool.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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. - */ - -#pragma once - -// TODO -#include - -#include -#include -#include - -namespace utils { - -template -class ObjectPool { - class ObjectDeleter { - public: - ObjectDeleter(ObjectPool *pool = nullptr) : pool_(pool) {} - - void operator()(T *t) { - if (pool_) { - pool_->add(t); - } else { - delete t; - } - } - - private: - ObjectPool *pool_; - }; - - public: - using Ptr = std::unique_ptr; - - ObjectPool() : destructor_(false) {} - - ~ObjectPool() { - destructor_ = true; - for (auto &ptr : object_pool_) { - ptr.reset(); - } - } - - std::pair get() { - if (object_pool_.empty()) { - return std::make_pair(false, makePtr(nullptr)); - } - - utils::SpinLock::Acquire locked(object_pool_lock_); - auto ret = std::move(object_pool_.front()); - object_pool_.pop_front(); - return std::make_pair(true, std::move(ret)); - } - - void add(T *object) { - utils::SpinLock::Acquire locked(object_pool_lock_); - - if (TRANSPORT_EXPECT_TRUE(!destructor_)) { - object_pool_.emplace_back(makePtr(object)); - } else { - delete object; - } - } - - Ptr makePtr(T *object) { return Ptr(object, ObjectDeleter(this)); } - - private: - // No copies - ObjectPool(const ObjectPool &other) = delete; - - utils::SpinLock object_pool_lock_; - std::deque object_pool_; - bool destructor_; -}; - -} // namespace utils \ No newline at end of file diff --git a/libtransport/src/hicn/transport/utils/ring_buffer.h b/libtransport/src/hicn/transport/utils/ring_buffer.h deleted file mode 100644 index 9babe56bd..000000000 --- a/libtransport/src/hicn/transport/utils/ring_buffer.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include - -namespace utils { - -/** - * NOTE: Single consumer single producer ring buffer - */ -template -class CircularFifo { - public: - enum { Capacity = Size + 1 }; - - CircularFifo() : tail_(0), head_(0), size_(0) {} - virtual ~CircularFifo() {} - - bool push(const Element& item); - bool push(Element&& item); - bool pop(Element& item); - - bool wasEmpty() const; - bool wasFull() const; - bool isLockFree() const; - std::size_t size() const; - - private: - std::size_t increment(std::size_t idx) const; - std::atomic tail_; // tail(input) index - Element array_[Capacity]; - std::atomic head_; // head(output) index - std::atomic size_; -}; - -template -bool CircularFifo::push(const Element& item) { - const auto current_tail = tail_.load(std::memory_order_relaxed); - const auto next_tail = increment(current_tail); - if (next_tail != head_.load(std::memory_order_acquire)) { - array_[current_tail] = item; - tail_.store(next_tail, std::memory_order_release); - size_++; - return true; - } - - // full queue - return false; -} - -/** - * Push by move - */ -template -bool CircularFifo::push(Element&& item) { - const auto current_tail = tail_.load(std::memory_order_relaxed); - const auto next_tail = increment(current_tail); - if (next_tail != head_.load(std::memory_order_acquire)) { - array_[current_tail] = std::move(item); - tail_.store(next_tail, std::memory_order_release); - size_++; - return true; - } - - // full queue - return false; -} - -// Pop by Consumer can only update the head -// (load with relaxed, store with release) -// the tail must be accessed with at least acquire -template -bool CircularFifo::pop(Element& item) { - const size_t current_head = head_.load(std::memory_order_relaxed); - if (current_head == tail_.load(std::memory_order_acquire)) { - return false; // empty queue - } - - item = std::move(array_[current_head]); - head_.store(increment(current_head), std::memory_order_release); - size_--; - return true; -} - -template -bool CircularFifo::wasEmpty() const { - // snapshot with acceptance of that this comparison operation is not atomic - return (head_.load() == tail_.load()); -} - -// snapshot with acceptance that this comparison is not atomic -template -bool CircularFifo::wasFull() const { - const auto next_tail = - increment(tail_.load()); // acquire, we dont know who call - return (next_tail == head_.load()); -} - -template -bool CircularFifo::isLockFree() const { - return (tail_.is_lock_free() && head_.is_lock_free()); -} - -template -std::size_t CircularFifo::increment(std::size_t idx) const { - return (idx + 1) % Capacity; -} - -template -std::size_t CircularFifo::size() const { - return size_.load(std::memory_order_relaxed); -} - -} // namespace utils \ No newline at end of file diff --git a/libtransport/src/hicn/transport/utils/signer.cc b/libtransport/src/hicn/transport/utils/signer.cc deleted file mode 100644 index 9ac9a2c45..000000000 --- a/libtransport/src/hicn/transport/utils/signer.cc +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Copyright 2017 Facebook, Inc. - * - * 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 -#include -#include -#include - -extern "C" { -#ifndef _WIN32 -TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat") -#endif -#include -#include -#include -#include -} - -#include - -#define ALLOW_UNALIGNED_READS 1 - -namespace utils { - -uint8_t Signer::zeros[200] = {0}; - -/*One signer_ per Private Key*/ -Signer::Signer(PARCKeyStore *keyStore, CryptoSuite suite) { - parcSecurity_Init(); - - switch (suite) { - case CryptoSuite::DSA_SHA256: - case CryptoSuite::RSA_SHA256: - case CryptoSuite::RSA_SHA512: - case CryptoSuite::ECDSA_256K1: { - this->signer_ = - parcSigner_Create(parcPublicKeySigner_Create( - keyStore, static_cast(suite)), - PARCPublicKeySignerAsSigner); - break; - } - case CryptoSuite::HMAC_SHA256: - case CryptoSuite::HMAC_SHA512: { - this->signer_ = - parcSigner_Create(parcSymmetricKeySigner_Create( - (PARCSymmetricKeyStore *)keyStore, - parcCryptoSuite_GetCryptoHash( - static_cast(suite))), - PARCSymmetricKeySignerAsSigner); - break; - } - default: { return; } - } - - suite_ = suite; - key_id_ = parcSigner_CreateKeyId(this->signer_); - signature_length_ = parcSigner_GetSignatureSize(this->signer_); -} - -Signer::Signer(const std::string &passphrase, CryptoSuite suite) { - parcSecurity_Init(); - - switch (suite) { - case CryptoSuite::HMAC_SHA256: - case CryptoSuite::HMAC_SHA512: { - composer_ = parcBufferComposer_Create(); - parcBufferComposer_PutString(composer_, passphrase.c_str()); - key_buffer_ = parcBufferComposer_ProduceBuffer(composer_); - symmetricKeyStore_ = parcSymmetricKeyStore_Create(key_buffer_); - this->signer_ = parcSigner_Create( - parcSymmetricKeySigner_Create( - symmetricKeyStore_, parcCryptoSuite_GetCryptoHash( - static_cast(suite))), - PARCSymmetricKeySignerAsSigner); - break; - } - default: { return; } - } - - suite_ = suite; - key_id_ = parcSigner_CreateKeyId(this->signer_); - signature_length_ = parcSigner_GetSignatureSize(this->signer_); -} - -Signer::Signer(const PARCSigner *signer, CryptoSuite suite) - : signer_(parcSigner_Acquire(signer)), - key_id_(parcSigner_CreateKeyId(this->signer_)), - suite_(suite), - signature_length_(parcSigner_GetSignatureSize(this->signer_)) { - parcSecurity_Init(); -} - -Signer::Signer(const PARCSigner *signer) - : Signer(signer, CryptoSuite::UNKNOWN) {} - -Signer::~Signer() { - if (signature_) parcSignature_Release(&signature_); - if (symmetricKeyStore_) parcSymmetricKeyStore_Release(&symmetricKeyStore_); - if (key_buffer_) parcBuffer_Release(&key_buffer_); - if (composer_) parcBufferComposer_Release(&composer_); - if (signer_) parcSigner_Release(&signer_); - if (key_id_) parcKeyId_Release(&key_id_); - parcSecurity_Fini(); -} - -void Signer::sign(Packet &packet) { - // header chain points to the IP + TCP hicn header + AH Header - MemBuf *header_chain = packet.header_head_; - MemBuf *payload_chain = packet.payload_head_; - uint8_t *hicn_packet = (uint8_t *)header_chain->writableData(); - Packet::Format format = packet.getFormat(); - - if (!(format & HFO_AH)) { - throw errors::MalformedAHPacketException(); - } - - packet.setSignatureSize(signature_length_); - - // Copy IP+TCP/ICMP header before zeroing them - hicn_header_t header_copy; - hicn_packet_copy_header(format, (const hicn_header_t *)packet.packet_start_, - &header_copy, false); - - std::size_t header_len = Packet::getHeaderSizeFromFormat(format); - - packet.resetForHash(); - - /* Fill the hicn_ah header */ - using namespace std::chrono; - auto now = duration_cast(system_clock::now().time_since_epoch()) - .count(); - packet.setSignatureTimestamp(now); - packet.setValidationAlgorithm(suite_); - - KeyId key_id; - key_id.first = (uint8_t *)parcBuffer_Overlay( - (PARCBuffer *)parcKeyId_GetKeyId(this->key_id_), 0); - packet.setKeyId(key_id); - - // Calculate hash - CryptoHasher hasher(parcSigner_GetCryptoHasher(signer_)); - hasher.init(); - hasher.updateBytes(hicn_packet, header_len + signature_length_); - - for (MemBuf *current = payload_chain; current != header_chain; - current = current->next()) { - hasher.updateBytes(current->data(), current->length()); - } - - CryptoHash hash = hasher.finalize(); - - signature_ = parcSigner_SignDigestNoAlloc(this->signer_, hash.hash_, - packet.getSignature(), - (uint32_t)signature_length_); - PARCBuffer *buffer = parcSignature_GetSignature(signature_); - - size_t bytes_len = parcBuffer_Remaining(buffer); - - if (bytes_len > signature_length_) { - throw errors::MalformedAHPacketException(); - } - - hicn_packet_copy_header(format, &header_copy, - (hicn_header_t *)packet.packet_start_, false); -} - -size_t Signer::getSignatureLength() { return signature_length_; } - -PARCKeyStore *Signer::getKeyStore() { - return parcSigner_GetKeyStore(this->signer_); -} - -} // namespace utils diff --git a/libtransport/src/hicn/transport/utils/signer.h b/libtransport/src/hicn/transport/utils/signer.h deleted file mode 100644 index 31b21462b..000000000 --- a/libtransport/src/hicn/transport/utils/signer.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -extern "C" { -#include -#include -#include -#include -#include -} - -namespace utils { - -using Packet = transport::core::Packet; - -/** - * A signer can use a single key (asymmetric or symmetric) to sign a packet. - */ -class Signer { - friend class Identity; - - public: - /** - * Create a Signer - * - * @param keyStore A keystore containing a private key or simmetric key to - * use to sign packet with this Signer. - * @param suite CryptoSuite to use to verify the signature - */ - Signer(PARCKeyStore *keyStore, CryptoSuite suite); - - /** - * Create a Signer - * - * @param passphrase A string from which the symmetric key will be derived - * @param suite CryptoSuite to use to verify the signature - */ - Signer(const std::string &passphrase, CryptoSuite suite); - - Signer(const PARCSigner *signer, CryptoSuite suite); - - Signer(const PARCSigner *signer); - - ~Signer(); - - /** - * @brief Sign a packet - * - * This method is general and must be used for Public-private key signature, - * HMAC and CRC. - * - * @param packet A pointer to the header of the packet to sign. Mutable - * field in the packet must be set to 0. - * @param key_id Indentifier of the key to use to generate the signature. - */ - void sign(Packet &packet); - - size_t getSignatureLength(); - - PARCKeyStore *getKeyStore(); - - private: - PARCBufferComposer *composer_ = nullptr; - PARCBuffer *key_buffer_ = nullptr; - PARCSymmetricKeyStore *symmetricKeyStore_ = nullptr; - PARCSigner *signer_ = nullptr; - PARCSignature *signature_ = nullptr; - PARCKeyId *key_id_ = nullptr; - CryptoSuite suite_; - size_t signature_length_; - static uint8_t zeros[200]; -}; - -} // namespace utils diff --git a/libtransport/src/hicn/transport/utils/spinlock.h b/libtransport/src/hicn/transport/utils/spinlock.h deleted file mode 100644 index 009a94454..000000000 --- a/libtransport/src/hicn/transport/utils/spinlock.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -namespace utils { - -class SpinLock : private std::atomic_flag { - public: - class Acquire { - public: - Acquire(SpinLock& spin_lock) : spin_lock_(spin_lock) { spin_lock_.lock(); } - - ~Acquire() { spin_lock_.unlock(); } - - // No copies - Acquire& operator=(const Acquire&) = delete; - Acquire(const Acquire&) = delete; - - private: - SpinLock& spin_lock_; - }; - - SpinLock() { clear(); } - - void lock() { - // busy-wait - while (std::atomic_flag::test_and_set(std::memory_order_acquire)) - ; - } - - void unlock() { clear(std::memory_order_release); } - - bool tryLock() { - return std::atomic_flag::test_and_set(std::memory_order_acquire); - } -}; - -} // namespace utils \ No newline at end of file diff --git a/libtransport/src/hicn/transport/utils/stream_buffer.h b/libtransport/src/hicn/transport/utils/stream_buffer.h deleted file mode 100644 index adfb696f2..000000000 --- a/libtransport/src/hicn/transport/utils/stream_buffer.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -namespace utils { - -template -struct ostreambuf - : public std::basic_streambuf > { - ostreambuf(char_type* buffer, std::streamsize buffer_length) { - // set the "put" pointer the start of the buffer and record it's length. - setp(buffer, buffer + buffer_length); - } -}; - -} // namespace utils \ No newline at end of file diff --git a/libtransport/src/hicn/transport/utils/string_tokenizer.cc b/libtransport/src/hicn/transport/utils/string_tokenizer.cc deleted file mode 100644 index a280a3c43..000000000 --- a/libtransport/src/hicn/transport/utils/string_tokenizer.cc +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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. - */ - -#include -#include - -namespace utils { - -StringTokenizer::StringTokenizer(const std::string &str) - : str_(str), delimiter_(" ") {} - -StringTokenizer::StringTokenizer(const std::string &str, - const std::string &delim) - : str_(str), delimiter_(delim) {} - -bool StringTokenizer::hasMoreTokens() { - return str_.find(delimiter_) != std::string::npos || !str_.empty(); -} - -std::string StringTokenizer::nextToken() { - unsigned long pos = (unsigned long)str_.find(delimiter_); - - bool token_found = std::string::npos != pos; - - if (!token_found && str_.empty()) { - throw errors::TokenizerException(); - } - - std::string token = str_.substr(0, pos); - str_.erase(0, token_found ? pos + delimiter_.length() : pos); - - return token; -} - -} // namespace utils \ No newline at end of file diff --git a/libtransport/src/hicn/transport/utils/string_tokenizer.h b/libtransport/src/hicn/transport/utils/string_tokenizer.h deleted file mode 100644 index 36630eb58..000000000 --- a/libtransport/src/hicn/transport/utils/string_tokenizer.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -namespace utils { - -class StringTokenizer { - public: - StringTokenizer(const std::string &str); - StringTokenizer(const std::string &str, const std::string &delim); - - bool hasMoreTokens(); - std::string nextToken(); - - private: - std::string str_; - std::string delimiter_; -}; - -} // namespace utils diff --git a/libtransport/src/hicn/transport/utils/suffix_strategy.h b/libtransport/src/hicn/transport/utils/suffix_strategy.h deleted file mode 100644 index ab9b1eff6..000000000 --- a/libtransport/src/hicn/transport/utils/suffix_strategy.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include - -namespace utils { - -using transport::core::NextSegmentCalculationStrategy; - -class SuffixStrategy { - public: - static constexpr uint32_t INVALID_SUFFIX = - std::numeric_limits::max(); - - SuffixStrategy(NextSegmentCalculationStrategy strategy) - : suffix_stragegy_(strategy), - total_count_(0), - final_suffix_(INVALID_SUFFIX) {} - - virtual ~SuffixStrategy() = default; - - virtual uint32_t getNextSuffix() = 0; - - virtual uint32_t getFinalSuffix() { return final_suffix_; } - - virtual void setFinalSuffix(std::uint32_t final_suffix) { - if (final_suffix != INVALID_SUFFIX) { - final_suffix_ = final_suffix; - } - } - - virtual uint32_t getNextManifestSuffix() = 0; - - virtual uint32_t getNextContentSuffix() = 0; - - virtual void reset(uint32_t offset = 0) = 0; - - virtual uint32_t getManifestCapacity() = 0; - - virtual void setManifestCapacity(uint32_t capacity) = 0; - - virtual uint32_t getTotalCount() { return total_count_; }; - - NextSegmentCalculationStrategy getSuffixStrategy() { - return suffix_stragegy_; - } - - protected: - inline void incrementTotalCount() { total_count_++; }; - - protected: - NextSegmentCalculationStrategy suffix_stragegy_; - std::uint32_t total_count_; - std::uint32_t final_suffix_; -}; - -class IncrementalSuffixStrategy : public SuffixStrategy { - public: - IncrementalSuffixStrategy(std::uint32_t start_offset) - : SuffixStrategy(NextSegmentCalculationStrategy::INCREMENTAL), - next_suffix_(start_offset) {} - - TRANSPORT_ALWAYS_INLINE std::uint32_t getNextSuffix() override { - incrementTotalCount(); - return next_suffix_++; - } - - TRANSPORT_ALWAYS_INLINE std::uint32_t getNextContentSuffix() override { - return getNextSuffix(); - } - - TRANSPORT_ALWAYS_INLINE std::uint32_t getNextManifestSuffix() override { - return getNextSuffix(); - } - - uint32_t getManifestCapacity() override { - throw errors::RuntimeException( - "No manifest capacity in IncrementalSuffixStrategy."); - } - - void setManifestCapacity(uint32_t capacity) override { - throw errors::RuntimeException( - "No manifest capacity in IncrementalSuffixStrategy."); - } - - void reset(std::uint32_t offset = 0) override { next_suffix_ = offset; } - - protected: - std::uint32_t next_suffix_; -}; - -class CapacityBasedSuffixStrategy : public SuffixStrategy { - public: - CapacityBasedSuffixStrategy(std::uint32_t start_offset, - std::uint32_t manifest_capacity) - : SuffixStrategy(NextSegmentCalculationStrategy::INCREMENTAL), - next_suffix_(start_offset), - segments_in_manifest_(manifest_capacity), - current_manifest_iteration_(0) {} - - TRANSPORT_ALWAYS_INLINE std::uint32_t getNextSuffix() override { - incrementTotalCount(); - return next_suffix_++; - } - - TRANSPORT_ALWAYS_INLINE std::uint32_t getNextContentSuffix() override { - incrementTotalCount(); - return next_suffix_ % segments_in_manifest_ == 0 ? next_suffix_++ - : ++next_suffix_; - } - - TRANSPORT_ALWAYS_INLINE std::uint32_t getNextManifestSuffix() override { - incrementTotalCount(); - return (current_manifest_iteration_++) * (segments_in_manifest_ + 1); - } - - TRANSPORT_ALWAYS_INLINE uint32_t getManifestCapacity() override { - return segments_in_manifest_; - } - - TRANSPORT_ALWAYS_INLINE void setManifestCapacity(uint32_t capacity) override { - segments_in_manifest_ = capacity; - } - - void reset(std::uint32_t offset = 0) override { next_suffix_ = offset; } - - protected: - std::uint32_t next_suffix_; - std::uint32_t segments_in_manifest_; - std::uint32_t current_manifest_iteration_; -}; - -class SuffixStrategyFactory { - public: - static std::unique_ptr getSuffixStrategy( - NextSegmentCalculationStrategy strategy, uint32_t start_offset, - uint32_t manifest_capacity = 0) { - switch (strategy) { - case NextSegmentCalculationStrategy::INCREMENTAL: - return std::make_unique(start_offset); - case NextSegmentCalculationStrategy::MANIFEST_CAPACITY_BASED: - return std::make_unique(start_offset, - manifest_capacity); - default: - throw errors::RuntimeException( - "No valid NextSegmentCalculationStrategy specified."); - } - } -}; - -} // namespace utils diff --git a/libtransport/src/hicn/transport/utils/test.h b/libtransport/src/hicn/transport/utils/test.h deleted file mode 100644 index e3dd619ac..000000000 --- a/libtransport/src/hicn/transport/utils/test.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -namespace testing { - -namespace internal { - -enum GTestColor { COLOR_DEFAULT, COLOR_RED, COLOR_GREEN, COLOR_YELLOW }; - -extern void ColoredPrintf(GTestColor color, const char *fmt, ...); - -} // namespace internal - -} // namespace testing - -#define PRINTF(...) \ - do { \ - testing::internal::ColoredPrintf(testing::internal::COLOR_GREEN, \ - "[ ] "); \ - testing::internal::ColoredPrintf(testing::internal::COLOR_YELLOW, \ - __VA_ARGS__); \ - } while (0) - -// C++ stream interface -class TestCout : public std::stringstream { - public: - ~TestCout() {} -}; - -#define TEST_COUT TestCout() \ No newline at end of file diff --git a/libtransport/src/hicn/transport/utils/uri.cc b/libtransport/src/hicn/transport/utils/uri.cc deleted file mode 100644 index 33eb8b45b..000000000 --- a/libtransport/src/hicn/transport/utils/uri.cc +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 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. - */ - -#include -#include - -namespace utils { - -Uri::Uri() {} - -Uri &Uri::parse(const std::string &uri) { - if (uri.length() == 0) { - throw errors::RuntimeException("Malformed URI."); - } - - iterator_t uri_end = uri.end(); - - // get query start - iterator_t query_start = std::find(uri.begin(), uri_end, '?'); - - // protocol - iterator_t protocol_start = uri.begin(); - iterator_t protocol_end = std::find(protocol_start, uri_end, ':'); //"://"); - - if (protocol_end != uri_end) { - std::string prot = &*(protocol_end); - if ((prot.length() > 3) && (prot.substr(0, 3) == "://")) { - protocol_ = std::string(protocol_start, protocol_end); - protocol_end += 3; // :// - } else { - protocol_end = uri.begin(); // no protocol - } - } else { - protocol_end = uri.begin(); // no protocol - } - // host - iterator_t host_start = protocol_end; - iterator_t path_start = - std::find(host_start, uri_end, '/'); // get path_start - - iterator_t host_end = std::find( - protocol_end, (path_start != uri_end) ? path_start : query_start, - ':'); // check for port - - locator_ = std::string(host_start, host_end); - - // port - if ((host_end != uri_end) && ((&*(host_end))[0] == ':')) { - host_end++; - iterator_t port_end = (path_start != uri_end) ? path_start : query_start; - port_ = std::string(host_end, port_end); - } - - // path - if (path_start != uri_end) { - path_ = std::string(path_start, query_start); - } - // query - if (query_start != uri_end) { - query_string_ = std::string(query_start, uri.end()); - } - - return *this; -} - -Uri &Uri::parseProtocolAndLocator(const std::string &locator) { - iterator_t total_end = locator.end(); - - // protocol - iterator_t protocol_start = locator.begin(); - iterator_t protocol_end = - std::find(protocol_start, total_end, ':'); //"://"); - - if (protocol_end != total_end) { - std::string prot = &*(protocol_end); - if ((prot.length() > 3) && (prot.substr(0, 3) == "://")) { - protocol_ = std::string(protocol_start, protocol_end); - protocol_end += 3; // :// - } else { - throw errors::RuntimeException("Malformed locator. (Missing \"://\")"); - } - } else { - throw errors::RuntimeException("Malformed locator. No protocol specified."); - } - - // locator - iterator_t host_start = protocol_end; - iterator_t host_end = std::find(protocol_end, total_end, '/'); - - if (host_start == host_end) { - throw errors::RuntimeException( - "Malformed locator. Locator name is missing"); - } - - locator_ = std::string(host_start, host_end); - - return *this; -} - -std::string Uri::getLocator() { return locator_; } - -std::string Uri::getPath() { return path_; } - -std::string Uri::getPort() { return port_; } - -std::string Uri::getProtocol() { return protocol_; } - -std::string Uri::getQueryString() { return query_string_; } - -} // end namespace utils diff --git a/libtransport/src/hicn/transport/utils/uri.h b/libtransport/src/hicn/transport/utils/uri.h deleted file mode 100644 index 7c28e8552..000000000 --- a/libtransport/src/hicn/transport/utils/uri.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include // find -#include - -namespace utils { - -class Uri { - typedef std::string::const_iterator iterator_t; - - public: - Uri(); - - Uri &parse(const std::string &uri); - - Uri &parseProtocolAndLocator(const std::string &locator); - - std::string getQueryString(); - - std::string getPath(); - - std::string getProtocol(); - - std::string getLocator(); - - std::string getPort(); - - private: - std::string query_string_, path_, protocol_, locator_, port_; -}; // uri - -} // namespace utils diff --git a/libtransport/src/hicn/transport/utils/verifier.cc b/libtransport/src/hicn/transport/utils/verifier.cc deleted file mode 100644 index 281ee21dc..000000000 --- a/libtransport/src/hicn/transport/utils/verifier.cc +++ /dev/null @@ -1,234 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include -#include -#include -#include - -extern "C" { -#ifndef _WIN32 -TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat") -#endif -#include -} - -#include - -namespace utils { - -TRANSPORT_ALWAYS_INLINE bool file_exists(const std::string &name) { - struct stat buffer; - return (stat(name.c_str(), &buffer) == 0); -} - -uint8_t Verifier::zeros[200] = {0}; - -Verifier::Verifier() { - parcSecurity_Init(); - PARCInMemoryVerifier *in_memory_verifier = parcInMemoryVerifier_Create(); - this->verifier_ = - parcVerifier_Create(in_memory_verifier, PARCInMemoryVerifierAsVerifier); -} - -Verifier::~Verifier() { - if (key_) parcKey_Release(&key_); - if (keyId_) parcKeyId_Release(&keyId_); - if (signer_) parcSigner_Release(&signer_); - if (symmetricKeyStore_) parcSymmetricKeyStore_Release(&symmetricKeyStore_); - if (key_buffer_) parcBuffer_Release(&key_buffer_); - if (composer_) parcBufferComposer_Release(&composer_); - if (certificate_) parcCertificate_Release(&certificate_); - if (factory_) parcCertificateFactory_Release(&factory_); - if (verifier_) parcVerifier_Release(&verifier_); - parcSecurity_Fini(); -} - -/* - * TODO: Unsupported in libparc - */ -bool Verifier::hasKey(PARCKeyId *keyId) { return false; } - -/* - * TODO: signal errors without trap. - */ -bool Verifier::addKey(PARCKey *key) { - parcVerifier_AddKey(this->verifier_, key); - return true; -} - -PARCKeyId *Verifier::addKeyFromPassphrase(const std::string &passphrase, - CryptoSuite suite) { - composer_ = parcBufferComposer_Create(); - parcBufferComposer_PutString(composer_, passphrase.c_str()); - key_buffer_ = parcBufferComposer_ProduceBuffer(composer_); - - symmetricKeyStore_ = parcSymmetricKeyStore_Create(key_buffer_); - signer_ = parcSigner_Create( - parcSymmetricKeySigner_Create( - symmetricKeyStore_, - parcCryptoSuite_GetCryptoHash(static_cast(suite))), - PARCSymmetricKeySignerAsSigner); - keyId_ = parcSigner_CreateKeyId(signer_); - key_ = parcKey_CreateFromSymmetricKey( - keyId_, parcSigner_GetSigningAlgorithm(signer_), key_buffer_); - - addKey(key_); - return keyId_; -} - -PARCKeyId *Verifier::addKeyFromCertificate(const std::string &file_name) { - factory_ = parcCertificateFactory_Create(PARCCertificateType_X509, - PARCContainerEncoding_PEM); - parcAssertNotNull(factory_, "Expected non-NULL factory"); - - if (!file_exists(file_name)) { - TRANSPORT_LOGW("Warning! The certificate %s file does not exist", - file_name.c_str()); - return nullptr; - } - - certificate_ = parcCertificateFactory_CreateCertificateFromFile( - factory_, (char *)file_name.c_str(), NULL); - PARCBuffer *derEncodedVersion = - parcCertificate_GetDEREncodedPublicKey(certificate_); - PARCCryptoHash *keyDigest = parcCertificate_GetPublicKeyDigest(certificate_); - keyId_ = parcKeyId_Create(parcCryptoHash_GetDigest(keyDigest)); - key_ = parcKey_CreateFromDerEncodedPublicKey(keyId_, PARCSigningAlgorithm_RSA, - derEncodedVersion); - - addKey(key_); - return keyId_; -} - -int Verifier::verify(const Packet &packet) { - // to initialize packet.payload_head_ - const_cast(&packet)->separateHeaderPayload(); - bool valid = false; - Packet::Format format = packet.getFormat(); - - if (!(packet.format_ & HFO_AH)) { - throw errors::MalformedAHPacketException(); - } - - // Copy IP+TCP/ICMP header before zeroing them - hicn_header_t header_copy; - hicn_packet_copy_header(format, (const hicn_header_t *)packet.packet_start_, - &header_copy, false); - - PARCCryptoSuite suite = - static_cast(packet.getValidationAlgorithm()); - PARCCryptoHashType hashtype = parcCryptoSuite_GetCryptoHash(suite); - KeyId _key_id = packet.getKeyId(); - PARCBuffer *buffer = - parcBuffer_Wrap(_key_id.first, _key_id.second, 0, _key_id.second); - PARCKeyId *key_id = parcKeyId_Create(buffer); - parcBuffer_Release(&buffer); - - int ah_payload_len = (int)packet.getSignatureSize(); - uint8_t *_signature = packet.getSignature(); - uint8_t *signature = new uint8_t[ah_payload_len]; - // TODO Remove signature copy at this point, by not setting to zero - // the validation payload. - std::memcpy(signature, _signature, ah_payload_len); - - std::shared_ptr hasher; - switch (CryptoSuite(suite)) { - case CryptoSuite::DSA_SHA256: - case CryptoSuite::RSA_SHA256: - case CryptoSuite::RSA_SHA512: - case CryptoSuite::ECDSA_256K1: { - hasher = std::make_shared( - parcVerifier_GetCryptoHasher(verifier_, key_id, hashtype)); - break; - } - case CryptoSuite::HMAC_SHA256: - case CryptoSuite::HMAC_SHA512: { - if (!signer_) return false; - hasher = - std::make_shared(parcSigner_GetCryptoHasher(signer_)); - break; - } - default: { return false; } - } - CryptoHash hash_computed_locally = getPacketHash(packet, hasher); - - PARCBuffer *bits = - parcBuffer_Wrap(signature, ah_payload_len, 0, ah_payload_len); - parcBuffer_Rewind(bits); - - /* IF the signature algo is ECDSA, the signature might be shorter than the - * signature field */ - PARCSigningAlgorithm algo = parcCryptoSuite_GetSigningAlgorithm(suite); - while (algo == PARCSigningAlgorithm_ECDSA && parcBuffer_HasRemaining(bits) && - parcBuffer_GetUint8(bits) == 0) - ; - - if (algo == PARCSigningAlgorithm_ECDSA) { - parcBuffer_SetPosition(bits, parcBuffer_Position(bits) - 1); - } - - if (!parcBuffer_HasRemaining(bits)) { - parcKeyId_Release(&key_id); - parcBuffer_Release(&bits); - return valid; - } - - PARCSignature *signatureToVerify = parcSignature_Create( - parcCryptoSuite_GetSigningAlgorithm(suite), hashtype, bits); - - if (algo == PARCSigningAlgorithm_RSA) { - parcBuffer_SetPosition(bits, 0); - } - - valid = parcVerifier_VerifyDigestSignature( - verifier_, key_id, hash_computed_locally.hash_, suite, signatureToVerify); - - /* Restore the resetted fields */ - hicn_packet_copy_header(format, &header_copy, - (hicn_header_t *)packet.packet_start_, false); - - delete[] signature; - parcKeyId_Release(&key_id); - parcBuffer_Release(&bits); - parcSignature_Release(&signatureToVerify); - - return valid; -} - -CryptoHash Verifier::getPacketHash(const Packet &packet, - std::shared_ptr hasher) { - MemBuf *header_chain = packet.header_head_; - MemBuf *payload_chain = packet.payload_head_; - Packet::Format format = packet.getFormat(); - int ah_payload_len = (int)packet.getSignatureSize(); - uint8_t *hicn_packet = header_chain->writableData(); - std::size_t header_len = Packet::getHeaderSizeFromFormat(format); - - // Reset fields that should not appear in the signature - const_cast(packet).resetForHash(); - hasher->init().updateBytes(hicn_packet, header_len + ah_payload_len); - - for (MemBuf *current = payload_chain; current != header_chain; - current = current->next()) { - hasher->updateBytes(current->data(), current->length()); - } - - return hasher->finalize(); -} - -} // namespace utils diff --git a/libtransport/src/hicn/transport/utils/verifier.h b/libtransport/src/hicn/transport/utils/verifier.h deleted file mode 100644 index 7ec6e7eda..000000000 --- a/libtransport/src/hicn/transport/utils/verifier.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -extern "C" { -#include -#include -#include -#include -#include -#include -} - -namespace utils { - -using Packet = transport::core::Packet; - -/** - * A verifier holds a crypto cache that contains all the keys to use for - * verify signatures/hmacs. - */ -class Verifier { - public: - Verifier(); - - ~Verifier(); - - /** - * @brief Check if a key is already in this Verifier. - * - * A PARCVerifier contains a CryptoCache with a set of key to use for - * verification purposes. - * - * @param keyId Identifier of the key to match in the CryptoCache of the - * Verifier. - * @return true if the key is found, false otherwise. - */ - bool hasKey(PARCKeyId *keyId); - - /** - * @brief Add a key to this Verifier - * - * @param key to add - * @return true if the key was added successfully, false otherwise. - */ - bool addKey(PARCKey *key); - - PARCKeyId *addKeyFromPassphrase(const std::string &passphrase, - CryptoSuite suite); - - PARCKeyId *addKeyFromCertificate(const std::string &file_name); - - /** - * @brief Verify a Signature - * - * This method is general and must be used for Public-private key signature, - * HMAC and CRC. - * - * @param signature A pointer to the buffer holding the signature - * @param sign_len Lenght of the signature (must be consistent with the type - * of the key) - * @param bufferSigned A pointer to the packet header signed with - * signature. Mutable fields and the signature field in the packet must be - * set to 0 - * @param buf_len Lenght of bufferSigned - * @param suite CryptoSuite to use to verify the signature - * @param key_id Indentifier of the key to use to verify the signature. The - * key must be already present in the Verifier. - */ - int verify(const Packet &packet); - - CryptoHash getPacketHash(const Packet &packet, - std::shared_ptr hasher); - - private: - PARCVerifier *verifier_ = nullptr; - PARCCertificateFactory *factory_ = nullptr; - PARCCertificate *certificate_ = nullptr; - PARCKeyId *keyId_ = nullptr; - PARCKey *key_ = nullptr; - PARCBuffer *key_buffer_ = nullptr; - PARCSymmetricKeyStore *symmetricKeyStore_ = nullptr; - PARCSigner *signer_ = nullptr; - PARCBufferComposer *composer_ = nullptr; - static uint8_t zeros[200]; -}; - -} // namespace utils diff --git a/libtransport/src/http/CMakeLists.txt b/libtransport/src/http/CMakeLists.txt new file mode 100644 index 000000000..00708822d --- /dev/null +++ b/libtransport/src/http/CMakeLists.txt @@ -0,0 +1,21 @@ +# 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) + +list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/client_connection.cc + ${CMAKE_CURRENT_SOURCE_DIR}/request.cc + ${CMAKE_CURRENT_SOURCE_DIR}/response.cc) + +set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) \ No newline at end of file diff --git a/libtransport/src/http/client_connection.cc b/libtransport/src/http/client_connection.cc new file mode 100644 index 000000000..7a3a636fe --- /dev/null +++ b/libtransport/src/http/client_connection.cc @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2017-2020 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 +#include +#include +#include +#include + +#include +#include + +#define DEFAULT_BETA 0.99 +#define DEFAULT_GAMMA 0.07 + +namespace transport { + +namespace http { + +using namespace transport; + +class HTTPClientConnection::Implementation + : public ConsumerSocket::ReadCallback { + static constexpr uint32_t max_buffer_capacity = 64 * 1024; + + public: + Implementation(HTTPClientConnection *http_client) + : http_client_(http_client), + consumer_(TransportProtocolAlgorithms::RAAQM), + read_bytes_callback_(nullptr), + read_buffer_(nullptr), + response_(std::make_shared()), + timer_(nullptr) { + consumer_.setSocketOption( + ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY, + (ConsumerContentObjectVerificationCallback)std::bind( + &Implementation::verifyData, this, std::placeholders::_1, + std::placeholders::_2)); + + consumer_.setSocketOption(ConsumerCallbacksOptions::READ_CALLBACK, this); + + consumer_.connect(); + timer_ = std::make_unique(consumer_.getIoService()); + } + + RC get(const std::string &url, HTTPHeaders headers = {}, + HTTPPayload &&payload = nullptr, + std::shared_ptr response = nullptr, + ReadBytesCallback *callback = nullptr, + std::string ipv6_first_word = "b001") { + return sendRequest(url, HTTPMethod::GET, headers, std::move(payload), + response, callback, ipv6_first_word); + } + + RC sendRequest(const std::string &url, HTTPMethod method, + HTTPHeaders headers = {}, HTTPPayload &&payload = nullptr, + std::shared_ptr response = nullptr, + ReadBytesCallback *callback = nullptr, + std::string ipv6_first_word = "b001") { + current_url_ = url; + read_bytes_callback_ = callback; + if (!response) { + response_ = std::make_shared(); + } else { + response_ = response; + } + + auto start = std::chrono::steady_clock::now(); + request_.init(method, url, headers, std::move(payload)); + + success_callback_ = [this, method = std::move(method), url = std::move(url), + start = std::move(start)](std::size_t size) -> void { + auto end = std::chrono::steady_clock::now(); + TRANSPORT_LOGI( + "%s %s [%s] duration: %llu [usec] %zu [bytes]\n", + method_map[method].c_str(), url.c_str(), name_.str().c_str(), + (unsigned long long) + std::chrono::duration_cast(end - start) + .count(), + size); + }; + + sendRequestGetReply(ipv6_first_word); + return return_code_; + } + + std::shared_ptr response() { + response_->coalescePayloadBuffer(); + return response_; + } + + HTTPClientConnection &stop() { + // This is thread safe and can be called from another thread + consumer_.stop(); + + return *http_client_; + } + + interface::ConsumerSocket &getConsumer() { + return consumer_; + } + + HTTPClientConnection &setTimeout(const std::chrono::seconds &timeout) { + timer_->cancel(); + timer_->expires_from_now(timeout); + timer_->async_wait([this](std::error_code ec) { + if (!ec) { + consumer_.stop(); + } + }); + + return *http_client_; + } + + HTTPClientConnection &setCertificate(const std::string &cert_path) { + if (consumer_.setSocketOption(GeneralTransportOptions::CERTIFICATE, + cert_path) == SOCKET_OPTION_NOT_SET) { + throw errors::RuntimeException("Error setting the certificate."); + } + + return *http_client_; + } + + private: + void sendRequestGetReply(std::string &ipv6_first_word) { + const std::string &request_string = request_.getRequestString(); + const std::string &locator = request_.getLocator(); + + // Hash it + + uint32_t locator_hash = + utils::hash::fnv32_buf(locator.c_str(), locator.size()); + uint64_t request_hash = + utils::hash::fnv64_buf(request_string.c_str(), request_string.size()); + + consumer_.setSocketOption( + ConsumerCallbacksOptions::INTEREST_OUTPUT, + (ConsumerInterestCallback)std::bind( + &Implementation::processLeavingInterest, this, + std::placeholders::_1, std::placeholders::_2)); + + // Factor hicn name using hash + name_.str(""); + + name_ << ipv6_first_word << ":"; + + for (uint16_t *word = (uint16_t *)&locator_hash; + std::size_t(word) < + (std::size_t(&locator_hash) + sizeof(locator_hash)); + word++) { + name_ << ":" << std::hex << *word; + } + + for (uint16_t *word = (uint16_t *)&request_hash; + std::size_t(word) < + (std::size_t(&request_hash) + sizeof(request_hash)); + word++) { + name_ << ":" << std::hex << *word; + } + + name_ << "|0"; + + consumer_.consume(Name(name_.str())); + + consumer_.stop(); + } + + bool verifyData(interface::ConsumerSocket &c, + const core::ContentObject &contentObject) { + if (contentObject.getPayloadType() == PayloadType::CONTENT_OBJECT) { + TRANSPORT_LOGI("VERIFY CONTENT\n"); + } else if (contentObject.getPayloadType() == PayloadType::MANIFEST) { + TRANSPORT_LOGI("VERIFY MANIFEST\n"); + } + + return true; + } + + void processLeavingInterest(interface::ConsumerSocket &c, + const core::Interest &interest) { + if (interest.payloadSize() == 0) { + Interest &int2 = const_cast(interest); + auto payload = request_.getRequestString(); + auto payload2 = request_.getPayload(); + int2.appendPayload((uint8_t *)payload.data(), payload.size()); + if (payload2) + int2.appendPayload((uint8_t *)payload2->data(), payload2->length()); + } + } + + // Read callback + bool isBufferMovable() noexcept override { return true; } + + void getReadBuffer(uint8_t **application_buffer, + size_t *max_length) override {} + + void readDataAvailable(size_t length) noexcept override {} + + size_t maxBufferSize() const override { return max_buffer_capacity; } + + void readBufferAvailable( + std::unique_ptr &&buffer) noexcept override { + if (!read_bytes_callback_) { + response_->appendResponseChunk(std::move(buffer)); + } else { + read_bytes_callback_->onBytesReceived(std::move(buffer)); + } + } + + void readError(const std::error_code ec) noexcept override { + TRANSPORT_LOGE("Error %s during download of %s", ec.message().c_str(), + current_url_.c_str()); + if (read_bytes_callback_) { + read_bytes_callback_->onError(ec); + } + + return_code_ = HTTPClientConnection::RC::DOWNLOAD_FAILED; + } + + void readSuccess(std::size_t total_size) noexcept override { + success_callback_(total_size); + if (read_bytes_callback_) { + read_bytes_callback_->onSuccess(total_size); + } + + return_code_ = HTTPClientConnection::RC::DOWNLOAD_SUCCESS; + } + + HTTPClientConnection *http_client_; + + // The consumer socket + ConsumerSocket consumer_; + + // The current url provided by the application + std::string current_url_; + // The current hICN name used for downloading + std::stringstream name_; + // Function to be called when the read is successful + std::function success_callback_; + // Return code for current download + RC return_code_; + + // Application provided callback for saving the received content during + // the download. If this callback is used, the HTTPClient will NOT save + // any byte internally. + ReadBytesCallback *read_bytes_callback_; + + HTTPRequest request_; + + // Internal read buffer and HTTP response, to be used if the application does + // not provide any read_bytes_callback + std::unique_ptr read_buffer_; + std::shared_ptr response_; + + // Timer + std::unique_ptr timer_; +}; + +HTTPClientConnection::HTTPClientConnection() { + implementation_ = new Implementation(this); +} + +HTTPClientConnection::~HTTPClientConnection() { delete implementation_; } + +HTTPClientConnection::RC HTTPClientConnection::get( + const std::string &url, HTTPHeaders headers, HTTPPayload &&payload, + std::shared_ptr response, ReadBytesCallback *callback, + std::string ipv6_first_word) { + return implementation_->get(url, headers, std::move(payload), response, + callback, ipv6_first_word); +} + +HTTPClientConnection::RC HTTPClientConnection::sendRequest( + const std::string &url, HTTPMethod method, HTTPHeaders headers, + HTTPPayload &&payload, std::shared_ptr response, + ReadBytesCallback *callback, std::string ipv6_first_word) { + return implementation_->sendRequest(url, method, headers, std::move(payload), + response, callback, ipv6_first_word); +} + +std::shared_ptr HTTPClientConnection::response() { + return implementation_->response(); +} + +ConsumerSocket &HTTPClientConnection::getConsumer() { + return implementation_->getConsumer(); +} + +HTTPClientConnection &HTTPClientConnection::stop() { + return implementation_->stop(); +} + +HTTPClientConnection &HTTPClientConnection::setTimeout( + const std::chrono::seconds &timeout) { + return implementation_->setTimeout(timeout); +} + +HTTPClientConnection &HTTPClientConnection::setCertificate( + const std::string &cert_path) { + return implementation_->setCertificate(cert_path); +} + +} // namespace http + +} // namespace transport diff --git a/libtransport/src/http/request.cc b/libtransport/src/http/request.cc new file mode 100644 index 000000000..09f709642 --- /dev/null +++ b/libtransport/src/http/request.cc @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2017-2020 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 +#include + +namespace transport { + +namespace http { + +HTTPRequest::HTTPRequest() {} + +HTTPRequest::HTTPRequest(HTTPMethod method, const std::string &url, + const HTTPHeaders &headers, HTTPPayload &&payload) { + init(method, url, headers, std::move(payload)); +} + +void HTTPRequest::init(HTTPMethod method, const std::string &url, + const HTTPHeaders &headers, HTTPPayload &&payload) { + utils::Uri uri; + uri.parse(url); + + path_ = uri.getPath(); + query_string_ = uri.getQueryString(); + protocol_ = uri.getProtocol(); + locator_ = uri.getLocator(); + port_ = uri.getPort(); + http_version_ = HTTP_VERSION; + + headers_ = headers; + payload_ = std::move(payload); + + std::transform(locator_.begin(), locator_.end(), locator_.begin(), ::tolower); + + std::transform(protocol_.begin(), protocol_.end(), protocol_.begin(), + ::tolower); + + std::stringstream stream; + stream << method_map[method] << " " << uri.getPath() << " HTTP/" + << HTTP_VERSION << "\r\n"; + for (auto &item : headers) { + stream << item.first << ": " << item.second << "\r\n"; + } + stream << "\r\n"; + request_string_ = stream.str(); +} + +std::string HTTPRequest::getPort() const { return port_; } + +std::string HTTPRequest::getLocator() const { return locator_; } + +std::string HTTPRequest::getProtocol() const { return protocol_; } + +std::string HTTPRequest::getPath() const { return path_; } + +std::string HTTPRequest::getQueryString() const { return query_string_; } + +std::string HTTPRequest::getRequestString() const { return request_string_; } + +} // namespace http + +} // namespace transport \ No newline at end of file diff --git a/libtransport/src/http/response.cc b/libtransport/src/http/response.cc new file mode 100644 index 000000000..ba0acd1ac --- /dev/null +++ b/libtransport/src/http/response.cc @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2017-2020 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 +#include + +#include +#include + +#include + +namespace transport { + +namespace http { + +HTTPResponse::HTTPResponse() {} + +HTTPResponse::HTTPResponse(std::unique_ptr &&response) { + parse(std::move(response)); +} + +void HTTPResponse::appendResponseChunk( + std::unique_ptr &&response_chunk) { + if (headers_.empty()) { + parse(std::move(response_chunk)); + } else { + payload_->prependChain(std::move(response_chunk)); + } +} + +bool HTTPResponse::parseHeaders(std::unique_ptr &&buffer) { + auto ret = + HTTPResponse::parseHeaders(buffer->data(), buffer->length(), headers_, + http_version_, status_code_, status_string_); + + if (ret) { + buffer->trimStart(ret); + payload_ = std::move(buffer); + return true; + } + + return false; +} + +std::size_t HTTPResponse::parseHeaders(const uint8_t *buffer, std::size_t size, + HTTPHeaders &headers, + std::string &http_version, + std::string &status_code, + std::string &status_string) { + const char *crlf2 = "\r\n\r\n"; + const char *begin = (const char *)buffer; + const char *end = begin + size; + auto it = + std::experimental::search(begin, end, + std::experimental::make_boyer_moore_searcher( + crlf2, crlf2 + strlen(crlf2))); + + if (it != end) { + std::stringstream ss; + ss.str(std::string(begin, it)); + + std::string line; + getline(ss, line); + std::istringstream line_s(line); + std::string _http_version; + + line_s >> _http_version; + std::size_t separator; + if ((separator = _http_version.find('/')) != std::string::npos) { + if (_http_version.substr(0, separator) != "HTTP") { + return 0; + } + http_version = + line.substr(separator + 1, _http_version.length() - separator - 1); + } else { + return 0; + } + + std::string _status_string; + + line_s >> status_code; + line_s >> _status_string; + + auto _it = std::search(line.begin(), line.end(), status_string.begin(), + status_string.end()); + + status_string = std::string(_it, line.end() - 1); + + std::size_t param_end; + std::size_t value_start; + while (getline(ss, line)) { + if ((param_end = line.find(':')) != std::string::npos) { + value_start = param_end + 1; + if ((value_start) < line.size()) { + if (line[value_start] == ' ') { + value_start++; + } + if (value_start < line.size()) { + headers[line.substr(0, param_end)] = + line.substr(value_start, line.size() - value_start - 1); + } + } + } else { + return 0; + } + } + } + + return it + strlen(crlf2) - begin; +} + +void HTTPResponse::parse(std::unique_ptr &&response) { + if (!parseHeaders(std::move(response))) { + throw errors::RuntimeException("Malformed HTTP response"); + } +} + +const std::string &HTTPResponse::getStatusCode() const { return status_code_; } + +const std::string &HTTPResponse::getStatusString() const { + return status_string_; +} + +} // namespace http + +} // namespace transport \ No newline at end of file diff --git a/libtransport/src/implementation/CMakeLists.txt b/libtransport/src/implementation/CMakeLists.txt new file mode 100644 index 000000000..5423a7697 --- /dev/null +++ b/libtransport/src/implementation/CMakeLists.txt @@ -0,0 +1,46 @@ +# 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) + +list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/rtc_socket_producer.cc +) + +list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/socket.h + ${CMAKE_CURRENT_SOURCE_DIR}/rtc_socket_producer.h + ${CMAKE_CURRENT_SOURCE_DIR}/socket_producer.h + ${CMAKE_CURRENT_SOURCE_DIR}/socket_consumer.h +) + +if (${OPENSSL_VERSION} VERSION_EQUAL "1.1.1a" OR ${OPENSSL_VERSION} VERSION_GREATER "1.1.1a") + list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_producer.cc + ${CMAKE_CURRENT_SOURCE_DIR}/tls_rtc_socket_producer.cc + ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_producer.cc + ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_consumer.cc + ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_consumer.cc + ) + + list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_producer.h + ${CMAKE_CURRENT_SOURCE_DIR}/tls_rtc_socket_producer.h + ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_producer.h + ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_consumer.h + ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_consumer.h + ) +endif() + +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) +set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) diff --git a/libtransport/src/implementation/p2psecure_socket_consumer.cc b/libtransport/src/implementation/p2psecure_socket_consumer.cc new file mode 100644 index 000000000..40ab58161 --- /dev/null +++ b/libtransport/src/implementation/p2psecure_socket_consumer.cc @@ -0,0 +1,403 @@ +/* + * Copyright (c) 2017-2020 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 +#include + +#include +#include +#include + +#include + +namespace transport { +namespace implementation { + +void P2PSecureConsumerSocket::setInterestPayload( + interface::ConsumerSocket &c, const core::Interest &interest) { + Interest &int2 = const_cast(interest); + random_suffix_ = int2.getName().getSuffix(); + + if (payload_ != NULL) int2.appendPayload(std::move(payload_)); +} + +// implement void readBufferAvailable(), size_t maxBufferSize() const override, +// void readError(), void readSuccess(). getReadBuffer() and readDataAvailable() +// must be implemented even if empty. + +/* Return the number of read bytes in the return param */ +int readOld(BIO *b, char *buf, int size) { + if (size < 0) return size; + + P2PSecureConsumerSocket *socket; + socket = (P2PSecureConsumerSocket *)BIO_get_data(b); + + std::unique_lock lck(socket->mtx_); + + if (!socket->something_to_read_) { + if (!socket->transport_protocol_->isRunning()) { + socket->network_name_.setSuffix(socket->random_suffix_); + socket->ConsumerSocket::asyncConsume(socket->network_name_); + } + if (!socket->something_to_read_) socket->cv_.wait(lck); + } + + size_t size_to_read, read; + size_t chain_size = socket->head_->length(); + if (socket->head_->isChained()) + chain_size = socket->head_->computeChainDataLength(); + + if (chain_size > (size_t)size) { + read = size_to_read = (size_t)size; + } else { + read = size_to_read = chain_size; + socket->something_to_read_ = false; + } + + while (size_to_read) { + if (socket->head_->length() < size_to_read) { + std::memcpy(buf, socket->head_->data(), socket->head_->length()); + size_to_read -= socket->head_->length(); + buf += socket->head_->length(); + socket->head_ = socket->head_->pop(); + } else { + std::memcpy(buf, socket->head_->data(), size_to_read); + socket->head_->trimStart(size_to_read); + size_to_read = 0; + } + } + + return read; +} + +/* Return the number of read bytes in readbytes */ +int read(BIO *b, char *buf, size_t size, size_t *readbytes) { + int ret; + + if (size > INT_MAX) size = INT_MAX; + + ret = readOld(b, buf, (int)size); + + if (ret <= 0) { + *readbytes = 0; + return ret; + } + + *readbytes = (size_t)ret; + + return 1; +} + +/* Return the number of written bytes in the return param */ +int writeOld(BIO *b, const char *buf, int num) { + P2PSecureConsumerSocket *socket; + socket = (P2PSecureConsumerSocket *)BIO_get_data(b); + + socket->payload_ = utils::MemBuf::copyBuffer(buf, num); + socket->ConsumerSocket::setSocketOption( + ConsumerCallbacksOptions::INTEREST_OUTPUT, + (ConsumerInterestCallback)std::bind( + &P2PSecureConsumerSocket::setInterestPayload, socket, + std::placeholders::_1, std::placeholders::_2)); + + return num; +} + +/* Return the number of written bytes in written */ +int write(BIO *b, const char *buf, size_t size, size_t *written) { + int ret; + + if (size > INT_MAX) size = INT_MAX; + + ret = writeOld(b, buf, (int)size); + + if (ret <= 0) { + *written = 0; + return ret; + } + + *written = (size_t)ret; + + return 1; +} + +long ctrl(BIO *b, int cmd, long num, void *ptr) { return 1; } + +int P2PSecureConsumerSocket::addHicnKeyIdCb(SSL *s, unsigned int ext_type, + unsigned int context, + const unsigned char **out, + size_t *outlen, X509 *x, + size_t chainidx, int *al, + void *add_arg) { + if (ext_type == 100) { + *out = (unsigned char *)malloc(4); + *(uint32_t *)*out = 10; + *outlen = 4; + } + return 1; +} + +void P2PSecureConsumerSocket::freeHicnKeyIdCb(SSL *s, unsigned int ext_type, + unsigned int context, + const unsigned char *out, + void *add_arg) { + free(const_cast(out)); +} + +int P2PSecureConsumerSocket::parseHicnKeyIdCb(SSL *s, unsigned int ext_type, + unsigned int context, + const unsigned char *in, + size_t inlen, X509 *x, + size_t chainidx, int *al, + void *add_arg) { + P2PSecureConsumerSocket *socket = + reinterpret_cast(add_arg); + if (ext_type == 100) { + memcpy(&socket->secure_prefix_, in, sizeof(ip_prefix_t)); + } + return 1; +} + +P2PSecureConsumerSocket::P2PSecureConsumerSocket( + interface::ConsumerSocket *consumer, int handshake_protocol, + int transport_protocol) + : ConsumerSocket(consumer, transport_protocol), + name_(), + tls_consumer_(), + buf_pool_(), + decrypted_content_(), + payload_(), + head_(), + something_to_read_(false), + content_downloaded_(false), + random_suffix_(), + secure_prefix_(), + producer_namespace_(), + read_callback_decrypted_(), + mtx_(), + cv_(), + protocol_(transport_protocol) { + /* Create the (d)TLS state */ + const SSL_METHOD *meth = TLS_client_method(); + ctx_ = SSL_CTX_new(meth); + + int result = + SSL_CTX_set_ciphersuites(ctx_, + "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_" + "SHA256:TLS_AES_128_GCM_SHA256"); + if (result != 1) { + throw errors::RuntimeException( + "Unable to set cipher list on TLS subsystem. Aborting."); + } + + SSL_CTX_set_min_proto_version(ctx_, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(ctx_, TLS1_3_VERSION); + SSL_CTX_set_verify(ctx_, SSL_VERIFY_NONE, NULL); + SSL_CTX_set_ssl_version(ctx_, meth); + + result = SSL_CTX_add_custom_ext( + ctx_, 100, SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS, + P2PSecureConsumerSocket::addHicnKeyIdCb, + P2PSecureConsumerSocket::freeHicnKeyIdCb, NULL, + P2PSecureConsumerSocket::parseHicnKeyIdCb, this); + + ssl_ = SSL_new(ctx_); + + bio_meth_ = BIO_meth_new(BIO_TYPE_CONNECT, "secure consumer socket"); + BIO_meth_set_read(bio_meth_, readOld); + BIO_meth_set_write(bio_meth_, writeOld); + BIO_meth_set_ctrl(bio_meth_, ctrl); + BIO *bio = BIO_new(bio_meth_); + BIO_set_init(bio, 1); + BIO_set_data(bio, this); + SSL_set_bio(ssl_, bio, bio); + + ConsumerSocket::getSocketOption(MAX_WINDOW_SIZE, old_max_win_); + ConsumerSocket::setSocketOption(MAX_WINDOW_SIZE, (double)1.0); + + ConsumerSocket::getSocketOption(CURRENT_WINDOW_SIZE, old_current_win_); + ConsumerSocket::setSocketOption(CURRENT_WINDOW_SIZE, (double)1.0); + + std::default_random_engine generator; + std::uniform_int_distribution distribution( + 1, std::numeric_limits::max()); + random_suffix_ = 0; + + this->ConsumerSocket::setSocketOption(ConsumerCallbacksOptions::READ_CALLBACK, + this); +}; + +P2PSecureConsumerSocket::~P2PSecureConsumerSocket() { + BIO_meth_free(bio_meth_); + SSL_shutdown(ssl_); +} + +int P2PSecureConsumerSocket::consume(const Name &name) { + if (transport_protocol_->isRunning()) { + return CONSUMER_BUSY; + } + + if ((SSL_in_before(this->ssl_) || SSL_in_init(this->ssl_))) { + ConsumerSocket::setSocketOption(MAX_WINDOW_SIZE, (double)1.0); + network_name_ = producer_namespace_.getRandomName(); + network_name_.setSuffix(0); + int result = SSL_connect(this->ssl_); + ConsumerSocket::setSocketOption(MAX_WINDOW_SIZE, old_max_win_); + ConsumerSocket::setSocketOption(CURRENT_WINDOW_SIZE, old_current_win_); + if (result != 1) + throw errors::RuntimeException("Unable to perform client handshake"); + } + std::shared_ptr prefix_name = std::make_shared( + secure_prefix_.family, + ip_address_get_buffer(&(secure_prefix_.address), secure_prefix_.family)); + std::shared_ptr prefix = + std::make_shared(*prefix_name, secure_prefix_.len); + TLSConsumerSocket tls_consumer(nullptr, this->protocol_, this->ssl_); + tls_consumer.setInterface(new interface::TLSConsumerSocket(&tls_consumer)); + + ConsumerTimerCallback *stats_summary_callback = nullptr; + this->getSocketOption(ConsumerCallbacksOptions::STATS_SUMMARY, + &stats_summary_callback); + + uint32_t lifetime; + this->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, lifetime); + tls_consumer.setSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, + lifetime); + tls_consumer.setSocketOption(ConsumerCallbacksOptions::READ_CALLBACK, + read_callback_decrypted_); + tls_consumer.setSocketOption(ConsumerCallbacksOptions::STATS_SUMMARY, + *stats_summary_callback); + tls_consumer.setSocketOption(GeneralTransportOptions::STATS_INTERVAL, + this->timer_interval_milliseconds_); + tls_consumer.setSocketOption(MAX_WINDOW_SIZE, old_max_win_); + tls_consumer.setSocketOption(CURRENT_WINDOW_SIZE, old_current_win_); + tls_consumer.connect(); + + if (payload_ != NULL) + return tls_consumer.consume((prefix->mapName(name)), std::move(payload_)); + else + return tls_consumer.consume((prefix->mapName(name))); +} + +int P2PSecureConsumerSocket::asyncConsume(const Name &name) { + if ((SSL_in_before(this->ssl_) || SSL_in_init(this->ssl_))) { + ConsumerSocket::setSocketOption(CURRENT_WINDOW_SIZE, (double)1.0); + ConsumerSocket::setSocketOption(MAX_WINDOW_SIZE, (double)1.0); + network_name_ = producer_namespace_.getRandomName(); + network_name_.setSuffix(0); + TRANSPORT_LOGD("Start handshake at %s", network_name_.toString().c_str()); + interface::ConsumerSocket::ReadCallback *on_payload = VOID_HANDLER; + this->getSocketOption(ConsumerCallbacksOptions::READ_CALLBACK, &on_payload); + int result = SSL_connect(this->ssl_); + ConsumerSocket::setSocketOption(MAX_WINDOW_SIZE, old_max_win_); + ConsumerSocket::setSocketOption(CURRENT_WINDOW_SIZE, old_current_win_); + if (result != 1) + throw errors::RuntimeException("Unable to perform client handshake"); + TRANSPORT_LOGD("Handshake performed!"); + } + + std::shared_ptr prefix_name = std::make_shared( + secure_prefix_.family, + ip_address_get_buffer(&(secure_prefix_.address), secure_prefix_.family)); + std::shared_ptr prefix = + std::make_shared(*prefix_name, secure_prefix_.len); + + tls_consumer_ = + std::make_shared(nullptr, this->protocol_, this->ssl_); + tls_consumer_->setInterface( + new interface::TLSConsumerSocket(tls_consumer_.get())); + + ConsumerTimerCallback *stats_summary_callback = nullptr; + this->getSocketOption(ConsumerCallbacksOptions::STATS_SUMMARY, + &stats_summary_callback); + + uint32_t lifetime; + this->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, lifetime); + tls_consumer_->setSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, + lifetime); + tls_consumer_->setSocketOption(ConsumerCallbacksOptions::READ_CALLBACK, + read_callback_decrypted_); + tls_consumer_->setSocketOption(ConsumerCallbacksOptions::STATS_SUMMARY, + *stats_summary_callback); + tls_consumer_->setSocketOption(GeneralTransportOptions::STATS_INTERVAL, + this->timer_interval_milliseconds_); + tls_consumer_->setSocketOption(MAX_WINDOW_SIZE, old_max_win_); + tls_consumer_->setSocketOption(CURRENT_WINDOW_SIZE, old_current_win_); + tls_consumer_->connect(); + + if (payload_ != NULL) + return tls_consumer_->asyncConsume((prefix->mapName(name)), + std::move(payload_)); + else + return tls_consumer_->asyncConsume((prefix->mapName(name))); +} + +void P2PSecureConsumerSocket::registerPrefix(const Prefix &producer_namespace) { + producer_namespace_ = producer_namespace; +} + +int P2PSecureConsumerSocket::setSocketOption( + int socket_option_key, ReadCallback *socket_option_value) { + return rescheduleOnIOService( + socket_option_key, socket_option_value, + [this](int socket_option_key, ReadCallback *socket_option_value) -> int { + switch (socket_option_key) { + case ConsumerCallbacksOptions::READ_CALLBACK: + read_callback_decrypted_ = socket_option_value; + break; + default: + return SOCKET_OPTION_NOT_SET; + } + + return SOCKET_OPTION_SET; + }); +} + +void P2PSecureConsumerSocket::getReadBuffer(uint8_t **application_buffer, + size_t *max_length){}; + +void P2PSecureConsumerSocket::readDataAvailable(size_t length) noexcept {}; + +size_t P2PSecureConsumerSocket::maxBufferSize() const { + return SSL3_RT_MAX_PLAIN_LENGTH; +} + +void P2PSecureConsumerSocket::readBufferAvailable( + std::unique_ptr &&buffer) noexcept { + std::unique_lock lck(this->mtx_); + if (head_) { + head_->prependChain(std::move(buffer)); + } else { + head_ = std::move(buffer); + } + + something_to_read_ = true; + cv_.notify_one(); +} + +void P2PSecureConsumerSocket::readError(const std::error_code ec) noexcept {}; + +void P2PSecureConsumerSocket::readSuccess(std::size_t total_size) noexcept { + std::unique_lock lck(this->mtx_); + content_downloaded_ = true; + something_to_read_ = true; + cv_.notify_one(); +} + +bool P2PSecureConsumerSocket::isBufferMovable() noexcept { return true; } + +} // namespace implementation + +} // namespace transport diff --git a/libtransport/src/implementation/p2psecure_socket_consumer.h b/libtransport/src/implementation/p2psecure_socket_consumer.h new file mode 100644 index 000000000..e2ebaf94e --- /dev/null +++ b/libtransport/src/implementation/p2psecure_socket_consumer.h @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2017-2020 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 + +#include +#include +#include + +namespace transport { +namespace implementation { + +class P2PSecureConsumerSocket : public ConsumerSocket, + public interface::ConsumerSocket::ReadCallback { + /* Return the number of read bytes in readbytes */ + friend int read(BIO *b, char *buf, size_t size, size_t *readbytes); + + /* Return the number of read bytes in the return param */ + friend int readOld(BIO *h, char *buf, int size); + + /* Return the number of written bytes in written */ + friend int write(BIO *b, const char *buf, size_t size, size_t *written); + + /* Return the number of written bytes in the return param */ + friend int writeOld(BIO *h, const char *buf, int num); + + friend long ctrl(BIO *b, int cmd, long num, void *ptr); + + public: + explicit P2PSecureConsumerSocket(interface::ConsumerSocket *consumer, + int handshake_protocol, + int transport_protocol); + + ~P2PSecureConsumerSocket(); + + int consume(const Name &name) override; + + int asyncConsume(const Name &name) override; + + void registerPrefix(const Prefix &producer_namespace); + + int setSocketOption( + int socket_option_key, + interface::ConsumerSocket::ReadCallback *socket_option_value) override; + + using ConsumerSocket::getSocketOption; + using ConsumerSocket::setSocketOption; + + protected: + /* Callback invoked once an interest has been received and its payload + * decrypted */ + ConsumerInterestCallback on_interest_input_decrypted_; + ConsumerInterestCallback on_interest_process_decrypted_; + + private: + Name name_; + std::shared_ptr tls_consumer_; + + /* SSL handle */ + SSL *ssl_; + SSL_CTX *ctx_; + BIO_METHOD *bio_meth_; + + /* Chain of MemBuf to be used as a temporary buffer to pass descypted data + * from the underlying layer to the application */ + utils::ObjectPool buf_pool_; + std::unique_ptr decrypted_content_; + + /* Chain of MemBuf holding the payload to be written into interest or data */ + std::unique_ptr payload_; + + /* Chain of MemBuf holding the data retrieved from the underlying layer */ + std::unique_ptr head_; + + bool something_to_read_; + + bool content_downloaded_; + + double old_max_win_; + + double old_current_win_; + + uint32_t random_suffix_; + + ip_prefix_t secure_prefix_; + + Prefix producer_namespace_; + + interface::ConsumerSocket::ReadCallback *read_callback_decrypted_; + + std::mutex mtx_; + + /* Condition variable for the wait */ + std::condition_variable cv_; + + int protocol_; + + void setInterestPayload(interface::ConsumerSocket &c, + const core::Interest &interest); + + static int addHicnKeyIdCb(SSL *s, unsigned int ext_type, unsigned int context, + const unsigned char **out, size_t *outlen, X509 *x, + size_t chainidx, int *al, void *add_arg); + + static void freeHicnKeyIdCb(SSL *s, unsigned int ext_type, + unsigned int context, const unsigned char *out, + void *add_arg); + + static int parseHicnKeyIdCb(SSL *s, unsigned int ext_type, + unsigned int context, const unsigned char *in, + size_t inlen, X509 *x, size_t chainidx, int *al, + void *add_arg); + + virtual void getReadBuffer(uint8_t **application_buffer, + size_t *max_length) override; + + virtual void readDataAvailable(size_t length) noexcept override; + + virtual size_t maxBufferSize() const override; + + virtual void readBufferAvailable( + std::unique_ptr &&buffer) noexcept override; + + virtual void readError(const std::error_code ec) noexcept override; + + virtual void readSuccess(std::size_t total_size) noexcept override; + virtual bool isBufferMovable() noexcept override; + + int download_content(const Name &name); +}; + +} // namespace implementation + +} // end namespace transport diff --git a/libtransport/src/implementation/p2psecure_socket_producer.cc b/libtransport/src/implementation/p2psecure_socket_producer.cc new file mode 100644 index 000000000..d7161986b --- /dev/null +++ b/libtransport/src/implementation/p2psecure_socket_producer.cc @@ -0,0 +1,404 @@ +/* + * Copyright (c) 2017-2020 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 + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace transport { +namespace implementation { + +/* Workaround to prevent content with expiry time equal to 0 to be lost when + * pushed in the forwarder */ +#define HICN_HANDSHAKE_CONTENT_EXPIRY_TIME 100; + +P2PSecureProducerSocket::P2PSecureProducerSocket( + interface::ProducerSocket *producer_socket) + : ProducerSocket(producer_socket), + mtx_(), + cv_(), + map_secure_producers(), + map_secure_rtc_producers(), + list_secure_producers() {} + +P2PSecureProducerSocket::P2PSecureProducerSocket( + interface::ProducerSocket *producer_socket, bool rtc, + const std::shared_ptr &identity) + : ProducerSocket(producer_socket), + rtc_(rtc), + mtx_(), + cv_(), + map_secure_producers(), + map_secure_rtc_producers(), + list_secure_producers() { + /* + * Setup SSL context (identity and parameter to use TLS 1.3) + */ + der_cert_ = parcKeyStore_GetDEREncodedCertificate( + (identity->getSigner()->getKeyStore())); + der_prk_ = parcKeyStore_GetDEREncodedPrivateKey( + (identity->getSigner()->getKeyStore())); + + int cert_size = parcBuffer_Limit(der_cert_); + int prk_size = parcBuffer_Limit(der_prk_); + const uint8_t *cert = + reinterpret_cast(parcBuffer_Overlay(der_cert_, cert_size)); + const uint8_t *prk = + reinterpret_cast(parcBuffer_Overlay(der_prk_, prk_size)); + cert_509_ = d2i_X509(NULL, &cert, cert_size); + pkey_rsa_ = d2i_AutoPrivateKey(NULL, &prk, prk_size); + + /* + * Set the callback so that when an interest is received we catch it and we + * decrypt the payload before passing it to the application. + */ + ProducerSocket::setSocketOption( + ProducerCallbacksOptions::INTEREST_INPUT, + (ProducerInterestCallback)std::bind( + &P2PSecureProducerSocket::onInterestCallback, this, + std::placeholders::_1, std::placeholders::_2)); +} + +P2PSecureProducerSocket::~P2PSecureProducerSocket() { + if (der_cert_) parcBuffer_Release(&der_cert_); + if (der_prk_) parcBuffer_Release(&der_prk_); +} + +void P2PSecureProducerSocket::onInterestCallback(interface::ProducerSocket &p, + Interest &interest) { + std::unique_lock lck(mtx_); + + TRANSPORT_LOGD("Start handshake at %s", + interest.getName().toString().c_str()); + if (!rtc_) { + auto it = map_secure_producers.find(interest.getName()); + if (it != map_secure_producers.end()) return; + TLSProducerSocket *tls_producer = + new TLSProducerSocket(nullptr, this, interest.getName()); + tls_producer->setInterface(new interface::TLSProducerSocket(tls_producer)); + + tls_producer->on_content_produced_application_ = + this->on_content_produced_application_; + tls_producer->setSocketOption(CONTENT_OBJECT_EXPIRY_TIME, + this->content_object_expiry_time_); + tls_producer->setSocketOption(SIGNER, this->signer_); + tls_producer->setSocketOption(MAKE_MANIFEST, this->making_manifest_); + tls_producer->setSocketOption(DATA_PACKET_SIZE, + (uint32_t)(this->data_packet_size_)); + tls_producer->output_buffer_.setLimit(this->output_buffer_.getLimit()); + map_secure_producers.insert( + {interest.getName(), std::unique_ptr(tls_producer)}); + tls_producer->onInterest(*tls_producer, interest); + tls_producer->async_accept(); + } else { + auto it = map_secure_rtc_producers.find(interest.getName()); + if (it != map_secure_rtc_producers.end()) return; + TLSRTCProducerSocket *tls_producer = + new TLSRTCProducerSocket(nullptr, this, interest.getName()); + tls_producer->setInterface( + new interface::TLSRTCProducerSocket(tls_producer)); + tls_producer->on_content_produced_application_ = + this->on_content_produced_application_; + tls_producer->setSocketOption(CONTENT_OBJECT_EXPIRY_TIME, + this->content_object_expiry_time_); + tls_producer->setSocketOption(SIGNER, this->signer_); + tls_producer->setSocketOption(MAKE_MANIFEST, this->making_manifest_); + tls_producer->setSocketOption(DATA_PACKET_SIZE, + (uint32_t)(this->data_packet_size_)); + tls_producer->output_buffer_.setLimit(this->output_buffer_.getLimit()); + map_secure_rtc_producers.insert( + {interest.getName(), + std::unique_ptr(tls_producer)}); + tls_producer->onInterest(*tls_producer, interest); + tls_producer->async_accept(); + } +} + +void P2PSecureProducerSocket::produce(const uint8_t *buffer, + size_t buffer_size) { + if (!rtc_) { + throw errors::RuntimeException( + "RTC must be the transport protocol to start the production of current " + "data. Aborting."); + } + + std::unique_lock lck(mtx_); + if (list_secure_rtc_producers.empty()) cv_.wait(lck); + + for (auto it = list_secure_rtc_producers.cbegin(); + it != list_secure_rtc_producers.cend(); it++) { + (*it)->produce(utils::MemBuf::copyBuffer(buffer, buffer_size)); + } +} + +uint32_t P2PSecureProducerSocket::produce( + Name content_name, std::unique_ptr &&buffer, bool is_last, + uint32_t start_offset) { + if (rtc_) { + throw errors::RuntimeException( + "RTC transport protocol is not compatible with the production of " + "current data. Aborting."); + } + + std::unique_lock lck(mtx_); + uint32_t segments = 0; + if (list_secure_producers.empty()) cv_.wait(lck); + + for (auto it = list_secure_producers.cbegin(); + it != list_secure_producers.cend(); it++) + segments += + (*it)->produce(content_name, buffer->clone(), is_last, start_offset); + return segments; +} + +uint32_t P2PSecureProducerSocket::produce(Name content_name, + const uint8_t *buffer, + size_t buffer_size, bool is_last, + uint32_t start_offset) { + if (rtc_) { + throw errors::RuntimeException( + "RTC transport protocol is not compatible with the production of " + "current data. Aborting."); + } + + std::unique_lock lck(mtx_); + uint32_t segments = 0; + if (list_secure_producers.empty()) cv_.wait(lck); + + for (auto it = list_secure_producers.cbegin(); + it != list_secure_producers.cend(); it++) + segments += (*it)->produce(content_name, buffer, buffer_size, is_last, + start_offset); + return segments; +} + +void P2PSecureProducerSocket::asyncProduce(const Name &content_name, + const uint8_t *buf, + size_t buffer_size, bool is_last, + uint32_t *start_offset) { + if (rtc_) { + throw errors::RuntimeException( + "RTC transport protocol is not compatible with the production of " + "current data. Aborting."); + } + + std::unique_lock lck(mtx_); + if (list_secure_producers.empty()) cv_.wait(lck); + + for (auto it = list_secure_producers.cbegin(); + it != list_secure_producers.cend(); it++) { + (*it)->asyncProduce(content_name, buf, buffer_size, is_last, start_offset); + } +} + +void P2PSecureProducerSocket::asyncProduce( + Name content_name, std::unique_ptr &&buffer, bool is_last, + uint32_t offset, uint32_t **last_segment) { + if (rtc_) { + throw errors::RuntimeException( + "RTC transport protocol is not compatible with the production of " + "current data. Aborting."); + } + + std::unique_lock lck(mtx_); + if (list_secure_producers.empty()) cv_.wait(lck); + + for (auto it = list_secure_producers.cbegin(); + it != list_secure_producers.cend(); it++) { + (*it)->asyncProduce(content_name, buffer->clone(), is_last, offset, + last_segment); + } +} + +// Socket Option Redefinition to avoid name hiding + +int P2PSecureProducerSocket::setSocketOption( + int socket_option_key, ProducerInterestCallback socket_option_value) { + if (!list_secure_producers.empty()) { + for (auto it = list_secure_producers.cbegin(); + it != list_secure_producers.cend(); it++) + (*it)->setSocketOption(socket_option_key, socket_option_value); + } + + switch (socket_option_key) { + case ProducerCallbacksOptions::INTEREST_INPUT: + on_interest_input_decrypted_ = socket_option_value; + return SOCKET_OPTION_SET; + + case ProducerCallbacksOptions::INTEREST_DROP: + on_interest_dropped_input_buffer_ = socket_option_value; + return SOCKET_OPTION_SET; + + case ProducerCallbacksOptions::INTEREST_PASS: + on_interest_inserted_input_buffer_ = socket_option_value; + return SOCKET_OPTION_SET; + + case ProducerCallbacksOptions::CACHE_HIT: + on_interest_satisfied_output_buffer_ = socket_option_value; + return SOCKET_OPTION_SET; + + case ProducerCallbacksOptions::CACHE_MISS: + on_interest_process_decrypted_ = socket_option_value; + return SOCKET_OPTION_SET; + + default: + return SOCKET_OPTION_NOT_SET; + } +} + +int P2PSecureProducerSocket::setSocketOption( + int socket_option_key, + const std::shared_ptr &socket_option_value) { + if (!list_secure_producers.empty()) + for (auto it = list_secure_producers.cbegin(); + it != list_secure_producers.cend(); it++) + (*it)->setSocketOption(socket_option_key, socket_option_value); + + switch (socket_option_key) { + case GeneralTransportOptions::SIGNER: { + signer_.reset(); + signer_ = socket_option_value; + + return SOCKET_OPTION_SET; + } + default: + return SOCKET_OPTION_NOT_SET; + } +} + +int P2PSecureProducerSocket::setSocketOption(int socket_option_key, + uint32_t socket_option_value) { + if (!list_secure_producers.empty()) { + for (auto it = list_secure_producers.cbegin(); + it != list_secure_producers.cend(); it++) + (*it)->setSocketOption(socket_option_key, socket_option_value); + } + switch (socket_option_key) { + case GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME: + content_object_expiry_time_ = + socket_option_value; // HICN_HANDSHAKE_CONTENT_EXPIRY_TIME; + return SOCKET_OPTION_SET; + } + return ProducerSocket::setSocketOption(socket_option_key, + socket_option_value); +} + +int P2PSecureProducerSocket::setSocketOption(int socket_option_key, + bool socket_option_value) { + if (!list_secure_producers.empty()) + for (auto it = list_secure_producers.cbegin(); + it != list_secure_producers.cend(); it++) + (*it)->setSocketOption(socket_option_key, socket_option_value); + + return ProducerSocket::setSocketOption(socket_option_key, + socket_option_value); +} + +int P2PSecureProducerSocket::setSocketOption(int socket_option_key, + Name *socket_option_value) { + if (!list_secure_producers.empty()) + for (auto it = list_secure_producers.cbegin(); + it != list_secure_producers.cend(); it++) + (*it)->setSocketOption(socket_option_key, socket_option_value); + + return ProducerSocket::setSocketOption(socket_option_key, + socket_option_value); +} + +int P2PSecureProducerSocket::setSocketOption( + int socket_option_key, std::list socket_option_value) { + if (!list_secure_producers.empty()) + for (auto it = list_secure_producers.cbegin(); + it != list_secure_producers.cend(); it++) + (*it)->setSocketOption(socket_option_key, socket_option_value); + + return ProducerSocket::setSocketOption(socket_option_key, + socket_option_value); +} + +int P2PSecureProducerSocket::setSocketOption( + int socket_option_key, ProducerContentObjectCallback socket_option_value) { + if (!list_secure_producers.empty()) + for (auto it = list_secure_producers.cbegin(); + it != list_secure_producers.cend(); it++) + (*it)->setSocketOption(socket_option_key, socket_option_value); + + return ProducerSocket::setSocketOption(socket_option_key, + socket_option_value); +} + +int P2PSecureProducerSocket::setSocketOption( + int socket_option_key, ProducerContentCallback socket_option_value) { + if (!list_secure_producers.empty()) + for (auto it = list_secure_producers.cbegin(); + it != list_secure_producers.cend(); it++) + (*it)->setSocketOption(socket_option_key, socket_option_value); + + switch (socket_option_key) { + case ProducerCallbacksOptions::CONTENT_PRODUCED: + on_content_produced_application_ = socket_option_value; + break; + + default: + return SOCKET_OPTION_NOT_SET; + } + + return SOCKET_OPTION_SET; +} + +int P2PSecureProducerSocket::setSocketOption( + int socket_option_key, HashAlgorithm socket_option_value) { + if (!list_secure_producers.empty()) + for (auto it = list_secure_producers.cbegin(); + it != list_secure_producers.cend(); it++) + (*it)->setSocketOption(socket_option_key, socket_option_value); + + return ProducerSocket::setSocketOption(socket_option_key, + socket_option_value); +} + +int P2PSecureProducerSocket::setSocketOption( + int socket_option_key, utils::CryptoSuite socket_option_value) { + if (!list_secure_producers.empty()) + for (auto it = list_secure_producers.cbegin(); + it != list_secure_producers.cend(); it++) + (*it)->setSocketOption(socket_option_key, socket_option_value); + + return ProducerSocket::setSocketOption(socket_option_key, + socket_option_value); +} + +int P2PSecureProducerSocket::setSocketOption( + int socket_option_key, const std::string &socket_option_value) { + if (!list_secure_producers.empty()) + for (auto it = list_secure_producers.cbegin(); + it != list_secure_producers.cend(); it++) + (*it)->setSocketOption(socket_option_key, socket_option_value); + + return ProducerSocket::setSocketOption(socket_option_key, + socket_option_value); +} + +} // namespace implementation + +} // namespace transport diff --git a/libtransport/src/implementation/p2psecure_socket_producer.h b/libtransport/src/implementation/p2psecure_socket_producer.h new file mode 100644 index 000000000..c2cbf31ac --- /dev/null +++ b/libtransport/src/implementation/p2psecure_socket_producer.h @@ -0,0 +1,130 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace transport { +namespace implementation { + +class P2PSecureProducerSocket : public ProducerSocket { + friend class TLSProducerSocket; + friend class TLSRTCProducerSocket; + + public: + explicit P2PSecureProducerSocket(interface::ProducerSocket *producer_socket); + explicit P2PSecureProducerSocket( + interface::ProducerSocket *producer_socket, bool rtc, + const std::shared_ptr &identity); + ~P2PSecureProducerSocket(); + + void produce(const uint8_t *buffer, size_t buffer_size) override; + + uint32_t produce(Name content_name, const uint8_t *buffer, size_t buffer_size, + bool is_last = true, uint32_t start_offset = 0) override; + + uint32_t produce(Name content_name, std::unique_ptr &&buffer, + bool is_last = true, uint32_t start_offset = 0) override; + + void asyncProduce(Name content_name, std::unique_ptr &&buffer, + bool is_last, uint32_t offset, + uint32_t **last_segment = nullptr) override; + + void asyncProduce(const Name &suffix, const uint8_t *buf, size_t buffer_size, + bool is_last = true, + uint32_t *start_offset = nullptr) override; + + int setSocketOption(int socket_option_key, + ProducerInterestCallback socket_option_value) override; + + int setSocketOption( + int socket_option_key, + const std::shared_ptr &socket_option_value) override; + + int setSocketOption(int socket_option_key, + uint32_t socket_option_value) override; + + int setSocketOption(int socket_option_key, bool socket_option_value) override; + + int setSocketOption(int socket_option_key, + Name *socket_option_value) override; + + int setSocketOption(int socket_option_key, + std::list socket_option_value) override; + + int setSocketOption( + int socket_option_key, + ProducerContentObjectCallback socket_option_value) override; + + int setSocketOption(int socket_option_key, + ProducerContentCallback socket_option_value) override; + + int setSocketOption(int socket_option_key, + HashAlgorithm socket_option_value) override; + + int setSocketOption(int socket_option_key, + utils::CryptoSuite socket_option_value) override; + + int setSocketOption(int socket_option_key, + const std::string &socket_option_value) override; + + using ProducerSocket::getSocketOption; + using ProducerSocket::onInterest; + + protected: + bool rtc_; + /* Callback invoked once an interest has been received and its payload + * decrypted */ + ProducerInterestCallback on_interest_input_decrypted_; + ProducerInterestCallback on_interest_process_decrypted_; + ProducerContentCallback on_content_produced_application_; + + private: + std::mutex mtx_; + + /* Condition variable for the wait */ + std::condition_variable cv_; + + PARCBuffer *der_cert_; + PARCBuffer *der_prk_; + X509 *cert_509_; + EVP_PKEY *pkey_rsa_; + std::unordered_map, + core::hash, core::compare2> + map_secure_producers; + std::unordered_map, + core::hash, core::compare2> + map_secure_rtc_producers; + std::list> list_secure_producers; + std::list> list_secure_rtc_producers; + + void onInterestCallback(interface::ProducerSocket &p, Interest &interest); +}; + +} // namespace implementation + +} // namespace transport diff --git a/libtransport/src/implementation/rtc_socket_producer.cc b/libtransport/src/implementation/rtc_socket_producer.cc new file mode 100644 index 000000000..a5b2b4a0e --- /dev/null +++ b/libtransport/src/implementation/rtc_socket_producer.cc @@ -0,0 +1,352 @@ +/* + * 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. + */ + +#include + +#include +#include +#include + +#define NACK_HEADER_SIZE 8 // bytes +#define TIMESTAMP_LEN 8 // bytes +#define TCP_HEADER_SIZE 20 +#define IP6_HEADER_SIZE 40 +#define INIT_PACKET_PRODUCTION_RATE 100 // pps random value (almost 1Mbps) +#define STATS_INTERVAL_DURATION 500 // ms +#define INTEREST_LIFETIME_REDUCTION_FACTOR 0.8 +#define INACTIVE_TIME \ + 500 // ms without producing before the socket + // is considered inactive +#define MILLI_IN_A_SEC 1000 // ms in a second + +#define HICN_MAX_DATA_SEQ 0xefffffff + +// slow production rate param +#define MIN_PRODUCTION_RATE \ + 10 // in pacekts per sec. this value is computed + // through experiments +#define LIFETIME_FRACTION 0.5 + +// NACK HEADER +// +-----------------------------------------+ +// | 4 bytes: current segment in production | +// +-----------------------------------------+ +// | 4 bytes: production rate (bytes x sec) | +// +-----------------------------------------+ +// + +// PACKET HEADER +// +-----------------------------------------+ +// | 8 bytes: TIMESTAMP | +// +-----------------------------------------+ +// | packet | +// +-----------------------------------------+ + +namespace transport { +namespace implementation { + +RTCProducerSocket::RTCProducerSocket(interface::ProducerSocket *producer_socket) + : ProducerSocket(producer_socket), + currentSeg_(1), + producedBytes_(0), + producedPackets_(0), + bytesProductionRate_(INIT_PACKET_PRODUCTION_RATE * 1400), + packetsProductionRate_(INIT_PACKET_PRODUCTION_RATE), + perSecondFactor_(MILLI_IN_A_SEC / STATS_INTERVAL_DURATION), + timer_on_(false) { + srand((unsigned int)time(NULL)); + prodLabel_ = ((rand() % 255) << 24UL); + interests_cache_timer_ = + std::make_unique(this->getIoService()); + round_timer_ = std::make_unique(this->getIoService()); + setSocketOption(GeneralTransportOptions::OUTPUT_BUFFER_SIZE, 10000U); + scheduleRoundTimer(); +} + +RTCProducerSocket::~RTCProducerSocket() {} + +void RTCProducerSocket::registerPrefix(const Prefix &producer_namespace) { + ProducerSocket::registerPrefix(producer_namespace); + + flowName_ = producer_namespace.getName(); + 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."); + } +} + +void RTCProducerSocket::scheduleRoundTimer() { + round_timer_->expires_from_now( + std::chrono::milliseconds(STATS_INTERVAL_DURATION)); + round_timer_->async_wait([this](std::error_code ec) { + if (ec) return; + updateStats(); + }); +} + +void RTCProducerSocket::updateStats() { + bytesProductionRate_ = producedBytes_.load() * perSecondFactor_; + packetsProductionRate_ = producedPackets_.load() * perSecondFactor_; + if (packetsProductionRate_.load() == 0) packetsProductionRate_ = 1; + producedBytes_ = 0; + producedPackets_ = 0; + scheduleRoundTimer(); +} + +void RTCProducerSocket::produce(std::unique_ptr &&buffer) { + auto buffer_size = buffer->length(); + + if (TRANSPORT_EXPECT_FALSE(buffer_size == 0)) { + return; + } + + if (TRANSPORT_EXPECT_FALSE((buffer_size + headerSize_ + TIMESTAMP_LEN) > + data_packet_size_)) { + return; + } + + uint64_t now = std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()) + .count(); + + producedBytes_ += (uint32_t)(buffer_size + headerSize_ + TIMESTAMP_LEN); + producedPackets_++; + + Name n(flowName_); + auto content_object = + std::make_shared(n.setSuffix(currentSeg_.load())); + auto payload = utils::MemBuf::create(TIMESTAMP_LEN); + + memcpy(payload->writableData(), &now, TIMESTAMP_LEN); + payload->append(TIMESTAMP_LEN); + payload->prependChain(std::move(buffer)); + content_object->appendPayload(std::move(payload)); + + content_object->setLifetime(500); // XXX this should be set by the APP + + content_object->setPathLabel(prodLabel_); + + output_buffer_.insert(std::static_pointer_cast( + content_object->shared_from_this())); + + if (on_content_object_in_output_buffer_) { + on_content_object_in_output_buffer_(*getInterface(), *content_object); + } + + TRANSPORT_LOGD("Send content %u (produce)", + content_object->getName().getSuffix()); + portal_->sendContentObject(*content_object); + + if (on_content_object_output_) { + on_content_object_output_(*getInterface(), *content_object); + } + + uint32_t old_curr = currentSeg_.load(); + currentSeg_ = (currentSeg_.load() + 1) % HICN_MAX_DATA_SEQ; + + // remove interests from the interest cache if it exists + // this generates nacks that will tell to the consumer + // that a new data packet was produced + utils::SpinLock::Acquire locked(interests_cache_lock_); + if (!seqs_map_.empty()) { + for (auto it = seqs_map_.begin(); it != seqs_map_.end(); it++) { + if (it->first != old_curr) sendNack(it->first); + } + seqs_map_.clear(); + timers_map_.clear(); + } +} + +void RTCProducerSocket::onInterest(Interest::Ptr &&interest) { + uint32_t interestSeg = interest->getName().getSuffix(); + uint32_t lifetime = interest->getLifetime(); + + if (on_interest_input_) { + on_interest_input_(*getInterface(), *interest); + } + + uint64_t now = std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()) + .count(); + + if (interestSeg > HICN_MAX_DATA_SEQ) { + sendNack(interestSeg); + return; + } + + const std::shared_ptr content_object = + output_buffer_.find(*interest); + + if (content_object) { + if (on_interest_satisfied_output_buffer_) { + on_interest_satisfied_output_buffer_(*getInterface(), *interest); + } + + if (on_content_object_output_) { + on_content_object_output_(*getInterface(), *content_object); + } + + TRANSPORT_LOGD("Send content %u (onInterest)", + content_object->getName().getSuffix()); + portal_->sendContentObject(*content_object); + return; + } else { + if (on_interest_process_) { + on_interest_process_(*getInterface(), *interest); + } + } + + // if the production rate is less than MIN_PRODUCTION_RATE we put the + // interest in a queue, otherwise we handle it in the usual way + if (packetsProductionRate_.load() < MIN_PRODUCTION_RATE && + interestSeg >= currentSeg_.load()) { + utils::SpinLock::Acquire locked(interests_cache_lock_); + + uint64_t next_timer = ~0; + if (!timers_map_.empty()) { + next_timer = timers_map_.begin()->first; + } + + uint64_t expiration = now + (lifetime * LIFETIME_FRACTION); + // check if the seq number exists already + auto it_seqs = seqs_map_.find(interestSeg); + if (it_seqs != seqs_map_.end()) { + // the seq already exists + if (expiration < it_seqs->second) { + // we need to update the timer becasue we got a smaller one + // 1) remove the entry from the multimap + // 2) update this entry + auto range = timers_map_.equal_range(it_seqs->second); + for (auto it_timers = range.first; it_timers != range.second; + it_timers++) { + if (it_timers->second == it_seqs->first) { + timers_map_.erase(it_timers); + break; + } + } + timers_map_.insert( + std::pair(expiration, interestSeg)); + it_seqs->second = expiration; + } else { + // nothing to do here + return; + } + } else { + // add the new seq + timers_map_.insert( + std::pair(expiration, interestSeg)); + seqs_map_.insert(std::pair(interestSeg, expiration)); + } + + // here we have at least one interest in the queue, we need to start or + // update the timer + if (!timer_on_) { + // set timeout + timer_on_ = true; + scheduleCacheTimer(timers_map_.begin()->first - now); + } else { + // re-schedule the timer because a new interest will expires sooner + if (next_timer > timers_map_.begin()->first) { + interests_cache_timer_->cancel(); + scheduleCacheTimer(timers_map_.begin()->first - now); + } + } + return; + } + + uint32_t max_gap = (uint32_t)floor( + (double)((double)((double)lifetime * INTEREST_LIFETIME_REDUCTION_FACTOR / + 1000.0) * + (double)packetsProductionRate_.load())); + + if (interestSeg < currentSeg_.load() || + interestSeg > (max_gap + currentSeg_.load())) { + sendNack(interestSeg); + } + // else drop packet +} + +void RTCProducerSocket::scheduleCacheTimer(uint64_t wait) { + interests_cache_timer_->expires_from_now(std::chrono::milliseconds(wait)); + interests_cache_timer_->async_wait([this](std::error_code ec) { + if (ec) return; + interestCacheTimer(); + }); +} + +void RTCProducerSocket::interestCacheTimer() { + uint64_t now = std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()) + .count(); + + utils::SpinLock::Acquire locked(interests_cache_lock_); + + for (auto it_timers = timers_map_.begin(); it_timers != timers_map_.end();) { + uint64_t expire = it_timers->first; + if (expire <= now) { + uint32_t seq = it_timers->second; + sendNack(seq); + // remove the interest from the other map + seqs_map_.erase(seq); + it_timers = timers_map_.erase(it_timers); + } else { + // stop, we are done! + break; + } + } + if (timers_map_.empty()) { + timer_on_ = false; + } else { + timer_on_ = true; + scheduleCacheTimer(timers_map_.begin()->first - now); + } +} + +void RTCProducerSocket::sendNack(uint32_t sequence) { + auto nack_payload = utils::MemBuf::create(NACK_HEADER_SIZE); + nack_payload->append(NACK_HEADER_SIZE); + ContentObject nack; + + Name n(flowName_); + nack.appendPayload(std::move(nack_payload)); + nack.setName(n.setSuffix(sequence)); + + uint32_t *payload_ptr = (uint32_t *)nack.getPayload()->data(); + *payload_ptr = currentSeg_.load(); + + *(++payload_ptr) = bytesProductionRate_.load(); + + nack.setLifetime(0); + nack.setPathLabel(prodLabel_); + + if (on_content_object_output_) { + on_content_object_output_(*getInterface(), nack); + } + + TRANSPORT_LOGD("Send nack %u", sequence); + portal_->sendContentObject(nack); +} + +} // namespace implementation + +} // end namespace transport diff --git a/libtransport/src/implementation/rtc_socket_producer.h b/libtransport/src/implementation/rtc_socket_producer.h new file mode 100644 index 000000000..87db2121d --- /dev/null +++ b/libtransport/src/implementation/rtc_socket_producer.h @@ -0,0 +1,74 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +#include +#include +#include + +namespace transport { +namespace implementation { + +class RTCProducerSocket : virtual public ProducerSocket { + public: + RTCProducerSocket(interface::ProducerSocket *producer_socket); + + ~RTCProducerSocket(); + + void registerPrefix(const Prefix &producer_namespace) override; + void produce(std::unique_ptr &&buffer) override; + + private: + void onInterest(Interest::Ptr &&interest) override; + void sendNack(uint32_t sequence); + void updateStats(); + void scheduleCacheTimer(uint64_t wait); + void scheduleRoundTimer(); + void interestCacheTimer(); + + std::atomic currentSeg_; + uint32_t prodLabel_; + uint16_t headerSize_; + Name flowName_; + std::atomic producedBytes_; + std::atomic producedPackets_; + std::atomic bytesProductionRate_; + std::atomic packetsProductionRate_; + uint32_t perSecondFactor_; + + std::unique_ptr round_timer_; + + // cache for the received interests + // this map maps the expiration time of an interest to + // its sequence number. the map is sorted by timeouts + // the same timeout may be used for multiple sequence numbers + // but for each sequence number we store only the smallest + // expiry time. In this way the mapping from seqs_map_ to + // timers_map_ is unique + std::multimap timers_map_; + // this map does the opposite, this map is not ordered + std::unordered_map seqs_map_; + bool timer_on_; + std::unique_ptr interests_cache_timer_; + utils::SpinLock interests_cache_lock_; +}; + +} // namespace implementation + +} // end namespace transport diff --git a/libtransport/src/implementation/socket.h b/libtransport/src/implementation/socket.h new file mode 100644 index 000000000..2e51f3027 --- /dev/null +++ b/libtransport/src/implementation/socket.h @@ -0,0 +1,89 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include + +#include + +#define SOCKET_OPTION_GET 0 +#define SOCKET_OPTION_NOT_GET 1 +#define SOCKET_OPTION_SET 2 +#define SOCKET_OPTION_NOT_SET 3 +#define SOCKET_OPTION_DEFAULT 12345 + +namespace transport { +namespace implementation { + +// Forward Declarations +template +class Socket; + +// Define the portal and its connector, depending on the compilation options +// passed by the build tool. +using HicnForwarderPortal = core::HicnForwarderPortal; + +#ifdef __linux__ +#ifndef __ANDROID__ +using RawSocketPortal = core::RawSocketPortal; +#endif +#endif + +#ifdef __vpp__ +using VPPForwarderPortal = core::VPPForwarderPortal; +using BaseSocket = Socket; +using BasePortal = VPPForwarderPortal; +#else +using BaseSocket = Socket; +using BasePortal = HicnForwarderPortal; +#endif + +template +class Socket { + static_assert(std::is_same::value +#ifdef __linux__ +#ifndef __ANDROID__ + || std::is_same::value +#ifdef __vpp__ + || std::is_same::value +#endif +#endif + , +#else + , + +#endif + "This class is not allowed as Portal"); + + public: + using Portal = PortalType; + + virtual asio::io_service &getIoService() = 0; + + virtual void connect() = 0; + + virtual bool isRunning() = 0; + + protected: + virtual ~Socket(){}; +}; + +} // namespace implementation + +} // namespace transport diff --git a/libtransport/src/implementation/socket_consumer.h b/libtransport/src/implementation/socket_consumer.h new file mode 100644 index 000000000..2fc8d2b48 --- /dev/null +++ b/libtransport/src/implementation/socket_consumer.h @@ -0,0 +1,950 @@ +/* + * Copyright (c) 2020 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 +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace transport { +namespace implementation { + +using namespace core; +using namespace interface; +using ReadCallback = interface::ConsumerSocket::ReadCallback; + +class ConsumerSocket : public Socket { + public: + ConsumerSocket(interface::ConsumerSocket *consumer, int protocol) + : consumer_interface_(consumer), + portal_(std::make_shared(io_service_)), + async_downloader_(), + interest_lifetime_(default_values::interest_lifetime), + min_window_size_(default_values::min_window_size), + max_window_size_(default_values::max_window_size), + current_window_size_(-1), + max_retransmissions_( + default_values::transport_protocol_max_retransmissions), + /****** RAAQM Parameters ******/ + minimum_drop_probability_(default_values::minimum_drop_probability), + sample_number_(default_values::sample_number), + gamma_(default_values::gamma_value), + beta_(default_values::beta_value), + drop_factor_(default_values::drop_factor), + /****** END RAAQM Parameters ******/ + rate_estimation_alpha_(default_values::rate_alpha), + rate_estimation_observer_(nullptr), + rate_estimation_batching_parameter_(default_values::batch), + rate_estimation_choice_(0), + verifier_(std::make_shared()), + verify_signature_(false), + key_content_(false), + on_interest_output_(VOID_HANDLER), + on_interest_timeout_(VOID_HANDLER), + on_interest_satisfied_(VOID_HANDLER), + on_content_object_input_(VOID_HANDLER), + on_content_object_verification_(VOID_HANDLER), + on_content_object_(VOID_HANDLER), + stats_summary_(VOID_HANDLER), + read_callback_(nullptr), + virtual_download_(false), + timer_interval_milliseconds_(0), + guard_raaqm_params_() { + switch (protocol) { + case TransportProtocolAlgorithms::CBR: + transport_protocol_ = + std::make_unique(this); + break; + case TransportProtocolAlgorithms::RTC: + transport_protocol_ = + std::make_unique(this); + break; + case TransportProtocolAlgorithms::RAAQM: + default: + transport_protocol_ = + std::make_unique(this); + break; + } + } + + ~ConsumerSocket() { + stop(); + async_downloader_.stop(); + } + + interface::ConsumerSocket *getInterface() { + return consumer_interface_; + } + + void setInterface(interface::ConsumerSocket *consumer_socket) { + consumer_interface_ = consumer_socket; + } + + void connect() { portal_->connect(); } + + bool isRunning() { return transport_protocol_->isRunning(); } + + virtual int consume(const Name &name) { + if (transport_protocol_->isRunning()) { + return CONSUMER_BUSY; + } + + network_name_ = name; + network_name_.setSuffix(0); + + transport_protocol_->start(); + + return CONSUMER_FINISHED; + } + + virtual int asyncConsume(const Name &name) { + if (!async_downloader_.stopped()) { + async_downloader_.add([this, name]() { + network_name_ = std::move(name); + network_name_.setSuffix(0); + transport_protocol_->start(); + }); + } + + return CONSUMER_RUNNING; + } + + bool verifyKeyPackets() { return transport_protocol_->verifyKeyPackets(); } + + void stop() { + if (transport_protocol_->isRunning()) { + transport_protocol_->stop(); + } + } + + void resume() { + if (!transport_protocol_->isRunning()) { + transport_protocol_->resume(); + } + } + + asio::io_service &getIoService() { return portal_->getIoService(); } + + virtual int setSocketOption(int socket_option_key, + ReadCallback *socket_option_value) { + // Reschedule the function on the io_service to avoid race condition in + // case setSocketOption is called while the io_service is running. + return rescheduleOnIOService( + socket_option_key, socket_option_value, + [this](int socket_option_key, + ReadCallback *socket_option_value) -> int { + switch (socket_option_key) { + case ConsumerCallbacksOptions::READ_CALLBACK: + read_callback_ = socket_option_value; + break; + default: + return SOCKET_OPTION_NOT_SET; + } + + return SOCKET_OPTION_SET; + }); + } + + int getSocketOption(int socket_option_key, + ReadCallback **socket_option_value) { + // Reschedule the function on the io_service to avoid race condition in + // case setSocketOption is called while the io_service is running. + return rescheduleOnIOService( + socket_option_key, socket_option_value, + [this](int socket_option_key, + ReadCallback **socket_option_value) -> int { + switch (socket_option_key) { + case ConsumerCallbacksOptions::READ_CALLBACK: + *socket_option_value = read_callback_; + break; + default: + return SOCKET_OPTION_NOT_GET; + } + + return SOCKET_OPTION_GET; + }); + } + + int setSocketOption(int socket_option_key, double socket_option_value) { + utils::SpinLock::Acquire locked(guard_raaqm_params_); + switch (socket_option_key) { + case MIN_WINDOW_SIZE: + min_window_size_ = socket_option_value; + break; + + case MAX_WINDOW_SIZE: + max_window_size_ = socket_option_value; + break; + + case CURRENT_WINDOW_SIZE: + current_window_size_ = socket_option_value; + break; + + case GAMMA_VALUE: + gamma_ = socket_option_value; + break; + + case BETA_VALUE: + beta_ = socket_option_value; + break; + + case DROP_FACTOR: + drop_factor_ = socket_option_value; + break; + + case MINIMUM_DROP_PROBABILITY: + minimum_drop_probability_ = socket_option_value; + break; + + case RATE_ESTIMATION_ALPHA: + if (socket_option_value >= 0 && socket_option_value < 1) { + rate_estimation_alpha_ = socket_option_value; + } else { + rate_estimation_alpha_ = default_values::alpha; + } + break; + default: + return SOCKET_OPTION_NOT_SET; + } + + return SOCKET_OPTION_SET; + } + + int setSocketOption(int socket_option_key, uint32_t socket_option_value) { + utils::SpinLock::Acquire locked(guard_raaqm_params_); + switch (socket_option_key) { + case GeneralTransportOptions::MAX_INTEREST_RETX: + max_retransmissions_ = socket_option_value; + break; + + case GeneralTransportOptions::INTEREST_LIFETIME: + interest_lifetime_ = socket_option_value; + break; + + case RateEstimationOptions::RATE_ESTIMATION_BATCH_PARAMETER: + if (socket_option_value > 0) { + rate_estimation_batching_parameter_ = socket_option_value; + } else { + rate_estimation_batching_parameter_ = default_values::batch; + } + break; + + case RateEstimationOptions::RATE_ESTIMATION_CHOICE: + if (socket_option_value > 0) { + rate_estimation_choice_ = socket_option_value; + } else { + rate_estimation_choice_ = default_values::rate_choice; + } + break; + + case GeneralTransportOptions::STATS_INTERVAL: + timer_interval_milliseconds_ = socket_option_value; + break; + + default: + return SOCKET_OPTION_NOT_SET; + } + + return SOCKET_OPTION_SET; + } + + int setSocketOption(int socket_option_key, + std::nullptr_t socket_option_value) { + // Reschedule the function on the io_service to avoid race condition in + // case setSocketOption is called while the io_service is running. + return rescheduleOnIOService( + socket_option_key, socket_option_value, + [this](int socket_option_key, + std::nullptr_t socket_option_value) -> int { + switch (socket_option_key) { + case ConsumerCallbacksOptions::INTEREST_RETRANSMISSION: + if (socket_option_value == VOID_HANDLER) { + on_interest_retransmission_ = VOID_HANDLER; + break; + } + + case ConsumerCallbacksOptions::INTEREST_EXPIRED: + if (socket_option_value == VOID_HANDLER) { + on_interest_timeout_ = VOID_HANDLER; + break; + } + + case ConsumerCallbacksOptions::INTEREST_SATISFIED: + if (socket_option_value == VOID_HANDLER) { + on_interest_satisfied_ = VOID_HANDLER; + break; + } + + case ConsumerCallbacksOptions::INTEREST_OUTPUT: + if (socket_option_value == VOID_HANDLER) { + on_interest_output_ = VOID_HANDLER; + break; + } + + case ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT: + if (socket_option_value == VOID_HANDLER) { + on_content_object_input_ = VOID_HANDLER; + break; + } + + case ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY: + if (socket_option_value == VOID_HANDLER) { + on_content_object_verification_ = VOID_HANDLER; + break; + } + + default: + return SOCKET_OPTION_NOT_SET; + } + + return SOCKET_OPTION_SET; + }); + } + + int setSocketOption(int socket_option_key, bool socket_option_value) { + int result = SOCKET_OPTION_NOT_SET; + if (!transport_protocol_->isRunning()) { + switch (socket_option_key) { + case OtherOptions::VIRTUAL_DOWNLOAD: + virtual_download_ = socket_option_value; + result = SOCKET_OPTION_SET; + break; + + case GeneralTransportOptions::VERIFY_SIGNATURE: + verify_signature_ = socket_option_value; + result = SOCKET_OPTION_SET; + break; + + case GeneralTransportOptions::KEY_CONTENT: + key_content_ = socket_option_value; + result = SOCKET_OPTION_SET; + break; + + default: + return result; + } + } + return result; + } + + int setSocketOption(int socket_option_key, + ConsumerContentObjectCallback socket_option_value) { + // Reschedule the function on the io_service to avoid race condition in + // case setSocketOption is called while the io_service is running. + return rescheduleOnIOService( + socket_option_key, socket_option_value, + [this](int socket_option_key, + ConsumerContentObjectCallback socket_option_value) -> int { + switch (socket_option_key) { + case ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT: + on_content_object_input_ = socket_option_value; + break; + + default: + return SOCKET_OPTION_NOT_SET; + } + + return SOCKET_OPTION_SET; + }); + } + + int setSocketOption( + int socket_option_key, + ConsumerContentObjectVerificationCallback socket_option_value) { + // Reschedule the function on the io_service to avoid race condition in + // case setSocketOption is called while the io_service is running. + return rescheduleOnIOService( + socket_option_key, socket_option_value, + [this](int socket_option_key, + ConsumerContentObjectVerificationCallback socket_option_value) + -> int { + switch (socket_option_key) { + case ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY: + on_content_object_verification_ = socket_option_value; + break; + + default: + return SOCKET_OPTION_NOT_SET; + } + + return SOCKET_OPTION_SET; + }); + } + + int setSocketOption(int socket_option_key, + ConsumerInterestCallback socket_option_value) { + // Reschedule the function on the io_service to avoid race condition in + // case setSocketOption is called while the io_service is running. + return rescheduleOnIOService( + socket_option_key, socket_option_value, + [this](int socket_option_key, + ConsumerInterestCallback socket_option_value) -> int { + switch (socket_option_key) { + case ConsumerCallbacksOptions::INTEREST_RETRANSMISSION: + on_interest_retransmission_ = socket_option_value; + break; + + case ConsumerCallbacksOptions::INTEREST_OUTPUT: + on_interest_output_ = socket_option_value; + break; + + case ConsumerCallbacksOptions::INTEREST_EXPIRED: + on_interest_timeout_ = socket_option_value; + break; + + case ConsumerCallbacksOptions::INTEREST_SATISFIED: + on_interest_satisfied_ = socket_option_value; + break; + + default: + return SOCKET_OPTION_NOT_SET; + } + + return SOCKET_OPTION_SET; + }); + } + + int setSocketOption( + int socket_option_key, + ConsumerContentObjectVerificationFailedCallback socket_option_value) { + return rescheduleOnIOService( + socket_option_key, socket_option_value, + [this]( + int socket_option_key, + ConsumerContentObjectVerificationFailedCallback socket_option_value) + -> int { + switch (socket_option_key) { + case ConsumerCallbacksOptions::VERIFICATION_FAILED: + verification_failed_callback_ = socket_option_value; + break; + + default: + return SOCKET_OPTION_NOT_SET; + } + + return SOCKET_OPTION_SET; + }); + } + + // int setSocketOption( + // int socket_option_key, + // ConsumerContentObjectVerificationFailedCallback socket_option_value) { + // return rescheduleOnIOService( + // socket_option_key, socket_option_value, + // [this]( + // int socket_option_key, + // ConsumerContentObjectVerificationFailedCallback + // socket_option_value) + // -> int { + // switch (socket_option_key) { + // case ConsumerCallbacksOptions::VERIFICATION_FAILED: + // verification_failed_callback_ = socket_option_value; + // break; + + // default: + // return SOCKET_OPTION_NOT_SET; + // } + + // return SOCKET_OPTION_SET; + // }); + // } + + int setSocketOption(int socket_option_key, IcnObserver *socket_option_value) { + utils::SpinLock::Acquire locked(guard_raaqm_params_); + switch (socket_option_key) { + case RateEstimationOptions::RATE_ESTIMATION_OBSERVER: + rate_estimation_observer_ = socket_option_value; + break; + + default: + return SOCKET_OPTION_NOT_SET; + } + + return SOCKET_OPTION_SET; + } + + int setSocketOption( + int socket_option_key, + const std::shared_ptr &socket_option_value) { + int result = SOCKET_OPTION_NOT_SET; + if (!transport_protocol_->isRunning()) { + switch (socket_option_key) { + case GeneralTransportOptions::VERIFIER: + verifier_.reset(); + verifier_ = socket_option_value; + result = SOCKET_OPTION_SET; + break; + default: + return result; + } + } + + return result; + } + + int setSocketOption(int socket_option_key, + const std::string &socket_option_value) { + int result = SOCKET_OPTION_NOT_SET; + if (!transport_protocol_->isRunning()) { + switch (socket_option_key) { + case GeneralTransportOptions::CERTIFICATE: + key_id_ = verifier_->addKeyFromCertificate(socket_option_value); + + if (key_id_ != nullptr) { + result = SOCKET_OPTION_SET; + } + break; + + case DataLinkOptions::OUTPUT_INTERFACE: + output_interface_ = socket_option_value; + portal_->setOutputInterface(output_interface_); + result = SOCKET_OPTION_SET; + break; + + default: + return result; + } + } + return result; + } + + int setSocketOption(int socket_option_key, + ConsumerTimerCallback socket_option_value) { + // Reschedule the function on the io_service to avoid race condition in + // case setSocketOption is called while the io_service is running. + return rescheduleOnIOService( + socket_option_key, socket_option_value, + [this](int socket_option_key, + ConsumerTimerCallback socket_option_value) -> int { + switch (socket_option_key) { + case ConsumerCallbacksOptions::STATS_SUMMARY: + stats_summary_ = socket_option_value; + break; + + default: + return SOCKET_OPTION_NOT_SET; + } + + return SOCKET_OPTION_SET; + }); + } + + int getSocketOption(int socket_option_key, double &socket_option_value) { + utils::SpinLock::Acquire locked(guard_raaqm_params_); + switch (socket_option_key) { + case GeneralTransportOptions::MIN_WINDOW_SIZE: + socket_option_value = min_window_size_; + break; + + case GeneralTransportOptions::MAX_WINDOW_SIZE: + socket_option_value = max_window_size_; + break; + + case GeneralTransportOptions::CURRENT_WINDOW_SIZE: + socket_option_value = current_window_size_; + break; + + // RAAQM parameters + + case RaaqmTransportOptions::GAMMA_VALUE: + socket_option_value = gamma_; + break; + + case RaaqmTransportOptions::BETA_VALUE: + socket_option_value = beta_; + break; + + case RaaqmTransportOptions::DROP_FACTOR: + socket_option_value = drop_factor_; + break; + + case RaaqmTransportOptions::MINIMUM_DROP_PROBABILITY: + socket_option_value = minimum_drop_probability_; + break; + + case RateEstimationOptions::RATE_ESTIMATION_ALPHA: + socket_option_value = rate_estimation_alpha_; + break; + + default: + return SOCKET_OPTION_NOT_GET; + } + + return SOCKET_OPTION_GET; + } + + int getSocketOption(int socket_option_key, uint32_t &socket_option_value) { + utils::SpinLock::Acquire locked(guard_raaqm_params_); + switch (socket_option_key) { + case GeneralTransportOptions::MAX_INTEREST_RETX: + socket_option_value = max_retransmissions_; + break; + + case GeneralTransportOptions::INTEREST_LIFETIME: + socket_option_value = interest_lifetime_; + break; + + case RaaqmTransportOptions::SAMPLE_NUMBER: + socket_option_value = sample_number_; + break; + + case RateEstimationOptions::RATE_ESTIMATION_BATCH_PARAMETER: + socket_option_value = rate_estimation_batching_parameter_; + break; + + case RateEstimationOptions::RATE_ESTIMATION_CHOICE: + socket_option_value = rate_estimation_choice_; + break; + + case GeneralTransportOptions::STATS_INTERVAL: + socket_option_value = timer_interval_milliseconds_; + break; + + default: + return SOCKET_OPTION_NOT_GET; + } + + return SOCKET_OPTION_GET; + } + + int getSocketOption(int socket_option_key, bool &socket_option_value) { + switch (socket_option_key) { + case GeneralTransportOptions::RUNNING: + socket_option_value = transport_protocol_->isRunning(); + break; + + case OtherOptions::VIRTUAL_DOWNLOAD: + socket_option_value = virtual_download_; + break; + + case GeneralTransportOptions::VERIFY_SIGNATURE: + socket_option_value = verify_signature_; + break; + + case GeneralTransportOptions::KEY_CONTENT: + socket_option_value = key_content_; + break; + + default: + return SOCKET_OPTION_NOT_GET; + } + + return SOCKET_OPTION_GET; + } + + int getSocketOption(int socket_option_key, Name **socket_option_value) { + switch (socket_option_key) { + case GeneralTransportOptions::NETWORK_NAME: + *socket_option_value = &network_name_; + break; + + default: + return SOCKET_OPTION_NOT_GET; + } + + return SOCKET_OPTION_GET; + } + + int getSocketOption(int socket_option_key, + ConsumerContentObjectCallback **socket_option_value) { + // Reschedule the function on the io_service to avoid race condition in + // case setSocketOption is called while the io_service is running. + return rescheduleOnIOService( + socket_option_key, socket_option_value, + [this](int socket_option_key, + ConsumerContentObjectCallback **socket_option_value) -> int { + switch (socket_option_key) { + case ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT: + *socket_option_value = &on_content_object_input_; + break; + + default: + return SOCKET_OPTION_NOT_GET; + } + + return SOCKET_OPTION_GET; + }); + } + + int getSocketOption( + int socket_option_key, + ConsumerContentObjectVerificationCallback **socket_option_value) { + // Reschedule the function on the io_service to avoid race condition in + // case setSocketOption is called while the io_service is running. + return rescheduleOnIOService( + socket_option_key, socket_option_value, + [this](int socket_option_key, + ConsumerContentObjectVerificationCallback **socket_option_value) + -> int { + switch (socket_option_key) { + case ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY: + *socket_option_value = &on_content_object_verification_; + break; + + default: + return SOCKET_OPTION_NOT_GET; + } + + return SOCKET_OPTION_GET; + }); + } + + int getSocketOption(int socket_option_key, + ConsumerInterestCallback **socket_option_value) { + // Reschedule the function on the io_service to avoid race condition in + // case setSocketOption is called while the io_service is running. + return rescheduleOnIOService( + socket_option_key, socket_option_value, + [this](int socket_option_key, + ConsumerInterestCallback **socket_option_value) -> int { + switch (socket_option_key) { + case ConsumerCallbacksOptions::INTEREST_RETRANSMISSION: + *socket_option_value = &on_interest_retransmission_; + break; + + case ConsumerCallbacksOptions::INTEREST_OUTPUT: + *socket_option_value = &on_interest_output_; + break; + + case ConsumerCallbacksOptions::INTEREST_EXPIRED: + *socket_option_value = &on_interest_timeout_; + break; + + case ConsumerCallbacksOptions::INTEREST_SATISFIED: + *socket_option_value = &on_interest_satisfied_; + break; + + default: + return SOCKET_OPTION_NOT_GET; + } + + return SOCKET_OPTION_GET; + }); + } + + int getSocketOption( + int socket_option_key, + ConsumerContentObjectVerificationFailedCallback **socket_option_value) { + // Reschedule the function on the io_service to avoid race condition in + // case setSocketOption is called while the io_service is running. + return rescheduleOnIOService( + socket_option_key, socket_option_value, + [this](int socket_option_key, + ConsumerContentObjectVerificationFailedCallback * + *socket_option_value) -> int { + switch (socket_option_key) { + case ConsumerCallbacksOptions::VERIFICATION_FAILED: + *socket_option_value = &verification_failed_callback_; + break; + default: + return SOCKET_OPTION_NOT_GET; + } + + return SOCKET_OPTION_GET; + }); + } + + int getSocketOption(int socket_option_key, + std::shared_ptr &socket_option_value) { + switch (socket_option_key) { + case PORTAL: + socket_option_value = portal_; + break; + + default: + return SOCKET_OPTION_NOT_GET; + } + + return SOCKET_OPTION_GET; + } + + int getSocketOption(int socket_option_key, + IcnObserver **socket_option_value) { + utils::SpinLock::Acquire locked(guard_raaqm_params_); + switch (socket_option_key) { + case RateEstimationOptions::RATE_ESTIMATION_OBSERVER: + *socket_option_value = (rate_estimation_observer_); + break; + + default: + return SOCKET_OPTION_NOT_GET; + } + + return SOCKET_OPTION_GET; + } + + int getSocketOption(int socket_option_key, + std::shared_ptr &socket_option_value) { + switch (socket_option_key) { + case GeneralTransportOptions::VERIFIER: + socket_option_value = verifier_; + break; + default: + return SOCKET_OPTION_NOT_GET; + } + + return SOCKET_OPTION_GET; + } + + int getSocketOption(int socket_option_key, std::string &socket_option_value) { + switch (socket_option_key) { + case DataLinkOptions::OUTPUT_INTERFACE: + socket_option_value = output_interface_; + break; + default: + return SOCKET_OPTION_NOT_GET; + } + + return SOCKET_OPTION_GET; + } + + int getSocketOption(int socket_option_key, + interface::TransportStatistics **socket_option_value) { + switch (socket_option_key) { + case OtherOptions::STATISTICS: + *socket_option_value = &stats_; + break; + default: + return SOCKET_OPTION_NOT_GET; + } + + return SOCKET_OPTION_GET; + } + + int getSocketOption(int socket_option_key, + ConsumerTimerCallback **socket_option_value) { + // Reschedule the function on the io_service to avoid race condition in + // case setSocketOption is called while the io_service is running. + return rescheduleOnIOService( + socket_option_key, socket_option_value, + [this](int socket_option_key, + ConsumerTimerCallback **socket_option_value) -> int { + switch (socket_option_key) { + case ConsumerCallbacksOptions::STATS_SUMMARY: + *socket_option_value = &stats_summary_; + break; + default: + return SOCKET_OPTION_NOT_GET; + } + + return SOCKET_OPTION_GET; + }); + } + + protected: + template + int rescheduleOnIOService(int socket_option_key, arg2 socket_option_value, + Lambda lambda_func) { + // To enforce type check + std::function func = lambda_func; + int result = SOCKET_OPTION_SET; + if (transport_protocol_->isRunning()) { + std::mutex mtx; + /* Condition variable for the wait */ + std::condition_variable cv; + bool done = false; + io_service_.dispatch([&socket_option_key, &socket_option_value, &mtx, &cv, + &result, &done, &func]() { + std::unique_lock lck(mtx); + done = true; + result = func(socket_option_key, socket_option_value); + cv.notify_all(); + }); + std::unique_lock lck(mtx); + if (!done) { + cv.wait(lck); + } + } else { + result = func(socket_option_key, socket_option_value); + } + + return result; + } + + protected: + interface::ConsumerSocket *consumer_interface_; + asio::io_service io_service_; + + std::shared_ptr portal_; + utils::EventThread async_downloader_; + + // No need to protect from multiple accesses in the async consumer + // The parameter is accessible only with a getSocketOption and + // set from the consume + Name network_name_; + + int interest_lifetime_; + + double min_window_size_; + double max_window_size_; + double current_window_size_; + uint32_t max_retransmissions_; + + // RAAQM Parameters + double minimum_drop_probability_; + unsigned int sample_number_; + double gamma_; + double beta_; + double drop_factor_; + + // Rate estimation parameters + double rate_estimation_alpha_; + IcnObserver *rate_estimation_observer_; + int rate_estimation_batching_parameter_; + int rate_estimation_choice_; + + bool is_async_; + + // Verification parameters + std::shared_ptr verifier_; + PARCKeyId *key_id_; + std::atomic_bool verify_signature_; + bool key_content_; + + ConsumerInterestCallback on_interest_retransmission_; + ConsumerInterestCallback on_interest_output_; + ConsumerInterestCallback on_interest_timeout_; + ConsumerInterestCallback on_interest_satisfied_; + ConsumerContentObjectCallback on_content_object_input_; + ConsumerContentObjectVerificationCallback on_content_object_verification_; + ConsumerContentObjectCallback on_content_object_; + ConsumerTimerCallback stats_summary_; + ConsumerContentObjectVerificationFailedCallback verification_failed_callback_; + + ReadCallback *read_callback_; + + // Virtual download for traffic generator + bool virtual_download_; + + uint32_t timer_interval_milliseconds_; + + // Transport protocol + std::unique_ptr transport_protocol_; + + // Statistic + TransportStatistics stats_; + + utils::SpinLock guard_raaqm_params_; + std::string output_interface_; +}; + +} // namespace implementation +} // namespace transport \ No newline at end of file diff --git a/libtransport/src/implementation/socket_producer.h b/libtransport/src/implementation/socket_producer.h new file mode 100644 index 000000000..1f03fe53d --- /dev/null +++ b/libtransport/src/implementation/socket_producer.h @@ -0,0 +1,1061 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define REGISTRATION_NOT_ATTEMPTED 0 +#define REGISTRATION_SUCCESS 1 +#define REGISTRATION_FAILURE 2 +#define REGISTRATION_IN_PROGRESS 3 + +namespace transport { +namespace implementation { + +using namespace core; +using namespace interface; + +class ProducerSocket : public Socket, + public BasePortal::ProducerCallback { + public: + explicit ProducerSocket(interface::ProducerSocket *producer_socket) + : producer_interface_(producer_socket), + portal_(std::make_shared(io_service_)), + data_packet_size_(default_values::content_object_packet_size), + content_object_expiry_time_(default_values::content_object_expiry_time), + output_buffer_(default_values::producer_socket_output_buffer_size), + async_thread_(), + registration_status_(REGISTRATION_NOT_ATTEMPTED), + making_manifest_(false), + hash_algorithm_(HashAlgorithm::SHA_256), + suffix_strategy_(core::NextSegmentCalculationStrategy::INCREMENTAL), + on_interest_input_(VOID_HANDLER), + on_interest_dropped_input_buffer_(VOID_HANDLER), + on_interest_inserted_input_buffer_(VOID_HANDLER), + on_interest_satisfied_output_buffer_(VOID_HANDLER), + on_interest_process_(VOID_HANDLER), + on_new_segment_(VOID_HANDLER), + on_content_object_to_sign_(VOID_HANDLER), + on_content_object_in_output_buffer_(VOID_HANDLER), + on_content_object_output_(VOID_HANDLER), + on_content_object_evicted_from_output_buffer_(VOID_HANDLER), + on_content_produced_(VOID_HANDLER) {} + + virtual ~ProducerSocket() { + stop(); + if (listening_thread_.joinable()) { + listening_thread_.join(); + } + } + + interface::ProducerSocket *getInterface() { + return producer_interface_; + } + + void setInterface(interface::ProducerSocket *producer_socket) { + producer_interface_ = producer_socket; + } + + void connect() override { + portal_->connect(false); + listening_thread_ = std::thread(std::bind(&ProducerSocket::listen, this)); + } + + bool isRunning() override { return !io_service_.stopped(); }; + + virtual uint32_t produce(Name content_name, const uint8_t *buffer, + size_t buffer_size, bool is_last = true, + uint32_t start_offset = 0) { + return ProducerSocket::produce( + content_name, utils::MemBuf::copyBuffer(buffer, buffer_size), is_last, + start_offset); + } + + virtual uint32_t produce(Name content_name, + std::unique_ptr &&buffer, + bool is_last = true, uint32_t start_offset = 0) { + if (TRANSPORT_EXPECT_FALSE(buffer->length() == 0)) { + return 0; + } + + // Copy the atomic variables to ensure they keep the same value + // during the production + std::size_t data_packet_size = data_packet_size_; + uint32_t content_object_expiry_time = content_object_expiry_time_; + HashAlgorithm hash_algo = hash_algorithm_; + bool making_manifest = making_manifest_; + auto suffix_strategy = utils::SuffixStrategyFactory::getSuffixStrategy( + suffix_strategy_, start_offset); + std::shared_ptr signer; + getSocketOption(GeneralTransportOptions::SIGNER, signer); + + auto buffer_size = buffer->length(); + int bytes_segmented = 0; + std::size_t header_size; + std::size_t manifest_header_size = 0; + std::size_t signature_length = 0; + std::uint32_t final_block_number = start_offset; + uint64_t free_space_for_content = 0; + + core::Packet::Format format; + std::shared_ptr manifest; + bool is_last_manifest = false; + + // TODO Manifest may still be used for indexing + if (making_manifest && !signer) { + TRANSPORT_LOGD("Making manifests without setting producer identity."); + } + + core::Packet::Format hf_format = core::Packet::Format::HF_UNSPEC; + core::Packet::Format hf_format_ah = core::Packet::Format::HF_UNSPEC; + if (content_name.getType() == HNT_CONTIGUOUS_V4 || + content_name.getType() == HNT_IOV_V4) { + hf_format = core::Packet::Format::HF_INET_TCP; + hf_format_ah = core::Packet::Format::HF_INET_TCP_AH; + } else if (content_name.getType() == HNT_CONTIGUOUS_V6 || + content_name.getType() == HNT_IOV_V6) { + hf_format = core::Packet::Format::HF_INET6_TCP; + hf_format_ah = core::Packet::Format::HF_INET6_TCP_AH; + } else { + throw errors::RuntimeException("Unknown name format."); + } + + format = hf_format; + if (making_manifest) { + manifest_header_size = core::Packet::getHeaderSizeFromFormat( + signer ? hf_format_ah : hf_format, + signer ? signer->getSignatureLength() : 0); + } else if (signer) { + format = hf_format_ah; + signature_length = signer->getSignatureLength(); + } + + header_size = + core::Packet::getHeaderSizeFromFormat(format, signature_length); + free_space_for_content = data_packet_size - header_size; + uint32_t number_of_segments = uint32_t( + std::ceil(double(buffer_size) / double(free_space_for_content))); + if (free_space_for_content * number_of_segments < buffer_size) { + number_of_segments++; + } + + // TODO allocate space for all the headers + if (making_manifest) { + uint32_t segment_in_manifest = static_cast( + std::floor(double(data_packet_size - manifest_header_size - + ContentObjectManifest::getManifestHeaderSize()) / + ContentObjectManifest::getManifestEntrySize()) - + 1.0); + uint32_t number_of_manifests = static_cast( + std::ceil(float(number_of_segments) / segment_in_manifest)); + final_block_number += number_of_segments + number_of_manifests - 1; + + manifest.reset(ContentObjectManifest::createManifest( + content_name.setSuffix(suffix_strategy->getNextManifestSuffix()), + core::ManifestVersion::VERSION_1, core::ManifestType::INLINE_MANIFEST, + hash_algo, is_last_manifest, content_name, suffix_strategy_, + signer ? signer->getSignatureLength() : 0)); + manifest->setLifetime(content_object_expiry_time); + + if (is_last) { + manifest->setFinalBlockNumber(final_block_number); + } else { + manifest->setFinalBlockNumber(utils::SuffixStrategy::INVALID_SUFFIX); + } + } + + TRANSPORT_LOGD("--------- START PRODUCE ----------"); + for (unsigned int packaged_segments = 0; + packaged_segments < number_of_segments; packaged_segments++) { + if (making_manifest) { + if (manifest->estimateManifestSize(2) > + data_packet_size - manifest_header_size) { + // Send the current manifest + manifest->encode(); + + // If identity set, sign manifest + if (signer) { + signer->sign(*manifest); + } + + passContentObjectToCallbacks(manifest); + TRANSPORT_LOGD("Send manifest %u", manifest->getName().getSuffix()); + + // Send content objects stored in the queue + while (!content_queue_.empty()) { + passContentObjectToCallbacks(content_queue_.front()); + TRANSPORT_LOGD("Send content %u", + content_queue_.front()->getName().getSuffix()); + content_queue_.pop(); + } + + // Create new manifest. The reference to the last manifest has been + // acquired in the passContentObjectToCallbacks function, so we can + // safely release this reference + manifest.reset(ContentObjectManifest::createManifest( + content_name.setSuffix(suffix_strategy->getNextManifestSuffix()), + core::ManifestVersion::VERSION_1, + core::ManifestType::INLINE_MANIFEST, hash_algo, is_last_manifest, + content_name, suffix_strategy_, + signer ? signer->getSignatureLength() : 0)); + + manifest->setLifetime(content_object_expiry_time); + manifest->setFinalBlockNumber( + is_last ? final_block_number + : utils::SuffixStrategy::INVALID_SUFFIX); + } + } + + auto content_suffix = suffix_strategy->getNextContentSuffix(); + auto content_object = std::make_shared( + content_name.setSuffix(content_suffix), format); + content_object->setLifetime(content_object_expiry_time); + + auto b = buffer->cloneOne(); + b->trimStart(free_space_for_content * packaged_segments); + b->trimEnd(b->length()); + + if (TRANSPORT_EXPECT_FALSE(packaged_segments == number_of_segments - 1)) { + b->append(buffer_size - bytes_segmented); + bytes_segmented += (int)(buffer_size - bytes_segmented); + + if (is_last && making_manifest) { + is_last_manifest = true; + } else if (is_last) { + content_object->setRst(); + } + + } else { + b->append(free_space_for_content); + bytes_segmented += (int)(free_space_for_content); + } + + content_object->appendPayload(std::move(b)); + + if (making_manifest) { + using namespace std::chrono_literals; + utils::CryptoHash hash = content_object->computeDigest(hash_algo); + manifest->addSuffixHash(content_suffix, hash); + content_queue_.push(content_object); + } else { + if (signer) { + signer->sign(*content_object); + } + passContentObjectToCallbacks(content_object); + TRANSPORT_LOGD("Send content %u", + content_object->getName().getSuffix()); + } + } + + if (making_manifest) { + if (is_last_manifest) { + manifest->setFinalManifest(is_last_manifest); + } + + manifest->encode(); + if (signer) { + signer->sign(*manifest); + } + + passContentObjectToCallbacks(manifest); + TRANSPORT_LOGD("Send manifest %u", manifest->getName().getSuffix()); + while (!content_queue_.empty()) { + passContentObjectToCallbacks(content_queue_.front()); + TRANSPORT_LOGD("Send content %u", + content_queue_.front()->getName().getSuffix()); + content_queue_.pop(); + } + } + + io_service_.dispatch([this, buffer_size]() { + if (on_content_produced_) { + on_content_produced_(*producer_interface_, + std::make_error_code(std::errc(0)), buffer_size); + } + }); + + TRANSPORT_LOGD("--------- END PRODUCE ------------"); + return suffix_strategy->getTotalCount(); + } + + virtual void produce(ContentObject &content_object) { + io_service_.dispatch([this, &content_object]() { + if (on_content_object_in_output_buffer_) { + on_content_object_in_output_buffer_(*producer_interface_, + content_object); + } + }); + + output_buffer_.insert(std::static_pointer_cast( + content_object.shared_from_this())); + + io_service_.dispatch([this, &content_object]() { + if (on_content_object_output_) { + on_content_object_output_(*producer_interface_, content_object); + } + }); + + portal_->sendContentObject(content_object); + } + + virtual void produce(const uint8_t *buffer, size_t buffer_size) { + produce(utils::MemBuf::copyBuffer(buffer, buffer_size)); + } + + virtual void produce(std::unique_ptr &&buffer) { + // 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(); + } + + virtual void asyncProduce(const Name &suffix, const uint8_t *buf, + size_t buffer_size, bool is_last = true, + uint32_t *start_offset = nullptr) { + if (!async_thread_.stopped()) { + async_thread_.add([this, suffix, buffer = buf, size = buffer_size, + is_last, start_offset]() { + if (start_offset != nullptr) { + *start_offset = ProducerSocket::produce(suffix, buffer, size, is_last, + *start_offset); + } else { + ProducerSocket::produce(suffix, buffer, size, is_last, 0); + } + }); + } + } + + void asyncProduce(const Name &suffix); + + virtual void asyncProduce(Name content_name, + std::unique_ptr &&buffer, + bool is_last, uint32_t offset, + uint32_t **last_segment = nullptr) { + if (!async_thread_.stopped()) { + auto a = buffer.release(); + async_thread_.add( + [this, content_name, a, is_last, offset, last_segment]() { + auto buf = std::unique_ptr(a); + if (last_segment != NULL) { + **last_segment = + offset + ProducerSocket::produce(content_name, std::move(buf), + is_last, offset); + } else { + ProducerSocket::produce(content_name, std::move(buf), is_last, + offset); + } + }); + } + } + + virtual void asyncProduce(ContentObject &content_object) { + if (!async_thread_.stopped()) { + auto co_ptr = std::static_pointer_cast( + content_object.shared_from_this()); + async_thread_.add([this, content_object = std::move(co_ptr)]() { + ProducerSocket::produce(*content_object); + }); + } + } + + virtual void registerPrefix(const Prefix &producer_namespace) { + served_namespaces_.push_back(producer_namespace); + } + + void serveForever() { + if (listening_thread_.joinable()) { + listening_thread_.join(); + } + } + + void stop() { portal_->stopEventsLoop(); } + + asio::io_service &getIoService() override { return portal_->getIoService(); }; + + virtual void onInterest(Interest &interest) { + if (on_interest_input_) { + on_interest_input_(*producer_interface_, interest); + } + + const std::shared_ptr content_object = + output_buffer_.find(interest); + + if (content_object) { + if (on_interest_satisfied_output_buffer_) { + on_interest_satisfied_output_buffer_(*producer_interface_, interest); + } + + if (on_content_object_output_) { + on_content_object_output_(*producer_interface_, *content_object); + } + + portal_->sendContentObject(*content_object); + } else { + if (on_interest_process_) { + on_interest_process_(*producer_interface_, interest); + } + } + } + + virtual void onInterest(Interest::Ptr &&interest) override { + onInterest(*interest); + }; + + virtual int setSocketOption(int socket_option_key, + uint32_t socket_option_value) { + switch (socket_option_key) { + case GeneralTransportOptions::DATA_PACKET_SIZE: + if (socket_option_value < default_values::max_content_object_size && + socket_option_value > 0) { + data_packet_size_ = socket_option_value; + } + break; + + case GeneralTransportOptions::OUTPUT_BUFFER_SIZE: + output_buffer_.setLimit(socket_option_value); + break; + + case GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME: + content_object_expiry_time_ = socket_option_value; + break; + + default: + return SOCKET_OPTION_NOT_SET; + } + + return SOCKET_OPTION_SET; + } + + virtual int setSocketOption(int socket_option_key, + std::nullptr_t socket_option_value) { + // Reschedule the function on the io_service to avoid race condition in case + // setSocketOption is called while the io_service is running. + return rescheduleOnIOService( + socket_option_key, socket_option_value, + [this](int socket_option_key, + ProducerContentObjectCallback socket_option_value) -> int { + switch (socket_option_key) { + case ProducerCallbacksOptions::INTEREST_INPUT: + if (socket_option_value == VOID_HANDLER) { + on_interest_input_ = VOID_HANDLER; + break; + } + + case ProducerCallbacksOptions::INTEREST_DROP: + if (socket_option_value == VOID_HANDLER) { + on_interest_dropped_input_buffer_ = VOID_HANDLER; + break; + } + + case ProducerCallbacksOptions::INTEREST_PASS: + if (socket_option_value == VOID_HANDLER) { + on_interest_inserted_input_buffer_ = VOID_HANDLER; + break; + } + + case ProducerCallbacksOptions::CACHE_HIT: + if (socket_option_value == VOID_HANDLER) { + on_interest_satisfied_output_buffer_ = VOID_HANDLER; + break; + } + + case ProducerCallbacksOptions::CACHE_MISS: + if (socket_option_value == VOID_HANDLER) { + on_interest_process_ = VOID_HANDLER; + break; + } + + case ProducerCallbacksOptions::NEW_CONTENT_OBJECT: + if (socket_option_value == VOID_HANDLER) { + on_new_segment_ = VOID_HANDLER; + break; + } + + case ProducerCallbacksOptions::CONTENT_OBJECT_SIGN: + if (socket_option_value == VOID_HANDLER) { + on_content_object_to_sign_ = VOID_HANDLER; + break; + } + + case ProducerCallbacksOptions::CONTENT_OBJECT_READY: + if (socket_option_value == VOID_HANDLER) { + on_content_object_in_output_buffer_ = VOID_HANDLER; + break; + } + + case ProducerCallbacksOptions::CONTENT_OBJECT_OUTPUT: + if (socket_option_value == VOID_HANDLER) { + on_content_object_output_ = VOID_HANDLER; + break; + } + + default: + return SOCKET_OPTION_NOT_SET; + } + + return SOCKET_OPTION_SET; + }); + } + + virtual int setSocketOption(int socket_option_key, bool socket_option_value) { + switch (socket_option_key) { + case GeneralTransportOptions::MAKE_MANIFEST: + making_manifest_ = socket_option_value; + break; + + default: + return SOCKET_OPTION_NOT_SET; + } + + return SOCKET_OPTION_SET; + } + + virtual int setSocketOption(int socket_option_key, + Name *socket_option_value) { + return SOCKET_OPTION_NOT_SET; + } + + virtual int setSocketOption(int socket_option_key, + std::list socket_option_value) { + switch (socket_option_key) { + case GeneralTransportOptions::NETWORK_NAME: + served_namespaces_ = socket_option_value; + break; + default: + return SOCKET_OPTION_NOT_SET; + } + + return SOCKET_OPTION_SET; + } + + virtual int setSocketOption( + int socket_option_key, + interface::ProducerContentObjectCallback socket_option_value) { + // Reschedule the function on the io_service to avoid race condition in case + // setSocketOption is called while the io_service is running. + return rescheduleOnIOService( + socket_option_key, socket_option_value, + [this](int socket_option_key, + ProducerContentObjectCallback socket_option_value) -> int { + switch (socket_option_key) { + case ProducerCallbacksOptions::NEW_CONTENT_OBJECT: + on_new_segment_ = socket_option_value; + break; + + case ProducerCallbacksOptions::CONTENT_OBJECT_SIGN: + on_content_object_to_sign_ = socket_option_value; + break; + + case ProducerCallbacksOptions::CONTENT_OBJECT_READY: + on_content_object_in_output_buffer_ = socket_option_value; + break; + + case ProducerCallbacksOptions::CONTENT_OBJECT_OUTPUT: + on_content_object_output_ = socket_option_value; + break; + + default: + return SOCKET_OPTION_NOT_SET; + } + + return SOCKET_OPTION_SET; + }); + } + + virtual int setSocketOption( + int socket_option_key, + interface::ProducerInterestCallback socket_option_value) { + // Reschedule the function on the io_service to avoid race condition in case + // setSocketOption is called while the io_service is running. + return rescheduleOnIOService( + socket_option_key, socket_option_value, + [this](int socket_option_key, + ProducerInterestCallback socket_option_value) -> int { + switch (socket_option_key) { + case ProducerCallbacksOptions::INTEREST_INPUT: + on_interest_input_ = socket_option_value; + break; + + case ProducerCallbacksOptions::INTEREST_DROP: + on_interest_dropped_input_buffer_ = socket_option_value; + break; + + case ProducerCallbacksOptions::INTEREST_PASS: + on_interest_inserted_input_buffer_ = socket_option_value; + break; + + case ProducerCallbacksOptions::CACHE_HIT: + on_interest_satisfied_output_buffer_ = socket_option_value; + break; + + case ProducerCallbacksOptions::CACHE_MISS: + on_interest_process_ = socket_option_value; + break; + + default: + return SOCKET_OPTION_NOT_SET; + } + + return SOCKET_OPTION_SET; + }); + } + + virtual int setSocketOption( + int socket_option_key, + interface::ProducerContentCallback socket_option_value) { + // Reschedule the function on the io_service to avoid race condition in case + // setSocketOption is called while the io_service is running. + return rescheduleOnIOService( + socket_option_key, socket_option_value, + [this](int socket_option_key, + ProducerContentCallback socket_option_value) -> int { + switch (socket_option_key) { + case ProducerCallbacksOptions::CONTENT_PRODUCED: + on_content_produced_ = socket_option_value; + break; + + default: + return SOCKET_OPTION_NOT_SET; + } + + return SOCKET_OPTION_SET; + }); + } + + virtual int setSocketOption(int socket_option_key, + HashAlgorithm socket_option_value) { + switch (socket_option_key) { + case GeneralTransportOptions::HASH_ALGORITHM: + hash_algorithm_ = socket_option_value; + break; + default: + return SOCKET_OPTION_NOT_SET; + } + + return SOCKET_OPTION_SET; + } + + virtual int setSocketOption(int socket_option_key, + utils::CryptoSuite socket_option_value) { + switch (socket_option_key) { + case GeneralTransportOptions::CRYPTO_SUITE: + crypto_suite_ = socket_option_value; + break; + default: + return SOCKET_OPTION_NOT_SET; + } + + return SOCKET_OPTION_SET; + } + + virtual int setSocketOption( + int socket_option_key, + const std::shared_ptr &socket_option_value) { + switch (socket_option_key) { + case GeneralTransportOptions::SIGNER: { + utils::SpinLock::Acquire locked(signer_lock_); + signer_.reset(); + signer_ = socket_option_value; + } break; + default: + return SOCKET_OPTION_NOT_SET; + } + + return SOCKET_OPTION_SET; + } + + virtual int getSocketOption(int socket_option_key, + uint32_t &socket_option_value) { + switch (socket_option_key) { + case GeneralTransportOptions::OUTPUT_BUFFER_SIZE: + socket_option_value = (uint32_t)output_buffer_.getLimit(); + break; + + case GeneralTransportOptions::DATA_PACKET_SIZE: + socket_option_value = (uint32_t)data_packet_size_; + break; + + case GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME: + socket_option_value = content_object_expiry_time_; + break; + + default: + return SOCKET_OPTION_NOT_SET; + } + + return SOCKET_OPTION_GET; + } + + virtual int getSocketOption(int socket_option_key, + bool &socket_option_value) { + switch (socket_option_key) { + case GeneralTransportOptions::MAKE_MANIFEST: + socket_option_value = making_manifest_; + break; + + default: + return SOCKET_OPTION_NOT_GET; + } + + return SOCKET_OPTION_GET; + } + + virtual int getSocketOption(int socket_option_key, + std::list &socket_option_value) { + switch (socket_option_key) { + case GeneralTransportOptions::NETWORK_NAME: + socket_option_value = served_namespaces_; + break; + + default: + return SOCKET_OPTION_NOT_GET; + } + + return SOCKET_OPTION_GET; + } + + virtual int getSocketOption( + int socket_option_key, + interface::ProducerContentObjectCallback **socket_option_value) { + // Reschedule the function on the io_service to avoid race condition in case + // setSocketOption is called while the io_service is running. + return rescheduleOnIOService( + socket_option_key, socket_option_value, + [this](int socket_option_key, + ProducerContentObjectCallback **socket_option_value) -> int { + switch (socket_option_key) { + case ProducerCallbacksOptions::NEW_CONTENT_OBJECT: + *socket_option_value = &on_new_segment_; + break; + + case ProducerCallbacksOptions::CONTENT_OBJECT_SIGN: + *socket_option_value = &on_content_object_to_sign_; + break; + + case ProducerCallbacksOptions::CONTENT_OBJECT_READY: + *socket_option_value = &on_content_object_in_output_buffer_; + break; + + case ProducerCallbacksOptions::CONTENT_OBJECT_OUTPUT: + *socket_option_value = &on_content_object_output_; + break; + + default: + return SOCKET_OPTION_NOT_GET; + } + + return SOCKET_OPTION_GET; + }); + } + + virtual int getSocketOption( + int socket_option_key, + interface::ProducerContentCallback **socket_option_value) { + // Reschedule the function on the io_service to avoid race condition in case + // setSocketOption is called while the io_service is running. + return rescheduleOnIOService( + socket_option_key, socket_option_value, + [this](int socket_option_key, + ProducerContentCallback **socket_option_value) -> int { + switch (socket_option_key) { + case ProducerCallbacksOptions::CONTENT_PRODUCED: + *socket_option_value = &on_content_produced_; + break; + + default: + return SOCKET_OPTION_NOT_GET; + } + + return SOCKET_OPTION_GET; + }); + } + + virtual int getSocketOption( + int socket_option_key, + interface::ProducerInterestCallback **socket_option_value) { + // Reschedule the function on the io_service to avoid race condition in case + // setSocketOption is called while the io_service is running. + return rescheduleOnIOService( + socket_option_key, socket_option_value, + [this](int socket_option_key, + ProducerInterestCallback **socket_option_value) -> int { + switch (socket_option_key) { + case ProducerCallbacksOptions::INTEREST_INPUT: + *socket_option_value = &on_interest_input_; + break; + + case ProducerCallbacksOptions::INTEREST_DROP: + *socket_option_value = &on_interest_dropped_input_buffer_; + break; + + case ProducerCallbacksOptions::INTEREST_PASS: + *socket_option_value = &on_interest_inserted_input_buffer_; + break; + + case CACHE_HIT: + *socket_option_value = &on_interest_satisfied_output_buffer_; + break; + + case CACHE_MISS: + *socket_option_value = &on_interest_process_; + break; + + default: + return SOCKET_OPTION_NOT_GET; + } + + return SOCKET_OPTION_GET; + }); + } + + virtual int getSocketOption(int socket_option_key, + std::shared_ptr &socket_option_value) { + switch (socket_option_key) { + case PORTAL: + socket_option_value = portal_; + break; + default: + return SOCKET_OPTION_NOT_GET; + ; + } + + return SOCKET_OPTION_GET; + } + + virtual int getSocketOption(int socket_option_key, + HashAlgorithm &socket_option_value) { + switch (socket_option_key) { + case GeneralTransportOptions::HASH_ALGORITHM: + socket_option_value = hash_algorithm_; + break; + default: + return SOCKET_OPTION_NOT_GET; + } + + return SOCKET_OPTION_GET; + } + + virtual int getSocketOption(int socket_option_key, + utils::CryptoSuite &socket_option_value) { + switch (socket_option_key) { + case GeneralTransportOptions::HASH_ALGORITHM: + socket_option_value = crypto_suite_; + break; + default: + return SOCKET_OPTION_NOT_GET; + } + + return SOCKET_OPTION_GET; + } + + virtual int getSocketOption( + int socket_option_key, + std::shared_ptr &socket_option_value) { + switch (socket_option_key) { + case GeneralTransportOptions::SIGNER: { + utils::SpinLock::Acquire locked(signer_lock_); + socket_option_value = signer_; + } break; + default: + return SOCKET_OPTION_NOT_GET; + } + + return SOCKET_OPTION_GET; + } + + virtual int setSocketOption(int socket_option_key, + const std::string &socket_option_value) { + return SOCKET_OPTION_NOT_SET; + } + + // If the thread calling lambda_func is not the same of io_service, this + // function reschedule the function on it + template + int rescheduleOnIOService(int socket_option_key, arg2 socket_option_value, + Lambda lambda_func) { + // To enforce type check + std::function func = lambda_func; + int result = SOCKET_OPTION_SET; + if (listening_thread_.joinable() && + std::this_thread::get_id() != listening_thread_.get_id()) { + std::mutex mtx; + /* Condition variable for the wait */ + std::condition_variable cv; + bool done = false; + io_service_.dispatch([&socket_option_key, &socket_option_value, &mtx, &cv, + &result, &done, &func]() { + std::unique_lock lck(mtx); + done = true; + result = func(socket_option_key, socket_option_value); + cv.notify_all(); + }); + std::unique_lock lck(mtx); + if (!done) { + cv.wait(lck); + } + } else { + result = func(socket_option_key, socket_option_value); + } + + return result; + } + + // If the thread calling lambda_func is not the same of io_service, this + // function reschedule the function on it + template + int rescheduleOnIOServiceWithReference(int socket_option_key, + arg2 &socket_option_value, + Lambda lambda_func) { + // To enforce type check + std::function func = lambda_func; + int result = SOCKET_OPTION_SET; + if (listening_thread_.joinable() && + std::this_thread::get_id() != this->listening_thread_.get_id()) { + std::mutex mtx; + /* Condition variable for the wait */ + std::condition_variable cv; + std::unique_lock lck(mtx); + bool done = false; + io_service_.dispatch([&socket_option_key, &socket_option_value, &mtx, &cv, + &result, &done, &func]() { + std::unique_lock lck(mtx); + done = true; + result = func(socket_option_key, socket_option_value); + + if (!done) { + cv.wait(lck); + } + }); + } else { + result = func(socket_option_key, socket_option_value); + } + + return result; + } + + // Threads + protected: + interface::ProducerSocket *producer_interface_; + std::thread listening_thread_; + asio::io_service io_service_; + std::shared_ptr portal_; + std::atomic data_packet_size_; + std::list + served_namespaces_; // No need to be threadsafe, this is always modified + // by the application thread + std::atomic content_object_expiry_time_; + + // buffers + // ContentStore is thread-safe + utils::ContentStore output_buffer_; + + utils::EventThread async_thread_; + int registration_status_; + + std::atomic making_manifest_; + + // map for storing sequence numbers for several calls of the publish + // function + std::unordered_map> seq_number_map_; + + std::atomic hash_algorithm_; + std::atomic crypto_suite_; + utils::SpinLock signer_lock_; + std::shared_ptr signer_; + core::NextSegmentCalculationStrategy suffix_strategy_; + + // While manifests are being built, contents are stored in a queue + std::queue> content_queue_; + + // callbacks + ProducerInterestCallback on_interest_input_; + ProducerInterestCallback on_interest_dropped_input_buffer_; + ProducerInterestCallback on_interest_inserted_input_buffer_; + ProducerInterestCallback on_interest_satisfied_output_buffer_; + ProducerInterestCallback on_interest_process_; + + ProducerContentObjectCallback on_new_segment_; + ProducerContentObjectCallback on_content_object_to_sign_; + ProducerContentObjectCallback on_content_object_in_output_buffer_; + ProducerContentObjectCallback on_content_object_output_; + ProducerContentObjectCallback on_content_object_evicted_from_output_buffer_; + + ProducerContentCallback on_content_produced_; + + private: + void listen() { + bool first = true; + + for (core::Prefix &producer_namespace : served_namespaces_) { + if (first) { + core::BindConfig bind_config(producer_namespace, 1000); + portal_->bind(bind_config); + portal_->setProducerCallback(this); + first = !first; + } else { + portal_->registerRoute(producer_namespace); + } + } + + portal_->runEventsLoop(); + } + + void passContentObjectToCallbacks( + const std::shared_ptr &content_object) { + if (content_object) { + io_service_.dispatch([this, content_object]() { + if (on_new_segment_) { + on_new_segment_(*producer_interface_, *content_object); + } + + if (on_content_object_to_sign_) { + on_content_object_to_sign_(*producer_interface_, *content_object); + } + + if (on_content_object_in_output_buffer_) { + on_content_object_in_output_buffer_(*producer_interface_, + *content_object); + } + }); + + output_buffer_.insert(content_object); + + io_service_.dispatch([this, content_object]() { + if (on_content_object_output_) { + on_content_object_output_(*producer_interface_, *content_object); + } + }); + + portal_->sendContentObject(*content_object); + } + } +}; // namespace implementation + +} // namespace implementation + +} // namespace transport diff --git a/libtransport/src/implementation/tls_rtc_socket_producer.cc b/libtransport/src/implementation/tls_rtc_socket_producer.cc new file mode 100644 index 000000000..3b3152993 --- /dev/null +++ b/libtransport/src/implementation/tls_rtc_socket_producer.cc @@ -0,0 +1,201 @@ +/* + * 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. + */ + +#include +#include + +#include +#include + +#include +#include +#include + +namespace transport { +namespace implementation { + +int TLSRTCProducerSocket::read(BIO *b, char *buf, size_t size, + size_t *readbytes) { + int ret; + + if (size > INT_MAX) size = INT_MAX; + + ret = TLSRTCProducerSocket::readOld(b, buf, (int)size); + + if (ret <= 0) { + *readbytes = 0; + return ret; + } + + *readbytes = (size_t)ret; + + return 1; +} + +int TLSRTCProducerSocket::readOld(BIO *b, char *buf, int size) { + TLSRTCProducerSocket *socket; + socket = (TLSRTCProducerSocket *)BIO_get_data(b); + + std::unique_lock lck(socket->mtx_); + if (!socket->something_to_read_) { + (socket->cv_).wait(lck); + } + + utils::MemBuf *membuf = socket->packet_->next(); + int size_to_read; + + if ((int)membuf->length() > size) { + size_to_read = size; + } else { + size_to_read = membuf->length(); + socket->something_to_read_ = false; + } + + std::memcpy(buf, membuf->data(), size_to_read); + membuf->trimStart(size_to_read); + + return size_to_read; +} + +int TLSRTCProducerSocket::write(BIO *b, const char *buf, size_t size, + size_t *written) { + int ret; + + if (size > INT_MAX) size = INT_MAX; + + ret = TLSRTCProducerSocket::writeOld(b, buf, (int)size); + + if (ret <= 0) { + *written = 0; + return ret; + } + + *written = (size_t)ret; + + return 1; +} + +int TLSRTCProducerSocket::writeOld(BIO *b, const char *buf, int num) { + TLSRTCProducerSocket *socket; + socket = (TLSRTCProducerSocket *)BIO_get_data(b); + + if ((SSL_in_before(socket->ssl_) || SSL_in_init(socket->ssl_)) && + socket->first_) { + socket->tls_chunks_--; + bool making_manifest = socket->parent_->making_manifest_; + socket->parent_->setSocketOption(GeneralTransportOptions::MAKE_MANIFEST, + false); + socket->parent_->ProducerSocket::produce( + socket->name_, (const uint8_t *)buf, num, socket->tls_chunks_ == 0, 0); + socket->parent_->setSocketOption(GeneralTransportOptions::MAKE_MANIFEST, + making_manifest); + socket->first_ = false; + + } else { + std::unique_ptr mbuf = + utils::MemBuf::copyBuffer(buf, (std::size_t)num, 0, 0); + auto a = mbuf.release(); + socket->async_thread_.add([socket = socket, a]() { + socket->to_call_oncontentproduced_--; + auto mbuf = std::unique_ptr(a); + socket->RTCProducerSocket::produce(std::move(mbuf)); + ProducerContentCallback on_content_produced_application; + socket->getSocketOption(ProducerCallbacksOptions::CONTENT_PRODUCED, + on_content_produced_application); + if (socket->to_call_oncontentproduced_ == 0 && + on_content_produced_application) { + on_content_produced_application( + (transport::interface::ProducerSocket &)(*socket->getInterface()), + std::error_code(), 0); + } + }); + } + + return num; +} + +TLSRTCProducerSocket::TLSRTCProducerSocket( + interface::ProducerSocket *producer_socket, P2PSecureProducerSocket *parent, + const Name &handshake_name) + : ProducerSocket(producer_socket), + RTCProducerSocket(producer_socket), + TLSProducerSocket(producer_socket, parent, handshake_name) { + BIO_METHOD *bio_meth = + BIO_meth_new(BIO_TYPE_ACCEPT, "secure rtc producer socket"); + BIO_meth_set_read(bio_meth, TLSRTCProducerSocket::readOld); + BIO_meth_set_write(bio_meth, TLSRTCProducerSocket::writeOld); + BIO_meth_set_ctrl(bio_meth, TLSProducerSocket::ctrl); + BIO *bio = BIO_new(bio_meth); + BIO_set_init(bio, 1); + BIO_set_data(bio, this); + SSL_set_bio(ssl_, bio, bio); +} + +void TLSRTCProducerSocket::accept() { + if (SSL_in_before(ssl_) || SSL_in_init(ssl_)) { + tls_chunks_ = 1; + int result = SSL_accept(ssl_); + if (result != 1) + throw errors::RuntimeException("Unable to perform client handshake"); + } + + TRANSPORT_LOGD("Handshake performed!"); + parent_->list_secure_rtc_producers.push_front( + std::move(parent_->map_secure_rtc_producers[handshake_name_])); + parent_->map_secure_rtc_producers.erase(handshake_name_); + + ProducerInterestCallback on_interest_process_decrypted; + getSocketOption(ProducerCallbacksOptions::CACHE_MISS, + on_interest_process_decrypted); + + if (on_interest_process_decrypted) { + Interest inter(std::move(packet_)); + on_interest_process_decrypted( + (transport::interface::ProducerSocket &)(*getInterface()), inter); + } + + parent_->cv_.notify_one(); +} + +int TLSRTCProducerSocket::async_accept() { + if (!async_thread_.stopped()) { + async_thread_.add([this]() { this->TLSRTCProducerSocket::accept(); }); + } else { + throw errors::RuntimeException( + "Async thread not running, impossible to perform handshake"); + } + + return 1; +} + +void TLSRTCProducerSocket::produce(std::unique_ptr &&buffer) { + if (SSL_in_before(ssl_) || SSL_in_init(ssl_)) { + throw errors::RuntimeException( + "New handshake on the same P2P secure producer socket not supported"); + } + + size_t buf_size = buffer->length(); + tls_chunks_ = ceil((float)buf_size / (float)SSL3_RT_MAX_PLAIN_LENGTH); + to_call_oncontentproduced_ = tls_chunks_; + + SSL_write(ssl_, buffer->data(), buf_size); + BIO *wbio = SSL_get_wbio(ssl_); + int i = BIO_flush(wbio); + (void)i; // To shut up gcc 5 +} + +} // namespace implementation + +} // namespace transport diff --git a/libtransport/src/implementation/tls_rtc_socket_producer.h b/libtransport/src/implementation/tls_rtc_socket_producer.h new file mode 100644 index 000000000..685c91244 --- /dev/null +++ b/libtransport/src/implementation/tls_rtc_socket_producer.h @@ -0,0 +1,58 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +namespace transport { +namespace implementation { + +class P2PSecureProducerSocket; + +class TLSRTCProducerSocket : public RTCProducerSocket, + public TLSProducerSocket { + friend class P2PSecureProducerSocket; + + public: + explicit TLSRTCProducerSocket(interface::ProducerSocket *producer_socket, + P2PSecureProducerSocket *parent, + const Name &handshake_name); + + ~TLSRTCProducerSocket() = default; + + void produce(std::unique_ptr &&buffer) override; + + void accept() override; + + int async_accept() override; + + using TLSProducerSocket::onInterest; + using TLSProducerSocket::produce; + + protected: + static int read(BIO *b, char *buf, size_t size, size_t *readbytes); + + static int readOld(BIO *h, char *buf, int size); + + static int write(BIO *b, const char *buf, size_t size, size_t *written); + + static int writeOld(BIO *h, const char *buf, int num); +}; + +} // namespace implementation + +} // end namespace transport diff --git a/libtransport/src/implementation/tls_socket_consumer.cc b/libtransport/src/implementation/tls_socket_consumer.cc new file mode 100644 index 000000000..95b287aa6 --- /dev/null +++ b/libtransport/src/implementation/tls_socket_consumer.cc @@ -0,0 +1,384 @@ +/* + * 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. + */ + +#include + +#include +#include +#include + +#include + +namespace transport { +namespace implementation { + +void TLSConsumerSocket::setInterestPayload(interface::ConsumerSocket &c, + const core::Interest &interest) { + Interest &int2 = const_cast(interest); + random_suffix_ = int2.getName().getSuffix(); + + if (payload_ != NULL) int2.appendPayload(std::move(payload_)); +} + +/* Return the number of read bytes in the return param */ +int readOldTLS(BIO *b, char *buf, int size) { + if (size < 0) return size; + + TLSConsumerSocket *socket; + socket = (TLSConsumerSocket *)BIO_get_data(b); + + std::unique_lock lck(socket->mtx_); + + if (!socket->something_to_read_) { + if (!socket->transport_protocol_->isRunning()) { + socket->network_name_.setSuffix(socket->random_suffix_); + socket->ConsumerSocket::asyncConsume(socket->network_name_); + } + if (!socket->something_to_read_) socket->cv_.wait(lck); + } + + size_t size_to_read, read; + size_t chain_size = socket->head_->length(); + if (socket->head_->isChained()) + chain_size = socket->head_->computeChainDataLength(); + + if (chain_size > (size_t)size) { + read = size_to_read = (size_t)size; + } else { + read = size_to_read = chain_size; + socket->something_to_read_ = false; + } + + while (size_to_read) { + if (socket->head_->length() < size_to_read) { + std::memcpy(buf, socket->head_->data(), socket->head_->length()); + size_to_read -= socket->head_->length(); + buf += socket->head_->length(); + socket->head_ = socket->head_->pop(); + } else { + std::memcpy(buf, socket->head_->data(), size_to_read); + socket->head_->trimStart(size_to_read); + size_to_read = 0; + } + } + + return read; +} + +/* Return the number of read bytes in readbytes */ +int readTLS(BIO *b, char *buf, size_t size, size_t *readbytes) { + int ret; + + if (size > INT_MAX) size = INT_MAX; + + ret = readOldTLS(b, buf, (int)size); + + if (ret <= 0) { + *readbytes = 0; + return ret; + } + + *readbytes = (size_t)ret; + + return 1; +} + +/* Return the number of written bytes in the return param */ +int writeOldTLS(BIO *b, const char *buf, int num) { + TLSConsumerSocket *socket; + socket = (TLSConsumerSocket *)BIO_get_data(b); + + socket->payload_ = utils::MemBuf::copyBuffer(buf, num); + socket->ConsumerSocket::setSocketOption( + ConsumerCallbacksOptions::INTEREST_OUTPUT, + (ConsumerInterestCallback)std::bind( + &TLSConsumerSocket::setInterestPayload, socket, std::placeholders::_1, + std::placeholders::_2)); + + return num; +} + +/* Return the number of written bytes in written */ +int writeTLS(BIO *b, const char *buf, size_t size, size_t *written) { + int ret; + + if (size > INT_MAX) size = INT_MAX; + + ret = writeOldTLS(b, buf, (int)size); + + if (ret <= 0) { + *written = 0; + return ret; + } + + *written = (size_t)ret; + + return 1; +} + +long ctrlTLS(BIO *b, int cmd, long num, void *ptr) { return 1; } + +TLSConsumerSocket::TLSConsumerSocket(interface::ConsumerSocket *consumer_socket, + int protocol, SSL *ssl) + : ConsumerSocket(consumer_socket, protocol), + name_(), + buf_pool_(), + decrypted_content_(), + payload_(), + head_(), + something_to_read_(false), + content_downloaded_(false), + random_suffix_(), + producer_namespace_(), + read_callback_decrypted_(), + mtx_(), + cv_(), + async_downloader_tls_() { + /* Create the (d)TLS state */ + const SSL_METHOD *meth = TLS_client_method(); + ctx_ = SSL_CTX_new(meth); + + int result = + SSL_CTX_set_ciphersuites(ctx_, + "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_" + "SHA256:TLS_AES_128_GCM_SHA256"); + if (result != 1) { + throw errors::RuntimeException( + "Unable to set cipher list on TLS subsystem. Aborting."); + } + + SSL_CTX_set_min_proto_version(ctx_, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(ctx_, TLS1_3_VERSION); + SSL_CTX_set_verify(ctx_, SSL_VERIFY_NONE, NULL); + SSL_CTX_set_ssl_version(ctx_, meth); + + ssl_ = ssl; + + BIO_METHOD *bio_meth = + BIO_meth_new(BIO_TYPE_CONNECT, "secure consumer socket"); + BIO_meth_set_read(bio_meth, readOldTLS); + BIO_meth_set_write(bio_meth, writeOldTLS); + BIO_meth_set_ctrl(bio_meth, ctrlTLS); + BIO *bio = BIO_new(bio_meth); + BIO_set_init(bio, 1); + BIO_set_data(bio, this); + SSL_set_bio(ssl_, bio, bio); + + ConsumerSocket::getSocketOption(MAX_WINDOW_SIZE, old_max_win_); + ConsumerSocket::setSocketOption(MAX_WINDOW_SIZE, (double)1.0); + + ConsumerSocket::getSocketOption(CURRENT_WINDOW_SIZE, old_current_win_); + ConsumerSocket::setSocketOption(CURRENT_WINDOW_SIZE, (double)1.0); + + std::default_random_engine generator; + std::uniform_int_distribution distribution( + 1, std::numeric_limits::max()); + random_suffix_ = 0; + + this->ConsumerSocket::setSocketOption(ConsumerCallbacksOptions::READ_CALLBACK, + this); +}; + +/* + * The producer interface is not owned by the application, so is TLSSocket task + * to deallocate the memory + */ +TLSConsumerSocket::~TLSConsumerSocket() { delete consumer_interface_; } + +int TLSConsumerSocket::consume(const Name &name, + std::unique_ptr &&buffer) { + this->payload_ = std::move(buffer); + + this->ConsumerSocket::setSocketOption( + ConsumerCallbacksOptions::INTEREST_OUTPUT, + (ConsumerInterestCallback)std::bind( + &TLSConsumerSocket::setInterestPayload, this, std::placeholders::_1, + std::placeholders::_2)); + + return consume(name); +} + +int TLSConsumerSocket::consume(const Name &name) { + if (transport_protocol_->isRunning()) { + return CONSUMER_BUSY; + } + + if ((SSL_in_before(this->ssl_) || SSL_in_init(this->ssl_))) { + throw errors::RuntimeException("Handshake not performed"); + } + + return download_content(name); +} + +int TLSConsumerSocket::download_content(const Name &name) { + network_name_ = name; + network_name_.setSuffix(0); + something_to_read_ = false; + content_downloaded_ = false; + + decrypted_content_ = utils::MemBuf::createCombined(SSL3_RT_MAX_PLAIN_LENGTH); + uint8_t *buf = decrypted_content_->writableData(); + size_t size = 0; + int result = -1; + + while (!content_downloaded_ || something_to_read_) { + if (decrypted_content_->tailroom() < SSL3_RT_MAX_PLAIN_LENGTH) { + decrypted_content_->appendChain( + utils::MemBuf::createCombined(SSL3_RT_MAX_PLAIN_LENGTH)); + // decrypted_content_->computeChainDataLength(); + buf = decrypted_content_->prev()->writableData(); + } else { + buf = decrypted_content_->writableTail(); + } + + result = SSL_read(this->ssl_, buf, SSL3_RT_MAX_PLAIN_LENGTH); + + /* SSL_read returns the data only if there were SSL3_RT_MAX_PLAIN_LENGTH of + * the data has been fully downloaded */ + + /* ASSERT((result < SSL3_RT_MAX_PLAIN_LENGTH && content_downloaded_) || */ + /* result == SSL3_RT_MAX_PLAIN_LENGTH); */ + + if (result >= 0) { + size += result; + decrypted_content_->prepend(result); + } else + throw errors::RuntimeException("Unable to download content"); + + if (size >= read_callback_decrypted_->maxBufferSize()) { + if (read_callback_decrypted_->isBufferMovable()) { + // No need to perform an additional copy. The whole buffer will be + // tranferred to the application. + + read_callback_decrypted_->readBufferAvailable( + std::move(decrypted_content_)); + decrypted_content_ = utils::MemBuf::create(SSL3_RT_MAX_PLAIN_LENGTH); + } else { + // The buffer will be copied into the application-provided buffer + uint8_t *buffer; + std::size_t length; + std::size_t total_length = decrypted_content_->length(); + + while (decrypted_content_->length()) { + buffer = nullptr; + length = 0; + read_callback_decrypted_->getReadBuffer(&buffer, &length); + + if (!buffer || !length) { + throw errors::RuntimeException( + "Invalid buffer provided by the application."); + } + + auto to_copy = std::min(decrypted_content_->length(), length); + std::memcpy(buffer, decrypted_content_->data(), to_copy); + decrypted_content_->trimStart(to_copy); + } + + read_callback_decrypted_->readDataAvailable(total_length); + decrypted_content_->clear(); + } + } + } + + read_callback_decrypted_->readSuccess(size); + + return CONSUMER_FINISHED; +} + +int TLSConsumerSocket::asyncConsume(const Name &name, + std::unique_ptr &&buffer) { + this->payload_ = std::move(buffer); + + this->ConsumerSocket::setSocketOption( + ConsumerCallbacksOptions::INTEREST_OUTPUT, + (ConsumerInterestCallback)std::bind( + &TLSConsumerSocket::setInterestPayload, this, std::placeholders::_1, + std::placeholders::_2)); + + return asyncConsume(name); +} + +int TLSConsumerSocket::asyncConsume(const Name &name) { + if ((SSL_in_before(this->ssl_) || SSL_in_init(this->ssl_))) { + throw errors::RuntimeException("Handshake not performed"); + } + + if (!async_downloader_tls_.stopped()) { + async_downloader_tls_.add([this, name]() { + is_async_ = true; + download_content(name); + }); + } + + return CONSUMER_RUNNING; +} + +void TLSConsumerSocket::registerPrefix(const Prefix &producer_namespace) { + producer_namespace_ = producer_namespace; +} + +int TLSConsumerSocket::setSocketOption(int socket_option_key, + ReadCallback *socket_option_value) { + return rescheduleOnIOService( + socket_option_key, socket_option_value, + [this](int socket_option_key, ReadCallback *socket_option_value) -> int { + switch (socket_option_key) { + case ConsumerCallbacksOptions::READ_CALLBACK: + read_callback_decrypted_ = socket_option_value; + break; + default: + return SOCKET_OPTION_NOT_SET; + } + + return SOCKET_OPTION_SET; + }); +} + +void TLSConsumerSocket::getReadBuffer(uint8_t **application_buffer, + size_t *max_length) {} + +void TLSConsumerSocket::readDataAvailable(size_t length) noexcept {} + +size_t TLSConsumerSocket::maxBufferSize() const { + return SSL3_RT_MAX_PLAIN_LENGTH; +} + +void TLSConsumerSocket::readBufferAvailable( + std::unique_ptr &&buffer) noexcept { + std::unique_lock lck(this->mtx_); + if (head_) { + head_->prependChain(std::move(buffer)); + } else { + head_ = std::move(buffer); + } + + something_to_read_ = true; + cv_.notify_one(); +} + +void TLSConsumerSocket::readError(const std::error_code ec) noexcept {} + +void TLSConsumerSocket::readSuccess(std::size_t total_size) noexcept { + std::unique_lock lck(this->mtx_); + content_downloaded_ = true; + something_to_read_ = true; + cv_.notify_one(); +} + +bool TLSConsumerSocket::isBufferMovable() noexcept { return true; } + +} // namespace implementation + +} // namespace transport diff --git a/libtransport/src/implementation/tls_socket_consumer.h b/libtransport/src/implementation/tls_socket_consumer.h new file mode 100644 index 000000000..2e88dc47e --- /dev/null +++ b/libtransport/src/implementation/tls_socket_consumer.h @@ -0,0 +1,133 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include + +#include + +namespace transport { +namespace implementation { + +class TLSConsumerSocket : public ConsumerSocket, + public interface::ConsumerSocket::ReadCallback { + /* Return the number of read bytes in readbytes */ + friend int readTLS(BIO *b, char *buf, size_t size, size_t *readbytes); + + /* Return the number of read bytes in the return param */ + friend int readOldTLS(BIO *h, char *buf, int size); + + /* Return the number of written bytes in written */ + friend int writeTLS(BIO *b, const char *buf, size_t size, size_t *written); + + /* Return the number of written bytes in the return param */ + friend int writeOldTLS(BIO *h, const char *buf, int num); + + friend long ctrlTLS(BIO *b, int cmd, long num, void *ptr); + + public: + explicit TLSConsumerSocket(interface::ConsumerSocket *consumer_socket, + int protocol, SSL *ssl_); + + ~TLSConsumerSocket(); + + int consume(const Name &name, std::unique_ptr &&buffer); + int consume(const Name &name) override; + + int asyncConsume(const Name &name, std::unique_ptr &&buffer); + int asyncConsume(const Name &name) override; + + void registerPrefix(const Prefix &producer_namespace); + + int setSocketOption( + int socket_option_key, + interface::ConsumerSocket::ReadCallback *socket_option_value) override; + + using ConsumerSocket::getSocketOption; + using ConsumerSocket::setSocketOption; + + protected: + /* Callback invoked once an interest has been received and its payload + * decrypted */ + ConsumerInterestCallback on_interest_input_decrypted_; + ConsumerInterestCallback on_interest_process_decrypted_; + + private: + Name name_; + + /* SSL handle */ + SSL *ssl_; + SSL_CTX *ctx_; + + /* Chain of MemBuf to be used as a temporary buffer to pass descypted data + * from the underlying layer to the application */ + utils::ObjectPool buf_pool_; + std::unique_ptr decrypted_content_; + + /* Chain of MemBuf holding the payload to be written into interest or data + */ + std::unique_ptr payload_; + + /* Chain of MemBuf holding the data retrieved from the underlying layer */ + std::unique_ptr head_; + + bool something_to_read_; + + bool content_downloaded_; + + double old_max_win_; + + double old_current_win_; + + uint32_t random_suffix_; + + Prefix producer_namespace_; + + interface::ConsumerSocket::ReadCallback *read_callback_decrypted_; + + std::mutex mtx_; + + /* Condition variable for the wait */ + std::condition_variable cv_; + + utils::EventThread async_downloader_tls_; + + void setInterestPayload(interface::ConsumerSocket &c, + const core::Interest &interest); + + virtual void getReadBuffer(uint8_t **application_buffer, + size_t *max_length) override; + + virtual void readDataAvailable(size_t length) noexcept override; + + virtual size_t maxBufferSize() const override; + + virtual void readBufferAvailable( + std::unique_ptr &&buffer) noexcept override; + + virtual void readError(const std::error_code ec) noexcept override; + + virtual void readSuccess(std::size_t total_size) noexcept override; + virtual bool isBufferMovable() noexcept override; + + int download_content(const Name &name); +}; + +} // namespace implementation + +} // end namespace transport \ No newline at end of file diff --git a/libtransport/src/implementation/tls_socket_producer.cc b/libtransport/src/implementation/tls_socket_producer.cc new file mode 100644 index 000000000..9a5b94a1c --- /dev/null +++ b/libtransport/src/implementation/tls_socket_producer.cc @@ -0,0 +1,611 @@ +/* + * Copyright (c) 2017-2020 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 + +#include +#include + +#include +#include +#include + +namespace transport { +namespace implementation { + +/* Return the number of read bytes in readbytes */ +int TLSProducerSocket::read(BIO *b, char *buf, size_t size, size_t *readbytes) { + int ret; + + if (size > INT_MAX) size = INT_MAX; + + ret = TLSProducerSocket::readOld(b, buf, (int)size); + + if (ret <= 0) { + *readbytes = 0; + return ret; + } + + *readbytes = (size_t)ret; + + return 1; +} + +/* Return the number of read bytes in the return param */ +int TLSProducerSocket::readOld(BIO *b, char *buf, int size) { + TLSProducerSocket *socket; + socket = (TLSProducerSocket *)BIO_get_data(b); + + /* take a lock on the mutex. It will be unlocked by */ + std::unique_lock lck(socket->mtx_); + if (!socket->something_to_read_) { + (socket->cv_).wait(lck); + } + + /* Either there already is something to read, or the thread has been waken up + */ + /* must return the payload in the interest */ + + utils::MemBuf *membuf = socket->packet_->next(); + int size_to_read; + if ((int)membuf->length() > size) { + size_to_read = size; + } else { + size_to_read = membuf->length(); + socket->something_to_read_ = false; + } + + std::memcpy(buf, membuf->data(), size_to_read); + membuf->trimStart(size_to_read); + + return size_to_read; +} + +/* Return the number of written bytes in written */ +int TLSProducerSocket::write(BIO *b, const char *buf, size_t size, + size_t *written) { + int ret; + + if (size > INT_MAX) size = INT_MAX; + + ret = TLSProducerSocket::writeOld(b, buf, (int)size); + + if (ret <= 0) { + *written = 0; + return ret; + } + + *written = (size_t)ret; + + return 1; +} + +/* Return the number of written bytes in the return param */ +int TLSProducerSocket::writeOld(BIO *b, const char *buf, int num) { + TLSProducerSocket *socket; + socket = (TLSProducerSocket *)BIO_get_data(b); + + if ((SSL_in_before(socket->ssl_) || SSL_in_init(socket->ssl_)) && + socket->first_) { + //! socket->tls_chunks_ corresponds to is_last + socket->tls_chunks_--; + bool making_manifest = socket->parent_->making_manifest_; + socket->parent_->setSocketOption(GeneralTransportOptions::MAKE_MANIFEST, + false); + socket->parent_->ProducerSocket::produce( + socket->name_, (const uint8_t *)buf, num, socket->tls_chunks_ == 0, + socket->last_segment_); + socket->parent_->setSocketOption(GeneralTransportOptions::MAKE_MANIFEST, + making_manifest); + socket->first_ = false; + } else { + socket->still_writing_ = true; + + std::unique_ptr mbuf = + utils::MemBuf::copyBuffer(buf, (std::size_t)num, 0, 0); + auto a = mbuf.release(); + socket->async_thread_.add([socket = socket, a]() { + socket->tls_chunks_--; + socket->to_call_oncontentproduced_--; + auto mbuf = std::unique_ptr(a); + socket->last_segment_ += socket->ProducerSocket::produce( + socket->name_, std::move(mbuf), socket->tls_chunks_ == 0, + socket->last_segment_); + ProducerContentCallback on_content_produced_application; + socket->getSocketOption(ProducerCallbacksOptions::CONTENT_PRODUCED, + on_content_produced_application); + if (socket->to_call_oncontentproduced_ == 0 && + on_content_produced_application) { + on_content_produced_application(*socket->getInterface(), + std::error_code(), 0); + } + }); + } + + return num; +} + +TLSProducerSocket::TLSProducerSocket(interface::ProducerSocket *producer_socket, + P2PSecureProducerSocket *parent, + const Name &handshake_name) + : ProducerSocket(producer_socket), + on_content_produced_application_(), + mtx_(), + cv_(), + something_to_read_(), + name_(), + last_segment_(0), + parent_(parent), + first_(true), + handshake_name_(handshake_name), + tls_chunks_(0), + to_call_oncontentproduced_(0), + still_writing_(false), + encryption_thread_() { + const SSL_METHOD *meth = TLS_server_method(); + ctx_ = SSL_CTX_new(meth); + + /* + * Setup SSL context (identity and parameter to use TLS 1.3) + */ + SSL_CTX_use_certificate(ctx_, parent->cert_509_); + SSL_CTX_use_PrivateKey(ctx_, parent->pkey_rsa_); + + int result = + SSL_CTX_set_ciphersuites(ctx_, + "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_" + "SHA256:TLS_AES_128_GCM_SHA256"); + if (result != 1) { + throw errors::RuntimeException( + "Unable to set cipher list on TLS subsystem. Aborting."); + } + + // We force it to be TLS 1.3 + SSL_CTX_set_min_proto_version(ctx_, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(ctx_, TLS1_3_VERSION); + SSL_CTX_set_verify(ctx_, SSL_VERIFY_NONE, NULL); + SSL_CTX_set_num_tickets(ctx_, 0); + + result = SSL_CTX_add_custom_ext( + ctx_, 100, SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS, + TLSProducerSocket::addHicnKeyIdCb, TLSProducerSocket::freeHicnKeyIdCb, + this, TLSProducerSocket::parseHicnKeyIdCb, NULL); + + ssl_ = SSL_new(ctx_); + /* + * Setup this producer socker as the bio that TLS will use to write and read + * data (in stream mode) + */ + BIO_METHOD *bio_meth = + BIO_meth_new(BIO_TYPE_ACCEPT, "secure producer socket"); + BIO_meth_set_read(bio_meth, TLSProducerSocket::readOld); + BIO_meth_set_write(bio_meth, TLSProducerSocket::writeOld); + BIO_meth_set_ctrl(bio_meth, TLSProducerSocket::ctrl); + BIO *bio = BIO_new(bio_meth); + BIO_set_init(bio, 1); + BIO_set_data(bio, this); + SSL_set_bio(ssl_, bio, bio); + /* + * Set the callback so that when an interest is received we catch it and we + * decrypt the payload before passing it to the application. + */ + this->ProducerSocket::setSocketOption( + ProducerCallbacksOptions::CACHE_MISS, + (ProducerInterestCallback)std::bind(&TLSProducerSocket::cacheMiss, this, + std::placeholders::_1, + std::placeholders::_2)); + this->ProducerSocket::setSocketOption( + ProducerCallbacksOptions::CONTENT_PRODUCED, + (ProducerContentCallback)bind( + &TLSProducerSocket::onContentProduced, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3)); +} + +/* + * The producer interface is not owned by the application, so is TLSSocket task + * to deallocate the memory + */ +TLSProducerSocket::~TLSProducerSocket() { delete producer_interface_; } + +void TLSProducerSocket::accept() { + if (SSL_in_before(ssl_) || SSL_in_init(ssl_)) { + tls_chunks_ = 1; + int result = SSL_accept(ssl_); + if (result != 1) + throw errors::RuntimeException("Unable to perform client handshake"); + } + TRANSPORT_LOGD("Handshake performed!"); + parent_->list_secure_producers.push_front( + std::move(parent_->map_secure_producers[handshake_name_])); + parent_->map_secure_producers.erase(handshake_name_); + + ProducerInterestCallback on_interest_process_decrypted; + getSocketOption(ProducerCallbacksOptions::CACHE_MISS, + on_interest_process_decrypted); + + if (on_interest_process_decrypted) { + Interest inter(std::move(packet_)); + on_interest_process_decrypted(*getInterface(), inter); + } else { + throw errors::RuntimeException( + "On interest process unset. Unable to perform handshake"); + } +} + +int TLSProducerSocket::async_accept() { + if (!async_thread_.stopped()) { + async_thread_.add([this]() { this->accept(); }); + } else { + throw errors::RuntimeException( + "Async thread not running, impossible to perform handshake"); + } + + return 1; +} + +void TLSProducerSocket::onInterest(ProducerSocket &p, Interest &interest) { + /* Based on the state machine of (D)TLS, we know what action to do */ + if (SSL_in_before(ssl_) || SSL_in_init(ssl_)) { + std::unique_lock lck(mtx_); + name_ = interest.getName(); + something_to_read_ = true; + packet_ = interest.acquireMemBufReference(); + if (head_) { + payload_->prependChain(interest.getPayload()); + } else { + payload_ = interest.getPayload(); // std::move(interest.getPayload()); + } + cv_.notify_one(); + } else { + name_ = interest.getName(); + packet_ = interest.acquireMemBufReference(); + payload_ = interest.getPayload(); + something_to_read_ = true; + + if (interest.getPayload()->length() > 0) + SSL_read( + ssl_, + const_cast(interest.getPayload()->writableData()), + interest.getPayload()->length()); + } + + ProducerInterestCallback on_interest_input_decrypted; + getSocketOption(ProducerCallbacksOptions::INTEREST_INPUT, + on_interest_input_decrypted); + if (on_interest_input_decrypted) + (on_interest_input_decrypted)(*getInterface(), interest); +} + +void TLSProducerSocket::cacheMiss(interface::ProducerSocket &p, + Interest &interest) { + if (SSL_in_before(ssl_) || SSL_in_init(ssl_)) { + std::unique_lock lck(mtx_); + name_ = interest.getName(); + something_to_read_ = true; + packet_ = interest.acquireMemBufReference(); + payload_ = interest.getPayload(); + cv_.notify_one(); + } else { + name_ = interest.getName(); + packet_ = interest.acquireMemBufReference(); + payload_ = interest.getPayload(); + something_to_read_ = true; + + if (interest.getPayload()->length() > 0) + SSL_read( + ssl_, + const_cast(interest.getPayload()->writableData()), + interest.getPayload()->length()); + + if (on_interest_process_decrypted_ != VOID_HANDLER) + on_interest_process_decrypted_(*getInterface(), interest); + } +} + +void TLSProducerSocket::onContentProduced(interface::ProducerSocket &p, + const std::error_code &err, + uint64_t bytes_written) {} + +uint32_t TLSProducerSocket::produce(Name content_name, + std::unique_ptr &&buffer, + bool is_last, uint32_t start_offset) { + if (SSL_in_before(ssl_) || SSL_in_init(ssl_)) { + throw errors::RuntimeException( + "New handshake on the same P2P secure producer socket not supported"); + } + size_t buf_size = buffer->length(); + name_ = served_namespaces_.front().mapName(content_name); + + tls_chunks_ = to_call_oncontentproduced_ = + ceil((float)buf_size / (float)SSL3_RT_MAX_PLAIN_LENGTH); + + if (!is_last) { + tls_chunks_++; + } + + last_segment_ = start_offset; + + SSL_write(ssl_, buffer->data(), buf_size); + BIO *wbio = SSL_get_wbio(ssl_); + int i = BIO_flush(wbio); + (void)i; // To shut up gcc 5 + + return 0; +} + +void TLSProducerSocket::asyncProduce(const Name &content_name, + const uint8_t *buf, size_t buffer_size, + bool is_last, uint32_t *start_offset) { + if (!encryption_thread_.stopped()) { + encryption_thread_.add([this, content_name, buffer = buf, + size = buffer_size, is_last, start_offset]() { + if (start_offset != NULL) { + produce(content_name, buffer, size, is_last, *start_offset); + } else { + produce(content_name, buffer, size, is_last, 0); + } + }); + } +} + +void TLSProducerSocket::asyncProduce(Name content_name, + std::unique_ptr &&buffer, + bool is_last, uint32_t offset, + uint32_t **last_segment) { + if (!encryption_thread_.stopped()) { + auto a = buffer.release(); + encryption_thread_.add( + [this, content_name, a, is_last, offset, last_segment]() { + auto buf = std::unique_ptr(a); + if (last_segment != NULL) { + *last_segment = &last_segment_; + } + produce(content_name, std::move(buf), is_last, offset); + }); + } +} + +void TLSProducerSocket::asyncProduce(ContentObject &content_object) { + throw errors::RuntimeException("API not supported"); +} + +void TLSProducerSocket::produce(ContentObject &content_object) { + throw errors::RuntimeException("API not supported"); +} + +long TLSProducerSocket::ctrl(BIO *b, int cmd, long num, void *ptr) { + if (cmd == BIO_CTRL_FLUSH) { + } + return 1; +} + +int TLSProducerSocket::addHicnKeyIdCb(SSL *s, unsigned int ext_type, + unsigned int context, + const unsigned char **out, size_t *outlen, + X509 *x, size_t chainidx, int *al, + void *add_arg) { + TLSProducerSocket *socket = reinterpret_cast(add_arg); + if (ext_type == 100) { + ip_prefix_t ip_prefix = + socket->parent_->served_namespaces_.front().toIpPrefixStruct(); + int inet_family = + socket->parent_->served_namespaces_.front().getAddressFamily(); + uint16_t prefix_len_bits = + socket->parent_->served_namespaces_.front().getPrefixLength(); + uint8_t prefix_len_bytes = prefix_len_bits / 8; + uint8_t prefix_len_u32 = prefix_len_bits / 32; + + ip_prefix_t *out_ip = (ip_prefix_t *)malloc(sizeof(ip_prefix_t)); + out_ip->family = inet_family; + out_ip->len = prefix_len_bits + 32; + u8 *out_ip_buf = const_cast( + ip_address_get_buffer(&(out_ip->address), inet_family)); + *out = reinterpret_cast(out_ip); + + RAND_bytes((unsigned char *)&socket->key_id_, 4); + + memcpy(out_ip_buf, ip_address_get_buffer(&(ip_prefix.address), inet_family), + prefix_len_bytes); + memcpy((out_ip_buf + prefix_len_bytes), &socket->key_id_, 4); + *outlen = sizeof(ip_prefix_t); + + ip_address_t mask = {}; + ip_address_t keyId_component = {}; + u32 *mask_buf; + u32 *keyId_component_buf; + switch (inet_family) { + case AF_INET: + mask_buf = &(mask.v4.as_u32); + keyId_component_buf = &(keyId_component.v4.as_u32); + break; + case AF_INET6: + mask_buf = mask.v6.as_u32; + keyId_component_buf = keyId_component.v6.as_u32; + break; + default: + throw errors::RuntimeException("Unknown protocol"); + } + + if (prefix_len_bits > (inet_family == AF_INET6 ? IPV6_ADDR_LEN_BITS - 32 + : IPV4_ADDR_LEN_BITS - 32)) + throw errors::RuntimeException( + "Not enough space in the content name to add key_id"); + + mask_buf[prefix_len_u32] = 0xffffffff; + keyId_component_buf[prefix_len_u32] = socket->key_id_; + socket->last_segment_ = 0; + + socket->on_interest_process_decrypted_ = + socket->parent_->on_interest_process_decrypted_; + + socket->registerPrefix( + Prefix(socket->parent_->served_namespaces_.front().getName( + Name(inet_family, (uint8_t *)&mask), + Name(inet_family, (uint8_t *)&keyId_component), + socket->parent_->served_namespaces_.front().getName()), + out_ip->len)); + socket->connect(); + } + return 1; +} + +void TLSProducerSocket::freeHicnKeyIdCb(SSL *s, unsigned int ext_type, + unsigned int context, + const unsigned char *out, + void *add_arg) { + free(const_cast(out)); +} + +int TLSProducerSocket::parseHicnKeyIdCb(SSL *s, unsigned int ext_type, + unsigned int context, + const unsigned char *in, size_t inlen, + X509 *x, size_t chainidx, int *al, + void *add_arg) { + return 1; +} + +int TLSProducerSocket::setSocketOption( + int socket_option_key, ProducerInterestCallback socket_option_value) { + return rescheduleOnIOService( + socket_option_key, socket_option_value, + [this](int socket_option_key, + ProducerInterestCallback socket_option_value) -> int { + int result = SOCKET_OPTION_SET; + switch (socket_option_key) { + case ProducerCallbacksOptions::INTEREST_INPUT: + on_interest_input_decrypted_ = socket_option_value; + break; + + case ProducerCallbacksOptions::INTEREST_DROP: + on_interest_dropped_input_buffer_ = socket_option_value; + break; + + case ProducerCallbacksOptions::INTEREST_PASS: + on_interest_inserted_input_buffer_ = socket_option_value; + break; + + case ProducerCallbacksOptions::CACHE_HIT: + on_interest_satisfied_output_buffer_ = socket_option_value; + break; + + case ProducerCallbacksOptions::CACHE_MISS: + on_interest_process_decrypted_ = socket_option_value; + break; + + default: + result = SOCKET_OPTION_NOT_SET; + break; + } + return result; + }); +} + +int TLSProducerSocket::setSocketOption( + int socket_option_key, ProducerContentCallback socket_option_value) { + return rescheduleOnIOService( + socket_option_key, socket_option_value, + [this](int socket_option_key, + ProducerContentCallback socket_option_value) -> int { + switch (socket_option_key) { + case ProducerCallbacksOptions::CONTENT_PRODUCED: + on_content_produced_application_ = socket_option_value; + break; + + default: + return SOCKET_OPTION_NOT_SET; + } + + return SOCKET_OPTION_SET; + }); +} + +int TLSProducerSocket::getSocketOption( + int socket_option_key, ProducerContentCallback **socket_option_value) { + return rescheduleOnIOService( + socket_option_key, socket_option_value, + [this](int socket_option_key, + ProducerContentCallback **socket_option_value) -> int { + switch (socket_option_key) { + case ProducerCallbacksOptions::CONTENT_PRODUCED: + *socket_option_value = &on_content_produced_application_; + break; + + default: + return SOCKET_OPTION_NOT_GET; + } + + return SOCKET_OPTION_GET; + }); +} + +int TLSProducerSocket::getSocketOption( + int socket_option_key, ProducerContentCallback &socket_option_value) { + return rescheduleOnIOServiceWithReference( + socket_option_key, socket_option_value, + [this](int socket_option_key, + ProducerContentCallback &socket_option_value) -> int { + switch (socket_option_key) { + case ProducerCallbacksOptions::CONTENT_PRODUCED: + socket_option_value = on_content_produced_application_; + break; + + default: + return SOCKET_OPTION_NOT_GET; + } + + return SOCKET_OPTION_GET; + }); +} + +int TLSProducerSocket::getSocketOption( + int socket_option_key, ProducerInterestCallback &socket_option_value) { + // Reschedule the function on the io_service to avoid race condition in case + // setSocketOption is called while the io_service is running. + return rescheduleOnIOServiceWithReference( + socket_option_key, socket_option_value, + [this](int socket_option_key, + ProducerInterestCallback &socket_option_value) -> int { + switch (socket_option_key) { + case ProducerCallbacksOptions::INTEREST_INPUT: + socket_option_value = on_interest_input_decrypted_; + break; + + case ProducerCallbacksOptions::INTEREST_DROP: + socket_option_value = on_interest_dropped_input_buffer_; + break; + + case ProducerCallbacksOptions::INTEREST_PASS: + socket_option_value = on_interest_inserted_input_buffer_; + break; + + case ProducerCallbacksOptions::CACHE_HIT: + socket_option_value = on_interest_satisfied_output_buffer_; + break; + + case ProducerCallbacksOptions::CACHE_MISS: + socket_option_value = on_interest_process_decrypted_; + break; + + default: + return SOCKET_OPTION_NOT_GET; + } + + return SOCKET_OPTION_GET; + }); +} + +} // namespace implementation + +} // namespace transport diff --git a/libtransport/src/implementation/tls_socket_producer.h b/libtransport/src/implementation/tls_socket_producer.h new file mode 100644 index 000000000..e910c8259 --- /dev/null +++ b/libtransport/src/implementation/tls_socket_producer.h @@ -0,0 +1,163 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include +#include +#include + +namespace transport { +namespace implementation { + +class P2PSecureProducerSocket; + +class TLSProducerSocket : virtual public ProducerSocket { + friend class P2PSecureProducerSocket; + + public: + explicit TLSProducerSocket(interface::ProducerSocket *producer_socket, + P2PSecureProducerSocket *parent, + const Name &handshake_name); + + ~TLSProducerSocket(); + + uint32_t produce(Name content_name, const uint8_t *buffer, size_t buffer_size, + bool is_last = true, uint32_t start_offset = 0) override { + return produce(content_name, utils::MemBuf::copyBuffer(buffer, buffer_size), + is_last, start_offset); + } + + uint32_t produce(Name content_name, std::unique_ptr &&buffer, + bool is_last = true, uint32_t start_offset = 0) override; + + void produce(ContentObject &content_object) override; + + void asyncProduce(const Name &suffix, const uint8_t *buf, size_t buffer_size, + bool is_last = true, + uint32_t *start_offset = nullptr) override; + + void asyncProduce(Name content_name, std::unique_ptr &&buffer, + bool is_last, uint32_t offset, + uint32_t **last_segment = nullptr) override; + + void asyncProduce(ContentObject &content_object) override; + + virtual void accept(); + + virtual int async_accept(); + + virtual int setSocketOption( + int socket_option_key, + ProducerInterestCallback socket_option_value) override; + + virtual int setSocketOption( + int socket_option_key, + ProducerContentCallback socket_option_value) override; + + virtual int getSocketOption( + int socket_option_key, + ProducerContentCallback **socket_option_value) override; + + int getSocketOption(int socket_option_key, + ProducerContentCallback &socket_option_value); + + int getSocketOption(int socket_option_key, + ProducerInterestCallback &socket_option_value); + + using ProducerSocket::getSocketOption; + using ProducerSocket::onInterest; + using ProducerSocket::setSocketOption; + + protected: + /* Callback invoked once an interest has been received and its payload + * decrypted */ + ProducerInterestCallback on_interest_input_decrypted_; + ProducerInterestCallback on_interest_process_decrypted_; + ProducerContentCallback on_content_produced_application_; + + std::mutex mtx_; + + /* Condition variable for the wait */ + std::condition_variable cv_; + + /* Bool variable, true if there is something to read (an interest arrived) */ + bool something_to_read_; + + /* First interest that open a secure connection */ + transport::core::Name name_; + + /* SSL handle */ + SSL *ssl_; + SSL_CTX *ctx_; + + Packet::MemBufPtr packet_; + + std::unique_ptr head_; + std::uint32_t last_segment_; + std::shared_ptr payload_; + std::uint32_t key_id_; + + std::thread *handshake; + P2PSecureProducerSocket *parent_; + + bool first_; + Name handshake_name_; + int tls_chunks_; + int to_call_oncontentproduced_; + + bool still_writing_; + + utils::EventThread encryption_thread_; + + void onInterest(ProducerSocket &p, Interest &interest); + void cacheMiss(interface::ProducerSocket &p, Interest &interest); + + /* Return the number of read bytes in readbytes */ + static int read(BIO *b, char *buf, size_t size, size_t *readbytes); + + /* Return the number of read bytes in the return param */ + static int readOld(BIO *h, char *buf, int size); + + /* Return the number of written bytes in written */ + static int write(BIO *b, const char *buf, size_t size, size_t *written); + + /* Return the number of written bytes in the return param */ + static int writeOld(BIO *h, const char *buf, int num); + + static long ctrl(BIO *b, int cmd, long num, void *ptr); + + static int addHicnKeyIdCb(SSL *s, unsigned int ext_type, unsigned int context, + const unsigned char **out, size_t *outlen, X509 *x, + size_t chainidx, int *al, void *add_arg); + + static void freeHicnKeyIdCb(SSL *s, unsigned int ext_type, + unsigned int context, const unsigned char *out, + void *add_arg); + + static int parseHicnKeyIdCb(SSL *s, unsigned int ext_type, + unsigned int context, const unsigned char *in, + size_t inlen, X509 *x, size_t chainidx, int *al, + void *add_arg); + + void onContentProduced(interface::ProducerSocket &p, + const std::error_code &err, uint64_t bytes_written); +}; + +} // namespace implementation + +} // end namespace transport diff --git a/libtransport/src/interfaces/CMakeLists.txt b/libtransport/src/interfaces/CMakeLists.txt new file mode 100644 index 000000000..daf4b31e5 --- /dev/null +++ b/libtransport/src/interfaces/CMakeLists.txt @@ -0,0 +1,39 @@ +# 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) + +list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/rtc_socket_producer.cc + ${CMAKE_CURRENT_SOURCE_DIR}/socket_producer.cc + ${CMAKE_CURRENT_SOURCE_DIR}/socket_consumer.cc + ${CMAKE_CURRENT_SOURCE_DIR}/callbacks.cc +) + +if (${OPENSSL_VERSION} VERSION_EQUAL "1.1.1a" OR ${OPENSSL_VERSION} VERSION_GREATER "1.1.1a") + list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_producer.cc + ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_consumer.cc + ${CMAKE_CURRENT_SOURCE_DIR}/tls_rtc_socket_producer.cc + ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_producer.cc + ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_consumer.cc + ) + + list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/tls_rtc_socket_producer.h + ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_producer.h + ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_consumer.h + ) +endif() + +set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) diff --git a/libtransport/src/interfaces/callbacks.cc b/libtransport/src/interfaces/callbacks.cc new file mode 100644 index 000000000..6869ac3f7 --- /dev/null +++ b/libtransport/src/interfaces/callbacks.cc @@ -0,0 +1,26 @@ +/* + * 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. + */ + +#include + +namespace transport { + +namespace interface { + +std::nullptr_t VOID_HANDLER = nullptr; + +} // namespace interface + +} // namespace transport \ No newline at end of file diff --git a/libtransport/src/interfaces/p2psecure_socket_consumer.cc b/libtransport/src/interfaces/p2psecure_socket_consumer.cc new file mode 100644 index 000000000..2fa8bb6e3 --- /dev/null +++ b/libtransport/src/interfaces/p2psecure_socket_consumer.cc @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#include + +#include + +namespace transport { +namespace interface { + +P2PSecureConsumerSocket::P2PSecureConsumerSocket(int handshake_protocol, + int protocol) + : ConsumerSocket() { + socket_ = std::unique_ptr( + new implementation::P2PSecureConsumerSocket(this, handshake_protocol, + protocol)); +} + +} // namespace interface +} // namespace transport diff --git a/libtransport/src/interfaces/p2psecure_socket_producer.cc b/libtransport/src/interfaces/p2psecure_socket_producer.cc new file mode 100644 index 000000000..37352259c --- /dev/null +++ b/libtransport/src/interfaces/p2psecure_socket_producer.cc @@ -0,0 +1,34 @@ +/* + * 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. + */ + +#include + +#include + +namespace transport { +namespace interface { + +P2PSecureProducerSocket::P2PSecureProducerSocket() { + socket_ = std::make_unique(this); +} + +P2PSecureProducerSocket::P2PSecureProducerSocket( + bool rtc, const std::shared_ptr &identity) { + socket_ = std::make_unique(this, rtc, + identity); +} + +} // namespace interface +} // namespace transport diff --git a/libtransport/src/interfaces/rtc_socket_producer.cc b/libtransport/src/interfaces/rtc_socket_producer.cc new file mode 100644 index 000000000..07d72db7e --- /dev/null +++ b/libtransport/src/interfaces/rtc_socket_producer.cc @@ -0,0 +1,29 @@ +/* + * 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. + */ + +#include + +#include + +namespace transport { +namespace interface { + +RTCProducerSocket::RTCProducerSocket() : ProducerSocket(false) { + socket_ = std::make_unique(this); +} + +} // namespace interface + +} // namespace transport diff --git a/libtransport/src/interfaces/socket_consumer.cc b/libtransport/src/interfaces/socket_consumer.cc new file mode 100644 index 000000000..b4be16ade --- /dev/null +++ b/libtransport/src/interfaces/socket_consumer.cc @@ -0,0 +1,196 @@ +/* + * 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. + */ + +#include + +#include + +namespace transport { +namespace interface { + +ConsumerSocket::ConsumerSocket(int protocol) { + socket_ = std::make_unique(this, protocol); +} + +ConsumerSocket::ConsumerSocket() {} + +ConsumerSocket::~ConsumerSocket() { socket_->stop(); } + +void ConsumerSocket::connect() { socket_->connect(); } + +bool ConsumerSocket::isRunning() { return socket_->isRunning(); } + +int ConsumerSocket::consume(const Name &name) { return socket_->consume(name); } + +int ConsumerSocket::asyncConsume(const Name &name) { + return socket_->asyncConsume(name); +} + +void ConsumerSocket::stop() { socket_->stop(); } + +void ConsumerSocket::resume() { socket_->resume(); } + +bool ConsumerSocket::verifyKeyPackets() { return socket_->verifyKeyPackets(); } + +asio::io_service &ConsumerSocket::getIoService() { + return socket_->getIoService(); +} + +int ConsumerSocket::setSocketOption(int socket_option_key, + ReadCallback *socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::getSocketOption(int socket_option_key, + ReadCallback **socket_option_value) { + return socket_->getSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::setSocketOption(int socket_option_key, + double socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::setSocketOption(int socket_option_key, + uint32_t socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::setSocketOption(int socket_option_key, + std::nullptr_t socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::setSocketOption(int socket_option_key, + bool socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::setSocketOption( + int socket_option_key, ConsumerContentObjectCallback socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::setSocketOption( + int socket_option_key, + ConsumerContentObjectVerificationCallback socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::setSocketOption( + int socket_option_key, ConsumerInterestCallback socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::setSocketOption( + int socket_option_key, + ConsumerContentObjectVerificationFailedCallback socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::setSocketOption(int socket_option_key, + IcnObserver *socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::setSocketOption( + int socket_option_key, + const std::shared_ptr &socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::setSocketOption(int socket_option_key, + const std::string &socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::setSocketOption(int socket_option_key, + ConsumerTimerCallback socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::getSocketOption(int socket_option_key, + double &socket_option_value) { + return socket_->getSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::getSocketOption(int socket_option_key, + uint32_t &socket_option_value) { + return socket_->getSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::getSocketOption(int socket_option_key, + bool &socket_option_value) { + return socket_->getSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::getSocketOption(int socket_option_key, + Name **socket_option_value) { + return socket_->getSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::getSocketOption( + int socket_option_key, + ConsumerContentObjectCallback **socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::getSocketOption( + int socket_option_key, + ConsumerContentObjectVerificationCallback **socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::getSocketOption( + int socket_option_key, ConsumerInterestCallback **socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::getSocketOption( + int socket_option_key, + ConsumerContentObjectVerificationFailedCallback **socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::getSocketOption(int socket_option_key, + IcnObserver **socket_option_value) { + return socket_->getSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::getSocketOption( + int socket_option_key, + std::shared_ptr &socket_option_value) { + return socket_->getSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::getSocketOption(int socket_option_key, + std::string &socket_option_value) { + return socket_->getSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::getSocketOption( + int socket_option_key, + interface::TransportStatistics **socket_option_value) { + return socket_->getSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::getSocketOption( + int socket_option_key, ConsumerTimerCallback **socket_option_value) { + return socket_->getSocketOption(socket_option_key, socket_option_value); +} + +} // namespace interface + +} // namespace transport diff --git a/libtransport/src/interfaces/socket_producer.cc b/libtransport/src/interfaces/socket_producer.cc new file mode 100644 index 000000000..679f7ccf4 --- /dev/null +++ b/libtransport/src/interfaces/socket_producer.cc @@ -0,0 +1,198 @@ +/* + * 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. + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +namespace transport { + +namespace interface { + +using namespace core; + +ProducerSocket::ProducerSocket(int protocol) { + if (protocol != 0) { + throw std::runtime_error("Production protocol must be 0."); + } + + socket_ = std::make_unique(this); +} + +ProducerSocket::ProducerSocket(bool) {} + +ProducerSocket::~ProducerSocket() { socket_->stop(); } + +void ProducerSocket::connect() { socket_->connect(); } + +bool ProducerSocket::isRunning() { return socket_->isRunning(); } + +uint32_t ProducerSocket::produce(Name content_name, + std::unique_ptr &&buffer, + bool is_last, uint32_t start_offset) { + return socket_->produce(content_name, std::move(buffer), is_last, + start_offset); +} + +void ProducerSocket::produce(ContentObject &content_object) { + return socket_->produce(content_object); +} + +void ProducerSocket::produce(std::unique_ptr &&buffer) { + socket_->produce(std::move(buffer)); +} + +void ProducerSocket::asyncProduce(Name content_name, + std::unique_ptr &&buffer, + bool is_last, uint32_t offset, + uint32_t **last_segment) { + return socket_->asyncProduce(content_name, std::move(buffer), is_last, offset, + last_segment); +} + +void ProducerSocket::asyncProduce(ContentObject &content_object) { + return socket_->asyncProduce(content_object); +} + +void ProducerSocket::registerPrefix(const Prefix &producer_namespace) { + return socket_->registerPrefix(producer_namespace); +} + +void ProducerSocket::serveForever() { return socket_->serveForever(); } + +void ProducerSocket::stop() { return socket_->stop(); } + +asio::io_service &ProducerSocket::getIoService() { + return socket_->getIoService(); +}; + +int ProducerSocket::setSocketOption(int socket_option_key, + uint32_t socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ProducerSocket::setSocketOption(int socket_option_key, + std::nullptr_t socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ProducerSocket::setSocketOption(int socket_option_key, + bool socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ProducerSocket::setSocketOption(int socket_option_key, + Name *socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ProducerSocket::setSocketOption(int socket_option_key, + std::list socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ProducerSocket::setSocketOption( + int socket_option_key, ProducerContentObjectCallback socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ProducerSocket::setSocketOption( + int socket_option_key, ProducerInterestCallback socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ProducerSocket::setSocketOption( + int socket_option_key, ProducerContentCallback socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ProducerSocket::setSocketOption(int socket_option_key, + HashAlgorithm socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ProducerSocket::setSocketOption(int socket_option_key, + utils::CryptoSuite socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ProducerSocket::setSocketOption( + int socket_option_key, + const std::shared_ptr &socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ProducerSocket::getSocketOption(int socket_option_key, + uint32_t &socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ProducerSocket::setSocketOption(int socket_option_key, + const std::string &socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ProducerSocket::getSocketOption(int socket_option_key, + bool &socket_option_value) { + return socket_->getSocketOption(socket_option_key, socket_option_value); +} + +int ProducerSocket::getSocketOption(int socket_option_key, + std::list &socket_option_value) { + return socket_->getSocketOption(socket_option_key, socket_option_value); +} + +int ProducerSocket::getSocketOption( + int socket_option_key, + ProducerContentObjectCallback **socket_option_value) { + return socket_->getSocketOption(socket_option_key, socket_option_value); +} + +int ProducerSocket::getSocketOption( + int socket_option_key, ProducerContentCallback **socket_option_value) { + return socket_->getSocketOption(socket_option_key, socket_option_value); +} + +int ProducerSocket::getSocketOption( + int socket_option_key, ProducerInterestCallback **socket_option_value) { + return socket_->getSocketOption(socket_option_key, socket_option_value); +} + +int ProducerSocket::getSocketOption(int socket_option_key, + HashAlgorithm &socket_option_value) { + return socket_->getSocketOption(socket_option_key, socket_option_value); +} + +int ProducerSocket::getSocketOption(int socket_option_key, + utils::CryptoSuite &socket_option_value) { + return socket_->getSocketOption(socket_option_key, socket_option_value); +} + +int ProducerSocket::getSocketOption( + int socket_option_key, + std::shared_ptr &socket_option_value) { + return socket_->getSocketOption(socket_option_key, socket_option_value); +} + +} // namespace interface + +} // namespace transport diff --git a/libtransport/src/interfaces/tls_rtc_socket_producer.cc b/libtransport/src/interfaces/tls_rtc_socket_producer.cc new file mode 100644 index 000000000..132f34721 --- /dev/null +++ b/libtransport/src/interfaces/tls_rtc_socket_producer.cc @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#include + +#include + +namespace transport { +namespace interface { + +TLSRTCProducerSocket::TLSRTCProducerSocket( + implementation::TLSRTCProducerSocket *implementation) { + socket_ = + std::unique_ptr(implementation); +} + +TLSRTCProducerSocket::~TLSRTCProducerSocket() { socket_.release(); } + +} // namespace interface +} // namespace transport diff --git a/libtransport/src/interfaces/tls_rtc_socket_producer.h b/libtransport/src/interfaces/tls_rtc_socket_producer.h new file mode 100644 index 000000000..434edb522 --- /dev/null +++ b/libtransport/src/interfaces/tls_rtc_socket_producer.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 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 + +namespace transport { + +namespace implementation { +class TLSRTCProducerSocket; +} + +namespace interface { + +class TLSRTCProducerSocket : public ProducerSocket { + public: + TLSRTCProducerSocket(implementation::TLSRTCProducerSocket *implementation); + ~TLSRTCProducerSocket(); +}; + +} // namespace interface + +} // end namespace transport \ No newline at end of file diff --git a/libtransport/src/interfaces/tls_socket_consumer.cc b/libtransport/src/interfaces/tls_socket_consumer.cc new file mode 100644 index 000000000..d87642f73 --- /dev/null +++ b/libtransport/src/interfaces/tls_socket_consumer.cc @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#include + +#include + +namespace transport { +namespace interface { + +TLSConsumerSocket::TLSConsumerSocket( + implementation::TLSConsumerSocket *implementation) { + socket_ = std::unique_ptr(implementation); +} + +TLSConsumerSocket::~TLSConsumerSocket() { socket_.release(); } + +} // namespace interface +} // namespace transport diff --git a/libtransport/src/interfaces/tls_socket_consumer.h b/libtransport/src/interfaces/tls_socket_consumer.h new file mode 100644 index 000000000..845a9181f --- /dev/null +++ b/libtransport/src/interfaces/tls_socket_consumer.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 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 + +namespace transport { + +namespace implementation { +class TLSConsumerSocket; +} + +namespace interface { + +class TLSConsumerSocket : public ConsumerSocket { + public: + TLSConsumerSocket(implementation::TLSConsumerSocket *implementation); + ~TLSConsumerSocket(); +}; + +} // namespace interface + +} // end namespace transport diff --git a/libtransport/src/interfaces/tls_socket_producer.cc b/libtransport/src/interfaces/tls_socket_producer.cc new file mode 100644 index 000000000..44aa0cf8b --- /dev/null +++ b/libtransport/src/interfaces/tls_socket_producer.cc @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#include + +#include + +namespace transport { +namespace interface { + +TLSProducerSocket::TLSProducerSocket( + implementation::TLSProducerSocket *implementation) { + socket_ = std::unique_ptr(implementation); +} + +TLSProducerSocket::~TLSProducerSocket() { socket_.release(); } + +} // namespace interface +} // namespace transport diff --git a/libtransport/src/interfaces/tls_socket_producer.h b/libtransport/src/interfaces/tls_socket_producer.h new file mode 100644 index 000000000..3c662176a --- /dev/null +++ b/libtransport/src/interfaces/tls_socket_producer.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 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 + +namespace transport { + +namespace implementation { +class TLSProducerSocket; +} + +namespace interface { + +class TLSProducerSocket : public ProducerSocket { + public: + TLSProducerSocket(implementation::TLSProducerSocket *implementation); + ~TLSProducerSocket(); +}; + +} // namespace interface + +} // end namespace transport diff --git a/libtransport/src/protocols/CMakeLists.txt b/libtransport/src/protocols/CMakeLists.txt new file mode 100644 index 000000000..3156d9ae9 --- /dev/null +++ b/libtransport/src/protocols/CMakeLists.txt @@ -0,0 +1,75 @@ +# 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) + +list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/indexer.h + ${CMAKE_CURRENT_SOURCE_DIR}/incremental_indexer.h + ${CMAKE_CURRENT_SOURCE_DIR}/manifest_incremental_indexer.h + ${CMAKE_CURRENT_SOURCE_DIR}/reassembly.h + ${CMAKE_CURRENT_SOURCE_DIR}/datagram_reassembly.h + ${CMAKE_CURRENT_SOURCE_DIR}/byte_stream_reassembly.h + ${CMAKE_CURRENT_SOURCE_DIR}/congestion_window_protocol.h + ${CMAKE_CURRENT_SOURCE_DIR}/packet_manager.h + ${CMAKE_CURRENT_SOURCE_DIR}/rate_estimation.h + ${CMAKE_CURRENT_SOURCE_DIR}/protocol.h + ${CMAKE_CURRENT_SOURCE_DIR}/raaqm.h + ${CMAKE_CURRENT_SOURCE_DIR}/raaqm_data_path.h + ${CMAKE_CURRENT_SOURCE_DIR}/cbr.h + ${CMAKE_CURRENT_SOURCE_DIR}/rtc.h + ${CMAKE_CURRENT_SOURCE_DIR}/rtc_data_path.h + ${CMAKE_CURRENT_SOURCE_DIR}/errors.h + ${CMAKE_CURRENT_SOURCE_DIR}/verification_manager.h + ${CMAKE_CURRENT_SOURCE_DIR}/data_processing_events.h +) + +list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/indexer.cc + ${CMAKE_CURRENT_SOURCE_DIR}/incremental_indexer.cc + ${CMAKE_CURRENT_SOURCE_DIR}/manifest_incremental_indexer.cc + ${CMAKE_CURRENT_SOURCE_DIR}/reassembly.cc + ${CMAKE_CURRENT_SOURCE_DIR}/datagram_reassembly.cc + ${CMAKE_CURRENT_SOURCE_DIR}/byte_stream_reassembly.cc + ${CMAKE_CURRENT_SOURCE_DIR}/protocol.cc + ${CMAKE_CURRENT_SOURCE_DIR}/raaqm.cc + ${CMAKE_CURRENT_SOURCE_DIR}/rate_estimation.cc + ${CMAKE_CURRENT_SOURCE_DIR}/raaqm_data_path.cc + ${CMAKE_CURRENT_SOURCE_DIR}/cbr.cc + ${CMAKE_CURRENT_SOURCE_DIR}/rtc.cc + ${CMAKE_CURRENT_SOURCE_DIR}/rtc_data_path.cc + ${CMAKE_CURRENT_SOURCE_DIR}/errors.cc + ${CMAKE_CURRENT_SOURCE_DIR}/verification_manager.cc +) + +set(RAAQM_CONFIG_INSTALL_PREFIX +${CMAKE_INSTALL_PREFIX}/etc/hicn +) + +set(raaqm_config_path + ${RAAQM_CONFIG_INSTALL_PREFIX}/consumer.conf + PARENT_SCOPE +) + +set(TRANSPORT_CONFIG + ${CMAKE_CURRENT_SOURCE_DIR}/consumer.conf +) + +install( + FILES ${TRANSPORT_CONFIG} + DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/hicn + COMPONENT lib${LIBTRANSPORT} +) + +set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file diff --git a/libtransport/src/protocols/byte_stream_reassembly.cc b/libtransport/src/protocols/byte_stream_reassembly.cc new file mode 100644 index 000000000..c2996ebc1 --- /dev/null +++ b/libtransport/src/protocols/byte_stream_reassembly.cc @@ -0,0 +1,126 @@ +/* + * 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. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace transport { + +namespace protocol { + +using namespace core; +using ReadCallback = interface::ConsumerSocket::ReadCallback; + +ByteStreamReassembly::ByteStreamReassembly( + implementation::ConsumerSocket *icn_socket, + TransportProtocol *transport_protocol) + : Reassembly(icn_socket, transport_protocol), + index_(IndexManager::invalid_index), + download_complete_(false) {} + +void ByteStreamReassembly::reassemble( + std::unique_ptr &&manifest) { + if (TRANSPORT_EXPECT_TRUE(manifest != nullptr)) { + received_packets_.emplace( + std::make_pair(manifest->getName().getSuffix(), nullptr)); + assembleContent(); + } +} + +void ByteStreamReassembly::reassemble(ContentObject::Ptr &&content_object) { + if (TRANSPORT_EXPECT_TRUE(content_object != nullptr)) { + received_packets_.emplace(std::make_pair( + content_object->getName().getSuffix(), std::move(content_object))); + assembleContent(); + } +} + +void ByteStreamReassembly::assembleContent() { + if (TRANSPORT_EXPECT_FALSE(index_ == IndexManager::invalid_index)) { + index_ = index_manager_->getNextReassemblySegment(); + if (index_ == IndexManager::invalid_index) { + return; + } + } + + auto it = received_packets_.find((const unsigned int)index_); + while (it != received_packets_.end()) { + // Check if valid packet + if (it->second) { + copyContent(*it->second); + } + + received_packets_.erase(it); + index_ = index_manager_->getNextReassemblySegment(); + it = received_packets_.find((const unsigned int)index_); + } + + if (!download_complete_ && index_ != IndexManager::invalid_index) { + transport_protocol_->onReassemblyFailed(index_); + } +} + +void ByteStreamReassembly::copyContent(const ContentObject &content_object) { + auto a = content_object.getPayload(); + auto payload_length = a->length(); + auto write_size = std::min(payload_length, read_buffer_->tailroom()); + auto additional_bytes = payload_length > read_buffer_->tailroom() + ? payload_length - read_buffer_->tailroom() + : 0; + + std::memcpy(read_buffer_->writableTail(), a->data(), write_size); + read_buffer_->append(write_size); + + if (!read_buffer_->tailroom()) { + notifyApplication(); + std::memcpy(read_buffer_->writableTail(), a->data() + write_size, + additional_bytes); + read_buffer_->append(additional_bytes); + } + + download_complete_ = + index_manager_->getFinalSuffix() == content_object.getName().getSuffix(); + + if (TRANSPORT_EXPECT_FALSE(download_complete_)) { + notifyApplication(); + transport_protocol_->onContentReassembled( + make_error_code(protocol_error::success)); + } +} + +void ByteStreamReassembly::reInitialize() { + index_ = IndexManager::invalid_index; + download_complete_ = false; + + received_packets_.clear(); + + // reset read buffer + ReadCallback *read_callback; + reassembly_consumer_socket_->getSocketOption( + interface::ConsumerCallbacksOptions::READ_CALLBACK, &read_callback); + + read_buffer_ = utils::MemBuf::create(read_callback->maxBufferSize()); +} + +} // namespace protocol + +} // namespace transport diff --git a/libtransport/src/protocols/byte_stream_reassembly.h b/libtransport/src/protocols/byte_stream_reassembly.h new file mode 100644 index 000000000..5e5c9ec6b --- /dev/null +++ b/libtransport/src/protocols/byte_stream_reassembly.h @@ -0,0 +1,54 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace transport { + +namespace protocol { + +class ByteStreamReassembly : public Reassembly { + public: + ByteStreamReassembly(implementation::ConsumerSocket *icn_socket, + TransportProtocol *transport_protocol); + + protected: + virtual void reassemble(core::ContentObject::Ptr &&content_object) override; + + virtual void reassemble( + std::unique_ptr &&manifest) override; + + virtual void copyContent(const core::ContentObject &content_object); + + virtual void reInitialize() override; + + private: + void assembleContent(); + + protected: + // The consumer socket + // std::unique_ptr incremental_index_manager_; + // std::unique_ptr manifest_index_manager_; + // IndexVerificationManager *index_manager_; + std::unordered_map received_packets_; + uint32_t index_; + bool download_complete_; +}; + +} // namespace protocol + +} // end namespace transport diff --git a/libtransport/src/protocols/cbr.cc b/libtransport/src/protocols/cbr.cc new file mode 100644 index 000000000..5df55bd5c --- /dev/null +++ b/libtransport/src/protocols/cbr.cc @@ -0,0 +1,52 @@ +/* + * 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. + */ + +#include + +#include + +namespace transport { + +namespace protocol { + +using namespace interface; + +CbrTransportProtocol::CbrTransportProtocol( + implementation::ConsumerSocket *icnet_socket) + : RaaqmTransportProtocol(icnet_socket) {} + +int CbrTransportProtocol::start() { return RaaqmTransportProtocol::start(); } + +void CbrTransportProtocol::reset() { + RaaqmTransportProtocol::reset(); + socket_->getSocketOption(GeneralTransportOptions::CURRENT_WINDOW_SIZE, + current_window_size_); +} + +void CbrTransportProtocol::afterDataUnsatisfied(uint64_t segment) {} + +void CbrTransportProtocol::afterContentReception( + const Interest &interest, const ContentObject &content_object) { + auto segment = content_object.getName().getSuffix(); + auto now = utils::SteadyClock::now(); + auto rtt = std::chrono::duration_cast( + now - interest_timepoints_[segment & mask]); + // Update stats + updateStats(segment, rtt.count(), now); +} + +} // end namespace protocol + +} // end namespace transport diff --git a/libtransport/src/protocols/cbr.h b/libtransport/src/protocols/cbr.h new file mode 100644 index 000000000..20129f6a3 --- /dev/null +++ b/libtransport/src/protocols/cbr.h @@ -0,0 +1,40 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace transport { + +namespace protocol { + +class CbrTransportProtocol : public RaaqmTransportProtocol { + public: + CbrTransportProtocol(implementation::ConsumerSocket *icnet_socket); + + int start() override; + + void reset() override; + + private: + void afterContentReception(const Interest &interest, + const ContentObject &content_object) override; + void afterDataUnsatisfied(uint64_t segment) override; +}; + +} // end namespace protocol + +} // end namespace transport \ No newline at end of file diff --git a/libtransport/src/protocols/congestion_window_protocol.h b/libtransport/src/protocols/congestion_window_protocol.h new file mode 100644 index 000000000..36ac6eb17 --- /dev/null +++ b/libtransport/src/protocols/congestion_window_protocol.h @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#pragma once + +namespace transport { + +namespace protocol { + +class CWindowProtocol { + protected: + virtual void increaseWindow() = 0; + virtual void decreaseWindow() = 0; +}; + +} // end namespace protocol + +} // end namespace transport diff --git a/libtransport/src/protocols/consumer.conf b/libtransport/src/protocols/consumer.conf new file mode 100644 index 000000000..1a366f32f --- /dev/null +++ b/libtransport/src/protocols/consumer.conf @@ -0,0 +1,21 @@ +; this file contais the parameters for RAAQM +autotune = no +lifetime = 500 +retransmissions = 128 +beta = 0.99 +drop = 0.003 +beta_wifi_ = 0.99 +drop_wifi_ = 0.6 +beta_lte_ = 0.99 +drop_lte_ = 0.003 +wifi_delay_ = 200 +lte_delay_ = 9000 + +alpha = 0.95 +batching_parameter = 200 + +;Choice of rate estimator: +;0 --> an estimation each $(batching_parameter) packets +;1 --> an estimation "a la TCP", estimation at the end of the download of the segment + +rate_estimator = 0 diff --git a/libtransport/src/protocols/data_processing_events.h b/libtransport/src/protocols/data_processing_events.h new file mode 100644 index 000000000..8975c2b4a --- /dev/null +++ b/libtransport/src/protocols/data_processing_events.h @@ -0,0 +1,33 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +namespace transport { +namespace protocol { + +class ContentObjectProcessingEventCallback { + public: + virtual ~ContentObjectProcessingEventCallback() = default; + virtual void onPacketDropped(core::Interest::Ptr &&i, + core::ContentObject::Ptr &&c) = 0; + virtual void onReassemblyFailed(std::uint32_t missing_segment) = 0; +}; + +} // namespace protocol +} // namespace transport diff --git a/libtransport/src/protocols/datagram_reassembly.cc b/libtransport/src/protocols/datagram_reassembly.cc new file mode 100644 index 000000000..abd7e984d --- /dev/null +++ b/libtransport/src/protocols/datagram_reassembly.cc @@ -0,0 +1,36 @@ +/* + * 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. + */ + +#include + +namespace transport { + +namespace protocol { + +DatagramReassembly::DatagramReassembly( + implementation::ConsumerSocket* icn_socket, + TransportProtocol* transport_protocol) + : Reassembly(icn_socket, transport_protocol) {} + +void DatagramReassembly::reassemble(core::ContentObject::Ptr&& content_object) { + read_buffer_ = content_object->getPayload(); + Reassembly::notifyApplication(); +} + +void DatagramReassembly::reInitialize() {} + +} // namespace protocol + +} // namespace transport diff --git a/libtransport/src/protocols/datagram_reassembly.h b/libtransport/src/protocols/datagram_reassembly.h new file mode 100644 index 000000000..2427ae62f --- /dev/null +++ b/libtransport/src/protocols/datagram_reassembly.h @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace transport { + +namespace protocol { + +class DatagramReassembly : public Reassembly { + public: + DatagramReassembly(implementation::ConsumerSocket *icn_socket, + TransportProtocol *transport_protocol); + + virtual void reassemble(core::ContentObject::Ptr &&content_object) override; + virtual void reInitialize() override; + virtual void reassemble( + std::unique_ptr &&manifest) override { + return; + } +}; + +} // namespace protocol + +} // end namespace transport diff --git a/libtransport/src/protocols/errors.cc b/libtransport/src/protocols/errors.cc new file mode 100644 index 000000000..eefb6f957 --- /dev/null +++ b/libtransport/src/protocols/errors.cc @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020 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 + +namespace transport { +namespace protocol { + +const std::error_category& protocol_category() { + static protocol_category_impl instance; + + return instance; +} + +const char* protocol_category_impl::name() const throw() { + return "transport::protocol::error"; +} + +std::string protocol_category_impl::message(int ev) const { + switch (static_cast(ev)) { + case protocol_error::success: { + return "Success"; + } + case protocol_error::signature_verification_failed: { + return "Signature verification failed."; + } + case protocol_error::integrity_verification_failed: { + return "Integrity verification failed"; + } + case protocol_error::no_verifier_provided: { + return "Transport cannot get any verifier for the given data."; + } + case protocol_error::io_error: { + return "Conectivity error between transport and local forwarder"; + } + case protocol_error::max_retransmissions_error: { + return "Transport protocol reached max number of retransmissions allowed " + "for the same interest."; + } + case protocol_error::session_aborted: { + return "The session has been aborted by the application."; + } + default: { return "Unknown protocol error"; } + } +} + +} // namespace protocol +} // namespace transport \ No newline at end of file diff --git a/libtransport/src/protocols/errors.h b/libtransport/src/protocols/errors.h new file mode 100644 index 000000000..cb3d3474e --- /dev/null +++ b/libtransport/src/protocols/errors.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2020 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 +#include + +namespace transport { +namespace protocol { + +/** + * @brief Get the default server error category. + * @return The default server error category instance. + * + * @warning The first call to this function is thread-safe only starting with + * C++11. + */ +const std::error_category& protocol_category(); + +/** + * The list of errors. + */ +enum class protocol_error { + success = 0, + signature_verification_failed, + integrity_verification_failed, + no_verifier_provided, + io_error, + max_retransmissions_error, + session_aborted, +}; + +/** + * @brief Create an error_code instance for the given error. + * @param error The error. + * @return The error_code instance. + */ +inline std::error_code make_error_code(protocol_error error) { + return std::error_code(static_cast(error), protocol_category()); +} + +/** + * @brief Create an error_condition instance for the given error. + * @param error The error. + * @return The error_condition instance. + */ +inline std::error_condition make_error_condition(protocol_error error) { + return std::error_condition(static_cast(error), protocol_category()); +} + +/** + * @brief A server error category. + */ +class protocol_category_impl : public std::error_category { + public: + /** + * @brief Get the name of the category. + * @return The name of the category. + */ + virtual const char* name() const throw(); + + /** + * @brief Get the error message for a given error. + * @param ev The error numeric value. + * @return The message associated to the error. + */ + virtual std::string message(int ev) const; +}; +} // namespace protocol +} // namespace transport + +namespace std { +// namespace system { +template <> +struct is_error_code_enum<::transport::protocol::protocol_error> + : public std::true_type {}; +// } // namespace system +} // namespace std \ No newline at end of file diff --git a/libtransport/src/protocols/incremental_indexer.cc b/libtransport/src/protocols/incremental_indexer.cc new file mode 100644 index 000000000..e590b4fee --- /dev/null +++ b/libtransport/src/protocols/incremental_indexer.cc @@ -0,0 +1,53 @@ +/* + * 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. + */ + +#include + +#include +#include + +namespace transport { +namespace protocol { + +void IncrementalIndexer::onContentObject( + core::Interest::Ptr &&interest, core::ContentObject::Ptr &&content_object) { + using namespace interface; + + if (TRANSPORT_EXPECT_FALSE(content_object->testRst())) { + final_suffix_ = content_object->getName().getSuffix(); + } + + auto ret = verification_manager_->onPacketToVerify(*content_object); + + switch (ret) { + case VerificationPolicy::ACCEPT_PACKET: { + reassembly_->reassemble(std::move(content_object)); + break; + } + case VerificationPolicy::DROP_PACKET: { + transport_protocol_->onPacketDropped(std::move(interest), + std::move(content_object)); + break; + } + case VerificationPolicy::ABORT_SESSION: { + transport_protocol_->onContentReassembled( + make_error_code(protocol_error::session_aborted)); + break; + } + } +} + +} // namespace protocol +} // namespace transport \ No newline at end of file diff --git a/libtransport/src/protocols/incremental_indexer.h b/libtransport/src/protocols/incremental_indexer.h new file mode 100644 index 000000000..20c5e4759 --- /dev/null +++ b/libtransport/src/protocols/incremental_indexer.h @@ -0,0 +1,143 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include + +#include + +namespace transport { + +namespace interface { +class ConsumerSocket; +} + +namespace protocol { + +class Reassembly; +class TransportProtocol; + +class IncrementalIndexer : public Indexer { + public: + IncrementalIndexer(implementation::ConsumerSocket *icn_socket, + TransportProtocol *transport, Reassembly *reassembly) + : socket_(icn_socket), + reassembly_(reassembly), + transport_protocol_(transport), + final_suffix_(std::numeric_limits::max()), + first_suffix_(0), + next_download_suffix_(0), + next_reassembly_suffix_(0), + verification_manager_( + std::make_unique(icn_socket)) { + if (reassembly_) { + reassembly_->setIndexer(this); + } + } + + IncrementalIndexer(const IncrementalIndexer &) = delete; + + IncrementalIndexer(IncrementalIndexer &&other) + : socket_(other.socket_), + reassembly_(other.reassembly_), + transport_protocol_(other.transport_protocol_), + final_suffix_(other.final_suffix_), + first_suffix_(other.first_suffix_), + next_download_suffix_(other.next_download_suffix_), + next_reassembly_suffix_(other.next_reassembly_suffix_), + verification_manager_(std::move(other.verification_manager_)) { + if (reassembly_) { + reassembly_->setIndexer(this); + } + } + + /** + * + */ + virtual ~IncrementalIndexer() {} + + TRANSPORT_ALWAYS_INLINE virtual void reset( + std::uint32_t offset = 0) override { + final_suffix_ = std::numeric_limits::max(); + next_download_suffix_ = offset; + next_reassembly_suffix_ = offset; + } + + /** + * Retrieve from the manifest the next suffix to retrieve. + */ + TRANSPORT_ALWAYS_INLINE virtual uint32_t getNextSuffix() override { + return next_download_suffix_ <= final_suffix_ ? next_download_suffix_++ + : IndexManager::invalid_index; + } + + TRANSPORT_ALWAYS_INLINE virtual void setFirstSuffix( + uint32_t suffix) override { + first_suffix_ = suffix; + } + + /** + * Retrive the next segment to be reassembled. + */ + TRANSPORT_ALWAYS_INLINE virtual uint32_t getNextReassemblySegment() override { + return next_reassembly_suffix_ <= final_suffix_ + ? next_reassembly_suffix_++ + : IndexManager::invalid_index; + } + + TRANSPORT_ALWAYS_INLINE virtual bool isFinalSuffixDiscovered() override { + return final_suffix_ != std::numeric_limits::max(); + } + + TRANSPORT_ALWAYS_INLINE virtual uint32_t getFinalSuffix() override { + return final_suffix_; + } + + void onContentObject(core::Interest::Ptr &&interest, + core::ContentObject::Ptr &&content_object) override; + + TRANSPORT_ALWAYS_INLINE void setReassembly(Reassembly *reassembly) { + reassembly_ = reassembly; + + if (reassembly_) { + reassembly_->setIndexer(this); + } + } + + TRANSPORT_ALWAYS_INLINE bool onKeyToVerify() override { + return verification_manager_->onKeyToVerify(); + } + + protected: + implementation::ConsumerSocket *socket_; + Reassembly *reassembly_; + TransportProtocol *transport_protocol_; + uint32_t final_suffix_; + uint32_t first_suffix_; + uint32_t next_download_suffix_; + uint32_t next_reassembly_suffix_; + std::unique_ptr verification_manager_; +}; + +} // end namespace protocol + +} // end namespace transport diff --git a/libtransport/src/protocols/indexer.cc b/libtransport/src/protocols/indexer.cc new file mode 100644 index 000000000..ca12330a6 --- /dev/null +++ b/libtransport/src/protocols/indexer.cc @@ -0,0 +1,79 @@ +/* + * 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. + */ + +#include + +#include +#include +#include +#include + +namespace transport { +namespace protocol { + +IndexManager::IndexManager(implementation::ConsumerSocket *icn_socket, + TransportProtocol *transport, Reassembly *reassembly) + : indexer_(std::make_unique(icn_socket, transport, + reassembly)), + first_segment_received_(false), + icn_socket_(icn_socket), + transport_(transport), + reassembly_(reassembly) {} + +void IndexManager::onContentObject(core::Interest::Ptr &&interest, + core::ContentObject::Ptr &&content_object) { + if (first_segment_received_) { + indexer_->onContentObject(std::move(interest), std::move(content_object)); + } else { + std::uint32_t segment_number = interest->getName().getSuffix(); + + if (segment_number == 0) { + // Check if manifest + if (content_object->getPayloadType() == PayloadType::MANIFEST) { + IncrementalIndexer *indexer = + static_cast(indexer_.release()); + indexer_ = + std::make_unique(std::move(*indexer)); + delete indexer; + } + + indexer_->onContentObject(std::move(interest), std::move(content_object)); + auto it = interest_data_set_.begin(); + while (it != interest_data_set_.end()) { + indexer_->onContentObject( + std::move(const_cast(it->first)), + std::move(const_cast(it->second))); + it = interest_data_set_.erase(it); + } + + first_segment_received_ = true; + } else { + interest_data_set_.emplace(std::move(interest), + std::move(content_object)); + } + } +} + +bool IndexManager::onKeyToVerify() { return indexer_->onKeyToVerify(); } + +void IndexManager::reset(std::uint32_t offset) { + indexer_ = std::make_unique(icn_socket_, transport_, + reassembly_); + first_segment_received_ = false; + interest_data_set_.clear(); +} + +} // namespace protocol +} // namespace transport diff --git a/libtransport/src/protocols/indexer.h b/libtransport/src/protocols/indexer.h new file mode 100644 index 000000000..8213a1503 --- /dev/null +++ b/libtransport/src/protocols/indexer.h @@ -0,0 +1,106 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +#include + +namespace transport { + +namespace implementation { +class ConsumerSocket; +} + +namespace protocol { + +class Reassembly; +class TransportProtocol; + +class Indexer { + public: + /** + * + */ + virtual ~Indexer() = default; + /** + * Retrieve from the manifest the next suffix to retrieve. + */ + virtual uint32_t getNextSuffix() = 0; + + virtual void setFirstSuffix(uint32_t suffix) = 0; + + /** + * Retrive the next segment to be reassembled. + */ + virtual uint32_t getNextReassemblySegment() = 0; + + virtual bool isFinalSuffixDiscovered() = 0; + + virtual uint32_t getFinalSuffix() = 0; + + virtual void reset(std::uint32_t offset = 0) = 0; + + virtual void onContentObject(core::Interest::Ptr &&interest, + core::ContentObject::Ptr &&content_object) = 0; + + virtual bool onKeyToVerify() = 0; +}; + +class IndexManager : Indexer { + public: + static constexpr uint32_t invalid_index = ~0; + + IndexManager(implementation::ConsumerSocket *icn_socket, + TransportProtocol *transport, Reassembly *reassembly); + + uint32_t getNextSuffix() override { return indexer_->getNextSuffix(); } + + void setFirstSuffix(uint32_t suffix) override { + indexer_->setFirstSuffix(suffix); + } + + uint32_t getNextReassemblySegment() override { + return indexer_->getNextReassemblySegment(); + } + + bool isFinalSuffixDiscovered() override { + return indexer_->isFinalSuffixDiscovered(); + } + + uint32_t getFinalSuffix() override { return indexer_->getFinalSuffix(); } + + void reset(std::uint32_t offset = 0) override; + + void onContentObject(core::Interest::Ptr &&interest, + core::ContentObject::Ptr &&content_object) override; + + bool onKeyToVerify() override; + + private: + std::unique_ptr indexer_; + bool first_segment_received_; + std::set> + interest_data_set_; + implementation::ConsumerSocket *icn_socket_; + TransportProtocol *transport_; + Reassembly *reassembly_; +}; + +} // end namespace protocol + +} // end namespace transport diff --git a/libtransport/src/protocols/manifest_incremental_indexer.cc b/libtransport/src/protocols/manifest_incremental_indexer.cc new file mode 100644 index 000000000..1a2f9dec3 --- /dev/null +++ b/libtransport/src/protocols/manifest_incremental_indexer.cc @@ -0,0 +1,234 @@ +/* + * 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. + */ + +#include + +#include +#include + +#include +#include + +namespace transport { + +namespace protocol { + +using namespace interface; + +ManifestIncrementalIndexer::ManifestIncrementalIndexer( + implementation::ConsumerSocket *icn_socket, TransportProtocol *transport, + Reassembly *reassembly) + : IncrementalIndexer(icn_socket, transport, reassembly), + suffix_strategy_(utils::SuffixStrategyFactory::getSuffixStrategy( + NextSegmentCalculationStrategy::INCREMENTAL, next_download_suffix_, + 0)) {} + +void ManifestIncrementalIndexer::onContentObject( + core::Interest::Ptr &&interest, core::ContentObject::Ptr &&content_object) { + // Check if mainfiest or not + if (content_object->getPayloadType() == PayloadType::MANIFEST) { + onUntrustedManifest(std::move(interest), std::move(content_object)); + } else if (content_object->getPayloadType() == PayloadType::CONTENT_OBJECT) { + onUntrustedContentObject(std::move(interest), std::move(content_object)); + } +} + +void ManifestIncrementalIndexer::onUntrustedManifest( + core::Interest::Ptr &&interest, core::ContentObject::Ptr &&content_object) { + auto ret = verification_manager_->onPacketToVerify(*content_object); + + switch (ret) { + case VerificationPolicy::ACCEPT_PACKET: { + processTrustedManifest(std::move(content_object)); + break; + } + case VerificationPolicy::DROP_PACKET: + case VerificationPolicy::ABORT_SESSION: { + transport_protocol_->onContentReassembled( + make_error_code(protocol_error::session_aborted)); + break; + } + } +} + +void ManifestIncrementalIndexer::processTrustedManifest( + ContentObject::Ptr &&content_object) { + auto manifest = + std::make_unique(std::move(*content_object)); + manifest->decode(); + + if (TRANSPORT_EXPECT_FALSE(manifest->getVersion() != + core::ManifestVersion::VERSION_1)) { + throw errors::RuntimeException("Received manifest with unknown version."); + } + + switch (manifest->getManifestType()) { + case core::ManifestType::INLINE_MANIFEST: { + auto _it = manifest->getSuffixList().begin(); + auto _end = manifest->getSuffixList().end(); + + suffix_strategy_->setFinalSuffix(manifest->getFinalBlockNumber()); + + for (; _it != _end; _it++) { + auto hash = + std::make_pair(std::vector(_it->second, _it->second + 32), + manifest->getHashAlgorithm()); + + if (!checkUnverifiedSegments(_it->first, hash)) { + suffix_hash_map_[_it->first] = std::move(hash); + } + } + + reassembly_->reassemble(std::move(manifest)); + + break; + } + case core::ManifestType::FLIC_MANIFEST: { + throw errors::NotImplementedException(); + } + case core::ManifestType::FINAL_CHUNK_NUMBER: { + throw errors::NotImplementedException(); + } + } +} + +bool ManifestIncrementalIndexer::checkUnverifiedSegments( + std::uint32_t suffix, const HashEntry &hash) { + auto it = unverified_segments_.find(suffix); + + if (it != unverified_segments_.end()) { + auto ret = verifyContentObject(hash, *it->second.second); + + switch (ret) { + case VerificationPolicy::ACCEPT_PACKET: { + reassembly_->reassemble(std::move(it->second.second)); + break; + } + case VerificationPolicy::DROP_PACKET: { + transport_protocol_->onPacketDropped(std::move(it->second.first), + std::move(it->second.second)); + break; + } + case VerificationPolicy::ABORT_SESSION: { + transport_protocol_->onContentReassembled( + make_error_code(protocol_error::session_aborted)); + break; + } + } + + unverified_segments_.erase(it); + return true; + } + + return false; +} + +VerificationPolicy ManifestIncrementalIndexer::verifyContentObject( + const HashEntry &manifest_hash, const ContentObject &content_object) { + VerificationPolicy ret; + + auto hash_type = static_cast(manifest_hash.second); + auto data_packet_digest = content_object.computeDigest(manifest_hash.second); + auto data_packet_digest_bytes = + data_packet_digest.getDigest().data(); + const std::vector &manifest_digest_bytes = manifest_hash.first; + + if (utils::CryptoHash::compareBinaryDigest( + data_packet_digest_bytes, manifest_digest_bytes.data(), hash_type)) { + ret = VerificationPolicy::ACCEPT_PACKET; + } else { + ConsumerContentObjectVerificationFailedCallback + *verification_failed_callback = VOID_HANDLER; + socket_->getSocketOption(ConsumerCallbacksOptions::VERIFICATION_FAILED, + &verification_failed_callback); + ret = (*verification_failed_callback)( + *socket_->getInterface(), content_object, + make_error_code(protocol_error::integrity_verification_failed)); + } + + return ret; +} + +void ManifestIncrementalIndexer::onUntrustedContentObject( + Interest::Ptr &&i, ContentObject::Ptr &&c) { + auto suffix = c->getName().getSuffix(); + auto it = suffix_hash_map_.find(suffix); + + if (it != suffix_hash_map_.end()) { + auto ret = verifyContentObject(it->second, *c); + + switch (ret) { + case VerificationPolicy::ACCEPT_PACKET: { + suffix_hash_map_.erase(it); + reassembly_->reassemble(std::move(c)); + break; + } + case VerificationPolicy::DROP_PACKET: { + transport_protocol_->onPacketDropped(std::move(i), std::move(c)); + break; + } + case VerificationPolicy::ABORT_SESSION: { + transport_protocol_->onContentReassembled( + make_error_code(protocol_error::session_aborted)); + break; + } + } + } else { + unverified_segments_[suffix] = std::make_pair(std::move(i), std::move(c)); + } +} + +uint32_t ManifestIncrementalIndexer::getNextSuffix() { + auto ret = suffix_strategy_->getNextSuffix(); + + if (ret <= suffix_strategy_->getFinalSuffix() && + ret != utils::SuffixStrategy::INVALID_SUFFIX) { + suffix_queue_.push(ret); + return ret; + } + + return IndexManager::invalid_index; +} + +uint32_t ManifestIncrementalIndexer::getFinalSuffix() { + return suffix_strategy_->getFinalSuffix(); +} + +bool ManifestIncrementalIndexer::isFinalSuffixDiscovered() { + return IncrementalIndexer::isFinalSuffixDiscovered(); +} + +uint32_t ManifestIncrementalIndexer::getNextReassemblySegment() { + if (suffix_queue_.empty()) { + return IndexManager::invalid_index; + } + + auto ret = suffix_queue_.front(); + suffix_queue_.pop(); + return ret; +} + +void ManifestIncrementalIndexer::reset(std::uint32_t offset) { + IncrementalIndexer::reset(offset); + suffix_hash_map_.clear(); + unverified_segments_.clear(); + SuffixQueue empty; + std::swap(suffix_queue_, empty); + suffix_strategy_->reset(offset); +} + +} // namespace protocol + +} // namespace transport diff --git a/libtransport/src/protocols/manifest_incremental_indexer.h b/libtransport/src/protocols/manifest_incremental_indexer.h new file mode 100644 index 000000000..88ae1720b --- /dev/null +++ b/libtransport/src/protocols/manifest_incremental_indexer.h @@ -0,0 +1,92 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include + +#include + +namespace transport { + +namespace protocol { + +class ManifestIncrementalIndexer : public IncrementalIndexer { + static constexpr double alpha = 0.3; + + public: + using SuffixQueue = std::queue; + using HashEntry = std::pair, core::HashAlgorithm>; + + ManifestIncrementalIndexer(implementation::ConsumerSocket *icn_socket, + TransportProtocol *transport, + Reassembly *reassembly); + + ManifestIncrementalIndexer(IncrementalIndexer &&indexer) + : IncrementalIndexer(std::move(indexer)), + suffix_strategy_(utils::SuffixStrategyFactory::getSuffixStrategy( + core::NextSegmentCalculationStrategy::INCREMENTAL, + next_download_suffix_, 0)) { + for (uint32_t i = first_suffix_; i < next_download_suffix_; i++) { + suffix_queue_.push(i); + } + } + + virtual ~ManifestIncrementalIndexer() = default; + + void reset(std::uint32_t offset = 0) override; + + void onContentObject(core::Interest::Ptr &&interest, + core::ContentObject::Ptr &&content_object) override; + + uint32_t getNextSuffix() override; + + uint32_t getNextReassemblySegment() override; + + bool isFinalSuffixDiscovered() override; + + uint32_t getFinalSuffix() override; + + private: + void onUntrustedManifest(core::Interest::Ptr &&interest, + core::ContentObject::Ptr &&content_object); + void onUntrustedContentObject(core::Interest::Ptr &&interest, + core::ContentObject::Ptr &&content_object); + void processTrustedManifest(core::ContentObject::Ptr &&content_object); + void onManifestReceived(core::Interest::Ptr &&i, + core::ContentObject::Ptr &&c); + void onManifestTimeout(core::Interest::Ptr &&i); + VerificationPolicy verifyContentObject( + const HashEntry &manifest_hash, + const core::ContentObject &content_object); + bool checkUnverifiedSegments(std::uint32_t suffix, const HashEntry &hash); + + protected: + std::unique_ptr suffix_strategy_; + SuffixQueue suffix_queue_; + + // Hash verification + std::unordered_map suffix_hash_map_; + + std::unordered_map> + unverified_segments_; +}; + +} // end namespace protocol + +} // end namespace transport diff --git a/libtransport/src/protocols/packet_manager.h b/libtransport/src/protocols/packet_manager.h new file mode 100644 index 000000000..a552607ea --- /dev/null +++ b/libtransport/src/protocols/packet_manager.h @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace transport { + +namespace protocol { + +using namespace core; + +template +class PacketManager { + static_assert(std::is_base_of::value, + "The packet manager support just Interest and Data."); + + public: + PacketManager(std::size_t size = packet_pool_size) : size_(0) { + // Create pool of interests + increasePoolSize(size); + } + + TRANSPORT_ALWAYS_INLINE void increasePoolSize(std::size_t size) { + for (std::size_t i = 0; i < size; i++) { + interest_pool_.add(new PacketType()); + } + + size_ += size; + } + + TRANSPORT_ALWAYS_INLINE typename PacketType::Ptr getPacket() { + auto result = interest_pool_.get(); + + while (TRANSPORT_EXPECT_FALSE(!result.first)) { + // Add packets to the pool + increasePoolSize(size_); + result = interest_pool_.get(); + } + + result.second->resetPayload(); + return std::move(result.second); + } + + private: + utils::ObjectPool interest_pool_; + std::size_t size_; +}; + +} // end namespace protocol + +} // end namespace transport diff --git a/libtransport/src/protocols/protocol.cc b/libtransport/src/protocols/protocol.cc new file mode 100644 index 000000000..aa290bef8 --- /dev/null +++ b/libtransport/src/protocols/protocol.cc @@ -0,0 +1,105 @@ +/* + * 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. + */ + +#include + +#include +#include + +namespace transport { + +namespace protocol { + +using namespace interface; + +TransportProtocol::TransportProtocol(implementation::ConsumerSocket *icn_socket, + Reassembly *reassembly_protocol) + : socket_(icn_socket), + reassembly_protocol_(reassembly_protocol), + index_manager_( + std::make_unique(socket_, this, reassembly_protocol)), + is_running_(false), + is_first_(false) { + socket_->getSocketOption(GeneralTransportOptions::PORTAL, portal_); + socket_->getSocketOption(OtherOptions::STATISTICS, &stats_); +} + +int TransportProtocol::start() { + // If the protocol is already running, return otherwise set as running + if (is_running_) return -1; + + // Reset the protocol state machine + reset(); + + // Set it is the first time we schedule an interest + is_first_ = true; + + // Schedule next interests + scheduleNextInterests(); + + is_first_ = false; + + // Set the protocol as running + is_running_ = true; + + // Start Event loop + portal_->runEventsLoop(); + + // Not running anymore + is_running_ = false; + + return 0; +} + +void TransportProtocol::stop() { + is_running_ = false; + portal_->stopEventsLoop(); +} + +void TransportProtocol::resume() { + if (is_running_) return; + + is_running_ = true; + + scheduleNextInterests(); + + portal_->runEventsLoop(); + + is_running_ = false; +} + +void TransportProtocol::onContentReassembled(std::error_code ec) { + interface::ConsumerSocket::ReadCallback *on_payload = VOID_HANDLER; + socket_->getSocketOption(READ_CALLBACK, &on_payload); + + if (!on_payload) { + throw errors::RuntimeException( + "The read callback must be installed in the transport before " + "starting " + "the content retrieval."); + } + + if (!ec) { + on_payload->readSuccess(stats_->getBytesRecv()); + } else { + on_payload->readError(ec); + } + + stop(); +} + +} // end namespace protocol + +} // end namespace transport diff --git a/libtransport/src/protocols/protocol.h b/libtransport/src/protocols/protocol.h new file mode 100644 index 000000000..c094adaae --- /dev/null +++ b/libtransport/src/protocols/protocol.h @@ -0,0 +1,92 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include +#include + +#include +#include +#include +#include +#include + +namespace transport { + +namespace protocol { + +using namespace core; + +class IndexVerificationManager; + +class TransportProtocolCallback { + virtual void onContentObject(const core::Interest &interest, + const core::ContentObject &content_object) = 0; + virtual void onTimeout(const core::Interest &interest) = 0; +}; + +class TransportProtocol : public implementation::BasePortal::ConsumerCallback, + public PacketManager, + public ContentObjectProcessingEventCallback { + static constexpr std::size_t interest_pool_size = 4096; + + friend class ManifestIndexManager; + + public: + TransportProtocol(implementation::ConsumerSocket *icn_socket, + Reassembly *reassembly_protocol); + + virtual ~TransportProtocol() = default; + + TRANSPORT_ALWAYS_INLINE bool isRunning() { return is_running_; } + + virtual int start(); + + virtual void stop(); + + virtual void resume(); + + virtual bool verifyKeyPackets() = 0; + + virtual void scheduleNextInterests() = 0; + + // Events generated by the indexing + virtual void onContentReassembled(std::error_code ec); + virtual void onPacketDropped(Interest::Ptr &&interest, + ContentObject::Ptr &&content_object) = 0; + virtual void onReassemblyFailed(std::uint32_t missing_segment) = 0; + + protected: + // Consumer Callback + virtual void reset() = 0; + virtual void onContentObject(Interest::Ptr &&i, ContentObject::Ptr &&c) = 0; + virtual void onTimeout(Interest::Ptr &&i) = 0; + + protected: + implementation::ConsumerSocket *socket_; + std::unique_ptr reassembly_protocol_; + std::unique_ptr index_manager_; + std::shared_ptr portal_; + std::atomic is_running_; + // True if it si the first time we schedule an interest + std::atomic is_first_; + interface::TransportStatistics *stats_; +}; + +} // end namespace protocol +} // end namespace transport diff --git a/libtransport/src/protocols/raaqm.cc b/libtransport/src/protocols/raaqm.cc new file mode 100644 index 000000000..8a38f8ccf --- /dev/null +++ b/libtransport/src/protocols/raaqm.cc @@ -0,0 +1,714 @@ +/* + * 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. + */ + +#include + +#include +#include +#include +#include + +#include +#include + +namespace transport { + +namespace protocol { + +using namespace interface; + +RaaqmTransportProtocol::RaaqmTransportProtocol( + implementation::ConsumerSocket *icn_socket) + : TransportProtocol(icn_socket, new ByteStreamReassembly(icn_socket, this)), + current_window_size_(1), + interests_in_flight_(0), + cur_path_(nullptr), + t0_(utils::SteadyClock::now()), + rate_estimator_(nullptr) { + init(); +} + +RaaqmTransportProtocol::~RaaqmTransportProtocol() { + if (rate_estimator_) { + delete rate_estimator_; + } +} + +int RaaqmTransportProtocol::start() { + if (rate_estimator_) { + rate_estimator_->onStart(); + } + + if (!cur_path_) { + // RAAQM + double drop_factor; + double minimum_drop_probability; + uint32_t sample_number; + uint32_t interest_lifetime; + + socket_->getSocketOption(RaaqmTransportOptions::DROP_FACTOR, drop_factor); + socket_->getSocketOption(RaaqmTransportOptions::MINIMUM_DROP_PROBABILITY, + minimum_drop_probability); + socket_->getSocketOption(RaaqmTransportOptions::SAMPLE_NUMBER, + sample_number); + socket_->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, + interest_lifetime); + + // Rate Estimation + double alpha = 0.0; + uint32_t batching_param = 0; + uint32_t choice_param = 0; + socket_->getSocketOption(RateEstimationOptions::RATE_ESTIMATION_ALPHA, + alpha); + socket_->getSocketOption( + RateEstimationOptions::RATE_ESTIMATION_BATCH_PARAMETER, batching_param); + socket_->getSocketOption(RateEstimationOptions::RATE_ESTIMATION_CHOICE, + choice_param); + + if (choice_param == 1) { + rate_estimator_ = new ALaTcpEstimator(); + } else { + rate_estimator_ = new SimpleEstimator(alpha, batching_param); + } + + socket_->getSocketOption(RateEstimationOptions::RATE_ESTIMATION_OBSERVER, + &rate_estimator_->observer_); + + // Current path + auto cur_path = std::make_unique( + drop_factor, minimum_drop_probability, interest_lifetime * 1000, + sample_number); + cur_path_ = cur_path.get(); + path_table_[default_values::path_id] = std::move(cur_path); + } + + portal_->setConsumerCallback(this); + return TransportProtocol::start(); +} + +void RaaqmTransportProtocol::resume() { return TransportProtocol::resume(); } + +void RaaqmTransportProtocol::reset() { + // Set first segment to retrieve + core::Name *name; + socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME, &name); + index_manager_->reset(); + index_manager_->setFirstSuffix(name->getSuffix()); + std::queue empty; + std::swap(interest_to_retransmit_, empty); + stats_->reset(); + + // Reset reassembly component + reassembly_protocol_->reInitialize(); + + // Reset protocol variables + interests_in_flight_ = 0; + t0_ = utils::SteadyClock::now(); +} + +bool RaaqmTransportProtocol::verifyKeyPackets() { + return index_manager_->onKeyToVerify(); +} + +void RaaqmTransportProtocol::increaseWindow() { + // return; + double max_window_size = 0.; + socket_->getSocketOption(GeneralTransportOptions::MAX_WINDOW_SIZE, + max_window_size); + if (current_window_size_ < max_window_size) { + double gamma = 0.; + socket_->getSocketOption(RaaqmTransportOptions::GAMMA_VALUE, gamma); + + current_window_size_ += gamma / current_window_size_; + socket_->setSocketOption(GeneralTransportOptions::CURRENT_WINDOW_SIZE, + current_window_size_); + } + rate_estimator_->onWindowIncrease(current_window_size_); +} + +void RaaqmTransportProtocol::decreaseWindow() { + // return; + double min_window_size = 0.; + socket_->getSocketOption(GeneralTransportOptions::MIN_WINDOW_SIZE, + min_window_size); + if (current_window_size_ > min_window_size) { + double beta = 0.; + socket_->getSocketOption(RaaqmTransportOptions::BETA_VALUE, beta); + + current_window_size_ = current_window_size_ * beta; + if (current_window_size_ < min_window_size) { + current_window_size_ = min_window_size; + } + + socket_->setSocketOption(GeneralTransportOptions::CURRENT_WINDOW_SIZE, + current_window_size_); + } + rate_estimator_->onWindowDecrease(current_window_size_); +} + +void RaaqmTransportProtocol::afterDataUnsatisfied(uint64_t segment) { + // Decrease the window because the timeout happened + decreaseWindow(); +} + +void RaaqmTransportProtocol::afterContentReception( + const Interest &interest, const ContentObject &content_object) { + updatePathTable(content_object); + increaseWindow(); + updateRtt(interest.getName().getSuffix()); + rate_estimator_->onDataReceived((int)content_object.payloadSize() + + (int)content_object.headerSize()); + // Set drop probablility and window size accordingly + RAAQM(); +} + +void RaaqmTransportProtocol::init() { + std::ifstream is(RAAQM_CONFIG_PATH); + + std::string line; + raaqm_autotune_ = false; + default_beta_ = default_values::beta_value; + default_drop_ = default_values::drop_factor; + beta_wifi_ = default_values::beta_value; + drop_wifi_ = default_values::drop_factor; + beta_lte_ = default_values::beta_value; + drop_lte_ = default_values::drop_factor; + wifi_delay_ = 1000; + lte_delay_ = 15000; + + if (!is) { + TRANSPORT_LOGW( + "WARNING: RAAQM parameters not found at %s, set default values", + RAAQM_CONFIG_PATH); + return; + } + + while (getline(is, line)) { + std::string command; + std::istringstream line_s(line); + + line_s >> command; + + if (command == ";") { + continue; + } + + if (command == "autotune") { + std::string tmp; + std::string val; + line_s >> tmp >> val; + if (val == "yes") { + raaqm_autotune_ = true; + } else { + raaqm_autotune_ = false; + } + continue; + } + + if (command == "lifetime") { + std::string tmp; + uint32_t lifetime; + line_s >> tmp >> lifetime; + socket_->setSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, + lifetime); + continue; + } + + if (command == "retransmissions") { + std::string tmp; + uint32_t rtx; + line_s >> tmp >> rtx; + socket_->setSocketOption(GeneralTransportOptions::MAX_INTEREST_RETX, rtx); + continue; + } + + if (command == "beta") { + std::string tmp; + line_s >> tmp >> default_beta_; + socket_->setSocketOption(RaaqmTransportOptions::BETA_VALUE, + default_beta_); + continue; + } + + if (command == "drop") { + std::string tmp; + line_s >> tmp >> default_drop_; + socket_->setSocketOption(RaaqmTransportOptions::DROP_FACTOR, + default_drop_); + continue; + } + + if (command == "beta_wifi_") { + std::string tmp; + line_s >> tmp >> beta_wifi_; + continue; + } + + if (command == "drop_wifi_") { + std::string tmp; + line_s >> tmp >> drop_wifi_; + continue; + } + + if (command == "beta_lte_") { + std::string tmp; + line_s >> tmp >> beta_lte_; + continue; + } + + if (command == "drop_lte_") { + std::string tmp; + line_s >> tmp >> drop_lte_; + continue; + } + + if (command == "wifi_delay_") { + std::string tmp; + line_s >> tmp >> wifi_delay_; + continue; + } + + if (command == "lte_delay_") { + std::string tmp; + line_s >> tmp >> lte_delay_; + continue; + } + if (command == "alpha") { + std::string tmp; + double rate_alpha = 0.0; + line_s >> tmp >> rate_alpha; + socket_->setSocketOption(RateEstimationOptions::RATE_ESTIMATION_ALPHA, + rate_alpha); + continue; + } + + if (command == "batching_parameter") { + std::string tmp; + uint32_t batching_param = 0; + line_s >> tmp >> batching_param; + socket_->setSocketOption( + RateEstimationOptions::RATE_ESTIMATION_BATCH_PARAMETER, + batching_param); + continue; + } + + if (command == "rate_estimator") { + std::string tmp; + uint32_t choice_param = 0; + line_s >> tmp >> choice_param; + socket_->setSocketOption(RateEstimationOptions::RATE_ESTIMATION_CHOICE, + choice_param); + continue; + } + } + + is.close(); +} + +void RaaqmTransportProtocol::onContentObject( + Interest::Ptr &&interest, ContentObject::Ptr &&content_object) { + // Check whether makes sense to continue + if (TRANSPORT_EXPECT_FALSE(!is_running_)) { + return; + } + + // Call application-defined callbacks + ConsumerContentObjectCallback *callback_content_object = VOID_HANDLER; + socket_->getSocketOption(ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT, + &callback_content_object); + if (*callback_content_object) { + (*callback_content_object)(*socket_->getInterface(), *content_object); + } + + ConsumerInterestCallback *callback_interest = VOID_HANDLER; + socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_SATISFIED, + &callback_interest); + if (*callback_interest) { + (*callback_interest)(*socket_->getInterface(), *interest); + } + + if (content_object->getPayloadType() == PayloadType::CONTENT_OBJECT) { + stats_->updateBytesRecv(content_object->payloadSize()); + } + + onContentSegment(std::move(interest), std::move(content_object)); + scheduleNextInterests(); +} + +void RaaqmTransportProtocol::onContentSegment( + Interest::Ptr &&interest, ContentObject::Ptr &&content_object) { + uint32_t incremental_suffix = content_object->getName().getSuffix(); + + // Decrease in-flight interests + interests_in_flight_--; + + // Update stats + if (!interest_retransmissions_[incremental_suffix & mask]) { + afterContentReception(*interest, *content_object); + } + + index_manager_->onContentObject(std::move(interest), + std::move(content_object)); +} + +void RaaqmTransportProtocol::onPacketDropped( + Interest::Ptr &&interest, ContentObject::Ptr &&content_object) { + uint32_t max_rtx = 0; + socket_->getSocketOption(GeneralTransportOptions::MAX_INTEREST_RETX, max_rtx); + + uint64_t segment = interest->getName().getSuffix(); + ConsumerInterestCallback *callback = VOID_HANDLER; + if (TRANSPORT_EXPECT_TRUE(interest_retransmissions_[segment & mask] < + max_rtx)) { + stats_->updateRetxCount(1); + + callback = VOID_HANDLER; + socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_RETRANSMISSION, + &callback); + if (*callback) { + (*callback)(*socket_->getInterface(), *interest); + } + + callback = VOID_HANDLER; + socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_OUTPUT, + &callback); + if (*callback) { + (*callback)(*socket_->getInterface(), *interest); + } + + if (!is_running_) { + return; + } + + interest_retransmissions_[segment & mask]++; + + interest_to_retransmit_.push(std::move(interest)); + } else { + TRANSPORT_LOGE( + "Stop: received not trusted packet %llu times", + (unsigned long long)interest_retransmissions_[segment & mask]); + onContentReassembled( + make_error_code(protocol_error::max_retransmissions_error)); + } +} + +void RaaqmTransportProtocol::onReassemblyFailed(std::uint32_t missing_segment) { + +} + +void RaaqmTransportProtocol::onTimeout(Interest::Ptr &&interest) { + checkForStalePaths(); + + const Name &n = interest->getName(); + + TRANSPORT_LOGW("Timeout on content %s", n.toString().c_str()); + + if (TRANSPORT_EXPECT_FALSE(!is_running_)) { + return; + } + + interests_in_flight_--; + + uint64_t segment = n.getSuffix(); + + // Do not retransmit interests asking contents that do not exist. + if (segment > index_manager_->getFinalSuffix()) { + return; + } + + ConsumerInterestCallback *callback = VOID_HANDLER; + socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_EXPIRED, + &callback); + if (*callback) { + (*callback)(*socket_->getInterface(), *interest); + } + + afterDataUnsatisfied(segment); + + uint32_t max_rtx = 0; + socket_->getSocketOption(GeneralTransportOptions::MAX_INTEREST_RETX, max_rtx); + + if (TRANSPORT_EXPECT_TRUE(interest_retransmissions_[segment & mask] < + max_rtx)) { + stats_->updateRetxCount(1); + + callback = VOID_HANDLER; + socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_RETRANSMISSION, + &callback); + if (*callback) { + (*callback)(*socket_->getInterface(), *interest); + } + + callback = VOID_HANDLER; + socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_OUTPUT, + &callback); + if (*callback) { + (*callback)(*socket_->getInterface(), *interest); + } + + if (!is_running_) { + return; + } + + interest_retransmissions_[segment & mask]++; + + interest_to_retransmit_.push(std::move(interest)); + + scheduleNextInterests(); + } else { + TRANSPORT_LOGE("Stop: reached max retx limit."); + onContentReassembled(std::make_error_code(std::errc(std::errc::io_error))); + } +} + +void RaaqmTransportProtocol::scheduleNextInterests() { + if (TRANSPORT_EXPECT_FALSE(!is_running_ && !is_first_)) { + return; + } + + if (TRANSPORT_EXPECT_FALSE(interests_in_flight_ >= current_window_size_ && + interest_to_retransmit_.size() > 0)) { + // send at least one interest if there are retransmissions to perform and + // there is no space left in the window + sendInterest(std::move(interest_to_retransmit_.front())); + TRANSPORT_LOGD("Window full, retransmit one content interest"); + interest_to_retransmit_.pop(); + } + + uint32_t index = IndexManager::invalid_index; + + // Send the interest needed for filling the window + while (interests_in_flight_ < current_window_size_) { + if (interest_to_retransmit_.size() > 0) { + sendInterest(std::move(interest_to_retransmit_.front())); + TRANSPORT_LOGD("Retransmit content interest"); + interest_to_retransmit_.pop(); + } else { + index = index_manager_->getNextSuffix(); + if (index == IndexManager::invalid_index) { + break; + } + + sendInterest(index); + TRANSPORT_LOGD("Send content interest %u", index); + } + } +} + +void RaaqmTransportProtocol::sendInterest(std::uint64_t next_suffix) { + auto interest = getPacket(); + core::Name *name; + socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME, &name); + name->setSuffix((uint32_t)next_suffix); + interest->setName(*name); + + uint32_t interest_lifetime; + socket_->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, + interest_lifetime); + interest->setLifetime(interest_lifetime); + + ConsumerInterestCallback *callback = VOID_HANDLER; + socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_OUTPUT, + &callback); + if (*callback) { + callback->operator()(*socket_->getInterface(), *interest); + } + + if (TRANSPORT_EXPECT_FALSE(!is_running_ && !is_first_)) { + return; + } + + // This is set to ~0 so that the next interest_retransmissions_ + 1, + // performed by sendInterest, will result in 0 + interest_retransmissions_[next_suffix & mask] = ~0; + interest_timepoints_[next_suffix & mask] = utils::SteadyClock::now(); + sendInterest(std::move(interest)); +} + +void RaaqmTransportProtocol::sendInterest(Interest::Ptr &&interest) { + interests_in_flight_++; + interest_retransmissions_[interest->getName().getSuffix() & mask]++; + + portal_->sendInterest(std::move(interest)); +} + +void RaaqmTransportProtocol::onContentReassembled(std::error_code ec) { + rate_estimator_->onDownloadFinished(); + TransportProtocol::onContentReassembled(ec); +} + +void RaaqmTransportProtocol::updateRtt(uint64_t segment) { + if (TRANSPORT_EXPECT_FALSE(!cur_path_)) { + throw std::runtime_error("RAAQM ERROR: no current path found, exit"); + } else { + auto now = utils::SteadyClock::now(); + utils::Microseconds rtt = std::chrono::duration_cast( + now - interest_timepoints_[segment & mask]); + + // Update stats + updateStats((uint32_t)segment, rtt.count(), now); + + if (rate_estimator_) { + rate_estimator_->onRttUpdate((double)rtt.count()); + } + + cur_path_->insertNewRtt(rtt.count()); + cur_path_->smoothTimer(); + + if (cur_path_->newPropagationDelayAvailable()) { + checkDropProbability(); + } + } +} + +void RaaqmTransportProtocol::RAAQM() { + if (!cur_path_) { + throw errors::RuntimeException("ERROR: no current path found, exit"); + exit(EXIT_FAILURE); + } else { + // Change drop probability according to RTT statistics + cur_path_->updateDropProb(); + + double coin = ((double)rand() / (RAND_MAX)); + if (coin <= cur_path_->getDropProb()) { + decreaseWindow(); + } + } +} + +void RaaqmTransportProtocol::updateStats(uint32_t suffix, uint64_t rtt, + utils::TimePoint &now) { + // Update RTT statistics + stats_->updateAverageRtt(rtt); + stats_->updateAverageWindowSize(current_window_size_); + + // Call statistics callback + ConsumerTimerCallback *stats_callback = VOID_HANDLER; + socket_->getSocketOption(ConsumerCallbacksOptions::STATS_SUMMARY, + &stats_callback); + if (*stats_callback) { + auto dt = std::chrono::duration_cast(now - t0_); + + uint32_t timer_interval_milliseconds = 0; + socket_->getSocketOption(GeneralTransportOptions::STATS_INTERVAL, + timer_interval_milliseconds); + if (dt.count() > timer_interval_milliseconds) { + (*stats_callback)(*socket_->getInterface(), *stats_); + t0_ = utils::SteadyClock::now(); + } + } +} + +void RaaqmTransportProtocol::updatePathTable( + const ContentObject &content_object) { + uint32_t path_id = content_object.getPathLabel(); + + if (path_table_.find(path_id) == path_table_.end()) { + if (TRANSPORT_EXPECT_TRUE(cur_path_ != nullptr)) { + // Create a new path with some default param + + if (TRANSPORT_EXPECT_FALSE(path_table_.empty())) { + throw errors::RuntimeException( + "[RAAQM] No path initialized for path table, error could be in " + "default path initialization."); + } + + // Initiate the new path default param + auto new_path = std::make_unique( + *(path_table_.at(default_values::path_id))); + + // Insert the new path into hash table + path_table_[path_id] = std::move(new_path); + } else { + throw errors::RuntimeException( + "UNEXPECTED ERROR: when running,current path not found."); + } + } + + cur_path_ = path_table_[path_id].get(); + + size_t header_size = content_object.headerSize(); + size_t data_size = content_object.payloadSize(); + + // Update measurements for path + cur_path_->updateReceivedStats(header_size + data_size, data_size); +} + +void RaaqmTransportProtocol::checkDropProbability() { + if (!raaqm_autotune_) { + return; + } + + unsigned int max_pd = 0; + PathTable::iterator it; + for (auto it = path_table_.begin(); it != path_table_.end(); ++it) { + if (it->second->getPropagationDelay() > max_pd && + it->second->getPropagationDelay() != UINT_MAX && + !it->second->isStale()) { + max_pd = it->second->getPropagationDelay(); + } + } + + double drop_prob = 0; + double beta = 0; + if (max_pd < wifi_delay_) { // only ethernet paths + drop_prob = default_drop_; + beta = default_beta_; + } else if (max_pd < lte_delay_) { // at least one wifi path + drop_prob = drop_wifi_; + beta = beta_wifi_; + } else { // at least one lte path + drop_prob = drop_lte_; + beta = beta_lte_; + } + + double old_drop_prob = 0; + double old_beta = 0; + socket_->getSocketOption(RaaqmTransportOptions::BETA_VALUE, old_beta); + socket_->getSocketOption(RaaqmTransportOptions::DROP_FACTOR, old_drop_prob); + + if (drop_prob == old_drop_prob && beta == old_beta) { + return; + } + + socket_->setSocketOption(RaaqmTransportOptions::BETA_VALUE, beta); + socket_->setSocketOption(RaaqmTransportOptions::DROP_FACTOR, drop_prob); + + for (it = path_table_.begin(); it != path_table_.end(); it++) { + it->second->setDropProb(drop_prob); + } +} + +void RaaqmTransportProtocol::checkForStalePaths() { + if (!raaqm_autotune_) { + return; + } + + bool stale = false; + PathTable::iterator it; + for (it = path_table_.begin(); it != path_table_.end(); ++it) { + if (it->second->isStale()) { + stale = true; + break; + } + } + if (stale) { + checkDropProbability(); + } +} + +} // end namespace protocol + +} // namespace transport diff --git a/libtransport/src/protocols/raaqm.h b/libtransport/src/protocols/raaqm.h new file mode 100644 index 000000000..412967770 --- /dev/null +++ b/libtransport/src/protocols/raaqm.h @@ -0,0 +1,142 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include +#include +#include +#include +#include + +#include +#include + +namespace transport { + +namespace protocol { + +class RaaqmTransportProtocol : public TransportProtocol, + public CWindowProtocol { + public: + RaaqmTransportProtocol(implementation::ConsumerSocket *icnet_socket); + + ~RaaqmTransportProtocol(); + + int start() override; + + void resume() override; + + void reset() override; + + virtual bool verifyKeyPackets() override; + + protected: + static constexpr uint32_t buffer_size = + 1 << interface::default_values::log_2_default_buffer_size; + static constexpr uint16_t mask = buffer_size - 1; + using PathTable = + std::unordered_map>; + + void increaseWindow() override; + void decreaseWindow() override; + + virtual void afterContentReception(const Interest &interest, + const ContentObject &content_object); + virtual void afterDataUnsatisfied(uint64_t segment); + + virtual void updateStats(uint32_t suffix, uint64_t rtt, + utils::TimePoint &now); + + private: + void init(); + + void onContentObject(Interest::Ptr &&i, ContentObject::Ptr &&c) override; + + void onContentSegment(Interest::Ptr &&interest, + ContentObject::Ptr &&content_object); + + void onPacketDropped(Interest::Ptr &&interest, + ContentObject::Ptr &&content_object) override; + + void onReassemblyFailed(std::uint32_t missing_segment) override; + + void onTimeout(Interest::Ptr &&i) override; + + virtual void scheduleNextInterests() override; + + void sendInterest(std::uint64_t next_suffix); + + void sendInterest(Interest::Ptr &&interest); + + void onContentReassembled(std::error_code ec) override; + + void updateRtt(uint64_t segment); + + void RAAQM(); + + void updatePathTable(const ContentObject &content_object); + + void checkDropProbability(); + + void checkForStalePaths(); + + void printRtt(); + + protected: + // Congestion window management + double current_window_size_; + // Protocol management + uint64_t interests_in_flight_; + std::array interest_retransmissions_; + std::array interest_timepoints_; + std::queue interest_to_retransmit_; + + private: + /** + * Current download path + */ + RaaqmDataPath *cur_path_; + + /** + * Hash table for path: each entry is a pair path ID(key) - path object + */ + PathTable path_table_; + + // TimePoints for statistic + utils::TimePoint t0_; + + bool set_interest_filter_; + + // for rate-estimation at packet level + IcnRateEstimator *rate_estimator_; + + // params for autotuning + bool raaqm_autotune_; + double default_beta_; + double default_drop_; + double beta_wifi_; + double drop_wifi_; + double beta_lte_; + double drop_lte_; + unsigned int wifi_delay_; + unsigned int lte_delay_; +}; + +} // end namespace protocol + +} // end namespace transport diff --git a/libtransport/src/protocols/raaqm_data_path.cc b/libtransport/src/protocols/raaqm_data_path.cc new file mode 100644 index 000000000..439549c85 --- /dev/null +++ b/libtransport/src/protocols/raaqm_data_path.cc @@ -0,0 +1,158 @@ +/* + * 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. + */ + +#include + +#include + +namespace transport { + +namespace protocol { + +RaaqmDataPath::RaaqmDataPath(double drop_factor, + double minimum_drop_probability, + unsigned new_timer, unsigned int samples, + uint64_t new_rtt, uint64_t new_rtt_min, + uint64_t new_rtt_max, unsigned new_pd) + + : drop_factor_(drop_factor), + minimum_drop_probability_(minimum_drop_probability), + timer_(new_timer), + samples_(samples), + rtt_(new_rtt), + rtt_min_(new_rtt_min), + rtt_max_(new_rtt_max), + prop_delay_(new_pd), + new_prop_delay_(false), + drop_prob_(0), + packets_received_(0), + last_packets_received_(0), + m_packets_bytes_received_(0), + last_packets_bytes_received_(0), + raw_data_bytes_received_(0), + last_raw_data_bytes_received_(0), + rtt_samples_(samples_), + last_received_pkt_(utils::SteadyClock::now()), + average_rtt_(0), + alpha_(ALPHA) {} + +RaaqmDataPath &RaaqmDataPath::insertNewRtt(uint64_t new_rtt) { + rtt_ = new_rtt; + rtt_samples_.pushBack(new_rtt); + + rtt_max_ = rtt_samples_.rBegin(); + rtt_min_ = rtt_samples_.begin(); + + if (rtt_min_ < prop_delay_) { + new_prop_delay_ = true; + prop_delay_ = rtt_min_; + } + + last_received_pkt_ = utils::SteadyClock::now(); + + return *this; +} + +RaaqmDataPath &RaaqmDataPath::updateReceivedStats(std::size_t packet_size, + std::size_t data_size) { + packets_received_++; + m_packets_bytes_received_ += packet_size; + raw_data_bytes_received_ += data_size; + + return *this; +} + +double RaaqmDataPath::getDropFactor() { return drop_factor_; } + +double RaaqmDataPath::getDropProb() { return drop_prob_; } + +RaaqmDataPath &RaaqmDataPath::setDropProb(double dropProb) { + drop_prob_ = dropProb; + + return *this; +} + +double RaaqmDataPath::getMinimumDropProbability() { + return minimum_drop_probability_; +} + +double RaaqmDataPath::getTimer() { return timer_; } + +RaaqmDataPath &RaaqmDataPath::smoothTimer() { + timer_ = (1 - TIMEOUT_SMOOTHER) * timer_ + + (TIMEOUT_SMOOTHER)*rtt_ * (TIMEOUT_RATIO); + + return *this; +} + +double RaaqmDataPath::getRtt() { return (double)rtt_; } + +double RaaqmDataPath::getAverageRtt() { return average_rtt_; } + +double RaaqmDataPath::getRttMax() { return (double)rtt_max_; } + +double RaaqmDataPath::getRttMin() { return (double)rtt_min_; } + +unsigned RaaqmDataPath::getSampleValue() { return samples_; } + +unsigned RaaqmDataPath::getRttQueueSize() { + return static_cast(rtt_samples_.size()); +} + +RaaqmDataPath &RaaqmDataPath::updateDropProb() { + drop_prob_ = 0.0; + + if (getSampleValue() == getRttQueueSize()) { + if (rtt_max_ == rtt_min_) { + drop_prob_ = minimum_drop_probability_; + } else { + drop_prob_ = minimum_drop_probability_ + + drop_factor_ * (rtt_ - rtt_min_) / (rtt_max_ - rtt_min_); + } + } + + return *this; +} + +void RaaqmDataPath::setAlpha(double alpha) { + if (alpha >= 0 && alpha <= 1) { + alpha_ = alpha; + } +} + +bool RaaqmDataPath::newPropagationDelayAvailable() { + bool r = new_prop_delay_; + new_prop_delay_ = false; + return r; +} + +unsigned int RaaqmDataPath::getPropagationDelay() { + return (unsigned int)prop_delay_; +} + +bool RaaqmDataPath::isStale() { + utils::TimePoint now = utils::SteadyClock::now(); + auto time = + std::chrono::duration_cast(now - last_received_pkt_) + .count(); + if (time > 2000000) { + return true; + } + return false; +} + +} // end namespace protocol + +} // end namespace transport diff --git a/libtransport/src/protocols/raaqm_data_path.h b/libtransport/src/protocols/raaqm_data_path.h new file mode 100644 index 000000000..6f2afde72 --- /dev/null +++ b/libtransport/src/protocols/raaqm_data_path.h @@ -0,0 +1,226 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include + +#include +#include +#include + +#define TIMEOUT_SMOOTHER 0.1 +#define TIMEOUT_RATIO 10 +#define ALPHA 0.8 + +namespace transport { + +namespace protocol { + +class RaaqmDataPath { + public: + RaaqmDataPath(double drop_factor, double minimum_drop_probability, + unsigned new_timer, unsigned int samples, + uint64_t new_rtt = 1000, uint64_t new_rtt_min = 1000, + uint64_t new_rtt_max = 1000, unsigned new_pd = UINT_MAX); + + public: + /* + * @brief Add a new RTT to the RTT queue of the path, check if RTT queue is + * full, and thus need overwrite. Also it maintains the validity of min and + * max of RTT. + * @param new_rtt is the value of the new RTT + */ + RaaqmDataPath &insertNewRtt(uint64_t new_rtt); + + /** + * @brief Update the path statistics + * @param packet_size the size of the packet received, including the ICN + * header + * @param data_size the size of the data received, without the ICN header + */ + RaaqmDataPath &updateReceivedStats(std::size_t packet_size, + std::size_t data_size); + + /** + * @brief Get the value of the drop factor parameter + */ + double getDropFactor(); + + /** + * @brief Get the value of the drop probability + */ + double getDropProb(); + + /** + * @brief Set the value pf the drop probability + * @param drop_prob is the value of the drop probability + */ + RaaqmDataPath &setDropProb(double drop_prob); + + /** + * @brief Get the minimum drop probability + */ + double getMinimumDropProbability(); + + /** + * @brief Get last RTT + */ + double getRtt(); + + /** + * @brief Get average RTT + */ + double getAverageRtt(); + + /** + * @brief Get the current m_timer value + */ + double getTimer(); + + /** + * @brief Smooth he value of the m_timer accordingly with the last RTT + * measured + */ + RaaqmDataPath &smoothTimer(); + + /** + * @brief Get the maximum RTT among the last samples + */ + double getRttMax(); + + /** + * @brief Get the minimum RTT among the last samples + */ + double getRttMin(); + + /** + * @brief Get the number of saved samples + */ + unsigned getSampleValue(); + + /** + * @brief Get the size og the RTT queue + */ + unsigned getRttQueueSize(); + + /* + * @brief Change drop probability according to RTT statistics + * Invoked in RAAQM(), before control window size update. + */ + RaaqmDataPath &updateDropProb(); + + void setAlpha(double alpha); + + /** + * @brief Returns the smallest RTT registered so far for this path + */ + + unsigned int getPropagationDelay(); + + bool newPropagationDelayAvailable(); + + bool isStale(); + + private: + /** + * The value of the drop factor + */ + double drop_factor_; + + /** + * The minumum drop probability + */ + double minimum_drop_probability_; + + /** + * The timer, expressed in milliseconds + */ + double timer_; + + /** + * The number of samples to store for computing the protocol measurements + */ + const unsigned int samples_; + + /** + * The last, the minimum and the maximum value of the RTT (among the last + * m_samples samples) + */ + uint64_t rtt_, rtt_min_, rtt_max_, prop_delay_; + + bool new_prop_delay_; + + /** + * The current drop probability + */ + double drop_prob_; + + /** + * The number of packets received in this path + */ + intmax_t packets_received_; + + /** + * The first packet received after the statistics print + */ + intmax_t last_packets_received_; + + /** + * Total number of bytes received including the ICN header + */ + intmax_t m_packets_bytes_received_; + + /** + * The amount of packet bytes received at the last path summary computation + */ + intmax_t last_packets_bytes_received_; + + /** + * Total number of bytes received without including the ICN header + */ + intmax_t raw_data_bytes_received_; + + /** + * The amount of raw dat bytes received at the last path summary computation + */ + intmax_t last_raw_data_bytes_received_; + + class byArrival; + + class byOrder; + + /** + * Double ended queue for the RTTs + */ + + typedef utils::MinFilter RTTQueue; + + RTTQueue rtt_samples_; + + /** + * Time of the last call to the path reporter method + */ + utils::TimePoint last_received_pkt_; + + double average_rtt_; + double alpha_; +}; + +} // end namespace protocol + +} // end namespace transport diff --git a/libtransport/src/protocols/rate_estimation.cc b/libtransport/src/protocols/rate_estimation.cc new file mode 100644 index 000000000..a2cf1aefe --- /dev/null +++ b/libtransport/src/protocols/rate_estimation.cc @@ -0,0 +1,356 @@ +/* + * 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. + */ + +#include +#include + +#include + +#include + +namespace transport { + +namespace protocol { + +void *Timer(void *data) { + InterRttEstimator *estimator = (InterRttEstimator *)data; + + double dat_rtt, my_avg_win, my_avg_rtt; + int my_win_change, number_of_packets, max_packet_size; + + pthread_mutex_lock(&(estimator->mutex_)); + dat_rtt = estimator->rtt_; + pthread_mutex_unlock(&(estimator->mutex_)); + + while (estimator->is_running_) { + std::this_thread::sleep_for(std::chrono::microseconds( + (uint64_t)(interface::default_values::kv * dat_rtt))); + + pthread_mutex_lock(&(estimator->mutex_)); + + dat_rtt = estimator->rtt_; + my_avg_win = estimator->avg_win_; + my_avg_rtt = estimator->avg_rtt_; + my_win_change = (int)(estimator->win_change_); + number_of_packets = estimator->number_of_packets_; + max_packet_size = estimator->max_packet_size_; + estimator->avg_rtt_ = estimator->rtt_; + estimator->avg_win_ = 0; + estimator->win_change_ = 0; + estimator->number_of_packets_ = 1; + + pthread_mutex_unlock(&(estimator->mutex_)); + + if (number_of_packets == 0 || my_win_change == 0) { + continue; + } + if (estimator->estimation_ == 0) { + estimator->estimation_ = (my_avg_win * 8.0 * max_packet_size * 1000000.0 / + (1.0 * my_win_change)) / + (my_avg_rtt / (1.0 * number_of_packets)); + } + + estimator->estimation_ = + estimator->alpha_ * estimator->estimation_ + + (1 - estimator->alpha_) * ((my_avg_win * 8.0 * max_packet_size * + 1000000.0 / (1.0 * my_win_change)) / + (my_avg_rtt / (1.0 * number_of_packets))); + + if (estimator->observer_) { + estimator->observer_->notifyStats(estimator->estimation_); + } + } + + return nullptr; +} + +InterRttEstimator::InterRttEstimator(double alpha_arg) { + this->estimated_ = false; + this->observer_ = NULL; + this->alpha_ = alpha_arg; + this->thread_is_running_ = false; + this->my_th_ = NULL; + this->is_running_ = true; + this->avg_rtt_ = 0.0; + this->estimation_ = 0.0; + this->avg_win_ = 0.0; + this->rtt_ = 0.0; + this->win_change_ = 0; + this->number_of_packets_ = 0; + this->max_packet_size_ = 0; + this->win_current_ = 1.0; + + pthread_mutex_init(&(this->mutex_), NULL); + this->start_time_ = std::chrono::steady_clock::now(); + this->begin_batch_ = std::chrono::steady_clock::now(); +} + +InterRttEstimator::~InterRttEstimator() { + this->is_running_ = false; + if (this->my_th_) { + pthread_join(*(this->my_th_), NULL); + } + this->my_th_ = NULL; + pthread_mutex_destroy(&(this->mutex_)); +} + +void InterRttEstimator::onRttUpdate(double rtt) { + pthread_mutex_lock(&(this->mutex_)); + this->rtt_ = rtt; + this->number_of_packets_++; + this->avg_rtt_ += rtt; + pthread_mutex_unlock(&(this->mutex_)); + + if (!thread_is_running_) { + my_th_ = (pthread_t *)malloc(sizeof(pthread_t)); + if (!my_th_) { + TRANSPORT_LOGE("Error allocating thread."); + my_th_ = NULL; + } + if (/*int err = */ pthread_create(my_th_, NULL, transport::protocol::Timer, + (void *)this)) { + TRANSPORT_LOGE("Error creating the thread"); + my_th_ = NULL; + } + thread_is_running_ = true; + } +} + +void InterRttEstimator::onWindowIncrease(double win_current) { + TimePoint end = std::chrono::steady_clock::now(); + auto delay = + std::chrono::duration_cast(end - this->begin_batch_) + .count(); + + pthread_mutex_lock(&(this->mutex_)); + this->avg_win_ += this->win_current_ * delay; + this->win_current_ = win_current; + this->win_change_ += delay; + pthread_mutex_unlock(&(this->mutex_)); + + this->begin_batch_ = std::chrono::steady_clock::now(); +} + +void InterRttEstimator::onWindowDecrease(double win_current) { + TimePoint end = std::chrono::steady_clock::now(); + auto delay = + std::chrono::duration_cast(end - this->begin_batch_) + .count(); + + pthread_mutex_lock(&(this->mutex_)); + this->avg_win_ += this->win_current_ * delay; + this->win_current_ = win_current; + this->win_change_ += delay; + pthread_mutex_unlock(&(this->mutex_)); + + this->begin_batch_ = std::chrono::steady_clock::now(); +} + +ALaTcpEstimator::ALaTcpEstimator() { + this->estimation_ = 0.0; + this->observer_ = NULL; + this->start_time_ = std::chrono::steady_clock::now(); + this->totalSize_ = 0.0; +} + +void ALaTcpEstimator::onStart() { + this->totalSize_ = 0.0; + this->start_time_ = std::chrono::steady_clock::now(); +} + +void ALaTcpEstimator::onDownloadFinished() { + TimePoint end = std::chrono::steady_clock::now(); + auto delay = + std::chrono::duration_cast(end - this->start_time_).count(); + this->estimation_ = this->totalSize_ * 8 * 1000000 / delay; + if (observer_) { + observer_->notifyStats(this->estimation_); + } +} + +void ALaTcpEstimator::onDataReceived(int packet_size) { + this->totalSize_ += packet_size; +} + +SimpleEstimator::SimpleEstimator(double alphaArg, int batching_param) { + this->estimation_ = 0.0; + this->estimated_ = false; + this->observer_ = nullptr; + this->batching_param_ = batching_param; + this->total_size_ = 0.0; + this->number_of_packets_ = 0; + this->base_alpha_ = alphaArg; + this->alpha_ = alphaArg; + this->start_time_ = std::chrono::steady_clock::now(); + this->begin_batch_ = std::chrono::steady_clock::now(); +} + +void SimpleEstimator::onStart() { + this->estimated_ = false; + this->number_of_packets_ = 0; + this->total_size_ = 0.0; + this->start_time_ = std::chrono::steady_clock::now(); + this->begin_batch_ = std::chrono::steady_clock::now(); +} + +void SimpleEstimator::onDownloadFinished() { + TimePoint end = std::chrono::steady_clock::now(); + auto delay = + std::chrono::duration_cast(end - this->start_time_).count(); + if (observer_) { + observer_->notifyDownloadTime((double)delay); + } + if (!this->estimated_) { + // Assuming all packets carry max_packet_size_ bytes of data + // (8*max_packet_size_ bits); 1000000 factor to convert us to seconds + if (this->estimation_) { + this->estimation_ = + alpha_ * this->estimation_ + + (1 - alpha_) * (total_size_ * 8 * 1000000.0 / (delay)); + } else { + this->estimation_ = total_size_ * 8 * 1000000.0 / (delay); + } + if (observer_) { + observer_->notifyStats(this->estimation_); + } + this->alpha_ = this->base_alpha_ * (((double)this->number_of_packets_) / + ((double)this->batching_param_)); + } else { + if (this->number_of_packets_ >= + (int)(75.0 * (double)this->batching_param_ / 100.0)) { + delay = std::chrono::duration_cast(end - this->begin_batch_) + .count(); + // Assuming all packets carry max_packet_size_ bytes of data + // (8*max_packet_size_ bits); 1000000 factor to convert us to seconds + if (this->estimation_) { + this->estimation_ = + alpha_ * this->estimation_ + + (1 - alpha_) * (total_size_ * 8 * 1000000.0 / (delay)); + } else { + this->estimation_ = total_size_ * 8 * 1000000.0 / (delay); + } + if (observer_) { + observer_->notifyStats(this->estimation_); + } + this->alpha_ = this->base_alpha_ * (((double)this->number_of_packets_) / + ((double)this->batching_param_)); + } + } + this->number_of_packets_ = 0; + this->total_size_ = 0.0; + this->start_time_ = std::chrono::steady_clock::now(); + this->begin_batch_ = std::chrono::steady_clock::now(); +} + +void SimpleEstimator::onDataReceived(int packet_size) { + this->total_size_ += packet_size; +} + +void SimpleEstimator::onRttUpdate(double rtt) { + this->number_of_packets_++; + + if (this->number_of_packets_ == this->batching_param_) { + TimePoint end = std::chrono::steady_clock::now(); + auto delay = + std::chrono::duration_cast(end - this->begin_batch_) + .count(); + // Assuming all packets carry max_packet_size_ bytes of data + // (8*max_packet_size_ bits); 1000000 factor to convert us to seconds + if (this->estimation_) { + this->estimation_ = + alpha_ * this->estimation_ + + (1 - alpha_) * (total_size_ * 8 * 1000000.0 / (delay)); + } else { + this->estimation_ = total_size_ * 8 * 1000000.0 / (delay); + } + if (observer_) { + observer_->notifyStats(this->estimation_); + } + this->alpha_ = this->base_alpha_; + this->number_of_packets_ = 0; + this->total_size_ = 0.0; + this->begin_batch_ = std::chrono::steady_clock::now(); + } +} + +BatchingPacketsEstimator::BatchingPacketsEstimator(double alpha_arg, + int param) { + this->estimated_ = false; + this->observer_ = NULL; + this->alpha_ = alpha_arg; + this->batching_param_ = param; + this->number_of_packets_ = 0; + this->avg_win_ = 0.0; + this->avg_rtt_ = 0.0; + this->win_change_ = 0.0; + this->max_packet_size_ = 0; + this->estimation_ = 0.0; + this->win_current_ = 1.0; + this->begin_batch_ = std::chrono::steady_clock::now(); + this->start_time_ = std::chrono::steady_clock::now(); +} + +void BatchingPacketsEstimator::onRttUpdate(double rtt) { + this->number_of_packets_++; + this->avg_rtt_ += rtt; + + if (number_of_packets_ == this->batching_param_) { + if (estimation_ == 0) { + estimation_ = (avg_win_ * 8.0 * max_packet_size_ * 1000000.0 / + (1.0 * win_change_)) / + (avg_rtt_ / (1.0 * number_of_packets_)); + } else { + estimation_ = alpha_ * estimation_ + + (1 - alpha_) * ((avg_win_ * 8.0 * max_packet_size_ * + 1000000.0 / (1.0 * win_change_)) / + (avg_rtt_ / (1.0 * number_of_packets_))); + } + + if (observer_) { + observer_->notifyStats(estimation_); + } + + this->number_of_packets_ = 0; + this->avg_win_ = 0.0; + this->avg_rtt_ = 0.0; + this->win_change_ = 0.0; + } +} + +void BatchingPacketsEstimator::onWindowIncrease(double win_current) { + TimePoint end = std::chrono::steady_clock::now(); + auto delay = + std::chrono::duration_cast(end - this->begin_batch_) + .count(); + this->avg_win_ += this->win_current_ * delay; + this->win_current_ = win_current; + this->win_change_ += delay; + this->begin_batch_ = std::chrono::steady_clock::now(); +} + +void BatchingPacketsEstimator::onWindowDecrease(double win_current) { + TimePoint end = std::chrono::steady_clock::now(); + auto delay = + std::chrono::duration_cast(end - this->begin_batch_) + .count(); + this->avg_win_ += this->win_current_ * delay; + this->win_current_ = win_current; + this->win_change_ += delay; + this->begin_batch_ = std::chrono::steady_clock::now(); +} + +} // end namespace protocol + +} // end namespace transport diff --git a/libtransport/src/protocols/rate_estimation.h b/libtransport/src/protocols/rate_estimation.h new file mode 100644 index 000000000..17f39e0b9 --- /dev/null +++ b/libtransport/src/protocols/rate_estimation.h @@ -0,0 +1,174 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include + +#include + +namespace transport { + +namespace protocol { + +class IcnRateEstimator { + public: + using TimePoint = std::chrono::steady_clock::time_point; + using Microseconds = std::chrono::microseconds; + + IcnRateEstimator(){}; + + virtual ~IcnRateEstimator(){}; + + virtual void onRttUpdate(double rtt){}; + + virtual void onDataReceived(int packetSize){}; + + virtual void onWindowIncrease(double winCurrent){}; + + virtual void onWindowDecrease(double winCurrent){}; + + virtual void onStart(){}; + + virtual void onDownloadFinished(){}; + + virtual void setObserver(interface::IcnObserver *observer) { + this->observer_ = observer; + }; + interface::IcnObserver *observer_; + TimePoint start_time_; + TimePoint begin_batch_; + double base_alpha_; + double alpha_; + double estimation_; + int number_of_packets_; + // this boolean is to make sure at least one estimation of the BW is done + bool estimated_; +}; + +// A rate estimator RTT-based. Computes EWMA(WinSize)/EWMA(RTT) + +class InterRttEstimator : public IcnRateEstimator { + public: + InterRttEstimator(double alpha_arg); + + ~InterRttEstimator(); + + void onRttUpdate(double rtt); + + void onDataReceived(int packet_size) { + if (packet_size > this->max_packet_size_) { + this->max_packet_size_ = packet_size; + } + }; + + void onWindowIncrease(double win_current); + + void onWindowDecrease(double win_current); + + void onStart(){}; + + void onDownloadFinished(){}; + + // private: should be done by using getters + pthread_t *my_th_; + bool thread_is_running_; + double rtt_; + bool is_running_; + pthread_mutex_t mutex_; + double avg_rtt_; + double avg_win_; + int max_packet_size_; + double win_change_; + double win_current_; +}; + +// A rate estimator, Batching Packets based. Computes EWMA(WinSize)/EWMA(RTT) + +class BatchingPacketsEstimator : public IcnRateEstimator { + public: + BatchingPacketsEstimator(double alpha_arg, int batchingParam); + + void onRttUpdate(double rtt); + + void onDataReceived(int packet_size) { + if (packet_size > this->max_packet_size_) { + this->max_packet_size_ = packet_size; + } + }; + + void onWindowIncrease(double win_current); + + void onWindowDecrease(double win_current); + + void onStart(){}; + + void onDownloadFinished(){}; + + private: + int batching_param_; + double avg_rtt_; + double avg_win_; + double win_change_; + int max_packet_size_; + double win_current_; +}; + +// Segment Estimator + +class ALaTcpEstimator : public IcnRateEstimator { + public: + ALaTcpEstimator(); + + void onDataReceived(int packet_size); + void onStart(); + void onDownloadFinished(); + + private: + double totalSize_; +}; + +// A Rate estimator, this one is the simplest: counting batching_param_ packets +// and then divide the sum of the size of these packets by the time taken to DL +// them. Should be the one used + +class SimpleEstimator : public IcnRateEstimator { + public: + SimpleEstimator(double alpha, int batching_param); + + void onRttUpdate(double rtt); + + void onDataReceived(int packet_size); + + void onWindowIncrease(double win_current){}; + + void onWindowDecrease(double win_current){}; + + void onStart(); + + void onDownloadFinished(); + + private: + int batching_param_; + double total_size_; +}; + +void *Timer(void *data); + +} // namespace protocol + +} // end namespace transport diff --git a/libtransport/src/protocols/reassembly.cc b/libtransport/src/protocols/reassembly.cc new file mode 100644 index 000000000..c6602153c --- /dev/null +++ b/libtransport/src/protocols/reassembly.cc @@ -0,0 +1,72 @@ +/* + * 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. + */ + +#include +#include +#include + +#include +#include +#include +#include + +namespace transport { + +namespace protocol { + +void Reassembly::notifyApplication() { + interface::ConsumerSocket::ReadCallback *read_callback = nullptr; + reassembly_consumer_socket_->getSocketOption( + interface::ConsumerCallbacksOptions::READ_CALLBACK, &read_callback); + + if (TRANSPORT_EXPECT_FALSE(!read_callback)) { + TRANSPORT_LOGE("Read callback not installed!"); + return; + } + + if (read_callback->isBufferMovable()) { + // No need to perform an additional copy. The whole buffer will be + // tranferred to the application. + + read_callback->readBufferAvailable(std::move(read_buffer_)); + read_buffer_ = utils::MemBuf::create(read_callback->maxBufferSize()); + } else { + // The buffer will be copied into the application-provided buffer + uint8_t *buffer; + std::size_t length; + std::size_t total_length = read_buffer_->length(); + + while (read_buffer_->length()) { + buffer = nullptr; + length = 0; + read_callback->getReadBuffer(&buffer, &length); + + if (!buffer || !length) { + throw errors::RuntimeException( + "Invalid buffer provided by the application."); + } + + auto to_copy = std::min(read_buffer_->length(), length); + std::memcpy(buffer, read_buffer_->data(), to_copy); + read_buffer_->trimStart(to_copy); + } + + read_callback->readDataAvailable(total_length); + read_buffer_->clear(); + } +} + +} // namespace protocol +} // namespace transport diff --git a/libtransport/src/protocols/reassembly.h b/libtransport/src/protocols/reassembly.h new file mode 100644 index 000000000..fdc9f2a05 --- /dev/null +++ b/libtransport/src/protocols/reassembly.h @@ -0,0 +1,67 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace transport { + +namespace implementation { +class ConsumerReadCallback; +class ConsumerSocket; +} // namespace implementation + +namespace protocol { + +class TransportProtocol; +class Indexer; + +// Forward Declaration +class ManifestManager; + +class Reassembly { + public: + class ContentReassembledCallback { + public: + virtual void onContentReassembled(std::error_code ec) = 0; + }; + + Reassembly(implementation::ConsumerSocket *icn_socket, + TransportProtocol *transport_protocol) + : reassembly_consumer_socket_(icn_socket), + transport_protocol_(transport_protocol) {} + + virtual ~Reassembly() = default; + + virtual void reassemble(core::ContentObject::Ptr &&content_object) = 0; + virtual void reassemble( + std::unique_ptr &&manifest) = 0; + virtual void reInitialize() = 0; + virtual void setIndexer(Indexer *indexer) { index_manager_ = indexer; } + + protected: + virtual void notifyApplication(); + + protected: + implementation::ConsumerSocket *reassembly_consumer_socket_; + TransportProtocol *transport_protocol_; + Indexer *index_manager_; + std::unique_ptr read_buffer_; +}; + +} // namespace protocol + +} // end namespace transport diff --git a/libtransport/src/protocols/rtc.cc b/libtransport/src/protocols/rtc.cc new file mode 100644 index 000000000..0ac3839dd --- /dev/null +++ b/libtransport/src/protocols/rtc.cc @@ -0,0 +1,1017 @@ +/* + * 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. + */ + +#include + +#include +#include + +#include +#include + +namespace transport { + +namespace protocol { + +using namespace interface; + +RTCTransportProtocol::RTCTransportProtocol( + implementation::ConsumerSocket *icn_socket) + : TransportProtocol(icn_socket, nullptr), + DatagramReassembly(icn_socket, this), + inflightInterests_(1 << default_values::log_2_default_buffer_size), + modMask_((1 << default_values::log_2_default_buffer_size) - 1) { + icn_socket->getSocketOption(PORTAL, portal_); + rtx_timer_ = std::make_unique(portal_->getIoService()); + probe_timer_ = std::make_unique(portal_->getIoService()); + sentinel_timer_ = + std::make_unique(portal_->getIoService()); + round_timer_ = std::make_unique(portal_->getIoService()); + reset(); +} + +RTCTransportProtocol::~RTCTransportProtocol() { + if (is_running_) { + stop(); + } +} + +int RTCTransportProtocol::start() { + if (is_running_) return -1; + + reset(); + is_first_ = true; + + probeRtt(); + sentinelTimer(); + newRound(); + scheduleNextInterests(); + + is_first_ = false; + is_running_ = true; + portal_->runEventsLoop(); + is_running_ = false; + + return 0; +} + +void RTCTransportProtocol::stop() { + if (!is_running_) return; + + is_running_ = false; + portal_->stopEventsLoop(); +} + +void RTCTransportProtocol::resume() { + if (is_running_) return; + + is_running_ = true; + inflightInterestsCount_ = 0; + + probeRtt(); + sentinelTimer(); + newRound(); + scheduleNextInterests(); + + portal_->runEventsLoop(); + is_running_ = false; +} + +// private +void RTCTransportProtocol::reset() { + portal_->setConsumerCallback(this); + // controller var + currentState_ = HICN_RTC_SYNC_STATE; + + // cwin var + currentCWin_ = HICN_INITIAL_CWIN; + maxCWin_ = HICN_INITIAL_CWIN_MAX; + + // names/packets var + actualSegment_ = 0; + inflightInterestsCount_ = 0; + interestRetransmissions_.clear(); + lastSegNacked_ = 0; + lastReceived_ = 0; + lastReceivedTime_ = std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()) + .count(); + lastEvent_ = lastReceivedTime_; + highestReceived_ = 0; + firstSequenceInRound_ = 0; + + rtx_timer_used_ = false; + for (int i = 0; i < (1 << default_values::log_2_default_buffer_size); i++) { + inflightInterests_[i] = {0}; + } + + // stats + firstPckReceived_ = false; + receivedBytes_ = 0; + sentInterest_ = 0; + receivedData_ = 0; + packetLost_ = 0; + lossRecovered_ = 0; + avgPacketSize_ = HICN_INIT_PACKET_SIZE; + gotNack_ = false; + gotFutureNack_ = 0; + rounds_ = 0; + roundsWithoutNacks_ = 0; + pathTable_.clear(); + + // CC var + estimatedBw_ = 0.0; + lossRate_ = 0.0; + queuingDelay_ = 0.0; + protocolState_ = HICN_RTC_NORMAL_STATE; + + producerPathLabels_[0] = 0; + producerPathLabels_[1] = 0; + initied = false; + + socket_->setSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, + (uint32_t)HICN_RTC_INTEREST_LIFETIME); + // XXX this should be done by the application +} + +uint32_t max(uint32_t a, uint32_t b) { + if (a > b) + return a; + else + return b; +} + +uint32_t min(uint32_t a, uint32_t b) { + if (a < b) + return a; + else + return b; +} + +void RTCTransportProtocol::newRound() { + round_timer_->expires_from_now(std::chrono::milliseconds(HICN_ROUND_LEN)); + round_timer_->async_wait([this](std::error_code ec) { + if (ec) return; + updateStats(HICN_ROUND_LEN); + newRound(); + }); +} + +void RTCTransportProtocol::updateDelayStats( + const ContentObject &content_object) { + uint32_t segmentNumber = content_object.getName().getSuffix(); + uint32_t pkt = segmentNumber & modMask_; + + if (inflightInterests_[pkt].state != sent_) return; + + if (interestRetransmissions_.find(segmentNumber) != + interestRetransmissions_.end()) + // this packet was rtx at least once + return; + + uint32_t pathLabel = content_object.getPathLabel(); + + if (pathTable_.find(pathLabel) == pathTable_.end()) { + // found a new path + std::shared_ptr newPath = std::make_shared(); + pathTable_[pathLabel] = newPath; + } + + // RTT measurements are useful both from NACKs and data packets + uint64_t RTT = std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()) + .count() - + inflightInterests_[pkt].transmissionTime; + + pathTable_[pathLabel]->insertRttSample(RTT); + auto payload = content_object.getPayload(); + + // we collect OWD only for datapackets + if (payload->length() != HICN_NACK_HEADER_SIZE) { + uint64_t *senderTimeStamp = (uint64_t *)payload->data(); + int64_t OWD = std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()) + .count() - + *senderTimeStamp; + + pathTable_[pathLabel]->insertOwdSample(OWD); + pathTable_[pathLabel]->computeInterArrivalGap(segmentNumber); + } else { + pathTable_[pathLabel]->receivedNack(); + } +} + +void RTCTransportProtocol::updateStats(uint32_t round_duration) { + if (pathTable_.empty()) return; + + if (receivedBytes_ != 0) { + double bytesPerSec = + (double)(receivedBytes_ * + ((double)HICN_MILLI_IN_A_SEC / (double)round_duration)); + estimatedBw_ = (estimatedBw_ * HICN_ESTIMATED_BW_ALPHA) + + ((1 - HICN_ESTIMATED_BW_ALPHA) * bytesPerSec); + } + + uint64_t minRtt = UINT_MAX; + uint64_t maxRtt = 0; + + for (auto it = pathTable_.begin(); it != pathTable_.end(); it++) { + it->second->roundEnd(); + if (it->second->isActive()) { + if (it->second->getMinRtt() < minRtt) { + minRtt = it->second->getMinRtt(); + producerPathLabels_[0] = it->first; + } + if (it->second->getMinRtt() > maxRtt) { + maxRtt = it->second->getMinRtt(); + producerPathLabels_[1] = it->first; + } + } + } + + if (pathTable_.find(producerPathLabels_[0]) == pathTable_.end() || + pathTable_.find(producerPathLabels_[1]) == pathTable_.end()) + return; // this should not happen + + // as a queuing delay we keep the lowest one among the two paths + // if one path is congested the forwarder should decide to do not + // use it so it does not make sense to inform the application + // that maybe we have a problem + if (pathTable_[producerPathLabels_[0]]->getQueuingDealy() < + pathTable_[producerPathLabels_[1]]->getQueuingDealy()) + queuingDelay_ = pathTable_[producerPathLabels_[0]]->getQueuingDealy(); + else + queuingDelay_ = pathTable_[producerPathLabels_[1]]->getQueuingDealy(); + + if (sentInterest_ != 0 && currentState_ == HICN_RTC_NORMAL_STATE) { + uint32_t numberTheoricallyReceivedPackets_ = + highestReceived_ - firstSequenceInRound_; + double lossRate = 0; + if (numberTheoricallyReceivedPackets_ != 0) + lossRate = (double)((double)(packetLost_ - lossRecovered_) / + (double)numberTheoricallyReceivedPackets_); + + if (lossRate < 0) lossRate = 0; + + if (initied) { + lossRate_ = lossRate_ * HICN_ESTIMATED_LOSSES_ALPHA + + (lossRate * (1 - HICN_ESTIMATED_LOSSES_ALPHA)); + } else { + lossRate_ = lossRate; + initied = true; + } + } + + if (avgPacketSize_ == 0) avgPacketSize_ = HICN_INIT_PACKET_SIZE; + + // for the BDP we use the max rtt, so that we calibrate the window on the + // RTT of the slowest path. In this way we are sure that the window will + // never be too small + uint32_t BDP = (uint32_t)ceil( + (estimatedBw_ * + (double)((double)pathTable_[producerPathLabels_[1]]->getMinRtt() / + (double)HICN_MILLI_IN_A_SEC) * + HICN_BANDWIDTH_SLACK_FACTOR) / + avgPacketSize_); + uint32_t BW = (uint32_t)ceil(estimatedBw_); + computeMaxWindow(BW, BDP); + + ConsumerTimerCallback *stats_callback = nullptr; + socket_->getSocketOption(ConsumerCallbacksOptions::STATS_SUMMARY, + &stats_callback); + if (*stats_callback) { + // Send the stats to the app + stats_->updateQueuingDelay(queuingDelay_); + stats_->updateLossRatio(lossRate_); + stats_->updateAverageRtt(pathTable_[producerPathLabels_[1]]->getMinRtt()); + (*stats_callback)(*socket_->getInterface(), *stats_); + } + // bound also by interest lifitime* production rate + if (!gotNack_) { + roundsWithoutNacks_++; + if (currentState_ == HICN_RTC_SYNC_STATE && + roundsWithoutNacks_ >= HICN_ROUNDS_IN_SYNC_BEFORE_SWITCH) { + currentState_ = HICN_RTC_NORMAL_STATE; + } + } else { + roundsWithoutNacks_ = 0; + } + + updateCCState(); + updateWindow(); + + if (queuingDelay_ > 25.0) { + // this indicates that the client will go soon out of synch, + // switch to synch mode + if (currentState_ == HICN_RTC_NORMAL_STATE) { + currentState_ = HICN_RTC_SYNC_STATE; + } + computeMaxWindow(BW, 0); + increaseWindow(); + } + + // in any case we reset all the counters + + gotNack_ = false; + gotFutureNack_ = 0; + receivedBytes_ = 0; + sentInterest_ = 0; + receivedData_ = 0; + packetLost_ = 0; + lossRecovered_ = 0; + rounds_++; + firstSequenceInRound_ = highestReceived_; +} + +void RTCTransportProtocol::updateCCState() { + // TODO +} + +void RTCTransportProtocol::computeMaxWindow(uint32_t productionRate, + uint32_t BDPWin) { + if (productionRate == + 0) // we have no info about the producer, keep the previous maxCWin + return; + + uint32_t interestLifetime = default_values::interest_lifetime; + socket_->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, + interestLifetime); + uint32_t maxWaintingInterest = (uint32_t)ceil( + (productionRate / avgPacketSize_) * + (double)((double)(interestLifetime * + HICN_INTEREST_LIFETIME_REDUCTION_FACTOR) / + (double)HICN_MILLI_IN_A_SEC)); + + if (currentState_ == HICN_RTC_SYNC_STATE) { + // in this case we do not limit the window with the BDP, beacuse most + // likely it is wrong + maxCWin_ = maxWaintingInterest; + return; + } + + // currentState = RTC_NORMAL_STATE + if (BDPWin != 0) { + maxCWin_ = (uint32_t)ceil((double)BDPWin + + (((double)BDPWin * 30.0) / 100.0)); // BDP + 30% + } else { + maxCWin_ = min(maxWaintingInterest, maxCWin_); + } + + if (maxCWin_ < HICN_MIN_CWIN) maxCWin_ = HICN_MIN_CWIN; +} + +void RTCTransportProtocol::updateWindow() { + if (currentState_ == HICN_RTC_SYNC_STATE) return; + + if (currentCWin_ < maxCWin_ * 0.9) { + currentCWin_ = + min(maxCWin_, (uint32_t)(currentCWin_ * HICN_WIN_INCREASE_FACTOR)); + } else if (currentCWin_ > maxCWin_) { + currentCWin_ = + max((uint32_t)(currentCWin_ * HICN_WIN_DECREASE_FACTOR), HICN_MIN_CWIN); + } +} + +void RTCTransportProtocol::decreaseWindow() { + // this is used only in SYNC mode + if (currentState_ == HICN_RTC_NORMAL_STATE) return; + + if (gotFutureNack_ == 1) + currentCWin_ = min((currentCWin_ - 1), + (uint32_t)ceil((double)maxCWin_ * 0.66)); // 2/3 + else + currentCWin_--; + + currentCWin_ = max(currentCWin_, HICN_MIN_CWIN); +} + +void RTCTransportProtocol::increaseWindow() { + // this is used only in SYNC mode + if (currentState_ == HICN_RTC_NORMAL_STATE) return; + + // we need to be carefull to do not increase the window to much + if (currentCWin_ < ((double)maxCWin_ * 0.7)) { + currentCWin_ = currentCWin_ + 1; // exponential + } else { + currentCWin_ = min( + maxCWin_, + (uint32_t)ceil(currentCWin_ + (1.0 / (double)currentCWin_))); // linear + } +} + +void RTCTransportProtocol::probeRtt() { + probe_timer_->expires_from_now(std::chrono::milliseconds(1000)); + probe_timer_->async_wait([this](std::error_code ec) { + if (ec) return; + probeRtt(); + }); + + // To avoid sending the first probe, because the transport is not running yet + if (is_first_ && !is_running_) return; + + time_sent_probe_ = std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()) + .count(); + + Name *interest_name = nullptr; + socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME, + &interest_name); + // get a random numbe in the probe seq range + std::default_random_engine eng((std::random_device())()); + std::uniform_int_distribution idis(HICN_MIN_PROBE_SEQ, + HICN_MAX_PROBE_SEQ); + probe_seq_number_ = idis(eng); + interest_name->setSuffix(probe_seq_number_); + + // we considere the probe as a rtx so that we do not incresea inFlightInt + received_probe_ = false; + TRANSPORT_LOGD("Send content interest %u (probeRtt)", + interest_name->getSuffix()); + sendInterest(interest_name, true); +} + +void RTCTransportProtocol::sendInterest(Name *interest_name, bool rtx) { + auto interest = getPacket(); + interest->setName(*interest_name); + + uint32_t interestLifetime = default_values::interest_lifetime; + socket_->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, + interestLifetime); + interest->setLifetime(uint32_t(interestLifetime)); + + ConsumerInterestCallback *on_interest_output = nullptr; + + socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_OUTPUT, + &on_interest_output); + + if (*on_interest_output) { + (*on_interest_output)(*socket_->getInterface(), *interest); + } + + if (TRANSPORT_EXPECT_FALSE(!is_running_ && !is_first_)) { + return; + } + + portal_->sendInterest(std::move(interest)); + + sentInterest_++; + + if (!rtx) { + packets_in_window_[interest_name->getSuffix()] = 0; + inflightInterestsCount_++; + } +} + +void RTCTransportProtocol::scheduleNextInterests() { + if (!is_running_ && !is_first_) return; + + TRANSPORT_LOGD("----- [window %u - inflight_interests %u = %d] -----", + currentCWin_, inflightInterestsCount_, + currentCWin_ - inflightInterestsCount_); + + while (inflightInterestsCount_ < currentCWin_) { + Name *interest_name = nullptr; + socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME, + &interest_name); + + interest_name->setSuffix(actualSegment_); + + // if the producer socket is not stated (does not reply even with nacks) + // we keep asking for something without marking anything as lost (see + // timeout). In this way when the producer socket will start the + // consumer socket will not miss any packet + if (TRANSPORT_EXPECT_FALSE(!firstPckReceived_)) { + uint32_t pkt = actualSegment_ & modMask_; + inflightInterests_[pkt].state = sent_; + inflightInterests_[pkt].sequence = actualSegment_; + actualSegment_ = (actualSegment_ + 1) % HICN_MIN_PROBE_SEQ; + TRANSPORT_LOGD( + "Send content interest %u (scheduleNextInterests no replies)", + interest_name->getSuffix()); + sendInterest(interest_name, false); + return; + } + + // we send the packet only if it is not pending yet + // notice that this is not true for rtx packets + if (portal_->interestIsPending(*interest_name)) { + actualSegment_ = (actualSegment_ + 1) % HICN_MIN_PROBE_SEQ; + continue; + } + + uint32_t pkt = actualSegment_ & modMask_; + // if we already reacevied the content we don't ask it again + if (inflightInterests_[pkt].state == received_ && + inflightInterests_[pkt].sequence == actualSegment_) { + actualSegment_ = (actualSegment_ + 1) % HICN_MIN_PROBE_SEQ; + continue; + } + + // same if the packet is lost + if (inflightInterests_[pkt].state == lost_ && + inflightInterests_[pkt].sequence == actualSegment_) { + actualSegment_ = (actualSegment_ + 1) % HICN_MIN_PROBE_SEQ; + continue; + } + + inflightInterests_[pkt].transmissionTime = + std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()) + .count(); + + // here the packet can be in any state except for lost or recevied + inflightInterests_[pkt].state = sent_; + inflightInterests_[pkt].sequence = actualSegment_; + actualSegment_ = (actualSegment_ + 1) % HICN_MIN_PROBE_SEQ; + + TRANSPORT_LOGD("Send content interest %u (scheduleNextInterests)", + interest_name->getSuffix()); + sendInterest(interest_name, false); + } + + TRANSPORT_LOGD("----- end of scheduleNextInterest -----"); +} + +bool RTCTransportProtocol::verifyKeyPackets() { + // Not yet implemented + return false; +} + +void RTCTransportProtocol::sentinelTimer() { + uint32_t wait = 50; + + if (pathTable_.find(producerPathLabels_[0]) != pathTable_.end() && + pathTable_.find(producerPathLabels_[1]) != pathTable_.end()) { + // we have all the info to set the timers + wait = round(pathTable_[producerPathLabels_[0]]->getInterArrivalGap()); + if (wait == 0) wait = 1; + } + + sentinel_timer_->expires_from_now(std::chrono::milliseconds(wait)); + sentinel_timer_->async_wait([this](std::error_code ec) { + if (ec) return; + + uint64_t now = std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()) + .count(); + + if (pathTable_.find(producerPathLabels_[0]) == pathTable_.end() || + pathTable_.find(producerPathLabels_[1]) == pathTable_.end()) { + // we have no info, so we send again + + for (auto it = packets_in_window_.begin(); it != packets_in_window_.end(); + it++) { + uint32_t pkt = it->first & modMask_; + if (inflightInterests_[pkt].sequence == it->first) { + inflightInterests_[pkt].transmissionTime = now; + Name *interest_name = nullptr; + socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME, + &interest_name); + interest_name->setSuffix(it->first); + it->second++; + sendInterest(interest_name, true); + } + } + } else { + uint64_t max_waiting_time = // wait at least 50ms + (pathTable_[producerPathLabels_[1]]->getMinRtt() - + pathTable_[producerPathLabels_[0]]->getMinRtt()) + + (ceil(pathTable_[producerPathLabels_[0]]->getInterArrivalGap()) * 50); + + if ((currentState_ == HICN_RTC_NORMAL_STATE) && + (inflightInterestsCount_ >= currentCWin_) && + ((now - lastEvent_) > max_waiting_time) && (lossRate_ >= 0.05)) { + uint64_t RTT = pathTable_[producerPathLabels_[1]]->getMinRtt(); + + for (auto it = packets_in_window_.begin(); + it != packets_in_window_.end(); it++) { + uint32_t pkt = it->first & modMask_; + if (inflightInterests_[pkt].sequence == it->first && + ((now - inflightInterests_[pkt].transmissionTime) >= RTT)) { + inflightInterests_[pkt].transmissionTime = now; + Name *interest_name = nullptr; + socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME, + &interest_name); + interest_name->setSuffix(it->first); + it->second++; + sendInterest(interest_name, true); + } + } + } + } + + sentinelTimer(); + }); +} +void RTCTransportProtocol::addRetransmissions(uint32_t val) { + // add only val in the rtx list + addRetransmissions(val, val + 1); +} + +void RTCTransportProtocol::addRetransmissions(uint32_t start, uint32_t stop) { + uint64_t now = std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()) + .count(); + + bool new_rtx = false; + for (uint32_t i = start; i < stop; i++) { + auto it = interestRetransmissions_.find(i); + if (it == interestRetransmissions_.end()) { + uint32_t pkt = i & modMask_; + if (lastSegNacked_ <= i && inflightInterests_[pkt].state != received_) { + // it must be larger than the last past nack received + packetLost_++; + interestRetransmissions_[i] = 0; + uint32_t pkt = i & modMask_; + // we reset the transmission time setting to now, so that rtx will + // happne in one RTT on waint one inter arrival gap + inflightInterests_[pkt].transmissionTime = now; + new_rtx = true; + } + } // if the retransmission is already there the rtx timer will + // take care of it + } + + // in case a new rtx is added to the map we need to run checkRtx() + if (new_rtx) { + if (rtx_timer_used_) { + // if a timer is pending we need to delete it + rtx_timer_->cancel(); + rtx_timer_used_ = false; + } + checkRtx(); + } +} + +uint64_t RTCTransportProtocol::retransmit() { + auto it = interestRetransmissions_.begin(); + + // cut len to max HICN_MAX_RTX_SIZE + // since we use a map, the smaller (and so the older) sequence number are at + // the beginnin of the map + while (interestRetransmissions_.size() > HICN_MAX_RTX_SIZE) { + it = interestRetransmissions_.erase(it); + } + + it = interestRetransmissions_.begin(); + uint64_t smallest_timeout = ULONG_MAX; + uint64_t now = std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()) + .count(); + + while (it != interestRetransmissions_.end()) { + uint32_t pkt = it->first & modMask_; + + if (inflightInterests_[pkt].sequence != it->first) { + // this packet is not anymore in the inflight buffer, erase it + it = interestRetransmissions_.erase(it); + continue; + } + + // we retransmitted the packet too many times + if (it->second >= HICN_MAX_RTX) { + it = interestRetransmissions_.erase(it); + continue; + } + + // this packet is too old + if ((lastReceived_ > it->first) && + (lastReceived_ - it->first) > HICN_MAX_RTX_MAX_AGE) { + it = interestRetransmissions_.erase(it); + continue; + } + + uint64_t rtx_time = now; + + if (it->second == 0) { + // first rtx + if (producerPathLabels_[0] != producerPathLabels_[1]) { + // multipath + if (pathTable_.find(producerPathLabels_[0]) != pathTable_.end() && + pathTable_.find(producerPathLabels_[1]) != pathTable_.end() && + (pathTable_[producerPathLabels_[0]]->getInterArrivalGap() < + HICN_MIN_INTER_ARRIVAL_GAP)) { + rtx_time = lastReceivedTime_ + + (pathTable_[producerPathLabels_[1]]->getMinRtt() - + pathTable_[producerPathLabels_[0]]->getMinRtt()) + + pathTable_[producerPathLabels_[0]]->getInterArrivalGap(); + } // else low rate producer, send it immediatly + } else { + // single path + if (pathTable_.find(producerPathLabels_[0]) != pathTable_.end() && + (pathTable_[producerPathLabels_[0]]->getInterArrivalGap() < + HICN_MIN_INTER_ARRIVAL_GAP)) { + rtx_time = lastReceivedTime_ + + pathTable_[producerPathLabels_[0]]->getInterArrivalGap(); + } // else low rate producer send immediatly + } + } else { + // second or plus rtx, wait for the min rtt + if (pathTable_.find(producerPathLabels_[0]) != pathTable_.end()) { + uint64_t sent_time = inflightInterests_[pkt].transmissionTime; + rtx_time = sent_time + pathTable_[producerPathLabels_[0]]->getMinRtt(); + } // if we don't have info we send it immediatly + } + + if (now >= rtx_time) { + inflightInterests_[pkt].transmissionTime = now; + it->second++; + + Name *interest_name = nullptr; + socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME, + &interest_name); + interest_name->setSuffix(it->first); + TRANSPORT_LOGD("Send content interest %u (retransmit)", + interest_name->getSuffix()); + sendInterest(interest_name, true); + } else if (rtx_time < smallest_timeout) { + smallest_timeout = rtx_time; + } + + ++it; + } + return smallest_timeout; +} + +void RTCTransportProtocol::checkRtx() { + if (interestRetransmissions_.empty()) { + rtx_timer_used_ = false; + return; + } + + uint64_t next_timeout = retransmit(); + uint64_t wait = 1; + uint64_t now = std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()) + .count(); + if (next_timeout != ULONG_MAX && now < next_timeout) { + wait = next_timeout - now; + } + rtx_timer_used_ = true; + rtx_timer_->expires_from_now(std::chrono::milliseconds(wait)); + rtx_timer_->async_wait([this](std::error_code ec) { + if (ec) return; + rtx_timer_used_ = false; + checkRtx(); + }); +} + +void RTCTransportProtocol::onTimeout(Interest::Ptr &&interest) { + uint32_t segmentNumber = interest->getName().getSuffix(); + + if (segmentNumber >= HICN_MIN_PROBE_SEQ) { + // this is a timeout on a probe, do nothing + return; + } + + uint32_t pkt = segmentNumber & modMask_; + + if (TRANSPORT_EXPECT_FALSE(!firstPckReceived_)) { + // we do nothing, and we keep asking the same stuff over + // and over until we get at least a packet + inflightInterestsCount_--; + lastEvent_ = std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()) + .count(); + packets_in_window_.erase(segmentNumber); + scheduleNextInterests(); + return; + } + + if (inflightInterests_[pkt].state == sent_) { + lastEvent_ = std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()) + .count(); + packets_in_window_.erase(segmentNumber); + inflightInterestsCount_--; + } + + // check how many times we sent this packet + auto it = interestRetransmissions_.find(segmentNumber); + if (it != interestRetransmissions_.end() && it->second >= HICN_MAX_RTX) { + inflightInterests_[pkt].state = lost_; + } + + if (inflightInterests_[pkt].state == sent_) { + inflightInterests_[pkt].state = timeout1_; + } else if (inflightInterests_[pkt].state == timeout1_) { + inflightInterests_[pkt].state = timeout2_; + } else if (inflightInterests_[pkt].state == timeout2_) { + inflightInterests_[pkt].state = lost_; + } + + if (inflightInterests_[pkt].state == lost_) { + interestRetransmissions_.erase(segmentNumber); + } else { + addRetransmissions(segmentNumber); + } + + scheduleNextInterests(); +} + +bool RTCTransportProtocol::onNack(const ContentObject &content_object, + bool rtx) { + uint32_t *payload = (uint32_t *)content_object.getPayload()->data(); + uint32_t productionSeg = *payload; + uint32_t productionRate = *(++payload); + uint32_t nackSegment = content_object.getName().getSuffix(); + + bool old_nack = false; + + // if we did not received anything between lastReceived_ + 1 and productionSeg + // most likelly some packets got lost + if (lastReceived_ != 0) { + addRetransmissions(lastReceived_ + 1, productionSeg); + } + + if (!rtx) { + gotNack_ = true; + // we synch the estimated production rate with the actual one + estimatedBw_ = (double)productionRate; + } + + if (productionSeg > nackSegment) { + // we are asking for stuff produced in the past + actualSegment_ = max(productionSeg, actualSegment_) % HICN_MIN_PROBE_SEQ; + + if (!rtx) { + if (currentState_ == HICN_RTC_NORMAL_STATE) { + currentState_ = HICN_RTC_SYNC_STATE; + } + + computeMaxWindow(productionRate, 0); + increaseWindow(); + } + + lastSegNacked_ = productionSeg; + old_nack = true; + + } else if (productionSeg < nackSegment) { + actualSegment_ = productionSeg % HICN_MIN_PROBE_SEQ; + + if (!rtx) { + // we are asking stuff in the future + gotFutureNack_++; + computeMaxWindow(productionRate, 0); + decreaseWindow(); + + if (currentState_ == HICN_RTC_SYNC_STATE) { + currentState_ = HICN_RTC_NORMAL_STATE; + } + } + } else { + // we are asking the right thing, but the producer is slow + // keep doing the same until the packet is produced + actualSegment_ = productionSeg % HICN_MIN_PROBE_SEQ; + } + + return old_nack; +} + +void RTCTransportProtocol::onContentObject( + Interest::Ptr &&interest, ContentObject::Ptr &&content_object) { + // as soon as we get a packet firstPckReceived_ will never be false + firstPckReceived_ = true; + + auto payload = content_object->getPayload(); + uint32_t payload_size = (uint32_t)payload->length(); + uint32_t segmentNumber = content_object->getName().getSuffix(); + uint32_t pkt = segmentNumber & modMask_; + + ConsumerContentObjectCallback *callback_content_object = nullptr; + socket_->getSocketOption(ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT, + &callback_content_object); + if (*callback_content_object) { + (*callback_content_object)(*socket_->getInterface(), *content_object); + } + + if (segmentNumber >= HICN_MIN_PROBE_SEQ) { + TRANSPORT_LOGD("Received probe %u", segmentNumber); + if (segmentNumber == probe_seq_number_ && !received_probe_) { + received_probe_ = true; + + uint32_t pathLabel = content_object->getPathLabel(); + if (pathTable_.find(pathLabel) == pathTable_.end()) { + std::shared_ptr newPath = std::make_shared(); + pathTable_[pathLabel] = newPath; + } + + // this is the expected probe, update the RTT and drop the packet + uint64_t RTT = std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()) + .count() - + time_sent_probe_; + + pathTable_[pathLabel]->insertRttSample(RTT); + pathTable_[pathLabel]->receivedNack(); + } + return; + } + + // check if the packet is a rtx + bool is_rtx = false; + if (interestRetransmissions_.find(segmentNumber) != + interestRetransmissions_.end()) { + is_rtx = true; + } else { + auto it_win = packets_in_window_.find(segmentNumber); + if (it_win != packets_in_window_.end() && it_win->second != 0) + is_rtx = true; + } + + if (payload_size == HICN_NACK_HEADER_SIZE) { + TRANSPORT_LOGD("Received nack %u", segmentNumber); + + if (inflightInterests_[pkt].state == sent_) { + lastEvent_ = std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()) + .count(); + packets_in_window_.erase(segmentNumber); + inflightInterestsCount_--; + } + + bool old_nack = false; + + if (!is_rtx) { + // this is not a retransmitted packet + old_nack = onNack(*content_object, false); + updateDelayStats(*content_object); + } else { + old_nack = onNack(*content_object, true); + } + + // the nacked_ state is used only to avoid to decrease + // inflightInterestsCount_ multiple times. In fact, every time that we + // receive an event related to an interest (timeout, nacked, content) we + // cange the state. In this way we are sure that we do not decrease twice + // the counter + if (old_nack) { + inflightInterests_[pkt].state = lost_; + interestRetransmissions_.erase(segmentNumber); + } else { + inflightInterests_[pkt].state = nacked_; + } + + } else { + TRANSPORT_LOGD("Received content %u", segmentNumber); + + avgPacketSize_ = (HICN_ESTIMATED_PACKET_SIZE * avgPacketSize_) + + ((1 - HICN_ESTIMATED_PACKET_SIZE) * payload->length()); + + receivedBytes_ += (uint32_t)(content_object->headerSize() + + content_object->payloadSize()); + + if (inflightInterests_[pkt].state == sent_) { + lastEvent_ = std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()) + .count(); + packets_in_window_.erase(segmentNumber); + inflightInterestsCount_--; // packet sent without timeouts + } + + if (inflightInterests_[pkt].state == sent_ && !is_rtx) { + // delay stats are computed only for non retransmitted data + updateDelayStats(*content_object); + } + + addRetransmissions(lastReceived_ + 1, segmentNumber); + if (segmentNumber > highestReceived_) { + highestReceived_ = segmentNumber; + } + if (segmentNumber > lastReceived_) { + lastReceived_ = segmentNumber; + lastReceivedTime_ = + std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()) + .count(); + } + receivedData_++; + inflightInterests_[pkt].state = received_; + + auto it = interestRetransmissions_.find(segmentNumber); + if (it != interestRetransmissions_.end()) lossRecovered_++; + + interestRetransmissions_.erase(segmentNumber); + + reassemble(std::move(content_object)); + increaseWindow(); + } + + scheduleNextInterests(); +} + +} // end namespace protocol + +} // end namespace transport diff --git a/libtransport/src/protocols/rtc.h b/libtransport/src/protocols/rtc.h new file mode 100644 index 000000000..f15cdd1eb --- /dev/null +++ b/libtransport/src/protocols/rtc.h @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiTC_SYNC_STATE + * 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 +#include +#include + +#include +#include +#include + +// algorithm state +#define HICN_RTC_SYNC_STATE 0 +#define HICN_RTC_NORMAL_STATE 1 +#define HICN_ROUNDS_IN_SYNC_BEFORE_SWITCH 3 + +// packet constants +#define HICN_INIT_PACKET_SIZE 1300 // bytes +#define HICN_PACKET_HEADER_SIZE 60 // bytes ipv6+tcp +#define HICN_NACK_HEADER_SIZE 8 // bytes +#define HICN_TIMESTAMP_SIZE 8 // bytes +#define HICN_RTC_INTEREST_LIFETIME 1000 // ms + +// rtt measurement +// normal interests for data goes from 0 to +// HICN_MIN_PROBE_SEQ, the rest is reserverd for +// probes +#define HICN_MIN_PROBE_SEQ 0xefffffff +#define HICN_MAX_PROBE_SEQ 0xffffffff + +// controller constant +#define HICN_ROUND_LEN \ + 200 // ms interval of time on which + // we take decisions / measurements +#define HICN_MAX_RTX 10 +#define HICN_MAX_RTX_SIZE 1024 +#define HICN_MAX_RTX_MAX_AGE 10000 +#define HICN_MIN_RTT_WIN 30 // rounds +#define HICN_MIN_INTER_ARRIVAL_GAP 100 // ms + +// cwin +#define HICN_INITIAL_CWIN 1 // packets +#define HICN_INITIAL_CWIN_MAX 100000 // packets +#define HICN_MIN_CWIN 10 // packets +#define HICN_WIN_INCREASE_FACTOR 1.5 +#define HICN_WIN_DECREASE_FACTOR 0.9 + +// statistics constants +#define HICN_BANDWIDTH_SLACK_FACTOR 1.8 +#define HICN_ESTIMATED_BW_ALPHA 0.7 +#define HICN_ESTIMATED_PACKET_SIZE 0.7 +#define HICN_ESTIMATED_LOSSES_ALPHA 0.8 +#define HICN_INTEREST_LIFETIME_REDUCTION_FACTOR 0.8 + +// other constants +#define HICN_NANO_IN_A_SEC 1000000000 +#define HICN_MICRO_IN_A_SEC 1000000 +#define HICN_MILLI_IN_A_SEC 1000 + +namespace transport { + +namespace protocol { + +enum packetState { sent_, nacked_, received_, timeout1_, timeout2_, lost_ }; + +typedef enum packetState packetState_t; + +struct sentInterest { + uint64_t transmissionTime; + uint32_t sequence; // sequence number of the interest sent + // to handle seq % buffer_size + packetState_t state; // see packet state +}; + +class RTCTransportProtocol : public TransportProtocol, + public DatagramReassembly { + public: + RTCTransportProtocol(implementation::ConsumerSocket *icnet_socket); + + ~RTCTransportProtocol(); + + int start() override; + + void stop() override; + + void resume() override; + + bool verifyKeyPackets() override; + + private: + // algo functions + void reset() override; + + // CC functions + void updateDelayStats(const ContentObject &content_object); + void updateStats(uint32_t round_duration); + void updateCCState(); + void computeMaxWindow(uint32_t productionRate, uint32_t BDPWin); + void updateWindow(); + void decreaseWindow(); + void increaseWindow(); + void resetPreviousWindow(); + + // packet functions + void sendInterest(Name *interest_name, bool rtx); + void scheduleNextInterests() override; + void sentinelTimer(); + void addRetransmissions(uint32_t val); + void addRetransmissions(uint32_t start, uint32_t stop); + uint64_t retransmit(); + void checkRtx(); + void probeRtt(); + void newRound(); + void onTimeout(Interest::Ptr &&interest) override; + bool onNack(const ContentObject &content_object, bool rtx); + void onContentObject(Interest::Ptr &&interest, + ContentObject::Ptr &&content_object) override; + void onPacketDropped(Interest::Ptr &&interest, + ContentObject::Ptr &&content_object) override {} + void onReassemblyFailed(std::uint32_t missing_segment) override {} + + TRANSPORT_ALWAYS_INLINE virtual void reassemble( + ContentObject::Ptr &&content_object) override { + auto read_buffer = content_object->getPayload(); + read_buffer->trimStart(HICN_TIMESTAMP_SIZE); + Reassembly::read_buffer_ = std::move(read_buffer); + Reassembly::notifyApplication(); + } + + // controller var + std::unique_ptr round_timer_; + unsigned currentState_; + + // cwin var + uint32_t currentCWin_; + uint32_t maxCWin_; + + // names/packets var + uint32_t actualSegment_; + uint32_t inflightInterestsCount_; + // map seq to rtx + std::map interestRetransmissions_; + bool rtx_timer_used_; + std::unique_ptr rtx_timer_; + std::vector inflightInterests_; + uint32_t lastSegNacked_; // indicates the segment id in the last received + // past Nack. we do not ask for retransmissions + // for samething that is older than this value. + uint32_t lastReceived_; // segment of the last content object received + // indicates the base of the window on the client + uint64_t lastReceivedTime_; // time at which we recevied the + // lastReceived_ packet + + // sentinel + // if all packets in the window get lost we need something that + // wakes up our consumer socket. Interest timeouts set to 1 sec + // expire too late. This timers expire much sooner and if it + // detects that all the interest in the window may be lost + // it sends all of them again + std::unique_ptr sentinel_timer_; + uint64_t lastEvent_; // time at which we removed a pending + // interest from the window + std::unordered_map packets_in_window_; + + // rtt probes + // the RTC transport tends to overestimate the RTT + // du to the production time on the server side + // once per second we send an interest for wich we know + // we will get a nack. This nack will keep our estimation + // close to the reality + std::unique_ptr probe_timer_; + uint64_t time_sent_probe_; + uint32_t probe_seq_number_; + bool received_probe_; + + uint32_t modMask_; + + // stats + bool firstPckReceived_; + uint32_t receivedBytes_; + uint32_t sentInterest_; + uint32_t receivedData_; + int32_t packetLost_; + int32_t lossRecovered_; + uint32_t firstSequenceInRound_; + uint32_t highestReceived_; + double avgPacketSize_; + bool gotNack_; + uint32_t gotFutureNack_; + uint32_t rounds_; + uint32_t roundsWithoutNacks_; + + // we keep track of up two paths (if only one path is in use + // the two values in the vector will be the same) + // position 0 stores the path with minRTT + // position 1 stores the path with maxRTT + uint32_t producerPathLabels_[2]; + + std::unordered_map> pathTable_; + uint32_t roundCounter_; + + // CC var + double estimatedBw_; + double lossRate_; + double queuingDelay_; + unsigned protocolState_; + + bool initied; +}; + +} // namespace protocol + +} // namespace transport diff --git a/libtransport/src/protocols/rtc_data_path.cc b/libtransport/src/protocols/rtc_data_path.cc new file mode 100644 index 000000000..30644e939 --- /dev/null +++ b/libtransport/src/protocols/rtc_data_path.cc @@ -0,0 +1,156 @@ +/* + * 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. + */ + +#include + +#include +#include + +#define MAX_ROUNDS_WITHOUT_PKTS 10 // 2sec + +namespace transport { + +namespace protocol { + +RTCDataPath::RTCDataPath() + : min_rtt(UINT_MAX), + prev_min_rtt(UINT_MAX), + min_owd(INT_MAX), // this is computed like in LEDBAT, so it is not the + // real OWD, but the measured one, that depends on the + // clock of sender and receiver. the only meaningful + // value is is the queueing delay. for this reason we + // keep both RTT (for the windowd calculation) and OWD + // (for congestion/quality control) + prev_min_owd(INT_MAX), + avg_owd(0.0), + queuing_delay(DBL_MAX), + lastRecvSeq_(0), + lastRecvTime_(0), + avg_inter_arrival_(DBL_MAX), + received_nacks_(false), + received_packets_(false), + rounds_without_packets_(0), + RTThistory_(HISTORY_LEN), + OWDhistory_(HISTORY_LEN){}; + +void RTCDataPath::insertRttSample(uint64_t rtt) { + // for the rtt we only keep track of the min one + if (rtt < min_rtt) min_rtt = rtt; +} + +void RTCDataPath::insertOwdSample(int64_t owd) { + // for owd we use both min and avg + if (owd < min_owd) min_owd = owd; + + if (avg_owd != DBL_MAX) + avg_owd = (avg_owd * (1 - ALPHA_RTC)) + (owd * ALPHA_RTC); + else { + avg_owd = owd; + } + + // owd is computed only for valid data packets so we count only + // this for decide if we recevie traffic or not + received_packets_ = true; +} + +void RTCDataPath::computeInterArrivalGap(uint32_t segmentNumber) { + // got packet in sequence, compute gap + if (lastRecvSeq_ == (segmentNumber - 1)) { + uint64_t now = std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()) + .count(); + uint64_t delta = now - lastRecvTime_; + lastRecvSeq_ = segmentNumber; + lastRecvTime_ = now; + if (avg_inter_arrival_ == DBL_MAX) + avg_inter_arrival_ = delta; + else + avg_inter_arrival_ = + (avg_inter_arrival_ * (1 - ALPHA_RTC)) + (delta * ALPHA_RTC); + return; + } + + // ooo packet, update the stasts if needed + if (lastRecvSeq_ <= segmentNumber) { + lastRecvSeq_ = segmentNumber; + lastRecvTime_ = std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()) + .count(); + } +} + +void RTCDataPath::receivedNack() { received_nacks_ = true; } + +double RTCDataPath::getInterArrivalGap() { + if (avg_inter_arrival_ == DBL_MAX) return 0; + return avg_inter_arrival_; +} + +bool RTCDataPath::isActive() { + if (received_nacks_ && rounds_without_packets_ < MAX_ROUNDS_WITHOUT_PKTS) + return true; + return false; +} + +void RTCDataPath::roundEnd() { + // reset min_rtt and add it to the history + if (min_rtt != UINT_MAX) { + prev_min_rtt = min_rtt; + } else { + // this may happen if we do not receive any packet + // from this path in the last round. in this case + // we use the measure from the previuos round + min_rtt = prev_min_rtt; + } + + if (min_rtt == 0) min_rtt = 1; + + RTThistory_.pushBack(min_rtt); + min_rtt = UINT_MAX; + + // do the same for min owd + if (min_owd != INT_MAX) { + prev_min_owd = min_owd; + } else { + min_owd = prev_min_owd; + } + + if (min_owd != INT_MAX) { + OWDhistory_.pushBack(min_owd); + min_owd = INT_MAX; + + // compute queuing delay + queuing_delay = avg_owd - getMinOwd(); + + } else { + queuing_delay = 0.0; + } + + if (!received_packets_) + rounds_without_packets_++; + else + rounds_without_packets_ = 0; + received_packets_ = false; +} + +double RTCDataPath::getQueuingDealy() { return queuing_delay; } + +uint64_t RTCDataPath::getMinRtt() { return RTThistory_.begin(); } + +int64_t RTCDataPath::getMinOwd() { return OWDhistory_.begin(); } + +} // end namespace protocol + +} // end namespace transport diff --git a/libtransport/src/protocols/rtc_data_path.h b/libtransport/src/protocols/rtc_data_path.h new file mode 100644 index 000000000..9076b355f --- /dev/null +++ b/libtransport/src/protocols/rtc_data_path.h @@ -0,0 +1,80 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +#include + +#define ALPHA_RTC 0.125 +#define HISTORY_LEN 20 // 4 sec + +namespace transport { + +namespace protocol { + +class RTCDataPath { + public: + RTCDataPath(); + + public: + void insertRttSample(uint64_t rtt); + void insertOwdSample(int64_t owd); + void computeInterArrivalGap(uint32_t segmentNumber); + void receivedNack(); + + uint64_t getMinRtt(); + double getQueuingDealy(); + double getInterArrivalGap(); + bool isActive(); + + void roundEnd(); + + private: + int64_t getMinOwd(); + + uint64_t min_rtt; + uint64_t prev_min_rtt; + + int64_t min_owd; + int64_t prev_min_owd; + + double avg_owd; + + double queuing_delay; + + uint32_t lastRecvSeq_; + uint64_t lastRecvTime_; + double avg_inter_arrival_; + + // flags to check if a path is active + // we considere a path active if it reaches a producer + //(not a cache) --aka we got at least one nack on this path-- + // and if we receives packets + bool received_nacks_; + bool received_packets_; + uint8_t rounds_without_packets_; // if we don't get any packet + // for MAX_ROUNDS_WITHOUT_PKTS + // we consider the path inactive + + utils::MinFilter RTThistory_; + utils::MinFilter OWDhistory_; +}; + +} // namespace protocol + +} // end namespace transport diff --git a/libtransport/src/protocols/test/CMakeLists.txt b/libtransport/src/protocols/test/CMakeLists.txt new file mode 100644 index 000000000..6f9fdb9aa --- /dev/null +++ b/libtransport/src/protocols/test/CMakeLists.txt @@ -0,0 +1,10 @@ +# Enable gcov output for the tests +add_definitions(--coverage) +set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage") + +set(TestsExpectedToPass + test_transport_producer) + +foreach(test ${TestsExpectedToPass}) + AddTest(${test}) +endforeach() \ No newline at end of file diff --git a/libtransport/src/protocols/test/test_transport_producer.cc b/libtransport/src/protocols/test/test_transport_producer.cc new file mode 100644 index 000000000..204f2cbe2 --- /dev/null +++ b/libtransport/src/protocols/test/test_transport_producer.cc @@ -0,0 +1,80 @@ +/* + * 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. + */ + +#include + +#include "../socket_producer.h" +#include "literals.h" + +#include +#include + +namespace transport { + +namespace protocol { + +namespace { +// The fixture for testing class Foo. +class ProducerTest : public ::testing::Test { + protected: + ProducerTest() : name_("b001::123|321"), producer_(io_service_) { + // You can do set-up work for each test here. + } + + virtual ~ProducerTest() { + // You can do clean-up work that doesn't throw exceptions here. + } + + // If the constructor and destructor are not enough for setting up + // and cleaning up each test, you can define the following methods: + + virtual void SetUp() { + // Code here will be called immediately after the constructor (right + // before each test). + } + + virtual void TearDown() { + // Code here will be called immediately after each test (right + // before the destructor). + } + + Name name_; + asio::io_service io_service_; + ProducerSocket producer_; +}; + +} // namespace + +// Tests that the Foo::Bar() method does Abc. +TEST_F(ProducerTest, ProduceContent) { + std::string content(250000, '?'); + + producer_.registerPrefix(Prefix("b001::/64")); + producer_.produce(name_, reinterpret_cast(content.data()), + content.size(), true); + producer_.setSocketOption(GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME, + 500000000_U32); + producer_.attach(); + producer_.serveForever(); +} + +} // namespace protocol + +} // namespace transport + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/libtransport/src/protocols/verification_manager.cc b/libtransport/src/protocols/verification_manager.cc new file mode 100644 index 000000000..8eedd6106 --- /dev/null +++ b/libtransport/src/protocols/verification_manager.cc @@ -0,0 +1,101 @@ +/* + * 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. + */ + +#include +#include + +#include +#include + +namespace transport { + +namespace protocol { + +interface::VerificationPolicy SignatureVerificationManager::onPacketToVerify( + const Packet& packet) { + using namespace interface; + + bool verify_signature = false, key_content = false; + VerificationPolicy ret = VerificationPolicy::DROP_PACKET; + + icn_socket_->getSocketOption(GeneralTransportOptions::VERIFY_SIGNATURE, + verify_signature); + icn_socket_->getSocketOption(GeneralTransportOptions::KEY_CONTENT, + key_content); + + if (!verify_signature) { + return VerificationPolicy::ACCEPT_PACKET; + } + + if (key_content) { + key_packets_.push(copyPacket(packet)); + return VerificationPolicy::ACCEPT_PACKET; + } else if (!key_packets_.empty()) { + std::queue().swap(key_packets_); + } + + ConsumerContentObjectVerificationFailedCallback* + verification_failed_callback = VOID_HANDLER; + icn_socket_->getSocketOption(ConsumerCallbacksOptions::VERIFICATION_FAILED, + &verification_failed_callback); + + if (!verification_failed_callback) { + throw errors::RuntimeException( + "No verification failed callback provided by application. " + "Aborting."); + } + + std::shared_ptr verifier; + icn_socket_->getSocketOption(GeneralTransportOptions::VERIFIER, verifier); + + if (TRANSPORT_EXPECT_FALSE(!verifier)) { + ret = (*verification_failed_callback)( + *icn_socket_->getInterface(), + dynamic_cast(packet), + make_error_code(protocol_error::no_verifier_provided)); + return ret; + } + + if (!verifier->verify(packet)) { + ret = (*verification_failed_callback)( + *icn_socket_->getInterface(), + dynamic_cast(packet), + make_error_code(protocol_error::signature_verification_failed)); + } else { + ret = VerificationPolicy::ACCEPT_PACKET; + } + + return ret; +} + +bool SignatureVerificationManager::onKeyToVerify() { + if (TRANSPORT_EXPECT_FALSE(key_packets_.empty())) { + throw errors::RuntimeException("No key to verify."); + } + + while (!key_packets_.empty()) { + ContentObjectPtr packet_to_verify = key_packets_.front(); + key_packets_.pop(); + if (onPacketToVerify(*packet_to_verify) != + VerificationPolicy::ACCEPT_PACKET) + return false; + } + + return true; +} + +} // end namespace protocol + +} // end namespace transport diff --git a/libtransport/src/protocols/verification_manager.h b/libtransport/src/protocols/verification_manager.h new file mode 100644 index 000000000..7d8a00a65 --- /dev/null +++ b/libtransport/src/protocols/verification_manager.h @@ -0,0 +1,71 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +#include + +#include + +#include + +namespace transport { + +namespace interface { +class ConsumerSocket; +} + +namespace protocol { + +using Packet = core::Packet; +using interface::VerificationPolicy; +using ContentObjectPtr = std::shared_ptr; + +class VerificationManager { + public: + virtual ~VerificationManager() = default; + virtual VerificationPolicy onPacketToVerify(const Packet& packet) = 0; + virtual bool onKeyToVerify() { return false; } +}; + +class SignatureVerificationManager : public VerificationManager { + public: + SignatureVerificationManager(implementation::ConsumerSocket* icn_socket) + : icn_socket_(icn_socket), key_packets_() {} + + interface::VerificationPolicy onPacketToVerify(const Packet& packet) override; + bool onKeyToVerify() override; + + private: + implementation::ConsumerSocket* icn_socket_; + std::queue key_packets_; + + ContentObjectPtr copyPacket(const Packet& packet) { + std::shared_ptr packet_copy = + packet.acquireMemBufReference(); + ContentObjectPtr content_object_copy = + std::make_shared(std::move(packet_copy)); + std::unique_ptr payload_copy = packet.getPayload(); + content_object_copy->appendPayload(std::move(payload_copy)); + return content_object_copy; + } +}; + +} // end namespace protocol + +} // end namespace transport diff --git a/libtransport/src/security/CMakeLists.txt b/libtransport/src/security/CMakeLists.txt new file mode 100644 index 000000000..0e7b5832b --- /dev/null +++ b/libtransport/src/security/CMakeLists.txt @@ -0,0 +1,22 @@ +# 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) + +list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/signer.cc + ${CMAKE_CURRENT_SOURCE_DIR}/verifier.cc + ${CMAKE_CURRENT_SOURCE_DIR}/identity.cc +) + +set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) diff --git a/libtransport/src/security/identity.cc b/libtransport/src/security/identity.cc new file mode 100644 index 000000000..55713245e --- /dev/null +++ b/libtransport/src/security/identity.cc @@ -0,0 +1,115 @@ +/* + * 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. + */ + +#include + +extern "C" { +#include +#include +} + +namespace utils { + +Identity::Identity(const std::string &keystore_name, + const std::string &keystore_password, CryptoSuite suite, + unsigned int key_length, unsigned int validity_days, + const std::string &subject_name) { + parcSecurity_Init(); + + bool success = parcPkcs12KeyStore_CreateFile( + keystore_name.c_str(), keystore_password.c_str(), subject_name.c_str(), + parcCryptoSuite_GetSigningAlgorithm(static_cast(suite)), + key_length, validity_days); + + parcAssertTrue( + success, + "parcPkcs12KeyStore_CreateFile('%s', '%s', '%s', %d, %d) failed.", + keystore_name.c_str(), keystore_password.c_str(), subject_name.c_str(), + static_cast(key_length), validity_days); + + PARCIdentityFile *identity_file = + parcIdentityFile_Create(keystore_name.c_str(), keystore_password.c_str()); + + identity_ = + parcIdentity_Create(identity_file, PARCIdentityFileAsPARCIdentity); + + PARCSigner *signer = parcIdentity_CreateSigner( + identity_, + parcCryptoSuite_GetCryptoHash(static_cast(suite))); + + signer_ = std::make_shared(signer, suite); + + parcSigner_Release(&signer); + parcIdentityFile_Release(&identity_file); +} + +Identity::Identity(const Identity &other) + : signer_(other.signer_), hash_algorithm_(other.hash_algorithm_) { + parcSecurity_Init(); + identity_ = parcIdentity_Acquire(other.identity_); +} + +Identity Identity::generateIdentity(const std::string &subject_name) { + std::string keystore_name = "keystore"; + std::string keystore_password = "password"; + std::size_t key_length = 1024; + unsigned int validity_days = 30; + CryptoSuite suite = CryptoSuite::RSA_SHA256; + + return utils::Identity(keystore_name, keystore_password, suite, + (unsigned int)key_length, validity_days, subject_name); +} + +Identity::Identity(std::string &file_name, std::string &password, + transport::core::HashAlgorithm hash_algorithm) + : hash_algorithm_(hash_algorithm) { + parcSecurity_Init(); + + PARCIdentityFile *identity_file = + parcIdentityFile_Create(file_name.c_str(), password.c_str()); + + identity_ = + parcIdentity_Create(identity_file, PARCIdentityFileAsPARCIdentity); + + PARCSigner *signer = parcIdentity_CreateSigner( + identity_, static_cast(hash_algorithm)); + + signer_ = std::make_shared( + signer, CryptoSuite(parcSigner_GetCryptoSuite(signer))); + + parcSigner_Release(&signer); + parcIdentityFile_Release(&identity_file); +} + +Identity::~Identity() { + parcIdentity_Release(&identity_); + parcSecurity_Fini(); +} + +std::string Identity::getFileName() { + return std::string(parcIdentity_GetFileName(identity_)); +} + +std::string Identity::getPassword() { + return std::string(parcIdentity_GetPassWord(identity_)); +} + +std::shared_ptr Identity::getSigner() { return signer_; } + +size_t Identity::getSignatureLength() const { + return signer_->getSignatureLength(); +} + +} // namespace utils diff --git a/libtransport/src/security/signer.cc b/libtransport/src/security/signer.cc new file mode 100644 index 000000000..314c3ea82 --- /dev/null +++ b/libtransport/src/security/signer.cc @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright 2017 Facebook, Inc. + * + * 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 +#include +#include +#include + +extern "C" { +#ifndef _WIN32 +TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat") +#endif +#include +#include +#include +#include +} + +#include + +#define ALLOW_UNALIGNED_READS 1 + +namespace utils { + +uint8_t Signer::zeros[200] = {0}; + +/*One signer_ per Private Key*/ +Signer::Signer(PARCKeyStore *keyStore, CryptoSuite suite) { + parcSecurity_Init(); + + switch (suite) { + case CryptoSuite::DSA_SHA256: + case CryptoSuite::RSA_SHA256: + case CryptoSuite::RSA_SHA512: + case CryptoSuite::ECDSA_256K1: { + this->signer_ = + parcSigner_Create(parcPublicKeySigner_Create( + keyStore, static_cast(suite)), + PARCPublicKeySignerAsSigner); + break; + } + case CryptoSuite::HMAC_SHA256: + case CryptoSuite::HMAC_SHA512: { + this->signer_ = + parcSigner_Create(parcSymmetricKeySigner_Create( + (PARCSymmetricKeyStore *)keyStore, + parcCryptoSuite_GetCryptoHash( + static_cast(suite))), + PARCSymmetricKeySignerAsSigner); + break; + } + default: { return; } + } + + suite_ = suite; + key_id_ = parcSigner_CreateKeyId(this->signer_); + signature_length_ = parcSigner_GetSignatureSize(this->signer_); +} + +Signer::Signer(const std::string &passphrase, CryptoSuite suite) { + parcSecurity_Init(); + + switch (suite) { + case CryptoSuite::HMAC_SHA256: + case CryptoSuite::HMAC_SHA512: { + composer_ = parcBufferComposer_Create(); + parcBufferComposer_PutString(composer_, passphrase.c_str()); + key_buffer_ = parcBufferComposer_ProduceBuffer(composer_); + symmetricKeyStore_ = parcSymmetricKeyStore_Create(key_buffer_); + this->signer_ = parcSigner_Create( + parcSymmetricKeySigner_Create( + symmetricKeyStore_, parcCryptoSuite_GetCryptoHash( + static_cast(suite))), + PARCSymmetricKeySignerAsSigner); + break; + } + default: { return; } + } + + suite_ = suite; + key_id_ = parcSigner_CreateKeyId(this->signer_); + signature_length_ = parcSigner_GetSignatureSize(this->signer_); +} + +Signer::Signer(const PARCSigner *signer, CryptoSuite suite) + : signer_(parcSigner_Acquire(signer)), + key_id_(parcSigner_CreateKeyId(this->signer_)), + suite_(suite), + signature_length_(parcSigner_GetSignatureSize(this->signer_)) { + parcSecurity_Init(); +} + +Signer::Signer(const PARCSigner *signer) + : Signer(signer, CryptoSuite::UNKNOWN) {} + +Signer::~Signer() { + if (signature_) parcSignature_Release(&signature_); + if (symmetricKeyStore_) parcSymmetricKeyStore_Release(&symmetricKeyStore_); + if (key_buffer_) parcBuffer_Release(&key_buffer_); + if (composer_) parcBufferComposer_Release(&composer_); + if (signer_) parcSigner_Release(&signer_); + if (key_id_) parcKeyId_Release(&key_id_); + parcSecurity_Fini(); +} + +void Signer::sign(Packet &packet) { + // header chain points to the IP + TCP hicn header + AH Header + MemBuf *header_chain = packet.header_head_; + MemBuf *payload_chain = packet.payload_head_; + uint8_t *hicn_packet = (uint8_t *)header_chain->writableData(); + Packet::Format format = packet.getFormat(); + + if (!(format & HFO_AH)) { + throw errors::MalformedAHPacketException(); + } + + packet.setSignatureSize(signature_length_); + + // Copy IP+TCP/ICMP header before zeroing them + hicn_header_t header_copy; + hicn_packet_copy_header(format, (const hicn_header_t *)packet.packet_start_, + &header_copy, false); + + std::size_t header_len = Packet::getHeaderSizeFromFormat(format); + + packet.resetForHash(); + + /* Fill the hicn_ah header */ + using namespace std::chrono; + auto now = duration_cast(system_clock::now().time_since_epoch()) + .count(); + packet.setSignatureTimestamp(now); + packet.setValidationAlgorithm(suite_); + + KeyId key_id; + key_id.first = (uint8_t *)parcBuffer_Overlay( + (PARCBuffer *)parcKeyId_GetKeyId(this->key_id_), 0); + packet.setKeyId(key_id); + + // Calculate hash + CryptoHasher hasher(parcSigner_GetCryptoHasher(signer_)); + hasher.init(); + hasher.updateBytes(hicn_packet, header_len + signature_length_); + + for (MemBuf *current = payload_chain; current != header_chain; + current = current->next()) { + hasher.updateBytes(current->data(), current->length()); + } + + CryptoHash hash = hasher.finalize(); + + signature_ = parcSigner_SignDigestNoAlloc(this->signer_, hash.hash_, + packet.getSignature(), + (uint32_t)signature_length_); + PARCBuffer *buffer = parcSignature_GetSignature(signature_); + + size_t bytes_len = parcBuffer_Remaining(buffer); + + if (bytes_len > signature_length_) { + throw errors::MalformedAHPacketException(); + } + + hicn_packet_copy_header(format, &header_copy, + (hicn_header_t *)packet.packet_start_, false); +} + +size_t Signer::getSignatureLength() { return signature_length_; } + +PARCKeyStore *Signer::getKeyStore() { + return parcSigner_GetKeyStore(this->signer_); +} + +} // namespace utils diff --git a/libtransport/src/security/verifier.cc b/libtransport/src/security/verifier.cc new file mode 100644 index 000000000..19796f718 --- /dev/null +++ b/libtransport/src/security/verifier.cc @@ -0,0 +1,241 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include +#include + +extern "C" { +#ifndef _WIN32 +TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat") +#endif +#include +} + +#include + +namespace utils { + +TRANSPORT_ALWAYS_INLINE bool file_exists(const std::string &name) { + struct stat buffer; + return (stat(name.c_str(), &buffer) == 0); +} + +uint8_t Verifier::zeros[200] = {0}; + +Verifier::Verifier() { + parcSecurity_Init(); + PARCInMemoryVerifier *in_memory_verifier = parcInMemoryVerifier_Create(); + this->verifier_ = + parcVerifier_Create(in_memory_verifier, PARCInMemoryVerifierAsVerifier); +} + +Verifier::~Verifier() { + if (key_) parcKey_Release(&key_); + if (keyId_) parcKeyId_Release(&keyId_); + if (signer_) parcSigner_Release(&signer_); + if (symmetricKeyStore_) parcSymmetricKeyStore_Release(&symmetricKeyStore_); + if (key_buffer_) parcBuffer_Release(&key_buffer_); + if (composer_) parcBufferComposer_Release(&composer_); + if (certificate_) parcCertificate_Release(&certificate_); + if (factory_) parcCertificateFactory_Release(&factory_); + if (verifier_) parcVerifier_Release(&verifier_); + parcSecurity_Fini(); +} + +/* + * TODO: Unsupported in libparc + */ +bool Verifier::hasKey(PARCKeyId *keyId) { return false; } + +/* + * TODO: signal errors without trap. + */ +bool Verifier::addKey(PARCKey *key) { + parcVerifier_AddKey(this->verifier_, key); + return true; +} + +PARCKeyId *Verifier::addKeyFromPassphrase(const std::string &passphrase, + CryptoSuite suite) { + composer_ = parcBufferComposer_Create(); + parcBufferComposer_PutString(composer_, passphrase.c_str()); + key_buffer_ = parcBufferComposer_ProduceBuffer(composer_); + + symmetricKeyStore_ = parcSymmetricKeyStore_Create(key_buffer_); + signer_ = parcSigner_Create( + parcSymmetricKeySigner_Create( + symmetricKeyStore_, + parcCryptoSuite_GetCryptoHash(static_cast(suite))), + PARCSymmetricKeySignerAsSigner); + keyId_ = parcSigner_CreateKeyId(signer_); + key_ = parcKey_CreateFromSymmetricKey( + keyId_, parcSigner_GetSigningAlgorithm(signer_), key_buffer_); + + addKey(key_); + return keyId_; +} + +PARCKeyId *Verifier::addKeyFromCertificate(const std::string &file_name) { + factory_ = parcCertificateFactory_Create(PARCCertificateType_X509, + PARCContainerEncoding_PEM); + parcAssertNotNull(factory_, "Expected non-NULL factory"); + + if (!file_exists(file_name)) { + TRANSPORT_LOGW("Warning! The certificate %s file does not exist", + file_name.c_str()); + return nullptr; + } + + certificate_ = parcCertificateFactory_CreateCertificateFromFile( + factory_, (char *)file_name.c_str(), NULL); + PARCBuffer *derEncodedVersion = + parcCertificate_GetDEREncodedPublicKey(certificate_); + PARCCryptoHash *keyDigest = parcCertificate_GetPublicKeyDigest(certificate_); + keyId_ = parcKeyId_Create(parcCryptoHash_GetDigest(keyDigest)); + key_ = parcKey_CreateFromDerEncodedPublicKey(keyId_, PARCSigningAlgorithm_RSA, + derEncodedVersion); + + addKey(key_); + return keyId_; +} + +int Verifier::verify(const Packet &packet) { + // to initialize packet.payload_head_ + const_cast(&packet)->separateHeaderPayload(); + bool valid = false; + + // initialize packet.payload_head_ + const_cast(&packet)->separateHeaderPayload(); + // header chain points to the IP + TCP hicn header + // utils::MemBuf *header_chain = packet.header_head_; + // utils::MemBuf *payload_chain = packet.payload_head_; + // uint8_t *hicn_packet = header_chain->writableData(); + Packet::Format format = packet.getFormat(); + + if (!(packet.format_ & HFO_AH)) { + throw errors::MalformedAHPacketException(); + } + + // Copy IP+TCP/ICMP header before zeroing them + hicn_header_t header_copy; + hicn_packet_copy_header(format, (const hicn_header_t *)packet.packet_start_, + &header_copy, false); + + PARCCryptoSuite suite = + static_cast(packet.getValidationAlgorithm()); + PARCCryptoHashType hashtype = parcCryptoSuite_GetCryptoHash(suite); + KeyId _key_id = packet.getKeyId(); + PARCBuffer *buffer = + parcBuffer_Wrap(_key_id.first, _key_id.second, 0, _key_id.second); + PARCKeyId *key_id = parcKeyId_Create(buffer); + parcBuffer_Release(&buffer); + + int ah_payload_len = (int)packet.getSignatureSize(); + uint8_t *_signature = packet.getSignature(); + uint8_t *signature = new uint8_t[ah_payload_len]; + // TODO Remove signature copy at this point, by not setting to zero + // the validation payload. + std::memcpy(signature, _signature, ah_payload_len); + + std::shared_ptr hasher; + switch (CryptoSuite(suite)) { + case CryptoSuite::DSA_SHA256: + case CryptoSuite::RSA_SHA256: + case CryptoSuite::RSA_SHA512: + case CryptoSuite::ECDSA_256K1: { + hasher = std::make_shared( + parcVerifier_GetCryptoHasher(verifier_, key_id, hashtype)); + break; + } + case CryptoSuite::HMAC_SHA256: + case CryptoSuite::HMAC_SHA512: { + if (!signer_) return false; + hasher = + std::make_shared(parcSigner_GetCryptoHasher(signer_)); + break; + } + default: { return false; } + } + CryptoHash hash_computed_locally = getPacketHash(packet, hasher); + + PARCBuffer *bits = + parcBuffer_Wrap(signature, ah_payload_len, 0, ah_payload_len); + parcBuffer_Rewind(bits); + + /* IF the signature algo is ECDSA, the signature might be shorter than the + * signature field */ + PARCSigningAlgorithm algo = parcCryptoSuite_GetSigningAlgorithm(suite); + while (algo == PARCSigningAlgorithm_ECDSA && parcBuffer_HasRemaining(bits) && + parcBuffer_GetUint8(bits) == 0) + ; + + if (algo == PARCSigningAlgorithm_ECDSA) { + parcBuffer_SetPosition(bits, parcBuffer_Position(bits) - 1); + } + + if (!parcBuffer_HasRemaining(bits)) { + parcKeyId_Release(&key_id); + parcBuffer_Release(&bits); + return valid; + } + + PARCSignature *signatureToVerify = parcSignature_Create( + parcCryptoSuite_GetSigningAlgorithm(suite), hashtype, bits); + + if (algo == PARCSigningAlgorithm_RSA) { + parcBuffer_SetPosition(bits, 0); + } + + valid = parcVerifier_VerifyDigestSignature( + verifier_, key_id, hash_computed_locally.hash_, suite, signatureToVerify); + + /* Restore the resetted fields */ + hicn_packet_copy_header(format, &header_copy, + (hicn_header_t *)packet.packet_start_, false); + + delete[] signature; + parcKeyId_Release(&key_id); + parcBuffer_Release(&bits); + parcSignature_Release(&signatureToVerify); + + return valid; +} + +CryptoHash Verifier::getPacketHash(const Packet &packet, + std::shared_ptr hasher) { + MemBuf *header_chain = packet.header_head_; + MemBuf *payload_chain = packet.payload_head_; + Packet::Format format = packet.getFormat(); + int ah_payload_len = (int)packet.getSignatureSize(); + uint8_t *hicn_packet = header_chain->writableData(); + std::size_t header_len = Packet::getHeaderSizeFromFormat(format); + + // Reset fields that should not appear in the signature + const_cast(packet).resetForHash(); + hasher->init().updateBytes(hicn_packet, header_len + ah_payload_len); + + for (MemBuf *current = payload_chain; current != header_chain; + current = current->next()) { + hasher->updateBytes(current->data(), current->length()); + } + + return hasher->finalize(); +} + +} // namespace utils diff --git a/libtransport/src/utils/CMakeLists.txt b/libtransport/src/utils/CMakeLists.txt new file mode 100644 index 000000000..88d451b6b --- /dev/null +++ b/libtransport/src/utils/CMakeLists.txt @@ -0,0 +1,53 @@ +# 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) + +list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/string_tokenizer.cc + ${CMAKE_CURRENT_SOURCE_DIR}/uri.cc + ${CMAKE_CURRENT_SOURCE_DIR}/log.cc + ${CMAKE_CURRENT_SOURCE_DIR}/membuf.cc + ${CMAKE_CURRENT_SOURCE_DIR}/content_store.cc +) + + +list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/event_reactor.h + ${CMAKE_CURRENT_SOURCE_DIR}/min_filter.h + ${CMAKE_CURRENT_SOURCE_DIR}/stream_buffer.h + ${CMAKE_CURRENT_SOURCE_DIR}/suffix_strategy.h + ${CMAKE_CURRENT_SOURCE_DIR}/event_thread.h + ${CMAKE_CURRENT_SOURCE_DIR}/content_store.h + ${CMAKE_CURRENT_SOURCE_DIR}/deadline_timer.h +) + +if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") + list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/epoll_event_reactor.h + ${CMAKE_CURRENT_SOURCE_DIR}/fd_deadline_timer.h + ) + + list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/epoll_event_reactor.cc + ) +endif() + +if(NOT WIN32) + list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/daemonizator.cc + ) +endif() + +set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) diff --git a/libtransport/src/utils/content_store.cc b/libtransport/src/utils/content_store.cc new file mode 100644 index 000000000..cb3db6d94 --- /dev/null +++ b/libtransport/src/utils/content_store.cc @@ -0,0 +1,122 @@ +/* + * 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. + */ + +#include +#include +#include +#include + +#include + +namespace utils { + +ContentStore::ContentStore(std::size_t max_packets) + : max_content_store_size_(max_packets) {} + +ContentStore::~ContentStore() {} + +void ContentStore::insert( + const std::shared_ptr &content_object) { + if (max_content_store_size_ == 0) { + return; + } + + utils::SpinLock::Acquire locked(cs_mutex_); + + if (TRANSPORT_EXPECT_FALSE(content_store_hash_table_.size() != + fifo_list_.size())) { + TRANSPORT_LOGW("Inconsistent size!!!!"); + TRANSPORT_LOGW("Hash Table: %zu |||| FIFO List: %zu", + content_store_hash_table_.size(), fifo_list_.size()); + } + + if (content_store_hash_table_.size() >= max_content_store_size_) { + content_store_hash_table_.erase(fifo_list_.back()); + fifo_list_.pop_back(); + } + + // Insert new item + auto it = content_store_hash_table_.find(content_object->getName()); + if (it != content_store_hash_table_.end()) { + fifo_list_.erase(it->second.second); + content_store_hash_table_.erase(content_object->getName()); + } + + fifo_list_.push_front(std::cref(content_object->getName())); + auto pos = fifo_list_.begin(); + content_store_hash_table_[content_object->getName()] = ContentStoreEntry( + ObjectTimeEntry(content_object, std::chrono::steady_clock::now()), pos); +} + +const std::shared_ptr ContentStore::find( + const Interest &interest) { + utils::SpinLock::Acquire locked(cs_mutex_); + + std::shared_ptr ret = empty_reference_; + auto it = content_store_hash_table_.find(interest.getName()); + if (it != content_store_hash_table_.end()) { + auto content_lifetime = it->second.first.first->getLifetime(); + auto time_passed_since_creation = + std::chrono::duration_cast( + std::chrono::steady_clock::now() - it->second.first.second) + .count(); + + if (time_passed_since_creation > content_lifetime) { + fifo_list_.erase(it->second.second); + content_store_hash_table_.erase(it); + } else { + ret = it->second.first.first; + } + } + + return ret; +} + +void ContentStore::erase(const Name &exact_name) { + utils::SpinLock::Acquire locked(cs_mutex_); + auto it = content_store_hash_table_.find(exact_name); + fifo_list_.erase(it->second.second); + content_store_hash_table_.erase(exact_name); +} + +void ContentStore::setLimit(size_t max_packets) { + utils::SpinLock::Acquire locked(cs_mutex_); + max_content_store_size_ = max_packets; +} + +std::size_t ContentStore::getLimit() const { + utils::SpinLock::Acquire locked(cs_mutex_); + return max_content_store_size_; +} + +std::size_t ContentStore::size() const { + utils::SpinLock::Acquire locked(cs_mutex_); + return content_store_hash_table_.size(); +} + +void ContentStore::printContent() { + for (auto &item : content_store_hash_table_) { + if (item.second.first.first->getPayloadType() == + transport::core::PayloadType::MANIFEST) { + TRANSPORT_LOGI("Manifest: %s", + item.second.first.first->getName().toString().c_str()); + } else { + TRANSPORT_LOGI("Data Packet: %s", + item.second.first.first->getName().toString().c_str()); + } + } +} + +} // end namespace utils \ No newline at end of file diff --git a/libtransport/src/utils/content_store.h b/libtransport/src/utils/content_store.h new file mode 100644 index 000000000..03ce76f42 --- /dev/null +++ b/libtransport/src/utils/content_store.h @@ -0,0 +1,76 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include + +namespace transport { + +namespace core { +class Name; +class ContentObject; +class Interest; +} // namespace core + +} // namespace transport + +namespace utils { + +using Name = transport::core::Name; +using ContentObject = transport::core::ContentObject; +using Interest = transport::core::Interest; + +typedef std::pair, + std::chrono::steady_clock::time_point> + ObjectTimeEntry; +typedef std::pair>::iterator> + ContentStoreEntry; +typedef std::list> FIFOList; +typedef std::unordered_map ContentStoreHashTable; + +class ContentStore { + public: + explicit ContentStore(std::size_t max_packets = (1 << 16)); + + ~ContentStore(); + + void insert(const std::shared_ptr &content_object); + + const std::shared_ptr find(const Interest &interest); + + void erase(const Name &exact_name); + + void setLimit(size_t max_packets); + + size_t getLimit() const; + + size_t size() const; + + void printContent(); + + private: + ContentStoreHashTable content_store_hash_table_; + FIFOList fifo_list_; + std::shared_ptr empty_reference_; + // Must be atomic + std::atomic_size_t max_content_store_size_; + mutable utils::SpinLock cs_mutex_; +}; + +} // end namespace utils \ No newline at end of file diff --git a/libtransport/src/utils/daemonizator.cc b/libtransport/src/utils/daemonizator.cc new file mode 100644 index 000000000..c51a68d14 --- /dev/null +++ b/libtransport/src/utils/daemonizator.cc @@ -0,0 +1,76 @@ +/* + * 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. + */ + +#ifndef _WIN32 +#include +#include +#include + +#include +#include + +namespace utils { + +void Daemonizator::daemonize(bool close_fds) { + pid_t process_id = 0; + pid_t sid = 0; + + // Create child process + process_id = fork(); + + // Indication of fork() failure + if (process_id < 0) { + throw errors::RuntimeException("Fork failed."); + } + + // PARENT PROCESS. Need to kill it. + if (process_id > 0) { + TRANSPORT_LOGE("Process id of child process %d", process_id); + // return success in exit status + exit(EXIT_SUCCESS); + } + + // unmask the file mode + umask(0); + + // set new session + sid = setsid(); + if (sid < 0) { + // Return failure + exit(EXIT_FAILURE); + } + + // Change the current working directory to root. + int ret = chdir("/"); + + if (ret < 0) { + throw errors::RuntimeException("Error changing working directory to root"); + } + + // Close stdin. Redirect stdout and stderr to file if possible + + if (close_fds) { + close(STDOUT_FILENO); + close(STDERR_FILENO); + } + + close(STDIN_FILENO); + + // Really start application +} + +} // namespace utils + +#endif diff --git a/libtransport/src/utils/deadline_timer.h b/libtransport/src/utils/deadline_timer.h new file mode 100644 index 000000000..5187754f0 --- /dev/null +++ b/libtransport/src/utils/deadline_timer.h @@ -0,0 +1,114 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include +#include +#include +#include + +namespace std { +namespace chrono { +namespace detail { + +template +struct posix_duration_cast; + +// chrono -> timespec caster +template +struct posix_duration_cast, + struct timespec> { + static struct timespec cast(std::chrono::duration const &d) { + struct timespec tv; + + std::chrono::seconds const sec = + std::chrono::duration_cast(d); + + tv.tv_sec = sec.count(); + tv.tv_nsec = + std::chrono::duration_cast(d - sec).count(); + + return tv; + } +}; + +// timespec -> chrono caster +template +struct posix_duration_cast> { + static std::chrono::duration cast(struct timespec const &tv) { + return std::chrono::duration_cast>( + std::chrono::seconds(tv.tv_sec) + std::chrono::nanoseconds(tv.tv_nsec)); + } +}; + +} // namespace detail + +// chrono -> timespec +template +auto duration_cast(std::chrono::duration const &d) -> + typename std::enable_if::value, + struct timespec>::type { + return detail::posix_duration_cast, + timespec>::cast(d); +} + +// timespec -> chrono +template +Duration duration_cast(struct timespec const &tv) { + return detail::posix_duration_cast::cast(tv); +} + +} // namespace chrono +} // namespace std + +namespace utils { + +template +class DeadlineTimer { + public: + virtual ~DeadlineTimer() = default; + + template + void asyncWait(WaitHandler &&callback) { + static_cast(this)->asyncWaitImpl( + std::forward(callback)); + } + + void wait() { static_cast(this)->waitImpl(); } + + template + void expiresFromNow(std::chrono::duration &&duration) { + static_cast(this)->expiresFromNowImpl( + std::forward>(duration)); + } + + template , + std::chrono::steady_clock::time_point>::value, + TimePoint>::type> + void expiresAt(TimePoint &&time_point) { + static_cast(this)->expiresAtImpl( + std::forward(time_point)); + } + + void cancel() { static_cast(this)->cancelImpl(); } +}; + +} // namespace utils diff --git a/libtransport/src/utils/epoll_event_reactor.cc b/libtransport/src/utils/epoll_event_reactor.cc new file mode 100644 index 000000000..0e6590d0e --- /dev/null +++ b/libtransport/src/utils/epoll_event_reactor.cc @@ -0,0 +1,187 @@ +/* + * 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. + */ + +#include + +#include +#include + +#include +#include +#include + +namespace utils { + +EpollEventReactor::EpollEventReactor() + : epoll_fd_(epoll_create(20000)), run_event_loop_(true) {} + +EpollEventReactor::~EpollEventReactor() { close(epoll_fd_); } + +int EpollEventReactor::addFileDescriptor(int fd, uint32_t events) { + if (TRANSPORT_EXPECT_FALSE(fd < 0)) { + TRANSPORT_LOGE("invalid fd %d", fd); + return -1; + } + + struct epoll_event evt; + std::memset(&evt, 0, sizeof(evt)); + evt.events = events; + evt.data.fd = fd; + + if (TRANSPORT_EXPECT_FALSE(epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &evt) < + 0)) { + TRANSPORT_LOGE("epoll_ctl: %s fd %d", strerror(errno), fd); + return -1; + } + + return 0; +} + +int EpollEventReactor::modFileDescriptor(int fd, uint32_t events) { + if (TRANSPORT_EXPECT_FALSE(fd < 0)) { + TRANSPORT_LOGE("invalid fd %d", fd); + return -1; + } + + struct epoll_event evt; + memset(&evt, 0, sizeof(evt)); + evt.events = events; + evt.data.fd = fd; + + if (TRANSPORT_EXPECT_FALSE(epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, fd, &evt) < + 0)) { + TRANSPORT_LOGE("epoll_ctl: %s fd %d", strerror(errno), fd); + return -1; + } + + return 0; +} + +std::size_t EpollEventReactor::mapSize() { return event_callback_map_.size(); } + +int EpollEventReactor::delFileDescriptor(int fd) { + if (TRANSPORT_EXPECT_FALSE(fd < 0)) { + TRANSPORT_LOGE("invalid fd %d", fd); + return -1; + } + + struct epoll_event evt; + memset(&evt, 0, sizeof(evt)); + + if (TRANSPORT_EXPECT_FALSE(epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, fd, &evt) < + 0)) { + TRANSPORT_LOGE("epoll_ctl: %s fd %d", strerror(errno), fd); + return -1; + } + + utils::SpinLock::Acquire locked(event_callback_map_lock_); + event_callback_map_.erase(fd); + + return 0; +} + +void EpollEventReactor::runEventLoop(int timeout) { + Event evt[128]; + int en = 0; + EventCallbackMap::iterator it; + EventCallback callback; + + // evt.events = EPOLLIN | EPOLLOUT; + sigset_t sigset; + sigemptyset(&sigset); + + while (run_event_loop_) { + memset(&evt, 0, sizeof(evt)); + + en = epoll_pwait(epoll_fd_, evt, 128, timeout, &sigset); + + if (TRANSPORT_EXPECT_FALSE(en < 0)) { + TRANSPORT_LOGE("epoll_pwait: %s", strerror(errno)); + return; + } + + for (int i = 0; i < en; i++) { + if (evt[i].data.fd > 0) { + { + utils::SpinLock::Acquire locked(event_callback_map_lock_); + it = event_callback_map_.find(evt[i].data.fd); + } + + if (TRANSPORT_EXPECT_FALSE(it == event_callback_map_.end())) { + TRANSPORT_LOGE("unexpected event. fd %d", evt[i].data.fd); + } else { + { + utils::SpinLock::Acquire locked(event_callback_map_lock_); + callback = event_callback_map_[evt[i].data.fd]; + } + + callback(evt[i]); + + // In the callback the epoll event reactor could have been stopped, + // then we need to check whether the event loop is still running. + if (TRANSPORT_EXPECT_FALSE(!run_event_loop_)) { + return; + } + } + } else { + TRANSPORT_LOGE("unexpected event. fd %d", evt[i].data.fd); + } + } + } +} + +void EpollEventReactor::runOneEvent() { + Event evt; + int en = 0; + EventCallbackMap::iterator it; + EventCallback callback; + + // evt.events = EPOLLIN | EPOLLOUT; + sigset_t sigset; + sigemptyset(&sigset); + + memset(&evt, 0, sizeof(evt)); + + en = epoll_pwait(epoll_fd_, &evt, 1, -1, &sigset); + + if (TRANSPORT_EXPECT_FALSE(en < 0)) { + TRANSPORT_LOGE("epoll_pwait: %s", strerror(errno)); + return; + } + + if (TRANSPORT_EXPECT_TRUE(evt.data.fd > 0)) { + { + utils::SpinLock::Acquire locked(event_callback_map_lock_); + it = event_callback_map_.find(evt.data.fd); + } + + if (TRANSPORT_EXPECT_FALSE(it == event_callback_map_.end())) { + TRANSPORT_LOGE("unexpected event. fd %d", evt.data.fd); + } else { + { + utils::SpinLock::Acquire locked(event_callback_map_lock_); + callback = event_callback_map_[evt.data.fd]; + } + + callback(evt); + } + } else { + TRANSPORT_LOGE("unexpected event. fd %d", evt.data.fd); + } +} + +void EpollEventReactor::stop() { run_event_loop_ = false; } + +} // namespace utils \ No newline at end of file diff --git a/libtransport/src/utils/epoll_event_reactor.h b/libtransport/src/utils/epoll_event_reactor.h new file mode 100644 index 000000000..4cb87ebd4 --- /dev/null +++ b/libtransport/src/utils/epoll_event_reactor.h @@ -0,0 +1,80 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include + +#define FD_NUMBER 20000 + +namespace utils { + +typedef struct epoll_event Event; +typedef std::function EventCallback; +typedef std::unordered_map EventCallbackMap; + +class EpollEventReactor : public EventReactor { + public: + explicit EpollEventReactor(); + + ~EpollEventReactor(); + + template + int addFileDescriptor(int fd, uint32_t events, EventHandler &&callback) { + auto it = event_callback_map_.find(fd); + int ret = 0; + + if (it == event_callback_map_.end()) { + { + utils::SpinLock::Acquire locked(event_callback_map_lock_); + event_callback_map_[fd] = std::forward(callback); + } + + ret = addFileDescriptor(fd, events); + } + + return ret; + } + + int delFileDescriptor(int fd); + + int modFileDescriptor(int fd, uint32_t events); + + void runEventLoop(int timeout = -1) override; + + void runOneEvent() override; + + void stop() override; + + std::size_t mapSize(); + + private: + int addFileDescriptor(int fd, uint32_t events); + + int epoll_fd_; + std::atomic_bool run_event_loop_; + EventCallbackMap event_callback_map_; + utils::SpinLock event_callback_map_lock_; +}; + +} // namespace utils diff --git a/libtransport/src/utils/event_reactor.h b/libtransport/src/utils/event_reactor.h new file mode 100644 index 000000000..4f8b58296 --- /dev/null +++ b/libtransport/src/utils/event_reactor.h @@ -0,0 +1,37 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include + +namespace utils { + +typedef std::function UserCallback; + +class EventReactor { + public: + virtual ~EventReactor() = default; + + virtual void runEventLoop(int timeout = -1) = 0; + + virtual void runOneEvent() = 0; + + virtual void stop() = 0; +}; + +} // namespace utils diff --git a/libtransport/src/utils/event_thread.h b/libtransport/src/utils/event_thread.h new file mode 100644 index 000000000..e50ae9648 --- /dev/null +++ b/libtransport/src/utils/event_thread.h @@ -0,0 +1,99 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +#include + +namespace utils { + +class EventThread { + private: + // No copies + EventThread(const EventThread&) = delete; // non construction-copyable + EventThread& operator=(const EventThread&) = delete; // non copyable + + public: + explicit EventThread(asio::io_service& io_service) + : internal_io_service_(nullptr), + io_service_(io_service), + work_(io_service_), + thread_(nullptr) { + run(); + } + + explicit EventThread() + : internal_io_service_(std::make_unique()), + io_service_(*internal_io_service_), + work_(io_service_), + thread_(nullptr) { + run(); + } + + ~EventThread() { stop(); } + + void run() { + if (stopped()) { + io_service_.reset(); + } + + thread_ = std::make_unique([this]() { io_service_.run(); }); + } + + std::thread::id getThreadId() const { + if (thread_) { + return thread_->get_id(); + } else { + throw errors::RuntimeException("Event thread is not running."); + } + } + + template + void add(Func&& f) { + // If the function f + // TODO USe post in mac os, asio->post in xenial + io_service_.post(std::forward(f)); + } + + template + void tryRunHandlerNow(Func&& f) { + io_service_.dispatch(std::forward(f)); + } + + void stop() { + io_service_.stop(); + + if (thread_ && thread_->joinable()) { + thread_->join(); + } + + thread_.reset(); + } + + bool stopped() { return io_service_.stopped(); } + + asio::io_service& getIoService() { return io_service_; } + + private: + std::unique_ptr internal_io_service_; + asio::io_service& io_service_; + asio::io_service::work work_; + std::unique_ptr thread_; +}; + +} // namespace utils \ No newline at end of file diff --git a/libtransport/src/utils/fd_deadline_timer.h b/libtransport/src/utils/fd_deadline_timer.h new file mode 100644 index 000000000..8bc3bbca3 --- /dev/null +++ b/libtransport/src/utils/fd_deadline_timer.h @@ -0,0 +1,129 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +namespace utils { + +class FdDeadlineTimer : public DeadlineTimer { + public: + explicit FdDeadlineTimer(EpollEventReactor &reactor) + : reactor_(reactor), + timer_fd_(timerfd_create(CLOCK_MONOTONIC, 0)), + flags_(0) { + if (timer_fd_ == -1) { + throw errors::RuntimeException("Impossible to create the timer!"); + } + } + + ~FdDeadlineTimer() { close(timer_fd_); } + + template + void asyncWaitImpl(WaitHandler &&callback) { + // ASIO_WAIT_HANDLER_CHECK(WaitHandler, callback) type_check; + + if (timerfd_settime(timer_fd_, flags_, &new_value_, NULL) == -1) { + throw errors::RuntimeException("Impossible to set the timer!"); + } + + uint32_t events = EPOLLIN; + + reactor_.addFileDescriptor( + timer_fd_, events, + [callback = std::forward(callback)]( + const Event &event) -> int { + uint64_t s = 0; + std::error_code ec; + + if (read(event.data.fd, &s, sizeof(s)) == -1) { + TRANSPORT_LOGE("Read error!!"); + } + + if (!(event.events & EPOLLIN)) { + ec = std::make_error_code(std::errc::operation_canceled); + } + + callback(ec); + + return 0; + }); + } + + void waitImpl() { + if (timerfd_settime(timer_fd_, flags_, &new_value_, NULL) == -1) { + throw errors::RuntimeException("Impossible to set the timer!"); + } + + uint64_t ret; + + if (read(timer_fd_, &ret, sizeof(ret)) == -1) { + throw errors::RuntimeException( + "Error while waiting for the timer expiration."); + } + } + + template + void expiresFromNowImpl(std::chrono::duration &&duration) { + std::memset(&new_value_, 0, sizeof(new_value_)); + new_value_.it_value = std::chrono::duration_cast( + std::forward>(duration)); + } + + template , + std::chrono::steady_clock::time_point>::value, + TimePoint>> + void expiresAtImpl(TimePoint &&time_point) { + std::memset(&new_value_, 0, sizeof(new_value_)); + + new_value_.it_value = std::chrono::duration_cast( + time_point.time_since_epoch()); + flags_ |= TFD_TIMER_ABSTIME; + } + + void cancelImpl() { + std::memset(&new_value_, 0, sizeof(new_value_)); + + if (timerfd_settime(timer_fd_, 0, &new_value_, NULL) == -1) { + throw errors::RuntimeException("Impossible to cancel the timer!"); + } + + // reactor_.delFileDescriptor(timer_fd_); + } + + EventReactor &getEventReactor() { return reactor_; } + + private: + EpollEventReactor &reactor_; + int timer_fd_; + EventCallback callback_; + struct itimerspec new_value_; + int flags_; +}; + +} // namespace utils diff --git a/libtransport/src/utils/log.cc b/libtransport/src/utils/log.cc new file mode 100644 index 000000000..27dd3f541 --- /dev/null +++ b/libtransport/src/utils/log.cc @@ -0,0 +1,1403 @@ +/* + * 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. + */ + +/* + * The MIT License (MIT) + * + * Copyright (c) 2017 wonder-mice + * + * 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. + */ + +/* When defined, Android log (android/log.h) will be used by default instead of + * stderr (ignored on non-Android platforms). Date, time, pid and tid (context) + * will be provided by Android log. Android log features will be used to output + * log level and tag. + */ + +#if defined(__ANDROID__) +#define TRANSPORT_LOG_USE_ANDROID_LOG 1 +#define ANDROID_TAG "HicnTransport" +#else +#define TRANSPORT_LOG_USE_ANDROID_LOG 0 +#endif + +/* When defined, NSLog (uses Apple System Log) will be used instead of stderr + * (ignored on non-Apple platforms). Date, time, pid and tid (context) will be + * provided by NSLog. Curiously, doesn't use NSLog() directly, but piggybacks on + * non-public CFLog() function. Both use Apple System Log internally, but it's + * easier to call CFLog() from C than NSLog(). Current implementation doesn't + * support "%@" format specifier. + */ +#ifdef TRANSPORT_LOG_USE_NSLOG +#undef TRANSPORT_LOG_USE_NSLOG +#if defined(__APPLE__) && defined(__MACH__) +#define TRANSPORT_LOG_USE_NSLOG 1 +#else +#define TRANSPORT_LOG_USE_NSLOG 0 +#endif +#else +#define TRANSPORT_LOG_USE_NSLOG 0 +#endif +/* When defined, OutputDebugString() will be used instead of stderr (ignored on + * non-Windows platforms). Uses OutputDebugStringA() variant and feeds it with + * UTF-8 data. + */ +#ifdef TRANSPORT_LOG_USE_DEBUGSTRING +#undef TRANSPORT_LOG_USE_DEBUGSTRING +#if defined(_WIN32) || defined(_WIN64) +#define TRANSPORT_LOG_USE_DEBUGSTRING 1 +#else +#define TRANSPORT_LOG_USE_DEBUGSTRING 0 +#endif +#else +#define TRANSPORT_LOG_USE_DEBUGSTRING 0 +#endif +/* When defined, TRANSPORT_LOG library will not contain definition of tag prefix + * variable. In that case it must be defined elsewhere using + * TRANSPORT_LOG_DEFINE_TAG_PREFIX macro, for example: + * + * TRANSPORT_LOG_DEFINE_TAG_PREFIX = "ProcessName"; + * + * This allows to specify custom value for static initialization and avoid + * overhead of setting this value in runtime. + */ +#ifdef TRANSPORT_LOG_EXTERN_TAG_PREFIX +#undef TRANSPORT_LOG_EXTERN_TAG_PREFIX +#define TRANSPORT_LOG_EXTERN_TAG_PREFIX 1 +#else +#define TRANSPORT_LOG_EXTERN_TAG_PREFIX 0 +#endif +/* When defined, TRANSPORT_LOG library will not contain definition of global + * format variable. In that case it must be defined elsewhere using + * TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT macro, for example: + * + * TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT = {MEM_WIDTH}; + * + * This allows to specify custom value for static initialization and avoid + * overhead of setting this value in runtime. + */ +#ifdef TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT +#undef TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT +#define TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT 1 +#else +#define TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT 0 +#endif +/* When defined, transport_log library will not contain definition of global + * output variable. In that case it must be defined elsewhere using + * TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT macro, for example: + * + * TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {TRANSPORT_LOG_PUT_STD, + * custom_output_callback}; + * + * This allows to specify custom value for static initialization and avoid + * overhead of setting this value in runtime. + */ +#ifdef TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT +#undef TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT +#define TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT 1 +#else +#define TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT 0 +#endif +/* When defined, transport_log library will not contain definition of global + * output level variable. In that case it must be defined elsewhere using + * TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL macro, for example: + * + * TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = TRANSPORT_LOG_WARN; + * + * This allows to specify custom value for static initialization and avoid + * overhead of setting this value in runtime. + */ +#ifdef TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL +#undef TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL +#define TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL 1 +#else +#define TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL 0 +#endif +/* When defined, implementation will prefer smaller code size over speed. + * Very rough estimate is that code will be up to 2x smaller and up to 2x + * slower. Disabled by default. + */ +#ifdef TRANSPORT_LOG_OPTIMIZE_SIZE +#undef TRANSPORT_LOG_OPTIMIZE_SIZE +#define TRANSPORT_LOG_OPTIMIZE_SIZE 1 +#else +#define TRANSPORT_LOG_OPTIMIZE_SIZE 0 +#endif +/* Size of the log line buffer. The buffer is allocated on stack. It limits + * maximum length of a log line. + */ +#ifndef TRANSPORT_LOG_BUF_SZ +#define TRANSPORT_LOG_BUF_SZ 512 +#endif +/* Default number of bytes in one line of memory output. For large values + * TRANSPORT_LOG_BUF_SZ also must be increased. + */ +#ifndef TRANSPORT_LOG_MEM_WIDTH +#define TRANSPORT_LOG_MEM_WIDTH 32 +#endif +/* String to put in the end of each log line (can be empty). Its value used by + * stderr output callback. Its size used as a default value for + * TRANSPORT_LOG_EOL_SZ. + */ +#ifndef TRANSPORT_LOG_EOL +#define TRANSPORT_LOG_EOL "\n" +#endif +/* Default delimiter that separates parts of log message. Can NOT contain '%' + * or '\0'. + * + * Log message format specifications can override (or ignore) this value. For + * more details see TRANSPORT_LOG_MESSAGE_CTX_FORMAT, + * TRANSPORT_LOG_MESSAGE_SRC_FORMAT and TRANSPORT_LOG_MESSAGE_TAG_FORMAT. + */ +#ifndef TRANSPORT_LOG_DEF_DELIMITER +#define TRANSPORT_LOG_DEF_DELIMITER " " +#endif +/* Specifies log message context format. Log message context includes date, + * time, process id, thread id and message's log level. Custom information can + * be added as well. Supported fields: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, + * MILLISECOND, PID, TID, LEVEL, S(str), F_INIT(statements), + * F_UINT(width, value). + * + * Must be defined as a tuple, for example: + * + * #define TRANSPORT_LOG_MESSAGE_CTX_FORMAT (YEAR, S("."), MONTH, S("."), DAY, + * S(" > ")) + * + * In that case, resulting log message will be: + * + * 2016.12.22 > TAG function@filename.c:line Message text + * + * Note, that tag, source location and message text are not impacted by + * this setting. See TRANSPORT_LOG_MESSAGE_TAG_FORMAT and + * TRANSPORT_LOG_MESSAGE_SRC_FORMAT. + * + * If message context must be visually separated from the rest of the message, + * it must be reflected in context format (notice trailing S(" > ") in the + * example above). + * + * S(str) adds constant string str. String can NOT contain '%' or '\0'. + * + * F_INIT(statements) adds initialization statement(s) that will be evaluated + * once for each log message. All statements are evaluated in specified order. + * Several F_INIT() fields can be used in every log message format + * specification. Fields, like F_UINT(width, value), are allowed to use results + * of initialization statements. If statement introduces variables (or other + * names, like structures) they must be prefixed with "f_". Statements must be + * enclosed into additional "()". Example: + * + * #define TRANSPORT_LOG_MESSAGE_CTX_FORMAT \ + * (F_INIT(( struct rusage f_ru; getrusage(RUSAGE_SELF, &f_ru); )), \ + * YEAR, S("."), MONTH, S("."), DAY, S(" "), \ + * F_UINT(5, f_ru.ru_nsignals), \ + * S(" ")) + * + * F_UINT(width, value) adds unsigned integer value extended with up to width + * spaces (for alignment purposes). Value can be any expression that evaluates + * to unsigned integer. If expression contains non-standard functions, they + * must be declared with F_INIT(). Example: + * + * #define TRANSPORT_LOG_MESSAGE_CTX_FORMAT \ + * (YEAR, S("."), MONTH, S("."), DAY, S(" "), \ + * F_INIT(( unsigned tickcount(); )), \ + * F_UINT(5, tickcount()), \ + * S(" ")) + * + * Other log message format specifications follow same rules, but have a + * different set of supported fields. + */ +#ifndef TRANSPORT_LOG_MESSAGE_CTX_FORMAT +#define TRANSPORT_LOG_MESSAGE_CTX_FORMAT \ + (MONTH, S("-"), DAY, S(TRANSPORT_LOG_DEF_DELIMITER), HOUR, S(":"), MINUTE, \ + S(":"), SECOND, S("."), MILLISECOND, S(TRANSPORT_LOG_DEF_DELIMITER), PID, \ + S(TRANSPORT_LOG_DEF_DELIMITER), TID, S(TRANSPORT_LOG_DEF_DELIMITER), LEVEL, \ + S(TRANSPORT_LOG_DEF_DELIMITER)) +#endif +/* Example: + */ +/* Specifies log message tag format. It includes tag prefix and tag. Custom + * information can be added as well. Supported fields: + * TAG(prefix_delimiter, tag_delimiter), S(str), F_INIT(statements), + * F_UINT(width, value). + * + * TAG(prefix_delimiter, tag_delimiter) adds following string to log message: + * + * PREFIXTAG + * + * Prefix delimiter will be used only when prefix is not empty. Tag delimiter + * will be used only when prefixed tag is not empty. Example: + * + * #define TRANSPORT_LOG_TAG_FORMAT (S("["), TAG(".", ""), S("] ")) + * + * See TRANSPORT_LOG_MESSAGE_CTX_FORMAT for details. + */ +#ifndef TRANSPORT_LOG_MESSAGE_TAG_FORMAT +#define TRANSPORT_LOG_MESSAGE_TAG_FORMAT (TAG(".", TRANSPORT_LOG_DEF_DELIMITER)) +#endif +/* Specifies log message source location format. It includes function name, + * file name and file line. Custom information can be added as well. Supported + * fields: FUNCTION, FILENAME, FILELINE, S(str), F_INIT(statements), + * F_UINT(width, value). + * + * See TRANSPORT_LOG_MESSAGE_CTX_FORMAT for details. + */ +#ifndef TRANSPORT_LOG_MESSAGE_SRC_FORMAT +#define TRANSPORT_LOG_MESSAGE_SRC_FORMAT \ + (FUNCTION, S("@"), FILENAME, S(":"), FILELINE, S(TRANSPORT_LOG_DEF_DELIMITER)) +#endif +/* Fields that can be used in log message format specifications (see above). + * Mentioning them here explicitly, so we know that nobody else defined them + * before us. See TRANSPORT_LOG_MESSAGE_CTX_FORMAT for details. + */ +#define YEAR YEAR +#define MONTH MONTH +#define DAY DAY +#define MINUTE MINUTE +#define SECOND SECOND +#define MILLISECOND MILLISECOND +#define PID PID +#define TID TID +#define LEVEL LEVEL +#define TAG(prefix_delim, tag_delim) TAG(prefix_delim, tag_delim) +#define FUNCTION FUNCTION +#define FILENAME FILENAME +#define FILELINE FILELINE +#define S(str) S(str) +#define F_INIT(statements) F_INIT(statements) +#define F_UINT(width, value) F_UINT(width, value) +/* Number of bytes to reserve for EOL in the log line buffer (must be >0). + * Must be larger than or equal to length of TRANSPORT_LOG_EOL with terminating + * null. + */ +#ifndef TRANSPORT_LOG_EOL_SZ +#define TRANSPORT_LOG_EOL_SZ sizeof(TRANSPORT_LOG_EOL) +#endif +/* Compile instrumented version of the library to facilitate unit testing. + */ +#ifndef TRANSPORT_LOG_INSTRUMENTED +#define TRANSPORT_LOG_INSTRUMENTED 0 +#endif + +#if defined(__linux__) +#if !defined(__ANDROID__) && !defined(_GNU_SOURCE) +#define _GNU_SOURCE +#endif +#endif +#if defined(__MINGW32__) +#ifdef __STRICT_ANSI__ +#undef __STRICT_ANSI__ +#endif +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_WIN32) || defined(_WIN64) +#include +#else +#include +#include +#if defined(__linux__) +#include +#else +#include +#endif +#endif + +#if defined(__linux__) +#include +#include +#if !defined(__ANDROID__) +#include +#endif +#endif +#if defined(__MACH__) +#include +#endif + +#define INLINE _TRANSPORT_LOG_INLINE +#define VAR_UNUSED(var) (void)var +#define RETVAL_UNUSED(expr) \ + do { \ + while (expr) break; \ + } while (0) +#define STATIC_ASSERT(name, cond) typedef char assert_##name[(cond) ? 1 : -1] +#define ASSERT_UNREACHABLE(why) assert(!sizeof(why)) +#ifndef _countof +#define _countof(xs) (sizeof(xs) / sizeof((xs)[0])) +#endif + +#if TRANSPORT_LOG_INSTRUMENTED +#define INSTRUMENTED_CONST +#else +#define INSTRUMENTED_CONST const +#endif + +#define _PP_PASTE_2(a, b) a##b +#define _PP_CONCAT_2(a, b) _PP_PASTE_2(a, b) + +#define _PP_PASTE_3(a, b, c) a##b##c +#define _PP_CONCAT_3(a, b, c) _PP_PASTE_3(a, b, c) + +/* Microsoft C preprocessor is a piece of shit. This moron treats __VA_ARGS__ + * as a single token and requires additional expansion to realize that it's + * actually a list. If not for it, there would be no need in this extra + * expansion. + */ +#define _PP_ID(x) x +#define _PP_NARGS_N(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, \ + _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, \ + _24, ...) \ + _24 +#define _PP_NARGS(...) \ + _PP_ID(_PP_NARGS_N(__VA_ARGS__, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, \ + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)) + +/* There is a more efficient way to implement this, but it requires + * working C preprocessor. Unfortunately, Microsoft Visual Studio doesn't + * have one. + */ +#define _PP_HEAD__(x, ...) x +#define _PP_HEAD_(...) _PP_ID(_PP_HEAD__(__VA_ARGS__, ~)) +#define _PP_HEAD(xs) _PP_HEAD_ xs +#define _PP_TAIL_(x, ...) (__VA_ARGS__) +#define _PP_TAIL(xs) _PP_TAIL_ xs +#define _PP_UNTUPLE_(...) __VA_ARGS__ +#define _PP_UNTUPLE(xs) _PP_UNTUPLE_ xs + +/* Apply function macro to each element in tuple. Output is not + * enforced to be a tuple. + */ +#define _PP_MAP_1(f, xs) f(_PP_HEAD(xs)) +#define _PP_MAP_2(f, xs) f(_PP_HEAD(xs)) _PP_MAP_1(f, _PP_TAIL(xs)) +#define _PP_MAP_3(f, xs) f(_PP_HEAD(xs)) _PP_MAP_2(f, _PP_TAIL(xs)) +#define _PP_MAP_4(f, xs) f(_PP_HEAD(xs)) _PP_MAP_3(f, _PP_TAIL(xs)) +#define _PP_MAP_5(f, xs) f(_PP_HEAD(xs)) _PP_MAP_4(f, _PP_TAIL(xs)) +#define _PP_MAP_6(f, xs) f(_PP_HEAD(xs)) _PP_MAP_5(f, _PP_TAIL(xs)) +#define _PP_MAP_7(f, xs) f(_PP_HEAD(xs)) _PP_MAP_6(f, _PP_TAIL(xs)) +#define _PP_MAP_8(f, xs) f(_PP_HEAD(xs)) _PP_MAP_7(f, _PP_TAIL(xs)) +#define _PP_MAP_9(f, xs) f(_PP_HEAD(xs)) _PP_MAP_8(f, _PP_TAIL(xs)) +#define _PP_MAP_10(f, xs) f(_PP_HEAD(xs)) _PP_MAP_9(f, _PP_TAIL(xs)) +#define _PP_MAP_11(f, xs) f(_PP_HEAD(xs)) _PP_MAP_10(f, _PP_TAIL(xs)) +#define _PP_MAP_12(f, xs) f(_PP_HEAD(xs)) _PP_MAP_11(f, _PP_TAIL(xs)) +#define _PP_MAP_13(f, xs) f(_PP_HEAD(xs)) _PP_MAP_12(f, _PP_TAIL(xs)) +#define _PP_MAP_14(f, xs) f(_PP_HEAD(xs)) _PP_MAP_13(f, _PP_TAIL(xs)) +#define _PP_MAP_15(f, xs) f(_PP_HEAD(xs)) _PP_MAP_14(f, _PP_TAIL(xs)) +#define _PP_MAP_16(f, xs) f(_PP_HEAD(xs)) _PP_MAP_15(f, _PP_TAIL(xs)) +#define _PP_MAP_17(f, xs) f(_PP_HEAD(xs)) _PP_MAP_16(f, _PP_TAIL(xs)) +#define _PP_MAP_18(f, xs) f(_PP_HEAD(xs)) _PP_MAP_17(f, _PP_TAIL(xs)) +#define _PP_MAP_19(f, xs) f(_PP_HEAD(xs)) _PP_MAP_18(f, _PP_TAIL(xs)) +#define _PP_MAP_20(f, xs) f(_PP_HEAD(xs)) _PP_MAP_19(f, _PP_TAIL(xs)) +#define _PP_MAP_21(f, xs) f(_PP_HEAD(xs)) _PP_MAP_20(f, _PP_TAIL(xs)) +#define _PP_MAP_22(f, xs) f(_PP_HEAD(xs)) _PP_MAP_21(f, _PP_TAIL(xs)) +#define _PP_MAP_23(f, xs) f(_PP_HEAD(xs)) _PP_MAP_22(f, _PP_TAIL(xs)) +#define _PP_MAP_24(f, xs) f(_PP_HEAD(xs)) _PP_MAP_23(f, _PP_TAIL(xs)) +#define _PP_MAP(f, xs) _PP_CONCAT_2(_PP_MAP_, _PP_NARGS xs)(f, xs) + +/* Apply function macro to each element in tuple in reverse order. + * Output is not enforced to be a tuple. + */ +#define _PP_RMAP_1(f, xs) f(_PP_HEAD(xs)) +#define _PP_RMAP_2(f, xs) _PP_RMAP_1(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) +#define _PP_RMAP_3(f, xs) _PP_RMAP_2(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) +#define _PP_RMAP_4(f, xs) _PP_RMAP_3(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) +#define _PP_RMAP_5(f, xs) _PP_RMAP_4(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) +#define _PP_RMAP_6(f, xs) _PP_RMAP_5(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) +#define _PP_RMAP_7(f, xs) _PP_RMAP_6(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) +#define _PP_RMAP_8(f, xs) _PP_RMAP_7(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) +#define _PP_RMAP_9(f, xs) _PP_RMAP_8(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) +#define _PP_RMAP_10(f, xs) _PP_RMAP_9(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) +#define _PP_RMAP_11(f, xs) _PP_RMAP_10(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) +#define _PP_RMAP_12(f, xs) _PP_RMAP_11(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) +#define _PP_RMAP_13(f, xs) _PP_RMAP_12(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) +#define _PP_RMAP_14(f, xs) _PP_RMAP_13(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) +#define _PP_RMAP_15(f, xs) _PP_RMAP_14(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) +#define _PP_RMAP_16(f, xs) _PP_RMAP_15(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) +#define _PP_RMAP_17(f, xs) _PP_RMAP_16(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) +#define _PP_RMAP_18(f, xs) _PP_RMAP_17(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) +#define _PP_RMAP_19(f, xs) _PP_RMAP_18(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) +#define _PP_RMAP_20(f, xs) _PP_RMAP_19(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) +#define _PP_RMAP_21(f, xs) _PP_RMAP_20(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) +#define _PP_RMAP_22(f, xs) _PP_RMAP_21(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) +#define _PP_RMAP_23(f, xs) _PP_RMAP_22(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) +#define _PP_RMAP_24(f, xs) _PP_RMAP_23(f, _PP_TAIL(xs)) f(_PP_HEAD(xs)) +#define _PP_RMAP(f, xs) _PP_CONCAT_2(_PP_RMAP_, _PP_NARGS xs)(f, xs) + +/* Used to implement _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS() macro. All + * possible fields must be mentioned here. Not counting F_INIT() here because + * it's somewhat special and is handled spearatly (at least for now). + */ +#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__ (0 << 0) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__YEAR (1 << 1) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__MONTH (1 << 2) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__DAY (1 << 3) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__HOUR (1 << 4) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__MINUTE (1 << 5) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__SECOND (1 << 6) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__MILLISECOND (1 << 7) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__PID (1 << 8) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__TID (1 << 9) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__LEVEL (1 << 10) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__TAG(ps, ts) (1 << 11) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__FUNCTION (1 << 12) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__FILENAME (1 << 13) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__FILELINE (1 << 14) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__S(s) (1 << 15) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__F_INIT(expr) (0 << 16) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__F_UINT(w, v) (1 << 17) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK(field) \ + _PP_CONCAT_3(_TRANSPORT_LOG_MESSAGE_FORMAT_MASK_, _, field) + +/* Logical "or" of masks of fields used in specified format specification. + */ +#define _TRANSPORT_LOG_MESSAGE_FORMAT_FIELDS(format) \ + (0 _PP_MAP(| _TRANSPORT_LOG_MESSAGE_FORMAT_MASK, format)) + +/* Expands to expressions that evaluates to true if field is used in + * specified format specification. Example: + * + * #if _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(F_UINT, + * TRANSPORT_LOG_MESSAGE_CTX_FORMAT) + * ... + * #endif + */ +#define _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(field, format) \ + (_TRANSPORT_LOG_MESSAGE_FORMAT_MASK(field) & \ + _TRANSPORT_LOG_MESSAGE_FORMAT_FIELDS(format)) + +/* Same, but checks all supported format specifications. + */ +#define _TRANSPORT_LOG_MESSAGE_FORMAT_FIELD_USED(field) \ + (_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(field, \ + TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \ + _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(field, \ + TRANSPORT_LOG_MESSAGE_TAG_FORMAT) || \ + _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(field, \ + TRANSPORT_LOG_MESSAGE_SRC_FORMAT)) + +#define _TRANSPORT_LOG_MESSAGE_FORMAT_DATETIME_USED \ + (_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(YEAR, \ + TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \ + _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(MONTH, \ + TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \ + _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(DAY, \ + TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \ + _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(HOUR, \ + TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \ + _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(MINUTE, \ + TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \ + _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(SECOND, \ + TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \ + _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(MILLISECOND, \ + TRANSPORT_LOG_MESSAGE_CTX_FORMAT)) + +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) +#pragma warning(disable : 4204) /* nonstandard extension used: non-constant \ + aggregate initializer */ +#define memccpy _memccpy +#endif + +#if (defined(_MSC_VER) && !defined(__INTEL_COMPILER)) || defined(__MINGW64__) +#define vsnprintf(s, sz, fmt, va) fake_vsnprintf(s, sz, fmt, va) +static int fake_vsnprintf(char *s, size_t sz, const char *fmt, va_list ap) { + const int n = vsnprintf_s(s, sz, _TRUNCATE, fmt, ap); + return 0 < n ? n : (int)sz + 1; /* no need in _vscprintf() for now */ +} +#if TRANSPORT_LOG_OPTIMIZE_SIZE +#define snprintf(s, sz, ...) fake_snprintf(s, sz, __VA_ARGS__) +static int fake_snprintf(char *s, size_t sz, const char *fmt, ...) { + va_list va; + va_start(va, fmt); + const int n = fake_vsnprintf(s, sz, fmt, va); + va_end(va); + return n; +} +#endif +#endif + +typedef void (*time_cb)(struct tm *const tm, unsigned *const usec); +typedef void (*pid_cb)(int *const pid, int *const tid); +typedef void (*buffer_cb)(transport_log_message *msg, char *buf); + +typedef struct src_location { + const char *const func; + const char *const file; + const unsigned line; +} src_location; + +typedef struct mem_block { + const void *const d; + const unsigned d_sz; +} mem_block; + +static void time_callback(struct tm *const tm, unsigned *const usec); +static void pid_callback(int *const pid, int *const tid); +static void buffer_callback(transport_log_message *msg, char *buf); + +STATIC_ASSERT(eol_fits_eol_sz, + sizeof(TRANSPORT_LOG_EOL) <= TRANSPORT_LOG_EOL_SZ); +STATIC_ASSERT(eol_sz_greater_than_zero, 0 < TRANSPORT_LOG_EOL_SZ); +STATIC_ASSERT(eol_sz_less_than_buf_sz, + TRANSPORT_LOG_EOL_SZ < TRANSPORT_LOG_BUF_SZ); +#if !defined(_WIN32) && !defined(_WIN64) +STATIC_ASSERT(buf_sz_less_than_pipe_buf, TRANSPORT_LOG_BUF_SZ <= PIPE_BUF); +#endif +static const char c_hex[] = "0123456789abcdef"; + +static INSTRUMENTED_CONST unsigned g_buf_sz = + TRANSPORT_LOG_BUF_SZ - TRANSPORT_LOG_EOL_SZ; +static INSTRUMENTED_CONST time_cb g_time_cb = time_callback; +static INSTRUMENTED_CONST pid_cb g_pid_cb = pid_callback; +static INSTRUMENTED_CONST buffer_cb g_buffer_cb = buffer_callback; + +#if TRANSPORT_LOG_USE_ANDROID_LOG +#include + +static INLINE int android_lvl(const int lvl) { + switch (lvl) { + case TRANSPORT_LOG_VERBOSE: + return ANDROID_LOG_VERBOSE; + case TRANSPORT_LOG_DEBUG: + return ANDROID_LOG_DEBUG; + case TRANSPORT_LOG_INFO: + return ANDROID_LOG_INFO; + case TRANSPORT_LOG_WARN: + return ANDROID_LOG_WARN; + case TRANSPORT_LOG_ERROR: + return ANDROID_LOG_ERROR; + case TRANSPORT_LOG_FATAL: + return ANDROID_LOG_FATAL; + default: + ASSERT_UNREACHABLE("Bad log level"); + return ANDROID_LOG_UNKNOWN; + } +} + +static void out_android_callback(const transport_log_message *const msg, + void *arg) { + VAR_UNUSED(arg); + *msg->p = 0; + const char *tag = msg->p; + if (msg->tag_e != msg->tag_b) { + tag = msg->tag_b; + *msg->tag_e = 0; + } + __android_log_print(android_lvl(msg->lvl), ANDROID_TAG, "%s", msg->msg_b); +} + +enum { OUT_ANDROID_MASK = TRANSPORT_LOG_PUT_STD & ~TRANSPORT_LOG_PUT_CTX }; +#define OUT_ANDROID OUT_ANDROID_MASK, 0, out_android_callback +#endif + +#if TRANSPORT_LOG_USE_NSLOG +#include +CF_EXPORT void CFLog(int32_t level, CFStringRef format, ...); + +static INLINE int apple_lvl(const int lvl) { + switch (lvl) { + case TRANSPORT_LOG_VERBOSE: + return 7; /* ASL_LEVEL_DEBUG / kCFLogLevelDebug */ + ; + case TRANSPORT_LOG_DEBUG: + return 7; /* ASL_LEVEL_DEBUG / kCFLogLevelDebug */ + ; + case TRANSPORT_LOG_INFO: + return 6; /* ASL_LEVEL_INFO / kCFLogLevelInfo */ + ; + case TRANSPORT_LOG_WARN: + return 4; /* ASL_LEVEL_WARNING / kCFLogLevelWarning */ + ; + case TRANSPORT_LOG_ERROR: + return 3; /* ASL_LEVEL_ERR / kCFLogLevelError */ + ; + case TRANSPORT_LOG_FATAL: + return 0; /* ASL_LEVEL_EMERG / kCFLogLevelEmergency */ + ; + default: + ASSERT_UNREACHABLE("Bad log level"); + return 0; /* ASL_LEVEL_EMERG / kCFLogLevelEmergency */ + ; + } +} + +static void out_nslog_callback(const transport_log_message *const msg, + void *arg) { + VAR_UNUSED(arg); + *msg->p = 0; + CFLog(apple_lvl(msg->lvl), CFSTR("%s"), msg->tag_b); +} + +enum { OUT_NSLOG_MASK = TRANSPORT_LOG_PUT_STD & ~TRANSPORT_LOG_PUT_CTX }; +#define OUT_NSLOG OUT_NSLOG_MASK, 0, out_nslog_callback +#endif + +#if TRANSPORT_LOG_USE_DEBUGSTRING +#include + +static void out_debugstring_callback(const transport_log_message *const msg, + void *arg) { + VAR_UNUSED(arg); + msg->p[0] = '\n'; + msg->p[1] = '\0'; + OutputDebugStringA(msg->buf); +} + +enum { OUT_DEBUGSTRING_MASK = TRANSPORT_LOG_PUT_STD }; +#define OUT_DEBUGSTRING OUT_DEBUGSTRING_MASK, 0, out_debugstring_callback +#endif + +void transport_log_out_stderr_callback(const transport_log_message *const msg, + void *arg) { + VAR_UNUSED(arg); + const size_t eol_len = sizeof(TRANSPORT_LOG_EOL) - 1; + memcpy(msg->p, TRANSPORT_LOG_EOL, eol_len); +#if defined(_WIN32) || defined(_WIN64) + /* WriteFile() is atomic for local files opened with FILE_APPEND_DATA and + without FILE_WRITE_DATA */ + DWORD written; + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg->buf, + (DWORD)(msg->p - msg->buf + eol_len), &written, 0); +#else + /* write() is atomic for buffers less than or equal to PIPE_BUF. */ + RETVAL_UNUSED( + write(STDERR_FILENO, msg->buf, (size_t)(msg->p - msg->buf) + eol_len)); +#endif +} + +static const transport_log_output out_stderr = {TRANSPORT_LOG_OUT_STDERR}; + +#if !TRANSPORT_LOG_EXTERN_TAG_PREFIX +TRANSPORT_LOG_DEFINE_TAG_PREFIX = 0; +#endif + +#if !TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT +TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT = {TRANSPORT_LOG_MEM_WIDTH}; +#endif + +#if !TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT +#if TRANSPORT_LOG_USE_ANDROID_LOG +TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {OUT_ANDROID}; +#elif TRANSPORT_LOG_USE_NSLOG +TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {OUT_NSLOG}; +#elif TRANSPORT_LOG_USE_DEBUGSTRING +TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {OUT_DEBUGSTRING}; +#else +TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {TRANSPORT_LOG_OUT_STDERR}; +#endif +#endif + +#if !TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL +TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = 0; +#endif + +const transport_log_spec _transport_log_stderr_spec = { + TRANSPORT_LOG_GLOBAL_FORMAT, + &out_stderr, +}; + +static const transport_log_spec global_spec = { + TRANSPORT_LOG_GLOBAL_FORMAT, + TRANSPORT_LOG_GLOBAL_OUTPUT, +}; + +#if _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(LEVEL, \ + TRANSPORT_LOG_MESSAGE_CTX_FORMAT) +static char lvl_char(const int lvl) { + switch (lvl) { + case TRANSPORT_LOG_VERBOSE: + return 'V'; + case TRANSPORT_LOG_DEBUG: + return 'D'; + case TRANSPORT_LOG_INFO: + return 'I'; + case TRANSPORT_LOG_WARN: + return 'W'; + case TRANSPORT_LOG_ERROR: + return 'E'; + case TRANSPORT_LOG_FATAL: + return 'F'; + default: + ASSERT_UNREACHABLE("Bad log level"); + return '?'; + } +} +#endif + +#define GCCVER_LESS(MAJOR, MINOR, PATCH) \ + (__GNUC__ < MAJOR || (__GNUC__ == MAJOR && (__GNUC_MINOR__ < MINOR || \ + (__GNUC_MINOR__ == MINOR && \ + __GNUC_PATCHLEVEL__ < PATCH)))) + +#if !defined(__clang__) && defined(__GNUC__) && GCCVER_LESS(4, 7, 0) +#define __atomic_load_n(vp, model) __sync_fetch_and_add(vp, 0) +#define __atomic_fetch_add(vp, n, model) __sync_fetch_and_add(vp, n) +#define __atomic_sub_fetch(vp, n, model) __sync_sub_and_fetch(vp, n) +#define __atomic_or_fetch(vp, n, model) __sync_or_and_fetch(vp, n) +#define __atomic_and_fetch(vp, n, model) __sync_and_and_fetch(vp, n) +/* Note: will not store old value of *vp in *ep (non-standard behaviour) */ +#define __atomic_compare_exchange_n(vp, ep, d, weak, smodel, fmodel) \ + __sync_bool_compare_and_swap(vp, *(ep), d) +#endif + +#if !TRANSPORT_LOG_OPTIMIZE_SIZE && !defined(_WIN32) && !defined(_WIN64) +#define TCACHE +#define TCACHE_STALE (0x40000000) +#define TCACHE_FLUID (0x40000000 | 0x80000000) +static unsigned g_tcache_mode = TCACHE_STALE; +static struct timeval g_tcache_tv = {0, 0}; +static struct tm g_tcache_tm = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +static INLINE int tcache_get(const struct timeval *const tv, + struct tm *const tm) { + unsigned mode; + mode = __atomic_load_n(&g_tcache_mode, __ATOMIC_RELAXED); + if (0 == (mode & TCACHE_FLUID)) { + mode = __atomic_fetch_add(&g_tcache_mode, 1, __ATOMIC_ACQUIRE); + if (0 == (mode & TCACHE_FLUID)) { + if (g_tcache_tv.tv_sec == tv->tv_sec) { + *tm = g_tcache_tm; + __atomic_sub_fetch(&g_tcache_mode, 1, __ATOMIC_RELEASE); + return !0; + } + __atomic_or_fetch(&g_tcache_mode, TCACHE_STALE, __ATOMIC_RELAXED); + } + __atomic_sub_fetch(&g_tcache_mode, 1, __ATOMIC_RELEASE); + } + return 0; +} + +static INLINE void tcache_set(const struct timeval *const tv, + struct tm *const tm) { + unsigned stale = TCACHE_STALE; + if (__atomic_compare_exchange_n(&g_tcache_mode, &stale, TCACHE_FLUID, 0, + __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) { + g_tcache_tv = *tv; + g_tcache_tm = *tm; + __atomic_and_fetch(&g_tcache_mode, ~TCACHE_FLUID, __ATOMIC_RELEASE); + } +} +#endif + +static void time_callback(struct tm *const tm, unsigned *const msec) { +#if !_TRANSPORT_LOG_MESSAGE_FORMAT_DATETIME_USED + VAR_UNUSED(tm); + VAR_UNUSED(msec); +#else +#if defined(_WIN32) || defined(_WIN64) + SYSTEMTIME st; + GetLocalTime(&st); + tm->tm_year = st.wYear; + tm->tm_mon = st.wMonth - 1; + tm->tm_mday = st.wDay; + tm->tm_wday = st.wDayOfWeek; + tm->tm_hour = st.wHour; + tm->tm_min = st.wMinute; + tm->tm_sec = st.wSecond; + *msec = st.wMilliseconds; +#else + struct timeval tv; + gettimeofday(&tv, 0); +#ifndef TCACHE + localtime_r(&tv.tv_sec, tm); +#else + if (!tcache_get(&tv, tm)) { + localtime_r(&tv.tv_sec, tm); + tcache_set(&tv, tm); + } +#endif + *msec = (unsigned)tv.tv_usec / 1000; +#endif +#endif +} + +static void pid_callback(int *const pid, int *const tid) { +#if !_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(PID, \ + TRANSPORT_LOG_MESSAGE_CTX_FORMAT) + VAR_UNUSED(pid); +#else +#if defined(_WIN32) || defined(_WIN64) + *pid = GetCurrentProcessId(); +#else + *pid = getpid(); +#endif +#endif + +#if !_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(TID, \ + TRANSPORT_LOG_MESSAGE_CTX_FORMAT) + VAR_UNUSED(tid); +#else +#if defined(_WIN32) || defined(_WIN64) + *tid = GetCurrentThreadId(); +#elif defined(__ANDROID__) + *tid = gettid(); +#elif defined(__linux__) + *tid = syscall(SYS_gettid); +#elif defined(__MACH__) + *tid = (int)pthread_mach_thread_np(pthread_self()); +#else +#define Platform not supported +#endif +#endif +} + +static void buffer_callback(transport_log_message *msg, char *buf) { + msg->e = (msg->p = msg->buf = buf) + g_buf_sz; +} + +#if _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(FUNCTION, \ + TRANSPORT_LOG_MESSAGE_SRC_FORMAT) +static const char *funcname(const char *func) { return func ? func : ""; } +#endif + +#if _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(FILENAME, \ + TRANSPORT_LOG_MESSAGE_SRC_FORMAT) +static const char *filename(const char *file) { + const char *f = file; + for (const char *p = file; 0 != *p; ++p) { + if ('/' == *p || '\\' == *p) { + f = p + 1; + } + } + return f; +} +#endif + +static INLINE size_t nprintf_size(transport_log_message *const msg) { + // *nprintf() always puts 0 in the end when input buffer is not empty. This + // 0 is not desired because its presence sets (ctx->p) to (ctx->e - 1) which + // leaves space for one more character. Some put_xxx() functions don't use + // *nprintf() and could use that last character. In that case log line will + // have multiple (two) half-written parts which is confusing. To workaround + // that we allow *nprintf() to write its 0 in the eol area (which is always + // not empty). + return (size_t)(msg->e - msg->p + 1); +} + +static INLINE void put_nprintf(transport_log_message *const msg, const int n) { + if (0 < n) { + msg->p = n < msg->e - msg->p ? msg->p + n : msg->e; + } +} + +static INLINE char *put_padding_r(const unsigned w, const char wc, char *p, + char *e) { + for (char *const b = e - w; b < p; *--p = wc) { + } + return p; +} + +static char *put_integer_r(unsigned v, const int sign, const unsigned w, + const char wc, char *const e) { + static const char _signs[] = {'-', '0', '+'}; + static const char *const signs = _signs + 1; + char *p = e; + do { + *--p = '0' + v % 10; + } while (0 != (v /= 10)); + if (0 == sign) return put_padding_r(w, wc, p, e); + if ('0' != wc) { + *--p = signs[sign]; + return put_padding_r(w, wc, p, e); + } + p = put_padding_r(w, wc, p, e + 1); + *--p = signs[sign]; + return p; +} + +static INLINE char *put_uint_r(const unsigned v, const unsigned w, + const char wc, char *const e) { + return put_integer_r(v, 0, w, wc, e); +} + +static INLINE char *put_int_r(const int v, const unsigned w, const char wc, + char *const e) { + return 0 <= v ? put_integer_r((unsigned)v, 0, w, wc, e) + : put_integer_r((unsigned)-v, -1, w, wc, e); +} + +static INLINE char *put_stringn(const char *const s_p, const char *const s_e, + char *const p, char *const e) { + const ptrdiff_t m = e - p; + ptrdiff_t n = s_e - s_p; + if (n > m) { + n = m; + } + memcpy(p, s_p, n); + return p + n; +} + +static INLINE char *put_string(const char *s, char *p, char *const e) { + const ptrdiff_t n = e - p; + char *const c = (char *)memccpy(p, s, '\0', n); + return 0 != c ? c - 1 : e; +} + +static INLINE char *put_uint(unsigned v, const unsigned w, const char wc, + char *const p, char *const e) { + char buf[16]; + char *const se = buf + _countof(buf); + char *sp = put_uint_r(v, w, wc, se); + return put_stringn(sp, se, p, e); +} + +#define PUT_CSTR_R(p, STR) \ + do { \ + for (unsigned i = sizeof(STR) - 1; 0 < i--;) { \ + *--(p) = (STR)[i]; \ + } \ + } \ + _TRANSPORT_LOG_ONCE + +#define PUT_CSTR_CHECKED(p, e, STR) \ + do { \ + for (unsigned i = 0; (e) > (p) && (sizeof(STR) - 1) > i; ++i) { \ + *(p)++ = (STR)[i]; \ + } \ + } \ + _TRANSPORT_LOG_ONCE + +/* F_INIT field support. + */ +#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__ +#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__YEAR +#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__MONTH +#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__DAY +#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__HOUR +#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__MINUTE +#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__SECOND +#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__MILLISECOND +#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__PID +#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__TID +#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__LEVEL +#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__TAG(ps, ts) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__FUNCTION +#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__FILENAME +#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__FILELINE +#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__S(s) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__F_INIT(expr) _PP_UNTUPLE(expr); +#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__F_UINT(w, v) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT(field) \ + _PP_CONCAT_3(_TRANSPORT_LOG_MESSAGE_FORMAT_INIT_, _, field) + +/* Implements generation of printf-like format string for log message + * format specification. + */ +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__ "" +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__YEAR "%04u" +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__MONTH "%02u" +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__DAY "%02u" +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__HOUR "%02u" +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__MINUTE "%02u" +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__SECOND "%02u" +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__MILLISECOND "%03u" +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__PID "%5i" +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__TID "%5i" +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__LEVEL "%c" +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__TAG UNDEFINED +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__FUNCTION "%s" +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__FILENAME "%s" +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__FILELINE "%u" +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__S(s) s +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__F_INIT(expr) "" +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__F_UINT(w, v) "%" #w "u" +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT(field) \ + _PP_CONCAT_3(_TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT_, _, field) + +/* Implements generation of printf-like format parameters for log message + * format specification. + */ +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__ +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__YEAR \ + , (unsigned)(tm.tm_year + 1900) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__MONTH \ + , (unsigned)(tm.tm_mon + 1) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__DAY , (unsigned)tm.tm_mday +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__HOUR , (unsigned)tm.tm_hour +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__MINUTE , (unsigned)tm.tm_min +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__SECOND , (unsigned)tm.tm_sec +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__MILLISECOND , (unsigned)msec +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__PID , pid +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__TID , tid +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__LEVEL \ + , (char)lvl_char(msg->lvl) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__TAG UNDEFINED +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__FUNCTION , funcname(src->func) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__FILENAME , filename(src->file) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__FILELINE , src->line +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__S(s) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__F_INIT(expr) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__F_UINT(w, v) , v +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL(field) \ + _PP_CONCAT_3(_TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL_, _, field) + +/* Implements generation of put_xxx_t statements for log message specification. + */ +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__ +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__YEAR \ + p = put_uint_r(tm.tm_year + 1900, 4, '0', p); +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__MONTH \ + p = put_uint_r((unsigned)tm.tm_mon + 1, 2, '0', p); +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__DAY \ + p = put_uint_r((unsigned)tm.tm_mday, 2, '0', p); +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__HOUR \ + p = put_uint_r((unsigned)tm.tm_hour, 2, '0', p); +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__MINUTE \ + p = put_uint_r((unsigned)tm.tm_min, 2, '0', p); +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__SECOND \ + p = put_uint_r((unsigned)tm.tm_sec, 2, '0', p); +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__MILLISECOND \ + p = put_uint_r(msec, 3, '0', p); +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__PID p = put_int_r(pid, 5, ' ', p); +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__TID p = put_int_r(tid, 5, ' ', p); +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__LEVEL *--p = lvl_char(msg->lvl); +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__TAG UNDEFINED +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__FUNCTION UNDEFINED +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__FILENAME UNDEFINED +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__FILELINE UNDEFINED +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__S(s) PUT_CSTR_R(p, s); +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__F_INIT(expr) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__F_UINT(w, v) \ + p = put_uint_r(v, w, ' ', p); +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R(field) \ + _PP_CONCAT_3(_TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R_, _, field) + +static void put_ctx(transport_log_message *const msg) { + _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_INIT, TRANSPORT_LOG_MESSAGE_CTX_FORMAT) +#if !_TRANSPORT_LOG_MESSAGE_FORMAT_FIELDS(TRANSPORT_LOG_MESSAGE_CTX_FORMAT) + VAR_UNUSED(msg); +#else +#if _TRANSPORT_LOG_MESSAGE_FORMAT_DATETIME_USED + struct tm tm; + unsigned msec; + g_time_cb(&tm, &msec); +#endif +#if _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS( \ + PID, TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \ + _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(TID, \ + TRANSPORT_LOG_MESSAGE_CTX_FORMAT) + int pid, tid; + g_pid_cb(&pid, &tid); +#endif + +#if TRANSPORT_LOG_OPTIMIZE_SIZE + int n; + n = snprintf(msg->p, nprintf_size(msg), + _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT, + TRANSPORT_LOG_MESSAGE_CTX_FORMAT) + _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL, + TRANSPORT_LOG_MESSAGE_CTX_FORMAT)); + put_nprintf(msg, n); +#else + char buf[64]; + char *const e = buf + sizeof(buf); + char *p = e; + _PP_RMAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R, + TRANSPORT_LOG_MESSAGE_CTX_FORMAT) + msg->p = put_stringn(p, e, msg->p, msg->e); +#endif +#endif +} + +#define PUT_TAG(msg, tag, prefix_delim, tag_delim) \ + do { \ + const char *ch; \ + msg->tag_b = msg->p; \ + if (0 != (ch = _transport_log_tag_prefix)) { \ + for (; msg->e != msg->p && 0 != (*msg->p = *ch); ++msg->p, ++ch) { \ + } \ + } \ + if (0 != (ch = tag) && 0 != tag[0]) { \ + if (msg->tag_b != msg->p) { \ + PUT_CSTR_CHECKED(msg->p, msg->e, prefix_delim); \ + } \ + for (; msg->e != msg->p && 0 != (*msg->p = *ch); ++msg->p, ++ch) { \ + } \ + } \ + msg->tag_e = msg->p; \ + if (msg->tag_b != msg->p) { \ + PUT_CSTR_CHECKED(msg->p, msg->e, tag_delim); \ + } \ + } \ + _TRANSPORT_LOG_ONCE + +/* Implements simple put statements for log message specification. + */ +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__ +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__YEAR UNDEFINED +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__MONTH UNDEFINED +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__DAY UNDEFINED +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__HOUR UNDEFINED +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__MINUTE UNDEFINED +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__SECOND UNDEFINED +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__MILLISECOND UNDEFINED +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__PID UNDEFINED +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__TID UNDEFINED +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__LEVEL UNDEFINED +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__TAG(pd, td) \ + PUT_TAG(msg, tag, pd, td); +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__FUNCTION \ + msg->p = put_string(funcname(src->func), msg->p, msg->e); +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__FILENAME \ + msg->p = put_string(filename(src->file), msg->p, msg->e); +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__FILELINE \ + msg->p = put_uint(src->line, 0, '\0', msg->p, msg->e); +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__S(s) \ + PUT_CSTR_CHECKED(msg->p, msg->e, s); +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__F_INIT(expr) +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__F_UINT(w, v) \ + msg->p = put_uint(v, w, ' ', msg->p, msg->e); +#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT(field) \ + _PP_CONCAT_3(_TRANSPORT_LOG_MESSAGE_FORMAT_PUT_, _, field) + +static void put_tag(transport_log_message *const msg, const char *const tag) { + _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_INIT, TRANSPORT_LOG_MESSAGE_TAG_FORMAT) +#if !_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(TAG, \ + TRANSPORT_LOG_MESSAGE_TAG_FORMAT) + VAR_UNUSED(tag); +#endif +#if !_TRANSPORT_LOG_MESSAGE_FORMAT_FIELDS(TRANSPORT_LOG_MESSAGE_TAG_FORMAT) + VAR_UNUSED(msg); +#else + _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PUT, TRANSPORT_LOG_MESSAGE_TAG_FORMAT) +#endif +} + +static void put_src(transport_log_message *const msg, + const src_location *const src) { + _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_INIT, TRANSPORT_LOG_MESSAGE_SRC_FORMAT) +#if !_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS( \ + FUNCTION, TRANSPORT_LOG_MESSAGE_SRC_FORMAT) && \ + !_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS( \ + FILENAME, TRANSPORT_LOG_MESSAGE_SRC_FORMAT) && \ + !_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(FILELINE, \ + TRANSPORT_LOG_MESSAGE_SRC_FORMAT) + VAR_UNUSED(src); +#endif +#if !_TRANSPORT_LOG_MESSAGE_FORMAT_FIELDS(TRANSPORT_LOG_MESSAGE_SRC_FORMAT) + VAR_UNUSED(msg); +#else +#if TRANSPORT_LOG_OPTIMIZE_SIZE + int n; + n = snprintf(msg->p, nprintf_size(msg), + _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT, + TRANSPORT_LOG_MESSAGE_SRC_FORMAT) + _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL, + TRANSPORT_LOG_MESSAGE_SRC_FORMAT)); + put_nprintf(msg, n); +#else + _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PUT, TRANSPORT_LOG_MESSAGE_SRC_FORMAT) +#endif +#endif +} + +static void put_msg(transport_log_message *const msg, const char *const fmt, + va_list va) { + int n; + msg->msg_b = msg->p; + n = vsnprintf(msg->p, nprintf_size(msg), fmt, va); + put_nprintf(msg, n); +} + +static void output_mem(const transport_log_spec *log, + transport_log_message *const msg, + const mem_block *const mem) { + if (0 == mem->d || 0 == mem->d_sz) { + return; + } + const unsigned char *mem_p = (const unsigned char *)mem->d; + const unsigned char *const mem_e = mem_p + mem->d_sz; + const unsigned char *mem_cut; + const ptrdiff_t mem_width = (ptrdiff_t)log->format->mem_width; + char *const hex_b = msg->msg_b; + char *const ascii_b = hex_b + 2 * mem_width + 2; + char *const ascii_e = ascii_b + mem_width; + if (msg->e < ascii_e) { + return; + } + while (mem_p != mem_e) { + char *hex = hex_b; + char *ascii = ascii_b; + for (mem_cut = mem_width < mem_e - mem_p ? mem_p + mem_width : mem_e; + mem_cut != mem_p; ++mem_p) { + const unsigned char ch = *mem_p; + *hex++ = c_hex[(0xf0 & ch) >> 4]; + *hex++ = c_hex[(0x0f & ch)]; + *ascii++ = isprint(ch) ? (char)ch : '?'; + } + while (hex != ascii_b) { + *hex++ = ' '; + } + msg->p = ascii; + log->output->callback(msg, log->output->arg); + } +} + +void transport_log_set_tag_prefix(const char *const prefix) { + _transport_log_tag_prefix = prefix; +} + +void transport_log_set_mem_width(const unsigned w) { + _transport_log_global_format.mem_width = w; +} + +void transport_log_set_output_level(const int lvl) { + _transport_log_global_output_lvl = lvl; +} + +void transport_log_set_output_v(const unsigned mask, void *const arg, + const transport_log_output_cb callback) { + _transport_log_global_output.mask = mask; + _transport_log_global_output.arg = arg; + _transport_log_global_output.callback = callback; +} + +static void _transport_log_write_imp(const transport_log_spec *log, + const src_location *const src, + const mem_block *const mem, const int lvl, + const char *const tag, + const char *const fmt, va_list va) { + transport_log_message msg; + char buf[TRANSPORT_LOG_BUF_SZ]; + const unsigned mask = log->output->mask; + msg.lvl = lvl; + msg.tag = tag; + g_buffer_cb(&msg, buf); + if (TRANSPORT_LOG_PUT_CTX & mask) { + put_ctx(&msg); + } + if (TRANSPORT_LOG_PUT_TAG & mask) { + put_tag(&msg, tag); + } + if (0 != src && TRANSPORT_LOG_PUT_SRC & mask) { + put_src(&msg, src); + } + if (TRANSPORT_LOG_PUT_MSG & mask) { + put_msg(&msg, fmt, va); + } + log->output->callback(&msg, log->output->arg); + if (0 != mem && TRANSPORT_LOG_PUT_MSG & mask) { + output_mem(log, &msg, mem); + } +} + +void _transport_log_write_d(const char *const func, const char *const file, + const unsigned line, const int lvl, + const char *const tag, const char *const fmt, ...) { + const src_location src = {func, file, line}; + va_list va; + va_start(va, fmt); + _transport_log_write_imp(&global_spec, &src, 0, lvl, tag, fmt, va); + va_end(va); +} + +void _transport_log_write_aux_d(const char *const func, const char *const file, + const unsigned line, + const transport_log_spec *const log, + const int lvl, const char *const tag, + const char *const fmt, ...) { + const src_location src = {func, file, line}; + va_list va; + va_start(va, fmt); + _transport_log_write_imp(log, &src, 0, lvl, tag, fmt, va); + va_end(va); +} + +void _transport_log_write(const int lvl, const char *const tag, + const char *const fmt, ...) { + va_list va; + va_start(va, fmt); + _transport_log_write_imp(&global_spec, 0, 0, lvl, tag, fmt, va); + va_end(va); +} + +void _transport_log_write_aux(const transport_log_spec *const log, + const int lvl, const char *const tag, + const char *const fmt, ...) { + va_list va; + va_start(va, fmt); + _transport_log_write_imp(log, 0, 0, lvl, tag, fmt, va); + va_end(va); +} + +void _transport_log_write_mem_d(const char *const func, const char *const file, + const unsigned line, const int lvl, + const char *const tag, const void *const d, + const unsigned d_sz, const char *const fmt, + ...) { + const src_location src = {func, file, line}; + const mem_block mem = {d, d_sz}; + va_list va; + va_start(va, fmt); + _transport_log_write_imp(&global_spec, &src, &mem, lvl, tag, fmt, va); + va_end(va); +} + +void _transport_log_write_mem_aux_d(const char *const func, + const char *const file, const unsigned line, + const transport_log_spec *const log, + const int lvl, const char *const tag, + const void *const d, const unsigned d_sz, + const char *const fmt, ...) { + const src_location src = {func, file, line}; + const mem_block mem = {d, d_sz}; + va_list va; + va_start(va, fmt); + _transport_log_write_imp(log, &src, &mem, lvl, tag, fmt, va); + va_end(va); +} + +void _transport_log_write_mem(const int lvl, const char *const tag, + const void *const d, const unsigned d_sz, + const char *const fmt, ...) { + const mem_block mem = {d, d_sz}; + va_list va; + va_start(va, fmt); + _transport_log_write_imp(&global_spec, 0, &mem, lvl, tag, fmt, va); + va_end(va); +} + +void _transport_log_write_mem_aux(const transport_log_spec *const log, + const int lvl, const char *const tag, + const void *const d, const unsigned d_sz, + const char *const fmt, ...) { + const mem_block mem = {d, d_sz}; + va_list va; + va_start(va, fmt); + _transport_log_write_imp(log, 0, &mem, lvl, tag, fmt, va); + va_end(va); +} \ No newline at end of file diff --git a/libtransport/src/utils/membuf.cc b/libtransport/src/utils/membuf.cc new file mode 100644 index 000000000..e75e85b35 --- /dev/null +++ b/libtransport/src/utils/membuf.cc @@ -0,0 +1,867 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright 2013-present Facebook, Inc. + * 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. + */ + +/* + * The code in this file if adapated from the IOBuf of folly: + * https://github.com/facebook/folly/blob/master/folly/io/IOBuf.h + */ +#ifdef _WIN32 +#include +#endif + +#include + +#include +#include +#include +#include +#include +#include + +using std::unique_ptr; + +namespace { + +enum : uint16_t { + kHeapMagic = 0xa5a5, + // This memory segment contains an MemBuf that is still in use + kMemBufInUse = 0x01, + // This memory segment contains buffer data that is still in use + kDataInUse = 0x02, +}; + +enum : std::size_t { + // When create() is called for buffers less than kDefaultCombinedBufSize, + // we allocate a single combined memory segment for the MemBuf and the data + // together. See the comments for createCombined()/createSeparate() for more + // details. + // + // (The size of 1k is largely just a guess here. We could could probably do + // benchmarks of real applications to see if adjusting this number makes a + // difference. Callers that know their exact use case can also explicitly + // call createCombined() or createSeparate().) + kDefaultCombinedBufSize = 1024 +}; + +// Helper function for MemBuf::takeOwnership() +void takeOwnershipError(bool freeOnError, void* buf, + utils::MemBuf::FreeFunction freeFn, void* userData) { + if (!freeOnError) { + return; + } + if (!freeFn) { + free(buf); + return; + } + try { + freeFn(buf, userData); + } catch (...) { + // The user's free function is not allowed to throw. + // (We are already in the middle of throwing an exception, so + // we cannot let this exception go unhandled.) + abort(); + } +} + +} // namespace + +namespace utils { + +struct MemBuf::HeapPrefix { + explicit HeapPrefix(uint16_t flg) : magic(kHeapMagic), flags(flg) {} + ~HeapPrefix() { + // Reset magic to 0 on destruction. This is solely for debugging purposes + // to help catch bugs where someone tries to use HeapStorage after it has + // been deleted. + magic = 0; + } + + uint16_t magic; + std::atomic flags; +}; + +struct MemBuf::HeapStorage { + HeapPrefix prefix; + // The MemBuf is last in the HeapStorage object. + // This way operator new will work even if allocating a subclass of MemBuf + // that requires more space. + utils::MemBuf buf; +}; + +struct MemBuf::HeapFullStorage { + // Make sure jemalloc allocates from the 64-byte class. Putting this here + // because HeapStorage is private so it can't be at namespace level. + static_assert(sizeof(HeapStorage) <= 64, + "MemBuf may not grow over 56 bytes!"); + + HeapStorage hs; + SharedInfo shared; + std::max_align_t align; +}; + +MemBuf::SharedInfo::SharedInfo() : freeFn(nullptr), userData(nullptr) { + // Use relaxed memory ordering here. Since we are creating a new SharedInfo, + // no other threads should be referring to it yet. + refcount.store(1, std::memory_order_relaxed); +} + +MemBuf::SharedInfo::SharedInfo(FreeFunction fn, void* arg) + : freeFn(fn), userData(arg) { + // Use relaxed memory ordering here. Since we are creating a new SharedInfo, + // no other threads should be referring to it yet. + refcount.store(1, std::memory_order_relaxed); +} + +void* MemBuf::operator new(size_t size) { + size_t fullSize = offsetof(HeapStorage, buf) + size; + auto* storage = static_cast(malloc(fullSize)); + + new (&storage->prefix) HeapPrefix(kMemBufInUse); + return &(storage->buf); +} + +void* MemBuf::operator new(size_t /* size */, void* ptr) { return ptr; } + +void MemBuf::operator delete(void* ptr) { + auto* storageAddr = static_cast(ptr) - offsetof(HeapStorage, buf); + auto* storage = reinterpret_cast(storageAddr); + releaseStorage(storage, kMemBufInUse); +} + +void MemBuf::operator delete(void* /* ptr */, void* /* placement */) { + // Provide matching operator for `MemBuf::new` to avoid MSVC compilation + // warning (C4291) about memory leak when exception is thrown in the + // constructor. +} + +void MemBuf::releaseStorage(HeapStorage* storage, uint16_t freeFlags) { + // Use relaxed memory order here. If we are unlucky and happen to get + // out-of-date data the compare_exchange_weak() call below will catch + // it and load new data with memory_order_acq_rel. + auto flags = storage->prefix.flags.load(std::memory_order_acquire); + + while (true) { + uint16_t newFlags = uint16_t(flags & ~freeFlags); + if (newFlags == 0) { + // The storage space is now unused. Free it. + storage->prefix.HeapPrefix::~HeapPrefix(); + free(storage); + return; + } + + // This storage segment still contains portions that are in use. + // Just clear the flags specified in freeFlags for now. + auto ret = storage->prefix.flags.compare_exchange_weak( + flags, newFlags, std::memory_order_acq_rel); + if (ret) { + // We successfully updated the flags. + return; + } + + // We failed to update the flags. Some other thread probably updated them + // and cleared some of the other bits. Continue around the loop to see if + // we are the last user now, or if we need to try updating the flags again. + } +} + +void MemBuf::freeInternalBuf(void* /* buf */, void* userData) { + auto* storage = static_cast(userData); + releaseStorage(storage, kDataInUse); +} + +MemBuf::MemBuf(CreateOp, std::size_t capacity) + : next_(this), + prev_(this), + data_(nullptr), + length_(0), + flags_and_shared_info_(0) { + SharedInfo* info; + allocExtBuffer(capacity, &buf_, &info, &capacity_); + setSharedInfo(info); + data_ = buf_; +} + +MemBuf::MemBuf(CopyBufferOp /* op */, const void* buf, std::size_t size, + std::size_t headroom, std::size_t min_tailroom) + : MemBuf(CREATE, headroom + size + min_tailroom) { + advance(headroom); + if (size > 0) { + assert(buf != nullptr); + memcpy(writableData(), buf, size); + append(size); + } +} + +unique_ptr MemBuf::create(std::size_t capacity) { + // For smaller-sized buffers, allocate the MemBuf, SharedInfo, and the buffer + // all with a single allocation. + // + // We don't do this for larger buffers since it can be wasteful if the user + // needs to reallocate the buffer but keeps using the same MemBuf object. + // In this case we can't free the data space until the MemBuf is also + // destroyed. Callers can explicitly call createCombined() or + // createSeparate() if they know their use case better, and know if they are + // likely to reallocate the buffer later. + if (capacity <= kDefaultCombinedBufSize) { + return createCombined(capacity); + } + return createSeparate(capacity); +} + +unique_ptr MemBuf::createCombined(std::size_t capacity) { + // To save a memory allocation, allocate space for the MemBuf object, the + // SharedInfo struct, and the data itself all with a single call to malloc(). + size_t requiredStorage = offsetof(HeapFullStorage, align) + capacity; + size_t mallocSize = requiredStorage; + auto* storage = static_cast(malloc(mallocSize)); + + new (&storage->hs.prefix) HeapPrefix(kMemBufInUse | kDataInUse); + new (&storage->shared) SharedInfo(freeInternalBuf, storage); + + uint8_t* bufAddr = reinterpret_cast(&storage->align); + uint8_t* storageEnd = reinterpret_cast(storage) + mallocSize; + size_t actualCapacity = size_t(storageEnd - bufAddr); + unique_ptr ret(new (&storage->hs.buf) MemBuf( + InternalConstructor(), packFlagsAndSharedInfo(0, &storage->shared), + bufAddr, actualCapacity, bufAddr, 0)); + return ret; +} + +unique_ptr MemBuf::createSeparate(std::size_t capacity) { + return std::make_unique(CREATE, capacity); +} + +unique_ptr MemBuf::createChain(size_t totalCapacity, + std::size_t maxBufCapacity) { + unique_ptr out = + create(std::min(totalCapacity, size_t(maxBufCapacity))); + size_t allocatedCapacity = out->capacity(); + + while (allocatedCapacity < totalCapacity) { + unique_ptr newBuf = create( + std::min(totalCapacity - allocatedCapacity, size_t(maxBufCapacity))); + allocatedCapacity += newBuf->capacity(); + out->prependChain(std::move(newBuf)); + } + + return out; +} + +MemBuf::MemBuf(TakeOwnershipOp, void* buf, std::size_t capacity, + std::size_t length, FreeFunction freeFn, void* userData, + bool freeOnError) + : next_(this), + prev_(this), + data_(static_cast(buf)), + buf_(static_cast(buf)), + length_(length), + capacity_(capacity), + flags_and_shared_info_( + packFlagsAndSharedInfo(flag_free_shared_info, nullptr)) { + try { + setSharedInfo(new SharedInfo(freeFn, userData)); + } catch (...) { + takeOwnershipError(freeOnError, buf, freeFn, userData); + throw; + } +} + +unique_ptr MemBuf::takeOwnership(void* buf, std::size_t capacity, + std::size_t length, + FreeFunction freeFn, void* userData, + bool freeOnError) { + try { + // TODO: We could allocate the MemBuf object and SharedInfo all in a single + // memory allocation. We could use the existing HeapStorage class, and + // define a new kSharedInfoInUse flag. We could change our code to call + // releaseStorage(flag_free_shared_info) when this flag_free_shared_info, + // rather than directly calling delete. + // + // Note that we always pass freeOnError as false to the constructor. + // If the constructor throws we'll handle it below. (We have to handle + // allocation failures from std::make_unique too.) + return std::make_unique(TAKE_OWNERSHIP, buf, capacity, length, + freeFn, userData, false); + } catch (...) { + takeOwnershipError(freeOnError, buf, freeFn, userData); + throw; + } +} + +MemBuf::MemBuf(WrapBufferOp, const void* buf, std::size_t capacity) noexcept + : MemBuf(InternalConstructor(), 0, + // We cast away the const-ness of the buffer here. + // This is okay since MemBuf users must use unshare() to create a + // copy of this buffer before writing to the buffer. + static_cast(const_cast(buf)), capacity, + static_cast(const_cast(buf)), capacity) {} + +unique_ptr MemBuf::wrapBuffer(const void* buf, std::size_t capacity) { + return std::make_unique(WRAP_BUFFER, buf, capacity); +} + +MemBuf MemBuf::wrapBufferAsValue(const void* buf, + std::size_t capacity) noexcept { + return MemBuf(WrapBufferOp::WRAP_BUFFER, buf, capacity); +} + +MemBuf::MemBuf() noexcept {} + +MemBuf::MemBuf(MemBuf&& other) noexcept + : data_(other.data_), + buf_(other.buf_), + length_(other.length_), + capacity_(other.capacity_), + flags_and_shared_info_(other.flags_and_shared_info_) { + // Reset other so it is a clean state to be destroyed. + other.data_ = nullptr; + other.buf_ = nullptr; + other.length_ = 0; + other.capacity_ = 0; + other.flags_and_shared_info_ = 0; + + // If other was part of the chain, assume ownership of the rest of its chain. + // (It's only valid to perform move assignment on the head of a chain.) + if (other.next_ != &other) { + next_ = other.next_; + next_->prev_ = this; + other.next_ = &other; + + prev_ = other.prev_; + prev_->next_ = this; + other.prev_ = &other; + } +} + +MemBuf::MemBuf(const MemBuf& other) { *this = other.cloneAsValue(); } + +MemBuf::MemBuf(InternalConstructor, uintptr_t flagsAndSharedInfo, uint8_t* buf, + std::size_t capacity, uint8_t* data, std::size_t length) noexcept + : next_(this), + prev_(this), + data_(data), + buf_(buf), + length_(length), + capacity_(capacity), + flags_and_shared_info_(flagsAndSharedInfo) { + assert(data >= buf); + assert(data + length <= buf + capacity); +} + +MemBuf::~MemBuf() { + // Destroying an MemBuf destroys the entire chain. + // Users of MemBuf should only explicitly delete the head of any chain. + // The other elements in the chain will be automatically destroyed. + while (next_ != this) { + // Since unlink() returns unique_ptr() and we don't store it, + // it will automatically delete the unlinked element. + (void)next_->unlink(); + } + + decrementRefcount(); +} + +MemBuf& MemBuf::operator=(MemBuf&& other) noexcept { + if (this == &other) { + return *this; + } + + // If we are part of a chain, delete the rest of the chain. + while (next_ != this) { + // Since unlink() returns unique_ptr() and we don't store it, + // it will automatically delete the unlinked element. + (void)next_->unlink(); + } + + // Decrement our refcount on the current buffer + decrementRefcount(); + + // Take ownership of the other buffer's data + data_ = other.data_; + buf_ = other.buf_; + length_ = other.length_; + capacity_ = other.capacity_; + flags_and_shared_info_ = other.flags_and_shared_info_; + // Reset other so it is a clean state to be destroyed. + other.data_ = nullptr; + other.buf_ = nullptr; + other.length_ = 0; + other.capacity_ = 0; + other.flags_and_shared_info_ = 0; + + // If other was part of the chain, assume ownership of the rest of its chain. + // (It's only valid to perform move assignment on the head of a chain.) + if (other.next_ != &other) { + next_ = other.next_; + next_->prev_ = this; + other.next_ = &other; + + prev_ = other.prev_; + prev_->next_ = this; + other.prev_ = &other; + } + + return *this; +} + +MemBuf& MemBuf::operator=(const MemBuf& other) { + if (this != &other) { + *this = MemBuf(other); + } + return *this; +} + +bool MemBuf::empty() const { + const MemBuf* current = this; + do { + if (current->length() != 0) { + return false; + } + current = current->next_; + } while (current != this); + return true; +} + +size_t MemBuf::countChainElements() const { + size_t numElements = 1; + for (MemBuf* current = next_; current != this; current = current->next_) { + ++numElements; + } + return numElements; +} + +std::size_t MemBuf::computeChainDataLength() const { + std::size_t fullLength = length_; + for (MemBuf* current = next_; current != this; current = current->next_) { + fullLength += current->length_; + } + return fullLength; +} + +void MemBuf::prependChain(unique_ptr&& iobuf) { + // Take ownership of the specified MemBuf + MemBuf* other = iobuf.release(); + + // Remember the pointer to the tail of the other chain + MemBuf* otherTail = other->prev_; + + // Hook up prev_->next_ to point at the start of the other chain, + // and other->prev_ to point at prev_ + prev_->next_ = other; + other->prev_ = prev_; + + // Hook up otherTail->next_ to point at us, + // and prev_ to point back at otherTail, + otherTail->next_ = this; + prev_ = otherTail; +} + +unique_ptr MemBuf::clone() const { + return std::make_unique(cloneAsValue()); +} + +unique_ptr MemBuf::cloneOne() const { + return std::make_unique(cloneOneAsValue()); +} + +unique_ptr MemBuf::cloneCoalesced() const { + return std::make_unique(cloneCoalescedAsValue()); +} + +unique_ptr MemBuf::cloneCoalescedWithHeadroomTailroom( + std::size_t new_headroom, std::size_t new_tailroom) const { + return std::make_unique( + cloneCoalescedAsValueWithHeadroomTailroom(new_headroom, new_tailroom)); +} + +MemBuf MemBuf::cloneAsValue() const { + auto tmp = cloneOneAsValue(); + + for (MemBuf* current = next_; current != this; current = current->next_) { + tmp.prependChain(current->cloneOne()); + } + + return tmp; +} + +MemBuf MemBuf::cloneOneAsValue() const { + if (SharedInfo* info = sharedInfo()) { + setFlags(flag_maybe_shared); + info->refcount.fetch_add(1, std::memory_order_acq_rel); + } + return MemBuf(InternalConstructor(), flags_and_shared_info_, buf_, capacity_, + data_, length_); +} + +MemBuf MemBuf::cloneCoalescedAsValue() const { + const std::size_t new_headroom = headroom(); + const std::size_t new_tailroom = prev()->tailroom(); + return cloneCoalescedAsValueWithHeadroomTailroom(new_headroom, new_tailroom); +} + +MemBuf MemBuf::cloneCoalescedAsValueWithHeadroomTailroom( + std::size_t new_headroom, std::size_t new_tailroom) const { + if (!isChained()) { + return cloneOneAsValue(); + } + // Coalesce into newBuf + const std::size_t new_length = computeChainDataLength(); + const std::size_t new_capacity = new_length + new_headroom + new_tailroom; + MemBuf newBuf{CREATE, new_capacity}; + newBuf.advance(new_headroom); + + auto current = this; + do { + if (current->length() > 0) { + memcpy(newBuf.writableTail(), current->data(), current->length()); + newBuf.append(current->length()); + } + current = current->next(); + } while (current != this); + + return newBuf; +} + +void MemBuf::unshareOneSlow() { + // Allocate a new buffer for the data + uint8_t* buf; + SharedInfo* sharedInfo; + std::size_t actualCapacity; + allocExtBuffer(capacity_, &buf, &sharedInfo, &actualCapacity); + + // Copy the data + // Maintain the same amount of headroom. Since we maintained the same + // minimum capacity we also maintain at least the same amount of tailroom. + std::size_t headlen = headroom(); + if (length_ > 0) { + assert(data_ != nullptr); + memcpy(buf + headlen, data_, length_); + } + + // Release our reference on the old buffer + decrementRefcount(); + // Make sure flag_maybe_shared and flag_free_shared_info are all cleared. + setFlagsAndSharedInfo(0, sharedInfo); + + // Update the buffer pointers to point to the new buffer + data_ = buf + headlen; + buf_ = buf; +} + +void MemBuf::unshareChained() { + // unshareChained() should only be called if we are part of a chain of + // multiple MemBufs. The caller should have already verified this. + assert(isChained()); + + MemBuf* current = this; + while (true) { + if (current->isSharedOne()) { + // we have to unshare + break; + } + + current = current->next_; + if (current == this) { + // None of the MemBufs in the chain are shared, + // so return without doing anything + return; + } + } + + // We have to unshare. Let coalesceSlow() do the work. + coalesceSlow(); +} + +void MemBuf::markExternallyShared() { + MemBuf* current = this; + do { + current->markExternallySharedOne(); + current = current->next_; + } while (current != this); +} + +void MemBuf::makeManagedChained() { + assert(isChained()); + + MemBuf* current = this; + while (true) { + current->makeManagedOne(); + current = current->next_; + if (current == this) { + break; + } + } +} + +void MemBuf::coalesceSlow() { + // coalesceSlow() should only be called if we are part of a chain of multiple + // MemBufs. The caller should have already verified this. + + // Compute the length of the entire chain + std::size_t new_length = 0; + MemBuf* end = this; + do { + new_length += end->length_; + end = end->next_; + } while (end != this); + + coalesceAndReallocate(new_length, end); + // We should be only element left in the chain now +} + +void MemBuf::coalesceSlow(size_t max_length) { + // coalesceSlow() should only be called if we are part of a chain of multiple + // MemBufs. The caller should have already verified this. + + // Compute the length of the entire chain + std::size_t new_length = 0; + MemBuf* end = this; + while (true) { + new_length += end->length_; + end = end->next_; + if (new_length >= max_length) { + break; + } + if (end == this) { + throw std::overflow_error( + "attempted to coalesce more data than " + "available"); + } + } + + coalesceAndReallocate(new_length, end); + // We should have the requested length now +} + +void MemBuf::coalesceAndReallocate(size_t new_headroom, size_t new_length, + MemBuf* end, size_t new_tailroom) { + std::size_t new_capacity = new_length + new_headroom + new_tailroom; + + // Allocate space for the coalesced buffer. + // We always convert to an external buffer, even if we happened to be an + // internal buffer before. + uint8_t* newBuf; + SharedInfo* newInfo; + std::size_t actualCapacity; + allocExtBuffer(new_capacity, &newBuf, &newInfo, &actualCapacity); + + // Copy the data into the new buffer + uint8_t* new_data = newBuf + new_headroom; + uint8_t* p = new_data; + MemBuf* current = this; + size_t remaining = new_length; + do { + if (current->length_ > 0) { + assert(current->length_ <= remaining); + assert(current->data_ != nullptr); + remaining -= current->length_; + memcpy(p, current->data_, current->length_); + p += current->length_; + } + current = current->next_; + } while (current != end); + assert(remaining == 0); + + // Point at the new buffer + decrementRefcount(); + + // Make sure flag_maybe_shared and flag_free_shared_info are all cleared. + setFlagsAndSharedInfo(0, newInfo); + + capacity_ = actualCapacity; + buf_ = newBuf; + data_ = new_data; + length_ = new_length; + + // Separate from the rest of our chain. + // Since we don't store the unique_ptr returned by separateChain(), + // this will immediately delete the returned subchain. + if (isChained()) { + (void)separateChain(next_, current->prev_); + } +} + +void MemBuf::decrementRefcount() { + // Externally owned buffers don't have a SharedInfo object and aren't managed + // by the reference count + SharedInfo* info = sharedInfo(); + if (!info) { + return; + } + + // Decrement the refcount + uint32_t newcnt = info->refcount.fetch_sub(1, std::memory_order_acq_rel); + // Note that fetch_sub() returns the value before we decremented. + // If it is 1, we were the only remaining user; if it is greater there are + // still other users. + if (newcnt > 1) { + return; + } + + // We were the last user. Free the buffer + freeExtBuffer(); + + // Free the SharedInfo if it was allocated separately. + // + // This is only used by takeOwnership(). + // + // To avoid this special case handling in decrementRefcount(), we could have + // takeOwnership() set a custom freeFn() that calls the user's free function + // then frees the SharedInfo object. (This would require that + // takeOwnership() store the user's free function with its allocated + // SharedInfo object.) However, handling this specially with a flag seems + // like it shouldn't be problematic. + if (flags() & flag_free_shared_info) { + delete sharedInfo(); + } +} + +void MemBuf::reserveSlow(std::size_t min_headroom, std::size_t min_tailroom) { + size_t new_capacity = (size_t)length_ + min_headroom + min_tailroom; + + // // reserveSlow() is dangerous if anyone else is sharing the buffer, as we + // may + // // reallocate and free the original buffer. It should only ever be called + // if + // // we are the only user of the buffer. + + // We'll need to reallocate the buffer. + // There are a few options. + // - If we have enough total room, move the data around in the buffer + // and adjust the data_ pointer. + // - If we're using an internal buffer, we'll switch to an external + // buffer with enough headroom and tailroom. + // - If we have enough headroom (headroom() >= min_headroom) but not too much + // (so we don't waste memory), we can try: + // - If we don't have too much to copy, we'll use realloc() (note that + // realloc might have to copy + // headroom + data + tailroom) + // - Otherwise, bite the bullet and reallocate. + if (headroom() + tailroom() >= min_headroom + min_tailroom) { + uint8_t* new_data = writableBuffer() + min_headroom; + std::memmove(new_data, data_, length_); + data_ = new_data; + return; + } + + size_t new_allocated_capacity = 0; + uint8_t* new_buffer = nullptr; + std::size_t new_headroom = 0; + std::size_t old_headroom = headroom(); + + // If we have a buffer allocated with malloc and we just need more tailroom, + // try to use realloc()/xallocx() to grow the buffer in place. + SharedInfo* info = sharedInfo(); + if (info && (info->freeFn == nullptr) && length_ != 0 && + old_headroom >= min_headroom) { + size_t head_slack = old_headroom - min_headroom; + new_allocated_capacity = goodExtBufferSize(new_capacity + head_slack); + + size_t copySlack = capacity() - length_; + if (copySlack * 2 <= length_) { + void* p = realloc(buf_, new_allocated_capacity); + if (TRANSPORT_EXPECT_FALSE(p == nullptr)) { + throw std::bad_alloc(); + } + new_buffer = static_cast(p); + new_headroom = old_headroom; + } + } + + // None of the previous reallocation strategies worked (or we're using + // an internal buffer). malloc/copy/free. + if (new_buffer == nullptr) { + new_allocated_capacity = goodExtBufferSize(new_capacity); + new_buffer = static_cast(malloc(new_allocated_capacity)); + if (length_ > 0) { + assert(data_ != nullptr); + memcpy(new_buffer + min_headroom, data_, length_); + } + if (sharedInfo()) { + freeExtBuffer(); + } + new_headroom = min_headroom; + } + + std::size_t cap; + initExtBuffer(new_buffer, new_allocated_capacity, &info, &cap); + + if (flags() & flag_free_shared_info) { + delete sharedInfo(); + } + + setFlagsAndSharedInfo(0, info); + capacity_ = cap; + buf_ = new_buffer; + data_ = new_buffer + new_headroom; + // length_ is unchanged +} + +void MemBuf::freeExtBuffer() { + SharedInfo* info = sharedInfo(); + + if (info->freeFn) { + try { + info->freeFn(buf_, info->userData); + } catch (...) { + // The user's free function should never throw. Otherwise we might + // throw from the MemBuf destructor. Other code paths like coalesce() + // also assume that decrementRefcount() cannot throw. + abort(); + } + } else { + free(buf_); + } +} + +void MemBuf::allocExtBuffer(std::size_t minCapacity, uint8_t** bufReturn, + SharedInfo** infoReturn, + std::size_t* capacityReturn) { + size_t mallocSize = goodExtBufferSize(minCapacity); + uint8_t* buf = static_cast(malloc(mallocSize)); + initExtBuffer(buf, mallocSize, infoReturn, capacityReturn); + *bufReturn = buf; +} + +size_t MemBuf::goodExtBufferSize(std::size_t minCapacity) { + // Determine how much space we should allocate. We'll store the SharedInfo + // for the external buffer just after the buffer itself. (We store it just + // after the buffer rather than just before so that the code can still just + // use free(buf_) to free the buffer.) + size_t minSize = static_cast(minCapacity) + sizeof(SharedInfo); + // Add room for padding so that the SharedInfo will be aligned on an 8-byte + // boundary. + minSize = (minSize + 7) & ~7; + + // Use goodMallocSize() to bump up the capacity to a decent size to request + // from malloc, so we can use all of the space that malloc will probably give + // us anyway. + return minSize; +} + +void MemBuf::initExtBuffer(uint8_t* buf, size_t mallocSize, + SharedInfo** infoReturn, + std::size_t* capacityReturn) { + // Find the SharedInfo storage at the end of the buffer + // and construct the SharedInfo. + uint8_t* infoStart = (buf + mallocSize) - sizeof(SharedInfo); + SharedInfo* sharedInfo = new (infoStart) SharedInfo; + + *capacityReturn = std::size_t(infoStart - buf); + *infoReturn = sharedInfo; +} + +} // namespace utils \ No newline at end of file diff --git a/libtransport/src/utils/memory_pool_allocator.h b/libtransport/src/utils/memory_pool_allocator.h new file mode 100644 index 000000000..adc1443ad --- /dev/null +++ b/libtransport/src/utils/memory_pool_allocator.h @@ -0,0 +1,152 @@ +/* + * 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.sudo make instamake install + */ + +#pragma once + +#include + +namespace utils { + +template +class MemoryPool { + struct Block { + Block *next; + }; + + class Buffer { + static const std::size_t blockSize = sizeof(T) > sizeof(Block) + ? sizeof(T) + : sizeof(Block); + uint8_t data[blockSize * growSize]; + + public: + Buffer *const next; + + Buffer(Buffer *next) : next(next) {} + + T *getBlock(std::size_t index) { + return reinterpret_cast(&data[blockSize * index]); + } + }; + + Block *firstFreeBlock = nullptr; + Buffer *firstBuffer = nullptr; + std::size_t bufferedBlocks = growSize; + + public: + MemoryPool() = default; + MemoryPool(MemoryPool &&memoryPool) = delete; + MemoryPool(const MemoryPool &memoryPool) = delete; + MemoryPool operator=(MemoryPool &&memoryPool) = delete; + MemoryPool operator=(const MemoryPool &memoryPool) = delete; + + ~MemoryPool() { + while (firstBuffer) { + Buffer *buffer = firstBuffer; + firstBuffer = buffer->next; + delete buffer; + } + } + + T *allocate() { + if (firstFreeBlock) { + Block *block = firstFreeBlock; + firstFreeBlock = block->next; + return reinterpret_cast(block); + } + + if (bufferedBlocks >= growSize) { + firstBuffer = new Buffer(firstBuffer); + bufferedBlocks = 0; + } + + return firstBuffer->getBlock(bufferedBlocks++); + } + + void deallocate(T *pointer) { + Block *block = reinterpret_cast(pointer); + block->next = firstFreeBlock; + firstFreeBlock = block; + } +}; + +template +class Allocator : private MemoryPool { +#ifdef _WIN32 + Allocator *copyAllocator; + std::allocator *rebindAllocator = nullptr; +#endif + + public: + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef T *pointer; + typedef const T *const_pointer; + typedef T &reference; + typedef const T &const_reference; + typedef T value_type; + + template + struct rebind { + typedef Allocator other; + }; + +#ifdef _WIN32 + Allocator() = default; + + Allocator(Allocator &allocator) : copyAllocator(&allocator) {} + + template + Allocator(const Allocator &other) { + if (!std::is_same::value) rebindAllocator = new std::allocator(); + } + + ~Allocator() { delete rebindAllocator; } +#endif + + pointer allocate(size_type n, const void *hint = 0) { +#ifdef _WIN32 + if (copyAllocator) return copyAllocator->allocate(n, hint); + + if (rebindAllocator) return rebindAllocator->allocate(n, hint); +#endif + + if (n != 1 || hint) throw std::bad_alloc(); + + return MemoryPool::allocate(); + } + + void deallocate(pointer p, size_type n) { +#ifdef _WIN32 + if (copyAllocator) { + copyAllocator->deallocate(p, n); + return; + } + + if (rebindAllocator) { + rebindAllocator->deallocate(p, n); + return; + } +#endif + + MemoryPool::deallocate(p); + } + + void construct(pointer p, const_reference val) { new (p) T(val); } + + void destroy(pointer p) { p->~T(); } +}; + +} \ No newline at end of file diff --git a/libtransport/src/utils/min_filter.h b/libtransport/src/utils/min_filter.h new file mode 100644 index 000000000..dcfd5652d --- /dev/null +++ b/libtransport/src/utils/min_filter.h @@ -0,0 +1,56 @@ +/* + * 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.sudo make instamake install + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include + +namespace utils { + +template +class MinFilter { + public: + MinFilter(std::size_t size) : size_(size) {} + + std::size_t size() { return by_arrival_.size(); } + + template + TRANSPORT_ALWAYS_INLINE void pushBack(R&& value) { + if (by_arrival_.size() >= size_) { + by_order_.erase(by_arrival_.back()); + by_arrival_.pop_back(); + } + + by_arrival_.push_front(by_order_.insert(std::forward(value))); + } + + TRANSPORT_ALWAYS_INLINE const T& begin() { return *by_order_.cbegin(); } + + TRANSPORT_ALWAYS_INLINE const T& rBegin() { return *by_order_.crbegin(); } + + private: + std::multiset by_order_; + std::deque::const_iterator> by_arrival_; + std::size_t size_; +}; + +} // namespace utils diff --git a/libtransport/src/utils/stream_buffer.h b/libtransport/src/utils/stream_buffer.h new file mode 100644 index 000000000..adfb696f2 --- /dev/null +++ b/libtransport/src/utils/stream_buffer.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace utils { + +template +struct ostreambuf + : public std::basic_streambuf > { + ostreambuf(char_type* buffer, std::streamsize buffer_length) { + // set the "put" pointer the start of the buffer and record it's length. + setp(buffer, buffer + buffer_length); + } +}; + +} // namespace utils \ No newline at end of file diff --git a/libtransport/src/utils/string_tokenizer.cc b/libtransport/src/utils/string_tokenizer.cc new file mode 100644 index 000000000..a280a3c43 --- /dev/null +++ b/libtransport/src/utils/string_tokenizer.cc @@ -0,0 +1,47 @@ +/* + * 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. + */ + +#include +#include + +namespace utils { + +StringTokenizer::StringTokenizer(const std::string &str) + : str_(str), delimiter_(" ") {} + +StringTokenizer::StringTokenizer(const std::string &str, + const std::string &delim) + : str_(str), delimiter_(delim) {} + +bool StringTokenizer::hasMoreTokens() { + return str_.find(delimiter_) != std::string::npos || !str_.empty(); +} + +std::string StringTokenizer::nextToken() { + unsigned long pos = (unsigned long)str_.find(delimiter_); + + bool token_found = std::string::npos != pos; + + if (!token_found && str_.empty()) { + throw errors::TokenizerException(); + } + + std::string token = str_.substr(0, pos); + str_.erase(0, token_found ? pos + delimiter_.length() : pos); + + return token; +} + +} // namespace utils \ No newline at end of file diff --git a/libtransport/src/utils/suffix_strategy.h b/libtransport/src/utils/suffix_strategy.h new file mode 100644 index 000000000..6c4dd2785 --- /dev/null +++ b/libtransport/src/utils/suffix_strategy.h @@ -0,0 +1,165 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace utils { + +using transport::core::NextSegmentCalculationStrategy; + +class SuffixStrategy { + public: + static constexpr uint32_t INVALID_SUFFIX = + std::numeric_limits::max(); + + SuffixStrategy(NextSegmentCalculationStrategy strategy) + : suffix_stragegy_(strategy), + total_count_(0), + final_suffix_(INVALID_SUFFIX) {} + + virtual ~SuffixStrategy() = default; + + virtual uint32_t getNextSuffix() = 0; + + virtual uint32_t getFinalSuffix() { return final_suffix_; } + + virtual void setFinalSuffix(std::uint32_t final_suffix) { + if (final_suffix != INVALID_SUFFIX) { + final_suffix_ = final_suffix; + } + } + + virtual uint32_t getNextManifestSuffix() = 0; + + virtual uint32_t getNextContentSuffix() = 0; + + virtual void reset(uint32_t offset = 0) = 0; + + virtual uint32_t getManifestCapacity() = 0; + + virtual void setManifestCapacity(uint32_t capacity) = 0; + + virtual uint32_t getTotalCount() { return total_count_; }; + + NextSegmentCalculationStrategy getSuffixStrategy() { + return suffix_stragegy_; + } + + protected: + inline void incrementTotalCount() { total_count_++; }; + + protected: + NextSegmentCalculationStrategy suffix_stragegy_; + std::uint32_t total_count_; + std::uint32_t final_suffix_; +}; + +class IncrementalSuffixStrategy : public SuffixStrategy { + public: + IncrementalSuffixStrategy(std::uint32_t start_offset) + : SuffixStrategy(NextSegmentCalculationStrategy::INCREMENTAL), + next_suffix_(start_offset) {} + + TRANSPORT_ALWAYS_INLINE std::uint32_t getNextSuffix() override { + incrementTotalCount(); + return next_suffix_++; + } + + TRANSPORT_ALWAYS_INLINE std::uint32_t getNextContentSuffix() override { + return getNextSuffix(); + } + + TRANSPORT_ALWAYS_INLINE std::uint32_t getNextManifestSuffix() override { + return getNextSuffix(); + } + + uint32_t getManifestCapacity() override { + throw errors::RuntimeException( + "No manifest capacity in IncrementalSuffixStrategy."); + } + + void setManifestCapacity(uint32_t capacity) override { + throw errors::RuntimeException( + "No manifest capacity in IncrementalSuffixStrategy."); + } + + void reset(std::uint32_t offset = 0) override { next_suffix_ = offset; } + + protected: + std::uint32_t next_suffix_; +}; + +class CapacityBasedSuffixStrategy : public SuffixStrategy { + public: + CapacityBasedSuffixStrategy(std::uint32_t start_offset, + std::uint32_t manifest_capacity) + : SuffixStrategy(NextSegmentCalculationStrategy::INCREMENTAL), + next_suffix_(start_offset), + segments_in_manifest_(manifest_capacity), + current_manifest_iteration_(0) {} + + TRANSPORT_ALWAYS_INLINE std::uint32_t getNextSuffix() override { + incrementTotalCount(); + return next_suffix_++; + } + + TRANSPORT_ALWAYS_INLINE std::uint32_t getNextContentSuffix() override { + incrementTotalCount(); + return next_suffix_ % segments_in_manifest_ == 0 ? next_suffix_++ + : ++next_suffix_; + } + + TRANSPORT_ALWAYS_INLINE std::uint32_t getNextManifestSuffix() override { + incrementTotalCount(); + return (current_manifest_iteration_++) * (segments_in_manifest_ + 1); + } + + TRANSPORT_ALWAYS_INLINE uint32_t getManifestCapacity() override { + return segments_in_manifest_; + } + + TRANSPORT_ALWAYS_INLINE void setManifestCapacity(uint32_t capacity) override { + segments_in_manifest_ = capacity; + } + + void reset(std::uint32_t offset = 0) override { next_suffix_ = offset; } + + protected: + std::uint32_t next_suffix_; + std::uint32_t segments_in_manifest_; + std::uint32_t current_manifest_iteration_; +}; + +class SuffixStrategyFactory { + public: + static std::unique_ptr getSuffixStrategy( + NextSegmentCalculationStrategy strategy, uint32_t start_offset, + uint32_t manifest_capacity = 0) { + switch (strategy) { + case NextSegmentCalculationStrategy::INCREMENTAL: + return std::make_unique(start_offset); + case NextSegmentCalculationStrategy::MANIFEST_CAPACITY_BASED: + return std::make_unique(start_offset, + manifest_capacity); + default: + throw errors::RuntimeException( + "No valid NextSegmentCalculationStrategy specified."); + } + } +}; + +} // namespace utils diff --git a/libtransport/src/utils/test.h b/libtransport/src/utils/test.h new file mode 100644 index 000000000..e3dd619ac --- /dev/null +++ b/libtransport/src/utils/test.h @@ -0,0 +1,46 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace testing { + +namespace internal { + +enum GTestColor { COLOR_DEFAULT, COLOR_RED, COLOR_GREEN, COLOR_YELLOW }; + +extern void ColoredPrintf(GTestColor color, const char *fmt, ...); + +} // namespace internal + +} // namespace testing + +#define PRINTF(...) \ + do { \ + testing::internal::ColoredPrintf(testing::internal::COLOR_GREEN, \ + "[ ] "); \ + testing::internal::ColoredPrintf(testing::internal::COLOR_YELLOW, \ + __VA_ARGS__); \ + } while (0) + +// C++ stream interface +class TestCout : public std::stringstream { + public: + ~TestCout() {} +}; + +#define TEST_COUT TestCout() \ No newline at end of file diff --git a/libtransport/src/utils/uri.cc b/libtransport/src/utils/uri.cc new file mode 100644 index 000000000..33eb8b45b --- /dev/null +++ b/libtransport/src/utils/uri.cc @@ -0,0 +1,122 @@ +/* + * 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. + */ + +#include +#include + +namespace utils { + +Uri::Uri() {} + +Uri &Uri::parse(const std::string &uri) { + if (uri.length() == 0) { + throw errors::RuntimeException("Malformed URI."); + } + + iterator_t uri_end = uri.end(); + + // get query start + iterator_t query_start = std::find(uri.begin(), uri_end, '?'); + + // protocol + iterator_t protocol_start = uri.begin(); + iterator_t protocol_end = std::find(protocol_start, uri_end, ':'); //"://"); + + if (protocol_end != uri_end) { + std::string prot = &*(protocol_end); + if ((prot.length() > 3) && (prot.substr(0, 3) == "://")) { + protocol_ = std::string(protocol_start, protocol_end); + protocol_end += 3; // :// + } else { + protocol_end = uri.begin(); // no protocol + } + } else { + protocol_end = uri.begin(); // no protocol + } + // host + iterator_t host_start = protocol_end; + iterator_t path_start = + std::find(host_start, uri_end, '/'); // get path_start + + iterator_t host_end = std::find( + protocol_end, (path_start != uri_end) ? path_start : query_start, + ':'); // check for port + + locator_ = std::string(host_start, host_end); + + // port + if ((host_end != uri_end) && ((&*(host_end))[0] == ':')) { + host_end++; + iterator_t port_end = (path_start != uri_end) ? path_start : query_start; + port_ = std::string(host_end, port_end); + } + + // path + if (path_start != uri_end) { + path_ = std::string(path_start, query_start); + } + // query + if (query_start != uri_end) { + query_string_ = std::string(query_start, uri.end()); + } + + return *this; +} + +Uri &Uri::parseProtocolAndLocator(const std::string &locator) { + iterator_t total_end = locator.end(); + + // protocol + iterator_t protocol_start = locator.begin(); + iterator_t protocol_end = + std::find(protocol_start, total_end, ':'); //"://"); + + if (protocol_end != total_end) { + std::string prot = &*(protocol_end); + if ((prot.length() > 3) && (prot.substr(0, 3) == "://")) { + protocol_ = std::string(protocol_start, protocol_end); + protocol_end += 3; // :// + } else { + throw errors::RuntimeException("Malformed locator. (Missing \"://\")"); + } + } else { + throw errors::RuntimeException("Malformed locator. No protocol specified."); + } + + // locator + iterator_t host_start = protocol_end; + iterator_t host_end = std::find(protocol_end, total_end, '/'); + + if (host_start == host_end) { + throw errors::RuntimeException( + "Malformed locator. Locator name is missing"); + } + + locator_ = std::string(host_start, host_end); + + return *this; +} + +std::string Uri::getLocator() { return locator_; } + +std::string Uri::getPath() { return path_; } + +std::string Uri::getPort() { return port_; } + +std::string Uri::getProtocol() { return protocol_; } + +std::string Uri::getQueryString() { return query_string_; } + +} // end namespace utils diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt index f52fec6c0..3e99fbae2 100644 --- a/utils/CMakeLists.txt +++ b/utils/CMakeLists.txt @@ -65,6 +65,7 @@ if (NOT DISABLE_EXECUTABLES) build_executable(hiperf SOURCES src/hiperf.cc LINK_LIBRARIES ${LIBTRANSPORT_LIBRARIES} ${WSOCK32_LIBRARY} ${WS2_32_LIBRARY} + INCLUDE_DIRS ${LIBTRANSPORT_INCLUDE_DIRS} DEPENDS ${DEPENDENCIES} COMPONENT ${HICN_UTILS} DEFINITIONS ${COMPILER_DEFINITIONS} @@ -74,6 +75,7 @@ if (NOT DISABLE_EXECUTABLES) build_executable(hicn-ping-server SOURCES src/ping_server.cc LINK_LIBRARIES ${LIBTRANSPORT_LIBRARIES} ${WSOCK32_LIBRARY} ${WS2_32_LIBRARY} + INCLUDE_DIRS ${LIBTRANSPORT_INCLUDE_DIRS} DEPENDS ${DEPENDENCIES} COMPONENT ${HICN_UTILS} DEFINITIONS ${COMPILER_DEFINITIONS} @@ -83,6 +85,7 @@ if (NOT DISABLE_EXECUTABLES) build_executable(hicn-ping-client SOURCES src/ping_client.cc LINK_LIBRARIES ${LIBTRANSPORT_LIBRARIES} ${WSOCK32_LIBRARY} ${WS2_32_LIBRARY} + INCLUDE_DIRS ${LIBTRANSPORT_INCLUDE_DIRS} DEPENDS ${DEPENDENCIES} COMPONENT ${HICN_UTILS} DEFINITIONS ${COMPILER_DEFINITIONS} diff --git a/utils/src/hiperf.cc b/utils/src/hiperf.cc index dd6ed0840..15bcb7405 100644 --- a/utils/src/hiperf.cc +++ b/utils/src/hiperf.cc @@ -14,12 +14,15 @@ */ #include +#include +#include #include #include #include +#include +#include #include -#include -#include +#include #ifdef SECURE_HICNTRANSPORT #include @@ -29,8 +32,9 @@ #ifndef _WIN32 #include #endif -#include +#include +#include #include #include #include @@ -294,7 +298,7 @@ class HIperfClient { void processLeavingInterest(ConsumerSocket &c, const Interest &interest) {} void handleTimerExpiration(ConsumerSocket &c, - const protocol::TransportStatistics &stats) { + const TransportStatistics &stats) { if (configuration_.rtc_) return; const char separator = ' '; @@ -642,9 +646,10 @@ class HIperfClient { void readSuccess(std::size_t total_size) noexcept override { std::cout << "Key size: " << total_size << " bytes" << std::endl; + afterRead(); } - void afterRead() override { + void afterRead() { std::shared_ptr verifier = std::make_shared(); verifier->addKeyFromPassphrase(*key_, utils::CryptoSuite::HMAC_SHA256); @@ -1355,9 +1360,6 @@ int main(int argc, char *argv[]) { 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; diff --git a/utils/src/ping_client.cc b/utils/src/ping_client.cc index cdf786cba..6dea17418 100644 --- a/utils/src/ping_client.cc +++ b/utils/src/ping_client.cc @@ -13,8 +13,10 @@ * limitations under the License. */ -#include -#include +#include +#include + +#include // Let's make the linker happy #if !TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL @@ -81,7 +83,7 @@ class Configuration { } }; -class Client : interface::BasePortal::ConsumerCallback { +class Client : implementation::BasePortal::ConsumerCallback { public: Client(Configuration *c) : portal_(), signals_(portal_.getIoService(), SIGINT) { @@ -296,7 +298,7 @@ class Client : interface::BasePortal::ConsumerCallback { private: SendTimeMap send_timestamps_; - interface::BasePortal portal_; + implementation::BasePortal portal_; asio::signal_set signals_; uint64_t sequence_number_; uint64_t last_jump_; diff --git a/utils/src/ping_server.cc b/utils/src/ping_server.cc index cd51ce5c3..d766e2811 100644 --- a/utils/src/ping_server.cc +++ b/utils/src/ping_server.cc @@ -19,10 +19,16 @@ #else #include #endif -#include -#include + +#include +#include +#include +#include #include +#include +#include + namespace transport { namespace interface { @@ -81,7 +87,8 @@ class CallbackContainer { } } - void processInterest(ProducerSocket &p, const Interest &interest, uint32_t lifetime) { + void processInterest(ProducerSocket &p, const Interest &interest, + uint32_t lifetime) { if (verbose_) { std::cout << "<<< received interest " << interest.getName() << " src port: " << interest.getSrcPort() @@ -230,8 +237,8 @@ int main(int argc, char **argv) { ttl = (uint8_t)std::stoi(optarg); break; case 'l': - data_lifetime = std::stoi(optarg); - break; + data_lifetime = std::stoi(optarg); + break; case 'V': verbose = true; break; @@ -299,10 +306,11 @@ int main(int argc, char **argv) { p.registerPrefix(producer_namespace); p.setSocketOption(GeneralTransportOptions::OUTPUT_BUFFER_SIZE, 0U); - p.setSocketOption(ProducerCallbacksOptions::CACHE_MISS, - (ProducerInterestCallback)bind( - &CallbackContainer::processInterest, stubs, - std::placeholders::_1, std::placeholders::_2, data_lifetime)); + p.setSocketOption( + ProducerCallbacksOptions::CACHE_MISS, + (ProducerInterestCallback)bind(&CallbackContainer::processInterest, stubs, + std::placeholders::_1, + std::placeholders::_2, data_lifetime)); p.connect(); -- cgit 1.2.3-korg