mirror of
https://github.com/openappsec/openappsec.git
synced 2025-09-29 19:24:26 +03:00
First release of open-appsec source code
This commit is contained in:
10
core/shmem_ipc/CMakeLists.txt
Executable file
10
core/shmem_ipc/CMakeLists.txt
Executable file
@@ -0,0 +1,10 @@
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
|
||||
add_library(shmem_ipc SHARED shmem_ipc.c shared_ring_queue.c)
|
||||
|
||||
target_link_libraries(shmem_ipc -lrt)
|
||||
|
||||
add_subdirectory(shmem_ipc_ut)
|
||||
|
||||
install(TARGETS shmem_ipc DESTINATION lib)
|
||||
install(TARGETS shmem_ipc DESTINATION http_transaction_handler_service/lib)
|
31
core/shmem_ipc/shared_ipc_debug.h
Executable file
31
core/shmem_ipc/shared_ipc_debug.h
Executable file
@@ -0,0 +1,31 @@
|
||||
// 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__
|
||||
|
||||
extern void (*debug_int)(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, WarningLevel = 3 };
|
||||
|
||||
#define writeDebug(debug_level, fmt, ...) \
|
||||
{ \
|
||||
debug_int(debug_level, __func__, __FILENAME__, __LINE__, fmt, ##__VA_ARGS__); \
|
||||
}
|
||||
|
||||
#endif // __SHARED_IPC_DEBUG_H__
|
556
core/shmem_ipc/shared_ring_queue.c
Executable file
556
core/shmem_ipc/shared_ring_queue.c
Executable file
@@ -0,0 +1,556 @@
|
||||
// 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);
|
||||
|
||||
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 = -1;
|
||||
int32_t g_tx_fd = -1;
|
||||
int32_t g_memory_size = -1;
|
||||
|
||||
static uint16_t g_num_of_data_segments = 0;
|
||||
|
||||
static int
|
||||
getNumOfDataSegmentsNeeded(uint16_t data_size)
|
||||
{
|
||||
int res = (data_size + SHARED_MEMORY_SEGMENT_ENTRY_SIZE - 1) / SHARED_MEMORY_SEGMENT_ENTRY_SIZE;
|
||||
writeDebug(
|
||||
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(uint16_t write_pos, uint16_t read_pos, uint8_t num_of_elem_to_push)
|
||||
{
|
||||
int res;
|
||||
|
||||
writeDebug(
|
||||
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,
|
||||
g_num_of_data_segments
|
||||
);
|
||||
if (num_of_elem_to_push >= g_num_of_data_segments) {
|
||||
writeDebug(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 > g_num_of_data_segments) {
|
||||
num_of_elem_to_push += 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 >= g_num_of_data_segments) {
|
||||
read_pos += g_num_of_data_segments;
|
||||
}
|
||||
|
||||
res = write_pos + num_of_elem_to_push < read_pos || write_pos >= read_pos;
|
||||
writeDebug(TraceLevel, "Finished checking if there is enough place in shared memory. Res: %d", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
isGetPossitionSucceccful(SharedRingQueue *queue, uint16_t *read_pos, uint16_t *write_pos)
|
||||
{
|
||||
if (g_num_of_data_segments == 0) return 0;
|
||||
|
||||
*read_pos = queue->read_pos;
|
||||
*write_pos = queue->write_pos;
|
||||
|
||||
if (queue->num_of_data_segments != g_num_of_data_segments) return 0;
|
||||
if (queue->size_of_memory != g_memory_size) return 0;
|
||||
if (*read_pos > g_num_of_data_segments) return 0;
|
||||
if (*write_pos > g_num_of_data_segments) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
resetRingQueue(SharedRingQueue *queue, uint16_t num_of_data_segments)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
SharedRingQueue *
|
||||
createSharedRingQueue(const char *shared_location_name, uint16_t num_of_data_segments, int is_owner, int is_tx)
|
||||
{
|
||||
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(TraceLevel, "Creating a new shared ring queue");
|
||||
|
||||
if (num_of_data_segments > max_num_of_data_segments) {
|
||||
writeDebug(
|
||||
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;
|
||||
}
|
||||
|
||||
g_num_of_data_segments = num_of_data_segments;
|
||||
|
||||
fd = shm_open(shared_location_name, shmem_fd_flags, S_IRUSR | S_IWUSR);
|
||||
if (fd == -1) {
|
||||
writeDebug(
|
||||
WarningLevel,
|
||||
"createSharedRingQueue: Failed to open shared memory for '%s'. Errno: %d (%s)\n",
|
||||
shared_location_name,
|
||||
errno,
|
||||
strerror(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(
|
||||
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(
|
||||
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;
|
||||
}
|
||||
|
||||
g_memory_size = size_of_memory;
|
||||
if (is_tx) {
|
||||
g_tx_fd = fd;
|
||||
snprintf(g_tx_location_name, MAX_ONE_WAY_QUEUE_NAME_LENGTH, "%s", shared_location_name);
|
||||
} else {
|
||||
g_rx_fd = fd;
|
||||
snprintf(g_rx_location_name, MAX_ONE_WAY_QUEUE_NAME_LENGTH, "%s", shared_location_name);
|
||||
}
|
||||
|
||||
writeDebug(
|
||||
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(SharedRingQueue *queue, int is_owner, int is_tx)
|
||||
{
|
||||
uint32_t size_of_memory = g_memory_size;
|
||||
int32_t fd = 0;
|
||||
|
||||
if(is_owner) {
|
||||
queue->owner_fd = 0;
|
||||
} else {
|
||||
queue->user_fd = 0;
|
||||
}
|
||||
|
||||
if (is_tx) {
|
||||
fd = g_tx_fd;
|
||||
g_tx_fd = -1;
|
||||
} else {
|
||||
fd = g_rx_fd;
|
||||
g_rx_fd = -1;
|
||||
}
|
||||
|
||||
if (munmap(queue, size_of_memory) != 0) {
|
||||
writeDebug(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 ? g_tx_location_name : g_rx_location_name);
|
||||
}
|
||||
writeDebug(TraceLevel, "Successfully destroyed shared ring queue. Is owner: %d", is_owner);
|
||||
}
|
||||
|
||||
void
|
||||
dumpRingQueueShmem(SharedRingQueue *queue)
|
||||
{
|
||||
uint16_t segment_idx;
|
||||
uint16_t data_idx;
|
||||
uint16_t *buffer_mgmt = NULL;
|
||||
char data_byte;
|
||||
|
||||
writeDebug(
|
||||
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(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(WarningLevel, "%s%u", (segment_idx == 0 ? " " : ", "), buffer_mgmt[segment_idx]);
|
||||
}
|
||||
|
||||
writeDebug(WarningLevel, "\ndata_segment: ");
|
||||
for (segment_idx = 0; segment_idx < queue->num_of_data_segments; segment_idx++) {
|
||||
writeDebug(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(WarningLevel, isprint(data_byte) ? "%c" : "%02X", data_byte);
|
||||
}
|
||||
}
|
||||
writeDebug(WarningLevel, "\nEnd of memory\n");
|
||||
}
|
||||
|
||||
int
|
||||
peekToQueue(SharedRingQueue *queue, 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, &read_pos, &write_pos)) {
|
||||
writeDebug(WarningLevel, "Corrupted shared memory - cannot peek");
|
||||
return -1;
|
||||
}
|
||||
|
||||
writeDebug(
|
||||
TraceLevel,
|
||||
"Reading data from queue. Read index: %u, number of queue elements: %u",
|
||||
read_pos,
|
||||
g_num_of_data_segments
|
||||
);
|
||||
|
||||
if (read_pos == write_pos) {
|
||||
writeDebug(WarningLevel, "peekToQueue: Failed to read from an empty queue\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (read_pos >= g_num_of_data_segments) {
|
||||
writeDebug(
|
||||
WarningLevel,
|
||||
"peekToQueue: Failed to read from a corrupted queue! (read_pos= %d > num_of_data_segments=%d)\n",
|
||||
read_pos,
|
||||
g_num_of_data_segments
|
||||
);
|
||||
return CORRUPTED_SHMEM_ERROR;
|
||||
}
|
||||
|
||||
if (buffer_mgmt[read_pos] == skip_buff_mgmt_magic) {
|
||||
for ( ; read_pos < 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 == 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(
|
||||
TraceLevel,
|
||||
"Successfully read data from queue. Data size: %u, new Read index: %u",
|
||||
*output_buffer_size,
|
||||
queue->read_pos
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
pushBuffersToQueue(
|
||||
SharedRingQueue *queue,
|
||||
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, &read_pos, &write_pos)) {
|
||||
writeDebug(WarningLevel, "Corrupted shared memory - cannot push new buffers");
|
||||
return -1;
|
||||
}
|
||||
|
||||
writeDebug(
|
||||
TraceLevel,
|
||||
"Writing new data to queue. write index: %u, number of queue elements: %u, number of elements to push: %u",
|
||||
write_pos,
|
||||
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(
|
||||
WarningLevel,
|
||||
"Requested write size %u exceeds the %u write limit",
|
||||
large_total_elem_size,
|
||||
max_write_size
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
total_elem_size = (uint16_t)large_total_elem_size;
|
||||
|
||||
num_of_segments_to_write = getNumOfDataSegmentsNeeded(total_elem_size);
|
||||
|
||||
writeDebug(
|
||||
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(write_pos, read_pos, num_of_segments_to_write)) {
|
||||
writeDebug(WarningLevel, "Cannot write to a full queue\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (write_pos >= g_num_of_data_segments) {
|
||||
writeDebug(
|
||||
WarningLevel,
|
||||
"Cannot write to a location outside the queue. Write index: %u, number of queue elements: %u",
|
||||
write_pos,
|
||||
g_num_of_data_segments
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (write_pos + num_of_segments_to_write > g_num_of_data_segments) {
|
||||
for ( ; write_pos < g_num_of_data_segments; ++write_pos) {
|
||||
buffer_mgmt[write_pos] = skip_buff_mgmt_magic;
|
||||
}
|
||||
write_pos = 0;
|
||||
}
|
||||
|
||||
writeDebug(
|
||||
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(
|
||||
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 >= g_num_of_data_segments) write_pos = 0;
|
||||
queue->write_pos = write_pos;
|
||||
writeDebug(TraceLevel, "Successfully pushed data to queue. New write index: %u", write_pos);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
pushToQueue(SharedRingQueue *queue, const char *input_buffer, const uint16_t input_buffer_size)
|
||||
{
|
||||
return pushBuffersToQueue(queue, &input_buffer, &input_buffer_size, 1);
|
||||
}
|
||||
|
||||
int
|
||||
popFromQueue(SharedRingQueue *queue)
|
||||
{
|
||||
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, &read_pos, &write_pos)) {
|
||||
writeDebug(WarningLevel, "Corrupted shared memory - cannot pop data");
|
||||
return -1;
|
||||
}
|
||||
|
||||
writeDebug(
|
||||
TraceLevel,
|
||||
"Removing data from queue. new data to queue. Read index: %u, number of queue elements: %u",
|
||||
read_pos,
|
||||
g_num_of_data_segments
|
||||
);
|
||||
|
||||
if (read_pos == write_pos) {
|
||||
writeDebug(TraceLevel, "Cannot pop data from empty queue");
|
||||
return -1;
|
||||
}
|
||||
num_of_read_segments = getNumOfDataSegmentsNeeded(buffer_mgmt[read_pos]);
|
||||
|
||||
end_pos = read_pos + num_of_read_segments;
|
||||
|
||||
writeDebug(
|
||||
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
|
||||
);
|
||||
|
||||
for ( ; read_pos < end_pos; ++read_pos ) {
|
||||
buffer_mgmt[read_pos] = empty_buff_mgmt_magic;
|
||||
}
|
||||
|
||||
if (read_pos < g_num_of_data_segments && buffer_mgmt[read_pos] == skip_buff_mgmt_magic) {
|
||||
for ( ; read_pos < g_num_of_data_segments; ++read_pos ) {
|
||||
buffer_mgmt[read_pos] = empty_buff_mgmt_magic;
|
||||
}
|
||||
}
|
||||
|
||||
if (read_pos == g_num_of_data_segments) read_pos = 0;
|
||||
|
||||
queue->read_pos = read_pos;
|
||||
writeDebug(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(SharedRingQueue *queue, int is_tx)
|
||||
{
|
||||
writeDebug(
|
||||
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",
|
||||
g_num_of_data_segments,
|
||||
queue->num_of_data_segments,
|
||||
queue->read_pos,
|
||||
queue->write_pos,
|
||||
g_memory_size,
|
||||
queue->size_of_memory,
|
||||
queue->shared_location_name,
|
||||
g_tx_location_name,
|
||||
g_rx_location_name,
|
||||
is_tx
|
||||
);
|
||||
|
||||
if (g_num_of_data_segments == 0) return 0;
|
||||
|
||||
if (queue->num_of_data_segments != g_num_of_data_segments) return 1;
|
||||
if (queue->size_of_memory != g_memory_size) return 1;
|
||||
if (queue->read_pos > g_num_of_data_segments) return 1;
|
||||
if (queue->write_pos > g_num_of_data_segments) return 1;
|
||||
if (strcmp(queue->shared_location_name, is_tx ? g_tx_location_name : g_rx_location_name) != 0) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
75
core/shmem_ipc/shared_ring_queue.h
Executable file
75
core/shmem_ipc/shared_ring_queue.h
Executable file
@@ -0,0 +1,75 @@
|
||||
// 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 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(
|
||||
const char *shared_location_name,
|
||||
uint16_t num_of_data_segments,
|
||||
int is_owner,
|
||||
int is_tx
|
||||
);
|
||||
|
||||
void destroySharedRingQueue(SharedRingQueue *queue, int is_owner, int is_tx);
|
||||
int isQueueEmpty(SharedRingQueue *queue);
|
||||
int isCorruptedQueue(SharedRingQueue *queue, int is_tx);
|
||||
int peekToQueue(SharedRingQueue *queue, const char **output_buffer, uint16_t *output_buffer_size);
|
||||
int popFromQueue(SharedRingQueue *queue);
|
||||
int pushToQueue(SharedRingQueue *queue, const char *input_buffer, const uint16_t input_buffer_size);
|
||||
void resetRingQueue(SharedRingQueue *queue, uint16_t num_of_data_segments);
|
||||
void dumpRingQueueShmem(SharedRingQueue *queue);
|
||||
|
||||
int
|
||||
pushBuffersToQueue(
|
||||
SharedRingQueue *queue,
|
||||
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__
|
289
core/shmem_ipc/shmem_ipc.c
Executable file
289
core/shmem_ipc/shmem_ipc.c
Executable file
@@ -0,0 +1,289 @@
|
||||
// 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.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;
|
||||
};
|
||||
|
||||
void
|
||||
debugInitial(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);
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vprintf(fmt, args);
|
||||
va_end(args);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void (*debug_int)(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(
|
||||
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
|
||||
)
|
||||
{
|
||||
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(
|
||||
TraceLevel,
|
||||
"Creating one way IPC queue. Name: %s, direction: %s, size: %d",
|
||||
name,
|
||||
direction,
|
||||
num_of_queue_elem
|
||||
);
|
||||
ring_queue = createSharedRingQueue(queue_name, num_of_queue_elem, is_owner, isTowardsOwner(is_owner, is_tx_queue));
|
||||
if (ring_queue == NULL) {
|
||||
writeDebug(
|
||||
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 && chown(shmem_path, user_id, group_id) == -1) {
|
||||
writeDebug(WarningLevel, "Failed to set the permissions");
|
||||
destroySharedRingQueue(ring_queue, is_owner, isTowardsOwner(is_owner, is_tx_queue));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
writeDebug(
|
||||
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;
|
||||
}
|
||||
|
||||
SharedMemoryIPC *
|
||||
initIpc(
|
||||
const char queue_name[32],
|
||||
uint32_t user_id,
|
||||
uint32_t group_id,
|
||||
int is_owner,
|
||||
uint16_t num_of_queue_elem,
|
||||
void (*debug_func)(int is_error, const char *func, const char *file, int line_num, const char *fmt, ...))
|
||||
{
|
||||
SharedMemoryIPC *ipc = NULL;
|
||||
debug_int = debug_func;
|
||||
|
||||
writeDebug(
|
||||
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(WarningLevel, "Failed to allocate Shared Memory IPC for '%s'\n", queue_name);
|
||||
debug_int = debugInitial;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ipc->rx_queue = NULL;
|
||||
ipc->tx_queue = NULL;
|
||||
|
||||
ipc->rx_queue = createOneWayIPCQueue(queue_name, user_id, group_id, 0, is_owner, num_of_queue_elem);
|
||||
if (ipc->rx_queue == NULL) {
|
||||
writeDebug(
|
||||
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(queue_name, user_id, group_id, 1, is_owner, num_of_queue_elem);
|
||||
if (ipc->tx_queue == NULL) {
|
||||
writeDebug(
|
||||
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(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(TraceLevel, "Reseting IPC queues\n");
|
||||
resetRingQueue(ipc->rx_queue, num_of_data_segments);
|
||||
resetRingQueue(ipc->tx_queue, num_of_data_segments);
|
||||
}
|
||||
|
||||
void
|
||||
destroyIpc(SharedMemoryIPC *shmem, int is_owner)
|
||||
{
|
||||
writeDebug(TraceLevel, "Destroying IPC queues\n");
|
||||
|
||||
if (shmem->rx_queue != NULL) {
|
||||
destroySharedRingQueue(shmem->rx_queue, is_owner, isTowardsOwner(is_owner, 0));
|
||||
shmem->rx_queue = NULL;
|
||||
}
|
||||
if (shmem->tx_queue != NULL) {
|
||||
destroySharedRingQueue(shmem->tx_queue, is_owner, isTowardsOwner(is_owner, 1));
|
||||
shmem->tx_queue = NULL;
|
||||
}
|
||||
debug_int = debugInitial;
|
||||
free(shmem);
|
||||
}
|
||||
|
||||
void
|
||||
dumpIpcMemory(SharedMemoryIPC *ipc)
|
||||
{
|
||||
writeDebug(WarningLevel, "Ipc memory dump:\n");
|
||||
writeDebug(WarningLevel, "RX queue:\n");
|
||||
dumpRingQueueShmem(ipc->rx_queue);
|
||||
writeDebug(WarningLevel, "TX queue:\n");
|
||||
dumpRingQueueShmem(ipc->tx_queue);
|
||||
}
|
||||
|
||||
int
|
||||
sendData(SharedMemoryIPC *ipc, const uint16_t data_to_send_size, const char *data_to_send)
|
||||
{
|
||||
writeDebug(TraceLevel, "Sending data of size %u\n", data_to_send_size);
|
||||
return pushToQueue(ipc->tx_queue, 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(TraceLevel, "Sending %u chunks of data\n", num_of_data_elem);
|
||||
|
||||
return pushBuffersToQueue(ipc->tx_queue, 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->rx_queue, received_data, received_data_size);
|
||||
writeDebug(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->rx_queue);
|
||||
writeDebug(TraceLevel, "Popped data from queue. Res: %d\n", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
isDataAvailable(SharedMemoryIPC *ipc)
|
||||
{
|
||||
int res = !isQueueEmpty(ipc->rx_queue);
|
||||
writeDebug(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->rx_queue, isTowardsOwner(is_owner, 0)) ||
|
||||
isCorruptedQueue(ipc->tx_queue, isTowardsOwner(is_owner, 1))
|
||||
) {
|
||||
writeDebug(WarningLevel, "Detected corrupted shared memory queue. Shared memory name: %s", ipc->shm_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
2
core/shmem_ipc/shmem_ipc_ut/CMakeLists.txt
Executable file
2
core/shmem_ipc/shmem_ipc_ut/CMakeLists.txt
Executable file
@@ -0,0 +1,2 @@
|
||||
add_unit_test(shared_ring_queue_ut "shared_ring_queue_ut.cc" "shmem_ipc;${RT_LIBRARY}")
|
||||
add_unit_test(shared_ipc_ut "shmem_ipc_ut.cc" "shmem_ipc;${RT_LIBRARY};time_proxy;mainloop;")
|
339
core/shmem_ipc/shmem_ipc_ut/shared_ring_queue_ut.cc
Executable file
339
core/shmem_ipc/shmem_ipc_ut/shared_ring_queue_ut.cc
Executable file
@@ -0,0 +1,339 @@
|
||||
#include "../shared_ring_queue.h"
|
||||
|
||||
#include "cptest.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace testing;
|
||||
|
||||
const static string bad_shmem_path = "/root/sadsadsadad/444";
|
||||
const static string valid_shmem_file_name = "shmem_ut";
|
||||
const static string valid_shmem_path = "/dev/shm/" + valid_shmem_file_name;
|
||||
const uint16_t max_num_of_data_segments = sizeof(DataSegment)/sizeof(uint16_t);
|
||||
const static uint16_t num_of_shmem_elem = 11;
|
||||
|
||||
class SharedRingQueueTest : public Test
|
||||
{
|
||||
public:
|
||||
SharedRingQueueTest()
|
||||
{
|
||||
// remove old fd from prev tests
|
||||
unlink(valid_shmem_path.c_str());
|
||||
|
||||
owners_queue = createSharedRingQueue(valid_shmem_file_name.c_str(), num_of_shmem_elem, 1, 1);
|
||||
users_queue = createSharedRingQueue(valid_shmem_file_name.c_str(), num_of_shmem_elem, 0, 0);
|
||||
}
|
||||
|
||||
~SharedRingQueueTest()
|
||||
{
|
||||
if (owners_queue != nullptr) destroySharedRingQueue(owners_queue, 1, 1);
|
||||
if (users_queue != nullptr) destroySharedRingQueue(users_queue, 0, 0);
|
||||
owners_queue = nullptr;
|
||||
users_queue = nullptr;
|
||||
}
|
||||
|
||||
SharedRingQueue *owners_queue = nullptr;
|
||||
SharedRingQueue *users_queue = nullptr;
|
||||
};
|
||||
|
||||
TEST_F(SharedRingQueueTest, init_queues)
|
||||
{
|
||||
EXPECT_NE(owners_queue, nullptr);
|
||||
EXPECT_NE(users_queue, nullptr);
|
||||
}
|
||||
|
||||
TEST_F(SharedRingQueueTest, basic_write_read_pop_transaction)
|
||||
{
|
||||
ASSERT_NE(owners_queue, nullptr);
|
||||
ASSERT_NE(users_queue, nullptr);
|
||||
const char data_to_write[] = "my basic_write_read_pop_transaction test data";
|
||||
const char *read_data;
|
||||
uint16_t read_bytes = 0;
|
||||
EXPECT_EQ(pushToQueue(users_queue, data_to_write, sizeof(data_to_write)), 0);
|
||||
EXPECT_EQ(peekToQueue(owners_queue, &read_data, &read_bytes), 0);
|
||||
EXPECT_STREQ(read_data, data_to_write);
|
||||
EXPECT_EQ(read_bytes, sizeof(data_to_write));
|
||||
EXPECT_EQ(popFromQueue(owners_queue), 0);
|
||||
}
|
||||
|
||||
TEST_F(SharedRingQueueTest, multiple_write_read_pop_transactions)
|
||||
{
|
||||
ASSERT_NE(owners_queue, nullptr);
|
||||
ASSERT_NE(users_queue, nullptr);
|
||||
vector<string> data_to_write = {
|
||||
"my basic_write_read_pop_transaction test data0",
|
||||
"my basic_write_read_pop_transaction test data1",
|
||||
"my basic_write_read_pop_transaction test data2",
|
||||
"my basic_write_read_pop_transaction test data3",
|
||||
"my basic_write_read_pop_transaction test data4",
|
||||
"my basic_write_read_pop_transaction test data5",
|
||||
"my basic_write_read_pop_transaction test data6",
|
||||
"my basic_write_read_pop_transaction test data7",
|
||||
"my basic_write_read_pop_transaction test data8",
|
||||
"my basic_write_read_pop_transaction test data9"
|
||||
};
|
||||
for (const string &data : data_to_write) {
|
||||
EXPECT_EQ(pushToQueue(users_queue, data.c_str(), data.size()), 0);
|
||||
}
|
||||
const char *read_buff = nullptr;
|
||||
uint16_t read_bytes = 0;
|
||||
vector<string> read_data;
|
||||
while (!isQueueEmpty(owners_queue)) {
|
||||
ASSERT_LT(read_data.size(), data_to_write.size());
|
||||
EXPECT_EQ(peekToQueue(owners_queue, &read_buff, &read_bytes), 0);
|
||||
read_data.push_back(string(read_buff, read_bytes));
|
||||
EXPECT_EQ(popFromQueue(owners_queue), 0);
|
||||
}
|
||||
EXPECT_EQ(read_data, data_to_write);
|
||||
}
|
||||
|
||||
// reduced padding to 1 in order to allow comparing sizeof this struct with actually read data
|
||||
#pragma pack(1)
|
||||
struct my_multi_elem_struct {
|
||||
int my_int;
|
||||
char my_char;
|
||||
char my_string[4];
|
||||
char my_array[6];
|
||||
};
|
||||
|
||||
struct my_multi_elem_struct
|
||||
createMyStruct(int my_int, char my_char, const char *my_string, const char *my_array)
|
||||
{
|
||||
struct my_multi_elem_struct my_struct;
|
||||
my_struct.my_int = my_int;
|
||||
my_struct.my_char = my_char;
|
||||
strncpy(my_struct.my_string, my_string, 4);
|
||||
strncpy(my_struct.my_array, my_array, 6);
|
||||
return my_struct;
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(const struct my_multi_elem_struct &first, const struct my_multi_elem_struct &second)
|
||||
{
|
||||
return first.my_int == second.my_int &&
|
||||
first.my_char == second.my_char &&
|
||||
strncmp(first.my_string, second.my_string, 4) == 0 &&
|
||||
strncmp(first.my_array, second.my_array, 6) == 0;
|
||||
}
|
||||
|
||||
TEST_F(SharedRingQueueTest, write_read_pop_mulltiple_elements_transaction)
|
||||
{
|
||||
ASSERT_NE(owners_queue, nullptr);
|
||||
ASSERT_NE(users_queue, nullptr);
|
||||
int my_first_int = 1;
|
||||
int my_second_int = 2;
|
||||
char my_first_char = '1';
|
||||
char my_second_char = '2';
|
||||
string my_first_string = "one";
|
||||
string my_second_string = "two";
|
||||
const char my_first_array[] = { '1', 'o', 'n', 'e', '!', '\0' };
|
||||
const char my_second_array[] = { '@', 't', 'w', 'o', '2', '\0' };
|
||||
|
||||
vector<const char *> data1 = {
|
||||
reinterpret_cast<const char *>(&my_first_int),
|
||||
const_cast<const char *>(&my_first_char),
|
||||
const_cast<const char *>(my_first_string.data()),
|
||||
my_first_array
|
||||
};
|
||||
vector<uint16_t> sizes1 = {
|
||||
sizeof(my_first_int),
|
||||
sizeof(my_first_char),
|
||||
static_cast<uint16_t>(my_first_string.size() + 1),
|
||||
sizeof(my_first_array)
|
||||
};
|
||||
|
||||
vector<const char *> data2 = {
|
||||
reinterpret_cast<const char *>(&my_second_int),
|
||||
const_cast<const char *>(&my_second_char),
|
||||
const_cast<const char *>(my_second_string.data()),
|
||||
my_second_array
|
||||
};
|
||||
vector<uint16_t> sizes2 = {
|
||||
sizeof(my_second_int),
|
||||
sizeof(my_second_char),
|
||||
static_cast<uint16_t>(my_second_string.size() + 1),
|
||||
sizeof(my_second_array)
|
||||
};
|
||||
|
||||
EXPECT_EQ(pushBuffersToQueue(users_queue, data1.data(), sizes1.data(), data1.size()), 0);
|
||||
EXPECT_EQ(pushBuffersToQueue(users_queue, data2.data(), sizes2.data(), data2.size()), 0);
|
||||
|
||||
const char *read_buff = nullptr;
|
||||
uint16_t read_bytes = 0;
|
||||
EXPECT_EQ(peekToQueue(owners_queue, &read_buff, &read_bytes), 0);
|
||||
struct my_multi_elem_struct expected_data = createMyStruct(
|
||||
my_first_int,
|
||||
my_first_char,
|
||||
my_first_string.data(),
|
||||
my_first_array
|
||||
);
|
||||
ASSERT_EQ(read_bytes, sizeof(expected_data));
|
||||
const struct my_multi_elem_struct actual_data = *reinterpret_cast<const struct my_multi_elem_struct *>(read_buff);
|
||||
EXPECT_TRUE(actual_data == expected_data);
|
||||
EXPECT_EQ(popFromQueue(owners_queue), 0);
|
||||
EXPECT_EQ(peekToQueue(owners_queue, &read_buff, &read_bytes), 0);
|
||||
expected_data = createMyStruct(my_first_int, my_first_char, my_first_string.data(), my_first_array);
|
||||
ASSERT_EQ(read_bytes, sizeof(expected_data));
|
||||
EXPECT_EQ(popFromQueue(owners_queue), 0);
|
||||
}
|
||||
|
||||
TEST_F(SharedRingQueueTest, write_read_pop_over_multiple_segments)
|
||||
{
|
||||
ASSERT_NE(owners_queue, nullptr);
|
||||
ASSERT_NE(users_queue, nullptr);
|
||||
|
||||
vector<vector<char>> data = {
|
||||
vector<char>(SHARED_MEMORY_SEGMENT_ENTRY_SIZE*2, '1'),
|
||||
vector<char>(SHARED_MEMORY_SEGMENT_ENTRY_SIZE*2, '2'),
|
||||
vector<char>(SHARED_MEMORY_SEGMENT_ENTRY_SIZE*2, '3'),
|
||||
vector<char>(SHARED_MEMORY_SEGMENT_ENTRY_SIZE*2, '4'),
|
||||
vector<char>(SHARED_MEMORY_SEGMENT_ENTRY_SIZE*2, '5')
|
||||
};
|
||||
|
||||
for (const vector<char> &long_buffer : data) {
|
||||
EXPECT_EQ(pushToQueue(users_queue, long_buffer.data(), long_buffer.size()), 0);
|
||||
}
|
||||
|
||||
vector<char> no_more_space_data(SHARED_MEMORY_SEGMENT_ENTRY_SIZE*2, '6');
|
||||
EXPECT_EQ(pushToQueue(users_queue, no_more_space_data.data(), no_more_space_data.size()), -1);
|
||||
|
||||
const char *read_data = nullptr;
|
||||
uint16_t read_bytes = 0;
|
||||
for (const vector<char> &long_buffer : data) {
|
||||
EXPECT_EQ(peekToQueue(owners_queue, &read_data, &read_bytes), 0);
|
||||
EXPECT_EQ(string(read_data, read_bytes), string(long_buffer.data(), long_buffer.size()));
|
||||
EXPECT_EQ(popFromQueue(owners_queue), 0);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(isQueueEmpty(owners_queue));
|
||||
EXPECT_TRUE(isQueueEmpty(users_queue));
|
||||
}
|
||||
|
||||
TEST_F(SharedRingQueueTest, write_element_that_fills_the_entire_queue)
|
||||
{
|
||||
ASSERT_NE(owners_queue, nullptr);
|
||||
ASSERT_NE(users_queue, nullptr);
|
||||
|
||||
vector<char> short_data(100, '1');
|
||||
vector<char> long_data(SHARED_MEMORY_SEGMENT_ENTRY_SIZE*(num_of_shmem_elem - 1), '2');
|
||||
|
||||
EXPECT_EQ(pushToQueue(users_queue, long_data.data(), long_data.size()), 0);
|
||||
EXPECT_EQ(pushToQueue(users_queue, short_data.data(), short_data.size()), -1);
|
||||
|
||||
const char *data_to_read = nullptr;
|
||||
uint16_t read_bytes = 0;
|
||||
EXPECT_EQ(peekToQueue(owners_queue, &data_to_read, &read_bytes), 0);
|
||||
EXPECT_EQ(read_bytes, long_data.size());
|
||||
EXPECT_EQ(popFromQueue(owners_queue), 0);
|
||||
|
||||
EXPECT_EQ(pushToQueue(users_queue, long_data.data(), long_data.size()), -1);
|
||||
EXPECT_EQ(pushToQueue(users_queue, short_data.data(), short_data.size()), 0);
|
||||
|
||||
EXPECT_EQ(peekToQueue(owners_queue, &data_to_read, &read_bytes), 0);
|
||||
EXPECT_EQ(read_bytes, short_data.size());
|
||||
EXPECT_EQ(popFromQueue(owners_queue), 0);
|
||||
}
|
||||
|
||||
TEST_F(SharedRingQueueTest, not_enought_space_to_push_on_end_but_enought_on_start)
|
||||
{
|
||||
ASSERT_NE(owners_queue, nullptr);
|
||||
ASSERT_NE(users_queue, nullptr);
|
||||
|
||||
vector<char> short_data(SHARED_MEMORY_SEGMENT_ENTRY_SIZE/2, '1');
|
||||
vector<char> long_data(SHARED_MEMORY_SEGMENT_ENTRY_SIZE*3, '2');
|
||||
|
||||
for (uint i = 0; i < num_of_shmem_elem - 1; i++) {
|
||||
EXPECT_EQ(pushToQueue(users_queue, short_data.data(), short_data.size()), 0);
|
||||
}
|
||||
EXPECT_EQ(pushToQueue(users_queue, long_data.data(), long_data.size()), -1);
|
||||
|
||||
for (uint i = 0; i < 3; i++) {
|
||||
EXPECT_EQ(popFromQueue(owners_queue), 0);
|
||||
EXPECT_EQ(pushToQueue(users_queue, long_data.data(), long_data.size()), -1);
|
||||
}
|
||||
|
||||
EXPECT_EQ(popFromQueue(owners_queue), 0);
|
||||
EXPECT_EQ(pushToQueue(users_queue, long_data.data(), long_data.size()), 0);
|
||||
}
|
||||
|
||||
TEST_F(SharedRingQueueTest, attempt_write_to_full_queue)
|
||||
{
|
||||
ASSERT_NE(owners_queue, nullptr);
|
||||
ASSERT_NE(users_queue, nullptr);
|
||||
|
||||
int data_to_write = 100;
|
||||
for (uint i = 0; i < num_of_shmem_elem - 1; i ++) {
|
||||
EXPECT_EQ(pushToQueue(users_queue, reinterpret_cast<char *>(&data_to_write), sizeof(data_to_write)), 0);
|
||||
}
|
||||
EXPECT_EQ(pushToQueue(users_queue, reinterpret_cast<char *>(&data_to_write), sizeof(data_to_write)), -1);
|
||||
|
||||
const char *data_to_read = nullptr;
|
||||
uint16_t read_bytes = 0;
|
||||
EXPECT_EQ(peekToQueue(owners_queue, &data_to_read, &read_bytes), 0);
|
||||
EXPECT_EQ(read_bytes, sizeof(data_to_write));
|
||||
EXPECT_EQ(*reinterpret_cast<const int *>(data_to_read), data_to_write);
|
||||
EXPECT_EQ(popFromQueue(owners_queue), 0);
|
||||
EXPECT_EQ(
|
||||
pushToQueue(users_queue, reinterpret_cast<char *>(&data_to_write), sizeof(data_to_write)),
|
||||
0
|
||||
);
|
||||
EXPECT_EQ(
|
||||
pushToQueue(users_queue, reinterpret_cast<char *>(&data_to_write), sizeof(data_to_write)),
|
||||
-1
|
||||
);
|
||||
|
||||
int popped_items_count = 0;
|
||||
while (!isQueueEmpty(owners_queue)) {
|
||||
EXPECT_EQ(peekToQueue(owners_queue, &data_to_read, &read_bytes), 0);
|
||||
EXPECT_EQ(read_bytes, sizeof(data_to_write));
|
||||
EXPECT_EQ(*reinterpret_cast<const int *>(data_to_read), data_to_write);
|
||||
EXPECT_EQ(popFromQueue(owners_queue), 0);
|
||||
ASSERT_NE(popped_items_count, num_of_shmem_elem);
|
||||
popped_items_count++;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(SharedRingQueueTest, attempt_to_read_and_pop_from_empty_queue)
|
||||
{
|
||||
ASSERT_NE(owners_queue, nullptr);
|
||||
ASSERT_NE(users_queue, nullptr);
|
||||
|
||||
EXPECT_TRUE(isQueueEmpty(owners_queue));
|
||||
EXPECT_TRUE(isQueueEmpty(users_queue));
|
||||
|
||||
const char *data_to_read = nullptr;
|
||||
uint16_t read_bytes = 0;
|
||||
EXPECT_EQ(peekToQueue(owners_queue, &data_to_read, &read_bytes), -1);
|
||||
EXPECT_EQ(popFromQueue(owners_queue), -1);
|
||||
|
||||
EXPECT_EQ(pushToQueue(users_queue, "abcd", 5), 0);
|
||||
EXPECT_FALSE(isQueueEmpty(owners_queue));
|
||||
EXPECT_FALSE(isQueueEmpty(users_queue));
|
||||
EXPECT_EQ(peekToQueue(owners_queue, &data_to_read, &read_bytes), 0);
|
||||
EXPECT_EQ(popFromQueue(owners_queue), 0);
|
||||
|
||||
EXPECT_EQ(read_bytes, 5);
|
||||
EXPECT_STREQ(data_to_read, "abcd");
|
||||
|
||||
EXPECT_TRUE(isQueueEmpty(owners_queue));
|
||||
EXPECT_TRUE(isQueueEmpty(users_queue));
|
||||
EXPECT_EQ(peekToQueue(owners_queue, &data_to_read, &read_bytes), -1);
|
||||
EXPECT_EQ(popFromQueue(owners_queue), -1);
|
||||
}
|
||||
|
||||
TEST_F(SharedRingQueueTest, ilegal_queue)
|
||||
{
|
||||
ASSERT_NE(owners_queue, nullptr);
|
||||
ASSERT_NE(users_queue, nullptr);
|
||||
|
||||
destroySharedRingQueue(users_queue, 0, 1);
|
||||
users_queue = createSharedRingQueue(valid_shmem_file_name.c_str(), max_num_of_data_segments + 1, 0, 0);
|
||||
EXPECT_EQ(users_queue, nullptr);
|
||||
|
||||
users_queue = createSharedRingQueue(bad_shmem_path.c_str(), max_num_of_data_segments, 0, 0);
|
||||
EXPECT_EQ(users_queue, nullptr);
|
||||
|
||||
ASSERT_NE(owners_queue, nullptr);
|
||||
destroySharedRingQueue(owners_queue, 1, 1);
|
||||
owners_queue = createSharedRingQueue(valid_shmem_file_name.c_str(), max_num_of_data_segments, 1, 1);
|
||||
EXPECT_NE(owners_queue, nullptr);
|
||||
}
|
271
core/shmem_ipc/shmem_ipc_ut/shmem_ipc_ut.cc
Executable file
271
core/shmem_ipc/shmem_ipc_ut/shmem_ipc_ut.cc
Executable file
@@ -0,0 +1,271 @@
|
||||
#include "shmem_ipc.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "../shared_ring_queue.h"
|
||||
#include "debug.h"
|
||||
#include "cptest.h"
|
||||
#include "time_proxy.h"
|
||||
#include "mock/mock_mainloop.h"
|
||||
#include "mock/mock_environment.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace testing;
|
||||
|
||||
const static string shmem_name = "shmem_ut";
|
||||
const static uint16_t num_of_shmem_elem = 11;
|
||||
const static size_t max_one_way_queue_name_length = 64;
|
||||
const uint16_t max_num_of_data_segments = sizeof(DataSegment)/sizeof(uint16_t);
|
||||
uint32_t uid = getuid();
|
||||
uint32_t gid = getgid();
|
||||
|
||||
USE_DEBUG_FLAG(D_SHMEM);
|
||||
|
||||
void
|
||||
debugFunc(int is_error, const char *func, const char *file, int line_num, const char *fmt, ...)
|
||||
{
|
||||
if (!Debug::evalFlags(Debug::DebugLevel::INFO, D_SHMEM)) return;
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
size_t len = vsnprintf(NULL, 0, fmt, args);
|
||||
va_end(args);
|
||||
vector<char> message(len + 1);
|
||||
va_start(args, fmt);
|
||||
vsnprintf(&message[0], len + 1, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
Debug(
|
||||
file,
|
||||
func,
|
||||
line_num,
|
||||
is_error ? Debug::DebugLevel::WARNING : Debug::DebugLevel::TRACE,
|
||||
D_SHMEM
|
||||
).getStreamAggr() << message.data();
|
||||
}
|
||||
|
||||
class SharedIPCTest : public Test
|
||||
{
|
||||
public:
|
||||
SharedIPCTest()
|
||||
{
|
||||
Debug::setNewDefaultStdout(&capture_debug);
|
||||
Debug::setUnitTestFlag(D_SHMEM, Debug::DebugLevel::TRACE);
|
||||
owners_queue = initIpc(shmem_name.c_str(), uid, gid, 1, num_of_shmem_elem, debugFunc);
|
||||
users_queue = initIpc(shmem_name.c_str(), uid, gid, 0, num_of_shmem_elem, debugFunc);
|
||||
}
|
||||
|
||||
~SharedIPCTest()
|
||||
{
|
||||
if(owners_queue != nullptr) destroyIpc(owners_queue, 1);
|
||||
if(users_queue != nullptr) destroyIpc(users_queue, 0);
|
||||
owners_queue = nullptr;
|
||||
users_queue = nullptr;
|
||||
Debug::setNewDefaultStdout(&cout);
|
||||
}
|
||||
|
||||
SharedMemoryIPC *owners_queue = nullptr;
|
||||
SharedMemoryIPC *users_queue = nullptr;
|
||||
stringstream capture_debug;
|
||||
TimeProxyComponent time_proxy;
|
||||
MockMainLoop mock_mainloop;
|
||||
MockEnvironment env;
|
||||
};
|
||||
|
||||
TEST_F(SharedIPCTest, init_owner_queue)
|
||||
{
|
||||
EXPECT_NE(owners_queue, nullptr);
|
||||
EXPECT_FALSE(isCorruptedShmem(owners_queue, 1));
|
||||
|
||||
EXPECT_NE(users_queue, nullptr);
|
||||
EXPECT_FALSE(isCorruptedShmem(users_queue, 0));
|
||||
}
|
||||
|
||||
TEST_F(SharedIPCTest, basic_write_read_pop_transaction)
|
||||
{
|
||||
ASSERT_NE(owners_queue, nullptr);
|
||||
ASSERT_NE(users_queue, nullptr);
|
||||
|
||||
const string message = "my basic_write_read_pop_transaction test data";
|
||||
const string respond = "my basic_write_read_pop_transaction test data";
|
||||
|
||||
const char *read_data = nullptr;
|
||||
uint16_t read_bytes = 0;
|
||||
|
||||
EXPECT_EQ(sendData(owners_queue, message.size(), message.c_str()), 0);
|
||||
EXPECT_TRUE(isDataAvailable(users_queue));
|
||||
EXPECT_EQ(receiveData(users_queue, &read_bytes, &read_data), 0);
|
||||
EXPECT_EQ(string(read_data, read_bytes), message);
|
||||
EXPECT_EQ(popData(users_queue), 0);
|
||||
EXPECT_FALSE(isDataAvailable(users_queue));
|
||||
|
||||
EXPECT_EQ(sendData(users_queue, respond.size(), respond.c_str()), 0);
|
||||
EXPECT_TRUE(isDataAvailable(owners_queue));
|
||||
EXPECT_EQ(receiveData(owners_queue, &read_bytes, &read_data), 0);
|
||||
EXPECT_EQ(string(read_data, read_bytes), respond);
|
||||
EXPECT_EQ(popData(owners_queue), 0);
|
||||
EXPECT_FALSE(isDataAvailable(owners_queue));
|
||||
}
|
||||
|
||||
TEST_F(SharedIPCTest, memory_dump)
|
||||
{
|
||||
const string message = "my basic_write_read_pop_transaction test data";
|
||||
sendData(owners_queue, message.size(), message.c_str());
|
||||
|
||||
dumpIpcMemory(owners_queue);
|
||||
|
||||
EXPECT_THAT(capture_debug.str(), HasSubstr("Ipc memory dump:"));
|
||||
}
|
||||
|
||||
TEST_F(SharedIPCTest, ilegal_ipc)
|
||||
{
|
||||
ASSERT_NE(owners_queue, nullptr);
|
||||
ASSERT_NE(users_queue, nullptr);
|
||||
|
||||
destroyIpc(owners_queue, 1);
|
||||
destroyIpc(users_queue, 0);
|
||||
|
||||
owners_queue = initIpc("i/am/a/bad/shmem/path", uid, gid, 1, num_of_shmem_elem, debugFunc);
|
||||
users_queue = initIpc(shmem_name.c_str(), uid, gid, 0, max_num_of_data_segments + 1, debugFunc);
|
||||
|
||||
EXPECT_EQ(owners_queue, nullptr);
|
||||
EXPECT_EQ(users_queue, nullptr);
|
||||
|
||||
EXPECT_THAT(
|
||||
capture_debug.str(),
|
||||
HasSubstr("Failed to open shared memory for '__cp_nano_rx_shared_memory_i/am/a/bad/shmem/path__'")
|
||||
);
|
||||
|
||||
EXPECT_THAT(
|
||||
capture_debug.str(),
|
||||
HasSubstr("Cannot create data segment with 513 elements (max number of elements is 512)")
|
||||
);
|
||||
}
|
||||
|
||||
TEST_F(SharedIPCTest, multiple_write_read_pop_transactions)
|
||||
{
|
||||
vector<string> data_to_write = {
|
||||
"my basic_write_read_pop_transaction test data0",
|
||||
"my basic_write_read_pop_transaction test data1",
|
||||
"my basic_write_read_pop_transaction test data2",
|
||||
"my basic_write_read_pop_transaction test data3",
|
||||
"my basic_write_read_pop_transaction test data4",
|
||||
"my basic_write_read_pop_transaction test data5",
|
||||
"my basic_write_read_pop_transaction test data6",
|
||||
"my basic_write_read_pop_transaction test data7",
|
||||
"my basic_write_read_pop_transaction test data8",
|
||||
"my basic_write_read_pop_transaction test data9"
|
||||
};
|
||||
for (const string &data : data_to_write) {
|
||||
EXPECT_EQ(sendData(users_queue, data.size(), data.c_str()), 0);
|
||||
}
|
||||
const char *read_buff = nullptr;
|
||||
uint16_t read_bytes = 0;
|
||||
vector<string> read_data;
|
||||
while (isDataAvailable(owners_queue)) {
|
||||
ASSERT_LT(read_data.size(), data_to_write.size());
|
||||
EXPECT_EQ(receiveData(owners_queue, &read_bytes, &read_buff), 0);
|
||||
read_data.push_back(string(read_buff, read_bytes));
|
||||
EXPECT_EQ(sendData(owners_queue, read_bytes, read_buff), 0);
|
||||
EXPECT_EQ(popData(owners_queue), 0);
|
||||
}
|
||||
|
||||
EXPECT_EQ(read_data, data_to_write);
|
||||
for (uint i = 0; i < read_data.size(); i++) {
|
||||
EXPECT_EQ(receiveData(users_queue, &read_bytes, &read_buff), 0);
|
||||
EXPECT_EQ(string(read_buff, read_bytes), read_data[i]);
|
||||
EXPECT_EQ(popData(users_queue), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(SharedIPCTest, reset_shmem)
|
||||
{
|
||||
string data_to_write = "my basic_write_read_pop_transaction test data";
|
||||
|
||||
int count = 0;
|
||||
while (sendData(users_queue, data_to_write.size(), data_to_write.c_str()) == 0) {
|
||||
count++;
|
||||
ASSERT_NE(count, num_of_shmem_elem);
|
||||
}
|
||||
|
||||
EXPECT_NE(sendData(users_queue, data_to_write.size(), data_to_write.c_str()), 0);
|
||||
EXPECT_TRUE(isDataAvailable(owners_queue));
|
||||
resetIpc(owners_queue, num_of_shmem_elem);
|
||||
EXPECT_FALSE(isDataAvailable(owners_queue));
|
||||
EXPECT_EQ(sendData(users_queue, data_to_write.size(), data_to_write.c_str()), 0);
|
||||
}
|
||||
|
||||
TEST_F(SharedIPCTest, write_read_pop_mulltiple_elements_transaction)
|
||||
{
|
||||
int my_first_int = 1;
|
||||
int my_second_int = 20;
|
||||
int my_third_int = 300;
|
||||
int my_fourth_int = 4000;
|
||||
int my_fifth_int = 50000;
|
||||
|
||||
char my_first_char = '1';
|
||||
char my_second_char = '2';
|
||||
char my_third_char = '3';
|
||||
char my_fourth_char = '4';
|
||||
char my_fifth_char = '5';
|
||||
|
||||
vector<const char *> data1 = {
|
||||
reinterpret_cast<const char *>(&my_first_int),
|
||||
reinterpret_cast<const char *>(&my_second_int),
|
||||
reinterpret_cast<const char *>(&my_third_int),
|
||||
reinterpret_cast<const char *>(&my_fourth_int),
|
||||
reinterpret_cast<const char *>(&my_fifth_int)
|
||||
};
|
||||
vector<uint16_t> sizes1 = { sizeof(int), sizeof(int), sizeof(int), sizeof(int), sizeof(int) };
|
||||
|
||||
vector<const char *> data2 = {
|
||||
const_cast<const char *>(&my_first_char),
|
||||
const_cast<const char *>(&my_second_char),
|
||||
const_cast<const char *>(&my_third_char),
|
||||
const_cast<const char *>(&my_fourth_char),
|
||||
const_cast<const char *>(&my_fifth_char)
|
||||
};
|
||||
vector<uint16_t> sizes2 = { sizeof(char), sizeof(char), sizeof(char), sizeof(char), sizeof(char) };
|
||||
|
||||
const char *read_data = nullptr;
|
||||
uint16_t read_bytes = 0;
|
||||
|
||||
EXPECT_EQ(sendChunkedData(owners_queue, sizes1.data(), data1.data(), data1.size()), 0);
|
||||
EXPECT_TRUE(isDataAvailable(users_queue));
|
||||
EXPECT_EQ(receiveData(users_queue, &read_bytes, &read_data), 0);
|
||||
vector<int> expected_data = { my_first_int, my_second_int, my_third_int, my_fourth_int, my_fifth_int };
|
||||
vector<int> received_data(
|
||||
reinterpret_cast<const int *>(read_data),
|
||||
reinterpret_cast<const int *>(read_data) + read_bytes/sizeof(int)
|
||||
);
|
||||
EXPECT_EQ(received_data, expected_data);
|
||||
EXPECT_EQ(popData(users_queue), 0);
|
||||
EXPECT_FALSE(isDataAvailable(users_queue));
|
||||
|
||||
EXPECT_EQ(sendChunkedData(users_queue, sizes1.data(), data1.data(), data1.size()), 0);
|
||||
EXPECT_TRUE(isDataAvailable(owners_queue));
|
||||
EXPECT_EQ(receiveData(owners_queue, &read_bytes, &read_data), 0);
|
||||
vector<char> expected_char_data = { my_first_char, my_second_char, my_third_char, my_fourth_char, my_fifth_char };
|
||||
vector<char> received_char_data(read_data, read_data + read_bytes/sizeof(char));
|
||||
EXPECT_EQ(received_data, expected_data);
|
||||
EXPECT_EQ(popData(owners_queue), 0);
|
||||
EXPECT_FALSE(isDataAvailable(owners_queue));
|
||||
}
|
||||
|
||||
TEST_F(SharedIPCTest, ensure_right_permissions)
|
||||
{
|
||||
char queue_name_tx[max_one_way_queue_name_length];
|
||||
char queue_name_rx[max_one_way_queue_name_length];
|
||||
snprintf(queue_name_tx, sizeof(queue_name_tx) - 1, "/dev/shm/__cp_nano_tx_shared_memory_%s__", shmem_name.c_str());
|
||||
snprintf(queue_name_rx, sizeof(queue_name_rx) - 1, "/dev/shm/__cp_nano_rx_shared_memory_%s__", shmem_name.c_str());
|
||||
for (char *queue_name : {queue_name_tx, queue_name_rx}) {
|
||||
struct stat info;
|
||||
stat(queue_name, &info);
|
||||
EXPECT_EQ(info.st_uid, uid);
|
||||
EXPECT_EQ(info.st_gid, gid);
|
||||
EXPECT_EQ(info.st_mode & S_IRUSR, S_IRUSR);
|
||||
EXPECT_EQ(info.st_mode & S_IWUSR, S_IWUSR);
|
||||
EXPECT_NE(info.st_mode & S_IXUSR, S_IXUSR);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user