// ------------------------------------------------------------------------------------------- // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. // This file is part of the AWS CDI-SDK, licensed under the BSD 2-Clause "Simplified" License. // License details at: https://github.com/aws/aws-cdi-sdk/blob/mainline/LICENSE // ------------------------------------------------------------------------------------------- #ifndef CDI_CORE_API_H__ #define CDI_CORE_API_H__ /** * @file * @brief * This file declares the public API data types, structures and functions that comprise the CDI low-level transport * SDK API. */ // Doxygen for CDI-CORE /*! @page Core_home_page CDI Core (CDI-CORE) API Home Page * @tableofcontents * * @section Core_arch CDI-CORE Architecture * * The diagram shown below provides a overview of the CDI-CORE architecture. * * @image html "high_level_architecture.jpg" * * @section Core_main_api CDI-CORE Application Programming Interface (API) * * The API is declared in: @ref cdi_core_api.h */ /* * With older distros (Ubuntu 16.04 in particular), "struct timespec" often is undefined prior to references to it. * C source files likely include time.h indirectly and sometimes directly prior to its inclusion below and if * _POSIX_C_SOURCE is undefined or defined to be less than 200112L, it does not get defined through the inclusion here. * The only solution is to ensure that it is defined with the required value early in each compilation unit. * * The block below ensures that _POSIX_C_SOURCE is defined with a value of 200112L or greater, erring out if not. */ #if !defined(_POSIX_C_SOURCE) /// @brief This define ensures that "struct timespec" is defined prior to using it. #define _POSIX_C_SOURCE 200112L #else #if _POSIX_C_SOURCE < 200112L /* * If the compiler hits this #error, define _POSIX_C_SOURCE to the value 200112L or a newer supported value in the * definitions passed in from the command line. */ #error _POSIX_C_SOURCE must be >= 200112L #endif // _POSIX_C_SOURCE < 200112L #endif // !defined(_POSIX_C_SOURCE) #include #include #include #include "cdi_log_enums.h" #include "cdi_utility_api.h" //********************************************************************************************************************* //***************************************** START OF DEFINITIONS AND TYPES ******************************************** //********************************************************************************************************************* // NOTE: Do not change the ordering of the three defines below. They are used internally by the CDI SDK makefile or // scripts to extract version information. /// @brief CDI version. #define CDI_SDK_VERSION 3 /// @brief CDI major version. #define CDI_SDK_MAJOR_VERSION 0 /// @brief CDI minor version. #define CDI_SDK_MINOR_VERSION 1 /// @brief CDI protocol version. #define CDI_PROTOCOL_VERSION 2 /// @brief CDI protocol major version. #define CDI_PROTOCOL_MAJOR_VERSION 3 /// @brief CDI probe command version. Possible value are: /// For Protocol version 2.0 (CDI_PROTOCOL_VERSION.CDI_PROTOCOL_MAJOR_VERSION): /// 0: SDK 1.x.x. Only supports protocol version 1.0. /// 1: not used /// 2: SDK 2.0.x, Only supports protocol version 1.0 /// 3: SDK 2.1.x. Supports the new protocol version command. See kProbeCommandProtocolVersion. Supports protocols /// version 1.0 and 2.0. /// /// For Protocol version 2.1 (CDI_PROTOCOL_VERSION.CDI_PROTOCOL_MAJOR_VERSION): /// 4: SDK 2.2.x. Supports bidirectional sockets for probe control interface. Logic added to maintain compatibility with /// previous probe version that used unidirectional sockets. /// 5. SDK 2.4.1 Rx waits for connected ping from Tx before enabling adapter level endpoint (ie. libfabric). #define CDI_PROBE_VERSION 5 /// @brief Define to limit the max number of allowable Tx or Rx connections that can be created in the SDK. #define CDI_MAX_SIMULTANEOUS_CONNECTIONS (30) /// @brief Define to limit the max number of allowable Tx or Rx endpoints for a single connection that can be created in /// the SDK. #define CDI_MAX_ENDPOINTS_PER_CONNECTION (5) /// @brief Define to limit the max number of allowable payloads that can be simultaneously sent on a single connection /// in the SDK. NOTE: This value is used to mask the MSBs of array indices so this value must be a power of two. #define CDI_MAX_SIMULTANEOUS_TX_PAYLOADS_PER_CONNECTION (8) /// @brief Define to limit the max number of allowable payload SGL entries that can be simultaneously sent on a single /// connection in the SDK. 3500 SGL entries supports 4K at 10-bits packed using 2110-20. #define CDI_MAX_SIMULTANEOUS_TX_PAYLOAD_SGL_ENTRIES_PER_CONNECTION (CDI_MAX_SIMULTANEOUS_TX_PAYLOADS_PER_CONNECTION*3500) /// @brief Define to limit the max number of allowable payloads that can be simultaneously received on a single /// connection in the SDK. This number should be larger than the respective Tx limit since more payloads can /// potentially be in flight in the receive logic. This is because Tx packets can get acknowledged to the transmitter /// before being fully processed by the receiver, allowing the transmitter to send more. /// This number must also be as large or larger than the maximum SRD packet ordering window so that we can be sure /// we make enough room in our state arrays for tracking all possible payloads that could be in flight at the same time. /// NOTE: This value must be a power of two because it is used to mask the MSBs of array indices. @see RxPacketReceive #define CDI_MAX_SIMULTANEOUS_RX_PAYLOADS_PER_CONNECTION (32) /// @brief Define the size of the Rx payload buffer used to hold out of order payloads. Value must be a power of 2. /// Sized to allow receive of 4K RGB 4:4:4 12 bit. #define CDI_MAX_RX_PAYLOAD_OUT_OF_ORDER_BUFFER (8192) /// @brief Define to limit the max number packets of that can arrive out of order and be put back in order. /// Sized to allow receive of 4K RGB 4:4:4 12 bit. #define CDI_MAX_RX_PACKET_OUT_OF_ORDER_WINDOW (5000) /// @brief Maximum connection name string length. #define CDI_MAX_CONNECTION_NAME_STRING_LENGTH (128) /// @brief Maximum stream name string length. #define CDI_MAX_STREAM_NAME_STRING_LENGTH (CDI_MAX_CONNECTION_NAME_STRING_LENGTH+10) /// @brief Maximum log filename string length. #define CDI_MAX_LOG_FILENAME_LENGTH (1024) /// @brief When Rx Buffer delay is enabled using "-1", this is the delay used in milliseconds. This is 4 video frames at /// 60FPS (4*16.6ms= 66.4ms). This value is the recommended buffer size for transport between instances that are not /// in a cluster placement group. #define CDI_ENABLED_RX_BUFFER_DELAY_DEFAULT_MS (67) /// @brief Maximum Rx buffer delay in milliseconds. This is approximately 6 video frames at 60FPS (6*16.6ms= ~100ms). #define CDI_MAXIMUM_RX_BUFFER_DELAY_MS (100) /// @brief The millisecond divisor used to calculate how many additional packet buffers to allocate for the Rx buffer. /// A value of 10 here corresponds to 100FPS (10ms). #define CDI_RX_BUFFER_DELAY_BUFFER_MS_DIVISOR (10) // Declare forward references for internal structures that are not directly available through the API. struct CdiAdapterState; struct CdiConnectionState; struct CdiMemoryState; /// @brief Forward structure declaration to create pointer to log data when used. typedef struct CdiLogMethodData CdiLogMethodData; /** * @brief Type used as the handle (pointer to an opaque structure) for a network adapter. Each handle represents an * instance of a network adapter. */ typedef struct CdiAdapterState* CdiAdapterHandle; /** * @brief Type used as the handle (pointer to an opaque structure) for a transmitter or receiver connection. Each handle * represents a single data flow. */ typedef struct CdiConnectionState* CdiConnectionHandle; /** * @brief Type used as the handle (pointer to an opaque structure) for a transmitter or receiver endpoint. Each handle * represents a single data flow. */ typedef struct CdiEndpointState* CdiEndpointHandle; /** * @brief Type used as the handle (pointer to an opaque structure) for holding private SDK data that relates to memory. */ typedef struct CdiMemoryState* CdiMemoryHandle; /** * @brief Type used as user defined data that is passed to the registered user RX/TX callback functions. */ typedef void* CdiUserCbParameter; /** * @brief Values used for API function return codes. * * NOTE: Additions to and removals from this enumeration need to be reflected in CdiCoreStatusToString(). */ typedef enum { /// The API function succeeded. kCdiStatusOk = 0, /// An unspecified, unrecoverable error occurred. kCdiStatusFatal = 1, /// An attemt to allocated memory from the heap failed. kCdiStatusNotEnoughMemory = 2, /// The appropriate SDK initialization function has not yet been called. kCdiStatusNotInitialized = 3, /// A chunk of data was not delivered to the receiver before its deadline was reached. kCdiStatusMaxLatencyExceeded = 4, /// The handle passed in to an SDK function is not valid. kCdiStatusInvalidHandle = 5, /// A parameter passed in to an SDK function is not valid. kCdiStatusInvalidParameter = 6, /// This status is only returned by CdiTxPayload() when the connection to the receiver has not been established or /// when the receiver has become disconnected due to either network problems or the receiving host becoming /// non-responsive. kCdiStatusNotConnected = 7, /// The operation failed due to a queue resource being full. kCdiStatusQueueFull = 8, /// The operation failed due to the connection type is not valid for the requested operation. kCdiStatusInvalidConnectionType = 9, /// A payload was received, but an error occurred. The payload is being discarded. kCdiStatusRxPayloadError = 10, /// A payload was received, but it was not using the protocol specified by the received connection. This means /// either a AVM payload was received on a RAW connection or a RAW payload was received on a AVM connection. kCdiStatusRxWrongProtocolType = 11, /// Unable to create a log file. kCdiStatusCreateLogFailed = 12, /// Unable to create a thread. kCdiStatusCreateThreadFailed = 13, /// The current connection is shutting down, so resources that may be actively being used (E.g. a FIFO) will abort /// and return this status. kCdiStatusShuttingDown = 14, /// An attempt was made to perform an Rx function on a Tx connection, or vice-versa. kCdiStatusWrongDirection = 15, /// When performing a port query, the function failed. kCdiStatusGetPortFailed = 16, /// Attempt to use a connection that is stopped. kCdiStatusNotReady = 17, /// Tx data failed to post to endpoint queue. kCdiStatusSendFailed = 18, /// Attempt to allocate a non-memory resource failed. kCdiStatusAllocationFailed = 19, /// Attempt to open a connection (e.g. socket) failed. kCdiStatusOpenFailed = 20, /// Attempt was made to create an identical endpoint that is already in use. kCdiStatusDuplicateConnection = 21, /// Invalid SGL found when processing. kCdiStatusInvalidSgl = 22, /// An endpoint state change occurred. kCdiStatusEndpointManagerState = 23, /// Buffer is not large enough to hold data. kCdiStatusBufferOverflow = 24, /// No packets were received for a payload. kCdiStatusRxPayloadMissing = 25, /// The size of an internal array that does not dynamically grow was exceeded. kCdiStatusArraySizeExceeded = 26, /// An unspecified, recoverable error occurred. kCdiStatusNonFatal = 27, /// The SDK was built without CloudWatch being enabled. The CloudWatch SDK is required and must be specifically /// referenced as part of building the SDK. See RELEASE_NOTES file or Setup/Install Guide for details. kCdiStatusCloudWatchNotEnabled = 28, /// A CloudWatch request was throttled. Need to try the request again at a later time. kCdiStatusCloudWatchThrottling = 29, /// A CloudWatch request failed due to invalid credentials. Verify that the access and secret keys have been setup /// correctly. kCdiStatusCloudWatchInvalidCredentials = 30, /// Internal only status: the function succeeded but did nothing productive. kCdiStatusInternalIdle = 31, /// An attempt was made to create a duplicate adapter entry. kCdiStatusAdapterDuplicateEntry = 32, /// An attempt was made to use a profile that is not supported. kCdiStatusProfileNotSupported = 33, /// Failed to decode a probe packet due to a CRC error. kCdiStatusProbePacketCrcError = 34, /// Failed to decode a probe packet due to invalid size. kCdiStatusProbePacketInvalidSize = 35, /// Payloads are being received, but back pressure is preventing allocation of resources to store them. Payloads are /// being discarded until another status message is provided (ie. kCdiStatusOk). kCdiStatusRxPayloadBackPressure = 36, /// An attempt was made to register an already registered baseline profile. kCdiStatusDuplicateBaselineVersion = 37, /// A received payload cannot be read because of format errors. kCdiStatusInvalidPayload = 38, /// Failed to dynamically load a shared library. kCdiStatusLibraryLoadFailed = 39, /// Failed to find symbol in dynamically loaded library. kCdiStatusLibrarySymbolNotFound = 40, /// Wrong version of dynamically loaded library. kCdiStatusLibraryWrongVersion = 41, } CdiReturnStatus; /// @brief A structure for holding a PTP timestamp defined in seconds and nanoseconds. This PTP time as defined by /// SMPTE ST 2059-2 and IEEE 1588-2008 with the exception that the seconds field is an unsigned 32 bit integer instead /// of the specified 48 bit integer. //typedef struct CdiPtpTimestamp CdiPtpTimestamp; typedef struct CdiPtpTimestamp { /// The number of seconds since the SMPTE Epoch which is 1970-01-01T00:00:00. uint32_t seconds; /// The number of fractional seconds as measured in nanoseconds. The value in this field is always less than 10^9. uint32_t nanoseconds; } CdiPtpTimestamp; /// @brief Extra data that is sent along with payloads to the receiver. It will be provided to the receiver through /// registered user receive data callback functions. typedef struct { /// @brief Origination timestamp to associate with the payload. This timestamp is a PTP timestamp as outlined /// by SMPTE ST 2059-2. The one exception is the seconds field is stored as an unsigned 32 bit integer instead of /// the specified unsigned 48 bit integer. CdiPtpTimestamp origination_ptp_timestamp; /// @brief User-defined data to associate with the payload. uint64_t payload_user_data; } CdiCoreExtraData; /// @brief A structure used to configure a transmit payload. typedef struct { /// @brief Extra data that was sent along with the payload. CdiCoreExtraData core_extra_data; /// @brief User defined callback parameter specified when using one of the Cdi...Tx...Payload() API functions. This /// allows the application to associate a TX payload to a single TX registered user callback function. CdiUserCbParameter user_cb_param; /// @brief The size in bits of the units being transferred. This ensures a single unit is not split across sgl /// entries. As an example a 10 bit pixel would be set to 10 to ensure that no pixels are split. int unit_size; } CdiCoreTxPayloadConfig; /** * @brief This enumeration is used to indicate the current state of a connection. * NOTE: Any changes made here MUST also be made to "connection_status_key_array" in cdi_utility_api.c. */ typedef enum { kCdiConnectionStatusDisconnected, ///< Disconnected. The SDK is trying to establish the connection. kCdiConnectionStatusConnected, ///< Connected and ready for use. } CdiConnectionStatus; /** * @brief A structure of this type is passed as the parameter to CdiCoreConnectionCallback(). It contains data related * to the status of a single connection. */ typedef struct { /// @brief Current status of the connection. CdiConnectionStatus status_code; /// @brief If the connection is not connected, this will point to a NULL terminated error message string. The memory /// containing the error string is allocated by the SDK and will be freed upon return from the callback function. /// The application needs to copy the message to its own memory before returning if it needs it to be retained. const char* err_msg_str; /// @brief Used to identify the handle of the stream endpoint associated with the connection. Only valid for Tx /// endpoints that were created using the CdiAvmTxStreamEndpointCreate() function. Value is NULL for Rx endpoints. CdiEndpointHandle tx_stream_endpoint_handle; const char* remote_ip_str; ///< Pointer to remote IP address string. int remote_dest_port; ///< Remote destination port. /// @brief User defined connection callback parameter. For a transmitter, this value is set as part of the /// CdiTxConfigData data provided as a parameter to one of the Cdi...TxCreate() API functions. For a receiver, this /// value is set as part of the CdiRxConfigData data provided to one of the Cdi...RxCreate() API functions. CdiUserCbParameter connection_user_cb_param; /// @brief Negotiated CDI protocol version number for the endpoint associated with this connection. uint8_t negotiated_version_num; uint8_t negotiated_major_version_num; ///< Negotiated CDI protocol major version number. uint8_t negotiated_probe_version_num; ///< Negotiated CDI protocol probe version number. } CdiCoreConnectionCbData; /** * @brief Prototype of connection callback function. The user code must implement a function with this prototype and * provide it in CdiTxConfigData or CdiRxConfigData structure when using one of the Cdi...Create() API functions. * * This callback function is invoked whenever the connection status changes. * * @param data_ptr A pointer to an CdiCoreConnectionCbData structure. */ typedef void (*CdiCoreConnectionCallback)(const CdiCoreConnectionCbData* data_ptr); /** * @brief A structure of this type is passed as part of the data to the TX/RX registered user callback functions. It * contains data related to the transmission of a single payload. */ typedef struct { /// @brief If payload was successfully sent and received by the receiver, value will be kCdiStatusOk. /// Otherwise,indicates the general reason for the error condition. Use err_msg_str for a detailed error message /// string. CdiReturnStatus status_code; /// @brief If an error or timeout occurred while transmitting the payload, this will point to a NULL terminated /// error message string. The memory containing the error string is allocated by the SDK and will be freed upon /// return from the callback function. The application needs to copy the message to its own memory before returning /// if it needs it to be retained. const char* err_msg_str; /// @brief The handle of the instance which was created using a previous call to one of the Cdi...Create() API /// functions. CdiConnectionHandle connection_handle; /// @brief Extra data that was sent along with the payload. CdiCoreExtraData core_extra_data; /// @brief User defined callback parameter. For a transmitter, this value is set as part of the /// CdiCoreTxPayloadConfig data provided as a parameter to one of the Cdi...TX..Payload() API functions. For a /// receiver, this value is set as part of the CdiRxConfigData data provided to one of the Cdi...RxCreate() /// APIs functions. CdiUserCbParameter user_cb_param; } CdiCoreCbData; /** * @brief This selector determines the type of network adapter in the API function. * NOTE: Any changes made here MUST also be made to "adapter_type_key_array" in cdi_avm_api.c. */ typedef enum { /// @brief This adapter type is the typical choice for high throughput, reliable delivery of data. In order to use /// it, the host must meet a number of requirements documented elsewhere. kCdiAdapterTypeEfa, /** * @brief This adapter type has significant performance limitations and is mainly useful for testing since there * are no special instances required for using applications with the SOCKET adapter. * * This adapter is implemented using kernel UDP sockets. UDP sockets do not provide the reliable delivery of * messages, or datagrams, that EFA provides. Additionally since this uses the kernel UDP socket instead of a polled * mode network driver the throughput is significantly constrained relative to EFA. Furthermore, the SOCKET adapter * does not use the same out-of-band connection management that is used by the EFA. Without the out-of-band * connection management the transmitting side does not have visibility into whether the receiving side is present * and receiving data. * * Due to these differences the successful use of the SOCKET adapter requires several special considerations: * 1. Keep the bandwidth utilization low by using a combination of small payloads and low frame rates. * 2. Ensure that the receive side is started before the transmitting side. * 3. Use the local interface, which should work more reliably than a physical network interface. * 4. If the above is not adequate for testing purposes consider tuning the kernel to increase network buffer * sizes. */ kCdiAdapterTypeSocket, /// @brief This adapter type is mainly useful for testing. This is similar to kCdiAdapterTypeSocket except that it /// uses libfabric to perform the work of sending over the socket. kCdiAdapterTypeSocketLibfabric } CdiAdapterTypeSelection; /** * @brief Configuration data used by the CdiCoreNetworkAdapterInitialize() API function. */ typedef struct { /// @brief The IP address to use for the local network interface dedicated to the SDK's use. NOTE: This must be the /// dotted form of an IPv4 address. DHCP and/or DNS may be supported in the future. const char* adapter_ip_addr_str; /// @brief The size in bytes of a memory region for holding payload data to transmit. If no transmit connections /// will be created, then this value can be zero. Otherwise it must be a value greater than 1. /// /// A special memory type is used so both CPU and DMA hardware can access the memory. The application manages how /// the buffer is partitioned and used. uint64_t tx_buffer_size_bytes; /// @brief Returned pointer to start of the allocated transmit buffer. Size is specified using /// tx_buffer_size_kbytes. void* ret_tx_buffer_ptr; /// @brief The type of adapter to use/initialize. CdiAdapterTypeSelection adapter_type; } CdiAdapterData; /** * @brief Transfer statistics data specific to payloads that contain counters that increment for the duration of * the connection. They are never reset. */ typedef struct { /// @brief Current number of payloads successfully transferred since the connection was created. uint64_t num_payloads_transferred; /// @brief The number of payloads that have been dropped due to timeout conditions since the connection was created. /// Payloads are typically dropped because of network connectivity issues but will also occur when the receiving /// host is unresponsive among other possible causes. uint64_t num_payloads_dropped; /// @brief Number of payloads that were transmitted late since the connection was created. uint64_t num_payloads_late; /// @brief Number of bytes that were transmitted since the connection was created. uint64_t num_bytes_transferred; } CdiPayloadCounterStats; /** * @brief Transfer statistics data specific to payloads that are reset at the start of each time interval as specified * using #CdiStatsConfigData.stats_period_seconds. A snapshot of the current values is made and provided through the * user-registered callback function CdiCoreStatsCallback(). */ typedef struct { /// @brief Minimum time to transfer a payload over the time interval. uint32_t transfer_time_min; /// @brief Maximum time to transfer a payload over the time interval. uint32_t transfer_time_max; /// @brief Number of payloads transferred over the time interval. int transfer_count; /// @brief Accumulating sum of time to transfer payloads over the time interval. uint64_t transfer_time_sum; /// @brief The median time to transfer a payload over the time interval. uint32_t transfer_time_P50; /// @brief The 90th percentile time to transfer a payload over the time interval. uint32_t transfer_time_P90; /// @brief The 99th percentile time to transfer a payload over the time interval. uint32_t transfer_time_P99; } CdiPayloadTimeIntervalStats; /** * @brief Transfer statistics data specific to an adapter endpoint. Used in the CdiTransferStats structure as a * parameter of the user-registered CdiCoreStatsCallback() API function. */ typedef struct { /// Number of times the connection has been lost. uint32_t dropped_connection_count; /// Number of probe command retries due to dropped/lost control packets. The control protocol is UDP based and does /// not use the SRD hardware. This provides a secondary channel of communication. uint32_t probe_command_retry_count; /// The true load on the poll thread's CPU core in units of hundredths of a percent. The normal range of this value /// is between 0 and 10000 (0% to 100.00%) but it may be -1 to indicate a computation error. This value is /// determined by computing the portion of each five second window that is spent doing productive work, as opposed /// to spinning while it has nothing to do. int poll_thread_load; bool connected; ///< true if connected, false if not connected. } CdiAdapterEndpointStats; /** * @brief Transfer statistics data. Used as a parameter of the user-registered CdiCoreStatsCallback() API function. */ typedef struct { /// @brief Time when last statistic of the set was gathered. Units is in milliseconds since epoch. uint64_t timestamp_in_ms_since_epoch; /// @brief A string that defines the name of the stream. This is a copy of the string, since the associated endpoint /// can be destroyed while this data is queuing to CloudWatch. char stream_name_str[CDI_MAX_STREAM_NAME_STRING_LENGTH]; CdiPayloadCounterStats payload_counter_stats; ///< Statistics data specific to payloads that don't reset. CdiPayloadTimeIntervalStats payload_time_interval_stats; ///< Statistics data specific to payloads that reset. CdiAdapterEndpointStats endpoint_stats; ///< Statistics data specific to adapter endpoints. } CdiTransferStats; /** * @brief A structure of this type is passed as the parameter to CdiCoreStatsCallback(). It contains data related * to the statistics of a single connection. */ typedef struct { int stats_count; ///< Number of items in transfer_stats_array. CdiTransferStats* transfer_stats_array; ///< Array of the accumulated statistics. /// @brief User defined statistics callback parameter. This value is set as part of the CdiStatsConfigData structure /// when creating a connection or using CdiCoreStatsReconfigure(). CdiUserCbParameter stats_user_cb_param; } CdiCoreStatsCbData; /** * @brief Prototype of statistics callback function. The user code must implement a function with this prototype and * provide it as a parameter to the CdiCoreStatsRegisterCallback() API function. * * This callback function is invoked whenever statistics gathering interval has expired. * * @param data_ptr A pointer to an CdiCoreStatsCbData structure. */ typedef void (*CdiCoreStatsCallback)(const CdiCoreStatsCbData* data_ptr); /** * @brief A structure that is used to hold statistics gathering configuration data. */ typedef struct { /// @brief How often to gather statistics and make available through the user-registered statistics callback /// function (see stats_cb_ptr). Statistics will also be sent directly to a CloudWatch Endpoint, if enabled (see /// #CdiCoreConfigData.cloudwatch_config_ptr). uint32_t stats_period_seconds; /// @brief If CloudWatch has been configured, use this value to disable/enable sending statistics to it. bool disable_cloudwatch_stats; } CdiStatsConfigData; /** * @brief Configuration data used by one of the Cdi...TxCreate() API functions. */ typedef struct { /// @brief Handle of the adapter to use for this connection. The handle is returned by the /// CdiCoreNetworkAdapterInitialize() API function. CdiAdapterHandle adapter_handle; /// @brief The IP address of the host which is to receive the flow from this transmitter. NOTE: This must be the /// dotted form of an IPv4 address. DNS may be supported in the future. const char* dest_ip_addr_str; /// @brief The port number to use at the receiving host. The range of valid values is 1 to 65535, inclusive and must /// match the value configured for the receiving connection. int dest_port; /// @brief The IP address of the host interface to bind to for internal CDI command communication. If NULL, /// interface binding is not used (default behavior). NOTE: This must be the dotted form of an IPv4 address. DNS may /// be supported in the future. const char* bind_ip_addr_str; /// @brief To reduce CPU core usage, multiple connections can share the same poll thread by specifying a shared poll /// thread identifier. Any connection that uses the same identifier will share a single instance of the poll thread. /// Dynamically adding/removing connections while payloads are transferring may cause them to be late. Therefore, /// connections that share the same poll thread should be created and connected before payloads are transferred. If /// the thread identifier is 0 or negative (ie. -1), a unique poll thread is created and associated only with this /// connection. NOTE: If enabled (greater than 0), then all connections with matching shared_thread_id must also /// match in their setting of thread_core_num. int shared_thread_id; /// @brief The core to dedicate to this connection's packet send poll thread. A value of -1 disables pinning the /// thread to a specific core otherwise the value must be between 0 (inclusive) and the number of CPU cores /// (exclusive) in the host. The packet send thread continuously polls the underlying hardware for a time to send /// packets when the packet send queue is not empty so it can consume a large portion of the available time on /// whatever CPU it's running whether pinned or not. int thread_core_num; /// @brief The max number of allowable payloads that can be simultaneously transmitted on a single connection in the /// SDK. This number should be smaller than the respective receive limit since more payloads can potentially be in /// flight in the receive logic. This is because Tx packets can get acknowledged to the transmitter before being /// fully processed by the receiver, allowing the transmitter to send more. /// NOTE: If it's 0, then CDI_MAX_SIMULTANEOUS_TX_PAYLOADS_PER_CONNECTION will be used. int max_simultaneous_tx_payloads; /// @brief The max number of sgl entries in use at one time for each transmit connection in the SDK. This number /// should be set to account for the number of payloads in flight (max_simultaneous_tx_payloads) as well as the /// maximum size of the payloads being sent. A 4K video payload will have at least one entry per packet sent so /// large payloads can have many SGL entries. The SGL entries for a given payload should all be returned by the /// transmit callback function. /// NOTE: If it's 0, then CDI_MAX_SIMULTANEOUS_TX_PAYLOAD_SGL_ENTRIES_PER_CONNECTION will be used. int max_simultaneous_tx_payload_sgl_entries; /// @brief Pointer to name of the connection. It is used as an identifier when generating log messages that are /// specific to this connection. If NULL, a name is internally generated. Length of name must not exceed /// MAX_CONNECTION_NAME_STRING_LENGTH. const char* connection_name_str; /// @brief Pointer to log configuration data for this connection. CdiLogMethodData* connection_log_method_data_ptr; /// @brief Address of the user function to call whenever the status of a connection changes. CdiCoreConnectionCallback connection_cb_ptr; /// @brief User defined callback parameter passed to the user registered connection callback function (see /// connection_cb_ptr). This allows the application to associate a TX connection to a single registered user /// callback function. CdiUserCbParameter connection_user_cb_param; /// @brief Address of the user function to call whenever a new set of statistics is available. CdiCoreStatsCallback stats_cb_ptr; /// @brief User defined callback parameter passed to the user registered statistics callback function (see /// stats_cb_ptr). This allows the application to associate statistics to a single registered user /// callback function. CdiUserCbParameter stats_user_cb_param; /// @brief Configuration data for gathering statistics. The data can be changed at runtime using the /// CdiCoreStatsReconfigure() API function. CdiStatsConfigData stats_config; } CdiTxConfigData; /** * @brief This typedef is declared here so we can use it as a pointer element within the structure. */ typedef struct CdiSglEntry CdiSglEntry; /** * @brief This structure represents a single, contiguous region of memory as part of a scatter-gather list. */ struct CdiSglEntry { /// @brief The starting address of the data. void* address_ptr; /// @brief The size of the data in bytes. int size_in_bytes; /// @brief Handle to private data used within the SDK that relates to this SGL entry. Do not use or modify this /// value. void* internal_data_ptr; /// @brief The next entry in the list or NULL if this is the final entry in the list. CdiSglEntry* next_ptr; }; /** * @brief This structure defines a scatter-gather list (SGL) which is used to represent an array of data comprising one * or more contiguous regions of memory. */ typedef struct { /// @brief Total size of data in the list, in units of bytes. This value can be calculated by walking the sgl_array, /// but is provided here for convenience and efficiency. NOTE: This value must be the same as the value calculated /// from walking the list and summing the size_in_bytes for each CdiSglEntry. int total_data_size; /// @brief Pointer to the first entry in the singly-linked list of SGL entries. CdiSglEntry* sgl_head_ptr; /// @brief Pointer to the last entry in the singly-linked list of SGL entries. CdiSglEntry* sgl_tail_ptr; /// @brief Handle to internal data used within the SDK that relates to this SGL. Do not use or modify this value. void* internal_data_ptr; } CdiSgList; /** * @brief Values used to determine type of receive buffer to configure for a receiver connection. * NOTE: Any changes made here MUST also be made to "buffer_type_key_array" in cdi_utility_api.c. */ typedef enum { /// @brief Use a linear buffer to store received payload data. Depending on hardware capabilities, this may require /// memcpy. kCdiLinearBuffer = 0, /// @brief Use scatter-gather buffers to store received payload data. kCdiSgl = 1, } CdiBufferType; /** * @brief Configuration data used by one of the Cdi...RxCreate() API functions. */ typedef struct { /// @brief Handle of the adapter to use for this connection. The handle is returned by the /// CdiCoreNetworkAdapterInitialize() API function. CdiAdapterHandle adapter_handle; /// @brief Destination port. Value must match the dest_port specified by the transmitter which must be configured to /// send to the same port number. If running in an unprivileged process, this value must be in the range of /// unprivileged port numbers. int dest_port; /// @brief The IP address of the host interface to bind to for internal CDI command communication. If NULL, /// interface binding is not used (default behavior). NOTE: This must be the dotted form of an IPv4 address. DNS may /// be supported in the future. const char* bind_ip_addr_str; /// @brief To reduce CPU core usage, multiple connections can share the same poll thread by specifying a shared poll /// thread identifier. Any connection that uses the same identifier will share a single instance of the poll thread. /// Dynamically adding/removing connections while payloads are transferring may cause them to be late. Therefore, /// connections that share the same poll thread should be created and connected before payloads are transferred. If /// the thread identifier is 0 or negative (ie. -1), a unique poll thread is created and associated only with this /// connection. NOTE: If enabled (greater than 0), then all connections with matching shared_thread_id must also /// match in their setting of thread_core_num. int shared_thread_id; /// @brief The core to dedicate to this connection's packet reception poll thread. A value of -1 disables pinning /// the thread to a specific core otherwise the value must be between 0 (inclusive) and the number of CPU cores /// (exclusive) in the host. The packet receive thread continuously polls the underlying hardware for packets so it /// always consumes 100% of the available time on whatever CPU it's running whether pinned or not. int thread_core_num; /// @brief Type of RX buffer to use for incoming data. CdiBufferType rx_buffer_type; /// @brief Number of milliseconds to delay invoking the user-registered callback function for incoming payloads. Use /// 0 to disable, -1 to enable and the SDK automatic default value (CDI_ENABLED_RX_BUFFER_DELAY_DEFAULT_MS) or use a /// value up to MAXIMUM_RX_BUFFER_DELAY_MS. int buffer_delay_ms; /// @brief Size in bytes of the linear receive buffer used by this RX connection. This buffer is reserved from the /// RX buffer allocated as part of initialization of the adapter (see adapter_rx_linear_buffer_size). NOTE: This /// value is only used if rx_buffer_type = kCdiLinearBuffer. uint64_t linear_buffer_size; /// @brief The max number of allowable payloads that can be simultaneously received on a single connection in the /// SDK. This number should be larger than the respective transmit limit since more payloads can potentially be in /// flight in the receive logic. This is because Tx packets can get acknowledged to the transmitter before being /// fully processed by the receiver, allowing the transmitter to send more. This number must also be as large or /// larger than the maximum SRD packet ordering window so that we can be sure we make enough room in our state /// arrays for tracking all possible payloads that could be in flight at the same time. /// NOTE: If it's 0, then CDI_MAX_SIMULTANEOUS_RX_PAYLOADS_PER_CONNECTION will be used. int max_simultaneous_rx_payloads_per_connection; /// @brief User defined callback parameter passed to a registered user RX callback function. This allows the /// application to associate an RX connection to a single RX callback function. CdiUserCbParameter user_cb_param; /// @brief Pointer to name of the connection. It is used as an identifier when generating log messages that are /// specific to this connection. If NULL or points to '\0', it is given the name generated from the SDK found in the /// saved_connection_name_str member of CdiConnectionState. const char* connection_name_str; /// @brief Pointer to log configuration data for this connection. CdiLogMethodData* connection_log_method_data_ptr; /// @brief Address of the user function to call whenever the status of a connection changes. CdiCoreConnectionCallback connection_cb_ptr; /// @brief User defined callback parameter passed to the user registered RX connection callback function (see /// connection_cb_ptr). This allows the application to associate a RX connection to a single registered user /// callback function. CdiUserCbParameter connection_user_cb_param; /// @brief Address of the user function to call whenever a new set of statistics is available. CdiCoreStatsCallback stats_cb_ptr; /// @brief User defined callback parameter passed to the user registered statistics callback function (see /// stats_cb_ptr). This allows the application to associate statistics to a single registered user /// callback function. CdiUserCbParameter stats_user_cb_param; /// @brief Configuration data for gathering statistics. The data can be changed at runtime using the /// CdiCoreStatsReconfigure() API function. CdiStatsConfigData stats_config; } CdiRxConfigData; /** * @brief A structure that is used to hold statistics gathering configuration data that is specific to CloudWatch. * * NOTE: For periods ((see #CdiStatsConfigData.stats_period_seconds) less than 60 seconds, high resolution storage for * metrics will be enabled. This means metrics are stored at 1-second resolution. If false, metrics are stored at * 1-minute resolution (CloudWatch default value). */ typedef struct { /// @brief Pointer to a string that defines the CloudWatch namespace used to hold metrics generated by CDI. If /// NULL is used, then the string defined by CLOUDWATCH_DEFAULT_NAMESPACE_STRING is used. const char* namespace_str; /// @brief Pointer to a string that defines the EC2 region where the CloudWatch container is located. If NULL, the /// region where CDI is running will be used. const char* region_str; /// @brief Pointer to a string that defines a dimension called "Domain" that is associated with each metric. This /// value is required and cannot be NULL. const char* dimension_domain_str; } CdiCloudWatchConfigData; /** * @brief SDK configuration data used by the CdiCoreInitialize() API function. */ typedef struct { /// @brief Specifies the default set of log messages to use. CdiLogLevel default_log_level; /// @brief Pointer to global log method configuration data. const CdiLogMethodData* global_log_method_data_ptr; /// @brief Pointer to configuration data specific to CloudWatch. The statics gathering period is uniquely defined /// for each connection (see #CdiStatsConfigData.stats_period_seconds) when the connection is created and can be /// changed at any time using CdiCoreStatsReconfigure(). If this value is NULL, then CloudWatch will not be used. const CdiCloudWatchConfigData* cloudwatch_config_ptr; } CdiCoreConfigData; /** * @brief SDK read-only settings used internally by SDK. */ typedef struct { /// @brief How long a Tx endpoint retries in milliseconds to send an out-of-band command to Rx before disconnecting /// from the Rx endpoint. If disconnected, the Tx endpoint will continuously attempt to re-establish the /// connection. uint64_t tx_retry_timeout_ms; /// @brief How long a Rx endpoint waits in milliseconds for an out-of-band ping command from Tx before removing the /// Rx endpoint. if removed, all resources associated with the endpoint are freed. See RX_PING_MONITOR_TIMEOUT_MSEC. uint64_t rx_wait_timeout_ms; } CdiCoreReadOnlySettings; //********************************************************************************************************************* //******************************************* START OF PUBLIC FUNCTIONS *********************************************** //********************************************************************************************************************* /** * Initialize the SDK. Must be called once before using any other SDK APIs. When done, must call CdiCoreShutdown() once. * * NOTE: Newly created data structures that are passed in to this function should be properly initialized before being * programmed with user values. Use memset or a zero structure initializer (= {0}) to set the whole structure to zero * before setting the desired members to the actual values required. * * @param core_config_ptr Pointer to core configuration data that is used to initialize the SDK. Value is required and * cannot be NULL. Copies of the data in the configuration data structure are made as needed. A * local variable can be used for composing the structure since its contents are not needed after * this function returns. * * @return A value from the CdiReturnStatus enumeration. */ CDI_INTERFACE CdiReturnStatus CdiCoreInitialize(const CdiCoreConfigData* core_config_ptr); /** * Create an instance of a network adapter. CdiCoreNetworkAdapterDestroy() must be called before CdiCoreShutdown() but * after all connections using the adapter are closed using CdiCoreConnectionDestroy(). * * NOTE: Currently if the shared memory provider is enabled in the EFA Adapter (see FI_EFA_ENABLE_SHM_TRANSFER in CDI), * libfabric uses fork() to determine capability (see rxr_check_cma_capability() in the EFA provider). This causes a * double flush of cached write data of any open files. By default, the shared memory provider is disabled. If enabled, * all open files must have used fflush() prior to using this API function. The CDI SDK always flushes all open log * files that were created using the CDI logger API functions. * * NOTE: Newly created data structures that are passed in to this function should be properly initialized before being * programmed with user values. Use memset or a zero structure initializer (= {0}) to set the whole structure to zero * before setting the desired members to the actual values required. * * @param adapter_data_ptr Pointer to network adapter configuration data. Copies of the data in the configuration data * structure are made as needed. A local variable can be used for composing the structure since * its contents are not needed after this function returns. * @param ret_handle_ptr Pointer to returned instance handle (used as parameter for other API functions). * * @return A value from the CdiReturnStatus enumeration. */ CDI_INTERFACE CdiReturnStatus CdiCoreNetworkAdapterInitialize(CdiAdapterData* adapter_data_ptr, CdiAdapterHandle* ret_handle_ptr); /** * Free resources associated with the specified network adapter that was previously created using * CdiCoreNetworkAdapterInitialize(). NOTE: Before calling this function, all connections that use the adapter should be * closed using CdiCoreConnectionDestroy(). * * @param handle Handle of network adapter to destroy. * * @return A value from the CdiReturnStatus enumeration. */ CDI_INTERFACE CdiReturnStatus CdiCoreNetworkAdapterDestroy(CdiAdapterHandle handle); /** * Free the receive buffer that was used in one of the Cdi...RxCallback() API functions. * * @param sgl_ptr The scatter-gather list containing the memory to be freed. * * @return A value from the CdiReturnStatus enumeration. */ CDI_INTERFACE CdiReturnStatus CdiCoreRxFreeBuffer(const CdiSgList* sgl_ptr); /** * Gather received data represented by a scatter-gather list into a contiguous buffer. The caller is responsible for * ensuring that the destination buffer is large enough to hold the data. * * A subset of the entire payload of the SGL can be extracted by using a non-zero value for offset and/or a smaller * number for byte_count than sgl->total_data_size. The number of bytes copied is the smaller of (sgl->total_data_size - * offset) or byte_count. * * @param sgl_ptr The scatter-gather list containing the data to be gathered. * @param offset Number of bytes to skip in SGL before starting the copy. * @param dest_data_ptr Where to write the gathered data in linear format. * @param byte_count The number of bytes to copy. * * @return The number of bytes copied. This will be less than byte_count if fewer than that number of bytes are present * in the source SGL starting from the specified offset. A value of -1 indicates that a fatal error was * encountered such as NULL values for sgl_ptr or dest_data_ptr. */ CDI_INTERFACE int CdiCoreGather(const CdiSgList* sgl_ptr, int offset, void* dest_data_ptr, int byte_count); /** * Configure transfer statistics. * * @param handle Connection handle returned by Cdi...TxCreate() API functions. * @param config_ptr Pointer to statistics configuration data. Copies of the data in the configuration data structure * are made as needed. A local variable can be used for composing the structure since its contents are * not needed after this function returns. * * @return A value from the CdiReturnStatus enumeration. */ CDI_INTERFACE CdiReturnStatus CdiCoreStatsReconfigure(CdiConnectionHandle handle, const CdiStatsConfigData* config_ptr); /** * Destroy a specific TX or RX connection and free resources that were created for it. * * @param handle Connection handle returned by Cdi...TxCreate() API functions. * * @return A value from the CdiReturnStatus enumeration. */ CDI_INTERFACE CdiReturnStatus CdiCoreConnectionDestroy(CdiConnectionHandle handle); /** * Application is shutting down. Stop open connections and free-up all resources being used by the SDK. * * @return A value from the CdiReturnStatus enumeration. */ CDI_INTERFACE CdiReturnStatus CdiCoreShutdown(void); /** * Get the current synced AWS network UTC time in a timespec structure. This function will be kept up to date with the * best practices for getting high accuracy time from Amazon Time Sync Service as improved accuracy time is available. * All EC2 instances that call this function should be using the Amazon Time Sync Service. Amazon Time Sync Service * setup directions for Linux can be found at: * https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/set-time.html#configure-amazon-time-service. For Windows follow * the directions at: https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/windows-set-time.html * * @param ret_time_ptr Address where to write the UTC timestamp in a timespec structure as defined by time.h. */ CDI_INTERFACE void CdiCoreGetUtcTime(struct timespec* ret_time_ptr); /** * @brief Get the current TAI time as a PTP timestamp. * * There seems to be no trivial solutions for automatically getting the current leap second adjustment. All leap second * adjustments occur on either December 31st or June 30th. The next possible leap second introduction is June 30th 2021. * This function applies a fixed 37 second adjustment to UTC time to get TAI time. * * @param ret_ptp_time_ptr Pointer to CdiPtpTimestamp to return the current PtpTimestamp to. This may be NULL. * @return The same value that is written to the location pointed to by ret_ptp_time_ptr. */ CDI_INTERFACE CdiPtpTimestamp CdiCoreGetPtpTimestamp(CdiPtpTimestamp* ret_ptp_time_ptr); /** * Get the current synced AWS network UTC time in microseconds. It uses CdiCoreGetUtcTime(). * * @return Current UTC time in microseconds. */ CDI_INTERFACE uint64_t CdiCoreGetUtcTimeMicroseconds(void); /** * Get the current TAI time in microseconds. * * @return Current TAI time in microseconds. */ CDI_INTERFACE uint64_t CdiCoreGetTaiTimeMicroseconds(); /** * Returns a short string that briefly describes the meaning of an CDI status code. * * @param status The value to be converted to a string. * * @return const char* A character array which describes the requested code. */ CDI_INTERFACE const char* CdiCoreStatusToString(CdiReturnStatus status); /** * Returns the core configuration read-only settings. * * @return Pointer to const structure that contains the settings. */ CDI_INTERFACE const CdiCoreReadOnlySettings* CdiCoreGetSettings(); #endif // CDI_CORE_API_H__