mirror of
https://github.com/openappsec/attachment.git
synced 2025-09-30 11:44:29 +03:00
Istio support (#30)
* adding istio files * fix the envoy CMakList file * fix the envoy CMakList file * adding the .mod file * adding the webhook injector image * adding istio files * adding istio files * fix the envoy CMakList file * fix the envoy CMakList file * adding the .mod file * adding the webhook injector image * adding istio files * pulling from dev * fix the envoy CMakList file * adding istio files * fix missing header * fix wrong name of library * fix envoy CMakeLists * remove cloud guard names * remove cloud guard names * adding istio files * adding istio files * [JIRA] INXT-44274: test agent image * add Daniel fixes * remove zlib library * remove nano attachment ut
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
add_subdirectory(shmem_ipc)
|
||||
add_subdirectory(shmem_ipc_2)
|
||||
add_subdirectory(compression)
|
||||
add_subdirectory(attachments)
|
||||
|
258
core/include/attachments/nano_attachment.h
Executable file
258
core/include/attachments/nano_attachment.h
Executable file
@@ -0,0 +1,258 @@
|
||||
#ifndef __NANO_ATTACHMENT_H__
|
||||
#define __NANO_ATTACHMENT_H__
|
||||
|
||||
#include "nano_attachment_common.h"
|
||||
|
||||
typedef struct NanoAttachment NanoAttachment;
|
||||
|
||||
///
|
||||
/// @brief Initializes a NanoAttachment structure.
|
||||
///
|
||||
/// This function initializes a NanoAttachment structure with the specified parameters and default values.
|
||||
///
|
||||
/// @param attachment_type The type of attachment to initialize.
|
||||
/// @param worker_id The ID of the worker associated with the attachment.
|
||||
/// @param num_of_workers The total number of workers.
|
||||
/// @param logging_fd The file descriptor for logging.
|
||||
///
|
||||
/// @return A pointer to the initialized NanoAttachment structure if the function completes, NULL otherwise.
|
||||
///
|
||||
NanoAttachment * InitNanoAttachment(uint8_t attachment_type, int worker_id, int num_of_workers, int logging_fd);
|
||||
|
||||
///
|
||||
/// @brief Cleans up resources associated with a NanoAttachment structure and deallocates memory.
|
||||
///
|
||||
/// This function performs cleanup operations on a NanoAttachment structure and deallocates
|
||||
/// the memory associated with it.
|
||||
/// The function closes the logging file descriptor associated with the NanoAttachment
|
||||
/// and frees the memory allocated for the structure.
|
||||
///
|
||||
/// @param attachment A pointer to the NanoAttachment structure to be cleaned up.
|
||||
///
|
||||
void FiniNanoAttachment(NanoAttachment *attachment);
|
||||
|
||||
///
|
||||
/// @brief Restarts the configuration of a NanoAttachment.
|
||||
///
|
||||
/// @param attachment A pointer to the NanoAttachment whose configuration is to be restarted.
|
||||
///
|
||||
/// @return A NanoCommunicationResult indicating the success or failure of the operation.
|
||||
|
||||
NanoCommunicationResult RestartAttachmentConfiguration(NanoAttachment *attachment);
|
||||
|
||||
///
|
||||
/// @brief Initializes a HttpSessionData structure with default values.
|
||||
///
|
||||
/// This function dynamically allocates memory for a HttpSessionData structure
|
||||
/// and initializes its fields with default values.
|
||||
///
|
||||
/// @param attachment A pointer to the NanoAttachment structure associated with the session.
|
||||
/// @param session_id The ID of the session to be initialized.
|
||||
///
|
||||
/// @return A pointer to the initialized HttpSessionData structure if the function completes, NULL otherwise.
|
||||
///
|
||||
HttpSessionData * InitSessionData(NanoAttachment *attachment, SessionID session_id);
|
||||
|
||||
///
|
||||
/// @brief Cleans up and deallocates resources associated with a HttpSessionData structure.
|
||||
///
|
||||
/// This function performs cleanup operations on a HttpSessionData structure and deallocates
|
||||
/// the memory associated with it. It writes a debug message indicating the session ID being
|
||||
/// freed, and then frees the memory allocated for the HttpSessionData structure.
|
||||
///
|
||||
/// @param attachment A pointer to the NanoAttachment structure associated with the session.
|
||||
/// @param session_data A pointer to the HttpSessionData structure to be cleaned up.
|
||||
///
|
||||
void FiniSessionData(NanoAttachment *attachment, HttpSessionData *session_data);
|
||||
|
||||
///
|
||||
/// @brief Updates a metric associated with a NanoAttachment.
|
||||
///
|
||||
/// This function updates a metric associated with a NanoAttachment structure
|
||||
/// based on the provided metric type and value. It delegates the actual updating
|
||||
/// of the metric to the helper function updateMetricField.
|
||||
///
|
||||
/// @param attachment A pointer to the NanoAttachment structure associated with the metric.
|
||||
/// @param metric The type of metric to be updated.
|
||||
/// @param value The value to be incorporated into the metric calculation.
|
||||
///
|
||||
void UpdateMetric(NanoAttachment *attachment, AttachmentMetricType metric, uint64_t value);
|
||||
|
||||
///
|
||||
/// @brief Sends metric data that been accumulated in the attachment to the service.
|
||||
///
|
||||
/// @param attachment A pointer to the NanoAttachment structure associated with the metric.
|
||||
///
|
||||
void SendAccumulatedMetricData(NanoAttachment *attachment);
|
||||
|
||||
///
|
||||
/// @brief Processes and sends attachment data to the appropriate handlers.
|
||||
///
|
||||
/// This function processes the attachment data based on its chunk type and sends
|
||||
/// it to the appropriate handler functions. If the chunk type is not recognized,
|
||||
/// it sets a default verdict of ATTACHMENT_VERDICT_INSPECT and returns an AttachmentVerdictResponse
|
||||
/// structure containing the default verdict and the session ID from the provided AttachmentData.
|
||||
///
|
||||
/// @param attachment A pointer to the NanoAttachment structure associated with the data.
|
||||
/// @param data A pointer to the AttachmentData structure containing the data to be processed.
|
||||
///
|
||||
/// @return An AttachmentVerdictResponse structure containing the verdict and session ID.
|
||||
///
|
||||
AttachmentVerdictResponse SendDataNanoAttachment(NanoAttachment *attachment, AttachmentData *data);
|
||||
|
||||
///
|
||||
/// @brief Sends a keep-alive signal using a socket connection.
|
||||
///
|
||||
/// @param attachment A pointer to a NanoAttachment struct containing attachment information.
|
||||
///
|
||||
void SendKeepAlive(NanoAttachment *attachment);
|
||||
|
||||
///
|
||||
/// @brief Checks if a session is finalized based on the session's verdict.
|
||||
///
|
||||
/// @param attachment The NanoAttachment object associated with the session.
|
||||
/// @param session_data The HttpSessionData object representing the session.
|
||||
///
|
||||
/// @return Returns 0 if the session is not finalized, 1 otherwise.
|
||||
///
|
||||
int IsSessionFinalized(NanoAttachment *attachment, HttpSessionData *session_data);
|
||||
|
||||
///
|
||||
/// @brief Checks if the response contains modifications.
|
||||
///
|
||||
/// This function determines whether the provided response contains modifications.
|
||||
///
|
||||
/// @param attachment A pointer to a NanoAttachment structure representing the attachment.
|
||||
/// @param session_data A pointer to a HttpSessionData structure containing session data.
|
||||
/// @param response A pointer to an AttachmentVerdictResponse structure representing the response.
|
||||
///
|
||||
/// @return 1 if the response contains modifications, 0 otherwise.
|
||||
///
|
||||
int IsResponseWithModification(
|
||||
NanoAttachment *attachment,
|
||||
HttpSessionData *session_data,
|
||||
AttachmentVerdictResponse *response
|
||||
);
|
||||
|
||||
///
|
||||
/// @brief Retrieves response modifications from the given attachment and session data.
|
||||
///
|
||||
/// @param attachment Pointer to a NanoAttachment object.
|
||||
/// @param session_data Pointer to HttpSessionData object containing session information.
|
||||
/// @param response Pointer to an AttachmentVerdictResponse object.
|
||||
///
|
||||
/// @return NanoResponseModifications structure containing response modifications.
|
||||
///
|
||||
NanoResponseModifications GetResponseModifications(
|
||||
NanoAttachment *attachment,
|
||||
HttpSessionData *session_data,
|
||||
AttachmentVerdictResponse *response
|
||||
);
|
||||
|
||||
///
|
||||
/// @brief Retrieves the type of web response associated with the given attachment and session data.
|
||||
///
|
||||
/// This function checks if the provided response object contains valid web response data.
|
||||
/// If the response object is null, it logs a warning and returns NO_WEB_RESPONSE.
|
||||
/// Otherwise, it returns the type of web response contained in the response object.
|
||||
///
|
||||
/// @param attachment Pointer to the NanoAttachment structure associated with the request.
|
||||
/// @param session_data Pointer to the HttpSessionData structure containing session-related data.
|
||||
/// @param response Pointer to the AttachmentVerdictResponse structure containing response data.
|
||||
///
|
||||
/// @return The type of web response, or NO_WEB_RESPONSE if no response object is provided.
|
||||
///
|
||||
NanoWebResponseType GetWebResponseType(
|
||||
NanoAttachment *attachment,
|
||||
HttpSessionData *session_data,
|
||||
AttachmentVerdictResponse *response
|
||||
);
|
||||
|
||||
///
|
||||
/// @brief Retrieves the block page data for a response.
|
||||
///
|
||||
/// @param attachment The NanoAttachment object associated with the session.
|
||||
/// @param session_data The HttpSessionData object representing the session.
|
||||
/// @param response The AttachmentVerdictResponse object containing the verdict.
|
||||
///
|
||||
/// @return
|
||||
///
|
||||
BlockPageData GetBlockPage(
|
||||
NanoAttachment *attachment,
|
||||
HttpSessionData *session_data,
|
||||
AttachmentVerdictResponse *response
|
||||
);
|
||||
|
||||
///
|
||||
/// @brief Retrieves the redict page data for a response.
|
||||
///
|
||||
/// @param attachment The NanoAttachment object associated with the session.
|
||||
/// @param session_data The HttpSessionData object representing the session.
|
||||
/// @param response The AttachmentVerdictResponse object containing the verdict.
|
||||
///
|
||||
/// @return
|
||||
///
|
||||
RedirectPageData GetRedirectPage(
|
||||
NanoAttachment *attachment,
|
||||
HttpSessionData *session_data,
|
||||
AttachmentVerdictResponse *response
|
||||
);
|
||||
|
||||
///
|
||||
/// @brief Free allocated resources of an AttachmentVerdictResponse.
|
||||
///
|
||||
/// This function frees the allocated resources of an AttachmentVerdictResponse.
|
||||
///
|
||||
/// @param attachment The NanoAttachment object associated with the session.
|
||||
/// @param session_data The HttpSessionData object representing the session.
|
||||
/// @param response The AttachmentVerdictResponse object to be freed.
|
||||
///
|
||||
void FreeAttachmentResponseContent(
|
||||
NanoAttachment *attachment,
|
||||
HttpSessionData *session_data,
|
||||
AttachmentVerdictResponse *response
|
||||
);
|
||||
|
||||
///
|
||||
/// @brief Compresses HttpBody and return allocated compressed body.
|
||||
///
|
||||
/// @param attachment The NanoAttachment object associated with the session.
|
||||
/// @param session_data The HttpSessionData object representing the session.
|
||||
/// @param bodies The bodies pointer to be compressed.
|
||||
///
|
||||
HttpBody * compressBody(
|
||||
NanoAttachment *attachment,
|
||||
HttpSessionData *session_data,
|
||||
HttpBody *bodies
|
||||
);
|
||||
|
||||
///
|
||||
/// @brief Compresses HttpBody and return allocated compressed body.
|
||||
///
|
||||
/// @param attachment The NanoAttachment object associated with the session.
|
||||
/// @param session_data The HttpSessionData object representing the session.
|
||||
/// @param bodies The bodies pointer to be decompressed.
|
||||
///
|
||||
HttpBody * decompressBody(
|
||||
NanoAttachment *attachment,
|
||||
HttpSessionData *session_data,
|
||||
HttpBody *bodies
|
||||
);
|
||||
|
||||
///
|
||||
/// @brief Free allocated compressed body.
|
||||
///
|
||||
/// This function frees the allocated resources of HttpBody object.
|
||||
///
|
||||
/// @param attachment The NanoAttachment object associated with the session.
|
||||
/// @param session_data The HttpSessionData object representing the session.
|
||||
/// @param bodies The bodies pointer to be freed.
|
||||
///
|
||||
void
|
||||
freeCompressedBody(
|
||||
NanoAttachment *attachment,
|
||||
HttpSessionData *session_data,
|
||||
HttpBody *bodies
|
||||
);
|
||||
|
||||
#endif // __NANO_ATTACHMENT_H__
|
489
core/include/attachments/nano_attachment_common.h
Normal file
489
core/include/attachments/nano_attachment_common.h
Normal file
@@ -0,0 +1,489 @@
|
||||
#ifndef __NANO_ATTACHMENT_COMMON_H__
|
||||
#define __NANO_ATTACHMENT_COMMON_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "compression_utils.h"
|
||||
|
||||
typedef uint32_t SessionID;
|
||||
typedef void* DataBuffer;
|
||||
|
||||
#define MAX_NGINX_UID_LEN 32
|
||||
#define MAX_SHARED_MEM_PATH_LEN 128
|
||||
#define NUM_OF_NGINX_IPC_ELEMENTS 200
|
||||
#define DEFAULT_KEEP_ALIVE_INTERVAL_MSEC 300000u
|
||||
#define SHARED_MEM_PATH "/dev/shm/"
|
||||
#define SHARED_REGISTRATION_SIGNAL_PATH SHARED_MEM_PATH "check-point/cp-nano-attachment-registration"
|
||||
#define SHARED_KEEP_ALIVE_PATH SHARED_MEM_PATH "check-point/cp-nano-attachment-registration-expiration-socket"
|
||||
#define SHARED_VERDICT_SIGNAL_PATH SHARED_MEM_PATH "check-point/cp-nano-http-transaction-handler"
|
||||
#define SHARED_ATTACHMENT_CONF_PATH SHARED_MEM_PATH "cp_nano_http_attachment_conf"
|
||||
#define DEFAULT_STATIC_RESOURCES_PATH SHARED_MEM_PATH "static_resources"
|
||||
#define INJECT_POS_IRRELEVANT -1
|
||||
#define CORRUPTED_SESSION_ID 0
|
||||
#define METRIC_PERIODIC_TIMEOUT 600
|
||||
#define MAX_CONTAINER_ID_LEN 12
|
||||
#define CONTAINER_ID_FILE_PATH "/proc/self/cgroup"
|
||||
#define RESPONSE_PAGE_PARTS 4
|
||||
#define UUID_SIZE 64
|
||||
#define CUSTOM_RESPONSE_TITLE_SIZE 64
|
||||
#define CUSTOM_RESPONSE_BODY_SIZE 128
|
||||
#define REDIRECT_RESPONSE_LOCATION_SIZE 512
|
||||
|
||||
#ifdef __cplusplus
|
||||
typedef enum class NanoWebResponseType
|
||||
#else
|
||||
typedef enum NanoWebResponseType
|
||||
#endif
|
||||
{
|
||||
CUSTOM_WEB_RESPONSE,
|
||||
REDIRECT_WEB_RESPONSE,
|
||||
|
||||
NO_WEB_RESPONSE
|
||||
} NanoWebResponseType;
|
||||
|
||||
#ifdef __cplusplus
|
||||
typedef enum class NanoHttpInspectionMode
|
||||
#else
|
||||
typedef enum NanoHttpInspectionMode
|
||||
#endif
|
||||
{
|
||||
NON_BLOCKING_THREAD,
|
||||
BLOCKING_THREAD,
|
||||
NO_THREAD,
|
||||
|
||||
INSPECTION_MODE_COUNT
|
||||
} NanoHttpInspectionMode;
|
||||
|
||||
#ifdef __cplusplus
|
||||
typedef enum class NanoCommunicationResult
|
||||
#else
|
||||
typedef enum NanoCommunicationResult
|
||||
#endif
|
||||
{
|
||||
NANO_OK,
|
||||
NANO_ERROR,
|
||||
NANO_ABORT,
|
||||
NANO_AGAIN,
|
||||
NANO_HTTP_FORBIDDEN,
|
||||
NANO_DECLINED,
|
||||
NANO_TIMEOUT
|
||||
} NanoCommunicationResult;
|
||||
|
||||
#ifdef __cplusplus
|
||||
typedef enum class nano_http_cp_debug_level
|
||||
#else
|
||||
typedef enum nano_http_cp_debug_level
|
||||
#endif
|
||||
{
|
||||
DBG_LEVEL_TRACE,
|
||||
DBG_LEVEL_DEBUG,
|
||||
DBG_LEVEL_INFO,
|
||||
DBG_LEVEL_WARNING,
|
||||
DBG_LEVEL_ERROR,
|
||||
#ifndef __cplusplus
|
||||
DBG_LEVEL_ASSERT,
|
||||
#endif
|
||||
DBG_LEVEL_COUNT
|
||||
} nano_http_cp_debug_level_e;
|
||||
|
||||
#ifdef __cplusplus
|
||||
typedef enum class AttachmentMetricType
|
||||
#else
|
||||
typedef enum AttachmentMetricType
|
||||
#endif
|
||||
{
|
||||
TRANSPARENTS_COUNT,
|
||||
TOTAL_TRANSPARENTS_TIME,
|
||||
INSPECTION_OPEN_FAILURES_COUNT,
|
||||
INSPECTION_CLOSE_FAILURES_COUNT,
|
||||
INSPECTION_SUCCESSES_COUNT,
|
||||
INJECT_VERDICTS_COUNT,
|
||||
DROP_VERDICTS_COUNT,
|
||||
ACCEPT_VERDICTS_COUNT,
|
||||
IRRELEVANT_VERDICTS_COUNT,
|
||||
RECONF_VERDICTS_COUNT,
|
||||
INSPECT_VERDICTS_COUNT,
|
||||
HOLD_VERDICTS_COUNT,
|
||||
AVERAGE_OVERALL_PPROCESSING_TIME_UNTIL_VERDICT,
|
||||
MAX_OVERALL_PPROCESSING_TIME_UNTIL_VERDICT,
|
||||
MIN_OVERALL_PPROCESSING_TIME_UNTIL_VERDICT,
|
||||
AVERAGE_REQ_PPROCESSING_TIME_UNTIL_VERDICT,
|
||||
MAX_REQ_PPROCESSING_TIME_UNTIL_VERDICT,
|
||||
MIN_REQ_PPROCESSING_TIME_UNTIL_VERDICT,
|
||||
AVERAGE_RES_PPROCESSING_TIME_UNTIL_VERDICT,
|
||||
MAX_RES_PPROCESSING_TIME_UNTIL_VERDICT,
|
||||
MIN_RES_PPROCESSING_TIME_UNTIL_VERDICT,
|
||||
THREAD_TIMEOUT,
|
||||
REG_THREAD_TIMEOUT,
|
||||
REQ_METADATA_THREAD_TIMEOUT,
|
||||
REQ_HEADER_THREAD_TIMEOUT,
|
||||
REQ_BODY_THREAD_TIMEOUT,
|
||||
REQ_END_THREAD_TIMEOUT,
|
||||
AVERAGE_REQ_BODY_SIZE_UPON_TIMEOUT,
|
||||
MAX_REQ_BODY_SIZE_UPON_TIMEOUT,
|
||||
MIN_REQ_BODY_SIZE_UPON_TIMEOUT,
|
||||
RES_HEADER_THREAD_TIMEOUT,
|
||||
RES_BODY_THREAD_TIMEOUT,
|
||||
RES_END_THREAD_TIMEOUT,
|
||||
HOLD_THREAD_TIMEOUT,
|
||||
AVERAGE_RES_BODY_SIZE_UPON_TIMEOUT,
|
||||
MAX_RES_BODY_SIZE_UPON_TIMEOUT,
|
||||
MIN_RES_BODY_SIZE_UPON_TIMEOUT,
|
||||
THREAD_FAILURE,
|
||||
REQ_PROCCESSING_TIMEOUT,
|
||||
RES_PROCCESSING_TIMEOUT,
|
||||
REQ_FAILED_TO_REACH_UPSTREAM,
|
||||
REQ_FAILED_COMPRESSION_COUNT,
|
||||
RES_FAILED_COMPRESSION_COUNT,
|
||||
REQ_FAILED_DECOMPRESSION_COUNT,
|
||||
RES_FAILED_DECOMPRESSION_COUNT,
|
||||
REQ_SUCCESSFUL_COMPRESSION_COUNT,
|
||||
RES_SUCCESSFUL_COMPRESSION_COUNT,
|
||||
REQ_SUCCESSFUL_DECOMPRESSION_COUNT,
|
||||
RES_SUCCESSFUL_DECOMPRESSION_COUNT,
|
||||
CORRUPTED_ZIP_SKIPPED_SESSION_COUNT,
|
||||
CPU_USAGE,
|
||||
AVERAGE_VM_MEMORY_USAGE,
|
||||
AVERAGE_RSS_MEMORY_USAGE,
|
||||
MAX_VM_MEMORY_USAGE,
|
||||
MAX_RSS_MEMORY_USAGE,
|
||||
REQUEST_OVERALL_SIZE_COUNT,
|
||||
RESPONSE_OVERALL_SIZE_COUNT,
|
||||
|
||||
METRIC_TYPES_COUNT
|
||||
} AttachmentMetricType;
|
||||
|
||||
#ifdef __cplusplus
|
||||
typedef enum class AttachmentDataType
|
||||
#else
|
||||
typedef enum AttachmentDataType
|
||||
#endif
|
||||
{
|
||||
REQUEST_START,
|
||||
REQUEST_HEADER,
|
||||
REQUEST_BODY,
|
||||
REQUEST_END,
|
||||
RESPONSE_CODE,
|
||||
RESPONSE_HEADER,
|
||||
RESPONSE_BODY,
|
||||
RESPONSE_END,
|
||||
CONTENT_LENGTH,
|
||||
METRIC_DATA_FROM_PLUGIN,
|
||||
REQUEST_DELAYED_VERDICT
|
||||
} AttachmentDataType;
|
||||
|
||||
#ifdef __cplusplus
|
||||
typedef enum class HttpChunkType
|
||||
#else
|
||||
typedef enum HttpChunkType
|
||||
#endif
|
||||
{
|
||||
HTTP_REQUEST_FILTER,
|
||||
HTTP_REQUEST_METADATA,
|
||||
HTTP_REQUEST_HEADER,
|
||||
HTTP_REQUEST_BODY,
|
||||
HTTP_REQUEST_END,
|
||||
HTTP_RESPONSE_HEADER,
|
||||
HTTP_RESPONSE_BODY,
|
||||
HTTP_RESPONSE_END,
|
||||
HOLD_DATA
|
||||
} HttpChunkType;
|
||||
|
||||
#ifdef __cplusplus
|
||||
typedef enum class ServiceVerdict
|
||||
#else
|
||||
typedef enum ServiceVerdict
|
||||
#endif
|
||||
{
|
||||
TRAFFIC_VERDICT_INSPECT,
|
||||
TRAFFIC_VERDICT_ACCEPT,
|
||||
TRAFFIC_VERDICT_DROP,
|
||||
TRAFFIC_VERDICT_INJECT,
|
||||
TRAFFIC_VERDICT_IRRELEVANT,
|
||||
TRAFFIC_VERDICT_RECONF,
|
||||
TRAFFIC_VERDICT_DELAYED
|
||||
} ServiceVerdict;
|
||||
|
||||
#ifdef __cplusplus
|
||||
typedef enum class AttachmentVerdict
|
||||
#else
|
||||
typedef enum AttachmentVerdict
|
||||
#endif
|
||||
{
|
||||
ATTACHMENT_VERDICT_INSPECT,
|
||||
ATTACHMENT_VERDICT_ACCEPT,
|
||||
ATTACHMENT_VERDICT_DROP,
|
||||
ATTACHMENT_VERDICT_INJECT
|
||||
} AttachmentVerdict;
|
||||
|
||||
#ifdef __cplusplus
|
||||
typedef enum class HttpModificationType
|
||||
#else
|
||||
typedef enum HttpModificationType
|
||||
#endif
|
||||
{
|
||||
APPEND,
|
||||
INJECT,
|
||||
REPLACE
|
||||
} HttpModificationType;
|
||||
|
||||
typedef struct __attribute__((__packed__)) HttpInjectData {
|
||||
int64_t injection_pos;
|
||||
HttpModificationType mod_type;
|
||||
uint16_t injection_size;
|
||||
uint8_t is_header;
|
||||
uint8_t orig_buff_index;
|
||||
char data[0];
|
||||
} HttpInjectData;
|
||||
|
||||
typedef struct __attribute__((__packed__)) HttpWebResponseData {
|
||||
uint8_t web_response_type;
|
||||
uint8_t uuid_size;
|
||||
|
||||
union {
|
||||
struct __attribute__((__packed__)) NanoHttpCpCustomWebResponseData {
|
||||
uint16_t response_code;
|
||||
uint8_t title_size;
|
||||
uint8_t body_size;
|
||||
char data[0];
|
||||
} custom_response_data;
|
||||
|
||||
struct __attribute__((__packed__)) NanoHttpCpRedirectData {
|
||||
uint8_t unused_dummy;
|
||||
uint8_t add_event_id;
|
||||
uint16_t redirect_location_size;
|
||||
char redirect_location[0];
|
||||
} redirect_data;
|
||||
} response_data;
|
||||
} HttpWebResponseData;
|
||||
|
||||
typedef struct {
|
||||
size_t len;
|
||||
unsigned char *data;
|
||||
} nano_str_t;
|
||||
|
||||
typedef struct CustomResponseData {
|
||||
uint16_t response_code;
|
||||
unsigned char title[CUSTOM_RESPONSE_TITLE_SIZE];
|
||||
unsigned char body[CUSTOM_RESPONSE_BODY_SIZE];
|
||||
} CustomResponseData;
|
||||
|
||||
typedef struct RedirectData {
|
||||
unsigned char redirect_location[REDIRECT_RESPONSE_LOCATION_SIZE];
|
||||
} RedirectData;
|
||||
|
||||
typedef struct WebResponseData {
|
||||
NanoWebResponseType web_response_type;
|
||||
unsigned char uuid[UUID_SIZE];
|
||||
DataBuffer data;
|
||||
} WebResponseData;
|
||||
|
||||
#ifdef __cplusplus
|
||||
typedef enum class HttpMetaDataType
|
||||
#else
|
||||
typedef enum HttpMetaDataType
|
||||
#endif
|
||||
{
|
||||
HTTP_PROTOCOL_SIZE,
|
||||
HTTP_PROTOCOL_DATA,
|
||||
HTTP_METHOD_SIZE,
|
||||
HTTP_METHOD_DATA,
|
||||
HOST_NAME_SIZE,
|
||||
HOST_NAME_DATA,
|
||||
LISTENING_ADDR_SIZE,
|
||||
LISTENING_ADDR_DATA,
|
||||
LISTENING_PORT,
|
||||
URI_SIZE,
|
||||
URI_DATA,
|
||||
CLIENT_ADDR_SIZE,
|
||||
CLIENT_ADDR_DATA,
|
||||
CLIENT_PORT,
|
||||
PARSED_HOST_SIZE,
|
||||
PARSED_HOST_DATA,
|
||||
PARSED_URI_SIZE,
|
||||
PARSED_URI_DATA,
|
||||
|
||||
META_DATA_COUNT
|
||||
} HttpMetaDataType;
|
||||
|
||||
#ifdef __cplusplus
|
||||
typedef enum class HttpHeaderDataType
|
||||
#else
|
||||
typedef enum HttpHeaderDataType
|
||||
#endif
|
||||
{
|
||||
HEADER_KEY_SIZE,
|
||||
HEADER_KEY_DATA,
|
||||
HEADER_VAL_SIZE,
|
||||
HEADER_VAL_DATA,
|
||||
|
||||
HEADER_DATA_COUNT
|
||||
} HttpHeaderDataType;
|
||||
|
||||
/// @struct NanoHttpModificationList
|
||||
/// @brief A node that holds all the information regarding modifications.
|
||||
typedef struct NanoHttpModificationList {
|
||||
struct NanoHttpModificationList *next; ///< Next node.
|
||||
HttpInjectData modification; ///< Modification data.
|
||||
char *modification_buffer; ///< Modification buffer used to store extra needed data.
|
||||
} NanoHttpModificationList;
|
||||
|
||||
/// @struct NanoHttpResponseData
|
||||
/// Holds all the data for Compression in a session.
|
||||
typedef struct {
|
||||
|
||||
/// Original compression type, can hold the following values:
|
||||
/// - #GZIP
|
||||
/// - #ZLIB
|
||||
CompressionType compression_type;
|
||||
|
||||
/// Compression stream
|
||||
CompressionStream *compression_stream;
|
||||
|
||||
/// Decompression stream
|
||||
CompressionStream *decompression_stream;
|
||||
} NanoHttpResponseData;
|
||||
|
||||
/// @struct HttpSessionData
|
||||
/// @brief Holds all the session's information needed to communicate with the nano service.
|
||||
/// @details Such as to save verdict and session ID between the request and the response
|
||||
typedef struct HttpSessionData {
|
||||
int was_request_fully_inspected; ///< Holds if the request fully inspected.
|
||||
ServiceVerdict verdict; ///< Holds the session's verdict from the Nano Service.
|
||||
uint32_t session_id; ///< Current session's Id.
|
||||
unsigned int remaining_messages_to_reply; ///< Remaining messages left for the agent to respond to.
|
||||
|
||||
NanoHttpResponseData response_data; ///< Holds session's response data.
|
||||
|
||||
double req_proccesing_time; ///< Holds session's request processing time.
|
||||
double res_proccesing_time; ///< Holds session's response processing time.
|
||||
uint64_t processed_req_body_size; ///< Holds session's request body's size.
|
||||
uint64_t processed_res_body_size; ///< Holds session's response body's size'.
|
||||
} HttpSessionData;
|
||||
|
||||
typedef struct HttpMetaData {
|
||||
nano_str_t http_protocol;
|
||||
nano_str_t method_name;
|
||||
nano_str_t host;
|
||||
nano_str_t listening_ip;
|
||||
uint16_t listening_port;
|
||||
nano_str_t uri;
|
||||
nano_str_t client_ip;
|
||||
uint16_t client_port;
|
||||
nano_str_t parsed_host;
|
||||
nano_str_t parsed_uri;
|
||||
} HttpMetaData;
|
||||
|
||||
typedef struct HttpHeaderData {
|
||||
nano_str_t key;
|
||||
nano_str_t value;
|
||||
} HttpHeaderData;
|
||||
|
||||
typedef struct HttpHeaders {
|
||||
HttpHeaderData *data;
|
||||
size_t headers_count;
|
||||
} HttpHeaders;
|
||||
|
||||
typedef struct HttpRequestFilterData {
|
||||
HttpMetaData *meta_data;
|
||||
HttpHeaders *req_headers;
|
||||
bool contains_body;
|
||||
} HttpRequestFilterData;
|
||||
|
||||
typedef struct ResHttpHeaders {
|
||||
HttpHeaders *headers;
|
||||
uint16_t response_code;
|
||||
uint64_t content_length;
|
||||
} ResHttpHeaders;
|
||||
|
||||
typedef struct HttpBody {
|
||||
nano_str_t *data;
|
||||
size_t bodies_count;
|
||||
} HttpBody;
|
||||
|
||||
typedef struct AttachmentData {
|
||||
SessionID session_id;
|
||||
HttpChunkType chunk_type;
|
||||
HttpSessionData *session_data;
|
||||
DataBuffer data;
|
||||
} AttachmentData;
|
||||
|
||||
typedef union __attribute__((__packed__)) HttpModifyData {
|
||||
HttpInjectData inject_data[0];
|
||||
HttpWebResponseData web_response_data[0];
|
||||
} HttpModifyData;
|
||||
|
||||
typedef struct __attribute__((__packed__)) HttpReplyFromService {
|
||||
uint16_t verdict;
|
||||
SessionID session_id;
|
||||
uint8_t modification_count;
|
||||
HttpModifyData modify_data[0];
|
||||
} HttpReplyFromService;
|
||||
|
||||
typedef struct AttachmentVerdictResponse {
|
||||
AttachmentVerdict verdict;
|
||||
SessionID session_id;
|
||||
WebResponseData *web_response_data;
|
||||
NanoHttpModificationList *modifications;
|
||||
} AttachmentVerdictResponse;
|
||||
|
||||
typedef struct __attribute__((__packed__)) AttachmentRequest {
|
||||
struct __attribute__((__packed__)) connection {
|
||||
int sockaddr;
|
||||
int local_sockaddr;
|
||||
} connection;
|
||||
|
||||
struct __attribute__((__packed__)) http_protocol {
|
||||
int len;
|
||||
int data;
|
||||
} http_protocol;
|
||||
|
||||
struct __attribute__((__packed__)) method {
|
||||
int name;
|
||||
int data;
|
||||
} method;
|
||||
|
||||
struct __attribute__((__packed__)) uri {
|
||||
int len;
|
||||
int data;
|
||||
} uri;
|
||||
|
||||
struct __attribute__((__packed__)) unparsed_uri {
|
||||
int len;
|
||||
int data;
|
||||
} unparsed_uri;
|
||||
} AttachmentRequest;
|
||||
|
||||
typedef struct BlockPageData {
|
||||
uint16_t response_code;
|
||||
nano_str_t title_prefix;
|
||||
nano_str_t title;
|
||||
nano_str_t body_prefix;
|
||||
nano_str_t body;
|
||||
nano_str_t uuid_prefix;
|
||||
nano_str_t uuid;
|
||||
nano_str_t uuid_suffix;
|
||||
} BlockPageData;
|
||||
|
||||
typedef struct RedirectPageData {
|
||||
nano_str_t redirect_location;
|
||||
} RedirectPageData;
|
||||
|
||||
typedef struct NanoResponseModifications {
|
||||
NanoHttpModificationList *modifications;
|
||||
} NanoResponseModifications;
|
||||
|
||||
typedef struct __attribute__((__packed__)) NanoHttpMetricData {
|
||||
uint16_t data_type;
|
||||
#ifdef __cplusplus
|
||||
uint64_t data[static_cast<int>(AttachmentMetricType::METRIC_TYPES_COUNT)];
|
||||
#else
|
||||
uint64_t data[METRIC_TYPES_COUNT];
|
||||
#endif
|
||||
} NanoHttpMetricData;
|
||||
|
||||
#endif // __NANO_ATTACHMENT_COMMON_H__
|
67
core/include/attachments/nano_attachment_util.h
Normal file
67
core/include/attachments/nano_attachment_util.h
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef __NGINX_ATTACHMENT_UTIL__
|
||||
#define __NGINX_ATTACHMENT_UTIL__
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "nano_attachment_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#define IP_STR_MAX_LEN 40
|
||||
|
||||
typedef const char * c_str;
|
||||
|
||||
int initAttachmentConfig(c_str conf_file);
|
||||
|
||||
NanoHttpInspectionMode getInspectionMode();
|
||||
unsigned int getNumOfNginxIpcElements();
|
||||
unsigned int getKeepAliveIntervalMsec();
|
||||
unsigned int getDbgLevel();
|
||||
int isDebugContext(c_str client, c_str server, unsigned int port, c_str method, c_str host, c_str uri);
|
||||
c_str getStaticResourcesPath();
|
||||
|
||||
int isFailOpenMode();
|
||||
unsigned int getFailOpenTimeout();
|
||||
|
||||
int isFailOpenHoldMode();
|
||||
unsigned int getFailOpenHoldTimeout();
|
||||
|
||||
unsigned int getMaxSessionsPerMinute();
|
||||
int isFailOpenOnSessionLimit();
|
||||
|
||||
unsigned int getRegistrationThreadTimeout();
|
||||
|
||||
unsigned int getReqProccessingTimeout();
|
||||
unsigned int getReqHeaderThreadTimeout();
|
||||
unsigned int getReqBodyThreadTimeout();
|
||||
|
||||
unsigned int getResProccessingTimeout();
|
||||
unsigned int getResHeaderThreadTimeout();
|
||||
unsigned int getResBodyThreadTimeout();
|
||||
|
||||
unsigned int getWaitingForVerdictThreadTimeout();
|
||||
|
||||
int isIPAddress(c_str ip_str);
|
||||
int isSkipSource(c_str ip_str);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __NGINX_ATTACHMENT_UTIL__
|
79
core/include/attachments/shmem_ipc_2.h
Executable file
79
core/include/attachments/shmem_ipc_2.h
Executable file
@@ -0,0 +1,79 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef __SHMEM_IPC_H__
|
||||
#define __SHMEM_IPC_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif // __cplusplus
|
||||
|
||||
typedef struct LoggingData LoggingData;
|
||||
typedef struct SharedMemoryIPC SharedMemoryIPC;
|
||||
extern const int corrupted_shmem_error;
|
||||
|
||||
LoggingData * initLoggingData(int dbg_level, int worker_id, int fd);
|
||||
|
||||
SharedMemoryIPC * initIpc(
|
||||
const char queue_name[32],
|
||||
const uint32_t user_id,
|
||||
const uint32_t group_id,
|
||||
int is_owner,
|
||||
uint16_t num_of_queue_elem,
|
||||
const LoggingData *logging_data,
|
||||
void (*debug_func)(
|
||||
const LoggingData *loggin_data,
|
||||
uint32_t worker_id,
|
||||
int is_error,
|
||||
const char *func,
|
||||
const char *file,
|
||||
int line_num,
|
||||
const char *fmt,
|
||||
...
|
||||
)
|
||||
);
|
||||
|
||||
void destroyIpc(SharedMemoryIPC *ipc, int is_owner);
|
||||
|
||||
int sendData(SharedMemoryIPC *ipc, const uint16_t data_to_send_size, const char *data_to_send);
|
||||
|
||||
int
|
||||
sendChunkedData(
|
||||
SharedMemoryIPC *ipc,
|
||||
const uint16_t *data_to_send_sizes,
|
||||
const char **data_elem_to_send,
|
||||
const uint8_t num_of_data_elem
|
||||
);
|
||||
|
||||
int receiveData(SharedMemoryIPC *ipc, uint16_t *received_data_size, const char **received_data);
|
||||
|
||||
int popData(SharedMemoryIPC *ipc);
|
||||
|
||||
int isDataAvailable(SharedMemoryIPC *ipc);
|
||||
|
||||
void resetIpc(SharedMemoryIPC *ipc, uint16_t num_of_data_segments);
|
||||
|
||||
void dumpIpcMemory(SharedMemoryIPC *ipc);
|
||||
|
||||
int isCorruptedShmem(SharedMemoryIPC *ipc, int is_owner);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // __SHMEM_IPC_H__
|
6
core/shmem_ipc_2/CMakeLists.txt
Executable file
6
core/shmem_ipc_2/CMakeLists.txt
Executable file
@@ -0,0 +1,6 @@
|
||||
add_library(shmem_ipc_2 SHARED shmem_ipc.c shared_ring_queue.c)
|
||||
|
||||
target_link_libraries(shmem_ipc_2 -lrt)
|
||||
|
||||
install(TARGETS shmem_ipc_2 DESTINATION lib)
|
||||
install(TARGETS shmem_ipc_2 DESTINATION nginx_attachment/lib PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ)
|
55
core/shmem_ipc_2/shared_ipc_debug.h
Executable file
55
core/shmem_ipc_2/shared_ipc_debug.h
Executable file
@@ -0,0 +1,55 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef __SHARED_IPC_DEBUG_H__
|
||||
#define __SHARED_IPC_DEBUG_H__
|
||||
|
||||
typedef struct LoggingData {
|
||||
int dbg_level;
|
||||
int worker_id;
|
||||
int fd;
|
||||
} LoggingData;
|
||||
|
||||
extern void (*debug_int)(
|
||||
const LoggingData *loggin_data,
|
||||
uint32_t worker_id,
|
||||
int is_error,
|
||||
const char *func,
|
||||
const char *file,
|
||||
int line_num,
|
||||
const char *fmt,
|
||||
...
|
||||
);
|
||||
|
||||
#ifndef __FILENAME__
|
||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
|
||||
#endif
|
||||
|
||||
enum debugLevel { TraceLevel = 0, DebugLevel = 1, WarningLevel = 3 };
|
||||
|
||||
#define writeDebug(logging_data, debug_level, fmt, ...) \
|
||||
{ \
|
||||
debug_int( \
|
||||
logging_data, \
|
||||
(logging_data)->worker_id, \
|
||||
debug_level, \
|
||||
__func__, \
|
||||
__FILENAME__, \
|
||||
__LINE__, \
|
||||
fmt, \
|
||||
##__VA_ARGS__ \
|
||||
); \
|
||||
}
|
||||
|
||||
#endif // __SHARED_IPC_DEBUG_H__
|
652
core/shmem_ipc_2/shared_ring_queue.c
Executable file
652
core/shmem_ipc_2/shared_ring_queue.c
Executable file
@@ -0,0 +1,652 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT 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 "shared_ring_queue.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "shared_ipc_debug.h"
|
||||
|
||||
static const uint16_t empty_buff_mgmt_magic = 0xfffe;
|
||||
static const uint16_t skip_buff_mgmt_magic = 0xfffd;
|
||||
static const uint32_t max_write_size = 0xfffc;
|
||||
const uint16_t max_num_of_data_segments = sizeof(DataSegment)/sizeof(uint16_t);
|
||||
|
||||
// LCOV_EXCL_START Reason: Handing it to Envoy prototype development
|
||||
|
||||
static int
|
||||
getNumOfDataSegmentsNeeded(LoggingData *logging_data, uint16_t data_size)
|
||||
{
|
||||
int res = (data_size + SHARED_MEMORY_SEGMENT_ENTRY_SIZE - 1) / SHARED_MEMORY_SEGMENT_ENTRY_SIZE;
|
||||
writeDebug(
|
||||
logging_data,
|
||||
TraceLevel,
|
||||
"Checking amount of segments needed. Res: %d, data size: %u, shmem entry size: %u",
|
||||
res,
|
||||
data_size,
|
||||
SHARED_MEMORY_SEGMENT_ENTRY_SIZE
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
isThereEnoughMemoryInQueue(
|
||||
LoggingData *logging_data,
|
||||
SharedRingGlobalData *global_data,
|
||||
uint16_t write_pos,
|
||||
uint16_t read_pos,
|
||||
uint8_t num_of_elem_to_push
|
||||
)
|
||||
{
|
||||
int res;
|
||||
|
||||
writeDebug(
|
||||
logging_data,
|
||||
TraceLevel, "Checking if memory has space for new elements. "
|
||||
"Num of elements to push: %u, write index: %u, read index: %u, amount of queue segments: %u",
|
||||
num_of_elem_to_push,
|
||||
write_pos,
|
||||
read_pos,
|
||||
global_data->g_num_of_data_segments
|
||||
);
|
||||
if (num_of_elem_to_push >= global_data->g_num_of_data_segments) {
|
||||
writeDebug(
|
||||
logging_data,
|
||||
TraceLevel,
|
||||
"Amount of elements to push is larger then amount of available elements in the queue"
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// add skipped elements during write that does not fit from cur write position till end of queue
|
||||
if (write_pos + num_of_elem_to_push > global_data->g_num_of_data_segments) {
|
||||
num_of_elem_to_push += global_data->g_num_of_data_segments - write_pos;
|
||||
}
|
||||
|
||||
// removing the aspect of circularity in queue and simulating as if the queue continued at its end
|
||||
if (write_pos + num_of_elem_to_push >= global_data->g_num_of_data_segments) {
|
||||
read_pos += global_data->g_num_of_data_segments;
|
||||
}
|
||||
|
||||
res = write_pos + num_of_elem_to_push < read_pos || write_pos >= read_pos;
|
||||
writeDebug(logging_data, TraceLevel, "Finished checking if there is enough place in shared memory. Res: %d", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
isGetPossitionSucceccful(
|
||||
SharedRingQueue *queue,
|
||||
SharedRingGlobalData *global_data,
|
||||
uint16_t *read_pos,
|
||||
uint16_t *write_pos
|
||||
)
|
||||
{
|
||||
if (global_data->g_num_of_data_segments == 0) return 0;
|
||||
|
||||
*read_pos = queue->read_pos;
|
||||
*write_pos = queue->write_pos;
|
||||
|
||||
if (queue->num_of_data_segments != global_data->g_num_of_data_segments) return 0;
|
||||
if (queue->size_of_memory != global_data->g_memory_size) return 0;
|
||||
if (*read_pos > global_data->g_num_of_data_segments) return 0;
|
||||
if (*write_pos > global_data->g_num_of_data_segments) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
resetRingQueue(LoggingData *logging_data, SharedRingQueue *queue, uint16_t num_of_data_segments)
|
||||
{
|
||||
(void)logging_data;
|
||||
uint16_t *buffer_mgmt;
|
||||
unsigned int idx;
|
||||
|
||||
queue->read_pos = 0;
|
||||
queue->write_pos = 0;
|
||||
queue->num_of_data_segments = num_of_data_segments;
|
||||
buffer_mgmt = (uint16_t *)queue->mgmt_segment.data;
|
||||
for (idx = 0; idx < queue->num_of_data_segments; idx++) {
|
||||
buffer_mgmt[idx] = empty_buff_mgmt_magic;
|
||||
}
|
||||
}
|
||||
|
||||
SharedRingGlobalData *
|
||||
createSharedRingGlobalData(LoggingData *logging_data)
|
||||
{
|
||||
SharedRingGlobalData *global_data = (SharedRingGlobalData *)malloc(sizeof(SharedRingGlobalData));
|
||||
if (global_data == NULL) {
|
||||
writeDebug(logging_data, WarningLevel, "Failed to allocate memory for global data\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
global_data->g_rx_fd = -1;
|
||||
global_data->g_tx_fd = -1;
|
||||
global_data->g_memory_size = -1;
|
||||
global_data->g_rx_location_name[0] = '\0';
|
||||
global_data->g_tx_location_name[0] = '\0';
|
||||
global_data->g_num_of_data_segments = 0;
|
||||
|
||||
return global_data;
|
||||
}
|
||||
|
||||
SharedRingQueue *
|
||||
createSharedRingQueue(
|
||||
LoggingData *logging_data,
|
||||
const char *shared_location_name,
|
||||
uint16_t num_of_data_segments,
|
||||
int is_owner,
|
||||
int is_tx,
|
||||
SharedRingGlobalData *global_data
|
||||
)
|
||||
{
|
||||
SharedRingQueue *queue = NULL;
|
||||
uint16_t *buffer_mgmt;
|
||||
uint16_t shmem_fd_flags = is_owner ? O_RDWR | O_CREAT : O_RDWR;
|
||||
int32_t fd = -1;
|
||||
uint32_t size_of_memory;
|
||||
unsigned int idx;
|
||||
|
||||
writeDebug(logging_data, TraceLevel, "Creating a new shared ring queue");
|
||||
|
||||
if (num_of_data_segments > max_num_of_data_segments) {
|
||||
writeDebug(
|
||||
logging_data,
|
||||
WarningLevel,
|
||||
"createSharedRingQueue: Cannot create data segment with %d elements (max number of elements is %u)\n",
|
||||
num_of_data_segments,
|
||||
max_num_of_data_segments
|
||||
);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
global_data->g_num_of_data_segments = num_of_data_segments;
|
||||
|
||||
fd = shm_open(shared_location_name, shmem_fd_flags, S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
if (fd == -1) {
|
||||
writeDebug(
|
||||
logging_data,
|
||||
WarningLevel,
|
||||
"createSharedRingQueue: Failed to open shared memory for '%s'. Errno: %d\n",
|
||||
shared_location_name,
|
||||
errno
|
||||
);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_of_memory = sizeof(SharedRingQueue) + (num_of_data_segments * sizeof(DataSegment));
|
||||
if (is_owner && ftruncate(fd, size_of_memory + 1) != 0) {
|
||||
writeDebug(
|
||||
logging_data,
|
||||
WarningLevel,
|
||||
"createSharedRingQueue: Failed to ftruncate shared memory '%s' to size '%x'\n",
|
||||
shared_location_name,
|
||||
size_of_memory
|
||||
);
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
queue = (SharedRingQueue *)mmap(0, size_of_memory, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (queue == NULL) {
|
||||
writeDebug(
|
||||
logging_data,
|
||||
WarningLevel,
|
||||
"createSharedRingQueue: Error allocating queue for '%s' of size=%x\n",
|
||||
shared_location_name,
|
||||
size_of_memory
|
||||
);
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (is_owner) {
|
||||
snprintf(queue->shared_location_name, MAX_ONE_WAY_QUEUE_NAME_LENGTH, "%s", shared_location_name);
|
||||
queue->num_of_data_segments = num_of_data_segments;
|
||||
queue->read_pos = 0;
|
||||
queue->write_pos = 0;
|
||||
queue->size_of_memory = size_of_memory;
|
||||
buffer_mgmt = (uint16_t *)queue->mgmt_segment.data;
|
||||
for (idx = 0; idx < queue->num_of_data_segments; idx++) {
|
||||
buffer_mgmt[idx] = empty_buff_mgmt_magic;
|
||||
}
|
||||
queue->owner_fd = fd;
|
||||
} else {
|
||||
queue->user_fd = fd;
|
||||
}
|
||||
|
||||
global_data->g_memory_size = size_of_memory;
|
||||
if (is_tx) {
|
||||
global_data->g_tx_fd = fd;
|
||||
snprintf(global_data->g_tx_location_name, MAX_ONE_WAY_QUEUE_NAME_LENGTH, "%s", shared_location_name);
|
||||
} else {
|
||||
global_data->g_rx_fd = fd;
|
||||
snprintf(global_data->g_rx_location_name, MAX_ONE_WAY_QUEUE_NAME_LENGTH, "%s", shared_location_name);
|
||||
}
|
||||
|
||||
writeDebug(
|
||||
logging_data,
|
||||
TraceLevel,
|
||||
"Successfully created a new shared ring queue. "
|
||||
"Shared memory path: %s, number of segments: %u, is owner: %d, "
|
||||
"fd flags: %u, fd: %d, memory size: %u, read index: %u, write index: %u",
|
||||
shared_location_name,
|
||||
queue->num_of_data_segments,
|
||||
is_owner,
|
||||
shmem_fd_flags,
|
||||
fd,
|
||||
queue->size_of_memory,
|
||||
queue->read_pos,
|
||||
queue->write_pos
|
||||
);
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
void
|
||||
destroySharedRingQueue(
|
||||
LoggingData *logging_data,
|
||||
SharedRingQueue *queue,
|
||||
SharedRingGlobalData *global_data,
|
||||
int is_owner,
|
||||
int is_tx
|
||||
)
|
||||
{
|
||||
uint32_t size_of_memory = global_data->g_memory_size;
|
||||
int32_t fd = 0;
|
||||
|
||||
if(is_owner) {
|
||||
queue->owner_fd = 0;
|
||||
} else {
|
||||
queue->user_fd = 0;
|
||||
}
|
||||
|
||||
if (is_tx) {
|
||||
fd = global_data->g_tx_fd;
|
||||
global_data->g_tx_fd = -1;
|
||||
} else {
|
||||
fd = global_data->g_rx_fd;
|
||||
global_data->g_rx_fd = -1;
|
||||
}
|
||||
|
||||
if (munmap(queue, size_of_memory) != 0) {
|
||||
writeDebug(logging_data, WarningLevel, "destroySharedRingQueue: Failed to unmap shared ring queue\n");
|
||||
}
|
||||
if (fd > 0) close(fd);
|
||||
fd = 0;
|
||||
|
||||
// shm_open cleanup
|
||||
if(is_owner) {
|
||||
shm_unlink(is_tx ? global_data->g_tx_location_name : global_data->g_rx_location_name);
|
||||
}
|
||||
writeDebug(logging_data, TraceLevel, "Successfully destroyed shared ring queue. Is owner: %d", is_owner);
|
||||
}
|
||||
|
||||
void
|
||||
dumpRingQueueShmem(LoggingData *logging_data, SharedRingQueue *queue)
|
||||
{
|
||||
uint16_t segment_idx;
|
||||
uint16_t data_idx;
|
||||
uint16_t *buffer_mgmt = NULL;
|
||||
char data_byte;
|
||||
|
||||
writeDebug(
|
||||
logging_data,
|
||||
WarningLevel,
|
||||
"owner_fd: %d, user_fd: %d, size_of_memory: %d, write_pos: %d, read_pos: %d, num_of_data_segments: %d\n",
|
||||
queue->owner_fd,
|
||||
queue->user_fd,
|
||||
queue->size_of_memory,
|
||||
queue->write_pos,
|
||||
queue->read_pos,
|
||||
queue->num_of_data_segments
|
||||
);
|
||||
|
||||
writeDebug(logging_data, WarningLevel, "mgmt_segment:");
|
||||
buffer_mgmt = (uint16_t *)queue->mgmt_segment.data;
|
||||
for (segment_idx = 0; segment_idx < queue->num_of_data_segments; segment_idx++) {
|
||||
writeDebug(logging_data, WarningLevel, "%s%u", (segment_idx == 0 ? " " : ", "), buffer_mgmt[segment_idx]);
|
||||
}
|
||||
|
||||
writeDebug(logging_data, WarningLevel, "\ndata_segment: ");
|
||||
for (segment_idx = 0; segment_idx < queue->num_of_data_segments; segment_idx++) {
|
||||
writeDebug(
|
||||
logging_data,
|
||||
WarningLevel,
|
||||
"\nMgmt index: %u, value: %u,\nactual data: ",
|
||||
segment_idx,
|
||||
buffer_mgmt[segment_idx]
|
||||
);
|
||||
for (data_idx = 0; data_idx < SHARED_MEMORY_SEGMENT_ENTRY_SIZE; data_idx++) {
|
||||
data_byte = queue->data_segment[segment_idx].data[data_idx];
|
||||
writeDebug(logging_data, WarningLevel, isprint(data_byte) ? "%c" : "%02X", data_byte);
|
||||
}
|
||||
}
|
||||
writeDebug(logging_data, WarningLevel, "\nEnd of memory\n");
|
||||
}
|
||||
|
||||
int
|
||||
peekToQueue(
|
||||
LoggingData *logging_data,
|
||||
SharedRingQueue *queue,
|
||||
SharedRingGlobalData *global_data,
|
||||
const char **output_buffer,
|
||||
uint16_t *output_buffer_size
|
||||
)
|
||||
{
|
||||
uint16_t read_pos;
|
||||
uint16_t write_pos;
|
||||
uint16_t *buffer_mgmt = (uint16_t *)queue->mgmt_segment.data;
|
||||
|
||||
if (!isGetPossitionSucceccful(queue, global_data, &read_pos, &write_pos)) {
|
||||
writeDebug(logging_data, WarningLevel, "Corrupted shared memory - cannot peek");
|
||||
return -1;
|
||||
}
|
||||
|
||||
writeDebug(
|
||||
logging_data,
|
||||
TraceLevel,
|
||||
"Reading data from queue. Read index: %u, number of queue elements: %u",
|
||||
read_pos,
|
||||
global_data->g_num_of_data_segments
|
||||
);
|
||||
|
||||
if (read_pos == write_pos) {
|
||||
writeDebug(logging_data, WarningLevel, "peekToQueue: Failed to read from an empty queue\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (read_pos >= global_data->g_num_of_data_segments) {
|
||||
writeDebug(
|
||||
logging_data,
|
||||
WarningLevel,
|
||||
"peekToQueue: Failed to read from a corrupted queue! (read_pos= %d > num_of_data_segments=%d)\n",
|
||||
read_pos,
|
||||
global_data->g_num_of_data_segments
|
||||
);
|
||||
return CORRUPTED_SHMEM_ERROR;
|
||||
}
|
||||
|
||||
if (buffer_mgmt[read_pos] == skip_buff_mgmt_magic) {
|
||||
for ( ; read_pos < global_data->g_num_of_data_segments &&
|
||||
buffer_mgmt[read_pos] == skip_buff_mgmt_magic;
|
||||
++read_pos) {
|
||||
buffer_mgmt[read_pos] = empty_buff_mgmt_magic;
|
||||
}
|
||||
}
|
||||
|
||||
if (read_pos == global_data->g_num_of_data_segments) read_pos = 0;
|
||||
|
||||
*output_buffer_size = buffer_mgmt[read_pos];
|
||||
*output_buffer = queue->data_segment[read_pos].data;
|
||||
|
||||
queue->read_pos = read_pos;
|
||||
|
||||
writeDebug(
|
||||
logging_data,
|
||||
TraceLevel,
|
||||
"Successfully read data from queue. Data size: %u, new Read index: %u",
|
||||
*output_buffer_size,
|
||||
queue->read_pos
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
pushBuffersToQueue(
|
||||
LoggingData *logging_data,
|
||||
SharedRingQueue *queue,
|
||||
SharedRingGlobalData *global_data,
|
||||
const char **input_buffers,
|
||||
const uint16_t *input_buffers_sizes,
|
||||
const uint8_t num_of_input_buffers
|
||||
)
|
||||
{
|
||||
int idx;
|
||||
uint32_t large_total_elem_size = 0;
|
||||
uint16_t read_pos;
|
||||
uint16_t write_pos;
|
||||
uint16_t total_elem_size;
|
||||
uint16_t *buffer_mgmt = (uint16_t *)queue->mgmt_segment.data;
|
||||
uint16_t end_pos;
|
||||
uint16_t num_of_segments_to_write;
|
||||
char *current_copy_pos;
|
||||
|
||||
if (!isGetPossitionSucceccful(queue, global_data, &read_pos, &write_pos)) {
|
||||
writeDebug(logging_data, WarningLevel, "Corrupted shared memory - cannot push new buffers");
|
||||
return -1;
|
||||
}
|
||||
|
||||
writeDebug(
|
||||
logging_data,
|
||||
TraceLevel,
|
||||
"Writing new data to queue. write index: %u, number of queue elements: %u, number of elements to push: %u",
|
||||
write_pos,
|
||||
global_data->g_num_of_data_segments,
|
||||
num_of_input_buffers
|
||||
);
|
||||
|
||||
for (idx = 0; idx < num_of_input_buffers; idx++) {
|
||||
large_total_elem_size += input_buffers_sizes[idx];
|
||||
|
||||
if (large_total_elem_size > max_write_size) {
|
||||
writeDebug(
|
||||
logging_data,
|
||||
WarningLevel,
|
||||
"Requested write size %u exceeds the %u write limit",
|
||||
large_total_elem_size,
|
||||
max_write_size
|
||||
);
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
total_elem_size = (uint16_t)large_total_elem_size;
|
||||
|
||||
num_of_segments_to_write = getNumOfDataSegmentsNeeded(logging_data, total_elem_size);
|
||||
|
||||
writeDebug(
|
||||
logging_data,
|
||||
TraceLevel,
|
||||
"Checking if there is enough space to push new data. Total new data size: %u, number of segments needed: %u",
|
||||
total_elem_size,
|
||||
num_of_segments_to_write
|
||||
);
|
||||
|
||||
|
||||
if (!isThereEnoughMemoryInQueue(logging_data, global_data, write_pos, read_pos, num_of_segments_to_write)) {
|
||||
writeDebug(logging_data, DebugLevel, "Cannot write to a full queue");
|
||||
return -3;
|
||||
}
|
||||
|
||||
if (write_pos >= global_data->g_num_of_data_segments) {
|
||||
writeDebug(
|
||||
logging_data,
|
||||
DebugLevel,
|
||||
"Cannot write to a location outside the queue. Write index: %u, number of queue elements: %u",
|
||||
write_pos,
|
||||
global_data->g_num_of_data_segments
|
||||
);
|
||||
return -4;
|
||||
}
|
||||
|
||||
if (write_pos + num_of_segments_to_write > global_data->g_num_of_data_segments) {
|
||||
for ( ; write_pos < global_data->g_num_of_data_segments; ++write_pos) {
|
||||
buffer_mgmt[write_pos] = skip_buff_mgmt_magic;
|
||||
}
|
||||
write_pos = 0;
|
||||
}
|
||||
|
||||
writeDebug(
|
||||
logging_data,
|
||||
TraceLevel,
|
||||
"Setting new management data. Write index: %u, total elements in index: %u",
|
||||
write_pos,
|
||||
total_elem_size
|
||||
);
|
||||
|
||||
buffer_mgmt[write_pos] = total_elem_size;
|
||||
current_copy_pos = queue->data_segment[write_pos].data;
|
||||
for (idx = 0; idx < num_of_input_buffers; idx++) {
|
||||
writeDebug(
|
||||
logging_data,
|
||||
TraceLevel,
|
||||
"Writing data to queue. Data index: %u, data size: %u, copy destination: %p",
|
||||
idx,
|
||||
input_buffers_sizes[idx],
|
||||
current_copy_pos
|
||||
);
|
||||
memcpy(current_copy_pos, input_buffers[idx], input_buffers_sizes[idx]);
|
||||
current_copy_pos += input_buffers_sizes[idx];
|
||||
}
|
||||
write_pos++;
|
||||
|
||||
end_pos = write_pos + num_of_segments_to_write - 1;
|
||||
for ( ; write_pos < end_pos; ++write_pos) {
|
||||
buffer_mgmt[write_pos] = skip_buff_mgmt_magic;
|
||||
}
|
||||
|
||||
if (write_pos >= global_data->g_num_of_data_segments) write_pos = 0;
|
||||
queue->write_pos = write_pos;
|
||||
writeDebug(logging_data, TraceLevel, "Successfully pushed data to queue. New write index: %u", write_pos);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
pushToQueue(
|
||||
LoggingData *logging_data,
|
||||
SharedRingQueue *queue,
|
||||
SharedRingGlobalData *global_data,
|
||||
const char *input_buffer,
|
||||
const uint16_t input_buffer_size
|
||||
)
|
||||
{
|
||||
return pushBuffersToQueue(logging_data, queue, global_data, &input_buffer, &input_buffer_size, 1);
|
||||
}
|
||||
|
||||
int
|
||||
popFromQueue(LoggingData *logging_data, SharedRingQueue *queue, SharedRingGlobalData *global_data)
|
||||
{
|
||||
uint16_t num_of_read_segments;
|
||||
uint16_t read_pos;
|
||||
uint16_t write_pos;
|
||||
uint16_t end_pos;
|
||||
uint16_t *buffer_mgmt = (uint16_t *)queue->mgmt_segment.data;
|
||||
|
||||
if (!isGetPossitionSucceccful(queue, global_data, &read_pos, &write_pos)) {
|
||||
writeDebug(logging_data, WarningLevel, "Corrupted shared memory - cannot pop data");
|
||||
return -1;
|
||||
}
|
||||
|
||||
writeDebug(
|
||||
logging_data,
|
||||
TraceLevel,
|
||||
"Removing data from queue. new data to queue. Read index: %u, number of queue elements: %u",
|
||||
read_pos,
|
||||
global_data->g_num_of_data_segments
|
||||
);
|
||||
|
||||
if (read_pos == write_pos) {
|
||||
writeDebug(logging_data, TraceLevel, "Cannot pop data from empty queue");
|
||||
return -1;
|
||||
}
|
||||
num_of_read_segments = getNumOfDataSegmentsNeeded(logging_data, buffer_mgmt[read_pos]);
|
||||
|
||||
if (read_pos + num_of_read_segments > global_data->g_num_of_data_segments) {
|
||||
for ( ; read_pos < global_data->g_num_of_data_segments; ++read_pos ) {
|
||||
buffer_mgmt[read_pos] = empty_buff_mgmt_magic;
|
||||
}
|
||||
read_pos = 0;
|
||||
}
|
||||
|
||||
end_pos = read_pos + num_of_read_segments;
|
||||
|
||||
for ( ; read_pos < end_pos; ++read_pos ) {
|
||||
buffer_mgmt[read_pos] = empty_buff_mgmt_magic;
|
||||
}
|
||||
|
||||
if (read_pos < global_data->g_num_of_data_segments && buffer_mgmt[read_pos] == skip_buff_mgmt_magic) {
|
||||
for ( ; read_pos < global_data->g_num_of_data_segments; ++read_pos ) {
|
||||
buffer_mgmt[read_pos] = empty_buff_mgmt_magic;
|
||||
}
|
||||
}
|
||||
|
||||
writeDebug(
|
||||
logging_data,
|
||||
TraceLevel,
|
||||
"Size of data to remove: %u, number of queue elements to free: %u, current read index: %u, end index: %u",
|
||||
buffer_mgmt[read_pos],
|
||||
num_of_read_segments,
|
||||
read_pos,
|
||||
end_pos
|
||||
);
|
||||
|
||||
if (read_pos == global_data->g_num_of_data_segments) read_pos = 0;
|
||||
|
||||
queue->read_pos = read_pos;
|
||||
writeDebug(logging_data, TraceLevel, "Successfully popped data from queue. New read index: %u", read_pos);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
isQueueEmpty(SharedRingQueue *queue)
|
||||
{
|
||||
return queue->read_pos == queue->write_pos;
|
||||
}
|
||||
|
||||
int
|
||||
isCorruptedQueue(LoggingData *logging_data, SharedRingQueue *queue, SharedRingGlobalData *global_data, int is_tx)
|
||||
{
|
||||
writeDebug(
|
||||
logging_data,
|
||||
TraceLevel,
|
||||
"Checking if shared ring queue is corrupted. "
|
||||
"g_num_of_data_segments = %u, queue->num_of_data_segments = %u, queue->read_pos = %u, queue->write_pos = %u, "
|
||||
"g_memory_size = %d, queue->size_of_memory = %d, "
|
||||
"queue->shared_location_name = %s, g_tx_location_name = %s, g_rx_location_name = %s, is_tx = %d",
|
||||
global_data->g_num_of_data_segments,
|
||||
queue->num_of_data_segments,
|
||||
queue->read_pos,
|
||||
queue->write_pos,
|
||||
global_data->g_memory_size,
|
||||
queue->size_of_memory,
|
||||
queue->shared_location_name,
|
||||
global_data->g_tx_location_name,
|
||||
global_data->g_rx_location_name,
|
||||
is_tx
|
||||
);
|
||||
|
||||
if (global_data->g_num_of_data_segments == 0) return 0;
|
||||
|
||||
if (queue->num_of_data_segments != global_data->g_num_of_data_segments) return 1;
|
||||
if (queue->size_of_memory != global_data->g_memory_size) return 1;
|
||||
if (queue->read_pos > global_data->g_num_of_data_segments) return 1;
|
||||
if (queue->write_pos > global_data->g_num_of_data_segments) return 1;
|
||||
if (strcmp(
|
||||
queue->shared_location_name,
|
||||
is_tx ? global_data->g_tx_location_name : global_data->g_rx_location_name
|
||||
) != 0
|
||||
) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
114
core/shmem_ipc_2/shared_ring_queue.h
Executable file
114
core/shmem_ipc_2/shared_ring_queue.h
Executable file
@@ -0,0 +1,114 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef __SHARED_RING_QUEUE_H__
|
||||
#define __SHARED_RING_QUEUE_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif // __cplusplus
|
||||
|
||||
#define SHARED_MEMORY_SEGMENT_ENTRY_SIZE 1024
|
||||
#define MAX_ONE_WAY_QUEUE_NAME_LENGTH 64
|
||||
#define CORRUPTED_SHMEM_ERROR -2
|
||||
|
||||
typedef struct LoggingData LoggingData;
|
||||
|
||||
typedef struct SharedRingGlobalData {
|
||||
char g_rx_location_name[MAX_ONE_WAY_QUEUE_NAME_LENGTH];
|
||||
char g_tx_location_name[MAX_ONE_WAY_QUEUE_NAME_LENGTH];
|
||||
int32_t g_rx_fd;
|
||||
int32_t g_tx_fd;
|
||||
int32_t g_memory_size;
|
||||
uint16_t g_num_of_data_segments;
|
||||
} SharedRingGlobalData;
|
||||
|
||||
typedef struct DataSegment {
|
||||
char data[SHARED_MEMORY_SEGMENT_ENTRY_SIZE];
|
||||
} DataSegment;
|
||||
|
||||
typedef struct __attribute__((__packed__)) SharedRingQueue {
|
||||
char shared_location_name[MAX_ONE_WAY_QUEUE_NAME_LENGTH];
|
||||
int32_t owner_fd;
|
||||
int32_t user_fd;
|
||||
int32_t size_of_memory;
|
||||
uint16_t write_pos;
|
||||
uint16_t read_pos;
|
||||
uint16_t num_of_data_segments;
|
||||
DataSegment mgmt_segment;
|
||||
DataSegment data_segment[0];
|
||||
} SharedRingQueue;
|
||||
|
||||
SharedRingQueue *
|
||||
createSharedRingQueue(
|
||||
LoggingData *logging_data,
|
||||
const char *shared_location_name,
|
||||
uint16_t num_of_data_segments,
|
||||
int is_owner,
|
||||
int is_tx,
|
||||
SharedRingGlobalData *global_data
|
||||
);
|
||||
|
||||
SharedRingGlobalData * createSharedRingGlobalData(LoggingData *logging_data);
|
||||
|
||||
void destroySharedRingQueue(
|
||||
LoggingData *logging_data,
|
||||
SharedRingQueue *queue,
|
||||
SharedRingGlobalData *global_data,
|
||||
int is_owner,
|
||||
int is_tx
|
||||
);
|
||||
int isQueueEmpty(SharedRingQueue *queue);
|
||||
int isCorruptedQueue(LoggingData *logging_data, SharedRingQueue *queue, SharedRingGlobalData *global_data, int is_tx);
|
||||
|
||||
int peekToQueue(
|
||||
LoggingData *logging_data,
|
||||
SharedRingQueue *queue,
|
||||
SharedRingGlobalData *global_data,
|
||||
const char **output_buffer,
|
||||
uint16_t *output_buffer_size
|
||||
);
|
||||
|
||||
int popFromQueue(LoggingData *logging_data, SharedRingQueue *queue, SharedRingGlobalData *global_data);
|
||||
|
||||
int pushToQueue(
|
||||
LoggingData *logging_data,
|
||||
SharedRingQueue *queue,
|
||||
SharedRingGlobalData *global_data,
|
||||
const char *input_buffer,
|
||||
const uint16_t input_buffer_size
|
||||
);
|
||||
|
||||
void resetRingQueue(LoggingData *logging_data, SharedRingQueue *queue, uint16_t num_of_data_segments);
|
||||
void dumpRingQueueShmem(LoggingData *logging_data, SharedRingQueue *queue);
|
||||
|
||||
int
|
||||
pushBuffersToQueue(
|
||||
LoggingData *logging_data,
|
||||
SharedRingQueue *queue,
|
||||
SharedRingGlobalData *global_data,
|
||||
const char **input_buffers,
|
||||
const uint16_t *input_buffers_sizes,
|
||||
const uint8_t num_of_input_buffers
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // __SHARED_RING_QUEUE_H__
|
419
core/shmem_ipc_2/shmem_ipc.c
Executable file
419
core/shmem_ipc_2/shmem_ipc.c
Executable file
@@ -0,0 +1,419 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT 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 "shmem_ipc_2.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "shared_ring_queue.h"
|
||||
#include "shared_ipc_debug.h"
|
||||
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
||||
const int corrupted_shmem_error = CORRUPTED_SHMEM_ERROR;
|
||||
static const size_t max_one_way_queue_name_length = MAX_ONE_WAY_QUEUE_NAME_LENGTH;
|
||||
static const size_t max_shmem_path_length = 72;
|
||||
|
||||
struct SharedMemoryIPC {
|
||||
char shm_name[32];
|
||||
SharedRingQueue *rx_queue;
|
||||
SharedRingQueue *tx_queue;
|
||||
SharedRingGlobalData *global_data;
|
||||
LoggingData logging_data;
|
||||
};
|
||||
|
||||
// LCOV_EXCL_START Reason: Handing it to Envoy prototype development
|
||||
|
||||
void
|
||||
debugInitial(
|
||||
const LoggingData *loggin_data,
|
||||
uint32_t worker_id,
|
||||
int is_error,
|
||||
const char *func,
|
||||
const char *file,
|
||||
int line_num,
|
||||
const char *fmt,
|
||||
...
|
||||
)
|
||||
{
|
||||
UNUSED(is_error);
|
||||
UNUSED(func);
|
||||
UNUSED(file);
|
||||
UNUSED(line_num);
|
||||
UNUSED(loggin_data);
|
||||
UNUSED(worker_id);
|
||||
|
||||
// Temporarily disabled till Shmem debugging is properly fixed.
|
||||
// va_list args;
|
||||
// va_start(args, fmt);
|
||||
// vprintf(fmt, args);
|
||||
// va_end(args);
|
||||
|
||||
UNUSED(fmt);
|
||||
}
|
||||
|
||||
void (*debug_int)(
|
||||
const LoggingData *loggin_data,
|
||||
uint32_t worker_id,
|
||||
int is_error,
|
||||
const char *func,
|
||||
const char *file,
|
||||
int line_num,
|
||||
const char *fmt,
|
||||
...
|
||||
) = debugInitial;
|
||||
|
||||
|
||||
static int
|
||||
isTowardsOwner(int is_owner, int is_tx)
|
||||
{
|
||||
if (is_owner) return !is_tx;
|
||||
return is_tx;
|
||||
}
|
||||
|
||||
static SharedRingQueue *
|
||||
createOneWayIPCQueue(
|
||||
LoggingData *logging_data,
|
||||
const char *name,
|
||||
const uint32_t user_id,
|
||||
const uint32_t group_id,
|
||||
int is_tx_queue,
|
||||
int is_owner,
|
||||
uint16_t num_of_queue_elem,
|
||||
SharedRingGlobalData *global_data
|
||||
)
|
||||
{
|
||||
SharedRingQueue *ring_queue = NULL;
|
||||
char queue_name[max_one_way_queue_name_length];
|
||||
char shmem_path[max_shmem_path_length];
|
||||
const char *direction = isTowardsOwner(is_owner, is_tx_queue) ? "rx" : "tx";
|
||||
snprintf(queue_name, sizeof(queue_name) - 1, "__cp_nano_%s_shared_memory_%s__", direction, name);
|
||||
|
||||
writeDebug(
|
||||
logging_data,
|
||||
TraceLevel,
|
||||
"Creating one way IPC queue. Name: %s, direction: %s, size: %d",
|
||||
name,
|
||||
direction,
|
||||
num_of_queue_elem
|
||||
);
|
||||
ring_queue = createSharedRingQueue(
|
||||
logging_data,
|
||||
queue_name,
|
||||
num_of_queue_elem,
|
||||
is_owner,
|
||||
isTowardsOwner(is_owner, is_tx_queue),
|
||||
global_data
|
||||
);
|
||||
if (ring_queue == NULL) {
|
||||
writeDebug(
|
||||
logging_data,
|
||||
WarningLevel,
|
||||
"Failed to create %s shared ring queue of size=%d for '%s'\n",
|
||||
direction,
|
||||
num_of_queue_elem,
|
||||
queue_name
|
||||
);
|
||||
return NULL;
|
||||
}
|
||||
int ret = snprintf(shmem_path, sizeof(shmem_path) - 1, "/dev/shm/%s", queue_name);
|
||||
if (ret < 0 || (size_t)ret < (strlen(direction) + strlen(name))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (is_owner && chmod(shmem_path, 0666) == -1) {
|
||||
writeDebug(logging_data, WarningLevel, "Failed to set the permissions");
|
||||
destroySharedRingQueue(logging_data, ring_queue, global_data, is_owner, isTowardsOwner(is_owner, is_tx_queue));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
writeDebug(
|
||||
logging_data,
|
||||
TraceLevel,
|
||||
"Successfully created one way IPC queue. "
|
||||
"Name: %s, user id: %u, group id: %u, is owner: %d, number of queue elements: %u, direction: %s, path: %s",
|
||||
queue_name,
|
||||
user_id,
|
||||
group_id,
|
||||
is_owner,
|
||||
num_of_queue_elem,
|
||||
direction,
|
||||
shmem_path
|
||||
);
|
||||
return ring_queue;
|
||||
}
|
||||
|
||||
LoggingData *
|
||||
initLoggingData(int dbg_level, int worker_id, int fd)
|
||||
{
|
||||
LoggingData *logging_data = malloc(sizeof(LoggingData));
|
||||
if (logging_data == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
logging_data->dbg_level = dbg_level;
|
||||
logging_data->worker_id = worker_id;
|
||||
logging_data->fd = fd;
|
||||
return logging_data;
|
||||
}
|
||||
|
||||
SharedMemoryIPC *
|
||||
initIpc(
|
||||
const char queue_name[32],
|
||||
uint32_t user_id,
|
||||
uint32_t group_id,
|
||||
int is_owner,
|
||||
uint16_t num_of_queue_elem,
|
||||
const LoggingData *logging_data,
|
||||
void (*debug_func)(
|
||||
const LoggingData *loggin_data,
|
||||
uint32_t worker_id,
|
||||
int is_error,
|
||||
const char *func,
|
||||
const char *file,
|
||||
int line_num,
|
||||
const char *fmt,
|
||||
...
|
||||
)
|
||||
)
|
||||
{
|
||||
UNUSED(debug_func);
|
||||
SharedMemoryIPC *ipc = NULL;
|
||||
// debug_int = debug_func;
|
||||
debug_int = debugInitial;
|
||||
|
||||
writeDebug(
|
||||
logging_data,
|
||||
TraceLevel,
|
||||
"Initializing new IPC. "
|
||||
"Queue name: %s, user id: %u, group id: %u, is owner: %d, number of queue elements: %u\n",
|
||||
queue_name,
|
||||
user_id,
|
||||
group_id,
|
||||
is_owner,
|
||||
num_of_queue_elem
|
||||
);
|
||||
|
||||
ipc = malloc(sizeof(SharedMemoryIPC));
|
||||
if (ipc == NULL) {
|
||||
writeDebug(logging_data, WarningLevel, "Failed to allocate Shared Memory IPC for '%s'\n", queue_name);
|
||||
debug_int = debugInitial;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ipc->logging_data.dbg_level = logging_data->dbg_level;
|
||||
ipc->logging_data.worker_id = logging_data->worker_id;
|
||||
ipc->logging_data.fd = logging_data->fd;
|
||||
|
||||
ipc->global_data = createSharedRingGlobalData(&(ipc->logging_data));
|
||||
if (ipc->global_data == NULL) {
|
||||
writeDebug(logging_data, WarningLevel, "Failed to allocate global data for '%s'\n", queue_name);
|
||||
debug_int = debugInitial;
|
||||
free(ipc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ipc->rx_queue = NULL;
|
||||
ipc->tx_queue = NULL;
|
||||
|
||||
ipc->rx_queue = createOneWayIPCQueue(
|
||||
&(ipc->logging_data),
|
||||
queue_name,
|
||||
user_id,
|
||||
group_id,
|
||||
0,
|
||||
is_owner,
|
||||
num_of_queue_elem,
|
||||
ipc->global_data
|
||||
);
|
||||
if (ipc->rx_queue == NULL) {
|
||||
writeDebug(
|
||||
&(ipc->logging_data),
|
||||
WarningLevel,
|
||||
"Failed to allocate rx queue. "
|
||||
"Queue name: %s, user id: %u, group id: %u, is owner: %d, number of queue elements: %u",
|
||||
queue_name,
|
||||
user_id,
|
||||
group_id,
|
||||
is_owner,
|
||||
num_of_queue_elem
|
||||
);
|
||||
|
||||
destroyIpc(ipc, is_owner);
|
||||
debug_int = debugInitial;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ipc->tx_queue = createOneWayIPCQueue(
|
||||
&(ipc->logging_data),
|
||||
queue_name,
|
||||
user_id,
|
||||
group_id,
|
||||
1,
|
||||
is_owner,
|
||||
num_of_queue_elem,
|
||||
ipc->global_data
|
||||
);
|
||||
if (ipc->tx_queue == NULL) {
|
||||
writeDebug(
|
||||
&(ipc->logging_data),
|
||||
WarningLevel,
|
||||
"Failed to allocate rx queue. "
|
||||
"Queue name: %s, user id: %u, group id: %u, is owner: %d, number of queue elements: %u",
|
||||
queue_name,
|
||||
user_id,
|
||||
group_id,
|
||||
is_owner,
|
||||
num_of_queue_elem
|
||||
);
|
||||
destroyIpc(ipc, is_owner);
|
||||
debug_int = debugInitial;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
writeDebug(&(ipc->logging_data), TraceLevel, "Successfully allocated IPC");
|
||||
|
||||
strncpy(ipc->shm_name, queue_name, sizeof(ipc->shm_name));
|
||||
return ipc;
|
||||
}
|
||||
|
||||
void
|
||||
resetIpc(SharedMemoryIPC *ipc, uint16_t num_of_data_segments)
|
||||
{
|
||||
writeDebug(&(ipc->logging_data), TraceLevel, "Reseting IPC queues\n");
|
||||
resetRingQueue(&(ipc->logging_data), ipc->rx_queue, num_of_data_segments);
|
||||
resetRingQueue(&(ipc->logging_data), ipc->tx_queue, num_of_data_segments);
|
||||
}
|
||||
|
||||
void
|
||||
destroyIpc(SharedMemoryIPC *shmem, int is_owner)
|
||||
{
|
||||
writeDebug(&(shmem->logging_data), TraceLevel, "Destroying IPC queues\n");
|
||||
|
||||
if (shmem->rx_queue != NULL) {
|
||||
destroySharedRingQueue(
|
||||
&(shmem->logging_data),
|
||||
shmem->rx_queue,
|
||||
shmem->global_data,
|
||||
is_owner,
|
||||
isTowardsOwner(is_owner, 0)
|
||||
);
|
||||
shmem->rx_queue = NULL;
|
||||
}
|
||||
if (shmem->tx_queue != NULL) {
|
||||
destroySharedRingQueue(
|
||||
&(shmem->logging_data),
|
||||
shmem->tx_queue,
|
||||
shmem->global_data,
|
||||
is_owner,
|
||||
isTowardsOwner(is_owner, 1)
|
||||
);
|
||||
shmem->tx_queue = NULL;
|
||||
}
|
||||
free(shmem->global_data);
|
||||
debug_int = debugInitial;
|
||||
free(shmem);
|
||||
}
|
||||
|
||||
void
|
||||
dumpIpcMemory(SharedMemoryIPC *ipc)
|
||||
{
|
||||
writeDebug(&(ipc->logging_data), WarningLevel, "Ipc memory dump:\n");
|
||||
writeDebug(&(ipc->logging_data), WarningLevel, "RX queue:\n");
|
||||
dumpRingQueueShmem(&(ipc->logging_data), ipc->rx_queue);
|
||||
writeDebug(&(ipc->logging_data), WarningLevel, "TX queue:\n");
|
||||
dumpRingQueueShmem(&(ipc->logging_data), ipc->tx_queue);
|
||||
}
|
||||
|
||||
int
|
||||
sendData(SharedMemoryIPC *ipc, const uint16_t data_to_send_size, const char *data_to_send)
|
||||
{
|
||||
writeDebug(&(ipc->logging_data), TraceLevel, "Sending data of size %u\n", data_to_send_size);
|
||||
return pushToQueue(&(ipc->logging_data), ipc->tx_queue, ipc->global_data, data_to_send, data_to_send_size);
|
||||
}
|
||||
|
||||
int
|
||||
sendChunkedData(
|
||||
SharedMemoryIPC *ipc,
|
||||
const uint16_t *data_to_send_sizes,
|
||||
const char **data_elem_to_send,
|
||||
const uint8_t num_of_data_elem
|
||||
)
|
||||
{
|
||||
writeDebug(&(ipc->logging_data), TraceLevel, "Sending %u chunks of data\n", num_of_data_elem);
|
||||
|
||||
return pushBuffersToQueue(
|
||||
&(ipc->logging_data),
|
||||
ipc->tx_queue,
|
||||
ipc->global_data,
|
||||
data_elem_to_send,
|
||||
data_to_send_sizes,
|
||||
num_of_data_elem
|
||||
);
|
||||
}
|
||||
|
||||
int
|
||||
receiveData(SharedMemoryIPC *ipc, uint16_t *received_data_size, const char **received_data)
|
||||
{
|
||||
int res = peekToQueue(&(ipc->logging_data), ipc->rx_queue, ipc->global_data, received_data, received_data_size);
|
||||
writeDebug(
|
||||
&(ipc->logging_data),
|
||||
TraceLevel,
|
||||
"Received data from queue. Res: %d, data size: %u\n",
|
||||
res,
|
||||
*received_data_size
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
popData(SharedMemoryIPC *ipc)
|
||||
{
|
||||
int res = popFromQueue(&(ipc->logging_data), ipc->rx_queue, ipc->global_data);
|
||||
writeDebug(&(ipc->logging_data), TraceLevel, "Popped data from queue. Res: %d\n", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
isDataAvailable(SharedMemoryIPC *ipc)
|
||||
{
|
||||
int res = !isQueueEmpty(ipc->rx_queue);
|
||||
writeDebug(&(ipc->logging_data), TraceLevel, "Checking if there is data pending to be read. Res: %d\n", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
isCorruptedShmem(SharedMemoryIPC *ipc, int is_owner)
|
||||
{
|
||||
if (isCorruptedQueue(&(ipc->logging_data), ipc->rx_queue, ipc->global_data, isTowardsOwner(is_owner, 0)) ||
|
||||
isCorruptedQueue(&(ipc->logging_data), ipc->tx_queue, ipc->global_data, isTowardsOwner(is_owner, 1))
|
||||
) {
|
||||
writeDebug(
|
||||
&(ipc->logging_data),
|
||||
WarningLevel,
|
||||
"Detected corrupted shared memory queue. Shared memory name: %s",
|
||||
ipc->shm_name
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
Reference in New Issue
Block a user