summaryrefslogtreecommitdiffstats
path: root/libtransport
diff options
context:
space:
mode:
Diffstat (limited to 'libtransport')
-rw-r--r--libtransport/.clang-format2
-rw-r--r--libtransport/CMakeLists.txt96
-rw-r--r--libtransport/cmake/Modules/Android.cmake19
-rw-r--r--libtransport/cmake/Modules/DefaultConfiguration.cmake30
-rw-r--r--libtransport/cmake/Modules/Ios.cmake20
-rw-r--r--libtransport/cmake/Modules/TestMacros.cmake15
-rw-r--r--libtransport/cmake/packaging.cmake (renamed from libtransport/cmake/Modules/Packaging.cmake)34
-rw-r--r--libtransport/includes/hicn/transport/CMakeLists.txt19
-rw-r--r--libtransport/includes/hicn/transport/auth/CMakeLists.txt3
-rw-r--r--libtransport/includes/hicn/transport/auth/common.h2
-rw-r--r--libtransport/includes/hicn/transport/auth/crypto_hash.h4
-rw-r--r--libtransport/includes/hicn/transport/auth/crypto_suite.h5
-rw-r--r--libtransport/includes/hicn/transport/auth/identity.h77
-rw-r--r--libtransport/includes/hicn/transport/auth/key_id.h2
-rw-r--r--libtransport/includes/hicn/transport/auth/policies.h4
-rw-r--r--libtransport/includes/hicn/transport/auth/signer.h22
-rw-r--r--libtransport/includes/hicn/transport/auth/verifier.h14
-rw-r--r--libtransport/includes/hicn/transport/core/CMakeLists.txt2
-rw-r--r--libtransport/includes/hicn/transport/core/connector.h24
-rw-r--r--libtransport/includes/hicn/transport/core/content_object.h21
-rw-r--r--libtransport/includes/hicn/transport/core/endpoint.h14
-rw-r--r--libtransport/includes/hicn/transport/core/global_object_pool.h14
-rw-r--r--libtransport/includes/hicn/transport/core/interest.h19
-rw-r--r--libtransport/includes/hicn/transport/core/io_module.h11
-rw-r--r--libtransport/includes/hicn/transport/core/name.h11
-rw-r--r--libtransport/includes/hicn/transport/core/packet.h218
-rw-r--r--libtransport/includes/hicn/transport/core/payload_type.h2
-rw-r--r--libtransport/includes/hicn/transport/core/prefix.h6
-rw-r--r--libtransport/includes/hicn/transport/errors/CMakeLists.txt2
-rw-r--r--libtransport/includes/hicn/transport/errors/errors.h2
-rw-r--r--libtransport/includes/hicn/transport/errors/indexing_exception.h2
-rw-r--r--libtransport/includes/hicn/transport/errors/invalid_ip_address_exception.h2
-rw-r--r--libtransport/includes/hicn/transport/errors/malformed_ahpacket_exception.h2
-rw-r--r--libtransport/includes/hicn/transport/errors/malformed_name_exception.h2
-rw-r--r--libtransport/includes/hicn/transport/errors/malformed_packet_exception.h2
-rw-r--r--libtransport/includes/hicn/transport/errors/not_implemented_exception.h2
-rw-r--r--libtransport/includes/hicn/transport/errors/null_pointer_exception.h2
-rw-r--r--libtransport/includes/hicn/transport/errors/runtime_exception.h2
-rw-r--r--libtransport/includes/hicn/transport/errors/tokenizer_exception.h2
-rw-r--r--libtransport/includes/hicn/transport/errors/unexpected_manifest_exception.h2
-rw-r--r--libtransport/includes/hicn/transport/http/CMakeLists.txt2
-rw-r--r--libtransport/includes/hicn/transport/http/client_connection.h6
-rw-r--r--libtransport/includes/hicn/transport/http/default_values.h2
-rw-r--r--libtransport/includes/hicn/transport/http/facade.h2
-rw-r--r--libtransport/includes/hicn/transport/http/message.h2
-rw-r--r--libtransport/includes/hicn/transport/http/request.h2
-rw-r--r--libtransport/includes/hicn/transport/http/response.h2
-rw-r--r--libtransport/includes/hicn/transport/interfaces/CMakeLists.txt3
-rw-r--r--libtransport/includes/hicn/transport/interfaces/callbacks.h9
-rw-r--r--libtransport/includes/hicn/transport/interfaces/notification.h (renamed from libtransport/src/protocols/fec_base.cc)19
-rw-r--r--libtransport/includes/hicn/transport/interfaces/p2psecure_socket_consumer.h2
-rw-r--r--libtransport/includes/hicn/transport/interfaces/p2psecure_socket_producer.h7
-rw-r--r--libtransport/includes/hicn/transport/interfaces/portal.h106
-rw-r--r--libtransport/includes/hicn/transport/interfaces/publication_options.h2
-rw-r--r--libtransport/includes/hicn/transport/interfaces/socket_consumer.h33
-rw-r--r--libtransport/includes/hicn/transport/interfaces/socket_options_default_values.h17
-rw-r--r--libtransport/includes/hicn/transport/interfaces/socket_options_keys.h44
-rw-r--r--libtransport/includes/hicn/transport/interfaces/socket_producer.h43
-rw-r--r--libtransport/includes/hicn/transport/interfaces/statistics.h62
-rw-r--r--libtransport/includes/hicn/transport/portability/CMakeLists.txt3
-rw-r--r--libtransport/includes/hicn/transport/portability/c_portability.h2
-rw-r--r--libtransport/includes/hicn/transport/portability/cpu.h40
-rw-r--r--libtransport/includes/hicn/transport/portability/portability.h5
-rw-r--r--libtransport/includes/hicn/transport/portability/win_portability.h86
-rw-r--r--libtransport/includes/hicn/transport/utils/CMakeLists.txt3
-rw-r--r--libtransport/includes/hicn/transport/utils/array.h2
-rw-r--r--libtransport/includes/hicn/transport/utils/branch_prediction.h2
-rw-r--r--libtransport/includes/hicn/transport/utils/chrono_typedefs.h101
-rw-r--r--libtransport/includes/hicn/transport/utils/conversions.h2
-rw-r--r--libtransport/includes/hicn/transport/utils/daemonizator.h2
-rw-r--r--libtransport/includes/hicn/transport/utils/event_thread.h15
-rw-r--r--libtransport/includes/hicn/transport/utils/fixed_block_allocator.h57
-rw-r--r--libtransport/includes/hicn/transport/utils/hash.h2
-rw-r--r--libtransport/includes/hicn/transport/utils/linux.h2
-rw-r--r--libtransport/includes/hicn/transport/utils/literals.h2
-rw-r--r--libtransport/includes/hicn/transport/utils/log.h2
-rw-r--r--libtransport/includes/hicn/transport/utils/move_wrapper.h1
-rw-r--r--libtransport/includes/hicn/transport/utils/noncopyable.h2
-rw-r--r--libtransport/includes/hicn/transport/utils/object_pool.h21
-rw-r--r--libtransport/includes/hicn/transport/utils/ring_buffer.h2
-rw-r--r--libtransport/includes/hicn/transport/utils/rtc_quality_score.h69
-rw-r--r--libtransport/includes/hicn/transport/utils/singleton.h15
-rw-r--r--libtransport/includes/hicn/transport/utils/spinlock.h2
-rw-r--r--libtransport/includes/hicn/transport/utils/string_tokenizer.h2
-rw-r--r--libtransport/includes/hicn/transport/utils/string_utils.h2
-rw-r--r--libtransport/includes/hicn/transport/utils/thread_pool.h39
-rw-r--r--libtransport/includes/hicn/transport/utils/uri.h2
-rw-r--r--libtransport/src/CMakeLists.txt166
-rw-r--r--libtransport/src/auth/CMakeLists.txt3
-rw-r--r--libtransport/src/auth/crypto_hash.cc46
-rw-r--r--libtransport/src/auth/crypto_suite.cc50
-rw-r--r--libtransport/src/auth/identity.cc288
-rw-r--r--libtransport/src/auth/signer.cc113
-rw-r--r--libtransport/src/auth/verifier.cc101
-rw-r--r--libtransport/src/config.h.in5
-rw-r--r--libtransport/src/core/CMakeLists.txt19
-rw-r--r--libtransport/src/core/content_object.cc39
-rw-r--r--libtransport/src/core/errors.cc11
-rw-r--r--libtransport/src/core/errors.h7
-rw-r--r--libtransport/src/core/facade.h2
-rw-r--r--libtransport/src/core/global_workers.h43
-rw-r--r--libtransport/src/core/interest.cc19
-rw-r--r--libtransport/src/core/io_module.cc9
-rw-r--r--libtransport/src/core/local_connector.cc12
-rw-r--r--libtransport/src/core/local_connector.h4
-rw-r--r--libtransport/src/core/manifest.cc2
-rw-r--r--libtransport/src/core/manifest.h74
-rw-r--r--libtransport/src/core/manifest_format.h108
-rw-r--r--libtransport/src/core/manifest_format_fixed.cc318
-rw-r--r--libtransport/src/core/manifest_format_fixed.h228
-rw-r--r--libtransport/src/core/manifest_inline.h42
-rw-r--r--libtransport/src/core/memif_connector.cc497
-rw-r--r--libtransport/src/core/memif_connector.h (renamed from libtransport/src/io_modules/memif/memif_connector.h)72
-rw-r--r--libtransport/src/core/name.cc60
-rw-r--r--libtransport/src/core/packet.cc618
-rw-r--r--libtransport/src/core/pending_interest.cc74
-rw-r--r--libtransport/src/core/pending_interest.h26
-rw-r--r--libtransport/src/core/portal.cc10
-rw-r--r--libtransport/src/core/portal.h550
-rw-r--r--libtransport/src/core/prefix.cc14
-rw-r--r--libtransport/src/core/tcp_socket_connector.cc16
-rw-r--r--libtransport/src/core/tcp_socket_connector.h2
-rw-r--r--libtransport/src/core/udp_connector.cc371
-rw-r--r--libtransport/src/core/udp_connector.h (renamed from libtransport/src/io_modules/forwarder/udp_tunnel.h)39
-rw-r--r--libtransport/src/core/udp_listener.cc (renamed from libtransport/src/io_modules/forwarder/udp_tunnel_listener.cc)20
-rw-r--r--libtransport/src/core/udp_listener.h (renamed from libtransport/src/io_modules/forwarder/udp_tunnel_listener.h)8
-rw-r--r--libtransport/src/http/CMakeLists.txt2
-rw-r--r--libtransport/src/http/client_connection.cc26
-rw-r--r--libtransport/src/http/request.cc2
-rw-r--r--libtransport/src/http/response.cc2
-rw-r--r--libtransport/src/implementation/CMakeLists.txt2
-rw-r--r--libtransport/src/implementation/p2psecure_socket_consumer.cc36
-rw-r--r--libtransport/src/implementation/p2psecure_socket_consumer.h6
-rw-r--r--libtransport/src/implementation/p2psecure_socket_producer.cc71
-rw-r--r--libtransport/src/implementation/p2psecure_socket_producer.h13
-rw-r--r--libtransport/src/implementation/socket.cc31
-rw-r--r--libtransport/src/implementation/socket.h24
-rw-r--r--libtransport/src/implementation/socket_consumer.h178
-rw-r--r--libtransport/src/implementation/socket_producer.h207
-rw-r--r--libtransport/src/implementation/tls_rtc_socket_producer.cc6
-rw-r--r--libtransport/src/implementation/tls_rtc_socket_producer.h2
-rw-r--r--libtransport/src/implementation/tls_socket_consumer.cc31
-rw-r--r--libtransport/src/implementation/tls_socket_consumer.h7
-rw-r--r--libtransport/src/implementation/tls_socket_producer.cc11
-rw-r--r--libtransport/src/implementation/tls_socket_producer.h2
-rw-r--r--libtransport/src/interfaces/CMakeLists.txt2
-rw-r--r--libtransport/src/interfaces/callbacks.cc2
-rw-r--r--libtransport/src/interfaces/p2psecure_socket_consumer.cc2
-rw-r--r--libtransport/src/interfaces/p2psecure_socket_producer.cc11
-rw-r--r--libtransport/src/interfaces/portal.cc115
-rw-r--r--libtransport/src/interfaces/socket_consumer.cc43
-rw-r--r--libtransport/src/interfaces/socket_producer.cc44
-rw-r--r--libtransport/src/interfaces/tls_rtc_socket_producer.cc2
-rw-r--r--libtransport/src/interfaces/tls_rtc_socket_producer.h2
-rw-r--r--libtransport/src/interfaces/tls_socket_consumer.cc2
-rw-r--r--libtransport/src/interfaces/tls_socket_consumer.h2
-rw-r--r--libtransport/src/interfaces/tls_socket_producer.cc2
-rw-r--r--libtransport/src/interfaces/tls_socket_producer.h2
-rw-r--r--libtransport/src/io_modules/CMakeLists.txt58
-rw-r--r--libtransport/src/io_modules/forwarder/CMakeLists.txt11
-rw-r--r--libtransport/src/io_modules/forwarder/errors.cc2
-rw-r--r--libtransport/src/io_modules/forwarder/forwarder.cc64
-rw-r--r--libtransport/src/io_modules/forwarder/forwarder.h29
-rw-r--r--libtransport/src/io_modules/forwarder/forwarder_module.cc19
-rw-r--r--libtransport/src/io_modules/forwarder/forwarder_module.h9
-rw-r--r--libtransport/src/io_modules/forwarder/udp_tunnel.cc290
-rw-r--r--libtransport/src/io_modules/hicn-light-ng/CMakeLists.txt62
-rw-r--r--libtransport/src/io_modules/hicn-light-ng/hicn_forwarder_module.cc264
-rw-r--r--libtransport/src/io_modules/hicn-light-ng/hicn_forwarder_module.h (renamed from libtransport/src/io_modules/udp/hicn_forwarder_module.h)34
-rw-r--r--libtransport/src/io_modules/loopback/CMakeLists.txt8
-rw-r--r--libtransport/src/io_modules/loopback/local_face.cc2
-rw-r--r--libtransport/src/io_modules/loopback/local_face.h2
-rw-r--r--libtransport/src/io_modules/loopback/loopback_module.cc14
-rw-r--r--libtransport/src/io_modules/loopback/loopback_module.h7
-rw-r--r--libtransport/src/io_modules/memif/CMakeLists.txt38
-rw-r--r--libtransport/src/io_modules/memif/hicn_vapi.c15
-rw-r--r--libtransport/src/io_modules/memif/hicn_vapi.h2
-rw-r--r--libtransport/src/io_modules/memif/memif_connector.cc492
-rw-r--r--libtransport/src/io_modules/memif/memif_vapi.c7
-rw-r--r--libtransport/src/io_modules/memif/memif_vapi.h6
-rw-r--r--libtransport/src/io_modules/memif/vpp_forwarder_module.cc35
-rw-r--r--libtransport/src/io_modules/memif/vpp_forwarder_module.h12
-rw-r--r--libtransport/src/io_modules/raw_socket/raw_socket_connector.cc200
-rw-r--r--libtransport/src/io_modules/raw_socket/raw_socket_connector.h79
-rw-r--r--libtransport/src/io_modules/raw_socket/raw_socket_interface.cc56
-rw-r--r--libtransport/src/io_modules/raw_socket/raw_socket_interface.h61
-rw-r--r--libtransport/src/io_modules/udp/CMakeLists.txt32
-rw-r--r--libtransport/src/io_modules/udp/hicn_forwarder_module.cc181
-rw-r--r--libtransport/src/io_modules/udp/udp_socket_connector.cc211
-rw-r--r--libtransport/src/io_modules/udp/udp_socket_connector.h88
-rw-r--r--libtransport/src/libhicntransport-config.cmake.in8
-rw-r--r--libtransport/src/protocols/CMakeLists.txt16
-rw-r--r--libtransport/src/protocols/byte_stream_reassembly.cc2
-rw-r--r--libtransport/src/protocols/byte_stream_reassembly.h2
-rw-r--r--libtransport/src/protocols/cbr.cc10
-rw-r--r--libtransport/src/protocols/cbr.h2
-rw-r--r--libtransport/src/protocols/congestion_window_protocol.h2
-rw-r--r--libtransport/src/protocols/data_processing_events.h2
-rw-r--r--libtransport/src/protocols/datagram_reassembly.cc2
-rw-r--r--libtransport/src/protocols/datagram_reassembly.h2
-rw-r--r--libtransport/src/protocols/errors.cc2
-rw-r--r--libtransport/src/protocols/errors.h2
-rw-r--r--libtransport/src/protocols/fec/CMakeLists.txt2
-rw-r--r--libtransport/src/protocols/fec/fec.cc176
-rw-r--r--libtransport/src/protocols/fec/rely.cc103
-rw-r--r--libtransport/src/protocols/fec/rely.h61
-rw-r--r--libtransport/src/protocols/fec/rs.cc161
-rw-r--r--libtransport/src/protocols/fec/rs.h101
-rw-r--r--libtransport/src/protocols/fec_base.h82
-rw-r--r--libtransport/src/protocols/incremental_indexer_bytestream.cc6
-rw-r--r--libtransport/src/protocols/incremental_indexer_bytestream.h10
-rw-r--r--libtransport/src/protocols/index_manager_bytestream.cc2
-rw-r--r--libtransport/src/protocols/index_manager_bytestream.h18
-rw-r--r--libtransport/src/protocols/indexer.cc35
-rw-r--r--libtransport/src/protocols/indexer.h26
-rw-r--r--libtransport/src/protocols/manifest_incremental_indexer_bytestream.cc59
-rw-r--r--libtransport/src/protocols/manifest_incremental_indexer_bytestream.h12
-rw-r--r--libtransport/src/protocols/prod_protocol_bytestream.cc231
-rw-r--r--libtransport/src/protocols/prod_protocol_bytestream.h11
-rw-r--r--libtransport/src/protocols/prod_protocol_rtc.cc553
-rw-r--r--libtransport/src/protocols/prod_protocol_rtc.h58
-rw-r--r--libtransport/src/protocols/production_protocol.cc141
-rw-r--r--libtransport/src/protocols/production_protocol.h34
-rw-r--r--libtransport/src/protocols/protocol.h73
-rw-r--r--libtransport/src/protocols/raaqm.cc33
-rw-r--r--libtransport/src/protocols/raaqm.h19
-rw-r--r--libtransport/src/protocols/raaqm_data_path.cc31
-rw-r--r--libtransport/src/protocols/raaqm_data_path.h16
-rw-r--r--libtransport/src/protocols/rate_estimation.cc101
-rw-r--r--libtransport/src/protocols/rate_estimation.h21
-rw-r--r--libtransport/src/protocols/reassembly.cc2
-rw-r--r--libtransport/src/protocols/reassembly.h8
-rw-r--r--libtransport/src/protocols/rtc/CMakeLists.txt23
-rw-r--r--libtransport/src/protocols/rtc/probe_handler.cc38
-rw-r--r--libtransport/src/protocols/rtc/probe_handler.h32
-rw-r--r--libtransport/src/protocols/rtc/rtc.cc616
-rw-r--r--libtransport/src/protocols/rtc/rtc.h24
-rw-r--r--libtransport/src/protocols/rtc/rtc_consts.h47
-rw-r--r--libtransport/src/protocols/rtc/rtc_data_path.cc99
-rw-r--r--libtransport/src/protocols/rtc/rtc_data_path.h26
-rw-r--r--libtransport/src/protocols/rtc/rtc_forwarding_strategy.cc155
-rw-r--r--libtransport/src/protocols/rtc/rtc_forwarding_strategy.h78
-rw-r--r--libtransport/src/protocols/rtc/rtc_indexer.h45
-rw-r--r--libtransport/src/protocols/rtc/rtc_ldr.cc539
-rw-r--r--libtransport/src/protocols/rtc/rtc_ldr.h100
-rw-r--r--libtransport/src/protocols/rtc/rtc_packet.h163
-rw-r--r--libtransport/src/protocols/rtc/rtc_rc.h12
-rw-r--r--libtransport/src/protocols/rtc/rtc_rc_congestion_detection.cc74
-rw-r--r--libtransport/src/protocols/rtc/rtc_rc_congestion_detection.h47
-rw-r--r--libtransport/src/protocols/rtc/rtc_rc_iat.cc287
-rw-r--r--libtransport/src/protocols/rtc/rtc_rc_iat.h93
-rw-r--r--libtransport/src/protocols/rtc/rtc_rc_queue.cc6
-rw-r--r--libtransport/src/protocols/rtc/rtc_rc_queue.h5
-rw-r--r--libtransport/src/protocols/rtc/rtc_reassembly.cc109
-rw-r--r--libtransport/src/protocols/rtc/rtc_reassembly.h21
-rw-r--r--libtransport/src/protocols/rtc/rtc_recovery_strategy.cc418
-rw-r--r--libtransport/src/protocols/rtc/rtc_recovery_strategy.h154
-rw-r--r--libtransport/src/protocols/rtc/rtc_rs_delay.cc122
-rw-r--r--libtransport/src/protocols/rtc/rtc_rs_delay.h53
-rw-r--r--libtransport/src/protocols/rtc/rtc_rs_fec_only.cc118
-rw-r--r--libtransport/src/protocols/rtc/rtc_rs_fec_only.h51
-rw-r--r--libtransport/src/protocols/rtc/rtc_rs_low_rate.cc167
-rw-r--r--libtransport/src/protocols/rtc/rtc_rs_low_rate.h69
-rw-r--r--libtransport/src/protocols/rtc/rtc_rs_recovery_off.cc60
-rw-r--r--libtransport/src/protocols/rtc/rtc_rs_recovery_off.h44
-rw-r--r--libtransport/src/protocols/rtc/rtc_rs_rtx_only.cc61
-rw-r--r--libtransport/src/protocols/rtc/rtc_rs_rtx_only.h44
-rw-r--r--libtransport/src/protocols/rtc/rtc_state.cc486
-rw-r--r--libtransport/src/protocols/rtc/rtc_state.h150
-rw-r--r--libtransport/src/protocols/rtc/rtc_verifier.cc238
-rw-r--r--libtransport/src/protocols/rtc/rtc_verifier.h79
-rw-r--r--libtransport/src/protocols/transport_protocol.cc144
-rw-r--r--libtransport/src/protocols/transport_protocol.h29
-rw-r--r--libtransport/src/test/CMakeLists.txt54
-rw-r--r--libtransport/src/test/main.cc1
-rw-r--r--libtransport/src/test/test_aggregated_header.cc622
-rw-r--r--libtransport/src/test/test_auth.cc178
-rw-r--r--libtransport/src/test/test_consumer_producer_rtc.cc7
-rw-r--r--libtransport/src/test/test_core_manifest.cc110
-rw-r--r--libtransport/src/test/test_event_thread.cc36
-rw-r--r--libtransport/src/test/test_fec_base_rely.cc453
-rw-r--r--libtransport/src/test/test_fec_base_rs.cc412
-rw-r--r--libtransport/src/test/test_fec_reedsolomon.cc122
-rw-r--r--libtransport/src/test/test_fec_rely_wrapper.cc131
-rw-r--r--libtransport/src/test/test_fixed_block_allocator.cc211
-rw-r--r--libtransport/src/test/test_interest.cc20
-rw-r--r--libtransport/src/test/test_memif_connector.cc152
-rw-r--r--libtransport/src/test/test_packet.cc11
-rw-r--r--libtransport/src/test/test_packet_allocator.cc106
-rw-r--r--libtransport/src/test/test_quality_score.cc135
-rw-r--r--libtransport/src/test/test_sessions.cc77
-rw-r--r--libtransport/src/test/test_thread_pool.cc70
-rw-r--r--libtransport/src/transport.config2
-rw-r--r--libtransport/src/utils/CMakeLists.txt7
-rw-r--r--libtransport/src/utils/content_store.cc9
-rw-r--r--libtransport/src/utils/content_store.h5
-rw-r--r--libtransport/src/utils/daemonizator.cc2
-rw-r--r--libtransport/src/utils/deadline_timer.h57
-rw-r--r--libtransport/src/utils/epoll_event_reactor.cc190
-rw-r--r--libtransport/src/utils/epoll_event_reactor.h165
-rw-r--r--libtransport/src/utils/event_reactor.h2
-rw-r--r--libtransport/src/utils/fd_deadline_timer.h8
-rw-r--r--libtransport/src/utils/log.cc4
-rw-r--r--libtransport/src/utils/max_filter.h58
-rw-r--r--libtransport/src/utils/membuf.cc23
-rw-r--r--libtransport/src/utils/memory_pool_allocator.h2
-rw-r--r--libtransport/src/utils/min_filter.h2
-rw-r--r--libtransport/src/utils/stream_buffer.h2
-rw-r--r--libtransport/src/utils/string_tokenizer.cc2
-rw-r--r--libtransport/src/utils/suffix_strategy.h166
-rw-r--r--libtransport/src/utils/test.h2
-rw-r--r--libtransport/src/utils/uri.cc2
-rw-r--r--libtransport/third-party/CMakeLists.txt77
-rw-r--r--libtransport/third-party/CMakeLists.txt.orig85
-rw-r--r--libtransport/third-party/CMakeLists.txt.rej21
-rw-r--r--libtransport/third-party/glog.patch2
-rw-r--r--libtransport/third-party/memif.patch43
317 files changed, 13120 insertions, 7040 deletions
diff --git a/libtransport/.clang-format b/libtransport/.clang-format
index 513da4d69..ae46ce82d 100644
--- a/libtransport/.clang-format
+++ b/libtransport/.clang-format
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2019 Cisco and/or its affiliates.
+# Copyright (c) 2021 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
diff --git a/libtransport/CMakeLists.txt b/libtransport/CMakeLists.txt
index a5009f353..62c0c0788 100644
--- a/libtransport/CMakeLists.txt
+++ b/libtransport/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2021 Cisco and/or its affiliates.
+# Copyright (c) 2021-2022 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
@@ -11,29 +11,36 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+##############################################################
+# Project and cmake version
+##############################################################
# CMake 3.11 required to use FetchContent
cmake_minimum_required(VERSION 3.11 FATAL_ERROR)
-
project(libtransport)
+
+##############################################################
+# Cmake modules
+##############################################################
set(CMAKE_MODULE_PATH
${CMAKE_MODULE_PATH}
- "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/Modules"
- "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules"
+ ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/Modules
)
+include("${CMAKE_CURRENT_SOURCE_DIR}/../versions.cmake")
-include(DefaultConfiguration)
-include(BuildMacros)
-if (NOT CMAKE_BUILD_TYPE)
- message(STATUS "${PROJECT_NAME}: No build type selected, default to Release")
- set(CMAKE_BUILD_TYPE "Release")
-endif ()
+##############################################################
+# C/CXX Standard
+##############################################################
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_C_STANDARD 11)
-set(TRANSPORT_ROOT_PATH "src")
+##############################################################
+# Libs and Bins names
+##############################################################
set(LIBTRANSPORT hicntransport)
-set(LIBTRANSPORT_COMPONENT libhicntransport)
+set(LIBTRANSPORT_COMPONENT lib${LIBTRANSPORT})
if ((BUILD_HICNPLUGIN OR BUILD_MEMIF_CONNECTOR) AND "${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
set(__vpp__ 1)
@@ -42,19 +49,32 @@ endif ()
set(LIBTRANSPORT ${LIBTRANSPORT} CACHE INTERNAL "" FORCE)
set(LIBTRANSPORT_SHARED ${LIBTRANSPORT}.shared CACHE INTERNAL "" FORCE)
set(LIBTRANSPORT_STATIC ${LIBTRANSPORT}.static CACHE INTERNAL "" FORCE)
-set(LIBTRANSPORT_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/src CACHE INTERNAL "" FORCE)
-include(WindowsMacros)
-include(IosMacros)
-find_package_wrapper(Asio REQUIRED)
-find_package(OpenSSL REQUIRED)
+##############################################################
+# Dependencies and third party libs
+##############################################################
+find_package(Asio ${ASIO_DEFAULT_VERSION} REQUIRED)
+find_package(OpenSSL ${OPENSSL_DEFAULT_VERSION} EXACT REQUIRED)
find_package(Threads REQUIRED)
-find_package(OpenSSL REQUIRED)
-find_package(Libconfig++ REQUIRED)
+find_package(Libconfig++ ${LIBCONFIG_DEFAULT_VERSION} REQUIRED)
+add_subdirectory(third-party)
+
+##############################################################
+# Check if building as subproject or as root project
+##############################################################
if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
- find_package_wrapper(Libhicn REQUIRED)
+ include(CommonSetup)
+ find_package(Libhicn ${CURRENT_VERSION} REQUIRED NO_MODULE)
+
+ if (DISABLE_SHARED_LIBRARIES)
+ set(LIBTYPE static)
+ else()
+ set(LIBTYPE shared)
+ endif()
+
+ list(APPEND HICN_LIBRARIES hicn::hicn.${LIBTYPE})
else()
if (DISABLE_SHARED_LIBRARIES)
if (WIN32)
@@ -73,34 +93,16 @@ else()
endif()
endif()
-include(Packaging)
-
-add_subdirectory(third-party)
-
-set(LIBRARIES
- PRIVATE ${HICN_LIBRARIES}
- PRIVATE ${CMAKE_THREAD_LIBS_INIT}
- PRIVATE ${CMAKE_DL_LIBS}
- PRIVATE ${OPENSSL_LIBRARIES}
- PRIVATE ${LIBCONFIG_CPP_LIBRARIES}
- PRIVATE ${THIRD_PARTY_LIBRARIES}
-)
-# Include dirs -- Order does matter!
-list(APPEND LIBTRANSPORT_INTERNAL_INCLUDE_DIRS
- ${HICN_INCLUDE_DIRS}
- ${HICNPLUGIN_INCLUDE_DIRS}
- ${CMAKE_THREADS_INCLUDE_DIRS}
- ${ASIO_INCLUDE_DIRS}
- ${WINDOWS_INCLUDE_DIRS}
- ${OPENSSL_INCLUDE_DIR}
- ${CONFIG_INCLUDE_DIRS}
- ${THIRD_PARTY_INCLUDE_DIRS}
-)
+##############################################################
+# Packaging and versioning
+##############################################################
+include(${CMAKE_CURRENT_SOURCE_DIR}/../versions.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/packaging.cmake)
-list(APPEND DEPENDENCIES
- ${THIRD_PARTY_DEPENDENCIES}
-)
+##############################################################
+# Subdirectories
+##############################################################
add_subdirectory(includes/hicn/transport)
-add_subdirectory(${TRANSPORT_ROOT_PATH})
+add_subdirectory(src)
diff --git a/libtransport/cmake/Modules/Android.cmake b/libtransport/cmake/Modules/Android.cmake
deleted file mode 100644
index 78918455a..000000000
--- a/libtransport/cmake/Modules/Android.cmake
+++ /dev/null
@@ -1,19 +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.
-
-function (configure_android_environment)
- set(CMAKE_CXX_FLAGS " -Wall -stdlib=libc++ -DASIO_STANDALONE -pthread -isystem -lm")
-
- #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" PARENT_SCOPE)
- #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ANDROID_C_FLAGS}" PARENT_SCOPE)
-endfunction() \ No newline at end of file
diff --git a/libtransport/cmake/Modules/DefaultConfiguration.cmake b/libtransport/cmake/Modules/DefaultConfiguration.cmake
deleted file mode 100644
index 402ad86f5..000000000
--- a/libtransport/cmake/Modules/DefaultConfiguration.cmake
+++ /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.
-
-# C/c++ standard
-set(CMAKE_CXX_STANDARD 17)
-set(CMAKE_C_STANDARD 11)
-
-# Compilation flags
-
-set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
-if (NOT WIN32)
- set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fpermissive")
- set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fpermissive")
- set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -fpermissive")
-endif ()
-
-set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG")
-set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
-set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
-set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}") \ No newline at end of file
diff --git a/libtransport/cmake/Modules/Ios.cmake b/libtransport/cmake/Modules/Ios.cmake
deleted file mode 100644
index 1b2aae2bf..000000000
--- a/libtransport/cmake/Modules/Ios.cmake
+++ /dev/null
@@ -1,20 +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.
-
-function (configure_ios_environment)
- find_host_package ( OpenSSL REQUIRED )
- include_directories(extras/iOS)
-
- find_host_package(Libhicn REQUIRED)
- include_directories(${HICN_INCLUDE_DIRS})
-endfunction() \ No newline at end of file
diff --git a/libtransport/cmake/Modules/TestMacros.cmake b/libtransport/cmake/Modules/TestMacros.cmake
deleted file mode 100644
index 680b5585f..000000000
--- a/libtransport/cmake/Modules/TestMacros.cmake
+++ /dev/null
@@ -1,15 +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(CTest)
-
diff --git a/libtransport/cmake/Modules/Packaging.cmake b/libtransport/cmake/packaging.cmake
index 9ff26aecc..f7f0c27e3 100644
--- a/libtransport/cmake/Modules/Packaging.cmake
+++ b/libtransport/cmake/packaging.cmake
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2019 Cisco and/or its affiliates.
+# Copyright (c) 2021-2022 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
@@ -17,6 +17,11 @@
# Packages section
######################
+##############################################################
+# Get VPP version
+##############################################################
+list(GET VPP_DEFAULT_VERSION 0 VPP_VERSION)
+
set(${LIBTRANSPORT_COMPONENT}_DESCRIPTION
"Libhicn-transport provides transport services and \
socket API for applications willing to communicate \
@@ -28,7 +33,7 @@ set(${LIBTRANSPORT_COMPONENT}-dev_DESCRIPTION
CACHE STRING "Header files for developing using libhicntransport."
)
-set(${LIBTRANSPORT_COMPONENT}-devel_DESCRIPTION
+set(lib${LIBTRANSPORT}-devel_DESCRIPTION
CACHE STRING "Header files for developing using libhicntransport."
)
@@ -37,31 +42,44 @@ set(${LIBTRANSPORT_COMPONENT}-io-modules_DESCRIPTION
)
set(${LIBTRANSPORT_COMPONENT}_DEB_DEPENDENCIES
- "lib${LIBHICN} (>= stable_version), libparc (>= 1.0), libconfig++9v5 (>= 1.5-0.4build1)"
+ "lib${LIBHICN} (= stable_version), libconfig++9v5 (>= 1.5-0.4build1)"
CACHE STRING "Dependencies for deb/rpm package."
)
set(${LIBTRANSPORT_COMPONENT}_RPM_DEPENDENCIES
- "lib${LIBHICN} >= stable_version, libparc >= 1.0, libconfig >= 1.5-9.el8"
+ "lib${LIBHICN} = stable_version, libconfig >= 1.5-9.el8"
CACHE STRING "Dependencies for deb/rpm package."
)
set(${LIBTRANSPORT_COMPONENT}-dev_DEB_DEPENDENCIES
- "${LIBTRANSPORT_COMPONENT} (>= stable_version), libasio-dev (>= 1.10), lib${LIBHICN}-dev (>= stable_version), libparc-dev (>= 1.0), libconfig++-dev (>= 1.5-0.4build1)"
+ "${LIBTRANSPORT_COMPONENT} (= stable_version), libasio-dev (>= 1.10), lib${LIBHICN}-dev (= stable_version), libconfig++-dev (>= 1.5-0.4build1)"
CACHE STRING "Dependencies for deb/rpm package."
)
set(${LIBTRANSPORT_COMPONENT}-dev_RPM_DEPENDENCIES
- "${LIBTRANSPORT_COMPONENT} >= stable_version, asio-devel >= 1.10, lib${LIBHICN}-devel >= stable_version, libparc-devel >= 1.0, libconfig-devel >= 1.5-9.el8"
+ "${LIBTRANSPORT_COMPONENT} = stable_version, asio-devel >= 1.10, lib${LIBHICN}-devel = stable_version, libconfig-devel >= 1.5-9.el8"
CACHE STRING "Dependencies for deb/rpm package."
)
set(${LIBTRANSPORT_COMPONENT}-io-modules_DEB_DEPENDENCIES
- "${LIBTRANSPORT_COMPONENT} (>= stable_version), libmemif (>= stable_version), vpp (>= stable_version-release), vpp (<< next_version-release), hicn-plugin (>= stable_version)"
+ "${LIBTRANSPORT_COMPONENT} (= stable_version), vpp (>= ${VPP_VERSION}), hicn-plugin (= stable_version)"
CACHE STRING "Dependencies for deb/rpm package."
)
set(${LIBTRANSPORT_COMPONENT}-io-modules_RPM_DEPENDENCIES
- "${LIBTRANSPORT_COMPONENT} >= stable_version, libmemif >= stable_version, vpp >= stable_version-release, vpp < next_version-release, hicn-plugin >= stable_version"
+ "${LIBTRANSPORT_COMPONENT} = stable_version, vpp >= ${VPP_VERSION}, hicn-plugin = stable_version"
CACHE STRING "Dependencies for deb/rpm package."
)
+
+if (INTERNAL_ENVIRONMENT)
+ include(CheckSsl)
+ CheckSsl()
+ set(${LIBTRANSPORT_COMPONENT}_DEB_DEPENDENCIES
+ "${${LIBTRANSPORT_COMPONENT}_DEB_DEPENDENCIES}, ${OPENSSL_DEPENDENCY}"
+ CACHE STRING "Dependencies for deb/rpm package."
+ )
+ set(${LIBTRANSPORT_COMPONENT}-dev_DEB_DEPENDENCIES
+ "${${LIBTRANSPORT_COMPONENT}-dev_DEB_DEPENDENCIES}, ${OPENSSL_DEPENDENCY_DEV}"
+ CACHE STRING "Dependencies for deb/rpm package."
+ )
+endif ()
diff --git a/libtransport/includes/hicn/transport/CMakeLists.txt b/libtransport/includes/hicn/transport/CMakeLists.txt
index eb339fb5a..8b9f907b9 100644
--- a/libtransport/includes/hicn/transport/CMakeLists.txt
+++ b/libtransport/includes/hicn/transport/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2020 Cisco and/or its affiliates.
+# Copyright (c) 2021-2022 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
@@ -23,14 +23,21 @@ add_subdirectory(portability)
add_subdirectory(auth)
add_subdirectory(utils)
-set(LIBTRANSPORT_INCLUDE_DIRS
- ${CMAKE_CURRENT_SOURCE_DIR}/../.. ""
+
+##############################################################
+# Public headers directory
+##############################################################
+set(Libhicntransport_INCLUDE_DIRS
+ ${CMAKE_CURRENT_SOURCE_DIR}/../..
CACHE INTERNAL
"" FORCE
)
+
+##############################################################
+# Header files to install
+##############################################################
set(LIBHICNTRANSPORT_TO_INSTALL_HEADER_FILES
- ${HEADER_FILES} ""
- CACHE INTERNAL
- "" FORCE
+ ${HEADER_FILES}
+ PARENT_SCOPE
)
diff --git a/libtransport/includes/hicn/transport/auth/CMakeLists.txt b/libtransport/includes/hicn/transport/auth/CMakeLists.txt
index 1e9fe4698..0b5ae1836 100644
--- a/libtransport/includes/hicn/transport/auth/CMakeLists.txt
+++ b/libtransport/includes/hicn/transport/auth/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2019 Cisco and/or its affiliates.
+# Copyright (c) 2021 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
@@ -15,7 +15,6 @@ list(APPEND HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/common.h
${CMAKE_CURRENT_SOURCE_DIR}/crypto_hash.h
${CMAKE_CURRENT_SOURCE_DIR}/crypto_suite.h
- ${CMAKE_CURRENT_SOURCE_DIR}/identity.h
${CMAKE_CURRENT_SOURCE_DIR}/key_id.h
${CMAKE_CURRENT_SOURCE_DIR}/policies.h
${CMAKE_CURRENT_SOURCE_DIR}/signer.h
diff --git a/libtransport/includes/hicn/transport/auth/common.h b/libtransport/includes/hicn/transport/auth/common.h
index fb0e82eb7..d2282436e 100644
--- a/libtransport/includes/hicn/transport/auth/common.h
+++ b/libtransport/includes/hicn/transport/auth/common.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/auth/crypto_hash.h b/libtransport/includes/hicn/transport/auth/crypto_hash.h
index 90f1627e9..3c734fee3 100644
--- a/libtransport/includes/hicn/transport/auth/crypto_hash.h
+++ b/libtransport/includes/hicn/transport/auth/crypto_hash.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -89,7 +89,7 @@ class CryptoHash {
static std::size_t getSize(CryptoHashType hash_type);
// Compare two raw buffers
- static bool compareDigest(const uint8_t *h1, const uint8_t *h2,
+ static bool compareDigest(const uint8_t *digest1, const uint8_t *digest2,
CryptoHashType hash_type);
private:
diff --git a/libtransport/includes/hicn/transport/auth/crypto_suite.h b/libtransport/includes/hicn/transport/auth/crypto_suite.h
index d0f1de395..ed21abb91 100644
--- a/libtransport/includes/hicn/transport/auth/crypto_suite.h
+++ b/libtransport/includes/hicn/transport/auth/crypto_suite.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -47,6 +47,9 @@ enum class CryptoSuite : uint8_t {
// Return the suite associated to the given NID
CryptoSuite getSuite(int nid);
+// Return the string representation of given suite
+std::string getStringSuite(CryptoSuite suite);
+
// Return the hash type associated to the given suite
CryptoHashType getHashType(CryptoSuite suite);
diff --git a/libtransport/includes/hicn/transport/auth/identity.h b/libtransport/includes/hicn/transport/auth/identity.h
deleted file mode 100644
index be072f5d3..000000000
--- a/libtransport/includes/hicn/transport/auth/identity.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (c) 2017-2021 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 <errno.h>
-#include <fcntl.h>
-#include <hicn/transport/auth/signer.h>
-#include <unistd.h>
-
-extern "C" {
-#include <openssl/pkcs12.h>
-#include <openssl/rand.h>
-#include <openssl/x509.h>
-#include <openssl/x509v3.h>
-}
-
-namespace transport {
-namespace auth {
-
-class Identity {
- // This class holds several information about a client, including its public
- // key.
- public:
- // Generate a new identity from the given parameters. The identity will be
- // saved in 'keystore_path' and encrypted using 'keystore_pwd'.
- Identity(const std::string &keystore_path, const std::string &keystore_pwd,
- CryptoSuite suite, unsigned int signature_len,
- unsigned int validity_days, const std::string &subject_name);
-
- // Create an identity from an already existing keystore path.
- Identity(std::string &keystore_path, std::string &keystore_pwd,
- CryptoHashType hash_type);
-
- Identity(const Identity &other);
- Identity(Identity &&other);
- ~Identity();
-
- // Return the asymmetric signer object created from the public key.
- std::shared_ptr<AsymmetricSigner> getSigner() const;
-
- // Return the key store filename.
- std::string getFilename() const;
-
- // Return the key store password.
- std::string getPassword() const;
-
- std::shared_ptr<X509> getCertificate() const;
-
- std::shared_ptr<EVP_PKEY> getPrivateKey() const;
-
- // Generate a new random identity.
- static Identity generateIdentity(const std::string &subject_name = "");
-
- private:
- static void free_key(EVP_PKEY *T) { EVP_PKEY_free(T); }
-
- std::string pwd_;
- std::string filename_;
- std::shared_ptr<AsymmetricSigner> signer_;
- std::shared_ptr<X509> cert_;
-};
-
-} // namespace auth
-} // namespace transport
diff --git a/libtransport/includes/hicn/transport/auth/key_id.h b/libtransport/includes/hicn/transport/auth/key_id.h
index 3aa09336f..8723ae698 100644
--- a/libtransport/includes/hicn/transport/auth/key_id.h
+++ b/libtransport/includes/hicn/transport/auth/key_id.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/auth/policies.h b/libtransport/includes/hicn/transport/auth/policies.h
index 00464d54b..b9755595c 100644
--- a/libtransport/includes/hicn/transport/auth/policies.h
+++ b/libtransport/includes/hicn/transport/auth/policies.h
@@ -23,10 +23,10 @@ namespace auth {
* perform after verification.
*/
enum class VerificationPolicy {
+ UNKNOWN,
ABORT,
- ACCEPT,
DROP,
- UNKNOWN,
+ ACCEPT,
};
} // namespace auth
diff --git a/libtransport/includes/hicn/transport/auth/signer.h b/libtransport/includes/hicn/transport/auth/signer.h
index 405dd83cf..5a7598991 100644
--- a/libtransport/includes/hicn/transport/auth/signer.h
+++ b/libtransport/includes/hicn/transport/auth/signer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2021 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -21,18 +21,19 @@
#include <hicn/transport/errors/errors.h>
#include <hicn/transport/utils/membuf.h>
+#include <memory>
extern "C" {
#include <openssl/evp.h>
#include <openssl/hmac.h>
+#include <openssl/pkcs12.h>
+#include <openssl/x509.h>
}
namespace transport {
namespace auth {
-class Identity;
class Signer {
// The base class from which all signer classes derive.
- friend class Identity;
public:
Signer();
@@ -47,6 +48,9 @@ class Signer {
// Return the signature.
std::vector<uint8_t> getSignature() const;
+ // Return the signature as a string
+ std::string getStringSignature() const;
+
// Return the signature size in bytes.
virtual std::size_t getSignatureSize() const;
@@ -61,6 +65,9 @@ class Signer {
// Return the hash algorithm associated to the signer.
CryptoHashType getHashType() const;
+ // Print signature to stdout
+ void display();
+
protected:
CryptoSuite suite_;
std::vector<uint8_t> signature_;
@@ -84,10 +91,17 @@ class AsymmetricSigner : public Signer {
public:
AsymmetricSigner() = default;
- // Construct an AsymmetricSigner from a key store and a given crypto suite.
+ // Create an AsymmetricSigner from a keystore file (.p12).
+ AsymmetricSigner(std::string keystore_path, std::string password);
+
+ // Construct an AsymmetricSigner from a key store and a given crypto
+ // suite.
AsymmetricSigner(CryptoSuite suite, std::shared_ptr<EVP_PKEY> key,
std::shared_ptr<EVP_PKEY> pub_key);
+ void setKey(CryptoSuite suite, std::shared_ptr<EVP_PKEY> key,
+ std::shared_ptr<EVP_PKEY> pub_key);
+
std::size_t getSignatureFieldSize() const override;
};
diff --git a/libtransport/includes/hicn/transport/auth/verifier.h b/libtransport/includes/hicn/transport/auth/verifier.h
index 6321d4ed5..677a1efe4 100644
--- a/libtransport/includes/hicn/transport/auth/verifier.h
+++ b/libtransport/includes/hicn/transport/auth/verifier.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2021 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -40,9 +40,9 @@ class Verifier {
// The VerificationFailedCallback will be called by the transport if a
// data packet (either a manifest or a content object) was not validated.
// The application decides what to do then by returning a
- // VerificationPolicy object.
+ // new VerificationPolicy.
using VerificationFailedCallback = std::function<auth::VerificationPolicy(
- const core::ContentObject &content_object, std::error_code ec)>;
+ Suffix suffix, VerificationPolicy policy)>;
// The list of VerificationPolicy that will trigger the
// VerificationFailedCallback.
@@ -96,13 +96,13 @@ class Verifier {
void getVerificationFailedCallback(
VerificationFailedCallback **verification_failed_cb);
+ // Call VerificationFailedCallback if it is set and update the packet policy.
+ void callVerificationFailedCallback(Suffix suffix,
+ VerificationPolicy &policy);
+
protected:
VerificationFailedCallback verification_failed_cb_;
std::vector<VerificationPolicy> failed_policies_;
-
- // Call VerificationFailedCallback if it is set and update the packet policy.
- void callVerificationFailedCallback(PacketPtr packet,
- VerificationPolicy &policy);
};
class VoidVerifier : public Verifier {
diff --git a/libtransport/includes/hicn/transport/core/CMakeLists.txt b/libtransport/includes/hicn/transport/core/CMakeLists.txt
index 14c795a7a..34048d93a 100644
--- a/libtransport/includes/hicn/transport/core/CMakeLists.txt
+++ b/libtransport/includes/hicn/transport/core/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2019 Cisco and/or its affiliates.
+# Copyright (c) 2021 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/core/connector.h b/libtransport/includes/hicn/transport/core/connector.h
index dcf38cdc8..b671a7d89 100644
--- a/libtransport/includes/hicn/transport/core/connector.h
+++ b/libtransport/includes/hicn/transport/core/connector.h
@@ -15,6 +15,7 @@
#pragma once
+#include <glog/logging.h>
#include <hicn/transport/core/connector_stats.h>
#include <hicn/transport/core/content_object.h>
#include <hicn/transport/core/endpoint.h>
@@ -50,22 +51,21 @@ class Connector : public std::enable_shared_from_this<Connector> {
enum class Role : std::uint8_t { CONSUMER, PRODUCER };
- public:
static constexpr std::size_t queue_size = 4096;
static constexpr std::uint32_t invalid_connector = ~0;
-
-#ifdef LINUX
+ static constexpr std::uint32_t max_reconnection_reattempts = 5;
static constexpr std::uint16_t max_burst = 256;
-#endif
using Ptr = std::shared_ptr<Connector>;
- using PacketQueue = std::deque<Packet::Ptr>;
- using PacketReceivedCallback = std::function<void(
- Connector *, utils::MemBuf &, const std::error_code &)>;
+ using PacketQueue = std::deque<utils::MemBuf::Ptr>;
+ using PacketReceivedCallback =
+ std::function<void(Connector *, const std::vector<utils::MemBuf::Ptr> &,
+ const std::error_code &)>;
using PacketSentCallback =
std::function<void(Connector *, const std::error_code &)>;
using OnCloseCallback = std::function<void(Connector *)>;
- using OnReconnectCallback = std::function<void(Connector *)>;
+ using OnReconnectCallback =
+ std::function<void(Connector *, const std::error_code &)>;
using Id = std::uint64_t;
template <typename ReceiveCallback, typename SentCallback, typename OnClose,
@@ -77,7 +77,8 @@ class Connector : public std::enable_shared_from_this<Connector> {
on_close_callback_(std::forward<OnClose &&>(close_callback)),
on_reconnect_callback_(std::forward<OnReconnect &&>(on_reconnect)),
state_(State::CLOSED),
- connector_id_(invalid_connector) {}
+ connector_id_(invalid_connector),
+ connection_reattempts_(0) {}
virtual ~Connector(){};
@@ -115,7 +116,7 @@ class Connector : public std::enable_shared_from_this<Connector> {
virtual void send(Packet &packet) = 0;
- virtual void send(const uint8_t *packet, std::size_t len) = 0;
+ virtual void send(const utils::MemBuf::Ptr &buffer) = 0;
virtual void close() = 0;
@@ -206,6 +207,9 @@ class Connector : public std::enable_shared_from_this<Connector> {
// Stats
AtomicConnectorStats stats_;
+
+ // Connection attempts
+ std::uint32_t connection_reattempts_;
};
} // namespace core
diff --git a/libtransport/includes/hicn/transport/core/content_object.h b/libtransport/includes/hicn/transport/core/content_object.h
index 38baafc69..a8df1e8e3 100644
--- a/libtransport/includes/hicn/transport/core/content_object.h
+++ b/libtransport/includes/hicn/transport/core/content_object.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -31,10 +31,9 @@ class ContentObject : public Packet {
using Ptr = std::shared_ptr<ContentObject>;
using HICNContentObject = hicn_header_t;
- ContentObject(Packet::Format format = HF_INET6_TCP,
- std::size_t additional_header_size = 0);
+ ContentObject(Packet::Format format, std::size_t additional_header_size = 0);
- ContentObject(const Name &name, Packet::Format format = HF_INET6_TCP,
+ ContentObject(const Name &name, Packet::Format format,
std::size_t additional_header_size = 0);
ContentObject(const Name &name, hicn_format_t format,
@@ -42,7 +41,7 @@ class ContentObject : public Packet {
std::size_t payload_size);
template <typename... Args>
- ContentObject(CopyBufferOp op, Args &&... args)
+ ContentObject(CopyBufferOp op, Args &&...args)
: Packet(op, std::forward<Args>(args)...) {
if (hicn_data_get_name(format_, packet_start_, name_.getStructReference()) <
0) {
@@ -51,7 +50,7 @@ class ContentObject : public Packet {
}
template <typename... Args>
- ContentObject(WrapBufferOp op, Args &&... args)
+ ContentObject(WrapBufferOp op, Args &&...args)
: Packet(op, std::forward<Args>(args)...) {
if (hicn_data_get_name(format_, packet_start_, name_.getStructReference()) <
0) {
@@ -60,8 +59,12 @@ class ContentObject : public Packet {
}
template <typename... Args>
- ContentObject(CreateOp op, Args &&... args)
+ ContentObject(CreateOp op, Args &&...args)
: Packet(op, std::forward<Args>(args)...) {
+ if (hicn_packet_set_data(format_, packet_start_) < 0) {
+ throw errors::MalformedPacketException();
+ }
+
if (hicn_data_get_name(format_, packet_start_, name_.getStructReference()) <
0) {
throw errors::MalformedPacketException();
@@ -96,6 +99,10 @@ class ContentObject : public Packet {
auto shared_from_this() { return utils::shared_from(this); }
+ bool isLast() const;
+
+ void setLast();
+
private:
void resetForHash() override;
};
diff --git a/libtransport/includes/hicn/transport/core/endpoint.h b/libtransport/includes/hicn/transport/core/endpoint.h
index cb6b0f562..e1fa193d7 100644
--- a/libtransport/includes/hicn/transport/core/endpoint.h
+++ b/libtransport/includes/hicn/transport/core/endpoint.h
@@ -42,14 +42,20 @@ class Endpoint {
~Endpoint() = default;
Endpoint &operator=(const Endpoint &other) {
- address_ = other.address_;
- port_ = other.port_;
+ if (this != &other) {
+ address_ = other.address_;
+ port_ = other.port_;
+ }
+
return *this;
}
Endpoint &operator=(Endpoint &&other) {
- address_ = std::move(other.address_);
- port_ = std::move(other.port_);
+ if (this != &other) {
+ address_ = std::move(other.address_);
+ port_ = std::move(other.port_);
+ }
+
return *this;
}
diff --git a/libtransport/includes/hicn/transport/core/global_object_pool.h b/libtransport/includes/hicn/transport/core/global_object_pool.h
index d7f3a9e41..f98df521f 100644
--- a/libtransport/includes/hicn/transport/core/global_object_pool.h
+++ b/libtransport/includes/hicn/transport/core/global_object_pool.h
@@ -27,9 +27,10 @@ namespace transport {
namespace core {
template <std::size_t packet_pool_size = 1024, std::size_t chunk_size = 2048>
-class PacketManager
- : public utils::Singleton<PacketManager<packet_pool_size, chunk_size>> {
- friend class utils::Singleton<PacketManager<packet_pool_size, chunk_size>>;
+class PacketManager : public utils::ThreadLocalSingleton<
+ PacketManager<packet_pool_size, chunk_size>> {
+ friend class utils::ThreadLocalSingleton<
+ PacketManager<packet_pool_size, chunk_size>>;
public:
using MemoryPool = utils::FixedBlockAllocator<chunk_size, packet_pool_size>;
@@ -71,7 +72,10 @@ class PacketManager
template <
typename PacketType, typename... Args,
typename = std::enable_if_t<std::is_base_of<Packet, PacketType>::value>>
- typename PacketType::Ptr getPacket(Args &&... args) {
+ typename PacketType::Ptr getPacket(Args &&...args) {
+ static_assert(sizeof(PacketType) + sizeof(std::shared_ptr<PacketType>) +
+ sizeof(std::max_align_t) <=
+ sizeof(PacketStorage::packet_and_shared_ptr));
PacketType *memory = nullptr;
memory = reinterpret_cast<PacketType *>(memory_pool_.allocateBlock());
@@ -98,7 +102,7 @@ class PacketManager
template <typename PacketType, typename... Args>
typename PacketType::Ptr getPacketFromExistingBuffer(uint8_t *buffer,
std::size_t length,
- Args &&... args) {
+ Args &&...args) {
auto offset = offsetof(PacketStorage, align);
auto memory = reinterpret_cast<PacketType *>(buffer - offset);
utils::STLAllocator<PacketType, MemoryPool> allocator(memory,
diff --git a/libtransport/includes/hicn/transport/core/interest.h b/libtransport/includes/hicn/transport/core/interest.h
index a5b9cf375..b7ce3c3a0 100644
--- a/libtransport/includes/hicn/transport/core/interest.h
+++ b/libtransport/includes/hicn/transport/core/interest.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -40,16 +40,15 @@ class Interest
public:
using Ptr = std::shared_ptr<Interest>;
- Interest(Packet::Format format = HF_INET6_TCP,
- std::size_t additional_header_size = 0);
+ Interest(Packet::Format format, std::size_t additional_header_size = 0);
- Interest(const Name &interest_name, Packet::Format format = HF_INET6_TCP,
+ Interest(const Name &interest_name, Packet::Format format,
std::size_t additional_header_size = 0);
Interest(MemBuf &&buffer);
template <typename... Args>
- Interest(CopyBufferOp op, Args &&... args)
+ Interest(CopyBufferOp op, Args &&...args)
: Packet(op, std::forward<Args>(args)...) {
if (hicn_interest_get_name(format_, packet_start_,
name_.getStructReference()) < 0) {
@@ -58,7 +57,7 @@ class Interest
}
template <typename... Args>
- Interest(WrapBufferOp op, Args &&... args)
+ Interest(WrapBufferOp op, Args &&...args)
: Packet(op, std::forward<Args>(args)...) {
if (hicn_interest_get_name(format_, packet_start_,
name_.getStructReference()) < 0) {
@@ -67,8 +66,12 @@ class Interest
}
template <typename... Args>
- Interest(CreateOp op, Args &&... args)
- : Packet(op, std::forward<Args>(args)...) {}
+ Interest(CreateOp op, Args &&...args)
+ : Packet(op, std::forward<Args>(args)...) {
+ if (hicn_packet_set_interest(format_, packet_start_) < 0) {
+ throw errors::MalformedPacketException();
+ }
+ }
/* Move constructor */
Interest(Interest &&other_interest);
diff --git a/libtransport/includes/hicn/transport/core/io_module.h b/libtransport/includes/hicn/transport/core/io_module.h
index ea3cf4e16..817d96d00 100644
--- a/libtransport/includes/hicn/transport/core/io_module.h
+++ b/libtransport/includes/hicn/transport/core/io_module.h
@@ -40,7 +40,7 @@ typedef struct {
class Connector;
-class IoModule {
+class IoModule : utils::NonCopyable {
protected:
IoModule()
: inet_address_({}),
@@ -64,15 +64,20 @@ class IoModule {
virtual bool isConnected() = 0;
virtual void init(Connector::PacketReceivedCallback &&receive_callback,
+ Connector::PacketSentCallback &&sent_callback,
Connector::OnReconnectCallback &&reconnect_callback,
asio::io_service &io_service,
const std::string &app_name = "Libtransport") = 0;
virtual void registerRoute(const Prefix &prefix) = 0;
+ virtual void sendMapme() {}
+
+ virtual void setForwardingStrategy(const Prefix &prefix,
+ std::string &strategy){};
virtual std::uint32_t getMtu() = 0;
- virtual bool isControlMessage(const uint8_t *message) = 0;
+ virtual bool isControlMessage(utils::MemBuf &packet_buffer) = 0;
virtual void processControlMessageReply(utils::MemBuf &packet_buffer) = 0;
@@ -89,7 +94,7 @@ class IoModule {
}
}
- virtual void send(const uint8_t *packet, std::size_t len) = 0;
+ virtual void send(const utils::MemBuf::Ptr &buffer) = 0;
void setContentStoreSize(uint32_t cs_size) {
content_store_reserved_ = cs_size;
diff --git a/libtransport/includes/hicn/transport/core/name.h b/libtransport/includes/hicn/transport/core/name.h
index 033582289..5cb4efd10 100644
--- a/libtransport/includes/hicn/transport/core/name.h
+++ b/libtransport/includes/hicn/transport/core/name.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -51,7 +51,7 @@ class Name {
public:
using NameStruct = hicn_name_t;
- using Type = hicn_name_type_t;
+ enum class Type { UNDEFINED, V4, V6 };
Name();
@@ -69,6 +69,8 @@ class Name {
Name(const Name &name);
+ ~Name();
+
Name &operator=(const Name &name);
bool operator==(const Name &name) const;
@@ -91,14 +93,11 @@ class Name {
uint32_t getSuffix() const;
- std::shared_ptr<Sockaddr> getAddress() const;
-
Name &setSuffix(uint32_t seq_number);
ip_prefix_t toIpAddress() const;
- void copyToDestination(uint8_t *destination,
- bool include_suffix = false) const;
+ void copyPrefixToDestination(uint8_t *destination) const;
int getAddressFamily() const;
diff --git a/libtransport/includes/hicn/transport/core/packet.h b/libtransport/includes/hicn/transport/core/packet.h
index 269a1571a..059430f1d 100644
--- a/libtransport/includes/hicn/transport/core/packet.h
+++ b/libtransport/includes/hicn/transport/core/packet.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -30,11 +30,7 @@ namespace transport {
namespace auth {
class Signer;
-class AsymmetricSigner;
-class SymmetricSigner;
class Verifier;
-class AsymmetricVerifier;
-class SymmetricVerifier;
} // namespace auth
namespace core {
@@ -51,16 +47,13 @@ namespace core {
class Packet : public utils::MemBuf,
public std::enable_shared_from_this<Packet> {
friend class auth::Signer;
- friend class auth::SymmetricSigner;
- friend class auth::AsymmetricSigner;
friend class auth::Verifier;
- friend class auth::AsymmetricVerifier;
- friend class auth::SymmetricVerifier;
public:
using Ptr = std::shared_ptr<Packet>;
using MemBufPtr = std::shared_ptr<utils::MemBuf>;
using Format = hicn_format_t;
+
static constexpr size_t default_mtu = 1500;
/**
@@ -68,146 +61,73 @@ class Packet : public utils::MemBuf,
* 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_INET6_TCP, std::size_t additional_header_size = 0);
-
- /**
- * Create new IP packet using raw buffer.
- */
-
+ Packet(Format format, std::size_t additional_header_size = 0);
/* Copy buffer */
Packet(CopyBufferOp, const uint8_t *buffer, std::size_t size);
/* Wrap buffer */
Packet(WrapBufferOp, uint8_t *buffer, std::size_t length, std::size_t size);
/* Create new using pre-allocated buffer */
Packet(CreateOp, uint8_t *buffer, std::size_t length, std::size_t size,
- Format format = HF_INET6_TCP, std::size_t additional_header_size = 0);
- /* Move MemBuf */
- Packet(MemBuf &&buffer);
+ Format format, std::size_t additional_header_size = 0);
+ Packet(MemBuf &&buffer);
Packet(Packet &&other);
-
- /*
- * Copy constructor and assignemnt operators.
- */
Packet(const Packet &other);
- Packet &operator=(const Packet &other);
-
- friend bool operator==(const Packet &l_packet, const Packet &r_packet);
+ // Destructor
virtual ~Packet();
- static std::size_t getHeaderSizeFromFormat(Format format,
- std::size_t signature_size = 0) {
- 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;
- }
-
- 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);
-
- bool isInterest();
-
- static Format getFormatFromBuffer(const uint8_t *buffer, std::size_t length) {
- Format format = HF_UNSPEC;
- hicn_packet_get_format((const hicn_header_t *)buffer, &format);
- return format;
- }
-
- void reset() {
- clear();
- packet_start_ = reinterpret_cast<hicn_header_t *>(writableData());
- header_offset_ = 0;
- format_ = HF_UNSPEC;
- payload_type_ = PayloadType::UNSPECIFIED;
- name_.clear();
-
- if (isChained()) {
- separateChain(next(), prev());
- }
- }
-
- void setFormat(Packet::Format format = HF_INET6_TCP,
- std::size_t additional_header_size = 0);
-
- std::size_t payloadSize() const;
-
- std::size_t headerSize() const;
+ // Operators
+ Packet &operator=(const Packet &other);
+ friend bool operator==(const Packet &l_packet, const Packet &r_packet);
+ // Cast to MemBuf
std::shared_ptr<utils::MemBuf> acquireMemBufReference();
- virtual const Name &getName() const = 0;
+ // Format
+ Format getFormat() const;
+ void setFormat(Packet::Format format, std::size_t additional_header_size = 0);
+ // Name
+ virtual const Name &getName() const = 0;
virtual Name &getWritableName() = 0;
-
virtual void setName(const Name &name) = 0;
+ // Lifetime
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<utils::MemBuf> &&payload);
-
- std::unique_ptr<utils::MemBuf> getPayload() const;
-
- Packet &updateLength(std::size_t length = 0);
-
- PayloadType getPayloadType() const;
-
- Packet &setPayloadType(PayloadType payload_type);
-
- Format getFormat() const;
-
- void dump() const;
-
- static void dump(uint8_t *buffer, std::size_t length);
-
+ // Locator
virtual void setLocator(const ip_address_t &locator) = 0;
-
virtual ip_address_t getLocator() const = 0;
- /**
- * @brief Set signature timestamp, in milliseconds.
- */
- void setSignatureTimestamp(const uint64_t &timestamp_milliseconds);
-
- uint64_t getSignatureTimestamp() const;
-
- void setValidationAlgorithm(const auth::CryptoSuite &validation_algorithm);
-
- auth::CryptoSuite getValidationAlgorithm() const;
-
- void setKeyId(const auth::KeyId &key_id);
+ // Payload type
+ PayloadType getPayloadType() const;
+ Packet &setPayloadType(PayloadType payload_type);
- auth::KeyId getKeyId() const;
+ // Payload
+ std::unique_ptr<utils::MemBuf> getPayload() const;
+ Packet &appendPayload(std::unique_ptr<utils::MemBuf> &&payload);
+ Packet &appendPayload(const uint8_t *buffer, std::size_t length);
- virtual auth::CryptoHash computeDigest(auth::CryptoHashType algorithm) const;
+ // Sizes
+ std::size_t headerSize() const;
+ std::size_t payloadSize() const;
- void setChecksum() {
- uint16_t partial_csum =
- csum(data() + HICN_V6_TCP_HDRLEN, length() - HICN_V6_TCP_HDRLEN, 0);
+ // Digest
+ auth::CryptoHash computeDigest(auth::CryptoHashType algorithm) const;
- for (utils::MemBuf *current = next(); current != this;
- current = current->next()) {
- partial_csum = csum(current->data(), current->length(), ~partial_csum);
- }
+ // Reset packet
+ void reset();
- if (hicn_packet_compute_header_checksum(format_, packet_start_,
- partial_csum) < 0) {
- throw errors::MalformedPacketException();
- }
- }
+ // Utils
+ bool isInterest();
+ Packet &updateLength(std::size_t length = 0);
+ void dump() const;
+ // TCP methods
+ void setChecksum();
bool checkIntegrity() const;
-
Packet &setSyn();
Packet &resetSyn();
bool testSyn() const;
@@ -222,53 +142,45 @@ class Packet : public utils::MemBuf,
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;
+ // Authentication Header methods
+ bool hasAH() const;
+ std::vector<uint8_t> getSignature() const;
+ std::size_t getSignatureFieldSize() const;
+ std::size_t getSignatureSize() const;
+ uint64_t getSignatureTimestamp() const;
+ auth::KeyId getKeyId() const;
+ auth::CryptoSuite getValidationAlgorithm() const;
+ void setSignature(const std::vector<uint8_t> &signature);
+ void setSignatureFieldSize(std::size_t size);
+ void setSignatureSize(std::size_t size);
+ void setSignatureTimestamp(const uint64_t &timestamp_ms);
+ void setKeyId(const auth::KeyId &key_id);
+ void setValidationAlgorithm(const auth::CryptoSuite &algo);
+
+ // Static methods
+ static Format toAHFormat(const Format &format);
+ static Format getFormatFromBuffer(const uint8_t *buffer, std::size_t length);
+ 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,
+ Format format = Format::HF_UNSPEC);
+ static void dump(uint8_t *buffer, std::size_t length);
+
private:
virtual void resetForHash() = 0;
- void setSignatureSize(std::size_t size_bytes);
- void setSignatureSizeGap(std::size_t size_bytes);
void prependPayload(const uint8_t **buffer, std::size_t *size);
- bool authenticationHeader() const { return _is_ah(format_); }
-
- std::size_t 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;
- }
-
- std::size_t getSignatureSizeGap() const {
- uint8_t size_bytes;
- int ret =
- hicn_packet_get_signature_gap(format_, packet_start_, &size_bytes);
-
- if (ret < 0) {
- throw errors::RuntimeException("Packet without Authentication Header.");
- }
-
- return (size_t)size_bytes;
- }
-
- std::size_t getSignatureSizeReal() const {
- return getSignatureSize() - getSignatureSizeGap();
- }
-
- uint8_t *getSignature() const;
-
protected:
hicn_header_t *packet_start_;
std::size_t header_offset_;
diff --git a/libtransport/includes/hicn/transport/core/payload_type.h b/libtransport/includes/hicn/transport/core/payload_type.h
index 8c918f792..3a682e177 100644
--- a/libtransport/includes/hicn/transport/core/payload_type.h
+++ b/libtransport/includes/hicn/transport/core/payload_type.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/core/prefix.h b/libtransport/includes/hicn/transport/core/prefix.h
index 7ef667bc8..13401e1a8 100644
--- a/libtransport/includes/hicn/transport/core/prefix.h
+++ b/libtransport/includes/hicn/transport/core/prefix.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -35,6 +35,10 @@ class Prefix {
Prefix(const core::Name &content_name, uint16_t prefix_length);
+ bool operator<(const Prefix &prefix) const;
+
+ bool operator==(const Prefix &prefix) const;
+
std::unique_ptr<Sockaddr> toSockaddr() const;
uint16_t getPrefixLength() const;
diff --git a/libtransport/includes/hicn/transport/errors/CMakeLists.txt b/libtransport/includes/hicn/transport/errors/CMakeLists.txt
index 1d35c5b34..c8642b51b 100644
--- a/libtransport/includes/hicn/transport/errors/CMakeLists.txt
+++ b/libtransport/includes/hicn/transport/errors/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2019 Cisco and/or its affiliates.
+# Copyright (c) 2021 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/errors/errors.h b/libtransport/includes/hicn/transport/errors/errors.h
index b659820fa..09ce97221 100644
--- a/libtransport/includes/hicn/transport/errors/errors.h
+++ b/libtransport/includes/hicn/transport/errors/errors.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/errors/indexing_exception.h b/libtransport/includes/hicn/transport/errors/indexing_exception.h
index 731314f0e..bdcc39aef 100644
--- a/libtransport/includes/hicn/transport/errors/indexing_exception.h
+++ b/libtransport/includes/hicn/transport/errors/indexing_exception.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/errors/invalid_ip_address_exception.h b/libtransport/includes/hicn/transport/errors/invalid_ip_address_exception.h
index 60226f576..26e0f98af 100644
--- a/libtransport/includes/hicn/transport/errors/invalid_ip_address_exception.h
+++ b/libtransport/includes/hicn/transport/errors/invalid_ip_address_exception.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/errors/malformed_ahpacket_exception.h b/libtransport/includes/hicn/transport/errors/malformed_ahpacket_exception.h
index f0cfe0b82..9b3ec7466 100644
--- a/libtransport/includes/hicn/transport/errors/malformed_ahpacket_exception.h
+++ b/libtransport/includes/hicn/transport/errors/malformed_ahpacket_exception.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/errors/malformed_name_exception.h b/libtransport/includes/hicn/transport/errors/malformed_name_exception.h
index 4ef45d2e8..57412cf7f 100644
--- a/libtransport/includes/hicn/transport/errors/malformed_name_exception.h
+++ b/libtransport/includes/hicn/transport/errors/malformed_name_exception.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/errors/malformed_packet_exception.h b/libtransport/includes/hicn/transport/errors/malformed_packet_exception.h
index ec5c97e6e..996d6a4ab 100644
--- a/libtransport/includes/hicn/transport/errors/malformed_packet_exception.h
+++ b/libtransport/includes/hicn/transport/errors/malformed_packet_exception.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/errors/not_implemented_exception.h b/libtransport/includes/hicn/transport/errors/not_implemented_exception.h
index e9869163d..3291fa425 100644
--- a/libtransport/includes/hicn/transport/errors/not_implemented_exception.h
+++ b/libtransport/includes/hicn/transport/errors/not_implemented_exception.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/errors/null_pointer_exception.h b/libtransport/includes/hicn/transport/errors/null_pointer_exception.h
index bd06485ed..7edb619b8 100644
--- a/libtransport/includes/hicn/transport/errors/null_pointer_exception.h
+++ b/libtransport/includes/hicn/transport/errors/null_pointer_exception.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/errors/runtime_exception.h b/libtransport/includes/hicn/transport/errors/runtime_exception.h
index ba5128a7e..498c41a7c 100644
--- a/libtransport/includes/hicn/transport/errors/runtime_exception.h
+++ b/libtransport/includes/hicn/transport/errors/runtime_exception.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/errors/tokenizer_exception.h b/libtransport/includes/hicn/transport/errors/tokenizer_exception.h
index 76eda838e..31f79644a 100644
--- a/libtransport/includes/hicn/transport/errors/tokenizer_exception.h
+++ b/libtransport/includes/hicn/transport/errors/tokenizer_exception.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/errors/unexpected_manifest_exception.h b/libtransport/includes/hicn/transport/errors/unexpected_manifest_exception.h
index 6f71471e4..c8e4eadd4 100644
--- a/libtransport/includes/hicn/transport/errors/unexpected_manifest_exception.h
+++ b/libtransport/includes/hicn/transport/errors/unexpected_manifest_exception.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/http/CMakeLists.txt b/libtransport/includes/hicn/transport/http/CMakeLists.txt
index 9f4cdaf39..36a2ca5ce 100644
--- a/libtransport/includes/hicn/transport/http/CMakeLists.txt
+++ b/libtransport/includes/hicn/transport/http/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2020 Cisco and/or its affiliates.
+# Copyright (c) 2021 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/http/client_connection.h b/libtransport/includes/hicn/transport/http/client_connection.h
index 7e78e9c59..d5edf6cd0 100644
--- a/libtransport/includes/hicn/transport/http/client_connection.h
+++ b/libtransport/includes/hicn/transport/http/client_connection.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -31,7 +31,7 @@ namespace http {
using namespace interface;
using namespace core;
-class HTTPClientConnection {
+class HTTPClientConnection : private utils::NonCopyable {
static constexpr uint32_t max_buffer_capacity = 64 * 1024;
public:
@@ -39,7 +39,7 @@ class HTTPClientConnection {
public:
virtual void onBytesReceived(std::unique_ptr<utils::MemBuf> &&buffer) = 0;
virtual void onSuccess(std::size_t bytes) = 0;
- virtual void onError(const std::error_code ec) = 0;
+ virtual void onError(const std::error_code &ec) = 0;
};
enum class RC : uint32_t { DOWNLOAD_FAILED, DOWNLOAD_SUCCESS };
diff --git a/libtransport/includes/hicn/transport/http/default_values.h b/libtransport/includes/hicn/transport/http/default_values.h
index 2d5a6b821..8cf247e19 100644
--- a/libtransport/includes/hicn/transport/http/default_values.h
+++ b/libtransport/includes/hicn/transport/http/default_values.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/http/facade.h b/libtransport/includes/hicn/transport/http/facade.h
index 8a465ce94..c886a7588 100644
--- a/libtransport/includes/hicn/transport/http/facade.h
+++ b/libtransport/includes/hicn/transport/http/facade.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/http/message.h b/libtransport/includes/hicn/transport/http/message.h
index b8756224f..a07941413 100644
--- a/libtransport/includes/hicn/transport/http/message.h
+++ b/libtransport/includes/hicn/transport/http/message.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/http/request.h b/libtransport/includes/hicn/transport/http/request.h
index b62f5b061..9939fbcaf 100644
--- a/libtransport/includes/hicn/transport/http/request.h
+++ b/libtransport/includes/hicn/transport/http/request.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/http/response.h b/libtransport/includes/hicn/transport/http/response.h
index bab41acb8..79def27cd 100644
--- a/libtransport/includes/hicn/transport/http/response.h
+++ b/libtransport/includes/hicn/transport/http/response.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/interfaces/CMakeLists.txt b/libtransport/includes/hicn/transport/interfaces/CMakeLists.txt
index 40623dfe1..1acaadcf0 100644
--- a/libtransport/includes/hicn/transport/interfaces/CMakeLists.txt
+++ b/libtransport/includes/hicn/transport/interfaces/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2019 Cisco and/or its affiliates.
+# Copyright (c) 2021 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
@@ -21,6 +21,7 @@ list(APPEND HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/global_conf_interface.h
${CMAKE_CURRENT_SOURCE_DIR}/statistics.h
${CMAKE_CURRENT_SOURCE_DIR}/portal.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/notification.h
)
if (${OPENSSL_VERSION} VERSION_EQUAL "1.1.1a" OR ${OPENSSL_VERSION} VERSION_GREATER "1.1.1a")
diff --git a/libtransport/includes/hicn/transport/interfaces/callbacks.h b/libtransport/includes/hicn/transport/interfaces/callbacks.h
index 22e111799..41e4fba3b 100644
--- a/libtransport/includes/hicn/transport/interfaces/callbacks.h
+++ b/libtransport/includes/hicn/transport/interfaces/callbacks.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -16,6 +16,7 @@
#pragma once
#include <hicn/transport/auth/policies.h>
+#include <hicn/transport/interfaces/notification.h>
#include <hicn/transport/interfaces/statistics.h>
#include <functional>
@@ -60,6 +61,12 @@ using ConsumerTimerCallback =
std::function<void(ConsumerSocket &, const TransportStatistics &stats)>;
/**
+ * The ConsumerTimerCallback is called when the forwarding/recovery stategy is
+ * changes.
+ */
+using StrategyCallback = std::function<void(notification::Strategy strategy)>;
+
+/**
* The ProducerContentCallback will be called by the producer socket right after
* a content has been segmented and published.
*/
diff --git a/libtransport/src/protocols/fec_base.cc b/libtransport/includes/hicn/transport/interfaces/notification.h
index 9252bc473..a0945c3f0 100644
--- a/libtransport/src/protocols/fec_base.cc
+++ b/libtransport/includes/hicn/transport/interfaces/notification.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Copyright (c) 2022 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -13,12 +13,19 @@
* limitations under the License.
*/
-#include <protocols/fec/rs.h>
-#include <protocols/fec_base.h>
+#pragma once
+
+#include <variant>
namespace transport {
-namespace protocol {
+namespace interface {
+namespace notification {
+
+enum class ForwardingStrategy { BEST_PATH, REPLICATION, BOTH, NONE };
+enum class RecoveryStrategy { RECOVERY_OFF, RTX_ONLY, FEC_ONLY, RTX_AND_FEC };
+
+using Strategy = std::variant<ForwardingStrategy, RecoveryStrategy>;
-namespace fec {} // namespace fec
-} // namespace protocol
+} // namespace notification
+} // namespace interface
} // namespace transport \ No newline at end of file
diff --git a/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_consumer.h b/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_consumer.h
index 224493f00..a67634c1e 100644
--- a/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_consumer.h
+++ b/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_consumer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_producer.h b/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_producer.h
index d86744514..e197a3658 100644
--- a/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_producer.h
+++ b/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_producer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -15,7 +15,6 @@
#pragma once
-#include <hicn/transport/auth/identity.h>
#include <hicn/transport/interfaces/socket_producer.h>
namespace transport {
@@ -25,8 +24,8 @@ namespace interface {
class P2PSecureProducerSocket : public ProducerSocket {
public:
P2PSecureProducerSocket();
- P2PSecureProducerSocket(bool rtc,
- const std::shared_ptr<auth::Identity> &identity);
+ P2PSecureProducerSocket(bool rtc, std::string &keystore_path,
+ std::string &keystore_pwd);
~P2PSecureProducerSocket() = default;
};
diff --git a/libtransport/includes/hicn/transport/interfaces/portal.h b/libtransport/includes/hicn/transport/interfaces/portal.h
index 66fc84256..1a22b1f1d 100644
--- a/libtransport/includes/hicn/transport/interfaces/portal.h
+++ b/libtransport/includes/hicn/transport/interfaces/portal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -19,6 +19,8 @@
#include <hicn/transport/core/content_object.h>
#include <hicn/transport/core/interest.h>
#include <hicn/transport/core/prefix.h>
+#include <hicn/transport/utils/event_thread.h>
+#include <hicn/transport/utils/noncopyable.h>
#include <functional>
@@ -28,58 +30,18 @@ namespace transport {
namespace interface {
-template <typename PrefixType>
-class BasicBindConfig {
- static_assert(std::is_same<core::Prefix, PrefixType>::value,
- "Prefix must be a Prefix type.");
-
- const uint32_t standard_cs_reserved = 5000;
-
- public:
- template <typename T>
- BasicBindConfig(T &&prefix)
- : prefix_(std::forward<T &&>(prefix)),
- content_store_reserved_(standard_cs_reserved) {}
-
- template <typename T>
- BasicBindConfig(T &&prefix, uint32_t cs_reserved)
- : prefix_(std::forward<T &&>(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<core::Prefix>;
-
-class Portal {
+class Portal : private utils::NonCopyable {
public:
/**
- * Consumer callback is an abstract class containing two methods to be
- * implemented by a consumer application.
+ * Transport callback is an abstract class containing two methods to be
+ * implemented by a consumer/producer application.
*/
- class ConsumerCallback {
+ class TransportCallback {
public:
+ virtual void onInterest(core::Interest &i) = 0;
virtual void onContentObject(core::Interest &i, core::ContentObject &c) = 0;
virtual void onTimeout(core::Interest::Ptr &i, const core::Name &n) = 0;
- virtual void onError(std::error_code ec) = 0;
- };
-
- /**
- * Producer callback is an abstract class containing two methods to be
- * implemented by a producer application.
- */
- class ProducerCallback {
- public:
- virtual void onInterest(core::Interest &i) = 0;
- virtual void onError(std::error_code ec) = 0;
+ virtual void onError(const std::error_code &ec) = 0;
};
using OnContentObjectCallback =
@@ -89,21 +51,14 @@ class Portal {
Portal();
- Portal(asio::io_service &io_service);
+ Portal(::utils::EventThread &worker);
/**
- * Set the consumer callback.
- *
- * @param consumer_callback - The pointer to the ConsumerCallback object.
- */
- void setConsumerCallback(ConsumerCallback *consumer_callback);
-
- /**
- * Set the producer callback.
+ * Set the transport protocl callback.
*
* @param producer_callback - The pointer to the ProducerCallback object.
*/
- void setProducerCallback(ProducerCallback *producer_callback);
+ void registerTransportCallback(TransportCallback *transport_callback);
/**
* Connect the transport to the local hicn forwarder.
@@ -146,34 +101,12 @@ class Portal {
UNSET_CALLBACK);
/**
- * 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.
- */
- void bind(const BindConfig &config);
-
- void runEventsLoop();
-
- /**
- * Run one event and return.
- */
- void runOneEvent();
-
- /**
* 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.
*/
void sendContentObject(core::ContentObject &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.
- */
- void stopEventsLoop();
/**
* Disconnect the transport from the local forwarder.
@@ -188,15 +121,26 @@ class Portal {
/**
* Get a reference to the io_service object.
*/
- asio::io_service &getIoService();
+ utils::EventThread &getThread();
/**
* Register a route to the local forwarder.
*/
void registerRoute(core::Prefix &prefix);
+ /**
+ * Send a MAP-Me command to traverse NATs.
+ */
+ void sendMapme();
+
+ /**
+ * Set forwarding strategy
+ */
+ void setForwardingStrategy(core::Prefix &prefix, std::string &strategy);
+
private:
- void *implementation_;
+ class Impl;
+ Impl *implementation_;
};
} // namespace interface
diff --git a/libtransport/includes/hicn/transport/interfaces/publication_options.h b/libtransport/includes/hicn/transport/interfaces/publication_options.h
index 6910e5371..03a0763f5 100644
--- a/libtransport/includes/hicn/transport/interfaces/publication_options.h
+++ b/libtransport/includes/hicn/transport/interfaces/publication_options.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/interfaces/socket_consumer.h b/libtransport/includes/hicn/transport/interfaces/socket_consumer.h
index 5e0e81b9f..e26fe5a85 100644
--- a/libtransport/includes/hicn/transport/interfaces/socket_consumer.h
+++ b/libtransport/includes/hicn/transport/interfaces/socket_consumer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -23,6 +23,8 @@
#include <hicn/transport/interfaces/callbacks.h>
#include <hicn/transport/interfaces/socket_options_default_values.h>
#include <hicn/transport/interfaces/socket_options_keys.h>
+#include <hicn/transport/utils/event_thread.h>
+#include <hicn/transport/utils/noncopyable.h>
#define CONSUMER_FINISHED 0
#define CONSUMER_BUSY 1
@@ -45,7 +47,7 @@ using namespace core;
* It allows to retrieve an application data from one/many producers, by
* hiding all the complexity of the transport protocol used underneath.
*/
-class ConsumerSocket {
+class ConsumerSocket : private utils::NonCopyable {
public:
/**
* The ReadCallback is a class which can be used by the transport for both
@@ -124,7 +126,7 @@ class ConsumerSocket {
*
* @param ec - An error code describing the error.
*/
- virtual void readError(const std::error_code ec) noexcept = 0;
+ virtual void readError(const std::error_code &ec) noexcept = 0;
/**
* This callback will be invoked when the whole content is retrieved. The
@@ -166,7 +168,12 @@ class ConsumerSocket {
* 110, 104-117
* - RTC: Real time communication
*/
- explicit ConsumerSocket(int protocol, asio::io_service &io_service);
+ explicit ConsumerSocket(int protocol, ::utils::EventThread &worker);
+
+ /**
+ * @brief Move contructor
+ */
+ ConsumerSocket(ConsumerSocket &&other) noexcept;
/**
* @brief Destroy the consumer socket.
@@ -200,12 +207,10 @@ class ConsumerSocket {
* 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);
+ int consume(const Name &name, bool blocking = false);
/**
- * Stops the consumer socket. If several downloads are queued (using
- * asyncConsume), this call stops just the current one.
+ * Stops the consumer socket.
*/
void stop();
@@ -255,6 +260,12 @@ class ConsumerSocket {
int setSocketOption(int socket_option_key,
ConsumerTimerCallback socket_option_value);
+ int setSocketOption(int socket_option_key,
+ StrategyCallback socket_option_value);
+
+ int setSocketOption(int socket_option_key,
+ Packet::Format socket_option_value);
+
int getSocketOption(int socket_option_key, double &socket_option_value);
int getSocketOption(int socket_option_key, uint32_t &socket_option_value);
@@ -280,8 +291,14 @@ class ConsumerSocket {
ConsumerTimerCallback **socket_option_value);
int getSocketOption(int socket_option_key,
+ StrategyCallback **socket_option_value);
+
+ int getSocketOption(int socket_option_key,
interface::TransportStatistics **socket_option_value);
+ int getSocketOption(int socket_option_key,
+ Packet::Format &socket_option_value);
+
protected:
ConsumerSocket();
std::unique_ptr<implementation::ConsumerSocket> socket_;
diff --git a/libtransport/includes/hicn/transport/interfaces/socket_options_default_values.h b/libtransport/includes/hicn/transport/interfaces/socket_options_default_values.h
index f4945ac8a..04454852b 100644
--- a/libtransport/includes/hicn/transport/interfaces/socket_options_default_values.h
+++ b/libtransport/includes/hicn/transport/interfaces/socket_options_default_values.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -15,7 +15,10 @@
#pragma once
+extern "C" {
#include <hicn/base.h>
+#include <hicn/compat.h>
+}
#include <chrono>
#include <cstdint>
@@ -26,6 +29,16 @@ namespace interface {
namespace default_values {
+// Packet format
+// #define NEW_PACKET_FORMAT
+static constexpr hicn_format_t packet_format =
+#ifdef NEW_PACKET_FORMAT
+ HF_INET6_UDP;
+#else
+ HF_INET6_TCP;
+#endif
+
+// Parameters
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 =
@@ -40,6 +53,8 @@ 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
+static constexpr uint32_t max_unverified_delay = 2001; // milliseconds
+static constexpr uint32_t manifest_capacity = 30;
// RAAQM
static constexpr int sample_number = 30;
diff --git a/libtransport/includes/hicn/transport/interfaces/socket_options_keys.h b/libtransport/includes/hicn/transport/interfaces/socket_options_keys.h
index 00cd44075..90f218770 100644
--- a/libtransport/includes/hicn/transport/interfaces/socket_options_keys.h
+++ b/libtransport/includes/hicn/transport/interfaces/socket_options_keys.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -26,15 +26,27 @@ namespace transport {
namespace interface {
typedef enum {
- RAAQM = 0,
- CBR = 1,
- RTC = 2,
+ UNKNOWN = 0,
+ BYTE_STREAM = 1,
+ RTC_PROD = 2,
+} ProductionProtocolAlgorithms;
+
+typedef enum {
+ RAAQM = 10,
+ CBR = 11,
+ RTC = 12,
} TransportProtocolAlgorithms;
typedef enum {
- BYTE_STREAM = 10,
- RTC_PROD = 11,
-} ProductionProtocolAlgorithms;
+ RECOVERY_OFF = 20,
+ RTX_ONLY = 21,
+ FEC_ONLY = 22,
+ DELAY_BASED = 23,
+ LOW_RATE = 24,
+ LOW_RATE_AND_BESTPATH = 25,
+ LOW_RATE_AND_REPLICATION = 26,
+ LOW_RATE_AND_ALL_FWD_STRATEGIES = 27,
+} RtcTransportRecoveryStrategies;
typedef enum {
INPUT_BUFFER_SIZE = 101,
@@ -45,6 +57,8 @@ typedef enum {
DATA_PACKET_SIZE = 106,
INTEREST_LIFETIME = 107,
CONTENT_OBJECT_EXPIRY_TIME = 108,
+ MAX_SEGMENT_SIZE = 109,
+ MAX_UNVERIFIED_TIME = 110,
MIN_WINDOW_SIZE = 111,
MAX_WINDOW_SIZE = 112,
CURRENT_WINDOW_SIZE = 113,
@@ -57,7 +71,9 @@ typedef enum {
SIGNER = 121,
VERIFIER = 122,
STATS_INTERVAL = 125,
- SUFFIX_STRATEGY = 126
+ SUFFIX_STRATEGY = 126,
+ PACKET_FORMAT = 127,
+ FEC_TYPE = 128,
} GeneralTransportOptions;
typedef enum {
@@ -87,7 +103,9 @@ typedef enum {
CONTENT_OBJECT_TO_VERIFY = 413,
VERIFICATION_FAILED = 414,
READ_CALLBACK = 415,
- STATS_SUMMARY = 416
+ STATS_SUMMARY = 416,
+ FWD_STRATEGY_CHANGE = 417,
+ REC_STRATEGY_CHANGE = 418,
} ConsumerCallbacksOptions;
typedef enum {
@@ -100,7 +118,8 @@ typedef enum {
CONTENT_OBJECT_READY = 510,
CONTENT_OBJECT_OUTPUT = 511,
CONTENT_PRODUCED = 512,
- CONTENT_OBJECT_TO_SIGN = 513
+ CONTENT_OBJECT_TO_SIGN = 513,
+ PRODUCER_CALLBACK = 514,
} ProducerCallbacksOptions;
typedef enum { OUTPUT_INTERFACE = 601 } DataLinkOptions;
@@ -116,6 +135,11 @@ typedef enum {
RSA_256 = 802,
} SignatureType;
+typedef enum {
+ RECOVERY_STRATEGY = 901,
+ AGGREGATED_DATA = 902,
+} RtcTransportOptions;
+
} // 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
index 27b603dfe..77b89742a 100644
--- a/libtransport/includes/hicn/transport/interfaces/socket_producer.h
+++ b/libtransport/includes/hicn/transport/interfaces/socket_producer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -23,6 +23,8 @@
#include <hicn/transport/interfaces/callbacks.h>
#include <hicn/transport/interfaces/socket_options_default_values.h>
#include <hicn/transport/interfaces/socket_options_keys.h>
+#include <hicn/transport/utils/event_thread.h>
+#include <hicn/transport/utils/noncopyable.h>
namespace transport {
@@ -34,12 +36,28 @@ namespace interface {
using namespace core;
-class ProducerSocket {
+class ProducerSocket : private utils::NonCopyable {
public:
+ /**
+ * @brief This class is used by the transport to notify events to the
+ * application.
+ */
+ class Callback {
+ public:
+ /**
+ * @brief This will invoked in an error occurred in the production protocol.
+ *
+ * @param ec - An error code describing the error.
+ */
+ virtual void produceError(const std::error_code &ec) noexcept = 0;
+ };
+
explicit ProducerSocket(
int protocol = ProductionProtocolAlgorithms::BYTE_STREAM);
- explicit ProducerSocket(int protocol, asio::io_service &io_service);
+ explicit ProducerSocket(int protocol, ::utils::EventThread &worker);
+
+ ProducerSocket(ProducerSocket &&other) noexcept;
virtual ~ProducerSocket();
@@ -63,21 +81,18 @@ class ProducerSocket {
uint32_t produceDatagram(const Name &content_name,
std::unique_ptr<utils::MemBuf> &&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<utils::MemBuf> &&buffer,
- bool is_last, uint32_t offset,
- uint32_t **last_segment = nullptr);
-
void produce(ContentObject &content_object);
- void serveForever();
+ void sendMapme();
void stop();
+ void start();
+
asio::io_service &getIoService();
+ int setSocketOption(int socket_option_key, Callback *socket_option_value);
+
int setSocketOption(int socket_option_key, uint32_t socket_option_value);
int setSocketOption(int socket_option_key,
@@ -111,6 +126,9 @@ class ProducerSocket {
int setSocketOption(int socket_option_key,
const std::string &socket_option_value);
+ int setSocketOption(int socket_option_key,
+ Packet::Format socket_option_value);
+
int getSocketOption(int socket_option_key, uint32_t &socket_option_value);
int getSocketOption(int socket_option_key, bool &socket_option_value);
@@ -138,6 +156,9 @@ class ProducerSocket {
int getSocketOption(int socket_option_key, std::string &socket_option_value);
+ int getSocketOption(int socket_option_key,
+ Packet::Format &socket_option_value);
+
protected:
ProducerSocket(bool);
std::unique_ptr<implementation::ProducerSocket> socket_;
diff --git a/libtransport/includes/hicn/transport/interfaces/statistics.h b/libtransport/includes/hicn/transport/interfaces/statistics.h
index 1ff6f3edd..4d9e1bfe2 100644
--- a/libtransport/includes/hicn/transport/interfaces/statistics.h
+++ b/libtransport/includes/hicn/transport/interfaces/statistics.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -16,6 +16,7 @@
#pragma once
#include <hicn/transport/portability/c_portability.h>
+#include <hicn/transport/utils/chrono_typedefs.h>
#include <cstdint>
@@ -37,6 +38,8 @@ class TransportStatistics {
static constexpr double default_alpha = 0.7;
public:
+ enum class statsAlerts : uint8_t { CONGESTION, LATENCY, LOSSES };
+
TransportStatistics(double alpha = default_alpha)
: retx_count_(0),
bytes_received_(0),
@@ -51,11 +54,15 @@ class TransportStatistics {
lost_data_(0),
definitely_lost_data_(0),
recovered_data_(0),
- status_(-1),
+ status_(0),
// avg_data_rtt_(0),
avg_pending_pkt_(0.0),
received_nacks_(0),
- received_fec_(0) {}
+ received_fec_(0),
+ in_congestion_(false),
+ residual_loss_rate_(0.0),
+ quality_score_(5),
+ alerts_(0) {}
TRANSPORT_ALWAYS_INLINE void updateRetxCount(uint64_t retx) {
retx_count_ += retx;
@@ -65,8 +72,11 @@ class TransportStatistics {
bytes_received_ += bytes;
}
- TRANSPORT_ALWAYS_INLINE void updateAverageRtt(uint64_t rtt) {
- average_rtt_ = (alpha_ * average_rtt_) + ((1. - alpha_) * double(rtt));
+ TRANSPORT_ALWAYS_INLINE void updateAverageRtt(
+ const utils::SteadyTime::Milliseconds &rtt) {
+ auto rtt_milliseconds = rtt.count();
+ average_rtt_ =
+ (alpha_ * average_rtt_) + ((1. - alpha_) * double(rtt_milliseconds));
}
TRANSPORT_ALWAYS_INLINE void updateAverageWindowSize(double current_window) {
@@ -120,6 +130,26 @@ class TransportStatistics {
received_fec_ += pkt;
}
+ TRANSPORT_ALWAYS_INLINE void updateResidualLossRate(double val) {
+ residual_loss_rate_ = val;
+ }
+
+ TRANSPORT_ALWAYS_INLINE void updateQualityScore(uint8_t val) {
+ quality_score_ = val;
+ }
+
+ TRANSPORT_ALWAYS_INLINE void updateCongestionState(bool state) {
+ in_congestion_ = state;
+ }
+
+ TRANSPORT_ALWAYS_INLINE void setAlert(statsAlerts x) {
+ alerts_ |= 1UL << (uint32_t)x;
+ }
+
+ TRANSPORT_ALWAYS_INLINE void clearAlert(statsAlerts x) {
+ alerts_ &= ~(1UL << (uint32_t)x);
+ }
+
TRANSPORT_ALWAYS_INLINE uint64_t getRetxCount() const { return retx_count_; }
TRANSPORT_ALWAYS_INLINE uint64_t getBytesRecv() const {
@@ -174,6 +204,18 @@ class TransportStatistics {
return received_fec_;
}
+ TRANSPORT_ALWAYS_INLINE double getResidualLossRate() const {
+ return residual_loss_rate_;
+ }
+
+ TRANSPORT_ALWAYS_INLINE uint8_t getQualityScore() const {
+ return quality_score_;
+ }
+
+ TRANSPORT_ALWAYS_INLINE bool isCongested() const { return in_congestion_; }
+
+ TRANSPORT_ALWAYS_INLINE uint32_t getAlerts() const { return alerts_; }
+
TRANSPORT_ALWAYS_INLINE void setAlpha(double val) { alpha_ = val; }
TRANSPORT_ALWAYS_INLINE void reset() {
@@ -193,6 +235,8 @@ class TransportStatistics {
avg_pending_pkt_ = 0;
received_nacks_ = 0;
received_fec_ = 0;
+ in_congestion_ = false;
+ quality_score_ = 5;
}
private:
@@ -213,6 +257,14 @@ class TransportStatistics {
double avg_pending_pkt_;
uint32_t received_nacks_;
uint32_t received_fec_;
+ bool in_congestion_;
+ double residual_loss_rate_;
+ uint8_t quality_score_;
+
+ // alerts is a bit vector used to signal to the upper layer that
+ // something bad is appening in the network, the encode is done accoding to
+ // the enum alerts;
+ uint32_t alerts_;
};
} // namespace interface
diff --git a/libtransport/includes/hicn/transport/portability/CMakeLists.txt b/libtransport/includes/hicn/transport/portability/CMakeLists.txt
index 8094c0661..7a688b1f1 100644
--- a/libtransport/includes/hicn/transport/portability/CMakeLists.txt
+++ b/libtransport/includes/hicn/transport/portability/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2019 Cisco and/or its affiliates.
+# Copyright (c) 2021 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
@@ -14,6 +14,7 @@
list(APPEND HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/c_portability.h
${CMAKE_CURRENT_SOURCE_DIR}/portability.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/cpu.h
)
list(APPEND SOURCE_FILES
diff --git a/libtransport/includes/hicn/transport/portability/c_portability.h b/libtransport/includes/hicn/transport/portability/c_portability.h
index 2675de000..bc697d8b1 100644
--- a/libtransport/includes/hicn/transport/portability/c_portability.h
+++ b/libtransport/includes/hicn/transport/portability/c_portability.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/libtransport/includes/hicn/transport/portability/cpu.h b/libtransport/includes/hicn/transport/portability/cpu.h
new file mode 100644
index 000000000..036bf9cd9
--- /dev/null
+++ b/libtransport/includes/hicn/transport/portability/cpu.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2022 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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
+
+#if defined(__aarch64__) && defined(__ARM_NEON) || defined(__i686__)
+#define TRANSPORT_HAVE_VEC128
+#endif
+
+#if defined(__SSE4_2__) && __GNUC__ >= 4
+#define TRANSPORT_HAVE_VEC128
+#endif
+
+#if defined(__ALTIVEC__)
+#define TRANSPORT_HAVE_VEC128
+#endif
+
+#if defined(__AVX2__)
+#define TRANSPORT_HAVE_VEC256
+#if defined(__clang__) && __clang_major__ < 4
+#undef TRANSPORT_HAVE_VEC256
+#endif
+#endif
+
+#if defined(__AVX512BITALG__)
+#define TRANSPORT_HAVE_VEC512
+#endif
diff --git a/libtransport/includes/hicn/transport/portability/portability.h b/libtransport/includes/hicn/transport/portability/portability.h
index 24ef012f7..b093f8892 100644
--- a/libtransport/includes/hicn/transport/portability/portability.h
+++ b/libtransport/includes/hicn/transport/portability/portability.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -28,9 +28,6 @@
namespace portability {
-constexpr bool little_endian_arch = __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__;
-constexpr bool big_endian_arch = !little_endian_arch;
-
// Generalize warning push/pop.
#if defined(__GNUC__) || defined(__clang__)
// Clang & GCC
diff --git a/libtransport/includes/hicn/transport/portability/win_portability.h b/libtransport/includes/hicn/transport/portability/win_portability.h
index 24c7a932a..81aa828cd 100644
--- a/libtransport/includes/hicn/transport/portability/win_portability.h
+++ b/libtransport/includes/hicn/transport/portability/win_portability.h
@@ -1,44 +1,44 @@
-/*
- * 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
-#ifndef NOMINMAX
-#define NOMINMAX
-#endif
-#include <fcntl.h>
-#include <io.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <time.h>
-#include <windows.h>
-#include <winsock2.h>
-#include <ws2ipdef.h>
-#include <ws2tcpip.h>
-
-#include <algorithm>
-
-#define __ORDER_LITTLE_ENDIAN__ 0x41424344UL
-#define __ORDER_BIG_ENDIAN__ 0x44434241UL
-#define __BYTE_ORDER__ ('ABCD')
-#undef DELETE
-
-#define HAVE_STRUCT_TIMESPEC
+/*
+ * Copyright (c) 2021 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
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+#include <fcntl.h>
+#include <io.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h>
+#include <windows.h>
+#include <winsock2.h>
+#include <ws2ipdef.h>
+#include <ws2tcpip.h>
+
+#include <algorithm>
+
+#define __ORDER_LITTLE_ENDIAN__ 0x41424344UL
+#define __ORDER_BIG_ENDIAN__ 0x44434241UL
+#define __BYTE_ORDER__ ('ABCD')
+#undef DELETE
+
+#define HAVE_STRUCT_TIMESPEC
#include <pthread.h> \ No newline at end of file
diff --git a/libtransport/includes/hicn/transport/utils/CMakeLists.txt b/libtransport/includes/hicn/transport/utils/CMakeLists.txt
index 75f727f03..bbd149e09 100644
--- a/libtransport/includes/hicn/transport/utils/CMakeLists.txt
+++ b/libtransport/includes/hicn/transport/utils/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2019 Cisco and/or its affiliates.
+# Copyright (c) 2021 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
@@ -19,6 +19,7 @@ list(APPEND HEADER_FILES
${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}/rtc_quality_score.h
${CMAKE_CURRENT_SOURCE_DIR}/literals.h
${CMAKE_CURRENT_SOURCE_DIR}/conversions.h
${CMAKE_CURRENT_SOURCE_DIR}/linux.h
diff --git a/libtransport/includes/hicn/transport/utils/array.h b/libtransport/includes/hicn/transport/utils/array.h
index 7c0ed65d8..d57bfabaf 100644
--- a/libtransport/includes/hicn/transport/utils/array.h
+++ b/libtransport/includes/hicn/transport/utils/array.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/utils/branch_prediction.h b/libtransport/includes/hicn/transport/utils/branch_prediction.h
index 8cbfaca76..626cb1573 100644
--- a/libtransport/includes/hicn/transport/utils/branch_prediction.h
+++ b/libtransport/includes/hicn/transport/utils/branch_prediction.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/utils/chrono_typedefs.h b/libtransport/includes/hicn/transport/utils/chrono_typedefs.h
index 8f28e763c..ddfbd00cd 100644
--- a/libtransport/includes/hicn/transport/utils/chrono_typedefs.h
+++ b/libtransport/includes/hicn/transport/utils/chrono_typedefs.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -17,11 +17,102 @@
#include <chrono>
+namespace std {
+namespace chrono {
+namespace detail {
+
+template <typename From, typename To>
+struct posix_duration_cast;
+
+// chrono -> timespec caster
+template <typename Rep, typename Period>
+struct posix_duration_cast<std::chrono::duration<Rep, Period>,
+ struct timespec> {
+ static struct timespec cast(std::chrono::duration<Rep, Period> const &d) {
+ struct timespec tv;
+
+ std::chrono::seconds const sec =
+ std::chrono::duration_cast<std::chrono::seconds>(d);
+
+ tv.tv_sec = sec.count();
+ tv.tv_nsec =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(d - sec).count();
+
+ return tv;
+ }
+};
+
+// timespec -> chrono caster
+template <typename Rep, typename Period>
+struct posix_duration_cast<struct timespec,
+ std::chrono::duration<Rep, Period>> {
+ static std::chrono::duration<Rep, Period> cast(struct timespec const &tv) {
+ return std::chrono::duration_cast<std::chrono::duration<Rep, Period>>(
+ std::chrono::seconds(tv.tv_sec) + std::chrono::nanoseconds(tv.tv_nsec));
+ }
+};
+
+} // namespace detail
+
+// chrono -> timespec
+template <typename T, typename Rep, typename Period>
+auto duration_cast(std::chrono::duration<Rep, Period> const &d) ->
+ typename std::enable_if<std::is_same<T, struct timespec>::value,
+ struct timespec>::type {
+ return detail::posix_duration_cast<std::chrono::duration<Rep, Period>,
+ timespec>::cast(d);
+}
+
+// timespec -> chrono
+template <typename Duration>
+Duration duration_cast(struct timespec const &tv) {
+ return detail::posix_duration_cast<struct timespec, Duration>::cast(tv);
+}
+
+} // namespace chrono
+} // namespace std
+
namespace utils {
-using SteadyClock = std::chrono::steady_clock;
-using TimePoint = SteadyClock::time_point;
-using Milliseconds = std::chrono::milliseconds;
-using Microseconds = std::chrono::microseconds;
+template <typename T>
+class Time {
+ public:
+ using Clock = T;
+ using TimePoint = typename Clock::time_point;
+ using Rep = double;
+ using Seconds = std::chrono::duration<Rep>;
+ using Milliseconds = std::chrono::duration<Rep, std::milli>;
+ using Microseconds = std::chrono::duration<Rep, std::micro>;
+
+ static auto now() { return Clock::now(); }
+
+ // From epochs
+ static auto nowMs() {
+ return std::chrono::duration_cast<Milliseconds>(now().time_since_epoch());
+ }
+
+ // From epoch
+ static auto nowUs() {
+ return std::chrono::duration_cast<Microseconds>(now().time_since_epoch());
+ }
+
+ template <typename D>
+ static auto getDuration(const TimePoint &start, const TimePoint &end) {
+ return std::chrono::duration_cast<D>(end - start);
+ }
+
+ static auto getDurationS(const TimePoint &start, const TimePoint &end) {
+ return getDuration<Seconds>(start, end);
+ }
+ static auto getDurationMs(const TimePoint &start, const TimePoint &end) {
+ return getDuration<Milliseconds>(start, end);
+ }
+ static auto getDurationUs(const TimePoint &start, const TimePoint &end) {
+ return getDuration<Microseconds>(start, end);
+ }
+};
+
+using SteadyTime = Time<std::chrono::steady_clock>;
+using SystemTime = Time<std::chrono::system_clock>;
} // namespace utils
diff --git a/libtransport/includes/hicn/transport/utils/conversions.h b/libtransport/includes/hicn/transport/utils/conversions.h
index 52d3e3168..812803175 100644
--- a/libtransport/includes/hicn/transport/utils/conversions.h
+++ b/libtransport/includes/hicn/transport/utils/conversions.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/utils/daemonizator.h b/libtransport/includes/hicn/transport/utils/daemonizator.h
index 028d74865..1d0a0b309 100644
--- a/libtransport/includes/hicn/transport/utils/daemonizator.h
+++ b/libtransport/includes/hicn/transport/utils/daemonizator.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/utils/event_thread.h b/libtransport/includes/hicn/transport/utils/event_thread.h
index 15ec1d62c..2cd2f3aca 100644
--- a/libtransport/includes/hicn/transport/utils/event_thread.h
+++ b/libtransport/includes/hicn/transport/utils/event_thread.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -97,6 +97,19 @@ class EventThread {
io_service_.get().dispatch(std::forward<Func&&>(f));
}
+ template <typename Func>
+ void addAndWaitForExecution(Func&& f) {
+ auto promise = std::promise<void>();
+ auto future = promise.get_future();
+
+ asio::dispatch(io_service_.get(), [&promise, f = std::forward<Func>(f)]() {
+ f();
+ promise.set_value();
+ });
+
+ future.wait();
+ }
+
void stop() {
work_.reset();
diff --git a/libtransport/includes/hicn/transport/utils/fixed_block_allocator.h b/libtransport/includes/hicn/transport/utils/fixed_block_allocator.h
index 298b6f9d1..19b52b37e 100644
--- a/libtransport/includes/hicn/transport/utils/fixed_block_allocator.h
+++ b/libtransport/includes/hicn/transport/utils/fixed_block_allocator.h
@@ -1,23 +1,28 @@
/*
- * Copyright (c) 2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
*/
#pragma once
#include <hicn/transport/portability/c_portability.h>
+#include <hicn/transport/utils/branch_prediction.h>
#include <hicn/transport/utils/singleton.h>
#include <hicn/transport/utils/spinlock.h>
#include <stdint.h>
#include <cassert>
#include <cstdlib>
+#include <list>
#include <memory>
namespace utils {
template <std::size_t SIZE = 512, std::size_t OBJECTS = 4096>
class FixedBlockAllocator
- : public utils::Singleton<FixedBlockAllocator<SIZE, OBJECTS>> {
- friend class utils::Singleton<FixedBlockAllocator<SIZE, OBJECTS>>;
+ : public utils::ThreadLocalSingleton<FixedBlockAllocator<SIZE, OBJECTS>> {
+ friend class utils::ThreadLocalSingleton<FixedBlockAllocator<SIZE, OBJECTS>>;
+
+ static inline const std::size_t BLOCK_SIZE = SIZE;
+ static inline const std::size_t BLOCKS_PER_POOL = OBJECTS;
public:
~FixedBlockAllocator() {
@@ -26,19 +31,19 @@ class FixedBlockAllocator
}
}
- void* allocateBlock(size_t size = SIZE) {
- assert(size <= SIZE);
+ void* allocateBlock() {
uint32_t index;
-
SpinLock::Acquire locked(lock_);
void* p_block = pop();
if (!p_block) {
- if (TRANSPORT_EXPECT_FALSE(current_pool_index_ >= max_objects_)) {
+ if (TRANSPORT_EXPECT_FALSE(current_pool_index_ >= BLOCKS_PER_POOL)) {
// Allocate new memory block
p_pools_.emplace_front(
- new typename std::aligned_storage<SIZE>::type[max_objects_]);
+ new typename std::aligned_storage<SIZE>::type[BLOCKS_PER_POOL]);
// reset current_pool_index_
current_pool_index_ = 0;
+ // Increase total block count
+ block_count_ += BLOCKS_PER_POOL;
}
auto& latest = p_pools_.front();
@@ -59,7 +64,7 @@ class FixedBlockAllocator
}
public:
- std::size_t blockSize() { return block_size_; }
+ std::size_t blockSize() { return BLOCK_SIZE; }
uint32_t blockCount() { return block_count_; }
@@ -69,20 +74,32 @@ class FixedBlockAllocator
uint32_t deallocations() { return deallocations_; }
+ void reset() {
+ p_head_ = nullptr;
+ blocks_in_use_ = 0;
+ allocations_ = 0;
+ deallocations_ = 0;
+ current_pool_index_ = 0;
+ block_count_ = BLOCKS_PER_POOL;
+
+ // Delete all memory pools but the first one
+ for (auto it = std::next(p_pools_.begin()); it != p_pools_.end();) {
+ delete[] * it;
+ it = p_pools_.erase(it);
+ }
+ }
+
private:
FixedBlockAllocator()
- : block_size_(SIZE),
- object_size_(SIZE),
- max_objects_(OBJECTS),
- p_head_(NULL),
+ : p_head_(NULL),
current_pool_index_(0),
- block_count_(0),
+ block_count_(BLOCKS_PER_POOL),
blocks_in_use_(0),
allocations_(0),
deallocations_(0) {
static_assert(SIZE >= sizeof(long*), "SIZE must be at least 8 bytes");
p_pools_.emplace_front(
- new typename std::aligned_storage<SIZE>::type[max_objects_]);
+ new typename std::aligned_storage<SIZE>::type[BLOCKS_PER_POOL]);
}
void push(void* p_memory) {
@@ -106,12 +123,6 @@ class FixedBlockAllocator
Block* p_next;
};
- static std::unique_ptr<FixedBlockAllocator> instance_;
-
- const std::size_t block_size_;
- const std::size_t object_size_;
- const std::size_t max_objects_;
-
Block* p_head_;
uint32_t current_pool_index_;
std::list<typename std::aligned_storage<SIZE>::type*> p_pools_;
@@ -123,10 +134,6 @@ class FixedBlockAllocator
SpinLock lock_;
};
-template <std::size_t A, std::size_t B>
-std::unique_ptr<FixedBlockAllocator<A, B>>
- FixedBlockAllocator<A, B>::instance_ = nullptr;
-
/**
* STL Allocator trait to be used with allocate_shared.
*/
diff --git a/libtransport/includes/hicn/transport/utils/hash.h b/libtransport/includes/hicn/transport/utils/hash.h
index 6815ca4bf..7943596e6 100644
--- a/libtransport/includes/hicn/transport/utils/hash.h
+++ b/libtransport/includes/hicn/transport/utils/hash.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/libtransport/includes/hicn/transport/utils/linux.h b/libtransport/includes/hicn/transport/utils/linux.h
index 4fbf5f01e..03d29c1db 100644
--- a/libtransport/includes/hicn/transport/utils/linux.h
+++ b/libtransport/includes/hicn/transport/utils/linux.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/utils/literals.h b/libtransport/includes/hicn/transport/utils/literals.h
index bd00e0a58..531f67362 100644
--- a/libtransport/includes/hicn/transport/utils/literals.h
+++ b/libtransport/includes/hicn/transport/utils/literals.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/utils/log.h b/libtransport/includes/hicn/transport/utils/log.h
index 0947b755e..f4d39b6b1 100644
--- a/libtransport/includes/hicn/transport/utils/log.h
+++ b/libtransport/includes/hicn/transport/utils/log.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/utils/move_wrapper.h b/libtransport/includes/hicn/transport/utils/move_wrapper.h
index 5dc3b461d..73389948d 100644
--- a/libtransport/includes/hicn/transport/utils/move_wrapper.h
+++ b/libtransport/includes/hicn/transport/utils/move_wrapper.h
@@ -23,6 +23,7 @@ namespace utils {
template <typename F>
struct MoveWrapper : F {
MoveWrapper(F&& f) : F(std::move(f)) {}
+ ~MoveWrapper() = default;
MoveWrapper(MoveWrapper&&) = default;
MoveWrapper& operator=(MoveWrapper&&) = default;
diff --git a/libtransport/includes/hicn/transport/utils/noncopyable.h b/libtransport/includes/hicn/transport/utils/noncopyable.h
index 83923e647..0c54d24a3 100644
--- a/libtransport/includes/hicn/transport/utils/noncopyable.h
+++ b/libtransport/includes/hicn/transport/utils/noncopyable.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/utils/object_pool.h b/libtransport/includes/hicn/transport/utils/object_pool.h
index d9b28e663..63288c655 100644
--- a/libtransport/includes/hicn/transport/utils/object_pool.h
+++ b/libtransport/includes/hicn/transport/utils/object_pool.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -16,6 +16,7 @@
#pragma once
#include <hicn/transport/utils/branch_prediction.h>
+#include <hicn/transport/utils/noncopyable.h>
#include <hicn/transport/utils/spinlock.h>
#include <deque>
@@ -25,7 +26,7 @@
namespace utils {
template <typename T>
-class ObjectPool {
+class ObjectPool : private utils::NonCopyable {
class ObjectDeleter {
public:
ObjectDeleter(ObjectPool<T> *pool = nullptr) : pool_(pool) {}
@@ -47,8 +48,20 @@ class ObjectPool {
ObjectPool() : destructor_(false) {}
- // No copies
- ObjectPool(const ObjectPool &other) = delete;
+ ObjectPool(ObjectPool &&other)
+ : object_pool_lock_(std::move(other.object_pool_lock_)),
+ object_pool_(std::move(other.object_pool_)),
+ destructor_(other.destructor_) {}
+
+ ObjectPool &operator=(ObjectPool &&other) {
+ if (this != &other) {
+ object_pool_lock_ = std::move(other.object_pool_lock_);
+ object_pool_ = std::move(other.object_pool_);
+ destructor_ = other.destructor_;
+ }
+
+ return *this;
+ }
~ObjectPool() {
destructor_ = true;
diff --git a/libtransport/includes/hicn/transport/utils/ring_buffer.h b/libtransport/includes/hicn/transport/utils/ring_buffer.h
index 52629b82b..3032032c9 100644
--- a/libtransport/includes/hicn/transport/utils/ring_buffer.h
+++ b/libtransport/includes/hicn/transport/utils/ring_buffer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/utils/rtc_quality_score.h b/libtransport/includes/hicn/transport/utils/rtc_quality_score.h
new file mode 100644
index 000000000..2e8ca97d3
--- /dev/null
+++ b/libtransport/includes/hicn/transport/utils/rtc_quality_score.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 {
+
+namespace rtc {
+
+class RTCQualityScore {
+ public:
+ RTCQualityScore(){};
+ ~RTCQualityScore(){};
+
+ uint8_t getQualityScore(uint64_t RTT, uint32_t loss_rate) {
+ uint32_t delay_index = getDelay(RTT);
+ uint32_t loss_index = getLossRate(loss_rate);
+ return quality_score_[loss_index][delay_index];
+ }
+
+ private:
+ // see quality score map
+ uint8_t quality_score_[7][6]{{5, 5, 5, 4, 3, 1}, {5, 4, 3, 2, 1, 1},
+ {5, 3, 2, 1, 1, 1}, {5, 2, 1, 1, 1, 1},
+ {4, 1, 1, 1, 1, 1}, {3, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 1}};
+
+ uint8_t getDelay(uint64_t RTT) {
+ uint64_t OWD = RTT / 2;
+ // we should never get a OWD of 0. so we take the first col if OWD is < 5ms
+ if (OWD < 5) return 0;
+ if (OWD < 50) return 1;
+ if (OWD < 100) return 2;
+ if (OWD < 200) return 3;
+ if (OWD < 300) return 4;
+ return 5;
+ }
+
+ uint8_t getLossRate(uint32_t loss_rate) {
+ // we use 3% as mean loss rate
+ if (loss_rate < 3) return 0;
+ if (loss_rate < 10) return 1;
+ if (loss_rate < 20) return 2;
+ if (loss_rate < 30) return 3;
+ if (loss_rate < 40) return 4;
+ if (loss_rate < 50) return 5;
+ return 6;
+ }
+};
+
+} // namespace rtc
+
+} // namespace protocol
+
+} // namespace transport
diff --git a/libtransport/includes/hicn/transport/utils/singleton.h b/libtransport/includes/hicn/transport/utils/singleton.h
index 4b7b19c0a..cdd8b03bf 100644
--- a/libtransport/includes/hicn/transport/utils/singleton.h
+++ b/libtransport/includes/hicn/transport/utils/singleton.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -32,4 +32,17 @@ class Singleton : NonCopyable {
~Singleton() {}
};
+template <typename T>
+class ThreadLocalSingleton : NonCopyable {
+ public:
+ static T& getInstance() {
+ static thread_local T instance;
+ return instance;
+ }
+
+ protected:
+ ThreadLocalSingleton() {}
+ ~ThreadLocalSingleton() {}
+};
+
} // 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
index 009a94454..40fc48de3 100644
--- a/libtransport/includes/hicn/transport/utils/spinlock.h
+++ b/libtransport/includes/hicn/transport/utils/spinlock.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/utils/string_tokenizer.h b/libtransport/includes/hicn/transport/utils/string_tokenizer.h
index 36630eb58..2b2b893a0 100644
--- a/libtransport/includes/hicn/transport/utils/string_tokenizer.h
+++ b/libtransport/includes/hicn/transport/utils/string_tokenizer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/utils/string_utils.h b/libtransport/includes/hicn/transport/utils/string_utils.h
index 313c28cc6..5f9cca13b 100644
--- a/libtransport/includes/hicn/transport/utils/string_utils.h
+++ b/libtransport/includes/hicn/transport/utils/string_utils.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/includes/hicn/transport/utils/thread_pool.h b/libtransport/includes/hicn/transport/utils/thread_pool.h
new file mode 100644
index 000000000..e4e47209c
--- /dev/null
+++ b/libtransport/includes/hicn/transport/utils/thread_pool.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <hicn/transport/utils/event_thread.h>
+#include <hicn/transport/utils/noncopyable.h>
+
+#include <thread>
+#include <vector>
+
+namespace utils {
+
+class ThreadPool : public NonCopyable {
+ public:
+ explicit ThreadPool(
+ std::size_t n_threads = std::thread::hardware_concurrency())
+ : workers_(n_threads > 0 ? n_threads : 1) {}
+
+ std::size_t getNThreads() const { return workers_.size(); }
+ EventThread &getWorker(std::size_t i) { return workers_.at(i); }
+
+ private:
+ std::vector<EventThread> workers_;
+};
+
+} // namespace utils \ No newline at end of file
diff --git a/libtransport/includes/hicn/transport/utils/uri.h b/libtransport/includes/hicn/transport/utils/uri.h
index 7c28e8552..30675e880 100644
--- a/libtransport/includes/hicn/transport/utils/uri.h
+++ b/libtransport/includes/hicn/transport/utils/uri.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/CMakeLists.txt b/libtransport/src/CMakeLists.txt
index 5e0cd38e7..477a21cb1 100644
--- a/libtransport/src/CMakeLists.txt
+++ b/libtransport/src/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2019 Cisco and/or its affiliates.
+# Copyright (c) 2021-2022 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
@@ -11,10 +11,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-include(GNUInstallDirs)
-
-set(ASIO_STANDALONE 1)
-
+##############################################################
+# Source files
+##############################################################
add_subdirectory(core)
add_subdirectory(interfaces)
add_subdirectory(protocols)
@@ -23,49 +22,131 @@ 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 ${LIBTRANSPORT_COMPONENT}-dev
+
+##############################################################
+# Libraries to link
+##############################################################
+set(LIBRARIES
+ PRIVATE ${HICN_LIBRARIES}
+ PRIVATE ${CMAKE_THREAD_LIBS_INIT}
+ PRIVATE ${CMAKE_DL_LIBS}
+ PRIVATE ${OPENSSL_LIBRARIES}
+ PRIVATE ${LIBCONFIG_CPP_LIBRARIES}
+ PRIVATE ${THIRD_PARTY_LIBRARIES}
)
-install(
- FILES "transport.config"
- DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/hicn
- COMPONENT ${LIBTRANSPORT_COMPONENT}
+
+##############################################################
+# Include dirs
+##############################################################
+list(APPEND LIBTRANSPORT_INTERNAL_INCLUDE_DIRS
+ PRIVATE
+ ${CMAKE_THREADS_INCLUDE_DIRS}
+ ${ASIO_INCLUDE_DIRS}
+ ${WINDOWS_INCLUDE_DIRS}
+ ${LIBCONFIG_CPP_INCLUDE_DIRS}
+ ${THIRD_PARTY_INCLUDE_DIRS}
+ PUBLIC
+ ${ASIO_INCLUDE_DIRS}
+ ${OPENSSL_INCLUDE_DIR}
)
-list(APPEND COMPILER_DEFINITIONS
- "-DASIO_STANDALONE"
+list(APPEND LIBTRANSPORT_INTERNAL_INCLUDE_DIRS
+ PRIVATE
+ ${CMAKE_CURRENT_SOURCE_DIR}/
+ PUBLIC
+ $<BUILD_INTERFACE:${Libhicntransport_INCLUDE_DIRS}>
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
-list(INSERT LIBTRANSPORT_INTERNAL_INCLUDE_DIRS 0
- ${CMAKE_CURRENT_SOURCE_DIR}/
- ${CMAKE_CURRENT_BINARY_DIR}/
+
+##############################################################
+# Dependencies
+##############################################################
+list(APPEND DEPENDENCIES
+ ${THIRD_PARTY_DEPENDENCIES}
)
-set(LIBTRANSPORT_INCLUDE_DIRS
- ${LIBTRANSPORT_INCLUDE_DIRS}
- "" CACHE INTERNAL
- "" FORCE
+##############################################################
+# Compiler definitions
+##############################################################
+list(APPEND COMPILER_DEFINITIONS
+ PUBLIC "-DASIO_STANDALONE"
+)
+
+if (ENABLE_RELY)
+ list(APPEND COMPILER_DEFINITIONS
+ PRIVATE "-DENABLE_RELY=1"
+ )
+endif()
+
+
+##############################################################
+# Compiler options
+##############################################################
+list(APPEND COMPILER_OPTIONS
+ ${DEFAULT_COMPILER_OPTIONS}
)
if (NOT WIN32)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
+ list(APPEND COMPILER_OPTIONS
+ PRIVATE "-pthread"
+ )
else ()
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4200 -D_WIN32_WINDOWS=0x0400")
+ list(APPEND COMPILER_OPTIONS
+ PRIVATE "-/wd4200 -D_WIN32_WINDOWS=0x0400"
+ )
if (CMAKE_BUILD_TYPE EQUAL "RELEASE")
- set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /NODEFAULTLIB:\"MSVCRTD\"" )
+ list(APPEND COMPILER_OPTIONS
+ PRIVATE "/NODEFAULTLIB:\"MSVCRTD\""
+ )
endif ()
endif ()
if (${CMAKE_SYSTEM_NAME} MATCHES "Android")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -isystem -lm")
+ list(APPEND COMPILER_OPTIONS
+ PRIVATE "-stdlib=libc++"
+ PRIVATE "-isystem"
+ PRIVATE "-lm"
+ )
endif()
+
+##############################################################
+# Configuration file
+##############################################################
+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 ${LIBTRANSPORT_COMPONENT}-dev
+)
+
+if (${CMAKE_SYSTEM_NAME} MATCHES Darwin OR ${CMAKE_SYSTEM_NAME} MATCHES Linux)
+ install(
+ FILES "transport.config"
+ DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/hicn
+ COMPONENT ${LIBTRANSPORT_COMPONENT}
+ )
+else ()
+ install(
+ FILES "transport.config"
+ DESTINATION ${CMAKE_INSTALL_PREFIX}/etc/hicn
+ COMPONENT ${LIBTRANSPORT_COMPONENT}
+ )
+endif()
+
+
+##############################################################
+# IO Modules
+##############################################################
+add_subdirectory(io_modules)
+
+
+##############################################################
+# Build type
+##############################################################
set (BUILD_TYPES "STATIC")
if (NOT DISABLE_SHARED_LIBRARIES)
@@ -74,8 +155,10 @@ if (NOT DISABLE_SHARED_LIBRARIES)
)
endif()
-add_subdirectory(io_modules)
+##############################################################
+# Build library
+##############################################################
build_library(${LIBTRANSPORT}
${BUILD_TYPES}
SOURCES ${SOURCE_FILES} ${HEADER_FILES}
@@ -84,12 +167,29 @@ build_library(${LIBTRANSPORT}
OBJECT_LIBRARIES ${THIRD_PARTY_OBJECT_LIBRARIES}
DEPENDS ${DEPENDENCIES}
COMPONENT ${LIBTRANSPORT_COMPONENT}
- INCLUDE_DIRS ${LIBTRANSPORT_INCLUDE_DIRS} ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS}
- HEADER_ROOT_DIR hicn/transport
+ INCLUDE_DIRS ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS}
DEFINITIONS ${COMPILER_DEFINITIONS}
- VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}
+ VERSION ${CURRENT_VERSION}
+ EXPORT_NAME ${LIBTRANSPORT_COMPONENT}
+ COMPILE_OPTIONS ${COMPILER_OPTIONS}
)
+
+##############################################################
+# Unit tests
+##############################################################
if (${BUILD_TESTS})
add_subdirectory(test)
endif()
+
+
+##############################################################
+# Cmake config files
+##############################################################
+create_cmake_config (
+ ${LIBTRANSPORT_COMPONENT}
+ INCLUDE_DIRS ${Libhicntransport_INCLUDE_DIRS}
+ VERSION ${CURRENT_VERSION}
+ COMPONENT ${LIBTRANSPORT_COMPONENT}
+ NAMESPACE hicn
+)
diff --git a/libtransport/src/auth/CMakeLists.txt b/libtransport/src/auth/CMakeLists.txt
index 699bc1050..8d3286338 100644
--- a/libtransport/src/auth/CMakeLists.txt
+++ b/libtransport/src/auth/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2019 Cisco and/or its affiliates.
+# Copyright (c) 2021 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
@@ -14,7 +14,6 @@
list(APPEND SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/signer.cc
${CMAKE_CURRENT_SOURCE_DIR}/verifier.cc
- ${CMAKE_CURRENT_SOURCE_DIR}/identity.cc
${CMAKE_CURRENT_SOURCE_DIR}/crypto_hash.cc
${CMAKE_CURRENT_SOURCE_DIR}/crypto_suite.cc
)
diff --git a/libtransport/src/auth/crypto_hash.cc b/libtransport/src/auth/crypto_hash.cc
index b4b0a8b81..f60f46051 100644
--- a/libtransport/src/auth/crypto_hash.cc
+++ b/libtransport/src/auth/crypto_hash.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -15,8 +15,6 @@
#include <hicn/transport/auth/crypto_hash.h>
-using namespace std;
-
namespace transport {
namespace auth {
@@ -28,7 +26,7 @@ CryptoHash::CryptoHash(const CryptoHash &other)
digest_size_(other.digest_size_) {}
CryptoHash::CryptoHash(CryptoHash &&other)
- : digest_type_(move(other.digest_type_)),
+ : digest_type_(std::move(other.digest_type_)),
digest_(other.digest_),
digest_size_(other.digest_size_) {
other.reset();
@@ -43,13 +41,16 @@ CryptoHash::CryptoHash(const uint8_t *hash, size_t size,
memcpy(digest_.data(), hash, size);
}
-CryptoHash::CryptoHash(const vector<uint8_t> &hash, CryptoHashType hash_type)
+CryptoHash::CryptoHash(const std::vector<uint8_t> &hash,
+ CryptoHashType hash_type)
: CryptoHash(hash.data(), hash.size(), hash_type) {}
CryptoHash &CryptoHash::operator=(const CryptoHash &other) {
- digest_type_ = other.digest_type_;
- digest_ = other.digest_;
- digest_size_ = other.digest_size_;
+ if (this != &other) {
+ digest_type_ = other.digest_type_;
+ digest_ = other.digest_;
+ digest_size_ = other.digest_size_;
+ }
return *this;
}
@@ -68,7 +69,7 @@ void CryptoHash::computeDigest(const uint8_t *buffer, size_t len) {
(*hash_evp)(), nullptr);
}
-void CryptoHash::computeDigest(const vector<uint8_t> &buffer) {
+void CryptoHash::computeDigest(const std::vector<uint8_t> &buffer) {
computeDigest(buffer.data(), buffer.size());
}
@@ -102,15 +103,15 @@ void CryptoHash::computeDigest(const utils::MemBuf *buffer) {
EVP_MD_CTX_free(mcdtx);
}
-vector<uint8_t> CryptoHash::getDigest() const { return digest_; }
+std::vector<uint8_t> CryptoHash::getDigest() const { return digest_; }
-string CryptoHash::getStringDigest() const {
- stringstream string_digest;
+std::string CryptoHash::getStringDigest() const {
+ std::stringstream string_digest;
- string_digest << hex << setfill('0');
+ string_digest << std::hex << std::setfill('0');
for (auto byte : digest_) {
- string_digest << hex << setw(2) << static_cast<int>(byte);
+ string_digest << std::hex << std::setw(2) << static_cast<int>(byte);
}
return string_digest.str();
@@ -130,23 +131,23 @@ void CryptoHash::setType(CryptoHashType hash_type) {
void CryptoHash::display() {
switch (digest_type_) {
case CryptoHashType::SHA256:
- cout << "SHA256";
+ std::cout << "SHA256";
break;
case CryptoHashType::SHA512:
- cout << "SHA512";
+ std::cout << "SHA512";
break;
case CryptoHashType::BLAKE2S256:
- cout << "BLAKE2s256";
+ std::cout << "BLAKE2s256";
break;
case CryptoHashType::BLAKE2B512:
- cout << "BLAKE2b512";
+ std::cout << "BLAKE2b512";
break;
default:
- cout << "UNKNOWN";
+ std::cout << "UNKNOWN";
break;
}
- cout << ": " << getStringDigest() << endl;
+ std::cout << ": " << getStringDigest() << std::endl;
}
void CryptoHash::reset() {
@@ -159,19 +160,14 @@ CryptoHashEVP CryptoHash::getEVP(CryptoHashType hash_type) {
switch (hash_type) {
case CryptoHashType::SHA256:
return &EVP_sha256;
- break;
case CryptoHashType::SHA512:
return &EVP_sha512;
- break;
case CryptoHashType::BLAKE2S256:
return &EVP_blake2s256;
- break;
case CryptoHashType::BLAKE2B512:
return &EVP_blake2b512;
- break;
default:
return nullptr;
- break;
}
}
diff --git a/libtransport/src/auth/crypto_suite.cc b/libtransport/src/auth/crypto_suite.cc
index 7e898ef09..44de85212 100644
--- a/libtransport/src/auth/crypto_suite.cc
+++ b/libtransport/src/auth/crypto_suite.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -22,31 +22,61 @@ CryptoSuite getSuite(int nid) {
switch (nid) {
case NID_ecdsa_with_SHA256:
return CryptoSuite::ECDSA_SHA256;
- break;
case NID_ecdsa_with_SHA512:
return CryptoSuite::ECDSA_SHA512;
- break;
case NID_sha256WithRSAEncryption:
return CryptoSuite::RSA_SHA256;
- break;
case NID_sha512WithRSAEncryption:
return CryptoSuite::RSA_SHA512;
- break;
case NID_hmacWithSHA256:
return CryptoSuite::HMAC_SHA256;
- break;
case NID_hmacWithSHA512:
return CryptoSuite::HMAC_SHA512;
- break;
case NID_dsa_with_SHA256:
return CryptoSuite::DSA_SHA256;
- break;
case NID_dsa_with_SHA512:
return CryptoSuite::DSA_SHA512;
- break;
default:
return CryptoSuite::UNKNOWN;
- break;
+ }
+}
+
+std::string getStringSuite(CryptoSuite suite) {
+ switch (suite) {
+ case CryptoSuite::ECDSA_BLAKE2B512:
+ return "ECDSA_BLAKE2B512";
+ case CryptoSuite::ECDSA_BLAKE2S256:
+ return "ECDSA_BLAKE2S256";
+ case CryptoSuite::ECDSA_SHA256:
+ return "ECDSA_SHA256";
+ case CryptoSuite::ECDSA_SHA512:
+ return "ECDSA_SHA512";
+ case CryptoSuite::RSA_BLAKE2B512:
+ return "RSA_BLAKE2B512";
+ case CryptoSuite::RSA_BLAKE2S256:
+ return "RSA_BLAKE2S256";
+ case CryptoSuite::RSA_SHA256:
+ return "RSA_SHA256";
+ case CryptoSuite::RSA_SHA512:
+ return "RSA_SHA512";
+ case CryptoSuite::HMAC_BLAKE2B512:
+ return "HMAC_BLAKE2B512";
+ case CryptoSuite::HMAC_BLAKE2S256:
+ return "HMAC_BLAKE2S256";
+ case CryptoSuite::HMAC_SHA256:
+ return "HMAC_SHA256";
+ case CryptoSuite::HMAC_SHA512:
+ return "HMAC_SHA512";
+ case CryptoSuite::DSA_BLAKE2B512:
+ return "DSA_BLAKE2B512";
+ case CryptoSuite::DSA_BLAKE2S256:
+ return "DSA_BLAKE2S256";
+ case CryptoSuite::DSA_SHA256:
+ return "DSA_SHA256";
+ case CryptoSuite::DSA_SHA512:
+ return "DSA_SHA512";
+ default:
+ return "UNKNOWN";
}
}
diff --git a/libtransport/src/auth/identity.cc b/libtransport/src/auth/identity.cc
deleted file mode 100644
index f56532033..000000000
--- a/libtransport/src/auth/identity.cc
+++ /dev/null
@@ -1,288 +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 <hicn/transport/auth/identity.h>
-
-using namespace std;
-
-// function needed to create the a certificate
-static bool _addRandomSerial(X509 *cert) {
- unsigned long serial = 0;
- unsigned char serial_bytes[sizeof(serial)];
-
- // Construct random positive serial number.
- RAND_bytes(serial_bytes, sizeof(serial_bytes));
- serial_bytes[0] &= 0x7F;
- serial = 0;
- for (size_t i = 0; i < sizeof(serial_bytes); i++) {
- serial = (256 * serial) + serial_bytes[i];
- }
- ASN1_INTEGER_set(X509_get_serialNumber(cert), serial);
- return true;
-}
-
-static bool _addValidityPeriod(X509 *cert, size_t validityDays) {
- // Set the validity from now for the specified number of days.
- X509_gmtime_adj(X509_get_notBefore(cert), (long)0);
- X509_gmtime_adj(X509_get_notAfter(cert), (long)(60 * 60 * 24 * validityDays));
- return true;
-}
-
-static bool _addSubjectName(X509 *cert, const char *subjectname) {
- // Set up the simple subject name and issuer name for the certificate.
- X509_NAME *name = X509_get_subject_name(cert);
-
- if (X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
- (unsigned char *)subjectname, -1, -1, 0)) {
- if (X509_set_issuer_name(cert, name)) {
- return true;
- }
- }
- return false;
-}
-static bool _addCertificateExtensionWithContext(X509 *cert, int nid,
- const char *value) {
- X509_EXTENSION *extension;
- X509V3_CTX context;
-
- X509V3_set_ctx_nodb(&context);
- X509V3_set_ctx(&context, cert, cert, NULL, NULL, 0);
- extension = X509V3_EXT_conf_nid(NULL, &context, nid, value);
- if (extension == NULL) {
- return false;
- }
- X509_add_ext(cert, extension, -1);
- X509_EXTENSION_free(extension);
- return true;
-}
-static bool _addCertificateExtension(X509 *cert, int nid, const char *value) {
- X509_EXTENSION *extension = X509V3_EXT_conf_nid(NULL, NULL, nid, value);
- if (extension == NULL) {
- return false;
- }
- X509_add_ext(cert, extension, -1);
- X509_EXTENSION_free(extension);
- return true;
-}
-
-static bool _addExtensions(X509 *cert) {
- // Add the necessary extensions.
- if (_addCertificateExtension(cert, NID_basic_constraints,
- "critical,CA:FALSE") == true) {
- if (_addCertificateExtension(
- cert, NID_key_usage,
- "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,"
- "keyAgreement") == true) {
- if (_addCertificateExtension(cert, NID_ext_key_usage, "clientAuth") ==
- true) {
- return true;
- }
- }
- }
- return false;
-}
-static bool _addKeyIdentifier(X509 *cert) {
- unsigned char spkid[SHA256_DIGEST_LENGTH];
- char spkid_hex[1 + 2 * SHA256_DIGEST_LENGTH];
- if (ASN1_item_digest(ASN1_ITEM_rptr(X509_PUBKEY), EVP_sha256(),
- X509_get_X509_PUBKEY(cert), spkid, NULL)) {
- for (int i = 0; i < 32; i++) {
- snprintf(&spkid_hex[2 * i], 3, "%02X", (unsigned)spkid[i]);
- }
- if (_addCertificateExtension(cert, NID_subject_key_identifier, spkid_hex) ==
- true) {
- if (_addCertificateExtensionWithContext(
- cert, NID_authority_key_identifier, "keyid:always") == true) {
- return true;
- }
- }
- }
- return false;
-}
-
-namespace transport {
-namespace auth {
-
-Identity::Identity(const string &keystore_path, const string &keystore_pwd,
- CryptoSuite suite, unsigned int signature_len,
- unsigned int validity_days, const string &subject_name)
- : cert_(X509_new(), ::X509_free) {
- // create the file and complete it.
- // first we create the certificate
-
- // to create the cert we will need a private key
-
- std::shared_ptr<EVP_PKEY> privateKey(EVP_PKEY_new(), EVP_PKEY_free);
-
- if (suite == CryptoSuite::RSA_SHA512 || suite == CryptoSuite::RSA_SHA256) {
- RSA *rsa = RSA_new();
- BIGNUM *pub_exp;
-
- pub_exp = BN_new();
-
- BN_set_word(pub_exp, RSA_F4);
- if (1 != RSA_generate_key_ex(rsa, signature_len, pub_exp, NULL))
- throw errors::RuntimeException("can't generate the key");
- if (1 != EVP_PKEY_set1_RSA(privateKey.get(), rsa))
- throw errors::RuntimeException("can't generate the key");
- } else if (suite == CryptoSuite::ECDSA_SHA256) {
- int curve_params;
- switch (signature_len) {
- case 160u:
- curve_params = NID_secp160k1;
- break;
- case 192u:
- curve_params = NID_secp192k1;
- break;
- case 224u:
- curve_params = NID_secp224k1;
- break;
- case 256u:
- curve_params = NID_secp256k1;
- break;
- default:
- curve_params = -1;
- break;
- }
- if (curve_params == -1)
- throw errors::RuntimeException("can't generate the key");
- EC_KEY *ec_key = EC_KEY_new_by_curve_name(curve_params);
- if (ec_key == NULL)
- throw errors::RuntimeException("can't create ecdsa key from curve");
- EC_KEY_set_asn1_flag(ec_key, OPENSSL_EC_NAMED_CURVE);
- if (EC_KEY_generate_key(ec_key) == 0)
- throw errors::RuntimeException("can't generate the ecdsa key");
- if (EVP_PKEY_set1_EC_KEY(privateKey.get(), ec_key) == 0)
- throw errors::RuntimeException("can't generate the ecdsa key");
- } else if (suite == CryptoSuite::DSA_SHA256) {
- DSA *dsa = DSA_new();
- unsigned char buffer[32];
- if (RAND_bytes(buffer, sizeof(buffer)) != 1) {
- throw errors::RuntimeException("can't generate the key");
- }
- if (DSA_generate_parameters_ex(dsa, signature_len, buffer, sizeof(buffer),
- NULL, NULL, NULL) != 1)
- throw errors::RuntimeException("can't generate the key");
- if (DSA_generate_key(dsa) != 1)
- throw errors::RuntimeException("can't generate the key");
- if (EVP_PKEY_set1_DSA(privateKey.get(), dsa) != 1)
- throw errors::RuntimeException("can't generate the key");
- }
- bool success = true;
- success = success && (X509_set_version(cert_.get(), 2) == 1); // 2 => X509v3
- success = success && _addRandomSerial(cert_.get());
- success = success && _addValidityPeriod(cert_.get(), validity_days);
- success = success && (X509_set_pubkey(cert_.get(), privateKey.get()) == 1);
- success = success && _addSubjectName(cert_.get(), subject_name.c_str());
- success = success && _addExtensions(cert_.get());
- success =
- success && (X509_sign(cert_.get(), privateKey.get(), EVP_sha256()) != 0);
- success = success && _addKeyIdentifier(cert_.get());
- if (!success) {
- throw errors::RuntimeException("error while creating the certificate");
- }
- // the certificate is created. We create the pkcs12 object to write the p12
- // file
- PKCS12 *p12 = PKCS12_create(
- keystore_pwd.c_str(), "ccnxuser", privateKey.get(), cert_.get(), NULL, 0,
- 0, 0 /*default iter*/, PKCS12_DEFAULT_ITER /*mac_iter*/, 0);
- filename_ = keystore_path;
- int fp = open(filename_.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0600);
- if (fp == -1) throw errors::RuntimeException("impossible to create the file");
- FILE *fp_f = fdopen(fp, "wb");
- if (fp_f == NULL)
- throw errors::RuntimeException("impossible to create the file");
- i2d_PKCS12_fp(fp_f, p12);
- fclose(fp_f);
- close(fp);
- std::shared_ptr<EVP_PKEY> publickey(X509_get_pubkey(cert_.get()),
- EVP_PKEY_free);
- signer_ = std::shared_ptr<AsymmetricSigner>(
- new AsymmetricSigner(suite, privateKey, publickey));
- signer_->signature_len_ = signature_len;
-}
-
-Identity::Identity(string &keystore_path, string &keystore_pwd,
- CryptoHashType hash_type)
- : cert_(X509_new(), ::X509_free) {
- filename_ = keystore_path;
- pwd_ = keystore_path;
- // get the key and certificate by first opening the keystore file
- FILE *p12file = fopen(keystore_path.c_str(), "r");
- if (p12file == NULL)
- throw errors::RuntimeException("impossible open keystore");
- PKCS12 *p12 = d2i_PKCS12_fp(p12file, NULL);
- EVP_PKEY *privatekey;
- EVP_PKEY *publickey;
- X509 *cert = cert_.get();
- // now we parse the file to get the first key and certificate
- if (1 != PKCS12_parse(p12, keystore_pwd.c_str(), &privatekey, &cert, NULL))
- throw errors::RuntimeException("impossible to get the private key");
- publickey = X509_get_pubkey(cert);
- // to have the cryptosuite we use the nid number that is used to identify the
- // suite.
- CryptoSuite suite = getSuite(X509_get_signature_nid(cert));
- signer_ = std::shared_ptr<AsymmetricSigner>(new AsymmetricSigner(
- suite, std::shared_ptr<EVP_PKEY>(privatekey, EVP_PKEY_free),
- std::shared_ptr<EVP_PKEY>(publickey, EVP_PKEY_free)));
- PKCS12_free(p12);
-}
-
-Identity::Identity(const Identity &other) {
- pwd_ = other.pwd_;
- filename_ = other.filename_;
- signer_ = other.signer_;
- cert_ = other.cert_;
-}
-
-Identity::Identity(Identity &&other) {
- signer_ = std::move(other.signer_);
- other.signer_.reset();
- cert_ = std::move(other.cert_);
- other.cert_.reset();
- pwd_ = other.pwd_;
- other.pwd_ = "";
- filename_ = other.filename_;
- other.filename_ = "";
- signer_ = other.signer_;
- other.signer_ = nullptr;
-}
-
-Identity::~Identity() {}
-
-shared_ptr<AsymmetricSigner> Identity::getSigner() const { return signer_; }
-
-string Identity::getFilename() const { return filename_; }
-
-std::shared_ptr<X509> Identity::getCertificate() const { return cert_; }
-std::shared_ptr<EVP_PKEY> Identity::getPrivateKey() const {
- return signer_->key_;
-}
-
-string Identity::getPassword() const { return pwd_; }
-
-Identity Identity::generateIdentity(const string &subject_name) {
- string keystore_name = "keystore";
- string keystore_password = "password";
- size_t key_length = 1024;
- unsigned int validity_days = 30;
- CryptoSuite suite = CryptoSuite::RSA_SHA256;
-
- return Identity(keystore_name, keystore_password, suite,
- (unsigned int)key_length, validity_days, subject_name);
-}
-
-} // namespace auth
-} // namespace transport
diff --git a/libtransport/src/auth/signer.cc b/libtransport/src/auth/signer.cc
index 884e850ca..e74e2f1b8 100644
--- a/libtransport/src/auth/signer.cc
+++ b/libtransport/src/auth/signer.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2021 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -13,9 +13,9 @@
* limitations under the License.
*/
+#include <glog/logging.h>
#include <hicn/transport/auth/signer.h>
-
-using namespace std;
+#include <hicn/transport/utils/chrono_typedefs.h>
namespace transport {
namespace auth {
@@ -29,31 +29,29 @@ Signer::Signer()
Signer::~Signer() {}
void Signer::signPacket(PacketPtr packet) {
- assert(key_ != nullptr);
+ DCHECK(key_ != nullptr);
core::Packet::Format format = packet->getFormat();
- if (!packet->authenticationHeader()) {
+ if (!packet->hasAH()) {
throw errors::MalformedAHPacketException();
}
// Set signature size
size_t signature_field_len = getSignatureFieldSize();
- packet->setSignatureSize(signature_field_len);
- packet->setSignatureSizeGap(0u);
+ packet->setSignatureFieldSize(signature_field_len);
+ packet->updateLength(); // update IP payload length
// Copy IP+TCP / ICMP header before zeroing them
hicn_header_t header_copy;
hicn_packet_copy_header(format, packet->packet_start_, &header_copy, false);
// Fill in the hICN AH header
- auto now = chrono::duration_cast<chrono::milliseconds>(
- chrono::system_clock::now().time_since_epoch())
- .count();
+ auto now = utils::SteadyTime::nowMs().count();
packet->setSignatureTimestamp(now);
packet->setValidationAlgorithm(suite_);
// Set key ID
- vector<uint8_t> key_id = key_id_.getDigest();
+ std::vector<uint8_t> key_id = key_id_.getDigest();
packet->setKeyId({key_id.data(), key_id.size()});
// Reset fields to compute the packet hash
@@ -61,22 +59,22 @@ void Signer::signPacket(PacketPtr packet) {
// Compute the signature and put it in the packet
signBuffer(packet);
- hicn_packet_copy_header(format, &header_copy, packet->packet_start_, false);
+ packet->setSignature(signature_);
+ packet->setSignatureSize(signature_len_);
- // Set the gap between the signature field size and the signature real size.
- packet->setSignatureSizeGap(signature_field_len - signature_len_);
- memcpy(packet->getSignature(), signature_.data(), signature_len_);
+ // Restore header
+ hicn_packet_copy_header(format, &header_copy, packet->packet_start_, false);
}
void Signer::signBuffer(const std::vector<uint8_t> &buffer) {
- assert(key_ != nullptr);
+ DCHECK(key_ != nullptr);
CryptoHashEVP hash_evp = CryptoHash::getEVP(getHashType());
if (hash_evp == nullptr) {
throw errors::RuntimeException("Unknown hash type");
}
- shared_ptr<EVP_MD_CTX> mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_free);
+ std::shared_ptr<EVP_MD_CTX> mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_free);
if (mdctx == nullptr) {
throw errors::RuntimeException("Digest context allocation failed");
@@ -106,7 +104,7 @@ void Signer::signBuffer(const std::vector<uint8_t> &buffer) {
}
void Signer::signBuffer(const utils::MemBuf *buffer) {
- assert(key_ != nullptr);
+ DCHECK(key_ != nullptr);
CryptoHashEVP hash_evp = CryptoHash::getEVP(getHashType());
if (hash_evp == nullptr) {
@@ -114,7 +112,7 @@ void Signer::signBuffer(const utils::MemBuf *buffer) {
}
const utils::MemBuf *p = buffer;
- shared_ptr<EVP_MD_CTX> mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_free);
+ std::shared_ptr<EVP_MD_CTX> mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_free);
if (mdctx == nullptr) {
throw errors::RuntimeException("Digest context allocation failed");
@@ -147,7 +145,18 @@ void Signer::signBuffer(const utils::MemBuf *buffer) {
signature_.resize(signature_len_);
}
-vector<uint8_t> Signer::getSignature() const { return signature_; }
+std::vector<uint8_t> Signer::getSignature() const { return signature_; }
+
+std::string Signer::getStringSignature() const {
+ std::stringstream string_sig;
+ string_sig << std::hex << std::setfill('0');
+
+ for (auto byte : signature_) {
+ string_sig << std::hex << std::setw(2) << static_cast<int>(byte);
+ }
+
+ return string_sig.str();
+}
size_t Signer::getSignatureSize() const { return signature_len_; }
@@ -159,36 +168,75 @@ size_t Signer::getSignatureFieldSize() const {
return (signature_len_ + 4) - (signature_len_ % 4);
}
+CryptoSuite Signer::getSuite() const { return suite_; }
+
CryptoHashType Signer::getHashType() const {
return ::transport::auth::getHashType(suite_);
}
-CryptoSuite Signer::getSuite() const { return suite_; }
+void Signer::display() {
+ std::cout << getStringSuite(suite_) << ": " << getStringSignature()
+ << std::endl;
+}
// ---------------------------------------------------------
// Void Signer
// ---------------------------------------------------------
-void VoidSigner::signPacket(PacketPtr packet){};
+void VoidSigner::signPacket(PacketPtr packet) {}
-void VoidSigner::signBuffer(const std::vector<uint8_t> &buffer){};
+void VoidSigner::signBuffer(const std::vector<uint8_t> &buffer) {}
-void VoidSigner::signBuffer(const utils::MemBuf *buffer){};
+void VoidSigner::signBuffer(const utils::MemBuf *buffer) {}
// ---------------------------------------------------------
// Asymmetric Signer
// ---------------------------------------------------------
-AsymmetricSigner::AsymmetricSigner(CryptoSuite suite, shared_ptr<EVP_PKEY> key,
- shared_ptr<EVP_PKEY> pub_key) {
+AsymmetricSigner::AsymmetricSigner(CryptoSuite suite,
+ std::shared_ptr<EVP_PKEY> key,
+ std::shared_ptr<EVP_PKEY> pub_key) {
+ setKey(suite, key, pub_key);
+}
+
+AsymmetricSigner::AsymmetricSigner(std::string keystore_path,
+ std::string password) {
+ FILE *p12file = fopen(keystore_path.c_str(), "r");
+
+ if (p12file == nullptr) {
+ throw errors::RuntimeException("failed to read keystore");
+ }
+
+ std::unique_ptr<PKCS12, decltype(&PKCS12_free)> p12(
+ d2i_PKCS12_fp(p12file, nullptr), &PKCS12_free);
+ X509 *cert_raw;
+ EVP_PKEY *key_raw;
+
+ if (PKCS12_parse(p12.get(), password.c_str(), &key_raw, &cert_raw, nullptr) !=
+ 1) {
+ fclose(p12file);
+ throw errors::RuntimeException("failed to parse keystore");
+ }
+
+ std::shared_ptr<EVP_PKEY> key(key_raw, EVP_PKEY_free);
+ std::shared_ptr<EVP_PKEY> pub_key(X509_get_pubkey(cert_raw), EVP_PKEY_free);
+
+ setKey(transport::auth::getSuite(X509_get_signature_nid(cert_raw)), key,
+ pub_key);
+
+ fclose(p12file);
+}
+
+void AsymmetricSigner::setKey(CryptoSuite suite, std::shared_ptr<EVP_PKEY> key,
+ std::shared_ptr<EVP_PKEY> pub_key) {
suite_ = suite;
key_ = key;
- key_id_ = CryptoHash(getHashType());
+ signature_len_ = EVP_PKEY_size(key.get());
+ signature_.resize(signature_len_);
- vector<uint8_t> pbk(i2d_PublicKey(pub_key.get(), nullptr));
+ std::vector<uint8_t> pbk(i2d_PublicKey(pub_key.get(), nullptr));
uint8_t *pbk_ptr = pbk.data();
int len = i2d_PublicKey(pub_key.get(), &pbk_ptr);
- signature_len_ = EVP_PKEY_size(key.get());
- signature_.resize(signature_len_);
+ key_id_ = CryptoHash(getHashType());
key_id_.computeDigest(pbk_ptr, len);
}
@@ -205,9 +253,10 @@ size_t AsymmetricSigner::getSignatureFieldSize() const {
// ---------------------------------------------------------
// Symmetric Signer
// ---------------------------------------------------------
-SymmetricSigner::SymmetricSigner(CryptoSuite suite, const string &passphrase) {
+SymmetricSigner::SymmetricSigner(CryptoSuite suite,
+ const std::string &passphrase) {
suite_ = suite;
- key_ = shared_ptr<EVP_PKEY>(
+ key_ = std::shared_ptr<EVP_PKEY>(
EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, nullptr,
(const unsigned char *)passphrase.c_str(),
passphrase.size()),
diff --git a/libtransport/src/auth/verifier.cc b/libtransport/src/auth/verifier.cc
index c9ac1650f..0c35437f3 100644
--- a/libtransport/src/auth/verifier.cc
+++ b/libtransport/src/auth/verifier.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2021 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -16,12 +16,10 @@
#include <hicn/transport/auth/verifier.h>
#include <protocols/errors.h>
-using namespace std;
-
namespace transport {
namespace auth {
-const vector<VerificationPolicy> Verifier::DEFAULT_FAILED_POLICIES = {
+const std::vector<VerificationPolicy> Verifier::DEFAULT_FAILED_POLICIES = {
VerificationPolicy::DROP,
VerificationPolicy::ABORT,
};
@@ -38,24 +36,21 @@ Verifier::~Verifier() {}
bool Verifier::verifyPacket(PacketPtr packet) {
core::Packet::Format format = packet->getFormat();
- if (!packet->authenticationHeader()) {
+ if (!packet->hasAH()) {
throw errors::MalformedAHPacketException();
}
// Get crypto suite, hash type, signature length
CryptoSuite suite = packet->getValidationAlgorithm();
CryptoHashType hash_type = getHashType(suite);
- size_t signature_len = packet->getSignatureSizeReal();
// Copy IP+TCP / ICMP header before zeroing them
hicn_header_t header_copy;
hicn_packet_copy_header(format, packet->packet_start_, &header_copy, false);
- packet->setSignatureSizeGap(0u);
// Retrieve packet signature
- uint8_t *packet_signature = packet->getSignature();
- vector<uint8_t> signature_raw(packet_signature,
- packet_signature + signature_len);
+ std::vector<uint8_t> signature_raw = packet->getSignature();
+ signature_raw.resize(packet->getSignatureSize());
// Reset fields that are not used to compute signature
packet->resetForHash();
@@ -66,12 +61,14 @@ bool Verifier::verifyPacket(PacketPtr packet) {
// Restore header
hicn_packet_copy_header(format, &header_copy, packet->packet_start_, false);
- packet->setSignatureSizeGap(packet->getSignatureSize() - signature_len);
+ packet->setSignature(signature_raw);
+ packet->setSignatureSize(signature_raw.size());
return valid_packet;
}
-Verifier::PolicyMap Verifier::verifyPackets(const vector<PacketPtr> &packets) {
+Verifier::PolicyMap Verifier::verifyPackets(
+ const std::vector<PacketPtr> &packets) {
PolicyMap policies;
for (const auto &packet : packets) {
@@ -82,8 +79,8 @@ Verifier::PolicyMap Verifier::verifyPackets(const vector<PacketPtr> &packets) {
policy = VerificationPolicy::ACCEPT;
}
+ callVerificationFailedCallback(suffix, policy);
policies[suffix] = policy;
- callVerificationFailedCallback(packet, policy);
}
return policies;
@@ -105,14 +102,15 @@ Verifier::PolicyMap Verifier::verifyHashes(const SuffixMap &packet_map,
}
}
+ callVerificationFailedCallback(packet_hash.first, policy);
policies[packet_hash.first] = policy;
}
return policies;
}
-Verifier::PolicyMap Verifier::verifyPackets(const vector<PacketPtr> &packets,
- const SuffixMap &suffix_map) {
+Verifier::PolicyMap Verifier::verifyPackets(
+ const std::vector<PacketPtr> &packets, const SuffixMap &suffix_map) {
PolicyMap policies;
for (const auto &packet : packets) {
@@ -130,8 +128,8 @@ Verifier::PolicyMap Verifier::verifyPackets(const vector<PacketPtr> &packets,
}
}
+ callVerificationFailedCallback(suffix, policy);
policies[suffix] = policy;
- callVerificationFailedCallback(packet, policy);
}
return policies;
@@ -139,7 +137,7 @@ Verifier::PolicyMap Verifier::verifyPackets(const vector<PacketPtr> &packets,
void Verifier::setVerificationFailedCallback(
VerificationFailedCallback verfication_failed_cb,
- const vector<VerificationPolicy> &failed_policies) {
+ const std::vector<VerificationPolicy> &failed_policies) {
verification_failed_cb_ = verfication_failed_cb;
failed_policies_ = failed_policies;
}
@@ -149,7 +147,7 @@ void Verifier::getVerificationFailedCallback(
*verfication_failed_cb = &verification_failed_cb_;
}
-void Verifier::callVerificationFailedCallback(PacketPtr packet,
+void Verifier::callVerificationFailedCallback(Suffix suffix,
VerificationPolicy &policy) {
if (verification_failed_cb_ == interface::VOID_HANDLER) {
return;
@@ -157,10 +155,7 @@ void Verifier::callVerificationFailedCallback(PacketPtr packet,
if (find(failed_policies_.begin(), failed_policies_.end(), policy) !=
failed_policies_.end()) {
- policy = verification_failed_cb_(
- static_cast<const core::ContentObject &>(*packet),
- make_error_code(
- protocol::protocol_error::signature_verification_failed));
+ policy = verification_failed_cb_(suffix, policy);
}
}
@@ -169,71 +164,75 @@ void Verifier::callVerificationFailedCallback(PacketPtr packet,
// ---------------------------------------------------------
bool VoidVerifier::verifyPacket(PacketPtr packet) { return true; }
-bool VoidVerifier::verifyBuffer(const vector<uint8_t> &buffer,
- const vector<uint8_t> &signature,
+bool VoidVerifier::verifyBuffer(const std::vector<uint8_t> &buffer,
+ const std::vector<uint8_t> &signature,
CryptoHashType hash_type) {
return true;
}
bool VoidVerifier::verifyBuffer(const utils::MemBuf *buffer,
- const vector<uint8_t> &signature,
+ const std::vector<uint8_t> &signature,
CryptoHashType hash_type) {
return true;
}
Verifier::PolicyMap VoidVerifier::verifyPackets(
- const vector<PacketPtr> &packets) {
+ const std::vector<PacketPtr> &packets) {
PolicyMap policies;
for (const auto &packet : packets) {
- policies[packet->getName().getSuffix()] = VerificationPolicy::ACCEPT;
+ auth::Suffix suffix = packet->getName().getSuffix();
+ VerificationPolicy policy = VerificationPolicy::ACCEPT;
+ callVerificationFailedCallback(suffix, policy);
+ policies[suffix] = policy;
}
return policies;
}
Verifier::PolicyMap VoidVerifier::verifyPackets(
- const vector<PacketPtr> &packets, const SuffixMap &suffix_map) {
+ const std::vector<PacketPtr> &packets, const SuffixMap &suffix_map) {
return verifyPackets(packets);
}
// ---------------------------------------------------------
// Asymmetric Verifier
// ---------------------------------------------------------
-AsymmetricVerifier::AsymmetricVerifier(shared_ptr<EVP_PKEY> key) {
+AsymmetricVerifier::AsymmetricVerifier(std::shared_ptr<EVP_PKEY> key) {
setKey(key);
}
-AsymmetricVerifier::AsymmetricVerifier(const string &cert_path) {
+AsymmetricVerifier::AsymmetricVerifier(const std::string &cert_path) {
useCertificate(cert_path);
}
-AsymmetricVerifier::AsymmetricVerifier(shared_ptr<X509> cert) {
+AsymmetricVerifier::AsymmetricVerifier(std::shared_ptr<X509> cert) {
useCertificate(cert);
}
-void AsymmetricVerifier::setKey(shared_ptr<EVP_PKEY> key) { key_ = key; };
+void AsymmetricVerifier::setKey(std::shared_ptr<EVP_PKEY> key) { key_ = key; };
-void AsymmetricVerifier::useCertificate(const string &cert_path) {
+void AsymmetricVerifier::useCertificate(const std::string &cert_path) {
FILE *certf = fopen(cert_path.c_str(), "rb");
if (certf == nullptr) {
throw errors::RuntimeException("Certificate not found");
}
- shared_ptr<X509> cert = shared_ptr<X509>(
+ std::shared_ptr<X509> cert = std::shared_ptr<X509>(
PEM_read_X509(certf, nullptr, nullptr, nullptr), ::X509_free);
useCertificate(cert);
fclose(certf);
}
-void AsymmetricVerifier::useCertificate(shared_ptr<X509> cert) {
- key_ = shared_ptr<EVP_PKEY>(X509_get_pubkey(cert.get()), ::EVP_PKEY_free);
+void AsymmetricVerifier::useCertificate(std::shared_ptr<X509> cert) {
+ key_ =
+ std::shared_ptr<EVP_PKEY>(X509_get_pubkey(cert.get()), ::EVP_PKEY_free);
}
-bool AsymmetricVerifier::verifyBuffer(const vector<uint8_t> &buffer,
- const vector<uint8_t> &signature,
+bool AsymmetricVerifier::verifyBuffer(const std::vector<uint8_t> &buffer,
+ const std::vector<uint8_t> &signature,
CryptoHashType hash_type) {
CryptoHashEVP hash_evp = CryptoHash::getEVP(hash_type);
@@ -241,7 +240,7 @@ bool AsymmetricVerifier::verifyBuffer(const vector<uint8_t> &buffer,
throw errors::RuntimeException("Unknown hash type");
}
- shared_ptr<EVP_MD_CTX> mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_free);
+ std::shared_ptr<EVP_MD_CTX> mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_free);
if (mdctx == nullptr) {
throw errors::RuntimeException("Digest context allocation failed");
@@ -261,7 +260,7 @@ bool AsymmetricVerifier::verifyBuffer(const vector<uint8_t> &buffer,
}
bool AsymmetricVerifier::verifyBuffer(const utils::MemBuf *buffer,
- const vector<uint8_t> &signature,
+ const std::vector<uint8_t> &signature,
CryptoHashType hash_type) {
CryptoHashEVP hash_evp = CryptoHash::getEVP(hash_type);
@@ -270,7 +269,7 @@ bool AsymmetricVerifier::verifyBuffer(const utils::MemBuf *buffer,
}
const utils::MemBuf *p = buffer;
- shared_ptr<EVP_MD_CTX> mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_free);
+ std::shared_ptr<EVP_MD_CTX> mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_free);
if (mdctx == nullptr) {
throw errors::RuntimeException("Digest context allocation failed");
@@ -296,21 +295,21 @@ bool AsymmetricVerifier::verifyBuffer(const utils::MemBuf *buffer,
// ---------------------------------------------------------
// Symmetric Verifier
// ---------------------------------------------------------
-SymmetricVerifier::SymmetricVerifier(const string &passphrase) {
+SymmetricVerifier::SymmetricVerifier(const std::string &passphrase) {
setPassphrase(passphrase);
}
// Create and set a symmetric key from a passphrase.
-void SymmetricVerifier::setPassphrase(const string &passphrase) {
- key_ = shared_ptr<EVP_PKEY>(
+void SymmetricVerifier::setPassphrase(const std::string &passphrase) {
+ key_ = std::shared_ptr<EVP_PKEY>(
EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, nullptr,
(const unsigned char *)passphrase.c_str(),
passphrase.size()),
EVP_PKEY_free);
}
-bool SymmetricVerifier::verifyBuffer(const vector<uint8_t> &buffer,
- const vector<uint8_t> &signature,
+bool SymmetricVerifier::verifyBuffer(const std::vector<uint8_t> &buffer,
+ const std::vector<uint8_t> &signature,
CryptoHashType hash_type) {
CryptoHashEVP hash_evp = CryptoHash::getEVP(hash_type);
@@ -318,9 +317,9 @@ bool SymmetricVerifier::verifyBuffer(const vector<uint8_t> &buffer,
throw errors::RuntimeException("Unknown hash type");
}
- vector<uint8_t> signature_bis(signature.size());
+ std::vector<uint8_t> signature_bis(signature.size());
size_t signature_bis_len;
- shared_ptr<EVP_MD_CTX> mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_free);
+ std::shared_ptr<EVP_MD_CTX> mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_free);
if (mdctx == nullptr) {
throw errors::RuntimeException("Digest context allocation failed");
@@ -344,7 +343,7 @@ bool SymmetricVerifier::verifyBuffer(const vector<uint8_t> &buffer,
}
bool SymmetricVerifier::verifyBuffer(const utils::MemBuf *buffer,
- const vector<uint8_t> &signature,
+ const std::vector<uint8_t> &signature,
CryptoHashType hash_type) {
CryptoHashEVP hash_evp = CryptoHash::getEVP(hash_type);
@@ -353,9 +352,9 @@ bool SymmetricVerifier::verifyBuffer(const utils::MemBuf *buffer,
}
const utils::MemBuf *p = buffer;
- vector<uint8_t> signature_bis(signature.size());
+ std::vector<uint8_t> signature_bis(signature.size());
size_t signature_bis_len;
- shared_ptr<EVP_MD_CTX> mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_free);
+ std::shared_ptr<EVP_MD_CTX> mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_free);
if (mdctx == nullptr) {
throw errors::RuntimeException("Digest context allocation failed");
diff --git a/libtransport/src/config.h.in b/libtransport/src/config.h.in
index 73a326a84..231a370aa 100644
--- a/libtransport/src/config.h.in
+++ b/libtransport/src/config.h.in
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -19,13 +19,12 @@
#define HICNTRANSPORT_VERSION_MAJOR "@VERSION_MAJOR@"
#define HICNTRANSPORT_VERSION_MINOR "@VERSION_MINOR@"
-#define HICNTRANSPORT_VERSION_REVISION "@VERSION_REVISION@"
+#define HICNTRANSPORT_VERSION_PATCH "@VERSION_PATCH@"
#ifndef ASIO_STANDALONE
#cmakedefine ASIO_STANDALONE
#endif
#define RAAQM_CONFIG_PATH "@raaqm_config_path@"
-#define ENABLE_RELY @ENABLE_RELY@
#cmakedefine __vpp__
diff --git a/libtransport/src/core/CMakeLists.txt b/libtransport/src/core/CMakeLists.txt
index e442bb863..b9b024d60 100644
--- a/libtransport/src/core/CMakeLists.txt
+++ b/libtransport/src/core/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2019 Cisco and/or its affiliates.
+# Copyright (c) 2021 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
@@ -22,6 +22,9 @@ list(APPEND HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/errors.h
${CMAKE_CURRENT_SOURCE_DIR}/global_configuration.h
${CMAKE_CURRENT_SOURCE_DIR}/local_connector.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/global_workers.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/udp_connector.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/udp_listener.h
)
list(APPEND SOURCE_FILES
@@ -36,7 +39,21 @@ list(APPEND SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/global_configuration.cc
${CMAKE_CURRENT_SOURCE_DIR}/io_module.cc
${CMAKE_CURRENT_SOURCE_DIR}/local_connector.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/udp_connector.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/udp_listener.cc
)
+if (NOT ${CMAKE_SYSTEM_NAME} MATCHES Android)
+ if (UNIX AND NOT APPLE)
+ list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/memif_connector.cc
+ )
+
+ list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/memif_connector.h
+ )
+ endif()
+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/content_object.cc b/libtransport/src/core/content_object.cc
index 411494fdf..643e0388e 100644
--- a/libtransport/src/core/content_object.cc
+++ b/libtransport/src/core/content_object.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -35,6 +35,11 @@ namespace core {
ContentObject::ContentObject(const Name &name, Packet::Format format,
std::size_t additional_header_size)
: Packet(format, additional_header_size) {
+ if (TRANSPORT_EXPECT_FALSE(hicn_packet_set_data(format_, packet_start_) <
+ 0)) {
+ throw errors::MalformedPacketException();
+ }
+
if (TRANSPORT_EXPECT_FALSE(
hicn_data_set_name(format, packet_start_, &name.name_) < 0)) {
throw errors::RuntimeException("Error filling the packet name.");
@@ -47,15 +52,20 @@ ContentObject::ContentObject(const Name &name, Packet::Format format,
}
}
-#ifdef __ANDROID__
ContentObject::ContentObject(hicn_format_t format,
std::size_t additional_header_size)
- : ContentObject(Name("0::0|0"), format, additional_header_size) {}
+ : ContentObject(
+#ifdef __ANDROID__
+ Name("0::0|0"),
#else
-ContentObject::ContentObject(hicn_format_t format,
- std::size_t additional_header_size)
- : ContentObject(Packet::base_name, format, additional_header_size) {}
+ Packet::base_name,
#endif
+ format, additional_header_size) {
+ if (TRANSPORT_EXPECT_FALSE(hicn_packet_set_data(format_, packet_start_) <
+ 0)) {
+ throw errors::MalformedPacketException();
+ }
+}
ContentObject::ContentObject(const Name &name, hicn_format_t format,
std::size_t additional_header_size,
@@ -167,6 +177,23 @@ void ContentObject::resetForHash() {
}
}
+bool ContentObject::isLast() const {
+ int is_last = 0;
+ if (hicn_data_is_last(format_, packet_start_, &is_last) < 0) {
+ throw errors::RuntimeException(
+ "Impossible to get last data flag from packet header.");
+ }
+
+ return is_last;
+}
+
+void ContentObject::setLast() {
+ if (hicn_data_set_last(format_, packet_start_) < 0) {
+ throw errors::RuntimeException(
+ "Impossible to set last data flag to packet header.");
+ }
+}
+
} // end namespace core
} // end namespace transport
diff --git a/libtransport/src/core/errors.cc b/libtransport/src/core/errors.cc
index 82647a60b..68fd7bf38 100644
--- a/libtransport/src/core/errors.cc
+++ b/libtransport/src/core/errors.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -39,6 +39,15 @@ std::string core_category_impl::message(int ev) const {
case core_error::configuration_not_applied: {
return "Configuration was not applied due to wrong parameters.";
}
+ case core_error::send_failed: {
+ return "Error sending data to socket.";
+ }
+ case core_error::send_buffer_allocation_failed: {
+ return "Error allocating buffers to send data.";
+ }
+ case core_error::receive_failed: {
+ return "Error receiving data from socket.";
+ }
default: {
return "Unknown core error";
}
diff --git a/libtransport/src/core/errors.h b/libtransport/src/core/errors.h
index a46f1dbcd..4532e6dc5 100644
--- a/libtransport/src/core/errors.h
+++ b/libtransport/src/core/errors.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -36,7 +36,10 @@ const std::error_category& core_category();
enum class core_error {
success = 0,
configuration_parse_failed,
- configuration_not_applied
+ configuration_not_applied,
+ send_failed,
+ send_buffer_allocation_failed,
+ receive_failed
};
/**
diff --git a/libtransport/src/core/facade.h b/libtransport/src/core/facade.h
index 199081271..1ad4437e2 100644
--- a/libtransport/src/core/facade.h
+++ b/libtransport/src/core/facade.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/core/global_workers.h b/libtransport/src/core/global_workers.h
new file mode 100644
index 000000000..1ac254188
--- /dev/null
+++ b/libtransport/src/core/global_workers.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <hicn/transport/utils/singleton.h>
+#include <hicn/transport/utils/thread_pool.h>
+
+#include <atomic>
+#include <mutex>
+
+namespace transport {
+namespace core {
+
+class GlobalWorkers : public utils::Singleton<GlobalWorkers> {
+ public:
+ friend class utils::Singleton<GlobalWorkers>;
+
+ ::utils::EventThread& getWorker() {
+ return thread_pool_.getWorker(counter_++ % thread_pool_.getNThreads());
+ }
+
+ private:
+ GlobalWorkers() : counter_(0), thread_pool_() {}
+
+ std::atomic_uint16_t counter_;
+ ::utils::ThreadPool thread_pool_;
+};
+
+} // namespace core
+} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/core/interest.cc b/libtransport/src/core/interest.cc
index 9d868ced0..b7719b3ed 100644
--- a/libtransport/src/core/interest.cc
+++ b/libtransport/src/core/interest.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -34,6 +34,10 @@ namespace core {
Interest::Interest(const Name &interest_name, Packet::Format format,
std::size_t additional_header_size)
: Packet(format, additional_header_size) {
+ if (hicn_packet_set_interest(format_, packet_start_) < 0) {
+ throw errors::MalformedPacketException();
+ }
+
if (hicn_interest_set_name(format_, packet_start_,
interest_name.getConstStructReference()) < 0) {
throw errors::MalformedPacketException();
@@ -45,13 +49,18 @@ Interest::Interest(const Name &interest_name, Packet::Format format,
}
}
-#ifdef __ANDROID__
Interest::Interest(hicn_format_t format, std::size_t additional_header_size)
- : Interest(Name("0::0|0"), format, additional_header_size) {}
+ : Interest(
+#ifdef __ANDROID__
+ Name("0::0|0"),
#else
-Interest::Interest(hicn_format_t format, std::size_t additional_header_size)
- : Interest(base_name, format, additional_header_size) {}
+ base_name,
#endif
+ format, additional_header_size) {
+ if (hicn_packet_set_interest(format_, packet_start_) < 0) {
+ throw errors::MalformedPacketException();
+ }
+}
Interest::Interest(MemBuf &&buffer) : Packet(std::move(buffer)) {
if (hicn_interest_get_name(format_, packet_start_,
diff --git a/libtransport/src/core/io_module.cc b/libtransport/src/core/io_module.cc
index a751eabf5..69e4e8bcf 100644
--- a/libtransport/src/core/io_module.cc
+++ b/libtransport/src/core/io_module.cc
@@ -19,8 +19,10 @@
#include <glog/logging.h>
#include <hicn/transport/core/io_module.h>
+#include <iostream>
+
#ifdef ANDROID
-#include <io_modules/udp/hicn_forwarder_module.h>
+#include <io_modules/hicn-light-ng/hicn_forwarder_module.h>
#elif _WIN32
#include <hicn/util/windows/windows_utils.h>
#endif
@@ -55,8 +57,9 @@ IoModule *IoModule::load(const char *module_name) {
if (!creator) {
if ((error = dlerror()) != 0) {
LOG(ERROR) << error;
- return 0;
}
+
+ return 0;
}
// create object and return it
@@ -85,4 +88,4 @@ bool IoModule::unload(IoModule *module) {
}
} // namespace core
-} // namespace transport \ No newline at end of file
+} // namespace transport
diff --git a/libtransport/src/core/local_connector.cc b/libtransport/src/core/local_connector.cc
index 50dadc677..f27be2e5c 100644
--- a/libtransport/src/core/local_connector.cc
+++ b/libtransport/src/core/local_connector.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -32,13 +32,17 @@ void LocalConnector::send(Packet &packet) {
return;
}
+ auto buffer =
+ std::static_pointer_cast<utils::MemBuf>(packet.shared_from_this());
+
DLOG_IF(INFO, VLOG_IS_ON(3)) << "Sending packet to local socket.";
- io_service_.get().post([this, p{packet.shared_from_this()}]() mutable {
- receive_callback_(this, *p, std::make_error_code(std::errc(0)));
+ io_service_.get().post([this, buffer]() mutable {
+ std::vector<utils::MemBuf::Ptr> v{std::move(buffer)};
+ receive_callback_(this, v, std::make_error_code(std::errc(0)));
});
}
-void LocalConnector::send(const uint8_t *packet, std::size_t len) {
+void LocalConnector::send(const utils::MemBuf::Ptr &buffer) {
throw errors::NotImplementedException();
}
diff --git a/libtransport/src/core/local_connector.h b/libtransport/src/core/local_connector.h
index 0e2d8f676..eede89e74 100644
--- a/libtransport/src/core/local_connector.h
+++ b/libtransport/src/core/local_connector.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -42,7 +42,7 @@ class LocalConnector : public Connector {
void send(Packet &packet) override;
- void send(const uint8_t *packet, std::size_t len) override;
+ void send(const utils::MemBuf::Ptr &buffer) override;
void close() override;
diff --git a/libtransport/src/core/manifest.cc b/libtransport/src/core/manifest.cc
index 3f890f3d0..da2689426 100644
--- a/libtransport/src/core/manifest.cc
+++ b/libtransport/src/core/manifest.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/core/manifest.h b/libtransport/src/core/manifest.h
index 9b25ebd67..5bdbfc6ff 100644
--- a/libtransport/src/core/manifest.h
+++ b/libtransport/src/core/manifest.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -16,6 +16,7 @@
#pragma once
#include <core/manifest_format.h>
+#include <glog/logging.h>
#include <hicn/transport/core/content_object.h>
#include <hicn/transport/core/name.h>
@@ -40,17 +41,20 @@ class Manifest : public Base {
using Encoder = typename FormatTraits::Encoder;
using Decoder = typename FormatTraits::Decoder;
- Manifest(std::size_t signature_size = 0)
- : Base(HF_INET6_TCP_AH, signature_size),
+ Manifest(Packet::Format format, std::size_t signature_size = 0)
+ : Base(format, signature_size),
encoder_(*this, signature_size),
decoder_(*this) {
+ DCHECK(_is_ah(format));
Base::setPayloadType(PayloadType::MANIFEST);
}
- Manifest(const core::Name &name, std::size_t signature_size = 0)
- : Base(name, HF_INET6_TCP_AH, signature_size),
+ Manifest(Packet::Format format, const core::Name &name,
+ std::size_t signature_size = 0)
+ : Base(name, format, signature_size),
encoder_(*this, signature_size),
decoder_(*this) {
+ DCHECK(_is_ah(format));
Base::setPayloadType(PayloadType::MANIFEST);
}
@@ -62,6 +66,11 @@ class Manifest : public Base {
Base::setPayloadType(PayloadType::MANIFEST);
}
+ // Useful for decoding manifests while avoiding packet copy
+ template <typename T>
+ Manifest(T &base)
+ : Base(base.getFormat()), encoder_(base, 0, false), decoder_(base) {}
+
virtual ~Manifest() = default;
std::size_t estimateManifestSize(std::size_t additional_entries = 0) {
@@ -78,24 +87,27 @@ class Manifest : public Base {
Manifest &decode() {
Manifest::decoder_.decode();
- manifest_type_ = decoder_.getManifestType();
+ manifest_type_ = decoder_.getType();
+ manifest_transport_type_ = decoder_.getTransportType();
hash_algorithm_ = decoder_.getHashAlgorithm();
- is_last_ = decoder_.getIsFinalManifest();
+ is_last_ = decoder_.getIsLast();
return static_cast<ManifestImpl &>(*this).decodeImpl();
}
- static std::size_t getManifestHeaderSize() {
- return Encoder::getManifestHeaderSize();
+ static std::size_t manifestHeaderSize(
+ interface::ProductionProtocolAlgorithms transport_type =
+ interface::ProductionProtocolAlgorithms::UNKNOWN) {
+ return Encoder::manifestHeaderSize(transport_type);
}
- static std::size_t getManifestEntrySize() {
- return Encoder::getManifestEntrySize();
+ static std::size_t manifestEntrySize() {
+ return Encoder::manifestEntrySize();
}
- Manifest &setManifestType(ManifestType type) {
+ Manifest &setType(ManifestType type) {
manifest_type_ = type;
- encoder_.setManifestType(manifest_type_);
+ encoder_.setType(manifest_type_);
return *this;
}
@@ -105,31 +117,46 @@ class Manifest : public Base {
return *this;
}
- auth::CryptoHashType getHashAlgorithm() { return hash_algorithm_; }
+ auth::CryptoHashType getHashAlgorithm() const { return hash_algorithm_; }
- ManifestType getManifestType() const { return manifest_type_; }
+ ManifestType getType() const { return manifest_type_; }
+
+ interface::ProductionProtocolAlgorithms getTransportType() const {
+ return manifest_transport_type_;
+ }
- bool isFinalManifest() const { return is_last_; }
+ bool getIsLast() 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);
+ Manifest &setParamsBytestream(const ParamsBytestream &params) {
+ manifest_transport_type_ =
+ interface::ProductionProtocolAlgorithms::BYTE_STREAM;
+ encoder_.setParamsBytestream(params);
return *this;
}
- uint32_t getFinalBlockNumber() const {
- return decoder_.getFinalBlockNumber();
+ Manifest &setParamsRTC(const ParamsRTC &params) {
+ manifest_transport_type_ =
+ interface::ProductionProtocolAlgorithms::RTC_PROD;
+ encoder_.setParamsRTC(params);
+ return *this;
+ }
+
+ ParamsBytestream getParamsBytestream() const {
+ return decoder_.getParamsBytestream();
}
+ ParamsRTC getParamsRTC() const { return decoder_.getParamsRTC(); }
+
ManifestVersion getVersion() const { return decoder_.getVersion(); }
- Manifest &setFinalManifest(bool is_final_manifest) {
- encoder_.setIsFinalManifest(is_final_manifest);
- is_last_ = is_final_manifest;
+ Manifest &setIsLast(bool is_last) {
+ encoder_.setIsLast(is_last);
+ is_last_ = is_last;
return *this;
}
@@ -141,6 +168,7 @@ class Manifest : public Base {
protected:
ManifestType manifest_type_;
+ interface::ProductionProtocolAlgorithms manifest_transport_type_;
auth::CryptoHashType hash_algorithm_;
bool is_last_;
diff --git a/libtransport/src/core/manifest_format.h b/libtransport/src/core/manifest_format.h
index 90d221f5e..38f26067e 100644
--- a/libtransport/src/core/manifest_format.h
+++ b/libtransport/src/core/manifest_format.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -17,6 +17,7 @@
#include <hicn/transport/auth/crypto_hash.h>
#include <hicn/transport/core/name.h>
+#include <hicn/transport/interfaces/socket_options_keys.h>
#include <cinttypes>
#include <type_traits>
@@ -26,15 +27,6 @@ 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,
};
@@ -45,18 +37,24 @@ enum class ManifestType : uint8_t {
FLIC_MANIFEST = 3,
};
-/**
- * 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,
+struct ParamsRTC {
+ std::uint64_t timestamp;
+ std::uint32_t prod_rate;
+ std::uint32_t prod_seg;
+ std::uint32_t support_fec;
+
+ bool operator==(const ParamsRTC &other) const {
+ return (timestamp == other.timestamp && prod_rate == other.prod_rate &&
+ prod_seg == other.prod_seg && support_fec == other.support_fec);
+ }
+};
+
+struct ParamsBytestream {
+ std::uint32_t final_segment;
+
+ bool operator==(const ParamsBytestream &other) const {
+ return (final_segment == other.final_segment);
+ }
};
template <typename T>
@@ -84,24 +82,14 @@ class ManifestEncoder {
return static_cast<Implementation &>(*this).clearImpl();
}
- ManifestEncoder &setManifestType(ManifestType type) {
- return static_cast<Implementation &>(*this).setManifestTypeImpl(type);
+ ManifestEncoder &setType(ManifestType type) {
+ return static_cast<Implementation &>(*this).setTypeImpl(type);
}
ManifestEncoder &setHashAlgorithm(auth::CryptoHashType hash) {
return static_cast<Implementation &>(*this).setHashAlgorithmImpl(hash);
}
- ManifestEncoder &setFinalChunkNumber(uint32_t final_chunk) {
- return static_cast<Implementation &>(*this).setFinalChunkImpl(final_chunk);
- }
-
- ManifestEncoder &setNextSegmentCalculationStrategy(
- NextSegmentCalculationStrategy strategy) {
- return static_cast<Implementation &>(*this)
- .setNextSegmentCalculationStrategyImpl(strategy);
- }
-
template <
typename T,
typename = std::enable_if_t<std::is_same<
@@ -116,8 +104,8 @@ class ManifestEncoder {
suffix, std::forward<Hash &&>(hash));
}
- ManifestEncoder &setIsFinalManifest(bool is_last) {
- return static_cast<Implementation &>(*this).setIsFinalManifestImpl(is_last);
+ ManifestEncoder &setIsLast(bool is_last) {
+ return static_cast<Implementation &>(*this).setIsLastImpl(is_last);
}
ManifestEncoder &setVersion(ManifestVersion version) {
@@ -133,17 +121,22 @@ class ManifestEncoder {
return static_cast<Implementation &>(*this).updateImpl();
}
- ManifestEncoder &setFinalBlockNumber(std::uint32_t final_block_number) {
- return static_cast<Implementation &>(*this).setFinalBlockNumberImpl(
- final_block_number);
+ ManifestEncoder &setParamsBytestream(const ParamsBytestream &params) {
+ return static_cast<Implementation &>(*this).setParamsBytestreamImpl(params);
+ }
+
+ ManifestEncoder &setParamsRTC(const ParamsRTC &params) {
+ return static_cast<Implementation &>(*this).setParamsRTCImpl(params);
}
- static std::size_t getManifestHeaderSize() {
- return Implementation::getManifestHeaderSizeImpl();
+ static std::size_t manifestHeaderSize(
+ interface::ProductionProtocolAlgorithms transport_type =
+ interface::ProductionProtocolAlgorithms::UNKNOWN) {
+ return Implementation::manifestHeaderSizeImpl(transport_type);
}
- static std::size_t getManifestEntrySize() {
- return Implementation::getManifestEntrySizeImpl();
+ static std::size_t manifestEntrySize() {
+ return Implementation::manifestEntrySizeImpl();
}
};
@@ -158,21 +151,16 @@ class ManifestDecoder {
void decode() { static_cast<Implementation &>(*this).decodeImpl(); }
- ManifestType getManifestType() const {
- return static_cast<const Implementation &>(*this).getManifestTypeImpl();
- }
-
- auth::CryptoHashType getHashAlgorithm() const {
- return static_cast<const Implementation &>(*this).getHashAlgorithmImpl();
+ ManifestType getType() const {
+ return static_cast<const Implementation &>(*this).getTypeImpl();
}
- uint32_t getFinalChunkNumber() const {
- return static_cast<const Implementation &>(*this).getFinalChunkImpl();
+ interface::ProductionProtocolAlgorithms getTransportType() const {
+ return static_cast<const Implementation &>(*this).getTransportTypeImpl();
}
- NextSegmentCalculationStrategy getNextSegmentCalculationStrategy() const {
- return static_cast<const Implementation &>(*this)
- .getNextSegmentCalculationStrategyImpl();
+ auth::CryptoHashType getHashAlgorithm() const {
+ return static_cast<const Implementation &>(*this).getHashAlgorithmImpl();
}
core::Name getBaseName() const {
@@ -183,8 +171,8 @@ class ManifestDecoder {
return static_cast<Implementation &>(*this).getSuffixHashListImpl();
}
- bool getIsFinalManifest() const {
- return static_cast<const Implementation &>(*this).getIsFinalManifestImpl();
+ bool getIsLast() const {
+ return static_cast<const Implementation &>(*this).getIsLastImpl();
}
ManifestVersion getVersion() const {
@@ -196,8 +184,12 @@ class ManifestDecoder {
.estimateSerializedLengthImpl(number_of_entries);
}
- uint32_t getFinalBlockNumber() const {
- return static_cast<const Implementation &>(*this).getFinalBlockNumberImpl();
+ ParamsBytestream getParamsBytestream() const {
+ return static_cast<const Implementation &>(*this).getParamsBytestreamImpl();
+ }
+
+ ParamsRTC getParamsRTC() const {
+ return static_cast<const Implementation &>(*this).getParamsRTCImpl();
}
};
diff --git a/libtransport/src/core/manifest_format_fixed.cc b/libtransport/src/core/manifest_format_fixed.cc
index 11d4a56cb..4c8a5e031 100644
--- a/libtransport/src/core/manifest_format_fixed.cc
+++ b/libtransport/src/core/manifest_format_fixed.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -27,164 +27,288 @@ FixedManifestEncoder::FixedManifestEncoder(Packet &packet,
bool clear)
: packet_(packet),
max_size_(Packet::default_mtu - packet_.headerSize()),
- manifest_header_(reinterpret_cast<ManifestHeader *>(
- packet_.writableData() + packet_.headerSize())),
- manifest_entries_(
- reinterpret_cast<ManifestEntry *>(manifest_header_ + 1)),
- current_entry_(0),
- signature_size_(signature_size) {
+ signature_size_(signature_size),
+ transport_type_(interface::ProductionProtocolAlgorithms::UNKNOWN),
+ encoded_(false),
+ params_bytestream_({0}),
+ params_rtc_({0}) {
+ manifest_meta_ = reinterpret_cast<ManifestMeta *>(packet_.writableData() +
+ packet_.headerSize());
+ manifest_entry_meta_ =
+ reinterpret_cast<ManifestEntryMeta *>(manifest_meta_ + 1);
+
if (clear) {
- *manifest_header_ = {0};
+ *manifest_meta_ = {0};
+ *manifest_entry_meta_ = {0};
}
}
FixedManifestEncoder::~FixedManifestEncoder() {}
FixedManifestEncoder &FixedManifestEncoder::encodeImpl() {
- packet_.append(sizeof(ManifestHeader) +
- manifest_header_->number_of_entries * sizeof(ManifestEntry));
+ if (encoded_) {
+ return *this;
+ }
+
+ manifest_meta_->transport_type = static_cast<uint8_t>(transport_type_);
+ manifest_entry_meta_->nb_entries = manifest_entries_.size();
+
+ packet_.append(FixedManifestEncoder::manifestHeaderSizeImpl());
packet_.updateLength();
+
+ switch (transport_type_) {
+ case interface::ProductionProtocolAlgorithms::BYTE_STREAM:
+ packet_.appendPayload(
+ reinterpret_cast<const uint8_t *>(&params_bytestream_),
+ MANIFEST_PARAMS_BYTESTREAM_SIZE);
+ break;
+ case interface::ProductionProtocolAlgorithms::RTC_PROD:
+ packet_.appendPayload(reinterpret_cast<const uint8_t *>(&params_rtc_),
+ MANIFEST_PARAMS_RTC_SIZE);
+ break;
+ default:
+ break;
+ }
+
+ packet_.appendPayload(
+ reinterpret_cast<const uint8_t *>(manifest_entries_.data()),
+ manifest_entries_.size() * FixedManifestEncoder::manifestEntrySizeImpl());
+
+ if (TRANSPORT_EXPECT_FALSE(packet_.payloadSize() <
+ estimateSerializedLengthImpl())) {
+ throw errors::RuntimeException("Error encoding the manifest");
+ }
+
+ encoded_ = true;
return *this;
}
FixedManifestEncoder &FixedManifestEncoder::clearImpl() {
- packet_.trimEnd(sizeof(ManifestHeader) +
- manifest_header_->number_of_entries * sizeof(ManifestEntry));
- current_entry_ = 0;
- *manifest_header_ = {0};
+ if (encoded_) {
+ packet_.trimEnd(FixedManifestEncoder::manifestHeaderSizeImpl() +
+ manifest_entries_.size() *
+ FixedManifestEncoder::manifestEntrySizeImpl());
+ }
+
+ transport_type_ = interface::ProductionProtocolAlgorithms::UNKNOWN;
+ encoded_ = false;
+ params_bytestream_ = {0};
+ params_rtc_ = {0};
+ *manifest_meta_ = {0};
+ *manifest_entry_meta_ = {0};
+ manifest_entries_.clear();
+
return *this;
}
-FixedManifestEncoder &FixedManifestEncoder::setHashAlgorithmImpl(
- auth::CryptoHashType algorithm) {
- manifest_header_->hash_algorithm = static_cast<uint8_t>(algorithm);
+FixedManifestEncoder &FixedManifestEncoder::updateImpl() {
+ max_size_ = Packet::default_mtu - packet_.headerSize() - signature_size_;
+ return *this;
+}
+
+FixedManifestEncoder &FixedManifestEncoder::setVersionImpl(
+ ManifestVersion version) {
+ manifest_meta_->version = static_cast<uint8_t>(version);
return *this;
}
-FixedManifestEncoder &FixedManifestEncoder::setManifestTypeImpl(
+FixedManifestEncoder &FixedManifestEncoder::setTypeImpl(
ManifestType manifest_type) {
- manifest_header_->manifest_type = static_cast<uint8_t>(manifest_type);
+ manifest_meta_->type = static_cast<uint8_t>(manifest_type);
+ return *this;
+}
+
+FixedManifestEncoder &FixedManifestEncoder::setHashAlgorithmImpl(
+ auth::CryptoHashType algorithm) {
+ manifest_meta_->hash_algorithm = static_cast<uint8_t>(algorithm);
return *this;
}
-FixedManifestEncoder &
-FixedManifestEncoder::setNextSegmentCalculationStrategyImpl(
- NextSegmentCalculationStrategy strategy) {
- manifest_header_->next_segment_strategy = static_cast<uint8_t>(strategy);
+FixedManifestEncoder &FixedManifestEncoder::setIsLastImpl(bool is_last) {
+ manifest_meta_->is_last = static_cast<uint8_t>(is_last);
return *this;
}
FixedManifestEncoder &FixedManifestEncoder::setBaseNameImpl(
const core::Name &base_name) {
- base_name.copyToDestination(
- reinterpret_cast<uint8_t *>(&manifest_header_->prefix[0]), false);
- manifest_header_->flags.ipv6 =
+ manifest_entry_meta_->is_ipv6 =
base_name.getAddressFamily() == AF_INET6 ? 1_U8 : 0_U8;
+ base_name.copyPrefixToDestination(
+ reinterpret_cast<uint8_t *>(&manifest_entry_meta_->prefix[0]));
return *this;
}
-FixedManifestEncoder &FixedManifestEncoder::addSuffixAndHashImpl(
- uint32_t suffix, const auth::CryptoHash &hash) {
- auto _hash = hash.getDigest();
- addSuffixHashBytes(suffix, _hash.data(), _hash.size());
+FixedManifestEncoder &FixedManifestEncoder::setParamsBytestreamImpl(
+ const ParamsBytestream &params) {
+ transport_type_ = interface::ProductionProtocolAlgorithms::BYTE_STREAM;
+ params_bytestream_ = TransportParamsBytestream{
+ .final_segment = params.final_segment,
+ };
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<uint8_t *>(manifest_entries_[current_entry_].hash), hash,
- length);
+FixedManifestEncoder &FixedManifestEncoder::setParamsRTCImpl(
+ const ParamsRTC &params) {
+ transport_type_ = interface::ProductionProtocolAlgorithms::RTC_PROD;
+ params_rtc_ = TransportParamsRTC{
+ .timestamp = params.timestamp,
+ .prod_rate = params.prod_rate,
+ .prod_seg = params.prod_seg,
+ .support_fec = params.support_fec,
+ };
+ return *this;
+}
- manifest_header_->number_of_entries++;
- current_entry_++;
+FixedManifestEncoder &FixedManifestEncoder::addSuffixAndHashImpl(
+ uint32_t suffix, const auth::CryptoHash &hash) {
+ std::vector<uint8_t> _hash = hash.getDigest();
+
+ manifest_entries_.push_back(ManifestEntry{
+ .suffix = htonl(suffix),
+ .hash = {0},
+ });
+
+ std::memcpy(reinterpret_cast<uint8_t *>(manifest_entries_.back().hash),
+ _hash.data(), _hash.size());
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<uint8_t>(is_last);
- return *this;
-}
-FixedManifestEncoder &FixedManifestEncoder::setVersionImpl(
- ManifestVersion version) {
- manifest_header_->version = static_cast<uint8_t>(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);
+ return FixedManifestEncoder::manifestHeaderSizeImpl(transport_type_) +
+ (manifest_entries_.size() + additional_entries) *
+ FixedManifestEncoder::manifestEntrySizeImpl();
}
-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::manifestHeaderSizeImpl(
+ interface::ProductionProtocolAlgorithms transport_type) {
+ uint32_t params_size = 0;
+
+ switch (transport_type) {
+ case interface::ProductionProtocolAlgorithms::BYTE_STREAM:
+ params_size = MANIFEST_PARAMS_BYTESTREAM_SIZE;
+ break;
+ case interface::ProductionProtocolAlgorithms::RTC_PROD:
+ params_size = MANIFEST_PARAMS_RTC_SIZE;
+ break;
+ default:
+ break;
+ }
-std::size_t FixedManifestEncoder::getManifestHeaderSizeImpl() {
- return sizeof(ManifestHeader);
+ return MANIFEST_META_SIZE + MANIFEST_ENTRY_META_SIZE + params_size;
}
-std::size_t FixedManifestEncoder::getManifestEntrySizeImpl() {
- return sizeof(ManifestEntry);
+std::size_t FixedManifestEncoder::manifestEntrySizeImpl() {
+ return MANIFEST_ENTRY_SIZE;
}
FixedManifestDecoder::FixedManifestDecoder(Packet &packet)
- : packet_(packet),
- manifest_header_(reinterpret_cast<ManifestHeader *>(
- packet_.getPayload()->writableData())),
- manifest_entries_(reinterpret_cast<ManifestEntry *>(
- packet_.getPayload()->writableData() + sizeof(ManifestHeader))) {}
+ : packet_(packet), decoded_(false) {
+ manifest_meta_ =
+ reinterpret_cast<ManifestMeta *>(packet_.getPayload()->writableData());
+ manifest_entry_meta_ =
+ reinterpret_cast<ManifestEntryMeta *>(manifest_meta_ + 1);
+ transport_type_ = getTransportTypeImpl();
+
+ switch (transport_type_) {
+ case interface::ProductionProtocolAlgorithms::BYTE_STREAM:
+ params_bytestream_ = reinterpret_cast<TransportParamsBytestream *>(
+ manifest_entry_meta_ + 1);
+ manifest_entries_ =
+ reinterpret_cast<ManifestEntry *>(params_bytestream_ + 1);
+ break;
+ case interface::ProductionProtocolAlgorithms::RTC_PROD:
+ params_rtc_ =
+ reinterpret_cast<TransportParamsRTC *>(manifest_entry_meta_ + 1);
+ manifest_entries_ = reinterpret_cast<ManifestEntry *>(params_rtc_ + 1);
+ break;
+ default:
+ manifest_entries_ =
+ reinterpret_cast<ManifestEntry *>(manifest_entry_meta_ + 1);
+ break;
+ }
+}
FixedManifestDecoder::~FixedManifestDecoder() {}
void FixedManifestDecoder::decodeImpl() {
+ if (decoded_) {
+ return;
+ }
+
std::size_t packet_size = packet_.payloadSize();
- if (packet_size < sizeof(ManifestHeader) ||
+ if (packet_size <
+ FixedManifestEncoder::manifestHeaderSizeImpl(transport_type_) ||
packet_size < estimateSerializedLengthImpl()) {
throw errors::RuntimeException(
"The packet does not match expected manifest size.");
}
+
+ decoded_ = true;
+}
+
+FixedManifestDecoder &FixedManifestDecoder::clearImpl() {
+ decoded_ = false;
+ return *this;
}
-FixedManifestDecoder &FixedManifestDecoder::clearImpl() { return *this; }
+ManifestType FixedManifestDecoder::getTypeImpl() const {
+ return static_cast<ManifestType>(manifest_meta_->type);
+}
-ManifestType FixedManifestDecoder::getManifestTypeImpl() const {
- return static_cast<ManifestType>(manifest_header_->manifest_type);
+ManifestVersion FixedManifestDecoder::getVersionImpl() const {
+ return static_cast<ManifestVersion>(manifest_meta_->version);
+}
+
+interface::ProductionProtocolAlgorithms
+FixedManifestDecoder::getTransportTypeImpl() const {
+ return static_cast<interface::ProductionProtocolAlgorithms>(
+ manifest_meta_->transport_type);
}
auth::CryptoHashType FixedManifestDecoder::getHashAlgorithmImpl() const {
- return static_cast<auth::CryptoHashType>(manifest_header_->hash_algorithm);
+ return static_cast<auth::CryptoHashType>(manifest_meta_->hash_algorithm);
}
-NextSegmentCalculationStrategy
-FixedManifestDecoder::getNextSegmentCalculationStrategyImpl() const {
- return static_cast<NextSegmentCalculationStrategy>(
- manifest_header_->next_segment_strategy);
+bool FixedManifestDecoder::getIsLastImpl() const {
+ return static_cast<bool>(manifest_meta_->is_last);
+}
+
+core::Name FixedManifestDecoder::getBaseNameImpl() const {
+ if (static_cast<bool>(manifest_entry_meta_->is_ipv6)) {
+ return core::Name(
+ AF_INET6, reinterpret_cast<uint8_t *>(&manifest_entry_meta_->prefix));
+ } else {
+ return core::Name(
+ AF_INET, reinterpret_cast<uint8_t *>(&manifest_entry_meta_->prefix));
+ }
+}
+
+ParamsBytestream FixedManifestDecoder::getParamsBytestreamImpl() const {
+ return ParamsBytestream{
+ .final_segment = params_bytestream_->final_segment,
+ };
+}
+
+ParamsRTC FixedManifestDecoder::getParamsRTCImpl() const {
+ return ParamsRTC{
+ .timestamp = params_rtc_->timestamp,
+ .prod_rate = params_rtc_->prod_rate,
+ .prod_seg = params_rtc_->prod_seg,
+ .support_fec = params_rtc_->support_fec,
+ };
}
typename Fixed::SuffixList FixedManifestDecoder::getSuffixHashListImpl() {
typename Fixed::SuffixList hash_list;
- for (int i = 0; i < manifest_header_->number_of_entries; i++) {
+ for (int i = 0; i < manifest_entry_meta_->nb_entries; i++) {
hash_list.insert(hash_list.end(),
std::make_pair(ntohl(manifest_entries_[i].suffix),
reinterpret_cast<uint8_t *>(
@@ -194,33 +318,11 @@ typename Fixed::SuffixList FixedManifestDecoder::getSuffixHashListImpl() {
return hash_list;
}
-core::Name FixedManifestDecoder::getBaseNameImpl() const {
- if (static_cast<bool>(manifest_header_->flags.ipv6)) {
- return core::Name(AF_INET6,
- reinterpret_cast<uint8_t *>(&manifest_header_->prefix));
- } else {
- return core::Name(AF_INET,
- reinterpret_cast<uint8_t *>(&manifest_header_->prefix));
- }
-}
-
-bool FixedManifestDecoder::getIsFinalManifestImpl() const {
- return static_cast<bool>(manifest_header_->flags.is_last);
-}
-
-ManifestVersion FixedManifestDecoder::getVersionImpl() const {
- return static_cast<ManifestVersion>(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);
+ return FixedManifestEncoder::manifestHeaderSizeImpl(transport_type_) +
+ (manifest_entry_meta_->nb_entries + additional_entries) *
+ FixedManifestEncoder::manifestEntrySizeImpl();
}
} // end namespace core
diff --git a/libtransport/src/core/manifest_format_fixed.h b/libtransport/src/core/manifest_format_fixed.h
index 56ad4ef6d..ade4bf02c 100644
--- a/libtransport/src/core/manifest_format_fixed.h
+++ b/libtransport/src/core/manifest_format_fixed.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -24,26 +24,74 @@ 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 |
-// | |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// Manifest Metadata:
+// 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| Type | Transport Type| Hash Algorithm|L| Reserved |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+// Manifest Entry Metadata:
+// 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
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Nb entries |I| Reserved |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | |
+// + +
+// | |
+// + Prefix +
+// | |
+// + +
+// | |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+// Manifest Transport Parameters - Bytestream:
+// 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
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Final Segment |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+// Manifest Transport Parameters - RTC:
+// 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
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | |
+// + Timestamp +
+// | |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Production Rate |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Current Segment |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |F| |
+// + Reserved for future parameters +
+// | |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+// Manifest Entry:
+// 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
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Packet Suffix |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | |
+// + +
+// | |
+// + +
+// | |
+// + +
+// | |
+// + Packet Digest +
+// | |
+// + +
+// | |
+// + +
+// | |
+// + +
+// | |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
class FixedManifestEncoder;
class FixedManifestDecoder;
@@ -58,28 +106,47 @@ struct Fixed {
using SuffixList = std::list<std::pair<uint32_t, uint8_t *>>;
};
-struct Flags {
- std::uint8_t ipv6 : 1;
- std::uint8_t is_last : 1;
- std::uint8_t unused : 6;
+const size_t MANIFEST_META_SIZE = 4;
+struct __attribute__((__packed__)) ManifestMeta {
+ std::uint8_t version : 4;
+ std::uint8_t type : 4;
+ std::uint8_t transport_type;
+ std::uint8_t hash_algorithm;
+ std::uint8_t is_last;
};
+static_assert(sizeof(ManifestMeta) == MANIFEST_META_SIZE);
-struct ManifestEntry {
- std::uint32_t suffix;
- std::uint32_t hash[8];
+const size_t MANIFEST_ENTRY_META_SIZE = 20;
+struct __attribute__((__packed__)) ManifestEntryMeta {
+ std::uint8_t nb_entries;
+ std::uint8_t is_ipv6;
+ std::uint16_t unused;
+ std::uint32_t prefix[4];
};
+static_assert(sizeof(ManifestEntryMeta) == MANIFEST_ENTRY_META_SIZE);
-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];
+const size_t MANIFEST_PARAMS_BYTESTREAM_SIZE = 4;
+struct __attribute__((__packed__)) TransportParamsBytestream {
+ std::uint32_t final_segment;
+};
+static_assert(sizeof(TransportParamsBytestream) ==
+ MANIFEST_PARAMS_BYTESTREAM_SIZE);
+
+const size_t MANIFEST_PARAMS_RTC_SIZE = 20;
+struct __attribute__((__packed__)) TransportParamsRTC {
+ std::uint64_t timestamp;
+ std::uint32_t prod_rate;
+ std::uint32_t prod_seg;
+ std::uint32_t support_fec;
+};
+static_assert(sizeof(TransportParamsRTC) == MANIFEST_PARAMS_RTC_SIZE);
+
+const size_t MANIFEST_ENTRY_SIZE = 36;
+struct __attribute__((__packed__)) ManifestEntry {
+ std::uint32_t suffix;
+ std::uint32_t hash[8];
};
+static_assert(sizeof(ManifestEntry) == MANIFEST_ENTRY_SIZE);
static const constexpr std::uint8_t manifest_version = 1;
@@ -91,46 +158,48 @@ class FixedManifestEncoder : public ManifestEncoder<FixedManifestEncoder> {
~FixedManifestEncoder();
FixedManifestEncoder &encodeImpl();
-
FixedManifestEncoder &clearImpl();
+ FixedManifestEncoder &updateImpl();
- FixedManifestEncoder &setManifestTypeImpl(ManifestType manifest_type);
-
+ // ManifestMeta
+ FixedManifestEncoder &setVersionImpl(ManifestVersion version);
+ FixedManifestEncoder &setTypeImpl(ManifestType manifest_type);
FixedManifestEncoder &setHashAlgorithmImpl(Fixed::HashType algorithm);
+ FixedManifestEncoder &setIsLastImpl(bool is_last);
- FixedManifestEncoder &setNextSegmentCalculationStrategyImpl(
- NextSegmentCalculationStrategy strategy);
-
+ // ManifestEntryMeta
FixedManifestEncoder &setBaseNameImpl(const core::Name &base_name);
+ // TransportParams
+ FixedManifestEncoder &setParamsBytestreamImpl(const ParamsBytestream &params);
+ FixedManifestEncoder &setParamsRTCImpl(const ParamsRTC &params);
+
+ // ManifestEntry
FixedManifestEncoder &addSuffixAndHashImpl(uint32_t suffix,
const Fixed::Hash &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();
+ static std::size_t manifestHeaderSizeImpl(
+ interface::ProductionProtocolAlgorithms transport_type =
+ interface::ProductionProtocolAlgorithms::UNKNOWN);
+ static std::size_t manifestEntrySizeImpl();
private:
- void addSuffixHashBytes(uint32_t suffix, const uint8_t *hash,
- std::size_t length);
-
Packet &packet_;
std::size_t max_size_;
- ManifestHeader *manifest_header_;
- ManifestEntry *manifest_entries_;
- std::size_t current_entry_;
std::size_t signature_size_;
+ interface::ProductionProtocolAlgorithms transport_type_;
+ bool encoded_;
+
+ // Manifest Header
+ ManifestMeta *manifest_meta_;
+ ManifestEntryMeta *manifest_entry_meta_;
+ TransportParamsBytestream params_bytestream_;
+ TransportParamsRTC params_rtc_;
+
+ // Manifest Entries
+ std::vector<ManifestEntry> manifest_entries_;
};
class FixedManifestDecoder : public ManifestDecoder<FixedManifestDecoder> {
@@ -140,31 +209,40 @@ class FixedManifestDecoder : public ManifestDecoder<FixedManifestDecoder> {
~FixedManifestDecoder();
void decodeImpl();
-
FixedManifestDecoder &clearImpl();
- ManifestType getManifestTypeImpl() const;
-
+ // ManifestMeta
+ ManifestVersion getVersionImpl() const;
+ ManifestType getTypeImpl() const;
+ interface::ProductionProtocolAlgorithms getTransportTypeImpl() const;
Fixed::HashType getHashAlgorithmImpl() const;
+ bool getIsLastImpl() const;
- NextSegmentCalculationStrategy getNextSegmentCalculationStrategyImpl() const;
-
- typename Fixed::SuffixList getSuffixHashListImpl();
-
+ // ManifestEntryMeta
core::Name getBaseNameImpl() const;
- bool getIsFinalManifestImpl() const;
+ // TransportParams
+ ParamsBytestream getParamsBytestreamImpl() const;
+ ParamsRTC getParamsRTCImpl() const;
+
+ // ManifestEntry
+ typename Fixed::SuffixList getSuffixHashListImpl();
std::size_t estimateSerializedLengthImpl(
std::size_t additional_entries = 0) const;
- ManifestVersion getVersionImpl() const;
-
- uint32_t getFinalBlockNumberImpl() const;
-
private:
Packet &packet_;
- ManifestHeader *manifest_header_;
+ interface::ProductionProtocolAlgorithms transport_type_;
+ bool decoded_;
+
+ // Manifest Header
+ ManifestMeta *manifest_meta_;
+ ManifestEntryMeta *manifest_entry_meta_;
+ TransportParamsBytestream *params_bytestream_;
+ TransportParamsRTC *params_rtc_;
+
+ // Manifest Entries
ManifestEntry *manifest_entries_;
};
diff --git a/libtransport/src/core/manifest_inline.h b/libtransport/src/core/manifest_inline.h
index a487ccfe3..ca48a4a79 100644
--- a/libtransport/src/core/manifest_inline.h
+++ b/libtransport/src/core/manifest_inline.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -40,25 +40,26 @@ class ManifestInline
public:
ManifestInline() : ManifestBase() {}
- ManifestInline(const core::Name &name, std::size_t signature_size = 0)
- : ManifestBase(name, signature_size) {}
+ ManifestInline(Packet::Format format, const core::Name &name,
+ std::size_t signature_size = 0)
+ : ManifestBase(format, name, signature_size) {}
template <typename T>
ManifestInline(T &&base) : ManifestBase(std::forward<T &&>(base)) {}
+ template <typename T>
+ ManifestInline(T &base) : ManifestBase(base) {}
+
static TRANSPORT_ALWAYS_INLINE ManifestInline *createManifest(
- const core::Name &manifest_name, ManifestVersion version,
- ManifestType type, HashType algorithm, bool is_last,
- const Name &base_name, NextSegmentCalculationStrategy strategy,
- std::size_t signature_size) {
- auto manifest = new ManifestInline(manifest_name, signature_size);
+ Packet::Format format, const core::Name &manifest_name,
+ ManifestVersion version, ManifestType type, bool is_last,
+ const Name &base_name, HashType hash_algo, std::size_t signature_size) {
+ auto manifest = new ManifestInline(format, manifest_name, signature_size);
manifest->setVersion(version);
- manifest->setManifestType(type);
- manifest->setHashAlgorithm(algorithm);
- manifest->setFinalManifest(is_last);
+ manifest->setType(type);
+ manifest->setHashAlgorithm(hash_algo);
+ manifest->setIsLast(is_last);
manifest->setBaseName(base_name);
- manifest->setNextSegmentCalculationStrategy(strategy);
-
return manifest;
}
@@ -69,8 +70,6 @@ class ManifestInline
ManifestInline &decodeImpl() {
base_name_ = ManifestBase::decoder_.getBaseName();
- next_segment_strategy_ =
- ManifestBase::decoder_.getNextSegmentCalculationStrategy();
suffix_hash_map_ = ManifestBase::decoder_.getSuffixHashList();
return *this;
@@ -96,18 +95,6 @@ class ManifestInline
// 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_;
- }
-
// Convert several manifests into a single map from suffixes to packet hashes.
// All manifests must have been decoded beforehand.
static std::unordered_map<Suffix, Hash> getSuffixMap(
@@ -134,7 +121,6 @@ class ManifestInline
private:
core::Name base_name_;
- NextSegmentCalculationStrategy next_segment_strategy_;
SuffixList suffix_hash_map_;
};
diff --git a/libtransport/src/core/memif_connector.cc b/libtransport/src/core/memif_connector.cc
new file mode 100644
index 000000000..fb38a6e23
--- /dev/null
+++ b/libtransport/src/core/memif_connector.cc
@@ -0,0 +1,497 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <core/errors.h>
+#include <core/memif_connector.h>
+#include <glog/logging.h>
+#include <hicn/transport/errors/not_implemented_exception.h>
+#include <sys/epoll.h>
+
+#include <cstdlib>
+
+/* sstrncpy */
+#include <hicn/util/sstrncpy.h>
+
+#define CANCEL_TIMER 1
+
+namespace transport {
+
+namespace core {
+
+MemifConnector::MemifConnector(PacketReceivedCallback &&receive_callback,
+ PacketSentCallback &&packet_sent,
+ OnCloseCallback &&close_callback,
+ OnReconnectCallback &&on_reconnect,
+ asio::io_service &io_service,
+ std::string app_name)
+ : Connector(std::move(receive_callback), std::move(packet_sent),
+ std::move(close_callback), std::move(on_reconnect)),
+ event_reactor_(),
+ memif_worker_(std::bind(&MemifConnector::threadMain, this)),
+ timer_set_(false),
+ send_timer_(event_reactor_),
+ disconnect_timer_(event_reactor_),
+ io_service_(io_service),
+ work_(asio::make_work_guard(io_service_)),
+ memif_connection_({0}),
+ tx_buf_counter_(0),
+ is_reconnection_(false),
+ data_available_(false),
+ app_name_(app_name),
+ socket_filename_(""),
+ buffer_size_(kbuf_size),
+ log2_ring_size_(klog2_ring_size),
+ max_memif_bufs_(1 << klog2_ring_size) {}
+
+MemifConnector::~MemifConnector() { close(); }
+
+void MemifConnector::connect(uint32_t memif_id, long memif_mode,
+ const std::string &socket_filename,
+ std::size_t buffer_size,
+ std::size_t log2_ring_size) {
+ state_ = State::CONNECTING;
+
+ memif_id_ = memif_id;
+ socket_filename_ = socket_filename;
+ buffer_size_ = buffer_size;
+ log2_ring_size_ = log2_ring_size;
+ max_memif_bufs_ = 1 << log2_ring_size;
+ createMemif(memif_id, memif_mode);
+}
+
+int MemifConnector::createMemif(uint32_t index, uint8_t is_master) {
+ int err = MEMIF_ERR_SUCCESS;
+
+ memif_socket_args_t socket_args;
+ memif_conn_args_t args;
+ memset(&socket_args, 0, sizeof(memif_socket_args_t));
+ memset(&args, 0, sizeof(memif_conn_args_t));
+
+ // Setup memif socket first
+
+ int rc = strcpy_s(socket_args.path, sizeof(socket_args.path) - 1,
+ socket_filename_.c_str());
+ if (rc != EOK) {
+ std::string error = "Provided socket path is larger than " +
+ std::to_string(sizeof(socket_args.path)) + " bytes.";
+ throw errors::RuntimeException(error);
+ }
+
+ rc = strcpy_s(socket_args.app_name, sizeof(socket_args.app_name) - 1,
+ app_name_.c_str());
+ if (rc != EOK) {
+ std::string error = "Provided app_name is larger than " +
+ std::to_string(sizeof(socket_args.app_name)) +
+ " bytes.";
+ throw errors::RuntimeException(error);
+ }
+
+ socket_args.on_control_fd_update = controlFdUpdate;
+ socket_args.alloc = nullptr;
+ socket_args.realloc = nullptr;
+ socket_args.free = nullptr;
+
+ err = memif_create_socket(&args.socket, &socket_args, this);
+
+ if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
+ throw errors::RuntimeException(memif_strerror(err));
+ }
+
+ // Setup memif connection using provided memif_socket_handle_t
+ args.is_master = is_master;
+ args.log2_ring_size = log2_ring_size_;
+ args.buffer_size = buffer_size_;
+ args.num_s2m_rings = 1;
+ args.num_m2s_rings = 1;
+ strcpy_s((char *)args.interface_name, sizeof(args.interface_name), IF_NAME);
+ args.mode = memif_interface_mode_t::MEMIF_INTERFACE_MODE_IP;
+ args.interface_id = index;
+ err = memif_create(&memif_connection_.conn, &args, onConnect, onDisconnect,
+ onInterrupt, this);
+
+ if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
+ throw errors::RuntimeException(memif_strerror(err));
+ }
+
+ memif_connection_.index = (uint16_t)index;
+ memif_connection_.tx_qid = 0;
+ /* alloc memif buffers */
+ memif_connection_.rx_buf_num = 0;
+ memif_connection_.rx_bufs = static_cast<memif_buffer_t *>(
+ malloc(sizeof(memif_buffer_t) * max_memif_bufs_));
+ memif_connection_.tx_buf_num = 0;
+ memif_connection_.tx_bufs = static_cast<memif_buffer_t *>(
+ malloc(sizeof(memif_buffer_t) * max_memif_bufs_));
+
+ return 0;
+}
+
+int MemifConnector::deleteMemif() {
+ if (memif_connection_.rx_bufs) {
+ free(memif_connection_.rx_bufs);
+ }
+
+ memif_connection_.rx_bufs = nullptr;
+ memif_connection_.rx_buf_num = 0;
+
+ if (memif_connection_.tx_bufs) {
+ free(memif_connection_.tx_bufs);
+ }
+
+ memif_connection_.tx_bufs = nullptr;
+ memif_connection_.tx_buf_num = 0;
+
+ int err;
+ /* disconenct then delete memif connection */
+ err = memif_delete(&memif_connection_.conn);
+
+ if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
+ LOG(ERROR) << "memif_delete: " << memif_strerror(err);
+ }
+
+ if (TRANSPORT_EXPECT_FALSE(memif_connection_.conn != nullptr)) {
+ LOG(ERROR) << "memif delete fail";
+ }
+
+ state_ = State::CLOSED;
+
+ return 0;
+}
+
+int MemifConnector::controlFdUpdate(memif_fd_event_t fde, void *private_ctx) {
+ auto self = reinterpret_cast<MemifConnector *>(private_ctx);
+ uint32_t evt = 0;
+
+ /* convert memif event definitions to epoll events */
+ auto events = fde.type;
+ auto fd = fde.fd;
+
+ if (events & MEMIF_FD_EVENT_ERROR) {
+ LOG(ERROR) << "memif fd event: Error";
+ return -1;
+ }
+
+ if (events & MEMIF_FD_EVENT_DEL) {
+ DLOG_IF(INFO, VLOG_IS_ON(4)) << "memif fd event: DEL fd " << fd;
+ return self->event_reactor_.delFileDescriptor(fd);
+ }
+
+ if (events & MEMIF_FD_EVENT_MOD) {
+ DLOG_IF(INFO, VLOG_IS_ON(4)) << "memif fd event: MOD fd " << fd;
+ return self->event_reactor_.modFileDescriptor(fd, evt);
+ }
+
+ if (events & MEMIF_FD_EVENT_READ) {
+ evt |= EPOLLIN;
+ }
+
+ if (events & MEMIF_FD_EVENT_WRITE) {
+ evt |= EPOLLOUT;
+ }
+
+ DLOG_IF(INFO, VLOG_IS_ON(4)) << "memif fd event: ADD fd " << fd;
+ return self->event_reactor_.addFileDescriptor(
+ fd, evt, [fde](const utils::Event &evt) -> int {
+ int 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(fde.private_ctx,
+ memif_fd_event_type_t(event));
+
+ if (TRANSPORT_EXPECT_FALSE(memif_err != MEMIF_ERR_SUCCESS)) {
+ LOG(ERROR) << "memif_control_fd_handler: "
+ << memif_strerror(memif_err);
+ }
+
+ return 0;
+ });
+}
+
+uint16_t MemifConnector::bufferAlloc(long n, uint16_t qid,
+ std::error_code &ec) {
+ int err;
+ uint16_t r = 0;
+ /* set data pointer to shared memory and set buffer_len to shared mmeory
+ * buffer len */
+ err = memif_buffer_alloc(memif_connection_.conn, qid,
+ memif_connection_.tx_bufs, n, &r, buffer_size_);
+
+ if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
+ ec = make_error_code(core_error::send_buffer_allocation_failed);
+ }
+
+ memif_connection_.tx_buf_num += r;
+ return r;
+}
+
+uint16_t MemifConnector::txBurst(uint16_t qid, std::error_code &ec) {
+ int err = MEMIF_ERR_SUCCESS;
+ ec = make_error_code(core_error::success);
+ uint16_t tx = 0;
+
+ /* inform peer memif interface about data in shared memory buffers */
+ /* mark memif buffers as free */
+ err = memif_tx_burst(memif_connection_.conn, qid, memif_connection_.tx_bufs,
+ memif_connection_.tx_buf_num, &tx);
+
+ if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
+ ec = make_error_code(core_error::send_failed);
+ }
+
+ memif_connection_.tx_buf_num -= tx;
+ return tx;
+}
+
+void MemifConnector::scheduleSend(std::uint64_t delay) {
+ if (!timer_set_) {
+ timer_set_ = true;
+ send_timer_.expiresFromNow(std::chrono::microseconds(delay));
+ send_timer_.asyncWait(
+ std::bind(&MemifConnector::sendCallback, this, std::placeholders::_1));
+ }
+}
+
+void MemifConnector::sendCallback(const std::error_code &ec) {
+ timer_set_ = false;
+
+ if (TRANSPORT_EXPECT_TRUE(!ec && state_ == State::CONNECTED)) {
+ doSend();
+ }
+}
+
+/* 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) {
+ auto self = reinterpret_cast<MemifConnector *>(private_ctx);
+ self->state_ = State::CONNECTED;
+ memif_refill_queue(conn, 0, -1, 0);
+
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Memif " << self->app_name_ << " connected";
+
+ // We are connected. Notify higher layers.
+ self->io_service_.post([self]() {
+ self->on_reconnect_callback_(self, make_error_code(core_error::success));
+ });
+
+ self->doSend();
+
+ 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;
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Memif " << connector->app_name_ << " disconnected";
+ return 0;
+}
+
+void MemifConnector::threadMain() { event_reactor_.runEventLoop(200); }
+
+int MemifConnector::onInterrupt(memif_conn_handle_t conn, void *private_ctx,
+ uint16_t qid) {
+ MemifConnector *connector = (MemifConnector *)private_ctx;
+
+ Details &c = connector->memif_connection_;
+ std::weak_ptr<MemifConnector> self = connector->shared_from_this();
+ std::vector<::utils::MemBuf::Ptr> v;
+ std::error_code ec = make_error_code(core_error::success);
+
+ int err = MEMIF_ERR_SUCCESS, ret_val;
+ uint16_t rx = 0;
+
+ do {
+ err = memif_rx_burst(conn, qid, c.rx_bufs, max_burst, &rx);
+ ret_val = err;
+
+ if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS &&
+ err != MEMIF_ERR_NOBUF)) {
+ ec = make_error_code(core_error::receive_failed);
+ LOG(ERROR) << "memif_rx_burst: " << memif_strerror(err);
+ goto error;
+ }
+
+ c.rx_buf_num += rx;
+
+ if (TRANSPORT_EXPECT_FALSE(connector->io_service_.stopped())) {
+ LOG(ERROR) << "socket stopped: ignoring " << rx << " packets";
+ goto error;
+ }
+
+ std::size_t packet_length;
+ v.reserve(rx);
+ for (int i = 0; i < rx; i++) {
+ auto buffer = connector->getRawBuffer();
+ packet_length = (c.rx_bufs + i)->len;
+ std::memcpy(buffer.first, (c.rx_bufs + i)->data, packet_length);
+ auto packet = connector->getPacketFromBuffer(buffer.first, packet_length);
+ v.emplace_back(std::move(packet));
+ }
+
+ /* 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)) {
+ LOG(ERROR) << "memif_buffer_free: " << memif_strerror(err);
+ }
+
+ c.rx_buf_num -= rx;
+
+ } while (ret_val == MEMIF_ERR_NOBUF);
+
+ connector->io_service_.post([self, buffers = std::move(v)]() {
+ if (auto c = self.lock()) {
+ c->receive_callback_(c.get(), buffers,
+ std::make_error_code(std::errc(0)));
+ }
+ });
+
+ return 0;
+
+error:
+ err = memif_refill_queue(c.conn, qid, rx, 0);
+
+ if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
+ LOG(ERROR) << "memif_buffer_free: " << memif_strerror(err);
+ }
+ c.rx_buf_num -= rx;
+
+ connector->io_service_.post([self, ec]() {
+ if (auto c = self.lock()) {
+ c->receive_callback_(c.get(), {}, ec);
+ }
+ });
+
+ return 0;
+}
+
+void MemifConnector::close() {
+ if (state_ != State::CLOSED) {
+ disconnect_timer_.expiresFromNow(std::chrono::microseconds(50));
+ disconnect_timer_.asyncWait([this](const std::error_code &ec) {
+ deleteMemif();
+ event_reactor_.stop();
+ });
+ }
+
+ if (memif_worker_.joinable()) {
+ memif_worker_.join();
+ }
+}
+
+void MemifConnector::send(Packet &packet) { send(packet.shared_from_this()); }
+
+void MemifConnector::send(const utils::MemBuf::Ptr &buffer) {
+ {
+ utils::SpinLock::Acquire locked(write_msgs_lock_);
+ output_buffer_.push_back(buffer);
+ }
+#if CANCEL_TIMER
+ scheduleSend(50);
+#endif
+}
+
+int MemifConnector::doSend() {
+ std::size_t max = 0;
+ std::size_t size = 0;
+ std::error_code ec = make_error_code(core_error::success);
+ int ret = 0;
+ uint64_t delay = 50; // microseconds
+
+ utils::SpinLock::Acquire locked(write_msgs_lock_);
+
+ // Check if there are pending buffers to send
+ if (memif_connection_.tx_buf_num > 0) {
+ ret = txBurst(memif_connection_.tx_qid, ec);
+ if (TRANSPORT_EXPECT_FALSE(ec.operator bool())) {
+ delay = 200;
+ goto done;
+ }
+ }
+
+ // Continue trying to send buffers in output_buffer_
+ size = output_buffer_.size();
+ max = size < max_burst ? size : max_burst;
+
+ ret = bufferAlloc(max, memif_connection_.tx_qid, ec);
+ if (TRANSPORT_EXPECT_FALSE(ec.operator bool() && ret == 0)) {
+ delay = 200;
+ goto done;
+ }
+
+ // Fill allocated buffers and remove them from output_buffer_
+ for (uint16_t i = 0; i < ret; i++) {
+ auto packet = output_buffer_.front().get();
+ const utils::MemBuf *current = packet;
+ std::size_t offset = 0;
+ uint8_t *shared_buffer =
+ reinterpret_cast<uint8_t *>(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();
+ }
+
+ // Try to send them
+ ret = txBurst(memif_connection_.tx_qid, ec);
+ if (TRANSPORT_EXPECT_FALSE(ec.operator bool())) {
+ LOG(ERROR) << "Tx burst failed " << ec.message();
+ delay = 200;
+ goto done;
+ }
+
+done:
+ memif_refill_queue(memif_connection_.conn, memif_connection_.tx_qid, ret, 0);
+
+ // If there are still packets to send, schedule another send
+ if (memif_connection_.tx_buf_num > 0 || !output_buffer_.empty()) {
+ scheduleSend(delay);
+ }
+
+ // If error, signal to upper layers
+ if (ec.operator bool()) {
+ std::weak_ptr<MemifConnector> self = shared_from_this();
+ io_service_.post([self, ec]() {
+ if (auto c = self.lock()) {
+ c->sent_callback_(c.get(), ec);
+ }
+ });
+ }
+
+ return 0;
+}
+
+} // end namespace core
+
+} // end namespace transport
diff --git a/libtransport/src/io_modules/memif/memif_connector.h b/libtransport/src/core/memif_connector.h
index 0a189f893..d36be4616 100644
--- a/libtransport/src/io_modules/memif/memif_connector.h
+++ b/libtransport/src/core/memif_connector.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -25,27 +25,48 @@
#include <utils/fd_deadline_timer.h>
#include <deque>
+#include <future>
#include <mutex>
#include <thread>
+extern "C" {
+#include <libmemif.h>
+};
+
#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 13
-#define MAX_MEMIF_BUFS (1 << MEMIF_LOG2_RING_SIZE)
-
class MemifConnector : public Connector {
- using memif_conn_handle_t = void *;
+ static inline std::size_t kbuf_size = 2048;
+ static inline std::size_t klog2_ring_size = 13;
+
using PacketRing = utils::CircularFifo<utils::MemBuf::Ptr, queue_size>;
+ struct Details {
+ // index
+ 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;
+ // allocated rx buffers counter
+ // number of rx buffers pointing to shared memory
+ uint16_t rx_buf_num;
+ // interface ip address
+ uint8_t ip_addr[4];
+ };
public:
MemifConnector(PacketReceivedCallback &&receive_callback,
@@ -59,11 +80,14 @@ class MemifConnector : public Connector {
void send(Packet &packet) override;
- void send(const uint8_t *packet, std::size_t len) override;
+ void send(const utils::MemBuf::Ptr &buffer) override;
void close() override;
- void connect(uint32_t memif_id, long memif_mode);
+ void connect(uint32_t memif_id, long memif_mode,
+ const std::string &socket_filename,
+ std::size_t buffer_size = kbuf_size,
+ std::size_t log2_ring_size = klog2_ring_size);
TRANSPORT_ALWAYS_INLINE uint32_t getMemifId() { return memif_id_; };
@@ -72,13 +96,13 @@ class MemifConnector : public Connector {
int doSend();
- int createMemif(uint32_t index, uint8_t mode, char *s);
+ int createMemif(uint32_t index, uint8_t is_master);
uint32_t getMemifConfiguration();
int deleteMemif();
- static int controlFdUpdate(int fd, uint8_t events, void *private_ctx);
+ static int controlFdUpdate(memif_fd_event_t fde, void *private_ctx);
static int onConnect(memif_conn_handle_t conn, void *private_ctx);
@@ -89,27 +113,26 @@ class MemifConnector : public Connector {
void threadMain();
- int txBurst(uint16_t qid);
+ uint16_t txBurst(uint16_t qid, std::error_code &ec);
+
+ uint16_t bufferAlloc(long n, uint16_t qid, std::error_code &ec);
- int bufferAlloc(long n, uint16_t qid);
+ void scheduleSend(std::uint64_t delay);
void sendCallback(const std::error_code &ec);
- void processInputBuffer(std::uint16_t total_packets);
+ auto shared_from_this() { return utils::shared_from(this); }
private:
- static utils::EpollEventReactor main_event_reactor_;
- static std::unique_ptr<std::thread> main_worker_;
-
int epfd;
- std::unique_ptr<std::thread> memif_worker_;
utils::EpollEventReactor event_reactor_;
+ std::thread memif_worker_;
std::atomic_bool timer_set_;
- std::unique_ptr<utils::FdDeadlineTimer> send_timer_;
- std::unique_ptr<utils::FdDeadlineTimer> disconnect_timer_;
+ utils::FdDeadlineTimer send_timer_;
+ utils::FdDeadlineTimer disconnect_timer_;
asio::io_service &io_service_;
asio::executor_work_guard<asio::io_context::executor_type> work_;
- std::unique_ptr<memif_connection_t> memif_connection_;
+ Details memif_connection_;
uint16_t tx_buf_counter_;
PacketRing input_buffer_;
@@ -121,8 +144,9 @@ class MemifConnector : public Connector {
uint16_t transmission_index_;
utils::SpinLock write_msgs_lock_;
std::string socket_filename_;
-
- static std::once_flag flag_;
+ std::size_t buffer_size_;
+ std::size_t log2_ring_size_;
+ std::size_t max_memif_bufs_;
};
} // end namespace core
diff --git a/libtransport/src/core/name.cc b/libtransport/src/core/name.cc
index 795c8a697..98091eea5 100644
--- a/libtransport/src/core/name.cc
+++ b/libtransport/src/core/name.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -26,30 +26,28 @@ namespace core {
Name::Name() { name_ = {}; }
+/**
+ * XXX This function does not use the name API provided by libhicn
+ */
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;
+ dst = name_.prefix.v4.as_u8;
length = IPV4_ADDR_LEN;
- name_.type = HNT_CONTIGUOUS_V4;
} else if (family == AF_INET6) {
- dst = name_.ip6.prefix_as_u8;
+ dst = name_.prefix.v6.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<std::uint32_t *>(dst + length) = suffix;
+ name_.suffix = suffix;
}
-
Name::Name(const char *name, uint32_t segment) {
- name_.type = HNT_UNSPEC;
if (hicn_name_create(name, segment, &name_) < 0) {
throw errors::InvalidIpAddressException();
}
@@ -59,7 +57,6 @@ 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;
@@ -80,9 +77,13 @@ Name::Name(const std::string &uri) {
Name::Name(const Name &name) { this->name_ = name.name_; }
+Name::~Name() {}
+
Name &Name::operator=(const Name &name) {
- if (hicn_name_copy(&this->name_, &name.name_) < 0) {
- throw errors::MalformedNameException();
+ if (this != &name) {
+ if (hicn_name_copy(&this->name_, &name.name_) < 0) {
+ throw errors::MalformedNameException();
+ }
}
return *this;
@@ -129,9 +130,13 @@ uint32_t Name::getHash32(bool consider_suffix) const {
return hash;
}
-void Name::clear() { name_.type = HNT_UNSPEC; };
+void Name::clear() { std::memset(&name_, 0, sizeof(name_)); };
-Name::Type Name::getType() const { return name_.type; }
+Name::Type Name::getType() const {
+ int family;
+ hicn_name_get_family(&name_, &family);
+ return family == AF_INET ? Name::Type::V4 : Name::Type::V6;
+}
uint32_t Name::getSuffix() const {
uint32_t ret = 0;
@@ -151,29 +156,6 @@ Name &Name::setSuffix(uint32_t seq_number) {
return *this;
}
-std::shared_ptr<Sockaddr> 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<Sockaddr>(ret);
-}
-
ip_prefix_t Name::toIpAddress() const {
ip_prefix_t ret;
std::memset(&ret, 0, sizeof(ret));
@@ -195,8 +177,8 @@ int Name::getAddressFamily() const {
return ret;
}
-void Name::copyToDestination(uint8_t *destination, bool include_suffix) const {
- if (hicn_name_copy_to_destination(destination, &name_, include_suffix) < 0) {
+void Name::copyPrefixToDestination(uint8_t *destination) const {
+ if (hicn_name_copy_prefix_to_destination(destination, &name_) < 0) {
throw errors::RuntimeException(
"Impossibe to copy the name into the "
"provided destination");
diff --git a/libtransport/src/core/packet.cc b/libtransport/src/core/packet.cc
index 51337201f..df27444af 100644
--- a/libtransport/src/core/packet.cc
+++ b/libtransport/src/core/packet.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -41,13 +41,6 @@ Packet::Packet(Format format, std::size_t additional_header_size)
setFormat(format_, additional_header_size);
}
-Packet::Packet(MemBuf &&buffer)
- : utils::MemBuf(std::move(buffer)),
- packet_start_(reinterpret_cast<hicn_header_t *>(writableData())),
- header_offset_(0),
- format_(getFormatFromBuffer(data(), length())),
- payload_type_(PayloadType::UNSPECIFIED) {}
-
Packet::Packet(CopyBufferOp, const uint8_t *buffer, std::size_t size)
: utils::MemBuf(COPY_BUFFER, buffer, size),
packet_start_(reinterpret_cast<hicn_header_t *>(writableData())),
@@ -74,11 +67,11 @@ Packet::Packet(CreateOp, uint8_t *buffer, std::size_t length, std::size_t size,
setFormat(format_, additional_header_size);
}
-Packet::Packet(const Packet &other)
- : utils::MemBuf(other),
+Packet::Packet(MemBuf &&buffer)
+ : utils::MemBuf(std::move(buffer)),
packet_start_(reinterpret_cast<hicn_header_t *>(writableData())),
- header_offset_(other.header_offset_),
- format_(other.format_),
+ header_offset_(0),
+ format_(getFormatFromBuffer(data(), length())),
payload_type_(PayloadType::UNSPECIFIED) {}
Packet::Packet(Packet &&other)
@@ -92,6 +85,13 @@ Packet::Packet(Packet &&other)
other.header_offset_ = 0;
}
+Packet::Packet(const Packet &other)
+ : utils::MemBuf(other),
+ packet_start_(reinterpret_cast<hicn_header_t *>(writableData())),
+ header_offset_(other.header_offset_),
+ format_(other.format_),
+ payload_type_(PayloadType::UNSPECIFIED) {}
+
Packet::~Packet() {}
Packet &Packet::operator=(const Packet &other) {
@@ -103,29 +103,19 @@ Packet &Packet::operator=(const Packet &other) {
return *this;
}
-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;
+std::shared_ptr<utils::MemBuf> Packet::acquireMemBufReference() {
+ return std::static_pointer_cast<utils::MemBuf>(shared_from_this());
}
-bool Packet::isInterest(const uint8_t *buffer) {
- bool is_interest = false;
-
- if (TRANSPORT_EXPECT_FALSE(hicn_packet_test_ece(HF_INET6_TCP,
- (const hicn_header_t *)buffer,
- &is_interest) < 0)) {
- throw errors::RuntimeException(
- "Impossible to retrieve ece flag from packet");
+Packet::Format Packet::getFormat() const {
+ // We check packet start because after a movement it will result in a nullptr
+ if (format_ == HF_UNSPEC && length()) {
+ if (hicn_packet_get_format(packet_start_, &format_) < 0) {
+ LOG(ERROR) << "Unexpected packet format HF_UNSPEC.";
+ }
}
- return !is_interest;
+ return format_;
}
void Packet::setFormat(Packet::Format format,
@@ -136,47 +126,43 @@ void Packet::setFormat(Packet::Format format,
}
auto header_size = getHeaderSizeFromFormat(format_);
- assert(header_size <= tailroom());
+ DCHECK(header_size <= tailroom());
append(header_size);
- assert(additional_header_size <= tailroom());
+ DCHECK(additional_header_size <= tailroom());
append(additional_header_size);
header_offset_ = length();
}
-bool Packet::isInterest() { return Packet::isInterest(data()); }
+PayloadType Packet::getPayloadType() const {
+ if (payload_type_ == PayloadType::UNSPECIFIED) {
+ hicn_payload_type_t ret;
-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();
+ if (hicn_packet_get_payload_type(format_, packet_start_, &ret) < 0) {
+ throw errors::RuntimeException("Impossible to retrieve payload type.");
+ }
+
+ payload_type_ = (PayloadType)ret;
}
- return payload_length;
+ return payload_type_;
}
-std::size_t Packet::payloadSize() const {
- std::size_t ret = 0;
-
- if (length()) {
- ret = getPayloadSizeFromBuffer(format_,
- reinterpret_cast<uint8_t *>(packet_start_));
+Packet &Packet::setPayloadType(PayloadType payload_type) {
+ if (hicn_packet_set_payload_type(format_, packet_start_,
+ hicn_payload_type_t(payload_type)) < 0) {
+ throw errors::RuntimeException("Error setting payload type of the packet.");
}
- return ret;
+ payload_type_ = payload_type;
+ return *this;
}
-std::size_t Packet::headerSize() const {
- if (header_offset_ == 0 && length()) {
- const_cast<Packet *>(this)->header_offset_ = getHeaderSizeFromBuffer(
- format_, reinterpret_cast<uint8_t *>(packet_start_));
- }
-
- return header_offset_;
+std::unique_ptr<utils::MemBuf> Packet::getPayload() const {
+ auto ret = clone();
+ ret->trimStart(headerSize());
+ return ret;
}
Packet &Packet::appendPayload(std::unique_ptr<utils::MemBuf> &&payload) {
@@ -196,12 +182,56 @@ Packet &Packet::appendPayload(const uint8_t *buffer, std::size_t length) {
return *this;
}
-std::unique_ptr<utils::MemBuf> Packet::getPayload() const {
- auto ret = clone();
- ret->trimStart(headerSize());
+std::size_t Packet::headerSize() const {
+ if (header_offset_ == 0 && length()) {
+ const_cast<Packet *>(this)->header_offset_ = getHeaderSizeFromBuffer(
+ format_, reinterpret_cast<uint8_t *>(packet_start_));
+ }
+
+ return header_offset_;
+}
+
+std::size_t Packet::payloadSize() const {
+ std::size_t ret = 0;
+
+ if (length()) {
+ ret = getPayloadSizeFromBuffer(format_,
+ reinterpret_cast<uint8_t *>(packet_start_));
+ }
+
return ret;
}
+auth::CryptoHash Packet::computeDigest(auth::CryptoHashType algorithm) const {
+ auth::CryptoHash hash;
+ hash.setType(algorithm);
+
+ // 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<Packet *>(this)->resetForHash();
+
+ hash.computeDigest(this);
+ hicn_packet_copy_header(format_, &header_copy, packet_start_, false);
+
+ return hash;
+}
+
+void Packet::reset() {
+ clear();
+ packet_start_ = reinterpret_cast<hicn_header_t *>(writableData());
+ header_offset_ = 0;
+ format_ = HF_UNSPEC;
+ payload_type_ = PayloadType::UNSPECIFIED;
+ name_.clear();
+
+ if (isChained()) {
+ separateChain(next(), prev());
+ }
+}
+
+bool Packet::isInterest() { return Packet::isInterest(data(), format_); }
+
Packet &Packet::updateLength(std::size_t length) {
std::size_t total_length = length;
@@ -221,47 +251,6 @@ Packet &Packet::updateLength(std::size_t length) {
return *this;
}
-PayloadType Packet::getPayloadType() const {
- if (payload_type_ == PayloadType::UNSPECIFIED) {
- hicn_payload_type_t ret;
- if (hicn_packet_get_payload_type(packet_start_, &ret) < 0) {
- throw errors::RuntimeException("Impossible to retrieve payload type.");
- }
-
- payload_type_ = (PayloadType)ret;
- }
-
- return payload_type_;
-}
-
-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.");
- }
-
- payload_type_ = payload_type;
-
- return *this;
-}
-
-Packet::Format Packet::getFormat() const {
- /**
- * We check packet start because after a movement it will result in a nullptr
- */
- if (format_ == HF_UNSPEC && length()) {
- if (hicn_packet_get_format(packet_start_, &format_) < 0) {
- LOG(ERROR) << "Unexpected packet format HF_UNSPEC.";
- }
- }
-
- return format_;
-}
-
-std::shared_ptr<utils::MemBuf> Packet::acquireMemBufReference() {
- return std::static_pointer_cast<utils::MemBuf>(shared_from_this());
-}
-
void Packet::dump() const {
LOG(INFO) << "HEADER -- Length: " << headerSize();
LOG(INFO) << "PAYLOAD -- Length: " << payloadSize();
@@ -274,180 +263,42 @@ void Packet::dump() const {
} while (current != this);
}
-void Packet::dump(uint8_t *buffer, std::size_t length) {
- hicn_packet_dump(buffer, length);
-}
-
-void Packet::setSignatureSize(std::size_t size_bytes) {
- if (!authenticationHeader()) {
- throw errors::RuntimeException("Packet without Authentication Header.");
- }
-
- int ret = hicn_packet_set_signature_size(format_, packet_start_, size_bytes);
-
- if (ret < 0) {
- throw errors::RuntimeException("Error setting signature size.");
- }
-}
-
-void Packet::setSignatureSizeGap(std::size_t size_bytes) {
- if (!authenticationHeader()) {
- throw errors::RuntimeException("Packet without Authentication Header.");
- }
-
- int ret = hicn_packet_set_signature_gap(format_, packet_start_,
- (uint8_t)size_bytes);
-
- if (ret < 0) {
- throw errors::RuntimeException("Error setting signature size.");
- }
-}
-
-uint8_t *Packet::getSignature() const {
- if (!authenticationHeader()) {
- throw errors::RuntimeException("Packet without Authentication Header.");
- }
-
- uint8_t *signature;
- int ret = hicn_packet_get_signature(format_, packet_start_, &signature);
-
- if (ret < 0) {
- throw errors::RuntimeException("Error getting signature.");
- }
-
- return signature;
-}
-
-void Packet::setSignatureTimestamp(const uint64_t &timestamp) {
- if (!authenticationHeader()) {
- throw errors::RuntimeException("Packet without Authentication Header.");
- }
-
- 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 {
- if (!authenticationHeader()) {
- throw errors::RuntimeException("Packet without Authentication Header.");
- }
-
- 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 auth::CryptoSuite &validation_algorithm) {
- if (!authenticationHeader()) {
- throw errors::RuntimeException("Packet without Authentication Header.");
- }
-
- 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.");
- }
-}
-
-auth::CryptoSuite Packet::getValidationAlgorithm() const {
- if (!authenticationHeader()) {
- throw errors::RuntimeException("Packet without Authentication Header.");
- }
-
- 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 auth::CryptoSuite(return_value);
-}
-
-void Packet::setKeyId(const auth::KeyId &key_id) {
- if (!authenticationHeader()) {
- throw errors::RuntimeException("Packet without Authentication Header.");
- }
-
- int ret = hicn_packet_set_key_id(format_, packet_start_, key_id.first);
-
- if (ret < 0) {
- throw errors::RuntimeException("Error setting the key id.");
- }
-}
-
-auth::KeyId Packet::getKeyId() const {
- if (!authenticationHeader()) {
- throw errors::RuntimeException("Packet without Authentication Header.");
- }
+void Packet::setChecksum() {
+ if (_is_tcp(format_)) {
+ uint16_t partial_csum =
+ csum(data() + HICN_V6_TCP_HDRLEN, length() - HICN_V6_TCP_HDRLEN, 0);
- auth::KeyId return_value;
- int ret = hicn_packet_get_key_id(format_, packet_start_, &return_value.first,
- &return_value.second);
+ for (utils::MemBuf *current = next(); current != this;
+ current = current->next()) {
+ partial_csum = csum(current->data(), current->length(), ~partial_csum);
+ }
- if (ret < 0) {
- throw errors::RuntimeException("Error getting the validation algorithm.");
+ if (hicn_packet_compute_header_checksum(format_, packet_start_,
+ partial_csum) < 0) {
+ throw errors::MalformedPacketException();
+ }
}
-
- return return_value;
-}
-
-auth::CryptoHash Packet::computeDigest(auth::CryptoHashType algorithm) const {
- auth::CryptoHash hash;
- hash.setType(algorithm);
-
- // 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<Packet *>(this)->resetForHash();
-
- hash.computeDigest(this);
- hicn_packet_copy_header(format_, &header_copy, packet_start_, false);
-
- return hash;
}
bool Packet::checkIntegrity() const {
- uint16_t partial_csum =
- csum(data() + HICN_V6_TCP_HDRLEN, length() - HICN_V6_TCP_HDRLEN, 0);
+ if (_is_tcp(format_)) {
+ uint16_t partial_csum =
+ csum(data() + HICN_V6_TCP_HDRLEN, length() - HICN_V6_TCP_HDRLEN, 0);
- for (const utils::MemBuf *current = next(); current != this;
- current = current->next()) {
- partial_csum = csum(current->data(), current->length(), ~partial_csum);
- }
+ for (const utils::MemBuf *current = next(); current != this;
+ current = current->next()) {
+ partial_csum = csum(current->data(), current->length(), ~partial_csum);
+ }
- if (hicn_packet_check_integrity_no_payload(format_, packet_start_,
- partial_csum) < 0) {
- return false;
+ if (hicn_packet_check_integrity_no_payload(format_, packet_start_,
+ partial_csum) < 0) {
+ return false;
+ }
}
return true;
}
-void Packet::prependPayload(const uint8_t **buffer, std::size_t *size) {
- auto last = prev();
- auto to_copy = std::min(*size, last->tailroom());
- std::memcpy(last->writableTail(), *buffer, to_copy);
- last->append(to_copy);
- *size -= to_copy;
- *buffer += to_copy;
-}
-
Packet &Packet::setSyn() {
if (hicn_packet_set_syn(format_, packet_start_) < 0) {
throw errors::RuntimeException("Error setting syn bit in the packet.");
@@ -553,29 +404,23 @@ Packet &Packet::resetFlags() {
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;
}
@@ -634,6 +479,245 @@ uint8_t Packet::getTTL() const {
return hops;
}
+bool Packet::hasAH() const { return _is_ah(format_); }
+
+std::vector<uint8_t> Packet::getSignature() const {
+ if (!hasAH()) {
+ throw errors::RuntimeException("Packet without Authentication Header.");
+ }
+
+ uint8_t *signature;
+ int ret = hicn_packet_get_signature(format_, packet_start_, &signature);
+
+ if (ret < 0) {
+ throw errors::RuntimeException("Error getting signature.");
+ }
+
+ return std::vector<uint8_t>(signature, signature + getSignatureFieldSize());
+}
+
+std::size_t Packet::getSignatureFieldSize() const {
+ if (!hasAH()) {
+ throw errors::RuntimeException("Packet without Authentication Header.");
+ }
+
+ size_t field_size;
+ int ret = hicn_packet_get_signature_size(format_, packet_start_, &field_size);
+ if (ret < 0) {
+ throw errors::RuntimeException("Error reading signature field size");
+ }
+ return field_size;
+}
+
+std::size_t Packet::getSignatureSize() const {
+ if (!hasAH()) {
+ throw errors::RuntimeException("Packet without Authentication Header.");
+ }
+
+ size_t padding;
+ int ret = hicn_packet_get_signature_padding(format_, packet_start_, &padding);
+ if (ret < 0) {
+ throw errors::RuntimeException("Error reading signature padding");
+ }
+
+ size_t size = getSignatureFieldSize() - padding;
+ if (size < 0) {
+ throw errors::RuntimeException("Error reading signature size");
+ }
+
+ return size;
+}
+
+uint64_t Packet::getSignatureTimestamp() const {
+ if (!hasAH()) {
+ throw errors::RuntimeException("Packet without Authentication Header.");
+ }
+
+ uint64_t timestamp;
+ int ret =
+ hicn_packet_get_signature_timestamp(format_, packet_start_, &timestamp);
+ if (ret < 0) {
+ throw errors::RuntimeException("Error getting the signature timestamp.");
+ }
+ return timestamp;
+}
+
+auth::KeyId Packet::getKeyId() const {
+ if (!hasAH()) {
+ throw errors::RuntimeException("Packet without Authentication Header.");
+ }
+
+ auth::KeyId key_id;
+ int ret = hicn_packet_get_key_id(format_, packet_start_, &key_id.first,
+ &key_id.second);
+ if (ret < 0) {
+ throw errors::RuntimeException("Error getting the validation algorithm.");
+ }
+ return key_id;
+}
+
+auth::CryptoSuite Packet::getValidationAlgorithm() const {
+ if (!hasAH()) {
+ throw errors::RuntimeException("Packet without Authentication Header.");
+ }
+
+ 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 auth::CryptoSuite(return_value);
+}
+
+void Packet::setSignature(const std::vector<uint8_t> &signature) {
+ if (!hasAH()) {
+ throw errors::RuntimeException("Packet without Authentication Header.");
+ }
+
+ uint8_t *signature_field;
+ int ret = hicn_packet_get_signature(format_, packet_start_, &signature_field);
+ if (ret < 0) {
+ throw errors::RuntimeException("Error getting signature.");
+ }
+ memcpy(signature_field, signature.data(), signature.size());
+}
+
+void Packet::setSignatureFieldSize(std::size_t size) {
+ if (!hasAH()) {
+ throw errors::RuntimeException("Packet without Authentication Header.");
+ }
+
+ int ret = hicn_packet_set_signature_size(format_, packet_start_, size);
+ if (ret < 0) {
+ throw errors::RuntimeException("Error setting signature size.");
+ }
+}
+
+void Packet::setSignatureSize(std::size_t size) {
+ if (!hasAH()) {
+ throw errors::RuntimeException("Packet without Authentication Header.");
+ }
+
+ size_t padding = getSignatureFieldSize() - size;
+ if (padding < 0) {
+ throw errors::RuntimeException("Error setting signature padding.");
+ }
+
+ int ret = hicn_packet_set_signature_padding(format_, packet_start_, padding);
+ if (ret < 0) {
+ throw errors::RuntimeException("Error setting signature padding.");
+ }
+}
+
+void Packet::setSignatureTimestamp(const uint64_t &timestamp) {
+ if (!hasAH()) {
+ throw errors::RuntimeException("Packet without Authentication Header.");
+ }
+
+ int ret =
+ hicn_packet_set_signature_timestamp(format_, packet_start_, timestamp);
+ if (ret < 0) {
+ throw errors::RuntimeException("Error setting the signature timestamp.");
+ }
+}
+
+void Packet::setKeyId(const auth::KeyId &key_id) {
+ if (!hasAH()) {
+ throw errors::RuntimeException("Packet without Authentication Header.");
+ }
+
+ int ret = hicn_packet_set_key_id(format_, packet_start_, key_id.first);
+ if (ret < 0) {
+ throw errors::RuntimeException("Error setting the key id.");
+ }
+}
+
+void Packet::setValidationAlgorithm(
+ const auth::CryptoSuite &validation_algorithm) {
+ if (!hasAH()) {
+ throw errors::RuntimeException("Packet without Authentication Header.");
+ }
+
+ 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.");
+ }
+}
+
+Packet::Format Packet::toAHFormat(const Format &format) {
+ return hicn_get_ah_format(format);
+}
+
+Packet::Format Packet::getFormatFromBuffer(const uint8_t *buffer,
+ std::size_t /* length */) {
+ Packet::Format format = HF_UNSPEC;
+ hicn_packet_get_format((const hicn_header_t *)buffer, &format);
+ return format;
+}
+
+std::size_t Packet::getHeaderSizeFromFormat(Format format,
+ std::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;
+}
+
+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;
+}
+
+bool Packet::isInterest(const uint8_t *buffer, Format format) {
+ int is_interest = 0;
+
+ if (TRANSPORT_EXPECT_FALSE(format == Format::HF_UNSPEC)) {
+ format = getFormatFromBuffer(buffer, /* Unused length */ 128);
+ }
+
+ if (TRANSPORT_EXPECT_FALSE(
+ hicn_packet_is_interest(format, (const hicn_header_t *)buffer,
+ &is_interest) < 0)) {
+ throw errors::RuntimeException("Error reading ece flag from packet");
+ }
+
+ return is_interest;
+}
+
+void Packet::dump(uint8_t *buffer, std::size_t length) {
+ hicn_packet_dump(buffer, length);
+}
+
+void Packet::prependPayload(const uint8_t **buffer, std::size_t *size) {
+ auto last = prev();
+ auto to_copy = std::min(*size, last->tailroom());
+ std::memcpy(last->writableTail(), *buffer, to_copy);
+ last->append(to_copy);
+ *size -= to_copy;
+ *buffer += to_copy;
+}
+
} // end namespace core
} // end namespace transport
diff --git a/libtransport/src/core/pending_interest.cc b/libtransport/src/core/pending_interest.cc
deleted file mode 100644
index fbe98cab5..000000000
--- a/libtransport/src/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 <core/pending_interest.h>
-
-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<asio::steady_timer> &&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<asio::steady_timer> &&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
index 99a8bd327..f8a4ba10e 100644
--- a/libtransport/src/core/pending_interest.h
+++ b/libtransport/src/core/pending_interest.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -48,19 +48,17 @@ class PendingInterest {
// on_content_object_callback_(),
// on_interest_timeout_callback_() {}
- PendingInterest(Interest::Ptr &&interest,
- std::unique_ptr<asio::steady_timer> &&timer)
- : interest_(std::move(interest)),
- timer_(std::move(timer)),
+ PendingInterest(asio::io_service &io_service, const Interest::Ptr &interest)
+ : interest_(interest),
+ timer_(io_service),
on_content_object_callback_(),
on_interest_timeout_callback_() {}
- PendingInterest(Interest::Ptr &&interest,
+ PendingInterest(asio::io_service &io_service, const Interest::Ptr &interest,
OnContentObjectCallback &&on_content_object,
- OnInterestTimeoutCallback &&on_interest_timeout,
- std::unique_ptr<asio::steady_timer> &&timer)
- : interest_(std::move(interest)),
- timer_(std::move(timer)),
+ OnInterestTimeoutCallback &&on_interest_timeout)
+ : interest_(interest),
+ timer_(io_service),
on_content_object_callback_(std::move(on_content_object)),
on_interest_timeout_callback_(std::move(on_interest_timeout)) {}
@@ -68,12 +66,12 @@ class PendingInterest {
template <typename Handler>
TRANSPORT_ALWAYS_INLINE void startCountdown(Handler &&cb) {
- timer_->expires_from_now(
+ timer_.expires_from_now(
std::chrono::milliseconds(interest_->getLifetime()));
- timer_->async_wait(std::forward<Handler &&>(cb));
+ timer_.async_wait(std::forward<Handler &&>(cb));
}
- TRANSPORT_ALWAYS_INLINE void cancelTimer() { timer_->cancel(); }
+ TRANSPORT_ALWAYS_INLINE void cancelTimer() { timer_.cancel(); }
TRANSPORT_ALWAYS_INLINE Interest::Ptr &&getInterest() {
return std::move(interest_);
@@ -105,7 +103,7 @@ class PendingInterest {
private:
Interest::Ptr interest_;
- std::unique_ptr<asio::steady_timer> timer_;
+ asio::steady_timer timer_;
OnContentObjectCallback on_content_object_callback_;
OnInterestTimeoutCallback on_interest_timeout_callback_;
};
diff --git a/libtransport/src/core/portal.cc b/libtransport/src/core/portal.cc
index c4c0cf8ba..d8e8d78ea 100644
--- a/libtransport/src/core/portal.cc
+++ b/libtransport/src/core/portal.cc
@@ -30,11 +30,11 @@ namespace core {
#ifdef ANDROID
static const constexpr char default_module[] = "";
#elif defined(MACINTOSH)
-static const constexpr char default_module[] = "hicnlight_module.dylib";
+static const constexpr char default_module[] = "hicnlightng_module.dylib";
#elif defined(LINUX)
-static const constexpr char default_module[] = "hicnlight_module.so";
+static const constexpr char default_module[] = "hicnlightng_module.so";
#elif defined(WINDOWS)
-static const constexpr char default_module[] = "hicnlight_module.lib";
+static const constexpr char default_module[] = "hicnlightng_module.lib";
#endif
IoModuleConfiguration Portal::conf_;
@@ -57,7 +57,7 @@ std::string Portal::defaultIoModule() {
void Portal::getModuleConfiguration(ConfigurationObject& object,
std::error_code& ec) {
- assert(object.getKey() == io_module_section);
+ DCHECK(object.getKey() == io_module_section);
auto conf = dynamic_cast<const IoModuleConfiguration&>(object);
conf = conf_;
@@ -103,7 +103,7 @@ std::string getIoModulePath(const std::string& name,
void Portal::setModuleConfiguration(const ConfigurationObject& object,
std::error_code& ec) {
- assert(object.getKey() == io_module_section);
+ DCHECK(object.getKey() == io_module_section);
const IoModuleConfiguration& conf =
dynamic_cast<const IoModuleConfiguration&>(object);
diff --git a/libtransport/src/core/portal.h b/libtransport/src/core/portal.h
index f6a9ce85b..aae4c573e 100644
--- a/libtransport/src/core/portal.h
+++ b/libtransport/src/core/portal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -15,6 +15,7 @@
#pragma once
+#include <core/global_workers.h>
#include <core/pending_interest.h>
#include <glog/logging.h>
#include <hicn/transport/config.h>
@@ -28,6 +29,7 @@
#include <hicn/transport/interfaces/global_conf_interface.h>
#include <hicn/transport/interfaces/portal.h>
#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/event_thread.h>
#include <hicn/transport/utils/fixed_block_allocator.h>
#include <future>
@@ -54,11 +56,11 @@ class HandlerMemory {
HandlerMemory(const HandlerMemory &) = delete;
HandlerMemory &operator=(const HandlerMemory &) = delete;
- TRANSPORT_ALWAYS_INLINE void *allocate(std::size_t size) {
+ void *allocate(std::size_t size) {
return utils::FixedBlockAllocator<128, 8192>::getInstance().allocateBlock();
}
- TRANSPORT_ALWAYS_INLINE void deallocate(void *pointer) {
+ void deallocate(void *pointer) {
utils::FixedBlockAllocator<128, 8192>::getInstance().deallocateBlock(
pointer);
}
@@ -69,13 +71,9 @@ class HandlerMemory {
HandlerMemory(const HandlerMemory &) = delete;
HandlerMemory &operator=(const HandlerMemory &) = delete;
- TRANSPORT_ALWAYS_INLINE void *allocate(std::size_t size) {
- return ::operator new(size);
- }
+ void *allocate(std::size_t size) { return ::operator new(size); }
- TRANSPORT_ALWAYS_INLINE void deallocate(void *pointer) {
- ::operator delete(pointer);
- }
+ void deallocate(void *pointer) { ::operator delete(pointer); }
#endif
};
@@ -92,21 +90,19 @@ class HandlerAllocator {
HandlerAllocator(const HandlerAllocator<U> &other) noexcept
: memory_(other.memory_) {}
- TRANSPORT_ALWAYS_INLINE bool operator==(
- const HandlerAllocator &other) const noexcept {
+ bool operator==(const HandlerAllocator &other) const noexcept {
return &memory_ == &other.memory_;
}
- TRANSPORT_ALWAYS_INLINE bool operator!=(
- const HandlerAllocator &other) const noexcept {
+ bool operator!=(const HandlerAllocator &other) const noexcept {
return &memory_ != &other.memory_;
}
- TRANSPORT_ALWAYS_INLINE T *allocate(std::size_t n) const {
+ T *allocate(std::size_t n) const {
return static_cast<T *>(memory_.allocate(sizeof(T) * n));
}
- TRANSPORT_ALWAYS_INLINE void deallocate(T *p, std::size_t /*n*/) const {
+ void deallocate(T *p, std::size_t /*n*/) const {
return memory_.deallocate(p);
}
@@ -135,7 +131,7 @@ class CustomAllocatorHandler {
}
template <typename... Args>
- void operator()(Args &&... args) {
+ void operator()(Args &&...args) {
handler_(std::forward<Args>(args)...);
}
@@ -151,49 +147,16 @@ inline CustomAllocatorHandler<Handler> makeCustomAllocatorHandler(
return CustomAllocatorHandler<Handler>(m, h);
}
-class Pool {
- public:
- Pool(asio::io_service &io_service) : io_service_(io_service) {
- increasePendingInterestPool();
- }
-
- TRANSPORT_ALWAYS_INLINE void increasePendingInterestPool() {
- // Create pool of pending interests to reuse
- for (uint32_t i = 0; i < pit_size; i++) {
- pending_interests_pool_.add(new PendingInterest(
- Interest::Ptr(nullptr),
- std::make_unique<asio::steady_timer>(io_service_)));
- }
- }
- 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);
- }
-
- private:
- utils::ObjectPool<PendingInterest> pending_interests_pool_;
- asio::io_service &io_service_;
-};
-
} // namespace portal_details
class PortalConfiguration;
-using PendingInterestHashTable =
- std::unordered_map<uint32_t, PendingInterest::Ptr>;
-
-using interface::BindConfig;
+using PendingInterestHashTable = std::unordered_map<uint32_t, PendingInterest>;
/**
* 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.
+ * packets over multiple kind of io_modules. The io_module itself is an external
+ * module loaded at runtime.
*
* The tasks performed by portal are the following:
* - Sending/Receiving Interest packets
@@ -210,22 +173,16 @@ using interface::BindConfig;
* users of this class.
*/
-class Portal {
- public:
- using ConsumerCallback = interface::Portal::ConsumerCallback;
- using ProducerCallback = interface::Portal::ProducerCallback;
-
- friend class PortalConfiguration;
-
- Portal() : Portal(internal_io_service_) {}
+class Portal : public ::utils::NonCopyable,
+ public std::enable_shared_from_this<Portal> {
+ private:
+ Portal() : Portal(GlobalWorkers::getInstance().getWorker()) {}
- Portal(asio::io_service &io_service)
+ Portal(::utils::EventThread &worker)
: io_module_(nullptr, [](IoModule *module) { IoModule::unload(module); }),
- io_service_(io_service),
- packet_pool_(io_service),
+ worker_(worker),
app_name_("libtransport_application"),
- consumer_callback_(nullptr),
- producer_callback_(nullptr),
+ transport_callback_(nullptr),
is_consumer_(false) {
/**
* This workaroung allows to initialize memory for packet buffers *before*
@@ -235,58 +192,105 @@ class Portal {
*/
PacketManager<>::getInstance();
}
+
+ public:
+ using TransportCallback = interface::Portal::TransportCallback;
+ friend class PortalConfiguration;
+
+ static std::shared_ptr<Portal> createShared() {
+ return std::shared_ptr<Portal>(new Portal());
+ }
+
+ static std::shared_ptr<Portal> createShared(::utils::EventThread &worker) {
+ return std::shared_ptr<Portal>(new Portal(worker));
+ }
+
+ bool isConnected() const { return io_module_.get() != nullptr; }
+
/**
- * Set the consumer callback.
+ * Set the transport callback. Must be called from the same worker thread.
*
- * @param consumer_callback - The pointer to the ConsumerCallback object.
+ * @param consumer_callback - The pointer to the TransportCallback object.
*/
- void setConsumerCallback(ConsumerCallback *consumer_callback) {
- consumer_callback_ = consumer_callback;
+ void registerTransportCallback(TransportCallback *transport_callback) {
+ DCHECK(std::this_thread::get_id() == worker_.getThreadId());
+ transport_callback_ = transport_callback;
}
/**
- * Set the producer callback.
- *
- * @param producer_callback - The pointer to the ProducerCallback object.
+ * Unset the consumer callback. Must be called from the same worker thread.
*/
- void setProducerCallback(ProducerCallback *producer_callback) {
- producer_callback_ = producer_callback;
+ void unregisterTransportCallback() {
+ DCHECK(std::this_thread::get_id() == worker_.getThreadId());
+ transport_callback_ = nullptr;
}
/**
- * 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
+ * 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) {
- io_module_->setOutputInterface(output_interface);
+ void setOutputInterface(const std::string &output_interface) {
+ if (io_module_) {
+ io_module_->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.
+ * @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) {
- if (!io_module_) {
- pending_interest_hash_table_.reserve(portal_details::pit_size);
- io_module_.reset(IoModule::load(io_module_path_.c_str()));
-
- CHECK(io_module_);
-
- io_module_->init(std::bind(&Portal::processIncomingMessages, this,
- std::placeholders::_1, std::placeholders::_2,
- std::placeholders::_3),
- std::bind(&Portal::setLocalRoutes, this), io_service_,
- app_name_);
- io_module_->connect(is_consumer);
- is_consumer_ = is_consumer;
+ void connect(bool is_consumer = true) {
+ if (isConnected()) {
+ return;
}
+
+ worker_.addAndWaitForExecution([this, is_consumer]() {
+ if (!io_module_) {
+ pending_interest_hash_table_.reserve(portal_details::pit_size);
+ io_module_.reset(IoModule::load(io_module_path_.c_str()));
+
+ CHECK(io_module_);
+
+ std::weak_ptr<Portal> self(shared_from_this());
+
+ io_module_->init(
+ [self](Connector *c, const std::vector<utils::MemBuf::Ptr> &buffers,
+ const std::error_code &ec) {
+ if (auto ptr = self.lock()) {
+ ptr->processIncomingMessages(c, buffers, ec);
+ }
+ },
+ [self](Connector *c, const std::error_code &ec) {
+ if (!ec) {
+ return;
+ }
+ auto ptr = self.lock();
+ if (ptr && ptr->transport_callback_) {
+ ptr->transport_callback_->onError(ec);
+ }
+ },
+ [self](Connector *c, const std::error_code &ec) {
+ auto ptr = self.lock();
+ if (ptr) {
+ if (ec && ptr->transport_callback_) {
+ ptr->transport_callback_->onError(ec);
+ return;
+ }
+ ptr->setLocalRoutes();
+ }
+ },
+ worker_.getIoService(), app_name_);
+
+ io_module_->connect(is_consumer);
+ is_consumer_ = is_consumer;
+ }
+ });
}
/**
@@ -295,18 +299,13 @@ class Portal {
~Portal() { killConnection(); }
/**
- * Compute name hash
- */
- TRANSPORT_ALWAYS_INLINE uint32_t getHash(const Name &name) {
- return name.getHash32(false) + name.getSuffix();
- }
-
- /**
* 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) {
+ bool interestIsPending(const Name &name) {
+ DCHECK(std::this_thread::get_id() == worker_.getThreadId());
+
auto it = pending_interest_hash_table_.find(getHash(name));
if (it != pending_interest_hash_table_.end()) {
return true;
@@ -321,19 +320,21 @@ class Portal {
* @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_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(
+ void sendInterest(
Interest::Ptr &&interest,
OnContentObjectCallback &&on_content_object_callback = UNSET_CALLBACK,
OnInterestTimeoutCallback &&on_interest_timeout_callback =
UNSET_CALLBACK) {
+ DCHECK(std::this_thread::get_id() == worker_.getThreadId());
+
// Send it
interest->encodeSuffixes();
io_module_->send(*interest);
@@ -346,35 +347,42 @@ class Portal {
uint32_t counter = 0;
// Set timers
do {
- auto pending_interest = packet_pool_.getPendingInterest();
- pending_interest->setInterest(interest);
+ if (suffix) {
+ hash = initial_hash + *suffix;
+ seq = *suffix;
+ suffix++;
+ }
+
+ auto it = pending_interest_hash_table_.find(hash);
+ PendingInterest *pending_interest = nullptr;
+ if (it != pending_interest_hash_table_.end()) {
+ it->second.cancelTimer();
+ pending_interest = &it->second;
+ pending_interest->setInterest(interest);
+ } else {
+ auto pend_int = pending_interest_hash_table_.try_emplace(
+ hash, worker_.getIoService(), interest);
+ pending_interest = &pend_int.first->second;
+ }
+
pending_interest->setOnContentObjectCallback(
std::move(on_content_object_callback));
pending_interest->setOnTimeoutCallback(
std::move(on_interest_timeout_callback));
+ auto self = weak_from_this();
pending_interest->startCountdown(
portal_details::makeCustomAllocatorHandler(
async_callback_memory_,
- std::bind(&Portal::timerHandler, this, std::placeholders::_1,
- hash, seq)));
+ [self, hash, seq](const std::error_code &ec) {
+ if (TRANSPORT_EXPECT_FALSE(ec.operator bool())) {
+ return;
+ }
- 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);
- }
-
- if (suffix) {
- hash = initial_hash + *suffix;
- seq = *suffix;
- suffix++;
- }
+ if (auto ptr = self.lock()) {
+ ptr->timerHandler(hash, seq);
+ }
+ }));
} while (counter++ < n_suffixes);
}
@@ -385,214 +393,174 @@ class Portal {
* @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.
+ * @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, uint32_t seq) {
- bool is_stopped = io_service_.stopped();
- if (TRANSPORT_EXPECT_FALSE(is_stopped)) {
- return;
- }
+ void timerHandler(uint32_t hash, uint32_t seq) {
+ PendingInterestHashTable::iterator it =
+ pending_interest_hash_table_.find(hash);
+ if (it != pending_interest_hash_table_.end()) {
+ PendingInterest &pend_interest = it->second;
+ auto _int = pend_interest.getInterest();
+ auto callback = pend_interest.getOnTimeoutCallback();
+ pending_interest_hash_table_.erase(it);
+ Name &name = const_cast<Name &>(_int->getName());
+ name.setSuffix(seq);
- 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();
- Name &name = const_cast<Name &>(_int->getName());
- name.setSuffix(seq);
-
- if (ptr->getOnTimeoutCallback() != UNSET_CALLBACK) {
- ptr->on_interest_timeout_callback_(_int, name);
- } else if (consumer_callback_) {
- consumer_callback_->onTimeout(_int, name);
- }
+ if (callback != UNSET_CALLBACK) {
+ callback(_int, name);
+ } else if (transport_callback_) {
+ transport_callback_->onTimeout(_int, name);
}
}
}
/**
- * 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) {
- assert(io_module_);
- io_module_->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.
+ * Send a data packet to the local forwarder.
*
* @param content_object - The data packet.
*/
- TRANSPORT_ALWAYS_INLINE void sendContentObject(
- ContentObject &content_object) {
+ void sendContentObject(ContentObject &content_object) {
+ DCHECK(io_module_);
+ DCHECK(std::this_thread::get_id() == worker_.getThreadId());
+
io_module_->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.
+ * Disconnect the transport from the local forwarder.
*/
- TRANSPORT_ALWAYS_INLINE void stopEventsLoop() {
- if (!io_service_.stopped()) {
- io_service_.dispatch([this]() {
- clear();
- io_service_.stop();
- });
+ void killConnection() {
+ if (TRANSPORT_EXPECT_TRUE(io_module_ != nullptr)) {
+ io_module_->closeConnection();
}
}
/**
- * Disconnect the transport from the local forwarder.
+ * Clear the pending interest hash table.
*/
- TRANSPORT_ALWAYS_INLINE void killConnection() {
- io_module_->closeConnection();
+ void clear() {
+ worker_.tryRunHandlerNow([self{shared_from_this()}]() { self->doClear(); });
}
/**
- * Clear the pending interest hash table.
+ * Get a reference to the io_service object.
*/
- TRANSPORT_ALWAYS_INLINE void clear() {
- if (!io_service_.stopped()) {
- io_service_.dispatch(std::bind(&Portal::doClear, this));
- } else {
- doClear();
- }
- }
+ utils::EventThread &getThread() { return worker_; }
/**
- * Remove one pending interest.
+ * Register a route to the local forwarder.
*/
- TRANSPORT_ALWAYS_INLINE void clearOne(const Name &name) {
- if (!io_service_.stopped()) {
- io_service_.dispatch(std::bind(&Portal::doClearOne, this, name));
- } else {
- doClearOne(name);
- }
+ void registerRoute(const Prefix &prefix) {
+ std::weak_ptr<Portal> self = shared_from_this();
+ worker_.tryRunHandlerNow([self, prefix]() {
+ if (auto ptr = self.lock()) {
+ auto ret = ptr->served_namespaces_.insert(prefix);
+ if (ret.second && ptr->io_module_ && ptr->io_module_->isConnected()) {
+ ptr->io_module_->registerRoute(prefix);
+ }
+ }
+ });
}
/**
- * Get a reference to the io_service object.
+ * Send a MAP-Me update to traverse NATs.
*/
- TRANSPORT_ALWAYS_INLINE asio::io_service &getIoService() {
- return io_service_;
+ TRANSPORT_ALWAYS_INLINE void sendMapme() {
+ if (io_module_->isConnected()) {
+ io_module_->sendMapme();
+ }
}
/**
- * Register a route to the local forwarder.
+ * set forwarding strategy
*/
- TRANSPORT_ALWAYS_INLINE void registerRoute(Prefix &prefix) {
- served_namespaces_.push_back(prefix);
+ TRANSPORT_ALWAYS_INLINE void setForwardingStrategy(Prefix &prefix,
+ std::string &strategy) {
if (io_module_->isConnected()) {
- io_module_->registerRoute(prefix);
+ io_module_->setForwardingStrategy(prefix, strategy);
}
}
/**
* Check if the transport is connected to a forwarder or not
*/
- TRANSPORT_ALWAYS_INLINE bool isConnectedToFwd() {
+ bool isConnectedToFwd() {
std::string mod = io_module_path_.substr(0, io_module_path_.find("."));
if (mod == "forwarder_module") return false;
return true;
}
+ auto &getServedNamespaces() { return served_namespaces_; }
+
private:
/**
- * Clear the pending interest hash table.
+ * Compute name hash
*/
- 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();
+ uint32_t getHash(const Name &name) {
+ return name.getHash32(false) + name.getSuffix();
}
/**
- * Remove one pending interest.
+ * Clear the pending interest hash table.
*/
- TRANSPORT_ALWAYS_INLINE void doClearOne(const Name &name) {
- auto it = pending_interest_hash_table_.find(getHash(name));
-
- if (it != pending_interest_hash_table_.end()) {
- it->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 = it->second->getInterest();
-
- pending_interest_hash_table_.erase(it);
+ void doClear() {
+ for (auto &pend_interest : pending_interest_hash_table_) {
+ pend_interest.second.cancelTimer();
}
+
+ pending_interest_hash_table_.clear();
}
/**
- * Callback called by the underlying connector upon reception of a packet from
- * the local forwarder.
+ * 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(
- Connector *c, utils::MemBuf &buffer, const std::error_code &ec) {
- bool is_stopped = io_service_.stopped();
- if (TRANSPORT_EXPECT_FALSE(is_stopped)) {
+ void processIncomingMessages(Connector *c,
+ const std::vector<utils::MemBuf::Ptr> &buffers,
+ const std::error_code &ec) {
+ if (!transport_callback_) {
return;
}
- if (TRANSPORT_EXPECT_FALSE(io_module_->isControlMessage(buffer.data()))) {
- processControlMessage(buffer);
+ if (TRANSPORT_EXPECT_FALSE(ec.operator bool())) {
+ // Error receiving from underlying infra.
+ if (transport_callback_) {
+ transport_callback_->onError(ec);
+ }
+
return;
}
- // The buffer is a base class for an interest or a content object
- Packet &packet_buffer = static_cast<Packet &>(buffer);
+ for (auto &buffer_ptr : buffers) {
+ auto &buffer = *buffer_ptr;
+
+ if (TRANSPORT_EXPECT_FALSE(io_module_->isControlMessage(buffer))) {
+ processControlMessage(buffer);
+ return;
+ }
- auto format = packet_buffer.getFormat();
- if (TRANSPORT_EXPECT_TRUE(_is_tcp(format))) {
- if (is_consumer_) {
- processContentObject(static_cast<ContentObject &>(packet_buffer));
+ auto format = Packet::getFormatFromBuffer(buffer.data(), buffer.length());
+ if (TRANSPORT_EXPECT_TRUE(_is_cmpr(format) || _is_tcp(format))) {
+ // The buffer is a base class for an interest or a content object
+ Packet &packet_buffer = static_cast<Packet &>(buffer);
+ if (is_consumer_ && !packet_buffer.isInterest()) {
+ processContentObject(static_cast<ContentObject &>(packet_buffer));
+ } else if (!is_consumer_ && packet_buffer.isInterest()) {
+ processInterest(static_cast<Interest &>(packet_buffer));
+ } else {
+ auto packet_type =
+ packet_buffer.isInterest() ? "Interest" : "ContentObject";
+ auto socket_type = is_consumer_ ? "consumer " : "producer ";
+ LOG(ERROR) << "Received a " << packet_type << " packet with name "
+ << packet_buffer.getName() << " in a " << socket_type
+ << " transport. Ignoring it.";
+ }
} else {
- processInterest(static_cast<Interest &>(packet_buffer));
+ LOG(ERROR) << "Received not supported packet. Ignoring it.";
}
- } else {
- LOG(ERROR) << "Received not supported packet. Ignoring it.";
}
}
@@ -601,19 +569,21 @@ class Portal {
* It register the prefixes in the served_namespaces_ list to the local
* forwarder.
*/
- TRANSPORT_ALWAYS_INLINE void setLocalRoutes() {
+ void setLocalRoutes() {
+ DCHECK(io_module_);
+ DCHECK(io_module_->isConnected());
+ DCHECK(std::this_thread::get_id() == worker_.getThreadId());
+
for (auto &prefix : served_namespaces_) {
- if (io_module_->isConnected()) {
- io_module_->registerRoute(prefix);
- }
+ io_module_->registerRoute(prefix);
}
}
- TRANSPORT_ALWAYS_INLINE void processInterest(Interest &interest) {
+ void processInterest(Interest &interest) {
// Interest for a producer
DLOG_IF(INFO, VLOG_IS_ON(3)) << "processInterest " << interest.getName();
- if (TRANSPORT_EXPECT_TRUE(producer_callback_ != nullptr)) {
- producer_callback_->onInterest(interest);
+ if (TRANSPORT_EXPECT_TRUE(transport_callback_ != nullptr)) {
+ transport_callback_->onInterest(interest);
}
}
@@ -625,8 +595,7 @@ class Portal {
*
* @param content_object - The data packet
*/
- TRANSPORT_ALWAYS_INLINE void processContentObject(
- ContentObject &content_object) {
+ void processContentObject(ContentObject &content_object) {
DLOG_IF(INFO, VLOG_IS_ON(3))
<< "processContentObject " << content_object.getName();
uint32_t hash = getHash(content_object.getName());
@@ -635,15 +604,16 @@ class Portal {
if (it != pending_interest_hash_table_.end()) {
DLOG_IF(INFO, VLOG_IS_ON(3)) << "Found pending interest.";
- PendingInterest::Ptr interest_ptr = std::move(it->second);
+ PendingInterest &pend_interest = it->second;
+ pend_interest.cancelTimer();
+ auto _int = pend_interest.getInterest();
+ auto callback = pend_interest.getOnDataCallback();
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_(*_int, content_object);
- } else if (consumer_callback_) {
- consumer_callback_->onContentObject(*_int, content_object);
+ if (callback != UNSET_CALLBACK) {
+ callback(*_int, content_object);
+ } else if (transport_callback_) {
+ transport_callback_->onContentObject(*_int, content_object);
}
} else {
DLOG_IF(INFO, VLOG_IS_ON(3))
@@ -652,12 +622,11 @@ class Portal {
}
/**
- * Process a control message. Control messages are different depending on the
- * connector, then the forwarder_interface will do the job of understanding
- * them.
+ * 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(
- utils::MemBuf &packet_buffer) {
+ void processControlMessage(utils::MemBuf &packet_buffer) {
io_module_->processControlMessageReply(packet_buffer);
}
@@ -665,17 +634,14 @@ class Portal {
portal_details::HandlerMemory async_callback_memory_;
std::unique_ptr<IoModule, void (*)(IoModule *)> io_module_;
- asio::io_service &io_service_;
- asio::io_service internal_io_service_;
- portal_details::Pool packet_pool_;
+ ::utils::EventThread &worker_;
std::string app_name_;
PendingInterestHashTable pending_interest_hash_table_;
- std::list<Prefix> served_namespaces_;
+ std::set<Prefix> served_namespaces_;
- ConsumerCallback *consumer_callback_;
- ProducerCallback *producer_callback_;
+ TransportCallback *transport_callback_;
bool is_consumer_;
diff --git a/libtransport/src/core/prefix.cc b/libtransport/src/core/prefix.cc
index d598cff75..4c1e191e9 100644
--- a/libtransport/src/core/prefix.cc
+++ b/libtransport/src/core/prefix.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -99,6 +99,14 @@ void Prefix::buildPrefix(std::string &prefix, uint16_t prefix_length,
ip_prefix_.family = family;
}
+bool Prefix::operator<(const Prefix &other) const {
+ return ip_prefix_cmp(&ip_prefix_, &other.ip_prefix_) < 0;
+}
+
+bool Prefix::operator==(const Prefix &other) const {
+ return ip_prefix_cmp(&ip_prefix_, &other.ip_prefix_) == 0;
+}
+
std::unique_ptr<Sockaddr> Prefix::toSockaddr() const {
Sockaddr *ret = nullptr;
@@ -211,8 +219,6 @@ Name Prefix::getName(const core::Name &mask, const core::Name &components,
}
}
- // if (this->contains(name_ip))
- // throw errors::RuntimeException("Mask overrides the prefix");
return Name(ip_prefix_.family, (uint8_t *)&name_ip);
}
@@ -279,8 +285,6 @@ Prefix &Prefix::setNetwork(std::string &network) {
}
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<uint32_t> idis(
diff --git a/libtransport/src/core/tcp_socket_connector.cc b/libtransport/src/core/tcp_socket_connector.cc
index a30264271..7758e2cf2 100644
--- a/libtransport/src/core/tcp_socket_connector.cc
+++ b/libtransport/src/core/tcp_socket_connector.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -85,8 +85,10 @@ 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(); });
+ [packet_sent](const std::error_code &ec)
+ std::size_t /*length*/) {
+ packet_sent();
+ });
} else {
if (state_ == ConnectorState::CONNECTED) {
asio::write(socket_, asio::buffer(packet, len));
@@ -151,7 +153,7 @@ void TcpSocketConnector::doWrite() {
asio::async_write(
socket_, std::move(array),
- [this, packet_store = std::move(packet_store)](std::error_code ec,
+ [this, packet_store = std::move(packet_store)](const std::error_code &ec,
std::size_t length) {
if (TRANSPORT_EXPECT_TRUE(!ec)) {
if (!output_buffer_.empty()) {
@@ -172,7 +174,7 @@ 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) {
+ [this](const std::error_code &ec, std::size_t length) {
read_msg_->append(length);
if (TRANSPORT_EXPECT_TRUE(!ec)) {
receive_callback_(std::move(read_msg_));
@@ -195,7 +197,7 @@ void TcpSocketConnector::doReadHeader() {
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) {
+ [this](const 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;
@@ -235,7 +237,7 @@ void TcpSocketConnector::tryReconnect() {
void TcpSocketConnector::doConnect() {
asio::async_connect(
socket_, endpoint_iterator_,
- [this](std::error_code ec, tcp::resolver::iterator) {
+ [this](const std::error_code &ec, tcp::resolver::iterator) {
if (!ec) {
timer_.cancel();
state_ = ConnectorState::CONNECTED;
diff --git a/libtransport/src/core/tcp_socket_connector.h b/libtransport/src/core/tcp_socket_connector.h
index 21db8301e..2901a5c9d 100644
--- a/libtransport/src/core/tcp_socket_connector.h
+++ b/libtransport/src/core/tcp_socket_connector.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/core/udp_connector.cc b/libtransport/src/core/udp_connector.cc
new file mode 100644
index 000000000..ee0c7ea9c
--- /dev/null
+++ b/libtransport/src/core/udp_connector.cc
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ */
+
+#include <core/errors.h>
+#include <core/udp_connector.h>
+#include <glog/logging.h>
+#include <hicn/transport/utils/branch_prediction.h>
+
+#include <iostream>
+#include <thread>
+#include <vector>
+
+namespace transport {
+namespace core {
+
+UdpTunnelConnector::~UdpTunnelConnector() {}
+
+void UdpTunnelConnector::connect(const std::string &hostname, uint16_t port,
+ const std::string &bind_address,
+ uint16_t bind_port) {
+ if (state_ == State::CLOSED) {
+ state_ = State::CONNECTING;
+
+ asio::ip::udp::resolver::query query(asio::ip::udp::v4(), hostname,
+ std::to_string(port));
+
+ endpoint_iterator_ = resolver_.resolve(query);
+ remote_endpoint_send_ = *endpoint_iterator_;
+ socket_->open(remote_endpoint_send_.protocol());
+
+ if (!bind_address.empty() && bind_port != 0) {
+ using namespace asio::ip;
+
+ auto address = address::from_string(bind_address);
+ if (address.is_v6()) {
+ std::error_code ec;
+ socket_->set_option(asio::ip::v6_only(false), ec);
+ // Call succeeds only on dual stack systems.
+ }
+
+ socket_->bind(udp::endpoint(address, bind_port));
+ }
+
+ remote_endpoint_ = Endpoint(remote_endpoint_send_);
+ local_endpoint_ = Endpoint(socket_->local_endpoint());
+
+ auto self = shared_from_this();
+ doConnect(self);
+ }
+}
+
+void UdpTunnelConnector::send(Packet &packet) {
+ send(packet.shared_from_this());
+}
+
+void UdpTunnelConnector::send(const utils::MemBuf::Ptr &buffer) {
+ auto self = shared_from_this();
+ io_service_.post([self, pkt{buffer}]() {
+ bool write_in_progress = !self->output_buffer_.empty();
+ self->output_buffer_.push_back(std::move(pkt));
+ if (TRANSPORT_EXPECT_TRUE(self->state_ == State::CONNECTED)) {
+ if (!write_in_progress) {
+ self->doSendPacket(self);
+ }
+ } else {
+ self->data_available_ = true;
+ }
+ });
+}
+
+void UdpTunnelConnector::close() {
+ DLOG_IF(INFO, VLOG_IS_ON(2)) << "UDPTunnelConnector::close";
+ state_ = State::CLOSED;
+ bool is_socket_owned = socket_.use_count() == 1;
+ if (is_socket_owned) {
+ // Here we use a shared ptr to keep the object alive until we call the close
+ // function
+ auto self = shared_from_this();
+ io_service_.dispatch([this, self]() {
+ socket_->close();
+ // on_close_callback_(shared_from_this());
+ });
+ }
+}
+
+void UdpTunnelConnector::doSendPacket(
+ const std::shared_ptr<UdpTunnelConnector> &self) {
+#ifdef LINUX
+ send_timer_.expires_from_now(std::chrono::microseconds(50));
+ send_timer_.async_wait([self](const std::error_code &ec) {
+ if (ec) {
+ return;
+ }
+
+ self->writeHandler();
+ });
+#else
+ auto packet = output_buffer_.front().get();
+ auto array = std::vector<asio::const_buffer>();
+
+ 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_to(
+ std::move(array), remote_endpoint_send_,
+ [this, self](const std::error_code &ec, std::size_t length) {
+ if (TRANSPORT_EXPECT_TRUE(!ec)) {
+ sent_callback_(this, make_error_code(core_error::success));
+ } else if (ec.value() ==
+ static_cast<int>(std::errc::operation_canceled)) {
+ // The connection has been closed by the application.
+ return;
+ } else {
+ sendFailed();
+ sent_callback_(this, ec);
+ }
+
+ output_buffer_.pop_front();
+ if (!output_buffer_.empty()) {
+ doSendPacket(self);
+ }
+ });
+#endif
+}
+
+void UdpTunnelConnector::retryConnection() {
+ // The connection was refused. In this case let's retry to reconnect.
+ connection_reattempts_++;
+ LOG(ERROR) << "Error in UDP: Connection refused. Retrying...";
+ state_ = State::CONNECTING;
+ timer_.expires_from_now(std::chrono::milliseconds(500));
+ std::weak_ptr<UdpTunnelConnector> self = shared_from_this();
+ timer_.async_wait([self, this](const std::error_code &ec) {
+ if (ec) {
+ }
+ if (auto ptr = self.lock()) {
+ doConnect(ptr);
+ }
+ });
+ return;
+}
+
+#ifdef LINUX
+void UdpTunnelConnector::writeHandler() {
+ if (TRANSPORT_EXPECT_FALSE(state_ != State::CONNECTED)) {
+ return;
+ }
+
+ auto len = std::min(output_buffer_.size(), std::size_t(Connector::max_burst));
+
+ if (len) {
+ int m = 0;
+ for (auto &p : output_buffer_) {
+ auto packet = p.get();
+ ::utils::MemBuf *current = packet;
+ int b = 0;
+ do {
+ // array.push_back(asio::const_buffer(current->data(),
+ // current->length()));
+ tx_iovecs_[m][b].iov_base = current->writableData();
+ tx_iovecs_[m][b].iov_len = current->length();
+ current = current->next();
+ b++;
+ } while (current != packet);
+
+ tx_msgs_[m].msg_hdr.msg_iov = tx_iovecs_[m];
+ tx_msgs_[m].msg_hdr.msg_iovlen = b;
+ tx_msgs_[m].msg_hdr.msg_name = remote_endpoint_send_.data();
+ tx_msgs_[m].msg_hdr.msg_namelen = remote_endpoint_send_.size();
+ m++;
+
+ if (--len == 0) {
+ break;
+ }
+ }
+
+ int retval = sendmmsg(socket_->native_handle(), tx_msgs_, m, MSG_DONTWAIT);
+ if (retval > 0) {
+ while (retval--) {
+ output_buffer_.pop_front();
+ }
+ } else if (errno != EWOULDBLOCK && errno != EAGAIN) {
+ LOG(ERROR) << "Error sending messages: " << strerror(errno);
+ sent_callback_(this, make_error_code(core_error::send_failed));
+ return;
+ }
+ }
+
+ if (!output_buffer_.empty()) {
+ send_timer_.expires_from_now(std::chrono::microseconds(50));
+ std::weak_ptr<UdpTunnelConnector> self = shared_from_this();
+ send_timer_.async_wait([self](const std::error_code &ec) {
+ if (ec) {
+ return;
+ }
+ if (auto ptr = self.lock()) {
+ ptr->writeHandler();
+ }
+ });
+ }
+}
+
+void UdpTunnelConnector::readHandler(const std::error_code &ec) {
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "UdpTunnelConnector receive packet";
+
+ if (TRANSPORT_EXPECT_TRUE(!ec)) {
+ if (TRANSPORT_EXPECT_TRUE(state_ == State::CONNECTED)) {
+ if (current_position_ == 0) {
+ for (int i = 0; i < max_burst; i++) {
+ auto read_buffer = getRawBuffer();
+ rx_iovecs_[i][0].iov_base = read_buffer.first;
+ rx_iovecs_[i][0].iov_len = read_buffer.second;
+ rx_msgs_[i].msg_hdr.msg_iov = rx_iovecs_[i];
+ rx_msgs_[i].msg_hdr.msg_iovlen = 1;
+ }
+ }
+
+ int res = recvmmsg(socket_->native_handle(), rx_msgs_ + current_position_,
+ max_burst - current_position_, MSG_DONTWAIT, nullptr);
+ if (res < 0) {
+ if (errno == EWOULDBLOCK || errno == EAGAIN) {
+ // Try again later
+ return;
+ }
+
+ if (errno == ECONNREFUSED &&
+ connection_reattempts_ < max_reconnection_reattempts) {
+ retryConnection();
+ return;
+ }
+
+ LOG(ERROR) << "Error receiving messages! " << strerror(errno) << " "
+ << res;
+ std::vector<utils::MemBuf::Ptr> v;
+ auto ec = make_error_code(core_error::receive_failed);
+
+ receive_callback_(this, v, ec);
+ return;
+ }
+
+ std::vector<utils::MemBuf::Ptr> v;
+ v.reserve(res);
+ for (int i = 0; i < res; i++) {
+ auto packet = getPacketFromBuffer(
+ reinterpret_cast<uint8_t *>(
+ rx_msgs_[current_position_].msg_hdr.msg_iov[0].iov_base),
+ rx_msgs_[current_position_].msg_len);
+ receiveSuccess(*packet);
+ v.push_back(std::move(packet));
+ ++current_position_;
+ }
+
+ receive_callback_(this, v, make_error_code(core_error::success));
+
+ doRecvPacket();
+ } else {
+ LOG(ERROR) << "Error in UDP: Receiving packets from a not "
+ "connected socket.";
+ }
+ } else if (ec.value() == static_cast<int>(std::errc::operation_canceled)) {
+ LOG(ERROR) << "The connection has been closed by the application.";
+ return;
+ } else {
+ if (TRANSPORT_EXPECT_TRUE(state_ == State::CONNECTED)) {
+ // receive_callback_(this, *read_msg_, ec);
+ LOG(ERROR) << "Error in UDP connector: " << ec.value() << " "
+ << ec.message();
+ } else {
+ LOG(ERROR) << "Error in connector while not connected. " << ec.value()
+ << " " << ec.message();
+ }
+ }
+}
+#endif
+
+void UdpTunnelConnector::doRecvPacket() {
+ std::weak_ptr<UdpTunnelConnector> self = shared_from_this();
+#ifdef LINUX
+ if (state_ == State::CONNECTED) {
+#if ((ASIO_VERSION / 100 % 1000) < 11)
+ socket_->async_receive(asio::null_buffers(),
+#else
+ socket_->async_wait(asio::ip::tcp::socket::wait_read,
+#endif
+ [self](const std::error_code &ec) {
+ if (ec) {
+ LOG(ERROR)
+ << "Error in UDP connector: " << ec.value()
+ << " " << ec.message();
+ return;
+ }
+ if (auto ptr = self.lock()) {
+ ptr->readHandler(ec);
+ }
+ });
+ }
+#else
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "UdpTunnelConnector receive packet";
+ read_msg_ = getRawBuffer();
+ socket_->async_receive_from(
+ asio::buffer(read_msg_.first, read_msg_.second), remote_endpoint_recv_,
+ [this, self](const std::error_code &ec, std::size_t length) {
+ if (auto ptr = self.lock()) {
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "UdpTunnelConnector received packet length=" << length;
+ if (TRANSPORT_EXPECT_TRUE(!ec)) {
+ if (TRANSPORT_EXPECT_TRUE(state_ == State::CONNECTED)) {
+ auto packet = getPacketFromBuffer(read_msg_.first, length);
+ receiveSuccess(*packet);
+ std::vector<utils::MemBuf::Ptr> v{std::move(packet)};
+ receive_callback_(this, v, make_error_code(core_error::success));
+ doRecvPacket();
+ } else {
+ LOG(ERROR) << "Error in UDP: Receiving packets from a not "
+ "connected socket.";
+ }
+ } else if (ec.value() ==
+ static_cast<int>(std::errc::operation_canceled)) {
+ LOG(ERROR) << "The connection has been closed by the application.";
+ return;
+ } else if (ec.value() ==
+ static_cast<int>(std::errc::connection_refused)) {
+ if (connection_reattempts_ < max_reconnection_reattempts) {
+ retryConnection();
+ }
+ } else {
+ if (TRANSPORT_EXPECT_TRUE(state_ == State::CONNECTED)) {
+ LOG(ERROR) << "Error in UDP connector: " << ec.value()
+ << ec.message();
+ } else {
+ LOG(ERROR) << "Error while not connected";
+ }
+ }
+ }
+ });
+#endif
+}
+
+void UdpTunnelConnector::doConnect(
+ std::shared_ptr<UdpTunnelConnector> &self_shared) {
+ std::weak_ptr<UdpTunnelConnector> self = self_shared;
+ asio::async_connect(*socket_, endpoint_iterator_,
+ [this, self](const std::error_code &ec,
+ asio::ip::udp::resolver::iterator) {
+ if (auto ptr = self.lock()) {
+ if (!ec) {
+ state_ = State::CONNECTED;
+ doRecvPacket();
+
+ if (data_available_) {
+ data_available_ = false;
+ doSendPacket(ptr);
+ }
+
+ on_reconnect_callback_(
+ this, make_error_code(core_error::success));
+ } else {
+ LOG(ERROR) << "UDP Connection failed!!!";
+ retryConnection();
+ }
+ }
+ });
+}
+
+} // namespace core
+
+} // namespace transport
diff --git a/libtransport/src/io_modules/forwarder/udp_tunnel.h b/libtransport/src/core/udp_connector.h
index 4f044f93f..65821852d 100644
--- a/libtransport/src/io_modules/forwarder/udp_tunnel.h
+++ b/libtransport/src/core/udp_connector.h
@@ -1,13 +1,13 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
*/
#pragma once
+#include <core/errors.h>
#include <hicn/transport/core/asio_wrapper.h>
#include <hicn/transport/core/connector.h>
#include <hicn/transport/portability/platform.h>
-#include <io_modules/forwarder/errors.h>
#include <iostream>
#include <memory>
@@ -30,16 +30,15 @@ class UdpTunnelConnector : public Connector {
: Connector(receive_callback, packet_sent, on_close_callback,
on_reconnect),
io_service_(io_service),
- strand_(std::make_shared<asio::io_service::strand>(io_service_)),
socket_(std::make_shared<asio::ip::udp::socket>(io_service_)),
resolver_(io_service_),
timer_(io_service_),
#ifdef LINUX
send_timer_(io_service_),
- tx_iovecs_{0},
- tx_msgs_{0},
- rx_iovecs_{0},
- rx_msgs_{0},
+ tx_iovecs_{},
+ tx_msgs_{},
+ rx_iovecs_{},
+ rx_msgs_{},
current_position_(0),
#else
read_msg_(nullptr, 0),
@@ -61,17 +60,16 @@ class UdpTunnelConnector : public Connector {
#else
io_service_((asio::io_context &)(socket->get_executor().context())),
#endif
- strand_(strand),
socket_(socket),
resolver_(io_service_),
remote_endpoint_send_(std::forward<EndpointType &&>(remote_endpoint)),
timer_(io_service_),
#ifdef LINUX
send_timer_(io_service_),
- tx_iovecs_{0},
- tx_msgs_{0},
- rx_iovecs_{0},
- rx_msgs_{0},
+ tx_iovecs_{},
+ tx_msgs_{},
+ rx_iovecs_{},
+ rx_msgs_{},
current_position_(0),
#else
read_msg_(nullptr, 0),
@@ -88,7 +86,7 @@ class UdpTunnelConnector : public Connector {
void send(Packet &packet) override;
- void send(const uint8_t *packet, std::size_t len) override;
+ void send(const utils::MemBuf::Ptr &buffer) override;
void close() override;
@@ -99,26 +97,27 @@ class UdpTunnelConnector : public Connector {
auto shared_from_this() { return utils::shared_from(this); }
private:
- void doConnect();
+ void retryConnection();
+ void doConnect(std::shared_ptr<UdpTunnelConnector> &self);
void doRecvPacket();
- void doRecvPacket(utils::MemBuf &buffer) {
- receive_callback_(this, buffer, make_error_code(forwarder_error::success));
+ void doRecvPacket(utils::MemBuf::Ptr &buffer) {
+ std::vector<utils::MemBuf::Ptr> v{std::move(buffer)};
+ receive_callback_(this, v, make_error_code(core_error::success));
}
#ifdef LINUX
- void readHandler(std::error_code ec);
- void writeHandler(std::error_code ec);
+ void readHandler(const std::error_code &ec);
+ void writeHandler();
#endif
void setConnected() { state_ = State::CONNECTED; }
- void doSendPacket();
+ void doSendPacket(const std::shared_ptr<UdpTunnelConnector> &self);
void doClose();
private:
asio::io_service &io_service_;
- std::shared_ptr<asio::io_service::strand> strand_;
std::shared_ptr<asio::ip::udp::socket> socket_;
asio::ip::udp::resolver resolver_;
asio::ip::udp::resolver::iterator endpoint_iterator_;
diff --git a/libtransport/src/io_modules/forwarder/udp_tunnel_listener.cc b/libtransport/src/core/udp_listener.cc
index d047cc568..c67673392 100644
--- a/libtransport/src/io_modules/forwarder/udp_tunnel_listener.cc
+++ b/libtransport/src/core/udp_listener.cc
@@ -1,11 +1,11 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
*/
+#include <core/udp_connector.h>
+#include <core/udp_listener.h>
#include <glog/logging.h>
#include <hicn/transport/utils/hash.h>
-#include <io_modules/forwarder/udp_tunnel.h>
-#include <io_modules/forwarder/udp_tunnel_listener.h>
#ifndef LINUX
namespace std {
@@ -35,7 +35,7 @@ void UdpTunnelListener::close() {
}
#ifdef LINUX
-void UdpTunnelListener::readHandler(std::error_code ec) {
+void UdpTunnelListener::readHandler(const std::error_code &ec) {
DLOG_IF(INFO, VLOG_IS_ON(3)) << "UdpTunnelConnector receive packet";
if (TRANSPORT_EXPECT_TRUE(!ec)) {
@@ -102,7 +102,8 @@ void UdpTunnelListener::readHandler(std::error_code ec) {
std::make_shared<UdpTunnelConnector>(
socket_, strand_, receive_callback_,
[](Connector *, const std::error_code &) {}, [](Connector *) {},
- [](Connector *) {}, std::move(remote_endpoint_)));
+ [](Connector *, const std::error_code &) {},
+ std::move(remote_endpoint_)));
connector = ret.first;
connector->second->setConnectorId(connector_id);
}
@@ -112,7 +113,7 @@ void UdpTunnelListener::readHandler(std::error_code ec) {
*/
UdpTunnelConnector *c =
dynamic_cast<UdpTunnelConnector *>(connector->second.get());
- c->doRecvPacket(*packet);
+ c->doRecvPacket(packet);
++current_position_;
}
@@ -141,7 +142,7 @@ void UdpTunnelListener::doRecvPacket() {
read_msg_ = Connector::getRawBuffer();
socket_->async_receive_from(
asio::buffer(read_msg_.first, read_msg_.second), remote_endpoint_,
- [this](std::error_code ec, std::size_t length) {
+ [this](const std::error_code &ec, std::size_t length) {
if (TRANSPORT_EXPECT_TRUE(!ec)) {
auto packet = Connector::getPacketFromBuffer(read_msg_.first, length);
auto connector_id =
@@ -153,7 +154,8 @@ void UdpTunnelListener::doRecvPacket() {
connector_id, std::make_shared<UdpTunnelConnector>(
socket_, strand_, receive_callback_,
[](Connector *, const std::error_code &) {},
- [](Connector *) {}, [](Connector *) {},
+ [](Connector *) {},
+ [](Connector *, const std::error_code &) {},
std::move(remote_endpoint_)));
connector = ret.first;
connector->second->setConnectorId(connector_id);
@@ -161,7 +163,7 @@ void UdpTunnelListener::doRecvPacket() {
UdpTunnelConnector *c =
dynamic_cast<UdpTunnelConnector *>(connector->second.get());
- c->doRecvPacket(*packet);
+ c->doRecvPacket(packet);
doRecvPacket();
} else if (ec.value() ==
static_cast<int>(std::errc::operation_canceled)) {
diff --git a/libtransport/src/io_modules/forwarder/udp_tunnel_listener.h b/libtransport/src/core/udp_listener.h
index 5d197dcb0..813520309 100644
--- a/libtransport/src/io_modules/forwarder/udp_tunnel_listener.h
+++ b/libtransport/src/core/udp_listener.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
*/
#pragma once
@@ -44,8 +44,8 @@ class UdpTunnelListener
#ifndef LINUX
read_msg_(nullptr, 0)
#else
- iovecs_{0},
- msgs_{0},
+ iovecs_{},
+ msgs_{},
current_position_(0)
#endif
{
@@ -83,7 +83,7 @@ class UdpTunnelListener
private:
void doRecvPacket();
- void readHandler(std::error_code ec);
+ void readHandler(const std::error_code &ec);
asio::io_service &io_service_;
std::shared_ptr<asio::io_service::strand> strand_;
diff --git a/libtransport/src/http/CMakeLists.txt b/libtransport/src/http/CMakeLists.txt
index 2407faea3..0060f8714 100644
--- a/libtransport/src/http/CMakeLists.txt
+++ b/libtransport/src/http/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2019 Cisco and/or its affiliates.
+# Copyright (c) 2021 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
diff --git a/libtransport/src/http/client_connection.cc b/libtransport/src/http/client_connection.cc
index b4ab7cbc3..05fa3e335 100644
--- a/libtransport/src/http/client_connection.cc
+++ b/libtransport/src/http/client_connection.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -77,9 +77,7 @@ class HTTPClientConnection::Implementation
auto end = std::chrono::steady_clock::now();
LOG(INFO) << method_map[method].c_str() << " " << url.c_str() << " ["
<< name_.str() << "] duration: "
- << std::chrono::duration_cast<std::chrono::microseconds>(end -
- start)
- .count()
+ << utils::SteadyTime::getDurationUs(start, end).count()
<< " [usec] " << size << " [bytes]";
};
@@ -106,7 +104,7 @@ class HTTPClientConnection::Implementation
HTTPClientConnection &setTimeout(const std::chrono::seconds &timeout) {
timer_->cancel();
timer_->expires_from_now(timeout);
- timer_->async_wait([this](std::error_code ec) {
+ timer_->async_wait([this](const std::error_code &ec) {
if (!ec) {
consumer_.stop();
}
@@ -147,18 +145,14 @@ class HTTPClientConnection::Implementation
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;
+ uint16_t *word = (uint16_t *)(&locator_hash);
+ for (std::size_t i = 0; i < sizeof(locator_hash) / 2; i++) {
+ name_ << ":" << std::hex << word[i];
}
- 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;
+ word = (uint16_t *)(&request_hash);
+ for (std::size_t i = 0; i < sizeof(request_hash) / 2; i++) {
+ name_ << ":" << std::hex << word[i];
}
name_ << "|0";
@@ -199,7 +193,7 @@ class HTTPClientConnection::Implementation
}
}
- void readError(const std::error_code ec) noexcept override {
+ void readError(const std::error_code &ec) noexcept override {
LOG(ERROR) << "Error " << ec.message() << " during download of "
<< current_url_.c_str();
if (read_bytes_callback_) {
diff --git a/libtransport/src/http/request.cc b/libtransport/src/http/request.cc
index 29118fd88..ad726741a 100644
--- a/libtransport/src/http/request.cc
+++ b/libtransport/src/http/request.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/http/response.cc b/libtransport/src/http/response.cc
index c665fbc5f..727e2c755 100644
--- a/libtransport/src/http/response.cc
+++ b/libtransport/src/http/response.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/implementation/CMakeLists.txt b/libtransport/src/implementation/CMakeLists.txt
index daf899d06..1f2a33a4c 100644
--- a/libtransport/src/implementation/CMakeLists.txt
+++ b/libtransport/src/implementation/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2019 Cisco and/or its affiliates.
+# Copyright (c) 2021 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
diff --git a/libtransport/src/implementation/p2psecure_socket_consumer.cc b/libtransport/src/implementation/p2psecure_socket_consumer.cc
index 4b14da5d2..6b67a5487 100644
--- a/libtransport/src/implementation/p2psecure_socket_consumer.cc
+++ b/libtransport/src/implementation/p2psecure_socket_consumer.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -44,7 +44,7 @@ int readOld(BIO *b, char *buf, int size) {
if (!socket->something_to_read_) {
if (!socket->transport_protocol_->isRunning()) {
socket->network_name_.setSuffix(socket->random_suffix_);
- socket->ConsumerSocket::asyncConsume(socket->network_name_);
+ socket->ConsumerSocket::consume(socket->network_name_);
}
if (!socket->something_to_read_) socket->cv_.wait(lck);
@@ -312,36 +312,6 @@ int P2PSecureConsumerSocket::consume(const Name &name) {
return tls_consumer_->consume((prefix->mapName(name)));
}
-int P2PSecureConsumerSocket::asyncConsume(const Name &name) {
- if (transport_protocol_->isRunning()) {
- return CONSUMER_BUSY;
- }
-
- if (handshake() != 1) {
- throw errors::RuntimeException("Unable to perform client handshake");
- } else {
- DLOG_IF(INFO, VLOG_IS_ON(2)) << "Handshake performed!";
- }
-
- initSessionSocket();
-
- if (tls_consumer_ == nullptr) {
- throw errors::RuntimeException("TLS socket does not exist");
- }
-
- std::shared_ptr<Name> prefix_name = std::make_shared<Name>(
- secure_prefix_.family,
- ip_address_get_buffer(&(secure_prefix_.address), secure_prefix_.family));
- std::shared_ptr<Prefix> prefix =
- std::make_shared<Prefix>(*prefix_name, secure_prefix_.len);
-
- 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;
}
@@ -385,7 +355,7 @@ void P2PSecureConsumerSocket::readBufferAvailable(
cv_.notify_one();
}
-void P2PSecureConsumerSocket::readError(const std::error_code ec) noexcept {};
+void P2PSecureConsumerSocket::readError(const std::error_code &ec) noexcept {};
void P2PSecureConsumerSocket::readSuccess(std::size_t total_size) noexcept {
std::unique_lock<std::mutex> lck(this->mtx_);
diff --git a/libtransport/src/implementation/p2psecure_socket_consumer.h b/libtransport/src/implementation/p2psecure_socket_consumer.h
index a35a50352..a5e69f611 100644
--- a/libtransport/src/implementation/p2psecure_socket_consumer.h
+++ b/libtransport/src/implementation/p2psecure_socket_consumer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -48,8 +48,6 @@ class P2PSecureConsumerSocket : public ConsumerSocket,
int consume(const Name &name) override;
- int asyncConsume(const Name &name) override;
-
void registerPrefix(const Prefix &producer_namespace);
int setSocketOption(
@@ -120,7 +118,7 @@ class P2PSecureConsumerSocket : public ConsumerSocket,
virtual void readBufferAvailable(
std::unique_ptr<utils::MemBuf> &&buffer) noexcept override;
- virtual void readError(const std::error_code ec) noexcept override;
+ virtual void readError(const std::error_code &ec) noexcept override;
virtual void readSuccess(std::size_t total_size) noexcept override;
diff --git a/libtransport/src/implementation/p2psecure_socket_producer.cc b/libtransport/src/implementation/p2psecure_socket_producer.cc
index 3748001fc..ee78ea53b 100644
--- a/libtransport/src/implementation/p2psecure_socket_producer.cc
+++ b/libtransport/src/implementation/p2psecure_socket_producer.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -20,6 +20,7 @@
#include <interfaces/tls_rtc_socket_producer.h>
#include <interfaces/tls_socket_producer.h>
#include <openssl/bio.h>
+#include <openssl/pkcs12.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
@@ -41,7 +42,7 @@ P2PSecureProducerSocket::P2PSecureProducerSocket(
P2PSecureProducerSocket::P2PSecureProducerSocket(
interface::ProducerSocket *producer_socket, bool rtc,
- const std::shared_ptr<auth::Identity> &identity)
+ std::string &keystore_path, std::string &keystore_pwd)
: ProducerSocket(producer_socket,
ProductionProtocolAlgorithms::BYTE_STREAM),
rtc_(rtc),
@@ -50,8 +51,16 @@ P2PSecureProducerSocket::P2PSecureProducerSocket(
map_producers(),
list_producers() {
/* Setup SSL context (identity and parameter to use TLS 1.3) */
- cert_509_ = identity->getCertificate().get();
- pkey_rsa_ = identity->getPrivateKey().get();
+ FILE *p12file = fopen(keystore_path.c_str(), "r");
+ if (p12file == NULL)
+ throw errors::RuntimeException("impossible open keystore");
+ std::unique_ptr<PKCS12, decltype(&::PKCS12_free)> p12(
+ d2i_PKCS12_fp(p12file, NULL), ::PKCS12_free);
+ // now we parse the file to get the first key and certificate
+ if (1 != PKCS12_parse(p12.get(), keystore_pwd.c_str(), &pkey_rsa_, &cert_509_,
+ NULL))
+ throw errors::RuntimeException("impossible to get the private key");
+ fclose(p12file);
/* Set the callback so that when an interest is received we catch it and we
* decrypt the payload before passing it to the application. */
@@ -133,15 +142,15 @@ uint32_t P2PSecureProducerSocket::produceDatagram(
// TODO
throw errors::NotImplementedException();
- if (!rtc_) {
- throw errors::RuntimeException(
- "RTC must be the transport protocol to start the production of current "
- "data. Aborting.");
- }
+ // if (!rtc_) {
+ // throw errors::RuntimeException(
+ // "RTC must be the transport protocol to start the production of
+ // current " "data. Aborting.");
+ // }
- std::unique_lock<std::mutex> lck(mtx_);
+ // std::unique_lock<std::mutex> lck(mtx_);
- if (list_producers.empty()) cv_.wait(lck);
+ // if (list_producers.empty()) cv_.wait(lck);
// TODO
// for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++)
@@ -151,7 +160,7 @@ uint32_t P2PSecureProducerSocket::produceDatagram(
// rtc_producer->produce(utils::MemBuf::copyBuffer(buffer, buffer_size));
// }
- return 0;
+ // return 0;
}
uint32_t P2PSecureProducerSocket::produceStream(
@@ -197,44 +206,6 @@ uint32_t P2PSecureProducerSocket::produceStream(const Name &content_name,
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<std::mutex> lck(mtx_);
-// if (list_producers.empty()) cv_.wait(lck);
-
-// for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++)
-// {
-// (*it)->asyncProduce(content_name, buf, buffer_size, is_last,
-// start_offset);
-// }
-// }
-
-void P2PSecureProducerSocket::asyncProduce(
- Name content_name, std::unique_ptr<utils::MemBuf> &&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<std::mutex> lck(mtx_);
- if (list_producers.empty()) cv_.wait(lck);
-
- for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++) {
- (*it)->asyncProduce(content_name, buffer->clone(), is_last, offset,
- last_segment);
- }
-}
-
/* Redefinition of socket options to avoid name hiding */
int P2PSecureProducerSocket::setSocketOption(
int socket_option_key, ProducerInterestCallback socket_option_value) {
diff --git a/libtransport/src/implementation/p2psecure_socket_producer.h b/libtransport/src/implementation/p2psecure_socket_producer.h
index f94347258..00f407a75 100644
--- a/libtransport/src/implementation/p2psecure_socket_producer.h
+++ b/libtransport/src/implementation/p2psecure_socket_producer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -15,7 +15,6 @@
#pragma once
-#include <hicn/transport/auth/identity.h>
#include <hicn/transport/auth/signer.h>
#include <implementation/socket_producer.h>
// #include <implementation/tls_rtc_socket_producer.h>
@@ -38,9 +37,9 @@ class P2PSecureProducerSocket : public ProducerSocket {
public:
explicit P2PSecureProducerSocket(interface::ProducerSocket *producer_socket);
- explicit P2PSecureProducerSocket(
- interface::ProducerSocket *producer_socket, bool rtc,
- const std::shared_ptr<auth::Identity> &identity);
+ explicit P2PSecureProducerSocket(interface::ProducerSocket *producer_socket,
+ bool rtc, std::string &keystore_path,
+ std::string &keystore_pwd);
~P2PSecureProducerSocket();
@@ -56,10 +55,6 @@ class P2PSecureProducerSocket : public ProducerSocket {
bool is_last = true,
uint32_t start_offset = 0) override;
- void asyncProduce(Name content_name, std::unique_ptr<utils::MemBuf> &&buffer,
- bool is_last, uint32_t offset,
- uint32_t **last_segment = nullptr) override;
-
int setSocketOption(int socket_option_key,
ProducerInterestCallback socket_option_value) override;
diff --git a/libtransport/src/implementation/socket.cc b/libtransport/src/implementation/socket.cc
index 2e21f2bc3..95941da07 100644
--- a/libtransport/src/implementation/socket.cc
+++ b/libtransport/src/implementation/socket.cc
@@ -14,13 +14,42 @@
*/
#include <core/global_configuration.h>
+#include <hicn/transport/interfaces/socket_options_default_values.h>
#include <implementation/socket.h>
namespace transport {
namespace implementation {
Socket::Socket(std::shared_ptr<core::Portal> &&portal)
- : portal_(std::move(portal)), is_async_(false) {}
+ : portal_(std::move(portal)),
+ is_async_(false),
+ packet_format_(interface::default_values::packet_format) {}
+
+int Socket::setSocketOption(int socket_option_key,
+ hicn_format_t packet_format) {
+ switch (socket_option_key) {
+ case interface::GeneralTransportOptions::PACKET_FORMAT:
+ packet_format_ = packet_format;
+ break;
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ return SOCKET_OPTION_SET;
+}
+
+int Socket::getSocketOption(int socket_option_key,
+ hicn_format_t &packet_format) {
+ switch (socket_option_key) {
+ case interface::GeneralTransportOptions::PACKET_FORMAT:
+ packet_format = packet_format_;
+ break;
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+
+ return SOCKET_OPTION_GET;
+}
} // namespace implementation
} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/implementation/socket.h b/libtransport/src/implementation/socket.h
index cf22c03e1..11c9a704d 100644
--- a/libtransport/src/implementation/socket.h
+++ b/libtransport/src/implementation/socket.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -38,7 +38,26 @@ class Socket {
virtual void connect() = 0;
virtual bool isRunning() = 0;
- virtual asio::io_service &getIoService() { return portal_->getIoService(); }
+ virtual asio::io_service &getIoService() {
+ return portal_->getThread().getIoService();
+ }
+
+ int setSocketOption(int socket_option_key, hicn_format_t packet_format);
+ int getSocketOption(int socket_option_key, hicn_format_t &packet_format);
+
+ int getSocketOption(int socket_option_key,
+ std::shared_ptr<core::Portal> &socket_option_value) {
+ switch (socket_option_key) {
+ case interface::GeneralTransportOptions::PORTAL:
+ socket_option_value = portal_;
+ break;
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ ;
+ }
+
+ return SOCKET_OPTION_GET;
+ }
protected:
Socket(std::shared_ptr<core::Portal> &&portal);
@@ -48,6 +67,7 @@ class Socket {
protected:
std::shared_ptr<core::Portal> portal_;
bool is_async_;
+ hicn_format_t packet_format_;
};
} // namespace implementation
diff --git a/libtransport/src/implementation/socket_consumer.h b/libtransport/src/implementation/socket_consumer.h
index e0981af7f..ebdac7f93 100644
--- a/libtransport/src/implementation/socket_consumer.h
+++ b/libtransport/src/implementation/socket_consumer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -20,6 +20,7 @@
#include <hicn/transport/interfaces/socket_options_default_values.h>
#include <hicn/transport/interfaces/statistics.h>
#include <hicn/transport/utils/event_thread.h>
+#include <implementation/socket.h>
#include <protocols/cbr.h>
#include <protocols/raaqm.h>
#include <protocols/rtc/rtc.h>
@@ -38,7 +39,6 @@ class ConsumerSocket : public Socket {
std::shared_ptr<core::Portal> &&portal)
: Socket(std::move(portal)),
consumer_interface_(consumer),
- async_downloader_(),
interest_lifetime_(default_values::interest_lifetime),
min_window_size_(default_values::min_window_size),
max_window_size_(default_values::max_window_size),
@@ -56,6 +56,7 @@ class ConsumerSocket : public Socket {
rate_estimation_observer_(nullptr),
rate_estimation_batching_parameter_(default_values::batch),
rate_estimation_choice_(0),
+ max_unverified_delay_(default_values::max_unverified_delay),
verifier_(std::make_shared<auth::VoidVerifier>()),
verify_signature_(false),
reset_window_(false),
@@ -64,41 +65,42 @@ class ConsumerSocket : public Socket {
on_interest_satisfied_(VOID_HANDLER),
on_content_object_input_(VOID_HANDLER),
stats_summary_(VOID_HANDLER),
+ on_fwd_strategy_(VOID_HANDLER),
+ on_rec_strategy_(VOID_HANDLER),
read_callback_(nullptr),
timer_interval_milliseconds_(0),
+ recovery_strategy_(RtcTransportRecoveryStrategies::RTX_ONLY),
+ aggregated_data_(false),
+ fec_setting_(""),
guard_raaqm_params_() {
switch (protocol) {
case TransportProtocolAlgorithms::CBR:
transport_protocol_ =
- std::make_unique<protocol::CbrTransportProtocol>(this);
+ std::make_shared<protocol::CbrTransportProtocol>(this);
break;
case TransportProtocolAlgorithms::RTC:
transport_protocol_ =
- std::make_unique<protocol::rtc::RTCTransportProtocol>(this);
+ std::make_shared<protocol::rtc::RTCTransportProtocol>(this);
break;
case TransportProtocolAlgorithms::RAAQM:
default:
transport_protocol_ =
- std::make_unique<protocol::RaaqmTransportProtocol>(this);
+ std::make_shared<protocol::RaaqmTransportProtocol>(this);
break;
}
}
public:
ConsumerSocket(interface::ConsumerSocket *consumer, int protocol)
- : ConsumerSocket(consumer, protocol, std::make_shared<core::Portal>()) {}
+ : ConsumerSocket(consumer, protocol, core::Portal::createShared()) {}
ConsumerSocket(interface::ConsumerSocket *consumer, int protocol,
- asio::io_service &io_service)
- : ConsumerSocket(consumer, protocol,
- std::make_shared<core::Portal>(io_service)) {
+ ::utils::EventThread &worker)
+ : ConsumerSocket(consumer, protocol, core::Portal::createShared(worker)) {
is_async_ = true;
}
- ~ConsumerSocket() {
- stop();
- async_downloader_.stop();
- }
+ ~ConsumerSocket() { stop(); }
interface::ConsumerSocket *getInterface() {
return consumer_interface_;
@@ -122,18 +124,6 @@ class ConsumerSocket : public Socket {
transport_protocol_->start();
- return is_async_ ? CONSUMER_RUNNING : 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;
}
@@ -149,6 +139,9 @@ class ConsumerSocket : public Socket {
}
}
+ using Socket::getSocketOption;
+ using Socket::setSocketOption;
+
virtual int setSocketOption(int socket_option_key,
ReadCallback *socket_option_value) {
// Reschedule the function on the io_service to avoid race condition in
@@ -245,6 +238,10 @@ class ConsumerSocket : public Socket {
interest_lifetime_ = socket_option_value;
break;
+ case GeneralTransportOptions::MAX_UNVERIFIED_TIME:
+ max_unverified_delay_ = socket_option_value;
+ break;
+
case RateEstimationOptions::RATE_ESTIMATION_BATCH_PARAMETER:
if (socket_option_value > 0) {
rate_estimation_batching_parameter_ = socket_option_value;
@@ -265,6 +262,11 @@ class ConsumerSocket : public Socket {
timer_interval_milliseconds_ = socket_option_value;
break;
+ case RtcTransportOptions::RECOVERY_STRATEGY:
+ recovery_strategy_ =
+ (RtcTransportRecoveryStrategies)socket_option_value;
+ break;
+
default:
return SOCKET_OPTION_NOT_SET;
}
@@ -328,6 +330,11 @@ class ConsumerSocket : public Socket {
result = SOCKET_OPTION_SET;
break;
+ case RtcTransportOptions::AGGREGATED_DATA:
+ aggregated_data_ = socket_option_value;
+ result = SOCKET_OPTION_SET;
+ break;
+
default:
return result;
}
@@ -406,36 +413,37 @@ class ConsumerSocket : public Socket {
int setSocketOption(
int socket_option_key,
const std::shared_ptr<auth::Verifier> &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 SOCKET_OPTION_NOT_SET;
}
}
-
- return result;
+ return SOCKET_OPTION_SET;
}
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 DataLinkOptions::OUTPUT_INTERFACE:
+ switch (socket_option_key) {
+ case DataLinkOptions::OUTPUT_INTERFACE:
+ if (!transport_protocol_->isRunning()) {
output_interface_ = socket_option_value;
portal_->setOutputInterface(output_interface_);
result = SOCKET_OPTION_SET;
- break;
+ }
+ break;
+ case GeneralTransportOptions::FEC_TYPE:
+ fec_setting_ = socket_option_value;
+ result = SOCKET_OPTION_SET;
+ break;
- default:
- return result;
- }
+ default:
+ return result;
}
return result;
}
@@ -461,6 +469,29 @@ class ConsumerSocket : public Socket {
});
}
+ int setSocketOption(int socket_option_key,
+ StrategyCallback 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,
+ StrategyCallback socket_option_value) -> int {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::FWD_STRATEGY_CHANGE:
+ on_fwd_strategy_ = socket_option_value;
+ break;
+ case ConsumerCallbacksOptions::REC_STRATEGY_CHANGE:
+ on_rec_strategy_ = 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) {
@@ -516,6 +547,10 @@ class ConsumerSocket : public Socket {
socket_option_value = interest_lifetime_;
break;
+ case GeneralTransportOptions::MAX_UNVERIFIED_TIME:
+ socket_option_value = max_unverified_delay_;
+ break;
+
case RaaqmTransportOptions::SAMPLE_NUMBER:
socket_option_value = sample_number_;
break;
@@ -532,6 +567,10 @@ class ConsumerSocket : public Socket {
socket_option_value = timer_interval_milliseconds_;
break;
+ case RtcTransportOptions::RECOVERY_STRATEGY:
+ socket_option_value = recovery_strategy_;
+ break;
+
default:
return SOCKET_OPTION_NOT_GET;
}
@@ -553,6 +592,10 @@ class ConsumerSocket : public Socket {
socket_option_value = reset_window_;
break;
+ case RtcTransportOptions::AGGREGATED_DATA:
+ socket_option_value = aggregated_data_;
+ break;
+
default:
return SOCKET_OPTION_NOT_GET;
}
@@ -628,20 +671,6 @@ class ConsumerSocket : public Socket {
}
int getSocketOption(int socket_option_key,
- std::shared_ptr<core::Portal> &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) {
@@ -665,7 +694,6 @@ class ConsumerSocket : public Socket {
default:
return SOCKET_OPTION_NOT_GET;
}
-
return SOCKET_OPTION_GET;
}
@@ -674,6 +702,9 @@ class ConsumerSocket : public Socket {
case DataLinkOptions::OUTPUT_INTERFACE:
socket_option_value = output_interface_;
break;
+ case GeneralTransportOptions::FEC_TYPE:
+ socket_option_value = fec_setting_;
+ break;
default:
return SOCKET_OPTION_NOT_GET;
}
@@ -714,6 +745,29 @@ class ConsumerSocket : public Socket {
});
}
+ int getSocketOption(int socket_option_key,
+ StrategyCallback **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,
+ StrategyCallback **socket_option_value) -> int {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::FWD_STRATEGY_CHANGE:
+ *socket_option_value = &on_fwd_strategy_;
+ break;
+ case ConsumerCallbacksOptions::REC_STRATEGY_CHANGE:
+ *socket_option_value = &on_rec_strategy_;
+ break;
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+
+ return SOCKET_OPTION_GET;
+ });
+ }
+
protected:
template <typename Lambda, typename arg2>
int rescheduleOnIOService(int socket_option_key, arg2 socket_option_value,
@@ -726,9 +780,9 @@ class ConsumerSocket : public Socket {
/* Condition variable for the wait */
std::condition_variable cv;
bool done = false;
- portal_->getIoService().dispatch([&socket_option_key,
- &socket_option_value, &mtx, &cv,
- &result, &done, &func]() {
+ portal_->getThread().tryRunHandlerNow([&socket_option_key,
+ &socket_option_value, &mtx, &cv,
+ &result, &done, &func]() {
std::unique_lock<std::mutex> lck(mtx);
done = true;
result = func(socket_option_key, socket_option_value);
@@ -748,8 +802,6 @@ class ConsumerSocket : public Socket {
protected:
interface::ConsumerSocket *consumer_interface_;
- 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
@@ -776,6 +828,7 @@ class ConsumerSocket : public Socket {
int rate_estimation_choice_;
// Verification parameters
+ int max_unverified_delay_;
std::shared_ptr<auth::Verifier> verifier_;
transport::auth::KeyId *key_id_;
std::atomic_bool verify_signature_;
@@ -787,17 +840,26 @@ class ConsumerSocket : public Socket {
ConsumerInterestCallback on_interest_satisfied_;
ConsumerContentObjectCallback on_content_object_input_;
ConsumerTimerCallback stats_summary_;
+ StrategyCallback on_fwd_strategy_;
+ StrategyCallback on_rec_strategy_;
ReadCallback *read_callback_;
uint32_t timer_interval_milliseconds_;
// Transport protocol
- std::unique_ptr<protocol::TransportProtocol> transport_protocol_;
+ std::shared_ptr<protocol::TransportProtocol> transport_protocol_;
// Statistic
TransportStatistics stats_;
+ // RTC protocol
+ RtcTransportRecoveryStrategies recovery_strategy_;
+ bool aggregated_data_;
+
+ // FEC setting
+ std::string fec_setting_;
+
utils::SpinLock guard_raaqm_params_;
std::string output_interface_;
};
diff --git a/libtransport/src/implementation/socket_producer.h b/libtransport/src/implementation/socket_producer.h
index 9daf79b9d..37151d497 100644
--- a/libtransport/src/implementation/socket_producer.h
+++ b/libtransport/src/implementation/socket_producer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -40,6 +40,7 @@ namespace implementation {
using namespace core;
using namespace interface;
+using ProducerCallback = interface::ProducerSocket::Callback;
class ProducerSocket : public Socket {
private:
@@ -48,11 +49,14 @@ class ProducerSocket : public Socket {
: Socket(std::move(portal)),
producer_interface_(producer_socket),
data_packet_size_(default_values::content_object_packet_size),
+ max_segment_size_(default_values::content_object_packet_size),
content_object_expiry_time_(default_values::content_object_expiry_time),
- async_thread_(),
- making_manifest_(false),
+ making_manifest_(default_values::manifest_capacity),
hash_algorithm_(auth::CryptoHashType::SHA256),
- suffix_strategy_(core::NextSegmentCalculationStrategy::INCREMENTAL),
+ signer_(std::make_shared<auth::VoidSigner>()),
+ suffix_strategy_(std::make_shared<utils::IncrementalSuffixStrategy>(0)),
+ aggregated_data_(false),
+ fec_setting_(""),
on_interest_input_(VOID_HANDLER),
on_interest_dropped_input_buffer_(VOID_HANDLER),
on_interest_inserted_input_buffer_(VOID_HANDLER),
@@ -63,29 +67,30 @@ class ProducerSocket : public Socket {
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) {
+ on_content_produced_(VOID_HANDLER),
+ application_callback_(nullptr) {
switch (protocol) {
case ProductionProtocolAlgorithms::RTC_PROD:
production_protocol_ =
- std::make_unique<protocol::RTCProductionProtocol>(this);
+ std::make_shared<protocol::RTCProductionProtocol>(this);
break;
case ProductionProtocolAlgorithms::BYTE_STREAM:
default:
production_protocol_ =
- std::make_unique<protocol::ByteStreamProductionProtocol>(this);
+ std::make_shared<protocol::ByteStreamProductionProtocol>(this);
break;
}
}
public:
ProducerSocket(interface::ProducerSocket *producer, int protocol)
- : ProducerSocket(producer, protocol, std::make_shared<core::Portal>()) {}
+ : ProducerSocket(producer, protocol, core::Portal::createShared()) {
+ is_async_ = true;
+ }
ProducerSocket(interface::ProducerSocket *producer, int protocol,
- asio::io_service &io_service)
- : ProducerSocket(producer, protocol,
- std::make_shared<core::Portal>(io_service)) {
- is_async_ = true;
+ ::utils::EventThread &worker)
+ : ProducerSocket(producer, protocol, core::Portal::createShared(worker)) {
}
virtual ~ProducerSocket() {}
@@ -98,31 +103,9 @@ class ProducerSocket : public Socket {
producer_interface_ = producer_socket;
}
- void connect() override {
- portal_->connect(false);
- production_protocol_->start();
- }
-
- bool isRunning() override { return !production_protocol_->isRunning(); };
+ void connect() override { portal_->connect(false); }
- virtual void asyncProduce(Name content_name,
- std::unique_ptr<utils::MemBuf> &&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<utils::MemBuf>(a);
- if (last_segment != NULL) {
- **last_segment = offset + produceStream(content_name, std::move(buf),
- is_last, offset);
- } else {
- produceStream(content_name, std::move(buf), is_last, offset);
- }
- });
- }
- }
+ bool isRunning() override { return production_protocol_->isRunning(); };
virtual uint32_t produceStream(const Name &content_name,
std::unique_ptr<utils::MemBuf> &&buffer,
@@ -156,12 +139,38 @@ class ProducerSocket : public Socket {
production_protocol_->produce(content_object);
}
+ void sendMapme() { production_protocol_->sendMapme(); }
+
void registerPrefix(const Prefix &producer_namespace) {
- production_protocol_->registerNamespaceWithNetwork(producer_namespace);
+ portal_->registerRoute(producer_namespace);
}
+ void start() { production_protocol_->start(); }
void stop() { production_protocol_->stop(); }
+ using Socket::getSocketOption;
+ using Socket::setSocketOption;
+
+ virtual int setSocketOption(int socket_option_key,
+ ProducerCallback *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,
+ ProducerCallback *socket_option_value) -> int {
+ switch (socket_option_key) {
+ case ProducerCallbacksOptions::PRODUCER_CALLBACK:
+ application_callback_ = socket_option_value;
+ break;
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ return SOCKET_OPTION_SET;
+ });
+ }
+
virtual int setSocketOption(int socket_option_key,
uint32_t socket_option_value) {
switch (socket_option_key) {
@@ -172,6 +181,17 @@ class ProducerSocket : public Socket {
}
break;
+ case GeneralTransportOptions::MAKE_MANIFEST:
+ making_manifest_ = socket_option_value;
+ break;
+
+ case GeneralTransportOptions::MAX_SEGMENT_SIZE:
+ if (socket_option_value <= default_values::max_content_object_size &&
+ socket_option_value > 0) {
+ max_segment_size_ = socket_option_value;
+ }
+ break;
+
case GeneralTransportOptions::OUTPUT_BUFFER_SIZE:
production_protocol_->setOutputBufferSize(socket_option_value);
break;
@@ -260,8 +280,8 @@ class ProducerSocket : public Socket {
virtual int setSocketOption(int socket_option_key, bool socket_option_value) {
switch (socket_option_key) {
- case GeneralTransportOptions::MAKE_MANIFEST:
- making_manifest_ = socket_option_value;
+ case RtcTransportOptions::AGGREGATED_DATA:
+ aggregated_data_ = socket_option_value;
break;
default:
@@ -385,7 +405,7 @@ class ProducerSocket : public Socket {
virtual int setSocketOption(
int socket_option_key,
- core::NextSegmentCalculationStrategy socket_option_value) {
+ const std::shared_ptr<utils::SuffixStrategy> &socket_option_value) {
switch (socket_option_key) {
case GeneralTransportOptions::SUFFIX_STRATEGY:
suffix_strategy_ = socket_option_value;
@@ -413,9 +433,33 @@ class ProducerSocket : public Socket {
return SOCKET_OPTION_SET;
}
+ int getSocketOption(int socket_option_key,
+ ProducerCallback **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,
+ ProducerCallback **socket_option_value) -> int {
+ switch (socket_option_key) {
+ case ProducerCallbacksOptions::PRODUCER_CALLBACK:
+ *socket_option_value = application_callback_;
+ break;
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+
+ return SOCKET_OPTION_GET;
+ });
+ }
+
virtual int getSocketOption(int socket_option_key,
uint32_t &socket_option_value) {
switch (socket_option_key) {
+ case GeneralTransportOptions::MAKE_MANIFEST:
+ socket_option_value = making_manifest_;
+ break;
+
case GeneralTransportOptions::OUTPUT_BUFFER_SIZE:
socket_option_value = production_protocol_->getOutputBufferSize();
break;
@@ -424,6 +468,10 @@ class ProducerSocket : public Socket {
socket_option_value = (uint32_t)data_packet_size_;
break;
+ case GeneralTransportOptions::MAX_SEGMENT_SIZE:
+ socket_option_value = (uint32_t)max_segment_size_;
+ break;
+
case GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME:
socket_option_value = content_object_expiry_time_;
break;
@@ -438,14 +486,14 @@ class ProducerSocket : public Socket {
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;
-
case GeneralTransportOptions::ASYNC_MODE:
socket_option_value = is_async_;
break;
+ case RtcTransportOptions::AGGREGATED_DATA:
+ socket_option_value = aggregated_data_;
+ break;
+
default:
return SOCKET_OPTION_NOT_GET;
}
@@ -547,21 +595,6 @@ class ProducerSocket : public Socket {
});
}
- virtual int getSocketOption(
- int socket_option_key,
- std::shared_ptr<core::Portal> &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,
auth::CryptoHashType &socket_option_value) {
switch (socket_option_key) {
@@ -577,7 +610,7 @@ class ProducerSocket : public Socket {
virtual int getSocketOption(
int socket_option_key,
- core::NextSegmentCalculationStrategy &socket_option_value) {
+ std::shared_ptr<utils::SuffixStrategy> &socket_option_value) {
switch (socket_option_key) {
case GeneralTransportOptions::SUFFIX_STRATEGY:
socket_option_value = suffix_strategy_;
@@ -603,9 +636,31 @@ class ProducerSocket : public Socket {
return SOCKET_OPTION_GET;
}
+ int getSocketOption(int socket_option_key, std::string &socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::FEC_TYPE:
+ socket_option_value = fec_setting_;
+ 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;
+ int result = SOCKET_OPTION_NOT_SET;
+ switch (socket_option_key) {
+ case GeneralTransportOptions::FEC_TYPE:
+ fec_setting_ = socket_option_value;
+ result = SOCKET_OPTION_SET;
+ break;
+
+ default:
+ return result;
+ }
+ return result;
}
// If the thread calling lambda_func is not the same of io_service, this
@@ -623,9 +678,9 @@ class ProducerSocket : public Socket {
std::condition_variable cv;
bool done = false;
- portal_->getIoService().dispatch([&socket_option_key,
- &socket_option_value, &mtx, &cv,
- &result, &done, &func]() {
+ portal_->getThread().tryRunHandlerNow([&socket_option_key,
+ &socket_option_value, &mtx, &cv,
+ &result, &done, &func]() {
std::unique_lock<std::mutex> lck(mtx);
done = true;
result = func(socket_option_key, socket_option_value);
@@ -655,9 +710,9 @@ class ProducerSocket : public Socket {
/* Condition variable for the wait */
std::condition_variable cv;
bool done = false;
- portal_->getIoService().dispatch([&socket_option_key,
- &socket_option_value, &mtx, &cv,
- &result, &done, &func]() {
+ portal_->getThread().tryRunHandlerNow([&socket_option_key,
+ &socket_option_value, &mtx, &cv,
+ &result, &done, &func]() {
std::unique_lock<std::mutex> lck(mtx);
done = true;
result = func(socket_option_key, socket_option_value);
@@ -677,20 +732,24 @@ class ProducerSocket : public Socket {
// Threads
protected:
interface::ProducerSocket *producer_interface_;
- asio::io_service io_service_;
std::atomic<size_t> data_packet_size_;
+ std::atomic<size_t> max_segment_size_;
std::atomic<uint32_t> content_object_expiry_time_;
- utils::EventThread async_thread_;
-
- std::atomic<bool> making_manifest_;
+ std::atomic<uint32_t> making_manifest_;
std::atomic<auth::CryptoHashType> hash_algorithm_;
std::atomic<auth::CryptoSuite> crypto_suite_;
utils::SpinLock signer_lock_;
std::shared_ptr<auth::Signer> signer_;
- core::NextSegmentCalculationStrategy suffix_strategy_;
+ std::shared_ptr<utils::SuffixStrategy> suffix_strategy_;
+
+ std::shared_ptr<protocol::ProductionProtocol> production_protocol_;
- std::unique_ptr<protocol::ProductionProtocol> production_protocol_;
+ // RTC transport
+ bool aggregated_data_;
+
+ // FEC setting
+ std::string fec_setting_;
// callbacks
ProducerInterestCallback on_interest_input_;
@@ -706,6 +765,8 @@ class ProducerSocket : public Socket {
ProducerContentObjectCallback on_content_object_evicted_from_output_buffer_;
ProducerContentCallback on_content_produced_;
+
+ ProducerCallback *application_callback_;
};
} // namespace implementation
diff --git a/libtransport/src/implementation/tls_rtc_socket_producer.cc b/libtransport/src/implementation/tls_rtc_socket_producer.cc
index db62b10c1..06d613ef0 100644
--- a/libtransport/src/implementation/tls_rtc_socket_producer.cc
+++ b/libtransport/src/implementation/tls_rtc_socket_producer.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -90,11 +90,11 @@ int TLSRTCProducerSocket::writeOld(BIO *b, const char *buf, int num) {
socket = (TLSRTCProducerSocket *)BIO_get_data(b);
if (socket->getHandshakeState() != SERVER_FINISHED && socket->first_) {
- bool making_manifest = socket->parent_->making_manifest_;
+ uint32_t making_manifest = socket->parent_->making_manifest_;
socket->tls_chunks_--;
socket->parent_->setSocketOption(GeneralTransportOptions::MAKE_MANIFEST,
- false);
+ 0U);
socket->parent_->ProducerSocket::produce(
socket->name_, (const uint8_t *)buf, num, socket->tls_chunks_ == 0, 0);
socket->parent_->setSocketOption(GeneralTransportOptions::MAKE_MANIFEST,
diff --git a/libtransport/src/implementation/tls_rtc_socket_producer.h b/libtransport/src/implementation/tls_rtc_socket_producer.h
index 92c657afc..f6dc425e4 100644
--- a/libtransport/src/implementation/tls_rtc_socket_producer.h
+++ b/libtransport/src/implementation/tls_rtc_socket_producer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/implementation/tls_socket_consumer.cc b/libtransport/src/implementation/tls_socket_consumer.cc
index 65472b41d..b368c4b88 100644
--- a/libtransport/src/implementation/tls_socket_consumer.cc
+++ b/libtransport/src/implementation/tls_socket_consumer.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -43,7 +43,7 @@ int readOldTLS(BIO *b, char *buf, int size) {
if (!socket->something_to_read_) {
if (!socket->transport_protocol_->isRunning()) {
socket->network_name_.setSuffix(socket->random_suffix_);
- socket->ConsumerSocket::asyncConsume(socket->network_name_);
+ socket->ConsumerSocket::consume(socket->network_name_);
}
if (!socket->something_to_read_) socket->cv_.wait(lck);
@@ -284,31 +284,6 @@ int TLSConsumerSocket::download_content(const Name &name) {
return CONSUMER_FINISHED;
}
-int TLSConsumerSocket::asyncConsume(const Name &name,
- std::unique_ptr<utils::MemBuf> &&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]() { download_content(name); });
- }
-
- return CONSUMER_RUNNING;
-}
-
void TLSConsumerSocket::registerPrefix(const Prefix &producer_namespace) {
producer_namespace_ = producer_namespace;
}
@@ -353,7 +328,7 @@ void TLSConsumerSocket::readBufferAvailable(
cv_.notify_one();
}
-void TLSConsumerSocket::readError(const std::error_code ec) noexcept {}
+void TLSConsumerSocket::readError(const std::error_code &ec) noexcept {}
void TLSConsumerSocket::readSuccess(std::size_t total_size) noexcept {
std::unique_lock<std::mutex> lck(this->mtx_);
diff --git a/libtransport/src/implementation/tls_socket_consumer.h b/libtransport/src/implementation/tls_socket_consumer.h
index be08ec47d..a74f1ee10 100644
--- a/libtransport/src/implementation/tls_socket_consumer.h
+++ b/libtransport/src/implementation/tls_socket_consumer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -47,9 +47,6 @@ class TLSConsumerSocket : public ConsumerSocket,
int consume(const Name &name, std::unique_ptr<utils::MemBuf> &&buffer);
int consume(const Name &name) override;
- int asyncConsume(const Name &name, std::unique_ptr<utils::MemBuf> &&buffer);
- int asyncConsume(const Name &name) override;
-
void registerPrefix(const Prefix &producer_namespace);
int setSocketOption(
@@ -100,7 +97,7 @@ class TLSConsumerSocket : public ConsumerSocket,
virtual void readBufferAvailable(
std::unique_ptr<utils::MemBuf> &&buffer) noexcept override;
- virtual void readError(const std::error_code ec) noexcept override;
+ virtual void readError(const std::error_code &ec) noexcept override;
virtual void readSuccess(std::size_t total_size) noexcept override;
diff --git a/libtransport/src/implementation/tls_socket_producer.cc b/libtransport/src/implementation/tls_socket_producer.cc
index 3992ca45c..47f3b43a6 100644
--- a/libtransport/src/implementation/tls_socket_producer.cc
+++ b/libtransport/src/implementation/tls_socket_producer.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -99,12 +99,12 @@ int TLSProducerSocket::writeOld(BIO *b, const char *buf, int num) {
socket = (TLSProducerSocket *)BIO_get_data(b);
if (socket->getHandshakeState() != SERVER_FINISHED && socket->first_) {
- bool making_manifest = socket->parent_->making_manifest_;
+ uint32_t making_manifest = socket->parent_->making_manifest_;
//! socket->tls_chunks_ corresponds to is_last
socket->tls_chunks_--;
socket->parent_->setSocketOption(GeneralTransportOptions::MAKE_MANIFEST,
- false);
+ 0U);
socket->parent_->ProducerSocket::produceStream(
socket->name_, (const uint8_t *)buf, num, socket->tls_chunks_ == 0,
socket->last_segment_);
@@ -358,7 +358,7 @@ uint32_t TLSProducerSocket::produceStream(
}
size_t buf_size = buffer->length();
- name_ = production_protocol_->getNamespaces().front().mapName(content_name);
+ name_ = portal_->getServedNamespaces().begin()->mapName(content_name);
tls_chunks_ = to_call_oncontentproduced_ =
(int)ceil((float)buf_size / (float)SSL3_RT_MAX_PLAIN_LENGTH);
@@ -394,8 +394,7 @@ int TLSProducerSocket::addHicnKeyIdCb(SSL *s, unsigned int ext_type,
<< "On addHicnKeyIdCb, for the prefix registration.";
if (ext_type == 100) {
- auto &prefix =
- socket->parent_->production_protocol_->getNamespaces().front();
+ auto &prefix = *socket->parent_->portal_->getServedNamespaces().begin();
const ip_prefix_t &ip_prefix = prefix.toIpPrefixStruct();
int inet_family = prefix.getAddressFamily();
uint16_t prefix_len_bits = prefix.getPrefixLength();
diff --git a/libtransport/src/implementation/tls_socket_producer.h b/libtransport/src/implementation/tls_socket_producer.h
index a542a4d9f..0e958b321 100644
--- a/libtransport/src/implementation/tls_socket_producer.h
+++ b/libtransport/src/implementation/tls_socket_producer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/interfaces/CMakeLists.txt b/libtransport/src/interfaces/CMakeLists.txt
index 7ec024fec..0a0603ac8 100644
--- a/libtransport/src/interfaces/CMakeLists.txt
+++ b/libtransport/src/interfaces/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2019 Cisco and/or its affiliates.
+# Copyright (c) 2021 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
diff --git a/libtransport/src/interfaces/callbacks.cc b/libtransport/src/interfaces/callbacks.cc
index 6869ac3f7..776b4cbe7 100644
--- a/libtransport/src/interfaces/callbacks.cc
+++ b/libtransport/src/interfaces/callbacks.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/interfaces/p2psecure_socket_consumer.cc b/libtransport/src/interfaces/p2psecure_socket_consumer.cc
index e473a1e2e..e329a50f1 100644
--- a/libtransport/src/interfaces/p2psecure_socket_consumer.cc
+++ b/libtransport/src/interfaces/p2psecure_socket_consumer.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/interfaces/p2psecure_socket_producer.cc b/libtransport/src/interfaces/p2psecure_socket_producer.cc
index 10d8a1367..5f98302d0 100644
--- a/libtransport/src/interfaces/p2psecure_socket_producer.cc
+++ b/libtransport/src/interfaces/p2psecure_socket_producer.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -23,10 +23,11 @@ P2PSecureProducerSocket::P2PSecureProducerSocket() {
socket_ = std::make_unique<implementation::P2PSecureProducerSocket>(this);
}
-P2PSecureProducerSocket::P2PSecureProducerSocket(
- bool rtc, const std::shared_ptr<auth::Identity> &identity) {
- socket_ = std::make_unique<implementation::P2PSecureProducerSocket>(this, rtc,
- identity);
+P2PSecureProducerSocket::P2PSecureProducerSocket(bool rtc,
+ std::string &keystore_path,
+ std::string &keystore_pwd) {
+ socket_ = std::make_unique<implementation::P2PSecureProducerSocket>(
+ this, rtc, keystore_path, keystore_pwd);
}
} // namespace interface
diff --git a/libtransport/src/interfaces/portal.cc b/libtransport/src/interfaces/portal.cc
index 9db0621f6..84634a282 100644
--- a/libtransport/src/interfaces/portal.cc
+++ b/libtransport/src/interfaces/portal.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -13,83 +13,106 @@
* limitations under the License.
*/
+#include <core/portal.h>
#include <hicn/transport/interfaces/portal.h>
-#include <implementation/socket.h>
namespace transport {
namespace interface {
-Portal::Portal() { implementation_ = new core::Portal(); }
+class Portal::Impl {
+ public:
+ Impl() : portal_(core::Portal::createShared()) {}
+ Impl(::utils::EventThread &worker)
+ : portal_(core::Portal::createShared(worker)) {}
-Portal::Portal(asio::io_service &io_service) {
- implementation_ = new core::Portal(io_service);
-}
+ void registerTransportCallback(TransportCallback *transport_callback) {
+ portal_->registerTransportCallback(transport_callback);
+ }
+
+ void connect(bool is_consumer) { portal_->connect(is_consumer); }
+
+ bool interestIsPending(const core::Name &name) {
+ return portal_->interestIsPending(name);
+ }
+
+ void sendInterest(core::Interest::Ptr &&interest,
+ OnContentObjectCallback &&on_content_object_callback,
+ OnInterestTimeoutCallback &&on_interest_timeout_callback) {
+ portal_->sendInterest(std::move(interest),
+ std::move(on_content_object_callback),
+ std::move(on_interest_timeout_callback));
+ }
+
+ void sendContentObject(core::ContentObject &content_object) {
+ portal_->sendContentObject(content_object);
+ }
+
+ void killConnection() { portal_->killConnection(); }
+
+ void clear() { portal_->clear(); }
-Portal::~Portal() { delete reinterpret_cast<core::Portal *>(implementation_); }
+ utils::EventThread &getThread() { return portal_->getThread(); }
-void Portal::setConsumerCallback(ConsumerCallback *consumer_callback) {
- reinterpret_cast<core::Portal *>(implementation_)
- ->setConsumerCallback(consumer_callback);
+ void registerRoute(core::Prefix &prefix) { portal_->registerRoute(prefix); }
+
+ void sendMapme() { portal_->sendMapme(); }
+
+ void setForwardingStrategy(core::Prefix &prefix, std::string &strategy) {
+ portal_->setForwardingStrategy(prefix, strategy);
+ }
+
+ private:
+ std::shared_ptr<core::Portal> portal_;
+};
+
+Portal::Portal() { implementation_ = new Impl(); }
+
+Portal::Portal(::utils::EventThread &worker) {
+ implementation_ = new Impl(worker);
}
-void Portal::setProducerCallback(ProducerCallback *producer_callback) {
- reinterpret_cast<core::Portal *>(implementation_)
- ->setProducerCallback(producer_callback);
+Portal::~Portal() { delete implementation_; }
+
+void Portal::registerTransportCallback(TransportCallback *transport_callback) {
+ implementation_->registerTransportCallback(transport_callback);
}
void Portal::connect(bool is_consumer) {
- reinterpret_cast<core::Portal *>(implementation_)->connect(is_consumer);
+ implementation_->connect(is_consumer);
}
bool Portal::interestIsPending(const core::Name &name) {
- return reinterpret_cast<core::Portal *>(implementation_)
- ->interestIsPending(name);
+ return implementation_->interestIsPending(name);
}
void Portal::sendInterest(
core::Interest::Ptr &&interest,
OnContentObjectCallback &&on_content_object_callback,
OnInterestTimeoutCallback &&on_interest_timeout_callback) {
- reinterpret_cast<core::Portal *>(implementation_)
- ->sendInterest(std::move(interest), std::move(on_content_object_callback),
- std::move(on_interest_timeout_callback));
-}
-
-void Portal::bind(const BindConfig &config) {
- reinterpret_cast<core::Portal *>(implementation_)->bind(config);
-}
-
-void Portal::runEventsLoop() {
- reinterpret_cast<core::Portal *>(implementation_)->runEventsLoop();
-}
-
-void Portal::runOneEvent() {
- reinterpret_cast<core::Portal *>(implementation_)->runOneEvent();
+ implementation_->sendInterest(std::move(interest),
+ std::move(on_content_object_callback),
+ std::move(on_interest_timeout_callback));
}
void Portal::sendContentObject(core::ContentObject &content_object) {
- reinterpret_cast<core::Portal *>(implementation_)
- ->sendContentObject(content_object);
+ implementation_->sendContentObject(content_object);
}
-void Portal::stopEventsLoop() {
- reinterpret_cast<core::Portal *>(implementation_)->stopEventsLoop();
-}
+void Portal::killConnection() { implementation_->killConnection(); }
-void Portal::killConnection() {
- reinterpret_cast<core::Portal *>(implementation_)->killConnection();
-}
+void Portal::clear() { implementation_->clear(); }
-void Portal::clear() {
- reinterpret_cast<core::Portal *>(implementation_)->clear();
-}
+utils::EventThread &Portal::getThread() { return implementation_->getThread(); }
-asio::io_service &Portal::getIoService() {
- return reinterpret_cast<core::Portal *>(implementation_)->getIoService();
+void Portal::registerRoute(core::Prefix &prefix) {
+ implementation_->registerRoute(prefix);
}
-void Portal::registerRoute(core::Prefix &prefix) {
- reinterpret_cast<core::Portal *>(implementation_)->registerRoute(prefix);
+void Portal::sendMapme() { implementation_->sendMapme(); }
+
+void Portal::setForwardingStrategy(core::Prefix &prefix,
+ std::string &strategy) {
+ implementation_->setForwardingStrategy(prefix, strategy);
}
} // namespace interface
diff --git a/libtransport/src/interfaces/socket_consumer.cc b/libtransport/src/interfaces/socket_consumer.cc
index 4eee73cab..747dc0974 100644
--- a/libtransport/src/interfaces/socket_consumer.cc
+++ b/libtransport/src/interfaces/socket_consumer.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -23,23 +23,28 @@ ConsumerSocket::ConsumerSocket(int protocol) {
socket_ = std::make_unique<implementation::ConsumerSocket>(this, protocol);
}
-ConsumerSocket::ConsumerSocket(int protocol, asio::io_service &io_service) {
- socket_ = std::make_unique<implementation::ConsumerSocket>(this, protocol,
- io_service);
+ConsumerSocket::ConsumerSocket(int protocol, ::utils::EventThread &worker) {
+ socket_ =
+ std::make_unique<implementation::ConsumerSocket>(this, protocol, worker);
}
ConsumerSocket::ConsumerSocket() {}
-ConsumerSocket::~ConsumerSocket() { socket_->stop(); }
+ConsumerSocket::ConsumerSocket(ConsumerSocket &&other) noexcept
+ : socket_(std::move(other.socket_)) {}
+
+ConsumerSocket::~ConsumerSocket() {
+ if (socket_) {
+ 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);
+int ConsumerSocket::consume(const Name &name, bool blocking) {
+ return socket_->consume(name);
}
void ConsumerSocket::stop() { socket_->stop(); }
@@ -111,6 +116,16 @@ int ConsumerSocket::setSocketOption(int socket_option_key,
return socket_->setSocketOption(socket_option_key, socket_option_value);
}
+int ConsumerSocket::setSocketOption(int socket_option_key,
+ StrategyCallback socket_option_value) {
+ return socket_->setSocketOption(socket_option_key, socket_option_value);
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+ Packet::Format 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);
@@ -169,6 +184,16 @@ int ConsumerSocket::getSocketOption(
return socket_->getSocketOption(socket_option_key, socket_option_value);
}
+int ConsumerSocket::getSocketOption(int socket_option_key,
+ StrategyCallback **socket_option_value) {
+ return socket_->getSocketOption(socket_option_key, socket_option_value);
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+ Packet::Format &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
index b04947dfd..10613c0e1 100644
--- a/libtransport/src/interfaces/socket_producer.cc
+++ b/libtransport/src/interfaces/socket_producer.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -33,14 +33,21 @@ ProducerSocket::ProducerSocket(int protocol) {
socket_ = std::make_unique<implementation::ProducerSocket>(this, protocol);
}
-ProducerSocket::ProducerSocket(int protocol, asio::io_service &io_service) {
- socket_ = std::make_unique<implementation::ProducerSocket>(this, protocol,
- io_service);
+ProducerSocket::ProducerSocket(int protocol, ::utils::EventThread &worker) {
+ socket_ =
+ std::make_unique<implementation::ProducerSocket>(this, protocol, worker);
}
+ProducerSocket::ProducerSocket(ProducerSocket &&other) noexcept
+ : socket_(std::move(other.socket_)) {}
+
ProducerSocket::ProducerSocket(bool) {}
-ProducerSocket::~ProducerSocket() { socket_->stop(); }
+ProducerSocket::~ProducerSocket() {
+ if (socket_) {
+ socket_->stop();
+ }
+}
void ProducerSocket::connect() { socket_->connect(); }
@@ -76,18 +83,14 @@ void ProducerSocket::produce(ContentObject &content_object) {
return socket_->produce(content_object);
}
-void ProducerSocket::asyncProduce(Name content_name,
- std::unique_ptr<utils::MemBuf> &&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::sendMapme() { return socket_->sendMapme(); }
void ProducerSocket::registerPrefix(const Prefix &producer_namespace) {
return socket_->registerPrefix(producer_namespace);
}
+void ProducerSocket::start() { return socket_->start(); }
+
void ProducerSocket::stop() { return socket_->stop(); }
asio::io_service &ProducerSocket::getIoService() {
@@ -95,6 +98,11 @@ asio::io_service &ProducerSocket::getIoService() {
};
int ProducerSocket::setSocketOption(int socket_option_key,
+ Callback *socket_option_value) {
+ return socket_->setSocketOption(socket_option_key, socket_option_value);
+}
+
+int ProducerSocket::setSocketOption(int socket_option_key,
uint32_t socket_option_value) {
return socket_->setSocketOption(socket_option_key, socket_option_value);
}
@@ -140,9 +148,14 @@ int ProducerSocket::setSocketOption(
return socket_->setSocketOption(socket_option_key, socket_option_value);
}
+int ProducerSocket::setSocketOption(int socket_option_key,
+ Packet::Format 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);
+ return socket_->getSocketOption(socket_option_key, socket_option_value);
}
int ProducerSocket::setSocketOption(int socket_option_key,
@@ -181,6 +194,11 @@ int ProducerSocket::getSocketOption(
return socket_->getSocketOption(socket_option_key, socket_option_value);
}
+int ProducerSocket::getSocketOption(int socket_option_key,
+ Packet::Format &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
index 7326fcbcb..6bf1b011c 100644
--- a/libtransport/src/interfaces/tls_rtc_socket_producer.cc
+++ b/libtransport/src/interfaces/tls_rtc_socket_producer.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/interfaces/tls_rtc_socket_producer.h b/libtransport/src/interfaces/tls_rtc_socket_producer.h
index 3ea84095b..b8b6ec298 100644
--- a/libtransport/src/interfaces/tls_rtc_socket_producer.h
+++ b/libtransport/src/interfaces/tls_rtc_socket_producer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/interfaces/tls_socket_consumer.cc b/libtransport/src/interfaces/tls_socket_consumer.cc
index 6c1c535b5..24060d1d8 100644
--- a/libtransport/src/interfaces/tls_socket_consumer.cc
+++ b/libtransport/src/interfaces/tls_socket_consumer.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/interfaces/tls_socket_consumer.h b/libtransport/src/interfaces/tls_socket_consumer.h
index 845a9181f..242dc91a5 100644
--- a/libtransport/src/interfaces/tls_socket_consumer.h
+++ b/libtransport/src/interfaces/tls_socket_consumer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/interfaces/tls_socket_producer.cc b/libtransport/src/interfaces/tls_socket_producer.cc
index 037702f72..b2b9e723a 100644
--- a/libtransport/src/interfaces/tls_socket_producer.cc
+++ b/libtransport/src/interfaces/tls_socket_producer.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/interfaces/tls_socket_producer.h b/libtransport/src/interfaces/tls_socket_producer.h
index 3c662176a..9b31cb483 100644
--- a/libtransport/src/interfaces/tls_socket_producer.h
+++ b/libtransport/src/interfaces/tls_socket_producer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/io_modules/CMakeLists.txt b/libtransport/src/io_modules/CMakeLists.txt
index 29aec236a..f4143de04 100644
--- a/libtransport/src/io_modules/CMakeLists.txt
+++ b/libtransport/src/io_modules/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2021 Cisco and/or its affiliates.
+# Copyright (c) 2021-2022 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
@@ -11,25 +11,69 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+
+##############################################################
+# Android case: no submodules
+##############################################################
if (${CMAKE_SYSTEM_NAME} MATCHES Android)
list(APPEND SOURCE_FILES
- ${CMAKE_CURRENT_SOURCE_DIR}/udp/hicn_forwarder_module.cc
- ${CMAKE_CURRENT_SOURCE_DIR}/udp/udp_socket_connector.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn-light-ng/hicn_forwarder_module.cc
)
list(APPEND HEADER_FILES
- ${CMAKE_CURRENT_SOURCE_DIR}/udp/hicn_forwarder_module.h
- ${CMAKE_CURRENT_SOURCE_DIR}/udp/udp_socket_connector.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn-light-ng/hicn_forwarder_module.h
+ )
+
+ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
+ find_package(Libhicnctrl ${CURRENT_VERSION} REQUIRED NO_MODULE)
+
+ if (DISABLE_SHARED_LIBRARIES)
+ set(LIBTYPE static)
+ else()
+ set(LIBTYPE shared)
+ endif()
+
+ list(APPEND LIBHICNCTRL_LIBRARIES hicn::hicnctrl.${LIBTYPE})
+ else()
+ if (DISABLE_SHARED_LIBRARIES)
+ if (WIN32)
+ set(LIBHICNCTRL_LIBRARIES ${LIBHICNCTRL_STATIC})
+ else ()
+ set(LIBHICNCTRL_LIBRARIES ${LIBHICNCTRL_STATIC} log)
+ endif ()
+ list(APPEND DEPENDENCIES
+ ${LIBHICNCTRL_STATIC}
+ )
+ else()
+ set(LIBHICNCTRL_LIBRARIES ${LIBHICNCTRL_SHARED})
+ list(APPEND DEPENDENCIES
+ ${LIBHICNCTRL_SHARED}
+ )
+ endif()
+ endif()
+
+ list(APPEND LIBRARIES
+ PRIVATE ${LIBHICNCTRL_LIBRARIES}
+ )
+
+ list(APPEND LIBTRANSPORT_INTERNAL_INCLUDE_DIRS
+ PUBLIC
+ $<BUILD_INTERFACE:${LIBHICNCTRL_INCLUDE_DIRS}>
)
set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
+ set(LIBRARIES ${LIBRARIES} PARENT_SCOPE)
+ set(LIBTRANSPORT_INTERNAL_INCLUDE_DIRS ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS} PARENT_SCOPE)
else()
- add_subdirectory(udp)
+##############################################################
+# Compile submodules
+##############################################################
+ add_subdirectory(hicn-light-ng)
add_subdirectory(loopback)
add_subdirectory(forwarder)
if (__vpp__)
add_subdirectory(memif)
endif()
-endif() \ No newline at end of file
+endif()
diff --git a/libtransport/src/io_modules/forwarder/CMakeLists.txt b/libtransport/src/io_modules/forwarder/CMakeLists.txt
index a1d0c5db5..3922316d3 100644
--- a/libtransport/src/io_modules/forwarder/CMakeLists.txt
+++ b/libtransport/src/io_modules/forwarder/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2021 Cisco and/or its affiliates.
+# Copyright (c) 2021-2022 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
@@ -17,8 +17,6 @@ list(APPEND MODULE_HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/errors.h
${CMAKE_CURRENT_SOURCE_DIR}/forwarder_module.h
${CMAKE_CURRENT_SOURCE_DIR}/forwarder.h
- ${CMAKE_CURRENT_SOURCE_DIR}/udp_tunnel_listener.h
- ${CMAKE_CURRENT_SOURCE_DIR}/udp_tunnel.h
${CMAKE_CURRENT_SOURCE_DIR}/global_counter.h
)
@@ -26,16 +24,13 @@ list(APPEND MODULE_SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/errors.cc
${CMAKE_CURRENT_SOURCE_DIR}/forwarder_module.cc
${CMAKE_CURRENT_SOURCE_DIR}/forwarder.cc
- ${CMAKE_CURRENT_SOURCE_DIR}/udp_tunnel_listener.cc
- ${CMAKE_CURRENT_SOURCE_DIR}/udp_tunnel.cc
)
build_module(forwarder_module
- SHARED
SOURCES ${MODULE_SOURCE_FILES}
DEPENDS ${DEPENDENCIES}
COMPONENT ${LIBTRANSPORT_COMPONENT}-io-modules
- INCLUDE_DIRS ${LIBTRANSPORT_INCLUDE_DIRS} ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS}
+ INCLUDE_DIRS ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS} ${Libhicn_INCLUDE_DIRS}
DEFINITIONS ${COMPILER_DEFINITIONS}
- COMPILE_OPTIONS ${COMPILE_FLAGS}
+ COMPILE_OPTIONS ${COMPILER_OPTIONS}
)
diff --git a/libtransport/src/io_modules/forwarder/errors.cc b/libtransport/src/io_modules/forwarder/errors.cc
index b5f131499..6e93d0453 100644
--- a/libtransport/src/io_modules/forwarder/errors.cc
+++ b/libtransport/src/io_modules/forwarder/errors.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
*/
#include <io_modules/forwarder/errors.h>
diff --git a/libtransport/src/io_modules/forwarder/forwarder.cc b/libtransport/src/io_modules/forwarder/forwarder.cc
index 0546cb8b3..3ae5bf397 100644
--- a/libtransport/src/io_modules/forwarder/forwarder.cc
+++ b/libtransport/src/io_modules/forwarder/forwarder.cc
@@ -15,11 +15,11 @@
#include <core/global_configuration.h>
#include <core/local_connector.h>
+#include <core/udp_connector.h>
+#include <core/udp_listener.h>
#include <glog/logging.h>
#include <io_modules/forwarder/forwarder.h>
#include <io_modules/forwarder/global_id_counter.h>
-#include <io_modules/forwarder/udp_tunnel.h>
-#include <io_modules/forwarder/udp_tunnel_listener.h>
namespace transport {
@@ -89,11 +89,12 @@ void Forwarder::initConnectors() {
Connector::Id Forwarder::registerLocalConnector(
asio::io_service &io_service,
Connector::PacketReceivedCallback &&receive_callback,
+ Connector::PacketSentCallback &&sent_callback,
Connector::OnReconnectCallback &&reconnect_callback) {
utils::SpinLock::Acquire locked(connector_lock_);
auto id = GlobalCounter<Connector::Id>::getInstance().getNext();
auto connector = std::make_shared<LocalConnector>(
- io_service, receive_callback, nullptr, nullptr, reconnect_callback);
+ io_service, receive_callback, sent_callback, nullptr, reconnect_callback);
connector->setConnectorId(id);
local_connectors_.emplace(id, std::move(connector));
return id;
@@ -105,6 +106,7 @@ Forwarder &Forwarder::deleteConnector(Connector::Id id) {
if (it != local_connectors_.end()) {
it->second->close();
local_connectors_.erase(it);
+ } else {
}
return *this;
@@ -120,9 +122,9 @@ Connector::Ptr Forwarder::getConnector(Connector::Id id) {
return nullptr;
}
-void Forwarder::onPacketFromListener(Connector *connector,
- utils::MemBuf &packet_buffer,
- const std::error_code &ec) {
+void Forwarder::onPacketFromListener(
+ Connector *connector, const std::vector<utils::MemBuf::Ptr> &packets,
+ const std::error_code &ec) {
// Create connector
connector->setReceiveCallback(
std::bind(&Forwarder::onPacketReceived, this, std::placeholders::_1,
@@ -135,37 +137,47 @@ void Forwarder::onPacketFromListener(Connector *connector,
remote_connectors_.emplace(connector->getConnectorId(),
connector->shared_from_this());
}
+
// TODO Check if control packet or not. For the moment it is not.
- onPacketReceived(connector, packet_buffer, ec);
+ onPacketReceived(connector, packets, ec);
}
void Forwarder::onPacketReceived(Connector *connector,
- utils::MemBuf &packet_buffer,
+ const std::vector<utils::MemBuf::Ptr> &packets,
const std::error_code &ec) {
- // Figure out the type of packet we received
- bool is_interest = Packet::isInterest(packet_buffer.data());
-
- Packet *packet = nullptr;
- if (is_interest) {
- packet = static_cast<Interest *>(&packet_buffer);
- } else {
- packet = static_cast<ContentObject *>(&packet_buffer);
+ if (ec) {
+ LOG(ERROR) << "Error receiving packet: " << ec.message();
+ return;
}
- for (auto &c : local_connectors_) {
- auto role = c.second->getRole();
- auto is_producer = role == Connector::Role::PRODUCER;
- if ((is_producer && is_interest) || (!is_producer && !is_interest)) {
- c.second->send(*packet);
+ for (auto &packet_buffer_ptr : packets) {
+ auto &packet_buffer = *packet_buffer_ptr;
+
+ // Figure out the type of packet we received
+ bool is_interest = Packet::isInterest(packet_buffer.data());
+
+ Packet *packet = nullptr;
+ if (is_interest) {
+ packet = static_cast<Interest *>(&packet_buffer);
} else {
- LOG(ERROR) << "Error sending packet to local connector. is_interest = "
- << is_interest << " - is_producer = " << is_producer;
+ packet = static_cast<ContentObject *>(&packet_buffer);
+ }
+
+ for (auto &c : local_connectors_) {
+ auto role = c.second->getRole();
+ auto is_producer = role == Connector::Role::PRODUCER;
+ if ((is_producer && is_interest) || (!is_producer && !is_interest)) {
+ c.second->send(*packet);
+ } else {
+ LOG(ERROR) << "Error sending packet to local connector. is_interest = "
+ << is_interest << " - is_producer = " << is_producer;
+ }
}
- }
- // PCS Lookup + FIB lookup. Skip for now
+ // PCS Lookup + FIB lookup. Skip for now
- // Forward packet to local connectors
+ // Forward packet to local connectors
+ }
}
void Forwarder::send(Packet &packet) {
diff --git a/libtransport/src/io_modules/forwarder/forwarder.h b/libtransport/src/io_modules/forwarder/forwarder.h
index 5b564bb5e..38b4260b3 100644
--- a/libtransport/src/io_modules/forwarder/forwarder.h
+++ b/libtransport/src/io_modules/forwarder/forwarder.h
@@ -15,13 +15,13 @@
#pragma once
+#include <core/udp_listener.h>
#include <hicn/transport/core/io_module.h>
#include <hicn/transport/core/prefix.h>
#include <hicn/transport/utils/event_thread.h>
#include <hicn/transport/utils/singleton.h>
#include <hicn/transport/utils/spinlock.h>
#include <io_modules/forwarder/configuration.h>
-#include <io_modules/forwarder/udp_tunnel_listener.h>
#include <atomic>
#include <libconfig.h++>
@@ -31,9 +31,8 @@ namespace transport {
namespace core {
-class Forwarder : public utils::Singleton<Forwarder> {
+class Forwarder {
static constexpr char forwarder_config_section[] = "forwarder";
- friend class utils::Singleton<Forwarder>;
public:
Forwarder();
@@ -47,6 +46,7 @@ class Forwarder : public utils::Singleton<Forwarder> {
Connector::Id registerLocalConnector(
asio::io_service &io_service,
Connector::PacketReceivedCallback &&receive_callback,
+ Connector::PacketSentCallback &&sent_callback,
Connector::OnReconnectCallback &&reconnect_callback);
Forwarder &deleteConnector(Connector::Id id);
@@ -58,9 +58,11 @@ class Forwarder : public utils::Singleton<Forwarder> {
void stop();
private:
- void onPacketFromListener(Connector *connector, utils::MemBuf &packet_buffer,
+ void onPacketFromListener(Connector *connector,
+ const std::vector<utils::MemBuf::Ptr> &packets,
const std::error_code &ec);
- void onPacketReceived(Connector *connector, utils::MemBuf &packet_buffer,
+ void onPacketReceived(Connector *connector,
+ const std::vector<utils::MemBuf::Ptr> &packets,
const std::error_code &ec);
void onPacketSent(Connector *connector, const std::error_code &ec);
void onConnectorClosed(Connector *connector);
@@ -86,5 +88,20 @@ class Forwarder : public utils::Singleton<Forwarder> {
Configuration config_;
};
+class ForwarderGlobal : public ::utils::Singleton<ForwarderGlobal> {
+ friend class utils::Singleton<ForwarderGlobal>;
+
+ public:
+ ~ForwarderGlobal() {}
+ std::shared_ptr<Forwarder> &getReference() { return forwarder_; }
+
+ private:
+ ForwarderGlobal() : forwarder_(std::make_shared<Forwarder>()) {}
+
+ private:
+ std::shared_ptr<Forwarder> forwarder_;
+};
+
} // namespace core
-} // namespace transport \ No newline at end of file
+
+} // namespace transport
diff --git a/libtransport/src/io_modules/forwarder/forwarder_module.cc b/libtransport/src/io_modules/forwarder/forwarder_module.cc
index 4f95b9ca0..0ced84ab4 100644
--- a/libtransport/src/io_modules/forwarder/forwarder_module.cc
+++ b/libtransport/src/io_modules/forwarder/forwarder_module.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -25,11 +25,10 @@ ForwarderModule::ForwarderModule()
: IoModule(),
name_(""),
connector_id_(Connector::invalid_connector),
- forwarder_(Forwarder::getInstance()) {}
+ forwarder_ptr_(ForwarderGlobal::getInstance().getReference()),
+ forwarder_(*forwarder_ptr_) {}
-ForwarderModule::~ForwarderModule() {
- forwarder_.deleteConnector(connector_id_);
-}
+ForwarderModule::~ForwarderModule() {}
bool ForwarderModule::isConnected() { return true; }
@@ -42,7 +41,7 @@ void ForwarderModule::send(Packet &packet) {
// local_faces_.at(1 - local_id_).onPacket(packet);
}
-void ForwarderModule::send(const uint8_t *packet, std::size_t len) {
+void ForwarderModule::send(const utils::MemBuf::Ptr &buffer) {
// not supported
throw errors::NotImplementedException();
}
@@ -58,11 +57,13 @@ void ForwarderModule::closeConnection() {
}
void ForwarderModule::init(Connector::PacketReceivedCallback &&receive_callback,
+ Connector::PacketSentCallback &&sent_callback,
Connector::OnReconnectCallback &&reconnect_callback,
asio::io_service &io_service,
const std::string &app_name) {
connector_id_ = forwarder_.registerLocalConnector(
- io_service, std::move(receive_callback), std::move(reconnect_callback));
+ io_service, std::move(receive_callback), std::move(sent_callback),
+ std::move(reconnect_callback));
name_ = app_name;
}
@@ -78,7 +79,9 @@ void ForwarderModule::connect(bool is_consumer) {
std::uint32_t ForwarderModule::getMtu() { return interface_mtu; }
-bool ForwarderModule::isControlMessage(const uint8_t *message) { return false; }
+bool ForwarderModule::isControlMessage(utils::MemBuf &packet_buffer) {
+ return false;
+}
extern "C" IoModule *create_module(void) { return new ForwarderModule(); }
diff --git a/libtransport/src/io_modules/forwarder/forwarder_module.h b/libtransport/src/io_modules/forwarder/forwarder_module.h
index 58bfb7996..52a12b67e 100644
--- a/libtransport/src/io_modules/forwarder/forwarder_module.h
+++ b/libtransport/src/io_modules/forwarder/forwarder_module.h
@@ -38,11 +38,12 @@ class ForwarderModule : public IoModule {
void connect(bool is_consumer) override;
void send(Packet &packet) override;
- void send(const uint8_t *packet, std::size_t len) override;
+ void send(const utils::MemBuf::Ptr &buffer) override;
bool isConnected() override;
void init(Connector::PacketReceivedCallback &&receive_callback,
+ Connector::PacketSentCallback &&sent_callback,
Connector::OnReconnectCallback &&reconnect_callback,
asio::io_service &io_service,
const std::string &app_name = "Libtransport") override;
@@ -51,15 +52,19 @@ class ForwarderModule : public IoModule {
std::uint32_t getMtu() override;
- bool isControlMessage(const uint8_t *message) override;
+ bool isControlMessage(utils::MemBuf &packet_buffer) override;
void processControlMessageReply(utils::MemBuf &packet_buffer) override;
void closeConnection() override;
private:
+ static void initForwarder();
+
+ private:
std::string name_;
Connector::Id connector_id_;
+ std::shared_ptr<Forwarder> forwarder_ptr_;
Forwarder &forwarder_;
};
diff --git a/libtransport/src/io_modules/forwarder/udp_tunnel.cc b/libtransport/src/io_modules/forwarder/udp_tunnel.cc
deleted file mode 100644
index bf6a69b92..000000000
--- a/libtransport/src/io_modules/forwarder/udp_tunnel.cc
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- */
-
-#include <glog/logging.h>
-#include <hicn/transport/utils/branch_prediction.h>
-#include <io_modules/forwarder/errors.h>
-#include <io_modules/forwarder/udp_tunnel.h>
-
-#include <iostream>
-#include <thread>
-#include <vector>
-
-namespace transport {
-namespace core {
-
-UdpTunnelConnector::~UdpTunnelConnector() {}
-
-void UdpTunnelConnector::connect(const std::string &hostname, uint16_t port,
- const std::string &bind_address,
- uint16_t bind_port) {
- if (state_ == State::CLOSED) {
- state_ = State::CONNECTING;
- endpoint_iterator_ = resolver_.resolve({hostname, std::to_string(port)});
- remote_endpoint_send_ = *endpoint_iterator_;
- socket_->open(remote_endpoint_send_.protocol());
-
- if (!bind_address.empty() && bind_port != 0) {
- using namespace asio::ip;
- socket_->bind(
- udp::endpoint(address::from_string(bind_address), bind_port));
- }
-
- state_ = State::CONNECTED;
-
- remote_endpoint_ = Endpoint(remote_endpoint_send_);
- local_endpoint_ = Endpoint(socket_->local_endpoint());
-
- doRecvPacket();
-
-#ifdef LINUX
- send_timer_.expires_from_now(std::chrono::microseconds(50));
- send_timer_.async_wait(std::bind(&UdpTunnelConnector::writeHandler, this,
- std::placeholders::_1));
-#endif
- }
-}
-
-void UdpTunnelConnector::send(Packet &packet) {
- strand_->post([this, pkt{packet.shared_from_this()}]() {
- bool write_in_progress = !output_buffer_.empty();
- output_buffer_.push_back(std::move(pkt));
- if (TRANSPORT_EXPECT_TRUE(state_ == State::CONNECTED)) {
- if (!write_in_progress) {
- doSendPacket();
- }
- } else {
- data_available_ = true;
- }
- });
-}
-
-void UdpTunnelConnector::send(const uint8_t *packet, std::size_t len) {}
-
-void UdpTunnelConnector::close() {
- DLOG_IF(INFO, VLOG_IS_ON(2)) << "UDPTunnelConnector::close";
- state_ = State::CLOSED;
- bool is_socket_owned = socket_.use_count() == 1;
- if (is_socket_owned) {
- io_service_.dispatch([this]() {
- this->socket_->close();
- // on_close_callback_(shared_from_this());
- });
- }
-}
-
-void UdpTunnelConnector::doSendPacket() {
-#ifdef LINUX
- send_timer_.expires_from_now(std::chrono::microseconds(50));
- send_timer_.async_wait(std::bind(&UdpTunnelConnector::writeHandler, this,
- std::placeholders::_1));
-#else
- auto packet = output_buffer_.front().get();
- auto array = std::vector<asio::const_buffer>();
-
- 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_to(
- std::move(array), remote_endpoint_send_,
- strand_->wrap([this](std::error_code ec, std::size_t length) {
- if (TRANSPORT_EXPECT_TRUE(!ec)) {
- sent_callback_(this, make_error_code(forwarder_error::success));
- } else if (ec.value() ==
- static_cast<int>(std::errc::operation_canceled)) {
- // The connection has been closed by the application.
- return;
- } else {
- sendFailed();
- sent_callback_(this, ec);
- }
-
- output_buffer_.pop_front();
- if (!output_buffer_.empty()) {
- doSendPacket();
- }
- }));
-#endif
-}
-
-#ifdef LINUX
-void UdpTunnelConnector::writeHandler(std::error_code ec) {
- if (TRANSPORT_EXPECT_FALSE(state_ != State::CONNECTED)) {
- return;
- }
-
- auto len = std::min(output_buffer_.size(), std::size_t(Connector::max_burst));
-
- if (len) {
- int m = 0;
- for (auto &p : output_buffer_) {
- auto packet = p.get();
- ::utils::MemBuf *current = packet;
- int b = 0;
- do {
- // array.push_back(asio::const_buffer(current->data(),
- // current->length()));
- tx_iovecs_[m][b].iov_base = current->writableData();
- tx_iovecs_[m][b].iov_len = current->length();
- current = current->next();
- b++;
- } while (current != packet);
-
- tx_msgs_[m].msg_hdr.msg_iov = tx_iovecs_[m];
- tx_msgs_[m].msg_hdr.msg_iovlen = b;
- tx_msgs_[m].msg_hdr.msg_name = remote_endpoint_send_.data();
- tx_msgs_[m].msg_hdr.msg_namelen = remote_endpoint_send_.size();
- m++;
-
- if (--len == 0) {
- break;
- }
- }
-
- int retval = sendmmsg(socket_->native_handle(), tx_msgs_, m, MSG_DONTWAIT);
- if (retval > 0) {
- while (retval--) {
- output_buffer_.pop_front();
- }
- } else if (retval != EWOULDBLOCK && retval != EAGAIN) {
- LOG(ERROR) << "Error sending messages! " << strerror(errno)
- << " << retval";
- return;
- }
- }
-
- if (!output_buffer_.empty()) {
- send_timer_.expires_from_now(std::chrono::microseconds(50));
- send_timer_.async_wait(std::bind(&UdpTunnelConnector::writeHandler, this,
- std::placeholders::_1));
- }
-}
-
-void UdpTunnelConnector::readHandler(std::error_code ec) {
- DLOG_IF(INFO, VLOG_IS_ON(3)) << "UdpTunnelConnector receive packet";
-
- if (TRANSPORT_EXPECT_TRUE(!ec)) {
- if (TRANSPORT_EXPECT_TRUE(state_ == State::CONNECTED)) {
- if (current_position_ == 0) {
- for (int i = 0; i < max_burst; i++) {
- auto read_buffer = getRawBuffer();
- rx_iovecs_[i][0].iov_base = read_buffer.first;
- rx_iovecs_[i][0].iov_len = read_buffer.second;
- rx_msgs_[i].msg_hdr.msg_iov = rx_iovecs_[i];
- rx_msgs_[i].msg_hdr.msg_iovlen = 1;
- }
- }
-
- int res = recvmmsg(socket_->native_handle(), rx_msgs_ + current_position_,
- max_burst - current_position_, MSG_DONTWAIT, nullptr);
- if (res < 0) {
- LOG(ERROR) << "Error receiving messages! " << strerror(errno) << " "
- << res;
- return;
- }
-
- for (int i = 0; i < res; i++) {
- auto packet = getPacketFromBuffer(
- reinterpret_cast<uint8_t *>(
- rx_msgs_[current_position_].msg_hdr.msg_iov[0].iov_base),
- rx_msgs_[current_position_].msg_len);
- receiveSuccess(*packet);
- receive_callback_(this, *packet,
- make_error_code(forwarder_error::success));
- ++current_position_;
- }
-
- doRecvPacket();
- } else {
- LOG(ERROR)
- << "Error in UDP: Receiving packets from a not connected socket.";
- }
- } else if (ec.value() == static_cast<int>(std::errc::operation_canceled)) {
- LOG(ERROR) << "The connection has been closed by the application.";
- return;
- } else {
- if (TRANSPORT_EXPECT_TRUE(state_ == State::CONNECTED)) {
- // receive_callback_(this, *read_msg_, ec);
- LOG(ERROR) << "Error in UDP connector: " << ec.value() << " "
- << ec.message();
- } else {
- LOG(ERROR) << "Error in connector while not connected. " << ec.value()
- << " " << ec.message();
- }
- }
-}
-#endif
-
-void UdpTunnelConnector::doRecvPacket() {
-#ifdef LINUX
- if (state_ == State::CONNECTED) {
-#if ((ASIO_VERSION / 100 % 1000) < 11)
- socket_->async_receive(asio::null_buffers(),
-#else
- socket_->async_wait(asio::ip::tcp::socket::wait_read,
-#endif
- std::bind(&UdpTunnelConnector::readHandler, this,
- std::placeholders::_1));
- }
-#else
- DLOG_IF(INFO, VLOG_IS_ON(3)) << "UdpTunnelConnector receive packet";
- read_msg_ = getRawBuffer();
- socket_->async_receive_from(
- asio::buffer(read_msg_.first, read_msg_.second), remote_endpoint_recv_,
- [this](std::error_code ec, std::size_t length) {
- DLOG_IF(INFO, VLOG_IS_ON(3))
- << "UdpTunnelConnector received packet length=" << length;
- if (TRANSPORT_EXPECT_TRUE(!ec)) {
- if (TRANSPORT_EXPECT_TRUE(state_ == State::CONNECTED)) {
- auto packet = getPacketFromBuffer(read_msg_.first, length);
- receiveSuccess(*packet);
- receive_callback_(this, *packet,
- make_error_code(forwarder_error::success));
- doRecvPacket();
- } else {
- LOG(ERROR) << "Error in UDP: Receiving packets from a not "
- "connected socket.";
- }
- } else if (ec.value() ==
- static_cast<int>(std::errc::operation_canceled)) {
- LOG(ERROR) << "The connection has been closed by the application.";
- return;
- } else {
- if (TRANSPORT_EXPECT_TRUE(state_ == State::CONNECTED)) {
- LOG(ERROR) << "Error in UDP connector: " << ec.value()
- << ec.message();
- } else {
- LOG(ERROR) << "Error while not connected";
- }
- }
- });
-#endif
-}
-
-void UdpTunnelConnector::doConnect() {
- asio::async_connect(
- *socket_, endpoint_iterator_,
- [this](std::error_code ec, asio::ip::udp::resolver::iterator) {
- if (!ec) {
- state_ = State::CONNECTED;
- doRecvPacket();
-
- if (data_available_) {
- data_available_ = false;
- doSendPacket();
- }
- } else {
- LOG(ERROR) << "UDP Connection failed!!!";
- timer_.expires_from_now(std::chrono::milliseconds(500));
- timer_.async_wait(std::bind(&UdpTunnelConnector::doConnect, this));
- }
- });
-}
-
-} // namespace core
-
-} // namespace transport
diff --git a/libtransport/src/io_modules/hicn-light-ng/CMakeLists.txt b/libtransport/src/io_modules/hicn-light-ng/CMakeLists.txt
new file mode 100644
index 000000000..325a8bd1d
--- /dev/null
+++ b/libtransport/src/io_modules/hicn-light-ng/CMakeLists.txt
@@ -0,0 +1,62 @@
+# Copyright (c) 2021-2022 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
+ find_package(Libhicnctrl ${CURRENT_VERSION} REQUIRED NO_MODULE)
+
+ if (DISABLE_SHARED_LIBRARIES)
+ set(LIBTYPE static)
+ else()
+ set(LIBTYPE shared)
+ endif()
+
+ list(APPEND LIBHICNCTRL_LIBRARIES hicn::hicnctrl.${LIBTYPE})
+else()
+ if (DISABLE_SHARED_LIBRARIES)
+ if (WIN32)
+ set(LIBHICNCTRL_LIBRARIES ${LIBHICNCTRL_STATIC})
+ else ()
+ set(LIBHICNCTRL_LIBRARIES ${LIBHICNCTRL_STATIC} log)
+ endif ()
+ list(APPEND DEPENDENCIES
+ ${LIBHICNCTRL_STATIC}
+ )
+ else()
+ set(LIBHICNCTRL_LIBRARIES ${LIBHICNCTRL_SHARED})
+ list(APPEND DEPENDENCIES
+ ${LIBHICNCTRL_SHARED}
+ )
+ endif()
+endif()
+
+list(APPEND MODULE_HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn_forwarder_module.h
+)
+
+list(APPEND MODULE_SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn_forwarder_module.cc
+)
+
+build_module(hicnlightng_module
+ SHARED
+ SOURCES ${MODULE_SOURCE_FILES}
+ DEPENDS ${DEPENDENCIES}
+ COMPONENT ${LIBTRANSPORT_COMPONENT}
+ LINK_LIBRARIES PRIVATE ${LIBHICNCTRL_LIBRARIES}
+ INCLUDE_DIRS
+ PRIVATE
+ ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS}
+ ${Libhicnctrl_INCLUDE_DIRS}
+ DEFINITIONS ${COMPILER_DEFINITIONS}
+ COMPILE_OPTIONS ${COMPILER_OPTIONS}
+)
diff --git a/libtransport/src/io_modules/hicn-light-ng/hicn_forwarder_module.cc b/libtransport/src/io_modules/hicn-light-ng/hicn_forwarder_module.cc
new file mode 100644
index 000000000..f67bd9447
--- /dev/null
+++ b/libtransport/src/io_modules/hicn-light-ng/hicn_forwarder_module.cc
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <core/udp_connector.h>
+#include <io_modules/hicn-light-ng/hicn_forwarder_module.h>
+
+extern "C" {
+#include <hicn/ctrl/hicn-light-ng.h>
+}
+
+namespace transport {
+
+namespace core {
+
+HicnForwarderModule::HicnForwarderModule()
+ : IoModule(), connector_(nullptr), seq_(0) {}
+
+HicnForwarderModule::~HicnForwarderModule() {}
+
+void HicnForwarderModule::connect(bool is_consumer) {
+ connector_->connect("localhost", 9695);
+ connector_->setRole(is_consumer ? Connector::Role::CONSUMER
+ : Connector::Role::PRODUCER);
+}
+
+bool HicnForwarderModule::isConnected() { return connector_->isConnected(); }
+
+void HicnForwarderModule::send(Packet &packet) {
+ IoModule::send(packet);
+ packet.setChecksum();
+ connector_->send(packet);
+}
+
+void HicnForwarderModule::send(const utils::MemBuf::Ptr &packet) {
+ counters_.tx_packets++;
+ counters_.tx_bytes += packet->length();
+
+ // Perfect forwarding
+ connector_->send(packet);
+}
+
+void HicnForwarderModule::registerRoute(const Prefix &prefix) {
+ auto command = createCommandRoute(prefix.toSockaddr(),
+ (uint8_t)prefix.getPrefixLength());
+ if (!command) {
+ // TODO error
+ return;
+ }
+ send(command);
+}
+
+void HicnForwarderModule::sendMapme() {
+ auto command = createCommandMapmeSendUpdate();
+ if (!command) {
+ // TODO error
+ return;
+ }
+ send(command);
+}
+
+void HicnForwarderModule::setForwardingStrategy(const Prefix &prefix,
+ std::string &strategy) {
+ auto command = createCommandSetForwardingStrategy(
+ prefix.toSockaddr(), (uint8_t)prefix.getPrefixLength(), strategy);
+ if (!command) {
+ // TODO error
+ return;
+ }
+ send(command);
+}
+
+void HicnForwarderModule::closeConnection() {
+ auto command = createCommandDeleteConnection();
+ if (!command) {
+ // TODO error
+ return;
+ }
+
+ connector_->setSentCallback([](Connector *c, const std::error_code &ec) {
+ if (!ec) {
+ c->close();
+ }
+ });
+
+ send(command);
+}
+
+void HicnForwarderModule::init(
+ Connector::PacketReceivedCallback &&receive_callback,
+ Connector::PacketSentCallback &&sent_callback,
+ Connector::OnReconnectCallback &&reconnect_callback,
+ asio::io_service &io_service, const std::string &app_name) {
+ if (!connector_) {
+ connector_.reset(new UdpTunnelConnector(
+ io_service, std::move(receive_callback), std::move(sent_callback),
+ nullptr, std::move(reconnect_callback)));
+ }
+}
+
+void HicnForwarderModule::processControlMessageReply(
+ utils::MemBuf &packet_buffer) {
+ if (packet_buffer.data()[0] == NACK_LIGHT) {
+ throw errors::RuntimeException(
+ "Received Nack message from hicn light forwarder.");
+ }
+}
+
+std::uint32_t HicnForwarderModule::getMtu() { return interface_mtu; }
+
+bool HicnForwarderModule::isControlMessage(utils::MemBuf &packet_buffer) {
+ return packet_buffer.data()[0] == ACK_LIGHT ||
+ packet_buffer.data()[0] == NACK_LIGHT;
+}
+
+/**
+ * @return A valid msg_route_add_t structure if the command was successful, or
+ * with .command_id == COMMAND_TYPE_UNDEFINED in case of error.
+ */
+utils::MemBuf::Ptr HicnForwarderModule::createCommandRoute(
+ std::unique_ptr<sockaddr> &&addr, uint8_t prefix_length) {
+ utils::MemBuf::Ptr ret = utils::MemBuf::create(sizeof(msg_route_add_t));
+ auto command = reinterpret_cast<msg_route_add_t *>(ret->writableData());
+ ret->append(sizeof(msg_route_add_t));
+ std::memset(command, 0, sizeof(*command));
+
+ if (!IS_VALID_FAMILY(addr->sa_family)) return nullptr;
+
+ *command = {
+ .header =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_ROUTE_ADD,
+ .length = 1,
+ .seq_num = 0,
+ },
+ .payload =
+ {
+ .cost = 1,
+ .family = (uint8_t)addr->sa_family,
+ .len = prefix_length,
+ },
+ };
+
+ switch (addr->sa_family) {
+ case AF_INET:
+ command->payload.address.v4.as_inaddr =
+ ((sockaddr_in *)addr.get())->sin_addr;
+ break;
+ case AF_INET6:
+ command->payload.address.v6.as_in6addr =
+ ((sockaddr_in6 *)addr.get())->sin6_addr;
+ break;
+ }
+ snprintf(command->payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%s",
+ "SELF");
+
+ return ret;
+}
+
+utils::MemBuf::Ptr HicnForwarderModule::createCommandDeleteConnection() {
+ utils::MemBuf::Ptr ret =
+ utils::MemBuf::create(sizeof(msg_connection_remove_t));
+ auto command =
+ reinterpret_cast<msg_connection_remove_t *>(ret->writableData());
+ ret->append(sizeof(msg_connection_remove_t));
+ std::memset(command, 0, sizeof(*command));
+
+ *command = {
+ .header =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_CONNECTION_REMOVE,
+ .length = 1,
+ .seq_num = 0,
+ },
+ };
+
+ snprintf(command->payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%s",
+ "SELF");
+
+ return ret;
+}
+
+utils::MemBuf::Ptr HicnForwarderModule::createCommandMapmeSendUpdate() {
+ utils::MemBuf::Ptr ret =
+ utils::MemBuf::create(sizeof(msg_mapme_send_update_t));
+ auto command =
+ reinterpret_cast<msg_mapme_send_update_t *>(ret->writableData());
+ ret->append(sizeof(msg_mapme_send_update_t));
+ std::memset(command, 0, sizeof(*command));
+
+ *command = {
+ .header =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_MAPME_SEND_UPDATE,
+ .length = 1,
+ .seq_num = seq_++,
+ },
+ };
+
+ return ret;
+}
+
+utils::MemBuf::Ptr HicnForwarderModule::createCommandSetForwardingStrategy(
+ std::unique_ptr<sockaddr> &&addr, uint32_t prefix_len,
+ std::string strategy) {
+ utils::MemBuf::Ptr ret = utils::MemBuf::create(sizeof(msg_strategy_set_t));
+ auto command = reinterpret_cast<msg_strategy_set_t *>(ret->writableData());
+ ret->append(sizeof(msg_strategy_set_t));
+ std::memset(command, 0, sizeof(*command));
+
+ if (!IS_VALID_FAMILY(addr->sa_family)) return nullptr;
+
+ strategy_type_t strategy_type = strategy_type_from_str(strategy.c_str());
+ if (strategy_type == STRATEGY_TYPE_UNDEFINED) return nullptr;
+
+ *command = {
+ .header =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_STRATEGY_SET,
+ .length = 1,
+ .seq_num = seq_++,
+ },
+ .payload =
+ {
+ .family = (uint8_t)addr->sa_family,
+ .len = (uint8_t)prefix_len,
+ .type = (uint8_t)strategy_type,
+ },
+ };
+
+ switch (addr->sa_family) {
+ case AF_INET:
+ command->payload.address.v4.as_inaddr =
+ ((sockaddr_in *)addr.get())->sin_addr;
+ break;
+ case AF_INET6:
+ command->payload.address.v6.as_in6addr =
+ ((sockaddr_in6 *)addr.get())->sin6_addr;
+ break;
+ }
+
+ return ret;
+}
+
+extern "C" IoModule *create_module(void) { return new HicnForwarderModule(); }
+
+} // namespace core
+
+} // namespace transport
diff --git a/libtransport/src/io_modules/udp/hicn_forwarder_module.h b/libtransport/src/io_modules/hicn-light-ng/hicn_forwarder_module.h
index 845db73bf..0bf82757d 100644
--- a/libtransport/src/io_modules/udp/hicn_forwarder_module.h
+++ b/libtransport/src/io_modules/hicn-light-ng/hicn_forwarder_module.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -18,15 +18,17 @@
#include <hicn/transport/core/io_module.h>
#include <hicn/transport/core/prefix.h>
+extern "C" {
+#include <hicn/ctrl/hicn-light-ng.h>
+}
+
namespace transport {
namespace core {
-class UdpSocketConnector;
+class UdpTunnelConnector;
class HicnForwarderModule : public IoModule {
- static constexpr uint8_t ack_code = 0xc2;
- static constexpr uint8_t nack_code = 0xc3;
static constexpr std::uint16_t interface_mtu = 1500;
public:
@@ -56,27 +58,45 @@ class HicnForwarderModule : public IoModule {
void connect(bool is_consumer) override;
void send(Packet &packet) override;
- void send(const uint8_t *packet, std::size_t len) override;
+ void send(const utils::MemBuf::Ptr &buffer) override;
bool isConnected() override;
void init(Connector::PacketReceivedCallback &&receive_callback,
+ Connector::PacketSentCallback &&sent_callback,
Connector::OnReconnectCallback &&reconnect_callback,
asio::io_service &io_service,
const std::string &app_name = "Libtransport") override;
void registerRoute(const Prefix &prefix) override;
+ void sendMapme() override;
+
+ void setForwardingStrategy(const Prefix &prefix,
+ std::string &strategy) override;
+
std::uint32_t getMtu() override;
- bool isControlMessage(const uint8_t *message) override;
+ bool isControlMessage(utils::MemBuf &packet_buffer) override;
void processControlMessageReply(utils::MemBuf &packet_buffer) override;
void closeConnection() override;
private:
- UdpSocketConnector *connector_;
+ utils::MemBuf::Ptr createCommandRoute(std::unique_ptr<sockaddr> &&addr,
+ uint8_t prefix_length);
+ utils::MemBuf::Ptr createCommandDeleteConnection();
+ utils::MemBuf::Ptr createCommandMapmeSendUpdate();
+ utils::MemBuf::Ptr createCommandSetForwardingStrategy(
+ std::unique_ptr<sockaddr> &&addr, uint32_t prefix_len,
+ std::string strategy);
+
+ private:
+ std::shared_ptr<UdpTunnelConnector> connector_;
+
+ /* Sequence number used for sending control messages */
+ uint32_t seq_;
};
extern "C" IoModule *create_module(void);
diff --git a/libtransport/src/io_modules/loopback/CMakeLists.txt b/libtransport/src/io_modules/loopback/CMakeLists.txt
index b5ae0b7f7..817effb3b 100644
--- a/libtransport/src/io_modules/loopback/CMakeLists.txt
+++ b/libtransport/src/io_modules/loopback/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2021 Cisco and/or its affiliates.
+# Copyright (c) 2021-2022 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
@@ -20,11 +20,11 @@ list(APPEND MODULE_SOURCE_FILES
)
build_module(loopback_module
- SHARED
SOURCES ${MODULE_SOURCE_FILES}
DEPENDS ${DEPENDENCIES}
COMPONENT ${LIBTRANSPORT_COMPONENT}
- INCLUDE_DIRS ${LIBTRANSPORT_INCLUDE_DIRS} ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS}
+ INCLUDE_DIRS
+ PRIVATE ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS} ${Libhicn_INCLUDE_DIRS}
DEFINITIONS ${COMPILER_DEFINITIONS}
- COMPILE_OPTIONS ${COMPILE_FLAGS}
+ COMPILE_OPTIONS ${COMPILER_OPTIONS}
)
diff --git a/libtransport/src/io_modules/loopback/local_face.cc b/libtransport/src/io_modules/loopback/local_face.cc
index b73444330..7ef3f1a59 100644
--- a/libtransport/src/io_modules/loopback/local_face.cc
+++ b/libtransport/src/io_modules/loopback/local_face.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/io_modules/loopback/local_face.h b/libtransport/src/io_modules/loopback/local_face.h
index 1f4101447..f54f38afa 100644
--- a/libtransport/src/io_modules/loopback/local_face.h
+++ b/libtransport/src/io_modules/loopback/local_face.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/io_modules/loopback/loopback_module.cc b/libtransport/src/io_modules/loopback/loopback_module.cc
index f7dd5e7b0..5b7ed5f61 100644
--- a/libtransport/src/io_modules/loopback/loopback_module.cc
+++ b/libtransport/src/io_modules/loopback/loopback_module.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -41,7 +41,7 @@ void LoopbackModule::send(Packet &packet) {
local_faces_.at(1 - local_id_)->send(packet);
}
-void LoopbackModule::send(const uint8_t *packet, std::size_t len) {
+void LoopbackModule::send(const utils::MemBuf::Ptr &buffer) {
// not supported
throw errors::NotImplementedException();
}
@@ -57,6 +57,7 @@ void LoopbackModule::closeConnection() {
}
void LoopbackModule::init(Connector::PacketReceivedCallback &&receive_callback,
+ Connector::PacketSentCallback &&sent_callback,
Connector::OnReconnectCallback &&reconnect_callback,
asio::io_service &io_service,
const std::string &app_name) {
@@ -64,8 +65,9 @@ void LoopbackModule::init(Connector::PacketReceivedCallback &&receive_callback,
local_id_ = global_counter_++;
local_faces_.emplace(
local_faces_.begin() + local_id_,
- new LocalConnector(io_service, std::move(receive_callback), nullptr,
- nullptr, std::move(reconnect_callback)));
+ new LocalConnector(io_service, std::move(receive_callback),
+ std::move(sent_callback), nullptr,
+ std::move(reconnect_callback)));
}
}
@@ -75,7 +77,9 @@ void LoopbackModule::processControlMessageReply(utils::MemBuf &packet_buffer) {
std::uint32_t LoopbackModule::getMtu() { return interface_mtu; }
-bool LoopbackModule::isControlMessage(const uint8_t *message) { return false; }
+bool LoopbackModule::isControlMessage(utils::MemBuf &packet_buffer) {
+ return false;
+}
extern "C" IoModule *create_module(void) { return new LoopbackModule(); }
diff --git a/libtransport/src/io_modules/loopback/loopback_module.h b/libtransport/src/io_modules/loopback/loopback_module.h
index 219fa8841..2779ae7e3 100644
--- a/libtransport/src/io_modules/loopback/loopback_module.h
+++ b/libtransport/src/io_modules/loopback/loopback_module.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -36,11 +36,12 @@ class LoopbackModule : public IoModule {
void connect(bool is_consumer) override;
void send(Packet &packet) override;
- void send(const uint8_t *packet, std::size_t len) override;
+ void send(const utils::MemBuf::Ptr &buffer) override;
bool isConnected() override;
void init(Connector::PacketReceivedCallback &&receive_callback,
+ Connector::PacketSentCallback &&sent_callback,
Connector::OnReconnectCallback &&reconnect_callback,
asio::io_service &io_service,
const std::string &app_name = "Libtransport") override;
@@ -49,7 +50,7 @@ class LoopbackModule : public IoModule {
std::uint32_t getMtu() override;
- bool isControlMessage(const uint8_t *message) override;
+ bool isControlMessage(utils::MemBuf &packet_buffer) override;
void processControlMessageReply(utils::MemBuf &packet_buffer) override;
diff --git a/libtransport/src/io_modules/memif/CMakeLists.txt b/libtransport/src/io_modules/memif/CMakeLists.txt
index fc1c1f135..134ac1db6 100644
--- a/libtransport/src/io_modules/memif/CMakeLists.txt
+++ b/libtransport/src/io_modules/memif/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2021 Cisco and/or its affiliates.
+# Copyright (c) 2021-2022 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
@@ -11,18 +11,28 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-find_package(Vpp REQUIRED)
-find_package(Libmemif REQUIRED)
+
+##############################################################
+# Dependencies and third party libs
+##############################################################
+find_package(Vpp ${VPP_DEFAULT_VERSION} EXACT REQUIRED)
if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
- find_package(HicnPlugin REQUIRED)
- find_package(SafeVapi REQUIRED)
+ find_package(HicnPlugin ${CURRENT_VERSION} REQUIRED)
+ find_package(SafeVapi ${CURRENT_VERSION} REQUIRED)
else()
list(APPEND DEPENDENCIES
${SAFE_VAPI_SHARED}
)
endif()
+list(APPEND DEPENDENCIES
+ ${MEMIF_THIRD_PARTY_DEPENDENCIES}
+)
+
+##############################################################
+# Sources
+##############################################################
list(APPEND MODULE_HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/hicn_vapi.h
${CMAKE_CURRENT_SOURCE_DIR}/memif_connector.h
@@ -32,23 +42,23 @@ list(APPEND MODULE_HEADER_FILES
list(APPEND MODULE_SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/hicn_vapi.c
- ${CMAKE_CURRENT_SOURCE_DIR}/memif_connector.cc
${CMAKE_CURRENT_SOURCE_DIR}/memif_vapi.c
${CMAKE_CURRENT_SOURCE_DIR}/vpp_forwarder_module.cc
)
build_module(memif_module
- SHARED
SOURCES ${MODULE_SOURCE_FILES}
DEPENDS ${DEPENDENCIES}
COMPONENT ${LIBTRANSPORT_COMPONENT}-io-modules
- LINK_LIBRARIES ${LIBMEMIF_LIBRARIES} ${SAFE_VAPI_LIBRARIES}
+ OBJECT_LIBRARIES ${MEMIF_THIRD_PARTY_OBJECT_LIBRARIES}
+ LINK_LIBRARIES PRIVATE ${HICN_LIBRARIES} ${SAFE_VAPI_LIBRARIES}
INCLUDE_DIRS
- ${LIBTRANSPORT_INCLUDE_DIRS}
- ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS}
- ${VPP_INCLUDE_DIRS}
- ${LIBMEMIF_INCLUDE_DIRS}
- ${SAFE_VAPI_INCLUDE_DIRS}
+ PUBLIC
+ ${MEMIF_THIRD_PARTY_INCLUDE_DIRS}
+ ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS}
+ ${VPP_INCLUDE_DIRS}
+ ${LIBMEMIF_INCLUDE_DIRS}
+ ${SAFE_VAPI_INCLUDE_DIRS}
DEFINITIONS ${COMPILER_DEFINITIONS}
- COMPILE_OPTIONS ${COMPILE_FLAGS}
+ COMPILE_OPTIONS ${COMPILER_OPTIONS} ${MARCH_COMPILER_OPTIONS}
)
diff --git a/libtransport/src/io_modules/memif/hicn_vapi.c b/libtransport/src/io_modules/memif/hicn_vapi.c
index 6d78026ab..753679f54 100644
--- a/libtransport/src/io_modules/memif/hicn_vapi.c
+++ b/libtransport/src/io_modules/memif/hicn_vapi.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -27,8 +27,6 @@
#include <vlibapi/api.h>
#include <vlibmemory/api.h>
#include <vnet/ip/format.h>
-#include <vnet/ip/ip4_packet.h>
-#include <vnet/ip/ip6_packet.h>
#include <vpp_plugins/hicn/error.h>
#include <vppinfra/error.h>
@@ -46,9 +44,6 @@ u8 *format_vl_api_address_union(u8 *s, va_list *args) { return NULL; }
/*********************************************************************************/
-DEFINE_VAPI_MSG_IDS_HICN_API_JSON
-DEFINE_VAPI_MSG_IDS_IP_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) {
@@ -78,7 +73,7 @@ int hicn_vapi_register_prod_app(vapi_ctx_t ctx,
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)) {
+ if (ip_address_is_v4((ip_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;
@@ -190,7 +185,7 @@ int hicn_vapi_register_route(vapi_ctx_t ctx,
vapi_msg_ip_route_add_del *msg = vapi_alloc_ip_route_add_del(ctx, 1);
msg->payload.is_add = 1;
- if (ip46_address_is_ip4((ip46_address_t *)(input_params->prod_addr))) {
+ if (ip_address_is_v4((ip_address_t *)(input_params->prod_addr))) {
memcpy(&msg->payload.route.prefix.address.un.ip4,
&input_params->prefix->address.v4, sizeof(ip4_address_t));
msg->payload.route.prefix.address.af = ADDRESS_IP4;
@@ -204,7 +199,7 @@ int hicn_vapi_register_route(vapi_ctx_t ctx,
msg->payload.route.paths[0].sw_if_index = ~0;
msg->payload.route.paths[0].table_id = 0;
- if (ip46_address_is_ip4((ip46_address_t *)(input_params->prod_addr))) {
+ if (ip_address_is_v4((ip_address_t *)(input_params->prod_addr))) {
memcpy(&(msg->payload.route.paths[0].nh.address.ip4),
input_params->prod_addr->v4.as_u8, sizeof(ip4_address_t));
msg->payload.route.paths[0].proto = FIB_API_PATH_NH_PROTO_IP4;
@@ -214,7 +209,7 @@ int hicn_vapi_register_route(vapi_ctx_t ctx,
msg->payload.route.paths[0].proto = FIB_API_PATH_NH_PROTO_IP6;
}
- msg->payload.route.paths[0].type = FIB_API_PATH_FLAG_NONE;
+ msg->payload.route.paths[0].type = FIB_API_PATH_TYPE_NORMAL;
msg->payload.route.paths[0].flags = FIB_API_PATH_FLAG_NONE;
int ret = vapi_ip_route_add_del(ctx, msg, reigster_route_cb, NULL);
diff --git a/libtransport/src/io_modules/memif/hicn_vapi.h b/libtransport/src/io_modules/memif/hicn_vapi.h
index e94c97749..967179f68 100644
--- a/libtransport/src/io_modules/memif/hicn_vapi.h
+++ b/libtransport/src/io_modules/memif/hicn_vapi.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/io_modules/memif/memif_connector.cc b/libtransport/src/io_modules/memif/memif_connector.cc
deleted file mode 100644
index 68ad52b63..000000000
--- a/libtransport/src/io_modules/memif/memif_connector.cc
+++ /dev/null
@@ -1,492 +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 <glog/logging.h>
-#include <hicn/transport/errors/not_implemented_exception.h>
-#include <io_modules/memif/memif_connector.h>
-#include <sys/epoll.h>
-
-#include <cstdlib>
-
-extern "C" {
-#include <memif/libmemif.h>
-};
-
-#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,
- PacketSentCallback &&packet_sent,
- OnCloseCallback &&close_callback,
- OnReconnectCallback &&on_reconnect,
- asio::io_service &io_service,
- std::string app_name)
- : Connector(std::move(receive_callback), std::move(packet_sent),
- std::move(close_callback), std::move(on_reconnect)),
- memif_worker_(nullptr),
- timer_set_(false),
- send_timer_(std::make_unique<utils::FdDeadlineTimer>(event_reactor_)),
- disconnect_timer_(
- std::make_unique<utils::FdDeadlineTimer>(event_reactor_)),
- io_service_(io_service),
- work_(asio::make_work_guard(io_service_)),
- memif_connection_(std::make_unique<memif_connection_t>()),
- 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<char *>(app_name_.c_str()),
- nullptr, nullptr, nullptr);
-
- if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
- LOG(ERROR) << "memif_init: " << memif_strerror(err);
- }
-}
-
-void MemifConnector::connect(uint32_t memif_id, long memif_mode) {
- state_ = State::CONNECTING;
-
- memif_id_ = memif_id;
- socket_filename_ = "/run/vpp/memif.sock";
-
- createMemif(memif_id, memif_mode, nullptr);
-
- while (state_ != State::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)) {
- LOG(ERROR) << "memif_get_queue_efd: " << 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::thread>(
- 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<memif_buffer_t *>(
- malloc(sizeof(memif_buffer_t) * MAX_MEMIF_BUFS));
- c->tx_buf_num = 0;
- c->tx_bufs = static_cast<memif_buffer_t *>(
- 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)) {
- LOG(ERROR) << "memif_delete: " << memif_strerror(err);
- }
-
- if (TRANSPORT_EXPECT_FALSE(c->conn != nullptr)) {
- LOG(ERROR) << "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)) {
- LOG(ERROR) << "memif_control_fd_handler: "
- << 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)) {
- LOG(ERROR) << "memif_buffer_alloc: " << memif_strerror(err);
- return -1;
- }
-
- 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)) {
- LOG(ERROR) << "memif_tx_burst: " << memif_strerror(err);
- }
-
- // err = memif_refill_queue(c->conn, qid, r, 0);
-
- if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
- LOG(ERROR) << "memif_tx_burst: " << 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_ == State::CONNECTED)) {
- doSend();
- }
-}
-
-void MemifConnector::processInputBuffer(std::uint16_t total_packets) {
- utils::MemBuf::Ptr ptr;
-
- for (; total_packets > 0; total_packets--) {
- if (input_buffer_.pop(ptr)) {
- receive_callback_(this, *ptr, std::make_error_code(std::errc(0)));
- }
- }
-}
-
-/* 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_ = State::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_ = State::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 total_packets = 0;
- 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)) {
- LOG(ERROR) << "memif_rx_burst: " << memif_strerror(err);
- goto error;
- }
-
- c->rx_buf_num += rx;
-
- if (TRANSPORT_EXPECT_FALSE(connector->io_service_.stopped())) {
- LOG(ERROR) << "socket stopped: ignoring " << rx << " packets";
- goto error;
- }
-
- std::size_t packet_length;
- for (int i = 0; i < rx; i++) {
- auto buffer = connector->getRawBuffer();
- packet_length = (c->rx_bufs + i)->len;
- std::memcpy(buffer.first, (c->rx_bufs + i)->data, packet_length);
- auto packet = connector->getPacketFromBuffer(buffer.first, packet_length);
-
- if (!connector->input_buffer_.push(std::move(packet))) {
- LOG(ERROR) << "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)) {
- LOG(ERROR) << "memif_buffer_free: " << memif_strerror(err);
- }
-
- c->rx_buf_num -= rx;
- total_packets += rx;
-
- } while (ret_val == MEMIF_ERR_NOBUF);
-
- connector->io_service_.post(
- std::bind(&MemifConnector::processInputBuffer, connector, total_packets));
-
- return 0;
-
-error:
- err = memif_refill_queue(c->conn, qid, rx, 0);
-
- if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
- LOG(ERROR) << "memif_buffer_free: " << memif_strerror(err);
- }
- c->rx_buf_num -= rx;
-
- return 0;
-}
-
-void MemifConnector::close() {
- if (state_ != State::CLOSED) {
- disconnect_timer_->expiresFromNow(std::chrono::microseconds(50));
- disconnect_timer_->asyncWait([this](const std::error_code &ec) {
- deleteMemif();
- event_reactor_.stop();
- });
-
- if (memif_worker_ && memif_worker_->joinable()) {
- memif_worker_->join();
- }
- }
-}
-
-void MemifConnector::send(Packet &packet) {
- {
- utils::SpinLock::Acquire locked(write_msgs_lock_);
- output_buffer_.push_back(packet.shared_from_this());
- }
-#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;
- int32_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;
- n = bufferAlloc(max, memif_connection_->tx_qid);
-
- if (TRANSPORT_EXPECT_FALSE(n < 0)) {
- LOG(ERROR) << "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<uint8_t *>(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) {
- throw errors::NotImplementedException();
-}
-
-} // end namespace core
-
-} // end namespace transport
diff --git a/libtransport/src/io_modules/memif/memif_vapi.c b/libtransport/src/io_modules/memif/memif_vapi.c
index b3da2b012..54e2c3134 100644
--- a/libtransport/src/io_modules/memif/memif_vapi.c
+++ b/libtransport/src/io_modules/memif/memif_vapi.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -22,8 +22,6 @@
#include <vapi/vapi_safe.h>
#include <vppinfra/clib.h>
-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) {
@@ -45,6 +43,9 @@ static vapi_error_e memif_details_cb(vapi_ctx_t ctx, void *callback_ctx,
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);
+
+ // Initialize memif id to 0
+ *memif_id = 0;
int ret = vapi_memif_dump(ctx, msg, memif_details_cb, memif_id);
vapi_unlock();
return ret;
diff --git a/libtransport/src/io_modules/memif/memif_vapi.h b/libtransport/src/io_modules/memif/memif_vapi.h
index bcf06ed43..f5f0639e7 100644
--- a/libtransport/src/io_modules/memif/memif_vapi.h
+++ b/libtransport/src/io_modules/memif/memif_vapi.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -44,6 +44,10 @@ typedef struct memif_output_params_s {
int memif_vapi_get_next_memif_id(vapi_ctx_t ctx, uint32_t *memif_id);
+int memif_vapi_create_socket(vapi_ctx_t ctx,
+ memif_create_params_t *input_params,
+ memif_output_params_t *output_params);
+
int memif_vapi_create_memif(vapi_ctx_t ctx, memif_create_params_t *input_params,
memif_output_params_t *output_params);
diff --git a/libtransport/src/io_modules/memif/vpp_forwarder_module.cc b/libtransport/src/io_modules/memif/vpp_forwarder_module.cc
index 44c8376df..65260077a 100644
--- a/libtransport/src/io_modules/memif/vpp_forwarder_module.cc
+++ b/libtransport/src/io_modules/memif/vpp_forwarder_module.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -13,16 +13,16 @@
* limitations under the License.
*/
+#include <core/memif_connector.h>
#include <glog/logging.h>
#include <hicn/transport/config.h>
#include <hicn/transport/errors/not_implemented_exception.h>
#include <io_modules/memif/hicn_vapi.h>
-#include <io_modules/memif/memif_connector.h>
#include <io_modules/memif/memif_vapi.h>
#include <io_modules/memif/vpp_forwarder_module.h>
extern "C" {
-#include <memif/libmemif.h>
+#include <libmemif.h>
};
typedef enum { MASTER = 0, SLAVE = 1 } memif_role_t;
@@ -39,21 +39,24 @@ namespace core {
VPPForwarderModule::VPPForwarderModule()
: IoModule(),
connector_(nullptr),
+ memif_id_(0),
sw_if_index_(~0),
face_id1_(~0),
face_id2_(~0),
is_consumer_(false) {}
-VPPForwarderModule::~VPPForwarderModule() { delete connector_; }
+VPPForwarderModule::~VPPForwarderModule() {}
void VPPForwarderModule::init(
Connector::PacketReceivedCallback &&receive_callback,
+ Connector::PacketSentCallback &&sent_callback,
Connector::OnReconnectCallback &&reconnect_callback,
asio::io_service &io_service, const std::string &app_name) {
if (!connector_) {
- connector_ =
- new MemifConnector(std::move(receive_callback), 0, 0,
- std::move(reconnect_callback), io_service, app_name);
+ connector_ = std::make_unique<MemifConnector>(
+ std::move(receive_callback), std::move(sent_callback),
+ Connector::OnCloseCallback(0), std::move(reconnect_callback),
+ io_service, app_name);
}
}
@@ -62,7 +65,7 @@ void VPPForwarderModule::processControlMessageReply(
throw errors::NotImplementedException();
}
-bool VPPForwarderModule::isControlMessage(const uint8_t *message) {
+bool VPPForwarderModule::isControlMessage(utils::MemBuf &packet_buffer) {
return false;
}
@@ -73,12 +76,12 @@ void VPPForwarderModule::send(Packet &packet) {
connector_->send(packet);
}
-void VPPForwarderModule::send(const uint8_t *packet, std::size_t len) {
+void VPPForwarderModule::send(const utils::MemBuf::Ptr &buffer) {
counters_.tx_packets++;
- counters_.tx_bytes += len;
+ counters_.tx_bytes += buffer->length();
// Perfect forwarding
- connector_->send(packet, len);
+ connector_->send(buffer);
}
std::uint32_t VPPForwarderModule::getMtu() { return interface_mtu; }
@@ -170,7 +173,8 @@ void VPPForwarderModule::connect(bool is_consumer) {
consumerConnection();
}
- connector_->connect(memif_id_, 0);
+ connector_->connect(memif_id_, 0 /* is_master = false */,
+ memif_socket_filename);
connector_->setRole(is_consumer_ ? Connector::Role::CONSUMER
: Connector::Role::PRODUCER);
}
@@ -207,7 +211,8 @@ void VPPForwarderModule::registerRoute(const Prefix &prefix) {
throw errors::RuntimeException(hicn_vapi_get_error_string(ret));
}
- inet6_address_ = *output.prod_addr;
+ std::memcpy(inet6_address_.v6.as_u8, output.prod_addr->v6.as_u8,
+ sizeof(inet6_address_));
face_id1_ = output.face_id;
} else {
@@ -228,8 +233,6 @@ void VPPForwarderModule::registerRoute(const Prefix &prefix) {
void VPPForwarderModule::closeConnection() {
if (VPPForwarderModule::sock_) {
- connector_->close();
-
if (is_consumer_) {
hicn_del_face_app_input_params params;
params.face_id = face_id1_;
@@ -242,6 +245,8 @@ void VPPForwarderModule::closeConnection() {
hicn_vapi_face_prod_del(VPPForwarderModule::sock_, &params);
}
+ connector_->close();
+
if (sw_if_index_ != uint32_t(~0)) {
int ret =
memif_vapi_delete_memif(VPPForwarderModule::sock_, sw_if_index_);
diff --git a/libtransport/src/io_modules/memif/vpp_forwarder_module.h b/libtransport/src/io_modules/memif/vpp_forwarder_module.h
index 8c4114fed..162ee0ca5 100644
--- a/libtransport/src/io_modules/memif/vpp_forwarder_module.h
+++ b/libtransport/src/io_modules/memif/vpp_forwarder_module.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -32,7 +32,8 @@ namespace core {
class MemifConnector;
class VPPForwarderModule : public IoModule {
- static constexpr std::uint16_t interface_mtu = 1500;
+ static inline std::uint16_t interface_mtu = 1500;
+ static inline std::string const memif_socket_filename = "/run/vpp/memif.sock";
public:
VPPForwarderModule();
@@ -41,11 +42,12 @@ class VPPForwarderModule : public IoModule {
void connect(bool is_consumer) override;
void send(Packet &packet) override;
- void send(const uint8_t *packet, std::size_t len) override;
+ void send(const utils::MemBuf::Ptr &buffer) override;
bool isConnected() override;
void init(Connector::PacketReceivedCallback &&receive_callback,
+ Connector::PacketSentCallback &&sent_callback,
Connector::OnReconnectCallback &&reconnect_callback,
asio::io_service &io_service,
const std::string &app_name = "Libtransport") override;
@@ -54,7 +56,7 @@ class VPPForwarderModule : public IoModule {
std::uint32_t getMtu() override;
- bool isControlMessage(const uint8_t *message) override;
+ bool isControlMessage(utils::MemBuf &packet_buffer) override;
void processControlMessageReply(utils::MemBuf &packet_buffer) override;
@@ -66,7 +68,7 @@ class VPPForwarderModule : public IoModule {
void producerConnection();
private:
- MemifConnector *connector_;
+ std::shared_ptr<MemifConnector> connector_;
uint32_t memif_id_;
uint32_t sw_if_index_;
// A consumer socket in vpp has two faces (ipv4 and ipv6)
diff --git a/libtransport/src/io_modules/raw_socket/raw_socket_connector.cc b/libtransport/src/io_modules/raw_socket/raw_socket_connector.cc
deleted file mode 100644
index 62efdc3a5..000000000
--- a/libtransport/src/io_modules/raw_socket/raw_socket_connector.cc
+++ /dev/null
@@ -1,200 +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 <core/raw_socket_connector.h>
-#include <hicn/transport/utils/conversions.h>
-#include <net/if.h>
-#include <netdb.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-
-#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(&ethernet_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<int>(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<asio::const_buffer>();
-
- 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 {
- LOG(ERROR) << ec.value() << " " << ec.message();
- }
- });
-}
-
-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<uint8_t *>(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 {
- LOG(ERROR) << ec.value() << " " << ec.message();
- }
- 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/io_modules/raw_socket/raw_socket_connector.h b/libtransport/src/io_modules/raw_socket/raw_socket_connector.h
deleted file mode 100644
index 06892b3d8..000000000
--- a/libtransport/src/io_modules/raw_socket/raw_socket_connector.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 <core/connector.h>
-#include <hicn/transport/config.h>
-#include <hicn/transport/core/asio_wrapper.h>
-#include <hicn/transport/core/name.h>
-#include <linux/if_packet.h>
-#include <net/ethernet.h>
-#include <sys/socket.h>
-
-#include <deque>
-
-namespace transport {
-
-namespace core {
-
-using asio::generic::raw_protocol;
-using raw_endpoint = asio::generic::basic_endpoint<raw_protocol>;
-
-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<utils::MemBuf>::Ptr read_msg_;
-
- bool data_available_;
- std::string app_name_;
-};
-
-} // end namespace core
-
-} // end namespace transport
diff --git a/libtransport/src/io_modules/raw_socket/raw_socket_interface.cc b/libtransport/src/io_modules/raw_socket/raw_socket_interface.cc
deleted file mode 100644
index dcf489f59..000000000
--- a/libtransport/src/io_modules/raw_socket/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 <core/raw_socket_interface.h>
-#include <hicn/transport/utils/linux.h>
-
-#include <fstream>
-
-namespace transport {
-
-namespace core {
-
-static std::string config_folder_path = "/etc/transport/interface.conf.d";
-
-RawSocketInterface::RawSocketInterface(RawSocketConnector &connector)
- : ForwarderInterface<RawSocketInterface, RawSocketConnector>(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/io_modules/raw_socket/raw_socket_interface.h b/libtransport/src/io_modules/raw_socket/raw_socket_interface.h
deleted file mode 100644
index 7036cac7e..000000000
--- a/libtransport/src/io_modules/raw_socket/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 <core/forwarder_interface.h>
-#include <core/raw_socket_connector.h>
-#include <hicn/transport/core/prefix.h>
-
-#include <atomic>
-#include <deque>
-
-namespace transport {
-
-namespace core {
-
-class RawSocketInterface
- : public ForwarderInterface<RawSocketInterface, RawSocketConnector> {
- 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/io_modules/udp/CMakeLists.txt b/libtransport/src/io_modules/udp/CMakeLists.txt
deleted file mode 100644
index b9c19d063..000000000
--- a/libtransport/src/io_modules/udp/CMakeLists.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (c) 2021 Cisco and/or its affiliates.
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at:
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-list(APPEND MODULE_HEADER_FILES
- ${CMAKE_CURRENT_SOURCE_DIR}/hicn_forwarder_module.h
- ${CMAKE_CURRENT_SOURCE_DIR}/udp_socket_connector.h
-)
-
-list(APPEND MODULE_SOURCE_FILES
- ${CMAKE_CURRENT_SOURCE_DIR}/hicn_forwarder_module.cc
- ${CMAKE_CURRENT_SOURCE_DIR}/udp_socket_connector.cc
-)
-
-build_module(hicnlight_module
- SHARED
- SOURCES ${MODULE_SOURCE_FILES}
- DEPENDS ${DEPENDENCIES}
- COMPONENT ${LIBTRANSPORT_COMPONENT}
- INCLUDE_DIRS ${LIBTRANSPORT_INCLUDE_DIRS} ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS}
- DEFINITIONS ${COMPILER_DEFINITIONS}
- COMPILE_OPTIONS ${COMPILE_FLAGS}
-)
diff --git a/libtransport/src/io_modules/udp/hicn_forwarder_module.cc b/libtransport/src/io_modules/udp/hicn_forwarder_module.cc
deleted file mode 100644
index ba08dd8c0..000000000
--- a/libtransport/src/io_modules/udp/hicn_forwarder_module.cc
+++ /dev/null
@@ -1,181 +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 <io_modules/udp/hicn_forwarder_module.h>
-#include <io_modules/udp/udp_socket_connector.h>
-
-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<sockaddr> &&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 {
-
-HicnForwarderModule::HicnForwarderModule() : IoModule(), connector_(nullptr) {}
-
-HicnForwarderModule::~HicnForwarderModule() {}
-
-void HicnForwarderModule::connect(bool is_consumer) {
- connector_->connect();
- connector_->setRole(is_consumer ? Connector::Role::CONSUMER
- : Connector::Role::PRODUCER);
-}
-
-bool HicnForwarderModule::isConnected() { return connector_->isConnected(); }
-
-void HicnForwarderModule::send(Packet &packet) {
- IoModule::send(packet);
- packet.setChecksum();
- connector_->send(packet);
-}
-
-void HicnForwarderModule::send(const uint8_t *packet, std::size_t len) {
- counters_.tx_packets++;
- counters_.tx_bytes += len;
-
- // Perfect forwarding
- connector_->send(packet, len);
-}
-
-void HicnForwarderModule::registerRoute(const Prefix &prefix) {
- auto command = createCommandRoute(prefix.toSockaddr(),
- (uint8_t)prefix.getPrefixLength());
- send((uint8_t *)&command, sizeof(RouteToSelfCommand));
-}
-
-void HicnForwarderModule::closeConnection() {
- auto command = createCommandDeleteConnection();
- send((uint8_t *)&command, sizeof(DeleteSelfConnectionCommand));
- connector_->close();
-}
-
-void HicnForwarderModule::init(
- Connector::PacketReceivedCallback &&receive_callback,
- Connector::OnReconnectCallback &&reconnect_callback,
- asio::io_service &io_service, const std::string &app_name) {
- if (!connector_) {
- connector_ = new UdpSocketConnector(std::move(receive_callback), nullptr,
- nullptr, std::move(reconnect_callback),
- io_service, app_name);
- }
-}
-
-void HicnForwarderModule::processControlMessageReply(
- utils::MemBuf &packet_buffer) {
- if (packet_buffer.data()[0] == nack_code) {
- throw errors::RuntimeException(
- "Received Nack message from hicn light forwarder.");
- }
-}
-
-std::uint32_t HicnForwarderModule::getMtu() { return interface_mtu; }
-
-bool HicnForwarderModule::isControlMessage(const uint8_t *message) {
- return message[0] == ack_code || message[0] == nack_code;
-}
-
-extern "C" IoModule *create_module(void) { return new HicnForwarderModule(); }
-
-} // namespace core
-
-} // namespace transport
diff --git a/libtransport/src/io_modules/udp/udp_socket_connector.cc b/libtransport/src/io_modules/udp/udp_socket_connector.cc
deleted file mode 100644
index 1412d8c07..000000000
--- a/libtransport/src/io_modules/udp/udp_socket_connector.cc
+++ /dev/null
@@ -1,211 +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 <hicn/transport/portability/win_portability.h>
-#endif
-
-#include <glog/logging.h>
-#include <hicn/transport/errors/errors.h>
-#include <hicn/transport/utils/object_pool.h>
-#include <io_modules/udp/udp_socket_connector.h>
-
-#include <thread>
-#include <vector>
-
-namespace transport {
-
-namespace core {
-
-UdpSocketConnector::UdpSocketConnector(
- PacketReceivedCallback &&receive_callback, PacketSentCallback &&packet_sent,
- OnCloseCallback &&close_callback, OnReconnectCallback &&on_reconnect,
- asio::io_service &io_service, std::string app_name)
- : Connector(std::move(receive_callback), std::move(packet_sent),
- std::move(close_callback), std::move(on_reconnect)),
- io_service_(io_service),
- socket_(io_service_),
- resolver_(io_service_),
- connection_timer_(io_service_),
- read_msg_(std::make_pair(nullptr, 0)),
- 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_ = Connector::State::CONNECTING;
- doConnect();
-}
-
-void UdpSocketConnector::send(const uint8_t *packet, std::size_t len) {
- socket_.async_send(asio::buffer(packet, len),
- [this](std::error_code ec, std::size_t /*length*/) {
- if (sent_callback_) {
- sent_callback_(this, ec);
- }
- });
-}
-
-void UdpSocketConnector::send(Packet &packet) {
- io_service_.post([this, _packet{packet.shared_from_this()}]() {
- bool write_in_progress = !output_buffer_.empty();
- output_buffer_.push_back(std::move(_packet));
- if (TRANSPORT_EXPECT_TRUE(state_ == Connector::State::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_ != Connector::State::CLOSED) {
- state_ = Connector::State::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<asio::const_buffer>();
-
- 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<int>(std::errc::operation_canceled)) {
- // The connection has been closed by the application.
- return;
- } else {
- LOG(ERROR) << ec.value() << " " << ec.message();
- tryReconnect();
- }
- });
-}
-
-void UdpSocketConnector::doRead() {
- read_msg_ = getRawBuffer();
- socket_.async_receive(
- asio::buffer(read_msg_.first, read_msg_.second),
- [this](std::error_code ec, std::size_t length) {
- if (TRANSPORT_EXPECT_TRUE(!ec)) {
- auto packet = getPacketFromBuffer(read_msg_.first, length);
- receive_callback_(this, *packet, std::make_error_code(std::errc(0)));
- doRead();
- } else if (ec.value() ==
- static_cast<int>(std::errc::operation_canceled)) {
- // The connection has been closed by the application.
- return;
- } else {
- LOG(ERROR) << ec.value() << " " << ec.message();
- tryReconnect();
- }
- });
-}
-
-void UdpSocketConnector::tryReconnect() {
- if (state_ == Connector::State::CONNECTED) {
- LOG(ERROR) << "Connection lost. Trying to reconnect...";
- state_ = Connector::State::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_ = Connector::State::CONNECTED;
- doRead();
-
- if (data_available_) {
- data_available_ = false;
- doWrite();
- }
-
- if (is_reconnection_) {
- is_reconnection_ = false;
- }
-
- on_reconnect_callback_(this);
- } else {
- doConnect();
- std::this_thread::sleep_for(std::chrono::milliseconds(500));
- }
- });
-}
-
-bool UdpSocketConnector::checkConnected() {
- return state_ == Connector::State::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();
- LOG(ERROR) << "Error connecting. Is the forwarder running?";
- });
- }
-}
-
-} // end namespace core
-
-} // end namespace transport
diff --git a/libtransport/src/io_modules/udp/udp_socket_connector.h b/libtransport/src/io_modules/udp/udp_socket_connector.h
deleted file mode 100644
index c483e14aa..000000000
--- a/libtransport/src/io_modules/udp/udp_socket_connector.h
+++ /dev/null
@@ -1,88 +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 <hicn/transport/config.h>
-#include <hicn/transport/core/asio_wrapper.h>
-#include <hicn/transport/core/connector.h>
-#include <hicn/transport/core/content_object.h>
-#include <hicn/transport/core/global_object_pool.h>
-#include <hicn/transport/core/interest.h>
-#include <hicn/transport/core/name.h>
-#include <hicn/transport/core/packet.h>
-#include <hicn/transport/utils/branch_prediction.h>
-
-#include <deque>
-
-namespace transport {
-namespace core {
-
-using asio::ip::udp;
-
-class UdpSocketConnector : public Connector {
- public:
- UdpSocketConnector(PacketReceivedCallback &&receive_callback,
- PacketSentCallback &&packet_sent,
- OnCloseCallback &&close_callback,
- OnReconnectCallback &&on_reconnect,
- asio::io_service &io_service,
- std::string app_name = "Libtransport");
-
- ~UdpSocketConnector() override;
-
- void send(Packet &packet) override;
-
- void send(const uint8_t *packet, std::size_t len) 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_;
-
- std::pair<uint8_t *, std::size_t> read_msg_;
-
- bool is_reconnection_;
- bool data_available_;
-
- std::string app_name_;
-};
-
-} // end namespace core
-
-} // end namespace transport
diff --git a/libtransport/src/libhicntransport-config.cmake.in b/libtransport/src/libhicntransport-config.cmake.in
new file mode 100644
index 000000000..9b8c51962
--- /dev/null
+++ b/libtransport/src/libhicntransport-config.cmake.in
@@ -0,0 +1,8 @@
+@PACKAGE_INIT@
+
+set(Libhicntransport_VERSION_MAJOR "@VERSION_MAJOR@")
+set(Libhicntransport_VERSION_MINOR "@VERSION_MINOR@")
+set(Libhicntransport_VERSION_PATCH "@VERSION_PATCH@")
+
+set_and_check(Libhicntransport_INCLUDE_DIRS "@PACKAGE_Libhicntransport_INCLUDE_DIRS@")
+include("${CMAKE_CURRENT_LIST_DIR}/libhicntransport-targets.cmake")
diff --git a/libtransport/src/protocols/CMakeLists.txt b/libtransport/src/protocols/CMakeLists.txt
index b763e95e2..51879a9ed 100644
--- a/libtransport/src/protocols/CMakeLists.txt
+++ b/libtransport/src/protocols/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2019 Cisco and/or its affiliates.
+# Copyright (c) 2021 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
@@ -52,9 +52,15 @@ list(APPEND SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/errors.cc
)
-set(RAAQM_CONFIG_INSTALL_PREFIX
- ${CMAKE_INSTALL_FULL_SYSCONFDIR}/hicn
-)
+if (${CMAKE_SYSTEM_NAME} MATCHES Darwin OR ${CMAKE_SYSTEM_NAME} MATCHES Linux)
+ set(RAAQM_CONFIG_INSTALL_PREFIX
+ ${CMAKE_INSTALL_FULL_SYSCONFDIR}/hicn
+ )
+else()
+ set(RAAQM_CONFIG_INSTALL_PREFIX
+ ${CMAKE_INSTALL_PREFIX}/etc/hicn
+ )
+endif()
set(raaqm_config_path
${RAAQM_CONFIG_INSTALL_PREFIX}/consumer.conf
@@ -67,7 +73,7 @@ set(TRANSPORT_CONFIG
install(
FILES ${TRANSPORT_CONFIG}
- DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/hicn
+ DESTINATION ${RAAQM_CONFIG_INSTALL_PREFIX}
COMPONENT ${LIBTRANSPORT_COMPONENT}
)
diff --git a/libtransport/src/protocols/byte_stream_reassembly.cc b/libtransport/src/protocols/byte_stream_reassembly.cc
index ac36d4e61..3278595b7 100644
--- a/libtransport/src/protocols/byte_stream_reassembly.cc
+++ b/libtransport/src/protocols/byte_stream_reassembly.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/protocols/byte_stream_reassembly.h b/libtransport/src/protocols/byte_stream_reassembly.h
index 278740bd3..bfcac3181 100644
--- a/libtransport/src/protocols/byte_stream_reassembly.h
+++ b/libtransport/src/protocols/byte_stream_reassembly.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/protocols/cbr.cc b/libtransport/src/protocols/cbr.cc
index 1548cc68d..446ea8b99 100644
--- a/libtransport/src/protocols/cbr.cc
+++ b/libtransport/src/protocols/cbr.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -37,11 +37,11 @@ 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<utils::Microseconds>(
- now - interest_timepoints_[segment & mask]);
+ auto now = utils::SteadyTime::Clock::now();
+ auto rtt = utils::SteadyTime::getDurationMs(
+ interest_timepoints_[segment & mask], now);
// Update stats
- updateStats(segment, rtt.count(), now);
+ updateStats(segment, rtt, now);
}
} // end namespace protocol
diff --git a/libtransport/src/protocols/cbr.h b/libtransport/src/protocols/cbr.h
index 41cdbc98c..c178dbf60 100644
--- a/libtransport/src/protocols/cbr.h
+++ b/libtransport/src/protocols/cbr.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/protocols/congestion_window_protocol.h b/libtransport/src/protocols/congestion_window_protocol.h
index 36ac6eb17..f9ff208cc 100644
--- a/libtransport/src/protocols/congestion_window_protocol.h
+++ b/libtransport/src/protocols/congestion_window_protocol.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/protocols/data_processing_events.h b/libtransport/src/protocols/data_processing_events.h
index 28732502b..182de3ed8 100644
--- a/libtransport/src/protocols/data_processing_events.h
+++ b/libtransport/src/protocols/data_processing_events.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/protocols/datagram_reassembly.cc b/libtransport/src/protocols/datagram_reassembly.cc
index 069873a52..3a32c81f5 100644
--- a/libtransport/src/protocols/datagram_reassembly.cc
+++ b/libtransport/src/protocols/datagram_reassembly.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/protocols/datagram_reassembly.h b/libtransport/src/protocols/datagram_reassembly.h
index de294df06..0def32dd2 100644
--- a/libtransport/src/protocols/datagram_reassembly.h
+++ b/libtransport/src/protocols/datagram_reassembly.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/protocols/errors.cc b/libtransport/src/protocols/errors.cc
index 183fcc574..a7dd26e16 100644
--- a/libtransport/src/protocols/errors.cc
+++ b/libtransport/src/protocols/errors.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/protocols/errors.h b/libtransport/src/protocols/errors.h
index 58dadae5a..33d5fbee4 100644
--- a/libtransport/src/protocols/errors.h
+++ b/libtransport/src/protocols/errors.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/protocols/fec/CMakeLists.txt b/libtransport/src/protocols/fec/CMakeLists.txt
index 6d61ae043..8ae0a7360 100644
--- a/libtransport/src/protocols/fec/CMakeLists.txt
+++ b/libtransport/src/protocols/fec/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2019 Cisco and/or its affiliates.
+# Copyright (c) 2021 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
diff --git a/libtransport/src/protocols/fec/fec.cc b/libtransport/src/protocols/fec/fec.cc
index 16a04cb98..912e7a40f 100644
--- a/libtransport/src/protocols/fec/fec.cc
+++ b/libtransport/src/protocols/fec/fec.cc
@@ -44,6 +44,7 @@
#include "fec.h"
+#include <assert.h>
#include <hicn/transport/portability/platform.h>
#include <stdio.h>
#include <stdlib.h>
@@ -60,72 +61,6 @@
#endif
/*
- * compatibility stuff
- */
-#ifdef MSDOS /* but also for others, e.g. sun... */
-#define NEED_BCOPY
-#define bcmp(a, b, n) memcmp(a, b, n)
-#endif
-
-#ifdef ANDROID
-#define bcmp(a, b, n) memcmp(a, b, n)
-#endif
-
-#ifdef NEED_BCOPY
-#define bcopy(s, d, siz) memcpy((d), (s), (siz))
-#define bzero(d, siz) memset((d), '\0', (siz))
-#endif
-
-/*
- * stuff used for testing purposes only
- */
-
-#ifdef TEST
-#define DEB(x)
-#define DDB(x) x
-#define DEBUG 0 /* minimal debugging */
-#ifdef MSDOS
-#include <time.h>
-struct timeval {
- unsigned long ticks;
-};
-#define gettimeofday(x, dummy) \
- { (x)->ticks = clock(); }
-#define DIFF_T(a, b) (1 + 1000000 * (a.ticks - b.ticks) / CLOCKS_PER_SEC)
-typedef unsigned long u_long;
-typedef unsigned short u_short;
-#else /* typically, unix systems */
-#include <sys/time.h>
-#define DIFF_T(a, b) \
- (1 + 1000000 * (a.tv_sec - b.tv_sec) + (a.tv_usec - b.tv_usec))
-#endif
-
-#define TICK(t) \
- { \
- struct timeval x; \
- gettimeofday(&x, NULL); \
- t = x.tv_usec + 1000000 * (x.tv_sec & 0xff); \
- }
-#define TOCK(t) \
- { \
- u_long t1; \
- TICK(t1); \
- if (t1 < t) \
- t = 256000000 + t1 - t; \
- else \
- t = t1 - t; \
- if (t == 0) t = 1; \
- }
-
-u_long ticks[10]; /* vars for timekeeping */
-#else
-#define DEB(x)
-#define DDB(x)
-#define TICK(x)
-#define TOCK(x)
-#endif /* TEST */
-
-/*
* You should not need to change anything beyond this point.
* The first part of the file implements linear algebra in GF.
*
@@ -402,31 +337,17 @@ static void matmul(gf *a, gf *b, gf *c, int n, int k, int m) {
}
}
-#ifdef DEBUGG
-/*
- * returns 1 if the square matrix is identiy
- * (only for test)
- */
-static int is_identity(gf *m, int k) {
- int row, col;
- for (row = 0; row < k; row++)
- for (col = 0; col < k; col++)
- if ((row == col && *m != 1) || (row != col && *m != 0))
- return 0;
- else
- m++;
- return 1;
-}
-#endif /* debug */
-
/*
* invert_mat() takes a matrix and produces its inverse
* k is the size of the matrix.
* (Gauss-Jordan, adapted from Numerical Recipes in C)
* Return non-zero if singular.
*/
-DEB(int pivloops = 0; int pivswaps = 0; /* diagnostic */)
+int pivloops = 0;
+int pivswaps = 0; /* diagnostic */
static int invert_mat(gf *src, int k) {
+ assert(k > 0);
+
gf c, *p;
int irow, icol, row, col, i, ix;
@@ -436,9 +357,9 @@ static int invert_mat(gf *src, int k) {
int *ipiv = (int *)my_malloc(k * sizeof(int), "ipiv");
gf *id_row = NEW_GF_MATRIX(1, k);
gf *temp_row = NEW_GF_MATRIX(1, k);
-
- bzero(id_row, k * sizeof(gf));
- DEB(pivloops = 0; pivswaps = 0; /* diagnostic */)
+ memset(id_row, '\0', k * sizeof(gf));
+ pivloops = 0;
+ pivswaps = 0; /* diagnostic */
/*
* ipiv marks elements already used as pivots.
*/
@@ -459,7 +380,7 @@ static int invert_mat(gf *src, int k) {
for (row = 0; row < k; row++) {
if (ipiv[row] != 1) {
for (ix = 0; ix < k; ix++) {
- DEB(pivloops++;)
+ pivloops++;
if (ipiv[ix] == 0) {
if (src[row * k + ix] != 0) {
irow = row;
@@ -497,12 +418,9 @@ static int invert_mat(gf *src, int k) {
fprintf(stderr, "singular matrix 2\n");
goto fail;
}
- if (c != 1) { /* otherwhise this is a NOP */
- /*
- * this is done often , but optimizing is not so
- * fruitful, at least in the obvious ways (unrolling)
- */
- DEB(pivswaps++;)
+
+ if (c != 1) {
+ pivswaps++;
c = inverse[c];
pivot_row[icol] = 1;
for (ix = 0; ix < k; ix++) pivot_row[ix] = gf_mul(c, pivot_row[ix]);
@@ -515,7 +433,7 @@ static int invert_mat(gf *src, int k) {
* we can optimize the addmul).
*/
id_row[icol] = 1;
- if (bcmp(pivot_row, id_row, k * sizeof(gf)) != 0) {
+ if (memcmp(pivot_row, id_row, k * sizeof(gf)) != 0) {
for (p = src, ix = 0; ix < k; ix++, p += k) {
if (ix != icol) {
c = p[icol];
@@ -560,6 +478,8 @@ fail:
*/
int invert_vdm(gf *src, int k) {
+ assert(k > 0);
+
int i, j, row, col;
gf *b, *c, *p;
gf t, xx;
@@ -614,14 +534,8 @@ int invert_vdm(gf *src, int k) {
static int fec_initialized = 0;
static void init_fec() {
- TICK(ticks[0]);
generate_gf();
- TOCK(ticks[0]);
- DDB(fprintf(stderr, "generate_gf took %ldus\n", ticks[0]);)
- TICK(ticks[0]);
init_mul_table();
- TOCK(ticks[0]);
- DDB(fprintf(stderr, "init_mul_table took %ldus\n", ticks[0]);)
fec_initialized = 1;
}
@@ -680,19 +594,14 @@ struct fec_parms *fec_new(int k, int n) {
* k*k vandermonde matrix, multiply right the bottom n-k rows
* by the inverse, and construct the identity matrix at the top.
*/
- TICK(ticks[3]);
invert_vdm(tmp_m, k); /* much faster than invert_mat */
matmul(tmp_m + k * k, tmp_m, retval->enc_matrix + k * k, n - k, k, k);
/*
* the upper matrix is I so do not bother with a slow multiply
*/
- bzero(retval->enc_matrix, k * k * sizeof(gf));
+ memset(retval->enc_matrix, '\0', k * k * sizeof(gf));
for (p = retval->enc_matrix, col = 0; col < k; col++, p += k + 1) *p = 1;
free(tmp_m);
- TOCK(ticks[3]);
-
- DDB(fprintf(stderr, "--- %ld us to build encoding matrix\n", ticks[3]);)
- DEB(pr_matrix(retval->enc_matrix, n, k, "encoding_matrix");)
return retval;
}
@@ -708,10 +617,10 @@ void fec_encode(struct fec_parms *code, gf *src[], gf *fec, int index, int sz) {
if (GF_BITS > 8) sz /= 2;
if (index < k)
- bcopy(src[index], fec, sz * sizeof(gf));
+ memcpy(fec, src[index], sz * sizeof(gf));
else if (index < code->n) {
p = &(code->enc_matrix[index * k]);
- bzero(fec, sz * sizeof(gf));
+ memset(fec, '\0', sz * sizeof(gf));
for (i = 0; i < k; i++) addmul(fec, src[i], p[i], sz);
} else
fprintf(stderr, "Invalid index %d (max %d)\n", index, code->n - 1);
@@ -733,22 +642,13 @@ static int shuffle(gf *pkt[], int index[], int k) {
int c = index[i];
if (index[c] == c) {
- DEB(fprintf(stderr, "\nshuffle, error at %d\n", i);)
+ fprintf(stderr, "\nshuffle, error at %d\n", i);
return 1;
}
SWAP(index[i], index[c], int);
SWAP(pkt[i], pkt[c], gf *);
}
}
- DEB(/* just test that it works... */
- for (i = 0; i < k; i++) {
- if (index[i] < k && index[i] != i) {
- fprintf(stderr, "shuffle: after\n");
- for (i = 0; i < k; i++) fprintf(stderr, "%3d ", index[i]);
- fprintf(stderr, "\n");
- return 1;
- }
- })
return 0;
}
@@ -757,20 +657,16 @@ static int shuffle(gf *pkt[], int index[], int k) {
* indexes. The matrix must be already allocated as
* a vector of k*k elements, in row-major order
*/
-static gf *build_decode_matrix(struct fec_parms *code, gf *pkt[], int index[]) {
+static gf *build_decode_matrix(struct fec_parms *code, int index[]) {
int i, k = code->k;
gf *p, *matrix = NEW_GF_MATRIX(k, k);
- TICK(ticks[9]);
for (i = 0, p = matrix; i < k; i++, p += k) {
-#if 1 /* this is simply an optimization, not very useful indeed */
if (index[i] < k) {
- bzero(p, k * sizeof(gf));
+ memset(p, '\0', k * sizeof(gf));
p[i] = 1;
- } else
-#endif
- if (index[i] < code->n)
- bcopy(&(code->enc_matrix[index[i] * k]), p, k * sizeof(gf));
+ } else if (index[i] < code->n)
+ memcpy(p, &(code->enc_matrix[index[i] * k]), k * sizeof(gf));
else {
fprintf(stderr, "decode: invalid index %d (max %d)\n", index[i],
code->n - 1);
@@ -778,12 +674,10 @@ static gf *build_decode_matrix(struct fec_parms *code, gf *pkt[], int index[]) {
return NULL;
}
}
- TICK(ticks[9]);
if (invert_mat(matrix, k)) {
free(matrix);
matrix = NULL;
}
- TOCK(ticks[9]);
return matrix;
}
@@ -800,39 +694,29 @@ static gf *build_decode_matrix(struct fec_parms *code, gf *pkt[], int index[]) {
*/
int fec_decode(struct fec_parms *code, gf *pkt[], int index[], int sz) {
gf *m_dec;
- gf **new_pkt;
+ gf **new_pkt = nullptr;
int row, col, k = code->k;
+ int i = 0;
if (GF_BITS > 8) sz /= 2;
if (shuffle(pkt, index, k)) /* error if true */
return 1;
- m_dec = build_decode_matrix(code, pkt, index);
+ m_dec = build_decode_matrix(code, index);
if (m_dec == NULL) return 1; /* error */
/*
* do the actual decoding
*/
- new_pkt = (gf **)my_malloc(k * sizeof(gf *), "new pkt pointers");
+ new_pkt = pkt + k;
for (row = 0; row < k; row++) {
if (index[row] >= k) {
- new_pkt[row] = (gf *)my_malloc(sz * sizeof(gf), "new pkt buffer");
- bzero(new_pkt[row], sz * sizeof(gf));
+ memset(new_pkt[i], '\0', sz * sizeof(gf));
for (col = 0; col < k; col++)
- addmul(new_pkt[row], pkt[col], m_dec[row * k + col], sz);
- }
- }
- /*
- * move pkts to their final destination
- */
- for (row = 0; row < k; row++) {
- if (index[row] >= k) {
- bcopy(new_pkt[row], pkt[row], sz * sizeof(gf));
- free(new_pkt[row]);
+ addmul(new_pkt[i], pkt[col], m_dec[row * k + col], sz);
+ i++;
}
}
- free(new_pkt);
free(m_dec);
-
return 0;
}
diff --git a/libtransport/src/protocols/fec/rely.cc b/libtransport/src/protocols/fec/rely.cc
index 7a30a62e2..d4d98a90b 100644
--- a/libtransport/src/protocols/fec/rely.cc
+++ b/libtransport/src/protocols/fec/rely.cc
@@ -23,38 +23,39 @@ namespace transport {
namespace protocol {
namespace fec {
-RelyEncoder::RelyEncoder(uint32_t k, uint32_t n, uint32_t seq_offset)
+RelyEncoder::RelyEncoder(uint32_t k, uint32_t n, uint32_t /* seq_offset */)
: RelyBase(k, n) {
configure(kmtu, ktimeout, kmax_stream_size);
set_repair_trigger(k_, n_ - k_, n_ - k_);
}
void RelyEncoder::onPacketProduced(core::ContentObject &content_object,
- uint32_t offset) {
+ uint32_t offset, uint32_t metadata) {
// Get pointer to payload, leaving space to insert FEC header.
// TODO Check if this additional header is really needed.
- auto data = content_object.writableData() + offset - sizeof(fec_header);
- auto length = content_object.length() - offset + sizeof(fec_header);
+ auto data = content_object.writableData() + offset - sizeof(fec_metadata);
+ auto length = content_object.length() - offset + sizeof(fec_metadata);
// Check packet length does not exceed maximum length supported by the
// encoder (otherwise segmentation would take place).
- assert(length < max_packet_bytes());
+ DCHECK(length < max_packet_bytes());
DLOG_IF(INFO, VLOG_IS_ON(4))
- << "Encoding packet of length " << length - sizeof(fec_header);
+ << "Encoding packet of length " << length - sizeof(fec_metadata);
- // Get the suffix. With rely we need to write it in the fec_header in order to
- // be able to recognize the seq number upon recovery.
+ // Get the suffix. With rely we need to write it in the fec_metadata in order
+ // to be able to recognize the seq number upon recovery.
auto suffix = content_object.getName().getSuffix();
DLOG_IF(INFO, VLOG_IS_ON(4)) << "Producing packet " << suffix
<< " (index == " << current_index_ << ")";
- // Consume payload. Add fec_header in front before feeding payload to encoder,
- // and copy original content of packet
- fec_header *h = reinterpret_cast<fec_header *>(data);
- fec_header copy = *h;
+ // Consume payload. Add fec_metadata in front before feeding payload to
+ // encoder, and copy original content of packet
+ fec_metadata *h = reinterpret_cast<fec_metadata *>(data);
+ fec_metadata copy = *h;
h->setSeqNumberBase(suffix);
+ h->setMetadataBase(metadata);
auto packets = consume(data, length, getCurrentTime());
- assert(packets == 1);
+ DCHECK(packets == 1);
// Update packet counter
current_index_ += packets;
@@ -62,7 +63,7 @@ void RelyEncoder::onPacketProduced(core::ContentObject &content_object,
// Restore original packet content and increment data pointer to the correct
// position
*h = copy;
- data += sizeof(fec_header);
+ data += sizeof(fec_metadata);
// Check position of this packet inside N size block
auto i = current_index_ % n_;
@@ -74,24 +75,24 @@ void RelyEncoder::onPacketProduced(core::ContentObject &content_object,
// TODO Optimize it by copying only the RELY header
// Be sure encoder can produce
- assert(can_produce());
+ DCHECK(can_produce());
// Check new payload size and make sure it fits in packet buffer
auto new_payload_size = produce_bytes();
int difference = new_payload_size - length;
- assert(difference > 0);
- assert(content_object.ensureCapacity(difference));
+ DCHECK(difference > 0);
+ DCHECK(content_object.ensureCapacity(difference));
// Update length
DLOG_IF(INFO, VLOG_IS_ON(4)) << "The packet length will be incremented by "
- << difference + sizeof(fec_header);
- content_object.append(difference + sizeof(fec_header));
+ << difference + sizeof(fec_metadata);
+ content_object.append(difference + sizeof(fec_metadata));
content_object.updateLength();
// Make sure we got a source packet, otherwise we would put a repair symbol
// in a source packet
- assert(rely::packet_is_systematic(produce_data()));
+ DCHECK(rely::packet_is_systematic(produce_data()));
// Copy rely packet replacing old source packet.
std::memcpy(data, produce_data(), new_payload_size);
@@ -111,7 +112,7 @@ void RelyEncoder::onPacketProduced(core::ContentObject &content_object,
while (can_produce()) {
// The current index MUST be k_, because we enforce n - k repair to be
// produced after k sources
- assert(current_index_ == k_);
+ DCHECK(current_index_ == k_);
buffer packet;
if (!buffer_callback_) {
@@ -130,7 +131,7 @@ void RelyEncoder::onPacketProduced(core::ContentObject &content_object,
std::memcpy(packet->writableData(), produce_data(), produce_bytes());
// Push symbol in repair_packets
- packets_.emplace_back(0, std::move(packet));
+ packets_.emplace_back(0, metadata, std::move(packet));
// Advance the encoder
produce_next();
@@ -143,7 +144,7 @@ void RelyEncoder::onPacketProduced(core::ContentObject &content_object,
// If we have generated repair symbols, let's notify caller via the installed
// callback
if (packets_.size()) {
- assert(packets_.size() == n_ - k_);
+ DCHECK(packets_.size() == n_ - k_);
fec_callback_(packets_);
packets_.clear();
current_index_ = 0;
@@ -156,7 +157,7 @@ RelyDecoder::RelyDecoder(uint32_t k, uint32_t n, uint32_t seq_offset)
}
void RelyDecoder::onDataPacket(core::ContentObject &content_object,
- uint32_t offset) {
+ uint32_t offset, uint32_t metadata) {
// Adjust pointers to point to packet payload
auto data = content_object.writableData() + offset;
auto size = content_object.length() - offset;
@@ -164,30 +165,38 @@ void RelyDecoder::onDataPacket(core::ContentObject &content_object,
// Pass payload to decoder
consume(data, size, getCurrentTime());
+ producePackets();
+}
+
+void RelyDecoder::producePackets() {
// Drain decoder if possible
while (can_produce()) {
- // Get size of decoded packet
- auto size = produce_bytes();
-
- // Get buffer to copy packet in
- auto packet = core::PacketManager<>::getInstance().getMemBuf();
+ auto fec_header_size = sizeof(fec_metadata);
+ auto payload_size = produce_bytes() - sizeof(fec_metadata);
- // Copy buffer
- packet->append(size);
- std::memcpy(packet->writableData(), produce_data(), size);
+ buffer packet;
+ if (!buffer_callback_) {
+ packet = core::PacketManager<>::getInstance().getMemBuf();
+ packet->append(payload_size);
+ } else {
+ packet = buffer_callback_(payload_size);
+ }
// Read seq number
- fec_header *h = reinterpret_cast<fec_header *>(packet->writableData());
+ const fec_metadata *h =
+ reinterpret_cast<const fec_metadata *>(produce_data());
uint32_t index = h->getSeqNumberBase();
+ uint32_t metadata = h->getMetadataBase();
DLOG_IF(INFO, VLOG_IS_ON(4))
<< "The index written in the packet is " << index;
- // Remove FEC header
- packet->trimStart(sizeof(fec_header));
+ // Copy payload
+ std::memcpy(packet->writableData(), produce_data() + fec_header_size,
+ payload_size);
// Save packet in buffer
- packets_.emplace_back(index, std::move(packet));
+ packets_.emplace_back(index, metadata, std::move(packet));
// Advance to next packet
produce_next();
@@ -198,8 +207,28 @@ void RelyDecoder::onDataPacket(core::ContentObject &content_object,
fec_callback_(packets_);
packets_.clear();
}
+
+ flushOutOfOrder();
+}
+
+void RelyDecoder::flushOutOfOrder() {
+ if (flush_timer_ == nullptr) return;
+ flush_timer_->cancel();
+
+ if (has_upcoming_flush()) {
+ flush_timer_->expires_from_now(std::chrono::milliseconds(
+ std::max((int64_t)0, upcoming_flush(getCurrentTime()))));
+
+ flush_timer_->async_wait([this](const std::error_code &ec) {
+ if (ec) return;
+ if (has_upcoming_flush()) {
+ flush(getCurrentTime());
+ producePackets();
+ }
+ });
+ }
}
} // namespace fec
} // namespace protocol
-} // namespace transport \ No newline at end of file
+} // namespace transport
diff --git a/libtransport/src/protocols/fec/rely.h b/libtransport/src/protocols/fec/rely.h
index bfbdb30bc..001a26002 100644
--- a/libtransport/src/protocols/fec/rely.h
+++ b/libtransport/src/protocols/fec/rely.h
@@ -33,8 +33,12 @@ namespace fec {
* @brief Table of used codes.
*/
#define foreach_rely_fec_type \
+ _(Rely, 1, 2) \
_(Rely, 1, 3) \
+ _(Rely, 1, 4) \
_(Rely, 2, 3) \
+ _(Rely, 2, 6) \
+ _(Rely, 3, 9) \
_(Rely, 4, 5) \
_(Rely, 4, 6) \
_(Rely, 4, 7) \
@@ -74,11 +78,17 @@ class RelyBase : public virtual FECBase {
* decoding operations. It may be removed once we know the meaning of the
* fields in the rely header.
*/
- struct fec_header {
- uint32_t seq_number;
-
+ class fec_metadata {
+ public:
void setSeqNumberBase(uint32_t suffix) { seq_number = htonl(suffix); }
- uint32_t getSeqNumberBase() { return ntohl(seq_number); }
+ uint32_t getSeqNumberBase() const { return ntohl(seq_number); }
+
+ void setMetadataBase(uint32_t value) { metadata = htonl(value); }
+ uint32_t getMetadataBase() const { return ntohl(metadata); }
+
+ private:
+ uint32_t seq_number;
+ uint32_t metadata;
};
/**
@@ -112,21 +122,20 @@ class RelyBase : public virtual FECBase {
#if RELY_DEBUG
return time_++;
#else
- auto _time = utils::SteadyClock::now().time_since_epoch();
- auto time = std::chrono::duration_cast<utils::Milliseconds>(_time).count();
- return time;
+ return utils::SteadyTime::nowMs().count();
#endif
}
- protected:
uint32_t k_;
uint32_t n_;
+
std::uint32_t seq_offset_;
+
/**
* @brief Vector of packets to be passed to caller callbacks. For encoder it
* will contain the repair packets, for decoder the recovered sources.
*/
- std::vector<std::pair<uint32_t, buffer>> packets_;
+ BufferArray packets_;
/**
* @brief Current index to be used for local packet count.
@@ -142,50 +151,54 @@ class RelyBase : public virtual FECBase {
* @brief The Rely Encoder implementation.
*
*/
-class RelyEncoder : private RelyBase,
- private rely::encoder,
- public ProducerFEC {
+class RelyEncoder : RelyBase, rely::encoder, public ProducerFEC {
public:
RelyEncoder(uint32_t k, uint32_t n, uint32_t seq_offset = 0);
/**
* Producers will call this function when they produce a data packet.
*/
- void onPacketProduced(core::ContentObject &content_object,
- uint32_t offset) override;
+ void onPacketProduced(core::ContentObject &content_object, uint32_t offset,
+ uint32_t metadata = FECBase::INVALID_METADATA) override;
/**
* @brief Get the fec header size, if added to source packets
*/
std::size_t getFecHeaderSize() override {
- return header_bytes() + sizeof(fec_header) + 4;
+ return header_bytes() + sizeof(fec_metadata) + 4;
}
- void reset() override {}
+ void reset() override {
+ // Nothing to do here
+ }
};
-class RelyDecoder : private RelyBase,
- private rely::decoder,
- public ConsumerFEC {
+class RelyDecoder : RelyBase, rely::decoder, public ConsumerFEC {
public:
RelyDecoder(uint32_t k, uint32_t n, uint32_t seq_offset = 0);
/**
* Consumers will call this function when they receive a data packet
*/
- void onDataPacket(core::ContentObject &content_object,
- uint32_t offset) override;
+ void onDataPacket(core::ContentObject &content_object, uint32_t offset,
+ uint32_t metadata = FECBase::INVALID_METADATA) override;
/**
* @brief Get the fec header size, if added to source packets
*/
std::size_t getFecHeaderSize() override {
- return header_bytes() + sizeof(fec_header);
+ return header_bytes() + sizeof(fec_metadata);
+ }
+
+ void reset() override {
+ // Nothing to do here
}
- void reset() override {}
+ private:
+ void producePackets();
+ void flushOutOfOrder();
};
} // namespace fec
} // namespace protocol
-} // namespace transport \ No newline at end of file
+} // namespace transport
diff --git a/libtransport/src/protocols/fec/rs.cc b/libtransport/src/protocols/fec/rs.cc
index 2c23d515d..9c0a3d4fb 100644
--- a/libtransport/src/protocols/fec/rs.cc
+++ b/libtransport/src/protocols/fec/rs.cc
@@ -46,23 +46,26 @@ bool BlockCode::addRepairSymbol(const fec::buffer &packet, uint32_t i,
to_decode_ = true;
DLOG_IF(INFO, VLOG_IS_ON(4)) << "Adding symbol of size " << packet->length();
return addSymbol(packet, i, offset,
- packet->length() - sizeof(fec_header) - offset);
+ packet->length() - sizeof(fec_header) - offset,
+ FECBase::INVALID_METADATA);
}
bool BlockCode::addSourceSymbol(const fec::buffer &packet, uint32_t i,
- uint32_t offset) {
+ uint32_t offset, uint32_t metadata) {
DLOG_IF(INFO, VLOG_IS_ON(4)) << "Adding source symbol of size "
<< packet->length() << ", offset " << offset;
- return addSymbol(packet, i, offset, packet->length() - offset);
+ return addSymbol(packet, i, offset, packet->length() - offset, metadata);
}
bool BlockCode::addSymbol(const fec::buffer &packet, uint32_t i,
- uint32_t offset, std::size_t size) {
+ uint32_t offset, std::size_t size,
+ uint32_t metadata) {
if (size > max_buffer_size_) {
max_buffer_size_ = size;
}
- operator[](current_block_size_++) = std::make_tuple(i, packet, offset);
+ operator[](current_block_size_) = RSBufferInfo(offset, i, metadata, packet);
+ current_block_size_++;
if (current_block_size_ >= k_) {
if (to_decode_) {
@@ -80,12 +83,13 @@ bool BlockCode::addSymbol(const fec::buffer &packet, uint32_t i,
void BlockCode::encode() {
gf *data[n_];
- uint32_t base = std::get<0>(operator[](0));
+ uint32_t base = operator[](0).getIndex();
// Set packet length in first 2 bytes
for (uint32_t i = 0; i < k_; i++) {
- auto &packet = std::get<1>(operator[](i));
- auto offset = std::get<2>(operator[](i));
+ auto &packet = operator[](i).getBuffer();
+ auto offset = operator[](i).getOffset();
+ auto metadata_base = operator[](i).getMetadata();
auto ret =
packet->ensureCapacityAndFillUnused(max_buffer_size_ + offset, 0);
@@ -98,10 +102,11 @@ void BlockCode::encode() {
// Buffers should hold 2 *after* the padding, in order to be
// able to set the length for the encoding operation.
// packet->trimStart(offset);
- uint16_t *length = reinterpret_cast<uint16_t *>(packet->writableData() +
- max_buffer_size_ + offset);
+ fec_metadata *metadata = reinterpret_cast<fec_metadata *>(
+ packet->writableData() + max_buffer_size_ + offset);
auto buffer_length = packet->length() - offset;
- *length = htons(buffer_length);
+ metadata->setPacketLength(buffer_length);
+ metadata->setMetadataBase(metadata_base);
DLOG_IF(INFO, VLOG_IS_ON(4)) << "Current buffer size: " << packet->length();
@@ -109,7 +114,7 @@ void BlockCode::encode() {
}
// Finish to fill source block with the buffers to hold the repair symbols
- auto length = max_buffer_size_ + sizeof(fec_header) + LEN_SIZE_BYTES;
+ auto length = max_buffer_size_ + sizeof(fec_header) + METADATA_BYTES;
for (uint32_t i = k_; i < n_; i++) {
buffer packet;
if (!params_.buffer_callback_) {
@@ -133,19 +138,20 @@ void BlockCode::encode() {
DLOG_IF(INFO, VLOG_IS_ON(4)) << "Current symbol size: " << packet->length();
data[i] = packet->writableData();
- operator[](i) = std::make_tuple(i, std::move(packet), uint32_t(0));
+ operator[](i) = RSBufferInfo(uint32_t(0), i, FECBase::INVALID_METADATA,
+ std::move(packet));
}
// Generate repair symbols and put them in corresponding buffers
DLOG_IF(INFO, VLOG_IS_ON(4))
<< "Calling encode with max_buffer_size_ = " << max_buffer_size_;
for (uint32_t i = k_; i < n_; i++) {
- fec_encode(code_, data, data[i], i, max_buffer_size_ + LEN_SIZE_BYTES);
+ fec_encode(code_, data, data[i], i, max_buffer_size_ + METADATA_BYTES);
}
// Re-include header in repair packets
for (uint32_t i = k_; i < n_; i++) {
- auto &packet = std::get<1>(operator[](i));
+ auto &packet = operator[](i).getBuffer();
packet->prepend(sizeof(fec_header));
DLOG_IF(INFO, VLOG_IS_ON(4))
<< "Produced repair symbol of size = " << packet->length();
@@ -153,16 +159,31 @@ void BlockCode::encode() {
}
void BlockCode::decode() {
- gf *data[k_];
+ gf *data[n_];
uint32_t index[k_];
+ buffer aux_fec_packets[n_ - k_];
+ // FEC packet number k0
+ uint32_t k0 = 0;
+
+ // Reorder block by index with in-place sorting
+ for (uint32_t i = 0; i < k_;) {
+ uint32_t idx = operator[](i).getIndex();
+ if (idx >= k_ || idx == i) {
+ i++;
+ } else {
+ std::swap(operator[](i), operator[](idx));
+ }
+ }
for (uint32_t i = 0; i < k_; i++) {
- auto &packet = std::get<1>(operator[](i));
- index[i] = std::get<0>(operator[](i));
- auto offset = std::get<2>(operator[](i));
+ auto &packet = operator[](i).getBuffer();
+ index[i] = operator[](i).getIndex();
+ auto offset = operator[](i).getOffset();
+ auto metadata_base = operator[](i).getMetadata();
sorted_index_[i] = index[i];
if (index[i] < k_) {
+ operator[](i).setReceived();
DLOG_IF(INFO, VLOG_IS_ON(4))
<< "DECODE SOURCE - index " << index[i]
<< " - Current buffer size: " << packet->length();
@@ -173,49 +194,51 @@ void BlockCode::decode() {
// able to set the length for the encoding operation
packet->trimStart(offset);
packet->ensureCapacityAndFillUnused(max_buffer_size_, 0);
- uint16_t *length = reinterpret_cast<uint16_t *>(
- packet->writableData() + max_buffer_size_ - LEN_SIZE_BYTES);
-
- *length = htons(packet->length());
+ fec_metadata *metadata = reinterpret_cast<fec_metadata *>(
+ packet->writableData() + max_buffer_size_ - METADATA_BYTES);
+ metadata->setPacketLength(packet->length());
+ metadata->setMetadataBase(metadata_base);
} else {
DLOG_IF(INFO, VLOG_IS_ON(4))
<< "DECODE SYMBOL - index " << index[i]
<< " - Current buffer size: " << packet->length();
packet->trimStart(sizeof(fec_header) + offset);
+ aux_fec_packets[k0] = core::PacketManager<>::getInstance().getMemBuf();
+ data[k_ + k0] = aux_fec_packets[k0]->writableData();
+ k0++;
}
-
data[i] = packet->writableData();
}
-
// We decode the source block
DLOG_IF(INFO, VLOG_IS_ON(4))
<< "Calling decode with max_buffer_size_ = " << max_buffer_size_;
+
fec_decode(code_, data, reinterpret_cast<int *>(index), max_buffer_size_);
// Find the index in the block for recovered packets
- for (uint32_t i = 0; i < k_; i++) {
- if (index[i] != i) {
- for (uint32_t j = 0; j < k_; j++)
- if (sorted_index_[j] == uint32_t(index[i])) {
- sorted_index_[j] = i;
- }
- }
- }
-
- // Reorder block by index with in-place sorting
- for (uint32_t i = 0; i < k_; i++) {
- for (uint32_t j = sorted_index_[i]; j != i; j = sorted_index_[i]) {
- std::swap(sorted_index_[j], sorted_index_[i]);
- std::swap(operator[](j), operator[](i));
+ for (uint32_t i = 0, j = 0; i < k_; i++) {
+ if (index[i] >= k_) {
+ operator[](i).setBuffer(aux_fec_packets[j++]);
+ operator[](i).setIndex(i);
}
}
// Adjust length according to the one written in the source packet
for (uint32_t i = 0; i < k_; i++) {
- auto &packet = std::get<1>(operator[](i));
- uint16_t *length = reinterpret_cast<uint16_t *>(
- packet->writableData() + max_buffer_size_ - LEN_SIZE_BYTES);
- packet->setLength(ntohs(*length));
+ auto &packet = operator[](i).getBuffer();
+ fec_metadata *metadata = reinterpret_cast<fec_metadata *>(
+ packet->writableData() + max_buffer_size_ - METADATA_BYTES);
+ // Adjust buffer length
+ packet->setLength(metadata->getPacketLength());
+ // Adjust metadata
+ operator[](i).setMetadata(metadata->getMetadataBase());
+
+ // reset the point to the beginning of the packets for all received packets
+ if (operator[](i).getReceived()) {
+ auto &packet = operator[](i).getBuffer();
+ auto offset = operator[](i).getOffset();
+ packet->prepend(offset);
+ }
}
}
@@ -252,12 +275,11 @@ RSEncoder::RSEncoder(uint32_t k, uint32_t n, uint32_t seq_offset)
source_block_(k_, n_, seq_offset_, current_code_, *this) {}
void RSEncoder::consume(const fec::buffer &packet, uint32_t index,
- uint32_t offset) {
- if (!source_block_.addSourceSymbol(packet, index, offset)) {
- std::vector<std::pair<uint32_t, buffer>> repair_packets;
+ uint32_t offset, uint32_t metadata) {
+ if (!source_block_.addSourceSymbol(packet, index, offset, metadata)) {
+ fec::BufferArray repair_packets;
for (uint32_t i = k_; i < n_; i++) {
- repair_packets.emplace_back(std::move(std::get<0>(source_block_[i])),
- std::move(std::get<1>(source_block_[i])));
+ repair_packets.emplace_back(std::move(source_block_[i]));
}
fec_callback_(repair_packets);
@@ -265,9 +287,9 @@ void RSEncoder::consume(const fec::buffer &packet, uint32_t index,
}
void RSEncoder::onPacketProduced(core::ContentObject &content_object,
- uint32_t offset) {
+ uint32_t offset, uint32_t metadata) {
consume(content_object.shared_from_this(),
- content_object.getName().getSuffix(), offset);
+ content_object.getName().getSuffix(), offset, metadata);
}
RSDecoder::RSDecoder(uint32_t k, uint32_t n, uint32_t seq_offset)
@@ -276,10 +298,15 @@ RSDecoder::RSDecoder(uint32_t k, uint32_t n, uint32_t seq_offset)
void RSDecoder::recoverPackets(SourceBlocks::iterator &src_block_it) {
DLOG_IF(INFO, VLOG_IS_ON(4)) << "recoverPackets for " << k_;
auto &src_block = src_block_it->second;
- std::vector<std::pair<uint32_t, buffer>> source_packets(k_);
+ auto base_index = src_block_it->first;
+ BufferArray source_packets(k_);
+
+ // Iterate over packets in the block and adjust indexed accordingly. This must
+ // be done because indexes are from 0 to (n - k - 1), but we need indexes from
+ // base_index to base_index + (n - k - 1)
for (uint32_t i = 0; i < src_block.getK(); i++) {
- source_packets[i] = std::make_pair(src_block_it->first + i,
- std::move(std::get<1>(src_block[i])));
+ src_block[i].setIndex(base_index + src_block[i].getIndex());
+ source_packets[i] = FECBufferInfo(std::move(src_block[i]));
}
setProcessed(src_block_it->first);
@@ -296,9 +323,9 @@ void RSDecoder::recoverPackets(SourceBlocks::iterator &src_block_it) {
}
void RSDecoder::consumeSource(const fec::buffer &packet, uint32_t index,
- uint32_t offset) {
+ uint32_t offset, uint32_t metadata) {
// Normalize index
- assert(index >= seq_offset_);
+ DCHECK(index >= seq_offset_);
auto i = (index - seq_offset_) % n_;
// Get base
@@ -324,16 +351,19 @@ void RSDecoder::consumeSource(const fec::buffer &packet, uint32_t index,
// protocol that may come in the future.
auto it = src_blocks_.find(base);
if (it != src_blocks_.end()) {
- auto ret = it->second.addSourceSymbol(packet, i, offset);
+ auto ret = it->second.addSourceSymbol(packet, i, offset, metadata);
if (!ret) {
recoverPackets(it);
}
} else {
DLOG_IF(INFO, VLOG_IS_ON(4)) << "Adding to parked source packets";
- auto ret = parked_packets_.emplace(
- base, std::vector<std::pair<buffer, uint32_t>>());
- ret.first->second.emplace_back(packet, i);
+ auto ret = parked_packets_.emplace(base, BufferInfoArray());
+ ret.first->second.emplace_back(offset, i, metadata, packet);
+ /**
+ * If we reached k source packets, we do not have any missing packet to
+ * recover via FEC. Delete the block.
+ */
if (ret.first->second.size() >= k_) {
setProcessed(ret.first->first);
parked_packets_.erase(ret.first);
@@ -356,8 +386,8 @@ void RSDecoder::consumeRepair(const fec::buffer &packet, uint32_t offset) {
DLOG_IF(INFO, VLOG_IS_ON(4))
<< "Decoder consume called for repair symbol. BASE = " << base
- << ", index = " << base + i << " and i = " << i << ". K=" << k
- << ", N=" << n;
+ << ", index = " << base + i << " and i = " << (int)i << ". K=" << (int)k
+ << ", N=" << (int)n;
// check if a source block already exist for this symbol
auto it = src_blocks_.find(base);
@@ -380,8 +410,9 @@ void RSDecoder::consumeRepair(const fec::buffer &packet, uint32_t offset) {
auto it2 = parked_packets_.find(base);
if (it2 != parked_packets_.end()) {
for (auto &packet_index : it2->second) {
- auto ret = it->second.addSourceSymbol(packet_index.first,
- packet_index.second, offset);
+ auto ret = it->second.addSourceSymbol(
+ packet_index.getBuffer(), packet_index.getIndex(),
+ packet_index.getOffset(), packet_index.getMetadata());
if (!ret) {
recoverPackets(it);
// Finish to delete packets in same source block that were
@@ -399,7 +430,7 @@ void RSDecoder::consumeRepair(const fec::buffer &packet, uint32_t offset) {
}
void RSDecoder::onDataPacket(core::ContentObject &content_object,
- uint32_t offset) {
+ uint32_t offset, uint32_t metadata) {
DLOG_IF(INFO, VLOG_IS_ON(4))
<< "Calling fec for data packet " << content_object.getName()
<< ". Offset: " << offset;
@@ -409,7 +440,7 @@ void RSDecoder::onDataPacket(core::ContentObject &content_object,
if (isSymbol(suffix)) {
consumeRepair(content_object.shared_from_this(), offset);
} else {
- consumeSource(content_object.shared_from_this(), suffix, offset);
+ consumeSource(content_object.shared_from_this(), suffix, offset, metadata);
}
}
diff --git a/libtransport/src/protocols/fec/rs.h b/libtransport/src/protocols/fec/rs.h
index e159ad9f7..034c32bdc 100644
--- a/libtransport/src/protocols/fec/rs.h
+++ b/libtransport/src/protocols/fec/rs.h
@@ -34,10 +34,28 @@ namespace protocol {
namespace fec {
#define foreach_rs_fec_type \
+ _(RS, 1, 2) \
_(RS, 1, 3) \
+ _(RS, 1, 4) \
+ _(RS, 2, 3) \
+ _(RS, 2, 4) \
+ _(RS, 2, 5) \
+ _(RS, 2, 6) \
+ _(RS, 3, 6) \
+ _(RS, 3, 7) \
+ _(RS, 3, 8) \
+ _(RS, 3, 9) \
+ _(RS, 3, 10) \
+ _(RS, 3, 11) \
+ _(RS, 3, 12) \
_(RS, 4, 5) \
_(RS, 4, 6) \
_(RS, 4, 7) \
+ _(RS, 4, 8) \
+ _(RS, 4, 9) \
+ _(RS, 4, 10) \
+ _(RS, 4, 11) \
+ _(RS, 4, 12) \
_(RS, 6, 10) \
_(RS, 8, 10) \
_(RS, 8, 11) \
@@ -45,6 +63,8 @@ namespace fec {
_(RS, 8, 14) \
_(RS, 8, 16) \
_(RS, 8, 32) \
+ _(RS, 10, 20) \
+ _(RS, 10, 25) \
_(RS, 10, 30) \
_(RS, 10, 40) \
_(RS, 10, 60) \
@@ -56,12 +76,24 @@ namespace fec {
_(RS, 16, 27) \
_(RS, 17, 21) \
_(RS, 17, 34) \
+ _(RS, 20, 45) \
+ _(RS, 20, 50) \
+ _(RS, 20, 60) \
+ _(RS, 20, 70) \
+ _(RS, 30, 70) \
+ _(RS, 30, 75) \
+ _(RS, 30, 85) \
+ _(RS, 30, 95) \
_(RS, 32, 36) \
_(RS, 32, 41) \
_(RS, 32, 46) \
_(RS, 32, 54) \
_(RS, 34, 42) \
_(RS, 35, 70) \
+ _(RS, 40, 95) \
+ _(RS, 40, 100) \
+ _(RS, 40, 110) \
+ _(RS, 40, 120) \
_(RS, 52, 62)
static const constexpr uint16_t MAX_SOURCE_BLOCK_SIZE = 128;
@@ -73,9 +105,24 @@ static const constexpr uint16_t MAX_SOURCE_BLOCK_SIZE = 128;
* std::array allows to be constructed in place, saving the allocation at the
* price os knowing in advance its size.
*/
-using Packets = std::array<std::tuple</* index */ uint32_t, /* buffer */ buffer,
- uint32_t /* offset */>,
- MAX_SOURCE_BLOCK_SIZE>;
+class RSBufferInfo : public FECBufferInfo {
+ public:
+ RSBufferInfo() : FECBufferInfo() {}
+
+ RSBufferInfo(uint32_t offset, uint32_t index, uint32_t metadata,
+ buffer buffer)
+ : FECBufferInfo(index, metadata, buffer), offset_(offset) {}
+
+ uint32_t getOffset() { return offset_; }
+ RSBufferInfo &setOffset(uint32_t offset) {
+ offset_ = offset;
+ return *this;
+ }
+
+ private:
+ uint32_t offset_ = 0;
+};
+using Packets = std::array<RSBufferInfo, MAX_SOURCE_BLOCK_SIZE>;
/**
* FEC Header, prepended to symbol packets.
@@ -123,10 +170,32 @@ class rs;
*/
class BlockCode : public Packets {
/**
+ * @brief Metadata to include when encoding the buffers. This does not need to
+ * be sent over the network, but just to be included in the FEC protected
+ * bytes.
+ *
+ */
+ class __attribute__((__packed__)) fec_metadata {
+ public:
+ void setPacketLength(uint16_t length) { packet_length = htons(length); }
+ uint32_t getPacketLength() { return ntohs(packet_length); }
+
+ void setMetadataBase(uint32_t value) { metadata = htonl(value); }
+ uint32_t getMetadataBase() { return ntohl(metadata); }
+
+ private:
+ uint16_t packet_length; /* Used to get the real size of the packet after we
+ pad it */
+ uint32_t
+ metadata; /* Caller may specify an integer for storing additional
+ metadata that can be used when recovering the packet. */
+ };
+
+ /**
* For variable length packet we need to prepend to the padded payload the
* real length of the packet. This is *not* sent over the network.
*/
- static constexpr std::size_t LEN_SIZE_BYTES = 2;
+ static constexpr std::size_t METADATA_BYTES = sizeof(fec_metadata);
public:
BlockCode(uint32_t k, uint32_t n, uint32_t seq_offset, struct fec_parms *code,
@@ -142,7 +211,8 @@ class BlockCode : public Packets {
* Add a source symbol to the source block.
*/
bool addSourceSymbol(const fec::buffer &packet, uint32_t i,
- uint32_t offset = 0);
+ uint32_t offset = 0,
+ uint32_t metadata = FECBase::INVALID_METADATA);
/**
* Get current length of source block.
@@ -169,7 +239,7 @@ class BlockCode : public Packets {
* Add symbol to source block
**/
bool addSymbol(const fec::buffer &packet, uint32_t i, uint32_t offset,
- std::size_t size);
+ std::size_t size, uint32_t metadata);
/**
* Starting from k source symbols, get the n - k repair symbols
@@ -310,10 +380,11 @@ class RSEncoder : public rs, public ProducerFEC {
/**
* Always consume source symbols.
*/
- void consume(const fec::buffer &packet, uint32_t index, uint32_t offset = 0);
+ void consume(const fec::buffer &packet, uint32_t index, uint32_t offset = 0,
+ uint32_t metadata = FECBase::INVALID_METADATA);
- void onPacketProduced(core::ContentObject &content_object,
- uint32_t offset) override;
+ void onPacketProduced(core::ContentObject &content_object, uint32_t offset,
+ uint32_t metadata = FECBase::INVALID_METADATA) override;
/**
* @brief Get the fec header size, if added to source packets
@@ -348,8 +419,8 @@ class RSDecoder : public rs, public ConsumerFEC {
/**
* Consume source symbol
*/
- void consumeSource(const fec::buffer &packet, uint32_t i,
- uint32_t offset = 0);
+ void consumeSource(const fec::buffer &packet, uint32_t i, uint32_t offset = 0,
+ uint32_t metadata = FECBase::INVALID_METADATA);
/**
* Consume repair symbol
@@ -359,8 +430,8 @@ class RSDecoder : public rs, public ConsumerFEC {
/**
* Consumers will call this function when they receive a data packet
*/
- void onDataPacket(core::ContentObject &content_object,
- uint32_t offset) override;
+ void onDataPacket(core::ContentObject &content_object, uint32_t offset,
+ uint32_t metadata = FECBase::INVALID_METADATA) override;
/**
* @brief Get the fec header size, if added to source packets
@@ -398,8 +469,8 @@ class RSDecoder : public rs, public ConsumerFEC {
* not make any sense to build the source block, since we received all the
* source packet of the block.
*/
- std::unordered_map<uint32_t, std::vector<std::pair<buffer, uint32_t>>>
- parked_packets_;
+ using BufferInfoArray = std::vector<RSBufferInfo>;
+ std::unordered_map<uint32_t, BufferInfoArray> parked_packets_;
};
} // namespace fec
diff --git a/libtransport/src/protocols/fec_base.h b/libtransport/src/protocols/fec_base.h
index a1929d85e..bda3ee756 100644
--- a/libtransport/src/protocols/fec_base.h
+++ b/libtransport/src/protocols/fec_base.h
@@ -15,6 +15,7 @@
#pragma once
+#include <hicn/transport/core/asio_wrapper.h>
#include <hicn/transport/core/content_object.h>
#include <hicn/transport/errors/not_implemented_exception.h>
@@ -25,12 +26,67 @@ namespace protocol {
namespace fec {
-using buffer = typename utils::MemBuf::Ptr;
-using BufferArray = std::vector<std::pair<uint32_t, buffer>>;
+using buffer = utils::MemBuf::Ptr;
+
+class FECBufferInfo {
+ public:
+ FECBufferInfo()
+ : index_(~0), metadata_(~0), received_(false), buffer_(nullptr) {}
+
+ template <typename T>
+ FECBufferInfo(uint32_t index, uint32_t metadata, T &&buffer)
+ : index_(index),
+ metadata_(metadata),
+ received_(false),
+ buffer_(std::forward<T>(buffer)) {}
+
+ // Getters
+ uint32_t getIndex() const { return index_; }
+
+ uint32_t getMetadata() const { return metadata_; }
+
+ bool getReceived() const { return received_; }
+
+ buffer &getBuffer() { return buffer_; }
+
+ // Setters
+ void setReceived() { received_ = true; }
+
+ FECBufferInfo &setIndex(uint32_t index) {
+ index_ = index;
+ return *this;
+ }
+
+ FECBufferInfo &setMetadata(uint32_t metadata) {
+ metadata_ = metadata;
+ return *this;
+ }
+
+ FECBufferInfo &setBuffer(buffer &buffer) {
+ buffer_ = buffer;
+ return *this;
+ }
+
+ FECBufferInfo &setBuffer(buffer &&buffer) {
+ buffer_ = std::move(buffer);
+ return *this;
+ }
+
+ private:
+ uint32_t index_;
+ uint32_t metadata_;
+ bool received_;
+ buffer buffer_;
+};
+
+using BufferArray = typename std::vector<FECBufferInfo>;
class FECBase {
public:
- virtual ~FECBase() = default;
+ static inline uint32_t INVALID_METADATA = ~0;
+ static inline uint32_t INVALID_INDEX = ~0;
+
+ virtual ~FECBase() {}
/**
* Callback to be called after the encode or the decode operations. In the
* former case it will contain the symbols, while in the latter the sources.
@@ -64,11 +120,21 @@ class FECBase {
buffer_callback_ = buffer_callback;
}
+ /**
+ * Creates the timer to flush packets. So far needed only if using Rely and
+ * want to avoid expired packets blocked by missing pkts to wait for a new
+ * packet to arrive and trigger the flush
+ */
+ void setIOService(asio::io_service &io_service) {
+ flush_timer_ = std::make_unique<asio::steady_timer>(io_service);
+ }
+
virtual void reset() = 0;
protected:
PacketsReady fec_callback_{0};
BufferRequested buffer_callback_{0};
+ std::unique_ptr<asio::steady_timer> flush_timer_;
};
/**
@@ -80,8 +146,9 @@ class ProducerFEC : public virtual FECBase {
/**
* Producers will call this function upon production of a new packet.
*/
- virtual void onPacketProduced(core::ContentObject &content_object,
- uint32_t offset) = 0;
+ virtual void onPacketProduced(
+ core::ContentObject &content_object, uint32_t offset,
+ uint32_t metadata = FECBase::INVALID_METADATA) = 0;
};
/**
@@ -95,9 +162,10 @@ class ConsumerFEC : public virtual FECBase {
* Consumers will call this function when they receive a data packet
*/
virtual void onDataPacket(core::ContentObject &content_object,
- uint32_t offset) = 0;
+ uint32_t offset,
+ uint32_t metadata = FECBase::INVALID_METADATA) = 0;
};
} // namespace fec
} // namespace protocol
-} // namespace transport \ No newline at end of file
+} // namespace transport
diff --git a/libtransport/src/protocols/incremental_indexer_bytestream.cc b/libtransport/src/protocols/incremental_indexer_bytestream.cc
index cc302a98a..b94f229e5 100644
--- a/libtransport/src/protocols/incremental_indexer_bytestream.cc
+++ b/libtransport/src/protocols/incremental_indexer_bytestream.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -29,9 +29,9 @@ void IncrementalIndexer::onContentObject(core::Interest &interest,
DLOG_IF(INFO, VLOG_IS_ON(3))
<< "Received content " << content_object.getName();
- assert(reassembly_);
+ DCHECK(reassembly_);
- if (TRANSPORT_EXPECT_FALSE(content_object.testRst())) {
+ if (TRANSPORT_EXPECT_FALSE(content_object.isLast())) {
final_suffix_ = content_object.getName().getSuffix();
}
diff --git a/libtransport/src/protocols/incremental_indexer_bytestream.h b/libtransport/src/protocols/incremental_indexer_bytestream.h
index c6a669629..422e49ecd 100644
--- a/libtransport/src/protocols/incremental_indexer_bytestream.h
+++ b/libtransport/src/protocols/incremental_indexer_bytestream.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -62,7 +62,7 @@ class IncrementalIndexer : public Indexer {
next_reassembly_suffix_ = first_suffix_;
}
- virtual uint32_t checkNextSuffix() override {
+ virtual uint32_t checkNextSuffix() const override {
return next_download_suffix_ <= final_suffix_ ? next_download_suffix_
: Indexer::invalid_index;
}
@@ -76,7 +76,7 @@ class IncrementalIndexer : public Indexer {
first_suffix_ = suffix;
}
- uint32_t getFirstSuffix() override { return first_suffix_; }
+ uint32_t getFirstSuffix() const override { return first_suffix_; }
virtual uint32_t jumpToIndex(uint32_t index) override {
next_download_suffix_ = index;
@@ -95,14 +95,14 @@ class IncrementalIndexer : public Indexer {
return final_suffix_ != Indexer::invalid_index;
}
- virtual uint32_t getFinalSuffix() override { return final_suffix_; }
+ virtual uint32_t getFinalSuffix() const override { return final_suffix_; }
void enableFec(fec::FECType fec_type) override {}
void disableFec() override {}
void setNFec(uint32_t n_fec) override {}
- virtual uint32_t getNFec() override { return 0; }
+ virtual uint32_t getNFec() const override { return 0; }
virtual void onContentObject(core::Interest &interest,
core::ContentObject &content_object,
diff --git a/libtransport/src/protocols/index_manager_bytestream.cc b/libtransport/src/protocols/index_manager_bytestream.cc
index c78dc634d..952f36e0e 100644
--- a/libtransport/src/protocols/index_manager_bytestream.cc
+++ b/libtransport/src/protocols/index_manager_bytestream.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/protocols/index_manager_bytestream.h b/libtransport/src/protocols/index_manager_bytestream.h
index e14c8845b..7ea31dfa5 100644
--- a/libtransport/src/protocols/index_manager_bytestream.h
+++ b/libtransport/src/protocols/index_manager_bytestream.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -40,7 +40,9 @@ class IndexManager : public IncrementalIndexer {
indexer_->setFirstSuffix(suffix);
}
- uint32_t getFirstSuffix() override { return indexer_->getFirstSuffix(); }
+ uint32_t getFirstSuffix() const override {
+ return indexer_->getFirstSuffix();
+ }
uint32_t getNextReassemblySegment() override {
return indexer_->getNextReassemblySegment();
@@ -50,22 +52,26 @@ class IndexManager : public IncrementalIndexer {
return indexer_->isFinalSuffixDiscovered();
}
- uint32_t getFinalSuffix() override { return indexer_->getFinalSuffix(); }
+ uint32_t getFinalSuffix() const override {
+ return indexer_->getFinalSuffix();
+ }
uint32_t jumpToIndex(uint32_t index) override {
return indexer_->jumpToIndex(index);
}
void setNFec(uint32_t n_fec) override { return indexer_->setNFec(n_fec); }
- uint32_t getNFec() override { return indexer_->getNFec(); }
+ uint32_t getNFec() const override { return indexer_->getNFec(); }
void enableFec(fec::FECType fec_type) override {
return indexer_->enableFec(fec_type);
}
- double getFecOverhead() override { return indexer_->getFecOverhead(); }
+ double getFecOverhead() const override { return indexer_->getFecOverhead(); }
- double getMaxFecOverhead() override { return indexer_->getMaxFecOverhead(); }
+ double getMaxFecOverhead() const override {
+ return indexer_->getMaxFecOverhead();
+ }
void disableFec() override { return indexer_->disableFec(); }
diff --git a/libtransport/src/protocols/indexer.cc b/libtransport/src/protocols/indexer.cc
index 8d4cf04d7..41465755b 100644
--- a/libtransport/src/protocols/indexer.cc
+++ b/libtransport/src/protocols/indexer.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -14,10 +14,10 @@
*/
#include <implementation/socket_consumer.h>
+#include <protocols/errors.h>
#include <protocols/indexer.h>
namespace transport {
-
namespace protocol {
using namespace interface;
@@ -36,6 +36,35 @@ void Indexer::setVerifier() {
}
}
-} // end namespace protocol
+void Indexer::applyPolicy(core::Interest &interest,
+ core::ContentObject &content_object, bool reassembly,
+ auth::VerificationPolicy policy) const {
+ DCHECK(reassembly_ != nullptr);
+
+ switch (policy) {
+ case auth::VerificationPolicy::ACCEPT: {
+ if (reassembly) {
+ reassembly_->reassemble(content_object);
+ }
+ break;
+ }
+ case auth::VerificationPolicy::UNKNOWN:
+ if (reassembly && reassembly_->reassembleUnverified()) {
+ reassembly_->reassemble(content_object);
+ }
+ break;
+ case auth::VerificationPolicy::DROP:
+ transport_->onPacketDropped(
+ interest, content_object,
+ make_error_code(protocol_error::verification_failed));
+ break;
+ case auth::VerificationPolicy::ABORT: {
+ transport_->onContentReassembled(
+ make_error_code(protocol_error::session_aborted));
+ break;
+ }
+ }
+}
+} // end namespace protocol
} // end namespace transport
diff --git a/libtransport/src/protocols/indexer.h b/libtransport/src/protocols/indexer.h
index 7e3a52fb0..1bacb13aa 100644
--- a/libtransport/src/protocols/indexer.h
+++ b/libtransport/src/protocols/indexer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -15,6 +15,7 @@
#pragma once
+#include <hicn/transport/auth/policies.h>
#include <hicn/transport/core/content_object.h>
#include <hicn/transport/core/interest.h>
#include <protocols/fec_utils.h>
@@ -44,7 +45,7 @@ class Indexer {
/**
* Suffix getters
*/
- virtual uint32_t checkNextSuffix() = 0;
+ virtual uint32_t checkNextSuffix() const = 0;
virtual uint32_t getNextSuffix() = 0;
virtual uint32_t getNextReassemblySegment() = 0;
@@ -52,24 +53,24 @@ class Indexer {
* Set first suffix from where to start.
*/
virtual void setFirstSuffix(uint32_t suffix) = 0;
- virtual uint32_t getFirstSuffix() = 0;
+ virtual uint32_t getFirstSuffix() const = 0;
/**
* Functions to set/enable/disable fec
*/
virtual void setNFec(uint32_t n_fec) = 0;
- virtual uint32_t getNFec() = 0;
+ virtual uint32_t getNFec() const = 0;
virtual void enableFec(fec::FECType fec_type) = 0;
virtual void disableFec() = 0;
virtual bool isFec(uint32_t index) { return false; }
- virtual double getFecOverhead() { return 0.0; }
- virtual double getMaxFecOverhead() { return 0.0; }
+ virtual double getFecOverhead() const { return 0.0; }
+ virtual double getMaxFecOverhead() const { return 0.0; }
/**
* Final suffix helpers.
*/
virtual bool isFinalSuffixDiscovered() = 0;
- virtual uint32_t getFinalSuffix() = 0;
+ virtual uint32_t getFinalSuffix() const = 0;
/**
* Set reassembly protocol
@@ -84,9 +85,15 @@ class Indexer {
virtual void setVerifier();
/**
+ * Apply a verification policy
+ */
+ virtual void applyPolicy(core::Interest &interest,
+ core::ContentObject &content_object, bool reassembly,
+ auth::VerificationPolicy policy) const;
+ /**
* Jump to suffix. This may be useful if, for any protocol dependent
- * mechanism, we need to suddenly change current suffix. This does not modify
- * the way suffixes re incremented/decremented (that's part of the
+ * mechanism, we need to suddenly change current suffix. This does not
+ * modify the way suffixes re incremented/decremented (that's part of the
* implementation).
*/
virtual uint32_t jumpToIndex(uint32_t index) = 0;
@@ -108,6 +115,7 @@ class Indexer {
TransportProtocol *transport_;
Reassembly *reassembly_;
std::shared_ptr<auth::Verifier> verifier_;
+ auth::CryptoHashType manifest_hash_type_;
};
} // end namespace protocol
diff --git a/libtransport/src/protocols/manifest_incremental_indexer_bytestream.cc b/libtransport/src/protocols/manifest_incremental_indexer_bytestream.cc
index 168aa57af..b5ab8184f 100644
--- a/libtransport/src/protocols/manifest_incremental_indexer_bytestream.cc
+++ b/libtransport/src/protocols/manifest_incremental_indexer_bytestream.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -31,8 +31,7 @@ ManifestIncrementalIndexer::ManifestIncrementalIndexer(
implementation::ConsumerSocket *icn_socket, TransportProtocol *transport)
: IncrementalIndexer(icn_socket, transport),
suffix_strategy_(utils::SuffixStrategyFactory::getSuffixStrategy(
- NextSegmentCalculationStrategy::INCREMENTAL, next_download_suffix_,
- 0)) {}
+ utils::NextSuffixStrategy::INCREMENTAL, next_download_suffix_)) {}
void ManifestIncrementalIndexer::onContentObject(
core::Interest &interest, core::ContentObject &content_object,
@@ -59,12 +58,7 @@ void ManifestIncrementalIndexer::onContentObject(
void ManifestIncrementalIndexer::onUntrustedManifest(
core::Interest &interest, core::ContentObject &content_object,
bool reassembly) {
- auto manifest =
- std::make_unique<ContentObjectManifest>(std::move(content_object));
-
- auth::VerificationPolicy policy = verifier_->verifyPackets(manifest.get());
-
- manifest->decode();
+ auth::VerificationPolicy policy = verifier_->verifyPackets(&content_object);
if (policy != auth::VerificationPolicy::ACCEPT) {
transport_->onContentReassembled(
@@ -72,6 +66,10 @@ void ManifestIncrementalIndexer::onUntrustedManifest(
return;
}
+ auto manifest =
+ std::make_unique<ContentObjectManifest>(std::move(content_object));
+ manifest->decode();
+
processTrustedManifest(interest, std::move(manifest), reassembly);
}
@@ -83,9 +81,10 @@ void ManifestIncrementalIndexer::processTrustedManifest(
throw errors::RuntimeException("Received manifest with unknown version.");
}
- switch (manifest->getManifestType()) {
+ switch (manifest->getType()) {
case core::ManifestType::INLINE_MANIFEST: {
- suffix_strategy_->setFinalSuffix(manifest->getFinalBlockNumber());
+ suffix_strategy_->setFinalSuffix(
+ manifest->getParamsBytestream().final_segment);
// The packets to verify with the received manifest
std::vector<auth::PacketPtr> packets;
@@ -162,45 +161,15 @@ void ManifestIncrementalIndexer::onUntrustedContentObject(
applyPolicy(interest, content_object, reassembly, policy);
}
-void ManifestIncrementalIndexer::applyPolicy(
- core::Interest &interest, core::ContentObject &content_object,
- bool reassembly, auth::VerificationPolicy policy) {
- assert(reassembly_);
- switch (policy) {
- case auth::VerificationPolicy::ACCEPT: {
- if (reassembly && !reassembly_->reassembleUnverified()) {
- reassembly_->reassemble(content_object);
- }
- break;
- }
- case auth::VerificationPolicy::DROP: {
- transport_->onPacketDropped(
- interest, content_object,
- make_error_code(protocol_error::verification_failed));
- break;
- }
- case auth::VerificationPolicy::ABORT: {
- transport_->onContentReassembled(
- make_error_code(protocol_error::session_aborted));
- break;
- }
- case auth::VerificationPolicy::UNKNOWN: {
- if (reassembly && reassembly_->reassembleUnverified()) {
- reassembly_->reassemble(content_object);
- }
- }
- }
-}
-
-uint32_t ManifestIncrementalIndexer::checkNextSuffix() {
- return suffix_strategy_->getNextSuffix();
+uint32_t ManifestIncrementalIndexer::checkNextSuffix() const {
+ return suffix_strategy_->checkNextSuffix();
}
uint32_t ManifestIncrementalIndexer::getNextSuffix() {
auto ret = suffix_strategy_->getNextSuffix();
if (ret <= suffix_strategy_->getFinalSuffix() &&
- ret != utils::SuffixStrategy::INVALID_SUFFIX) {
+ ret != utils::SuffixStrategy::MAX_SUFFIX) {
suffix_queue_.push(ret);
return ret;
}
@@ -208,7 +177,7 @@ uint32_t ManifestIncrementalIndexer::getNextSuffix() {
return Indexer::invalid_index;
}
-uint32_t ManifestIncrementalIndexer::getFinalSuffix() {
+uint32_t ManifestIncrementalIndexer::getFinalSuffix() const {
return suffix_strategy_->getFinalSuffix();
}
diff --git a/libtransport/src/protocols/manifest_incremental_indexer_bytestream.h b/libtransport/src/protocols/manifest_incremental_indexer_bytestream.h
index d8cf5892f..12876f35c 100644
--- a/libtransport/src/protocols/manifest_incremental_indexer_bytestream.h
+++ b/libtransport/src/protocols/manifest_incremental_indexer_bytestream.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -39,8 +39,7 @@ class ManifestIncrementalIndexer : public IncrementalIndexer {
ManifestIncrementalIndexer(IncrementalIndexer &&indexer)
: IncrementalIndexer(std::move(indexer)),
suffix_strategy_(utils::SuffixStrategyFactory::getSuffixStrategy(
- core::NextSegmentCalculationStrategy::INCREMENTAL,
- next_download_suffix_, 0)) {
+ utils::NextSuffixStrategy::INCREMENTAL, next_download_suffix_)) {
for (uint32_t i = first_suffix_; i < next_download_suffix_; i++) {
suffix_queue_.push(i);
}
@@ -54,7 +53,7 @@ class ManifestIncrementalIndexer : public IncrementalIndexer {
core::ContentObject &content_object,
bool reassembly) override;
- uint32_t checkNextSuffix() override;
+ uint32_t checkNextSuffix() const override;
uint32_t getNextSuffix() override;
@@ -62,7 +61,7 @@ class ManifestIncrementalIndexer : public IncrementalIndexer {
bool isFinalSuffixDiscovered() override;
- uint32_t getFinalSuffix() override;
+ uint32_t getFinalSuffix() const override;
protected:
std::unique_ptr<utils::SuffixStrategy> suffix_strategy_;
@@ -82,9 +81,6 @@ class ManifestIncrementalIndexer : public IncrementalIndexer {
void onUntrustedContentObject(core::Interest &interest,
core::ContentObject &content_object,
bool reassembly);
- void applyPolicy(core::Interest &interest,
- core::ContentObject &content_object, bool reassembly,
- auth::VerificationPolicy policy);
};
} // end namespace protocol
diff --git a/libtransport/src/protocols/prod_protocol_bytestream.cc b/libtransport/src/protocols/prod_protocol_bytestream.cc
index f659cb37c..2a3ec07e1 100644
--- a/libtransport/src/protocols/prod_protocol_bytestream.cc
+++ b/libtransport/src/protocols/prod_protocol_bytestream.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -29,12 +29,7 @@ ByteStreamProductionProtocol::ByteStreamProductionProtocol(
implementation::ProducerSocket *icn_socket)
: ProductionProtocol(icn_socket) {}
-ByteStreamProductionProtocol::~ByteStreamProductionProtocol() {
- stop();
- if (listening_thread_.joinable()) {
- listening_thread_.join();
- }
-}
+ByteStreamProductionProtocol::~ByteStreamProductionProtocol() { stop(); }
uint32_t ByteStreamProductionProtocol::produceDatagram(
const Name &content_name, std::unique_ptr<utils::MemBuf> &&buffer) {
@@ -68,16 +63,16 @@ uint32_t ByteStreamProductionProtocol::produceStream(
return 0;
}
- Name name(content_name);
-
- // Get the atomic variables to ensure they keep the same value
- // during the production
-
// Total size of the data packet
uint32_t data_packet_size;
socket_->getSocketOption(GeneralTransportOptions::DATA_PACKET_SIZE,
data_packet_size);
+ // Maximum size of a segment
+ uint32_t max_segment_size;
+ socket_->getSocketOption(GeneralTransportOptions::MAX_SEGMENT_SIZE,
+ max_segment_size);
+
// Expiry time
uint32_t content_object_expiry_time;
socket_->getSocketOption(GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME,
@@ -88,106 +83,90 @@ uint32_t ByteStreamProductionProtocol::produceStream(
socket_->getSocketOption(GeneralTransportOptions::HASH_ALGORITHM, hash_algo);
// Suffix calculation strategy
- core::NextSegmentCalculationStrategy _suffix_strategy;
+ std::shared_ptr<utils::SuffixStrategy> suffix_strategy;
socket_->getSocketOption(GeneralTransportOptions::SUFFIX_STRATEGY,
- _suffix_strategy);
- auto suffix_strategy = utils::SuffixStrategyFactory::getSuffixStrategy(
- _suffix_strategy, start_offset);
+ suffix_strategy);
+ suffix_strategy->reset(start_offset);
- auto buffer_size = buffer->length();
+ // Default format
+ core::Packet::Format default_format;
+ socket_->getSocketOption(GeneralTransportOptions::PACKET_FORMAT,
+ default_format);
+
+ Name name(content_name);
+ size_t buffer_size = buffer->length();
+ size_t signature_length = signer_->getSignatureFieldSize();
+ uint32_t final_block_number = start_offset;
+
+ // Content-related
+ core::Packet::Format content_format;
+ uint32_t content_header_size;
+ uint64_t content_free_space;
+ uint32_t nb_segments;
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;
+ // Manifest-related
+ core::Packet::Format manifest_format;
+ uint32_t manifest_header_size;
+ uint64_t manifest_free_space;
+ uint32_t nb_manifests;
std::shared_ptr<core::ContentObjectManifest> manifest;
+ uint32_t manifest_capacity = making_manifest_;
bool is_last_manifest = false;
-
- // TODO Manifest may still be used for indexing
- if (making_manifest_ && !signer_) {
- LOG(FATAL) << "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 (name.getType() == HNT_CONTIGUOUS_V4 || 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 (name.getType() == HNT_CONTIGUOUS_V6 ||
- 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_->getSignatureFieldSize() : 0);
- } else if (signer_) {
- format = hf_format_ah;
- signature_length = signer_->getSignatureFieldSize();
+ ParamsBytestream transport_params;
+
+ manifest_format = Packet::toAHFormat(default_format);
+ content_format =
+ !making_manifest_ ? Packet::toAHFormat(default_format) : default_format;
+
+ content_header_size =
+ core::Packet::getHeaderSizeFromFormat(content_format, signature_length);
+ manifest_header_size =
+ core::Packet::getHeaderSizeFromFormat(manifest_format, signature_length);
+ content_free_space =
+ std::min(max_segment_size, data_packet_size - content_header_size);
+ manifest_free_space =
+ std::min(max_segment_size, data_packet_size - manifest_header_size);
+
+ // Compute the number of segments the data will be split into
+ nb_segments =
+ uint32_t(std::ceil(double(buffer_size) / double(content_free_space)));
+ if (content_free_space * nb_segments < buffer_size) {
+ nb_segments++;
}
- 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<uint32_t>(
- std::floor(double(data_packet_size - manifest_header_size -
- ContentObjectManifest::getManifestHeaderSize()) /
- ContentObjectManifest::getManifestEntrySize()) -
- 1.0);
- uint32_t number_of_manifests = static_cast<uint32_t>(
- std::ceil(float(number_of_segments) / segment_in_manifest));
- final_block_number += number_of_segments + number_of_manifests - 1;
+ nb_manifests = static_cast<uint32_t>(
+ std::ceil(float(nb_segments) / manifest_capacity));
+ final_block_number += nb_segments + nb_manifests - 1;
+ transport_params.final_segment =
+ is_last ? final_block_number : utils::SuffixStrategy::MAX_SUFFIX;
manifest.reset(ContentObjectManifest::createManifest(
+ manifest_format,
name.setSuffix(suffix_strategy->getNextManifestSuffix()),
core::ManifestVersion::VERSION_1, core::ManifestType::INLINE_MANIFEST,
- hash_algo, is_last_manifest, name, _suffix_strategy,
- signer_ ? signer_->getSignatureFieldSize() : 0));
- manifest->setLifetime(content_object_expiry_time);
+ is_last_manifest, name, hash_algo, signature_length));
- if (is_last) {
- manifest->setFinalBlockNumber(final_block_number);
- } else {
- manifest->setFinalBlockNumber(utils::SuffixStrategy::INVALID_SUFFIX);
- }
+ manifest->setLifetime(content_object_expiry_time);
+ manifest->setParamsBytestream(transport_params);
}
- for (unsigned int packaged_segments = 0;
- packaged_segments < number_of_segments; packaged_segments++) {
+ auto self = shared_from_this();
+ for (unsigned int packaged_segments = 0; packaged_segments < nb_segments;
+ packaged_segments++) {
if (making_manifest_) {
- if (manifest->estimateManifestSize(2) >
- data_packet_size - manifest_header_size) {
+ if (manifest->estimateManifestSize(1) > manifest_free_space) {
manifest->encode();
-
- // If identity set, sign manifest
- if (signer_) {
- signer_->signPacket(manifest.get());
- }
+ signer_->signPacket(manifest.get());
// Send the current manifest
- passContentObjectToCallbacks(manifest);
-
+ passContentObjectToCallbacks(manifest, self);
DLOG_IF(INFO, VLOG_IS_ON(3)) << "Send manifest " << manifest->getName();
// Send content objects stored in the queue
while (!content_queue_.empty()) {
- passContentObjectToCallbacks(content_queue_.front());
+ passContentObjectToCallbacks(content_queue_.front(), self);
DLOG_IF(INFO, VLOG_IS_ON(3))
<< "Send content " << content_queue_.front()->getName();
content_queue_.pop();
@@ -195,86 +174,84 @@ uint32_t ByteStreamProductionProtocol::produceStream(
// Create new manifest. The reference to the last manifest has been
// acquired in the passContentObjectToCallbacks function, so we can
- // safely release this reference
+ // safely release this reference.
manifest.reset(ContentObjectManifest::createManifest(
+ manifest_format,
name.setSuffix(suffix_strategy->getNextManifestSuffix()),
core::ManifestVersion::VERSION_1,
- core::ManifestType::INLINE_MANIFEST, hash_algo, is_last_manifest,
- name, _suffix_strategy,
- signer_ ? signer_->getSignatureFieldSize() : 0));
+ core::ManifestType::INLINE_MANIFEST, is_last_manifest, name,
+ hash_algo, signature_length));
manifest->setLifetime(content_object_expiry_time);
- manifest->setFinalBlockNumber(
- is_last ? final_block_number
- : utils::SuffixStrategy::INVALID_SUFFIX);
+ manifest->setParamsBytestream(transport_params);
}
}
- auto content_suffix = suffix_strategy->getNextContentSuffix();
+ // Create content object
+ uint32_t content_suffix = suffix_strategy->getNextContentSuffix();
auto content_object = std::make_shared<ContentObject>(
- name.setSuffix(content_suffix), format,
- signer_ && !making_manifest_ ? signer_->getSignatureFieldSize() : 0);
+ name.setSuffix(content_suffix), content_format,
+ !making_manifest_ ? signature_length : 0);
content_object->setLifetime(content_object_expiry_time);
auto b = buffer->cloneOne();
- b->trimStart(free_space_for_content * packaged_segments);
+ b->trimStart(content_free_space * packaged_segments);
b->trimEnd(b->length());
- if (TRANSPORT_EXPECT_FALSE(packaged_segments == number_of_segments - 1)) {
+ // Segment the input data
+ if (TRANSPORT_EXPECT_FALSE(packaged_segments == nb_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();
+ content_object->setLast();
}
} else {
- b->append(free_space_for_content);
- bytes_segmented += (int)(free_space_for_content);
+ b->append(content_free_space);
+ bytes_segmented += (int)(content_free_space);
}
+ // Set the segmented data as payload
content_object->appendPayload(std::move(b));
+ // Either we sign the content object or we save its hash into the current
+ // manifest
if (making_manifest_) {
- using namespace std::chrono_literals;
auth::CryptoHash hash = content_object->computeDigest(hash_algo);
manifest->addSuffixHash(content_suffix, hash);
content_queue_.push(content_object);
} else {
- if (signer_) {
- signer_->signPacket(content_object.get());
- }
- passContentObjectToCallbacks(content_object);
+ signer_->signPacket(content_object.get());
+ passContentObjectToCallbacks(content_object, self);
DLOG_IF(INFO, VLOG_IS_ON(3))
<< "Send content " << content_object->getName();
}
}
+ // We send the manifest that hasn't been fully filled yet
if (making_manifest_) {
if (is_last_manifest) {
- manifest->setFinalManifest(is_last_manifest);
+ manifest->setIsLast(is_last_manifest);
}
manifest->encode();
+ signer_->signPacket(manifest.get());
- if (signer_) {
- signer_->signPacket(manifest.get());
- }
-
- passContentObjectToCallbacks(manifest);
+ passContentObjectToCallbacks(manifest, self);
DLOG_IF(INFO, VLOG_IS_ON(3)) << "Send manifest " << manifest->getName();
while (!content_queue_.empty()) {
- passContentObjectToCallbacks(content_queue_.front());
+ passContentObjectToCallbacks(content_queue_.front(), self);
DLOG_IF(INFO, VLOG_IS_ON(3))
<< "Send content " << content_queue_.front()->getName();
content_queue_.pop();
}
}
- portal_->getIoService().post([this]() {
+ portal_->getThread().add([this, self]() {
std::shared_ptr<ContentObject> co;
while (object_queue_for_callbacks_.pop(co)) {
if (*on_new_segment_) {
@@ -296,7 +273,7 @@ uint32_t ByteStreamProductionProtocol::produceStream(
}
});
- portal_->getIoService().dispatch([this, buffer_size]() {
+ portal_->getThread().add([this, buffer_size, self]() {
if (*on_content_produced_) {
on_content_produced_->operator()(*socket_->getInterface(),
std::make_error_code(std::errc(0)),
@@ -307,9 +284,10 @@ uint32_t ByteStreamProductionProtocol::produceStream(
return suffix_strategy->getTotalCount();
}
-void ByteStreamProductionProtocol::scheduleSendBurst() {
- portal_->getIoService().post([this]() {
- std::shared_ptr<ContentObject> co;
+void ByteStreamProductionProtocol::scheduleSendBurst(
+ const std::shared_ptr<ByteStreamProductionProtocol> &self) {
+ portal_->getThread().add([this, self]() {
+ ContentObject::Ptr co;
for (uint32_t i = 0; i < burst_size; i++) {
if (object_queue_for_callbacks_.pop(co)) {
@@ -321,11 +299,15 @@ void ByteStreamProductionProtocol::scheduleSendBurst() {
on_content_object_to_sign_->operator()(*socket_->getInterface(), *co);
}
+ output_buffer_.insert(co);
+
if (*on_content_object_in_output_buffer_) {
on_content_object_in_output_buffer_->operator()(
*socket_->getInterface(), *co);
}
+ portal_->sendContentObject(*co);
+
if (*on_content_object_output_) {
on_content_object_output_->operator()(*socket_->getInterface(), *co);
}
@@ -337,13 +319,12 @@ void ByteStreamProductionProtocol::scheduleSendBurst() {
}
void ByteStreamProductionProtocol::passContentObjectToCallbacks(
- const std::shared_ptr<ContentObject> &content_object) {
- output_buffer_.insert(content_object);
- portal_->sendContentObject(*content_object);
+ const std::shared_ptr<ContentObject> &content_object,
+ const std::shared_ptr<ByteStreamProductionProtocol> &self) {
object_queue_for_callbacks_.push(std::move(content_object));
if (object_queue_for_callbacks_.size() >= burst_size) {
- scheduleSendBurst();
+ scheduleSendBurst(self);
}
}
@@ -376,7 +357,5 @@ void ByteStreamProductionProtocol::onInterest(Interest &interest) {
}
}
-void ByteStreamProductionProtocol::onError(std::error_code ec) {}
-
} // namespace protocol
} // end namespace transport
diff --git a/libtransport/src/protocols/prod_protocol_bytestream.h b/libtransport/src/protocols/prod_protocol_bytestream.h
index cf36b90a5..809ad8d5c 100644
--- a/libtransport/src/protocols/prod_protocol_bytestream.h
+++ b/libtransport/src/protocols/prod_protocol_bytestream.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -50,16 +50,19 @@ class ByteStreamProductionProtocol : public ProductionProtocol {
uint32_t produceDatagram(const Name &content_name, const uint8_t *buffer,
size_t buffer_size) override;
+ auto shared_from_this() { return utils::shared_from(this); }
+
protected:
// Consumer Callback
// void reset() override;
void onInterest(core::Interest &i) override;
- void onError(std::error_code ec) override;
private:
void passContentObjectToCallbacks(
- const std::shared_ptr<ContentObject> &content_object);
- void scheduleSendBurst();
+ const std::shared_ptr<ContentObject> &content_object,
+ const std::shared_ptr<ByteStreamProductionProtocol> &self);
+ void scheduleSendBurst(
+ const std::shared_ptr<ByteStreamProductionProtocol> &self);
private:
// While manifests are being built, contents are stored in a queue
diff --git a/libtransport/src/protocols/prod_protocol_rtc.cc b/libtransport/src/protocols/prod_protocol_rtc.cc
index cdc882d81..242abd30d 100644
--- a/libtransport/src/protocols/prod_protocol_rtc.cc
+++ b/libtransport/src/protocols/prod_protocol_rtc.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -13,9 +13,11 @@
* limitations under the License.
*/
+#include <glog/logging.h>
#include <hicn/transport/core/global_object_pool.h>
#include <implementation/socket_producer.h>
#include <protocols/prod_protocol_rtc.h>
+#include <protocols/rtc/probe_handler.h>
#include <protocols/rtc/rtc_consts.h>
#include <stdlib.h>
#include <time.h>
@@ -38,71 +40,89 @@ RTCProductionProtocol::RTCProductionProtocol(
bytes_production_rate_(0),
packets_production_rate_(0),
fec_packets_production_rate_(0),
- last_round_(std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count()),
+ last_produced_data_ts_(0),
+ last_round_(utils::SteadyTime::nowMs().count()),
allow_delayed_nacks_(false),
queue_timer_on_(false),
consumer_in_sync_(false),
- on_consumer_in_sync_(nullptr) {
- srand((unsigned int)time(NULL));
- prod_label_ = rand() % 256;
+ on_consumer_in_sync_(nullptr),
+ pending_fec_pace_(false),
+ max_len_(0),
+ queue_len_(0),
+ data_aggregation_(true),
+ data_aggregation_timer_switch_(false) {
+ std::uniform_int_distribution<> dis(0, 255);
+ prod_label_ = dis(gen_);
cache_label_ = (prod_label_ + 1) % 256;
interests_queue_timer_ =
- std::make_unique<asio::steady_timer>(portal_->getIoService());
- round_timer_ = std::make_unique<asio::steady_timer>(portal_->getIoService());
+ std::make_unique<asio::steady_timer>(portal_->getThread().getIoService());
+ round_timer_ =
+ std::make_unique<asio::steady_timer>(portal_->getThread().getIoService());
+ fec_pacing_timer_ =
+ std::make_unique<asio::steady_timer>(portal_->getThread().getIoService());
+ app_packets_timer_ =
+ std::make_unique<asio::steady_timer>(portal_->getThread().getIoService());
setOutputBufferSize(10000);
- scheduleRoundTimer();
+}
+
+RTCProductionProtocol::~RTCProductionProtocol() {}
+
+void RTCProductionProtocol::setProducerParam() {
+ // Flow name: here we assume there is only one prefix registered in the portal
+ flow_name_ = portal_->getServedNamespaces().begin()->getName();
+
+ // Manifest
+ uint32_t making_manifest;
+ socket_->getSocketOption(interface::GeneralTransportOptions::MAKE_MANIFEST,
+ making_manifest);
+
+ // Signer
+ std::shared_ptr<auth::Signer> signer;
+ socket_->getSocketOption(interface::GeneralTransportOptions::SIGNER, signer);
+
+ // Default format
+ core::Packet::Format default_format;
+ socket_->getSocketOption(interface::GeneralTransportOptions::PACKET_FORMAT,
+ default_format);
// FEC
using namespace std::placeholders;
enableFEC(std::bind(&RTCProductionProtocol::onFecPackets, this, _1),
std::bind(&RTCProductionProtocol::getBuffer, this, _1));
-}
-RTCProductionProtocol::~RTCProductionProtocol() {}
+ // Aggregated data
+ socket_->getSocketOption(interface::RtcTransportOptions::AGGREGATED_DATA,
+ data_aggregation_);
-void RTCProductionProtocol::registerNamespaceWithNetwork(
- const Prefix &producer_namespace) {
- ProductionProtocol::registerNamespaceWithNetwork(producer_namespace);
-
- flow_name_ = producer_namespace.getName();
- auto family = flow_name_.getAddressFamily();
-
- switch (family) {
- case AF_INET6:
- data_header_size_ =
- signer_ && !making_manifest_
- ? (uint32_t)Packet::getHeaderSizeFromFormat(
- HF_INET6_TCP_AH, signer_->getSignatureFieldSize())
- : (uint32_t)Packet::getHeaderSizeFromFormat(HF_INET6_TCP);
- ;
- break;
- case AF_INET:
- data_header_size_ =
- signer_ && !making_manifest_
- ? (uint32_t)Packet::getHeaderSizeFromFormat(
- HF_INET_TCP_AH, signer_->getSignatureFieldSize())
- : (uint32_t)Packet::getHeaderSizeFromFormat(HF_INET_TCP);
- break;
- default:
- throw errors::RuntimeException("Unknown name format.");
- }
+ size_t signature_size = signer->getSignatureFieldSize();
+ data_header_format_ = {
+ !making_manifest ? Packet::toAHFormat(default_format) : default_format,
+ !making_manifest ? signature_size : 0};
+ manifest_header_format_ = {Packet::toAHFormat(default_format),
+ signature_size};
+ nack_header_format_ = {Packet::toAHFormat(default_format), signature_size};
+ fec_header_format_ = {Packet::toAHFormat(default_format), signature_size};
+
+ // Schedule round timer
+ scheduleRoundTimer();
}
void RTCProductionProtocol::scheduleRoundTimer() {
round_timer_->expires_from_now(
std::chrono::milliseconds(rtc::PRODUCER_STATS_INTERVAL));
- round_timer_->async_wait([this](std::error_code ec) {
+ std::weak_ptr<RTCProductionProtocol> self = shared_from_this();
+ round_timer_->async_wait([self](const std::error_code &ec) {
if (ec) return;
- updateStats();
+
+ auto sp = self.lock();
+ if (sp && sp->isRunning()) {
+ sp->updateStats();
+ }
});
}
void RTCProductionProtocol::updateStats() {
- uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
+ uint64_t now = utils::SteadyTime::nowMs().count();
uint64_t duration = now - last_round_;
if (duration == 0) duration = 1;
double per_second = rtc::MILLI_IN_A_SEC / duration;
@@ -125,11 +145,12 @@ void RTCProductionProtocol::updateStats() {
if (max_packet_production_ < rtc::WIN_MIN)
max_packet_production_ = rtc::WIN_MIN;
- if (packets_production_rate_ != 0) {
- allow_delayed_nacks_ = false;
- } else if (prev_packets_production_rate == 0) {
- // at least 2 rounds with production rate = 0
+ if (packets_production_rate_ <= rtc::MIN_PRODUCTION_RATE ||
+ prev_packets_production_rate <= rtc::MIN_PRODUCTION_RATE) {
allow_delayed_nacks_ = true;
+ } else {
+ // at least 2 rounds with enough packets
+ allow_delayed_nacks_ = false;
}
// check if the production rate is decreased. if yes send nacks if needed
@@ -170,42 +191,237 @@ uint32_t RTCProductionProtocol::produceDatagram(
socket_->getSocketOption(interface::GeneralTransportOptions::DATA_PACKET_SIZE,
data_packet_size);
- if (TRANSPORT_EXPECT_FALSE((buffer_size + data_header_size_ +
- rtc::DATA_HEADER_SIZE) > data_packet_size)) {
+ if (TRANSPORT_EXPECT_FALSE(
+ (Packet::getHeaderSizeFromFormat(data_header_format_.first,
+ data_header_format_.second) +
+ rtc::DATA_HEADER_SIZE + buffer_size) > data_packet_size)) {
return 0;
}
+ if (!data_aggregation_) {
+ // if data aggregation is off emptyQueue will always return doing nothing
+ emptyQueue();
+
+ sendManifest(content_name);
+
+ // create content object
+ auto content_object =
+ core::PacketManager<>::getInstance().getPacket<ContentObject>(
+ data_header_format_.first, data_header_format_.second);
+
+ // add rtc header to the payload
+ struct rtc::data_packet_t header;
+ content_object->appendPayload((const uint8_t *)&header,
+ rtc::DATA_HEADER_SIZE);
+ content_object->appendPayload(buffer->data(), buffer->length());
+
+ // schedule actual sending on internal thread
+ portal_->getThread().tryRunHandlerNow(
+ [this, content_object{std::move(content_object)},
+ content_name]() mutable {
+ produceInternal(std::move(content_object), content_name);
+ });
+ } else {
+ // XXX here we assume that all the packets that we push to the queue have
+ // the same name
+ auto app_pkt = utils::MemBuf::copyBuffer(buffer->data(), buffer->length());
+ addPacketToQueue(std::move(app_pkt));
+ }
+
+ return 1;
+}
+
+void RTCProductionProtocol::addPacketToQueue(
+ std::unique_ptr<utils::MemBuf> &&buffer) {
+ std::size_t buffer_size = buffer->length();
+ if ((queue_len_ + buffer_size) > rtc::MAX_RTC_PAYLOAD_SIZE) {
+ emptyQueue(); // this should guaranty that the generated packet will never
+ // be larger than an MTU
+ }
+
+ waiting_app_packets_.push(std::move(buffer));
+ if (max_len_ < buffer_size) max_len_ = buffer_size;
+ queue_len_ += buffer_size;
+
+ if (waiting_app_packets_.size() >= rtc::MAX_AGGREGATED_PACKETS) {
+ emptyQueue();
+ }
+
+ if (waiting_app_packets_.size() >= 1 && !data_aggregation_timer_switch_) {
+ data_aggregation_timer_switch_ = true;
+ app_packets_timer_->expires_from_now(
+ std::chrono::milliseconds(rtc::AGGREGATED_PACKETS_TIMER));
+ std::weak_ptr<RTCProductionProtocol> self = shared_from_this();
+ app_packets_timer_->async_wait([self](const std::error_code &ec) {
+ if (ec) return;
+
+ auto ptr = self.lock();
+ if (ptr && ptr->isRunning()) {
+ if (!ptr->data_aggregation_timer_switch_) return;
+ ptr->emptyQueue();
+ }
+ });
+ }
+}
+
+void RTCProductionProtocol::emptyQueue() {
+ if (waiting_app_packets_.size() == 0) return; // queue is empty
+
+ Name n(flow_name_);
+
+ // cancel timer is scheduled
+ if (data_aggregation_timer_switch_) {
+ data_aggregation_timer_switch_ = false;
+ app_packets_timer_->cancel();
+ }
+
+ // send a manifest beforehand if the hash buffer if full
+ sendManifest(n);
+
+ // create content object
auto content_object =
core::PacketManager<>::getInstance().getPacket<ContentObject>(
- signer_ ? Format::HF_INET6_TCP_AH : Format::HF_INET6_TCP,
- signer_ ? signer_->getSignatureFieldSize() : 0);
+ data_header_format_.first, data_header_format_.second);
+
// add rtc header to the payload
struct rtc::data_packet_t header;
content_object->appendPayload((const uint8_t *)&header,
rtc::DATA_HEADER_SIZE);
- content_object->appendPayload(buffer->data(), buffer->length());
- // schedule actual sending on internal thread
- portal_->getIoService().dispatch([this,
- content_object{std::move(content_object)},
- content_name]() mutable {
- produceInternal(std::move(content_object), content_name);
+ // init aggregated header
+ rtc::AggrPktHeader hdr(
+ (uint8_t *)(content_object->getPayload()->data() + rtc::DATA_HEADER_SIZE),
+ max_len_, waiting_app_packets_.size());
+ uint32_t header_size = hdr.getHeaderLen();
+ content_object->append(header_size); // leave space for the aggregated header
+
+ uint8_t index = 0;
+ while (waiting_app_packets_.size() != 0) {
+ std::unique_ptr<utils::MemBuf> pkt =
+ std::move(waiting_app_packets_.front());
+ waiting_app_packets_.pop();
+ // XXX for the moment we have a single name, so this works, otherwise we
+ // need to do something else
+ hdr.addPacketToHeader(index, pkt->length());
+ // append packet
+ content_object->appendPayload(pkt->data(), pkt->length());
+ index++;
+ }
+
+ // reset queue values
+ max_len_ = 0;
+ queue_len_ = 0;
+
+ // the packet is ready we need to send it
+ portal_->getThread().tryRunHandlerNow(
+ [this, content_object{std::move(content_object)}, n]() mutable {
+ produceInternal(std::move(content_object), n);
+ });
+}
+
+void RTCProductionProtocol::sendManifest(const Name &name) {
+ if (!making_manifest_) {
+ return;
+ }
+
+ Name manifest_name(name);
+
+ uint32_t data_packet_size;
+ socket_->getSocketOption(interface::GeneralTransportOptions::DATA_PACKET_SIZE,
+ data_packet_size);
+
+ // The maximum number of entries a manifest can hold
+ uint32_t manifest_capacity = making_manifest_;
+
+ // If there is not enough hashes to fill a manifest, return early
+ if (manifest_entries_.size() < manifest_capacity) {
+ return;
+ }
+
+ // Create a new manifest
+ std::shared_ptr<core::ContentObjectManifest> manifest =
+ createManifest(manifest_name.setSuffix(current_seg_));
+
+ // Fill the manifest with packet hashes that were previously saved
+ uint32_t nb_entries;
+ for (nb_entries = 0; nb_entries < manifest_capacity; ++nb_entries) {
+ if (manifest_entries_.empty()) {
+ break;
+ }
+ std::pair<uint32_t, auth::CryptoHash> front = manifest_entries_.front();
+ manifest->addSuffixHash(front.first, front.second);
+ manifest_entries_.pop();
+ }
+
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Sending manifest " << manifest->getName().getSuffix() << " of size "
+ << nb_entries;
+
+ // Encode and send the manifest
+ manifest->encode();
+ portal_->getThread().tryRunHandlerNow(
+ [this, content_object{std::move(manifest)}, manifest_name]() mutable {
+ produceInternal(std::move(content_object), manifest_name);
+ });
+}
+
+std::shared_ptr<core::ContentObjectManifest>
+RTCProductionProtocol::createManifest(const Name &content_name) const {
+ Name name(content_name);
+
+ auth::CryptoHashType hash_algo;
+ socket_->getSocketOption(interface::GeneralTransportOptions::HASH_ALGORITHM,
+ hash_algo);
+
+ uint64_t now = utils::SteadyTime::nowMs().count();
+
+ // Create a new manifest
+ std::shared_ptr<core::ContentObjectManifest> manifest(
+ ContentObjectManifest::createManifest(
+ manifest_header_format_.first, name, core::ManifestVersion::VERSION_1,
+ core::ManifestType::INLINE_MANIFEST, false, name, hash_algo,
+ manifest_header_format_.second));
+
+ // Set connection parameters
+ manifest->setParamsRTC(ParamsRTC{
+ .timestamp = now,
+ .prod_rate = bytes_production_rate_,
+ .prod_seg = current_seg_,
+ .support_fec = false,
});
- return 1;
+ return manifest;
}
void RTCProductionProtocol::produceInternal(
std::shared_ptr<ContentObject> &&content_object, const Name &content_name,
bool fec) {
+ uint64_t now = utils::SteadyTime::nowMs().count();
+
+ if (fec && (now - last_produced_data_ts_) < rtc::FEC_PACING_TIME) {
+ paced_fec_packets_.push(std::pair<uint64_t, ContentObject::Ptr>(
+ now, std::move(content_object)));
+ postponeFecPacket();
+ } else {
+ // need to check if there are FEC packets waiting to be sent
+ flushFecPkts(current_seg_);
+ producePktInternal(std::move(content_object), content_name, fec);
+ }
+}
+
+void RTCProductionProtocol::producePktInternal(
+ std::shared_ptr<ContentObject> &&content_object, const Name &content_name,
+ bool fec) {
+ bool is_manifest = content_object->getPayloadType() == PayloadType::MANIFEST;
+ uint64_t now = utils::SteadyTime::nowMs().count();
+
// set rtc header
- struct rtc::data_packet_t *data_pkt =
- (struct rtc::data_packet_t *)content_object->getPayload()->data();
- uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
- data_pkt->setTimestamp(now);
- data_pkt->setProductionRate(bytes_production_rate_);
+ if (!is_manifest) {
+ struct rtc::data_packet_t *data_pkt =
+ (struct rtc::data_packet_t *)content_object->getPayload()->data();
+ data_pkt->setTimestamp(now);
+ data_pkt->setProductionRate(bytes_production_rate_);
+ }
// set hicn stuff
Name n(content_name);
@@ -213,11 +429,6 @@ void RTCProductionProtocol::produceInternal(
content_object->setLifetime(500); // XXX this should be set by the APP
content_object->setPathLabel(prod_label_);
- // sign packet
- if (signer_) {
- signer_->signPacket(content_object.get());
- }
-
// update stats
if (!fec) {
produced_bytes_ +=
@@ -227,7 +438,7 @@ void RTCProductionProtocol::produceInternal(
produced_fec_packets_++;
}
- if (produced_packets_ >= max_packet_production_) {
+ if (!data_aggregation_ && produced_packets_ >= max_packet_production_) {
// in this case all the pending interests may be used to accomodate the
// sudden increase in the production rate. calling the updateStats we will
// notify all the clients
@@ -240,8 +451,12 @@ void RTCProductionProtocol::produceInternal(
// pass packet to FEC encoder
if (fec_encoder_ && !fec) {
- fec_encoder_->onPacketProduced(
- *content_object, content_object->headerSize() + rtc::DATA_HEADER_SIZE);
+ uint32_t offset =
+ is_manifest ? content_object->headerSize()
+ : content_object->headerSize() + rtc::DATA_HEADER_SIZE;
+ uint32_t metadata = static_cast<uint32_t>(content_object->getPayloadType());
+
+ fec_encoder_->onPacketProduced(*content_object, offset, metadata);
}
output_buffer_.insert(content_object);
@@ -253,7 +468,7 @@ void RTCProductionProtocol::produceInternal(
auto seq_it = seqs_map_.find(current_seg_);
if (seq_it != seqs_map_.end()) {
- portal_->sendContentObject(*content_object);
+ sendContentObject(content_object, false, fec);
}
if (*on_content_object_output_) {
@@ -264,6 +479,8 @@ void RTCProductionProtocol::produceInternal(
// remove interests from the interest cache if it exists
removeFromInterestQueue(current_seg_);
+ if (!fec) last_produced_data_ts_ = now;
+
// Update current segment
current_seg_ = (current_seg_ + 1) % rtc::MIN_PROBE_SEQ;
@@ -277,6 +494,55 @@ void RTCProductionProtocol::produceInternal(
}
}
+void RTCProductionProtocol::flushFecPkts(uint32_t current_seq_num) {
+ // Currently we immediately send all the pending fec packets
+ // A pacing policy may be helpful, but we do not want to delay too much
+ // the packets at this moment.
+ while (paced_fec_packets_.size() > 0) {
+ producePktInternal(std::move(paced_fec_packets_.front().second), flow_name_,
+ true);
+ paced_fec_packets_.pop();
+ }
+ fec_pacing_timer_->cancel();
+ pending_fec_pace_ = false;
+ postponeFecPacket();
+}
+
+void RTCProductionProtocol::postponeFecPacket() {
+ if (paced_fec_packets_.size() == 0) return;
+ if (pending_fec_pace_) {
+ return;
+ }
+
+ uint64_t produced_time = paced_fec_packets_.front().first;
+ uint64_t now = utils::SteadyTime::nowMs().count();
+
+ uint64_t wait_time = 0;
+ if ((produced_time + rtc::FEC_PACING_TIME) > now)
+ wait_time = produced_time + rtc::FEC_PACING_TIME - now;
+
+ fec_pacing_timer_->expires_from_now(std::chrono::milliseconds(wait_time));
+ pending_fec_pace_ = true;
+
+ std::weak_ptr<RTCProductionProtocol> self = shared_from_this();
+ fec_pacing_timer_->async_wait([self](const std::error_code &ec) {
+ if (ec) return;
+
+ auto sp = self.lock();
+ if (sp && sp->isRunning()) {
+ if (!sp->pending_fec_pace_) return;
+
+ if (sp->paced_fec_packets_.size() > 0) {
+ sp->producePktInternal(std::move(sp->paced_fec_packets_.front().second),
+ sp->flow_name_, true);
+ sp->paced_fec_packets_.pop();
+ }
+ sp->pending_fec_pace_ = false;
+ sp->postponeFecPacket();
+ }
+ });
+}
+
void RTCProductionProtocol::onInterest(Interest &interest) {
if (*on_interest_input_) {
on_interest_input_->operator()(*socket_->getInterface(), interest);
@@ -284,7 +550,7 @@ void RTCProductionProtocol::onInterest(Interest &interest) {
auto suffix = interest.firstSuffix();
// numberOfSuffixes returns only the prefixes in the payalod
- // we add + 1 to count anche the seq in the name
+ // we add + 1 to count also the seq in the name
auto n_suffixes = interest.numberOfSuffixes() + 1;
Name name = interest.getName();
bool prev_consumer_state = consumer_in_sync_;
@@ -293,6 +559,7 @@ void RTCProductionProtocol::onInterest(Interest &interest) {
if (i > 0) {
name.setSuffix(*(suffix + (i - 1)));
}
+
DLOG_IF(INFO, VLOG_IS_ON(3)) << "Received interest " << name;
const std::shared_ptr<ContentObject> content_object =
@@ -312,7 +579,7 @@ void RTCProductionProtocol::onInterest(Interest &interest) {
DLOG_IF(INFO, VLOG_IS_ON(3))
<< "Send content %u (onInterest) " << content_object->getName();
content_object->setPathLabel(cache_label_);
- portal_->sendContentObject(*content_object);
+ sendContentObject(content_object);
} else {
if (*on_interest_process_) {
on_interest_process_->operator()(*socket_->getInterface(), interest);
@@ -332,14 +599,19 @@ void RTCProductionProtocol::processInterest(uint32_t interest_seg,
consumer_in_sync_ = false;
}
- uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
+ uint64_t now = utils::SteadyTime::nowMs().count();
- if (interest_seg > rtc::MIN_PROBE_SEQ) {
- DLOG_IF(INFO, VLOG_IS_ON(3)) << "Received probe " << interest_seg;
- sendNack(interest_seg);
- return;
+ switch (rtc::ProbeHandler::getProbeType(interest_seg)) {
+ case rtc::ProbeType::INIT:
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Received init probe " << interest_seg;
+ sendManifestProbe(interest_seg);
+ return;
+ case rtc::ProbeType::RTT:
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Received RTT probe " << interest_seg;
+ sendNack(interest_seg);
+ return;
+ default:
+ break;
}
// if the production rate 0 use delayed nacks
@@ -349,7 +621,7 @@ void RTCProductionProtocol::processInterest(uint32_t interest_seg,
next_timer = timers_map_.begin()->first;
}
- uint64_t expiration = now + rtc::SENTINEL_TIMER_INTERVAL;
+ uint64_t expiration = now + rtc::NACK_DELAY;
addToInterestQueue(interest_seg, expiration);
// here we have at least one interest in the queue, we need to start or
@@ -369,8 +641,8 @@ void RTCProductionProtocol::processInterest(uint32_t interest_seg,
}
if (queue_timer_on_) {
- // the producer is producing. Send nacks to packets that will expire before
- // the data production and remove the timer
+ // the producer is producing. Send nacks to packets that will expire
+ // before the data production and remove the timer
queue_timer_on_ = false;
interests_queue_timer_->cancel();
sendNacksForPendingInterests();
@@ -387,8 +659,8 @@ void RTCProductionProtocol::processInterest(uint32_t interest_seg,
sendNack(interest_seg);
} else {
if (!consumer_in_sync_ && on_consumer_in_sync_) {
- // we consider the remote consumer to be in sync as soon as it covers 70%
- // of the production window with interests
+ // we consider the remote consumer to be in sync as soon as it covers
+ // 70% of the production window with interests
uint32_t perc = ceil((double)max_gap * 0.7);
if (interest_seg > (perc + current_seg_)) {
consumer_in_sync_ = true;
@@ -401,13 +673,18 @@ void RTCProductionProtocol::processInterest(uint32_t interest_seg,
}
}
-void RTCProductionProtocol::onError(std::error_code ec) {}
-
void RTCProductionProtocol::scheduleQueueTimer(uint64_t wait) {
interests_queue_timer_->expires_from_now(std::chrono::milliseconds(wait));
- interests_queue_timer_->async_wait([this](std::error_code ec) {
- if (ec) return;
- interestQueueTimer();
+ std::weak_ptr<RTCProductionProtocol> self = shared_from_this();
+ interests_queue_timer_->async_wait([self](const std::error_code &ec) {
+ if (ec) {
+ return;
+ }
+
+ auto sp = self.lock();
+ if (sp && sp->isRunning()) {
+ sp->interestQueueTimer();
+ }
});
}
@@ -450,9 +727,7 @@ void RTCProductionProtocol::sendNacksForPendingInterests() {
if (packets_production_rate_ != 0)
packet_gap = ceil(rtc::MILLI_IN_A_SEC / (double)packets_production_rate_);
- uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
+ uint64_t now = utils::SteadyTime::nowMs().count();
for (auto it = seqs_map_.begin(); it != seqs_map_.end(); it++) {
if (it->first > current_seg_) {
@@ -486,9 +761,7 @@ void RTCProductionProtocol::removeFromInterestQueue(uint32_t interest_seg) {
}
void RTCProductionProtocol::interestQueueTimer() {
- uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
+ uint64_t now = utils::SteadyTime::nowMs().count();
for (auto it_timers = timers_map_.begin(); it_timers != timers_map_.end();) {
uint64_t expire = it_timers->first;
@@ -511,20 +784,37 @@ void RTCProductionProtocol::interestQueueTimer() {
}
}
+void RTCProductionProtocol::sendManifestProbe(uint32_t sequence) {
+ Name manifest_name(flow_name_);
+ manifest_name.setSuffix(sequence);
+
+ std::shared_ptr<core::ContentObjectManifest> manifest_probe =
+ createManifest(manifest_name);
+
+ manifest_probe->setLifetime(0);
+ manifest_probe->setPathLabel(prod_label_);
+ manifest_probe->encode();
+
+ if (*on_content_object_output_) {
+ on_content_object_output_->operator()(*socket_->getInterface(),
+ *manifest_probe);
+ }
+
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Send init probe " << sequence;
+ sendContentObject(manifest_probe, true, false);
+}
+
void RTCProductionProtocol::sendNack(uint32_t sequence) {
auto nack = core::PacketManager<>::getInstance().getPacket<ContentObject>(
- signer_ ? Format::HF_INET6_TCP_AH : Format::HF_INET6_TCP,
- signer_ ? signer_->getSignatureFieldSize() : 0);
- uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
+ nack_header_format_.first, nack_header_format_.second);
+ uint64_t now = utils::SteadyTime::nowMs().count();
uint32_t next_packet = current_seg_;
uint32_t prod_rate = bytes_production_rate_;
struct rtc::nack_packet_t header;
header.setTimestamp(now);
header.setProductionRate(prod_rate);
- header.setProductionSegement(next_packet);
+ header.setProductionSegment(next_packet);
nack->appendPayload((const uint8_t *)&header, rtc::NACK_HEADER_SIZE);
Name n(flow_name_);
@@ -533,14 +823,16 @@ void RTCProductionProtocol::sendNack(uint32_t sequence) {
nack->setLifetime(0);
nack->setPathLabel(prod_label_);
- if (signer_) {
- signer_->signPacket(nack.get());
- }
-
if (!consumer_in_sync_ && on_consumer_in_sync_ &&
- sequence < rtc::MIN_PROBE_SEQ && sequence > next_packet) {
+ rtc::ProbeHandler::getProbeType(sequence) == rtc::ProbeType::NOT_PROBE &&
+ sequence > next_packet) {
consumer_in_sync_ = true;
- auto interest = core::PacketManager<>::getInstance().getPacket<Interest>();
+ Packet::Format format;
+ socket_->getSocketOption(interface::GeneralTransportOptions::PACKET_FORMAT,
+ format);
+
+ auto interest =
+ core::PacketManager<>::getInstance().getPacket<Interest>(format);
interest->setName(n);
on_consumer_in_sync_(*socket_->getInterface(), *interest);
}
@@ -550,16 +842,37 @@ void RTCProductionProtocol::sendNack(uint32_t sequence) {
}
DLOG_IF(INFO, VLOG_IS_ON(3)) << "Send nack " << sequence;
- portal_->sendContentObject(*nack);
+ sendContentObject(nack, true, false);
}
-void RTCProductionProtocol::onFecPackets(
- std::vector<std::pair<uint32_t, fec::buffer>> &packets) {
+void RTCProductionProtocol::sendContentObject(
+ std::shared_ptr<ContentObject> content_object, bool nack, bool fec) {
+ bool is_ah = _is_ah(content_object->getFormat());
+
+ // Compute signature
+ if (is_ah) {
+ signer_->signPacket(content_object.get());
+ }
+
+ portal_->sendContentObject(*content_object);
+
+ // Compute and save data packet digest
+ if (making_manifest_ && !is_ah) {
+ auth::CryptoHashType hash_algo;
+ socket_->getSocketOption(interface::GeneralTransportOptions::HASH_ALGORITHM,
+ hash_algo);
+ manifest_entries_.push({content_object->getName().getSuffix(),
+ content_object->computeDigest(hash_algo)});
+ }
+}
+
+void RTCProductionProtocol::onFecPackets(fec::BufferArray &packets) {
DLOG_IF(INFO, VLOG_IS_ON(3))
<< "Produced " << packets.size() << " FEC packets";
+
for (auto &packet : packets) {
auto content_object =
- std::static_pointer_cast<ContentObject>(packet.second);
+ std::static_pointer_cast<ContentObject>(packet.getBuffer());
content_object->prepend(content_object->headerSize() +
rtc::DATA_HEADER_SIZE);
pending_fec_packets_.push(std::move(content_object));
@@ -569,19 +882,21 @@ void RTCProductionProtocol::onFecPackets(
fec::buffer RTCProductionProtocol::getBuffer(std::size_t size) {
DLOG_IF(INFO, VLOG_IS_ON(3))
<< "Asked buffer for FEC symbol of size " << size;
+
auto ret = core::PacketManager<>::getInstance().getPacket<ContentObject>(
- signer_ ? Format::HF_INET6_TCP_AH : Format::HF_INET6_TCP,
- signer_ ? signer_->getSignatureFieldSize() : 0);
+ fec_header_format_.first, fec_header_format_.second);
+
ret->updateLength(rtc::DATA_HEADER_SIZE + size);
ret->append(rtc::DATA_HEADER_SIZE + size);
ret->trimStart(ret->headerSize() + rtc::DATA_HEADER_SIZE);
+
DLOG_IF(INFO, VLOG_IS_ON(3))
<< "Responding with buffer of length " << ret->length();
- assert(ret->length() >= size);
+ DCHECK(ret->length() >= size);
return ret;
}
} // namespace protocol
-} // end namespace transport
+} // namespace transport
diff --git a/libtransport/src/protocols/prod_protocol_rtc.h b/libtransport/src/protocols/prod_protocol_rtc.h
index 96ad5673d..7f50a2505 100644
--- a/libtransport/src/protocols/prod_protocol_rtc.h
+++ b/libtransport/src/protocols/prod_protocol_rtc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -32,6 +32,7 @@ class RTCProductionProtocol : public ProductionProtocol {
using ProductionProtocol::start;
using ProductionProtocol::stop;
+ void setProducerParam() override;
void produce(ContentObject &content_object) override;
uint32_t produceStream(const Name &content_name,
@@ -49,21 +50,31 @@ class RTCProductionProtocol : public ProductionProtocol {
buffer, buffer_size, buffer_size));
}
- void registerNamespaceWithNetwork(const Prefix &producer_namespace) override;
-
void setConsumerInSyncCallback(
interface::ProducerInterestCallback &&callback) {
on_consumer_in_sync_ = std::move(callback);
}
+ auto shared_from_this() { return utils::shared_from(this); }
+
private:
// packet handlers
void onInterest(Interest &interest) override;
- void onError(std::error_code ec) override;
+ void onError(const std::error_code &ec) override{};
void processInterest(uint32_t interest_seg, uint32_t lifetime);
+ void producePktInternal(std::shared_ptr<ContentObject> &&content_object,
+ const Name &content_name, bool fec = false);
void produceInternal(std::shared_ptr<ContentObject> &&content_object,
const Name &content_name, bool fec = false);
void sendNack(uint32_t sequence);
+ void sendContentObject(std::shared_ptr<ContentObject> content_object,
+ bool nac = false, bool fec = false);
+
+ // manifests
+ void sendManifestProbe(uint32_t sequence);
+ void sendManifest(const Name &content_name);
+ std::shared_ptr<core::ContentObjectManifest> createManifest(
+ const Name &name) const;
// stats
void updateStats();
@@ -77,15 +88,25 @@ class RTCProductionProtocol : public ProductionProtocol {
void interestQueueTimer();
// FEC functions
- void onFecPackets(std::vector<std::pair<uint32_t, fec::buffer>> &packets);
+ void onFecPackets(fec::BufferArray &packets);
fec::buffer getBuffer(std::size_t size);
+ void postponeFecPacket();
+ void dispatchFecPacket();
+ void flushFecPkts(uint32_t current_seq_num);
+ // aggregated data functions
+ void emptyQueue();
+ void addPacketToQueue(std::unique_ptr<utils::MemBuf> &&buffer);
core::Name flow_name_;
- uint32_t current_seg_; // seq id of the next packet produced
- uint32_t prod_label_; // path lable of the producer
- uint32_t cache_label_; // path lable for content from the producer cache
- uint16_t data_header_size_; // hicn data header size
+ std::pair<core::Packet::Format, size_t> data_header_format_;
+ std::pair<core::Packet::Format, size_t> manifest_header_format_;
+ std::pair<core::Packet::Format, size_t> fec_header_format_;
+ std::pair<core::Packet::Format, size_t> nack_header_format_;
+
+ uint32_t current_seg_; // seq id of the next packet produced
+ uint32_t prod_label_; // path label of the producer
+ uint32_t cache_label_; // path label for content from the producer cache
uint32_t produced_bytes_; // bytes produced in the last round
uint32_t produced_packets_; // packet produed in the last round
@@ -98,7 +119,11 @@ class RTCProductionProtocol : public ProductionProtocol {
uint32_t packets_production_rate_; // pps
uint32_t fec_packets_production_rate_; // pps
+ uint64_t last_produced_data_ts_; // ms
+
std::unique_ptr<asio::steady_timer> round_timer_;
+ std::unique_ptr<asio::steady_timer> fec_pacing_timer_;
+
uint64_t last_round_;
// delayed nacks are used by the producer to avoid to send too
@@ -131,6 +156,21 @@ class RTCProductionProtocol : public ProductionProtocol {
// Save FEC packets here before sending them
std::queue<ContentObject::Ptr> pending_fec_packets_;
+ std::queue<std::pair<uint64_t, ContentObject::Ptr>> paced_fec_packets_;
+ bool pending_fec_pace_;
+
+ // Save application packets if they are small
+ std::queue<std::unique_ptr<utils::MemBuf>> waiting_app_packets_;
+ uint16_t max_len_; // len of the largest packet
+ uint16_t queue_len_; // total size of all packet in the queue
+ bool data_aggregation_; // turns on/off data aggregation
+ // timer to check the queue len
+ std::unique_ptr<asio::steady_timer> app_packets_timer_;
+ bool data_aggregation_timer_switch_; // bool to check if the timer is on
+
+ // Manifest
+ std::queue<std::pair<uint32_t, auth::CryptoHash>>
+ manifest_entries_; // map a packet suffix to a packet hash
};
} // namespace protocol
diff --git a/libtransport/src/protocols/production_protocol.cc b/libtransport/src/protocols/production_protocol.cc
index 6b317d47d..8b781e38a 100644
--- a/libtransport/src/protocols/production_protocol.cc
+++ b/libtransport/src/protocols/production_protocol.cc
@@ -24,8 +24,8 @@ using namespace interface;
ProductionProtocol::ProductionProtocol(
implementation::ProducerSocket *icn_socket)
- : socket_(icn_socket),
- is_running_(false),
+ : Protocol(),
+ socket_(icn_socket),
fec_encoder_(nullptr),
on_interest_input_(VOID_HANDLER),
on_interest_dropped_input_buffer_(VOID_HANDLER),
@@ -38,101 +38,92 @@ ProductionProtocol::ProductionProtocol(
on_content_object_output_(VOID_HANDLER),
on_content_object_evicted_from_output_buffer_(VOID_HANDLER),
on_content_produced_(VOID_HANDLER),
+ producer_callback_(VOID_HANDLER),
fec_type_(fec::FECType::UNKNOWN) {
socket_->getSocketOption(GeneralTransportOptions::PORTAL, portal_);
// TODO add statistics for producer
// socket_->getSocketOption(OtherOptions::STATISTICS, &stats_);
}
-ProductionProtocol::~ProductionProtocol() {
- if (!is_async_ && is_running_) {
- stop();
- }
+ProductionProtocol::~ProductionProtocol() {}
- if (listening_thread_.joinable()) {
- listening_thread_.join();
+int ProductionProtocol::start() {
+ if (isRunning()) {
+ return -1;
}
-}
-int ProductionProtocol::start() {
- socket_->getSocketOption(ProducerCallbacksOptions::INTEREST_INPUT,
- &on_interest_input_);
- socket_->getSocketOption(ProducerCallbacksOptions::INTEREST_DROP,
- &on_interest_dropped_input_buffer_);
- socket_->getSocketOption(ProducerCallbacksOptions::INTEREST_PASS,
- &on_interest_inserted_input_buffer_);
- socket_->getSocketOption(ProducerCallbacksOptions::CACHE_HIT,
- &on_interest_satisfied_output_buffer_);
- socket_->getSocketOption(ProducerCallbacksOptions::CACHE_MISS,
- &on_interest_process_);
- socket_->getSocketOption(ProducerCallbacksOptions::NEW_CONTENT_OBJECT,
- &on_new_segment_);
- socket_->getSocketOption(ProducerCallbacksOptions::CONTENT_OBJECT_READY,
- &on_content_object_in_output_buffer_);
- socket_->getSocketOption(ProducerCallbacksOptions::CONTENT_OBJECT_OUTPUT,
- &on_content_object_output_);
- socket_->getSocketOption(ProducerCallbacksOptions::CONTENT_OBJECT_TO_SIGN,
- &on_content_object_to_sign_);
- socket_->getSocketOption(ProducerCallbacksOptions::CONTENT_PRODUCED,
- &on_content_produced_);
-
- socket_->getSocketOption(GeneralTransportOptions::ASYNC_MODE, is_async_);
- socket_->getSocketOption(GeneralTransportOptions::SIGNER, signer_);
- socket_->getSocketOption(GeneralTransportOptions::MAKE_MANIFEST,
- making_manifest_);
-
- 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_->getThread().addAndWaitForExecution([this]() {
+ socket_->getSocketOption(ProducerCallbacksOptions::INTEREST_INPUT,
+ &on_interest_input_);
+ socket_->getSocketOption(ProducerCallbacksOptions::INTEREST_DROP,
+ &on_interest_dropped_input_buffer_);
+ socket_->getSocketOption(ProducerCallbacksOptions::INTEREST_PASS,
+ &on_interest_inserted_input_buffer_);
+ socket_->getSocketOption(ProducerCallbacksOptions::CACHE_HIT,
+ &on_interest_satisfied_output_buffer_);
+ socket_->getSocketOption(ProducerCallbacksOptions::CACHE_MISS,
+ &on_interest_process_);
+ socket_->getSocketOption(ProducerCallbacksOptions::NEW_CONTENT_OBJECT,
+ &on_new_segment_);
+ socket_->getSocketOption(ProducerCallbacksOptions::CONTENT_OBJECT_READY,
+ &on_content_object_in_output_buffer_);
+ socket_->getSocketOption(ProducerCallbacksOptions::CONTENT_OBJECT_OUTPUT,
+ &on_content_object_output_);
+ socket_->getSocketOption(ProducerCallbacksOptions::CONTENT_OBJECT_TO_SIGN,
+ &on_content_object_to_sign_);
+ socket_->getSocketOption(ProducerCallbacksOptions::CONTENT_PRODUCED,
+ &on_content_produced_);
+ socket_->getSocketOption(ProducerCallbacksOptions::PRODUCER_CALLBACK,
+ &producer_callback_);
+
+ socket_->getSocketOption(GeneralTransportOptions::ASYNC_MODE, is_async_);
+ socket_->getSocketOption(GeneralTransportOptions::SIGNER, signer_);
+ socket_->getSocketOption(GeneralTransportOptions::MAKE_MANIFEST,
+ making_manifest_);
+
+ std::string fec_type_str = "";
+ socket_->getSocketOption(GeneralTransportOptions::FEC_TYPE, fec_type_str);
+ if (fec_type_str != "") {
+ fec_type_ = fec::FECUtils::fecTypeFromString(fec_type_str.c_str());
}
- }
- is_running_ = true;
+ portal_->registerTransportCallback(this);
+ setProducerParam();
- if (!is_async_) {
- listening_thread_ = std::thread([this]() { portal_->runEventsLoop(); });
- }
+ setRunning();
+ });
return 0;
}
-void ProductionProtocol::stop() {
- is_running_ = false;
-
- if (!is_async_) {
- portal_->stopEventsLoop();
- } else {
- portal_->clear();
- }
-}
-
void ProductionProtocol::produce(ContentObject &content_object) {
- if (*on_content_object_in_output_buffer_) {
- on_content_object_in_output_buffer_->operator()(*socket_->getInterface(),
- content_object);
- }
+ auto content_object_ptr = content_object.shared_from_this();
+ portal_->getThread().add([this, co = std::move(content_object_ptr)]() {
+ if (*on_content_object_in_output_buffer_) {
+ on_content_object_in_output_buffer_->operator()(*socket_->getInterface(),
+ *co);
+ }
- output_buffer_.insert(std::static_pointer_cast<ContentObject>(
- content_object.shared_from_this()));
+ output_buffer_.insert(co);
- if (*on_content_object_output_) {
- on_content_object_output_->operator()(*socket_->getInterface(),
- content_object);
- }
+ if (*on_content_object_output_) {
+ on_content_object_output_->operator()(*socket_->getInterface(), *co);
+ }
- portal_->sendContentObject(content_object);
+ portal_->sendContentObject(*co);
+ });
}
-void ProductionProtocol::registerNamespaceWithNetwork(
- const Prefix &producer_namespace) {
- served_namespaces_.push_back(producer_namespace);
+void ProductionProtocol::sendMapme() { portal_->sendMapme(); }
+
+void ProductionProtocol::onError(const std::error_code &ec) {
+ // Stop production protocol
+ stop();
+
+ // Call error callback
+ if (producer_callback_) {
+ producer_callback_->produceError(ec);
+ }
}
} // namespace protocol
diff --git a/libtransport/src/protocols/production_protocol.h b/libtransport/src/protocols/production_protocol.h
index 7366311eb..8e10d2f40 100644
--- a/libtransport/src/protocols/production_protocol.h
+++ b/libtransport/src/protocols/production_protocol.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -22,6 +22,7 @@
#include <implementation/socket.h>
#include <protocols/fec_base.h>
#include <protocols/fec_utils.h>
+#include <protocols/protocol.h>
#include <utils/content_store.h>
#include <atomic>
@@ -33,17 +34,20 @@ namespace protocol {
using namespace core;
-class ProductionProtocol : public Portal::ProducerCallback {
+class ProductionProtocol
+ : public Protocol,
+ public std::enable_shared_from_this<ProductionProtocol> {
public:
ProductionProtocol(implementation::ProducerSocket *icn_socket);
virtual ~ProductionProtocol();
- bool isRunning() { return is_running_; }
-
virtual int start();
- virtual void stop();
+ using Protocol::stop;
+
+ virtual void setProducerParam(){};
virtual void produce(ContentObject &content_object);
+ virtual void sendMapme();
virtual uint32_t produceStream(const Name &content_name,
std::unique_ptr<utils::MemBuf> &&buffer,
bool is_last = true,
@@ -61,20 +65,18 @@ class ProductionProtocol : public Portal::ProducerCallback {
void setOutputBufferSize(std::size_t size) { output_buffer_.setLimit(size); }
std::size_t getOutputBufferSize() { return output_buffer_.getLimit(); }
- virtual void registerNamespaceWithNetwork(const Prefix &producer_namespace);
- const std::list<Prefix> &getNamespaces() const { return served_namespaces_; }
-
protected:
// Producer callback
virtual void onInterest(core::Interest &i) override = 0;
- virtual void onError(std::error_code ec) override{};
+ virtual void onError(const std::error_code &ec) override;
template <typename FECHandler, typename AllocatorHandler>
void enableFEC(FECHandler &&fec_handler,
AllocatorHandler &&allocator_handler) {
if (!fec_encoder_) {
// Try to get FEC from environment
- if (const char *fec_str = std::getenv("TRANSPORT_FEC_TYPE")) {
+ const char *fec_str = std::getenv("TRANSPORT_FEC_TYPE");
+ if (fec_str && (fec_type_ == fec::FECType::UNKNOWN)) {
LOG(INFO) << "Using FEC " << fec_str;
fec_type_ = fec::FECUtils::fecTypeFromString(fec_str);
}
@@ -95,11 +97,6 @@ class ProductionProtocol : public Portal::ProducerCallback {
// Thread pool responsible for IO operations (send data / receive interests)
std::vector<utils::EventThread> io_threads_;
-
- // TODO remove this thread
- std::thread listening_thread_;
- std::shared_ptr<Portal> portal_;
- std::atomic<bool> is_running_;
interface::ProductionStatistics *stats_;
std::unique_ptr<fec::ProducerFEC> fec_encoder_;
@@ -119,15 +116,14 @@ class ProductionProtocol : public Portal::ProducerCallback {
interface::ProducerContentCallback *on_content_produced_;
+ interface::ProducerSocket::Callback *producer_callback_;
+
// Output buffer
utils::ContentStore output_buffer_;
- // List ot routes served by current producer protocol
- std::list<Prefix> served_namespaces_;
-
// Signature and manifest
std::shared_ptr<auth::Signer> signer_;
- bool making_manifest_;
+ uint32_t making_manifest_;
bool is_async_;
fec::FECType fec_type_;
diff --git a/libtransport/src/protocols/protocol.h b/libtransport/src/protocols/protocol.h
new file mode 100644
index 000000000..a9f929db9
--- /dev/null
+++ b/libtransport/src/protocols/protocol.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <core/portal.h>
+#include <hicn/transport/errors/runtime_exception.h>
+#include <hicn/transport/utils/noncopyable.h>
+
+#include <random>
+
+namespace transport {
+
+namespace protocol {
+
+class Protocol : public core::Portal::TransportCallback, utils::NonCopyable {
+ public:
+ virtual void stop() {
+ portal_->getThread().addAndWaitForExecution([this]() {
+ unSetRunning();
+ portal_->unregisterTransportCallback();
+ portal_->clear();
+ });
+ }
+
+ virtual void onInterest(core::Interest &i) {
+ throw errors::RuntimeException("Not implemented");
+ }
+
+ virtual void onContentObject(core::Interest &i, core::ContentObject &c) {
+ throw errors::RuntimeException("Not implemented");
+ }
+
+ virtual void onTimeout(core::Interest::Ptr &i, const core::Name &n) {
+ throw errors::RuntimeException("Not implemented");
+ }
+
+ virtual void onError(const std::error_code &ec) {
+ throw errors::RuntimeException("Not implemented");
+ }
+
+ bool isRunning() { return is_running_; }
+ void setRunning() { is_running_ = true; }
+ void unSetRunning() { is_running_ = false; }
+
+ protected:
+ Protocol() : portal_(nullptr), is_running_(false), gen_(rd_()) {}
+ virtual ~Protocol() {}
+
+ protected:
+ std::shared_ptr<core::Portal> portal_;
+ std::atomic_bool is_running_;
+
+ // Random engine
+ std::random_device rd_;
+ std::mt19937 gen_;
+};
+
+} // namespace protocol
+
+} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/protocols/raaqm.cc b/libtransport/src/protocols/raaqm.cc
index 1247af400..131367d78 100644
--- a/libtransport/src/protocols/raaqm.cc
+++ b/libtransport/src/protocols/raaqm.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -36,8 +36,9 @@ RaaqmTransportProtocol::RaaqmTransportProtocol(
current_window_size_(1),
interests_in_flight_(0),
cur_path_(nullptr),
- t0_(utils::SteadyClock::now()),
+ t0_(utils::SteadyTime::Clock::now()),
rate_estimator_(nullptr),
+ dis_(0, 1.0),
schedule_interests_(true) {
init();
}
@@ -60,7 +61,7 @@ void RaaqmTransportProtocol::reset() {
// Reset protocol variables
interests_in_flight_ = 0;
- t0_ = utils::SteadyClock::now();
+ t0_ = utils::SteadyTime::Clock::now();
// Optionally reset congestion window
bool reset_window;
@@ -389,6 +390,8 @@ void RaaqmTransportProtocol::sendInterest(
uint32_t len) {
interests_in_flight_++;
interest_retransmissions_[interest_name.getSuffix() & mask]++;
+ interest_timepoints_[interest_name.getSuffix() & mask] =
+ utils::SteadyTime::Clock::now();
TransportProtocol::sendInterest(interest_name, additional_suffixes, len);
}
@@ -477,7 +480,7 @@ void RaaqmTransportProtocol::scheduleNextInterests() {
}
}
-void RaaqmTransportProtocol::onContentReassembled(std::error_code ec) {
+void RaaqmTransportProtocol::onContentReassembled(const std::error_code &ec) {
rate_estimator_->onDownloadFinished();
TransportProtocol::onContentReassembled(ec);
schedule_interests_ = false;
@@ -487,18 +490,18 @@ 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<utils::Microseconds>(
- now - interest_timepoints_[segment & mask]);
+ auto now = utils::SteadyTime::Clock::now();
+ utils::SteadyTime::Milliseconds rtt = utils::SteadyTime::getDurationMs(
+ interest_timepoints_[segment & mask], now);
// Update stats
- updateStats((uint32_t)segment, rtt.count(), now);
+ updateStats((uint32_t)segment, rtt, now);
if (rate_estimator_) {
- rate_estimator_->onRttUpdate((double)rtt.count());
+ rate_estimator_->onRttUpdate(rtt);
}
- cur_path_->insertNewRtt(rtt.count(), now);
+ cur_path_->insertNewRtt(rtt, now);
cur_path_->smoothTimer();
if (cur_path_->newPropagationDelayAvailable()) {
@@ -510,27 +513,27 @@ void RaaqmTransportProtocol::updateRtt(uint64_t segment) {
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));
+ double coin = dis_(gen_);
if (coin <= cur_path_->getDropProb()) {
decreaseWindow();
}
}
}
-void RaaqmTransportProtocol::updateStats(uint32_t suffix, uint64_t rtt,
- utils::TimePoint &now) {
+void RaaqmTransportProtocol::updateStats(
+ uint32_t suffix, const utils::SteadyTime::Milliseconds &rtt,
+ utils::SteadyTime::TimePoint &now) {
// Update RTT statistics
stats_->updateAverageRtt(rtt);
stats_->updateAverageWindowSize(current_window_size_);
// Call statistics callback
if (*stats_summary_) {
- auto dt = std::chrono::duration_cast<utils::Milliseconds>(now - t0_);
+ auto dt = utils::SteadyTime::getDurationMs(t0_, now);
uint32_t timer_interval_milliseconds = 0;
socket_->getSocketOption(GeneralTransportOptions::STATS_INTERVAL,
diff --git a/libtransport/src/protocols/raaqm.h b/libtransport/src/protocols/raaqm.h
index ffbb30d3a..ec344c23a 100644
--- a/libtransport/src/protocols/raaqm.h
+++ b/libtransport/src/protocols/raaqm.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -23,6 +23,7 @@
#include <protocols/transport_protocol.h>
#include <queue>
+#include <random>
#include <vector>
namespace transport {
@@ -55,8 +56,9 @@ class RaaqmTransportProtocol : public TransportProtocol,
const ContentObject &content_object);
virtual void afterDataUnsatisfied(uint64_t segment);
- virtual void updateStats(uint32_t suffix, uint64_t rtt,
- utils::TimePoint &now);
+ virtual void updateStats(uint32_t suffix,
+ const utils::SteadyTime::Milliseconds &rtt,
+ utils::SteadyTime::TimePoint &now);
private:
void init();
@@ -73,7 +75,7 @@ class RaaqmTransportProtocol : public TransportProtocol,
*additional_suffixes = nullptr,
uint32_t len = 0) override;
- void onContentReassembled(std::error_code ec) override;
+ void onContentReassembled(const std::error_code &ec) override;
void updateRtt(uint64_t segment);
void RAAQM();
void updatePathTable(const ContentObject &content_object);
@@ -81,13 +83,15 @@ class RaaqmTransportProtocol : public TransportProtocol,
void checkForStalePaths();
void printRtt();
+ auto shared_from_this() { return utils::shared_from(this); }
+
protected:
// Congestion window management
double current_window_size_;
// Protocol management
uint64_t interests_in_flight_;
std::array<std::uint32_t, buffer_size> interest_retransmissions_;
- std::array<utils::TimePoint, buffer_size> interest_timepoints_;
+ std::array<utils::SteadyTime::TimePoint, buffer_size> interest_timepoints_;
std::queue<uint32_t> interest_to_retransmit_;
private:
@@ -102,13 +106,16 @@ class RaaqmTransportProtocol : public TransportProtocol,
PathTable path_table_;
// TimePoints for statistic
- utils::TimePoint t0_;
+ utils::SteadyTime::TimePoint t0_;
bool set_interest_filter_;
// for rate-estimation at packet level
IcnRateEstimator *rate_estimator_;
+ // Real distribution
+ std::uniform_real_distribution<> dis_;
+
// params for autotuning
bool raaqm_autotune_;
double default_beta_;
diff --git a/libtransport/src/protocols/raaqm_data_path.cc b/libtransport/src/protocols/raaqm_data_path.cc
index f2c21b9ef..d06fee918 100644
--- a/libtransport/src/protocols/raaqm_data_path.cc
+++ b/libtransport/src/protocols/raaqm_data_path.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -23,16 +23,18 @@ 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)
+ const utils::SteadyTime::Milliseconds &new_rtt,
+ const utils::SteadyTime::Milliseconds &new_rtt_min,
+ const utils::SteadyTime::Milliseconds &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),
+ rtt_(new_rtt.count()),
+ rtt_min_(new_rtt_min.count()),
+ rtt_max_(new_rtt_max.count()),
prop_delay_(new_pd),
new_prop_delay_(false),
drop_prob_(0),
@@ -43,14 +45,15 @@ RaaqmDataPath::RaaqmDataPath(double drop_factor,
raw_data_bytes_received_(0),
last_raw_data_bytes_received_(0),
rtt_samples_(samples_),
- last_received_pkt_(utils::SteadyClock::now()),
+ last_received_pkt_(utils::SteadyTime::Clock::now()),
average_rtt_(0),
alpha_(ALPHA) {}
-RaaqmDataPath &RaaqmDataPath::insertNewRtt(uint64_t new_rtt,
- const utils::TimePoint &now) {
- rtt_ = new_rtt;
- rtt_samples_.pushBack(new_rtt);
+RaaqmDataPath &RaaqmDataPath::insertNewRtt(
+ const utils::SteadyTime::Milliseconds &new_rtt,
+ const utils::SteadyTime::TimePoint &now) {
+ rtt_ = new_rtt.count();
+ rtt_samples_.pushBack(rtt_);
rtt_max_ = rtt_samples_.rBegin();
rtt_min_ = rtt_samples_.begin();
@@ -143,10 +146,8 @@ unsigned int RaaqmDataPath::getPropagationDelay() {
}
bool RaaqmDataPath::isStale() {
- utils::TimePoint now = utils::SteadyClock::now();
- auto time =
- std::chrono::duration_cast<utils::Microseconds>(now - last_received_pkt_)
- .count();
+ utils::SteadyTime::TimePoint now = utils::SteadyTime::Clock::now();
+ auto time = utils::SteadyTime::getDurationUs(last_received_pkt_, now).count();
if (time > 2000000) {
return true;
}
diff --git a/libtransport/src/protocols/raaqm_data_path.h b/libtransport/src/protocols/raaqm_data_path.h
index c0b53a690..b6f7c5ac1 100644
--- a/libtransport/src/protocols/raaqm_data_path.h
+++ b/libtransport/src/protocols/raaqm_data_path.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -34,8 +34,13 @@ 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);
+ const utils::SteadyTime::Milliseconds &new_rtt =
+ utils::SteadyTime::Milliseconds(1000),
+ const utils::SteadyTime::Milliseconds &new_rtt_min =
+ utils::SteadyTime::Milliseconds(1000),
+ const utils::SteadyTime::Milliseconds &new_rtt_max =
+ utils::SteadyTime::Milliseconds(1000),
+ unsigned new_pd = UINT_MAX);
public:
/*
@@ -44,7 +49,8 @@ class RaaqmDataPath {
* max of RTT.
* @param new_rtt is the value of the new RTT
*/
- RaaqmDataPath &insertNewRtt(uint64_t new_rtt, const utils::TimePoint &now);
+ RaaqmDataPath &insertNewRtt(const utils::SteadyTime::Milliseconds &new_rtt,
+ const utils::SteadyTime::TimePoint &now);
/**
* @brief Update the path statistics
@@ -214,7 +220,7 @@ class RaaqmDataPath {
/**
* Time of the last call to the path reporter method
*/
- utils::TimePoint last_received_pkt_;
+ utils::SteadyTime::TimePoint last_received_pkt_;
double average_rtt_;
double alpha_;
diff --git a/libtransport/src/protocols/rate_estimation.cc b/libtransport/src/protocols/rate_estimation.cc
index 2337e18be..d834b53e6 100644
--- a/libtransport/src/protocols/rate_estimation.cc
+++ b/libtransport/src/protocols/rate_estimation.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -14,6 +14,7 @@
*/
#include <glog/logging.h>
+#include <hicn/transport/errors/runtime_exception.h>
#include <hicn/transport/interfaces/socket_options_default_values.h>
#include <protocols/rate_estimation.h>
@@ -92,8 +93,8 @@ InterRttEstimator::InterRttEstimator(double alpha_arg) {
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();
+ this->start_time_ = utils::SteadyTime::now();
+ this->begin_batch_ = utils::SteadyTime::now();
}
InterRttEstimator::~InterRttEstimator() {
@@ -105,33 +106,35 @@ InterRttEstimator::~InterRttEstimator() {
pthread_mutex_destroy(&(this->mutex_));
}
-void InterRttEstimator::onRttUpdate(double rtt) {
+void InterRttEstimator::onRttUpdate(
+ const utils::SteadyTime::Milliseconds &rtt) {
pthread_mutex_lock(&(this->mutex_));
- this->rtt_ = rtt;
+ this->rtt_ = rtt.count();
this->number_of_packets_++;
- this->avg_rtt_ += rtt;
+ this->avg_rtt_ += this->rtt_;
pthread_mutex_unlock(&(this->mutex_));
if (!thread_is_running_) {
my_th_ = (pthread_t *)malloc(sizeof(pthread_t));
if (!my_th_) {
- LOG(ERROR) << "Error allocating thread.";
- my_th_ = NULL;
+ throw errors::RuntimeException("Error allocating thread.");
}
- if (/*int err = */ pthread_create(my_th_, NULL, transport::protocol::Timer,
- (void *)this)) {
- LOG(ERROR) << "Error creating the thread";
+
+ if (pthread_create(my_th_, NULL, transport::protocol::Timer,
+ (void *)this)) {
+ free(my_th_);
my_th_ = NULL;
+ throw errors::RuntimeException("Error allocating thread.");
}
+
thread_is_running_ = true;
}
}
void InterRttEstimator::onWindowIncrease(double win_current) {
- TimePoint end = std::chrono::steady_clock::now();
+ auto end = utils::SteadyTime::now();
auto delay =
- std::chrono::duration_cast<Microseconds>(end - this->begin_batch_)
- .count();
+ utils::SteadyTime::getDurationUs(this->begin_batch_, end).count();
pthread_mutex_lock(&(this->mutex_));
this->avg_win_ += this->win_current_ * delay;
@@ -139,14 +142,13 @@ void InterRttEstimator::onWindowIncrease(double win_current) {
this->win_change_ += delay;
pthread_mutex_unlock(&(this->mutex_));
- this->begin_batch_ = std::chrono::steady_clock::now();
+ this->begin_batch_ = utils::SteadyTime::now();
}
void InterRttEstimator::onWindowDecrease(double win_current) {
- TimePoint end = std::chrono::steady_clock::now();
+ auto end = utils::SteadyTime::now();
auto delay =
- std::chrono::duration_cast<Microseconds>(end - this->begin_batch_)
- .count();
+ utils::SteadyTime::getDurationUs(this->begin_batch_, end).count();
pthread_mutex_lock(&(this->mutex_));
this->avg_win_ += this->win_current_ * delay;
@@ -154,25 +156,24 @@ void InterRttEstimator::onWindowDecrease(double win_current) {
this->win_change_ += delay;
pthread_mutex_unlock(&(this->mutex_));
- this->begin_batch_ = std::chrono::steady_clock::now();
+ this->begin_batch_ = utils::SteadyTime::now();
}
ALaTcpEstimator::ALaTcpEstimator() {
this->estimation_ = 0.0;
this->observer_ = NULL;
- this->start_time_ = std::chrono::steady_clock::now();
+ this->start_time_ = utils::SteadyTime::now();
this->totalSize_ = 0.0;
}
void ALaTcpEstimator::onStart() {
this->totalSize_ = 0.0;
- this->start_time_ = std::chrono::steady_clock::now();
+ this->start_time_ = utils::SteadyTime::now();
}
void ALaTcpEstimator::onDownloadFinished() {
- TimePoint end = std::chrono::steady_clock::now();
- auto delay =
- std::chrono::duration_cast<Microseconds>(end - this->start_time_).count();
+ auto end = utils::SteadyTime::now();
+ auto delay = utils::SteadyTime::getDurationUs(this->start_time_, end).count();
this->estimation_ = this->totalSize_ * 8 * 1000000 / delay;
if (observer_) {
observer_->notifyStats(this->estimation_);
@@ -192,22 +193,21 @@ SimpleEstimator::SimpleEstimator(double alphaArg, int batching_param) {
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();
+ this->start_time_ = utils::SteadyTime::now();
+ this->begin_batch_ = utils::SteadyTime::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();
+ this->start_time_ = utils::SteadyTime::now();
+ this->begin_batch_ = utils::SteadyTime::now();
}
void SimpleEstimator::onDownloadFinished() {
- TimePoint end = std::chrono::steady_clock::now();
- auto delay =
- std::chrono::duration_cast<Microseconds>(end - this->start_time_).count();
+ auto end = utils::SteadyTime::now();
+ auto delay = utils::SteadyTime::getDurationUs(this->start_time_, end).count();
if (observer_) {
observer_->notifyDownloadTime((double)delay);
}
@@ -229,8 +229,7 @@ void SimpleEstimator::onDownloadFinished() {
} else {
if (this->number_of_packets_ >=
(int)(75.0 * (double)this->batching_param_ / 100.0)) {
- delay = std::chrono::duration_cast<Microseconds>(end - this->begin_batch_)
- .count();
+ delay = utils::SteadyTime::getDurationUs(this->begin_batch_, end).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_) {
@@ -249,22 +248,21 @@ void SimpleEstimator::onDownloadFinished() {
}
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();
+ this->start_time_ = utils::SteadyTime::now();
+ this->begin_batch_ = utils::SteadyTime::now();
}
void SimpleEstimator::onDataReceived(int packet_size) {
this->total_size_ += packet_size;
}
-void SimpleEstimator::onRttUpdate(double rtt) {
+void SimpleEstimator::onRttUpdate(const utils::SteadyTime::Milliseconds &rtt) {
this->number_of_packets_++;
if (this->number_of_packets_ == this->batching_param_) {
- TimePoint end = std::chrono::steady_clock::now();
+ auto end = utils::SteadyTime::now();
auto delay =
- std::chrono::duration_cast<Microseconds>(end - this->begin_batch_)
- .count();
+ utils::SteadyTime::getDurationUs(this->begin_batch_, end).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_) {
@@ -280,7 +278,7 @@ void SimpleEstimator::onRttUpdate(double rtt) {
this->alpha_ = this->base_alpha_;
this->number_of_packets_ = 0;
this->total_size_ = 0.0;
- this->begin_batch_ = std::chrono::steady_clock::now();
+ this->begin_batch_ = utils::SteadyTime::now();
}
}
@@ -297,13 +295,14 @@ BatchingPacketsEstimator::BatchingPacketsEstimator(double alpha_arg,
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();
+ this->begin_batch_ = utils::SteadyTime::now();
+ this->start_time_ = utils::SteadyTime::now();
}
-void BatchingPacketsEstimator::onRttUpdate(double rtt) {
+void BatchingPacketsEstimator::onRttUpdate(
+ const utils::SteadyTime::Milliseconds &rtt) {
this->number_of_packets_++;
- this->avg_rtt_ += rtt;
+ this->avg_rtt_ += rtt.count();
if (number_of_packets_ == this->batching_param_) {
if (estimation_ == 0) {
@@ -329,25 +328,23 @@ void BatchingPacketsEstimator::onRttUpdate(double rtt) {
}
void BatchingPacketsEstimator::onWindowIncrease(double win_current) {
- TimePoint end = std::chrono::steady_clock::now();
+ auto end = utils::SteadyTime::now();
auto delay =
- std::chrono::duration_cast<Microseconds>(end - this->begin_batch_)
- .count();
+ utils::SteadyTime::getDurationUs(this->begin_batch_, end).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();
+ this->begin_batch_ = utils::SteadyTime::now();
}
void BatchingPacketsEstimator::onWindowDecrease(double win_current) {
- TimePoint end = std::chrono::steady_clock::now();
+ auto end = utils::SteadyTime::now();
auto delay =
- std::chrono::duration_cast<Microseconds>(end - this->begin_batch_)
- .count();
+ utils::SteadyTime::getDurationUs(this->begin_batch_, end).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();
+ this->begin_batch_ = utils::SteadyTime::now();
}
} // end namespace protocol
diff --git a/libtransport/src/protocols/rate_estimation.h b/libtransport/src/protocols/rate_estimation.h
index 42ae74194..b71de12e4 100644
--- a/libtransport/src/protocols/rate_estimation.h
+++ b/libtransport/src/protocols/rate_estimation.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -16,6 +16,7 @@
#pragma once
#include <hicn/transport/interfaces/statistics.h>
+#include <hicn/transport/utils/noncopyable.h>
#include <protocols/raaqm_data_path.h>
#include <chrono>
@@ -24,16 +25,13 @@ namespace transport {
namespace protocol {
-class IcnRateEstimator {
+class IcnRateEstimator : utils::NonCopyable {
public:
- using TimePoint = std::chrono::steady_clock::time_point;
- using Microseconds = std::chrono::microseconds;
-
IcnRateEstimator(){};
virtual ~IcnRateEstimator(){};
- virtual void onRttUpdate(double rtt){};
+ virtual void onRttUpdate(const utils::SteadyTime::Milliseconds &rtt){};
virtual void onDataReceived(int packetSize){};
@@ -48,9 +46,10 @@ class IcnRateEstimator {
virtual void setObserver(interface::IcnObserver *observer) {
this->observer_ = observer;
};
+
interface::IcnObserver *observer_;
- TimePoint start_time_;
- TimePoint begin_batch_;
+ utils::SteadyTime::TimePoint start_time_;
+ utils::SteadyTime::TimePoint begin_batch_;
double base_alpha_;
double alpha_;
double estimation_;
@@ -67,7 +66,7 @@ class InterRttEstimator : public IcnRateEstimator {
~InterRttEstimator();
- void onRttUpdate(double rtt);
+ void onRttUpdate(const utils::SteadyTime::Milliseconds &rtt);
void onDataReceived(int packet_size) {
if (packet_size > this->max_packet_size_) {
@@ -102,7 +101,7 @@ class BatchingPacketsEstimator : public IcnRateEstimator {
public:
BatchingPacketsEstimator(double alpha_arg, int batchingParam);
- void onRttUpdate(double rtt);
+ void onRttUpdate(const utils::SteadyTime::Milliseconds &rtt);
void onDataReceived(int packet_size) {
if (packet_size > this->max_packet_size_) {
@@ -149,7 +148,7 @@ class SimpleEstimator : public IcnRateEstimator {
public:
SimpleEstimator(double alpha, int batching_param);
- void onRttUpdate(double rtt);
+ void onRttUpdate(const utils::SteadyTime::Milliseconds &rtt);
void onDataReceived(int packet_size);
diff --git a/libtransport/src/protocols/reassembly.cc b/libtransport/src/protocols/reassembly.cc
index ce24fce1b..065458f7e 100644
--- a/libtransport/src/protocols/reassembly.cc
+++ b/libtransport/src/protocols/reassembly.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/protocols/reassembly.h b/libtransport/src/protocols/reassembly.h
index e072ad123..b0879201d 100644
--- a/libtransport/src/protocols/reassembly.h
+++ b/libtransport/src/protocols/reassembly.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -36,7 +36,7 @@ class Reassembly {
public:
class ContentReassembledCallback {
public:
- virtual void onContentReassembled(std::error_code ec) = 0;
+ virtual void onContentReassembled(const std::error_code &ec) = 0;
};
Reassembly(implementation::ConsumerSocket *icn_socket,
@@ -47,12 +47,12 @@ class Reassembly {
virtual ~Reassembly() = default;
/**
- * Hanle reassembly of content object.
+ * Handle reassembly of content object.
*/
virtual void reassemble(core::ContentObject &content_object) = 0;
/**
- * Hanle reassembly of content object.
+ * Handle reassembly of content object.
*/
virtual void reassemble(utils::MemBuf &buffer, uint32_t suffix) = 0;
diff --git a/libtransport/src/protocols/rtc/CMakeLists.txt b/libtransport/src/protocols/rtc/CMakeLists.txt
index 873b345d0..be8e0189c 100644
--- a/libtransport/src/protocols/rtc/CMakeLists.txt
+++ b/libtransport/src/protocols/rtc/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2019 Cisco and/or its affiliates.
+# Copyright (c) 2021 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
@@ -16,22 +16,43 @@ list(APPEND HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/rtc.h
${CMAKE_CURRENT_SOURCE_DIR}/rtc_consts.h
${CMAKE_CURRENT_SOURCE_DIR}/rtc_data_path.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_forwarding_strategy.h
${CMAKE_CURRENT_SOURCE_DIR}/rtc_indexer.h
${CMAKE_CURRENT_SOURCE_DIR}/rtc_ldr.h
${CMAKE_CURRENT_SOURCE_DIR}/rtc_packet.h
${CMAKE_CURRENT_SOURCE_DIR}/rtc_rc.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_rc_congestion_detection.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_rc_iat.h
${CMAKE_CURRENT_SOURCE_DIR}/rtc_rc_queue.h
${CMAKE_CURRENT_SOURCE_DIR}/rtc_reassembly.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_recovery_strategy.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_rs_delay.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_rs_fec_only.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_rs_low_rate.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_rs_recovery_off.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_rs_rtx_only.h
${CMAKE_CURRENT_SOURCE_DIR}/rtc_state.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_verifier.h
)
list(APPEND SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/probe_handler.cc
${CMAKE_CURRENT_SOURCE_DIR}/rtc.cc
${CMAKE_CURRENT_SOURCE_DIR}/rtc_data_path.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_forwarding_strategy.cc
${CMAKE_CURRENT_SOURCE_DIR}/rtc_ldr.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_rc_congestion_detection.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_rc_iat.cc
${CMAKE_CURRENT_SOURCE_DIR}/rtc_rc_queue.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_reassembly.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_recovery_strategy.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_rs_delay.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_rs_fec_only.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_rs_low_rate.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_rs_recovery_off.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_rs_rtx_only.cc
${CMAKE_CURRENT_SOURCE_DIR}/rtc_state.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_verifier.cc
)
set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
diff --git a/libtransport/src/protocols/rtc/probe_handler.cc b/libtransport/src/protocols/rtc/probe_handler.cc
index abaca6ad9..abb234757 100644
--- a/libtransport/src/protocols/rtc/probe_handler.cc
+++ b/libtransport/src/protocols/rtc/probe_handler.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2021 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -13,6 +13,7 @@
* limitations under the License.
*/
+#include <hicn/transport/utils/chrono_typedefs.h>
#include <protocols/rtc/probe_handler.h>
#include <protocols/rtc/rtc_consts.h>
@@ -27,6 +28,7 @@ ProbeHandler::ProbeHandler(SendProbeCallback &&send_callback,
: probe_interval_(0),
max_probes_(0),
sent_probes_(0),
+ recv_probes_(0),
probe_timer_(std::make_unique<asio::steady_timer>(io_service)),
rand_eng_((std::random_device())()),
distr_(MIN_RTT_PROBE_SEQ, MAX_RTT_PROBE_SEQ),
@@ -39,17 +41,25 @@ uint64_t ProbeHandler::getRtt(uint32_t seq) {
if (it == pending_probes_.end()) return 0;
- uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
+ uint64_t now = utils::SteadyTime::nowMs().count();
uint64_t rtt = now - it->second;
if (rtt < 1) rtt = 1;
pending_probes_.erase(it);
+ recv_probes_++;
return rtt;
}
+double ProbeHandler::getProbeLossRate() {
+ return 1.0 - ((double)recv_probes_ / (double)sent_probes_);
+}
+
+void ProbeHandler::setSuffixRange(uint32_t min, uint32_t max) {
+ assert(min <= max && min >= MIN_PROBE_SEQ);
+ distr_ = std::uniform_int_distribution<uint32_t>(min, max);
+}
+
void ProbeHandler::setProbes(uint32_t probe_interval, uint32_t max_probes) {
stopProbes();
probe_interval_ = probe_interval;
@@ -60,6 +70,7 @@ void ProbeHandler::stopProbes() {
probe_interval_ = 0;
max_probes_ = 0;
sent_probes_ = 0;
+ recv_probes_ = 0;
probe_timer_->cancel();
}
@@ -67,9 +78,7 @@ void ProbeHandler::sendProbes() {
if (probe_interval_ == 0) return;
if (max_probes_ != 0 && sent_probes_ >= max_probes_) return;
- uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
+ uint64_t now = utils::SteadyTime::nowMs().count();
uint32_t seq = distr_(rand_eng_);
pending_probes_.insert(std::pair<uint32_t, uint64_t>(seq, now));
@@ -92,14 +101,25 @@ void ProbeHandler::sendProbes() {
std::weak_ptr<ProbeHandler> self(shared_from_this());
probe_timer_->expires_from_now(std::chrono::microseconds(probe_interval_));
- probe_timer_->async_wait([self](std::error_code ec) {
+ probe_timer_->async_wait([self](const std::error_code &ec) {
if (ec) return;
- if (auto s = self.lock()) {
+ auto s = self.lock();
+ if (s) {
s->sendProbes();
}
});
}
+ProbeType ProbeHandler::getProbeType(uint32_t seq) {
+ if (MIN_INIT_PROBE_SEQ <= seq && seq <= MAX_INIT_PROBE_SEQ) {
+ return ProbeType::INIT;
+ }
+ if (MIN_RTT_PROBE_SEQ <= seq && seq <= MAX_RTT_PROBE_SEQ) {
+ return ProbeType::RTT;
+ }
+ return ProbeType::NOT_PROBE;
+}
+
} // namespace rtc
} // namespace protocol
diff --git a/libtransport/src/protocols/rtc/probe_handler.h b/libtransport/src/protocols/rtc/probe_handler.h
index e34b23df0..2de908176 100644
--- a/libtransport/src/protocols/rtc/probe_handler.h
+++ b/libtransport/src/protocols/rtc/probe_handler.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2021 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -26,6 +26,12 @@ namespace protocol {
namespace rtc {
+enum class ProbeType {
+ NOT_PROBE,
+ INIT,
+ RTT,
+};
+
class ProbeHandler : public std::enable_shared_from_this<ProbeHandler> {
public:
using SendProbeCallback = std::function<void(uint32_t)>;
@@ -35,31 +41,39 @@ class ProbeHandler : public std::enable_shared_from_this<ProbeHandler> {
~ProbeHandler();
- // if the function returns 0 the probe is not valaid
+ // If the function returns 0 the probe is not valid.
uint64_t getRtt(uint32_t seq);
- // reset the probes parameters. it stop the current probing.
- // to restar call sendProbes.
- // probe_interval = 0 means that no event will be scheduled
- // max_probe = 0 means no limit to the number of probe to send
+ // this function may return a residual loss rate higher than the real one if
+ // we don't wait enough time for the probes to come back
+ double getProbeLossRate();
+
+ // Set the probe suffix range [min, max]
+ void setSuffixRange(uint32_t min, uint32_t max);
+
+ // Reset the probes parameters and stops the current probing.
+ // probe_interval = 0 means that no event will be scheduled.
+ // max_probe = 0 means no limit to the number of probe to send.
void setProbes(uint32_t probe_interval, uint32_t max_probes);
- // stop to schedule probes
void stopProbes();
void sendProbes();
+ static ProbeType getProbeType(uint32_t seq);
+
private:
uint32_t probe_interval_; // us
uint32_t max_probes_; // packets
uint32_t sent_probes_; // packets
+ uint32_t recv_probes_; // packets
std::unique_ptr<asio::steady_timer> probe_timer_;
- // map from seqnumber to timestamp
+ // Map from packet suffixes to timestamp
std::unordered_map<uint32_t, uint64_t> pending_probes_;
- // random generator
+ // Random generator
std::default_random_engine rand_eng_;
std::uniform_int_distribution<uint32_t> distr_;
diff --git a/libtransport/src/protocols/rtc/rtc.cc b/libtransport/src/protocols/rtc/rtc.cc
index 0cb4cda1d..df6522471 100644
--- a/libtransport/src/protocols/rtc/rtc.cc
+++ b/libtransport/src/protocols/rtc/rtc.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -22,7 +22,7 @@
#include <protocols/rtc/rtc.h>
#include <protocols/rtc/rtc_consts.h>
#include <protocols/rtc/rtc_indexer.h>
-#include <protocols/rtc/rtc_rc_queue.h>
+#include <protocols/rtc/rtc_rc_congestion_detection.h>
#include <algorithm>
@@ -37,13 +37,15 @@ using namespace interface;
RTCTransportProtocol::RTCTransportProtocol(
implementation::ConsumerSocket *icn_socket)
: TransportProtocol(icn_socket, new RtcIndexer<>(icn_socket, this),
- new DatagramReassembly(icn_socket, this)),
+ new RtcReassembly(icn_socket, this)),
number_(0) {
icn_socket->getSocketOption(PORTAL, portal_);
- round_timer_ = std::make_unique<asio::steady_timer>(portal_->getIoService());
+ round_timer_ =
+ std::make_unique<asio::steady_timer>(portal_->getThread().getIoService());
scheduler_timer_ =
- std::make_unique<asio::steady_timer>(portal_->getIoService());
- pacing_timer_ = std::make_unique<asio::steady_timer>(portal_->getIoService());
+ std::make_unique<asio::steady_timer>(portal_->getThread().getIoService());
+ pacing_timer_ =
+ std::make_unique<asio::steady_timer>(portal_->getThread().getIoService());
}
RTCTransportProtocol::~RTCTransportProtocol() {}
@@ -61,25 +63,52 @@ std::size_t RTCTransportProtocol::transportHeaderLength() {
// private
void RTCTransportProtocol::initParams() {
TransportProtocol::reset();
+ fwd_strategy_.setCallback(on_fwd_strategy_);
- rc_ = std::make_shared<RTCRateControlQueue>();
+ std::weak_ptr<RTCTransportProtocol> self = shared_from_this();
+
+ std::shared_ptr<auth::Verifier> verifier;
+ socket_->getSocketOption(GeneralTransportOptions::VERIFIER, verifier);
+
+ uint32_t max_unverified_delay;
+ socket_->getSocketOption(GeneralTransportOptions::MAX_UNVERIFIED_TIME,
+ max_unverified_delay);
+
+ rc_ = std::make_shared<RTCRateControlCongestionDetection>();
ldr_ = std::make_shared<RTCLossDetectionAndRecovery>(
- indexer_verifier_.get(),
- std::bind(&RTCTransportProtocol::sendRtxInterest, this,
- std::placeholders::_1),
- portal_->getIoService());
+ indexer_verifier_.get(), portal_->getThread().getIoService(),
+ interface::RtcTransportRecoveryStrategies::RTX_ONLY,
+ [self](uint32_t seq) {
+ auto ptr = self.lock();
+ if (ptr && ptr->isRunning()) {
+ ptr->sendRtxInterest(seq);
+ }
+ },
+ on_rec_strategy_);
+ verifier_ = std::make_shared<RTCVerifier>(verifier, max_unverified_delay);
state_ = std::make_shared<RTCState>(
indexer_verifier_.get(),
- std::bind(&RTCTransportProtocol::sendProbeInterest, this,
- std::placeholders::_1),
- std::bind(&RTCTransportProtocol::discoveredRtt, this),
- portal_->getIoService());
+ [self](uint32_t seq) {
+ auto ptr = self.lock();
+ if (ptr && ptr->isRunning()) {
+ ptr->sendProbeInterest(seq);
+ }
+ },
+ [self]() {
+ auto ptr = self.lock();
+ if (ptr && ptr->isRunning()) {
+ ptr->discoveredRtt();
+ }
+ },
+ portal_->getThread().getIoService());
+ state_->initParams();
rc_->setState(state_);
- // TODO: for the moment we keep the congestion control disabled
- // rc_->tunrOnRateControl();
- ldr_->setState(state_);
+ rc_->turnOnRateControl();
+ ldr_->setState(state_.get());
+ ldr_->setRateControl(rc_.get());
+ verifier_->setState(state_);
// protocol state
start_send_interest_ = false;
@@ -102,6 +131,10 @@ void RTCTransportProtocol::initParams() {
}
#else
max_aggregated_interest_ = 1;
+ if (const char *max_aggr = std::getenv("MAX_AGGREGATED_INTERESTS")) {
+ LOG(INFO) << "Max Aggregated: " << max_aggr;
+ max_aggregated_interest_ = std::stoul(std::string(max_aggr));
+ }
#endif
max_sent_int_ =
@@ -131,6 +164,7 @@ void RTCTransportProtocol::initParams() {
indexer_verifier_->setNFec(0);
ldr_->setFecParams(fec::FECUtils::getBlockSymbols(fec_type_),
fec::FECUtils::getSourceSymbols(fec_type_));
+ fec_decoder_->setIOService(portal_->getThread().getIoService());
} else {
indexer_verifier_->disableFec();
}
@@ -162,61 +196,97 @@ void RTCTransportProtocol::inactiveProducer() {
void RTCTransportProtocol::newRound() {
round_timer_->expires_from_now(std::chrono::milliseconds(ROUND_LEN));
- // TODO pass weak_ptr here
- round_timer_->async_wait([this, n{number_}](std::error_code ec) {
- if (ec) return;
- if (n != number_) {
+ std::weak_ptr<RTCTransportProtocol> self = shared_from_this();
+ round_timer_->async_wait([self](const std::error_code &ec) {
+ if (ec) {
return;
}
+ auto ptr = self.lock();
+
+ if (!ptr || !ptr->isRunning()) {
+ return;
+ }
+
+ auto &state = ptr->state_;
+
// saving counters that will be reset on new round
- uint32_t sent_retx = state_->getSentRtxInRound();
- uint32_t received_bytes = state_->getReceivedBytesInRound();
- uint32_t sent_interest = state_->getSentInterestInRound();
- uint32_t lost_data = state_->getLostData();
- uint32_t definitely_lost = state_->getDefinitelyLostPackets();
- uint32_t recovered_losses = state_->getRecoveredLosses();
- uint32_t received_nacks = state_->getReceivedNacksInRound();
- uint32_t received_fec = state_->getReceivedFecPackets();
-
- bool in_sync = (current_state_ == SyncState::in_sync);
- ldr_->onNewRound(in_sync);
- state_->onNewRound((double)ROUND_LEN, in_sync);
- rc_->onNewRound((double)ROUND_LEN);
+ uint32_t sent_retx = state->getSentRtxInRound();
+ uint32_t received_bytes =
+ (state->getReceivedBytesInRound() + // data packets received
+ state->getReceivedFecBytesInRound()); // fec packets received
+ uint32_t sent_interest = state->getSentInterestInRound();
+ uint32_t lost_data = state->getLostData();
+ uint32_t definitely_lost = state->getDefinitelyLostPackets();
+ uint32_t recovered_losses = state->getRecoveredLosses();
+ uint32_t received_nacks = state->getReceivedNacksInRound();
+ uint32_t received_fec = state->getReceivedFecPackets();
+
+ bool in_sync = (ptr->current_state_ == SyncState::in_sync);
+ ptr->ldr_->onNewRound(in_sync);
+ ptr->state_->onNewRound((double)ROUND_LEN, in_sync);
+ ptr->rc_->onNewRound((double)ROUND_LEN);
// update sync state if needed
- if (current_state_ == SyncState::in_sync) {
- double cache_rate = state_->getPacketFromCacheRatio();
+ if (ptr->current_state_ == SyncState::in_sync) {
+ double cache_rate = state->getPacketFromCacheRatio();
if (cache_rate > MAX_DATA_FROM_CACHE) {
- current_state_ = SyncState::catch_up;
+ ptr->current_state_ = SyncState::catch_up;
}
} else {
- double target_rate = state_->getProducerRate() * PRODUCTION_RATE_FRACTION;
- double received_rate = state_->getReceivedRate();
- uint32_t round_without_nacks = state_->getRoundsWithoutNacks();
- double cache_ratio = state_->getPacketFromCacheRatio();
+ double target_rate = state->getProducerRate() * PRODUCTION_RATE_FRACTION;
+ double received_rate =
+ state->getReceivedRate() + state->getRecoveredFecRate();
+ uint32_t round_without_nacks = state->getRoundsWithoutNacks();
+ double cache_ratio = state->getPacketFromCacheRatio();
if (round_without_nacks >= ROUNDS_IN_SYNC_BEFORE_SWITCH &&
received_rate >= target_rate && cache_ratio < MAX_DATA_FROM_CACHE) {
- current_state_ = SyncState::in_sync;
+ ptr->current_state_ = SyncState::in_sync;
}
}
DLOG_IF(INFO, VLOG_IS_ON(3))
<< "Calling updateSyncWindow in newRound function";
- updateSyncWindow();
+ ptr->updateSyncWindow();
- sendStatsToApp(sent_retx, received_bytes, sent_interest, lost_data,
- definitely_lost, recovered_losses, received_nacks,
- received_fec);
- newRound();
+ ptr->sendStatsToApp(sent_retx, received_bytes, sent_interest, lost_data,
+ definitely_lost, recovered_losses, received_nacks,
+ received_fec);
+ ptr->fwd_strategy_.checkStrategy();
+ ptr->newRound();
});
}
void RTCTransportProtocol::discoveredRtt() {
start_send_interest_ = true;
- ldr_->turnOnRTX();
+ uint32_t strategy;
+ socket_->getSocketOption(RtcTransportOptions::RECOVERY_STRATEGY, strategy);
+ ldr_->changeRecoveryStrategy(
+ (interface::RtcTransportRecoveryStrategies)strategy);
+ ldr_->turnOnRecovery();
ldr_->onNewRound(false);
+
+ // set forwarding strategy switch if selected
+ Name *name = nullptr;
+ socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME, &name);
+ Prefix prefix(*name, 128);
+ if ((interface::RtcTransportRecoveryStrategies)strategy ==
+ interface::RtcTransportRecoveryStrategies::LOW_RATE_AND_BESTPATH) {
+ fwd_strategy_.initFwdStrategy(portal_, prefix, state_.get(),
+ RTCForwardingStrategy::BEST_PATH);
+ } else if ((interface::RtcTransportRecoveryStrategies)strategy ==
+ interface::RtcTransportRecoveryStrategies::
+ LOW_RATE_AND_REPLICATION) {
+ fwd_strategy_.initFwdStrategy(portal_, prefix, state_.get(),
+ RTCForwardingStrategy::REPLICATION);
+ } else if ((interface::RtcTransportRecoveryStrategies)strategy ==
+ interface::RtcTransportRecoveryStrategies::
+ LOW_RATE_AND_ALL_FWD_STRATEGIES) {
+ fwd_strategy_.initFwdStrategy(portal_, prefix, state_.get(),
+ RTCForwardingStrategy::BOTH);
+ }
+
updateSyncWindow();
}
@@ -244,7 +314,7 @@ void RTCTransportProtocol::computeMaxSyncWindow() {
(production_rate * lifetime_ms * INTEREST_LIFETIME_REDUCTION_FACTOR) /
packet_size);
- max_sync_win_ = std::min(max_sync_win_, rc_->getCongesionWindow());
+ max_sync_win_ = std::min(max_sync_win_, rc_->getCongestionWindow());
}
void RTCTransportProtocol::updateSyncWindow() {
@@ -259,25 +329,14 @@ void RTCTransportProtocol::updateSyncWindow() {
}
double prod_rate = state_->getProducerRate();
- double rtt = (double)state_->getRTT() / MILLI_IN_A_SEC;
+ double rtt = (double)state_->getMinRTT() / MILLI_IN_A_SEC;
double packet_size = state_->getAveragePacketSize();
// if some of the info are not available do not update the current win
if (prod_rate != 0.0 && rtt != 0.0 && packet_size != 0.0) {
- double fec_interest_overhead = (double)state_->getPendingFecPackets() /
- (double)(state_->getPendingInterestNumber() -
- state_->getPendingFecPackets());
-
- double fec_overhead =
- std::max(indexer_verifier_->getFecOverhead(), fec_interest_overhead);
-
- prod_rate += (prod_rate * fec_overhead);
-
current_sync_win_ = (uint32_t)ceil(prod_rate * rtt / packet_size);
uint32_t buffer = PRODUCER_BUFFER_MS;
- if (rtt > 150)
- buffer = buffer * 2; // if the RTT is too large we increase the
- // the size of the buffer
+
current_sync_win_ +=
ceil(prod_rate * (buffer / MILLI_IN_A_SEC) / packet_size);
@@ -285,8 +344,17 @@ void RTCTransportProtocol::updateSyncWindow() {
current_sync_win_ = current_sync_win_ * CATCH_UP_WIN_INCREMENT;
}
+ uint32_t min_win = WIN_MIN;
+ bool aggregated_data_on;
+ socket_->getSocketOption(RtcTransportOptions::AGGREGATED_DATA,
+ aggregated_data_on);
+ if (aggregated_data_on) {
+ min_win = WIN_MIN_WITH_AGGREGARED_DATA;
+ min_win += (min_win * (1 - (std::max(0.3, rtt) - rtt) / 0.3));
+ }
+
current_sync_win_ = std::min(current_sync_win_, max_sync_win_);
- current_sync_win_ = std::max(current_sync_win_, WIN_MIN);
+ current_sync_win_ = std::max(current_sync_win_, min_win);
}
scheduleNextInterests();
@@ -322,7 +390,7 @@ void RTCTransportProtocol::sendProbeInterest(uint32_t seq) {
socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME,
&interest_name);
- DLOG_IF(INFO, VLOG_IS_ON(3)) << "send probe " << seq;
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Send probe " << seq;
interest_name->setSuffix(seq);
sendInterest(*interest_name);
}
@@ -330,13 +398,18 @@ void RTCTransportProtocol::sendProbeInterest(uint32_t seq) {
void RTCTransportProtocol::scheduleNextInterests() {
DLOG_IF(INFO, VLOG_IS_ON(3)) << "Schedule next interests";
- if (!isRunning() && !is_first_) return;
+ if (!isRunning() && !is_first_) {
+ return;
+ }
- if (pacing_timer_on_) return; // wait pacing timer for the next send
+ if (pacing_timer_on_) {
+ return; // wait pacing timer for the next send
+ }
- if (!start_send_interest_)
+ if (!start_send_interest_) {
return; // RTT discovering phase is not finished so
// do not start to send interests
+ }
if (TRANSPORT_EXPECT_FALSE(!state_->isProducerActive())) {
DLOG_IF(INFO, VLOG_IS_ON(3)) << "Inactive producer.";
@@ -352,7 +425,7 @@ void RTCTransportProtocol::scheduleNextInterests() {
&interest_name);
uint32_t next_seg = 0;
- DLOG_IF(INFO, VLOG_IS_ON(3)) << "send interest " << next_seg;
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Send interest " << next_seg;
interest_name->setSuffix(next_seg);
if (portal_->interestIsPending(*interest_name)) {
@@ -370,28 +443,37 @@ void RTCTransportProtocol::scheduleNextInterests() {
<< " -- current_sync_win_: " << current_sync_win_;
uint32_t pending = state_->getPendingInterestNumber();
- if (pending >= current_sync_win_) return; // no space in the window
+ uint32_t pending_fec = state_->getPendingFecPackets();
+
+ if ((pending - pending_fec) >= current_sync_win_)
+ return; // no space in the window
- if ((current_sync_win_ - pending) < max_aggregated_interest_) {
+ // XXX double check if aggregated interests are still working here
+ if ((current_sync_win_ - (pending - pending_fec)) <
+ max_aggregated_interest_) {
if (scheduler_timer_on_) return; // timer already scheduled
- uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
+ uint64_t now = utils::SteadyTime::nowMs().count();
uint64_t time = now - last_interest_sent_time_;
if (time < WAIT_FOR_INTEREST_BATCH) {
uint64_t next = WAIT_FOR_INTEREST_BATCH - time;
scheduler_timer_on_ = true;
scheduler_timer_->expires_from_now(std::chrono::milliseconds(next));
- scheduler_timer_->async_wait([this](std::error_code ec) {
+
+ std::weak_ptr<RTCTransportProtocol> self = shared_from_this();
+ scheduler_timer_->async_wait([self](const std::error_code &ec) {
if (ec) return;
- if (!scheduler_timer_on_) return;
- scheduler_timer_on_ = false;
- scheduleNextInterests();
+ auto ptr = self.lock();
+ if (ptr && ptr->isRunning()) {
+ if (!ptr->scheduler_timer_on_) return;
+
+ ptr->scheduler_timer_on_ = false;
+ ptr->scheduleNextInterests();
+ }
});
- return; // whait for the timer
+ return; // wait for the timer
}
}
@@ -403,7 +485,7 @@ void RTCTransportProtocol::scheduleNextInterests() {
indexer_verifier_->jumpToIndex(state_->getLastSeqNacked() + 1);
}
- // skipe received packets
+ // skip received packets
if (indexer_verifier_->checkNextSuffix() <=
state_->getHighestSeqReceivedInOrder()) {
indexer_verifier_->jumpToIndex(state_->getHighestSeqReceivedInOrder() + 1);
@@ -417,7 +499,8 @@ void RTCTransportProtocol::scheduleNextInterests() {
socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME, &name);
std::array<uint32_t, MAX_AGGREGATED_INTEREST> additional_suffixes;
- while ((state_->getPendingInterestNumber() < current_sync_win_) &&
+ while (((state_->getPendingInterestNumber() -
+ state_->getPendingFecPackets()) < current_sync_win_) &&
(sent_interests < max_sent_int_)) {
DLOG_IF(INFO, VLOG_IS_ON(3))
<< "In while loop. Window size: " << current_sync_win_;
@@ -428,19 +511,20 @@ void RTCTransportProtocol::scheduleNextInterests() {
// send the packet only if:
// 1) it is not pending yet (not true for rtx)
- // 2) the packet is not received or lost
+ // 2) the packet is not received or def lost
// 3) is not in the rtx list
// 4) is fec and is not in order (!= last sent + 1)
+ PacketState packet_state = state_->getPacketState(next_seg);
if (portal_->interestIsPending(*name) ||
- state_->isReceivedOrLost(next_seg) != PacketState::UNKNOWN ||
- ldr_->isRtx(next_seg) ||
+ packet_state == PacketState::RECEIVED ||
+ packet_state == PacketState::DEFINITELY_LOST || ldr_->isRtx(next_seg) ||
(indexer_verifier_->isFec(next_seg) &&
next_seg != last_interest_sent_seq_ + 1)) {
DLOG_IF(INFO, VLOG_IS_ON(3))
<< "skip interest " << next_seg << " because: pending "
- << portal_->interestIsPending(*name) << ", recv "
- << (state_->isReceivedOrLost(next_seg) != PacketState::UNKNOWN)
- << ", rtx " << (ldr_->isRtx(next_seg)) << ", is old fec "
+ << portal_->interestIsPending(*name) << ", recv or lost"
+ << (int)packet_state << ", rtx " << (ldr_->isRtx(next_seg))
+ << ", is old fec "
<< ((indexer_verifier_->isFec(next_seg) &&
next_seg != last_interest_sent_seq_ + 1));
continue;
@@ -462,10 +546,7 @@ void RTCTransportProtocol::scheduleNextInterests() {
sent_packets++;
sent_interests++;
sendInterest(interest_name, &additional_suffixes, aggregated_counter - 1);
- last_interest_sent_time_ =
- std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
+ last_interest_sent_time_ = utils::SteadyTime::nowMs().count();
aggregated_counter = 0;
}
}
@@ -473,25 +554,29 @@ void RTCTransportProtocol::scheduleNextInterests() {
// exiting the while we may have some pending interest to send
if (aggregated_counter != 0) {
sent_packets++;
- last_interest_sent_time_ =
- std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
+ last_interest_sent_time_ = utils::SteadyTime::nowMs().count();
sendInterest(interest_name, &additional_suffixes, aggregated_counter - 1);
}
- if (state_->getPendingInterestNumber() < current_sync_win_) {
+ if ((state_->getPendingInterestNumber() - state_->getPendingFecPackets()) <
+ current_sync_win_) {
// we still have space in the window but we already sent too many packets
// wait PACING_WAIT to avoid drops in the kernel
pacing_timer_on_ = true;
pacing_timer_->expires_from_now(std::chrono::microseconds(PACING_WAIT));
- scheduler_timer_->async_wait([this](std::error_code ec) {
+
+ std::weak_ptr<RTCTransportProtocol> self = shared_from_this();
+ scheduler_timer_->async_wait([self](const std::error_code &ec) {
if (ec) return;
- if (!pacing_timer_on_) return;
- pacing_timer_on_ = false;
- scheduleNextInterests();
+ auto ptr = self.lock();
+ if (ptr && ptr->isRunning()) {
+ if (!ptr->pacing_timer_on_) return;
+
+ ptr->pacing_timer_on_ = false;
+ ptr->scheduleNextInterests();
+ }
});
}
}
@@ -500,13 +585,13 @@ void RTCTransportProtocol::onInterestTimeout(Interest::Ptr &interest,
const Name &name) {
uint32_t segment_number = name.getSuffix();
- if (segment_number >= MIN_PROBE_SEQ) {
+ if (ProbeHandler::getProbeType(segment_number) != ProbeType::NOT_PROBE) {
// this is a timeout on a probe, do nothing
return;
}
- PacketState state = state_->isReceivedOrLost(segment_number);
- if (state != PacketState::UNKNOWN) {
+ PacketState state = state_->getPacketState(segment_number);
+ if (state == PacketState::RECEIVED || state == PacketState::DEFINITELY_LOST) {
// we may recover a packets using fec, ignore this timer
return;
}
@@ -524,13 +609,18 @@ void RTCTransportProtocol::onInterestTimeout(Interest::Ptr &interest,
DLOG_IF(INFO, VLOG_IS_ON(3))
<< "handle timeout for packet " << segment_number << " using rtx";
if (ldr_->isRtxOn()) {
- ldr_->onTimeout(segment_number);
- if (indexer_verifier_->isFec(segment_number))
+ if (indexer_verifier_->isFec(segment_number)) {
+ // if this is a fec packet we do not recover it with rtx so we consider
+ // the packet to be lost
+ ldr_->onTimeout(segment_number, true);
state_->onTimeout(segment_number, true);
- else
+ } else {
+ ldr_->onTimeout(segment_number, false);
state_->onTimeout(segment_number, false);
+ }
} else {
// in this case we wil never recover the timeout
+ ldr_->onTimeout(segment_number, true);
state_->onTimeout(segment_number, true);
}
scheduleNextInterests();
@@ -559,7 +649,7 @@ void RTCTransportProtocol::onInterestTimeout(Interest::Ptr &interest,
void RTCTransportProtocol::onNack(const ContentObject &content_object) {
struct nack_packet_t *nack =
(struct nack_packet_t *)content_object.getPayload()->data();
- uint32_t production_seg = nack->getProductionSegement();
+ uint32_t production_seg = nack->getProductionSegment();
uint32_t nack_segment = content_object.getName().getSuffix();
bool is_rtx = ldr_->isRtx(nack_segment);
@@ -592,6 +682,8 @@ void RTCTransportProtocol::onNack(const ContentObject &content_object) {
// remove the nack is it exists
if (tn_it != timeouts_or_nacks_.end()) timeouts_or_nacks_.erase(tn_it);
+ state_->onJumpForward(production_seg);
+ verifier_->onJumpForward(production_seg);
// the client is asking for content in the past
// switch to catch up state and increase the window
// this is true only if the packet is not an RTX
@@ -618,11 +710,9 @@ void RTCTransportProtocol::onProbe(const ContentObject &content_object) {
bool valid = state_->onProbePacketReceived(content_object);
if (!valid) return;
- struct nack_packet_t *probe =
- (struct nack_packet_t *)content_object.getPayload()->data();
- uint32_t production_seg = probe->getProductionSegement();
+ uint32_t production_seg = RTCState::getProbeParams(content_object).prod_seg;
- // as for the nacks set next_segment
+ // As for the nacks set next_segment
DLOG_IF(INFO, VLOG_IS_ON(3))
<< "on probe next seg = " << indexer_verifier_->checkNextSuffix()
<< ", jump to " << production_seg;
@@ -636,12 +726,39 @@ void RTCTransportProtocol::onContentObjectReceived(
Interest &interest, ContentObject &content_object, std::error_code &ec) {
DLOG_IF(INFO, VLOG_IS_ON(3))
<< "Received content object of size: " << content_object.payloadSize();
- uint32_t payload_size = content_object.payloadSize();
+
uint32_t segment_number = content_object.getName().getSuffix();
+ PayloadType payload_type = content_object.getPayloadType();
+ PacketState state;
+
+ ContentObject *content_ptr = &content_object;
+ ContentObject::Ptr manifest_ptr = nullptr;
+
+ bool is_probe =
+ ProbeHandler::getProbeType(segment_number) != ProbeType::NOT_PROBE;
+ bool is_nack = !is_probe && content_object.payloadSize() == NACK_HEADER_SIZE;
+ bool is_fec = indexer_verifier_->isFec(segment_number);
+ bool is_manifest =
+ !is_probe && !is_nack && !is_fec && payload_type == PayloadType::MANIFEST;
+ bool is_data =
+ !is_probe && !is_nack && !is_fec && payload_type == PayloadType::DATA;
+ bool compute_stats = is_data || is_manifest;
ec = make_error_code(protocol_error::not_reassemblable);
- if (segment_number >= MIN_PROBE_SEQ) {
+ // A helper function to process manifests or data packets received
+ auto onDataPacketReceived = [this](ContentObject &content_object,
+ bool compute_stats) {
+ ldr_->onDataPacketReceived(content_object);
+ rc_->onDataPacketReceived(content_object, compute_stats);
+ updateSyncWindow();
+ };
+
+ // First verify the packet signature and apply the corresponding policy
+ auth::VerificationPolicy policy = verifier_->verify(content_object, is_fec);
+ indexer_verifier_->applyPolicy(interest, content_object, false, policy);
+
+ if (is_probe) {
DLOG_IF(INFO, VLOG_IS_ON(3)) << "Received probe " << segment_number;
if (*on_content_object_input_) {
(*on_content_object_input_)(*socket_->getInterface(), content_object);
@@ -650,7 +767,7 @@ void RTCTransportProtocol::onContentObjectReceived(
return;
}
- if (payload_size == NACK_HEADER_SIZE) {
+ if (is_nack) {
DLOG_IF(INFO, VLOG_IS_ON(3)) << "Received nack " << segment_number;
if (*on_content_object_input_) {
(*on_content_object_input_)(*socket_->getInterface(), content_object);
@@ -659,57 +776,122 @@ void RTCTransportProtocol::onContentObjectReceived(
return;
}
+ // content_ptr will point either to the input data packet or to a manifest
+ // whose FEC header has been removed
+ if (is_manifest) {
+ manifest_ptr = removeFecHeader(content_object);
+ if (manifest_ptr) {
+ content_ptr = manifest_ptr.get();
+ }
+ }
+
+ // From there, the packet is either a FEC, a manifest or a data packet.
DLOG_IF(INFO, VLOG_IS_ON(3)) << "Received content " << segment_number;
- bool compute_stats = true;
+ // Do not count timed out packets in stats
auto tn_it = timeouts_or_nacks_.find(segment_number);
if (tn_it != timeouts_or_nacks_.end()) {
compute_stats = false;
timeouts_or_nacks_.erase(tn_it);
}
- if (ldr_->isRtx(segment_number)) {
+
+ // Do not count retransmissions or losses in stats
+ if (ldr_->isRtx(segment_number) ||
+ ldr_->isPossibleLossWithNoRtx(segment_number)) {
compute_stats = false;
}
- // check if the packet was already received
- PacketState state = state_->isReceivedOrLost(segment_number);
+ // Fetch packet state
+ state = state_->getPacketState(segment_number);
- if (state != PacketState::RECEIVED) {
- // send packet to decoder
- if (fec_decoder_) {
- DLOG_IF(INFO, VLOG_IS_ON(4))
- << "send packet " << segment_number << " to FEC decoder";
- fec_decoder_->onDataPacket(
- content_object, content_object.headerSize() + rtc::DATA_HEADER_SIZE);
- }
- if (!indexer_verifier_->isFec(segment_number)) {
- // the packet may be alredy sent to the ap by the decoder, check again if
- // it is already received
- state = state_->isReceivedOrLost(segment_number);
- if (state != PacketState::RECEIVED) {
- DLOG_IF(INFO, VLOG_IS_ON(4)) << "Received content " << segment_number;
+ // Check if the packet is a retransmission
+ if (ldr_->isRtx(segment_number) && state != PacketState::RECEIVED) {
+ if (is_data || is_manifest) {
+ state_->onPacketRecoveredRtx(segment_number);
- state_->onDataPacketReceived(content_object, compute_stats);
+ if (*on_content_object_input_) {
+ (*on_content_object_input_)(*socket_->getInterface(), content_object);
+ }
- if (*on_content_object_input_) {
- (*on_content_object_input_)(*socket_->getInterface(), content_object);
- }
- ec = make_error_code(protocol_error::success);
+ if (is_manifest) {
+ processManifest(interest, *content_ptr);
}
- } else {
- DLOG_IF(INFO, VLOG_IS_ON(4)) << "Received fec " << segment_number;
- state_->onFecPacketReceived(content_object);
+
+ ec = is_manifest ? make_error_code(protocol_error::not_reassemblable)
+ : make_error_code(protocol_error::success);
+
+ // The packet is considered received, return early
+ onDataPacketReceived(*content_ptr, compute_stats);
+ return;
}
- } else {
+
+ if (is_fec) {
+ state_->onFecPacketRecoveredRtx(segment_number);
+ }
+ }
+
+ // Fetch packet state again; it may have changed
+ state = state_->getPacketState(segment_number);
+
+ // Check if the packet was already received
+ if (state == PacketState::RECEIVED || state == PacketState::TO_BE_RECEIVED) {
DLOG_IF(INFO, VLOG_IS_ON(3))
<< "Received duplicated content " << segment_number << ", drop it";
ec = make_error_code(protocol_error::duplicated_content);
+ onDataPacketReceived(*content_ptr, compute_stats);
+ return;
}
- ldr_->onDataPacketReceived(content_object);
- rc_->onDataPacketReceived(content_object);
+ if (!is_fec) {
+ state_->dataToBeReceived(segment_number);
+ }
- updateSyncWindow();
+ // Send packet to FEC decoder
+ if (fec_decoder_) {
+ DLOG_IF(INFO, VLOG_IS_ON(4))
+ << "Send packet " << segment_number << " to FEC decoder";
+
+ uint32_t offset = is_manifest
+ ? content_object.headerSize()
+ : content_object.headerSize() + rtc::DATA_HEADER_SIZE;
+ uint32_t metadata = static_cast<uint32_t>(content_object.getPayloadType());
+
+ fec_decoder_->onDataPacket(content_object, offset, metadata);
+ }
+
+ // We can return early if FEC
+ if (is_fec) {
+ DLOG_IF(INFO, VLOG_IS_ON(4)) << "Received FEC " << segment_number;
+ state_->onFecPacketReceived(content_object);
+ onDataPacketReceived(*content_ptr, compute_stats);
+ return;
+ }
+
+ // The packet may have been already sent to the app by the decoder, check
+ // again if it is already received
+ state = state_->getPacketState(
+ segment_number); // state == RECEIVED or TO_BE_RECEIVED
+
+ if (state != PacketState::RECEIVED) {
+ DLOG_IF(INFO, VLOG_IS_ON(4))
+ << (is_manifest ? "Received manifest " : "Received data ")
+ << segment_number;
+
+ if (is_manifest) {
+ processManifest(interest, *content_ptr);
+ }
+
+ state_->onDataPacketReceived(*content_ptr, compute_stats);
+
+ if (*on_content_object_input_) {
+ (*on_content_object_input_)(*socket_->getInterface(), content_object);
+ }
+
+ ec = is_manifest ? make_error_code(protocol_error::not_reassemblable)
+ : make_error_code(protocol_error::success);
+ }
+
+ onDataPacketReceived(*content_ptr, compute_stats);
}
void RTCTransportProtocol::sendStatsToApp(
@@ -729,33 +911,149 @@ void RTCTransportProtocol::sendStatsToApp(
stats_->updateReceivedNacks(received_nacks);
stats_->updateReceivedFEC(received_fec);
- stats_->updateAverageWindowSize(current_sync_win_);
- stats_->updateLossRatio(state_->getLossRate());
- stats_->updateAverageRtt(state_->getRTT());
+ stats_->updateAverageWindowSize(state_->getPendingInterestNumber());
+ stats_->updateLossRatio(state_->getPerSecondLossRate());
+ uint64_t rtt = state_->getAvgRTT();
+ stats_->updateAverageRtt(utils::SteadyTime::Milliseconds(rtt));
+
stats_->updateQueuingDelay(state_->getQueuing());
stats_->updateLostData(lost_data);
stats_->updateDefinitelyLostData(definitely_lost);
stats_->updateRecoveredData(recovered_losses);
stats_->updateCCState((unsigned int)current_state_ ? 1 : 0);
(*stats_summary_)(*socket_->getInterface(), *stats_);
+ bool in_congestion = rc_->inCongestionState();
+ stats_->updateCongestionState(in_congestion);
+ double residual_losses = state_->getResidualLossRate();
+ stats_->updateResidualLossRate(residual_losses);
+ stats_->updateQualityScore(state_->getQualityScore());
+
+ // set alerts
+ if (rtt > MAX_RTT)
+ stats_->setAlert(interface::TransportStatistics::statsAlerts::LATENCY);
+ else
+ stats_->clearAlert(interface::TransportStatistics::statsAlerts::LATENCY);
+
+ if (in_congestion)
+ stats_->setAlert(interface::TransportStatistics::statsAlerts::CONGESTION);
+ else
+ stats_->clearAlert(
+ interface::TransportStatistics::statsAlerts::CONGESTION);
+
+ if (residual_losses > MAX_RESIDUAL_LOSSES)
+ stats_->setAlert(interface::TransportStatistics::statsAlerts::LOSSES);
+ else
+ stats_->clearAlert(interface::TransportStatistics::statsAlerts::LOSSES);
}
}
-void RTCTransportProtocol::onFecPackets(
- std::vector<std::pair<uint32_t, fec::buffer>> &packets) {
+void RTCTransportProtocol::onFecPackets(fec::BufferArray &packets) {
+ Packet::Format format;
+ socket_->getSocketOption(interface::GeneralTransportOptions::PACKET_FORMAT,
+ format);
+
+ Name *name = nullptr;
+ socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME, &name);
+
for (auto &packet : packets) {
- PacketState state = state_->isReceivedOrLost(packet.first);
- if (state != PacketState::RECEIVED) {
- state_->onPacketRecoveredFec(packet.first);
- ldr_->onPacketRecoveredFec(packet.first);
- DLOG_IF(INFO, VLOG_IS_ON(3))
- << "Recovered packet " << packet.first << " through FEC.";
- reassembly_->reassemble(*packet.second, packet.first);
- } else {
- DLOG_IF(INFO, VLOG_IS_ON(3))
- << "Packet" << packet.first << "already received.";
+ uint32_t seq_number = packet.getIndex();
+ uint32_t metadata = packet.getMetadata();
+ fec::buffer buffer = packet.getBuffer();
+
+ PayloadType payload_type = static_cast<PayloadType>(metadata);
+ switch (payload_type) {
+ case PayloadType::DATA:
+ case PayloadType::MANIFEST:
+ break;
+ case PayloadType::UNSPECIFIED:
+ default:
+ payload_type = PayloadType::DATA;
+ break;
}
+
+ switch (state_->getPacketState(seq_number)) {
+ case PacketState::RECEIVED:
+ case PacketState::TO_BE_RECEIVED: {
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Packet " << seq_number << " already received";
+ break;
+ }
+ default: {
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Recovered packet " << seq_number << " through FEC";
+
+ if (payload_type == PayloadType::MANIFEST) {
+ name->setSuffix(seq_number);
+
+ auto interest =
+ core::PacketManager<>::getInstance().getPacket<Interest>(format);
+ interest->setName(*name);
+
+ auto content_object = toContentObject(
+ *name, format, payload_type, buffer->data(), buffer->length());
+
+ processManifest(*interest, *content_object);
+ }
+
+ state_->onPacketRecoveredFec(seq_number, buffer->length());
+ ldr_->onPacketRecoveredFec(seq_number);
+
+ if (payload_type == PayloadType::DATA) {
+ verifier_->onDataRecoveredFec(seq_number);
+ reassembly_->reassemble(*buffer, seq_number);
+ }
+
+ break;
+ }
+ }
+ }
+}
+
+void RTCTransportProtocol::processManifest(Interest &interest,
+ ContentObject &manifest) {
+ auth::VerificationPolicy policy = verifier_->processManifest(manifest);
+ indexer_verifier_->applyPolicy(interest, manifest, false, policy);
+}
+
+ContentObject::Ptr RTCTransportProtocol::removeFecHeader(
+ const ContentObject &content_object) {
+ if (!fec_decoder_ || !fec_decoder_->getFecHeaderSize()) {
+ return nullptr;
}
+
+ size_t fec_header_size = fec_decoder_->getFecHeaderSize();
+ const uint8_t *payload =
+ content_object.data() + content_object.headerSize() + fec_header_size;
+ size_t payload_size = content_object.payloadSize() - fec_header_size;
+
+ ContentObject::Ptr co =
+ toContentObject(content_object.getName(), content_object.getFormat(),
+ content_object.getPayloadType(), payload, payload_size);
+
+ return co;
+}
+
+ContentObject::Ptr RTCTransportProtocol::toContentObject(
+ const Name &name, Packet::Format format, PayloadType payload_type,
+ const uint8_t *payload, std::size_t payload_size,
+ std::size_t additional_header_size) {
+ // Recreate ContentObject
+ ContentObject::Ptr co =
+ core::PacketManager<>::getInstance().getPacket<ContentObject>(
+ format, additional_header_size);
+ co->updateLength(payload_size);
+ co->append(payload_size);
+ co->trimStart(co->headerSize());
+
+ // Copy payload
+ std::memcpy(co->writableData(), payload, payload_size);
+
+ // Restore network headers and some fields
+ co->prepend(co->headerSize());
+ co->setName(name);
+ co->setPayloadType(payload_type);
+
+ return co;
}
} // end namespace rtc
diff --git a/libtransport/src/protocols/rtc/rtc.h b/libtransport/src/protocols/rtc/rtc.h
index e6431264d..37706eb1c 100644
--- a/libtransport/src/protocols/rtc/rtc.h
+++ b/libtransport/src/protocols/rtc/rtc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2021 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -15,10 +15,12 @@
#pragma once
-#include <protocols/datagram_reassembly.h>
+#include <protocols/rtc/rtc_forwarding_strategy.h>
#include <protocols/rtc/rtc_ldr.h>
#include <protocols/rtc/rtc_rc.h>
+#include <protocols/rtc/rtc_reassembly.h>
#include <protocols/rtc/rtc_state.h>
+#include <protocols/rtc/rtc_verifier.h>
#include <protocols/transport_protocol.h>
#include <unordered_set>
@@ -44,6 +46,8 @@ class RTCTransportProtocol : public TransportProtocol {
std::size_t transportHeaderLength() override;
+ auto shared_from_this() { return utils::shared_from(this); }
+
private:
enum class SyncState { catch_up = 0, in_sync = 1, last };
@@ -76,6 +80,7 @@ class RTCTransportProtocol : public TransportProtocol {
void onPacketDropped(Interest &interest, ContentObject &content_object,
const std::error_code &reason) override {}
void onReassemblyFailed(std::uint32_t missing_segment) override {}
+ void processManifest(Interest &interest, ContentObject &manifest);
// interaction with app functions
void sendStatsToApp(uint32_t retx_count, uint32_t received_bytes,
@@ -84,11 +89,20 @@ class RTCTransportProtocol : public TransportProtocol {
uint32_t received_nacks, uint32_t received_fec);
// FEC functions
- void onFecPackets(std::vector<std::pair<uint32_t, fec::buffer>> &packets);
+ void onFecPackets(fec::BufferArray &packets);
+
+ // Utils
+ ContentObject::Ptr removeFecHeader(const ContentObject &content_object);
+ ContentObject::Ptr toContentObject(const Name &name, Packet::Format format,
+ PayloadType payload_type,
+ const uint8_t *payload,
+ std::size_t payload_size,
+ std::size_t additional_header_size = 0);
// protocol state
bool start_send_interest_;
SyncState current_state_;
+
// cwin vars
uint32_t current_sync_win_;
uint32_t max_sync_win_;
@@ -120,6 +134,10 @@ class RTCTransportProtocol : public TransportProtocol {
std::shared_ptr<RTCState> state_;
std::shared_ptr<RTCRateControl> rc_;
std::shared_ptr<RTCLossDetectionAndRecovery> ldr_;
+ std::shared_ptr<RTCVerifier> verifier_;
+
+ // forwarding strategy selection
+ RTCForwardingStrategy fwd_strategy_;
uint32_t number_;
};
diff --git a/libtransport/src/protocols/rtc/rtc_consts.h b/libtransport/src/protocols/rtc/rtc_consts.h
index d04bc1b1f..03efd8e84 100644
--- a/libtransport/src/protocols/rtc/rtc_consts.h
+++ b/libtransport/src/protocols/rtc/rtc_consts.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2021 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -45,22 +45,22 @@ const uint32_t MAX_INTERESTS_IN_BATCH = 5; // number of seq numbers per
const uint32_t WAIT_FOR_INTEREST_BATCH = 20; // msec. timer that we wait to try
// to aggregate interest in the
// same packet
-const uint32_t MAX_PACING_BATCH = 5;
-// number of interest that we can send inside
-// the loop before they get dropped by the
-// kernel.
+const uint32_t MAX_PACING_BATCH = 5; // number of interest that we can send
+ // inside the loop before they get dropped
+ // by the kernel.
const uint32_t PACING_WAIT = 1000; // usec to wait betwing two pacing batch. As
// for MAX_PACING_BATCH this value was
// computed during tests
const uint32_t MAX_RTX_IN_BATCH = 10; // max rtx to send in loop
// packet const
-const uint32_t HICN_HEADER_SIZE = 40 + 20; // IPv6 + TCP bytes
const uint32_t RTC_INTEREST_LIFETIME = 2000;
// probes sequence range
const uint32_t MIN_PROBE_SEQ = 0xefffffff;
-const uint32_t MIN_RTT_PROBE_SEQ = MIN_PROBE_SEQ;
+const uint32_t MIN_INIT_PROBE_SEQ = MIN_PROBE_SEQ;
+const uint32_t MAX_INIT_PROBE_SEQ = 0xf7ffffff - 1;
+const uint32_t MIN_RTT_PROBE_SEQ = MAX_INIT_PROBE_SEQ + 1;
const uint32_t MAX_RTT_PROBE_SEQ = 0xffffffff - 1;
// RTT_PROBE_INTERVAL will be used during the section while
// INIT_RTT_PROBE_INTERVAL is used at the beginning to
@@ -78,15 +78,16 @@ const uint32_t INIT_RTT_MIN_PROBES_TO_RECV = 5; // ms
const uint32_t MAX_PENDING_PROBES = 10;
// congestion
-const double MAX_QUEUING_DELAY = 100.0; // ms
+const double MAX_QUEUING_DELAY = 50.0; // ms
// data from cache
const double MAX_DATA_FROM_CACHE = 0.25; // 25%
// window const
-const uint32_t INITIAL_WIN = 5; // pkts
-const uint32_t INITIAL_WIN_MAX = 1000000; // pkts
-const uint32_t WIN_MIN = 5; // pkts
+const uint32_t INITIAL_WIN = 5; // pkts
+const uint32_t INITIAL_WIN_MAX = 1000000; // pkts
+const uint32_t WIN_MIN = 5; // pkts
+const uint32_t WIN_MIN_WITH_AGGREGARED_DATA = 10; // pkts
const double CATCH_UP_WIN_INCREMENT = 1.2;
// used in rate control
const double WIN_DECREASE_FACTOR = 0.5;
@@ -105,10 +106,8 @@ const double MOVING_AVG_ALPHA = 0.8;
const double MILLI_IN_A_SEC = 1000.0;
const double MICRO_IN_A_SEC = 1000000.0;
-
-const double MAX_CACHED_PACKETS = 262144; // 2^18
- // about 50 sec of traffic at 50Mbps
- // with 1200 bytes packets
+const uint32_t ROUNDS_PER_SEC = (uint32_t)(MILLI_IN_A_SEC / ROUND_LEN);
+const uint32_t ROUNDS_PER_MIN = (uint32_t)ROUNDS_PER_SEC * 60;
const uint32_t MAX_ROUND_WHIOUT_PACKETS =
(20 * MILLI_IN_A_SEC) / ROUND_LEN; // 20 sec in rounds;
@@ -120,12 +119,24 @@ const uint64_t MAX_TIMER_RTX = ~0;
const uint32_t SENTINEL_TIMER_INTERVAL = 100; // ms
const uint32_t MAX_RTX_WITH_SENTINEL = 10; // packets
const double CATCH_UP_RTT_INCREMENT = 1.2;
+const double MAX_RESIDUAL_LOSS_RATE = 2.0; // %
+const uint32_t WAIT_BEFORE_FEC_UPDATE = ROUNDS_PER_SEC * 5;
// used by producer
const uint32_t PRODUCER_STATS_INTERVAL = 200; // ms
-const uint32_t MIN_PRODUCTION_RATE = 10; // pps
- // min prod rate
- // set running several test
+const uint32_t MIN_PRODUCTION_RATE = 25; // pps, equal to min window *
+ // rounds in a second
+const uint32_t NACK_DELAY = 1500; // ms
+const uint32_t FEC_PACING_TIME = 5; // ms
+
+// aggregated data consts
+const uint16_t MAX_RTC_PAYLOAD_SIZE = 1200; // bytes
+const uint16_t MAX_AGGREGATED_PACKETS = 5; // pkt
+const uint32_t AGGREGATED_PACKETS_TIMER = 2; // ms
+
+// alert thresholds
+const uint32_t MAX_RTT = 200; // ms
+const double MAX_RESIDUAL_LOSSES = 0.05; // %
} // namespace rtc
diff --git a/libtransport/src/protocols/rtc/rtc_data_path.cc b/libtransport/src/protocols/rtc/rtc_data_path.cc
index c098088a3..b3abf5ea8 100644
--- a/libtransport/src/protocols/rtc/rtc_data_path.cc
+++ b/libtransport/src/protocols/rtc/rtc_data_path.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -13,14 +13,17 @@
* limitations under the License.
*/
+#include <hicn/transport/utils/chrono_typedefs.h>
#include <protocols/rtc/rtc_data_path.h>
#include <stdlib.h>
#include <algorithm>
#include <cfloat>
#include <chrono>
+#include <cmath>
#define MAX_ROUNDS_WITHOUT_PKTS 10 // 2sec
+#define AVG_RTT_TIME 1000 // (ms) 1sec
namespace transport {
@@ -32,6 +35,8 @@ RTCDataPath::RTCDataPath(uint32_t path_id)
: path_id_(path_id),
min_rtt(UINT_MAX),
prev_min_rtt(UINT_MAX),
+ max_rtt(0),
+ prev_max_rtt(0),
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
@@ -46,20 +51,46 @@ RTCDataPath::RTCDataPath(uint32_t path_id)
largest_recv_seq_(0),
largest_recv_seq_time_(0),
avg_inter_arrival_(DBL_MAX),
+ rtt_sum_(0),
+ last_avg_rtt_compute_(0),
+ rtt_samples_(0),
+ avg_rtt_(0.0),
received_nacks_(false),
- received_packets_(false),
+ received_packets_(0),
rounds_without_packets_(0),
last_received_data_packet_(0),
- RTT_history_(HISTORY_LEN),
+ min_RTT_history_(HISTORY_LEN),
+ max_RTT_history_(HISTORY_LEN),
OWD_history_(HISTORY_LEN){};
-void RTCDataPath::insertRttSample(uint64_t rtt) {
- // for the rtt we only keep track of the min one
+void RTCDataPath::insertRttSample(
+ const utils::SteadyTime::Milliseconds& rtt_milliseconds, bool is_probe) {
+ // compute min rtt
+ uint64_t rtt = rtt_milliseconds.count();
if (rtt < min_rtt) min_rtt = rtt;
- last_received_data_packet_ =
- std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
+
+ uint64_t now = utils::SteadyTime::nowMs().count();
+ last_received_data_packet_ = now;
+
+ // compute avg rtt
+ if (is_probe) {
+ // max rtt is computed only on probes to avoid to take into account the
+ // production time at the server
+ if (rtt > max_rtt) max_rtt = rtt;
+
+ rtt_sum_ += rtt;
+ rtt_samples_++;
+ }
+
+ if ((now - last_avg_rtt_compute_) >= AVG_RTT_TIME) {
+ // compute a new avg rtt
+ // if rtt_samples_ = 0 keep the same rtt
+ if (rtt_samples_ != 0) avg_rtt_ = (double)rtt_sum_ / (double)rtt_samples_;
+
+ rtt_sum_ = 0;
+ rtt_samples_ = 0;
+ last_avg_rtt_compute_ = now;
+ }
}
void RTCDataPath::insertOwdSample(int64_t owd) {
@@ -87,15 +118,13 @@ void RTCDataPath::insertOwdSample(int64_t 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;
+ received_packets_++;
}
void RTCDataPath::computeInterArrivalGap(uint32_t segment_number) {
// got packet in sequence, compute gap
if (largest_recv_seq_ == (segment_number - 1)) {
- uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
+ uint64_t now = utils::SteadyTime::nowMs().count();
uint64_t delta = now - largest_recv_seq_time_;
largest_recv_seq_ = segment_number;
largest_recv_seq_time_ = now;
@@ -110,10 +139,7 @@ void RTCDataPath::computeInterArrivalGap(uint32_t segment_number) {
// ooo packet, update the stasts if needed
if (largest_recv_seq_ <= segment_number) {
largest_recv_seq_ = segment_number;
- largest_recv_seq_time_ =
- std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
+ largest_recv_seq_time_ = utils::SteadyTime::nowMs().count();
}
}
@@ -146,10 +172,20 @@ void RTCDataPath::roundEnd() {
min_rtt = prev_min_rtt;
}
+ // same for max_rtt
+ if (max_rtt != 0) {
+ prev_max_rtt = max_rtt;
+ } else {
+ max_rtt = prev_max_rtt;
+ }
+
if (min_rtt == 0) min_rtt = 1;
+ if (max_rtt == 0) max_rtt = 1;
- RTT_history_.pushBack(min_rtt);
+ min_RTT_history_.pushBack(min_rtt);
+ max_RTT_history_.pushBack(max_rtt);
min_rtt = UINT_MAX;
+ max_rtt = 0;
// do the same for min owd
if (min_owd != INT_MAX) {
@@ -163,32 +199,47 @@ void RTCDataPath::roundEnd() {
min_owd = INT_MAX;
}
- if (!received_packets_)
+ if (received_packets_ == 0)
rounds_without_packets_++;
else
rounds_without_packets_ = 0;
- received_packets_ = false;
+ received_packets_ = 0;
}
uint32_t RTCDataPath::getPathId() { return path_id_; }
-double RTCDataPath::getQueuingDealy() { return queuing_delay; }
+double RTCDataPath::getQueuingDealy() {
+ if (queuing_delay == DBL_MAX) return 0;
+ return queuing_delay;
+}
uint64_t RTCDataPath::getMinRtt() {
- if (RTT_history_.size() != 0) return RTT_history_.begin();
+ if (min_RTT_history_.size() != 0) return min_RTT_history_.begin();
+ return 0;
+}
+
+uint64_t RTCDataPath::getAvgRtt() { return std::round(avg_rtt_); }
+
+uint64_t RTCDataPath::getMaxRtt() {
+ if (max_RTT_history_.size() != 0) return max_RTT_history_.begin();
return 0;
}
int64_t RTCDataPath::getMinOwd() {
if (OWD_history_.size() != 0) return OWD_history_.begin();
- return 0;
+ return INT_MAX;
}
double RTCDataPath::getJitter() { return jitter_; }
uint64_t RTCDataPath::getLastPacketTS() { return last_received_data_packet_; }
-void RTCDataPath::clearRtt() { RTT_history_.clear(); }
+uint32_t RTCDataPath::getPacketsLastRound() { return received_packets_; }
+
+void RTCDataPath::clearRtt() {
+ min_RTT_history_.clear();
+ max_RTT_history_.clear();
+}
} // end namespace rtc
diff --git a/libtransport/src/protocols/rtc/rtc_data_path.h b/libtransport/src/protocols/rtc/rtc_data_path.h
index c5c37fc0d..5afbbb87f 100644
--- a/libtransport/src/protocols/rtc/rtc_data_path.h
+++ b/libtransport/src/protocols/rtc/rtc_data_path.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -15,7 +15,9 @@
#pragma once
+#include <hicn/transport/utils/chrono_typedefs.h>
#include <stdint.h>
+#include <utils/max_filter.h>
#include <utils/min_filter.h>
#include <climits>
@@ -34,19 +36,23 @@ class RTCDataPath {
RTCDataPath(uint32_t path_id);
public:
- void insertRttSample(uint64_t rtt);
+ void insertRttSample(const utils::SteadyTime::Milliseconds &rtt,
+ bool is_probe);
void insertOwdSample(int64_t owd);
void computeInterArrivalGap(uint32_t segment_number);
void receivedNack();
uint32_t getPathId();
uint64_t getMinRtt();
+ uint64_t getAvgRtt();
+ uint64_t getMaxRtt();
double getQueuingDealy();
double getInterArrivalGap();
double getJitter();
bool isActive();
bool pathToProducer();
uint64_t getLastPacketTS();
+ uint32_t getPacketsLastRound();
void clearRtt();
@@ -60,6 +66,9 @@ class RTCDataPath {
uint64_t min_rtt;
uint64_t prev_min_rtt;
+ uint64_t max_rtt;
+ uint64_t prev_max_rtt;
+
int64_t min_owd;
int64_t prev_min_owd;
@@ -74,19 +83,26 @@ class RTCDataPath {
uint64_t largest_recv_seq_time_;
double avg_inter_arrival_;
+ // compute the avg rtt over one sec
+ uint64_t rtt_sum_;
+ uint64_t last_avg_rtt_compute_;
+ uint32_t rtt_samples_;
+ double avg_rtt_;
+
// 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
+ uint32_t received_packets_;
+ uint32_t rounds_without_packets_; // if we don't get any packet
// for MAX_ROUNDS_WITHOUT_PKTS
// we consider the path inactive
uint64_t last_received_data_packet_; // timestamp for the last data received
// on this path
- utils::MinFilter<uint64_t> RTT_history_;
+ utils::MinFilter<uint64_t> min_RTT_history_;
+ utils::MaxFilter<uint64_t> max_RTT_history_;
utils::MinFilter<int64_t> OWD_history_;
};
diff --git a/libtransport/src/protocols/rtc/rtc_forwarding_strategy.cc b/libtransport/src/protocols/rtc/rtc_forwarding_strategy.cc
new file mode 100644
index 000000000..9503eed3e
--- /dev/null
+++ b/libtransport/src/protocols/rtc/rtc_forwarding_strategy.cc
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <hicn/transport/interfaces/notification.h>
+#include <protocols/rtc/rtc_forwarding_strategy.h>
+
+namespace transport {
+
+namespace protocol {
+
+namespace rtc {
+
+using namespace transport::interface;
+
+RTCForwardingStrategy::RTCForwardingStrategy()
+ : init_(false),
+ forwarder_set_(false),
+ selected_strategy_(NONE),
+ current_strategy_(NONE),
+ rounds_since_last_set_(0),
+ portal_(nullptr),
+ state_(nullptr) {}
+
+RTCForwardingStrategy::~RTCForwardingStrategy() {}
+
+void RTCForwardingStrategy::setCallback(interface::StrategyCallback* callback) {
+ callback_ = callback;
+}
+
+void RTCForwardingStrategy::initFwdStrategy(
+ std::shared_ptr<core::Portal> portal, core::Prefix& prefix, RTCState* state,
+ strategy_t strategy) {
+ init_ = true;
+ selected_strategy_ = strategy;
+ if (strategy == BOTH)
+ current_strategy_ = BEST_PATH;
+ else
+ current_strategy_ = strategy;
+ rounds_since_last_set_ = 0;
+ prefix_ = prefix;
+ portal_ = portal;
+ state_ = state;
+}
+
+void RTCForwardingStrategy::checkStrategy() {
+ if (*callback_) {
+ strategy_t used_strategy = selected_strategy_;
+ if (used_strategy == BOTH) used_strategy = current_strategy_;
+ assert(used_strategy == BEST_PATH || used_strategy == REPLICATION ||
+ used_strategy == NONE);
+
+ notification::ForwardingStrategy strategy =
+ notification::ForwardingStrategy::NONE;
+ switch (used_strategy) {
+ case BEST_PATH:
+ strategy = notification::ForwardingStrategy::BEST_PATH;
+ break;
+ case REPLICATION:
+ strategy = notification::ForwardingStrategy::REPLICATION;
+ break;
+ default:
+ break;
+ }
+
+ (*callback_)(strategy);
+ }
+
+ if (!init_) return;
+
+ if (selected_strategy_ == NONE) return;
+
+ if (selected_strategy_ == BEST_PATH) {
+ checkStrategyBestPath();
+ return;
+ }
+
+ if (selected_strategy_ == REPLICATION) {
+ checkStrategyReplication();
+ return;
+ }
+
+ checkStrategyBoth();
+}
+
+void RTCForwardingStrategy::checkStrategyBestPath() {
+ if (!forwarder_set_) {
+ setStrategy(BEST_PATH);
+ forwarder_set_ = true;
+ return;
+ }
+
+ uint8_t qs = state_->getQualityScore();
+
+ if (qs >= 4 || rounds_since_last_set_ < 25) { // wait a least 5 sec
+ // between each switch
+ rounds_since_last_set_++;
+ return;
+ }
+
+ // try to switch path
+ setStrategy(BEST_PATH);
+}
+
+void RTCForwardingStrategy::checkStrategyReplication() {
+ if (!forwarder_set_) {
+ setStrategy(REPLICATION);
+ forwarder_set_ = true;
+ return;
+ }
+
+ // here we have nothing to do for the moment
+ return;
+}
+
+void RTCForwardingStrategy::checkStrategyBoth() {
+ if (!forwarder_set_) {
+ setStrategy(current_strategy_);
+ forwarder_set_ = true;
+ return;
+ }
+
+ checkStrategyBestPath();
+
+ // TODO
+ // for the moment we use only best path.
+ // but later:
+ // 1. if both paths are bad use replication
+ // 2. while using replication compute the effectiveness. if the majority of
+ // the packets are coming from a single path, try to use bestpath
+}
+
+void RTCForwardingStrategy::setStrategy(strategy_t strategy) {
+ rounds_since_last_set_ = 0;
+ current_strategy_ = strategy;
+ portal_->setForwardingStrategy(prefix_,
+ string_strategies_[current_strategy_]);
+}
+
+} // namespace rtc
+
+} // namespace protocol
+
+} // namespace transport
diff --git a/libtransport/src/protocols/rtc/rtc_forwarding_strategy.h b/libtransport/src/protocols/rtc/rtc_forwarding_strategy.h
new file mode 100644
index 000000000..821b28051
--- /dev/null
+++ b/libtransport/src/protocols/rtc/rtc_forwarding_strategy.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <core/portal.h>
+#include <hicn/transport/interfaces/callbacks.h>
+#include <protocols/rtc/rtc_state.h>
+
+#include <array>
+
+namespace transport {
+
+namespace protocol {
+
+namespace rtc {
+
+class RTCForwardingStrategy {
+ public:
+ enum strategy_t {
+ BEST_PATH,
+ REPLICATION,
+ BOTH,
+ NONE,
+ };
+
+ RTCForwardingStrategy();
+ ~RTCForwardingStrategy();
+
+ void initFwdStrategy(std::shared_ptr<core::Portal> portal,
+ core::Prefix& prefix, RTCState* state,
+ strategy_t strategy);
+
+ void checkStrategy();
+ void setCallback(interface::StrategyCallback* callback);
+
+ private:
+ void checkStrategyBestPath();
+ void checkStrategyReplication();
+ void checkStrategyBoth();
+
+ void setStrategy(strategy_t strategy);
+
+ std::array<std::string, 4> string_strategies_ = {"bestpath", "replication",
+ "both", "none"};
+
+ bool init_; // true if all val are initializes
+ bool forwarder_set_; // true if the strategy is been set at least
+ // once
+ strategy_t selected_strategy_; // this is the strategy selected using socket
+ // options. this can also be equal to BOTH
+ strategy_t current_strategy_; // if both strategies can be used this
+ // indicates the one that is currently in use
+ // that can be only replication or best path
+ uint32_t rounds_since_last_set_;
+ core::Prefix prefix_;
+ std::shared_ptr<core::Portal> portal_;
+ RTCState* state_;
+ interface::StrategyCallback* callback_;
+};
+
+} // namespace rtc
+
+} // namespace protocol
+
+} // namespace transport
diff --git a/libtransport/src/protocols/rtc/rtc_indexer.h b/libtransport/src/protocols/rtc/rtc_indexer.h
index 4aee242bb..cda156b22 100644
--- a/libtransport/src/protocols/rtc/rtc_indexer.h
+++ b/libtransport/src/protocols/rtc/rtc_indexer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -18,8 +18,10 @@
#include <protocols/errors.h>
#include <protocols/fec_utils.h>
#include <protocols/indexer.h>
+#include <protocols/rtc/probe_handler.h>
#include <protocols/rtc/rtc_consts.h>
#include <protocols/transport_protocol.h>
+#include <utils/suffix_strategy.h>
#include <deque>
@@ -54,7 +56,7 @@ class RtcIndexer : public Indexer {
n_fec_ = 0;
}
- uint32_t checkNextSuffix() override { return next_suffix_; }
+ uint32_t checkNextSuffix() const override { return next_suffix_; }
uint32_t getNextSuffix() override {
if (isFec(next_suffix_)) {
@@ -77,7 +79,7 @@ class RtcIndexer : public Indexer {
first_suffix_ = suffix % LIMIT;
}
- uint32_t getFirstSuffix() override { return first_suffix_; }
+ uint32_t getFirstSuffix() const override { return first_suffix_; }
uint32_t jumpToIndex(uint32_t index) override {
next_suffix_ = index % LIMIT;
@@ -87,30 +89,8 @@ class RtcIndexer : public Indexer {
void onContentObject(core::Interest &interest,
core::ContentObject &content_object,
bool reassembly) override {
- setVerifier();
- auto ret = verifier_->verifyPackets(&content_object);
-
- switch (ret) {
- case auth::VerificationPolicy::ACCEPT: {
- if (reassembly) {
- reassembly_->reassemble(content_object);
- }
- break;
- }
-
- case auth::VerificationPolicy::UNKNOWN:
- case auth::VerificationPolicy::DROP: {
- transport_->onPacketDropped(
- interest, content_object,
- make_error_code(protocol_error::verification_failed));
- break;
- }
-
- case auth::VerificationPolicy::ABORT: {
- transport_->onContentReassembled(
- make_error_code(protocol_error::session_aborted));
- break;
- }
+ if (reassembly) {
+ reassembly_->reassemble(content_object);
}
}
@@ -120,13 +100,12 @@ class RtcIndexer : public Indexer {
uint32_t getNextReassemblySegment() override {
throw errors::RuntimeException(
"Get reassembly segment called on rtc indexer. RTC indexer does not "
- "provide "
- "reassembly.");
+ "provide reassembly.");
}
bool isFinalSuffixDiscovered() override { return true; }
- uint32_t getFinalSuffix() override { return LIMIT; }
+ uint32_t getFinalSuffix() const override { return LIMIT; }
void enableFec(fec::FECType fec_type) override { fec_type_ = fec_type; }
@@ -137,13 +116,13 @@ class RtcIndexer : public Indexer {
n_current_fec_ = n_fec_;
}
- uint32_t getNFec() override { return n_fec_; }
+ uint32_t getNFec() const override { return n_fec_; }
bool isFec(uint32_t index) override {
return isFec(fec_type_, index, first_suffix_);
}
- double getFecOverhead() override {
+ double getFecOverhead() const override {
if (fec_type_ == fec::FECType::UNKNOWN) {
return 0;
}
@@ -152,7 +131,7 @@ class RtcIndexer : public Indexer {
return (double)n_fec_ / k;
}
- double getMaxFecOverhead() override {
+ double getMaxFecOverhead() const override {
if (fec_type_ == fec::FECType::UNKNOWN) {
return 0;
}
diff --git a/libtransport/src/protocols/rtc/rtc_ldr.cc b/libtransport/src/protocols/rtc/rtc_ldr.cc
index f0de48871..1ca1cf48d 100644
--- a/libtransport/src/protocols/rtc/rtc_ldr.cc
+++ b/libtransport/src/protocols/rtc/rtc_ldr.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2021 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -16,6 +16,12 @@
#include <glog/logging.h>
#include <protocols/rtc/rtc_consts.h>
#include <protocols/rtc/rtc_ldr.h>
+#include <protocols/rtc/rtc_rs_delay.h>
+#include <protocols/rtc/rtc_rs_fec_only.h>
+#include <protocols/rtc/rtc_rs_low_rate.h>
+#include <protocols/rtc/rtc_rs_recovery_off.h>
+#include <protocols/rtc/rtc_rs_rtx_only.h>
+#include <protocols/rtc/rtc_state.h>
#include <algorithm>
#include <unordered_set>
@@ -27,146 +33,115 @@ namespace protocol {
namespace rtc {
RTCLossDetectionAndRecovery::RTCLossDetectionAndRecovery(
- Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service)
- : rtx_on_(false),
- fec_on_(false),
- next_rtx_timer_(MAX_TIMER_RTX),
- last_event_(0),
- sentinel_timer_interval_(MAX_TIMER_RTX),
- indexer_(indexer),
- send_rtx_callback_(std::move(callback)) {
- timer_ = std::make_unique<asio::steady_timer>(io_service);
- sentinel_timer_ = std::make_unique<asio::steady_timer>(io_service);
+ Indexer *indexer, asio::io_service &io_service,
+ interface::RtcTransportRecoveryStrategies type,
+ RecoveryStrategy::SendRtxCallback &&callback,
+ interface::StrategyCallback *external_callback) {
+ rs_type_ = type;
+ if (type == interface::RtcTransportRecoveryStrategies::RECOVERY_OFF) {
+ rs_ = std::make_shared<RecoveryStrategyRecoveryOff>(
+ indexer, std::move(callback), io_service, external_callback);
+ } else if (type == interface::RtcTransportRecoveryStrategies::DELAY_BASED) {
+ rs_ = std::make_shared<RecoveryStrategyDelayBased>(
+ indexer, std::move(callback), io_service, external_callback);
+ } else if (type == interface::RtcTransportRecoveryStrategies::FEC_ONLY) {
+ rs_ = std::make_shared<RecoveryStrategyFecOnly>(
+ indexer, std::move(callback), io_service, external_callback);
+ } else if (type == interface::RtcTransportRecoveryStrategies::LOW_RATE ||
+ type == interface::RtcTransportRecoveryStrategies::
+ LOW_RATE_AND_BESTPATH ||
+ type == interface::RtcTransportRecoveryStrategies::
+ LOW_RATE_AND_REPLICATION ||
+ type == interface::RtcTransportRecoveryStrategies::
+ LOW_RATE_AND_ALL_FWD_STRATEGIES) {
+ rs_ = std::make_shared<RecoveryStrategyLowRate>(
+ indexer, std::move(callback), io_service, external_callback);
+ } else {
+ // default
+ rs_type_ = interface::RtcTransportRecoveryStrategies::RTX_ONLY;
+ rs_ = std::make_shared<RecoveryStrategyRtxOnly>(
+ indexer, std::move(callback), io_service, external_callback);
+ }
}
RTCLossDetectionAndRecovery::~RTCLossDetectionAndRecovery() {}
-void RTCLossDetectionAndRecovery::turnOnRTX() {
- rtx_on_ = true;
- scheduleSentinelTimer(state_->getRTT() * CATCH_UP_RTT_INCREMENT);
-}
-
-void RTCLossDetectionAndRecovery::turnOffRTX() {
- rtx_on_ = false;
- clear();
-}
-
-uint32_t RTCLossDetectionAndRecovery::computeFecPacketsToAsk(bool in_sync) {
- uint32_t current_fec = indexer_->getNFec();
- double current_loss_rate = state_->getLossRate();
- double last_loss_rate = state_->getLastRoundLossRate();
-
- // when in sync ask for fec only if there are losses for 2 rounds
- if (in_sync && current_fec == 0 &&
- (current_loss_rate == 0 || last_loss_rate == 0))
- return 0;
-
- double loss_rate = state_->getMaxLossRate() * 1.5;
-
- if (!in_sync && loss_rate == 0) loss_rate = 0.05;
- if (loss_rate > 0.5) loss_rate = 0.5;
-
- double exp_losses = (double)k_ * loss_rate;
- uint32_t fec_to_ask = ceil(exp_losses / (1 - loss_rate));
-
- if (fec_to_ask > (n_ - k_)) fec_to_ask = n_ - k_;
-
- return fec_to_ask;
+void RTCLossDetectionAndRecovery::changeRecoveryStrategy(
+ interface::RtcTransportRecoveryStrategies type) {
+ if (type == rs_type_) return;
+
+ rs_type_ = type;
+ if (type == interface::RtcTransportRecoveryStrategies::RECOVERY_OFF) {
+ rs_ =
+ std::make_shared<RecoveryStrategyRecoveryOff>(std::move(*(rs_.get())));
+ } else if (type == interface::RtcTransportRecoveryStrategies::DELAY_BASED) {
+ rs_ = std::make_shared<RecoveryStrategyDelayBased>(std::move(*(rs_.get())));
+ } else if (type == interface::RtcTransportRecoveryStrategies::FEC_ONLY) {
+ rs_ = std::make_shared<RecoveryStrategyFecOnly>(std::move(*(rs_.get())));
+ } else if (type == interface::RtcTransportRecoveryStrategies::LOW_RATE ||
+ type == interface::RtcTransportRecoveryStrategies::
+ LOW_RATE_AND_BESTPATH ||
+ type == interface::RtcTransportRecoveryStrategies::
+ LOW_RATE_AND_REPLICATION ||
+ type == interface::RtcTransportRecoveryStrategies::
+ LOW_RATE_AND_ALL_FWD_STRATEGIES) {
+ rs_ = std::make_shared<RecoveryStrategyLowRate>(std::move(*(rs_.get())));
+ } else {
+ // default
+ rs_ = std::make_shared<RecoveryStrategyRtxOnly>(std::move(*(rs_.get())));
+ }
}
void RTCLossDetectionAndRecovery::onNewRound(bool in_sync) {
- uint64_t rtt = state_->getRTT();
- if (!fec_on_ && rtt >= 100) {
- // turn on fec, here we may have no info so ask for all packets
- fec_on_ = true;
- turnOffRTX();
- indexer_->setNFec(computeFecPacketsToAsk(in_sync));
- return;
- }
-
- if (fec_on_ && rtt > 80) {
- // keep using fec, maybe update it
- indexer_->setNFec(computeFecPacketsToAsk(in_sync));
- return;
- }
-
- if ((fec_on_ && rtt <= 80) || (!rtx_on_ && rtt <= 100)) {
- // turn on rtx
- fec_on_ = false;
- indexer_->setNFec(0);
- turnOnRTX();
- return;
- }
+ rs_->incRoundId();
+ rs_->onNewRound(in_sync);
}
-void RTCLossDetectionAndRecovery::onTimeout(uint32_t seq) {
- // always add timeouts to the RTX list to avoid to send the same packet as if
- // it was not a rtx
- addToRetransmissions(seq, seq + 1);
- last_event_ = getNow();
+void RTCLossDetectionAndRecovery::onTimeout(uint32_t seq, bool lost) {
+ if (!lost) {
+ detectLoss(seq, seq + 1);
+ } else {
+ rs_->onLostTimeout(seq);
+ }
}
void RTCLossDetectionAndRecovery::onPacketRecoveredFec(uint32_t seq) {
- // if an RTX is scheduled for a packet recovered using FEC delete it
- deleteRtx(seq);
- recover_with_fec_.erase(seq);
+ rs_->receivedPacket(seq);
}
void RTCLossDetectionAndRecovery::onDataPacketReceived(
const core::ContentObject &content_object) {
- last_event_ = getNow();
-
uint32_t seq = content_object.getName().getSuffix();
- if (deleteRtx(seq)) {
- state_->onPacketRecoveredRtx(seq);
- } else {
- DLOG_IF(INFO, VLOG_IS_ON(3))
- << "received data. add from "
- << state_->getHighestSeqReceivedInOrder() + 1 << " to " << seq;
- addToRetransmissions(state_->getHighestSeqReceivedInOrder() + 1, seq);
- }
+ bool is_rtx = rs_->isRtx(seq);
+ rs_->receivedPacket(seq);
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "received data. add from "
+ << rs_->getState()->getHighestSeqReceivedInOrder() + 1 << " to " << seq;
+ if (!is_rtx)
+ detectLoss(rs_->getState()->getHighestSeqReceivedInOrder() + 1, seq);
}
void RTCLossDetectionAndRecovery::onNackPacketReceived(
const core::ContentObject &nack) {
- last_event_ = getNow();
-
- uint32_t seq = nack.getName().getSuffix();
-
struct nack_packet_t *nack_pkt =
(struct nack_packet_t *)nack.getPayload()->data();
- uint32_t production_seq = nack_pkt->getProductionSegement();
+ uint32_t production_seq = nack_pkt->getProductionSegment();
+ uint32_t seq = nack.getName().getSuffix();
- if (production_seq > seq) {
- // this is a past nack, all data before productionSeq are lost. if
- // productionSeq > state_->getHighestSeqReceivedInOrder() is impossible to
- // recover any packet. If this is not the case we can try to recover the
- // packets between state_->getHighestSeqReceivedInOrder() and productionSeq.
- // e.g.: the client receives packets 8 10 11 9 where 9 is a nack with
- // productionSeq = 14. 9 is lost but we can try to recover packets 12 13 and
- // 14 that are not arrived yet
- deleteRtx(seq);
- DLOG_IF(INFO, VLOG_IS_ON(3)) << "received past nack. add from "
- << state_->getHighestSeqReceivedInOrder() + 1
- << " to " << production_seq;
- addToRetransmissions(state_->getHighestSeqReceivedInOrder() + 1,
- production_seq);
- } else {
- // future nack. here there should be a gap between the last data received
- // and this packet and is it possible to recover the packets between the
- // last received data and the production seq. we should not use the seq
- // number of the nack since we know that is too early to ask for this seq
- // number
- // e.g.: // e.g.: the client receives packets 10 11 12 20 where 20 is a nack
- // with productionSeq = 18. this says that all the packets between 12 and 18
- // may got lost and we should ask them
- deleteRtx(seq);
- DLOG_IF(INFO, VLOG_IS_ON(3)) << "received futrue nack. add from "
- << state_->getHighestSeqReceivedInOrder() + 1
- << " to " << production_seq;
- addToRetransmissions(state_->getHighestSeqReceivedInOrder() + 1,
- production_seq);
- }
+ // received a nack. we can try to recover all data packets between the last
+ // received data and the production seq in the nack. this is similar to the
+ // recption of a probe
+ // e.g.: the client receives packets 10 11 12 20 where 20 is a nack
+ // with productionSeq = 18. this says that all the packets between 12 and 18
+ // may got lost and we should ask them
+
+ rs_->receivedPacket(seq);
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "received nack. add from "
+ << rs_->getState()->getHighestSeqReceivedInOrder() + 1 << " to "
+ << production_seq;
+ detectLoss(rs_->getState()->getHighestSeqReceivedInOrder() + 1,
+ production_seq);
}
void RTCLossDetectionAndRecovery::onProbePacketReceived(
@@ -174,336 +149,38 @@ void RTCLossDetectionAndRecovery::onProbePacketReceived(
// we don't log the reception of a probe packet for the sentinel timer because
// probes are not taken into account into the sync window. we use them as
// future nacks to detect possible packets lost
- struct nack_packet_t *probe_pkt =
- (struct nack_packet_t *)probe.getPayload()->data();
- uint32_t production_seq = probe_pkt->getProductionSegement();
+
+ uint32_t production_seq = RTCState::getProbeParams(probe).prod_seg;
+
DLOG_IF(INFO, VLOG_IS_ON(3))
<< "received probe. add from "
- << state_->getHighestSeqReceivedInOrder() + 1 << " to " << production_seq;
+ << rs_->getState()->getHighestSeqReceivedInOrder() + 1 << " to "
+ << production_seq;
- addToRetransmissions(state_->getHighestSeqReceivedInOrder() + 1,
- production_seq);
+ detectLoss(rs_->getState()->getHighestSeqReceivedInOrder() + 1,
+ production_seq);
}
-void RTCLossDetectionAndRecovery::clear() {
- rtx_state_.clear();
- rtx_timers_.clear();
- sentinel_timer_->cancel();
- if (next_rtx_timer_ != MAX_TIMER_RTX) {
- next_rtx_timer_ = MAX_TIMER_RTX;
- timer_->cancel();
- }
-}
+void RTCLossDetectionAndRecovery::detectLoss(uint32_t start, uint32_t stop) {
+ if (start >= stop) return;
-void RTCLossDetectionAndRecovery::addToRetransmissions(uint32_t start,
- uint32_t stop) {
// skip nacked packets
- if (start <= state_->getLastSeqNacked()) {
- start = state_->getLastSeqNacked() + 1;
+ if (start <= rs_->getState()->getLastSeqNacked()) {
+ start = rs_->getState()->getLastSeqNacked() + 1;
}
// skip received or lost packets
- if (start <= state_->getHighestSeqReceivedInOrder()) {
- start = state_->getHighestSeqReceivedInOrder() + 1;
+ if (start <= rs_->getState()->getHighestSeqReceivedInOrder()) {
+ start = rs_->getState()->getHighestSeqReceivedInOrder() + 1;
}
for (uint32_t seq = start; seq < stop; seq++) {
- if (state_->isReceivedOrLost(seq) == PacketState::UNKNOWN) {
- if (rtx_on_) {
- if (!indexer_->isFec(seq)) {
- // handle it with rtx
- if (!isRtx(seq)) {
- state_->onLossDetected(seq);
- rtxState state;
- state.first_send_ = state_->getInterestSentTime(seq);
- if (state.first_send_ == 0) // this interest was never sent before
- state.first_send_ = getNow();
- state.next_send_ = computeNextSend(seq, true);
- state.rtx_count_ = 0;
- DLOG_IF(INFO, VLOG_IS_ON(4))
- << "Add " << seq << " to retransmissions. next rtx is %lu "
- << state.next_send_ - getNow();
- rtx_state_.insert(std::pair<uint32_t, rtxState>(seq, state));
- rtx_timers_.insert(
- std::pair<uint64_t, uint32_t>(state.next_send_, seq));
- }
- } else {
- // is fec, do not send it
- auto it = recover_with_fec_.find(seq);
- if (it == recover_with_fec_.end()) {
- state_->onLossDetected(seq);
- recover_with_fec_.insert(seq);
- }
- }
- } else {
- // keep track of losses but recover with FEC
- auto it = recover_with_fec_.find(seq);
- if (it == recover_with_fec_.end()) {
- state_->onLossDetected(seq);
- recover_with_fec_.insert(seq);
- }
- }
- }
- }
- scheduleNextRtx();
-}
-
-uint64_t RTCLossDetectionAndRecovery::computeNextSend(uint32_t seq,
- bool new_rtx) {
- uint64_t now = getNow();
- if (new_rtx) {
- // for the new rtx we wait one estimated IAT after the loss detection. this
- // is bacause, assuming that packets arrive with a constant IAT, we should
- // get a new packet every IAT
- double prod_rate = state_->getProducerRate();
- uint32_t estimated_iat = SENTINEL_TIMER_INTERVAL;
- uint32_t jitter = 0;
-
- if (prod_rate != 0) {
- double packet_size = state_->getAveragePacketSize();
- estimated_iat = ceil(1000.0 / (prod_rate / packet_size));
- jitter = ceil(state_->getJitter());
- }
-
- uint32_t wait = estimated_iat + jitter;
- DLOG_IF(INFO, VLOG_IS_ON(3))
- << "first rtx for " << seq << " in " << wait
- << " ms, rtt = " << state_->getRTT() << " ait = " << estimated_iat
- << " jttr = " << jitter;
-
- return now + wait;
- } else {
- // wait one RTT
- // however if the IAT is larger than the RTT, wait one IAT
- uint32_t wait = SENTINEL_TIMER_INTERVAL;
-
- double prod_rate = state_->getProducerRate();
- if (prod_rate == 0) {
- return now + SENTINEL_TIMER_INTERVAL;
- }
-
- double packet_size = state_->getAveragePacketSize();
- uint32_t estimated_iat = ceil(1000.0 / (prod_rate / packet_size));
-
- uint64_t rtt = state_->getRTT();
- if (rtt == 0) rtt = SENTINEL_TIMER_INTERVAL;
- wait = rtt;
-
- if (estimated_iat > rtt) wait = estimated_iat;
-
- uint32_t jitter = ceil(state_->getJitter());
- wait += jitter;
-
- // it may happen that the channel is congested and we have some additional
- // queuing delay to take into account
- uint32_t queue = ceil(state_->getQueuing());
- wait += queue;
-
- DLOG_IF(INFO, VLOG_IS_ON(3))
- << "next rtx for " << seq << " in " << wait
- << " ms, rtt = " << state_->getRTT() << " ait = " << estimated_iat
- << " jttr = " << jitter << " queue = " << queue;
-
- return now + wait;
- }
-}
-
-void RTCLossDetectionAndRecovery::retransmit() {
- if (rtx_timers_.size() == 0) return;
-
- uint64_t now = getNow();
-
- auto it = rtx_timers_.begin();
- std::unordered_set<uint32_t> lost_pkt;
- uint32_t sent_counter = 0;
- while (it != rtx_timers_.end() && it->first <= now &&
- sent_counter < MAX_RTX_IN_BATCH) {
- uint32_t seq = it->second;
- auto rtx_it =
- rtx_state_.find(seq); // this should always return a valid iter
- if (rtx_it->second.rtx_count_ >= RTC_MAX_RTX ||
- (now - rtx_it->second.first_send_) >= RTC_MAX_AGE ||
- seq < state_->getLastSeqNacked()) {
- // max rtx reached or packet too old or packet nacked, this packet is lost
- DLOG_IF(INFO, VLOG_IS_ON(3))
- << "packet " << seq << " lost because 1) max rtx: "
- << (rtx_it->second.rtx_count_ >= RTC_MAX_RTX) << " 2) max age: "
- << ((now - rtx_it->second.first_send_) >= RTC_MAX_AGE)
- << " 3) nacked: " << (seq < state_->getLastSeqNacked());
- lost_pkt.insert(seq);
- it++;
- } else {
- // resend the packet
- state_->onRetransmission(seq);
- double prod_rate = state_->getProducerRate();
- if (prod_rate != 0) rtx_it->second.rtx_count_++;
- rtx_it->second.next_send_ = computeNextSend(seq, false);
- it = rtx_timers_.erase(it);
- rtx_timers_.insert(
- std::pair<uint64_t, uint32_t>(rtx_it->second.next_send_, seq));
- DLOG_IF(INFO, VLOG_IS_ON(3))
- << "send rtx for sequence " << seq << ", next send in "
- << (rtx_it->second.next_send_ - now);
- send_rtx_callback_(seq);
- sent_counter++;
- }
- }
-
- // remove packets if needed
- for (auto lost_it = lost_pkt.begin(); lost_it != lost_pkt.end(); lost_it++) {
- uint32_t seq = *lost_it;
- state_->onPacketLost(seq);
- deleteRtx(seq);
- }
-}
-
-void RTCLossDetectionAndRecovery::scheduleNextRtx() {
- if (rtx_timers_.size() == 0) {
- // all the rtx were removed, reset timer
- next_rtx_timer_ = MAX_TIMER_RTX;
- return;
- }
-
- // check if timer is alreay set
- if (next_rtx_timer_ != MAX_TIMER_RTX) {
- // a new check for rtx is already scheduled
- if (next_rtx_timer_ > rtx_timers_.begin()->first) {
- // we need to re-schedule it
- timer_->cancel();
- } else {
- // wait for the next timer
- return;
- }
- }
-
- // set a new timer
- next_rtx_timer_ = rtx_timers_.begin()->first;
- uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
- uint64_t wait = 1;
- if (next_rtx_timer_ != MAX_TIMER_RTX && next_rtx_timer_ > now)
- wait = next_rtx_timer_ - now;
-
- std::weak_ptr<RTCLossDetectionAndRecovery> self(shared_from_this());
- timer_->expires_from_now(std::chrono::milliseconds(wait));
- timer_->async_wait([self](std::error_code ec) {
- if (ec) return;
- if (auto s = self.lock()) {
- s->retransmit();
- s->next_rtx_timer_ = MAX_TIMER_RTX;
- s->scheduleNextRtx();
- }
- });
-}
-
-bool RTCLossDetectionAndRecovery::deleteRtx(uint32_t seq) {
- auto it_rtx = rtx_state_.find(seq);
- if (it_rtx == rtx_state_.end()) return false; // rtx not found
-
- uint64_t ts = it_rtx->second.next_send_;
- auto it_timers = rtx_timers_.find(ts);
- while (it_timers != rtx_timers_.end() && it_timers->first == ts) {
- if (it_timers->second == seq) {
- rtx_timers_.erase(it_timers);
- break;
- }
- it_timers++;
- }
-
- bool lost = it_rtx->second.rtx_count_ > 0;
- rtx_state_.erase(it_rtx);
-
- return lost;
-}
-
-void RTCLossDetectionAndRecovery::scheduleSentinelTimer(
- uint64_t expires_from_now) {
- std::weak_ptr<RTCLossDetectionAndRecovery> self(shared_from_this());
- sentinel_timer_->expires_from_now(
- std::chrono::milliseconds(expires_from_now));
- sentinel_timer_->async_wait([self](std::error_code ec) {
- if (ec) return;
- if (auto s = self.lock()) {
- s->sentinelTimer();
- }
- });
-}
-
-void RTCLossDetectionAndRecovery::sentinelTimer() {
- uint64_t now = getNow();
-
- bool expired = false;
- bool sent = false;
- if ((now - last_event_) >= sentinel_timer_interval_) {
- // at least a sentinel_timer_interval_ elapsed since last event
- expired = true;
- if (TRANSPORT_EXPECT_FALSE(!state_->isProducerActive())) {
- // this happens at the beginning (or if the producer stops for some
- // reason) we need to keep sending interest 0 until we get an answer
- DLOG_IF(INFO, VLOG_IS_ON(3))
- << "sentinel timer: the producer is not active, send packet 0";
- state_->onRetransmission(0);
- send_rtx_callback_(0);
- } else {
- DLOG_IF(INFO, VLOG_IS_ON(3)) << "sentinel timer: the producer is active, "
- "send the 10 oldest packets";
- sent = true;
- uint32_t rtx = 0;
- auto it = state_->getPendingInterestsMapBegin();
- auto end = state_->getPendingInterestsMapEnd();
- while (it != end && rtx < MAX_RTX_WITH_SENTINEL) {
- uint32_t seq = it->first;
- DLOG_IF(INFO, VLOG_IS_ON(3))
- << "sentinel timer, add " << seq << " to the rtx list";
- addToRetransmissions(seq, seq + 1);
- rtx++;
- it++;
- }
- }
- } else {
- // sentinel timer did not expire because we registered at least one event
- }
-
- uint32_t next_timer;
- double prod_rate = state_->getProducerRate();
- if (TRANSPORT_EXPECT_FALSE(!state_->isProducerActive()) || prod_rate == 0) {
- DLOG_IF(INFO, VLOG_IS_ON(3)) << "next timer in " << SENTINEL_TIMER_INTERVAL;
- next_timer = SENTINEL_TIMER_INTERVAL;
- } else {
- double prod_rate = state_->getProducerRate();
- double packet_size = state_->getAveragePacketSize();
- uint32_t estimated_iat = ceil(1000.0 / (prod_rate / packet_size));
- uint32_t jitter = ceil(state_->getJitter());
-
- // try to reduce the number of timers if the estimated IAT is too small
- next_timer = std::max((estimated_iat + jitter) * 20, (uint32_t)1);
- DLOG_IF(INFO, VLOG_IS_ON(3))
- << "next sentinel in " << next_timer
- << " ms, rate: " << ((prod_rate * 8.0) / 1000000.0)
- << ", iat: " << estimated_iat << ", jitter: " << jitter;
-
- if (!expired) {
- // discount the amout of time that is already passed
- uint32_t discount = now - last_event_;
- if (next_timer > discount) {
- next_timer = next_timer - discount;
- } else {
- // in this case we trigger the timer in 1 ms
- next_timer = 1;
+ if (rs_->getState()->getPacketState(seq) == PacketState::UNKNOWN) {
+ if (rs_->lossDetected(seq)) {
+ rs_->getState()->onLossDetected(seq);
}
- DLOG_IF(INFO, VLOG_IS_ON(3)) << "timer after discout: " << next_timer;
- } else if (sent) {
- // wait at least one producer stats interval + owd to check if the
- // production rate is reducing.
- uint32_t min_wait = PRODUCER_STATS_INTERVAL + ceil(state_->getQueuing());
- next_timer = std::max(next_timer, min_wait);
- DLOG_IF(INFO, VLOG_IS_ON(3))
- << "wait for updates from prod, next timer: " << next_timer;
}
}
-
- scheduleSentinelTimer(next_timer);
}
} // namespace rtc
diff --git a/libtransport/src/protocols/rtc/rtc_ldr.h b/libtransport/src/protocols/rtc/rtc_ldr.h
index 1b9f9afd6..e7f8ce5db 100644
--- a/libtransport/src/protocols/rtc/rtc_ldr.h
+++ b/libtransport/src/protocols/rtc/rtc_ldr.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2021 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -15,16 +15,14 @@
#pragma once
#include <hicn/transport/config.h>
+#include <hicn/transport/interfaces/socket_options_keys.h>
+// RtcTransportRecoveryStrategies
#include <hicn/transport/core/asio_wrapper.h>
#include <hicn/transport/core/content_object.h>
#include <hicn/transport/core/name.h>
-#include <protocols/indexer.h>
-#include <protocols/rtc/rtc_consts.h>
-#include <protocols/rtc/rtc_state.h>
+#include <protocols/rtc/rtc_recovery_strategy.h>
#include <functional>
-#include <map>
-#include <unordered_map>
namespace transport {
@@ -34,91 +32,45 @@ namespace rtc {
class RTCLossDetectionAndRecovery
: public std::enable_shared_from_this<RTCLossDetectionAndRecovery> {
- struct rtx_state_ {
- uint64_t first_send_;
- uint64_t next_send_;
- uint32_t rtx_count_;
- };
-
- using rtxState = struct rtx_state_;
- using SendRtxCallback = std::function<void(uint32_t)>;
-
public:
- RTCLossDetectionAndRecovery(Indexer *indexer, SendRtxCallback &&callback,
- asio::io_service &io_service);
+ RTCLossDetectionAndRecovery(Indexer *indexer, asio::io_service &io_service,
+ interface::RtcTransportRecoveryStrategies type,
+ RecoveryStrategy::SendRtxCallback &&callback,
+ interface::StrategyCallback *external_callback);
~RTCLossDetectionAndRecovery();
- void setState(std::shared_ptr<RTCState> state) { state_ = state; }
- void setFecParams(uint32_t n, uint32_t k) {
- n_ = n;
- k_ = k;
+ void setState(RTCState *state) { rs_->setState(state); }
+ void setRateControl(RTCRateControl *rateControl) {
+ rs_->setRateControl(rateControl);
}
- void turnOnRTX();
- void turnOffRTX();
- bool isRtxOn() { return rtx_on_; }
+
+ void setFecParams(uint32_t n, uint32_t k) { rs_->setFecParams(n, k); }
+
+ void turnOnRecovery() { rs_->tunrOnRecovery(); }
+ bool isRtxOn() { return rs_->isRtxOn(); }
+
+ void changeRecoveryStrategy(interface::RtcTransportRecoveryStrategies type);
void onNewRound(bool in_sync);
- void onTimeout(uint32_t seq);
+ void onTimeout(uint32_t seq, bool lost);
void onPacketRecoveredFec(uint32_t seq);
void onDataPacketReceived(const core::ContentObject &content_object);
void onNackPacketReceived(const core::ContentObject &nack);
void onProbePacketReceived(const core::ContentObject &probe);
- void clear();
+ void clear() { rs_->clear(); }
- bool isRtx(uint32_t seq) {
- if (rtx_state_.find(seq) != rtx_state_.end()) return true;
- return false;
+ bool isRtx(uint32_t seq) { return rs_->isRtx(seq); }
+ bool isPossibleLossWithNoRtx(uint32_t seq) {
+ return rs_->isPossibleLossWithNoRtx(seq);
}
private:
- void addToRetransmissions(uint32_t start, uint32_t stop);
- uint64_t computeNextSend(uint32_t seq, bool new_rtx);
- void retransmit();
- void scheduleNextRtx();
- bool deleteRtx(uint32_t seq);
- void scheduleSentinelTimer(uint64_t expires_from_now);
- void sentinelTimer();
- uint32_t computeFecPacketsToAsk(bool in_sync);
-
- uint64_t getNow() {
- using namespace std::chrono;
- uint64_t now =
- duration_cast<milliseconds>(steady_clock::now().time_since_epoch())
- .count();
- return now;
- }
-
- // this map keeps track of the retransmitted interest, ordered from the oldest
- // to the newest one. the state contains the timer of the first send of the
- // interest (from pendingIntetests_), the timer of the next send (key of the
- // multimap) and the number of rtx
- std::map<uint32_t, rtxState> rtx_state_;
- // this map stored the rtx by timer. The key is the time at which the rtx
- // should be sent, and the val is the interest seq number
- std::multimap<uint64_t, uint32_t> rtx_timers_;
-
- // lost packets that will be recovered with fec
- std::unordered_set<uint32_t> recover_with_fec_;
-
- bool rtx_on_;
- bool fec_on_;
- uint64_t next_rtx_timer_;
- uint64_t last_event_;
- uint64_t sentinel_timer_interval_;
-
- // fec params
- uint32_t n_;
- uint32_t k_;
-
- std::unique_ptr<asio::steady_timer> timer_;
- std::unique_ptr<asio::steady_timer> sentinel_timer_;
- std::shared_ptr<RTCState> state_;
-
- Indexer *indexer_;
+ void detectLoss(uint32_t start, uint32_t stop);
- SendRtxCallback send_rtx_callback_;
+ interface::RtcTransportRecoveryStrategies rs_type_;
+ std::shared_ptr<RecoveryStrategy> rs_;
};
} // end namespace rtc
diff --git a/libtransport/src/protocols/rtc/rtc_packet.h b/libtransport/src/protocols/rtc/rtc_packet.h
index 7dc2f82c3..391aedfc6 100644
--- a/libtransport/src/protocols/rtc/rtc_packet.h
+++ b/libtransport/src/protocols/rtc/rtc_packet.h
@@ -24,6 +24,27 @@
* +-----------------------------------------+
*/
+/* aggregated packets
+ * +---------------------------------+
+ * |c| #pkts | len1 | len2 | .... |
+ * +----------------------------------
+ *
+ * +---------------------------------+
+ * |c| #pkts | resv | len 1 |
+ * +----------------------------------
+ *
+ * aggregated packets header.
+ * header position. just after the data packet header
+ *
+ * c: 1 bit: 0 8bit encoding, 1 16bit encoding
+ * #pkts: 7 bits: number of application packets contained
+ * 8bits encoding:
+ * lenX: 8 bits: len in bites of packet X
+ * 16bits econding:
+ * resv: 8 bits: reserved field (unused)
+ * lenX: 16bits: len in bytes of packet X
+ */
+
#pragma once
#ifndef _WIN32
#include <arpa/inet.h>
@@ -31,6 +52,8 @@
#include <hicn/transport/portability/win_portability.h>
#endif
+#include <cstring>
+
namespace transport {
namespace protocol {
@@ -82,8 +105,144 @@ struct nack_packet_t {
inline uint32_t getProductionRate() const { return ntohl(prod_rate); }
inline void setProductionRate(uint32_t rate) { prod_rate = htonl(rate); }
- inline uint32_t getProductionSegement() const { return ntohl(prod_seg); }
- inline void setProductionSegement(uint32_t seg) { prod_seg = htonl(seg); }
+ inline uint32_t getProductionSegment() const { return ntohl(prod_seg); }
+ inline void setProductionSegment(uint32_t seg) { prod_seg = htonl(seg); }
+};
+
+class AggrPktHeader {
+ public:
+ // XXX buf always point to the payload after the data header
+ AggrPktHeader(uint8_t *buf, uint16_t max_packet_len, uint16_t pkt_number)
+ : buf_(buf), pkt_num_(pkt_number) {
+ *buf_ = 0; // reset the first byte to correctly add the header
+ // encoding and the packet number
+ if (max_packet_len > 0xff) {
+ setAggrPktEncoding16bit();
+ } else {
+ setAggrPktEncoding8bit();
+ }
+ setAggrPktNUmber(pkt_number);
+ header_len_ = computeHeaderLen();
+ memset(buf_ + 1, 0, header_len_ - 1);
+ }
+
+ // XXX buf always point to the payload after the data header
+ AggrPktHeader(uint8_t *buf) : buf_(buf) {
+ encoding_ = getAggrPktEncoding();
+ pkt_num_ = getAggrPktNumber();
+ header_len_ = computeHeaderLen();
+ }
+
+ ~AggrPktHeader(){};
+
+ int addPacketToHeader(uint8_t index, uint16_t len) {
+ if (index > pkt_num_) return -1;
+
+ setAggrPktLen(index, len);
+ return 0;
+ }
+
+ int getPointerToPacket(uint8_t index, uint8_t **pkt_ptr, uint16_t *pkt_len) {
+ if (index > pkt_num_) return -1;
+
+ uint16_t len = 0;
+ for (int i = 0; i < index; i++)
+ len += getAggrPktLen(i); // sum the pkts len from 0 to index - 1
+
+ uint16_t offset = len + header_len_;
+ *pkt_ptr = buf_ + offset;
+ *pkt_len = getAggrPktLen(index);
+ return 0;
+ }
+
+ int getPacketOffsets(uint8_t index, uint16_t *pkt_offset, uint16_t *pkt_len) {
+ if (index > pkt_num_) return -1;
+
+ uint16_t len = 0;
+ for (int i = 0; i < index; i++)
+ len += getAggrPktLen(i); // sum the pkts len from 0 to index - 1
+
+ uint16_t offset = len + header_len_;
+ *pkt_offset = offset;
+ *pkt_len = getAggrPktLen(index);
+
+ return 0;
+ }
+
+ uint8_t *getPayloadAppendPtr() { return buf_ + header_len_; }
+
+ uint16_t getHeaderLen() { return header_len_; }
+
+ uint8_t getNumberOfPackets() { return pkt_num_; }
+
+ private:
+ inline uint16_t computeHeaderLen() const {
+ uint16_t len = 4; // min len in bytes
+ if (!encoding_) {
+ while (pkt_num_ >= len) {
+ len += 4;
+ }
+ } else {
+ while (pkt_num_ * 2 >= len) {
+ len += 4;
+ }
+ }
+ return len;
+ }
+
+ inline uint8_t getAggrPktEncoding() const {
+ // get the first bit of the first byte
+ return (*buf_ >> 7);
+ }
+
+ inline void setAggrPktEncoding8bit() {
+ // reset the first bit of the first byte
+ encoding_ = 0;
+ *buf_ &= 0x7f;
+ }
+
+ inline void setAggrPktEncoding16bit() {
+ // set the first bit of the first byte
+ encoding_ = 1;
+ *buf_ ^= 0x80;
+ }
+
+ inline uint8_t getAggrPktNumber() const {
+ // return the first byte with the first bit = 0
+ return (*buf_ & 0x7f);
+ }
+
+ inline void setAggrPktNUmber(uint8_t val) {
+ // set the val without modifying the first bit
+ *buf_ &= 0x80; // reset everithing but the first bit
+ val &= 0x7f; // reset the first bit
+ *buf_ |= val; // or the vals, done!
+ }
+
+ inline uint16_t getAggrPktLen(uint8_t pkt_index) const {
+ pkt_index++;
+ if (!encoding_) { // 8 bits
+ return (uint16_t) * (buf_ + pkt_index);
+ } else { // 16 bits
+ uint16_t *buf_16 = (uint16_t *)buf_;
+ return ntohs(*(buf_16 + pkt_index));
+ }
+ }
+
+ inline void setAggrPktLen(uint8_t pkt_index, uint16_t len) {
+ pkt_index++;
+ if (!encoding_) { // 8 bits
+ *(buf_ + pkt_index) = (uint8_t)len;
+ } else { // 16 bits
+ uint16_t *buf_16 = (uint16_t *)buf_;
+ *(buf_16 + pkt_index) = htons(len);
+ }
+ }
+
+ uint8_t *buf_;
+ uint8_t encoding_;
+ uint8_t pkt_num_;
+ uint16_t header_len_;
};
} // end namespace rtc
diff --git a/libtransport/src/protocols/rtc/rtc_rc.h b/libtransport/src/protocols/rtc/rtc_rc.h
index 34d090092..62636ce40 100644
--- a/libtransport/src/protocols/rtc/rtc_rc.h
+++ b/libtransport/src/protocols/rtc/rtc_rc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2021 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -34,11 +34,15 @@ class RTCRateControl : public std::enable_shared_from_this<RTCRateControl> {
void turnOnRateControl() { rc_on_ = true; }
void setState(std::shared_ptr<RTCState> state) { protocol_state_ = state; };
- uint32_t getCongesionWindow() { return congestion_win_; };
+ uint32_t getCongestionWindow() { return congestion_win_; };
+ bool inCongestionState() {
+ if (congestion_state_ == CongestionState::Congested) return true;
+ return false;
+ }
virtual void onNewRound(double round_len) = 0;
- virtual void onDataPacketReceived(
- const core::ContentObject &content_object) = 0;
+ virtual void onDataPacketReceived(const core::ContentObject &content_object,
+ bool compute_stats) = 0;
protected:
enum class CongestionState { Normal = 0, Underuse = 1, Congested = 2, Last };
diff --git a/libtransport/src/protocols/rtc/rtc_rc_congestion_detection.cc b/libtransport/src/protocols/rtc/rtc_rc_congestion_detection.cc
new file mode 100644
index 000000000..6cd3094b5
--- /dev/null
+++ b/libtransport/src/protocols/rtc/rtc_rc_congestion_detection.cc
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <protocols/rtc/rtc_consts.h>
+#include <protocols/rtc/rtc_rc_congestion_detection.h>
+
+#include <algorithm>
+
+namespace transport {
+
+namespace protocol {
+
+namespace rtc {
+
+RTCRateControlCongestionDetection::RTCRateControlCongestionDetection()
+ : rounds_without_congestion_(4), last_queue_(0) {} // must be > 3
+
+RTCRateControlCongestionDetection::~RTCRateControlCongestionDetection() {}
+
+void RTCRateControlCongestionDetection::onNewRound(double round_len) {
+ if (!rc_on_) return;
+
+ double rtt = (double)protocol_state_->getMinRTT() / MILLI_IN_A_SEC;
+ double queue = protocol_state_->getQueuing();
+
+ if (rtt == 0.0) return; // no info from the producer
+
+ if (last_queue_ == queue) {
+ // if last_queue == queue the consumer didn't receive any
+ // packet from the producer. we do not change the current congestion state.
+ // we just increase the counter of rounds whithout congestion if needed
+ // (in case of congestion the counter is already set to 0)
+ if (congestion_state_ == CongestionState::Normal)
+ rounds_without_congestion_++;
+ } else {
+ if (queue > MAX_QUEUING_DELAY) {
+ // here we detect congestion.
+ congestion_state_ = CongestionState::Congested;
+ rounds_without_congestion_ = 0;
+ } else {
+ // wait 3 rounds before switch back to no congestion
+ if (rounds_without_congestion_ > 3) {
+ // nothing bad is happening
+ congestion_state_ = CongestionState::Normal;
+ }
+ rounds_without_congestion_++;
+ }
+ last_queue_ = queue;
+ }
+}
+
+void RTCRateControlCongestionDetection::onDataPacketReceived(
+ const core::ContentObject &content_object, bool compute_stats) {
+ // nothing to do
+ return;
+}
+
+} // end namespace rtc
+
+} // end namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/protocols/rtc/rtc_rc_congestion_detection.h b/libtransport/src/protocols/rtc/rtc_rc_congestion_detection.h
new file mode 100644
index 000000000..9afa6c39a
--- /dev/null
+++ b/libtransport/src/protocols/rtc/rtc_rc_congestion_detection.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <hicn/transport/utils/shared_ptr_utils.h>
+#include <protocols/rtc/rtc_rc.h>
+
+namespace transport {
+
+namespace protocol {
+
+namespace rtc {
+
+class RTCRateControlCongestionDetection : public RTCRateControl {
+ public:
+ RTCRateControlCongestionDetection();
+
+ ~RTCRateControlCongestionDetection();
+
+ void onNewRound(double round_len);
+ void onDataPacketReceived(const core::ContentObject &content_object,
+ bool compute_stats);
+
+ auto shared_from_this() { return utils::shared_from(this); }
+
+ private:
+ uint32_t rounds_without_congestion_;
+ double last_queue_;
+};
+
+} // end namespace rtc
+
+} // end namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/protocols/rtc/rtc_rc_iat.cc b/libtransport/src/protocols/rtc/rtc_rc_iat.cc
new file mode 100644
index 000000000..f06f377f3
--- /dev/null
+++ b/libtransport/src/protocols/rtc/rtc_rc_iat.cc
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <protocols/rtc/rtc_consts.h>
+#include <protocols/rtc/rtc_rc_iat.h>
+
+namespace transport {
+
+namespace protocol {
+
+namespace rtc {
+
+RTCRateControlIAT::RTCRateControlIAT()
+ : rounds_since_last_drop_(0),
+ rounds_without_congestion_(0),
+ rounds_with_congestion_(0),
+ last_queue_(0),
+ last_rcv_time_(0),
+ last_prod_time_(0),
+ last_seq_number_(0),
+ target_rate_avg_(0),
+ round_index_(0),
+ congestion_cause_(CongestionCause::UNKNOWN) {}
+
+RTCRateControlIAT::~RTCRateControlIAT() {}
+
+void RTCRateControlIAT::onNewRound(double round_len) {
+ if (!rc_on_) return;
+
+ double received_rate = protocol_state_->getReceivedRate() +
+ protocol_state_->getRecoveredFecRate();
+
+ double target_rate =
+ protocol_state_->getProducerRate(); // * PRODUCTION_RATE_FRACTION;
+ double rtt = (double)protocol_state_->getMinRTT() / MILLI_IN_A_SEC;
+ // double packet_size = protocol_state_->getAveragePacketSize();
+ double queue = protocol_state_->getQueuing();
+
+ if (rtt == 0.0) return; // no info from the producer
+
+ CongestionState prev_congestion_state = congestion_state_;
+
+ target_rate_avg_ = target_rate_avg_ * (1 - MOVING_AVG_ALPHA) +
+ target_rate * MOVING_AVG_ALPHA;
+
+ if (prev_congestion_state == CongestionState::Congested) {
+ if (queue > MAX_QUEUING_DELAY || last_queue_ == queue) {
+ congestion_state_ = CongestionState::Congested;
+
+ received_rate_.push_back(received_rate);
+ target_rate_.push_back(target_rate);
+
+ // We assume the cause does not change
+ // Note that the first assumption about the cause could be wrong
+ // the cause of congestion could change
+ if (congestion_cause_ == CongestionCause::UNKNOWN)
+ if (rounds_with_congestion_ >= 1)
+ congestion_cause_ = apply_classification_tree(
+ rounds_with_congestion_ > ROUND_TO_WAIT_FORCE_DECISION);
+
+ rounds_with_congestion_++;
+ } else {
+ congestion_state_ = CongestionState::Normal;
+
+ // clear past history
+ reset_congestion_statistics();
+
+ // TODO maybe we can use some of these values for the stdev of the
+ // congestion mode
+ for (int i = 0; i < ROUND_HISTORY_SIZE; i++) {
+ iat_on_hold_[i].clear();
+ }
+ }
+ } else if (queue > MAX_QUEUING_DELAY) {
+ if (prev_congestion_state == CongestionState::Normal) {
+ rounds_with_congestion_ = 0;
+
+ if (rounds_without_congestion_ > ROUND_TO_RESET_CAUSE)
+ congestion_cause_ = CongestionCause::UNKNOWN;
+ }
+ congestion_state_ = CongestionState::Congested;
+ received_rate_.push_back(received_rate);
+ target_rate_.push_back(target_rate);
+ } else {
+ // nothing bad is happening
+ congestion_state_ = CongestionState::Normal;
+ reset_congestion_statistics();
+
+ int past_index = (round_index_ + 1) % ROUND_HISTORY_SIZE;
+ for (std::vector<double>::iterator it = iat_on_hold_[past_index].begin();
+ it != iat_on_hold_[past_index].end(); ++it) {
+ congestion_free_iat_.push_back(*it);
+ if (congestion_free_iat_.size() > 50) {
+ congestion_free_iat_.erase(congestion_free_iat_.begin());
+ }
+ }
+ iat_on_hold_[past_index].clear();
+ round_index_ = (round_index_ + 1) % ROUND_HISTORY_SIZE;
+ }
+
+ last_queue_ = queue;
+
+ if (congestion_state_ == CongestionState::Congested) {
+ if (prev_congestion_state == CongestionState::Normal) {
+ // init the congetion window using the received rate
+ // disabling for the moment the congestion window setup
+ // congestion_win_ = (uint32_t)ceil(received_rate * rtt / packet_size);
+ rounds_since_last_drop_ = ROUNDS_BEFORE_TAKE_ACTION + 1;
+ }
+
+ if (rounds_since_last_drop_ >= ROUNDS_BEFORE_TAKE_ACTION) {
+ // disabling for the moment the congestion window setup
+ // uint32_t win = congestion_win_ * WIN_DECREASE_FACTOR;
+ // congestion_win_ = std::max(win, WIN_MIN);
+ rounds_since_last_drop_ = 0;
+ return;
+ }
+
+ rounds_since_last_drop_++;
+ }
+
+ if (congestion_state_ == CongestionState::Normal) {
+ if (prev_congestion_state == CongestionState::Congested) {
+ rounds_without_congestion_ = 0;
+ }
+
+ rounds_without_congestion_++;
+ if (rounds_without_congestion_ < ROUNDS_BEFORE_TAKE_ACTION) return;
+
+ // disabling for the moment the congestion window setup
+ // congestion_win_ = congestion_win_ * WIN_INCREASE_FACTOR;
+ // congestion_win_ = std::min(congestion_win_, INITIAL_WIN_MAX);
+ }
+
+ if (received_rate_.size() > 1000)
+ received_rate_.erase(received_rate_.begin());
+ if (target_rate_.size() > 1000) target_rate_.erase(target_rate_.begin());
+}
+
+void RTCRateControlIAT::onDataPacketReceived(
+ const core::ContentObject &content_object, bool compute_stats) {
+ core::ParamsRTC params = RTCState::getDataParams(content_object);
+
+ uint64_t now = utils::SteadyTime::nowMs().count();
+
+ uint32_t segment_number = content_object.getName().getSuffix();
+
+ if (segment_number == (last_seq_number_ + 1) && compute_stats) {
+ uint64_t iat = now - last_rcv_time_;
+ uint64_t ist = params.timestamp - last_prod_time_;
+ if (now >= last_rcv_time_ && params.timestamp > last_prod_time_) {
+ if (iat >= ist && ist < MIN_IST_VALUE) {
+ if (congestion_state_ == CongestionState::Congested) {
+ iat_.push_back((iat - ist));
+ } else {
+ // no congestion, but we do not always add new values, but only when
+ // there is no sign of congestion
+ double queue = protocol_state_->getQueuing();
+ if (queue <= CONGESTION_FREE_QUEUEING_DELAY) {
+ iat_on_hold_[round_index_].push_back((iat - ist));
+ }
+ }
+ }
+ }
+ }
+
+ last_seq_number_ = segment_number;
+ last_rcv_time_ = now;
+ last_prod_time_ = params.timestamp;
+
+ if (iat_.size() > 1000) iat_.erase(iat_.begin());
+ return;
+}
+
+CongestionCause RTCRateControlIAT::apply_classification_tree(bool force_reply) {
+ if (iat_.size() <= 2 || received_rate_.size() < 2)
+ return CongestionCause::UNKNOWN;
+
+ double received_ratio = 0;
+ double iat_ratio = 0;
+ double iat_stdev = compute_iat_stdev(iat_);
+ double iat_congestion_free_stdev = compute_iat_stdev(congestion_free_iat_);
+
+ double iat_avg = 0.0;
+
+ double recv_avg = 0.0;
+ double recv_max = 0.0;
+
+ double target_rate_avg = 0.0;
+
+ int counter = 0;
+ std::vector<double>::reverse_iterator target_it = target_rate_.rbegin();
+ for (std::vector<double>::reverse_iterator it = received_rate_.rbegin();
+ it != received_rate_.rend(); ++it) {
+ recv_avg += *it;
+ target_rate_avg += *target_it;
+ if (counter < ROUND_HISTORY_SIZE)
+ if (recv_max < *it) {
+ recv_max = *it; // we consider only the last 2 seconds
+ }
+ counter++;
+ target_it++;
+ }
+ recv_avg = recv_avg / received_rate_.size();
+ target_rate_avg = target_rate_avg / target_rate_.size();
+
+ for (std::vector<double>::iterator it = iat_.begin(); it != iat_.end();
+ ++it) {
+ iat_avg += *it;
+ }
+ iat_avg = iat_avg / iat_.size();
+
+ double congestion_free_iat_avg = 0.0;
+ for (std::vector<double>::iterator it = congestion_free_iat_.begin();
+ it != congestion_free_iat_.end(); ++it) {
+ congestion_free_iat_avg += *it;
+ }
+ congestion_free_iat_avg =
+ congestion_free_iat_avg / congestion_free_iat_.size();
+
+ received_ratio = recv_avg / target_rate_avg;
+
+ iat_ratio = iat_stdev / iat_congestion_free_stdev;
+
+ CongestionCause congestion_cause = CongestionCause::UNKNOWN;
+ // applying classification tree model
+ if (received_ratio <= 0.87)
+ if (iat_stdev <= 6.48)
+ if (received_ratio <= 0.83)
+ congestion_cause = CongestionCause::LINK_CAPACITY;
+ else if (force_reply)
+ congestion_cause = CongestionCause::LINK_CAPACITY;
+ else
+ congestion_cause = CongestionCause::UNKNOWN; // accuracy is too low
+ else if (iat_ratio <= 2.46)
+ if (force_reply)
+ congestion_cause = CongestionCause::LINK_CAPACITY;
+ else
+ congestion_cause = CongestionCause::UNKNOWN; // accuracy is too low
+ else
+ congestion_cause = CongestionCause::COMPETING_CROSS_TRAFFIC;
+ else if (received_ratio <= 0.913 && iat_stdev <= 0.784)
+ congestion_cause = CongestionCause::LINK_CAPACITY;
+ else
+ congestion_cause = CongestionCause::COMPETING_CROSS_TRAFFIC;
+
+ return congestion_cause;
+}
+
+void RTCRateControlIAT::reset_congestion_statistics() {
+ iat_.clear();
+ received_rate_.clear();
+ target_rate_.clear();
+}
+
+double RTCRateControlIAT::compute_iat_stdev(std::vector<double> v) {
+ if (v.size() == 0) return 0;
+
+ float sum = 0.0, mean, standard_deviation = 0.0;
+ for (std::vector<double>::iterator it = v.begin(); it != v.end(); it++) {
+ sum += *it;
+ }
+
+ mean = sum / v.size();
+ for (std::vector<double>::iterator it = v.begin(); it != v.end(); it++) {
+ standard_deviation += pow(*it - mean, 2);
+ }
+ return sqrt(standard_deviation / v.size());
+}
+
+} // end namespace rtc
+
+} // end namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/protocols/rtc/rtc_rc_iat.h b/libtransport/src/protocols/rtc/rtc_rc_iat.h
new file mode 100644
index 000000000..715637807
--- /dev/null
+++ b/libtransport/src/protocols/rtc/rtc_rc_iat.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <hicn/transport/utils/shared_ptr_utils.h>
+#include <protocols/rtc/rtc_rc.h>
+
+namespace transport {
+
+namespace protocol {
+
+namespace rtc {
+
+const int ROUND_HISTORY_SIZE = 10; // equivalent to two seconds
+const int ROUND_TO_WAIT_FORCE_DECISION = 5;
+
+// once congestion is gone, we need to wait for k rounds before changing the
+// congestion cause in the case it appears again
+const int ROUND_TO_RESET_CAUSE = 5;
+
+const int MIN_IST_VALUE = 150; // samples of ist larger than 150ms are
+ // discarded
+const double CONGESTION_FREE_QUEUEING_DELAY = 10;
+
+enum class CongestionCause : uint8_t {
+ COMPETING_CROSS_TRAFFIC,
+ FRIENDLY_CROSS_TRAFFIC,
+ UNKNOWN_CROSS_TRAFFIC,
+ LINK_CAPACITY,
+ UNKNOWN
+};
+
+class RTCRateControlIAT : public RTCRateControl {
+ public:
+ RTCRateControlIAT();
+
+ ~RTCRateControlIAT();
+
+ void onNewRound(double round_len);
+ void onDataPacketReceived(const core::ContentObject &content_object,
+ bool compute_stats);
+
+ auto shared_from_this() { return utils::shared_from(this); }
+
+ private:
+ void reset_congestion_statistics();
+
+ double compute_iat_stdev(std::vector<double> v);
+
+ CongestionCause apply_classification_tree(bool force_reply);
+
+ private:
+ uint32_t rounds_since_last_drop_;
+ uint32_t rounds_without_congestion_;
+ uint32_t rounds_with_congestion_;
+ double last_queue_;
+ uint64_t last_rcv_time_;
+ uint64_t last_prod_time_;
+ uint32_t last_seq_number_;
+ double target_rate_avg_;
+
+ // Iat values are not immediately added to the congestion free set of values
+ std::array<std::vector<double>, ROUND_HISTORY_SIZE> iat_on_hold_;
+ uint32_t round_index_;
+
+ // with congestion statistics
+ std::vector<double> iat_;
+ std::vector<double> received_rate_;
+ std::vector<double> target_rate_;
+
+ // congestion free statistics
+ std::vector<double> congestion_free_iat_;
+
+ CongestionCause congestion_cause_;
+};
+
+} // end namespace rtc
+
+} // end namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/protocols/rtc/rtc_rc_queue.cc b/libtransport/src/protocols/rtc/rtc_rc_queue.cc
index a1c89e329..ecabc5205 100644
--- a/libtransport/src/protocols/rtc/rtc_rc_queue.cc
+++ b/libtransport/src/protocols/rtc/rtc_rc_queue.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2021 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -37,7 +37,7 @@ void RTCRateControlQueue::onNewRound(double round_len) {
double received_rate = protocol_state_->getReceivedRate();
double target_rate =
protocol_state_->getProducerRate() * PRODUCTION_RATE_FRACTION;
- double rtt = (double)protocol_state_->getRTT() / MILLI_IN_A_SEC;
+ double rtt = (double)protocol_state_->getMinRTT() / MILLI_IN_A_SEC;
double packet_size = protocol_state_->getAveragePacketSize();
double queue = protocol_state_->getQueuing();
@@ -94,7 +94,7 @@ void RTCRateControlQueue::onNewRound(double round_len) {
}
void RTCRateControlQueue::onDataPacketReceived(
- const core::ContentObject &content_object) {
+ const core::ContentObject &content_object, bool compute_stats) {
// nothing to do
return;
}
diff --git a/libtransport/src/protocols/rtc/rtc_rc_queue.h b/libtransport/src/protocols/rtc/rtc_rc_queue.h
index 407354d43..cdf78fd47 100644
--- a/libtransport/src/protocols/rtc/rtc_rc_queue.h
+++ b/libtransport/src/protocols/rtc/rtc_rc_queue.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2021 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -30,7 +30,8 @@ class RTCRateControlQueue : public RTCRateControl {
~RTCRateControlQueue();
void onNewRound(double round_len);
- void onDataPacketReceived(const core::ContentObject &content_object);
+ void onDataPacketReceived(const core::ContentObject &content_object,
+ bool compute_stats);
auto shared_from_this() { return utils::shared_from(this); }
diff --git a/libtransport/src/protocols/rtc/rtc_reassembly.cc b/libtransport/src/protocols/rtc/rtc_reassembly.cc
new file mode 100644
index 000000000..992bab50e
--- /dev/null
+++ b/libtransport/src/protocols/rtc/rtc_reassembly.cc
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <hicn/transport/interfaces/socket_consumer.h>
+#include <implementation/socket_consumer.h>
+#include <protocols/rtc/rtc_reassembly.h>
+#include <protocols/transport_protocol.h>
+
+namespace transport {
+
+namespace protocol {
+
+namespace rtc {
+
+RtcReassembly::RtcReassembly(implementation::ConsumerSocket* icn_socket,
+ TransportProtocol* transport_protocol)
+ : DatagramReassembly(icn_socket, transport_protocol) {
+ is_setup_ = false;
+}
+
+void RtcReassembly::reassemble(core::ContentObject& content_object) {
+ if (!is_setup_) {
+ is_setup_ = true;
+ reassembly_consumer_socket_->getSocketOption(
+ interface::RtcTransportOptions::AGGREGATED_DATA, data_aggregation_);
+ }
+
+ auto read_buffer = content_object.getPayload();
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Size of payload: " << read_buffer->length();
+
+ read_buffer->trimStart(transport_protocol_->transportHeaderLength());
+
+ if (data_aggregation_) {
+ rtc::AggrPktHeader hdr((uint8_t*)read_buffer->data());
+
+ for (uint8_t i = 0; i < hdr.getNumberOfPackets(); i++) {
+ std::unique_ptr<utils::MemBuf> segment = read_buffer->clone();
+
+ uint16_t pkt_start = 0;
+ uint16_t pkt_len = 0;
+ int res = hdr.getPacketOffsets(i, &pkt_start, &pkt_len);
+ if (res == -1) {
+ // this should not happen
+ break;
+ }
+
+ segment->trimStart(pkt_start);
+ segment->trimEnd(segment->length() - pkt_len);
+
+ Reassembly::read_buffer_ = std::move(segment);
+ Reassembly::notifyApplication();
+ }
+ } else {
+ Reassembly::read_buffer_ = std::move(read_buffer);
+ Reassembly::notifyApplication();
+ }
+}
+
+void RtcReassembly::reassemble(utils::MemBuf& buffer, uint32_t suffix) {
+ if (!is_setup_) {
+ is_setup_ = true;
+ reassembly_consumer_socket_->getSocketOption(
+ interface::RtcTransportOptions::AGGREGATED_DATA, data_aggregation_);
+ }
+
+ if (data_aggregation_) {
+ rtc::AggrPktHeader hdr((uint8_t*)buffer.data());
+
+ for (uint8_t i = 0; i < hdr.getNumberOfPackets(); i++) {
+ std::unique_ptr<utils::MemBuf> segment = buffer.clone();
+
+ uint16_t pkt_start = 0;
+ uint16_t pkt_len = 0;
+ int res = hdr.getPacketOffsets(i, &pkt_start, &pkt_len);
+ if (res == -1) {
+ // this should not happen
+ break;
+ }
+
+ segment->trimStart(pkt_start);
+ segment->trimEnd(segment->length() - pkt_len);
+
+ Reassembly::read_buffer_ = std::move(segment);
+ Reassembly::notifyApplication();
+ }
+
+ } else {
+ Reassembly::read_buffer_ = buffer.cloneOne();
+ Reassembly::notifyApplication();
+ }
+}
+
+} // namespace rtc
+
+} // namespace protocol
+
+} // namespace transport
diff --git a/libtransport/src/protocols/rtc/rtc_reassembly.h b/libtransport/src/protocols/rtc/rtc_reassembly.h
index 15722a6d5..132004605 100644
--- a/libtransport/src/protocols/rtc/rtc_reassembly.h
+++ b/libtransport/src/protocols/rtc/rtc_reassembly.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -28,17 +28,14 @@ namespace rtc {
class RtcReassembly : public DatagramReassembly {
public:
RtcReassembly(implementation::ConsumerSocket *icn_socket,
- TransportProtocol *transport_protocol)
- : DatagramReassembly(icn_socket, transport_protocol) {}
-
- void reassemble(core::ContentObject &content_object) override {
- auto read_buffer = content_object.getPayload();
- DLOG_IF(INFO, VLOG_IS_ON(3))
- << "Size of payload: " << read_buffer->length();
- read_buffer->trimStart(transport_protocol_->transportHeaderLength());
- Reassembly::read_buffer_ = std::move(read_buffer);
- Reassembly::notifyApplication();
- }
+ TransportProtocol *transport_protocol);
+
+ void reassemble(core::ContentObject &content_object) override;
+ void reassemble(utils::MemBuf &buffer, uint32_t suffix) override;
+
+ private:
+ bool is_setup_;
+ bool data_aggregation_;
};
} // namespace rtc
diff --git a/libtransport/src/protocols/rtc/rtc_recovery_strategy.cc b/libtransport/src/protocols/rtc/rtc_recovery_strategy.cc
new file mode 100644
index 000000000..888105eab
--- /dev/null
+++ b/libtransport/src/protocols/rtc/rtc_recovery_strategy.cc
@@ -0,0 +1,418 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <glog/logging.h>
+#include <hicn/transport/interfaces/notification.h>
+#include <hicn/transport/interfaces/socket_options_keys.h>
+#include <protocols/rtc/rtc_consts.h>
+#include <protocols/rtc/rtc_recovery_strategy.h>
+
+namespace transport {
+
+namespace protocol {
+
+namespace rtc {
+
+using namespace transport::interface;
+
+RecoveryStrategy::RecoveryStrategy(
+ Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service,
+ bool use_rtx, bool use_fec, interface::StrategyCallback *external_callback)
+ : recovery_on_(false),
+ next_rtx_timer_(MAX_TIMER_RTX),
+ send_rtx_callback_(std::move(callback)),
+ indexer_(indexer),
+ round_id_(0),
+ last_fec_used_(0),
+ callback_(external_callback) {
+ setRtxFec(use_rtx, use_fec);
+ timer_ = std::make_unique<asio::steady_timer>(io_service);
+}
+
+RecoveryStrategy::RecoveryStrategy(RecoveryStrategy &&rs)
+ : rtx_state_(std::move(rs.rtx_state_)),
+ rtx_timers_(std::move(rs.rtx_timers_)),
+ recover_with_fec_(std::move(rs.recover_with_fec_)),
+ timer_(std::move(rs.timer_)),
+ next_rtx_timer_(std::move(rs.next_rtx_timer_)),
+ send_rtx_callback_(std::move(rs.send_rtx_callback_)),
+ n_(std::move(rs.n_)),
+ k_(std::move(rs.k_)),
+ indexer_(std::move(rs.indexer_)),
+ state_(std::move(rs.state_)),
+ rc_(std::move(rs.rc_)),
+ round_id_(std::move(rs.round_id_)),
+ last_fec_used_(std::move(rs.last_fec_used_)),
+ callback_(rs.callback_) {
+ setFecParams(n_, k_);
+}
+
+RecoveryStrategy::~RecoveryStrategy() {}
+
+void RecoveryStrategy::setFecParams(uint32_t n, uint32_t k) {
+ n_ = n;
+ k_ = k;
+
+ // XXX for the moment we go in steps of 5% loss rate.
+ // max loss rate = 95%
+ for (uint32_t loss_rate = 5; loss_rate < 100; loss_rate += 5) {
+ double dec_loss_rate = (double)loss_rate / 100.0;
+ double exp_losses = (double)k_ * dec_loss_rate;
+ uint32_t fec_to_ask = ceil(exp_losses / (1 - dec_loss_rate));
+
+ fec_state_ f;
+ f.fec_to_ask = std::min(fec_to_ask, (n_ - k_));
+ f.last_update = round_id_;
+ f.avg_residual_losses = 0.0;
+ f.consecutive_use = 0;
+ fec_per_loss_rate_.push_back(f);
+ }
+}
+
+bool RecoveryStrategy::lossDetected(uint32_t seq) {
+ if (isRtx(seq)) {
+ // this packet is already in the list of rtx
+ return false;
+ }
+
+ auto it = recover_with_fec_.find(seq);
+ if (it != recover_with_fec_.end()) {
+ // this packet is already in list of packets to recover with fec
+ // this list contians also fec packets that will not be recovered with rtx
+ return false;
+ }
+
+ // new loss detected, recover it according to the strategy
+ newPacketLoss(seq);
+ return true;
+}
+
+void RecoveryStrategy::clear() {
+ rtx_state_.clear();
+ rtx_timers_.clear();
+ recover_with_fec_.clear();
+
+ if (next_rtx_timer_ != MAX_TIMER_RTX) {
+ next_rtx_timer_ = MAX_TIMER_RTX;
+ timer_->cancel();
+ }
+}
+
+// rtx functions
+void RecoveryStrategy::addNewRtx(uint32_t seq, bool force) {
+ if (!indexer_->isFec(seq) || force) {
+ // this packet needs to be re-transmitted
+ rtxState state;
+ state.first_send_ = state_->getInterestSentTime(seq);
+ if (state.first_send_ == 0) // this interest was never sent before
+ state.first_send_ = getNow();
+ state.next_send_ = computeNextSend(seq, true);
+ state.rtx_count_ = 0;
+ DLOG_IF(INFO, VLOG_IS_ON(4))
+ << "Add " << seq << " to retransmissions. next rtx is in "
+ << state.next_send_ - getNow() << " ms";
+ rtx_state_.insert(std::pair<uint32_t, rtxState>(seq, state));
+ rtx_timers_.insert(std::pair<uint64_t, uint32_t>(state.next_send_, seq));
+
+ // if a new rtx is introduced, check the rtx timer
+ scheduleNextRtx();
+ } else {
+ // do not re-send fec packets but keep track of them
+ recover_with_fec_.insert(seq);
+ state_->onPossibleLossWithNoRtx(seq);
+ }
+}
+
+uint64_t RecoveryStrategy::computeNextSend(uint32_t seq, bool new_rtx) {
+ uint64_t now = getNow();
+ if (new_rtx) {
+ // for the new rtx we wait one estimated IAT after the loss detection. this
+ // is bacause, assuming that packets arrive with a constant IAT, we should
+ // get a new packet every IAT
+ double prod_rate = state_->getProducerRate();
+ uint32_t estimated_iat = SENTINEL_TIMER_INTERVAL;
+ uint32_t jitter = 0;
+
+ if (prod_rate != 0) {
+ double packet_size = state_->getAveragePacketSize();
+ estimated_iat = ceil(1000.0 / (prod_rate / packet_size));
+ jitter = ceil(state_->getJitter());
+ }
+
+ uint32_t wait = 1;
+ if (estimated_iat < 18) {
+ // for low rate app we do not wait to send a RTX
+ // we consider low rate stream with less than 50pps (iat >= 20ms)
+ // (e.g. audio in videoconf, mobile games).
+ // in the check we use 18ms to accomodate for measurements errors
+ // for flows with higher rate wait 1 ait + jitter
+ wait = estimated_iat + jitter;
+ }
+
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "first rtx for " << seq << " in " << wait
+ << " ms, rtt = " << state_->getMinRTT() << " ait = " << estimated_iat
+ << " jttr = " << jitter;
+
+ return now + wait;
+ } else {
+ // wait one RTT
+ uint32_t wait = SENTINEL_TIMER_INTERVAL;
+
+ double prod_rate = state_->getProducerRate();
+ if (prod_rate == 0) {
+ return now + SENTINEL_TIMER_INTERVAL;
+ }
+
+ double packet_size = state_->getAveragePacketSize();
+ uint32_t estimated_iat = ceil(1000.0 / (prod_rate / packet_size));
+
+ uint64_t rtt = state_->getMinRTT();
+ if (rtt == 0) rtt = SENTINEL_TIMER_INTERVAL;
+ wait = rtt;
+
+ uint32_t jitter = ceil(state_->getJitter());
+ wait += jitter;
+
+ // it may happen that the channel is congested and we have some additional
+ // queuing delay to take into account
+ uint32_t queue = ceil(state_->getQueuing());
+ wait += queue;
+
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "next rtx for " << seq << " in " << wait
+ << " ms, rtt = " << state_->getMinRTT() << " ait = " << estimated_iat
+ << " jttr = " << jitter << " queue = " << queue;
+
+ return now + wait;
+ }
+}
+
+void RecoveryStrategy::retransmit() {
+ if (rtx_timers_.size() == 0) return;
+
+ uint64_t now = getNow();
+
+ auto it = rtx_timers_.begin();
+ std::unordered_set<uint32_t> lost_pkt;
+ uint32_t sent_counter = 0;
+ while (it != rtx_timers_.end() && it->first <= now &&
+ sent_counter < MAX_RTX_IN_BATCH) {
+ uint32_t seq = it->second;
+ auto rtx_it =
+ rtx_state_.find(seq); // this should always return a valid iter
+ if (rtx_it->second.rtx_count_ >= RTC_MAX_RTX ||
+ (now - rtx_it->second.first_send_) >= RTC_MAX_AGE ||
+ seq < state_->getLastSeqNacked()) {
+ // max rtx reached or packet too old or packet nacked, this packet is lost
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "packet " << seq << " lost because 1) max rtx: "
+ << (rtx_it->second.rtx_count_ >= RTC_MAX_RTX) << " 2) max age: "
+ << ((now - rtx_it->second.first_send_) >= RTC_MAX_AGE)
+ << " 3) nacked: " << (seq < state_->getLastSeqNacked());
+ lost_pkt.insert(seq);
+ it++;
+ } else {
+ // resend the packet
+ state_->onRetransmission(seq);
+ double prod_rate = state_->getProducerRate();
+ if (prod_rate != 0) rtx_it->second.rtx_count_++;
+ rtx_it->second.next_send_ = computeNextSend(seq, false);
+ it = rtx_timers_.erase(it);
+ rtx_timers_.insert(
+ std::pair<uint64_t, uint32_t>(rtx_it->second.next_send_, seq));
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "send rtx for sequence " << seq << ", next send in "
+ << (rtx_it->second.next_send_ - now);
+ send_rtx_callback_(seq);
+ sent_counter++;
+ }
+ }
+
+ // remove packets if needed
+ for (auto lost_it = lost_pkt.begin(); lost_it != lost_pkt.end(); lost_it++) {
+ uint32_t seq = *lost_it;
+ state_->onPacketLost(seq);
+ deleteRtx(seq);
+ }
+}
+
+void RecoveryStrategy::scheduleNextRtx() {
+ if (rtx_timers_.size() == 0) {
+ // all the rtx were removed, reset timer
+ next_rtx_timer_ = MAX_TIMER_RTX;
+ return;
+ }
+
+ // check if timer is alreay set
+ if (next_rtx_timer_ != MAX_TIMER_RTX) {
+ // a new check for rtx is already scheduled
+ if (next_rtx_timer_ > rtx_timers_.begin()->first) {
+ // we need to re-schedule it
+ timer_->cancel();
+ } else {
+ // wait for the next timer
+ return;
+ }
+ }
+
+ // set a new timer
+ next_rtx_timer_ = rtx_timers_.begin()->first;
+ uint64_t now = utils::SteadyTime::nowMs().count();
+ uint64_t wait = 1;
+ if (next_rtx_timer_ != MAX_TIMER_RTX && next_rtx_timer_ > now)
+ wait = next_rtx_timer_ - now;
+
+ std::weak_ptr<RecoveryStrategy> self(shared_from_this());
+ timer_->expires_from_now(std::chrono::milliseconds(wait));
+ timer_->async_wait([self](const std::error_code &ec) {
+ if (ec) return;
+ if (auto s = self.lock()) {
+ s->retransmit();
+ s->next_rtx_timer_ = MAX_TIMER_RTX;
+ s->scheduleNextRtx();
+ }
+ });
+}
+
+void RecoveryStrategy::deleteRtx(uint32_t seq) {
+ auto it_rtx = rtx_state_.find(seq);
+ if (it_rtx == rtx_state_.end()) return; // rtx not found
+
+ // remove the rtx from the timers list
+ uint64_t ts = it_rtx->second.next_send_;
+ auto it_timers = rtx_timers_.find(ts);
+ while (it_timers != rtx_timers_.end() && it_timers->first == ts) {
+ if (it_timers->second == seq) {
+ rtx_timers_.erase(it_timers);
+ break;
+ }
+ it_timers++;
+ }
+ // remove rtx
+ rtx_state_.erase(it_rtx);
+}
+
+// fec functions
+uint32_t RecoveryStrategy::computeFecPacketsToAsk(bool in_sync) {
+ double loss_rate = state_->getMaxLossRate() * 100; // use loss rate in %
+
+ if (loss_rate > 95) loss_rate = 95; // max loss rate
+
+ if (loss_rate == 0) return 0;
+
+ // once per minute try to reduce the fec rate. it may happen that for some bin
+ // we ask too many fec packet. here we try to reduce this values gently
+ if (round_id_ % ROUNDS_PER_MIN == 0) {
+ reduceFec();
+ }
+
+ // keep track of the last used fec. if we use a new bin on this round reset
+ // consecutive use and avg loss in the prev bin
+ uint32_t bin = ceil(loss_rate / 5.0) - 1;
+ if (bin > fec_per_loss_rate_.size() - 1) bin = fec_per_loss_rate_.size() - 1;
+
+ if (bin != last_fec_used_) {
+ fec_per_loss_rate_[last_fec_used_].consecutive_use = 0;
+ fec_per_loss_rate_[last_fec_used_].avg_residual_losses = 0.0;
+ }
+ last_fec_used_ = bin;
+ fec_per_loss_rate_[last_fec_used_].consecutive_use++;
+
+ // we update the stats only once very 5 rounds (1sec) that is the rate at
+ // which we compute residual losses
+ if (round_id_ % ROUNDS_PER_SEC == 0) {
+ double residual_losses = state_->getResidualLossRate() * 100;
+ // update residual loss rate
+ fec_per_loss_rate_[bin].avg_residual_losses =
+ (fec_per_loss_rate_[bin].avg_residual_losses * MOVING_AVG_ALPHA) +
+ (1 - MOVING_AVG_ALPHA) * residual_losses;
+
+ if ((fec_per_loss_rate_[bin].last_update - round_id_) <
+ WAIT_BEFORE_FEC_UPDATE) {
+ // this bin is been updated recently so don't modify it and
+ // return the current state
+ return fec_per_loss_rate_[bin].fec_to_ask;
+ }
+
+ // if the residual loss rate is too high and we can ask more fec packets and
+ // we are using this configuration since at least 5 sec update fec
+ if (fec_per_loss_rate_[bin].avg_residual_losses > MAX_RESIDUAL_LOSS_RATE &&
+ fec_per_loss_rate_[bin].fec_to_ask < (n_ - k_) &&
+ fec_per_loss_rate_[bin].consecutive_use > WAIT_BEFORE_FEC_UPDATE) {
+ // so increase the number of fec packets to ask
+ fec_per_loss_rate_[bin].fec_to_ask++;
+ fec_per_loss_rate_[bin].last_update = round_id_;
+ fec_per_loss_rate_[bin].avg_residual_losses = 0.0;
+ }
+ }
+
+ return fec_per_loss_rate_[bin].fec_to_ask;
+}
+
+void RecoveryStrategy::setRtxFec(std::optional<bool> rtx_on,
+ std::optional<bool> fec_on) {
+ if (rtx_on) rtx_on_ = *rtx_on;
+ if (fec_on) fec_on_ = *fec_on;
+
+ if (*callback_) {
+ notification::RecoveryStrategy strategy =
+ notification::RecoveryStrategy::RECOVERY_OFF;
+
+ if (rtx_on_ && fec_on_)
+ strategy = notification::RecoveryStrategy::RTX_AND_FEC;
+ else if (rtx_on_)
+ strategy = notification::RecoveryStrategy::RTX_ONLY;
+ else if (fec_on_)
+ strategy = notification::RecoveryStrategy::FEC_ONLY;
+
+ (*callback_)(strategy);
+ }
+}
+
+// common functions
+void RecoveryStrategy::onLostTimeout(uint32_t seq) { removePacketState(seq); }
+
+void RecoveryStrategy::removePacketState(uint32_t seq) {
+ auto it_fec = recover_with_fec_.find(seq);
+ if (it_fec != recover_with_fec_.end()) {
+ recover_with_fec_.erase(it_fec);
+ return;
+ }
+
+ deleteRtx(seq);
+}
+
+// private methods
+
+void RecoveryStrategy::reduceFec() {
+ for (uint32_t loss_rate = 5; loss_rate < 100; loss_rate += 5) {
+ double dec_loss_rate = (double)loss_rate / 100.0;
+ double exp_losses = (double)k_ * dec_loss_rate;
+ uint32_t fec_to_ask = ceil(exp_losses / (1 - dec_loss_rate));
+
+ uint32_t bin = ceil(loss_rate / 5.0) - 1;
+ if (fec_per_loss_rate_[bin].fec_to_ask > fec_to_ask) {
+ fec_per_loss_rate_[bin].fec_to_ask--;
+ // std::cout << "reduce fec to ask for bin " << bin << std::endl;
+ }
+ }
+}
+
+} // end namespace rtc
+
+} // end namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/protocols/rtc/rtc_recovery_strategy.h b/libtransport/src/protocols/rtc/rtc_recovery_strategy.h
new file mode 100644
index 000000000..9ffc69a1b
--- /dev/null
+++ b/libtransport/src/protocols/rtc/rtc_recovery_strategy.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <hicn/transport/interfaces/callbacks.h>
+#include <hicn/transport/utils/chrono_typedefs.h>
+#include <protocols/indexer.h>
+#include <protocols/rtc/rtc_rc.h>
+#include <protocols/rtc/rtc_state.h>
+
+#include <map>
+#include <unordered_map>
+
+namespace transport {
+
+namespace protocol {
+
+namespace rtc {
+
+class RecoveryStrategy : public std::enable_shared_from_this<RecoveryStrategy> {
+ protected:
+ struct rtx_state_ {
+ uint64_t first_send_;
+ uint64_t next_send_;
+ uint32_t rtx_count_;
+ };
+
+ using rtxState = struct rtx_state_;
+
+ public:
+ using SendRtxCallback = std::function<void(uint32_t)>;
+
+ RecoveryStrategy(Indexer *indexer, SendRtxCallback &&callback,
+ asio::io_service &io_service, bool use_rtx, bool use_fec,
+ interface::StrategyCallback *external_callback);
+
+ RecoveryStrategy(RecoveryStrategy &&rs);
+
+ virtual ~RecoveryStrategy();
+
+ void setRtxFec(std::optional<bool> rtx_on = {},
+ std::optional<bool> fec_on = {});
+ void setState(RTCState *state) { state_ = state; }
+ void setRateControl(RTCRateControl *rateControl) { rc_ = rateControl; }
+ void setFecParams(uint32_t n, uint32_t k);
+
+ void tunrOnRecovery() { recovery_on_ = true; }
+
+ bool isRtx(uint32_t seq) {
+ if (rtx_state_.find(seq) != rtx_state_.end()) return true;
+ return false;
+ }
+
+ bool isPossibleLossWithNoRtx(uint32_t seq) {
+ if (recover_with_fec_.find(seq) != recover_with_fec_.end()) return true;
+ return false;
+ }
+
+ bool isRtxOn() { return rtx_on_; }
+
+ RTCState *getState() { return state_; }
+ bool lossDetected(uint32_t seq);
+ void clear();
+
+ virtual void onNewRound(bool in_sync) = 0;
+ virtual void newPacketLoss(uint32_t seq) = 0;
+ virtual void receivedPacket(uint32_t seq) = 0;
+ void onLostTimeout(uint32_t seq);
+
+ void incRoundId() { round_id_++; }
+
+ // utils
+ uint64_t getNow() {
+ uint64_t now = utils::SteadyTime::nowMs().count();
+ return now;
+ }
+
+ protected:
+ // rtx functions
+ void addNewRtx(uint32_t seq, bool force);
+ uint64_t computeNextSend(uint32_t seq, bool new_rtx);
+ void retransmit();
+ void scheduleNextRtx();
+ void deleteRtx(uint32_t seq);
+
+ // fec functions
+ uint32_t computeFecPacketsToAsk(bool in_sync);
+
+ // common functons
+ void removePacketState(uint32_t seq);
+
+ bool recovery_on_;
+ bool rtx_on_;
+ bool fec_on_;
+
+ // this map keeps track of the retransmitted interest, ordered from the oldest
+ // to the newest one. the state contains the timer of the first send of the
+ // interest (from pendingIntetests_), the timer of the next send (key of the
+ // multimap) and the number of rtx
+ std::map<uint32_t, rtxState> rtx_state_;
+ // this map stored the rtx by timer. The key is the time at which the rtx
+ // should be sent, and the val is the interest seq number
+ std::multimap<uint64_t, uint32_t> rtx_timers_;
+
+ // lost packets that will be recovered with fec
+ std::unordered_set<uint32_t> recover_with_fec_;
+
+ // rtx vars
+ std::unique_ptr<asio::steady_timer> timer_;
+ uint64_t next_rtx_timer_;
+ SendRtxCallback send_rtx_callback_;
+
+ // fec vars
+ uint32_t n_;
+ uint32_t k_;
+ Indexer *indexer_;
+
+ RTCState *state_;
+ RTCRateControl *rc_;
+
+ private:
+ struct fec_state_ {
+ uint32_t fec_to_ask;
+ uint32_t last_update; // round id of the last update
+ // (wait 10 ruonds (2sec) between updates)
+ uint32_t consecutive_use; // consecutive ruonds where this fec was used
+ double avg_residual_losses;
+ };
+
+ void reduceFec();
+
+ uint32_t round_id_; // number of rounds
+ uint32_t last_fec_used_;
+ std::vector<fec_state_> fec_per_loss_rate_;
+ interface::StrategyCallback *callback_;
+};
+
+} // end namespace rtc
+
+} // end namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/protocols/rtc/rtc_rs_delay.cc b/libtransport/src/protocols/rtc/rtc_rs_delay.cc
new file mode 100644
index 000000000..e2c60ca77
--- /dev/null
+++ b/libtransport/src/protocols/rtc/rtc_rs_delay.cc
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <glog/logging.h>
+#include <protocols/rtc/rtc_consts.h>
+#include <protocols/rtc/rtc_rs_delay.h>
+
+namespace transport {
+
+namespace protocol {
+
+namespace rtc {
+
+RecoveryStrategyDelayBased::RecoveryStrategyDelayBased(
+ Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service,
+ interface::StrategyCallback *external_callback)
+ : RecoveryStrategy(indexer, std::move(callback), io_service, true, false,
+ external_callback), // start with rtx
+ congestion_state_(false),
+ probing_state_(false),
+ switch_rounds_(0) {}
+
+RecoveryStrategyDelayBased::RecoveryStrategyDelayBased(RecoveryStrategy &&rs)
+ : RecoveryStrategy(std::move(rs)) {
+ setRtxFec(true, false);
+ // we have to re-init congestion and
+ // probing
+ congestion_state_ = false;
+ probing_state_ = false;
+}
+
+RecoveryStrategyDelayBased::~RecoveryStrategyDelayBased() {}
+
+void RecoveryStrategyDelayBased::softSwitchToFec(uint32_t fec_to_ask) {
+ if (fec_to_ask == 0) {
+ setRtxFec(true, false);
+ switch_rounds_ = 0;
+ } else {
+ switch_rounds_++;
+ if (switch_rounds_ >= 5) {
+ setRtxFec(false, true);
+ } else {
+ setRtxFec({}, true);
+ }
+ }
+}
+
+void RecoveryStrategyDelayBased::onNewRound(bool in_sync) {
+ if (!recovery_on_) {
+ // disable fec so that no extra packet will be sent
+ // for rtx we check if recovery is on in newPacketLoss
+ setRtxFec(true, false);
+ indexer_->setNFec(0);
+ return;
+ }
+
+ uint64_t rtt = state_->getMinRTT();
+
+ bool congestion = false;
+ // XXX at the moment we are not looking at congestion events
+ // congestion = rc_->inCongestionState();
+
+ if ((!fec_on_ && rtt >= 100) || (fec_on_ && rtt > 80) || congestion) {
+ // switch from rtx to fec or keep use fec. Notice that if some rtx are
+ // waiting to be scheduled, they will be sent normally, but no new rtx will
+ // be created If the loss rate is 0 keep to use RTX.
+ uint32_t fec_to_ask = computeFecPacketsToAsk(in_sync);
+ softSwitchToFec(fec_to_ask);
+ indexer_->setNFec(fec_to_ask);
+ return;
+ }
+
+ if ((fec_on_ && rtt <= 80) || (!rtx_on_ && rtt <= 100)) {
+ // turn on rtx
+ softSwitchToFec(0);
+ indexer_->setNFec(0);
+ return;
+ }
+}
+
+void RecoveryStrategyDelayBased::newPacketLoss(uint32_t seq) {
+ if (rtx_on_ && recovery_on_) {
+ addNewRtx(seq, false);
+ } else {
+ if (!state_->isPending(seq) && !indexer_->isFec(seq)) {
+ addNewRtx(seq, true);
+ } else {
+ recover_with_fec_.insert(seq);
+ state_->onPossibleLossWithNoRtx(seq);
+ }
+ }
+}
+
+void RecoveryStrategyDelayBased::receivedPacket(uint32_t seq) {
+ removePacketState(seq);
+}
+
+void RecoveryStrategyDelayBased::probing() {
+ // TODO
+ // for the moment ask for all fec and exit the probing phase
+ probing_state_ = false;
+ setRtxFec(false, true);
+ indexer_->setNFec(computeFecPacketsToAsk(true));
+}
+
+} // end namespace rtc
+
+} // end namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/protocols/rtc/rtc_rs_delay.h b/libtransport/src/protocols/rtc/rtc_rs_delay.h
new file mode 100644
index 000000000..0dd199965
--- /dev/null
+++ b/libtransport/src/protocols/rtc/rtc_rs_delay.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <protocols/rtc/rtc_recovery_strategy.h>
+
+namespace transport {
+
+namespace protocol {
+
+namespace rtc {
+
+class RecoveryStrategyDelayBased : public RecoveryStrategy {
+ public:
+ RecoveryStrategyDelayBased(Indexer *indexer, SendRtxCallback &&callback,
+ asio::io_service &io_service,
+ interface::StrategyCallback *external_callback);
+
+ RecoveryStrategyDelayBased(RecoveryStrategy &&rs);
+
+ ~RecoveryStrategyDelayBased();
+
+ void onNewRound(bool in_sync);
+ void newPacketLoss(uint32_t seq);
+ void receivedPacket(uint32_t seq);
+
+ private:
+ void softSwitchToFec(uint32_t fec_to_ask);
+
+ bool congestion_state_;
+ bool probing_state_;
+ uint32_t switch_rounds_;
+
+ void probing();
+};
+
+} // end namespace rtc
+
+} // end namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/protocols/rtc/rtc_rs_fec_only.cc b/libtransport/src/protocols/rtc/rtc_rs_fec_only.cc
new file mode 100644
index 000000000..36d8e39f0
--- /dev/null
+++ b/libtransport/src/protocols/rtc/rtc_rs_fec_only.cc
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <glog/logging.h>
+#include <protocols/rtc/rtc_consts.h>
+#include <protocols/rtc/rtc_rs_fec_only.h>
+
+namespace transport {
+
+namespace protocol {
+
+namespace rtc {
+
+RecoveryStrategyFecOnly::RecoveryStrategyFecOnly(
+ Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service,
+ interface::StrategyCallback *external_callback)
+ : RecoveryStrategy(indexer, std::move(callback), io_service, false, true,
+ external_callback),
+ congestion_state_(false),
+ probing_state_(false),
+ switch_rounds_(0) {}
+
+RecoveryStrategyFecOnly::RecoveryStrategyFecOnly(RecoveryStrategy &&rs)
+ : RecoveryStrategy(std::move(rs)) {
+ setRtxFec(false, true);
+ congestion_state_ = false;
+ probing_state_ = false;
+}
+
+RecoveryStrategyFecOnly::~RecoveryStrategyFecOnly() {}
+
+void RecoveryStrategyFecOnly::onNewRound(bool in_sync) {
+ if (!recovery_on_) {
+ indexer_->setNFec(0);
+ return;
+ }
+
+ // XXX for the moment we are considering congestion events
+ // if(rc_->inCongestionState()){
+ // congestion_state_ = true;
+ // probing_state_ = false;
+ // indexer_->setNFec(0);
+ // return;
+ // }
+
+ // no congestion
+ if (congestion_state_) {
+ // this is the first round after congestion
+ // enter probing phase
+ probing_state_ = true;
+ congestion_state_ = false;
+ }
+
+ if (probing_state_) {
+ probing();
+ } else {
+ uint32_t fec_to_ask = computeFecPacketsToAsk(in_sync);
+ // If fec_to_ask == 0 we use rtx even if in these strategy we use only fec.
+ // In this way the first packet loss that triggers the usage of fec can be
+ // recovered using rtx, otherwise it will always be lost
+ if (fec_to_ask == 0) {
+ setRtxFec(true, false);
+ switch_rounds_ = 0;
+ } else {
+ switch_rounds_++;
+ if (switch_rounds_ >= 5) {
+ setRtxFec(false, true);
+ } else {
+ setRtxFec({}, true);
+ }
+ }
+ indexer_->setNFec(fec_to_ask);
+ }
+}
+
+void RecoveryStrategyFecOnly::newPacketLoss(uint32_t seq) {
+ if (rtx_on_ && recovery_on_) {
+ addNewRtx(seq, false);
+ } else {
+ if (!state_->isPending(seq) && !indexer_->isFec(seq)) {
+ addNewRtx(seq, true);
+ } else {
+ // if not pending add rtc
+ recover_with_fec_.insert(seq);
+ state_->onPossibleLossWithNoRtx(seq);
+ }
+ }
+}
+
+void RecoveryStrategyFecOnly::receivedPacket(uint32_t seq) {
+ removePacketState(seq);
+}
+
+void RecoveryStrategyFecOnly::probing() {
+ // TODO
+ // for the moment ask for all fec and exit the probing phase
+ probing_state_ = false;
+ uint32_t fec_to_ask = computeFecPacketsToAsk(true);
+ indexer_->setNFec(fec_to_ask);
+}
+
+} // end namespace rtc
+
+} // end namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/protocols/rtc/rtc_rs_fec_only.h b/libtransport/src/protocols/rtc/rtc_rs_fec_only.h
new file mode 100644
index 000000000..37b505d35
--- /dev/null
+++ b/libtransport/src/protocols/rtc/rtc_rs_fec_only.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <protocols/rtc/rtc_recovery_strategy.h>
+
+namespace transport {
+
+namespace protocol {
+
+namespace rtc {
+
+class RecoveryStrategyFecOnly : public RecoveryStrategy {
+ public:
+ RecoveryStrategyFecOnly(Indexer *indexer, SendRtxCallback &&callback,
+ asio::io_service &io_service,
+ interface::StrategyCallback *external_callback);
+
+ RecoveryStrategyFecOnly(RecoveryStrategy &&rs);
+
+ ~RecoveryStrategyFecOnly();
+
+ void onNewRound(bool in_sync);
+ void newPacketLoss(uint32_t seq);
+ void receivedPacket(uint32_t seq);
+
+ private:
+ bool congestion_state_;
+ bool probing_state_;
+ uint32_t switch_rounds_;
+
+ void probing();
+};
+
+} // end namespace rtc
+
+} // end namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/protocols/rtc/rtc_rs_low_rate.cc b/libtransport/src/protocols/rtc/rtc_rs_low_rate.cc
new file mode 100644
index 000000000..bd153d209
--- /dev/null
+++ b/libtransport/src/protocols/rtc/rtc_rs_low_rate.cc
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <glog/logging.h>
+#include <protocols/rtc/rtc_consts.h>
+#include <protocols/rtc/rtc_rs_low_rate.h>
+
+namespace transport {
+
+namespace protocol {
+
+namespace rtc {
+
+RecoveryStrategyLowRate::RecoveryStrategyLowRate(
+ Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service,
+ interface::StrategyCallback *external_callback)
+ : RecoveryStrategy(indexer, std::move(callback), io_service, false, true,
+ external_callback), // start with fec
+ fec_consecutive_rounds_((MILLI_IN_A_SEC / ROUND_LEN) * 5), // 5 sec
+ rtx_allowed_consecutive_rounds_(0) {
+ initSwitchVector();
+}
+
+RecoveryStrategyLowRate::RecoveryStrategyLowRate(RecoveryStrategy &&rs)
+ : RecoveryStrategy(std::move(rs)),
+ fec_consecutive_rounds_((MILLI_IN_A_SEC / ROUND_LEN) * 5), // 5 sec
+ rtx_allowed_consecutive_rounds_(0) {
+ setRtxFec(false, true);
+ initSwitchVector();
+}
+
+RecoveryStrategyLowRate::~RecoveryStrategyLowRate() {}
+
+void RecoveryStrategyLowRate::initSwitchVector() {
+ // TODO adjust thresholds here when new data are collected
+ // see resutls in
+ // https://confluence-eng-gpk1.cisco.com/conf/display/SPT/dailyreports
+ thresholds_t t1;
+ t1.rtt = 15; // 15ms
+ t1.loss_rtx_to_fec = 15; // 15%
+ t1.loss_fec_to_rtx = 10; // 10%
+ thresholds_t t2;
+ t2.rtt = 35; // 35ms
+ t2.loss_rtx_to_fec = 5; // 5%
+ t2.loss_fec_to_rtx = 1; // 1%
+ switch_vector.push_back(t1);
+ switch_vector.push_back(t2);
+}
+
+void RecoveryStrategyLowRate::setRecoveryParameters(bool use_rtx, bool use_fec,
+ uint32_t fec_to_ask) {
+ setRtxFec(use_rtx, use_fec);
+ indexer_->setNFec(fec_to_ask);
+}
+
+void RecoveryStrategyLowRate::selectRecoveryStrategy(bool in_sync) {
+ uint32_t fec_to_ask = computeFecPacketsToAsk(in_sync);
+ if (fec_to_ask == 0) {
+ // fec is off, turn on RTX immediatly to avoid packet losses
+ setRecoveryParameters(true, false, 0);
+ fec_consecutive_rounds_ = 0;
+ return;
+ }
+
+ uint32_t loss_rate = std::round(state_->getPerSecondLossRate() * 100);
+ uint32_t rtt = state_->getAvgRTT();
+
+ bool use_rtx = false;
+ for (size_t i = 0; i < switch_vector.size(); i++) {
+ uint32_t max_loss_rate = 0;
+ if (fec_on_)
+ max_loss_rate = switch_vector[i].loss_fec_to_rtx;
+ else
+ max_loss_rate = switch_vector[i].loss_rtx_to_fec;
+
+ if (rtt < switch_vector[i].rtt && loss_rate < max_loss_rate) {
+ use_rtx = true;
+ rtx_allowed_consecutive_rounds_++;
+ break;
+ }
+ }
+
+ if (!use_rtx) rtx_allowed_consecutive_rounds_ = 0;
+
+ if (use_rtx) {
+ if (fec_on_) {
+ // here we should swtich from RTX to FEC
+ // wait 10sec where the switch is allowed before actually switch
+ if (rtx_allowed_consecutive_rounds_ >=
+ ((MILLI_IN_A_SEC / ROUND_LEN) * 10)) { // 10 sec
+ // use RTX
+ setRecoveryParameters(true, false, 0);
+ fec_consecutive_rounds_ = 0;
+ } else {
+ // keep using FEC (and maybe RTX)
+ setRecoveryParameters(true, true, fec_to_ask);
+ fec_consecutive_rounds_++;
+ }
+ } else {
+ // keep using RTX
+ setRecoveryParameters(true, false, 0);
+ fec_consecutive_rounds_ = 0;
+ }
+ } else {
+ // use FEC and RTX
+ setRecoveryParameters(true, true, fec_to_ask);
+ fec_consecutive_rounds_++;
+ }
+
+ // everytime that we anable FEC we keep also RTX on. in this way the first
+ // losses that are not covered by FEC are recovered using RTX. after 5 sec we
+ // disable fec
+ if (fec_consecutive_rounds_ >= ((MILLI_IN_A_SEC / ROUND_LEN) * 5)) {
+ // turn off RTX
+ setRtxFec(false);
+ }
+}
+
+void RecoveryStrategyLowRate::onNewRound(bool in_sync) {
+ if (!recovery_on_) {
+ // disable fec so that no extra packet will be sent
+ // for rtx we check if recovery is on in newPacketLoss
+ setRtxFec(true, false);
+ indexer_->setNFec(0);
+ return;
+ }
+
+ // XXX since this strategy will be used only for flow at low rate we do not
+ // consider congestion events like in other strategies
+
+ selectRecoveryStrategy(in_sync);
+}
+
+void RecoveryStrategyLowRate::newPacketLoss(uint32_t seq) {
+ if (rtx_on_ && recovery_on_) {
+ addNewRtx(seq, false);
+ } else {
+ if (!state_->isPending(seq) && !indexer_->isFec(seq)) {
+ addNewRtx(seq, true);
+ } else {
+ recover_with_fec_.insert(seq);
+ state_->onPossibleLossWithNoRtx(seq);
+ }
+ }
+}
+
+void RecoveryStrategyLowRate::receivedPacket(uint32_t seq) {
+ removePacketState(seq);
+}
+
+} // end namespace rtc
+
+} // end namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/protocols/rtc/rtc_rs_low_rate.h b/libtransport/src/protocols/rtc/rtc_rs_low_rate.h
new file mode 100644
index 000000000..f0c7bd0d5
--- /dev/null
+++ b/libtransport/src/protocols/rtc/rtc_rs_low_rate.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <protocols/rtc/rtc_recovery_strategy.h>
+
+#include <vector>
+
+namespace transport {
+
+namespace protocol {
+
+namespace rtc {
+
+struct thresholds_t {
+ uint32_t rtt;
+ uint32_t loss_rtx_to_fec; // loss rate used to move from rtx to fec
+ uint32_t loss_fec_to_rtx; // loss rate used to move from fec to rtx
+};
+
+class RecoveryStrategyLowRate : public RecoveryStrategy {
+ public:
+ RecoveryStrategyLowRate(Indexer *indexer, SendRtxCallback &&callback,
+ asio::io_service &io_service,
+ interface::StrategyCallback *external_callback);
+
+ RecoveryStrategyLowRate(RecoveryStrategy &&rs);
+
+ ~RecoveryStrategyLowRate();
+
+ void onNewRound(bool in_sync);
+ void newPacketLoss(uint32_t seq);
+ void receivedPacket(uint32_t seq);
+
+ private:
+ void initSwitchVector();
+ void setRecoveryParameters(bool use_rtx, bool use_fec, uint32_t fec_to_ask);
+ void selectRecoveryStrategy(bool in_sync);
+
+ uint32_t fec_consecutive_rounds_;
+ uint32_t rtx_allowed_consecutive_rounds_;
+
+ // this table contains the thresholds that indicates when to switch from RTX
+ // to FEC and viceversa. values in the vector are detected with a set of
+ // experiments. the vector is used in the following way: if rtt and loss rate
+ // are less than one of the values in the in the vector, losses are
+ // recovered using RTX. otherwive losses are recovered using FEC. as for FEC
+ // only and delay based strategy, the swith from RTX to FEC is smooth,
+ // meaning that FEC and RTX are used together for some rounds
+ std::vector<thresholds_t> switch_vector;
+};
+
+} // end namespace rtc
+
+} // end namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/protocols/rtc/rtc_rs_recovery_off.cc b/libtransport/src/protocols/rtc/rtc_rs_recovery_off.cc
new file mode 100644
index 000000000..499e978f1
--- /dev/null
+++ b/libtransport/src/protocols/rtc/rtc_rs_recovery_off.cc
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <glog/logging.h>
+#include <protocols/rtc/rtc_consts.h>
+#include <protocols/rtc/rtc_rs_recovery_off.h>
+
+namespace transport {
+
+namespace protocol {
+
+namespace rtc {
+
+RecoveryStrategyRecoveryOff::RecoveryStrategyRecoveryOff(
+ Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service,
+ interface::StrategyCallback *external_callback)
+ : RecoveryStrategy(indexer, std::move(callback), io_service, false, false,
+ external_callback) {}
+
+RecoveryStrategyRecoveryOff::RecoveryStrategyRecoveryOff(RecoveryStrategy &&rs)
+ : RecoveryStrategy(std::move(rs)) {
+ setRtxFec(false, false);
+}
+
+RecoveryStrategyRecoveryOff::~RecoveryStrategyRecoveryOff() {}
+
+void RecoveryStrategyRecoveryOff::onNewRound(bool in_sync) {
+ // nothing to do
+ return;
+}
+
+void RecoveryStrategyRecoveryOff::newPacketLoss(uint32_t seq) {
+ // here we only keep track of the lost packets to avoid to
+ // count them multple times in the counters. for this we
+ // use the recover_with_fec_ set
+ recover_with_fec_.insert(seq);
+ state_->onPossibleLossWithNoRtx(seq);
+}
+
+void RecoveryStrategyRecoveryOff::receivedPacket(uint32_t seq) {
+ removePacketState(seq);
+}
+
+} // end namespace rtc
+
+} // end namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/protocols/rtc/rtc_rs_recovery_off.h b/libtransport/src/protocols/rtc/rtc_rs_recovery_off.h
new file mode 100644
index 000000000..98cd1e6a5
--- /dev/null
+++ b/libtransport/src/protocols/rtc/rtc_rs_recovery_off.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <protocols/rtc/rtc_recovery_strategy.h>
+
+namespace transport {
+
+namespace protocol {
+
+namespace rtc {
+
+class RecoveryStrategyRecoveryOff : public RecoveryStrategy {
+ public:
+ RecoveryStrategyRecoveryOff(Indexer *indexer, SendRtxCallback &&callback,
+ asio::io_service &io_service,
+ interface::StrategyCallback *external_callback);
+
+ RecoveryStrategyRecoveryOff(RecoveryStrategy &&rs);
+
+ ~RecoveryStrategyRecoveryOff();
+
+ void onNewRound(bool in_sync);
+ void newPacketLoss(uint32_t seq);
+ void receivedPacket(uint32_t seq);
+};
+
+} // end namespace rtc
+
+} // end namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/protocols/rtc/rtc_rs_rtx_only.cc b/libtransport/src/protocols/rtc/rtc_rs_rtx_only.cc
new file mode 100644
index 000000000..c1ae9b53d
--- /dev/null
+++ b/libtransport/src/protocols/rtc/rtc_rs_rtx_only.cc
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <glog/logging.h>
+#include <protocols/rtc/rtc_consts.h>
+#include <protocols/rtc/rtc_rs_rtx_only.h>
+
+namespace transport {
+
+namespace protocol {
+
+namespace rtc {
+
+RecoveryStrategyRtxOnly::RecoveryStrategyRtxOnly(
+ Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service,
+ interface::StrategyCallback *external_callback)
+ : RecoveryStrategy(indexer, std::move(callback), io_service, true, false,
+ external_callback) {}
+
+RecoveryStrategyRtxOnly::RecoveryStrategyRtxOnly(RecoveryStrategy &&rs)
+ : RecoveryStrategy(std::move(rs)) {
+ setRtxFec(true, false);
+}
+
+RecoveryStrategyRtxOnly::~RecoveryStrategyRtxOnly() {}
+
+void RecoveryStrategyRtxOnly::onNewRound(bool in_sync) {
+ // nothing to do
+ return;
+}
+
+void RecoveryStrategyRtxOnly::newPacketLoss(uint32_t seq) {
+ if (!recovery_on_) {
+ recover_with_fec_.insert(seq);
+ state_->onPossibleLossWithNoRtx(seq);
+ return;
+ }
+ addNewRtx(seq, false);
+}
+
+void RecoveryStrategyRtxOnly::receivedPacket(uint32_t seq) {
+ removePacketState(seq);
+}
+
+} // end namespace rtc
+
+} // end namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/protocols/rtc/rtc_rs_rtx_only.h b/libtransport/src/protocols/rtc/rtc_rs_rtx_only.h
new file mode 100644
index 000000000..7ae909454
--- /dev/null
+++ b/libtransport/src/protocols/rtc/rtc_rs_rtx_only.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <protocols/rtc/rtc_recovery_strategy.h>
+
+namespace transport {
+
+namespace protocol {
+
+namespace rtc {
+
+class RecoveryStrategyRtxOnly : public RecoveryStrategy {
+ public:
+ RecoveryStrategyRtxOnly(Indexer *indexer, SendRtxCallback &&callback,
+ asio::io_service &io_service,
+ interface::StrategyCallback *external_callback);
+
+ RecoveryStrategyRtxOnly(RecoveryStrategy &&rs);
+
+ ~RecoveryStrategyRtxOnly();
+
+ void onNewRound(bool in_sync);
+ void newPacketLoss(uint32_t seq);
+ void receivedPacket(uint32_t seq);
+};
+
+} // end namespace rtc
+
+} // end namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/protocols/rtc/rtc_state.cc b/libtransport/src/protocols/rtc/rtc_state.cc
index c99205a26..6a21531f8 100644
--- a/libtransport/src/protocols/rtc/rtc_state.cc
+++ b/libtransport/src/protocols/rtc/rtc_state.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2021 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -24,15 +24,15 @@ namespace protocol {
namespace rtc {
RTCState::RTCState(Indexer *indexer,
- ProbeHandler::SendProbeCallback &&rtt_probes_callback,
+ ProbeHandler::SendProbeCallback &&probe_callback,
DiscoveredRttCallback &&discovered_rtt_callback,
asio::io_service &io_service)
- : indexer_(indexer),
- rtt_probes_(std::make_shared<ProbeHandler>(std::move(rtt_probes_callback),
- io_service)),
+ : loss_history_(10), // log 10sec history
+ indexer_(indexer),
+ probe_handler_(std::make_shared<ProbeHandler>(std::move(probe_callback),
+ io_service)),
discovered_rtt_callback_(std::move(discovered_rtt_callback)) {
init_rtt_timer_ = std::make_unique<asio::steady_timer>(io_service);
- initParams();
}
RTCState::~RTCState() {}
@@ -55,9 +55,19 @@ void RTCState::initParams() {
highest_seq_received_in_order_ = 0;
last_seq_nacked_ = 0;
loss_rate_ = 0.0;
- avg_loss_rate_ = 0.0;
+ avg_loss_rate_ = -1.0;
max_loss_rate_ = 0.0;
last_round_loss_rate_ = 0.0;
+
+ // loss rate per sec
+ lost_per_sec_ = 0;
+ total_expected_packets_ = 0;
+ per_sec_loss_rate_ = 0.0;
+
+ // residual losses counters
+ expected_packets_ = 0;
+ packets_sent_to_app_ = 0;
+ rounds_from_last_compute_ = 0;
residual_loss_rate_ = 0.0;
// fec counters
@@ -66,9 +76,13 @@ void RTCState::initParams() {
// bw counters
received_bytes_ = 0;
+ received_fec_bytes_ = 0;
+ recovered_bytes_with_fec_ = 0;
+
avg_packet_size_ = INIT_PACKET_SIZE;
production_rate_ = 0.0;
received_rate_ = 0.0;
+ fec_recovered_rate_ = 0.0;
// nack counter
nack_on_last_round_ = false;
@@ -95,31 +109,30 @@ void RTCState::initParams() {
path_table_.clear();
main_path_ = nullptr;
- // packet received
- received_or_lost_packets_.clear();
+ // packet cache (not pending anymore)
+ packet_cache_.clear();
// pending interests
pending_interests_.clear();
- // skipped interest
+ // used to keep track of the skipped interest
last_interest_sent_ = 0;
- skipped_interests_.clear();
// init rtt
first_interest_sent_time_ = ~0;
first_interest_sent_seq_ = 0;
+ // start probing the producer
init_rtt_ = false;
- rtt_probes_->setProbes(INIT_RTT_PROBE_INTERVAL, INIT_RTT_PROBES);
- rtt_probes_->sendProbes();
+ probe_handler_->setSuffixRange(MIN_INIT_PROBE_SEQ, MAX_INIT_PROBE_SEQ);
+ probe_handler_->setProbes(INIT_RTT_PROBE_INTERVAL, INIT_RTT_PROBES);
+ probe_handler_->sendProbes();
setInitRttTimer(INIT_RTT_PROBE_RESTART);
}
// packet events
void RTCState::onSendNewInterest(const core::Name *interest_name) {
- uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
+ uint64_t now = utils::SteadyTime::nowMs().count();
uint32_t seq = interest_name->getSuffix();
pending_interests_.insert(std::pair<uint32_t, uint64_t>(seq, now));
@@ -137,11 +150,12 @@ void RTCState::onSendNewInterest(const core::Name *interest_name) {
}
// TODO what happen in case of jumps?
- // look for skipped interests
- skipped_interests_.erase(seq); // remove seq if it is there
+ eraseFromPacketCache(
+ seq); // if we send this interest we don't know its state
for (uint32_t i = last_interest_sent_ + 1; i < seq; i++) {
if (indexer_->isFec(i)) {
- skipped_interests_.insert(i);
+ // only fec packets can be skipped
+ addToPacketCache(i, PacketState::SKIPPED);
}
}
@@ -155,6 +169,7 @@ void RTCState::onTimeout(uint32_t seq, bool lost) {
auto it = pending_interests_.find(seq);
if (it != pending_interests_.end()) {
pending_interests_.erase(it);
+ if (indexer_->isFec(seq)) pending_fec_pkt_--;
}
received_timeouts_++;
@@ -162,11 +177,12 @@ void RTCState::onTimeout(uint32_t seq, bool lost) {
}
void RTCState::onLossDetected(uint32_t seq) {
- if (!indexer_->isFec(seq)) {
- packets_lost_++;
- } else if (skipped_interests_.find(seq) == skipped_interests_.end() &&
- seq >= first_interest_sent_seq_) {
+ PacketState state = getPacketState(seq);
+
+ // if the packet is already marked with a state, do nothing
+ if (state == PacketState::UNKNOWN) {
packets_lost_++;
+ addToPacketCache(seq, PacketState::LOST);
}
}
@@ -178,30 +194,40 @@ void RTCState::onRetransmission(uint32_t seq) {
auto it = pending_interests_.find(seq);
if (it != pending_interests_.end()) {
pending_interests_.erase(it);
-#if 0
- packets_lost_++;
-#endif
+ if (indexer_->isFec(seq)) pending_fec_pkt_--;
}
sent_rtx_++;
sent_rtx_last_round_++;
}
+void RTCState::onPossibleLossWithNoRtx(uint32_t seq) {
+ // if fec is on or rtx is disable we don't need to do anything to recover a
+ // packet. however in both cases we need to remove possible missing packets
+ // from the window of pendinig interest in order to free space without wating
+ // for the timeout.
+ auto it = pending_interests_.find(seq);
+ if (it != pending_interests_.end()) {
+ pending_interests_.erase(it);
+ if (indexer_->isFec(seq)) pending_fec_pkt_--;
+ }
+}
+
void RTCState::onDataPacketReceived(const core::ContentObject &content_object,
bool compute_stats) {
uint32_t seq = content_object.getName().getSuffix();
+
if (compute_stats) {
updatePathStats(content_object, false);
received_data_last_round_++;
}
received_data_++;
+ packets_sent_to_app_++;
- struct data_packet_t *data_pkt =
- (struct data_packet_t *)content_object.getPayload()->data();
- uint64_t production_time = data_pkt->getTimestamp();
- if (last_prod_update_ < production_time) {
- last_prod_update_ = production_time;
- uint32_t production_rate = data_pkt->getProductionRate();
- production_rate_ = (double)production_rate;
+ core::ParamsRTC params = RTCState::getDataParams(content_object);
+
+ if (last_prod_update_ < params.timestamp) {
+ last_prod_update_ = params.timestamp;
+ production_rate_ = (double)params.prod_rate;
}
updatePacketSize(content_object);
@@ -219,9 +245,18 @@ void RTCState::onDataPacketReceived(const core::ContentObject &content_object,
void RTCState::onFecPacketReceived(const core::ContentObject &content_object) {
uint32_t seq = content_object.getName().getSuffix();
- updateReceivedBytes(content_object);
+ // updateReceivedBytes(content_object);
+ received_fec_bytes_ +=
+ (uint32_t)(content_object.headerSize() + content_object.payloadSize());
+
+ if (seq > highest_seq_received_) highest_seq_received_ = seq;
+
+ PacketState state = getPacketState(seq);
+ if (state != PacketState::LOST) {
+ // increase only for not lost packets
+ received_fec_pkt_++;
+ }
addRecvOrLost(seq, PacketState::RECEIVED);
- received_fec_pkt_++;
// the producer is responding
// it is generating valid data packets so we consider it active
producer_is_active_ = true;
@@ -233,7 +268,7 @@ void RTCState::onNackPacketReceived(const core::ContentObject &nack,
struct nack_packet_t *nack_pkt =
(struct nack_packet_t *)nack.getPayload()->data();
uint64_t production_time = nack_pkt->getTimestamp();
- uint32_t production_seq = nack_pkt->getProductionSegement();
+ uint32_t production_seq = nack_pkt->getProductionSegment();
uint32_t production_rate = nack_pkt->getProductionRate();
if (TRANSPORT_EXPECT_FALSE(main_path_ == nullptr) ||
@@ -255,6 +290,7 @@ void RTCState::onNackPacketReceived(const core::ContentObject &nack,
received_nacks_++;
received_nacks_last_round_++;
+ bool to_delete = false;
if (production_seq > seq) {
// old nack, seq is lost
// update last nacked
@@ -266,12 +302,19 @@ void RTCState::onNackPacketReceived(const core::ContentObject &nack,
// future nack
// remove the nack from the pending interest map
// (the packet is not received/lost yet)
- if (indexer_->isFec(seq)) pending_fec_pkt_--;
- pending_interests_.erase(seq);
+ to_delete = true;
} else {
// this should be a quite rear event. simply remove the
// packet from the pending interest list
- pending_interests_.erase(seq);
+ to_delete = true;
+ }
+
+ if (to_delete) {
+ auto it = pending_interests_.find(seq);
+ if (it != pending_interests_.end()) {
+ pending_interests_.erase(it);
+ if (indexer_->isFec(seq)) pending_fec_pkt_--;
+ }
}
// the producer is responding
@@ -295,44 +338,58 @@ void RTCState::onPacketLost(uint32_t seq) {
}
#endif
if (!indexer_->isFec(seq)) {
- definitely_lost_pkt_++;
- DLOG_IF(INFO, VLOG_IS_ON(4)) << "packet " << seq << " is lost";
+ PacketState state = getPacketState(seq);
+ if (state == PacketState::LOST || state == PacketState::UNKNOWN) {
+ definitely_lost_pkt_++;
+ DLOG_IF(INFO, VLOG_IS_ON(4)) << "packet " << seq << " is lost";
+ }
}
- addRecvOrLost(seq, PacketState::LOST);
+ addRecvOrLost(seq, PacketState::DEFINITELY_LOST);
}
void RTCState::onPacketRecoveredRtx(uint32_t seq) {
+ packets_sent_to_app_++;
+ if (seq > highest_seq_received_) highest_seq_received_ = seq;
losses_recovered_++;
addRecvOrLost(seq, PacketState::RECEIVED);
}
-void RTCState::onPacketRecoveredFec(uint32_t seq) {
+void RTCState::onFecPacketRecoveredRtx(uint32_t seq) {
+ // This is the same as onPacketRecoveredRtx, but in this is case the
+ // pkt is also a FEC pkt, the addRecvOrLost will be called afterwards
+ if (seq > highest_seq_received_) highest_seq_received_ = seq;
+ losses_recovered_++;
+}
+
+void RTCState::onPacketRecoveredFec(uint32_t seq, uint32_t size) {
losses_recovered_++;
+ packets_sent_to_app_++;
+ recovered_bytes_with_fec_ += size;
+
+ if (seq > highest_seq_received_) highest_seq_received_ = seq;
+
+ // adding header to the count
+ recovered_bytes_with_fec_ += 60; // XXX get header size some where
+
+ if (getPacketState(seq) == PacketState::UNKNOWN)
+ onLossDetected(seq); // the pkt was lost but didn't account for it yet
+
addRecvOrLost(seq, PacketState::RECEIVED);
}
bool RTCState::onProbePacketReceived(const core::ContentObject &probe) {
uint32_t seq = probe.getName().getSuffix();
- uint64_t rtt;
-
- rtt = rtt_probes_->getRtt(seq);
+ uint64_t rtt;
+ rtt = probe_handler_->getRtt(seq);
if (rtt == 0) return false; // this is not a valid probe
- // like for data and nacks update the path stats. Here the RTT is computed
- // by the probe handler. Both probes for rtt and bw are good to esimate
- // info on the path
+ // Like for data and nacks update the path stats. Here the RTT is computed
+ // by the probe handler. Both probes for rtt and bw are good to estimate
+ // info on the path.
uint32_t path_label = probe.getPathLabel();
-
auto path_it = path_table_.find(path_label);
- // update production rate and last_seq_nacked like in case of a nack
- struct nack_packet_t *probe_pkt =
- (struct nack_packet_t *)probe.getPayload()->data();
- uint64_t sender_timestamp = probe_pkt->getTimestamp();
- uint32_t production_seq = probe_pkt->getProductionSegement();
- uint32_t production_rate = probe_pkt->getProductionRate();
-
if (path_it == path_table_.end()) {
// found a new path
std::shared_ptr<RTCDataPath> newPath =
@@ -344,26 +401,26 @@ bool RTCState::onProbePacketReceived(const core::ContentObject &probe) {
auto path = path_it->second;
- path->insertRttSample(rtt);
+ path->insertRttSample(utils::SteadyTime::Milliseconds(rtt), true);
path->receivedNack();
- uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
+ uint64_t now = utils::SteadyTime::nowMs().count();
+
+ core::ParamsRTC params = RTCState::getProbeParams(probe);
- int64_t OWD = now - sender_timestamp;
+ int64_t OWD = now - params.timestamp;
path->insertOwdSample(OWD);
- if (last_prod_update_ < sender_timestamp) {
- last_production_seq_ = production_seq;
- last_prod_update_ = sender_timestamp;
- production_rate_ = (double)production_rate;
+ if (last_prod_update_ < params.timestamp) {
+ last_production_seq_ = params.prod_seg;
+ last_prod_update_ = params.timestamp;
+ production_rate_ = (double)params.prod_rate;
}
// the producer is responding
// we consider it active only if the production rate is not 0
// or the production sequence numner is not 1
- if (production_rate_ != 0 || production_seq != 1) {
+ if (production_rate_ != 0 || params.prod_seg != 1) {
producer_is_active_ = true;
}
@@ -375,7 +432,7 @@ bool RTCState::onProbePacketReceived(const core::ContentObject &probe) {
if (!init_rtt_ && received_probes_ <= INIT_RTT_PROBES) {
if (received_probes_ == 1) {
// we got the first probe, wait at most INIT_RTT_PROBE_WAIT sec for the
- // others
+ // others.
main_path_ = path;
setInitRttTimer(INIT_RTT_PROBE_WAIT);
}
@@ -393,11 +450,21 @@ bool RTCState::onProbePacketReceived(const core::ContentObject &probe) {
return true;
}
-void RTCState::onNewRound(double round_len, bool in_sync) {
- // XXX
- // here we take into account only the single path case so we assume that we
- // don't use two paths in parellel for this single flow
+void RTCState::onJumpForward(uint32_t next_seq) {
+ for (uint32_t seq = highest_seq_received_in_order_ + 1; seq < next_seq;
+ seq++) {
+ auto it = pending_interests_.find(seq);
+ PacketState packet_state = getPacketState(seq);
+ if (it == pending_interests_.end() &&
+ packet_state != PacketState::RECEIVED &&
+ packet_state != PacketState::DEFINITELY_LOST) {
+ onLossDetected(seq);
+ onPacketLost(seq);
+ }
+ }
+}
+void RTCState::onNewRound(double round_len, bool in_sync) {
if (path_table_.empty()) return;
double bytes_per_sec =
@@ -407,7 +474,24 @@ void RTCState::onNewRound(double round_len, bool in_sync) {
else
received_rate_ = (received_rate_ * MOVING_AVG_ALPHA) +
((1 - MOVING_AVG_ALPHA) * bytes_per_sec);
+ double fec_bytes_per_sec =
+ ((double)received_fec_bytes_ * (MILLI_IN_A_SEC / round_len));
+
+ if (fec_received_rate_ == 0)
+ fec_received_rate_ = fec_bytes_per_sec;
+ else
+ fec_received_rate_ = (fec_received_rate_ * 0.8) + (0.2 * fec_bytes_per_sec);
+
+ double fec_recovered_bytes_per_sec =
+ ((double)recovered_bytes_with_fec_ * (MILLI_IN_A_SEC / round_len));
+ if (fec_recovered_rate_ == 0)
+ fec_recovered_rate_ = fec_recovered_bytes_per_sec;
+ else
+ fec_recovered_rate_ =
+ (fec_recovered_rate_ * 0.8) + (0.2 * fec_recovered_bytes_per_sec);
+
+#if 0
// search for an active path. There should be only one active path (meaning a
// path that leads to the producer socket -no cache- and from which we are
// currently getting data packets) at any time. However it may happen that
@@ -428,9 +512,36 @@ void RTCState::onNewRound(double round_len, bool in_sync) {
}
}
}
+#endif
+
+ // search for an active path. Is it possible to have multiple path that are
+ // used at the same time. We use as reference path the one from where we gets
+ // more packets. This means that the path should have better lantecy or less
+ // channel losses
+
+ uint32_t last_round_packets = 0;
+ std::shared_ptr<RTCDataPath> old_main_path = main_path_;
+ main_path_ = nullptr;
+
+ for (auto it = path_table_.begin(); it != path_table_.end(); it++) {
+ if (it->second->isActive()) {
+ uint32_t pkt = it->second->getPacketsLastRound();
+ if (pkt > last_round_packets) {
+ last_round_packets = pkt;
+ main_path_ = it->second;
+ }
+ }
+ it->second->roundEnd();
+ }
- // if (in_sync) updateLossRate();
- updateLossRate();
+ if (main_path_ == nullptr) main_path_ = old_main_path;
+
+ // in case we get a new main path we reset the stats of the old one. this is
+ // beacuse, in case we need to switch back we don't what to take decisions on
+ // old stats that may be outdated.
+ if (main_path_ != old_main_path) old_main_path->clearRtt();
+
+ updateLossRate(in_sync);
// handle nacks
if (!nack_on_last_round_ && received_bytes_ > 0) {
@@ -460,6 +571,8 @@ void RTCState::onNewRound(double round_len, bool in_sync) {
// reset counters
received_bytes_ = 0;
+ received_fec_bytes_ = 0;
+ recovered_bytes_with_fec_ = 0;
packets_lost_ = 0;
definitely_lost_pkt_ = 0;
losses_recovered_ = 0;
@@ -516,20 +629,16 @@ void RTCState::updatePathStats(const core::ContentObject &content_object,
// it means that we are processing an interest
// that is not pending
- uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
+ uint64_t now = utils::SteadyTime::nowMs().count();
uint64_t RTT = now - interest_sent_time;
- path->insertRttSample(RTT);
+ path->insertRttSample(utils::SteadyTime::Milliseconds(RTT), false);
// compute OWD (the first part of the nack and data packet header are the
// same, so we cast to data data packet)
- struct data_packet_t *packet =
- (struct data_packet_t *)content_object.getPayload()->data();
- uint64_t sender_timestamp = packet->getTimestamp();
- int64_t OWD = now - sender_timestamp;
+ core::ParamsRTC params = RTCState::getDataParams(content_object);
+ int64_t OWD = now - params.timestamp;
path->insertOwdSample(OWD);
// compute IAT or set path to producer
@@ -543,59 +652,106 @@ void RTCState::updatePathStats(const core::ContentObject &content_object,
}
}
-void RTCState::updateLossRate() {
+void RTCState::updateLossRate(bool in_sync) {
last_round_loss_rate_ = loss_rate_;
loss_rate_ = 0.0;
- residual_loss_rate_ = 0.0;
uint32_t number_theorically_received_packets_ =
highest_seq_received_ - first_seq_in_round_;
- // in this case no new packet was recevied after the previuos round, avoid
- // division by 0
- if (number_theorically_received_packets_ == 0) return;
-
// XXX this may be quite inefficient if the rate is high
// maybe is better to iterate over the set?
- for (uint32_t i = first_seq_in_round_; i < highest_seq_received_; i++) {
- auto it = skipped_interests_.find(i);
- if (it != skipped_interests_.end()) {
+
+ uint32_t fec_packets = 0;
+ for (uint32_t i = (first_seq_in_round_ + 1); i < highest_seq_received_; i++) {
+ PacketState state = getPacketState(i);
+ if (state == PacketState::SKIPPED) {
if (number_theorically_received_packets_ > 0)
number_theorically_received_packets_--;
- skipped_interests_.erase(it);
}
+ if (indexer_->isFec(i)) fec_packets++;
}
+ if (indexer_->isFec(highest_seq_received_)) fec_packets++;
- loss_rate_ = (double)((double)(packets_lost_) /
- (double)number_theorically_received_packets_);
+ // in this case no new packet was received after the previous round, avoid
+ // division by 0
+ if (number_theorically_received_packets_ == 0 && packets_lost_ == 0) return;
- if (rounds_ % 15 == 0) max_loss_rate_ = 0; // reset every 3 sec
- if (loss_rate_ > max_loss_rate_) max_loss_rate_ = loss_rate_;
+ if (number_theorically_received_packets_ != 0)
+ loss_rate_ = (double)((double)(packets_lost_) /
+ (double)number_theorically_received_packets_);
+ else
+ // we didn't receive anything except NACKs that triggered losses
+ loss_rate_ = 1.0;
- if (avg_loss_rate_ == 0)
+ if (avg_loss_rate_ == -1.0)
avg_loss_rate_ = loss_rate_;
else
avg_loss_rate_ =
avg_loss_rate_ * MOVING_AVG_ALPHA + loss_rate_ * (1 - MOVING_AVG_ALPHA);
- residual_loss_rate_ = (double)((double)(packets_lost_ - losses_recovered_) /
- (double)number_theorically_received_packets_);
+ // update counters for loss rate per second
+ total_expected_packets_ += number_theorically_received_packets_;
+ lost_per_sec_ += packets_lost_;
+
+ if (in_sync) {
+ // update counters for residual losses
+ // fec packets are not sent to the app so we don't want to count them here
+ expected_packets_ +=
+ ((highest_seq_received_ - first_seq_in_round_) - fec_packets);
+ } else {
+ packets_sent_to_app_ = 0;
+ }
+
+ if (rounds_from_last_compute_ >= (MILLI_IN_A_SEC / ROUND_LEN)) {
+ // compute loss rate per second
+ if (lost_per_sec_ > total_expected_packets_)
+ lost_per_sec_ = total_expected_packets_;
+
+ if (total_expected_packets_ == 0)
+ per_sec_loss_rate_ = 0;
+ else
+ per_sec_loss_rate_ =
+ (double)((double)(lost_per_sec_) / (double)total_expected_packets_);
+
+ loss_history_.pushBack(per_sec_loss_rate_);
+ max_loss_rate_ = getMaxLoss();
+
+ if (in_sync && expected_packets_ != 0) {
+ // compute residual loss rate
+ if (packets_sent_to_app_ > expected_packets_) {
+ // this may happen if we get packet from the prev bin that get recovered
+ // on the current one
+ packets_sent_to_app_ = expected_packets_;
+ }
+
+ residual_loss_rate_ =
+ 1.0 - ((double)packets_sent_to_app_ / (double)expected_packets_);
+ if (residual_loss_rate_ < 0.0) residual_loss_rate_ = 0.0;
+ }
+
+ lost_per_sec_ = 0;
+ total_expected_packets_ = 0;
+ expected_packets_ = 0;
+ packets_sent_to_app_ = 0;
+ rounds_from_last_compute_ = 0;
+ }
+
+ rounds_from_last_compute_++;
+}
- if (residual_loss_rate_ < 0) residual_loss_rate_ = 0;
+void RTCState::dataToBeReceived(uint32_t seq) {
+ addToPacketCache(seq, PacketState::TO_BE_RECEIVED);
}
void RTCState::addRecvOrLost(uint32_t seq, PacketState state) {
- if (indexer_->isFec(seq)) {
- pending_fec_pkt_--;
+ auto it = pending_interests_.find(seq);
+ if (it != pending_interests_.end()) {
+ pending_interests_.erase(it);
+ if (indexer_->isFec(seq)) pending_fec_pkt_--;
}
- pending_interests_.erase(seq);
- if (received_or_lost_packets_.size() >= MAX_CACHED_PACKETS) {
- received_or_lost_packets_.erase(received_or_lost_packets_.begin());
- }
- // notice that it may happen that a packet that we consider lost arrives after
- // some time, in this case we simply overwrite the packet state.
- received_or_lost_packets_[seq] = state;
+ addToPacketCache(seq, state);
// keep track of the last packet received/lost
// without holes.
@@ -608,16 +764,25 @@ void RTCState::addRecvOrLost(uint32_t seq, PacketState state) {
} else if (seq <= highest_seq_received_in_order_) {
// here we do nothing
} else if (seq > highest_seq_received_in_order_) {
- // 1) there is a gap in the sequence so we do not update largest_in_seq_
- // 2) all the packets from largest_in_seq_ to seq are in
- // received_or_lost_packets_ an we upate largest_in_seq_
- // or are FEC packets
+ // 1) there is a gap in the sequence so we do not update
+ // highest_seq_received_in_order_
+ // 2) all the packets from highest_seq_received_in_order_ to seq are
+ // received or lost or are fec packetis. In this case we increase
+ // highest_seq_received_in_order_ until we find an hole in the sequence
for (uint32_t i = highest_seq_received_in_order_ + 1; i <= seq; i++) {
- if (received_or_lost_packets_.find(i) ==
- received_or_lost_packets_.end() &&
- !indexer_->isFec(i)) {
- break;
+ PacketState state = getPacketState(i);
+ if ((state == PacketState::UNKNOWN || state == PacketState::LOST)) {
+ if (indexer_->isFec(i)) {
+ // this is a fec packet and we don't care to receive it
+ // however we may need to increse the number or lost packets
+ // XXX: in case we want to use rtx to recover fec packets,
+ // this may prevent to detect a packet loss and no rtx will be sent
+ onLossDetected(i);
+ } else {
+ // this is a data packet and we need to get it
+ break;
+ }
}
// this packet is in order so we can update the
// highest_seq_received_in_order_
@@ -629,9 +794,14 @@ void RTCState::addRecvOrLost(uint32_t seq, PacketState state) {
void RTCState::setInitRttTimer(uint32_t wait) {
init_rtt_timer_->cancel();
init_rtt_timer_->expires_from_now(std::chrono::milliseconds(wait));
- init_rtt_timer_->async_wait([this](std::error_code ec) {
+
+ std::weak_ptr<RTCState> self = shared_from_this();
+ init_rtt_timer_->async_wait([self](const std::error_code &ec) {
if (ec) return;
- checkInitRttTimer();
+
+ if (auto ptr = self.lock()) {
+ ptr->checkInitRttTimer();
+ }
});
}
@@ -639,19 +809,25 @@ void RTCState::checkInitRttTimer() {
if (received_probes_ < INIT_RTT_MIN_PROBES_TO_RECV) {
// we didn't received enough probes, restart
received_probes_ = 0;
- rtt_probes_->setProbes(INIT_RTT_PROBE_INTERVAL, INIT_RTT_PROBES);
- rtt_probes_->sendProbes();
+ probe_handler_->setSuffixRange(MIN_INIT_PROBE_SEQ, MAX_INIT_PROBE_SEQ);
+ probe_handler_->setProbes(INIT_RTT_PROBE_INTERVAL, INIT_RTT_PROBES);
+ probe_handler_->sendProbes();
setInitRttTimer(INIT_RTT_PROBE_RESTART);
return;
}
+
init_rtt_ = true;
main_path_->roundEnd();
- rtt_probes_->setProbes(RTT_PROBE_INTERVAL, 0);
- rtt_probes_->sendProbes();
+ loss_history_.pushBack(probe_handler_->getProbeLossRate());
+ max_loss_rate_ = getMaxLoss();
+
+ probe_handler_->setSuffixRange(MIN_RTT_PROBE_SEQ, MAX_RTT_PROBE_SEQ);
+ probe_handler_->setProbes(RTT_PROBE_INTERVAL, 0);
+ probe_handler_->sendProbes();
// init last_seq_nacked_. skip packets that may come from the cache
double prod_rate = getProducerRate();
- double rtt = (double)getRTT() / MILLI_IN_A_SEC;
+ double rtt = (double)getMinRTT() / MILLI_IN_A_SEC;
double packet_size = getAveragePacketSize();
uint32_t pkt_in_rtt_ = std::floor(((prod_rate / packet_size) * rtt) * 0.8);
last_seq_nacked_ = last_production_seq_ + pkt_in_rtt_;
@@ -659,6 +835,68 @@ void RTCState::checkInitRttTimer() {
discovered_rtt_callback_();
}
+double RTCState::getMaxLoss() {
+ if (loss_history_.size() != 0) return loss_history_.begin();
+ return 0;
+}
+
+core::ParamsRTC RTCState::getProbeParams(const core::ContentObject &probe) {
+ uint32_t seq = probe.getName().getSuffix();
+ core::ParamsRTC params;
+
+ switch (ProbeHandler::getProbeType(seq)) {
+ case ProbeType::INIT: {
+ core::ContentObjectManifest manifest(
+ const_cast<core::ContentObject &>(probe));
+ manifest.decode();
+ params = manifest.getParamsRTC();
+ break;
+ }
+ case ProbeType::RTT: {
+ struct nack_packet_t *probe_pkt =
+ (struct nack_packet_t *)probe.getPayload()->data();
+ params = core::ParamsRTC{
+ .timestamp = probe_pkt->getTimestamp(),
+ .prod_rate = probe_pkt->getProductionRate(),
+ .prod_seg = probe_pkt->getProductionSegment(),
+ };
+ break;
+ }
+ default:
+ break;
+ }
+
+ return params;
+}
+
+core::ParamsRTC RTCState::getDataParams(const core::ContentObject &data) {
+ core::ParamsRTC params;
+
+ switch (data.getPayloadType()) {
+ case core::PayloadType::DATA: {
+ struct data_packet_t *data_pkt =
+ (struct data_packet_t *)data.getPayload()->data();
+ params = core::ParamsRTC{
+ .timestamp = data_pkt->getTimestamp(),
+ .prod_rate = data_pkt->getProductionRate(),
+ .prod_seg = data.getName().getSuffix(),
+ };
+ break;
+ }
+ case core::PayloadType::MANIFEST: {
+ core::ContentObjectManifest manifest(
+ const_cast<core::ContentObject &>(data));
+ manifest.decode();
+ params = manifest.getParamsRTC();
+ break;
+ }
+ default:
+ break;
+ }
+
+ return params;
+}
+
} // namespace rtc
} // namespace protocol
diff --git a/libtransport/src/protocols/rtc/rtc_state.h b/libtransport/src/protocols/rtc/rtc_state.h
index 729ba7a1b..8bf48ccc2 100644
--- a/libtransport/src/protocols/rtc/rtc_state.h
+++ b/libtransport/src/protocols/rtc/rtc_state.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2021 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -14,13 +14,16 @@
*/
#pragma once
+#include <core/facade.h>
#include <hicn/transport/config.h>
#include <hicn/transport/core/asio_wrapper.h>
#include <hicn/transport/core/content_object.h>
#include <hicn/transport/core/name.h>
+#include <hicn/transport/utils/rtc_quality_score.h>
#include <protocols/indexer.h>
#include <protocols/rtc/probe_handler.h>
#include <protocols/rtc/rtc_data_path.h>
+#include <utils/max_filter.h>
#include <map>
#include <set>
@@ -31,25 +34,50 @@ namespace protocol {
namespace rtc {
-enum class PacketState : uint8_t { RECEIVED, LOST, UNKNOWN };
+// packet state
+// RECEIVED: the packet was already received
+// LOST: the packet is marked as lost but can be recovered
+// DEFINITELY_LOST: the packet is lost and cannot be recovered
+// TO_BE_RECEIVED: when a packet is received is sent to the FEC decoder. the fec
+// decoder may decide to send the packet directly to the app. to avoid
+// duplicated the packet is marked with this state
+// SKIPPED: an interest that was not sent, only for FEC packets
+// UNKNOWN: unknown state
+enum class PacketState : uint8_t {
+ RECEIVED,
+ TO_BE_RECEIVED,
+ LOST,
+ DEFINITELY_LOST,
+ SKIPPED,
+ UNKNOWN
+};
+
+class RTCState : public std::enable_shared_from_this<RTCState> {
+ using PendingInterestsMap = std::map<uint32_t, uint64_t>;
+
+ private:
+ const double MAX_CACHED_PACKETS = 8192; // XXX this value may be too small
+ // for high rate apps
-class RTCState : std::enable_shared_from_this<RTCState> {
public:
using DiscoveredRttCallback = std::function<void()>;
public:
- RTCState(Indexer *indexer,
- ProbeHandler::SendProbeCallback &&rtt_probes_callback,
+ RTCState(Indexer *indexer, ProbeHandler::SendProbeCallback &&probe_callback,
DiscoveredRttCallback &&discovered_rtt_callback,
asio::io_service &io_service);
~RTCState();
+ // initialization
+ void initParams();
+
// packet events
void onSendNewInterest(const core::Name *interest_name);
void onTimeout(uint32_t seq, bool lost);
void onLossDetected(uint32_t seq);
void onRetransmission(uint32_t seq);
+ void onPossibleLossWithNoRtx(uint32_t seq);
void onDataPacketReceived(const core::ContentObject &content_object,
bool compute_stats);
void onFecPacketReceived(const core::ContentObject &content_object);
@@ -57,8 +85,10 @@ class RTCState : std::enable_shared_from_this<RTCState> {
bool compute_stats);
void onPacketLost(uint32_t seq);
void onPacketRecoveredRtx(uint32_t seq);
- void onPacketRecoveredFec(uint32_t seq);
+ void onFecPacketRecoveredRtx(uint32_t seq);
+ void onPacketRecoveredFec(uint32_t seq, uint32_t size);
bool onProbePacketReceived(const core::ContentObject &probe);
+ void onJumpForward(uint32_t next_seq);
// protocol state
void onNewRound(double round_len, bool in_sync);
@@ -72,10 +102,21 @@ class RTCState : std::enable_shared_from_this<RTCState> {
// delay metrics
bool isRttDiscovered() const { return init_rtt_; }
- uint64_t getRTT() const {
+ uint64_t getMinRTT() const {
if (mainPathIsValid()) return main_path_->getMinRtt();
return 0;
}
+
+ uint64_t getAvgRTT() const {
+ if (mainPathIsValid()) return main_path_->getAvgRtt();
+ return 0;
+ }
+
+ uint64_t getMaxRTT() const {
+ if (mainPathIsValid()) return main_path_->getMaxRtt();
+ return 0;
+ }
+
void resetRttStats() {
if (mainPathIsValid()) main_path_->clearRtt();
}
@@ -98,6 +139,7 @@ class RTCState : std::enable_shared_from_this<RTCState> {
uint64_t getInterestSentTime(uint32_t seq) {
auto it = pending_interests_.find(seq);
if (it != pending_interests_.end()) return it->second;
+
return 0;
}
@@ -110,14 +152,15 @@ class RTCState : std::enable_shared_from_this<RTCState> {
return pending_interests_.size();
}
- PacketState isReceivedOrLost(uint32_t seq) {
- auto it = received_or_lost_packets_.find(seq);
- if (it != received_or_lost_packets_.end()) return it->second;
+ PacketState getPacketState(uint32_t seq) {
+ auto it = packet_cache_.find(seq);
+ if (it != packet_cache_.end()) return it->second;
return PacketState::UNKNOWN;
}
// loss rate
- double getLossRate() const { return loss_rate_; }
+ double getPerRoundLossRate() const { return loss_rate_; }
+ double getPerSecondLossRate() const { return per_sec_loss_rate_; }
double getAvgLossRate() const { return avg_loss_rate_; }
double getMaxLossRate() const { return max_loss_rate_; }
double getLastRoundLossRate() const { return last_round_loss_rate_; }
@@ -134,15 +177,22 @@ class RTCState : std::enable_shared_from_this<RTCState> {
return highest_seq_received_in_order_;
}
+ double getMaxLoss();
+
// fec packets
uint32_t getReceivedFecPackets() const { return received_fec_pkt_; }
uint32_t getPendingFecPackets() const { return pending_fec_pkt_; }
// generic stats
uint32_t getReceivedBytesInRound() const { return received_bytes_; }
+ uint32_t getReceivedFecBytesInRound() const { return received_fec_bytes_; }
+ uint32_t getRecoveredFecBytesInRound() const {
+ return recovered_bytes_with_fec_;
+ }
uint32_t getReceivedNacksInRound() const {
return received_nacks_last_round_;
}
+ uint32_t getReceivedDataInRound() const { return received_data_last_round_; }
uint32_t getSentInterestInRound() const { return sent_interests_last_round_; }
uint32_t getSentRtxInRound() const { return sent_rtx_last_round_; }
@@ -150,6 +200,9 @@ class RTCState : std::enable_shared_from_this<RTCState> {
double getAvailableBw() const { return 0.0; }; // TODO
double getProducerRate() const { return production_rate_; }
double getReceivedRate() const { return received_rate_; }
+ double getReceivedFecRate() const { return fec_received_rate_; }
+ double getRecoveredFecRate() const { return fec_recovered_rate_; }
+
double getAveragePacketSize() const { return avg_packet_size_; }
// nacks
@@ -162,22 +215,46 @@ class RTCState : std::enable_shared_from_this<RTCState> {
// packets from cache
double getPacketFromCacheRatio() const { return data_from_cache_rate_; }
- std::map<uint32_t, uint64_t>::iterator getPendingInterestsMapBegin() {
+ PendingInterestsMap::iterator getPendingInterestsMapBegin() {
return pending_interests_.begin();
}
- std::map<uint32_t, uint64_t>::iterator getPendingInterestsMapEnd() {
+ PendingInterestsMap::iterator getPendingInterestsMapEnd() {
return pending_interests_.end();
}
+ // quality
+ uint8_t getQualityScore() {
+ uint8_t qs = quality_score_.getQualityScore(
+ getMaxRTT(), std::round(getResidualLossRate() * 100));
+ return qs;
+ }
+
+ // We received a data pkt that will be set to RECEIVED, but first we have to
+ // go through FEC. We do not want to consider this pkt as recovered, thus we
+ // set it as TO_BE_RECEIVED.
+ void dataToBeReceived(uint32_t seq);
+
+ // Extract RTC parameters from probes (init or RTT probes) and data packets.
+ static core::ParamsRTC getProbeParams(const core::ContentObject &probe);
+ static core::ParamsRTC getDataParams(const core::ContentObject &data);
+
private:
- void initParams();
+ void addToPacketCache(uint32_t seq, PacketState state) {
+ // this function adds or updates the current state
+ if (packet_cache_.size() >= MAX_CACHED_PACKETS) {
+ packet_cache_.erase(packet_cache_.begin());
+ }
+ packet_cache_[seq] = state;
+ }
+
+ void eraseFromPacketCache(uint32_t seq) { packet_cache_.erase(seq); }
// update stats
void updateState();
void updateReceivedBytes(const core::ContentObject &content_object);
void updatePacketSize(const core::ContentObject &content_object);
void updatePathStats(const core::ContentObject &content_object, bool is_nack);
- void updateLossRate();
+ void updateLossRate(bool in_sycn);
void addRecvOrLost(uint32_t seq, PacketState state);
@@ -211,22 +288,39 @@ class RTCState : std::enable_shared_from_this<RTCState> {
double avg_loss_rate_;
double max_loss_rate_;
double last_round_loss_rate_;
+ utils::MaxFilter<double> loss_history_;
+
+ // per second loss rate
+ uint32_t lost_per_sec_;
+ uint32_t total_expected_packets_;
+ double per_sec_loss_rate_;
+
+ // conunters for residual losses
+ // residual losses are computed every second and are used
+ // as feedback to the upper levels (e.g application)
+ uint32_t expected_packets_;
+ uint32_t packets_sent_to_app_;
+ uint32_t rounds_from_last_compute_;
double residual_loss_rate_;
// bw counters
uint32_t received_bytes_;
+ uint32_t received_fec_bytes_;
+ uint32_t recovered_bytes_with_fec_;
double avg_packet_size_;
- double production_rate_; // rate communicated by the producer using nacks
- double received_rate_; // rate recevied by the consumer
+ double production_rate_; // rate communicated by the producer using nacks
+ double received_rate_; // rate recevied by the consumer (only data)
+ double fec_received_rate_; // fec rate recevied by the consumer
+ double fec_recovered_rate_; // rate recovered using fec
- // nack counter
+ // nack counters
// the bool takes tracks only about the valid nacks (no rtx) and it is used to
// switch between the states. Instead received_nacks_last_round_ logs all the
// nacks for statistics
bool nack_on_last_round_;
uint32_t received_nacks_last_round_;
- // packets counter
+ // packets counters
uint32_t received_packets_last_round_;
uint32_t received_data_last_round_;
uint32_t received_data_from_cache_;
@@ -234,11 +328,11 @@ class RTCState : std::enable_shared_from_this<RTCState> {
uint32_t sent_interests_last_round_;
uint32_t sent_rtx_last_round_;
- // fec counter
+ // fec counters
uint32_t received_fec_pkt_;
uint32_t pending_fec_pkt_;
- // round conunters
+ // round counters
uint32_t rounds_;
uint32_t rounds_without_nacks_;
uint32_t rounds_without_packets_;
@@ -261,23 +355,27 @@ class RTCState : std::enable_shared_from_this<RTCState> {
// packet received
// cache where to store info about the last MAX_CACHED_PACKETS
- std::map<uint32_t, PacketState> received_or_lost_packets_;
+ // these are packets that are received or lost or definitely lost and are not
+ // anymore in the pending intetest list
+ std::map<uint32_t, PacketState> packet_cache_;
// pending interests
- std::map<uint32_t, uint64_t> pending_interests_;
+ PendingInterestsMap pending_interests_;
// indexer
Indexer *indexer_;
- // skipped interests
+ // used to keep track of the skipped interests
uint32_t last_interest_sent_;
- std::unordered_set<uint32_t> skipped_interests_;
// probes
- std::shared_ptr<ProbeHandler> rtt_probes_;
+ std::shared_ptr<ProbeHandler> probe_handler_;
bool init_rtt_;
std::unique_ptr<asio::steady_timer> init_rtt_timer_;
+ // quality score
+ RTCQualityScore quality_score_;
+
// callbacks
DiscoveredRttCallback discovered_rtt_callback_;
};
diff --git a/libtransport/src/protocols/rtc/rtc_verifier.cc b/libtransport/src/protocols/rtc/rtc_verifier.cc
new file mode 100644
index 000000000..29968dd02
--- /dev/null
+++ b/libtransport/src/protocols/rtc/rtc_verifier.cc
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2017-2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <core/facade.h>
+#include <protocols/rtc/rtc_packet.h>
+#include <protocols/rtc/rtc_verifier.h>
+
+namespace transport {
+namespace protocol {
+namespace rtc {
+
+RTCVerifier::RTCVerifier(std::shared_ptr<auth::Verifier> verifier,
+ uint32_t max_unverified_delay)
+ : verifier_(verifier), max_unverified_delay_(max_unverified_delay) {}
+
+void RTCVerifier::setState(std::shared_ptr<RTCState> rtc_state) {
+ rtc_state_ = rtc_state;
+}
+
+void RTCVerifier::setVerifier(std::shared_ptr<auth::Verifier> verifier) {
+ verifier_ = verifier;
+}
+
+void RTCVerifier::setMaxUnverifiedDelay(uint32_t max_unverified_delay) {
+ max_unverified_delay_ = max_unverified_delay;
+}
+
+auth::VerificationPolicy RTCVerifier::verify(
+ core::ContentObject &content_object, bool is_fec) {
+ uint32_t suffix = content_object.getName().getSuffix();
+ core::PayloadType payload_type = content_object.getPayloadType();
+
+ bool is_probe = ProbeHandler::getProbeType(suffix) != ProbeType::NOT_PROBE;
+ bool is_nack = !is_probe && content_object.payloadSize() == NACK_HEADER_SIZE;
+ bool is_manifest = !is_probe && !is_nack && !is_fec &&
+ payload_type == core::PayloadType::MANIFEST;
+ bool is_data = !is_probe && !is_nack && !is_fec &&
+ payload_type == core::PayloadType::DATA;
+
+ if (is_probe) return verifyProbe(content_object);
+ if (is_nack) return verifyNack(content_object);
+ if (is_fec) return verifyFec(content_object);
+ if (is_data) return verifyData(content_object);
+ if (is_manifest) return verifyManifest(content_object);
+
+ auth::VerificationPolicy policy = auth::VerificationPolicy::ABORT;
+ verifier_->callVerificationFailedCallback(suffix, policy);
+ return policy;
+}
+
+auth::VerificationPolicy RTCVerifier::verifyProbe(
+ core::ContentObject &content_object) {
+ switch (ProbeHandler::getProbeType(content_object.getName().getSuffix())) {
+ case ProbeType::INIT: {
+ auth::VerificationPolicy policy = verifyManifest(content_object);
+ if (policy != auth::VerificationPolicy::ACCEPT) {
+ return policy;
+ }
+ return processManifest(content_object);
+ }
+ case ProbeType::RTT:
+ return verifyNack(content_object);
+ default:
+ auth::VerificationPolicy policy = auth::VerificationPolicy::ABORT;
+ verifier_->callVerificationFailedCallback(
+ content_object.getName().getSuffix(), policy);
+ return policy;
+ }
+}
+
+auth::VerificationPolicy RTCVerifier::verifyNack(
+ core::ContentObject &content_object) {
+ return verifier_->verifyPackets(&content_object);
+}
+
+auth::VerificationPolicy RTCVerifier::verifyFec(
+ core::ContentObject &content_object) {
+ return verifier_->verifyPackets(&content_object);
+}
+
+auth::VerificationPolicy RTCVerifier::verifyData(
+ core::ContentObject &content_object) {
+ uint32_t suffix = content_object.getName().getSuffix();
+
+ if (_is_ah(content_object.getFormat())) {
+ return verifier_->verifyPackets(&content_object);
+ }
+
+ unverified_bytes_[suffix] =
+ content_object.headerSize() + content_object.payloadSize();
+ unverified_packets_[suffix] =
+ content_object.computeDigest(manifest_hash_algo_);
+
+ // An alert is raised when too much packets remain unverified
+ if (getTotalUnverified() > max_unverified_bytes_) {
+ unverified_bytes_.clear();
+ unverified_packets_.clear();
+
+ auth::VerificationPolicy policy = auth::VerificationPolicy::ABORT;
+ verifier_->callVerificationFailedCallback(suffix, policy);
+ return policy;
+ }
+
+ return auth::VerificationPolicy::ACCEPT;
+}
+
+auth::VerificationPolicy RTCVerifier::verifyManifest(
+ core::ContentObject &content_object) {
+ return verifier_->verifyPackets(&content_object);
+}
+
+auth::VerificationPolicy RTCVerifier::processManifest(
+ core::ContentObject &content_object) {
+ uint32_t suffix = content_object.getName().getSuffix();
+
+ core::ContentObjectManifest manifest(content_object);
+ manifest.decode();
+
+ // Update last manifest
+ if (suffix > last_manifest_) {
+ last_manifest_ = suffix;
+ }
+
+ // Extract parameters
+ manifest_hash_algo_ = manifest.getHashAlgorithm();
+ core::ParamsRTC params = manifest.getParamsRTC();
+
+ if (params.prod_rate > 0) {
+ max_unverified_bytes_ = static_cast<uint64_t>(
+ (max_unverified_delay_ / 1000.0) * params.prod_rate);
+ }
+
+ if (max_unverified_bytes_ == 0 || !rtc_state_) {
+ auth::VerificationPolicy policy = auth::VerificationPolicy::ABORT;
+ verifier_->callVerificationFailedCallback(suffix, policy);
+ return policy;
+ }
+
+ // Extract hashes
+ auth::Verifier::SuffixMap suffix_map =
+ core::ContentObjectManifest::getSuffixMap(&manifest);
+
+ // Return early if the manifest is empty
+ if (suffix_map.empty()) {
+ return auth::VerificationPolicy::ACCEPT;
+ }
+
+ // Remove lost packets from digest map
+ manifest_digests_.insert(suffix_map.begin(), suffix_map.end());
+ for (auto it = manifest_digests_.begin(); it != manifest_digests_.end();) {
+ if (rtc_state_->getPacketState(it->first) == PacketState::DEFINITELY_LOST) {
+ unverified_packets_.erase(it->first);
+ unverified_bytes_.erase(it->first);
+ it = manifest_digests_.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ // Verify packets
+ auth::Verifier::PolicyMap policies =
+ verifier_->verifyHashes(unverified_packets_, manifest_digests_);
+
+ for (const auto &policy : policies) {
+ switch (policy.second) {
+ case auth::VerificationPolicy::ACCEPT: {
+ manifest_digests_.erase(policy.first);
+ unverified_packets_.erase(policy.first);
+ unverified_bytes_.erase(policy.first);
+ break;
+ }
+ case auth::VerificationPolicy::UNKNOWN:
+ break;
+ case auth::VerificationPolicy::DROP:
+ case auth::VerificationPolicy::ABORT:
+ auth::VerificationPolicy p = policy.second;
+ verifier_->callVerificationFailedCallback(policy.first, p);
+ return p;
+ }
+ }
+
+ return auth::VerificationPolicy::ACCEPT;
+}
+
+void RTCVerifier::onDataRecoveredFec(uint32_t suffix) {
+ manifest_digests_.erase(suffix);
+}
+
+void RTCVerifier::onJumpForward(uint32_t next_suffix) {
+ if (next_suffix <= last_manifest_ + 1) {
+ return;
+ }
+
+ // When we jump forward in the suffix sequence, we remove packets that
+ // probably won't be verified. Those packets have a suffix in the range
+ // [last_manifest_ + 1, next_suffix[.
+ for (auto it = unverified_packets_.begin();
+ it != unverified_packets_.end();) {
+ if (it->first > last_manifest_) {
+ unverified_bytes_.erase(it->first);
+ it = unverified_packets_.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
+uint32_t RTCVerifier::getTotalUnverified() const {
+ uint32_t total = 0;
+
+ for (auto bytes : unverified_bytes_) {
+ if (bytes.second > UINT32_MAX - total) {
+ total = UINT32_MAX;
+ break;
+ }
+ total += bytes.second;
+ }
+
+ return total;
+}
+
+uint32_t RTCVerifier::getMaxUnverified() const { return max_unverified_bytes_; }
+
+} // end namespace rtc
+} // end namespace protocol
+} // end namespace transport
diff --git a/libtransport/src/protocols/rtc/rtc_verifier.h b/libtransport/src/protocols/rtc/rtc_verifier.h
new file mode 100644
index 000000000..596bd8536
--- /dev/null
+++ b/libtransport/src/protocols/rtc/rtc_verifier.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2017-2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <core/facade.h>
+#include <hicn/transport/auth/verifier.h>
+#include <hicn/transport/core/content_object.h>
+#include <protocols/rtc/rtc_state.h>
+
+namespace transport {
+namespace protocol {
+namespace rtc {
+
+class RTCVerifier {
+ public:
+ RTCVerifier(std::shared_ptr<auth::Verifier> verifier,
+ uint32_t max_unverified_delay);
+
+ virtual ~RTCVerifier() = default;
+
+ void setState(std::shared_ptr<RTCState> rtc_state);
+
+ void setVerifier(std::shared_ptr<auth::Verifier> verifier);
+
+ void setMaxUnverifiedDelay(uint32_t max_unverified_delay);
+
+ void onDataRecoveredFec(uint32_t suffix);
+ void onJumpForward(uint32_t next_suffix);
+
+ uint32_t getTotalUnverified() const;
+ uint32_t getMaxUnverified() const;
+
+ auth::VerificationPolicy verify(core::ContentObject &content_object,
+ bool is_fec = false);
+ auth::VerificationPolicy verifyProbe(core::ContentObject &content_object);
+ auth::VerificationPolicy verifyNack(core::ContentObject &content_object);
+ auth::VerificationPolicy verifyFec(core::ContentObject &content_object);
+ auth::VerificationPolicy verifyData(core::ContentObject &content_object);
+ auth::VerificationPolicy verifyManifest(core::ContentObject &content_object);
+
+ auth::VerificationPolicy processManifest(core::ContentObject &content_object);
+
+ protected:
+ // The RTC state.
+ std::shared_ptr<RTCState> rtc_state_;
+ // The verifier instance.
+ std::shared_ptr<auth::Verifier> verifier_;
+ // Hash algorithm used by manifests.
+ auth::CryptoHashType manifest_hash_algo_;
+ // The last manifest processed.
+ auth::Suffix last_manifest_;
+ // Hold digests extracted from all manifests received.
+ auth::Verifier::SuffixMap manifest_digests_;
+ // Hold hashes of all content objects received before they are verified.
+ auth::Verifier::SuffixMap unverified_packets_;
+ // Hold number of unverified bytes.
+ std::unordered_map<auth::Suffix, uint32_t> unverified_bytes_;
+ // Maximum delay (in ms) for an unverified byte to become verifed.
+ uint32_t max_unverified_delay_;
+ // Maximum number of unverified bytes before aborting the connection.
+ uint64_t max_unverified_bytes_;
+};
+
+} // end namespace rtc
+} // namespace protocol
+} // namespace transport
diff --git a/libtransport/src/protocols/transport_protocol.cc b/libtransport/src/protocols/transport_protocol.cc
index d6954ac37..f1e49ec0b 100644
--- a/libtransport/src/protocols/transport_protocol.cc
+++ b/libtransport/src/protocols/transport_protocol.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -25,7 +25,8 @@ using namespace interface;
TransportProtocol::TransportProtocol(implementation::ConsumerSocket *icn_socket,
Indexer *indexer, Reassembly *reassembly)
- : socket_(icn_socket),
+ : Protocol(),
+ socket_(icn_socket),
indexer_verifier_(indexer),
reassembly_(reassembly),
fec_decoder_(nullptr),
@@ -36,90 +37,82 @@ TransportProtocol::TransportProtocol(implementation::ConsumerSocket *icn_socket,
on_interest_satisfied_(VOID_HANDLER),
on_content_object_input_(VOID_HANDLER),
stats_summary_(VOID_HANDLER),
+ on_fwd_strategy_(VOID_HANDLER),
+ on_rec_strategy_(VOID_HANDLER),
on_payload_(VOID_HANDLER),
- fec_type_(fec::FECType::UNKNOWN),
- is_running_(false) {
+ fec_type_(fec::FECType::UNKNOWN) {
socket_->getSocketOption(GeneralTransportOptions::PORTAL, portal_);
socket_->getSocketOption(OtherOptions::STATISTICS, &stats_);
- // Set this transport protocol as portal's consumer callback
- portal_->setConsumerCallback(this);
-
indexer_verifier_->setReassembly(reassembly_.get());
reassembly->setIndexer(indexer_verifier_.get());
}
+TransportProtocol::~TransportProtocol() {}
+
int TransportProtocol::start() {
// If the protocol is already running, return otherwise set as running
- if (is_running_) return -1;
-
- // Get all callbacks references
- socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_RETRANSMISSION,
- &on_interest_retransmission_);
- socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_OUTPUT,
- &on_interest_output_);
- socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_EXPIRED,
- &on_interest_timeout_);
- socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_SATISFIED,
- &on_interest_satisfied_);
- socket_->getSocketOption(ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT,
- &on_content_object_input_);
- socket_->getSocketOption(ConsumerCallbacksOptions::STATS_SUMMARY,
- &stats_summary_);
- socket_->getSocketOption(ConsumerCallbacksOptions::READ_CALLBACK,
- &on_payload_);
-
- socket_->getSocketOption(GeneralTransportOptions::ASYNC_MODE, is_async_);
-
- // Set it is the first time we schedule an interest
- is_first_ = true;
-
- // Reset the protocol state machine
- reset();
-
- // Schedule next interests
- scheduleNextInterests();
-
- is_first_ = false;
-
- // Set the protocol as running
- is_running_ = true;
-
- if (!is_async_) {
- // Start Event loop
- portal_->runEventsLoop();
-
- // Not running anymore
- is_running_ = false;
+ if (isRunning()) {
+ return -1;
}
- return 0;
-}
-
-void TransportProtocol::stop() {
- is_running_ = false;
+ // Start protocol on its own thread
+ portal_->getThread().add([this]() {
+ // Get all callbacks references
+ socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_RETRANSMISSION,
+ &on_interest_retransmission_);
+ socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_OUTPUT,
+ &on_interest_output_);
+ socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_EXPIRED,
+ &on_interest_timeout_);
+ socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_SATISFIED,
+ &on_interest_satisfied_);
+ socket_->getSocketOption(ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT,
+ &on_content_object_input_);
+ socket_->getSocketOption(ConsumerCallbacksOptions::STATS_SUMMARY,
+ &stats_summary_);
+ socket_->getSocketOption(ConsumerCallbacksOptions::FWD_STRATEGY_CHANGE,
+ &on_fwd_strategy_);
+ socket_->getSocketOption(ConsumerCallbacksOptions::REC_STRATEGY_CHANGE,
+ &on_rec_strategy_);
+ socket_->getSocketOption(ConsumerCallbacksOptions::READ_CALLBACK,
+ &on_payload_);
+
+ socket_->getSocketOption(GeneralTransportOptions::ASYNC_MODE, is_async_);
+
+ std::string fec_type_str = "";
+ socket_->getSocketOption(GeneralTransportOptions::FEC_TYPE, fec_type_str);
+ if (fec_type_str != "") {
+ fec_type_ = fec::FECUtils::fecTypeFromString(fec_type_str.c_str());
+ }
+
+ // Set it is the first time we schedule an interest
+ is_first_ = true;
+
+ // Reset the protocol state machine
+ reset();
+
+ // Set this transport protocol as portal's consumer callback
+ portal_->registerTransportCallback(this);
+
+ // Schedule next interests
+ scheduleNextInterests();
+
+ is_first_ = false;
+
+ // Set the protocol as running
+ setRunning();
+ });
- if (!is_async_) {
- portal_->stopEventsLoop();
- } else {
- portal_->clear();
- }
+ return 0;
}
void TransportProtocol::resume() {
if (isRunning()) return;
- is_running_ = true;
+ setRunning();
- scheduleNextInterests();
-
- if (!is_async_) {
- // Start Event loop
- portal_->runEventsLoop();
-
- // Not running anymore
- is_running_ = false;
- }
+ portal_->getThread().tryRunHandlerNow([this]() { scheduleNextInterests(); });
}
void TransportProtocol::reset() {
@@ -130,7 +123,7 @@ void TransportProtocol::reset() {
}
}
-void TransportProtocol::onContentReassembled(std::error_code ec) {
+void TransportProtocol::onContentReassembled(const std::error_code &ec) {
stop();
if (!on_payload_) {
@@ -153,7 +146,12 @@ void TransportProtocol::sendInterest(
uint32_t len) {
DLOG_IF(INFO, VLOG_IS_ON(3)) << "Sending interest for name " << interest_name;
- auto interest = core::PacketManager<>::getInstance().getPacket<Interest>();
+ Packet::Format format;
+ socket_->getSocketOption(interface::GeneralTransportOptions::PACKET_FORMAT,
+ format);
+
+ auto interest =
+ core::PacketManager<>::getInstance().getPacket<Interest>(format);
interest->setName(interest_name);
for (uint32_t i = 0; i < len; i++) {
@@ -176,6 +174,14 @@ void TransportProtocol::sendInterest(
portal_->sendInterest(std::move(interest));
}
+void TransportProtocol::onError(const std::error_code &ec) {
+ // error from portal: stop socket
+ stop();
+
+ // signal error to application
+ on_payload_->readError(ec);
+}
+
void TransportProtocol::onTimeout(Interest::Ptr &i, const Name &n) {
if (TRANSPORT_EXPECT_FALSE(!isRunning())) {
return;
diff --git a/libtransport/src/protocols/transport_protocol.h b/libtransport/src/protocols/transport_protocol.h
index 1008a238b..ad8cf0346 100644
--- a/libtransport/src/protocols/transport_protocol.h
+++ b/libtransport/src/protocols/transport_protocol.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -19,10 +19,10 @@
#include <hicn/transport/interfaces/socket_consumer.h>
#include <hicn/transport/interfaces/statistics.h>
#include <hicn/transport/utils/object_pool.h>
-#include <implementation/socket.h>
#include <protocols/data_processing_events.h>
#include <protocols/fec_base.h>
#include <protocols/indexer.h>
+#include <protocols/protocol.h>
#include <protocols/reassembly.h>
#include <array>
@@ -38,8 +38,10 @@ class IndexVerificationManager;
using ReadCallback = interface::ConsumerSocket::ReadCallback;
-class TransportProtocol : public core::Portal::ConsumerCallback,
- public ContentObjectProcessingEventCallback {
+class TransportProtocol
+ : public ContentObjectProcessingEventCallback,
+ public Protocol,
+ public std::enable_shared_from_this<TransportProtocol> {
static constexpr std::size_t interest_pool_size = 4096;
friend class ManifestIndexManager;
@@ -48,13 +50,11 @@ class TransportProtocol : public core::Portal::ConsumerCallback,
TransportProtocol(implementation::ConsumerSocket *icn_socket,
Indexer *indexer, Reassembly *reassembly);
- virtual ~TransportProtocol() = default;
-
- TRANSPORT_ALWAYS_INLINE bool isRunning() { return is_running_; }
+ virtual ~TransportProtocol();
virtual int start();
- virtual void stop();
+ using Protocol::stop;
virtual void resume();
@@ -69,7 +69,7 @@ class TransportProtocol : public core::Portal::ConsumerCallback,
virtual void scheduleNextInterests() = 0;
// Events generated by the indexing
- virtual void onContentReassembled(std::error_code ec);
+ virtual void onContentReassembled(const std::error_code &ec);
virtual void onPacketDropped(Interest &interest,
ContentObject &content_object,
const std::error_code &ec) override = 0;
@@ -90,7 +90,8 @@ class TransportProtocol : public core::Portal::ConsumerCallback,
AllocatorHandler &&allocator_handler) {
if (!fec_decoder_) {
// Try to get FEC from environment
- if (const char *fec_str = std::getenv("TRANSPORT_FEC_TYPE")) {
+ const char *fec_str = std::getenv("TRANSPORT_FEC_TYPE");
+ if (fec_str && (fec_type_ == fec::FECType::UNKNOWN)) {
LOG(INFO) << "Using FEC " << fec_str;
fec_type_ = fec::FECUtils::fecTypeFromString(fec_str);
}
@@ -114,14 +115,13 @@ class TransportProtocol : public core::Portal::ConsumerCallback,
// Consumer Callback
void onContentObject(Interest &i, ContentObject &c) override;
void onTimeout(Interest::Ptr &i, const Name &n) override;
- void onError(std::error_code ec) override {}
+ void onError(const std::error_code &ec) override;
protected:
implementation::ConsumerSocket *socket_;
std::unique_ptr<Indexer> indexer_verifier_;
std::unique_ptr<Reassembly> reassembly_;
std::unique_ptr<fec::ConsumerFEC> fec_decoder_;
- std::shared_ptr<core::Portal> portal_;
// True if it si the first time we schedule an interest
std::atomic<bool> is_first_;
interface::TransportStatistics *stats_;
@@ -134,14 +134,13 @@ class TransportProtocol : public core::Portal::ConsumerCallback,
interface::ConsumerContentObjectCallback *on_content_object_input_;
interface::ConsumerContentObjectCallback *on_content_object_;
interface::ConsumerTimerCallback *stats_summary_;
+ interface::StrategyCallback *on_fwd_strategy_;
+ interface::StrategyCallback *on_rec_strategy_;
ReadCallback *on_payload_;
bool is_async_;
fec::FECType fec_type_;
-
- private:
- std::atomic<bool> is_running_;
};
} // end namespace protocol
diff --git a/libtransport/src/test/CMakeLists.txt b/libtransport/src/test/CMakeLists.txt
index 26fe7aee1..e7018ceed 100644
--- a/libtransport/src/test/CMakeLists.txt
+++ b/libtransport/src/test/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2021 Cisco and/or its affiliates.
+# Copyright (c) 2021-2022 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
@@ -11,42 +11,68 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-include(BuildMacros)
-
+##############################################################
+# Test sources
+##############################################################
list(APPEND TESTS_SRC
main.cc
+ test_aggregated_header.cc
test_auth.cc
- test_consumer_producer_rtc.cc
+ # test_consumer_producer_rtc.cc
test_core_manifest.cc
- test_event_thread.cc
+ # test_event_thread.cc
+ test_fec_base_rs.cc
test_fec_reedsolomon.cc
+ test_fixed_block_allocator.cc
test_indexer.cc
test_interest.cc
test_packet.cc
+ test_packet_allocator.cc
+ test_quality_score.cc
+ test_sessions.cc
+ test_thread_pool.cc
)
if (ENABLE_RELY)
list(APPEND TESTS_SRC
test_fec_rely_wrapper.cc
+ test_fec_base_rely.cc
+ )
+endif()
+
+if (UNIX AND NOT APPLE)
+ list(APPEND TESTS_SRC
+ test_memif_connector.cc
)
endif()
-build_executable(unit_tests
+
+##############################################################
+# Link libraries
+##############################################################
+set(MEMIF_MODULE_LIBRARIES
+ ${LIBRARIES}
+ ${LIBTRANSPORT_SHARED}
+ ${GTEST_LIBRARIES}
+)
+
+
+##############################################################
+# Build single unit test executable and add it to test list
+##############################################################
+build_executable(libtransport_tests
NO_INSTALL
SOURCES ${TESTS_SRC}
LINK_LIBRARIES
- ${LIBRARIES}
- ${LIBTRANSPORT_STATIC}
- ${GTEST_LIBRARIES}
+ ${MEMIF_MODULE_LIBRARIES}
INCLUDE_DIRS
- ${LIBTRANSPORT_INCLUDE_DIRS}
- ${LIBHICN_INCLUDE_DIRS}
- ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS}
+ $<TARGET_PROPERTY:${LIBTRANSPORT_SHARED},INCLUDE_DIRECTORIES>
${GTEST_INCLUDE_DIRS}
DEPENDS gtest ${LIBTRANSPORT_SHARED}
COMPONENT ${LIBTRANSPORT_COMPONENT}
- DEFINITIONS "${COMPILER_DEFINITIONS}"
+ DEFINITIONS ${COMPILER_DEFINITIONS}
+ COMPILE_OPTIONS ${COMPILER_OPTIONS}
LINK_FLAGS ${LINK_FLAGS}
)
-add_test_internal(unit_tests)
+add_test_internal(libtransport_tests)
diff --git a/libtransport/src/test/main.cc b/libtransport/src/test/main.cc
index a4d7ce1b3..591ed0d5b 100644
--- a/libtransport/src/test/main.cc
+++ b/libtransport/src/test/main.cc
@@ -16,7 +16,6 @@
#include <gtest/gtest.h>
int main(int argc, char **argv) {
- srand(time(0));
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
} \ No newline at end of file
diff --git a/libtransport/src/test/test_aggregated_header.cc b/libtransport/src/test/test_aggregated_header.cc
new file mode 100644
index 000000000..0d88af5ab
--- /dev/null
+++ b/libtransport/src/test/test_aggregated_header.cc
@@ -0,0 +1,622 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <gtest/gtest.h>
+#include <hicn/transport/errors/not_implemented_exception.h>
+#include <protocols/rtc/rtc_packet.h>
+#include <test/packet_samples.h>
+
+#include <climits>
+#include <random>
+#include <vector>
+
+namespace transport {
+
+namespace core {
+
+namespace {
+// The fixture for testing class Foo.
+class AggregatedPktHeaderTest : public ::testing::Test {
+ protected:
+ AggregatedPktHeaderTest() {
+ // You can do set-up work for each test here.
+ }
+
+ virtual ~AggregatedPktHeaderTest() {
+ // 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).
+ }
+};
+
+} // namespace
+
+TEST_F(AggregatedPktHeaderTest, Add2Packets8bit) {
+ uint8_t buf[1500];
+ std::vector<uint8_t> pkt1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
+ uint16_t pkt1_len = 14;
+
+ std::vector<uint8_t> pkt2 = {11, 12, 13, 14, 15, 16, 17};
+ uint16_t pkt2_len = 7;
+
+ for (uint16_t i = 0; i < 1500; i++) {
+ buf[i] = 0;
+ }
+
+ // skip protocol::rtc::DATA_HEADER_SIZE that will be the rtc header
+ protocol::rtc::AggrPktHeader hdr(buf + protocol::rtc::DATA_HEADER_SIZE,
+ pkt1_len, 2);
+ hdr.addPacketToHeader(0, pkt1_len);
+ hdr.addPacketToHeader(1, pkt2_len);
+ uint8_t* ptr = hdr.getPayloadAppendPtr();
+
+ // copy packet 1
+ for (uint16_t i = 0; i < pkt1_len; i++) {
+ *(ptr + i) = pkt1[i];
+ }
+
+ // copy packet 2
+ for (uint16_t i = 0; i < pkt2_len; i++) {
+ *(ptr + i + pkt1_len) = pkt2[i];
+ }
+
+ // print
+ // for (uint16_t i = 0; i < 40; i++){
+ // std::cout << (int) i << " " << (int) buf[i] << std::endl;
+ //}
+
+ uint8_t* pkt_ptr = nullptr;
+ uint16_t pkt_len = 0;
+
+ hdr.getPointerToPacket(0, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt1_len);
+ for (uint16_t i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt1[i]);
+ }
+
+ hdr.getPointerToPacket(1, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt2_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt2[i]);
+ }
+}
+
+TEST_F(AggregatedPktHeaderTest, Add2Packets8bit255) {
+ uint8_t buf[1500];
+
+ std::vector<uint8_t> pkt1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
+ uint16_t pkt1_len = 14;
+
+ std::vector<uint8_t> pkt2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 20
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 40
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 60
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 80
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 100
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 120
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 140
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 160
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 180
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 200
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 220
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 240
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14}; // 255
+ uint16_t pkt2_len = 255;
+
+ for (uint16_t i = 0; i < 1500; i++) {
+ buf[i] = 0;
+ }
+
+ // skip protocol::rtc::DATA_HEADER_SIZE that will be the rtc header
+ protocol::rtc::AggrPktHeader hdr(buf + protocol::rtc::DATA_HEADER_SIZE,
+ pkt2_len, 2);
+ hdr.addPacketToHeader(0, pkt1_len);
+ hdr.addPacketToHeader(1, pkt2_len);
+ uint8_t* ptr = hdr.getPayloadAppendPtr();
+
+ // copy packet 1
+ for (uint16_t i = 0; i < pkt1_len; i++) {
+ *(ptr + i) = pkt1[i];
+ }
+
+ // copy packet 2
+ for (uint16_t i = 0; i < pkt2_len; i++) {
+ *(ptr + i + pkt1_len) = pkt2[i];
+ }
+
+ uint8_t* pkt_ptr = nullptr;
+ uint16_t pkt_len = 0;
+
+ hdr.getPointerToPacket(0, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt1_len);
+ for (uint16_t i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt1[i]);
+ }
+
+ hdr.getPointerToPacket(1, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt2_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt2[i]);
+ }
+}
+
+TEST_F(AggregatedPktHeaderTest, Add2Packets8bit256) {
+ uint8_t buf[1500];
+
+ std::vector<uint8_t> pkt1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
+ uint16_t pkt1_len = 14;
+
+ std::vector<uint8_t> pkt2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 20
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 40
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 60
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 80
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 100
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 120
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 140
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 160
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 180
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 200
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 220
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 240
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15}; // 256
+ uint16_t pkt2_len = 256;
+
+ for (uint16_t i = 0; i < 1500; i++) {
+ buf[i] = 0;
+ }
+
+ // skip protocol::rtc::DATA_HEADER_SIZE that will be the rtc header
+ protocol::rtc::AggrPktHeader hdr(buf + protocol::rtc::DATA_HEADER_SIZE,
+ pkt2_len, 2);
+ hdr.addPacketToHeader(0, pkt1_len);
+ hdr.addPacketToHeader(1, pkt2_len);
+ uint8_t* ptr = hdr.getPayloadAppendPtr();
+
+ // copy packet 1
+ for (uint16_t i = 0; i < pkt1_len; i++) {
+ *(ptr + i) = pkt1[i];
+ }
+
+ // copy packet 2
+ for (uint16_t i = 0; i < pkt2_len; i++) {
+ *(ptr + i + pkt1_len) = pkt2[i];
+ }
+
+ uint8_t* pkt_ptr = nullptr;
+ uint16_t pkt_len = 0;
+
+ hdr.getPointerToPacket(0, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt1_len);
+ for (uint16_t i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt1[i]);
+ }
+
+ hdr.getPointerToPacket(1, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt2_len);
+ for (uint16_t i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt2[i]);
+ }
+}
+
+TEST_F(AggregatedPktHeaderTest, Add4Packets8bit) {
+ uint8_t buf[1500];
+
+ std::vector<uint8_t> pkt1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
+ uint16_t pkt1_len = 14;
+
+ std::vector<uint8_t> pkt2 = {11, 12, 13, 14, 15, 16, 17};
+ uint16_t pkt2_len = 7;
+
+ std::vector<uint8_t> pkt3 = {21, 22, 23, 24, 25, 26, 27, 28, 29, 30};
+ uint16_t pkt3_len = 10;
+
+ std::vector<uint8_t> pkt4 = {100, 110};
+ uint16_t pkt4_len = 2;
+
+ for (uint16_t i = 0; i < 1500; i++) {
+ buf[i] = 0;
+ }
+
+ // skip protocol::rtc::DATA_HEADER_SIZE that will be the rtc header
+ protocol::rtc::AggrPktHeader hdr(buf + protocol::rtc::DATA_HEADER_SIZE,
+ pkt1_len, 4);
+ hdr.addPacketToHeader(0, pkt1_len);
+ hdr.addPacketToHeader(1, pkt2_len);
+ hdr.addPacketToHeader(2, pkt3_len);
+ hdr.addPacketToHeader(3, pkt4_len);
+ uint8_t* ptr = hdr.getPayloadAppendPtr();
+
+ // copy packet 1
+ for (uint16_t i = 0; i < pkt1_len; i++) {
+ *(ptr + i) = pkt1[i];
+ }
+
+ // copy packet 2
+ for (uint16_t i = 0; i < pkt2_len; i++) {
+ *(ptr + i + pkt1_len) = pkt2[i];
+ }
+
+ // copy packet 3
+ for (uint16_t i = 0; i < pkt3_len; i++) {
+ *(ptr + i + pkt1_len + pkt2_len) = pkt3[i];
+ }
+
+ // copy packet 2
+ for (uint16_t i = 0; i < pkt4_len; i++) {
+ *(ptr + i + pkt1_len + pkt2_len + pkt3_len) = pkt4[i];
+ }
+
+ uint8_t* pkt_ptr = nullptr;
+ uint16_t pkt_len = 0;
+
+ hdr.getPointerToPacket(0, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt1_len);
+ for (uint16_t i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt1[i]);
+ }
+
+ hdr.getPointerToPacket(1, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt2_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt2[i]);
+ }
+
+ hdr.getPointerToPacket(2, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt3_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt3[i]);
+ }
+
+ hdr.getPointerToPacket(3, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt4_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt4[i]);
+ }
+}
+
+TEST_F(AggregatedPktHeaderTest, Add4Packets16bit) {
+ uint8_t buf[1500];
+
+ std::vector<uint8_t> pkt1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
+ uint16_t pkt1_len = 14;
+
+ std::vector<uint8_t> pkt2 = {11, 12, 13, 14, 15, 16, 17};
+ uint16_t pkt2_len = 7;
+
+ std::vector<uint8_t> pkt3 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 20
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 40
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 60
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 80
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 100
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 120
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 140
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 160
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 180
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 200
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 220
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 240
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; // 260
+ uint16_t pkt3_len = 260;
+
+ std::vector<uint8_t> pkt4 = {100, 110};
+ uint16_t pkt4_len = 2;
+
+ for (uint16_t i = 0; i < 1500; i++) {
+ buf[i] = 0;
+ }
+
+ // skip protocol::rtc::DATA_HEADER_SIZE that will be the rtc header
+ protocol::rtc::AggrPktHeader hdr(buf + protocol::rtc::DATA_HEADER_SIZE,
+ pkt3_len, 4);
+ hdr.addPacketToHeader(0, pkt1_len);
+ hdr.addPacketToHeader(1, pkt2_len);
+ hdr.addPacketToHeader(2, pkt3_len);
+ hdr.addPacketToHeader(3, pkt4_len);
+ uint8_t* ptr = hdr.getPayloadAppendPtr();
+
+ // copy packet 1
+ for (uint16_t i = 0; i < pkt1_len; i++) {
+ *(ptr + i) = pkt1[i];
+ }
+
+ // copy packet 2
+ for (uint16_t i = 0; i < pkt2_len; i++) {
+ *(ptr + i + pkt1_len) = pkt2[i];
+ }
+
+ // copy packet 3
+ for (uint16_t i = 0; i < pkt3_len; i++) {
+ *(ptr + i + pkt1_len + pkt2_len) = pkt3[i];
+ }
+
+ // copy packet 2
+ for (uint16_t i = 0; i < pkt4_len; i++) {
+ *(ptr + i + pkt1_len + pkt2_len + pkt3_len) = pkt4[i];
+ }
+
+ uint8_t* pkt_ptr = nullptr;
+ uint16_t pkt_len = 0;
+
+ hdr.getPointerToPacket(0, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt1_len);
+ for (uint16_t i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt1[i]);
+ }
+
+ hdr.getPointerToPacket(1, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt2_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt2[i]);
+ }
+
+ hdr.getPointerToPacket(2, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt3_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt3[i]);
+ }
+
+ hdr.getPointerToPacket(3, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt4_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt4[i]);
+ }
+}
+
+TEST_F(AggregatedPktHeaderTest, Defrag4Packets8bit) {
+ uint8_t buf[1500];
+
+ std::vector<uint8_t> pkt1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
+ uint16_t pkt1_len = 14;
+
+ std::vector<uint8_t> pkt2 = {11, 12, 13, 14, 15, 16, 17};
+ uint16_t pkt2_len = 7;
+
+ std::vector<uint8_t> pkt3 = {21, 22, 23, 24, 25, 26, 27, 28, 29, 30};
+ uint16_t pkt3_len = 10;
+
+ std::vector<uint8_t> pkt4 = {100, 110};
+ uint16_t pkt4_len = 2;
+
+ for (uint16_t i = 0; i < 1500; i++) {
+ buf[i] = 0;
+ }
+
+ // skip protocol::rtc::DATA_HEADER_SIZE that will be the rtc header
+ protocol::rtc::AggrPktHeader hdr(buf + protocol::rtc::DATA_HEADER_SIZE,
+ pkt1_len, 4);
+ hdr.addPacketToHeader(0, pkt1_len);
+ hdr.addPacketToHeader(1, pkt2_len);
+ hdr.addPacketToHeader(2, pkt3_len);
+ hdr.addPacketToHeader(3, pkt4_len);
+
+ uint16_t offset = protocol::rtc::DATA_HEADER_SIZE + 8; // 8 = aggr hdr
+
+ // copy packet 1
+ for (uint16_t i = 0; i < pkt1_len; i++) {
+ buf[i + offset] = pkt1[i];
+ }
+ offset += pkt1_len;
+
+ // copy packet 2
+ for (uint16_t i = 0; i < pkt2_len; i++) {
+ buf[i + offset] = pkt2[i];
+ }
+ offset += pkt2_len;
+
+ // copy packet 3
+ for (uint16_t i = 0; i < pkt3_len; i++) {
+ buf[i + offset] = pkt3[i];
+ }
+ offset += pkt3_len;
+
+ // copy packet 2
+ for (uint16_t i = 0; i < pkt4_len; i++) {
+ buf[i + offset] = pkt4[i];
+ }
+
+ protocol::rtc::AggrPktHeader hdr2(buf + protocol::rtc::DATA_HEADER_SIZE);
+
+ uint8_t* pkt_ptr = nullptr;
+ uint16_t pkt_len = 0;
+
+ uint8_t packet_number = hdr2.getNumberOfPackets();
+ EXPECT_EQ(packet_number, 4);
+
+ hdr2.getPointerToPacket(0, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt1_len);
+ for (uint16_t i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt1[i]);
+ }
+
+ hdr2.getPointerToPacket(1, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt2_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt2[i]);
+ }
+
+ hdr2.getPointerToPacket(2, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt3_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt3[i]);
+ }
+
+ hdr2.getPointerToPacket(3, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt4_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt4[i]);
+ }
+}
+
+TEST_F(AggregatedPktHeaderTest, Defrag4Packets16bit) {
+ uint8_t buf[1500];
+
+ std::vector<uint8_t> pkt1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
+ uint16_t pkt1_len = 14;
+
+ std::vector<uint8_t> pkt2 = {11, 12, 13, 14, 15, 16, 17};
+ uint16_t pkt2_len = 7;
+
+ std::vector<uint8_t> pkt3 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 20
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 40
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 60
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 80
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 100
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 120
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 140
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 160
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 180
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 200
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 220
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 240
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; // 260
+ uint16_t pkt3_len = 260;
+
+ std::vector<uint8_t> pkt4 = {100, 110};
+ uint16_t pkt4_len = 2;
+
+ for (uint16_t i = 0; i < 1500; i++) {
+ buf[i] = 0;
+ }
+
+ // skip protocol::rtc::DATA_HEADER_SIZE that will be the rtc header
+ protocol::rtc::AggrPktHeader hdr(buf + protocol::rtc::DATA_HEADER_SIZE,
+ pkt3_len, 4);
+ hdr.addPacketToHeader(0, pkt1_len);
+ hdr.addPacketToHeader(1, pkt2_len);
+ hdr.addPacketToHeader(2, pkt3_len);
+ hdr.addPacketToHeader(3, pkt4_len);
+
+ uint16_t offset = protocol::rtc::DATA_HEADER_SIZE + 12; // 12 = aggr hdr
+
+ // copy packet 1
+ for (uint16_t i = 0; i < pkt1_len; i++) {
+ buf[i + offset] = pkt1[i];
+ }
+ offset += pkt1_len;
+
+ // copy packet 2
+ for (uint16_t i = 0; i < pkt2_len; i++) {
+ buf[i + offset] = pkt2[i];
+ }
+ offset += pkt2_len;
+
+ // copy packet 3
+ for (uint16_t i = 0; i < pkt3_len; i++) {
+ buf[i + offset] = pkt3[i];
+ }
+ offset += pkt3_len;
+
+ // copy packet 2
+ for (uint16_t i = 0; i < pkt4_len; i++) {
+ buf[i + offset] = pkt4[i];
+ }
+
+ protocol::rtc::AggrPktHeader hdr2(buf + protocol::rtc::DATA_HEADER_SIZE);
+
+ uint8_t* pkt_ptr = nullptr;
+ uint16_t pkt_len = 0;
+
+ uint8_t packet_number = hdr2.getNumberOfPackets();
+ EXPECT_EQ(packet_number, 4);
+
+ hdr2.getPointerToPacket(0, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt1_len);
+ for (uint16_t i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt1[i]);
+ }
+
+ hdr2.getPointerToPacket(1, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt2_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt2[i]);
+ }
+
+ hdr2.getPointerToPacket(2, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt3_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt3[i]);
+ }
+
+ hdr2.getPointerToPacket(3, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt4_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt4[i]);
+ }
+}
+
+} // namespace core
+} // namespace transport
diff --git a/libtransport/src/test/test_auth.cc b/libtransport/src/test/test_auth.cc
index db1c3b52f..d7fd55433 100644
--- a/libtransport/src/test/test_auth.cc
+++ b/libtransport/src/test/test_auth.cc
@@ -15,10 +15,15 @@
#include <gtest/gtest.h>
#include <hicn/transport/auth/crypto_hash.h>
-#include <hicn/transport/auth/identity.h>
#include <hicn/transport/auth/signer.h>
#include <hicn/transport/auth/verifier.h>
#include <hicn/transport/core/content_object.h>
+#include <openssl/rand.h>
+
+using BN_ptr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
+using RSA_ptr = std::unique_ptr<RSA, decltype(&::RSA_free)>;
+using EC_KEY_ptr = std::unique_ptr<EC_KEY, decltype(&::EC_KEY_free)>;
+using DSA_ptr = std::unique_ptr<DSA, decltype(&::DSA_free)>;
namespace transport {
namespace auth {
@@ -50,11 +55,23 @@ TEST_F(AuthTest, VoidVerifier) {
}
TEST_F(AuthTest, AsymmetricRSA) {
- // Create the RSA signer from an Identity object
- Identity identity("test_rsa.p12", PASSPHRASE, CryptoSuite::RSA_SHA256, 1024u,
- 30, "RSAVerifier");
-
- std::shared_ptr<Signer> signer = identity.getSigner();
+ // Create the RSA keys
+ std::shared_ptr<EVP_PKEY> privateKey(EVP_PKEY_new(), EVP_PKEY_free);
+ std::shared_ptr<EVP_PKEY> pubKey(EVP_PKEY_new(), EVP_PKEY_free);
+ RSA_ptr rsa(RSA_new(), ::RSA_free);
+ BN_ptr pub_exp(BN_new(), ::BN_free);
+
+ BN_set_word(pub_exp.get(), RSA_F4);
+ if (1 != RSA_generate_key_ex(rsa.get(), 2048u, pub_exp.get(), NULL))
+ throw errors::RuntimeException("can't generate the key");
+ RSA_ptr rsa_pub(RSAPublicKey_dup(rsa.get()), ::RSA_free);
+ RSA_ptr rsa_priv(RSAPrivateKey_dup(rsa.get()), ::RSA_free);
+ if (1 != EVP_PKEY_set1_RSA(pubKey.get(), rsa_pub.get()))
+ throw errors::RuntimeException("can't generate the key");
+ if (1 != EVP_PKEY_set1_RSA(privateKey.get(), rsa_priv.get()))
+ throw errors::RuntimeException("can't generate the key");
+ std::shared_ptr<AsymmetricSigner> signer = std::make_shared<AsymmetricSigner>(
+ CryptoSuite::RSA_SHA256, privateKey, pubKey);
// Create a content object
core::ContentObject packet(HF_INET6_TCP_AH, signer->getSignatureSize());
@@ -68,61 +85,112 @@ TEST_F(AuthTest, AsymmetricRSA) {
// Create the RSA verifier
std::shared_ptr<Verifier> verifier =
- std::make_shared<AsymmetricVerifier>(identity.getCertificate());
+ std::make_shared<AsymmetricVerifier>(pubKey);
EXPECT_EQ(packet.getFormat(), HF_INET6_TCP_AH);
EXPECT_EQ(signer->getHashType(), CryptoHashType::SHA256);
EXPECT_EQ(signer->getSuite(), CryptoSuite::RSA_SHA256);
- EXPECT_EQ(signer->getSignatureSize(), 128u);
+ EXPECT_EQ(signer->getSignatureSize(), 256u);
EXPECT_EQ(verifier->verifyPackets(&packet), VerificationPolicy::ACCEPT);
}
TEST_F(AuthTest, AsymmetricBufferRSA) {
- // Create the RSA signer from an Identity object
- Identity identity("test_rsa.p12", PASSPHRASE, CryptoSuite::RSA_SHA256, 1024u,
- 30, "RSAVerifier");
+ // Create the RSA keys
+ std::shared_ptr<EVP_PKEY> privateKey(EVP_PKEY_new(), EVP_PKEY_free);
+ std::shared_ptr<EVP_PKEY> pubKey(EVP_PKEY_new(), EVP_PKEY_free);
+ RSA_ptr rsa(RSA_new(), ::RSA_free);
+ BN_ptr pub_exp(BN_new(), ::BN_free);
+
+ BN_set_word(pub_exp.get(), RSA_F4);
+ if (1 != RSA_generate_key_ex(rsa.get(), 2048u, pub_exp.get(), NULL))
+ throw errors::RuntimeException("can't generate the key");
+ RSA_ptr rsa_pub(RSAPublicKey_dup(rsa.get()), ::RSA_free);
+ RSA_ptr rsa_priv(RSAPrivateKey_dup(rsa.get()), ::RSA_free);
+ if (1 != EVP_PKEY_set1_RSA(pubKey.get(), rsa_pub.get()))
+ throw errors::RuntimeException("can't generate the key");
+ if (1 != EVP_PKEY_set1_RSA(privateKey.get(), rsa_priv.get()))
+ throw errors::RuntimeException("can't generate the key");
+ std::shared_ptr<AsymmetricSigner> signer = std::make_shared<AsymmetricSigner>(
+ CryptoSuite::RSA_SHA256, privateKey, pubKey);
- std::shared_ptr<AsymmetricSigner> signer = identity.getSigner();
std::string payload = "bonjour";
std::vector<uint8_t> buffer(payload.begin(), payload.end());
signer->signBuffer(buffer);
std::vector<uint8_t> sig = signer->getSignature();
- std::shared_ptr<X509> cert = identity.getCertificate();
- AsymmetricVerifier verif(cert);
- bool res = verif.verifyBuffer(
+ std::shared_ptr<AsymmetricVerifier> verif =
+ std::make_shared<AsymmetricVerifier>(pubKey);
+ bool res = verif->verifyBuffer(
buffer, std::vector<uint8_t>(sig.data(), sig.data() + sig.size()),
CryptoHashType::SHA256);
EXPECT_EQ(res, true);
}
TEST_F(AuthTest, AsymmetricBufferDSA) {
- // Create the DSA signer from an Identity object
- Identity identity("test_dsa.p12", PASSPHRASE, CryptoSuite::DSA_SHA256, 1024u,
- 30, "DSAVerifier");
+ // Create the DSA keys
+
+ std::shared_ptr<EVP_PKEY> privateKey(EVP_PKEY_new(), EVP_PKEY_free);
+
+ DSA_ptr dsa(DSA_new(), ::DSA_free);
+ unsigned char buf[32];
+ if (RAND_bytes(buf, sizeof(buf)) != 1) {
+ throw errors::RuntimeException("can't generate the key");
+ }
+ if (DSA_generate_parameters_ex(dsa.get(), 1024u, buf, sizeof(buf), NULL, NULL,
+ NULL) != 1)
+ throw errors::RuntimeException("can't generate the key");
+ if (DSA_generate_key(dsa.get()) != 1)
+ throw errors::RuntimeException("can't generate the key");
+ if (EVP_PKEY_set1_DSA(privateKey.get(), dsa.get()) != 1)
+ throw errors::RuntimeException("can't generate the key");
+ if (1 != EVP_PKEY_set1_DSA(privateKey.get(), dsa.get()))
+ throw errors::RuntimeException("can't generate the key");
+
+ std::shared_ptr<X509> cert(X509_new(), ::X509_free);
+ X509_set_pubkey(cert.get(), privateKey.get());
+ std::shared_ptr<EVP_PKEY> pubKey(X509_get_pubkey(cert.get()), EVP_PKEY_free);
+ std::shared_ptr<AsymmetricSigner> signer = std::make_shared<AsymmetricSigner>(
+ CryptoSuite::DSA_SHA256, privateKey, pubKey);
- std::shared_ptr<AsymmetricSigner> signer = identity.getSigner();
std::string payload = "bonjour";
std::vector<uint8_t> buffer(payload.begin(), payload.end());
signer->signBuffer(buffer);
std::vector<uint8_t> sig = signer->getSignature();
- std::shared_ptr<X509> cert = identity.getCertificate();
- AsymmetricVerifier verif(cert);
- bool res = verif.verifyBuffer(
+ std::shared_ptr<AsymmetricVerifier> verif =
+ std::make_shared<AsymmetricVerifier>(pubKey);
+ bool res = verif->verifyBuffer(
buffer, std::vector<uint8_t>(sig.data(), sig.data() + sig.size()),
CryptoHashType::SHA256);
EXPECT_EQ(res, true);
}
TEST_F(AuthTest, AsymmetricVerifierDSA) {
- // Create the DSA signer from an Identity object
- Identity identity("test_dsa.p12", PASSPHRASE, CryptoSuite::DSA_SHA256, 1024u,
- 30, "DSAVerifier");
+ // Create the DSA keys
+ std::shared_ptr<EVP_PKEY> privateKey(EVP_PKEY_new(), EVP_PKEY_free);
- std::shared_ptr<Signer> signer = identity.getSigner();
+ DSA_ptr dsa(DSA_new(), ::DSA_free);
+ unsigned char buf[32];
+ if (RAND_bytes(buf, sizeof(buf)) != 1) {
+ throw errors::RuntimeException("can't generate the key");
+ }
+ if (DSA_generate_parameters_ex(dsa.get(), 1024u, buf, sizeof(buf), NULL, NULL,
+ NULL) != 1)
+ throw errors::RuntimeException("can't generate the key");
+ if (DSA_generate_key(dsa.get()) != 1)
+ throw errors::RuntimeException("can't generate the key");
+ if (EVP_PKEY_set1_DSA(privateKey.get(), dsa.get()) != 1)
+ throw errors::RuntimeException("can't generate the key");
+ if (1 != EVP_PKEY_set1_DSA(privateKey.get(), dsa.get()))
+ throw errors::RuntimeException("can't generate the key");
+
+ std::shared_ptr<X509> cert(X509_new(), ::X509_free);
+ X509_set_pubkey(cert.get(), privateKey.get());
+ std::shared_ptr<EVP_PKEY> pubKey(X509_get_pubkey(cert.get()), EVP_PKEY_free);
+ std::shared_ptr<AsymmetricSigner> signer = std::make_shared<AsymmetricSigner>(
+ CryptoSuite::DSA_SHA256, privateKey, pubKey);
// Create a content object
core::ContentObject packet(HF_INET6_TCP_AH, signer->getSignatureSize());
@@ -134,7 +202,7 @@ TEST_F(AuthTest, AsymmetricVerifierDSA) {
// EXPECT_EQ(signer->getSignatureSize(), 256u);
signer->signPacket(&packet);
std::shared_ptr<Verifier> verifier =
- std::make_shared<AsymmetricVerifier>(identity.getCertificate());
+ std::make_shared<AsymmetricVerifier>(cert);
EXPECT_EQ(packet.getFormat(), HF_INET6_TCP_AH);
EXPECT_EQ(signer->getHashType(), CryptoHashType::SHA256);
@@ -143,33 +211,59 @@ TEST_F(AuthTest, AsymmetricVerifierDSA) {
}
TEST_F(AuthTest, AsymmetricBufferECDSA) {
- // Create the ECDSA signer from an Identity object
- Identity identity("test_ecdsa.p12", PASSPHRASE, CryptoSuite::ECDSA_SHA256,
- 256u, 30, "ECDSAVerifier");
+ // Create the ECDSA keys
+ std::shared_ptr<EVP_PKEY> privateKey(EVP_PKEY_new(), EVP_PKEY_free);
+ std::shared_ptr<EVP_PKEY> pubKey(EVP_PKEY_new(), EVP_PKEY_free);
+ EC_KEY_ptr ec_priv(EC_KEY_new_by_curve_name(NID_secp256k1), ::EC_KEY_free);
+ EC_KEY_ptr ec_pub(EC_KEY_new(), ::EC_KEY_free);
+ EC_KEY_set_asn1_flag(ec_priv.get(), OPENSSL_EC_NAMED_CURVE);
+ if (EC_KEY_generate_key(ec_priv.get()) == 0)
+ throw errors::RuntimeException("can't generate the ecdsa key");
+ if (1 != EVP_PKEY_set1_EC_KEY(privateKey.get(), ec_priv.get()))
+ throw errors::RuntimeException("can't generate the key");
+ EC_KEY_set_group(ec_pub.get(), EC_KEY_get0_group(ec_priv.get()));
+ EC_KEY_set_public_key(ec_pub.get(), EC_KEY_get0_public_key(ec_priv.get()));
+ if (1 != EVP_PKEY_set1_EC_KEY(pubKey.get(), ec_pub.get()))
+ throw errors::RuntimeException("can't generate the key");
+
+ std::shared_ptr<AsymmetricSigner> signer = std::make_shared<AsymmetricSigner>(
+ CryptoSuite::ECDSA_SHA256, privateKey, pubKey);
- std::shared_ptr<AsymmetricSigner> signer = identity.getSigner();
std::string payload = "bonjour";
std::vector<uint8_t> buffer(payload.begin(), payload.end());
signer->signBuffer(buffer);
std::vector<uint8_t> sig = signer->getSignature();
- std::shared_ptr<X509> cert = identity.getCertificate();
- AsymmetricVerifier verif(cert);
- bool res = verif.verifyBuffer(
+ std::shared_ptr<AsymmetricVerifier> verif =
+ std::make_shared<AsymmetricVerifier>(pubKey);
+ bool res = verif->verifyBuffer(
buffer, std::vector<uint8_t>(sig.data(), sig.data() + sig.size()),
CryptoHashType::SHA256);
EXPECT_EQ(res, true);
-}
+} // namespace auth
TEST_F(AuthTest, AsymmetricVerifierECDSA) {
- Identity identity("test_ecdsa.p12", PASSPHRASE, CryptoSuite::ECDSA_SHA256,
- 256u, 30, "ECDSAVerifier");
-
- std::shared_ptr<Signer> signer = identity.getSigner();
- std::shared_ptr<Verifier> verifier =
- std::make_shared<AsymmetricVerifier>(identity.getCertificate());
- // Create a content object
+ // Create the ECDSA keys
+ std::shared_ptr<EVP_PKEY> privateKey(EVP_PKEY_new(), EVP_PKEY_free);
+ std::shared_ptr<EVP_PKEY> pubKey(EVP_PKEY_new(), EVP_PKEY_free);
+ EC_KEY_ptr ec_priv(EC_KEY_new_by_curve_name(NID_secp256k1), ::EC_KEY_free);
+ EC_KEY_ptr ec_pub(EC_KEY_new(), ::EC_KEY_free);
+ EC_KEY_set_asn1_flag(ec_priv.get(), OPENSSL_EC_NAMED_CURVE);
+ if (EC_KEY_generate_key(ec_priv.get()) == 0)
+ throw errors::RuntimeException("can't generate the ecdsa key");
+ if (1 != EVP_PKEY_set1_EC_KEY(privateKey.get(), ec_priv.get()))
+ throw errors::RuntimeException("can't generate the key");
+ EC_KEY_set_group(ec_pub.get(), EC_KEY_get0_group(ec_priv.get()));
+ EC_KEY_set_public_key(ec_pub.get(), EC_KEY_get0_public_key(ec_priv.get()));
+ if (1 != EVP_PKEY_set1_EC_KEY(pubKey.get(), ec_pub.get()))
+ throw errors::RuntimeException("can't generate the key");
+
+ std::shared_ptr<AsymmetricSigner> signer = std::make_shared<AsymmetricSigner>(
+ CryptoSuite::ECDSA_SHA256, privateKey, pubKey);
+
+ std::shared_ptr<AsymmetricVerifier> verifier =
+ std::make_shared<AsymmetricVerifier>(pubKey);
for (int i = 0; i < 100; i++) {
core::ContentObject packet(HF_INET6_TCP_AH, signer->getSignatureSize());
diff --git a/libtransport/src/test/test_consumer_producer_rtc.cc b/libtransport/src/test/test_consumer_producer_rtc.cc
index 8541a9e1a..b11a6a388 100644
--- a/libtransport/src/test/test_consumer_producer_rtc.cc
+++ b/libtransport/src/test/test_consumer_producer_rtc.cc
@@ -41,7 +41,7 @@ class ConsumerProducerTest : public ::testing::Test,
rtc_timer_(io_service_),
stop_timer_(io_service_),
consumer_(TransportProtocolAlgorithms::RTC, io_service_),
- producer_(ProductionProtocolAlgorithms::RTC_PROD, io_service_),
+ producer_(ProductionProtocolAlgorithms::RTC_PROD, thread_),
producer_prefix_(prefix),
consumer_name_(name),
packets_sent_(0),
@@ -120,14 +120,13 @@ class ConsumerProducerTest : public ::testing::Test,
size_t maxBufferSize() const override { return receive_buffer_size; }
- void readError(const std::error_code ec) noexcept override {
- FAIL() << "Error while reading from RTC socket";
+ void readError(const std::error_code &ec) noexcept override {
io_service_.stop();
+ FAIL() << "Error while reading from RTC socket";
}
void readSuccess(std::size_t total_size) noexcept override {
packets_received_++;
- std::cout << "Received something" << std::endl;
}
asio::io_service io_service_;
diff --git a/libtransport/src/test/test_core_manifest.cc b/libtransport/src/test/test_core_manifest.cc
index 93f4e87cb..23fd5e342 100644
--- a/libtransport/src/test/test_core_manifest.cc
+++ b/libtransport/src/test/test_core_manifest.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -17,6 +17,8 @@
#include <core/manifest_inline.h>
#include <gtest/gtest.h>
#include <hicn/transport/auth/crypto_hash.h>
+#include <hicn/transport/auth/signer.h>
+#include <hicn/transport/auth/verifier.h>
#include <test/packet_samples.h>
#include <climits>
@@ -33,7 +35,7 @@ class ManifestTest : public ::testing::Test {
protected:
using ContentObjectManifest = ManifestInline<ContentObject, Fixed>;
- ManifestTest() : name_("b001::123|321"), manifest1_(name_) {
+ ManifestTest() : name_("b001::123|321"), manifest1_(HF_INET6_TCP_AH, name_) {
// You can do set-up work for each test here.
}
@@ -97,8 +99,8 @@ TEST_F(ManifestTest, MoveConstructor) {
TEST_F(ManifestTest, SetLastManifest) {
manifest1_.clear();
- manifest1_.setFinalManifest(true);
- bool fcn = manifest1_.isFinalManifest();
+ manifest1_.setIsLast(true);
+ bool fcn = manifest1_.getIsLast();
ASSERT_TRUE(fcn == true);
}
@@ -109,13 +111,13 @@ TEST_F(ManifestTest, SetManifestType) {
ManifestType type1 = ManifestType::INLINE_MANIFEST;
ManifestType type2 = ManifestType::FLIC_MANIFEST;
- manifest1_.setManifestType(type1);
- ManifestType type_returned1 = manifest1_.getManifestType();
+ manifest1_.setType(type1);
+ ManifestType type_returned1 = manifest1_.getType();
manifest1_.clear();
- manifest1_.setManifestType(type2);
- ManifestType type_returned2 = manifest1_.getManifestType();
+ manifest1_.setType(type2);
+ ManifestType type_returned2 = manifest1_.getType();
ASSERT_EQ(type1, type_returned1);
ASSERT_EQ(type2, type_returned2);
@@ -146,17 +148,80 @@ TEST_F(ManifestTest, SetHashAlgorithm) {
ASSERT_EQ(hash3, type_returned3);
}
-TEST_F(ManifestTest, SetNextSegmentCalculationStrategy) {
+TEST_F(ManifestTest, setParamsBytestream) {
manifest1_.clear();
- NextSegmentCalculationStrategy strategy1 =
- NextSegmentCalculationStrategy::INCREMENTAL;
+ ParamsBytestream params{
+ .final_segment = 1,
+ };
+
+ manifest1_.setParamsBytestream(params);
+ manifest1_.encode();
+
+ ContentObjectManifest manifest(manifest1_);
+ manifest.decode();
+
+ ASSERT_EQ(interface::ProductionProtocolAlgorithms::BYTE_STREAM,
+ manifest.getTransportType());
+ ASSERT_EQ(params, manifest.getParamsBytestream());
+}
+
+TEST_F(ManifestTest, SetParamsRTC) {
+ manifest1_.clear();
+
+ ParamsRTC params{
+ .timestamp = 1,
+ .prod_rate = 2,
+ .prod_seg = 3,
+ .support_fec = 1,
+ };
+
+ manifest1_.setParamsRTC(params);
+ manifest1_.encode();
- manifest1_.setNextSegmentCalculationStrategy(strategy1);
- NextSegmentCalculationStrategy type_returned1 =
- manifest1_.getNextSegmentCalculationStrategy();
+ ContentObjectManifest manifest(manifest1_);
+ manifest.decode();
+
+ ASSERT_EQ(interface::ProductionProtocolAlgorithms::RTC_PROD,
+ manifest.getTransportType());
+ ASSERT_EQ(params, manifest.getParamsRTC());
+}
- ASSERT_EQ(strategy1, type_returned1);
+TEST_F(ManifestTest, SignManifest) {
+ Name name("b001::", 0);
+ auto signer = std::make_shared<auth::SymmetricSigner>(
+ auth::CryptoSuite::HMAC_SHA256, "hunter2");
+ auto verifier = std::make_shared<auth::SymmetricVerifier>("hunter2");
+ std::shared_ptr<ContentObjectManifest> manifest;
+
+ // Instantiate Manifest
+ manifest.reset(ContentObjectManifest::createManifest(
+ HF_INET6_TCP_AH, name, ManifestVersion::VERSION_1,
+ ManifestType::INLINE_MANIFEST, false, name, signer->getHashType(),
+ signer->getSignatureFieldSize()));
+
+ // Add Manifest entry
+ auth::CryptoHash hash(signer->getHashType());
+ hash.computeDigest(std::vector<uint8_t>{0x01, 0x02, 0x03, 0x04});
+ manifest->addSuffixHash(1, hash);
+
+ // Encode manifest
+ manifest->encode();
+
+ // Sign manifest
+ signer->signPacket(manifest.get());
+
+ // Check size
+ ASSERT_EQ(manifest->payloadSize(), manifest->estimateManifestSize());
+ ASSERT_EQ(manifest->length(),
+ manifest->headerSize() + manifest->payloadSize());
+ ASSERT_EQ(ContentObjectManifest::manifestHeaderSize(
+ interface::ProductionProtocolAlgorithms::UNKNOWN),
+ manifest->manifestHeaderSize());
+
+ // Verify manifest
+ auth::VerificationPolicy policy = verifier->verifyPackets(manifest.get());
+ ASSERT_EQ(auth::VerificationPolicy::ACCEPT, policy);
}
TEST_F(ManifestTest, SetBaseName) {
@@ -198,23 +263,8 @@ TEST_F(ManifestTest, SetSuffixList) {
}
manifest1_.setBaseName(base_name);
-
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 = auth::CryptoHash::compareBinaryDigest(hash,
- // entries[i].second.getDigest<uint8_t>().data(),
- // entries[i].second.getType());
- // ASSERT_TRUE(cond);
- // i++;
- // }
-
ASSERT_EQ(base_name, ret_name);
delete[] entries;
diff --git a/libtransport/src/test/test_event_thread.cc b/libtransport/src/test/test_event_thread.cc
index 549ff9c1a..324250717 100644
--- a/libtransport/src/test/test_event_thread.cc
+++ b/libtransport/src/test/test_event_thread.cc
@@ -14,6 +14,7 @@
*/
#include <gtest/gtest.h>
+#include <hicn/transport/utils/chrono_typedefs.h>
#include <hicn/transport/utils/event_thread.h>
#include <cmath>
@@ -48,7 +49,7 @@ class EventThreadTest : public ::testing::Test {
utils::EventThread event_thread_;
};
-double average(const unsigned long samples[], int size) {
+inline double average(const unsigned long samples[], int size) {
double sum = 0;
for (int i = 0; i < size; i++) {
@@ -58,7 +59,7 @@ double average(const unsigned long samples[], int size) {
return sum / size;
}
-double stdDeviation(const unsigned long samples[], int size) {
+inline double stdDeviation(const unsigned long samples[], int size) {
double avg = average(samples, size);
double var = 0;
@@ -72,26 +73,23 @@ double stdDeviation(const unsigned long samples[], int size) {
} // namespace
TEST_F(EventThreadTest, DISABLED_SchedulingDelay) {
- using namespace std::chrono;
- const size_t size = 1000000;
- std::vector<unsigned long> samples(size);
-
- for (unsigned int i = 0; i < size; i++) {
- auto t0 = steady_clock::now();
- event_thread_.add([t0, &samples, i]() {
- auto t1 = steady_clock::now();
- samples[i] = duration_cast<nanoseconds>(t1 - t0).count();
- });
- }
+ // using namespace std::chrono;
+ // const size_t size = 1000000;
+ // std::vector<unsigned long> samples(size);
+
+ // for (unsigned int i = 0; i < size; i++) {
+ // event_thread_.add([t0, &samples, i]() {
+ // });
+ // }
- event_thread_.stop();
+ // event_thread_.stop();
- auto avg = average(&samples[0], size);
- auto sd = stdDeviation(&samples[0], size);
- (void)sd;
+ // auto avg = average(&samples[0], size);
+ // auto sd = stdDeviation(&samples[0], size);
+ // (void)sd;
- // Expect average to be less that 1 ms
- EXPECT_LT(avg, 1000000);
+ // // Expect average to be less that 1 ms
+ // EXPECT_LT(avg, 1000000);
}
} // namespace utils
diff --git a/libtransport/src/test/test_fec_base_rely.cc b/libtransport/src/test/test_fec_base_rely.cc
new file mode 100644
index 000000000..41e1eae49
--- /dev/null
+++ b/libtransport/src/test/test_fec_base_rely.cc
@@ -0,0 +1,453 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <gtest/gtest.h>
+#include <hicn/transport/core/content_object.h>
+#include <hicn/transport/core/global_object_pool.h>
+#include <protocols/fec_base.h>
+#include <protocols/fec_utils.h>
+#include <protocols/rtc/rtc_consts.h>
+
+#include <algorithm>
+#include <iostream>
+#include <queue>
+#include <random>
+
+namespace transport {
+namespace protocol {
+
+class PacketFactory {
+ public:
+ PacketFactory(){};
+
+ ~PacketFactory(){};
+
+ std::shared_ptr<transport::core::ContentObject> createData(
+ core::Name &name, uint32_t suffix, uint32_t payload_size,
+ uint32_t payload_filler) {
+ auto &packet_manager = core::PacketManager<>::getInstance();
+
+ // create payload
+ auto buff = packet_manager.getMemBuf();
+ buff->append(payload_size);
+ std::fill(buff->writableData(), buff->writableTail(), payload_filler);
+
+ // create data packet
+ auto data = packet_manager.getPacket<transport::core::ContentObject>(
+ HF_INET6_TCP, 0);
+ struct rtc::data_packet_t header;
+ header.setTimestamp(1000);
+ header.setProductionRate(1);
+ data->appendPayload((const uint8_t *)&header, rtc::DATA_HEADER_SIZE);
+ data->appendPayload(buff->data(), buff->length());
+ data->setName(name.setSuffix(suffix));
+ data->setLifetime(500);
+ data->setPathLabel(12);
+
+ return data;
+ }
+
+ std::shared_ptr<transport::core::ContentObject> createData(
+ core::Name &name, uint32_t suffix, fec::buffer payload) {
+ auto &packet_manager = core::PacketManager<>::getInstance();
+
+ auto data = packet_manager.getPacket<transport::core::ContentObject>(
+ HF_INET6_TCP, 0);
+ struct rtc::data_packet_t header;
+ header.setTimestamp(1000);
+ header.setProductionRate(1);
+ data->appendPayload((const uint8_t *)&header, rtc::DATA_HEADER_SIZE);
+ data->appendPayload(payload->data(), payload->length());
+ data->setName(name.setSuffix(suffix));
+ data->setLifetime(500);
+ data->setPathLabel(12);
+
+ return data;
+ }
+};
+
+class Encoder {
+ public:
+ Encoder(std::string fec_str) {
+ fec_type_ = fec::FECUtils::fecTypeFromString(fec_str.c_str());
+ if (fec_type_ == fec::FECType::UNKNOWN)
+ std::cout << "x" << fec_str << "x" << std::endl;
+ encoder_ = fec::FECUtils::getEncoder(fec_type_, 1);
+ encoder_->setFECCallback(
+ std::bind(&Encoder::onFecPackets, this, std::placeholders::_1));
+ encoder_->setBufferCallback(
+ std::bind(&Encoder::getBuffer, this, std::placeholders::_1));
+ };
+
+ ~Encoder(){};
+
+ void onFecPackets(fec::BufferArray &packets) {
+ for (auto &packet : packets) {
+ fec_packets_.push(packet.getBuffer());
+ }
+ }
+
+ fec::buffer getBuffer(std::size_t size) {
+ auto ret = core::PacketManager<>::getInstance()
+ .getPacket<transport::core::ContentObject>(HF_INET6_TCP, 0);
+ ret->updateLength(rtc::DATA_HEADER_SIZE + size);
+ ret->append(rtc::DATA_HEADER_SIZE + size);
+ ret->trimStart(ret->headerSize() + rtc::DATA_HEADER_SIZE);
+
+ return ret;
+ }
+
+ void onPacketProduced(core::ContentObject &content_object, uint32_t offset,
+ uint32_t metadata) {
+ encoder_->onPacketProduced(content_object, offset, metadata);
+ }
+
+ public:
+ std::queue<fec::buffer> fec_packets_;
+
+ private:
+ std::unique_ptr<fec::ProducerFEC> encoder_;
+ fec::FECType fec_type_;
+};
+
+class Decoder {
+ public:
+ Decoder(std::string fec_str) {
+ fec_type_ = fec::FECUtils::fecTypeFromString(fec_str.c_str());
+ decoder_ = fec::FECUtils::getDecoder(fec_type_, 1);
+ decoder_->setFECCallback(
+ std::bind(&Decoder::onFecPackets, this, std::placeholders::_1));
+ decoder_->setBufferCallback(fec::FECBase::BufferRequested(0));
+ };
+
+ ~Decoder(){};
+
+ void onFecPackets(fec::BufferArray &packets) {
+ for (auto &packet : packets) {
+ hicn_packet_dump(packet.getBuffer()->data(),
+ packet.getBuffer()->length());
+ recovered_packets_.push(packet.getBuffer());
+ }
+ }
+
+ void onPacketReceived(core::ContentObject &content_object, uint32_t offset) {
+ decoder_->onDataPacket(content_object, offset);
+ }
+
+ public:
+ std::queue<fec::buffer> recovered_packets_;
+
+ private:
+ std::unique_ptr<fec::ConsumerFEC> decoder_;
+ fec::FECType fec_type_;
+};
+
+TEST(FECtestRely, RelyTestInOrder1) {
+ // use Rely k = 2 N = 6
+ std::string fec_str = "Rely_K2_N6";
+ Encoder encoder(fec_str);
+ Decoder decoder(fec_str);
+
+ PacketFactory pf;
+
+ core::Name name("b001::");
+
+ auto data1 = pf.createData(name, 1, 50, 1);
+ // we cannot use the original data 1 to check it we recovered the packet
+ // correclty because Rely modifies the packet so here we create a copy
+ auto data1_copy = pf.createData(name, 1, 50, 1);
+
+ auto data2 = pf.createData(name, 2, 45, 2);
+
+ // encoding
+ uint32_t metadata = static_cast<uint32_t>(data1->getPayloadType());
+ encoder.onPacketProduced(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+
+ // create fec packet
+ auto data3 = pf.createData(name, 3, encoder.fec_packets_.front());
+
+ // decode in order, data 1 is lost
+ decoder.onPacketReceived(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data3, data3->headerSize() + rtc::DATA_HEADER_SIZE);
+
+ // check recovered packet
+ EXPECT_EQ(decoder.recovered_packets_.size(), (size_t)2);
+ auto recovered = pf.createData(name, 1, decoder.recovered_packets_.front());
+
+ bool eq_len = (data1_copy->length() == recovered->length());
+ EXPECT_TRUE(eq_len);
+ int ret = -1;
+ if (eq_len)
+ ret = memcmp(data1_copy->data(), recovered->data(), recovered->length());
+ EXPECT_EQ(ret, (int)0);
+}
+
+TEST(FECtestRely, RelyTestInOrder2) {
+ // use Rely k = 2 N = 6
+ std::string fec_str = "Rely_K2_N6";
+ Encoder encoder(fec_str);
+ Decoder decoder(fec_str);
+
+ PacketFactory pf;
+
+ core::Name name("b001::");
+
+ auto data1 = pf.createData(name, 1, 50, 1);
+
+ auto data2 = pf.createData(name, 2, 45, 2);
+ auto data2_copy = pf.createData(name, 2, 45, 2);
+
+ // encoding
+ uint32_t metadata = static_cast<uint32_t>(data1->getPayloadType());
+ encoder.onPacketProduced(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+
+ // create fec packet
+ auto data3 = pf.createData(name, 3, encoder.fec_packets_.front());
+
+ // decode in order, data 2 is lost
+ decoder.onPacketReceived(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data3, data3->headerSize() + rtc::DATA_HEADER_SIZE);
+
+ // check recovered packet
+ EXPECT_EQ(decoder.recovered_packets_.size(), (size_t)2);
+ decoder.recovered_packets_.pop(); // pop data 1
+ auto recovered = pf.createData(name, 2, decoder.recovered_packets_.front());
+
+ bool eq_len = (data2_copy->length() == recovered->length());
+ EXPECT_TRUE(eq_len);
+ int ret = -1;
+ if (eq_len)
+ ret = memcmp(data2_copy->data(), recovered->data(), recovered->length());
+ EXPECT_EQ(ret, (int)0);
+}
+
+#if 0
+TEST(FECtestRely, RelyTestOutOfOrder1) {
+ //use Rely k = 2 N = 6
+ std::string fec_str = "Rely_K2_N6";
+ Encoder encoder(fec_str);
+ Decoder decoder(fec_str);
+
+ PacketFactory pf;
+
+ core::Name name("b001::");
+
+ auto data1 = pf.createData(name, 1, 50, 1);
+ auto data1_copy = pf.createData(name, 1, 50, 1);
+
+ auto data2 = pf.createData(name, 2, 45, 2);
+
+ std::cout << "dump packet 2" << std::endl;
+ hicn_packet_dump(data2->data(), data2->length());
+
+ // encoding
+ uint32_t metadata = static_cast<uint32_t>(data1->getPayloadType());
+ encoder.onPacketProduced(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+
+ // create fec packet
+ auto data3 = pf.createData(name, 3, encoder.fec_packets_.front());
+
+ std::cout << "dump packet 2" << std::endl;
+ hicn_packet_dump(data2->data(), data2->length());
+
+ std::cout << "dump packet 3" << std::endl;
+ hicn_packet_dump(data3->data(), data3->length());
+
+ // decoding ooo packets. data 1 is lost.
+ decoder.onPacketReceived(*data3, data3->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE);
+
+ // get recovered packet
+ EXPECT_EQ(decoder.recovered_packets_.size(), (size_t) 2);
+ auto recovered = pf.createData(name, 1, decoder.recovered_packets_.front());
+ bool eq_len = (data1_copy->length() == recovered->length());
+ EXPECT_TRUE(eq_len);
+ int ret = -1;
+ if(eq_len)
+ ret = memcmp(data1_copy->data(), recovered->data(), recovered->length());
+ EXPECT_EQ(ret, (int) 0);
+}
+#endif
+
+TEST(FECtestRely, RelyTestOutOfOrder2) {
+ // use Rely k = 2 N = 6
+ std::string fec_str = "Rely_K2_N6";
+ Encoder encoder(fec_str);
+ Decoder decoder(fec_str);
+
+ PacketFactory pf;
+
+ core::Name name("b001::");
+
+ auto data1 = pf.createData(name, 1, 50, 1);
+
+ auto data2 = pf.createData(name, 2, 45, 2);
+ auto data2_copy = pf.createData(name, 2, 45, 2);
+
+ // encoding
+ uint32_t metadata = static_cast<uint32_t>(data1->getPayloadType());
+ encoder.onPacketProduced(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+
+ // create fec packet
+ auto data3 = pf.createData(name, 3, encoder.fec_packets_.front());
+
+ // decoding ooo packets. data 2 is lost.
+ decoder.onPacketReceived(*data3, data3->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data1, data2->headerSize() + rtc::DATA_HEADER_SIZE);
+
+ // get recovered packet
+ EXPECT_EQ(decoder.recovered_packets_.size(), (size_t)2);
+ decoder.recovered_packets_.pop(); // pop data 1
+ auto recovered = pf.createData(name, 2, decoder.recovered_packets_.front());
+ bool eq_len = (data2_copy->length() == recovered->length());
+ EXPECT_TRUE(eq_len);
+ int ret = -1;
+ if (eq_len)
+ ret = memcmp(data2_copy->data(), recovered->data(), recovered->length());
+ EXPECT_EQ(ret, (int)0);
+}
+
+TEST(FECtestRely, RelyTestLargerBlocks) {
+ // use Rely k = 4 N = 7
+ std::string fec_str = "Rely_K4_N7";
+ Encoder encoder(fec_str);
+ Decoder decoder(fec_str);
+
+ PacketFactory pf;
+
+ core::Name name("b001::");
+
+ auto data1 = pf.createData(name, 1, 50, 1);
+
+ auto data2 = pf.createData(name, 2, 45, 2);
+
+ auto data3 = pf.createData(name, 3, 12, 3);
+ auto data3_copy = pf.createData(name, 3, 12, 3);
+
+ auto data4 = pf.createData(name, 4, 20, 4);
+ auto data4_copy = pf.createData(name, 4, 20, 4);
+
+ // encoding
+ uint32_t metadata = static_cast<uint32_t>(data1->getPayloadType());
+ encoder.onPacketProduced(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data3, data3->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data4, data4->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+
+ // create fec packet
+ auto data5 = pf.createData(name, 5, encoder.fec_packets_.front());
+ encoder.fec_packets_.pop(); // pop 5
+ encoder.fec_packets_.pop(); // pop 6
+ auto data7 = pf.createData(name, 7, encoder.fec_packets_.front());
+
+ // decoding packets: lost data 3 and data 4
+ decoder.onPacketReceived(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data7, data7->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data5, data5->headerSize() + rtc::DATA_HEADER_SIZE);
+
+ // get recovered packet
+ EXPECT_EQ(decoder.recovered_packets_.size(), (size_t)4);
+ decoder.recovered_packets_.pop(); // pop data 1
+ decoder.recovered_packets_.pop(); // pop data 2
+ auto recovered3 = pf.createData(name, 3, decoder.recovered_packets_.front());
+ decoder.recovered_packets_.pop();
+ auto recovered4 = pf.createData(name, 4, decoder.recovered_packets_.front());
+
+ bool eq_len = (data3_copy->length() == recovered3->length());
+ EXPECT_TRUE(eq_len);
+ int ret = -1;
+ if (eq_len)
+ ret = memcmp(data3_copy->data(), recovered3->data(), recovered3->length());
+ EXPECT_EQ(ret, (int)0);
+
+ eq_len = (data4_copy->length() == recovered4->length());
+ EXPECT_TRUE(eq_len);
+ ret = -1;
+ if (eq_len)
+ ret = memcmp(data4_copy->data(), recovered4->data(), recovered4->length());
+ EXPECT_EQ(ret, (int)0);
+}
+
+TEST(FECtestRely, RelyTestK1_N3) {
+ // use Rely k = 1 N = 3
+ std::string fec_str = "Rely_K1_N3";
+ Encoder encoder(fec_str);
+ Decoder decoder1(fec_str); // recv 2
+ Decoder decoder2(fec_str); // recv 3
+
+ PacketFactory pf;
+
+ core::Name name("b001::");
+
+ auto data1 = pf.createData(name, 1, 50, 1);
+ auto data1_copy = pf.createData(name, 1, 50, 1);
+
+ // encoding
+ uint32_t metadata = static_cast<uint32_t>(data1->getPayloadType());
+ encoder.onPacketProduced(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+
+ // create fec packets
+ EXPECT_TRUE(encoder.fec_packets_.size() == 2);
+ auto data2 = pf.createData(name, 2, encoder.fec_packets_.front());
+ encoder.fec_packets_.pop(); // pop 2
+ auto data3 = pf.createData(name, 3, encoder.fec_packets_.front());
+
+ // test1: recv data 2
+ decoder1.onPacketReceived(*data2,
+ data2->headerSize() + rtc::DATA_HEADER_SIZE);
+ EXPECT_EQ(decoder1.recovered_packets_.size(), (size_t)1);
+
+ auto recovered = pf.createData(name, 1, decoder1.recovered_packets_.front());
+ bool eq_len = (data1_copy->length() == recovered->length());
+ EXPECT_TRUE(eq_len);
+ int ret = -1;
+ if (eq_len)
+ ret = memcmp(data1_copy->data(), recovered->data(), recovered->length());
+ EXPECT_EQ(ret, (int)0);
+
+ // test2: recv data 3
+ decoder2.onPacketReceived(*data3,
+ data3->headerSize() + rtc::DATA_HEADER_SIZE);
+ EXPECT_EQ(decoder2.recovered_packets_.size(), (size_t)1);
+
+ recovered = pf.createData(name, 1, decoder2.recovered_packets_.front());
+ eq_len = (data1_copy->length() == recovered->length());
+ EXPECT_TRUE(eq_len);
+ ret = -1;
+ if (eq_len)
+ ret = memcmp(data1_copy->data(), recovered->data(), recovered->length());
+ EXPECT_EQ(ret, (int)0);
+}
+
+} // namespace protocol
+} // namespace transport
diff --git a/libtransport/src/test/test_fec_base_rs.cc b/libtransport/src/test/test_fec_base_rs.cc
new file mode 100644
index 000000000..7d7bcebc3
--- /dev/null
+++ b/libtransport/src/test/test_fec_base_rs.cc
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <gtest/gtest.h>
+#include <hicn/transport/core/content_object.h>
+#include <hicn/transport/core/global_object_pool.h>
+#include <protocols/fec_base.h>
+#include <protocols/fec_utils.h>
+#include <protocols/rtc/rtc_consts.h>
+
+#include <algorithm>
+#include <iostream>
+#include <queue>
+#include <random>
+
+namespace transport {
+namespace protocol {
+
+class PacketFactory {
+ public:
+ PacketFactory(){};
+
+ ~PacketFactory(){};
+
+ std::shared_ptr<transport::core::ContentObject> createData(
+ core::Name &name, uint32_t suffix, uint32_t payload_size,
+ uint32_t payload_filler) {
+ auto &packet_manager = core::PacketManager<>::getInstance();
+
+ // create payload
+ auto buff = packet_manager.getMemBuf();
+ buff->append(payload_size);
+ std::fill(buff->writableData(), buff->writableTail(), payload_filler);
+
+ // create data packet
+ auto data = packet_manager.getPacket<transport::core::ContentObject>(
+ HF_INET6_TCP, 0);
+ struct rtc::data_packet_t header;
+ header.setTimestamp(1000);
+ header.setProductionRate(1);
+ data->appendPayload((const uint8_t *)&header, rtc::DATA_HEADER_SIZE);
+ data->appendPayload(buff->data(), buff->length());
+ data->setName(name.setSuffix(suffix));
+ data->setLifetime(500);
+ data->setPathLabel(12);
+
+ return data;
+ }
+
+ std::shared_ptr<transport::core::ContentObject> createData(
+ core::Name &name, uint32_t suffix, fec::buffer payload) {
+ auto &packet_manager = core::PacketManager<>::getInstance();
+
+ auto data = packet_manager.getPacket<transport::core::ContentObject>(
+ HF_INET6_TCP, 0);
+ struct rtc::data_packet_t header;
+ header.setTimestamp(1000);
+ header.setProductionRate(1);
+ data->appendPayload((const uint8_t *)&header, rtc::DATA_HEADER_SIZE);
+ data->appendPayload(payload->data(), payload->length());
+ data->setName(name.setSuffix(suffix));
+ data->setLifetime(500);
+ data->setPathLabel(12);
+
+ return data;
+ }
+};
+
+class Encoder {
+ public:
+ Encoder(std::string fec_str) {
+ fec_type_ = fec::FECUtils::fecTypeFromString(fec_str.c_str());
+ encoder_ = fec::FECUtils::getEncoder(fec_type_, 1);
+ encoder_->setFECCallback(
+ std::bind(&Encoder::onFecPackets, this, std::placeholders::_1));
+ encoder_->setBufferCallback(
+ std::bind(&Encoder::getBuffer, this, std::placeholders::_1));
+ };
+
+ ~Encoder(){};
+
+ void onFecPackets(fec::BufferArray &packets) {
+ for (auto &packet : packets) {
+ fec_packets_.push(packet.getBuffer());
+ }
+ }
+
+ fec::buffer getBuffer(std::size_t size) {
+ auto ret = core::PacketManager<>::getInstance()
+ .getPacket<transport::core::ContentObject>(HF_INET6_TCP, 0);
+ ret->updateLength(rtc::DATA_HEADER_SIZE + size);
+ ret->append(rtc::DATA_HEADER_SIZE + size);
+ ret->trimStart(ret->headerSize() + rtc::DATA_HEADER_SIZE);
+
+ return ret;
+ }
+
+ void onPacketProduced(core::ContentObject &content_object, uint32_t offset,
+ uint32_t metadata) {
+ encoder_->onPacketProduced(content_object, offset, metadata);
+ }
+
+ public:
+ std::queue<fec::buffer> fec_packets_;
+
+ private:
+ std::unique_ptr<fec::ProducerFEC> encoder_;
+ fec::FECType fec_type_;
+};
+
+class Decoder {
+ public:
+ Decoder(std::string fec_str) {
+ fec_type_ = fec::FECUtils::fecTypeFromString(fec_str.c_str());
+ decoder_ = fec::FECUtils::getDecoder(fec_type_, 1);
+ decoder_->setFECCallback(
+ std::bind(&Decoder::onFecPackets, this, std::placeholders::_1));
+ decoder_->setBufferCallback(fec::FECBase::BufferRequested(0));
+ };
+
+ ~Decoder(){};
+
+ void onFecPackets(fec::BufferArray &packets) {
+ for (auto &packet : packets) {
+ recovered_packets_.push(packet.getBuffer());
+ }
+ }
+
+ void onPacketReceived(core::ContentObject &content_object, uint32_t offset) {
+ decoder_->onDataPacket(content_object, offset);
+ }
+
+ public:
+ std::queue<fec::buffer> recovered_packets_;
+
+ private:
+ std::unique_ptr<fec::ConsumerFEC> decoder_;
+ fec::FECType fec_type_;
+};
+
+TEST(FECtestRS, RSTestInOrder1) {
+ // use RS k = 2 N = 6
+ std::string fec_str = "RS_K2_N6";
+ Encoder encoder(fec_str);
+ Decoder decoder(fec_str);
+
+ PacketFactory pf;
+
+ core::Name name("b001::");
+
+ auto data1 = pf.createData(name, 1, 50, 1);
+ const uint8_t *data1_ptr = data1->data();
+
+ auto data2 = pf.createData(name, 2, 45, 2);
+ const uint8_t *data2_ptr = data2->data();
+
+ // encoding
+ uint32_t metadata = static_cast<uint32_t>(data1->getPayloadType());
+ encoder.onPacketProduced(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+
+ // create fec packet
+ auto data3 = pf.createData(name, 3, encoder.fec_packets_.front());
+
+ // decode in order, data 1 is lost
+ decoder.onPacketReceived(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data3, data3->headerSize() + rtc::DATA_HEADER_SIZE);
+
+ // test payload pointers off the original packets
+ EXPECT_EQ((const uint8_t *)data1->data(), data1_ptr);
+ EXPECT_EQ((const uint8_t *)data2->data(), data2_ptr);
+
+ // check recovered packet
+ EXPECT_EQ(decoder.recovered_packets_.size(), (size_t)2);
+ auto recovered = pf.createData(name, 1, decoder.recovered_packets_.front());
+ bool eq_len = (data1->length() == recovered->length());
+ EXPECT_TRUE(eq_len);
+ int ret = -1;
+ if (eq_len)
+ ret = memcmp(data1->data(), recovered->data(), recovered->length());
+ EXPECT_EQ(ret, (int)0);
+}
+
+TEST(FECtestRS, RSTestInOrder2) {
+ // use RS k = 2 N = 6
+ std::string fec_str = "RS_K2_N6";
+ Encoder encoder(fec_str);
+ Decoder decoder(fec_str);
+
+ PacketFactory pf;
+
+ core::Name name("b001::");
+
+ auto data1 = pf.createData(name, 1, 50, 1);
+ const uint8_t *data1_ptr = data1->data();
+
+ auto data2 = pf.createData(name, 2, 45, 2);
+ const uint8_t *data2_ptr = data2->data();
+
+ // encoding
+ uint32_t metadata = static_cast<uint32_t>(data1->getPayloadType());
+ encoder.onPacketProduced(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+
+ // create fec packet
+ auto data3 = pf.createData(name, 3, encoder.fec_packets_.front());
+
+ // decode in order, data 2 is lost
+ decoder.onPacketReceived(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data3, data3->headerSize() + rtc::DATA_HEADER_SIZE);
+
+ // test payload pointers off the original packets
+ EXPECT_EQ((const uint8_t *)data1->data(), data1_ptr);
+ EXPECT_EQ((const uint8_t *)data2->data(), data2_ptr);
+
+ // check recovered packet
+ EXPECT_EQ(decoder.recovered_packets_.size(), (size_t)2);
+ decoder.recovered_packets_.pop(); // pop data packet 1
+ auto recovered = pf.createData(name, 2, decoder.recovered_packets_.front());
+
+ bool eq_len = (data2->length() == recovered->length());
+ EXPECT_TRUE(eq_len);
+ int ret = -1;
+ if (eq_len)
+ ret = memcmp(data2->data(), recovered->data(), recovered->length());
+ EXPECT_EQ(ret, (int)0);
+}
+
+TEST(FECtestRS, RSTestOutOfOrder1) {
+ // use RS k = 2 N = 6
+ std::string fec_str = "RS_K2_N6";
+ Encoder encoder(fec_str);
+ Decoder decoder(fec_str);
+
+ PacketFactory pf;
+
+ core::Name name("b001::");
+
+ auto data1 = pf.createData(name, 1, 50, 1);
+ const uint8_t *data1_ptr = data1->data();
+
+ auto data2 = pf.createData(name, 2, 45, 2);
+ const uint8_t *data2_ptr = data2->data();
+
+ // encoding
+ uint32_t metadata = static_cast<uint32_t>(data1->getPayloadType());
+ encoder.onPacketProduced(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+
+ // create fec packet
+ auto data3 = pf.createData(name, 3, encoder.fec_packets_.front());
+
+ // decoding ooo packets. data 1 is lost.
+ decoder.onPacketReceived(*data3, data3->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE);
+
+ // test payload pointers off the original packets
+ EXPECT_EQ((const uint8_t *)data1->data(), data1_ptr);
+ EXPECT_EQ((const uint8_t *)data2->data(), data2_ptr);
+
+ // get recovered packet
+ EXPECT_EQ(decoder.recovered_packets_.size(), (size_t)2);
+ auto recovered = pf.createData(name, 1, decoder.recovered_packets_.front());
+ bool eq_len = (data1->length() == recovered->length());
+ EXPECT_TRUE(eq_len);
+ int ret = -1;
+ if (eq_len)
+ ret = memcmp(data1->data(), recovered->data(), recovered->length());
+ EXPECT_EQ(ret, (int)0);
+}
+
+TEST(FECtestRS, RSTestOutOfOrder2) {
+ // use RS k = 2 N = 6
+ std::string fec_str = "RS_K2_N6";
+ Encoder encoder(fec_str);
+ Decoder decoder(fec_str);
+
+ PacketFactory pf;
+
+ core::Name name("b001::");
+
+ auto data1 = pf.createData(name, 1, 50, 1);
+ const uint8_t *data1_ptr = data1->data();
+
+ auto data2 = pf.createData(name, 2, 45, 2);
+ const uint8_t *data2_ptr = data2->data();
+
+ // encoding
+ uint32_t metadata = static_cast<uint32_t>(data1->getPayloadType());
+ encoder.onPacketProduced(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+
+ // create fec packet
+ auto data3 = pf.createData(name, 3, encoder.fec_packets_.front());
+
+ // decoding ooo packets. data 2 is lost.
+ decoder.onPacketReceived(*data3, data3->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data1, data2->headerSize() + rtc::DATA_HEADER_SIZE);
+
+ // test payload pointers off the original packets
+ EXPECT_EQ((const uint8_t *)data1->data(), data1_ptr);
+ EXPECT_EQ((const uint8_t *)data2->data(), data2_ptr);
+
+ // get recovered packet
+ EXPECT_EQ(decoder.recovered_packets_.size(), (size_t)2);
+ decoder.recovered_packets_.pop(); // pop data packet 1
+
+ auto recovered = pf.createData(name, 2, decoder.recovered_packets_.front());
+ bool eq_len = (data2->length() == recovered->length());
+ EXPECT_TRUE(eq_len);
+ int ret = -1;
+ if (eq_len)
+ ret = memcmp(data2->data(), recovered->data(), recovered->length());
+ EXPECT_EQ(ret, (int)0);
+}
+
+TEST(FECtestRS, RSTestLargerBlocks) {
+ // use RS k = 4 N = 7
+ std::string fec_str = "RS_K4_N7";
+ Encoder encoder(fec_str);
+ Decoder decoder(fec_str);
+
+ PacketFactory pf;
+
+ core::Name name("b001::");
+
+ auto data1 = pf.createData(name, 1, 50, 1);
+ const uint8_t *data1_ptr = data1->data();
+
+ auto data2 = pf.createData(name, 2, 45, 2);
+ const uint8_t *data2_ptr = data2->data();
+
+ auto data3 = pf.createData(name, 3, 12, 3);
+ const uint8_t *data3_ptr = data3->data();
+
+ auto data4 = pf.createData(name, 4, 20, 4);
+ const uint8_t *data4_ptr = data4->data();
+
+ // encoding
+ uint32_t metadata = static_cast<uint32_t>(data1->getPayloadType());
+ encoder.onPacketProduced(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data3, data3->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data4, data4->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+
+ // create fec packet
+ auto data5 = pf.createData(name, 5, encoder.fec_packets_.front());
+ encoder.fec_packets_.pop(); // pop 5
+ encoder.fec_packets_.pop(); // pop 6
+ auto data7 = pf.createData(name, 7, encoder.fec_packets_.front());
+
+ // decoding packets: lost data 3 and data 4
+ decoder.onPacketReceived(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data7, data7->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data5, data5->headerSize() + rtc::DATA_HEADER_SIZE);
+
+ // test payload pointers off the original packets
+ EXPECT_EQ((const uint8_t *)data1->data(), data1_ptr);
+ EXPECT_EQ((const uint8_t *)data2->data(), data2_ptr);
+ EXPECT_EQ((const uint8_t *)data3->data(), data3_ptr);
+ EXPECT_EQ((const uint8_t *)data4->data(), data4_ptr);
+
+ // get recovered packet
+ EXPECT_EQ(decoder.recovered_packets_.size(), (size_t)4);
+ decoder.recovered_packets_.pop(); // pop data 1
+ decoder.recovered_packets_.pop(); // pop data 2
+ auto recovered3 = pf.createData(name, 3, decoder.recovered_packets_.front());
+ decoder.recovered_packets_.pop(); // pop data 3
+ auto recovered4 = pf.createData(name, 4, decoder.recovered_packets_.front());
+
+ bool eq_len = (data3->length() == recovered3->length());
+ EXPECT_TRUE(eq_len);
+ int ret = -1;
+ if (eq_len)
+ ret = memcmp(data3->data(), recovered3->data(), recovered3->length());
+ EXPECT_EQ(ret, (int)0);
+
+ eq_len = (data4->length() == recovered4->length());
+ EXPECT_TRUE(eq_len);
+ ret = -1;
+ if (eq_len)
+ ret = memcmp(data4->data(), recovered4->data(), recovered4->length());
+ EXPECT_EQ(ret, (int)0);
+}
+
+} // namespace protocol
+} // namespace transport
diff --git a/libtransport/src/test/test_fec_reedsolomon.cc b/libtransport/src/test/test_fec_reedsolomon.cc
index c7e10d111..0973069b1 100644
--- a/libtransport/src/test/test_fec_reedsolomon.cc
+++ b/libtransport/src/test/test_fec_reedsolomon.cc
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <glog/logging.h>
#include <gtest/gtest.h>
#include <hicn/transport/core/content_object.h>
#include <hicn/transport/core/global_object_pool.h>
@@ -30,28 +31,35 @@ double ReedSolomonTest(int k, int n, int seq_offset, int size) {
fec::RSEncoder encoder(k, n, seq_offset);
fec::RSDecoder decoder(k, n, seq_offset);
- std::vector<fec::buffer> tx_block(k);
- std::vector<fec::buffer> rx_block(k);
+ using BufferMetadata = std::pair<fec::buffer, uint32_t>;
+
+ std::vector<BufferMetadata> tx_block(k);
+ std::vector<BufferMetadata> rx_block(k);
int count = 0;
int run = 0;
+ // Setup random engine
+ std::random_device
+ rd; // Will be used to obtain a seed for the random number engine
+ std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd()
+ std::uniform_int_distribution<> dis(0, 99);
+
int iterations = 100;
auto &packet_manager = core::PacketManager<>::getInstance();
- encoder.setFECCallback(
- [&tx_block](
- std::vector<std::pair<uint32_t, fec::buffer>> &repair_packets) {
- for (auto &p : repair_packets) {
- // Append repair symbols to tx_block
- tx_block.emplace_back(std::move(p).second);
- }
- });
+ encoder.setFECCallback([&tx_block](fec::BufferArray &repair_packets) {
+ for (auto &p : repair_packets) {
+ // Append repair symbols to tx_block
+ tx_block.emplace_back(p.getBuffer(), p.getMetadata());
+ }
+ });
decoder.setFECCallback(
- [&](std::vector<std::pair<uint32_t, fec::buffer>> &source_packets) {
+ [&tx_block, &count, &k](fec::BufferArray &source_packets) {
for (int i = 0; i < k; i++) {
// Compare decoded source packets with original transmitted packets.
- if (*tx_block[i] != *source_packets[i].second) {
+ if (*tx_block[i].first != *source_packets[i].getBuffer() ||
+ tx_block[i].second != source_packets[i].getMetadata()) {
count++;
}
}
@@ -60,7 +68,7 @@ double ReedSolomonTest(int k, int n, int seq_offset, int size) {
do {
// Discard eventual packet appended in previous callback call
tx_block.erase(tx_block.begin() + k, tx_block.end());
- auto _seq_offet = seq_offset;
+ uint32_t _seq_offset = seq_offset;
// Initialization. Feed encoder with first k source packets
for (int i = 0; i < k; i++) {
@@ -69,45 +77,46 @@ double ReedSolomonTest(int k, int n, int seq_offset, int size) {
// Let's append a bit less than size, so that the FEC class will take care
// of filling the rest with zeros
- auto cur_size = size - (rand() % 100);
+ auto cur_size = size - dis(gen);
// Set payload, saving 2 bytes at the beginning of the buffer for encoding
// the length
packet->append(cur_size);
- packet->trimStart(2);
- std::generate(packet->writableData(), packet->writableTail(), rand);
std::fill(packet->writableData(), packet->writableTail(), i + 1);
// Set first byte of payload to seq_offset, to reorder at receiver side
- packet->writableData()[0] = uint8_t(_seq_offet++);
+ uint32_t *pkt_head = (uint32_t *)packet->writableData();
+ *pkt_head = _seq_offset++;
+
+ // Set a metadata integer
+ uint32_t metadata = dis(gen);
// Store packet in tx buffer and clear rx buffer
- tx_block[i] = std::move(packet);
+ tx_block[i] = std::make_pair(std::move(packet), metadata);
}
// Create the repair packets
for (auto &tx : tx_block) {
- encoder.consume(tx, tx->writableBuffer()[0]);
+ encoder.consume(tx.first, tx.first->writableBuffer()[0], 0, tx.second);
}
// Simulate transmission on lossy channel
- unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
std::vector<bool> losses(n, false);
for (int i = 0; i < n - k; i++) losses[i] = true;
int rxi = 0;
- std::shuffle(losses.begin(), losses.end(),
- std::default_random_engine(seed));
+ std::shuffle(losses.begin(), losses.end(), gen);
for (int i = 0; i < n && rxi < k; i++)
if (losses[i] == false) {
rx_block[rxi++] = tx_block[i];
if (i < k) {
// Source packet
- decoder.consumeSource(rx_block[rxi - 1],
- rx_block[rxi - 1]->data()[0]);
+ uint32_t index = *((uint32_t *)rx_block[rxi - 1].first->data());
+ decoder.consumeSource(rx_block[rxi - 1].first, index, 0,
+ rx_block[rxi - 1].second);
} else {
// Repair packet
- decoder.consumeRepair(rx_block[rxi - 1]);
+ decoder.consumeRepair(rx_block[rxi - 1].first);
}
}
@@ -126,6 +135,12 @@ void ReedSolomonMultiBlockTest(int n_sourceblocks) {
fec::RSEncoder encoder(k, n);
fec::RSDecoder decoder(k, n);
+ // Setup random engine
+ std::random_device
+ rd; // Will be used to obtain a seed for the random number engine
+ std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd()
+ std::uniform_int_distribution<> dis(0, 99);
+
auto &packet_manager = core::PacketManager<>::getInstance();
std::vector<std::pair<fec::buffer, uint32_t>> tx_block;
@@ -136,33 +151,39 @@ void ReedSolomonMultiBlockTest(int n_sourceblocks) {
// Receiver will receive packet for n_sourceblocks in a random order.
int total_packets = n * n_sourceblocks;
int tx_packets = k * n_sourceblocks;
- unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
- encoder.setFECCallback(
- [&](std::vector<std::pair<uint32_t, fec::buffer>> &repair_packets) {
- for (auto &p : repair_packets) {
- // Append repair symbols to tx_block
- tx_block.emplace_back(std::move(p.second), ++i);
- }
+ encoder.setFECCallback([&tx_block, &rx_block, &i, &n, &k,
+ &encoder](fec::BufferArray &repair_packets) {
+ for (auto &p : repair_packets) {
+ // Append repair symbols to tx_block
+ ++i;
+ tx_block.emplace_back(std::move(p.getBuffer()), i);
+ }
- EXPECT_EQ(tx_block.size(), size_t(n));
+ EXPECT_EQ(tx_block.size(), size_t(n));
- // Select k packets to send, including at least one symbol. We start
- // from the end for this reason.
- for (int j = n - 1; j > n - k - 1; j--) {
- rx_block.emplace_back(std::move(tx_block[j]));
- }
+ // Select k packets to send, including at least one symbol. We start
+ // from the end for this reason.
+ for (int j = n - 1; j > n - k - 1; j--) {
+ rx_block.emplace_back(std::move(tx_block[j]));
+ }
- // Clear tx block for next source block
- tx_block.clear();
- encoder.clear();
- });
+ // Clear tx block for next source block
+ tx_block.clear();
+ encoder.clear();
+ });
// The decode callback must be called exactly n_sourceblocks times
- decoder.setFECCallback(
- [&](std::vector<std::pair<uint32_t, fec::buffer>> &source_packets) {
- count++;
- });
+ decoder.setFECCallback([&count](fec::BufferArray &source_packets) {
+ // Check buffers
+ for (auto &packet : source_packets) {
+ auto packet_index = ((uint32_t *)packet.getBuffer()->writableData())[0];
+ EXPECT_EQ(packet_index, packet.getIndex())
+ << "Packet index: " << packet_index
+ << " -- FEC Index: " << packet.getIndex();
+ }
+ count++;
+ });
// Produce n * n_sourceblocks
// - ( k ) * n_sourceblocks source packets
@@ -173,7 +194,7 @@ void ReedSolomonMultiBlockTest(int n_sourceblocks) {
// Let's append a bit less than size, so that the FEC class will take care
// of filling the rest with zeros
- auto cur_size = size - (rand() % 100);
+ auto cur_size = size - dis(gen);
// Set payload, saving 2 bytes at the beginning of the buffer for encoding
// the length
@@ -182,7 +203,7 @@ void ReedSolomonMultiBlockTest(int n_sourceblocks) {
std::fill(packet->writableData(), packet->writableTail(), i + 1);
// Set first byte of payload to i, to reorder at receiver side
- packet->writableData()[0] = uint8_t(i);
+ ((uint32_t *)packet->writableData())[0] = uint32_t(i);
// Store packet in tx buffer
tx_block.emplace_back(packet, i);
@@ -195,8 +216,7 @@ void ReedSolomonMultiBlockTest(int n_sourceblocks) {
EXPECT_EQ(size_t(tx_packets), size_t(rx_block.size()));
// Lets shuffle the rx_block before starting feeding the decoder.
- std::shuffle(rx_block.begin(), rx_block.end(),
- std::default_random_engine(seed));
+ std::shuffle(rx_block.begin(), rx_block.end(), gen);
for (auto &p : rx_block) {
int index = p.second % n;
@@ -231,7 +251,7 @@ foreach_rs_fec_type
#undef _
TEST(ReedSolomonMultiBlockTest, RSMB10) {
- int blocks = 10;
+ int blocks = 1;
ReedSolomonMultiBlockTest(blocks);
}
diff --git a/libtransport/src/test/test_fec_rely_wrapper.cc b/libtransport/src/test/test_fec_rely_wrapper.cc
index c5b73f8d2..764e4dd2d 100644
--- a/libtransport/src/test/test_fec_rely_wrapper.cc
+++ b/libtransport/src/test/test_fec_rely_wrapper.cc
@@ -13,18 +13,23 @@
* limitations under the License.
*/
+#include <glog/logging.h>
#include <gtest/gtest.h>
#include <hicn/transport/core/global_object_pool.h>
+#include <hicn/transport/interfaces/socket_options_default_values.h>
#include <hicn/transport/utils/log.h>
#include <protocols/fec/rely.h>
#include <queue>
+#include <random>
namespace transport {
namespace protocol {
-std::string printMissing(
- const std::map<uint32_t, core::ContentObject::Ptr> &missing) {
+using SavedPacketMap =
+ std::map<uint32_t, std::pair<core::ContentObject::Ptr, uint32_t>>;
+
+std::string printMissing(const SavedPacketMap &missing) {
std::stringstream stream;
for (auto &[seq, packet] : missing) {
@@ -48,14 +53,15 @@ std::string printMissing(
* @param loss_rate The loss rate
*/
void testRelyEncoderDecoder(uint32_t k, uint32_t n, size_t max_packet_size,
- int64_t timeout, uint32_t max_iterations,
+ int64_t /* timeout */, uint32_t max_iterations,
int loss_rate) {
// Create 1 encoder and 1 decoder
fec::RelyEncoder _encoder(k, n);
fec::RelyDecoder _decoder(k, n);
// Seed the pseudo-random with known value to always get same loss pattern
- srand(k * n);
+ std::mt19937 gen(k *
+ n); // Standard mersenne_twister_engine seeded with rd();
// We will interact with rely encoder/decoder using the interface
fec::ProducerFEC &encoder = _encoder;
@@ -68,73 +74,78 @@ void testRelyEncoderDecoder(uint32_t k, uint32_t n, size_t max_packet_size,
auto &packet_manager = core::PacketManager<>::getInstance();
// Store packets to verify them in the decoder callback
- std::map<uint32_t, core::ContentObject::Ptr> saved_packets;
+ SavedPacketMap saved_packets;
// Save repair packets here in encoder callback
std::queue<fec::buffer> pending_repair_packets;
// Set callback called by encoder when a buffer is required.
- encoder.setBufferCallback([](std::size_t size) -> fec::buffer {
+ encoder.setBufferCallback([](std::size_t size) {
auto ret =
- core::PacketManager<>::getInstance().getPacket<core::ContentObject>();
+ core::PacketManager<>::getInstance().getPacket<core::ContentObject>(
+ transport::interface::default_values::packet_format);
ret->updateLength(size);
ret->append(size);
ret->trimStart(ret->headerSize());
- assert(ret->length() >= size);
+ DCHECK(ret->length() >= size);
return ret;
});
// Set callback to be called by encoder when repair packets are ready
- encoder.setFECCallback(
- [&](std::vector<std::pair<uint32_t, fec::buffer>> &packets) {
- // We must get n - k symbols
- EXPECT_EQ(packets.size(), n - k);
- // TRANSPORT_LOGD("Got %zu symbols", packets.size());
-
- // Save symbols in pending_repair_packets queue and increment iterations
- for (auto &packet : packets) {
- ++iterations;
- pending_repair_packets.push(packet.second);
- }
- });
+ encoder.setFECCallback([&iterations, &pending_repair_packets, &n,
+ &k](fec::BufferArray &packets) {
+ // We must get n - k symbols
+ EXPECT_EQ(packets.size(), n - k);
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Got " << packets.size() << " symbols";
+
+ // Save symbols in pending_repair_packets queue and increment iterations
+ for (auto &packet : packets) {
+ ++iterations;
+ pending_repair_packets.push(packet.getBuffer());
+ }
+ });
// Set callback to be called when decoder recover a packet
- decoder.setFECCallback(
- [&](std::vector<std::pair<uint32_t, fec::buffer>> &packets) {
- for (auto &packet : packets) {
- // TRANSPORT_LOGD("Recovering packet %u", packet.first);
+ decoder.setFECCallback([&saved_packets](fec::BufferArray &packets) {
+ for (auto &packet : packets) {
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Recovering packet " << packet.getIndex();
+
+ // Ensure recovered packet is in packets actually produced by encoder
+ auto original = saved_packets.find(packet.getIndex());
+ ASSERT_TRUE(original != saved_packets.end());
+ auto &original_packet = *original->second.first;
- // Ensure recovered packet is in packets actually produced by encoder
- auto original = saved_packets.find(packet.first);
- ASSERT_TRUE(original != saved_packets.end());
- auto &original_packet = *original->second;
+ // Remove additional headers at the beginning of the packet. This may
+ // change in the future.
+ original_packet.trimStart(60 /* Ip + TCP */ + 32 /* Rely header */ +
+ 4 /* Packet size */);
- // Remove additional headers at the beginning of the packet. This may
- // change in the future.
- original_packet.trimStart(60 /* Ip + TCP */ + 28 /* Rely header */ +
- 4 /* Packet size */);
+ // Recovered packet should be equal to the original one
+ EXPECT_TRUE(original_packet == *packet.getBuffer());
- // Recovered packet should be equal to the original one
- EXPECT_TRUE(original_packet == *packet.second);
+ // Also metadata should correspond
+ EXPECT_TRUE(original->second.second == packet.getMetadata());
- // Restore removed headers
- original_packet.prepend(60 + 28 + 4);
+ // Restore removed headers
+ original_packet.prepend(60 + 32 + 4);
- // Erase packet from saved packet list
- saved_packets.erase(original);
- }
- });
+ // Erase packet from saved packet list
+ saved_packets.erase(original);
+ }
+ });
// Send max_iterations packets from encoder to decoder
+ std::uniform_int_distribution<> dis(0, 1299);
while (iterations < max_iterations) {
// Create a payload, the size is between 50 and 1350 bytes.
- auto payload_size = 50 + (rand() % 1300);
+ auto payload_size = 50 + (dis(gen));
uint8_t payload[max_packet_size];
- std::generate(payload, payload + payload_size, rand);
+ std::generate(payload, payload + payload_size, gen);
// Get a packet from global pool and set name
- auto buffer = packet_manager.getPacket<core::ContentObject>();
+ auto buffer = packet_manager.getPacket<core::ContentObject>(
+ transport::interface::default_values::packet_format);
buffer->setName(core::Name("b001::abcd", iterations));
// Get offset
@@ -145,20 +156,23 @@ void testRelyEncoderDecoder(uint32_t k, uint32_t n, size_t max_packet_size,
// its own header).
buffer->appendPayload(payload, payload_size);
+ // Set an u32 metadata to pass altogether with the buffer
+ uint32_t metadata = dis(gen);
+
// Save packet in the saving_packets list
- // TRANSPORT_LOGD("Saving packet with index %lu", iterations);
- saved_packets.emplace(iterations, buffer);
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Saving packet with index " << iterations;
+ saved_packets.emplace(iterations, std::make_pair(buffer, metadata));
// Feed buffer into the encoder. This will eventually trigger a call to the
// FEC callback as soon as k packets are fed into the endocer.
- encoder.onPacketProduced(*buffer, offset);
+ encoder.onPacketProduced(*buffer, offset, metadata);
// Check returned packet. We calculate the difference in size and we compare
// only the part of the returned packet corresponding to the original
// payload. Rely should only add a header and should not modify the actual
// payload content. If it does it, this check will fail.
auto diff = buffer->length() - payload_size - offset;
- // TRANSPORT_LOGD("Difference is %zu", diff);
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Difference is " << diff;
auto cmp =
std::memcmp(buffer->data() + offset + diff, payload, payload_size);
EXPECT_FALSE(cmp);
@@ -170,29 +184,33 @@ void testRelyEncoderDecoder(uint32_t k, uint32_t n, size_t max_packet_size,
// using future packets that are not created in the test. For this reason,
// we ensure the test ends without losses.
#define DROP_CONDITION(loss_rate, max_iterations) \
- (rand() % 100) >= loss_rate || iterations >= max_iterations * 0.9
+ (dis(gen)) >= loss_rate || iterations >= max_iterations * 0.9
// Handle the source packet to the decoder, id drop condition returns true
if (DROP_CONDITION(loss_rate, max_iterations)) {
// Pass packet to decoder
- // TRANSPORT_LOGD("Passing packet %u to decoder",
- // buffer->getName().getSuffix());
- decoder.onDataPacket(*buffer, offset);
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Passing packet " << buffer->getName().getSuffix()
+ << " to decoder";
+ decoder.onDataPacket(*buffer, offset, metadata);
} else {
- // TRANSPORT_LOGD("Packet %u, dropped", buffer->getName().getSuffix());
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Packet " << buffer->getName().getSuffix() << " dropped";
}
- // Check if previous call to encoder.consumer() generated repair packets,
+ // Check if previous call to encoder.consume() generated repair packets,
// and if yes, feed them to the decoder.
while (pending_repair_packets.size()) {
// Also repair packets can be lost
if (DROP_CONDITION(loss_rate, max_iterations)) {
auto &packet = pending_repair_packets.front();
- // TRANSPORT_LOGD("Passing packet %u to decoder", iterations);
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Passing packet " << iterations << " to decoder";
core::ContentObject &co = (core::ContentObject &)(*packet);
decoder.onDataPacket(co, 0);
} else {
- // TRANSPORT_LOGD("Packet (repair) %u dropped", iterations);
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Packet (repair) " << iterations << " dropped";
}
// Remove packet from the queue
@@ -206,9 +224,6 @@ void testRelyEncoderDecoder(uint32_t k, uint32_t n, size_t max_packet_size,
// 0.001 residual losses
EXPECT_LE(saved_packets.size(), iterations * 0.001)
<< printMissing(saved_packets);
-
- // Reset seed
- srand(time(0));
}
/**
diff --git a/libtransport/src/test/test_fixed_block_allocator.cc b/libtransport/src/test/test_fixed_block_allocator.cc
new file mode 100644
index 000000000..33e048031
--- /dev/null
+++ b/libtransport/src/test/test_fixed_block_allocator.cc
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hicn/transport/core/global_object_pool.h>
+#include <hicn/transport/utils/event_thread.h>
+#include <hicn/transport/utils/fixed_block_allocator.h>
+
+namespace utils {
+
+class FixedBlockAllocatorTest : public ::testing::Test {
+ protected:
+ static inline const std::size_t default_size = 2048;
+ static inline const std::size_t default_n_buffer = 1024;
+
+ // Get fixed block allocator_ of 1024 buffers of size 2048 bytes
+ FixedBlockAllocatorTest()
+ : allocator_(
+ ::utils::FixedBlockAllocator<default_size,
+ default_n_buffer>::getInstance()) {
+ // You can do set-up work for each test here.
+ }
+
+ virtual ~FixedBlockAllocatorTest() {
+ // 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).
+ allocator_.reset();
+ }
+
+ virtual void TearDown() {
+ // Code here will be called immediately after each test (right
+ // before the destructor).
+ allocator_.reset();
+ }
+
+ static bool pointerIsAligned(const void *pointer, size_t byte_count) {
+ // Sanity check
+ EXPECT_THAT(reinterpret_cast<std::uintptr_t>(pointer) &
+ (alignof(std::max_align_t) - 1),
+ testing::Eq(std::uintptr_t(0)));
+
+ return uintptr_t(pointer) % byte_count == 0;
+ }
+
+ ::utils::FixedBlockAllocator<default_size, default_n_buffer> &allocator_;
+};
+
+TEST_F(FixedBlockAllocatorTest, DefaultChecks) {
+ EXPECT_EQ(allocator_.blockSize(), default_size);
+ EXPECT_EQ(allocator_.blockCount(), default_n_buffer);
+ EXPECT_EQ(allocator_.allocations(), 0UL);
+ EXPECT_EQ(allocator_.deallocations(), 0UL);
+ EXPECT_EQ(allocator_.blocksInUse(), 0UL);
+
+ // Allocate one single block of memory
+ auto block = allocator_.allocateBlock();
+
+ ASSERT_THAT(block, testing::NotNull());
+
+ // Check statistics
+ EXPECT_EQ(allocator_.allocations(), 1UL);
+ EXPECT_EQ(allocator_.deallocations(), 0UL);
+ EXPECT_EQ(allocator_.blocksInUse(), 1UL);
+
+ // Deallocate it
+ allocator_.deallocateBlock(block);
+
+ // check statistics
+ EXPECT_EQ(allocator_.allocations(), 1UL);
+ EXPECT_EQ(allocator_.deallocations(), 1UL);
+ EXPECT_EQ(allocator_.blocksInUse(), 0UL);
+
+ // Test reset
+ allocator_.reset();
+
+ EXPECT_EQ(allocator_.blockSize(), default_size);
+ EXPECT_EQ(allocator_.blockCount(), default_n_buffer);
+ EXPECT_EQ(allocator_.allocations(), 0UL);
+ EXPECT_EQ(allocator_.deallocations(), 0UL);
+ EXPECT_EQ(allocator_.blocksInUse(), 0UL);
+}
+
+TEST_F(FixedBlockAllocatorTest, CheckMemoryIsReused) {
+ // Get one block. As it is the first one, it will be retrieved from the pool
+ auto block = allocator_.allocateBlock();
+
+ // Make sure block is valid
+ ASSERT_THAT(block, testing::NotNull());
+
+ // Release block
+ allocator_.deallocateBlock(block);
+
+ // Get same memory block again
+ auto block2 = allocator_.allocateBlock();
+
+ // Make sure memory is reused
+ ASSERT_EQ(block, block2);
+
+ // Get a third block
+ auto block3 = allocator_.allocateBlock();
+
+ // Make sure is different memory
+ ASSERT_NE(block2, block3);
+
+ // Deallocate both and check we get back the laso one
+ allocator_.deallocateBlock(block2);
+ allocator_.deallocateBlock(block3);
+
+ auto block4 = allocator_.allocateBlock();
+ ASSERT_EQ(block3, block4);
+}
+
+TEST_F(FixedBlockAllocatorTest, CheckMemoryIsContiguous) {
+ // Get one block. As it is the first one, it will be retrieved from the pool
+ auto block = reinterpret_cast<uint8_t *>(allocator_.allocateBlock());
+
+ // Make sure block is valid
+ ASSERT_THAT(block, testing::NotNull());
+
+ // Get another block
+ auto block2 = reinterpret_cast<uint8_t *>(allocator_.allocateBlock());
+
+ // Make sure block is valid
+ ASSERT_THAT(block2, testing::NotNull());
+
+ // Check the 2 blocks come from contiguous memory
+ ASSERT_THAT(std::size_t(block2 - block), testing::Eq(default_size));
+}
+
+TEST_F(FixedBlockAllocatorTest, CheckPoolExpansion) {
+ // Get all the blocks we setup when constructing the allocator
+ std::array<uint8_t *, default_n_buffer> blocks;
+ blocks[0] = reinterpret_cast<uint8_t *>(allocator_.allocateBlock());
+ for (std::size_t i = 1; i < default_n_buffer; i++) {
+ blocks[i] = reinterpret_cast<uint8_t *>(allocator_.allocateBlock());
+ ASSERT_THAT(std::size_t(blocks[i] - blocks[i - 1]),
+ testing::Eq(default_size));
+ }
+
+ ASSERT_THAT(allocator_.blockCount(), testing::Eq(default_n_buffer));
+
+ // We should have finished all the blocks belonging to first pool. Let's get
+ // one additional block
+ auto new_block = reinterpret_cast<uint8_t *>(allocator_.allocateBlock());
+
+ // Make sure the block count doubled its size
+ ASSERT_THAT(allocator_.blockCount(), testing::Eq(2 * default_n_buffer));
+
+ // Check the new block is not contiguous with respect last block in blocks
+ ASSERT_THAT(std::size_t(new_block - blocks[default_n_buffer - 1]),
+ testing::Ne(default_size));
+}
+
+TEST_F(FixedBlockAllocatorTest, CheckMemoryIsAligned) {
+ for (std::size_t i = 0; i < default_n_buffer; i++) {
+ auto block = reinterpret_cast<uint8_t *>(allocator_.allocateBlock());
+ ASSERT_THAT(pointerIsAligned(block, alignof(std::max_align_t)),
+ testing::IsTrue);
+ }
+}
+
+TEST_F(FixedBlockAllocatorTest, Multithreading) {
+ // Create 4 threads
+ utils::EventThread threads[4];
+ ::utils::FixedBlockAllocator<default_size, default_n_buffer>
+ *allocator_addresses[4] = {nullptr, nullptr, nullptr, nullptr};
+ int i = 0;
+ for (auto &t : threads) {
+ t.add([&allocator_addresses, i]() {
+ auto &allocator =
+ ::utils::FixedBlockAllocator<default_size,
+ default_n_buffer>::getInstance();
+ allocator_addresses[i] = &allocator;
+ });
+ i++;
+ }
+
+ // Stop threads
+ for (auto &t : threads) {
+ t.stop();
+ }
+
+ // Check the instance of allocator was different for each thread
+ for (int i = 0; i < 4; i++) {
+ for (int j = i + 1; j < 4; j++) {
+ ASSERT_NE(allocator_addresses[i], allocator_addresses[j]);
+ }
+ }
+}
+
+} // namespace utils \ No newline at end of file
diff --git a/libtransport/src/test/test_interest.cc b/libtransport/src/test/test_interest.cc
index 8853563b0..d9c535881 100644
--- a/libtransport/src/test/test_interest.cc
+++ b/libtransport/src/test/test_interest.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -30,7 +30,7 @@ namespace {
// The fixture for testing class Foo.
class InterestTest : public ::testing::Test {
protected:
- InterestTest() : name_("b001::123|321"), interest_() {
+ InterestTest() : name_("b001::123|321"), interest_(HF_INET6_TCP) {
// You can do set-up work for each test here.
}
@@ -108,7 +108,7 @@ TEST_F(InterestTest, ConstructorWithName) {
Name n("b001::1|123");
try {
- Interest interest(n);
+ Interest interest(HF_INET6_TCP, n);
} catch (...) {
FAIL() << "ERROR: Unexpected exception thrown";
}
@@ -176,27 +176,27 @@ TEST_F(InterestTest, SetGetLocator) {
auto l = interest.getLocator();
ip_address_t address;
- ip_address_pton("b006::ab:cdab:cdef", &address);
- auto ret = !std::memcmp(&l, &address, sizeof(address));
+ inet_pton(AF_INET6, "b006::ab:cdab:cdef", &address);
+ auto ret = !ip_address_cmp(&l, &address, AF_INET6);
EXPECT_TRUE(ret);
// Set different locator
- ip_address_pton("2001::1234::4321::abcd::", &address);
+ inet_pton(AF_INET6, "2001::1234::4321::abcd::", &address);
// Set it on interest
interest.setLocator(address);
// Check it was set
l = interest.getLocator();
- ret = !std::memcmp(&l, &address, sizeof(address));
+ ret = !ip_address_cmp(&l, &address, AF_INET6);
EXPECT_TRUE(ret);
}
TEST_F(InterestTest, SetGetLifetime) {
// Create interest from buffer
- Interest interest;
+ Interest interest(HF_INET6_TCP);
const constexpr uint32_t lifetime = 10000;
// Set lifetime
@@ -211,7 +211,7 @@ TEST_F(InterestTest, SetGetLifetime) {
TEST_F(InterestTest, HasManifest) {
// Create interest from buffer
- Interest interest;
+ Interest interest(HF_INET6_TCP);
// Let's expect anexception here
try {
@@ -232,7 +232,7 @@ TEST_F(InterestTest, HasManifest) {
TEST_F(InterestTest, AppendSuffixesEncodeAndIterate) {
// Create interest from buffer
- Interest interest;
+ Interest interest(HF_INET6_TCP);
// Appenad some suffixes, with some duplicates
interest.appendSuffix(1);
diff --git a/libtransport/src/test/test_memif_connector.cc b/libtransport/src/test/test_memif_connector.cc
new file mode 100644
index 000000000..562a12c88
--- /dev/null
+++ b/libtransport/src/test/test_memif_connector.cc
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2022 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <core/memif_connector.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hicn/transport/core/global_object_pool.h>
+#include <hicn/transport/utils/chrono_typedefs.h>
+
+namespace transport {
+namespace core {
+
+namespace {
+
+using namespace std::placeholders;
+
+/**
+ * Master memif connector
+ */
+template <int Master>
+class Memif {
+ static inline std::size_t counter = 256;
+ static inline std::size_t total_packets = counter * 4096;
+ static inline std::size_t packet_size = 64;
+
+ public:
+ Memif(asio::io_service &io_service)
+ : io_service_(io_service),
+ memif_connector_(std::make_shared<MemifConnector>(
+ std::bind(&Memif::onPacketReceived, this, _1, _2, _3),
+ std::bind(&Memif::onPacketSent, this, _1, _2),
+ std::bind(&Memif::onClose, this, _1),
+ std::bind(&Memif::onReconnect, this, _1, _2), io_service_,
+ Master ? "test_master" : "test_slave")),
+ recv_counter_(0),
+ sent_counter_(0) {
+ memif_connector_->connect(0 /* Memif ID */, Master /* Is Master */,
+ "@hicntransport/test/memif");
+ }
+
+ void setStart() { t0_ = utils::SteadyTime::now(); }
+
+ void startTest() {
+ if constexpr (!Master) {
+ auto &packet_manager = core::PacketManager<>::getInstance();
+
+ // Send in busrt of 256 packet per time
+ for (std::size_t i = 0; i < counter; i++) {
+ auto packet = packet_manager.getMemBuf();
+ packet->append(packet_size);
+ memif_connector_->send(packet);
+ sent_counter_++;
+ }
+
+ if (sent_counter_ < total_packets) {
+ asio::post(io_service_, std::bind(&Memif::startTest, this));
+ }
+ } else {
+ setStart();
+ }
+ }
+
+ auto getRecvCounter() { return recv_counter_; }
+ auto getSentCounter() { return sent_counter_; }
+
+ private:
+ void onPacketReceived(Connector *c,
+ const std::vector<utils::MemBuf::Ptr> &buffers,
+ const std::error_code &ec) {
+ if constexpr (Master) {
+ recv_counter_ += buffers.size();
+ if (recv_counter_ == total_packets) {
+ auto t1 = utils::SteadyTime::now();
+ auto delta = utils::SteadyTime::getDurationS(t0_, t1);
+ auto rate = recv_counter_ / delta.count();
+ LOG(INFO) << "rate: " << rate << " packets/s";
+ io_service_.stop();
+ }
+ } else {
+ FAIL() << "Slave should not receive packets";
+ }
+ }
+ void onPacketSent(Connector *c, const std::error_code &ec) {}
+ void onClose(Connector *c) {}
+ void onReconnect(Connector *c, const std::error_code &ec) {}
+
+ private:
+ asio::io_service &io_service_;
+ std::shared_ptr<MemifConnector> memif_connector_;
+ std::size_t recv_counter_;
+ std::size_t sent_counter_;
+ utils::SteadyTime::TimePoint t0_;
+};
+
+using MemifMaster = Memif<1>;
+using MemifSlave = Memif<0>;
+
+} // namespace
+
+class MemifTest : public ::testing::Test {
+ protected:
+ MemifTest() : io_service_(), master_(io_service_), slave_(io_service_) {
+ // You can do set-up work for each test here.
+ }
+
+ void run() {
+ asio::post(io_service_, std::bind(&MemifSlave::startTest, &slave_));
+ master_.startTest();
+ io_service_.run();
+
+ EXPECT_THAT(master_.getRecvCounter(),
+ ::testing::Eq(slave_.getSentCounter()));
+ }
+
+ virtual ~MemifTest() {
+ // 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).
+ }
+
+ protected:
+ asio::io_service io_service_;
+ MemifMaster master_;
+ MemifSlave slave_;
+};
+
+TEST_F(MemifTest, Test) { run(); }
+} // namespace core
+} // namespace transport
diff --git a/libtransport/src/test/test_packet.cc b/libtransport/src/test/test_packet.cc
index 76ad352d6..ca20cdfb7 100644
--- a/libtransport/src/test/test_packet.cc
+++ b/libtransport/src/test/test_packet.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -16,6 +16,7 @@
#include <gtest/gtest.h>
#include <hicn/transport/core/packet.h>
#include <hicn/transport/errors/not_implemented_exception.h>
+#include <hicn/transport/utils/chrono_typedefs.h>
#include <test/packet_samples.h>
#include <climits>
@@ -33,7 +34,7 @@ namespace core {
class PacketForTest : public Packet {
public:
template <typename... Args>
- PacketForTest(Args &&... args) : Packet(std::forward<Args>(args)...) {}
+ PacketForTest(Args &&...args) : Packet(std::forward<Args>(args)...) {}
virtual ~PacketForTest() {}
@@ -302,7 +303,7 @@ TEST_F(PacketTest, ConstructorWithNew) {
auto &_packet = raw_packets_[HF_INET6_TCP];
auto packet_ptr = new PacketForTest(Packet::WRAP_BUFFER, &_packet[0],
_packet.size(), _packet.size());
- (void)packet_ptr;
+ delete packet_ptr;
}
TEST_F(PacketTest, ConstructorWithRawBufferInet6Tcp) {
@@ -682,9 +683,7 @@ TEST_F(PacketTest, SetGetTestSignatureTimestamp) {
// Let's try to set the signature timestamp in a packet without AH header. We
// expect an exception.
using namespace std::chrono;
- uint64_t now =
- duration_cast<milliseconds>(system_clock::now().time_since_epoch())
- .count();
+ uint64_t now = utils::SteadyTime::nowMs().count();
try {
packet.setSignatureTimestamp(now);
diff --git a/libtransport/src/test/test_packet_allocator.cc b/libtransport/src/test/test_packet_allocator.cc
new file mode 100644
index 000000000..b63ddde8d
--- /dev/null
+++ b/libtransport/src/test/test_packet_allocator.cc
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <glog/logging.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hicn/transport/core/content_object.h>
+#include <hicn/transport/core/interest.h>
+#define ALLOCATION_CHECKS
+#include <hicn/transport/core/global_object_pool.h>
+#undef ALLOCATION_CHECKS
+#include <hicn/transport/utils/event_thread.h>
+
+namespace transport {
+namespace core {
+
+class PacketAllocatorTest : public ::testing::Test {
+ protected:
+ static inline const std::size_t default_size = 2048;
+ static inline const std::size_t default_n_buffer = 1024;
+
+ // Get fixed block allocator_ of 1024 buffers of size 2048 bytes
+ PacketAllocatorTest() : allocator_(PacketManager<>::getInstance()) {
+ // You can do set-up work for each test here.
+ }
+
+ virtual ~PacketAllocatorTest() {
+ // 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() {}
+
+ virtual void TearDown() {}
+
+ static bool pointerIsAligned(const void *pointer, size_t byte_count) {
+ return uintptr_t(pointer) % byte_count == 0;
+ }
+
+ template <typename T, typename... Args>
+ void allocationTest(Args &&...args) {
+ // Create packet
+ auto packet = allocator_.getPacket<T>(std::forward<Args>(args)...);
+
+ // Check boundaries
+ LOG(INFO) << "packet size: " << sizeof(*packet) + sizeof(packet)
+ << std::endl;
+ EXPECT_LE(sizeof(*packet) + sizeof(packet) + sizeof(std::max_align_t),
+ sizeof(PacketManager<>::PacketStorage::packet_and_shared_ptr));
+ }
+
+ PacketManager<> &allocator_;
+};
+
+TEST_F(PacketAllocatorTest, ContentObjectAllocation) {
+ allocationTest<core::ContentObject>(HF_INET_TCP);
+}
+
+TEST_F(PacketAllocatorTest, InterestAllocation) {
+ allocationTest<core::Interest>(HF_INET_TCP);
+}
+
+// TEST_F(PacketAllocatorTest, MemBufAllocation) {
+// allocationTest<::utils::MemBuf>();
+// }
+
+TEST_F(PacketAllocatorTest, CheckAllocationIsCorrect) {
+ // Create packet
+ auto packet = allocator_.getPacket<core::ContentObject>(HF_INET_TCP);
+
+ // Address of actual buffer
+ uint8_t *buffer_address = packet->writableData();
+
+ // Address of packet
+ uint8_t *packet_address = reinterpret_cast<uint8_t *>(packet.get());
+
+ uint8_t *start_address =
+ buffer_address -
+ sizeof(PacketManager<>::PacketStorage::packet_and_shared_ptr);
+
+ // Check memory was allocated on correct positions
+ EXPECT_TRUE(pointerIsAligned(start_address, alignof(std::max_align_t)));
+ EXPECT_TRUE(packet_address > start_address &&
+ packet_address < buffer_address);
+ EXPECT_TRUE(pointerIsAligned(buffer_address, alignof(std::max_align_t)));
+ EXPECT_THAT(std::size_t(buffer_address - start_address),
+ testing::Eq(sizeof(
+ PacketManager<>::PacketStorage::packet_and_shared_ptr)));
+}
+
+} // namespace core
+} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/test/test_quality_score.cc b/libtransport/src/test/test_quality_score.cc
new file mode 100644
index 000000000..9513c94a6
--- /dev/null
+++ b/libtransport/src/test/test_quality_score.cc
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <gtest/gtest.h>
+#include <hicn/transport/utils/rtc_quality_score.h>
+
+#include <climits>
+#include <random>
+#include <vector>
+
+namespace transport {
+
+namespace protocol {
+
+namespace rtc {
+
+TEST(QualityScoreTest, testQS) {
+ RTCQualityScore qs;
+ uint8_t score;
+
+ // 0 losses
+ score = qs.getQualityScore(0, 0);
+ EXPECT_EQ(score, (uint8_t)5);
+
+ score = qs.getQualityScore(98, 0);
+ EXPECT_EQ(score, (uint8_t)5);
+
+ score = qs.getQualityScore(188, 0);
+ EXPECT_EQ(score, (uint8_t)5);
+
+ score = qs.getQualityScore(398, 0);
+ EXPECT_EQ(score, (uint8_t)4);
+
+ score = qs.getQualityScore(400, 0);
+ EXPECT_EQ(score, (uint8_t)3);
+
+ score = qs.getQualityScore(598, 0);
+ EXPECT_EQ(score, (uint8_t)3);
+
+ score = qs.getQualityScore(600, 0);
+ EXPECT_EQ(score, (uint8_t)1);
+
+ score = qs.getQualityScore(700, 0);
+ EXPECT_EQ(score, (uint8_t)1);
+
+ score = qs.getQualityScore(50000, 0);
+ EXPECT_EQ(score, (uint8_t)1);
+
+ // 0 delay
+ score = qs.getQualityScore(0, 2);
+ EXPECT_EQ(score, (uint8_t)5);
+
+ score = qs.getQualityScore(0, 9);
+ EXPECT_EQ(score, (uint8_t)5);
+
+ score = qs.getQualityScore(0, 29);
+ EXPECT_EQ(score, (uint8_t)5);
+
+ score = qs.getQualityScore(0, 30);
+ EXPECT_EQ(score, (uint8_t)4);
+
+ score = qs.getQualityScore(0, 39);
+ EXPECT_EQ(score, (uint8_t)4);
+
+ score = qs.getQualityScore(0, 40);
+ EXPECT_EQ(score, (uint8_t)3);
+
+ score = qs.getQualityScore(0, 50);
+ EXPECT_EQ(score, (uint8_t)1);
+
+ score = qs.getQualityScore(0, 5000);
+ EXPECT_EQ(score, (uint8_t)1);
+
+ // loss < 10
+ score = qs.getQualityScore(0, 3);
+ EXPECT_EQ(score, (uint8_t)5);
+
+ score = qs.getQualityScore(98, 9);
+ EXPECT_EQ(score, (uint8_t)4);
+
+ score = qs.getQualityScore(100, 9);
+ EXPECT_EQ(score, (uint8_t)3);
+
+ score = qs.getQualityScore(398, 5);
+ EXPECT_EQ(score, (uint8_t)2);
+
+ score = qs.getQualityScore(400, 5);
+ EXPECT_EQ(score, (uint8_t)1);
+
+ score = qs.getQualityScore(4000, 5);
+ EXPECT_EQ(score, (uint8_t)1);
+
+ // loss < 20
+ score = qs.getQualityScore(0, 10);
+ EXPECT_EQ(score, (uint8_t)5);
+
+ score = qs.getQualityScore(30, 10);
+ EXPECT_EQ(score, (uint8_t)3);
+
+ score = qs.getQualityScore(198, 15);
+ EXPECT_EQ(score, (uint8_t)2);
+
+ score = qs.getQualityScore(200, 19);
+ EXPECT_EQ(score, (uint8_t)1);
+
+ score = qs.getQualityScore(300, 10);
+ EXPECT_EQ(score, (uint8_t)1);
+
+ // loss < 30
+
+ score = qs.getQualityScore(0, 29);
+ EXPECT_EQ(score, (uint8_t)5);
+
+ score = qs.getQualityScore(10, 29);
+ EXPECT_EQ(score, (uint8_t)2);
+
+ score = qs.getQualityScore(0, 100);
+ EXPECT_EQ(score, (uint8_t)1);
+}
+
+} // namespace rtc
+} // namespace protocol
+} // namespace transport
diff --git a/libtransport/src/test/test_sessions.cc b/libtransport/src/test/test_sessions.cc
new file mode 100644
index 000000000..d2e8c27bb
--- /dev/null
+++ b/libtransport/src/test/test_sessions.cc
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hicn/transport/interfaces/global_conf_interface.h>
+#include <hicn/transport/interfaces/socket_consumer.h>
+#include <hicn/transport/interfaces/socket_options_keys.h>
+#include <hicn/transport/interfaces/socket_producer.h>
+
+namespace transport {
+namespace interface {
+
+class SessionsTest : public ::testing::Test {
+ protected:
+ static inline const std::size_t default_size = 2048;
+ static inline const std::size_t default_n_buffer = 1024;
+
+ // Get fixed block allocator_ of 1024 buffers of size 2048 bytes
+ SessionsTest() {
+ // You can do set-up work for each test here.
+ // Set io_module to local forwarder with no external connections
+ global_config::IoModuleConfiguration config;
+ config.name = "forwarder_module";
+ config.set();
+ }
+
+ virtual ~SessionsTest() {
+ // 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).
+ }
+
+ std::vector<ConsumerSocket> consumers_;
+ std::vector<ProducerSocket> producers_;
+};
+
+TEST_F(SessionsTest, SessionAllocations) {
+ // Create 1000 consumer sockets and 1000 producer sockets
+ int cprotocol = TransportProtocolAlgorithms::RAAQM;
+ int pprotocol = ProductionProtocolAlgorithms::BYTE_STREAM;
+ int offset = 0;
+
+ for (int i = 0; i < 1000; i++) {
+ auto &c = consumers_.emplace_back(cprotocol + (offset % 3));
+ auto &p = producers_.emplace_back(pprotocol + (offset % 2));
+ c.connect();
+ p.connect();
+ offset++;
+ }
+}
+
+} // namespace interface
+} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/test/test_thread_pool.cc b/libtransport/src/test/test_thread_pool.cc
new file mode 100644
index 000000000..1b6b4cc81
--- /dev/null
+++ b/libtransport/src/test/test_thread_pool.cc
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hicn/transport/utils/thread_pool.h>
+
+namespace utils {
+
+class ThreadPoolTest : public ::testing::Test {
+ protected:
+ ThreadPoolTest() : thread_pool_() {
+ // You can do set-up work for each test here.
+ }
+
+ virtual ~ThreadPoolTest() {
+ // 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).
+ }
+
+ ::utils::ThreadPool thread_pool_;
+};
+
+TEST_F(ThreadPoolTest, DefaultConstructor) {
+ // EXPECT_EQ(thread_pool_.GetNumThreads(), 0);
+ // EXPECT_EQ(thread_pool_.GetNumIdleThreads(), 0);
+ // EXPECT_EQ(thread_pool_.GetNumBusyThreads(), 0);
+}
+
+TEST_F(ThreadPoolTest, GetNThreads) {
+ auto n_threads = thread_pool_.getNThreads();
+ EXPECT_GT(n_threads, std::size_t(0));
+ EXPECT_EQ(n_threads, std::thread::hardware_concurrency());
+
+ ::utils::ThreadPool pool(64);
+ n_threads = pool.getNThreads();
+ EXPECT_GT(n_threads, std::size_t(0));
+ EXPECT_NE(n_threads, std::thread::hardware_concurrency());
+ EXPECT_EQ(n_threads, std::size_t(64));
+
+ // EXPECT_EQ(thread_pool_.GetNumThreads(), 0);
+ // EXPECT_EQ(thread_pool_.GetNumIdleThreads(), 0);
+ // EXPECT_EQ(thread_pool_.GetNumBusyThreads(), 0);
+}
+
+} // namespace utils \ No newline at end of file
diff --git a/libtransport/src/transport.config b/libtransport/src/transport.config
index 89db204d5..d5c2918a6 100644
--- a/libtransport/src/transport.config
+++ b/libtransport/src/transport.config
@@ -17,7 +17,7 @@ forwarder = {
remote_port = 33436;
}
};
-
+
listeners = {
l0 = {
local_address = "127.0.0.1";
diff --git a/libtransport/src/utils/CMakeLists.txt b/libtransport/src/utils/CMakeLists.txt
index a85ab16bf..5bb76303a 100644
--- a/libtransport/src/utils/CMakeLists.txt
+++ b/libtransport/src/utils/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2019 Cisco and/or its affiliates.
+# Copyright (c) 2021 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
@@ -23,6 +23,7 @@ list(APPEND SOURCE_FILES
list(APPEND HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/event_reactor.h
${CMAKE_CURRENT_SOURCE_DIR}/min_filter.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/max_filter.h
${CMAKE_CURRENT_SOURCE_DIR}/stream_buffer.h
${CMAKE_CURRENT_SOURCE_DIR}/suffix_strategy.h
${CMAKE_CURRENT_SOURCE_DIR}/content_store.h
@@ -34,10 +35,6 @@ if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
${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)
diff --git a/libtransport/src/utils/content_store.cc b/libtransport/src/utils/content_store.cc
index 8ae7fd4d4..d9d4147f7 100644
--- a/libtransport/src/utils/content_store.cc
+++ b/libtransport/src/utils/content_store.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -17,6 +17,7 @@
#include <hicn/transport/core/content_object.h>
#include <hicn/transport/core/interest.h>
#include <hicn/transport/core/name.h>
+#include <hicn/transport/utils/chrono_typedefs.h>
#include <utils/content_store.h>
namespace utils {
@@ -56,7 +57,7 @@ void ContentStore::insert(
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);
+ ObjectTimeEntry(content_object, utils::SteadyTime::now()), pos);
}
std::shared_ptr<ContentObject> ContentStore::find(const Name &name) {
@@ -67,8 +68,8 @@ std::shared_ptr<ContentObject> ContentStore::find(const Name &name) {
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::milliseconds>(
- std::chrono::steady_clock::now() - it->second.first.second)
+ utils::SteadyTime::getDurationMs(it->second.first.second,
+ utils::SteadyTime::now())
.count();
if (time_passed_since_creation > content_lifetime) {
diff --git a/libtransport/src/utils/content_store.h b/libtransport/src/utils/content_store.h
index abe5e7f6c..ecd62cc2c 100644
--- a/libtransport/src/utils/content_store.h
+++ b/libtransport/src/utils/content_store.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -35,8 +35,7 @@ using Name = transport::core::Name;
using ContentObject = transport::core::ContentObject;
using Interest = transport::core::Interest;
-typedef std::pair<std::shared_ptr<ContentObject>,
- std::chrono::steady_clock::time_point>
+typedef std::pair<std::shared_ptr<ContentObject>, utils::SteadyTime::TimePoint>
ObjectTimeEntry;
typedef std::pair<ObjectTimeEntry,
std::list<std::reference_wrapper<const Name>>::iterator>
diff --git a/libtransport/src/utils/daemonizator.cc b/libtransport/src/utils/daemonizator.cc
index 6cb7d16ba..4c17aa96b 100644
--- a/libtransport/src/utils/daemonizator.cc
+++ b/libtransport/src/utils/daemonizator.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/utils/deadline_timer.h b/libtransport/src/utils/deadline_timer.h
index 5187754f0..6c105ed3d 100644
--- a/libtransport/src/utils/deadline_timer.h
+++ b/libtransport/src/utils/deadline_timer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -22,61 +22,6 @@
#include <cstring>
#include <utility>
-namespace std {
-namespace chrono {
-namespace detail {
-
-template <typename From, typename To>
-struct posix_duration_cast;
-
-// chrono -> timespec caster
-template <typename Rep, typename Period>
-struct posix_duration_cast<std::chrono::duration<Rep, Period>,
- struct timespec> {
- static struct timespec cast(std::chrono::duration<Rep, Period> const &d) {
- struct timespec tv;
-
- std::chrono::seconds const sec =
- std::chrono::duration_cast<std::chrono::seconds>(d);
-
- tv.tv_sec = sec.count();
- tv.tv_nsec =
- std::chrono::duration_cast<std::chrono::nanoseconds>(d - sec).count();
-
- return tv;
- }
-};
-
-// timespec -> chrono caster
-template <typename Rep, typename Period>
-struct posix_duration_cast<struct timespec,
- std::chrono::duration<Rep, Period>> {
- static std::chrono::duration<Rep, Period> cast(struct timespec const &tv) {
- return std::chrono::duration_cast<std::chrono::duration<Rep, Period>>(
- std::chrono::seconds(tv.tv_sec) + std::chrono::nanoseconds(tv.tv_nsec));
- }
-};
-
-} // namespace detail
-
-// chrono -> timespec
-template <typename T, typename Rep, typename Period>
-auto duration_cast(std::chrono::duration<Rep, Period> const &d) ->
- typename std::enable_if<std::is_same<T, struct timespec>::value,
- struct timespec>::type {
- return detail::posix_duration_cast<std::chrono::duration<Rep, Period>,
- timespec>::cast(d);
-}
-
-// timespec -> chrono
-template <typename Duration>
-Duration duration_cast(struct timespec const &tv) {
- return detail::posix_duration_cast<struct timespec, Duration>::cast(tv);
-}
-
-} // namespace chrono
-} // namespace std
-
namespace utils {
template <typename Implementation>
diff --git a/libtransport/src/utils/epoll_event_reactor.cc b/libtransport/src/utils/epoll_event_reactor.cc
deleted file mode 100644
index 457727bbe..000000000
--- a/libtransport/src/utils/epoll_event_reactor.cc
+++ /dev/null
@@ -1,190 +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 <glog/logging.h>
-#include <hicn/transport/utils/branch_prediction.h>
-#include <signal.h>
-#include <unistd.h>
-#include <utils/epoll_event_reactor.h>
-#include <utils/fd_deadline_timer.h>
-
-#include <iostream>
-
-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)) {
- LOG(ERROR) << "invalid fd " << 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)) {
- LOG(ERROR) << "epoll_ctl: " << strerror(errno) << " fd " << fd;
- return -1;
- }
-
- return 0;
-}
-
-int EpollEventReactor::modFileDescriptor(int fd, uint32_t events) {
- if (TRANSPORT_EXPECT_FALSE(fd < 0)) {
- LOG(ERROR) << "invalid fd " << 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)) {
- LOG(ERROR) << "epoll_ctl: " << strerror(errno) << " fd " << 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)) {
- LOG(ERROR) << "invalid fd " << 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)) {
- LOG(ERROR) << "epoll_ctl: " << strerror(errno) << " fd " << 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)) {
- LOG(ERROR) << "epoll_pwait: " << strerror(errno);
- if (errno == EINTR) {
- continue;
- } else {
- 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())) {
- LOG(ERROR) << "unexpected event. fd " << 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 {
- LOG(ERROR) << "unexpected event. fd " << 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)) {
- LOG(ERROR) << "epoll_pwait: " << 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())) {
- LOG(ERROR) << "unexpected event. fd " << evt.data.fd;
- } else {
- {
- utils::SpinLock::Acquire locked(event_callback_map_lock_);
- callback = event_callback_map_[evt.data.fd];
- }
-
- callback(evt);
- }
- } else {
- LOG(ERROR) << "unexpected event. fd " << 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
index 9ebfca937..8e7681c20 100644
--- a/libtransport/src/utils/epoll_event_reactor.h
+++ b/libtransport/src/utils/epoll_event_reactor.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -15,6 +15,7 @@
#pragma once
+#include <glog/logging.h>
#include <hicn/transport/utils/spinlock.h>
#include <sys/epoll.h>
#include <utils/event_reactor.h>
@@ -35,9 +36,10 @@ typedef std::unordered_map<int, EventCallback> EventCallbackMap;
class EpollEventReactor : public EventReactor {
public:
- explicit EpollEventReactor();
+ explicit EpollEventReactor()
+ : epoll_fd_(epoll_create(20000)), run_event_loop_(true) {}
- ~EpollEventReactor();
+ ~EpollEventReactor() { close(epoll_fd_); }
template <typename EventHandler>
int addFileDescriptor(int fd, uint32_t events, EventHandler &&callback) {
@@ -56,20 +58,163 @@ class EpollEventReactor : public EventReactor {
return ret;
}
- int delFileDescriptor(int fd);
+ int delFileDescriptor(int fd) {
+ if (TRANSPORT_EXPECT_FALSE(fd < 0)) {
+ LOG(ERROR) << "invalid fd " << 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)) {
+ return -1;
+ }
+
+ utils::SpinLock::Acquire locked(event_callback_map_lock_);
+ event_callback_map_.erase(fd);
+
+ return 0;
+ }
+
+ int modFileDescriptor(int fd, uint32_t events) {
+ if (TRANSPORT_EXPECT_FALSE(fd < 0)) {
+ LOG(ERROR) << "invalid fd " << 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)) {
+ LOG(ERROR) << "epoll_ctl: " << strerror(errno) << " fd " << fd;
+ return -1;
+ }
+
+ return 0;
+ }
+
+ void runEventLoop(int timeout = -1) override {
+ 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)) {
+ LOG(ERROR) << "epoll_pwait: " << strerror(errno);
+ if (errno == EINTR) {
+ continue;
+ } else {
+ 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())) {
+ LOG(ERROR) << "unexpected event. fd " << 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 {
+ LOG(ERROR) << "unexpected event. fd " << evt[i].data.fd;
+ }
+ }
+ }
+ }
+
+ void runOneEvent() override {
+ Event evt;
+ int en = 0;
+ EventCallbackMap::iterator it;
+ EventCallback callback;
- int modFileDescriptor(int fd, uint32_t events);
+ // evt.events = EPOLLIN | EPOLLOUT;
+ sigset_t sigset;
+ sigemptyset(&sigset);
- void runEventLoop(int timeout = -1) override;
+ memset(&evt, 0, sizeof(evt));
- void runOneEvent() override;
+ en = epoll_pwait(epoll_fd_, &evt, 1, -1, &sigset);
- void stop() override;
+ if (TRANSPORT_EXPECT_FALSE(en < 0)) {
+ LOG(ERROR) << "epoll_pwait: " << 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);
+ }
- std::size_t mapSize();
+ if (TRANSPORT_EXPECT_FALSE(it == event_callback_map_.end())) {
+ LOG(ERROR) << "unexpected event. fd " << evt.data.fd;
+ } else {
+ {
+ utils::SpinLock::Acquire locked(event_callback_map_lock_);
+ callback = event_callback_map_[evt.data.fd];
+ }
+
+ callback(evt);
+ }
+ } else {
+ LOG(ERROR) << "unexpected event. fd " << evt.data.fd;
+ }
+ }
+
+ void stop() override { run_event_loop_ = false; }
+
+ std::size_t mapSize() { return event_callback_map_.size(); }
private:
- int addFileDescriptor(int fd, uint32_t events);
+ int addFileDescriptor(int fd, uint32_t events) {
+ if (TRANSPORT_EXPECT_FALSE(fd < 0)) {
+ LOG(ERROR) << "invalid fd " << 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)) {
+ LOG(ERROR) << "epoll_ctl: " << strerror(errno) << " fd " << fd;
+ return -1;
+ }
+
+ return 0;
+ }
int epoll_fd_;
std::atomic_bool run_event_loop_;
diff --git a/libtransport/src/utils/event_reactor.h b/libtransport/src/utils/event_reactor.h
index 4f8b58296..09af6f84c 100644
--- a/libtransport/src/utils/event_reactor.h
+++ b/libtransport/src/utils/event_reactor.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/utils/fd_deadline_timer.h b/libtransport/src/utils/fd_deadline_timer.h
index 22c13a763..e15cd4d2a 100644
--- a/libtransport/src/utils/fd_deadline_timer.h
+++ b/libtransport/src/utils/fd_deadline_timer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -16,6 +16,7 @@
#pragma once
#include <hicn/transport/errors/runtime_exception.h>
+#include <hicn/transport/utils/chrono_typedefs.h>
#include <sys/timerfd.h>
#include <unistd.h>
#include <utils/deadline_timer.h>
@@ -37,6 +38,11 @@ class FdDeadlineTimer : public DeadlineTimer<FdDeadlineTimer> {
}
}
+ FdDeadlineTimer(const FdDeadlineTimer &other)
+ : reactor_(other.reactor_),
+ timer_fd_(other.timer_fd_),
+ flags_(other.flags_) {}
+
~FdDeadlineTimer() { close(timer_fd_); }
template <typename WaitHandler>
diff --git a/libtransport/src/utils/log.cc b/libtransport/src/utils/log.cc
index 755d5bafa..44acf4595 100644
--- a/libtransport/src/utils/log.cc
+++ b/libtransport/src/utils/log.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2021 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -36,7 +36,7 @@ foreach_log_level
static constexpr char log_config_section[] = "log";
#define LOG_NAME \
"Libhicntransport-" HICNTRANSPORT_VERSION_MAJOR \
- "." HICNTRANSPORT_VERSION_MINOR "." HICNTRANSPORT_VERSION_REVISION
+ "." HICNTRANSPORT_VERSION_MINOR "." HICNTRANSPORT_VERSION_PATCH
static constexpr char log_name[] = LOG_NAME;
#define foreach_log_config \
diff --git a/libtransport/src/utils/max_filter.h b/libtransport/src/utils/max_filter.h
new file mode 100644
index 000000000..7a2c6aace
--- /dev/null
+++ b/libtransport/src/utils/max_filter.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <deque>
+#include <iostream>
+#include <set>
+#include <type_traits>
+#include <vector>
+
+namespace utils {
+
+template <typename T>
+class MaxFilter {
+ public:
+ MaxFilter(std::size_t size) : size_(size) {}
+
+ std::size_t size() { return by_arrival_.size(); }
+
+ template <typename R>
+ 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<R>(value)));
+ }
+
+ void clear() {
+ by_arrival_.clear();
+ by_order_.clear();
+ }
+
+ const T& begin() { return *by_order_.crbegin(); }
+
+ const T& rBegin() { return *by_order_.rbegin(); }
+
+ private:
+ std::multiset<T> by_order_;
+ std::deque<typename std::multiset<T>::const_iterator> by_arrival_;
+ std::size_t size_;
+};
+
+} // namespace utils
diff --git a/libtransport/src/utils/membuf.cc b/libtransport/src/utils/membuf.cc
index 73c45cf6d..952116bb7 100644
--- a/libtransport/src/utils/membuf.cc
+++ b/libtransport/src/utils/membuf.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 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.
@@ -22,6 +22,7 @@
#include <hicn/transport/portability/win_portability.h>
#endif
+#include <glog/logging.h>
#include <hicn/transport/utils/membuf.h>
#include <cassert>
@@ -209,7 +210,7 @@ MemBuf::MemBuf(CopyBufferOp /* op */, const void* buf, std::size_t size,
: MemBuf(CREATE, headroom + size + min_tailroom) {
advance(headroom);
if (size > 0) {
- assert(buf != nullptr);
+ DCHECK(buf != nullptr);
memcpy(writableData(), buf, size);
append(size);
}
@@ -369,8 +370,8 @@ MemBuf::MemBuf(InternalConstructor, uintptr_t flagsAndSharedInfo, uint8_t* buf,
length_(length),
capacity_(capacity),
flags_and_shared_info_(flagsAndSharedInfo) {
- assert(data >= buf);
- assert(data + length <= buf + capacity);
+ DCHECK(data >= buf);
+ DCHECK(data + length <= buf + capacity);
}
MemBuf::~MemBuf() {
@@ -559,7 +560,7 @@ void MemBuf::unshareOneSlow() {
// minimum capacity we also maintain at least the same amount of tailroom.
std::size_t headlen = headroom();
if (length_ > 0) {
- assert(data_ != nullptr);
+ DCHECK(data_ != nullptr);
memcpy(buf + headlen, data_, length_);
}
@@ -576,7 +577,7 @@ void MemBuf::unshareOneSlow() {
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());
+ DCHECK(isChained());
MemBuf* current = this;
while (true) {
@@ -606,7 +607,7 @@ void MemBuf::markExternallyShared() {
}
void MemBuf::makeManagedChained() {
- assert(isChained());
+ DCHECK(isChained());
MemBuf* current = this;
while (true) {
@@ -677,15 +678,15 @@ void MemBuf::coalesceAndReallocate(size_t new_headroom, size_t new_length,
size_t remaining = new_length;
do {
if (current->length_ > 0) {
- assert(current->length_ <= remaining);
- assert(current->data_ != nullptr);
+ DCHECK(current->length_ <= remaining);
+ DCHECK(current->data_ != nullptr);
remaining -= current->length_;
memcpy(p, current->data_, current->length_);
p += current->length_;
}
current = current->next_;
} while (current != end);
- assert(remaining == 0);
+ DCHECK(remaining == 0);
// Point at the new buffer
decrementRefcount();
@@ -799,7 +800,7 @@ void MemBuf::reserveSlow(std::size_t min_headroom, std::size_t min_tailroom) {
new_allocated_capacity = goodExtBufferSize(new_capacity);
new_buffer = static_cast<uint8_t*>(malloc(new_allocated_capacity));
if (length_ > 0) {
- assert(data_ != nullptr);
+ DCHECK(data_ != nullptr);
memcpy(new_buffer + min_headroom, data_, length_);
}
if (sharedInfo()) {
diff --git a/libtransport/src/utils/memory_pool_allocator.h b/libtransport/src/utils/memory_pool_allocator.h
index a960b91bb..c2b34e7aa 100644
--- a/libtransport/src/utils/memory_pool_allocator.h
+++ b/libtransport/src/utils/memory_pool_allocator.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/utils/min_filter.h b/libtransport/src/utils/min_filter.h
index 092555ce0..4c7ae81f1 100644
--- a/libtransport/src/utils/min_filter.h
+++ b/libtransport/src/utils/min_filter.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/utils/stream_buffer.h b/libtransport/src/utils/stream_buffer.h
index adfb696f2..dde769a55 100644
--- a/libtransport/src/utils/stream_buffer.h
+++ b/libtransport/src/utils/stream_buffer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/utils/string_tokenizer.cc b/libtransport/src/utils/string_tokenizer.cc
index a280a3c43..cb0a4a3ad 100644
--- a/libtransport/src/utils/string_tokenizer.cc
+++ b/libtransport/src/utils/string_tokenizer.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/utils/suffix_strategy.h b/libtransport/src/utils/suffix_strategy.h
index ee016308e..96eaed662 100644
--- a/libtransport/src/utils/suffix_strategy.h
+++ b/libtransport/src/utils/suffix_strategy.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -15,72 +15,88 @@
#pragma once
-#include <core/manifest_format.h>
+#include <hicn/transport/core/name.h>
+#include <hicn/transport/errors/runtime_exception.h>
namespace utils {
-using transport::core::NextSegmentCalculationStrategy;
+/**
+ * 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 NextSuffixStrategy : uint8_t {
+ INCREMENTAL = 1,
+};
class SuffixStrategy {
public:
- static constexpr uint32_t INVALID_SUFFIX =
- std::numeric_limits<uint32_t>::max();
+ static constexpr uint32_t MAX_SUFFIX = std::numeric_limits<uint32_t>::max();
+ static constexpr uint8_t MAX_MANIFEST_CAPACITY =
+ std::numeric_limits<uint8_t>::max();
- SuffixStrategy(NextSegmentCalculationStrategy strategy)
+ SuffixStrategy(NextSuffixStrategy strategy, uint32_t offset = 0,
+ uint32_t manifest_capacity = MAX_MANIFEST_CAPACITY)
: suffix_stragegy_(strategy),
+ next_suffix_(offset),
+ manifest_capacity_(manifest_capacity),
total_count_(0),
- final_suffix_(INVALID_SUFFIX) {}
+ final_suffix_(MAX_SUFFIX) {}
virtual ~SuffixStrategy() = default;
- virtual uint32_t checkNextSuffix() = 0;
-
+ virtual uint32_t checkNextSuffix() const = 0;
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 checkNextManifestSuffix() = 0;
-
+ virtual uint32_t checkNextManifestSuffix() const = 0;
virtual uint32_t getNextManifestSuffix() = 0;
- virtual uint32_t checkNextContentSuffix() = 0;
-
+ virtual uint32_t checkNextContentSuffix() const = 0;
virtual uint32_t getNextContentSuffix() = 0;
- virtual void reset(uint32_t offset = 0) = 0;
+ virtual void reset(uint32_t offset = 0) {
+ next_suffix_ = offset;
+ total_count_ = 0;
+ }
- virtual uint32_t getManifestCapacity() = 0;
+ virtual uint32_t getManifestCapacity() const { return manifest_capacity_; };
- virtual void setManifestCapacity(uint32_t capacity) = 0;
+ virtual void setManifestCapacity(uint8_t capacity) {
+ manifest_capacity_ = capacity;
+ }
- virtual uint32_t getTotalCount() { return total_count_; };
+ virtual uint32_t getFinalSuffix() const { return final_suffix_; }
- NextSegmentCalculationStrategy getSuffixStrategy() {
- return suffix_stragegy_;
+ virtual void setFinalSuffix(std::uint32_t final_suffix) {
+ if (final_suffix != MAX_SUFFIX) {
+ final_suffix_ = final_suffix;
+ }
}
- protected:
- inline void incrementTotalCount() { total_count_++; };
+ NextSuffixStrategy getSuffixStrategy() const { return suffix_stragegy_; }
+
+ virtual uint32_t getTotalCount() const { return total_count_; }
protected:
- NextSegmentCalculationStrategy suffix_stragegy_;
+ NextSuffixStrategy suffix_stragegy_;
+ std::uint32_t next_suffix_;
+ std::uint8_t manifest_capacity_;
std::uint32_t total_count_;
std::uint32_t final_suffix_;
+
+ inline void incrementTotalCount() { total_count_++; };
};
class IncrementalSuffixStrategy : public SuffixStrategy {
public:
IncrementalSuffixStrategy(std::uint32_t start_offset)
- : SuffixStrategy(NextSegmentCalculationStrategy::INCREMENTAL),
- next_suffix_(start_offset) {}
+ : SuffixStrategy(NextSuffixStrategy::INCREMENTAL, start_offset) {}
- TRANSPORT_ALWAYS_INLINE std::uint32_t checkNextSuffix() override {
+ TRANSPORT_ALWAYS_INLINE std::uint32_t checkNextSuffix() const override {
return next_suffix_;
}
@@ -89,7 +105,8 @@ class IncrementalSuffixStrategy : public SuffixStrategy {
return next_suffix_++;
}
- TRANSPORT_ALWAYS_INLINE std::uint32_t checkNextContentSuffix() override {
+ TRANSPORT_ALWAYS_INLINE std::uint32_t checkNextContentSuffix()
+ const override {
return checkNextSuffix();
}
@@ -97,7 +114,8 @@ class IncrementalSuffixStrategy : public SuffixStrategy {
return getNextSuffix();
}
- TRANSPORT_ALWAYS_INLINE std::uint32_t checkNextManifestSuffix() override {
+ TRANSPORT_ALWAYS_INLINE std::uint32_t checkNextManifestSuffix()
+ const override {
return checkNextSuffix();
}
@@ -105,90 +123,20 @@ class IncrementalSuffixStrategy : public SuffixStrategy {
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 checkNextSuffix() override {
- return next_suffix_;
- }
-
- TRANSPORT_ALWAYS_INLINE std::uint32_t getNextSuffix() override {
- incrementTotalCount();
- return next_suffix_++;
- }
-
- TRANSPORT_ALWAYS_INLINE std::uint32_t checkNextContentSuffix() override {
- return next_suffix_ % segments_in_manifest_ == 0 ? next_suffix_
- : (next_suffix_ + 1);
- }
-
- 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 checkNextManifestSuffix() override {
- return (current_manifest_iteration_ + 1) * (segments_in_manifest_ + 1);
- }
-
- 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<SuffixStrategy> getSuffixStrategy(
- NextSegmentCalculationStrategy strategy, uint32_t start_offset,
- uint32_t manifest_capacity = 0) {
+ NextSuffixStrategy strategy, uint32_t start_offset = 0,
+ uint32_t manifest_capacity = SuffixStrategy::MAX_MANIFEST_CAPACITY) {
switch (strategy) {
- case NextSegmentCalculationStrategy::INCREMENTAL:
+ case NextSuffixStrategy::INCREMENTAL:
return std::make_unique<IncrementalSuffixStrategy>(start_offset);
- case NextSegmentCalculationStrategy::MANIFEST_CAPACITY_BASED:
- return std::make_unique<CapacityBasedSuffixStrategy>(start_offset,
- manifest_capacity);
default:
throw errors::RuntimeException(
- "No valid NextSegmentCalculationStrategy specified.");
+ "No valid NextSuffixStrategy specified.");
}
}
};
diff --git a/libtransport/src/utils/test.h b/libtransport/src/utils/test.h
index e3dd619ac..b91c8cb1f 100644
--- a/libtransport/src/utils/test.h
+++ b/libtransport/src/utils/test.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/src/utils/uri.cc b/libtransport/src/utils/uri.cc
index 33eb8b45b..12b11641c 100644
--- a/libtransport/src/utils/uri.cc
+++ b/libtransport/src/utils/uri.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
diff --git a/libtransport/third-party/CMakeLists.txt b/libtransport/third-party/CMakeLists.txt
index 46a4c0f23..ad7b14ead 100644
--- a/libtransport/third-party/CMakeLists.txt
+++ b/libtransport/third-party/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2021 Cisco and/or its affiliates.
+# Copyright (c) 2021-2022 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
@@ -11,8 +11,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-include(FetchContent)
-
set (THIRD_PARTY_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR})
option(ENABLE_RELY "Enable download/build of rely library" OFF)
@@ -20,21 +18,34 @@ option(ENABLE_RELY "Enable download/build of rely library" OFF)
if (ENABLE_RELY)
##################################
# Download librely
-
- if(DEFINED ENV{BITBUCKET_USERNAME} AND DEFINED ENV{BITBUCKET_PASSWORD})
- set(GIT_REPO https://$ENV{BITBUCKET_USERNAME}:$ENV{BITBUCKET_PASSWORD}@bitbucket-eng-gpk1.cisco.com/bitbucket/scm/icn/rely.git)
+
+ if (INTERNAL_ENVIRONMENT)
+ include(SetRelyGitRepo)
+ SetRelyGitRepo()
else()
- set(GIT_REPO ssh://git@bitbucket-eng-gpk1.cisco.com:7999/icn/rely.git)
+ if(DEFINED ENV{GITHUB_USERNAME} AND DEFINED ENV{GITHUB_PASSWORD})
+ set(GIT_REPO https://$ENV{GITHUB_USERNAME}:$ENV{GITHUB_PASSWORD}@github.com/steinwurf/rely.git)
+ else()
+ set(GIT_REPO ssh://github.com/steinwurf/rely.git)
+ endif()
endif()
FetchContent_Declare(
rely
GIT_REPOSITORY ${GIT_REPO}
GIT_TAG release/latest
+ GIT_SHALLOW
+ GIT_PROGRESS
+ EXCLUDE_FROM_ALL
)
set(ENABLE_PIC ON)
- FetchContent_MakeAvailable(rely)
+ FetchContent_GetProperties(rely)
+ if(NOT rely_POPULATED)
+ pr("Download and build" "rely")
+ FetchContent_Populate(rely)
+ add_subdirectory(${rely_SOURCE_DIR} ${rely_BINARY_DIR} EXCLUDE_FROM_ALL)
+ endif()
list(APPEND THIRD_PARTY_INCLUDE_DIRS
${rely_BINARY_DIR}
@@ -44,7 +55,7 @@ if (ENABLE_RELY)
# Get rely libraries
get_property(steinwurf_object_libraries GLOBAL
PROPERTY steinwurf::object_libraries)
-
+
foreach(rely_library ${steinwurf_object_libraries})
list(APPEND THIRD_PARTY_OBJECT_LIBRARIES
$<TARGET_OBJECTS:${rely_library}>
@@ -60,9 +71,19 @@ FetchContent_Declare(
glog
URL https://github.com/google/glog/archive/refs/tags/v0.5.0.zip
PATCH_COMMAND patch -p1 CMakeLists.txt ${CMAKE_CURRENT_SOURCE_DIR}/glog.patch
+ EXCLUDE_FROM_ALL
)
-FetchContent_MakeAvailable(glog)
+FetchContent_GetProperties(glog)
+if(NOT glog_POPULATED)
+ pr("Download and build" "glog")
+ FetchContent_Populate(glog)
+ option(WITH_GFLAGS OFF)
+ option(WITH_GTEST OFF)
+ option(WITH_UNWIND OFF)
+ option(BUILD_TESTING OFF)
+ add_subdirectory(${glog_SOURCE_DIR} ${glog_BINARY_DIR} EXCLUDE_FROM_ALL)
+endif()
list(APPEND THIRD_PARTY_INCLUDE_DIRS
${glog_BINARY_DIR}
@@ -77,6 +98,42 @@ list(APPEND THIRD_PARTY_DEPENDENCIES
glog
)
+if(UNIX AND (NOT APPLE) AND (NOT ${CMAKE_SYSTEM_NAME} MATCHES Android))
+ ##############################################################
+ # Get memif version
+ ##############################################################
+ list(GET LIBMEMIF_DEFAULT_VERSION 0 MEMIF_VERSION)
+
+ FetchContent_Declare(
+ memif
+ GIT_REPOSITORY https://github.com/FDio/vpp
+ GIT_TAG v${MEMIF_VERSION}
+ GIT_SHALLOW
+ GIT_PROGRESS
+ PATCH_COMMAND git apply ${CMAKE_CURRENT_SOURCE_DIR}/memif.patch
+ EXCLUDE_FROM_ALL
+ )
+
+ FetchContent_GetProperties(memif)
+ if(NOT memif_POPULATED)
+ FetchContent_Populate(memif)
+ add_subdirectory(${memif_SOURCE_DIR}/extras/libmemif ${memif_BINARY_DIR} EXCLUDE_FROM_ALL)
+ endif()
+
+ list(APPEND THIRD_PARTY_INCLUDE_DIRS
+ ${memif_BINARY_DIR}
+ ${memif_SOURCE_DIR}/extras/libmemif/src
+ )
+
+ list(APPEND THIRD_PARTY_OBJECT_LIBRARIES
+ $<TARGET_OBJECTS:memif>
+ )
+
+ list(APPEND THIRD_PARTY_DEPENDENCIES
+ memif
+ )
+endif()
+
set (THIRD_PARTY_LIBRARIES ${THIRD_PARTY_LIBRARIES} PARENT_SCOPE)
set (THIRD_PARTY_OBJECT_LIBRARIES ${THIRD_PARTY_OBJECT_LIBRARIES} PARENT_SCOPE)
set (THIRD_PARTY_INCLUDE_DIRS ${THIRD_PARTY_INCLUDE_DIRS} PARENT_SCOPE)
diff --git a/libtransport/third-party/CMakeLists.txt.orig b/libtransport/third-party/CMakeLists.txt.orig
deleted file mode 100644
index 84db8cb4c..000000000
--- a/libtransport/third-party/CMakeLists.txt.orig
+++ /dev/null
@@ -1,85 +0,0 @@
-# Copyright (c) 2021 Cisco and/or its affiliates.
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at:
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT 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(FetchContent)
-
-set (THIRD_PARTY_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR})
-
-option(ENABLE_RELY "Enable download/build of rely library" OFF)
-
-if (ENABLE_RELY)
- ##################################
- # Download librely
-
- if(DEFINED ENV{BITBUCKET_USERNAME} AND DEFINED ENV{BITBUCKET_PASSWORD})
- set(GIT_REPO https://$ENV{BITBUCKET_USERNAME}:$ENV{BITBUCKET_PASSWORD}@bitbucket-eng-gpk1.cisco.com/bitbucket/scm/icn/rely.git)
- else()
- set(GIT_REPO ssh://git@bitbucket-eng-gpk1.cisco.com:7999/icn/rely.git)
- endif()
-
- FetchContent_Declare(
- rely
- GIT_REPOSITORY ${GIT_REPO}
- GIT_TAG release/latest
- FETCHCONTENT_QUIET
- )
-
- set(ENABLE_PIC ON)
- FetchContent_MakeAvailable(rely)
-
- list(APPEND THIRD_PARTY_INCLUDE_DIRS
- ${rely_BINARY_DIR}
- ${rely_SOURCE_DIR}/src
- )
-
- # Get rely libraries
- get_property(steinwurf_object_libraries GLOBAL
- PROPERTY steinwurf::object_libraries)
-
- foreach(rely_library ${steinwurf_object_libraries})
- list(APPEND THIRD_PARTY_OBJECT_LIBRARIES
- $<TARGET_OBJECTS:${rely_library}>
- )
- endforeach()
-
- list(APPEND THIRD_PARTY_DEPENDENCIES
- rely
- )
-endif()
-
-FetchContent_Declare(
- glog
- URL https://github.com/google/glog/archive/refs/tags/v0.5.0.zip
- PATCH_COMMAND patch -p1 CMakeLists.txt ${CMAKE_CURRENT_SOURCE_DIR}/glog.patch
- FETCHCONTENT_QUIET
-)
-
-FetchContent_MakeAvailable(glog)
-
-list(APPEND THIRD_PARTY_INCLUDE_DIRS
- ${glog_BINARY_DIR}
- ${glog_SOURCE_DIR}/src
-)
-
-list(APPEND THIRD_PARTY_OBJECT_LIBRARIES
- $<TARGET_OBJECTS:glog>
-)
-
-list(APPEND THIRD_PARTY_DEPENDENCIES
- glog
-)
-
-set (THIRD_PARTY_LIBRARIES ${THIRD_PARTY_LIBRARIES} PARENT_SCOPE)
-set (THIRD_PARTY_OBJECT_LIBRARIES ${THIRD_PARTY_OBJECT_LIBRARIES} PARENT_SCOPE)
-set (THIRD_PARTY_INCLUDE_DIRS ${THIRD_PARTY_INCLUDE_DIRS} PARENT_SCOPE)
-set (THIRD_PARTY_DEPENDENCIES ${THIRD_PARTY_DEPENDENCIES} PARENT_SCOPE)
diff --git a/libtransport/third-party/CMakeLists.txt.rej b/libtransport/third-party/CMakeLists.txt.rej
deleted file mode 100644
index 4ebaf9061..000000000
--- a/libtransport/third-party/CMakeLists.txt.rej
+++ /dev/null
@@ -1,21 +0,0 @@
---- CMakeLists.txt
-+++ CMakeLists.txt
-@@ -41,9 +41,6 @@ if (NOT WITH_THREADS)
- set (CMAKE_DISABLE_FIND_PACKAGE_Threads ON)
- endif (NOT WITH_THREADS)
-
--set (CMAKE_C_VISIBILITY_PRESET hidden)
--set (CMAKE_CXX_VISIBILITY_PRESET hidden)
--set (CMAKE_VISIBILITY_INLINES_HIDDEN 1)
- list (APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
-
- include (CheckCXXSourceCompiles)
-@@ -570,7 +567,7 @@ if (_glog_CMake_MODULES)
- )
- endif (_glog_CMake_MODULES)
-
--add_library (glog
-+add_library (glog OBJECT
- ${GLOG_SRCS}
- ${_glog_BINARY_CMake_MODULES}
- )
diff --git a/libtransport/third-party/glog.patch b/libtransport/third-party/glog.patch
index 9d6e46df0..4f4d440eb 100644
--- a/libtransport/third-party/glog.patch
+++ b/libtransport/third-party/glog.patch
@@ -20,4 +20,4 @@ index 62ebbcc..7d92fa5 100644
+add_library (glog OBJECT
${GLOG_SRCS}
${_glog_BINARY_CMake_MODULES}
- )
+ ) \ No newline at end of file
diff --git a/libtransport/third-party/memif.patch b/libtransport/third-party/memif.patch
new file mode 100644
index 000000000..0a64513e3
--- /dev/null
+++ b/libtransport/third-party/memif.patch
@@ -0,0 +1,43 @@
+diff --git a/extras/libmemif/CMakeLists.txt b/extras/libmemif/CMakeLists.txt
+index b6b658c2d..28bb8c135 100644
+--- a/extras/libmemif/CMakeLists.txt
++++ b/extras/libmemif/CMakeLists.txt
+@@ -24,7 +24,7 @@ if (NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE "Release")
+ endif ()
+
+-set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g -DMEMIF_DBG -DICMP_DBG")
++set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g -DICMP_DBG")
+ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
+ set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib)
+ set(CMAKE_INSTALL_MESSAGE NEVER)
+diff --git a/extras/libmemif/src/CMakeLists.txt b/extras/libmemif/src/CMakeLists.txt
+index ddb8a52f8..b52566e5c 100644
+--- a/extras/libmemif/src/CMakeLists.txt
++++ b/extras/libmemif/src/CMakeLists.txt
+@@ -32,22 +32,7 @@ list(APPEND MEMIF_SOURCES
+
+ include_directories(${HEADERS_DIR})
+
+-add_library(memif SHARED ${MEMIF_SOURCES})
+-target_link_libraries(memif ${CMAKE_THREAD_LIBS_INIT})
++add_library(memif OBJECT ${MEMIF_SOURCES})
++set_property(TARGET memif PROPERTY POSITION_INDEPENDENT_CODE ON)
+
+-find_library(LIB_BSD bsd)
+-if(LIB_BSD)
+- add_compile_definitions(HAS_LIB_BSD)
+- target_link_libraries(memif ${LIB_BSD})
+-endif()
+-
+-foreach(file ${MEMIF_HEADERS})
+- get_filename_component(dir ${file} DIRECTORY)
+- install(
+- FILES ${file}
+- DESTINATION include/${lib}/${dir}
+- COMPONENT libmemif-dev
+- )
+-endforeach()
+-
+-install(TARGETS memif DESTINATION lib COMPONENT libmemif)
++target_link_libraries(memif ${CMAKE_THREAD_LIBS_INIT})