mirror of
https://github.com/openappsec/attachment.git
synced 2025-06-28 16:41:03 +03:00
adding istio files
This commit is contained in:
parent
3c614f385a
commit
1290c51ab6
@ -1 +1,3 @@
|
|||||||
|
add_subdirectory(envoy)
|
||||||
|
add_subdirectory(nano_attachment)
|
||||||
add_subdirectory(nginx)
|
add_subdirectory(nginx)
|
||||||
|
31
attachments/envoy/CMakeLists.txt
Executable file
31
attachments/envoy/CMakeLists.txt
Executable file
@ -0,0 +1,31 @@
|
|||||||
|
if("${PLATFORM_TYPE}" STREQUAL "x86")
|
||||||
|
set(ATTACHMENTS_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/core/include/attachments)
|
||||||
|
set(NANO_ATTACHMENT_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/attachments/nano_attachment)
|
||||||
|
set(SHMEM_LIBRARY_DIR ${CMAKE_BINARY_DIR}/core/shmem_ipc_2)
|
||||||
|
set(NANO_ATTACHMENT_LIBRARY_DIR ${CMAKE_BINARY_DIR}/attachments/nano_attachment)
|
||||||
|
set(NANO_ATTACHMENT_UTIL_LIBRARY_DIR ${CMAKE_BINARY_DIR}/attachments/nano_attachment/nano_attachment_util)
|
||||||
|
set(LIBRARIES "-lnano_attachment -lnano_attachment_util -lshmem_ipc_2")
|
||||||
|
set(ENVOY_ATTACHMENT_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
# Configure the build.sh script from the template
|
||||||
|
configure_file(
|
||||||
|
${PROJECT_SOURCE_DIR}/attachments/envoy/build_template
|
||||||
|
${CMAKE_BINARY_DIR}/attachments/envoy/build.sh
|
||||||
|
@ONLY
|
||||||
|
)
|
||||||
|
|
||||||
|
# Define a custom command to run the bash script
|
||||||
|
add_custom_target(
|
||||||
|
envoy_attachment ALL
|
||||||
|
COMMAND chmod +x ${CMAKE_BINARY_DIR}/attachments/envoy/build.sh
|
||||||
|
COMMAND ${CMAKE_BINARY_DIR}/attachments/envoy/build.sh
|
||||||
|
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/attachments/envoy
|
||||||
|
COMMENT "Building envoy attachment"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_dependencies(envoy_attachment shmem_ipc_2 nano_attachment nano_attachment_util)
|
||||||
|
|
||||||
|
install(FILES libenvoy_attachment.so DESTINATION ${CMAKE_BINARY_DIR}/attachments/envoy PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ)
|
||||||
|
install(FILES libenvoy_attachment.so DESTINATION lib PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ)
|
||||||
|
endif()
|
||||||
|
|
13
attachments/envoy/build_template
Normal file
13
attachments/envoy/build_template
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Set environment variables
|
||||||
|
SHMEM_LIBRARY_DIR="@SHMEM_LIBRARY_DIR@"
|
||||||
|
NANO_ATTACHMENT_LIBRARY_DIR="@NANO_ATTACHMENT_LIBRARY_DIR@"
|
||||||
|
NANO_ATTACHMENT_UTIL_LIBRARY_DIR="@NANO_ATTACHMENT_UTIL_LIBRARY_DIR@"
|
||||||
|
LIBRARIES="@LIBRARIES@"
|
||||||
|
ENVOY_ATTACHMENT_DIR="@ENVOY_ATTACHMENT_DIR@"
|
||||||
|
|
||||||
|
cd $ENVOY_ATTACHMENT_DIR
|
||||||
|
|
||||||
|
# Run the go build command
|
||||||
|
CGO_CFLAGS="-I@ATTACHMENTS_INCLUDE_DIR@ -I@NANO_ATTACHMENT_INCLUDE_DIR@" go build -o ${ENVOY_ATTACHMENT_DIR}/libenvoy_attachment.so -buildmode=c-shared -ldflags="-extldflags '-L${SHMEM_LIBRARY_DIR} -L${NANO_ATTACHMENT_LIBRARY_DIR} -L${NANO_ATTACHMENT_UTIL_LIBRARY_DIR} ${LIBRARIES}'"
|
352
attachments/envoy/config.go
Executable file
352
attachments/envoy/config.go
Executable file
@ -0,0 +1,352 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-chi/chi/v5"
|
||||||
|
|
||||||
|
xds "github.com/cncf/xds/go/xds/type/v3"
|
||||||
|
"google.golang.org/protobuf/types/known/anypb"
|
||||||
|
|
||||||
|
"github.com/envoyproxy/envoy/contrib/golang/common/go/api"
|
||||||
|
envoyHttp "github.com/envoyproxy/envoy/contrib/golang/filters/http/source/go/pkg/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
unsigned long get_thread_id() {
|
||||||
|
return (unsigned long)pthread_self();
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "nano_initializer.h"
|
||||||
|
#include "nano_attachment.h"
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
const Name = "cp_nano_filter"
|
||||||
|
|
||||||
|
const Admin_api = "http://127.0.0.1:%s/server_info"
|
||||||
|
|
||||||
|
var filter_id atomic.Int64
|
||||||
|
|
||||||
|
type nano_attachment C.struct_NanoAttachment
|
||||||
|
|
||||||
|
var attachments_map map[int]*nano_attachment = nil
|
||||||
|
var thread_to_attachment_mapping map[int]int = nil
|
||||||
|
var attachment_to_thread_mapping map[int]int = nil
|
||||||
|
|
||||||
|
var attachment_to_filter_request_structs map[int]*filterRequestStructs = nil
|
||||||
|
|
||||||
|
var mutex sync.Mutex
|
||||||
|
|
||||||
|
const keep_alive_interval = 10 * time.Second
|
||||||
|
|
||||||
|
var last_keep_alive time.Time
|
||||||
|
|
||||||
|
// EnvoyServerInfo represents the structure of the JSON response from /server_info
|
||||||
|
type EnvoyServerInfo struct {
|
||||||
|
Concurrency int `json:"concurrency"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// getEnvoyConcurrency fetches and returns the concurrency level of Envoy from the admin API
|
||||||
|
func getEnvoyConcurrency(admin_api_address string) (int, error) {
|
||||||
|
resp, err := http.Get(admin_api_address)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("failed to reach Envoy admin API: %w", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return 0, fmt.Errorf("unexpected status code from Envoy admin API: %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("failed to read response body: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var info EnvoyServerInfo
|
||||||
|
if err := json.Unmarshal(body, &info); err != nil {
|
||||||
|
return 0, fmt.Errorf("failed to parse JSON response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return info.Concurrency, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func configurationServer() {
|
||||||
|
r := chi.NewRouter()
|
||||||
|
|
||||||
|
r.Get("/load-config", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
mutex.Lock()
|
||||||
|
defer mutex.Unlock()
|
||||||
|
worker_ids := make([]int, 0)
|
||||||
|
workersParam := r.URL.Query().Get("workers")
|
||||||
|
num_of_workers := len(attachments_map) // concurrency
|
||||||
|
if workersParam == "" {
|
||||||
|
for i := 0; i < num_of_workers; i++ {
|
||||||
|
worker_ids = append(worker_ids, i)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
workers := strings.Split(workersParam, ",")
|
||||||
|
for _, worker := range workers {
|
||||||
|
worker_id, err := strconv.Atoi(worker)
|
||||||
|
|
||||||
|
if worker_id >= num_of_workers {
|
||||||
|
api.LogWarnf(
|
||||||
|
"Can not load configuration of invalid worker ID %d. worker ID should be lower than: %d",
|
||||||
|
worker_id,
|
||||||
|
num_of_workers)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil || worker_id >= num_of_workers {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.Write([]byte(fmt.Sprintf(`{"error": "invalid worker ID: %s"}`, worker)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
worker_ids = append(worker_ids, worker_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
workers_reload_status := make(map[string]string, len(worker_ids))
|
||||||
|
res := C.NANO_OK
|
||||||
|
for _, worker_id := range worker_ids {
|
||||||
|
worker_reload_res := C.RestartAttachmentConfiguration((*C.NanoAttachment)(attachments_map[worker_id]))
|
||||||
|
if worker_reload_res == C.NANO_ERROR {
|
||||||
|
res = C.NANO_ERROR
|
||||||
|
workers_reload_status[strconv.Itoa(worker_id)] = "Reload Configuraiton Failed"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
workers_reload_status[strconv.Itoa(worker_id)] = "Reload Configuraiton Succeded"
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := json.Marshal(workers_reload_status)
|
||||||
|
if err != nil {
|
||||||
|
api.LogWarnf("Error while sending reponse about reload configuration. Err: %s", err.Error())
|
||||||
|
response = []byte(`{"error": "Internal Error"}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if res == C.NANO_ERROR || err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.Write(response)
|
||||||
|
})
|
||||||
|
|
||||||
|
http.ListenAndServe(":8119", r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
last_keep_alive = time.Time{}
|
||||||
|
envoyHttp.RegisterHttpFilterFactoryAndConfigParser(Name, ConfigFactory, &parser{})
|
||||||
|
//envoyHttp.RegisterHttpFilterConfigFactoryAndParser(Name, ConfigFactory, &parser{})
|
||||||
|
go configurationServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
type config struct {}
|
||||||
|
|
||||||
|
type parser struct {}
|
||||||
|
|
||||||
|
func sendKeepAlive() {
|
||||||
|
for {
|
||||||
|
attachment_ptr := (*C.NanoAttachment)(attachments_map[0])
|
||||||
|
if attachment_ptr == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
C.SendKeepAlive(attachment_ptr)
|
||||||
|
time.Sleep(30 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) initFilterStructs() *filterRequestStructs {
|
||||||
|
return &filterRequestStructs {
|
||||||
|
http_start_data: (*C.HttpRequestFilterData)(C.malloc(C.sizeof_HttpRequestFilterData)),
|
||||||
|
http_meta_data: (*C.HttpMetaData)(C.malloc(C.sizeof_HttpMetaData)),
|
||||||
|
http_headers: (*C.HttpHeaders)(C.malloc(C.sizeof_HttpHeaders)),
|
||||||
|
http_headers_data: (*C.HttpHeaderData)(C.malloc(10000 * C.sizeof_HttpHeaderData)),
|
||||||
|
http_res_headers: (*C.ResHttpHeaders)(C.malloc(C.sizeof_ResHttpHeaders)),
|
||||||
|
http_body_data: (*C.nano_str_t)(C.malloc(10000 * C.sizeof_nano_str_t)),
|
||||||
|
attachment_data: (*C.AttachmentData)(C.malloc(C.sizeof_AttachmentData)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the filter configuration. We can call the ConfigCallbackHandler to control the filter's
|
||||||
|
// behavior
|
||||||
|
func (p *parser) Parse(any *anypb.Any, callbacks api.ConfigCallbackHandler) (interface{}, error) {
|
||||||
|
conf := &config{}
|
||||||
|
|
||||||
|
if attachments_map != nil {
|
||||||
|
api.LogInfof("Waf Configuration already loaded")
|
||||||
|
return conf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var num_of_workers int
|
||||||
|
concurrency_method := getEnv("CONCURRENCY_CALC", "numOfCores")
|
||||||
|
|
||||||
|
if concurrency_method == "numOfCores" {
|
||||||
|
num_of_workers = runtime.NumCPU()
|
||||||
|
api.LogInfof("using number of cpu cores %d", num_of_workers)
|
||||||
|
} else if concurrency_method == "config" {
|
||||||
|
config_port := getEnv("CONFIG_PORT", "15000")
|
||||||
|
admin_api := fmt.Sprintf(Admin_api, config_port)
|
||||||
|
workers, err := getEnvoyConcurrency(admin_api)
|
||||||
|
if err != nil {
|
||||||
|
api.LogWarnf("unable to fetch concurrency from admin server, using cpu cores. err: %s", err.Error())
|
||||||
|
num_of_workers = runtime.NumCPU()
|
||||||
|
} else {
|
||||||
|
num_of_workers = workers
|
||||||
|
}
|
||||||
|
} else if concurrency_method == "custom" {
|
||||||
|
conc_number := getEnv("CONCURRENCY_NUMBER", "-1")
|
||||||
|
if conc_number == "-1" {
|
||||||
|
api.LogWarnf("concurrency number is not set as an env variable, using cpu cores")
|
||||||
|
num_of_workers = runtime.NumCPU()
|
||||||
|
} else if conc_num, err := strconv.Atoi(conc_number); err == nil && conc_num > 0 {
|
||||||
|
num_of_workers = conc_num
|
||||||
|
} else {
|
||||||
|
api.LogWarnf("error converting conc_number %s, using num of cpu cores", conc_number)
|
||||||
|
num_of_workers = runtime.NumCPU()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
api.LogWarnf("unable to fetch concurrency from %s, using cpu cores", concurrency_method)
|
||||||
|
num_of_workers = runtime.NumCPU()
|
||||||
|
}
|
||||||
|
|
||||||
|
configStruct := &xds.TypedStruct{}
|
||||||
|
if err := any.UnmarshalTo(configStruct); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
attachments_map = make(map[int]*nano_attachment)
|
||||||
|
attachment_to_filter_request_structs = make(map[int]*filterRequestStructs)
|
||||||
|
attachment_to_thread_mapping = make(map[int]int, 0)
|
||||||
|
thread_to_attachment_mapping = make(map[int]int, 0)
|
||||||
|
api.LogInfof("Number of worker threds: %d", num_of_workers)
|
||||||
|
for worker_id := 0; worker_id < num_of_workers; worker_id++ {
|
||||||
|
|
||||||
|
attachment := C.InitNanoAttachment(C.uint8_t(0), C.int(worker_id), C.int(num_of_workers), C.int(C.fileno(C.stdout)))
|
||||||
|
for attachment == nil {
|
||||||
|
api.LogWarnf("attachment is nill going to sleep for two seconds and retry")
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
attachment = C.InitNanoAttachment(C.uint8_t(0), C.int(worker_id), C.int(num_of_workers), C.int(C.fileno(C.stdout)))
|
||||||
|
}
|
||||||
|
|
||||||
|
//mutex.Lock()
|
||||||
|
attachments_map[worker_id] = (*nano_attachment)(attachment)
|
||||||
|
attachment_to_filter_request_structs[worker_id] = p.initFilterStructs()
|
||||||
|
//mutex.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
go func (){
|
||||||
|
sendKeepAlive()
|
||||||
|
}()
|
||||||
|
|
||||||
|
return conf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge configuration from the inherited parent configuration
|
||||||
|
func (p *parser) Merge(parent interface{}, child interface{}) interface{} {
|
||||||
|
parentConfig := parent.(*config)
|
||||||
|
|
||||||
|
// copy one, do not update parentConfig directly.
|
||||||
|
newConfig := *parentConfig
|
||||||
|
return &newConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// func ConfigFactory(c interface{}) api.StreamFilterFactory {
|
||||||
|
// conf, ok := c.(*config)
|
||||||
|
// if !ok {
|
||||||
|
// panic("unexpected config type")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return func(callbacks api.FilterCallbackHandler) api.StreamFilter {
|
||||||
|
// worker_thread_id := int(C.get_thread_id())
|
||||||
|
// api.LogDebugf("worker_thread_id: %d", worker_thread_id)
|
||||||
|
// if _, ok := thread_to_attachment_mapping[int(worker_thread_id)]; !ok {
|
||||||
|
// api.LogDebugf("need to add new thread to the map")
|
||||||
|
// map_size := len(attachment_to_thread_mapping)
|
||||||
|
// if map_size < len(attachments_map) {
|
||||||
|
// attachment_to_thread_mapping[map_size] = worker_thread_id
|
||||||
|
// thread_to_attachment_mapping[worker_thread_id] = map_size
|
||||||
|
// api.LogDebugf("len(attachment_to_thread_mapping): %d", len(attachment_to_thread_mapping))
|
||||||
|
// api.LogDebugf("thread_to_attachment_mapping: %v", thread_to_attachment_mapping)
|
||||||
|
// api.LogDebugf("attachment_to_thread_mapping: %v", attachment_to_thread_mapping)
|
||||||
|
// } else {
|
||||||
|
// panic("unexpected thread id")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// worker_id := thread_to_attachment_mapping[int(worker_thread_id)]
|
||||||
|
// api.LogDebugf("worker_id: %d", worker_id)
|
||||||
|
|
||||||
|
// filter_id.Add(1)
|
||||||
|
// session_id := filter_id.Load()
|
||||||
|
// attachment_ptr := attachments_map[worker_id]
|
||||||
|
// session_data := C.InitSessionData((*C.NanoAttachment)(attachment_ptr), C.SessionID(session_id))
|
||||||
|
|
||||||
|
// return &filter{
|
||||||
|
// callbacks: callbacks,
|
||||||
|
// config: conf,
|
||||||
|
// session_id: session_id,
|
||||||
|
// cp_attachment: attachment_ptr,
|
||||||
|
// session_data: session_data,
|
||||||
|
// request_structs: attachment_to_filter_request_structs[worker_id],
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
func ConfigFactory(c interface{}, callbacks api.FilterCallbackHandler) api.StreamFilter {
|
||||||
|
conf, ok := c.(*config)
|
||||||
|
if !ok {
|
||||||
|
panic("unexpected config type")
|
||||||
|
}
|
||||||
|
|
||||||
|
worker_thread_id := int(C.get_thread_id())
|
||||||
|
api.LogDebugf("worker_thread_id: %d", worker_thread_id)
|
||||||
|
if _, ok := thread_to_attachment_mapping[int(worker_thread_id)]; !ok {
|
||||||
|
api.LogDebugf("need to add new thread to the map")
|
||||||
|
map_size := len(attachment_to_thread_mapping)
|
||||||
|
if map_size < len(attachments_map) {
|
||||||
|
attachment_to_thread_mapping[map_size] = worker_thread_id
|
||||||
|
thread_to_attachment_mapping[worker_thread_id] = map_size
|
||||||
|
api.LogDebugf("len(attachment_to_thread_mapping): %d", len(attachment_to_thread_mapping))
|
||||||
|
api.LogDebugf("thread_to_attachment_mapping: %v", thread_to_attachment_mapping)
|
||||||
|
api.LogDebugf("attachment_to_thread_mapping: %v", attachment_to_thread_mapping)
|
||||||
|
} else {
|
||||||
|
panic("unexpected thread id")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
worker_id := thread_to_attachment_mapping[int(worker_thread_id)]
|
||||||
|
api.LogDebugf("worker_id: %d", worker_id)
|
||||||
|
|
||||||
|
filter_id.Add(1)
|
||||||
|
session_id := filter_id.Load()
|
||||||
|
attachment_ptr := attachments_map[worker_id]
|
||||||
|
session_data := C.InitSessionData((*C.NanoAttachment)(attachment_ptr), C.SessionID(session_id))
|
||||||
|
|
||||||
|
return &filter{
|
||||||
|
callbacks: callbacks,
|
||||||
|
config: conf,
|
||||||
|
session_id: session_id,
|
||||||
|
cp_attachment: attachment_ptr,
|
||||||
|
session_data: session_data,
|
||||||
|
request_structs: attachment_to_filter_request_structs[worker_id],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func main() {}
|
488
attachments/envoy/filter.go
Executable file
488
attachments/envoy/filter.go
Executable file
@ -0,0 +1,488 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
unsigned long get_thread_id_2() {
|
||||||
|
return (unsigned long)pthread_self();
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "nano_attachment.h"
|
||||||
|
|
||||||
|
HttpHeaderData* createHttpHeaderDataArray(int size) {
|
||||||
|
return (HttpHeaderData*)malloc(size * sizeof(HttpHeaderData));
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpMetaData* createHttpMetaData() {
|
||||||
|
return (HttpMetaData*)malloc(sizeof(HttpMetaData));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setHeaderElement(HttpHeaderData* arr, int index, nano_str_t key, nano_str_t value) {
|
||||||
|
if (arr == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
arr[index].key = key;
|
||||||
|
arr[index].value = value;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"github.com/envoyproxy/envoy/contrib/golang/common/go/api"
|
||||||
|
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func convertBlockPageToString(block_page C.BlockPageData) string {
|
||||||
|
block_page_size := block_page.title_prefix.len +
|
||||||
|
block_page.title.len +
|
||||||
|
block_page.body_prefix.len +
|
||||||
|
block_page.body.len +
|
||||||
|
block_page.uuid_prefix.len +
|
||||||
|
block_page.uuid.len +
|
||||||
|
block_page.uuid_suffix.len
|
||||||
|
|
||||||
|
block_page_bytes := make([]byte, block_page_size)
|
||||||
|
|
||||||
|
location := 0
|
||||||
|
location = copyToSlice(
|
||||||
|
block_page_bytes,
|
||||||
|
unsafe.Pointer(block_page.title_prefix.data),
|
||||||
|
C.size_t(block_page.title_prefix.len),
|
||||||
|
location)
|
||||||
|
|
||||||
|
location = copyToSlice(
|
||||||
|
block_page_bytes,
|
||||||
|
unsafe.Pointer(block_page.title.data),
|
||||||
|
C.size_t(block_page.title.len),
|
||||||
|
location)
|
||||||
|
|
||||||
|
location = copyToSlice(
|
||||||
|
block_page_bytes,
|
||||||
|
unsafe.Pointer(block_page.body_prefix.data),
|
||||||
|
C.size_t(block_page.body_prefix.len),
|
||||||
|
location)
|
||||||
|
|
||||||
|
location = copyToSlice(
|
||||||
|
block_page_bytes,
|
||||||
|
unsafe.Pointer(block_page.body.data),
|
||||||
|
C.size_t(block_page.body.len),
|
||||||
|
location)
|
||||||
|
|
||||||
|
location = copyToSlice(
|
||||||
|
block_page_bytes,
|
||||||
|
unsafe.Pointer(block_page.uuid_prefix.data),
|
||||||
|
C.size_t(block_page.uuid_prefix.len),
|
||||||
|
location)
|
||||||
|
|
||||||
|
location = copyToSlice(
|
||||||
|
block_page_bytes,
|
||||||
|
unsafe.Pointer(block_page.uuid.data),
|
||||||
|
C.size_t(block_page.uuid.len),
|
||||||
|
location)
|
||||||
|
|
||||||
|
copyToSlice(
|
||||||
|
block_page_bytes,
|
||||||
|
unsafe.Pointer(block_page.uuid_suffix.data),
|
||||||
|
C.size_t(block_page.uuid_suffix.len),
|
||||||
|
location)
|
||||||
|
|
||||||
|
return string(block_page_bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The callbacks in the filter, like `DecodeHeaders`, can be implemented on demand.
|
||||||
|
// Because api.PassThroughStreamFilter provides a default implementation.
|
||||||
|
type filter struct {
|
||||||
|
api.PassThroughStreamFilter
|
||||||
|
|
||||||
|
callbacks api.FilterCallbackHandler
|
||||||
|
path string
|
||||||
|
config *config
|
||||||
|
session_id int64
|
||||||
|
session_data *C.HttpSessionData
|
||||||
|
cp_attachment *nano_attachment
|
||||||
|
request_structs *filterRequestStructs
|
||||||
|
}
|
||||||
|
|
||||||
|
type filterRequestStructs struct {
|
||||||
|
http_start_data *C.HttpRequestFilterData
|
||||||
|
http_meta_data *C.HttpMetaData
|
||||||
|
http_headers *C.HttpHeaders
|
||||||
|
http_headers_data *C.HttpHeaderData
|
||||||
|
http_res_headers *C.ResHttpHeaders
|
||||||
|
http_body_data *C.nano_str_t
|
||||||
|
attachment_data *C.AttachmentData
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filterRequestStructs) ZeroInitialize() {
|
||||||
|
if f.http_start_data != nil {
|
||||||
|
C.memset(unsafe.Pointer(f.http_start_data), 0, C.size_t(unsafe.Sizeof(*f.http_start_data)))
|
||||||
|
}
|
||||||
|
if f.http_meta_data != nil {
|
||||||
|
C.memset(unsafe.Pointer(f.http_meta_data), 0, C.size_t(unsafe.Sizeof(*f.http_meta_data)))
|
||||||
|
}
|
||||||
|
if f.http_headers != nil {
|
||||||
|
C.memset(unsafe.Pointer(f.http_headers), 0, C.size_t(unsafe.Sizeof(*f.http_headers)))
|
||||||
|
}
|
||||||
|
if f.http_headers_data != nil {
|
||||||
|
C.memset(unsafe.Pointer(f.http_headers_data), 0, C.size_t(unsafe.Sizeof(*f.http_headers_data)))
|
||||||
|
}
|
||||||
|
if f.attachment_data != nil {
|
||||||
|
C.memset(unsafe.Pointer(f.attachment_data), 0, C.size_t(unsafe.Sizeof(*f.attachment_data)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) isSessionFinalized() bool {
|
||||||
|
return C.IsSessionFinalized((*C.NanoAttachment)(f.cp_attachment), (*C.HttpSessionData)(f.session_data)) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) sendData(data unsafe.Pointer, chunkType C.HttpChunkType) C.AttachmentVerdictResponse {
|
||||||
|
|
||||||
|
attachment_data := f.request_structs.attachment_data
|
||||||
|
attachment_data.session_id = C.uint32_t(f.session_id)
|
||||||
|
attachment_data.chunk_type = chunkType // Adjust type as needed
|
||||||
|
attachment_data.session_data = f.session_data // Ensure `f.session_data` is compatible
|
||||||
|
attachment_data.data = C.DataBuffer(data) // Ensure `data` is compatible with `C.DataBuffer`
|
||||||
|
|
||||||
|
return C.SendDataNanoAttachment((*C.NanoAttachment)(f.cp_attachment), attachment_data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) handleCustomResponse(verdict_response *C.AttachmentVerdictResponse) api.StatusType {
|
||||||
|
if verdict_response.web_response_data.web_response_type == C.CUSTOM_WEB_RESPONSE {
|
||||||
|
headers := map[string][]string{
|
||||||
|
"Content-Type": []string{"text/html"},
|
||||||
|
}
|
||||||
|
block_page_parts := C.GetBlockPage(
|
||||||
|
(*C.NanoAttachment)(f.cp_attachment),
|
||||||
|
(*C.HttpSessionData)(f.session_data),
|
||||||
|
(*C.AttachmentVerdictResponse)(verdict_response))
|
||||||
|
return f.sendLocalReplyInternal(int(block_page_parts.response_code), convertBlockPageToString(block_page_parts), headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
redirect_data := C.GetRedirectPage(
|
||||||
|
(*C.NanoAttachment)(f.cp_attachment),
|
||||||
|
(*C.HttpSessionData)(f.session_data),
|
||||||
|
(*C.AttachmentVerdictResponse)(verdict_response))
|
||||||
|
redirect_location := redirect_data.redirect_location
|
||||||
|
|
||||||
|
redirect_location_slice := unsafe.Slice((*byte)(unsafe.Pointer(redirect_location.data)), redirect_location.len)
|
||||||
|
headers := map[string][]string{
|
||||||
|
"Location": []string{string(redirect_location_slice)},
|
||||||
|
}
|
||||||
|
|
||||||
|
return f.sendLocalReplyInternal(307, "", headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) finalizeRequest(verdict_response *C.AttachmentVerdictResponse) api.StatusType {
|
||||||
|
if C.AttachmentVerdict(verdict_response.verdict) == C.ATTACHMENT_VERDICT_DROP {
|
||||||
|
return f.handleCustomResponse(verdict_response)
|
||||||
|
}
|
||||||
|
|
||||||
|
return api.Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) handleHeaders(header api.HeaderMap) {
|
||||||
|
const envoy_headers_prefix = "x-envoy"
|
||||||
|
i := 0
|
||||||
|
header.Range(func(key, value string) bool {
|
||||||
|
if i > 10000 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
api.LogInfof("inserting headers: key %s, value %s", key, value)
|
||||||
|
|
||||||
|
if strings.HasPrefix(key, envoy_headers_prefix) ||
|
||||||
|
key == "x-request-id" ||
|
||||||
|
key == ":method" ||
|
||||||
|
key == ":path" ||
|
||||||
|
key == ":scheme" ||
|
||||||
|
key == "x-forwarded-proto" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if key == ":authority" {
|
||||||
|
key = "Host"
|
||||||
|
}
|
||||||
|
|
||||||
|
key_nano_str := createNanoStrWithoutCopy(key)
|
||||||
|
value_nano_str := createNanoStrWithoutCopy(value)
|
||||||
|
C.setHeaderElement((*C.HttpHeaderData)(f.request_structs.http_headers_data), C.int(i), key_nano_str, value_nano_str)
|
||||||
|
i++
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
http_headers := f.request_structs.http_headers
|
||||||
|
http_headers.data = f.request_structs.http_headers_data
|
||||||
|
http_headers.headers_count = C.size_t(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) sendBody(buffer api.BufferInstance, is_req bool) C.AttachmentVerdictResponse {
|
||||||
|
chunk_type := C.HTTP_REQUEST_BODY
|
||||||
|
if !is_req {
|
||||||
|
chunk_type = C.HTTP_RESPONSE_BODY
|
||||||
|
}
|
||||||
|
|
||||||
|
data := buffer.Bytes()
|
||||||
|
data_len := len(data)
|
||||||
|
buffer_size := 8 * 1024
|
||||||
|
|
||||||
|
// body_chunk := newNanoStr(data)
|
||||||
|
// body_chunk.data = (*C.uchar)(unsafe.Pointer(&data[0]))
|
||||||
|
|
||||||
|
num_of_buffers := ((data_len - 1) / buffer_size) + 1
|
||||||
|
|
||||||
|
// TO DO: FIX THIS ASAP
|
||||||
|
if num_of_buffers > 10000 {
|
||||||
|
num_of_buffers = 10000
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for i := 0; i < num_of_buffers; i++ {
|
||||||
|
nanoStrPtr := (*C.nano_str_t)(unsafe.Pointer(uintptr(unsafe.Pointer(f.request_structs.http_body_data)) + uintptr(i)*unsafe.Sizeof(*f.request_structs.http_body_data)))
|
||||||
|
nanoStrPtr.data = (*C.uchar)(unsafe.Pointer(&data[i * buffer_size]))
|
||||||
|
|
||||||
|
if i + 1 == num_of_buffers {
|
||||||
|
nanoStrPtr.len = C.size_t(data_len - (i * buffer_size))
|
||||||
|
} else {
|
||||||
|
nanoStrPtr.len = C.size_t(buffer_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
http_chunks_array := C.HttpBody{
|
||||||
|
data: f.request_structs.http_body_data,
|
||||||
|
bodies_count: C.size_t(num_of_buffers),
|
||||||
|
}
|
||||||
|
|
||||||
|
api.LogInfof("sending body data: %+v", http_chunks_array)
|
||||||
|
return f.sendData(unsafe.Pointer(&http_chunks_array), C.HttpChunkType(chunk_type))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) sendStartTransaction(start_transaction_data *C.HttpRequestFilterData) C.AttachmentVerdictResponse {
|
||||||
|
return f.sendData(unsafe.Pointer(&start_transaction_data), C.HTTP_REQUEST_FILTER)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) handleStartTransaction(header api.RequestHeaderMap) {
|
||||||
|
stream_info := f.callbacks.StreamInfo()
|
||||||
|
|
||||||
|
ip_location := 0
|
||||||
|
port_location := 1
|
||||||
|
|
||||||
|
listening_address := stream_info.DownstreamLocalAddress()
|
||||||
|
listening_address_arr := strings.Split(listening_address, ":")
|
||||||
|
listening_port, _ := strconv.Atoi(listening_address_arr[port_location])
|
||||||
|
|
||||||
|
client_address := stream_info.DownstreamRemoteAddress()
|
||||||
|
client_addr_arr := strings.Split(client_address, ":")
|
||||||
|
client_port, _ := strconv.Atoi(client_addr_arr[port_location])
|
||||||
|
|
||||||
|
host := strings.Split(header.Host(), ":")[0]
|
||||||
|
|
||||||
|
protocol, _ := stream_info.Protocol()
|
||||||
|
|
||||||
|
// init start transaction struct
|
||||||
|
meta_data := f.request_structs.http_meta_data
|
||||||
|
meta_data.http_protocol = createNanoStr(protocol)
|
||||||
|
meta_data.method_name = createNanoStr(header.Method())
|
||||||
|
meta_data.host = createNanoStr(host)
|
||||||
|
meta_data.listening_ip = createNanoStr(listening_address_arr[ip_location])
|
||||||
|
meta_data.listening_port = C.uint16_t(listening_port)
|
||||||
|
meta_data.uri = createNanoStr(header.Path())
|
||||||
|
meta_data.client_ip = createNanoStr(client_addr_arr[ip_location])
|
||||||
|
meta_data.client_port = C.uint16_t(client_port)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) sendLocalReplyInternal(ret_code int, custom_response string, headers map[string][]string) api.StatusType {
|
||||||
|
//f.callbacks.DecoderFilterCallbacks().SendLocalReply(ret_code, custom_response, headers, 0, "") // new api
|
||||||
|
// var headers_map map[string]string = nil
|
||||||
|
// if headers != nil {
|
||||||
|
// headers_map = make(map[string]string)
|
||||||
|
// for key, val := range headers {
|
||||||
|
// header_val := ""
|
||||||
|
// if len(val) > 0 {
|
||||||
|
// header_val = val[0]
|
||||||
|
// }
|
||||||
|
|
||||||
|
// headers_map[key] = header_val
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
f.callbacks.DecoderFilterCallbacks().SendLocalReply(ret_code, custom_response, headers, 0, "")
|
||||||
|
return api.LocalReply
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) endInspectionPart(chunk_type C.HttpChunkType) api.StatusType {
|
||||||
|
api.LogInfof("Ending inspection for current chunk")
|
||||||
|
res := f.sendData(nil, chunk_type)
|
||||||
|
|
||||||
|
if C.AttachmentVerdict(res.verdict) != C.ATTACHMENT_VERDICT_INSPECT {
|
||||||
|
api.LogInfof("got final verict: %v", res.verdict)
|
||||||
|
return f.finalizeRequest(&res)
|
||||||
|
}
|
||||||
|
|
||||||
|
return api.Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callbacks which are called in request path
|
||||||
|
// The endStream is true if the request doesn't have body
|
||||||
|
func (f *filter) DecodeHeaders(header api.RequestHeaderMap, endStream bool) api.StatusType {
|
||||||
|
ret := api.Continue
|
||||||
|
|
||||||
|
defer RecoverPanic(&ret)
|
||||||
|
|
||||||
|
if f.isSessionFinalized() {
|
||||||
|
api.LogInfof("session has already been inspected, no need for further inspection")
|
||||||
|
return api.Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
f.handleStartTransaction(header)
|
||||||
|
f.handleHeaders(header)
|
||||||
|
|
||||||
|
http_start_data := f.request_structs.http_start_data
|
||||||
|
http_start_data.meta_data = f.request_structs.http_meta_data
|
||||||
|
http_start_data.req_headers = f.request_structs.http_headers
|
||||||
|
http_start_data.contains_body = C.bool(!endStream)
|
||||||
|
|
||||||
|
res := f.sendData(unsafe.Pointer(http_start_data), C.HTTP_REQUEST_FILTER)
|
||||||
|
if C.AttachmentVerdict(res.verdict) != C.ATTACHMENT_VERDICT_INSPECT {
|
||||||
|
api.LogInfof("got final verict: %v", res.verdict)
|
||||||
|
return f.finalizeRequest(&res)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeData might be called multiple times during handling the request body.
|
||||||
|
// The endStream is true when handling the last piece of the body.
|
||||||
|
func (f *filter) DecodeData(buffer api.BufferInstance, endStream bool) api.StatusType {
|
||||||
|
ret := api.Continue
|
||||||
|
|
||||||
|
defer RecoverPanic(&ret)
|
||||||
|
|
||||||
|
if f.isSessionFinalized() {
|
||||||
|
return api.Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if endStream && buffer.Len() == 0 {
|
||||||
|
return f.endInspectionPart(C.HttpChunkType(C.HTTP_REQUEST_END))
|
||||||
|
}
|
||||||
|
|
||||||
|
if buffer.Len() == 0 {
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
res := f.sendBody(buffer, true)
|
||||||
|
if C.AttachmentVerdict(res.verdict) != C.ATTACHMENT_VERDICT_INSPECT {
|
||||||
|
api.LogInfof("got final verict: %v", res.verdict)
|
||||||
|
return f.finalizeRequest(&res)
|
||||||
|
}
|
||||||
|
|
||||||
|
if endStream {
|
||||||
|
return f.endInspectionPart(C.HttpChunkType(C.HTTP_REQUEST_END))
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callbacks which are called in response path
|
||||||
|
// The endStream is true if the response doesn't have body
|
||||||
|
func (f *filter) EncodeHeaders(header api.ResponseHeaderMap, endStream bool) api.StatusType {
|
||||||
|
ret := api.Continue
|
||||||
|
|
||||||
|
defer RecoverPanic(&ret)
|
||||||
|
|
||||||
|
if f.isSessionFinalized() {
|
||||||
|
return api.Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const content_length_key = "content-length"
|
||||||
|
const status_code_key = ":status"
|
||||||
|
|
||||||
|
|
||||||
|
content_length_str, _ := header.Get(content_length_key)
|
||||||
|
status_code_str, _ := header.Get(status_code_key)
|
||||||
|
content_length, _ := strconv.Atoi(content_length_str)
|
||||||
|
status_code, _ := strconv.Atoi(status_code_str)
|
||||||
|
|
||||||
|
f.handleHeaders(header)
|
||||||
|
res_http_headers := f.request_structs.http_res_headers
|
||||||
|
res_http_headers.headers = f.request_structs.http_headers
|
||||||
|
res_http_headers.content_length = C.uint64_t(content_length)
|
||||||
|
res_http_headers.response_code = C.uint16_t(status_code)
|
||||||
|
|
||||||
|
res := f.sendData(unsafe.Pointer(res_http_headers), C.HTTP_RESPONSE_HEADER)
|
||||||
|
if C.AttachmentVerdict(res.verdict) != C.ATTACHMENT_VERDICT_INSPECT {
|
||||||
|
api.LogInfof("got final verict: %v", res.verdict)
|
||||||
|
return f.finalizeRequest(&res)
|
||||||
|
}
|
||||||
|
|
||||||
|
if endStream {
|
||||||
|
return f.endInspectionPart(C.HttpChunkType(C.HTTP_RESPONSE_END))
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeData might be called multiple times during handling the response body.
|
||||||
|
// The endStream is true when handling the last piece of the body.
|
||||||
|
func (f *filter) EncodeData(buffer api.BufferInstance, endStream bool) api.StatusType {
|
||||||
|
ret := api.Continue
|
||||||
|
|
||||||
|
defer RecoverPanic(&ret)
|
||||||
|
|
||||||
|
if f.isSessionFinalized() {
|
||||||
|
return api.Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if endStream && buffer.Len() == 0 {
|
||||||
|
return f.endInspectionPart(C.HttpChunkType(C.HTTP_RESPONSE_END))
|
||||||
|
}
|
||||||
|
|
||||||
|
if buffer.Len() == 0 {
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
res := f.sendBody(buffer, false)
|
||||||
|
if C.AttachmentVerdict(res.verdict) != C.ATTACHMENT_VERDICT_INSPECT {
|
||||||
|
api.LogInfof("got final verict: %v", res.verdict)
|
||||||
|
return f.finalizeRequest(&res)
|
||||||
|
}
|
||||||
|
|
||||||
|
if endStream {
|
||||||
|
return f.endInspectionPart(C.HttpChunkType(C.HTTP_RESPONSE_END))
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// ____________NOT IMPLEMENTED AT THE MOMENT____________
|
||||||
|
func (f *filter) DecodeTrailers(trailers api.RequestTrailerMap) api.StatusType {
|
||||||
|
// support suspending & resuming the filter in a background goroutine
|
||||||
|
return api.Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) EncodeTrailers(trailers api.ResponseTrailerMap) api.StatusType {
|
||||||
|
return api.Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnLog is called when the HTTP stream is ended on HTTP Connection Manager filter.
|
||||||
|
func (f *filter) OnLog(api.RequestHeaderMap, api.RequestTrailerMap, api.ResponseHeaderMap, api.ResponseTrailerMap) {}
|
||||||
|
|
||||||
|
// OnLogDownstreamStart is called when HTTP Connection Manager filter receives a new HTTP request
|
||||||
|
// (required the corresponding access log type is enabled)
|
||||||
|
func (f *filter) OnLogDownstreamStart(api.RequestHeaderMap) {}
|
||||||
|
|
||||||
|
// OnLogDownstreamPeriodic is called on any HTTP Connection Manager periodic log record
|
||||||
|
// (required the corresponding access log type is enabled)
|
||||||
|
func (f *filter) OnLogDownstreamPeriodic(api.RequestHeaderMap, api.RequestTrailerMap, api.ResponseHeaderMap, api.ResponseTrailerMap) {}
|
||||||
|
|
||||||
|
func (f *filter) OnDestroy(reason api.DestroyReason) {
|
||||||
|
freeHttpMetaDataFields(f.request_structs.http_meta_data)
|
||||||
|
f.request_structs.ZeroInitialize()
|
||||||
|
C.FiniSessionData((*C.NanoAttachment)(f.cp_attachment), f.session_data)
|
||||||
|
}
|
23
attachments/envoy/go.sum
Executable file
23
attachments/envoy/go.sum
Executable file
@ -0,0 +1,23 @@
|
|||||||
|
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM=
|
||||||
|
github.com/envoyproxy/envoy v1.32.1 h1:+HeajIC+S9PH3mjY/bVqJabjprqxA7h6pSQ+Ie1Ziww=
|
||||||
|
github.com/envoyproxy/envoy v1.32.1/go.mod h1:KGS+IUehDX1mSIdqodPTWskKOo7bZMLLy3GHxvOKcJk=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
|
||||||
|
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
|
||||||
|
github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||||
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
|
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||||
|
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 h1:rcS6EyEaoCO52hQDupoSfrxI3R6C2Tq741is7X8OvnM=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917/go.mod h1:CmlNWB9lSezaYELKS5Ym1r44VrrbPUa7JTvw+6MbpJ0=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 h1:6G8oQ016D88m1xAKljMlBOOGWDZkes4kMhgGFlf8WcQ=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917/go.mod h1:xtjpI3tXFPP051KaWnhvxkiubL/6dJ18vLVf7q2pTOU=
|
||||||
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
|
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||||
|
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
108
attachments/envoy/utils.go
Executable file
108
attachments/envoy/utils.go
Executable file
@ -0,0 +1,108 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <string.h>
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "nano_attachment.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"github.com/envoyproxy/envoy/contrib/golang/common/go/api"
|
||||||
|
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
func getEnv(key, defaultValue string) string {
|
||||||
|
value, exists := os.LookupEnv(key)
|
||||||
|
if !exists {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyToSlice(dest []byte, src unsafe.Pointer, size C.size_t, location int) int {
|
||||||
|
C.memcpy(unsafe.Pointer(&dest[location]), src, size)
|
||||||
|
return location + int(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newNanoStr(data []byte) *C.nano_str_t {
|
||||||
|
// Allocate memory for the nano_str_t struct
|
||||||
|
nanoStr := (*C.nano_str_t)(C.malloc(C.size_t(unsafe.Sizeof(C.nano_str_t{}))))
|
||||||
|
if nanoStr == nil {
|
||||||
|
panic("failed to allocate memory for nano_str_t struct")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the length of the data
|
||||||
|
nanoStr.len = C.size_t(len(data))
|
||||||
|
|
||||||
|
// Allocate memory for the data field and copy the Go byte slice into it
|
||||||
|
// nanoStr.data = (*C.uchar)(C.malloc(C.size_t(len(data))))
|
||||||
|
// if nanoStr.data == nil {
|
||||||
|
// C.free(unsafe.Pointer(nanoStr))
|
||||||
|
// panic("failed to allocate memory for data field")
|
||||||
|
// }
|
||||||
|
// copy((*[1 << 30]byte)(unsafe.Pointer(nanoStr.data))[:len(data):len(data)], data)
|
||||||
|
|
||||||
|
return nanoStr
|
||||||
|
}
|
||||||
|
|
||||||
|
func createNanoStr(str string) C.nano_str_t {
|
||||||
|
c_str := C.CString(str)
|
||||||
|
// nanoStr := (*C.nano_str_t)(C.malloc(C.size_t(unsafe.Sizeof(C.nano_str_t{}))))
|
||||||
|
nanoStr := C.nano_str_t{
|
||||||
|
len: C.size_t(len(str)),
|
||||||
|
data: (*C.uchar)(unsafe.Pointer(c_str)),
|
||||||
|
}
|
||||||
|
|
||||||
|
// nanoStr.len = C.size_t(len(str))
|
||||||
|
// nanoStr.data = (*C.uchar)(unsafe.Pointer(c_str))
|
||||||
|
|
||||||
|
return nanoStr
|
||||||
|
}
|
||||||
|
|
||||||
|
func createNanoStrWithoutCopy(str string) C.nano_str_t {
|
||||||
|
//c_str := C.CString(str)
|
||||||
|
|
||||||
|
nanoStr := C.nano_str_t{
|
||||||
|
len: C.size_t(len(str)),
|
||||||
|
data: (*C.uchar)(unsafe.Pointer((*(*reflect.StringHeader)(unsafe.Pointer(&str))).Data)),
|
||||||
|
}
|
||||||
|
|
||||||
|
return nanoStr
|
||||||
|
}
|
||||||
|
|
||||||
|
func freeNanoStr(str *C.nano_str_t) {
|
||||||
|
C.free(unsafe.Pointer(str.data))
|
||||||
|
}
|
||||||
|
|
||||||
|
func freeHttpMetaDataFields(meta_data *C.HttpMetaData) {
|
||||||
|
freeNanoStr(&(*meta_data).http_protocol)
|
||||||
|
freeNanoStr(&(*meta_data).method_name)
|
||||||
|
freeNanoStr(&(*meta_data).host)
|
||||||
|
freeNanoStr(&(*meta_data).listening_ip)
|
||||||
|
freeNanoStr(&(*meta_data).uri)
|
||||||
|
freeNanoStr(&(*meta_data).client_ip)
|
||||||
|
}
|
||||||
|
|
||||||
|
func freeHeaders(header_arr *C.HttpHeaderData, header_slice []C.HttpHeaderData) {
|
||||||
|
C.free(unsafe.Pointer(header_arr))
|
||||||
|
|
||||||
|
for _, header := range header_slice {
|
||||||
|
freeNanoStr(&(header.key))
|
||||||
|
freeNanoStr(&(header.value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func RecoverPanic(ret *api.StatusType) {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
const size = 64 << 10
|
||||||
|
buf := make([]byte, size)
|
||||||
|
buf = buf[:runtime.Stack(buf, false)]
|
||||||
|
api.LogErrorf("http: panic serving: %v\n%s", e, buf)
|
||||||
|
|
||||||
|
*ret = api.Continue
|
||||||
|
}
|
||||||
|
}
|
32
attachments/nano_attachment/CMakeLists.txt
Normal file
32
attachments/nano_attachment/CMakeLists.txt
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
add_subdirectory(nano_attachment_util)
|
||||||
|
|
||||||
|
include_directories(include)
|
||||||
|
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_GNU_SOURCE -lpthread -Wall")
|
||||||
|
|
||||||
|
link_directories(../../core)
|
||||||
|
link_directories(../../core/shmem_ipc)
|
||||||
|
include_directories(../../core/include/attachments)
|
||||||
|
|
||||||
|
|
||||||
|
add_library(
|
||||||
|
nano_attachment
|
||||||
|
SHARED
|
||||||
|
nano_attachment.c
|
||||||
|
nano_configuration.c
|
||||||
|
nano_initializer.c
|
||||||
|
nano_utils.c
|
||||||
|
nano_attachment_io.c
|
||||||
|
nano_attachment_thread.c
|
||||||
|
nano_attachment_sender.c
|
||||||
|
nano_attachment_sender_thread.c
|
||||||
|
nano_attachment_metric.c
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(nano_attachment shmem_ipc_2 nano_attachment_util)
|
||||||
|
|
||||||
|
# add_subdirectory(nano_attachment_ut)
|
||||||
|
# add_subdirectory(manual_testing)
|
||||||
|
|
||||||
|
install(TARGETS nano_attachment DESTINATION lib)
|
||||||
|
install(TARGETS nano_attachment DESTINATION http_transaction_handler_service/lib/ PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ)
|
22
attachments/nano_attachment/include/mock_nano_access.h
Normal file
22
attachments/nano_attachment/include/mock_nano_access.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#ifndef __MOCK_ACCESS_H__
|
||||||
|
#define __MOCK_ACCESS_H__
|
||||||
|
|
||||||
|
#include "cmock.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <unistd.h> // For the access function
|
||||||
|
}
|
||||||
|
|
||||||
|
class NanoAccessMocker : public CMockMocker<NanoAccessMocker>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MOCK_METHOD2(access, int(const char *path, int mode));
|
||||||
|
};
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION2(
|
||||||
|
NanoAccessMocker,
|
||||||
|
access,
|
||||||
|
int(const char *path, int mode)
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif // __MOCK_ACCESS_H__
|
213
attachments/nano_attachment/include/mock_nano_attachment_io.h
Normal file
213
attachments/nano_attachment/include/mock_nano_attachment_io.h
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
#ifndef __MOCK_NANO_INITIALIZER_IO_H__
|
||||||
|
#define __MOCK_NANO_INITIALIZER_IO_H__
|
||||||
|
|
||||||
|
#include "cmock.h"
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "nano_attachment_io.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
class NanoAttachmentIoMocker : public CMockMocker<NanoAttachmentIoMocker>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MOCK_METHOD1(
|
||||||
|
connect_to_comm_socket,
|
||||||
|
NanoCommunicationResult(NanoAttachment *attachment)
|
||||||
|
);
|
||||||
|
|
||||||
|
MOCK_METHOD1(
|
||||||
|
connect_to_registration_socket,
|
||||||
|
NanoCommunicationResult(NanoAttachment *attachment)
|
||||||
|
);
|
||||||
|
|
||||||
|
MOCK_METHOD6(
|
||||||
|
nano_metadata_sender,
|
||||||
|
void(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
HttpMetaData *metadata,
|
||||||
|
HttpEventThreadCtx *ctx,
|
||||||
|
uint32_t cur_request_id,
|
||||||
|
unsigned int *num_of_messages_sent,
|
||||||
|
bool is_verdict_requested
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
MOCK_METHOD7(
|
||||||
|
nano_header_sender,
|
||||||
|
void(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
HttpHeaders *headers,
|
||||||
|
HttpEventThreadCtx *ctx,
|
||||||
|
AttachmentDataType header_type,
|
||||||
|
uint32_t cur_request_id,
|
||||||
|
unsigned int *num_messages_sent,
|
||||||
|
bool is_verdict_requested
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
MOCK_METHOD5(
|
||||||
|
nano_send_response_code,
|
||||||
|
void(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
uint16_t response_code,
|
||||||
|
HttpEventThreadCtx *ctx,
|
||||||
|
uint32_t cur_request_id,
|
||||||
|
unsigned int *num_messages_sent
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
MOCK_METHOD5(
|
||||||
|
nano_send_response_content_length,
|
||||||
|
void(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
uint64_t content_length,
|
||||||
|
HttpEventThreadCtx *ctx,
|
||||||
|
uint32_t cur_request_id,
|
||||||
|
unsigned int *num_messages_sent
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
MOCK_METHOD6(
|
||||||
|
nano_body_sender,
|
||||||
|
void(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
HttpBody *bodies,
|
||||||
|
HttpEventThreadCtx *ctx,
|
||||||
|
AttachmentDataType body_type,
|
||||||
|
uint32_t cur_request_id,
|
||||||
|
unsigned int *num_messages_sent
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
MOCK_METHOD5(
|
||||||
|
nano_end_transaction_sender,
|
||||||
|
void(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
AttachmentDataType end_transaction_type,
|
||||||
|
HttpEventThreadCtx *ctx,
|
||||||
|
SessionID cur_request_id,
|
||||||
|
unsigned int *num_messages_sent
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
MOCK_METHOD4(
|
||||||
|
nano_request_delayed_verdict,
|
||||||
|
void(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
HttpEventThreadCtx *ctx,
|
||||||
|
SessionID cur_request_id,
|
||||||
|
unsigned int *num_messages_sent
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
MOCK_METHOD1(nano_send_metric_data_sender, void(NanoAttachment *Attachment));
|
||||||
|
};
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION1(
|
||||||
|
NanoAttachmentIoMocker,
|
||||||
|
connect_to_comm_socket,
|
||||||
|
NanoCommunicationResult(NanoAttachment *attachment)
|
||||||
|
);
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION1(
|
||||||
|
NanoAttachmentIoMocker,
|
||||||
|
connect_to_registration_socket,
|
||||||
|
NanoCommunicationResult(NanoAttachment *attachment)
|
||||||
|
);
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION6(
|
||||||
|
NanoAttachmentIoMocker,
|
||||||
|
nano_metadata_sender,
|
||||||
|
void(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
HttpMetaData *metadata,
|
||||||
|
HttpEventThreadCtx *ctx,
|
||||||
|
uint32_t cur_request_id,
|
||||||
|
unsigned int *num_of_messages_sent,
|
||||||
|
bool is_verdict_requested
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION7(
|
||||||
|
NanoAttachmentIoMocker,
|
||||||
|
nano_header_sender,
|
||||||
|
void(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
HttpHeaders *headers,
|
||||||
|
HttpEventThreadCtx *ctx,
|
||||||
|
AttachmentDataType header_type,
|
||||||
|
uint32_t cur_request_id,
|
||||||
|
unsigned int *num_messages_sent,
|
||||||
|
bool is_verdict_requested
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION5(
|
||||||
|
NanoAttachmentIoMocker,
|
||||||
|
nano_send_response_code,
|
||||||
|
void(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
uint16_t response_code,
|
||||||
|
HttpEventThreadCtx *ctx,
|
||||||
|
uint32_t cur_request_id,
|
||||||
|
unsigned int *num_messages_sent
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION5(
|
||||||
|
NanoAttachmentIoMocker,
|
||||||
|
nano_send_response_content_length,
|
||||||
|
void(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
uint64_t content_length,
|
||||||
|
HttpEventThreadCtx *ctx,
|
||||||
|
uint32_t cur_request_id,
|
||||||
|
unsigned int *num_messages_sent
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION6(
|
||||||
|
NanoAttachmentIoMocker,
|
||||||
|
nano_body_sender,
|
||||||
|
void(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
HttpBody *bodies,
|
||||||
|
HttpEventThreadCtx *ctx,
|
||||||
|
AttachmentDataType body_type,
|
||||||
|
uint32_t cur_request_id,
|
||||||
|
unsigned int *num_messages_sent
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION5(
|
||||||
|
NanoAttachmentIoMocker,
|
||||||
|
nano_end_transaction_sender,
|
||||||
|
void(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
AttachmentDataType end_transaction_type,
|
||||||
|
HttpEventThreadCtx *ctx,
|
||||||
|
SessionID cur_request_id,
|
||||||
|
unsigned int *num_messages_sent
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION4(
|
||||||
|
NanoAttachmentIoMocker,
|
||||||
|
nano_request_delayed_verdict,
|
||||||
|
void(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
HttpEventThreadCtx *ctx,
|
||||||
|
SessionID cur_request_id,
|
||||||
|
unsigned int *num_messages_sent
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION1(
|
||||||
|
NanoAttachmentIoMocker,
|
||||||
|
nano_send_metric_data_sender,
|
||||||
|
void(NanoAttachment *Attachment)
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif // __MOCK_NANO_INITIALIZER_IO_H__
|
@ -0,0 +1,72 @@
|
|||||||
|
#ifndef __MOCK_NANO_ATTACHMENT_SENDER_H__
|
||||||
|
#define __MOCK_NANO_ATTACHMENT_SENDER_H__
|
||||||
|
|
||||||
|
#include "cmock.h"
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "nano_attachment_sender.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
class NanoAttachmentSenderMocker : public CMockMocker<NanoAttachmentSenderMocker>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MOCK_METHOD2(SendMetadata, AttachmentVerdictResponse(NanoAttachment *attachment, AttachmentData *data));
|
||||||
|
MOCK_METHOD2(SendRequestHeaders, AttachmentVerdictResponse(NanoAttachment *attachment, AttachmentData *data));
|
||||||
|
MOCK_METHOD2(SendResponseHeaders, AttachmentVerdictResponse(NanoAttachment *attachment, AttachmentData *data));
|
||||||
|
MOCK_METHOD2(SendRequestBody, AttachmentVerdictResponse(NanoAttachment *attachment, AttachmentData *data));
|
||||||
|
MOCK_METHOD2(SendResponseBody, AttachmentVerdictResponse(NanoAttachment *attachment, AttachmentData *data));
|
||||||
|
MOCK_METHOD2(SendRequestEnd, AttachmentVerdictResponse(NanoAttachment *attachment, AttachmentData *data));
|
||||||
|
MOCK_METHOD2(SendResponseEnd, AttachmentVerdictResponse(NanoAttachment *attachment, AttachmentData *data));
|
||||||
|
MOCK_METHOD1(SendMetricData, NanoCommunicationResult(NanoAttachment *attachment));
|
||||||
|
};
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION2(
|
||||||
|
NanoAttachmentSenderMocker,
|
||||||
|
SendMetadata,
|
||||||
|
AttachmentVerdictResponse(NanoAttachment *attachment, AttachmentData *data)
|
||||||
|
);
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION2(
|
||||||
|
NanoAttachmentSenderMocker,
|
||||||
|
SendRequestHeaders,
|
||||||
|
AttachmentVerdictResponse(NanoAttachment *attachment, AttachmentData *data)
|
||||||
|
);
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION2(
|
||||||
|
NanoAttachmentSenderMocker,
|
||||||
|
SendResponseHeaders,
|
||||||
|
AttachmentVerdictResponse(NanoAttachment *attachment, AttachmentData *data)
|
||||||
|
);
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION2(
|
||||||
|
NanoAttachmentSenderMocker,
|
||||||
|
SendRequestBody,
|
||||||
|
AttachmentVerdictResponse(NanoAttachment *attachment, AttachmentData *data)
|
||||||
|
);
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION2(
|
||||||
|
NanoAttachmentSenderMocker,
|
||||||
|
SendResponseBody,
|
||||||
|
AttachmentVerdictResponse(NanoAttachment *attachment, AttachmentData *data)
|
||||||
|
);
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION2(
|
||||||
|
NanoAttachmentSenderMocker,
|
||||||
|
SendRequestEnd,
|
||||||
|
AttachmentVerdictResponse(NanoAttachment *attachment, AttachmentData *data)
|
||||||
|
);
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION2(
|
||||||
|
NanoAttachmentSenderMocker,
|
||||||
|
SendResponseEnd,
|
||||||
|
AttachmentVerdictResponse(NanoAttachment *attachment, AttachmentData *data)
|
||||||
|
);
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION1(
|
||||||
|
NanoAttachmentSenderMocker,
|
||||||
|
SendMetricData,
|
||||||
|
NanoCommunicationResult(NanoAttachment *attachment)
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif // __MOCK_NANO_ATTACHMENT_SENDER_H__
|
@ -0,0 +1,42 @@
|
|||||||
|
#ifndef __MOCK_NANO_ATTACHMENT_THREAD_H__
|
||||||
|
#define __MOCK_NANO_ATTACHMENT_THREAD_H__
|
||||||
|
|
||||||
|
#include "cmock.h"
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "nano_attachment_thread.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
class NanoAttachmentThreadMocker : public CMockMocker<NanoAttachmentThreadMocker>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MOCK_METHOD7(
|
||||||
|
NanoRunInThreadTimeout,
|
||||||
|
int(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
AttachmentData *data,
|
||||||
|
CpThreadRoutine thread_func,
|
||||||
|
void *arg,
|
||||||
|
int timeout_msecs,
|
||||||
|
char *func_name,
|
||||||
|
TransactionType transaction_type
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION7(
|
||||||
|
NanoAttachmentThreadMocker,
|
||||||
|
NanoRunInThreadTimeout,
|
||||||
|
int(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
AttachmentData *data,
|
||||||
|
CpThreadRoutine thread_func,
|
||||||
|
void *arg,
|
||||||
|
int timeout_msecs,
|
||||||
|
char *func_name,
|
||||||
|
TransactionType transaction_type
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif // __MOCK_NANO_ATTACHMENT_THREAD_H__
|
@ -0,0 +1,39 @@
|
|||||||
|
#ifndef __MOCK_NANO_CONFIGURATION_H__
|
||||||
|
#define __MOCK_NANO_CONFIGURATION_H__
|
||||||
|
|
||||||
|
#include "cmock.h"
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "nano_configuration.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
class NanoConfigurationMocker : public CMockMocker<NanoConfigurationMocker>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MOCK_METHOD2(
|
||||||
|
init_attachment_config,
|
||||||
|
NanoCommunicationResult(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
const char *conf_path
|
||||||
|
)
|
||||||
|
);
|
||||||
|
MOCK_METHOD1(reset_attachment_config, NanoCommunicationResult(NanoAttachment *attachment));
|
||||||
|
};
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION2(
|
||||||
|
NanoConfigurationMocker,
|
||||||
|
init_attachment_config,
|
||||||
|
NanoCommunicationResult(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
const char *conf_path
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION1(
|
||||||
|
NanoConfigurationMocker,
|
||||||
|
reset_attachment_config,
|
||||||
|
NanoCommunicationResult(NanoAttachment *attachment)
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif // __MOCK_NANO_CONFIGURATION_H__
|
52
attachments/nano_attachment/include/mock_nano_initializer.h
Normal file
52
attachments/nano_attachment/include/mock_nano_initializer.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#ifndef __MOCK_NANO_INITIALIZER_H__
|
||||||
|
#define __MOCK_NANO_INITIALIZER_H__
|
||||||
|
|
||||||
|
#include "cmock.h"
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "nano_initializer.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
class NanoInitializerMocker : public CMockMocker<NanoInitializerMocker>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MOCK_METHOD1(nano_attachment_init_process, NanoCommunicationResult(NanoAttachment *attachment));
|
||||||
|
MOCK_METHOD5(
|
||||||
|
write_to_service,
|
||||||
|
NanoCommunicationResult(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
int *socket,
|
||||||
|
void *data,
|
||||||
|
uint32_t size,
|
||||||
|
struct timeval *absolute_end_time
|
||||||
|
)
|
||||||
|
);
|
||||||
|
MOCK_METHOD1(handle_shmem_corruption, NanoCommunicationResult(NanoAttachment *attachment));
|
||||||
|
};
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION1(
|
||||||
|
NanoInitializerMocker,
|
||||||
|
nano_attachment_init_process,
|
||||||
|
NanoCommunicationResult(NanoAttachment *attachment)
|
||||||
|
);
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION5(
|
||||||
|
NanoInitializerMocker,
|
||||||
|
write_to_service,
|
||||||
|
NanoCommunicationResult(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
int *socket,
|
||||||
|
void *data,
|
||||||
|
uint32_t size,
|
||||||
|
struct timeval *absolute_end_time
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION1(
|
||||||
|
NanoInitializerMocker,
|
||||||
|
handle_shmem_corruption,
|
||||||
|
NanoCommunicationResult(NanoAttachment *attachment)
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif // __MOCK_NANO_INITIALIZER_H__
|
22
attachments/nano_attachment/include/mock_nano_poll.h
Normal file
22
attachments/nano_attachment/include/mock_nano_poll.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#ifndef __MOCK_NANO_POLL_H__
|
||||||
|
#define __MOCK_NANO_POLL_H__
|
||||||
|
|
||||||
|
#include "cmock.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <poll.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
class NanoPollMocker : public CMockMocker<NanoPollMocker>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MOCK_METHOD3(poll, int(pollfd *fds, nfds_t nfds, int timeout));
|
||||||
|
};
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION3(
|
||||||
|
NanoPollMocker,
|
||||||
|
poll,
|
||||||
|
int(pollfd *fds, nfds_t nfds, int timeout)
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif // __MOCK_NANO_POLL_H__
|
@ -0,0 +1,23 @@
|
|||||||
|
#ifndef __MOCK_NANO_ATTACHMENT_SENDER_THREAD_H__
|
||||||
|
#define __MOCK_NANO_ATTACHMENT_SENDER_THREAD_H__
|
||||||
|
|
||||||
|
#include "cmock.h"
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "nano_attachment_sender_thread.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
class NanoSenderThreadMocker : public CMockMocker<NanoSenderThreadMocker>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MOCK_METHOD1(SendRequestEndThread, void *(void *_ctx));
|
||||||
|
};
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION1(
|
||||||
|
NanoSenderThreadMocker,
|
||||||
|
SendRequestEndThread,
|
||||||
|
void *(void *_ctx)
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif // __MOCK_NANO_ATTACHMENT_SENDER_THREAD_H__
|
50
attachments/nano_attachment/include/mock_nano_socket.h
Normal file
50
attachments/nano_attachment/include/mock_nano_socket.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#ifndef __MOCK_NANO_SOCKET_H__
|
||||||
|
#define __MOCK_NANO_SOCKET_H__
|
||||||
|
|
||||||
|
#include "cmock.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <sys/socket.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
class NanoSocketMocker : public CMockMocker<NanoSocketMocker>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MOCK_METHOD3(socket, int(int domain, int type, int protocol));
|
||||||
|
MOCK_METHOD3(connect, int(int sockfd, const struct sockaddr *addr, socklen_t addrlen));
|
||||||
|
MOCK_METHOD1(close, int(int sockfd));
|
||||||
|
MOCK_METHOD3(write, ssize_t(int fd, const void *buf, size_t count));
|
||||||
|
MOCK_METHOD3(read, ssize_t(int fd, void *buf, size_t count));
|
||||||
|
};
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION3(
|
||||||
|
NanoSocketMocker,
|
||||||
|
socket,
|
||||||
|
int(int domain, int type, int protocol)
|
||||||
|
);
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION3(
|
||||||
|
NanoSocketMocker,
|
||||||
|
connect,
|
||||||
|
int(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
|
||||||
|
);
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION1(
|
||||||
|
NanoSocketMocker,
|
||||||
|
close,
|
||||||
|
int(int sockfd)
|
||||||
|
);
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION3(
|
||||||
|
NanoSocketMocker,
|
||||||
|
write,
|
||||||
|
ssize_t(int fd, const void *buf, size_t count)
|
||||||
|
);
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION3(
|
||||||
|
NanoSocketMocker,
|
||||||
|
read,
|
||||||
|
ssize_t(int fd, void *buf, size_t count)
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif // __MOCK_NANO_SOCKET_H__
|
22
attachments/nano_attachment/include/mock_nano_stat.h
Normal file
22
attachments/nano_attachment/include/mock_nano_stat.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#ifndef __MOCK_NANO_STAT_H__
|
||||||
|
#define __MOCK_NANO_STAT_H__
|
||||||
|
|
||||||
|
#include "cmock.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <sys/stat.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
class NanoStatMocker : public CMockMocker<NanoStatMocker>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MOCK_METHOD2(mkdir, int(const char *pathname, mode_t mode));
|
||||||
|
};
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION2(
|
||||||
|
NanoStatMocker,
|
||||||
|
mkdir,
|
||||||
|
int(const char *pathname, mode_t mode)
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif // __MOCK_NANO_STAT_H__
|
107
attachments/nano_attachment/include/mock_shmem_ipc.h
Normal file
107
attachments/nano_attachment/include/mock_shmem_ipc.h
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
#ifndef __MOCK_SHMEM_IPC__
|
||||||
|
#define __MOCK_SHMEM_IPC__
|
||||||
|
|
||||||
|
#include "cmock.h"
|
||||||
|
#include "cptest.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "shmem_ipc_2.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
class NanoShmemIPCMocker : public CMockMocker<NanoShmemIPCMocker>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MOCK_METHOD7(
|
||||||
|
initIpc,
|
||||||
|
SharedMemoryIPC *(
|
||||||
|
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,
|
||||||
|
...
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
MOCK_METHOD2(destroyIpc, void(SharedMemoryIPC *ipc, int is_owner));
|
||||||
|
MOCK_METHOD2(resetIpc, void(SharedMemoryIPC *ipc, uint16_t num_of_data_segments));
|
||||||
|
MOCK_METHOD3(
|
||||||
|
sendData,
|
||||||
|
int(SharedMemoryIPC *ipc, const uint16_t data_to_send_size, const char *data_to_send)
|
||||||
|
);
|
||||||
|
MOCK_METHOD4(
|
||||||
|
sendChunkedData,
|
||||||
|
int(
|
||||||
|
SharedMemoryIPC *ipc,
|
||||||
|
const uint16_t *data_to_send_sizes,
|
||||||
|
const char **data_elem_to_send,
|
||||||
|
const uint8_t num_of_data_elem
|
||||||
|
)
|
||||||
|
);
|
||||||
|
MOCK_METHOD3(
|
||||||
|
receiveData,
|
||||||
|
int(SharedMemoryIPC *ipc, uint16_t *received_data_size, const char **received_data)
|
||||||
|
);
|
||||||
|
MOCK_METHOD1(popData, int(SharedMemoryIPC *ipc));
|
||||||
|
MOCK_METHOD1(isDataAvailable, int(SharedMemoryIPC *ipc));
|
||||||
|
MOCK_METHOD2(isCorruptedShmem, int(SharedMemoryIPC *ipc, int));
|
||||||
|
};
|
||||||
|
|
||||||
|
CMOCK_MOCK_FUNCTION7(
|
||||||
|
NanoShmemIPCMocker,
|
||||||
|
initIpc,
|
||||||
|
SharedMemoryIPC *(
|
||||||
|
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,
|
||||||
|
...
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
CMOCK_MOCK_FUNCTION2(NanoShmemIPCMocker, destroyIpc, void(SharedMemoryIPC *ipc, int is_owner));
|
||||||
|
CMOCK_MOCK_FUNCTION3(
|
||||||
|
NanoShmemIPCMocker,
|
||||||
|
sendData,
|
||||||
|
int(SharedMemoryIPC *ipc, const uint16_t data_to_send_size, const char *data_to_send)
|
||||||
|
)
|
||||||
|
CMOCK_MOCK_FUNCTION4(
|
||||||
|
NanoShmemIPCMocker,
|
||||||
|
sendChunkedData,
|
||||||
|
int(
|
||||||
|
SharedMemoryIPC *ipc,
|
||||||
|
const uint16_t *data_to_send_sizes,
|
||||||
|
const char **data_elem_to_send,
|
||||||
|
const uint8_t num_of_data_elem
|
||||||
|
)
|
||||||
|
);
|
||||||
|
CMOCK_MOCK_FUNCTION3(
|
||||||
|
NanoShmemIPCMocker,
|
||||||
|
receiveData,
|
||||||
|
int(SharedMemoryIPC *ipc, uint16_t *received_data_size, const char **received_data)
|
||||||
|
);
|
||||||
|
CMOCK_MOCK_FUNCTION1(NanoShmemIPCMocker, popData, int(SharedMemoryIPC *ipc));
|
||||||
|
CMOCK_MOCK_FUNCTION1(NanoShmemIPCMocker, isDataAvailable, int(SharedMemoryIPC *ipc));
|
||||||
|
CMOCK_MOCK_FUNCTION2(NanoShmemIPCMocker, resetIpc, void(SharedMemoryIPC *ipc, uint16_t num_of_data_segments));
|
||||||
|
CMOCK_MOCK_FUNCTION2(NanoShmemIPCMocker, isCorruptedShmem, int(SharedMemoryIPC *ipc, int));
|
||||||
|
|
||||||
|
#endif // __MOCK_SHMEM_IPC__
|
589
attachments/nano_attachment/nano_attachment.c
Normal file
589
attachments/nano_attachment/nano_attachment.c
Normal file
@ -0,0 +1,589 @@
|
|||||||
|
#include "nano_attachment.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#include "nano_attachment_sender.h"
|
||||||
|
#include "nano_attachment_metric.h"
|
||||||
|
#include "nano_initializer.h"
|
||||||
|
#include "nano_configuration.h"
|
||||||
|
#include "nano_utils.h"
|
||||||
|
#include "attachment_types.h"
|
||||||
|
#include "nano_blockpage.h"
|
||||||
|
|
||||||
|
NanoAttachment *
|
||||||
|
InitNanoAttachment(uint8_t attachment_type, int worker_id, int num_of_workers, int logging_fd)
|
||||||
|
{
|
||||||
|
// NanoAttachment *attachment = malloc(sizeof(NanoAttachment));
|
||||||
|
NanoAttachment *attachment = calloc(1, sizeof(NanoAttachment));
|
||||||
|
if (attachment == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// memset(attachment, 0, sizeof(NanoAttachment));
|
||||||
|
|
||||||
|
attachment->shared_verdict_signal_path[0] = '\0';
|
||||||
|
attachment->worker_id = worker_id;
|
||||||
|
attachment->num_of_workers = num_of_workers;
|
||||||
|
attachment->nano_user_id = getuid();
|
||||||
|
attachment->nano_group_id = getgid();
|
||||||
|
attachment->registration_socket = -1;
|
||||||
|
attachment->registration_state = NOT_REGISTERED;
|
||||||
|
attachment->attachment_type = attachment_type;
|
||||||
|
attachment->nano_service_ipc = NULL;
|
||||||
|
attachment->comm_socket = -1;
|
||||||
|
attachment->logging_data = NULL;
|
||||||
|
|
||||||
|
if (set_docker_id(attachment) == NANO_ERROR) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Could not evaluate container id");
|
||||||
|
close_logging_fd(attachment);
|
||||||
|
free(attachment);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set_logging_fd(attachment, logging_fd) == NANO_ERROR) {
|
||||||
|
free(attachment);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
attachment->logging_data = initLoggingData(
|
||||||
|
attachment->logging_fd,
|
||||||
|
DBG_LEVEL_INFO,
|
||||||
|
attachment->worker_id
|
||||||
|
);
|
||||||
|
if (attachment->logging_data == NULL) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Failed to initialize logging data");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set_unique_id(attachment) == NANO_ERROR) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Could not evaluate unique name");
|
||||||
|
close_logging_fd(attachment);
|
||||||
|
free(attachment);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
attachment->is_configuration_updated = NANO_ERROR;
|
||||||
|
attachment->current_config_version = 0;
|
||||||
|
|
||||||
|
attachment->fail_mode_verdict = NANO_OK;
|
||||||
|
attachment->fail_mode_delayed_verdict = NANO_OK;
|
||||||
|
attachment->dbg_level = DBG_LEVEL_INFO;
|
||||||
|
attachment->num_of_connection_attempts = 0;
|
||||||
|
attachment->fail_open_timeout = 50;
|
||||||
|
attachment->fail_open_delayed_timeout = 150;
|
||||||
|
attachment->sessions_per_minute_limit_verdict = ATTACHMENT_VERDICT_ACCEPT;
|
||||||
|
attachment->max_sessions_per_minute = 0;
|
||||||
|
attachment->req_max_proccessing_ms_time = 3000;
|
||||||
|
attachment->res_max_proccessing_ms_time = 3000;
|
||||||
|
attachment->registration_thread_timeout_msec = 100;
|
||||||
|
attachment->req_start_thread_timeout_msec = 100;
|
||||||
|
attachment->req_header_thread_timeout_msec = 100;
|
||||||
|
attachment->req_body_thread_timeout_msec = 150;
|
||||||
|
attachment->res_header_thread_timeout_msec = 100;
|
||||||
|
attachment->res_body_thread_timeout_msec = 150;
|
||||||
|
attachment->waiting_for_verdict_thread_timeout_msec = 150;
|
||||||
|
attachment->metric_timeout_timeout = 100;
|
||||||
|
attachment->inspection_mode = NON_BLOCKING_THREAD;
|
||||||
|
attachment->num_of_nano_ipc_elements = 200;
|
||||||
|
attachment->keep_alive_interval_msec = DEFAULT_KEEP_ALIVE_INTERVAL_MSEC;
|
||||||
|
|
||||||
|
if (nano_attachment_init_process(attachment) != NANO_OK) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Could not initialize nano attachment");
|
||||||
|
close_logging_fd(attachment);
|
||||||
|
free(attachment);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_metric_data(attachment);
|
||||||
|
return attachment;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
FiniNanoAttachment(NanoAttachment *attachment)
|
||||||
|
{
|
||||||
|
close_logging_fd(attachment);
|
||||||
|
free(attachment);
|
||||||
|
};
|
||||||
|
|
||||||
|
NanoCommunicationResult
|
||||||
|
RestartAttachmentConfiguration(NanoAttachment *attachment)
|
||||||
|
{
|
||||||
|
return reset_attachment_config(attachment);
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpSessionData *
|
||||||
|
InitSessionData(NanoAttachment *attachment, SessionID session_id)
|
||||||
|
{
|
||||||
|
HttpSessionData *session_data = malloc(sizeof(HttpSessionData));
|
||||||
|
if (session_data == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_TRACE,
|
||||||
|
"Initiating session data"
|
||||||
|
);
|
||||||
|
|
||||||
|
session_data->was_request_fully_inspected = 0;
|
||||||
|
session_data->verdict = TRAFFIC_VERDICT_INSPECT;
|
||||||
|
session_data->session_id = session_id;
|
||||||
|
session_data->remaining_messages_to_reply = 0;
|
||||||
|
session_data->req_proccesing_time = 0;
|
||||||
|
session_data->res_proccesing_time = 0;
|
||||||
|
session_data->processed_req_body_size = 0;
|
||||||
|
session_data->processed_res_body_size = 0;
|
||||||
|
|
||||||
|
return session_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
FiniSessionData(NanoAttachment *attachment, HttpSessionData *session_data)
|
||||||
|
{
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_data->session_id,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"Freeing session data for session_id"
|
||||||
|
);
|
||||||
|
free(session_data);
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
UpdateMetric(NanoAttachment *attachment, AttachmentMetricType metric_type, uint64_t value)
|
||||||
|
{
|
||||||
|
updateMetricField(attachment, metric_type, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SendAccumulatedMetricData(NanoAttachment *attachment)
|
||||||
|
{
|
||||||
|
SendMetricData(attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
AttachmentVerdictResponse
|
||||||
|
SendDataNanoAttachment(NanoAttachment *attachment, AttachmentData *data)
|
||||||
|
{
|
||||||
|
switch (data->chunk_type) {
|
||||||
|
case HTTP_REQUEST_FILTER: {
|
||||||
|
return SendRequestFilter(attachment, data);
|
||||||
|
}
|
||||||
|
case HTTP_REQUEST_METADATA: {
|
||||||
|
return SendMetadata(attachment, data);
|
||||||
|
}
|
||||||
|
case HTTP_REQUEST_HEADER: {
|
||||||
|
return SendRequestHeaders(attachment, data);
|
||||||
|
}
|
||||||
|
case HTTP_REQUEST_BODY: {
|
||||||
|
return SendRequestBody(attachment, data);
|
||||||
|
}
|
||||||
|
case HTTP_REQUEST_END: {
|
||||||
|
return SendRequestEnd(attachment, data);
|
||||||
|
}
|
||||||
|
case HTTP_RESPONSE_HEADER: {
|
||||||
|
return SendResponseHeaders(attachment, data);
|
||||||
|
}
|
||||||
|
case HTTP_RESPONSE_BODY: {
|
||||||
|
return SendResponseBody(attachment, data);
|
||||||
|
}
|
||||||
|
case HTTP_RESPONSE_END: {
|
||||||
|
return SendResponseEnd(attachment, data);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
AttachmentVerdictResponse response = {
|
||||||
|
.verdict = ATTACHMENT_VERDICT_INSPECT,
|
||||||
|
.session_id = data->session_id,
|
||||||
|
.modifications = NULL
|
||||||
|
};
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LCOV_EXCL_START Reason: Simple wrapper.
|
||||||
|
AttachmentVerdictResponse SendDataNanoAttachmentWrapper(NanoAttachment *attachment, AttachmentData data)
|
||||||
|
{
|
||||||
|
return SendDataNanoAttachment(attachment, &data);
|
||||||
|
}
|
||||||
|
// LCOV_EXCL_STOP
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Connects to the keep-alive socket.
|
||||||
|
///
|
||||||
|
/// @param attachment A pointer to a NanoAttachment struct containing attachment information.
|
||||||
|
///
|
||||||
|
/// @return An int representing an opened socket, if failed returns -1.
|
||||||
|
///
|
||||||
|
static int
|
||||||
|
connect_to_keep_alive_socket(NanoAttachment *attachment)
|
||||||
|
{
|
||||||
|
struct sockaddr_un server;
|
||||||
|
int keep_alive_socket;
|
||||||
|
|
||||||
|
// Connect a new socket.
|
||||||
|
keep_alive_socket = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (keep_alive_socket < 0) {
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
attachment->worker_id,
|
||||||
|
DBG_LEVEL_WARNING,
|
||||||
|
"Could not create socket, Error: %s",
|
||||||
|
strerror(errno)
|
||||||
|
);
|
||||||
|
return keep_alive_socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
server.sun_family = AF_UNIX;
|
||||||
|
strncpy(server.sun_path, SHARED_KEEP_ALIVE_PATH, sizeof(server.sun_path) - 1);
|
||||||
|
|
||||||
|
if (connect(keep_alive_socket, (struct sockaddr *)&server, sizeof(struct sockaddr_un)) != -1 ) {
|
||||||
|
return keep_alive_socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
attachment->worker_id,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"Could not connect to nano service. Path: %s, Error: %s, Errno: %d",
|
||||||
|
server.sun_path,
|
||||||
|
strerror(errno),
|
||||||
|
errno
|
||||||
|
);
|
||||||
|
close(keep_alive_socket);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends the keep-alive signal to the alive socket.
|
||||||
|
///
|
||||||
|
/// @param attachment A pointer to a NanoAttachment struct containing attachment information.
|
||||||
|
/// @param keep_alive_socket Socket descriptor for the keep-alive socket.
|
||||||
|
///
|
||||||
|
/// @return A NanoCommunicationResult indicating the result of the communication operation.
|
||||||
|
///
|
||||||
|
static NanoCommunicationResult
|
||||||
|
send_keep_alive_to_alive_socket(NanoAttachment *attachment, int keep_alive_socket)
|
||||||
|
{
|
||||||
|
uint8_t container_id_size = strlen(attachment->container_id);
|
||||||
|
struct timeval timeout = get_absolute_timeout_val_sec(1);
|
||||||
|
NanoCommunicationResult res;
|
||||||
|
|
||||||
|
// Exchanging worker id with the nano service.
|
||||||
|
res = write_to_service(
|
||||||
|
attachment,
|
||||||
|
&keep_alive_socket,
|
||||||
|
&attachment->worker_id,
|
||||||
|
sizeof(attachment->worker_id),
|
||||||
|
&timeout
|
||||||
|
);
|
||||||
|
if (res != NANO_OK) {
|
||||||
|
// Failed to send worker id
|
||||||
|
write_dbg(attachment, attachment->worker_id, DBG_LEVEL_WARNING, "Failed to send worker id");
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exchanging container id size with the nano service.
|
||||||
|
res = write_to_service(
|
||||||
|
attachment,
|
||||||
|
&keep_alive_socket,
|
||||||
|
&container_id_size,
|
||||||
|
sizeof(container_id_size),
|
||||||
|
&timeout
|
||||||
|
);
|
||||||
|
if (res != NANO_OK) {
|
||||||
|
// Failed to send container id size.
|
||||||
|
write_dbg(attachment, attachment->worker_id, DBG_LEVEL_WARNING, "Failed to send container id size");
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (container_id_size > 0) {
|
||||||
|
// Exchanging container id with the nano service.
|
||||||
|
res = write_to_service(
|
||||||
|
attachment,
|
||||||
|
&keep_alive_socket,
|
||||||
|
attachment->container_id,
|
||||||
|
container_id_size,
|
||||||
|
&timeout
|
||||||
|
);
|
||||||
|
if (res != NANO_OK) {
|
||||||
|
// Failed to send container id name.
|
||||||
|
write_dbg(attachment, attachment->worker_id, DBG_LEVEL_WARNING, "Failed to send container id");
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NANO_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SendKeepAlive(NanoAttachment *attachment)
|
||||||
|
{
|
||||||
|
int keep_alive_socket;
|
||||||
|
NanoCommunicationResult res;
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
attachment->worker_id,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"Keep alive signal. Family id: %s, UID: %u",
|
||||||
|
attachment->container_id,
|
||||||
|
attachment->worker_id
|
||||||
|
);
|
||||||
|
|
||||||
|
keep_alive_socket = connect_to_keep_alive_socket(attachment);
|
||||||
|
if (keep_alive_socket < 0) {
|
||||||
|
write_dbg(attachment, attachment->worker_id, DBG_LEVEL_WARNING, "Failed to connect to keep alive socket");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
attachment->worker_id,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"connected to socket: %d. sending keep alive signals"
|
||||||
|
);
|
||||||
|
|
||||||
|
res = send_keep_alive_to_alive_socket(attachment, keep_alive_socket);
|
||||||
|
if (res == NANO_ERROR) {
|
||||||
|
write_dbg(attachment, attachment->worker_id, DBG_LEVEL_WARNING, "Failed to send keep alive data");
|
||||||
|
}
|
||||||
|
|
||||||
|
close(keep_alive_socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
IsSessionFinalized(NanoAttachment *attachment, HttpSessionData *session_data)
|
||||||
|
{
|
||||||
|
if (session_data->verdict == TRAFFIC_VERDICT_INSPECT) {
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
attachment->worker_id,
|
||||||
|
DBG_LEVEL_TRACE,
|
||||||
|
"Inspecting data for session id: %d",
|
||||||
|
session_data->session_id
|
||||||
|
);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
attachment->worker_id,
|
||||||
|
DBG_LEVEL_TRACE,
|
||||||
|
"Skipping already inspected for session id: %d",
|
||||||
|
session_data->session_id
|
||||||
|
);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
NanoWebResponseType
|
||||||
|
GetWebResponseType(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
HttpSessionData *session_data,
|
||||||
|
AttachmentVerdictResponse *response
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (response->web_response_data == NULL) {
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_data->session_id,
|
||||||
|
DBG_LEVEL_WARNING,
|
||||||
|
"Trying to get web response with no response object"
|
||||||
|
);
|
||||||
|
return NO_WEB_RESPONSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return response->web_response_data->web_response_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
IsResponseWithModification(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
HttpSessionData *session_data,
|
||||||
|
AttachmentVerdictResponse *response
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int res = response->modifications != NULL;
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_data->session_id,
|
||||||
|
DBG_LEVEL_TRACE,
|
||||||
|
"Response %s have modifications",
|
||||||
|
res ? "does" : "does not"
|
||||||
|
);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
NanoResponseModifications
|
||||||
|
GetResponseModifications(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
HttpSessionData *session_data,
|
||||||
|
AttachmentVerdictResponse *response
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (response == NULL) {
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_data->session_id,
|
||||||
|
DBG_LEVEL_WARNING,
|
||||||
|
"Trying to get modifications with no response object"
|
||||||
|
);
|
||||||
|
return (NanoResponseModifications) {
|
||||||
|
.modifications = NULL
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return (NanoResponseModifications) {
|
||||||
|
.modifications = response->modifications
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockPageData
|
||||||
|
GetBlockPage(NanoAttachment *attachment, HttpSessionData *session_data, AttachmentVerdictResponse *response)
|
||||||
|
{
|
||||||
|
WebResponseData *web_response_data = response->web_response_data;
|
||||||
|
CustomResponseData *custom_response_data;
|
||||||
|
|
||||||
|
if (web_response_data->web_response_type != CUSTOM_WEB_RESPONSE) {
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_data->session_id,
|
||||||
|
DBG_LEVEL_WARNING,
|
||||||
|
"Trying to generate custom block page with a non custom response object"
|
||||||
|
);
|
||||||
|
|
||||||
|
return (BlockPageData) {
|
||||||
|
.response_code = 0,
|
||||||
|
.title_prefix = { .len = 0, .data = NULL },
|
||||||
|
.title = { .len = 0, .data = NULL },
|
||||||
|
.body_prefix = { .len = 0, .data = NULL },
|
||||||
|
.body = { .len = 0, .data = NULL },
|
||||||
|
.uuid_prefix = { .len = 0, .data = NULL },
|
||||||
|
.uuid = { .len = 0, .data = NULL },
|
||||||
|
.uuid_suffix = { .len = 0, .data = NULL }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_data->session_id,
|
||||||
|
DBG_LEVEL_TRACE,
|
||||||
|
"Getting custom block page"
|
||||||
|
);
|
||||||
|
|
||||||
|
custom_response_data = (CustomResponseData *) web_response_data->data;
|
||||||
|
return (BlockPageData) {
|
||||||
|
.response_code = custom_response_data->response_code,
|
||||||
|
.title_prefix = { .len = strlen(title_prefix), .data = (unsigned char *)title_prefix },
|
||||||
|
.title = { .len = strlen((char *)custom_response_data->title), .data = custom_response_data->title },
|
||||||
|
.body_prefix = { .len = strlen(body_prefix), .data = (unsigned char *)body_prefix },
|
||||||
|
.body = { .len = strlen((char *)custom_response_data->body), .data = custom_response_data->body },
|
||||||
|
.uuid_prefix = { .len = strlen(uuid_prefix), .data = (unsigned char *)uuid_prefix },
|
||||||
|
.uuid = { .len = strlen((char *)web_response_data->uuid), .data = web_response_data->uuid },
|
||||||
|
.uuid_suffix = { .len = strlen(uuid_suffix), .data = (unsigned char *)uuid_suffix }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RedirectPageData
|
||||||
|
GetRedirectPage(NanoAttachment *attachment, HttpSessionData *session_data, AttachmentVerdictResponse *response)
|
||||||
|
{
|
||||||
|
WebResponseData *web_response_data = response->web_response_data;
|
||||||
|
RedirectData *redirect_data;
|
||||||
|
|
||||||
|
if (web_response_data->web_response_type != REDIRECT_WEB_RESPONSE) {
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_data->session_id,
|
||||||
|
DBG_LEVEL_WARNING,
|
||||||
|
"Trying to generate custom block page with a non redirect response object"
|
||||||
|
);
|
||||||
|
|
||||||
|
return (RedirectPageData) {
|
||||||
|
.redirect_location = { .len = 0, .data = NULL }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_data->session_id,
|
||||||
|
DBG_LEVEL_TRACE,
|
||||||
|
"Getting redirect data"
|
||||||
|
);
|
||||||
|
|
||||||
|
redirect_data = (RedirectData *) web_response_data->data;
|
||||||
|
return (RedirectPageData) {
|
||||||
|
.redirect_location = {
|
||||||
|
.len = strlen((char*)redirect_data->redirect_location),
|
||||||
|
.data = redirect_data->redirect_location
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FreeAttachmentResponseContent(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
HttpSessionData *session_data,
|
||||||
|
AttachmentVerdictResponse *response
|
||||||
|
)
|
||||||
|
{
|
||||||
|
NanoHttpModificationList *current_modification;
|
||||||
|
NanoHttpModificationList *modification_list;
|
||||||
|
|
||||||
|
if (response == NULL) {
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_data->session_id,
|
||||||
|
DBG_LEVEL_WARNING,
|
||||||
|
"Attempting to free NULL response"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_data->session_id,
|
||||||
|
DBG_LEVEL_TRACE,
|
||||||
|
"Freeing AttachmentResponse object"
|
||||||
|
);
|
||||||
|
if (response->web_response_data != NULL) {
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_data->session_id,
|
||||||
|
DBG_LEVEL_TRACE,
|
||||||
|
"Freeing custom web response data"
|
||||||
|
);
|
||||||
|
|
||||||
|
free(response->web_response_data->data);
|
||||||
|
free(response->web_response_data);
|
||||||
|
response->web_response_data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response->modifications != NULL) {
|
||||||
|
modification_list = response->modifications;
|
||||||
|
while (modification_list) {
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_data->session_id,
|
||||||
|
DBG_LEVEL_TRACE,
|
||||||
|
"Freeing modifications list"
|
||||||
|
);
|
||||||
|
current_modification = modification_list;
|
||||||
|
modification_list = modification_list->next;
|
||||||
|
free(current_modification);
|
||||||
|
}
|
||||||
|
response->modifications = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
217
attachments/nano_attachment/nano_attachment.h
Normal file
217
attachments/nano_attachment/nano_attachment.h
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
#ifndef __NANO_ATTACHMENT_H__
|
||||||
|
#define __NANO_ATTACHMENT_H__
|
||||||
|
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "nano_initializer.h"
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @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);
|
||||||
|
|
||||||
|
AttachmentVerdictResponse SendDataNanoAttachmentWrapper(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
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif // __NANO_ATTACHMENT_H__
|
1762
attachments/nano_attachment/nano_attachment_io.c
Normal file
1762
attachments/nano_attachment/nano_attachment_io.c
Normal file
File diff suppressed because it is too large
Load Diff
230
attachments/nano_attachment/nano_attachment_io.h
Normal file
230
attachments/nano_attachment/nano_attachment_io.h
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
#ifndef __NANO_ATTACHMENT_IO_H__
|
||||||
|
#define __NANO_ATTACHMENT_IO_H__
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "nano_initializer.h"
|
||||||
|
#include "nano_attachment_sender_thread.h"
|
||||||
|
#include "shmem_ipc_2.h"
|
||||||
|
|
||||||
|
/// @brief Sends session data chunk to a nano service for inspection.
|
||||||
|
///
|
||||||
|
/// This function sends the provided data fragments to the nano service for inspection.
|
||||||
|
///
|
||||||
|
/// @param attachment A pointer to a NanoAttachment structure representing the attachment to the nano service.
|
||||||
|
/// @param fragments An array of pointers to character arrays representing the data fragments to send.
|
||||||
|
/// @param fragments_sizes An array of uint16_t values representing the sizes of the data fragments.
|
||||||
|
/// @param num_of_data_elem An 8-bit integer representing the number of data elements (fragments) to send.
|
||||||
|
/// @param cur_session_id An unsigned 32-bit integer representing the current session ID.
|
||||||
|
/// @param chunk_type An enumeration representing the type of data chunk being sent.
|
||||||
|
///
|
||||||
|
/// @return NANO_OK if the data is sent successfully, NANO_ERROR otherwise.
|
||||||
|
///
|
||||||
|
NanoCommunicationResult
|
||||||
|
send_session_data_to_service(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
char **fragments,
|
||||||
|
const uint16_t *fragments_sizes,
|
||||||
|
uint8_t num_of_data_elem,
|
||||||
|
uint32_t cur_session_id,
|
||||||
|
AttachmentDataType chunk_type
|
||||||
|
);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Connect to the communication socket.
|
||||||
|
///
|
||||||
|
/// This function creates a new socket and connects it to the verdict
|
||||||
|
/// Unix domain socket address. If the attachment already has a communication
|
||||||
|
/// socket open, it is closed before creating a new one.
|
||||||
|
///
|
||||||
|
/// @param[in] attachment The NanoAttachment struct containing socket information.
|
||||||
|
/// @returns A NanoCommunicationResult indicating the success of the operation.
|
||||||
|
///
|
||||||
|
NanoCommunicationResult connect_to_comm_socket(NanoAttachment *attachment);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Create an unix socket and connect to the attachment registration service.
|
||||||
|
/// @param[in] attachment Points to initiated NanoAttachment struct.
|
||||||
|
/// @returns NanoCommunicationResult
|
||||||
|
/// - #NANO_OK
|
||||||
|
/// - #NANO_ERROR
|
||||||
|
///
|
||||||
|
NanoCommunicationResult connect_to_registration_socket(NanoAttachment *attachment);
|
||||||
|
|
||||||
|
/// @brief Receives and processes replies from a nano service regarding traffic inspection verdicts.
|
||||||
|
///
|
||||||
|
/// This function waits for replies from the service and handles each reply based on the verdict received.
|
||||||
|
///
|
||||||
|
/// @param attachment A pointer to a NanoAttachment structure representing the attachment to the nano service.
|
||||||
|
/// @param session_data A pointer to a HttpSessionData which holds the session data.
|
||||||
|
/// @param web_response_data A pointer to a WebResponseData structure representing the response data.
|
||||||
|
/// @param modification_list A pointer to a pointer to a NanoHttpModificationList structure
|
||||||
|
/// representing a list of HTTP modifications.
|
||||||
|
///
|
||||||
|
/// @return NANO_OK if the function completes successfully
|
||||||
|
/// NANO_ERROR if an error occurs during processing
|
||||||
|
/// NANO_HTTP_FORBIDDEN if a drop verdict is received.
|
||||||
|
///
|
||||||
|
NanoCommunicationResult
|
||||||
|
service_reply_receiver(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
HttpSessionData *session_data,
|
||||||
|
WebResponseData **web_response_data,
|
||||||
|
NanoHttpModificationList **modification_list,
|
||||||
|
AttachmentDataType chunk_type
|
||||||
|
);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends request start metadata for inspection to the nano service.
|
||||||
|
///
|
||||||
|
/// @param attachment Pointer to the NanoAttachment struct representing the attachment.
|
||||||
|
/// @param metadata Pointer to the HttpMetaData struct containing the HTTP metadata.
|
||||||
|
/// @param ctx Pointer to the HttpEventThreadCtx struct containing the HTTP event context.
|
||||||
|
/// @param cur_request_id The current request ID.
|
||||||
|
/// @param num_of_messages_sent Pointer to an unsigned int to store the number of messages sent.
|
||||||
|
/// @param is_verdict_requested Boolean value indicating if a verdict is requested.
|
||||||
|
///
|
||||||
|
void
|
||||||
|
nano_metadata_sender(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
HttpMetaData *metadata,
|
||||||
|
HttpEventThreadCtx *ctx,
|
||||||
|
uint32_t cur_request_id,
|
||||||
|
unsigned int *num_of_messages_sent,
|
||||||
|
bool is_verdict_requested
|
||||||
|
);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends a response code for inspection.
|
||||||
|
///
|
||||||
|
/// This function sends a response code for inspection to a service.
|
||||||
|
///
|
||||||
|
/// @param attachment A pointer to the NanoAttachment structure.
|
||||||
|
/// @param response_code The response code to send.
|
||||||
|
/// @param ctx The HttpEventThreadCtx context.
|
||||||
|
/// @param cur_request_id The current request ID.
|
||||||
|
/// @param num_messages_sent A pointer to the number of messages sent.
|
||||||
|
///
|
||||||
|
void
|
||||||
|
nano_send_response_code(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
uint16_t response_code,
|
||||||
|
HttpEventThreadCtx *ctx,
|
||||||
|
uint32_t cur_request_id,
|
||||||
|
unsigned int *num_messages_sent
|
||||||
|
);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends the content length to the intaker.
|
||||||
|
///
|
||||||
|
/// This function sends the content length to the intaker for processing.
|
||||||
|
///
|
||||||
|
/// @param attachment A pointer to the NanoAttachment structure.
|
||||||
|
/// @param content_length The content length to send.
|
||||||
|
/// @param ctx The HttpEventThreadCtx context.
|
||||||
|
/// @param cur_request_id The current request ID.
|
||||||
|
/// @param num_messages_sent A pointer to the number of messages sent.
|
||||||
|
///
|
||||||
|
void
|
||||||
|
nano_send_response_content_length(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
uint64_t content_length,
|
||||||
|
HttpEventThreadCtx *ctx,
|
||||||
|
uint32_t cur_request_id,
|
||||||
|
unsigned int *num_messages_sent
|
||||||
|
);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends HTTP headers for inspection using a NanoAttachment.
|
||||||
|
///
|
||||||
|
/// This function takes a NanoAttachment pointer, an HttpHeaders struct containing the headers to send,
|
||||||
|
/// the type of the headers (request or response), the current request ID, and a pointer to store
|
||||||
|
/// the number of messages sent.
|
||||||
|
///
|
||||||
|
/// @param attachment Pointer to the NanoAttachment struct representing the attachment.
|
||||||
|
/// @param headers Pointer to the HttpHeaders struct containing the headers to send.
|
||||||
|
/// @param ctx Pointer to the HttpEventThreadCtx struct containing the context of the current thread.
|
||||||
|
/// @param header_type Type of the headers (REQUEST_HEADER or RESPONSE_HEADER).
|
||||||
|
/// @param cur_request_id Current request ID.
|
||||||
|
/// @param num_messages_sent Pointer to an unsigned int to store the number of messages sent.
|
||||||
|
///
|
||||||
|
void
|
||||||
|
nano_header_sender(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
HttpHeaders *headers,
|
||||||
|
HttpEventThreadCtx *ctx,
|
||||||
|
AttachmentDataType header_type,
|
||||||
|
uint32_t cur_request_id,
|
||||||
|
unsigned int *num_messages_sent,
|
||||||
|
bool is_verdict_requested
|
||||||
|
);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends the body of a request or response for inspection to a nano service.
|
||||||
|
///
|
||||||
|
/// This function iterates over the body chunks, creates fragments, and sends them
|
||||||
|
/// in bulk to the service. It also handles the final chunk and updates the number
|
||||||
|
/// of messages sent.
|
||||||
|
///
|
||||||
|
/// @param attachment Pointer to a NanoAttachment struct representing the attachment/module.
|
||||||
|
/// @param bodies Pointer to an HttpBody struct containing the HTTP request/response body data.
|
||||||
|
/// @param ctx Pointer to an HttpEventThreadCtx struct representing the HTTP event thread context.
|
||||||
|
/// @param body_type Enum value indicating whether the body is a request or response body.
|
||||||
|
/// @param cur_request_id Current request ID for logging and tracking purposes.
|
||||||
|
/// @param num_messages_sent Pointer to an unsigned int to track the number of messages sent.
|
||||||
|
///
|
||||||
|
void
|
||||||
|
nano_body_sender(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
HttpBody *bodies,
|
||||||
|
HttpEventThreadCtx *ctx,
|
||||||
|
AttachmentDataType body_type,
|
||||||
|
uint32_t cur_request_id,
|
||||||
|
unsigned int *num_messages_sent
|
||||||
|
);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends an end transaction event to a service for inspection.
|
||||||
|
///
|
||||||
|
/// @param attachment The NanoAttachment struct representing the attachment/module.
|
||||||
|
/// @param end_transaction_type The type of end transaction event (REQUEST_END or RESPONSE_END).
|
||||||
|
/// @param ctx Pointer to the HttpEventThreadCtx struct containing the context of the current thread.
|
||||||
|
/// @param cur_request_id The ID of the current request.
|
||||||
|
/// @param num_messages_sent Pointer to an unsigned integer to store the number of messages sent.
|
||||||
|
/// @return NANO_OK if the end transaction event was sent successfully, NANO_ERROR otherwise.
|
||||||
|
///
|
||||||
|
void
|
||||||
|
nano_end_transaction_sender(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
AttachmentDataType end_transaction_type,
|
||||||
|
HttpEventThreadCtx *ctx,
|
||||||
|
SessionID cur_request_id,
|
||||||
|
unsigned int *num_messages_sent
|
||||||
|
);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends delayed transaction event to a service for inspection.
|
||||||
|
///
|
||||||
|
/// @param attachment The NanoAttachment struct representing the attachment/module.
|
||||||
|
/// @param ctx Pointer to the HttpEventThreadCtx struct containing the context of the current thread.
|
||||||
|
/// @param cur_request_id The ID of the current request.
|
||||||
|
/// @param num_messages_sent Pointer to an unsigned integer to store the number of messages sent.
|
||||||
|
///
|
||||||
|
void
|
||||||
|
nano_request_delayed_verdict(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
HttpEventThreadCtx *ctx,
|
||||||
|
SessionID cur_request_id,
|
||||||
|
unsigned int *num_messages_sent
|
||||||
|
);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends attachment's metric data to the service.
|
||||||
|
///
|
||||||
|
/// @param attachment The NanoAttachment struct representing the attachment/module, which contains the metric data.
|
||||||
|
///
|
||||||
|
void
|
||||||
|
nano_send_metric_data_sender(NanoAttachment *attachment);
|
||||||
|
|
||||||
|
#endif // __NANO_ATTACHMENT_IO_H__
|
83
attachments/nano_attachment/nano_attachment_metric.c
Normal file
83
attachments/nano_attachment/nano_attachment_metric.c
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
#include "nano_attachment_metric.h"
|
||||||
|
|
||||||
|
#include "nano_initializer.h"
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
reset_metric_data(NanoAttachment *attachment)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0 ; i < METRIC_TYPES_COUNT ; i++) {
|
||||||
|
attachment->metric_data[i] = 0;
|
||||||
|
attachment->metric_average_data_divisor[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
updateCounterMetricField(NanoAttachment *attachment, AttachmentMetricType metric_type, uint64_t value)
|
||||||
|
{
|
||||||
|
attachment->metric_data[metric_type] += value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
updateAverageMetricField(NanoAttachment *attachment, AttachmentMetricType metric_type, uint64_t value)
|
||||||
|
{
|
||||||
|
attachment->metric_data[metric_type] =
|
||||||
|
(((attachment->metric_data[metric_type] * attachment->metric_average_data_divisor[metric_type]) + value) /
|
||||||
|
(attachment->metric_average_data_divisor[metric_type] + 1));
|
||||||
|
attachment->metric_average_data_divisor[metric_type] += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
updateMaxMetricField(NanoAttachment *attachment, AttachmentMetricType metric_type, uint64_t value)
|
||||||
|
{
|
||||||
|
if (attachment->metric_data[metric_type] < value) attachment->metric_data[metric_type] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
updateMinMetricField(NanoAttachment *attachment, AttachmentMetricType metric_type, uint64_t value)
|
||||||
|
{
|
||||||
|
if (attachment->metric_data[metric_type] == 0) {
|
||||||
|
attachment->metric_data[metric_type] = value;
|
||||||
|
} else if (attachment->metric_data[metric_type] > value) {
|
||||||
|
attachment->metric_data[metric_type] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
updateMetricField(NanoAttachment *attachment, AttachmentMetricType metric_type, uint64_t value)
|
||||||
|
{
|
||||||
|
switch (metric_type) {
|
||||||
|
case CPU_USAGE:
|
||||||
|
case AVERAGE_VM_MEMORY_USAGE:
|
||||||
|
case AVERAGE_RSS_MEMORY_USAGE:
|
||||||
|
case AVERAGE_REQ_BODY_SIZE_UPON_TIMEOUT:
|
||||||
|
case AVERAGE_RES_BODY_SIZE_UPON_TIMEOUT:
|
||||||
|
case AVERAGE_OVERALL_PPROCESSING_TIME_UNTIL_VERDICT:
|
||||||
|
case AVERAGE_REQ_PPROCESSING_TIME_UNTIL_VERDICT:
|
||||||
|
case AVERAGE_RES_PPROCESSING_TIME_UNTIL_VERDICT: {
|
||||||
|
if (value != 0) updateAverageMetricField(attachment, metric_type, value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MAX_VM_MEMORY_USAGE:
|
||||||
|
case MAX_RSS_MEMORY_USAGE:
|
||||||
|
case MAX_REQ_BODY_SIZE_UPON_TIMEOUT:
|
||||||
|
case MAX_RES_BODY_SIZE_UPON_TIMEOUT:
|
||||||
|
case MAX_OVERALL_PPROCESSING_TIME_UNTIL_VERDICT:
|
||||||
|
case MAX_REQ_PPROCESSING_TIME_UNTIL_VERDICT:
|
||||||
|
case MAX_RES_PPROCESSING_TIME_UNTIL_VERDICT: {
|
||||||
|
if (value != 0) updateMaxMetricField(attachment, metric_type, value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MIN_REQ_BODY_SIZE_UPON_TIMEOUT:
|
||||||
|
case MIN_RES_BODY_SIZE_UPON_TIMEOUT:
|
||||||
|
case MIN_OVERALL_PPROCESSING_TIME_UNTIL_VERDICT:
|
||||||
|
case MIN_REQ_PPROCESSING_TIME_UNTIL_VERDICT:
|
||||||
|
case MIN_RES_PPROCESSING_TIME_UNTIL_VERDICT: {
|
||||||
|
if (value != 0) updateMinMetricField(attachment, metric_type, value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
updateCounterMetricField(attachment, metric_type, value);
|
||||||
|
}
|
||||||
|
}
|
33
attachments/nano_attachment/nano_attachment_metric.h
Normal file
33
attachments/nano_attachment/nano_attachment_metric.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#ifndef __NANO_ATTACHMENT_METRIC_H__
|
||||||
|
#define __NANO_ATTACHMENT_METRIC_H__
|
||||||
|
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "nano_initializer.h"
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Updates a specified metric field of the NanoAttachment structure.
|
||||||
|
///
|
||||||
|
/// This function updates the value of a specified metric field within the NanoAttachment structure.
|
||||||
|
/// It selects the appropriate update strategy (counter, average, maximum, or minimum) based on the type
|
||||||
|
/// of the metric provided. For average, maximum, and minimum metrics, the function updates the metric value
|
||||||
|
/// only if the provided value is non-zero. For counter metrics, the value is always incremented.
|
||||||
|
///
|
||||||
|
/// @param attachment A pointer to the NanoAttachment structure.
|
||||||
|
/// @param metric_type The type of the metric to be updated. This determines the update strategy used.
|
||||||
|
/// @param value The value to update the metric with. For average, maximum, and minimum metrics,
|
||||||
|
/// this value must be non-zero to be considered.
|
||||||
|
///
|
||||||
|
void updateMetricField(NanoAttachment *attachment, AttachmentMetricType metric_type, uint64_t value);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Resets all metric data fields of the NanoAttachment structure.
|
||||||
|
///
|
||||||
|
/// This function resets the metric data and the average data divisor fields within the NanoAttachment structure
|
||||||
|
/// to zero. It is typically used to initialize or clear the metric data before starting a new measurement session
|
||||||
|
/// or after completing an existing session.
|
||||||
|
///
|
||||||
|
/// @param attachment A pointer to the NanoAttachment structure.
|
||||||
|
///
|
||||||
|
void reset_metric_data(NanoAttachment *attachment);
|
||||||
|
|
||||||
|
#endif // __NANO_ATTACHMENT_METRIC_H__
|
795
attachments/nano_attachment/nano_attachment_sender.c
Normal file
795
attachments/nano_attachment/nano_attachment_sender.c
Normal file
@ -0,0 +1,795 @@
|
|||||||
|
#include "nano_attachment_sender.h"
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "nano_attachment_sender_thread.h"
|
||||||
|
#include "nano_attachment_thread.h"
|
||||||
|
#include "nano_utils.h"
|
||||||
|
#include "nano_attachment_metric.h"
|
||||||
|
|
||||||
|
static unsigned char default_uuid[] = "20118dba-81f7-4999-8e94-003cf242f5dd\0";
|
||||||
|
static const size_t default_uuid_size = 37;
|
||||||
|
|
||||||
|
static unsigned char default_title[] = "Default Title\0";
|
||||||
|
static const size_t default_title_size = 14;
|
||||||
|
|
||||||
|
static unsigned char default_body[] = "Default Body\0";
|
||||||
|
static const size_t default_body_size = 13;
|
||||||
|
|
||||||
|
static uint16_t default_response_code = 403;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Creates a default block page.
|
||||||
|
///
|
||||||
|
/// @param attachment Pointer to the NanoAttachment struct representing the attachment.
|
||||||
|
/// @param session_id The session ID associated with the attachment.
|
||||||
|
/// @return A pointer to a WebResponseData struct containing the default block page data.
|
||||||
|
///
|
||||||
|
static WebResponseData*
|
||||||
|
CreateDefaultBlockPage(NanoAttachment *attachment, SessionID session_id)
|
||||||
|
{
|
||||||
|
WebResponseData *web_response_data = NULL;
|
||||||
|
CustomResponseData *custom_response_data = NULL;
|
||||||
|
|
||||||
|
web_response_data = (WebResponseData *)malloc(sizeof(WebResponseData));
|
||||||
|
if (web_response_data == NULL) {
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_WARNING,
|
||||||
|
"Failed to allocate memory for WebResponseData"
|
||||||
|
);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
custom_response_data = (CustomResponseData *)malloc(sizeof(CustomResponseData));
|
||||||
|
if (custom_response_data == NULL) {
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_WARNING,
|
||||||
|
"Failed to allocate memory for CustomResponseData"
|
||||||
|
);
|
||||||
|
free(web_response_data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
web_response_data->web_response_type = CUSTOM_WEB_RESPONSE;
|
||||||
|
memcpy(web_response_data->uuid, default_uuid, default_uuid_size);
|
||||||
|
custom_response_data->response_code = default_response_code;
|
||||||
|
memcpy(custom_response_data->title, default_title, default_title_size);
|
||||||
|
memcpy(custom_response_data->body, default_body, default_body_size);
|
||||||
|
web_response_data->data = (DataBuffer*)custom_response_data;
|
||||||
|
|
||||||
|
return web_response_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Get a string representation of the AttachmentVerdict enum.
|
||||||
|
///
|
||||||
|
/// @param verdict The AttachmentVerdict enum value.
|
||||||
|
/// @return A string representation of the enum value.
|
||||||
|
///
|
||||||
|
static const char*
|
||||||
|
AttachmentVerdictToString(AttachmentVerdict verdict)
|
||||||
|
{
|
||||||
|
switch (verdict) {
|
||||||
|
case ATTACHMENT_VERDICT_INSPECT:
|
||||||
|
return "inspect";
|
||||||
|
case ATTACHMENT_VERDICT_ACCEPT:
|
||||||
|
return "accept";
|
||||||
|
case ATTACHMENT_VERDICT_DROP:
|
||||||
|
return "drop";
|
||||||
|
case ATTACHMENT_VERDICT_INJECT:
|
||||||
|
return "inject";
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends a verdict response for a corrupt memory condition.
|
||||||
|
///
|
||||||
|
/// @param attachment Pointer to the NanoAttachment struct representing the attachment.
|
||||||
|
/// @param session_data_p Pointer to the HttpSessionData struct containing the session data.
|
||||||
|
/// @return An AttachmentVerdictResponse struct containing the session ID and verdict.
|
||||||
|
///
|
||||||
|
static AttachmentVerdictResponse
|
||||||
|
SendCorruptMemoryVerdict(NanoAttachment *attachment, HttpSessionData *session_data_p)
|
||||||
|
{
|
||||||
|
AttachmentVerdictResponse response = {
|
||||||
|
.session_id = session_data_p->session_id,
|
||||||
|
.web_response_data = NULL,
|
||||||
|
.modifications = NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
if (attachment->fail_mode_verdict == NANO_OK) {
|
||||||
|
updateMetricField(attachment, INSPECTION_OPEN_FAILURES_COUNT, 1);
|
||||||
|
response.verdict = ATTACHMENT_VERDICT_ACCEPT;
|
||||||
|
session_data_p->verdict = TRAFFIC_VERDICT_ACCEPT;
|
||||||
|
} else {
|
||||||
|
updateMetricField(attachment, INSPECTION_CLOSE_FAILURES_COUNT, 1);
|
||||||
|
response.verdict = ATTACHMENT_VERDICT_DROP;
|
||||||
|
session_data_p->verdict = TRAFFIC_VERDICT_DROP;
|
||||||
|
response.web_response_data = CreateDefaultBlockPage(attachment, session_data_p->session_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
response.session_id,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"Shared memory is corrupted, returning default fail mode verdict. Session id: %d, verdict: %s",
|
||||||
|
response.session_id,
|
||||||
|
response.verdict == ATTACHMENT_VERDICT_ACCEPT ? "accept" : "drop"
|
||||||
|
);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends a verdict response for a thread timeout condition.
|
||||||
|
///
|
||||||
|
/// @param attachment Pointer to the NanoAttachment struct representing the attachment.
|
||||||
|
/// @param session_id The session ID associated with the attachment.
|
||||||
|
/// @param ctx Pointer to the HttpEventThreadCtx struct containing the HTTP event context.
|
||||||
|
/// @return An AttachmentVerdictResponse struct containing the session ID and verdict.
|
||||||
|
///
|
||||||
|
static AttachmentVerdictResponse
|
||||||
|
SendThreadTimeoutVerdict(NanoAttachment *attachment, SessionID session_id, HttpEventThreadCtx *ctx)
|
||||||
|
{
|
||||||
|
AttachmentVerdictResponse response = {
|
||||||
|
.session_id = session_id,
|
||||||
|
.web_response_data = NULL,
|
||||||
|
.modifications = NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
if (attachment->fail_mode_verdict == NANO_OK) {
|
||||||
|
response.verdict = ATTACHMENT_VERDICT_ACCEPT;
|
||||||
|
ctx->session_data_p->verdict = TRAFFIC_VERDICT_ACCEPT;
|
||||||
|
} else {
|
||||||
|
response.verdict = ATTACHMENT_VERDICT_DROP;
|
||||||
|
ctx->session_data_p->verdict = TRAFFIC_VERDICT_DROP;
|
||||||
|
response.web_response_data = CreateDefaultBlockPage(attachment, session_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
response.session_id,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"Thread failed, returning fail mode verdict. Session id: %d, verdict: %s",
|
||||||
|
response.session_id,
|
||||||
|
response.verdict == ATTACHMENT_VERDICT_ACCEPT ? "accept" : "drop"
|
||||||
|
);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Finalizes a successful response by determining the verdict based on the HTTP response code.
|
||||||
|
///
|
||||||
|
/// @param attachment Pointer to the NanoAttachment struct representing the attachment.
|
||||||
|
/// @param session_id The session ID associated with the attachment.
|
||||||
|
/// @param ctx Pointer to the HttpEventThreadCtx struct containing the HTTP event context.
|
||||||
|
/// @return An AttachmentVerdictResponse struct containing the session ID and verdict.
|
||||||
|
///
|
||||||
|
static AttachmentVerdictResponse
|
||||||
|
FinalizeSuccessfulResponse(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
SessionID session_id,
|
||||||
|
HttpEventThreadCtx *ctx
|
||||||
|
)
|
||||||
|
{
|
||||||
|
AttachmentVerdictResponse response = {
|
||||||
|
.session_id = session_id,
|
||||||
|
.web_response_data = ctx->web_response_data,
|
||||||
|
.modifications = ctx->modifications
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (ctx->session_data_p->verdict) {
|
||||||
|
case TRAFFIC_VERDICT_INSPECT:
|
||||||
|
response.verdict = ATTACHMENT_VERDICT_INSPECT;
|
||||||
|
break;
|
||||||
|
case TRAFFIC_VERDICT_ACCEPT:
|
||||||
|
response.verdict = ATTACHMENT_VERDICT_ACCEPT;
|
||||||
|
break;
|
||||||
|
case TRAFFIC_VERDICT_DROP:
|
||||||
|
response.verdict = ATTACHMENT_VERDICT_DROP;
|
||||||
|
break;
|
||||||
|
case TRAFFIC_VERDICT_INJECT:
|
||||||
|
// Not yet supported
|
||||||
|
response.verdict = ATTACHMENT_VERDICT_INSPECT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_WARNING,
|
||||||
|
"Unknown verdict %d",
|
||||||
|
ctx->session_data_p->verdict
|
||||||
|
);
|
||||||
|
response.verdict = ATTACHMENT_VERDICT_INSPECT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateMetricField(attachment, INSPECTION_SUCCESSES_COUNT, 1);
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
response.session_id,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"Finalizing successful response to Session id: %d, verdict: %s",
|
||||||
|
response.session_id,
|
||||||
|
AttachmentVerdictToString(response.verdict)
|
||||||
|
);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Finalizes an irrelevant response by setting the verdict to accept.
|
||||||
|
///
|
||||||
|
/// @param attachment Pointer to the NanoAttachment struct representing the attachment.
|
||||||
|
/// @param session_id The session ID associated with the attachment.
|
||||||
|
/// @return An AttachmentVerdictResponse struct containing the session ID and verdict.
|
||||||
|
///
|
||||||
|
static AttachmentVerdictResponse
|
||||||
|
FinalizeIrrelevantResponse(NanoAttachment *attachment, SessionID session_id)
|
||||||
|
{
|
||||||
|
AttachmentVerdictResponse response = {
|
||||||
|
.verdict = ATTACHMENT_VERDICT_ACCEPT,
|
||||||
|
.session_id = session_id,
|
||||||
|
.web_response_data = NULL,
|
||||||
|
.modifications = NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
updateMetricField(attachment, IRRELEVANT_VERDICTS_COUNT, 1);
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
response.session_id,
|
||||||
|
DBG_LEVEL_TRACE,
|
||||||
|
"Finalizing irrelevant response to Session id: %d",
|
||||||
|
response.session_id
|
||||||
|
);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Finalizes a failed response by determining the verdict
|
||||||
|
/// based on the fail mode verdict associated with the attachment.
|
||||||
|
///
|
||||||
|
/// @param attachment Pointer to the NanoAttachment struct representing the attachment.
|
||||||
|
/// @param session_id The session ID associated with the attachment.
|
||||||
|
/// @param ctx Pointer to the HttpEventThreadCtx struct containing the HTTP event context.
|
||||||
|
/// @return An AttachmentVerdictResponse struct containing the session ID and verdict.
|
||||||
|
///
|
||||||
|
static AttachmentVerdictResponse
|
||||||
|
FinalizeFailedResponse(NanoAttachment *attachment, SessionID session_id, HttpEventThreadCtx *ctx)
|
||||||
|
{
|
||||||
|
AttachmentVerdictResponse response = {
|
||||||
|
.session_id = session_id,
|
||||||
|
.web_response_data = NULL,
|
||||||
|
.modifications = NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
if (attachment->fail_mode_verdict == NANO_OK) {
|
||||||
|
updateMetricField(attachment, INSPECTION_OPEN_FAILURES_COUNT, 1);
|
||||||
|
response.verdict = ATTACHMENT_VERDICT_ACCEPT;
|
||||||
|
ctx->session_data_p->verdict = TRAFFIC_VERDICT_ACCEPT;
|
||||||
|
} else {
|
||||||
|
updateMetricField(attachment, INSPECTION_CLOSE_FAILURES_COUNT, 1);
|
||||||
|
response.verdict = ATTACHMENT_VERDICT_DROP;
|
||||||
|
ctx->session_data_p->verdict = TRAFFIC_VERDICT_DROP;
|
||||||
|
response.web_response_data = CreateDefaultBlockPage(attachment, session_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
response.session_id,
|
||||||
|
DBG_LEVEL_TRACE,
|
||||||
|
"Handling Failure with fail %s mode",
|
||||||
|
response.verdict == ATTACHMENT_VERDICT_ACCEPT ? "open" : "close"
|
||||||
|
);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
AttachmentVerdictResponse
|
||||||
|
SendRequestFilter(NanoAttachment *attachment, AttachmentData *data)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx ctx;
|
||||||
|
HttpSessionData *session_data_p = data->session_data;
|
||||||
|
SessionID session_id = session_data_p->session_id;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"Request filter handling session ID: %d",
|
||||||
|
session_id
|
||||||
|
);
|
||||||
|
|
||||||
|
if (handle_shmem_corruption(attachment) == NANO_ERROR) {
|
||||||
|
return SendCorruptMemoryVerdict(attachment, session_data_p);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(attachment, session_id, DBG_LEVEL_DEBUG, "spawn SendRequestFilterThread");
|
||||||
|
res = NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
data,
|
||||||
|
SendRequestFilterThread,
|
||||||
|
(void *)&ctx,
|
||||||
|
attachment->req_header_thread_timeout_msec,
|
||||||
|
"SendRequestFilterThread",
|
||||||
|
REQUEST
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!res) {
|
||||||
|
updateMetricField(attachment, REQ_METADATA_THREAD_TIMEOUT, 1);
|
||||||
|
return SendThreadTimeoutVerdict(attachment, session_id, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"finished SendMetadataThread successfully. res=%d",
|
||||||
|
ctx.res
|
||||||
|
);
|
||||||
|
|
||||||
|
if (ctx.res == NANO_DECLINED) {
|
||||||
|
return FinalizeIrrelevantResponse(attachment, session_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.res != NANO_HTTP_FORBIDDEN && ctx.res != NANO_OK) {
|
||||||
|
return FinalizeFailedResponse(attachment, session_id, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FinalizeSuccessfulResponse(attachment, session_id, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
AttachmentVerdictResponse
|
||||||
|
SendMetadata(NanoAttachment *attachment, AttachmentData *data)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx ctx;
|
||||||
|
HttpSessionData *session_data_p = data->session_data;
|
||||||
|
SessionID session_id = session_data_p->session_id;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"Request start handling session ID: %d",
|
||||||
|
session_id
|
||||||
|
);
|
||||||
|
|
||||||
|
if (handle_shmem_corruption(attachment) == NANO_ERROR) {
|
||||||
|
return SendCorruptMemoryVerdict(attachment, session_data_p);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(attachment, session_id, DBG_LEVEL_DEBUG, "spawn SendMetadataThread");
|
||||||
|
res = NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
data,
|
||||||
|
SendMetadataThread,
|
||||||
|
(void *)&ctx,
|
||||||
|
attachment->req_start_thread_timeout_msec,
|
||||||
|
"SendMetadataThread",
|
||||||
|
REQUEST
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!res) {
|
||||||
|
updateMetricField(attachment, REQ_METADATA_THREAD_TIMEOUT, 1);
|
||||||
|
return SendThreadTimeoutVerdict(attachment, session_id, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"finished SendMetadataThread successfully. res=%d",
|
||||||
|
ctx.res
|
||||||
|
);
|
||||||
|
|
||||||
|
if (ctx.res == NANO_DECLINED) {
|
||||||
|
return FinalizeIrrelevantResponse(attachment, session_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.res != NANO_HTTP_FORBIDDEN && ctx.res != NANO_OK) {
|
||||||
|
return FinalizeFailedResponse(attachment, session_id, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FinalizeSuccessfulResponse(attachment, session_id, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
AttachmentVerdictResponse
|
||||||
|
SendRequestHeaders(NanoAttachment *attachment, AttachmentData *data)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx ctx;
|
||||||
|
HttpSessionData *session_data_p = data->session_data;
|
||||||
|
SessionID session_id = session_data_p->session_id;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"Request header handling session ID: %d",
|
||||||
|
session_id
|
||||||
|
);
|
||||||
|
|
||||||
|
if (handle_shmem_corruption(attachment) == NANO_ERROR) {
|
||||||
|
return SendCorruptMemoryVerdict(attachment, session_data_p);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(attachment, session_id, DBG_LEVEL_DEBUG, "spawn SendRequestHeadersThread");
|
||||||
|
res = NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
data,
|
||||||
|
SendRequestHeadersThread,
|
||||||
|
(void *)&ctx,
|
||||||
|
attachment->req_header_thread_timeout_msec,
|
||||||
|
"SendRequestHeadersThread",
|
||||||
|
REQUEST
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!res) {
|
||||||
|
updateMetricField(attachment, REQ_HEADER_THREAD_TIMEOUT, 1);
|
||||||
|
return SendThreadTimeoutVerdict(attachment, session_id, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"finished SendRequestHeadersThread successfully. res=%d",
|
||||||
|
ctx.res
|
||||||
|
);
|
||||||
|
|
||||||
|
if (session_data_p->verdict == TRAFFIC_VERDICT_DELAYED) {
|
||||||
|
write_dbg(attachment, session_id, DBG_LEVEL_DEBUG, "spawn SendDelayedVerdictRequestThread");
|
||||||
|
res = NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
data,
|
||||||
|
SendDelayedVerdictRequestThread,
|
||||||
|
(void *)&ctx,
|
||||||
|
attachment->waiting_for_verdict_thread_timeout_msec,
|
||||||
|
"SendDelayedVerdictRequestThread",
|
||||||
|
REQUEST
|
||||||
|
);
|
||||||
|
if (!res) {
|
||||||
|
updateMetricField(attachment, HOLD_THREAD_TIMEOUT, 1);
|
||||||
|
return SendThreadTimeoutVerdict(attachment, session_id, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"finished SendDelayedVerdictRequestThread successfully. res=%d",
|
||||||
|
ctx.res
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.res != NANO_HTTP_FORBIDDEN && ctx.res != NANO_OK) {
|
||||||
|
return FinalizeFailedResponse(attachment, session_id, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FinalizeSuccessfulResponse(attachment, session_id, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
AttachmentVerdictResponse
|
||||||
|
SendResponseHeaders(NanoAttachment *attachment, AttachmentData *data)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx ctx;
|
||||||
|
HttpSessionData *session_data_p = data->session_data;
|
||||||
|
SessionID session_id = session_data_p->session_id;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"Response header handling session ID: %d",
|
||||||
|
session_id
|
||||||
|
);
|
||||||
|
|
||||||
|
if (handle_shmem_corruption(attachment) == NANO_ERROR) {
|
||||||
|
return SendCorruptMemoryVerdict(attachment, session_data_p);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(attachment, session_id, DBG_LEVEL_DEBUG, "spawn SendResponseHeadersThread");
|
||||||
|
res = NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
data,
|
||||||
|
SendResponseHeadersThread,
|
||||||
|
(void *)&ctx,
|
||||||
|
attachment->res_header_thread_timeout_msec,
|
||||||
|
"SendResponseHeadersThread",
|
||||||
|
RESPONSE
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!res) {
|
||||||
|
updateMetricField(attachment, RES_HEADER_THREAD_TIMEOUT, 1);
|
||||||
|
return SendThreadTimeoutVerdict(attachment, session_id, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"finished SendResponseHeadersThread successfully. res=%d",
|
||||||
|
ctx.res
|
||||||
|
);
|
||||||
|
|
||||||
|
if (ctx.res != NANO_HTTP_FORBIDDEN && ctx.res != NANO_OK) {
|
||||||
|
return FinalizeFailedResponse(attachment, session_id, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FinalizeSuccessfulResponse(attachment, session_id, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
AttachmentVerdictResponse
|
||||||
|
SendRequestBody(NanoAttachment *attachment, AttachmentData *data)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx ctx;
|
||||||
|
HttpSessionData *session_data_p = data->session_data;
|
||||||
|
SessionID session_id = session_data_p->session_id;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
write_dbg(attachment, session_id, DBG_LEVEL_DEBUG, "Request body handling session ID: %d", session_id);
|
||||||
|
|
||||||
|
if (handle_shmem_corruption(attachment) == NANO_ERROR) {
|
||||||
|
return SendCorruptMemoryVerdict(attachment, session_data_p);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(attachment, session_id, DBG_LEVEL_DEBUG, "spawn SendRequestBodyThread");
|
||||||
|
res = NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
data,
|
||||||
|
SendRequestBodyThread,
|
||||||
|
(void *)&ctx,
|
||||||
|
attachment->req_body_thread_timeout_msec,
|
||||||
|
"SendRequestBodyThread",
|
||||||
|
REQUEST
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!res) {
|
||||||
|
updateMetricField(attachment, REQ_BODY_THREAD_TIMEOUT, 1);
|
||||||
|
return SendThreadTimeoutVerdict(attachment, session_id, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"finished SendRequestBodyThread successfully. res=%d",
|
||||||
|
ctx.res
|
||||||
|
);
|
||||||
|
|
||||||
|
if (session_data_p->verdict == TRAFFIC_VERDICT_DELAYED) {
|
||||||
|
write_dbg(attachment, session_id, DBG_LEVEL_DEBUG, "spawn SendDelayedVerdictRequestThread");
|
||||||
|
res = NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
data,
|
||||||
|
SendDelayedVerdictRequestThread,
|
||||||
|
(void *)&ctx,
|
||||||
|
attachment->waiting_for_verdict_thread_timeout_msec,
|
||||||
|
"SendDelayedVerdictRequestThread",
|
||||||
|
REQUEST
|
||||||
|
);
|
||||||
|
if (!res) {
|
||||||
|
updateMetricField(attachment, HOLD_THREAD_TIMEOUT, 1);
|
||||||
|
return SendThreadTimeoutVerdict(attachment, session_id, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"finished SendDelayedVerdictRequestThread successfully. res=%d",
|
||||||
|
ctx.res
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.res != NANO_HTTP_FORBIDDEN && ctx.res != NANO_OK) {
|
||||||
|
return FinalizeFailedResponse(attachment, session_id, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FinalizeSuccessfulResponse(attachment, session_id, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
AttachmentVerdictResponse
|
||||||
|
SendResponseBody(NanoAttachment *attachment, AttachmentData *data)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx ctx;
|
||||||
|
HttpSessionData *session_data_p = data->session_data;
|
||||||
|
SessionID session_id = session_data_p->session_id;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
write_dbg(attachment, session_id, DBG_LEVEL_DEBUG, "Response body handling session ID: %d", session_id);
|
||||||
|
|
||||||
|
if (handle_shmem_corruption(attachment) == NANO_ERROR) {
|
||||||
|
return SendCorruptMemoryVerdict(attachment, session_data_p);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(attachment, session_id, DBG_LEVEL_DEBUG, "spawn SendResponseBodyThread");
|
||||||
|
res = NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
data,
|
||||||
|
SendResponseBodyThread,
|
||||||
|
(void *)&ctx,
|
||||||
|
attachment->res_body_thread_timeout_msec,
|
||||||
|
"SendResponseBodyThread",
|
||||||
|
RESPONSE
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!res) {
|
||||||
|
updateMetricField(attachment, RES_BODY_THREAD_TIMEOUT, 1);
|
||||||
|
return SendThreadTimeoutVerdict(attachment, session_id, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"finished SendResponseBodyThread successfully. res=%d",
|
||||||
|
ctx.res
|
||||||
|
);
|
||||||
|
|
||||||
|
if (ctx.res != NANO_HTTP_FORBIDDEN && ctx.res != NANO_OK) {
|
||||||
|
return FinalizeFailedResponse(attachment, session_id, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FinalizeSuccessfulResponse(attachment, session_id, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
AttachmentVerdictResponse
|
||||||
|
SendRequestEnd(NanoAttachment *attachment, AttachmentData *data)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx ctx;
|
||||||
|
HttpSessionData *session_data_p = data->session_data;
|
||||||
|
SessionID session_id = session_data_p->session_id;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"Request end handling session ID: %d",
|
||||||
|
session_id
|
||||||
|
);
|
||||||
|
|
||||||
|
if (handle_shmem_corruption(attachment) == NANO_ERROR) {
|
||||||
|
return SendCorruptMemoryVerdict(attachment, session_data_p);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(attachment, session_id, DBG_LEVEL_DEBUG, "spawn SendRequestEndThread");
|
||||||
|
res = NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
data,
|
||||||
|
SendRequestEndThread,
|
||||||
|
(void *)&ctx,
|
||||||
|
attachment->req_header_thread_timeout_msec,
|
||||||
|
"SendRequestEndThread",
|
||||||
|
REQUEST
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!res) {
|
||||||
|
updateMetricField(attachment, REQ_END_THREAD_TIMEOUT, 1);
|
||||||
|
return SendThreadTimeoutVerdict(attachment, session_id, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"finished SendRequestEndThread successfully. res=%d",
|
||||||
|
ctx.res
|
||||||
|
);
|
||||||
|
|
||||||
|
if (ctx.res != NANO_HTTP_FORBIDDEN && ctx.res != NANO_OK) {
|
||||||
|
return FinalizeFailedResponse(attachment, session_id, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FinalizeSuccessfulResponse(attachment, session_id, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
AttachmentVerdictResponse
|
||||||
|
SendResponseEnd(NanoAttachment *attachment, AttachmentData *data)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx ctx;
|
||||||
|
HttpSessionData *session_data_p = data->session_data;
|
||||||
|
SessionID session_id = session_data_p->session_id;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"Response end handling session ID: %d",
|
||||||
|
session_id
|
||||||
|
);
|
||||||
|
|
||||||
|
if (handle_shmem_corruption(attachment) == NANO_ERROR) {
|
||||||
|
return SendCorruptMemoryVerdict(attachment, session_data_p);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(attachment, session_id, DBG_LEVEL_DEBUG, "spawn SendResponseEndThread");
|
||||||
|
res = NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
data,
|
||||||
|
SendResponseEndThread,
|
||||||
|
(void *)&ctx,
|
||||||
|
attachment->req_header_thread_timeout_msec,
|
||||||
|
"SendResponseEndThread",
|
||||||
|
RESPONSE
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!res) {
|
||||||
|
updateMetricField(attachment, RES_END_THREAD_TIMEOUT, 1);
|
||||||
|
return SendThreadTimeoutVerdict(attachment, session_id, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"finished SendResponseEndThread successfully. res=%d",
|
||||||
|
ctx.res
|
||||||
|
);
|
||||||
|
|
||||||
|
if (ctx.res != NANO_HTTP_FORBIDDEN && ctx.res != NANO_OK) {
|
||||||
|
return FinalizeFailedResponse(attachment, session_id, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FinalizeSuccessfulResponse(attachment, session_id, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
NanoCommunicationResult
|
||||||
|
SendMetricData(NanoAttachment *attachment)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx ctx;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
0,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"Sending metric data saved in worker ID: %d",
|
||||||
|
attachment->worker_id
|
||||||
|
);
|
||||||
|
|
||||||
|
if (handle_shmem_corruption(attachment) == NANO_ERROR) {
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
0,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"Failed to send metric data, shmem corruption Worker ID: %d",
|
||||||
|
attachment->worker_id
|
||||||
|
);
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
NULL,
|
||||||
|
SendMetricToServiceThread,
|
||||||
|
(void *)&ctx,
|
||||||
|
attachment->metric_timeout_timeout,
|
||||||
|
"SendMetricToServiceThread",
|
||||||
|
METRICS
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!res) {
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
0,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"Thread timeout while sending metric data from worker ID: %d",
|
||||||
|
attachment->worker_id
|
||||||
|
);
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NANO_OK;
|
||||||
|
}
|
137
attachments/nano_attachment/nano_attachment_sender.h
Normal file
137
attachments/nano_attachment/nano_attachment_sender.h
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
#ifndef __NANO_ATTACHMENT_SENDER_H__
|
||||||
|
#define __NANO_ATTACHMENT_SENDER_H__
|
||||||
|
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "nano_initializer.h"
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends start request data to the nano service.
|
||||||
|
///
|
||||||
|
/// This function handles the sending of starting meta data, request headers and end request to the nano service.
|
||||||
|
/// It creates a new thread to perform the sending operation, ensuring that the main execution flow
|
||||||
|
/// is not blocked. It also handles potential errors and timeouts that may occur during
|
||||||
|
/// the sending process.
|
||||||
|
///
|
||||||
|
/// @param attachment A pointer to the NanoAttachment structure.
|
||||||
|
/// @param data A pointer to AttachmentData structure containing the data to send and the session data.
|
||||||
|
///
|
||||||
|
/// @return An AttachmentVerdictResponse structure indicating the outcome of the operation.
|
||||||
|
///
|
||||||
|
AttachmentVerdictResponse SendRequestFilter(NanoAttachment *attachment, AttachmentData *data);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends start request data to the nano service.
|
||||||
|
///
|
||||||
|
/// This function handles the sending of starting meta data to the nano service. It creates
|
||||||
|
/// a new thread to perform the sending operation, ensuring that the main execution flow
|
||||||
|
/// is not blocked. It also handles potential errors and timeouts that may occur during
|
||||||
|
/// the sending process.
|
||||||
|
///
|
||||||
|
/// @param attachment A pointer to the NanoAttachment structure.
|
||||||
|
/// @param data A pointer to AttachmentData structure containing the data to send and the session data.
|
||||||
|
///
|
||||||
|
/// @return An AttachmentVerdictResponse structure indicating the outcome of the operation.
|
||||||
|
///
|
||||||
|
AttachmentVerdictResponse SendMetadata(NanoAttachment *attachment, AttachmentData *data);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends request headers to the nano service.
|
||||||
|
///
|
||||||
|
/// This function handles the sending of request headers to the nano service. It creates
|
||||||
|
/// a new thread to perform the sending operation, ensuring that the main execution flow
|
||||||
|
/// is not blocked. It also handles potential errors and timeouts that may occur during
|
||||||
|
/// the sending process.
|
||||||
|
///
|
||||||
|
/// @param attachment A pointer to the NanoAttachment structure.
|
||||||
|
/// @param data A pointer to AttachmentData structure containing the headers to send and the session data.
|
||||||
|
///
|
||||||
|
/// @return An AttachmentVerdictResponse structure indicating the outcome of the operation.
|
||||||
|
///
|
||||||
|
AttachmentVerdictResponse SendRequestHeaders(NanoAttachment *attachment, AttachmentData *data);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends response headers to the nano service.
|
||||||
|
///
|
||||||
|
/// This function handles the sending of response headers to the nano service. It creates
|
||||||
|
/// a new thread to perform the sending operation, ensuring that the main execution flow
|
||||||
|
/// is not blocked. It also handles potential errors and timeouts that may occur during
|
||||||
|
/// the sending process.
|
||||||
|
///
|
||||||
|
/// @param attachment A pointer to the NanoAttachment structure.
|
||||||
|
/// @param data A pointer to AttachmentData structure containing the headers to send and the session data.
|
||||||
|
///
|
||||||
|
/// @return An AttachmentVerdictResponse structure indicating the outcome of the operation.
|
||||||
|
///
|
||||||
|
AttachmentVerdictResponse SendResponseHeaders(NanoAttachment *attachment, AttachmentData *data);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends request body to the nano service.
|
||||||
|
///
|
||||||
|
/// This function handles the sending of request body to the nano service. It creates
|
||||||
|
/// a new thread to perform the sending operation, ensuring that the main execution flow
|
||||||
|
/// is not blocked. It also handles potential errors and timeouts that may occur during
|
||||||
|
/// the sending process.
|
||||||
|
///
|
||||||
|
/// @param attachment A pointer to the NanoAttachment structure.
|
||||||
|
/// @param data A pointer to AttachmentData structure containing the body to send and the session data.
|
||||||
|
///
|
||||||
|
/// @return An AttachmentVerdictResponse structure indicating the outcome of the operation.
|
||||||
|
///
|
||||||
|
AttachmentVerdictResponse SendRequestBody(NanoAttachment *attachment, AttachmentData *data);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends response body to the nano service.
|
||||||
|
///
|
||||||
|
/// This function handles the sending of response body to the nano service. It creates
|
||||||
|
/// a new thread to perform the sending operation, ensuring that the main execution flow
|
||||||
|
/// is not blocked. It also handles potential errors and timeouts that may occur during
|
||||||
|
/// the sending process.
|
||||||
|
///
|
||||||
|
/// @param attachment A pointer to the NanoAttachment structure.
|
||||||
|
/// @param data A pointer to AttachmentData structure containing the body to send and the session data.
|
||||||
|
///
|
||||||
|
/// @return An AttachmentVerdictResponse structure indicating the outcome of the operation.
|
||||||
|
///
|
||||||
|
AttachmentVerdictResponse SendResponseBody(NanoAttachment *attachment, AttachmentData *data);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends end request signal to the nano service.
|
||||||
|
///
|
||||||
|
/// This function handles the sending a request end signal to the nano service. It creates
|
||||||
|
/// a new thread to perform the sending operation, ensuring that the main execution flow
|
||||||
|
/// is not blocked. It also handles potential errors and timeouts that may occur during
|
||||||
|
/// the sending process.
|
||||||
|
///
|
||||||
|
/// @param attachment A pointer to the NanoAttachment structure.
|
||||||
|
/// @param data A pointer to AttachmentData structure containing the necessery data to send and the session data.
|
||||||
|
///
|
||||||
|
/// @return An AttachmentVerdictResponse structure indicating the outcome of the operation.
|
||||||
|
///
|
||||||
|
AttachmentVerdictResponse SendRequestEnd(NanoAttachment *attachment, AttachmentData *data);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends end response signal to the nano service.
|
||||||
|
///
|
||||||
|
/// This function handles the sending a response end signal to the nano service. It creates
|
||||||
|
/// a new thread to perform the sending operation, ensuring that the main execution flow
|
||||||
|
/// is not blocked. It also handles potential errors and timeouts that may occur during
|
||||||
|
/// the sending process.
|
||||||
|
///
|
||||||
|
/// @param attachment A pointer to the NanoAttachment structure.
|
||||||
|
/// @param data A pointer to AttachmentData structure containing the necessery data to send and the session data.
|
||||||
|
///
|
||||||
|
/// @return An AttachmentVerdictResponse structure indicating the outcome of the operation.
|
||||||
|
///
|
||||||
|
AttachmentVerdictResponse SendResponseEnd(NanoAttachment *attachment, AttachmentData *data);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends metric data to the nano service and resets it on the attachment.
|
||||||
|
///
|
||||||
|
/// @param attachment A pointer to the NanoAttachment structure that contains metrics data.
|
||||||
|
///
|
||||||
|
/// @return An NanoCommunication enum indicating the outcome of the operation.
|
||||||
|
/// NANO_OK if the operation was successful, NANO_ERROR otherwise.
|
||||||
|
///
|
||||||
|
NanoCommunicationResult SendMetricData(NanoAttachment *attachment);
|
||||||
|
|
||||||
|
#endif // __NANO_ATTACHMENT_SENDER_H__
|
269
attachments/nano_attachment/nano_attachment_sender_thread.c
Normal file
269
attachments/nano_attachment/nano_attachment_sender_thread.c
Normal file
@ -0,0 +1,269 @@
|
|||||||
|
#include "nano_attachment_sender_thread.h"
|
||||||
|
|
||||||
|
#include "nano_initializer.h"
|
||||||
|
#include "nano_attachment_sender.h"
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "nano_attachment_io.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
init_thread_ctx(HttpEventThreadCtx *ctx, NanoAttachment *attachment, AttachmentData *data)
|
||||||
|
{
|
||||||
|
ctx->attachment = attachment;
|
||||||
|
ctx->data = data;
|
||||||
|
ctx->session_data_p = (data == NULL) ? NULL : data->session_data;
|
||||||
|
ctx->res = NANO_OK;
|
||||||
|
ctx->web_response_data = NULL;
|
||||||
|
ctx->modifications = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
RegistrationCommSocketThread(void *_ctx)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx *ctx = (HttpEventThreadCtx *)_ctx;
|
||||||
|
NanoAttachment *attachment = ctx->attachment;
|
||||||
|
|
||||||
|
ctx->res = connect_to_comm_socket(attachment);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
RegistrationSocketThread(void *_ctx)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx *ctx = (HttpEventThreadCtx *)_ctx;
|
||||||
|
NanoAttachment *attachment = ctx->attachment;
|
||||||
|
|
||||||
|
ctx->res = connect_to_registration_socket(attachment);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
SendRequestFilterThread(void *_ctx)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx *ctx = (HttpEventThreadCtx *)_ctx;
|
||||||
|
|
||||||
|
HttpRequestFilterData *start_data = (HttpRequestFilterData*)ctx->data->data;
|
||||||
|
HttpMetaData *metadata = start_data->meta_data;
|
||||||
|
HttpHeaders *headers = start_data->req_headers;
|
||||||
|
bool contains_body = start_data->contains_body;
|
||||||
|
NanoAttachment *attachment = ctx->attachment;
|
||||||
|
HttpSessionData *session_data_p = ctx->session_data_p;
|
||||||
|
bool is_verdict_requested = false;
|
||||||
|
|
||||||
|
nano_metadata_sender(
|
||||||
|
attachment,
|
||||||
|
metadata,
|
||||||
|
ctx,
|
||||||
|
session_data_p->session_id,
|
||||||
|
&session_data_p->remaining_messages_to_reply,
|
||||||
|
is_verdict_requested
|
||||||
|
);
|
||||||
|
|
||||||
|
nano_header_sender(
|
||||||
|
attachment,
|
||||||
|
headers,
|
||||||
|
ctx,
|
||||||
|
REQUEST_HEADER,
|
||||||
|
session_data_p->session_id,
|
||||||
|
&session_data_p->remaining_messages_to_reply,
|
||||||
|
is_verdict_requested
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!contains_body) {
|
||||||
|
nano_end_transaction_sender(
|
||||||
|
attachment,
|
||||||
|
REQUEST_END,
|
||||||
|
ctx,
|
||||||
|
session_data_p->session_id,
|
||||||
|
&session_data_p->remaining_messages_to_reply
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
SendMetadataThread(void *_ctx)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx *ctx = (HttpEventThreadCtx *)_ctx;
|
||||||
|
HttpMetaData *metadata = (HttpMetaData*)ctx->data->data;
|
||||||
|
NanoAttachment *attachment = ctx->attachment;
|
||||||
|
HttpSessionData *session_data_p = ctx->session_data_p;
|
||||||
|
bool is_verdict_requested = false;
|
||||||
|
|
||||||
|
nano_metadata_sender(
|
||||||
|
attachment,
|
||||||
|
metadata,
|
||||||
|
ctx,
|
||||||
|
session_data_p->session_id,
|
||||||
|
&session_data_p->remaining_messages_to_reply,
|
||||||
|
is_verdict_requested
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
SendRequestHeadersThread(void *_ctx)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx *ctx = (HttpEventThreadCtx *)_ctx;
|
||||||
|
HttpHeaders *headers = (HttpHeaders*)ctx->data->data;
|
||||||
|
NanoAttachment *attachment = ctx->attachment;
|
||||||
|
HttpSessionData *session_data_p = ctx->session_data_p;
|
||||||
|
bool is_verdict_requested = false;
|
||||||
|
|
||||||
|
nano_header_sender(
|
||||||
|
attachment,
|
||||||
|
headers,
|
||||||
|
ctx,
|
||||||
|
REQUEST_HEADER,
|
||||||
|
session_data_p->session_id,
|
||||||
|
&session_data_p->remaining_messages_to_reply,
|
||||||
|
is_verdict_requested
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
SendResponseHeadersThread(void *_ctx)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx *ctx = (HttpEventThreadCtx *)_ctx;
|
||||||
|
ResHttpHeaders *headers = (ResHttpHeaders*)ctx->data->data;
|
||||||
|
NanoAttachment *attachment = ctx->attachment;
|
||||||
|
HttpSessionData *session_data_p = ctx->session_data_p;
|
||||||
|
HttpHeaders *http_headers = headers->headers;
|
||||||
|
bool is_verdict_requested = false;
|
||||||
|
|
||||||
|
nano_send_response_code(
|
||||||
|
attachment,
|
||||||
|
headers->response_code,
|
||||||
|
ctx,
|
||||||
|
session_data_p->session_id,
|
||||||
|
&session_data_p->remaining_messages_to_reply
|
||||||
|
);
|
||||||
|
|
||||||
|
nano_send_response_content_length(
|
||||||
|
attachment,
|
||||||
|
headers->content_length,
|
||||||
|
ctx,
|
||||||
|
session_data_p->session_id,
|
||||||
|
&session_data_p->remaining_messages_to_reply
|
||||||
|
);
|
||||||
|
|
||||||
|
nano_header_sender(
|
||||||
|
attachment,
|
||||||
|
http_headers,
|
||||||
|
ctx,
|
||||||
|
RESPONSE_HEADER,
|
||||||
|
session_data_p->session_id,
|
||||||
|
&session_data_p->remaining_messages_to_reply,
|
||||||
|
is_verdict_requested
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
SendRequestBodyThread(void *_ctx)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx *ctx = (HttpEventThreadCtx *)_ctx;
|
||||||
|
HttpBody *bodies = (HttpBody*)ctx->data->data;
|
||||||
|
NanoAttachment *attachment = ctx->attachment;
|
||||||
|
HttpSessionData *session_data_p = ctx->session_data_p;
|
||||||
|
|
||||||
|
nano_body_sender(
|
||||||
|
attachment,
|
||||||
|
bodies,
|
||||||
|
ctx,
|
||||||
|
REQUEST_BODY,
|
||||||
|
session_data_p->session_id,
|
||||||
|
&session_data_p->remaining_messages_to_reply
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
SendResponseBodyThread(void *_ctx)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx *ctx = (HttpEventThreadCtx *)_ctx;
|
||||||
|
HttpBody *bodies = (HttpBody*)ctx->data->data;
|
||||||
|
NanoAttachment *attachment = ctx->attachment;
|
||||||
|
HttpSessionData *session_data_p = ctx->session_data_p;
|
||||||
|
|
||||||
|
nano_body_sender(
|
||||||
|
attachment,
|
||||||
|
bodies,
|
||||||
|
ctx,
|
||||||
|
RESPONSE_BODY,
|
||||||
|
session_data_p->session_id,
|
||||||
|
&session_data_p->remaining_messages_to_reply
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
SendRequestEndThread(void *_ctx)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx *ctx = (HttpEventThreadCtx *)_ctx;
|
||||||
|
NanoAttachment *attachment = ctx->attachment;
|
||||||
|
HttpSessionData *session_data_p = ctx->session_data_p;
|
||||||
|
|
||||||
|
nano_end_transaction_sender(
|
||||||
|
attachment,
|
||||||
|
REQUEST_END,
|
||||||
|
ctx,
|
||||||
|
session_data_p->session_id,
|
||||||
|
&session_data_p->remaining_messages_to_reply
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
SendResponseEndThread(void *_ctx)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx *ctx = (HttpEventThreadCtx *)_ctx;
|
||||||
|
NanoAttachment *attachment = ctx->attachment;
|
||||||
|
HttpSessionData *session_data_p = ctx->session_data_p;
|
||||||
|
|
||||||
|
nano_end_transaction_sender(
|
||||||
|
attachment,
|
||||||
|
RESPONSE_END,
|
||||||
|
ctx,
|
||||||
|
session_data_p->session_id,
|
||||||
|
&session_data_p->remaining_messages_to_reply
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
SendDelayedVerdictRequestThread(void *_ctx)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx *ctx = (HttpEventThreadCtx *)_ctx;
|
||||||
|
NanoAttachment *attachment = ctx->attachment;
|
||||||
|
HttpSessionData *session_data_p = ctx->session_data_p;
|
||||||
|
|
||||||
|
nano_request_delayed_verdict(
|
||||||
|
attachment,
|
||||||
|
ctx,
|
||||||
|
session_data_p->session_id,
|
||||||
|
&session_data_p->remaining_messages_to_reply
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
SendMetricToServiceThread(void *_data)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx *ctx = (HttpEventThreadCtx *)_data;
|
||||||
|
NanoAttachment *attachment = ctx->attachment;
|
||||||
|
|
||||||
|
nano_send_metric_data_sender(attachment);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
178
attachments/nano_attachment/nano_attachment_sender_thread.h
Normal file
178
attachments/nano_attachment/nano_attachment_sender_thread.h
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
#ifndef __NANO_ATTACHMENT_SENDER_THREAD_H__
|
||||||
|
#define __NANO_ATTACHMENT_SENDER_THREAD_H__
|
||||||
|
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "nano_initializer.h"
|
||||||
|
|
||||||
|
/// @struct HttpEventThreadCtx
|
||||||
|
/// @brief Holds all the information needed to communicate with the attachment service.
|
||||||
|
typedef struct HttpEventThreadCtx
|
||||||
|
{
|
||||||
|
NanoAttachment *attachment; ///< NanoAttachment.
|
||||||
|
AttachmentData *data; ///< Attachment data.
|
||||||
|
HttpSessionData *session_data_p; ///< Provided session data.
|
||||||
|
|
||||||
|
/// Connection results with the attachment service
|
||||||
|
/// - #NANO_OK
|
||||||
|
/// - #NANO_ERROR
|
||||||
|
NanoCommunicationResult res;
|
||||||
|
|
||||||
|
WebResponseData *web_response_data; ///< Web response data.
|
||||||
|
NanoHttpModificationList *modifications; ///< Context's modification.
|
||||||
|
} HttpEventThreadCtx;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Initializes a thread context structure for an NANO event thread.
|
||||||
|
///
|
||||||
|
/// This function initializes a thread context structure with the provided data
|
||||||
|
/// and default values for other fields.
|
||||||
|
///
|
||||||
|
/// @param ctx A pointer to a struct HttpEventThreadCtx structure representing the thread context to initialize.
|
||||||
|
/// @param attachment A pointer to a NanoAttachment structure representing the attachment data for the thread.
|
||||||
|
/// @param data A pointer to an AttachmentData structure representing the attachment data for the thread.
|
||||||
|
///
|
||||||
|
void
|
||||||
|
init_thread_ctx(HttpEventThreadCtx *ctx, NanoAttachment *attachment, AttachmentData *data);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Connect attachment communication socket to the nano service.
|
||||||
|
///
|
||||||
|
/// @param _ctx A pointer to the HttpEventThreadCtx context.
|
||||||
|
///
|
||||||
|
/// @return NULL.
|
||||||
|
///
|
||||||
|
void * RegistrationCommSocketThread(void *_ctx);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Connect attachment to registration socket to the nano service.
|
||||||
|
///
|
||||||
|
/// @param _ctx A pointer to the HttpEventThreadCtx context.
|
||||||
|
///
|
||||||
|
/// @return NULL.
|
||||||
|
///
|
||||||
|
void * RegistrationSocketThread(void *_ctx);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends request start data to the nano service.
|
||||||
|
///
|
||||||
|
/// This thread function sends metadata to start a request interaction with the nano service.
|
||||||
|
///
|
||||||
|
/// @param _ctx A pointer to the HttpEventThreadCtx context.
|
||||||
|
///
|
||||||
|
/// @return NULL.
|
||||||
|
///
|
||||||
|
void * SendMetadataThread(void *_ctx);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends request headers to the nano service.
|
||||||
|
///
|
||||||
|
/// This thread function sends request headers to the nano service using the provided
|
||||||
|
/// HttpEventThreadCtx context. It updates the session data and handles any
|
||||||
|
/// errors that occur during the header sending process.
|
||||||
|
///
|
||||||
|
/// @param _ctx A pointer to the HttpEventThreadCtx context.
|
||||||
|
///
|
||||||
|
/// @return NULL.
|
||||||
|
///
|
||||||
|
void * SendRequestHeadersThread(void *_ctx);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends response headers to the nano service.
|
||||||
|
///
|
||||||
|
/// This thread function sends response headers to the nano service using the provided
|
||||||
|
/// HttpEventThreadCtx context. It updates the session data and handles any
|
||||||
|
/// errors that occur during the header sending process.
|
||||||
|
///
|
||||||
|
/// @param _ctx A pointer to the HttpEventThreadCtx context.
|
||||||
|
///
|
||||||
|
/// @return NULL.
|
||||||
|
///
|
||||||
|
void * SendResponseHeadersThread(void *_ctx);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends request body to the nano service.
|
||||||
|
///
|
||||||
|
/// This thread function sends request body to the nano service using the provided
|
||||||
|
/// HttpEventThreadCtx context. It updates the session data and handles any
|
||||||
|
/// errors that occur during the body sending process.
|
||||||
|
///
|
||||||
|
/// @param _ctx A pointer to the HttpEventThreadCtx context.
|
||||||
|
///
|
||||||
|
/// @return NULL.
|
||||||
|
///
|
||||||
|
void * SendRequestBodyThread(void *_ctx);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends response body to the nano service.
|
||||||
|
///
|
||||||
|
/// This thread function sends response body to the nano service using the provided
|
||||||
|
/// HttpEventThreadCtx context. It updates the session data and handles any
|
||||||
|
/// errors that occur during the body sending process.
|
||||||
|
///
|
||||||
|
/// @param _ctx A pointer to the HttpEventThreadCtx context.
|
||||||
|
///
|
||||||
|
/// @return NULL.
|
||||||
|
///
|
||||||
|
void * SendResponseBodyThread(void *_ctx);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends request end data to the nano service.
|
||||||
|
///
|
||||||
|
/// This thread function sends signal to the nano service that the response has ended
|
||||||
|
/// and with it the whole session transaction.
|
||||||
|
///
|
||||||
|
/// @param _ctx A pointer to the HttpEventThreadCtx context.
|
||||||
|
///
|
||||||
|
/// @return NULL.
|
||||||
|
///
|
||||||
|
void * SendRequestEndThread(void *_ctx);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sends response end data to the nano service.
|
||||||
|
///
|
||||||
|
/// This thread function sends signal to the nano service that the response has ended
|
||||||
|
/// and with it the whole session transaction.
|
||||||
|
///
|
||||||
|
/// @param _ctx A pointer to the HttpEventThreadCtx context.
|
||||||
|
///
|
||||||
|
/// @return NULL.
|
||||||
|
///
|
||||||
|
void * SendResponseEndThread(void *_ctx);
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Thread function to send request filters.
|
||||||
|
///
|
||||||
|
/// This thread function sends metadata, request headers and end request
|
||||||
|
/// to the nano service using the provided HttpEventThreadCtx context.
|
||||||
|
/// It updates the session data and handles any errors that occur during the header sending process.
|
||||||
|
///
|
||||||
|
/// @param _ctx A pointer to the HttpEventThreadCtx context.
|
||||||
|
///
|
||||||
|
/// @return NULL
|
||||||
|
///
|
||||||
|
void * SendRequestFilterThread(void *_ctx);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Send query for requesting delayed data verdict.
|
||||||
|
///
|
||||||
|
/// This thread function sends a delayed data query to the service and waits for the response.
|
||||||
|
///
|
||||||
|
/// @param _ctx A pointer to the HttpEventThreadCtx context.
|
||||||
|
///
|
||||||
|
/// @return NULL.
|
||||||
|
///
|
||||||
|
void * SendDelayedVerdictRequestThread(void *_ctx);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Send data metric fo the service.
|
||||||
|
///
|
||||||
|
/// This thread function sends data metric to the service and resets it.
|
||||||
|
///
|
||||||
|
/// @param _ctx A pointer to the HttpEventThreadCtx context.
|
||||||
|
///
|
||||||
|
/// @return NULL.
|
||||||
|
///
|
||||||
|
void * SendMetricToServiceThread(void *_data);
|
||||||
|
|
||||||
|
#endif // __NANO_ATTACHMENT_SENDER_THREAD_H__
|
233
attachments/nano_attachment/nano_attachment_thread.c
Normal file
233
attachments/nano_attachment/nano_attachment_thread.c
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
#include "nano_attachment_thread.h"
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "nano_attachment_sender.h"
|
||||||
|
#include "nano_attachment_sender_thread.h"
|
||||||
|
#include "nano_utils.h"
|
||||||
|
#include "nano_attachment_metric.h"
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Calculate the processing time of a transaction and update the session data accordingly.
|
||||||
|
///
|
||||||
|
/// @param session_data_p Pointer to the HttpSessionData struct containing session data.
|
||||||
|
/// @param thread_time_begin Pointer to the timespec struct representing the start time of the transaction.
|
||||||
|
/// @param transaction_type The type of transaction (REQUEST or RESPONSE).
|
||||||
|
///
|
||||||
|
static void
|
||||||
|
CalcProcessingTime(
|
||||||
|
HttpSessionData *session_data_p,
|
||||||
|
struct timespec *thread_time_begin,
|
||||||
|
TransactionType transaction_type
|
||||||
|
)
|
||||||
|
{
|
||||||
|
struct timespec thread_time_end;
|
||||||
|
|
||||||
|
if (transaction_type == START || transaction_type == METRICS) return;
|
||||||
|
|
||||||
|
clock_gettime(CLOCK_REALTIME, &thread_time_end);
|
||||||
|
|
||||||
|
double begin_usec = (thread_time_begin->tv_sec * 1000 * 1000) + (thread_time_begin->tv_nsec / 1000);
|
||||||
|
double end_usec = (thread_time_end.tv_sec * 1000 * 1000) + (thread_time_end.tv_nsec / 1000);
|
||||||
|
double elapsed = end_usec - begin_usec;
|
||||||
|
if (transaction_type == REQUEST) {
|
||||||
|
session_data_p->req_proccesing_time += elapsed;
|
||||||
|
} else {
|
||||||
|
session_data_p->res_proccesing_time += elapsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief runs the provided routine with the arguments in a non thread and without a timeout.
|
||||||
|
/// @param[in, out] attachment A pointer to the NanoAttachment struct.
|
||||||
|
/// @param[in] session_id The session ID.
|
||||||
|
/// @param[in, out] thread_func A pointer to the provided routine to run in a thread.
|
||||||
|
/// @param[in, out] arg Routine's arguments.
|
||||||
|
/// @param[in, out] func_name Called thread timeout.
|
||||||
|
/// @returns 1
|
||||||
|
///
|
||||||
|
int
|
||||||
|
NanoRunInWithoutThreadTimeout(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
SessionID session_id,
|
||||||
|
CpThreadRoutine thread_func,
|
||||||
|
void *arg,
|
||||||
|
char *func_name
|
||||||
|
)
|
||||||
|
{
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_TRACE,
|
||||||
|
"Executing cb in blocking mode, fn=%s",
|
||||||
|
func_name
|
||||||
|
);
|
||||||
|
|
||||||
|
thread_func(arg);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
NanoRunInThreadTimeout(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
AttachmentData *data,
|
||||||
|
CpThreadRoutine thread_func,
|
||||||
|
void *arg,
|
||||||
|
int timeout_msecs,
|
||||||
|
char *func_name,
|
||||||
|
TransactionType transaction_type
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int status = 0;
|
||||||
|
int ret = 0;
|
||||||
|
void *res = NULL;
|
||||||
|
pthread_t thread;
|
||||||
|
struct timespec ts;
|
||||||
|
struct timespec thread_time_begin;
|
||||||
|
uint32_t session_id;
|
||||||
|
HttpEventThreadCtx *ctx = (HttpEventThreadCtx *)arg;
|
||||||
|
|
||||||
|
session_id = (data == NULL) ? attachment->worker_id : data->session_data->session_id;
|
||||||
|
init_thread_ctx(ctx, attachment, data);
|
||||||
|
|
||||||
|
if (attachment->inspection_mode == NO_THREAD) {
|
||||||
|
return NanoRunInWithoutThreadTimeout(attachment, session_id, thread_func, arg, func_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clock_gettime(CLOCK_REALTIME, &thread_time_begin) == -1) {
|
||||||
|
updateMetricField(attachment, THREAD_FAILURE, 1);
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_ERROR,
|
||||||
|
"clock_gettime(CLOCK_REALTIME) failed. Status: %s",
|
||||||
|
strerror(errno)
|
||||||
|
);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runs the routine in a dedicated thread.
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_TRACE,
|
||||||
|
"Executing cb in dedicated thread, fn=%s",
|
||||||
|
func_name
|
||||||
|
);
|
||||||
|
|
||||||
|
if (pthread_create(&thread, NULL, thread_func, arg) != 0) {
|
||||||
|
updateMetricField(attachment, THREAD_FAILURE, 1);
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_TRACE,
|
||||||
|
"pthread_create failed with errno=%d, fn=%s",
|
||||||
|
errno,
|
||||||
|
func_name
|
||||||
|
);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attachment->inspection_mode == BLOCKING_THREAD) {
|
||||||
|
// Runs the function in a blocking thread.
|
||||||
|
status = pthread_join(thread, &res);
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_TRACE,
|
||||||
|
"pthread_join returned from blocking call. status=%d, fn=%s",
|
||||||
|
status,
|
||||||
|
func_name
|
||||||
|
);
|
||||||
|
return status == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
|
||||||
|
updateMetricField(attachment, THREAD_FAILURE, 1);
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_ERROR,
|
||||||
|
"clock_gettime(CLOCK_REALTIME) failed. Status: %s",
|
||||||
|
strerror(errno)
|
||||||
|
);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert milliseconds to timespec
|
||||||
|
ts.tv_sec += timeout_msecs / 1000;
|
||||||
|
ts.tv_nsec += (timeout_msecs % 1000) * 1000 * 1000;
|
||||||
|
if (ts.tv_nsec > 1000 * 1000 * 1000) {
|
||||||
|
ts.tv_nsec -= 1000 * 1000 * 1000;
|
||||||
|
++ts.tv_sec;
|
||||||
|
}
|
||||||
|
|
||||||
|
long long tv_nsec = ts.tv_nsec + (timeout_msecs % 1000) * 1000000;
|
||||||
|
|
||||||
|
ts.tv_sec += timeout_msecs / 1000 + tv_nsec / 1000000000;
|
||||||
|
ts.tv_nsec = tv_nsec % 1000000000;
|
||||||
|
|
||||||
|
status = pthread_timedjoin_np(thread, NULL, &ts);
|
||||||
|
|
||||||
|
if (status != 0) {
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
status == ETIMEDOUT ? DBG_LEVEL_DEBUG : DBG_LEVEL_WARNING,
|
||||||
|
"pthread_timejoin_np returns with %d (%s), fn=%s",
|
||||||
|
status,
|
||||||
|
strerror(status),
|
||||||
|
func_name
|
||||||
|
);
|
||||||
|
|
||||||
|
ret = pthread_cancel(thread);
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"pthread_cancel returns with ret=%d, fn=%s",
|
||||||
|
ret,
|
||||||
|
func_name
|
||||||
|
);
|
||||||
|
|
||||||
|
ret = pthread_join(thread, &res);
|
||||||
|
if (ret != 0) {
|
||||||
|
updateMetricField(attachment, THREAD_FAILURE, 1);
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_WARNING,
|
||||||
|
"pthread_join failed while fail open is enabled. RET=%d, fn=%s",
|
||||||
|
ret,
|
||||||
|
func_name
|
||||||
|
);
|
||||||
|
return ret != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateMetricField(attachment, res == PTHREAD_CANCELED ? THREAD_TIMEOUT : THREAD_FAILURE, 1);
|
||||||
|
if (res == PTHREAD_CANCELED) {
|
||||||
|
write_dbg(attachment, session_id, DBG_LEVEL_DEBUG, "thread was canceled, fn=%s", func_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(attachment, session_id, DBG_LEVEL_DEBUG, "pthread_join returns with ret=%d", ret);
|
||||||
|
} else {
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
session_id,
|
||||||
|
DBG_LEVEL_TRACE,
|
||||||
|
"Successfully executed thread. fn=%s",
|
||||||
|
func_name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data != NULL) {
|
||||||
|
CalcProcessingTime(data->session_data, &thread_time_begin, transaction_type);
|
||||||
|
}
|
||||||
|
return status == 0;
|
||||||
|
}
|
46
attachments/nano_attachment/nano_attachment_thread.h
Normal file
46
attachments/nano_attachment/nano_attachment_thread.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#ifndef __NANO_ATTACHMENT_THREAD_H__
|
||||||
|
#define __NANO_ATTACHMENT_THREAD_H__
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "nano_initializer.h"
|
||||||
|
|
||||||
|
typedef void *(*CpThreadRoutine)(void *); ///< Func
|
||||||
|
|
||||||
|
typedef enum TransactionType
|
||||||
|
{
|
||||||
|
START,
|
||||||
|
REQUEST,
|
||||||
|
RESPONSE,
|
||||||
|
METRICS,
|
||||||
|
REGISTRATION
|
||||||
|
} TransactionType;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Runs a function in a thread with a timeout.
|
||||||
|
///
|
||||||
|
/// This function runs the specified thread function in a dedicated thread with a timeout.
|
||||||
|
/// If the function does not complete within the specified timeout, it is cancelled.
|
||||||
|
///
|
||||||
|
/// @param[in] attachment The NanoAttachment object.
|
||||||
|
/// @param[in] data The AttachmentData object.
|
||||||
|
/// @param[in] thread_func The function to run in the thread.
|
||||||
|
/// @param[in] arg The argument to pass to the thread function.
|
||||||
|
/// @param[in] timeout_msecs The timeout value in milliseconds.
|
||||||
|
/// @param[in] func_name The name of the function for debugging purposes.
|
||||||
|
/// @param[in] transaction_type The type of transaction (request or response), used for timeout.
|
||||||
|
///
|
||||||
|
/// @return Returns 1 if the function completes within the timeout, 0 otherwise.
|
||||||
|
///
|
||||||
|
int
|
||||||
|
NanoRunInThreadTimeout(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
AttachmentData *data,
|
||||||
|
CpThreadRoutine thread_func,
|
||||||
|
void *arg,
|
||||||
|
int timeout_msecs,
|
||||||
|
char *func_name,
|
||||||
|
TransactionType transaction_type
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif // __NANO_ATTACHMENT_THREAD_H__
|
@ -0,0 +1,51 @@
|
|||||||
|
include_directories(${CMAKE_SOURCE_DIR}/attachments/nano_attachment)
|
||||||
|
|
||||||
|
add_unit_test(
|
||||||
|
nano_attachment_ut
|
||||||
|
"nano_attachment_ut.cc"
|
||||||
|
"nano_attachment"
|
||||||
|
)
|
||||||
|
|
||||||
|
if( NOT "${PLATFORM_TYPE}" STREQUAL "alpine")
|
||||||
|
add_unit_test(
|
||||||
|
nano_attachment_io_ut
|
||||||
|
"nano_attachment_io_ut.cc"
|
||||||
|
"nano_attachment"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_unit_test(
|
||||||
|
nano_attachment_sender_ut
|
||||||
|
"nano_attachment_sender_ut.cc"
|
||||||
|
"nano_attachment"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_unit_test(
|
||||||
|
nano_thread_ut
|
||||||
|
"nano_thread_ut.cc"
|
||||||
|
"nano_attachment"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_unit_test(
|
||||||
|
nano_sender_thread_ut
|
||||||
|
"nano_sender_thread_ut.cc"
|
||||||
|
"nano_attachment"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_unit_test(
|
||||||
|
nano_configuration_ut
|
||||||
|
"nano_configuration_ut.cc"
|
||||||
|
"nano_attachment"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_unit_test(
|
||||||
|
nano_initializer_ut
|
||||||
|
"nano_initializer_ut.cc"
|
||||||
|
"nano_attachment"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_unit_test(
|
||||||
|
nano_attachment_metrics_ut
|
||||||
|
"nano_attachment_metrics_ut.cc"
|
||||||
|
"nano_attachment"
|
||||||
|
)
|
@ -0,0 +1,975 @@
|
|||||||
|
#include "cptest.h"
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "attachment_types.h"
|
||||||
|
|
||||||
|
#include "mock_nano_initializer.h"
|
||||||
|
#include "mock_shmem_ipc.h"
|
||||||
|
#include "mock_nano_socket.h"
|
||||||
|
#include "mock_nano_poll.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "nano_attachment.h"
|
||||||
|
#include "nano_attachment_io.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace testing;
|
||||||
|
|
||||||
|
class NanoAttachmentIoTest : public Test
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void
|
||||||
|
SetUp() override
|
||||||
|
{
|
||||||
|
EXPECT_CALL(
|
||||||
|
initializer_mocker,
|
||||||
|
nano_attachment_init_process(_)).WillOnce(Return(NanoCommunicationResult::NANO_OK)
|
||||||
|
);
|
||||||
|
setenv("CLOUDGUARD_UID", "Testing", 1);
|
||||||
|
attachment = InitNanoAttachment(
|
||||||
|
static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID),
|
||||||
|
2,
|
||||||
|
4,
|
||||||
|
STDOUT_FILENO
|
||||||
|
);
|
||||||
|
EXPECT_NE(attachment, nullptr);
|
||||||
|
|
||||||
|
attachment->dbg_level = nano_http_cp_debug_level::DBG_LEVEL_TRACE;
|
||||||
|
|
||||||
|
session_data = InitSessionData(attachment, 501);
|
||||||
|
EXPECT_NE(session_data, nullptr);
|
||||||
|
|
||||||
|
ctx_data.session_data = session_data;
|
||||||
|
init_thread_ctx(&ctx, attachment, &ctx_data);
|
||||||
|
|
||||||
|
reply_from_service_mock = (HttpReplyFromService *)malloc(
|
||||||
|
sizeof(HttpReplyFromService) +
|
||||||
|
sizeof(HttpModifyData) +
|
||||||
|
sizeof(HttpInjectData) +
|
||||||
|
sizeof(HttpWebResponseData)
|
||||||
|
);
|
||||||
|
reply_from_service_mock->verdict = static_cast<uint16_t>(ServiceVerdict::TRAFFIC_VERDICT_INSPECT);
|
||||||
|
reply_from_service_mock->session_id = session_data->session_id;
|
||||||
|
reply_from_service_mock->modification_count = 0;
|
||||||
|
|
||||||
|
modify_data_mock = reinterpret_cast<HttpModifyData *>(reply_from_service_mock->modify_data);
|
||||||
|
inject_data = reinterpret_cast<HttpInjectData *>(
|
||||||
|
reply_from_service_mock->modify_data + sizeof(HttpModifyData)
|
||||||
|
);
|
||||||
|
web_response_data = reinterpret_cast<HttpWebResponseData *>(
|
||||||
|
reply_from_service_mock->modify_data + sizeof(HttpModifyData)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TearDown() override
|
||||||
|
{
|
||||||
|
free(reply_from_service_mock);
|
||||||
|
FiniSessionData(attachment, session_data);
|
||||||
|
FiniNanoAttachment(attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
nano_str_t
|
||||||
|
create_nano_str(const char *str)
|
||||||
|
{
|
||||||
|
nano_str_t nano_str;
|
||||||
|
nano_str.data = reinterpret_cast<unsigned char *>(const_cast<char *>(str));
|
||||||
|
nano_str.len = strlen(str);
|
||||||
|
return nano_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
AttachmentVerdictResponse inspect_response = {
|
||||||
|
AttachmentVerdict::ATTACHMENT_VERDICT_INSPECT,
|
||||||
|
1,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentVerdictResponse accept_response = {
|
||||||
|
AttachmentVerdict::ATTACHMENT_VERDICT_ACCEPT,
|
||||||
|
1,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentVerdictResponse custom_drop_response = {
|
||||||
|
AttachmentVerdict::ATTACHMENT_VERDICT_DROP,
|
||||||
|
1,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpMetaData http_meta_data = {
|
||||||
|
create_nano_str("HTTP/1.1"),
|
||||||
|
create_nano_str("GET"),
|
||||||
|
create_nano_str("www.nanoattachmentut.com"),
|
||||||
|
create_nano_str("192.168.1.100"),
|
||||||
|
80,
|
||||||
|
create_nano_str("/dogs.html"),
|
||||||
|
create_nano_str("192.168.1.101"),
|
||||||
|
253,
|
||||||
|
create_nano_str("nanoattachmentut.com"),
|
||||||
|
create_nano_str("/dogs.html")
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpHeaderData http_headers[3] = {
|
||||||
|
{
|
||||||
|
create_nano_str("Host"),
|
||||||
|
create_nano_str("www.nanoattachmentut.com")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
create_nano_str("User-Agent"),
|
||||||
|
create_nano_str("Mozilla/5.0")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
create_nano_str("Accept"),
|
||||||
|
create_nano_str("text/html")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpHeaders http_headers_data = {
|
||||||
|
http_headers,
|
||||||
|
3
|
||||||
|
};
|
||||||
|
|
||||||
|
nano_str_t body[3] = {
|
||||||
|
create_nano_str("Hello"),
|
||||||
|
create_nano_str("World"),
|
||||||
|
create_nano_str("!")
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpBody http_body_data = {
|
||||||
|
body,
|
||||||
|
3
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentData ctx_data = {
|
||||||
|
1,
|
||||||
|
HttpChunkType::HTTP_REQUEST_METADATA,
|
||||||
|
session_data,
|
||||||
|
nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpReplyFromService *reply_from_service_mock;
|
||||||
|
HttpModifyData *modify_data_mock;
|
||||||
|
HttpInjectData *inject_data;
|
||||||
|
HttpWebResponseData *web_response_data;
|
||||||
|
uint32_t reply_session_id = -1;
|
||||||
|
void *reply_session_id_void = &reply_session_id;
|
||||||
|
const char **replay_data_mock;
|
||||||
|
|
||||||
|
NanoAttachment *attachment;
|
||||||
|
HttpSessionData *session_data;
|
||||||
|
HttpEventThreadCtx ctx;
|
||||||
|
|
||||||
|
StrictMock<NanoInitializerMocker> initializer_mocker;
|
||||||
|
StrictMock<NanoShmemIPCMocker> mock_shmem_ipc;
|
||||||
|
StrictMock<NanoSocketMocker> mock_nano_socket;
|
||||||
|
StrictMock<NanoPollMocker> mock_nano_poll;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentIoTest, ConnectToCommSocket)
|
||||||
|
{
|
||||||
|
NanoCommunicationResult res;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
socket(AF_UNIX, SOCK_STREAM, 0)
|
||||||
|
).WillOnce(Return(53));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
connect(53, _, _)
|
||||||
|
).WillOnce(Return(0));
|
||||||
|
|
||||||
|
res = connect_to_comm_socket(attachment);
|
||||||
|
|
||||||
|
EXPECT_EQ(res, NanoCommunicationResult::NANO_OK);
|
||||||
|
EXPECT_EQ(attachment->comm_socket, 53);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentIoTest, ConnectToRegistrationSocket)
|
||||||
|
{
|
||||||
|
NanoCommunicationResult res;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
socket(AF_UNIX, SOCK_STREAM, 0)
|
||||||
|
).WillOnce(Return(39));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
connect(39, _, _)
|
||||||
|
).WillOnce(Return(0));
|
||||||
|
|
||||||
|
res = connect_to_registration_socket(attachment);
|
||||||
|
|
||||||
|
EXPECT_EQ(res, NanoCommunicationResult::NANO_OK);
|
||||||
|
EXPECT_EQ(attachment->registration_socket, 39);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentIoTest, NanoMetadataSender)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
sendChunkedData(_, _, _, _)
|
||||||
|
).WillOnce(Return(0));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
isDataAvailable(_)
|
||||||
|
).WillOnce(Return(1));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
receiveData(_, _, _)
|
||||||
|
).WillOnce(
|
||||||
|
DoAll(
|
||||||
|
SaveArg<2>(&replay_data_mock),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
*replay_data_mock = reinterpret_cast<const char *>(reply_from_service_mock);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
popData(_)
|
||||||
|
).WillOnce(Return(1));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_poll,
|
||||||
|
poll(_, _, _)
|
||||||
|
).Times(2)
|
||||||
|
.WillOnce(Return(1))
|
||||||
|
.WillOnce(Return(2));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
write(_, _, _)
|
||||||
|
).WillOnce(Return(sizeof(SessionID)));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
read(_, _, _)
|
||||||
|
).WillOnce(
|
||||||
|
DoAll(
|
||||||
|
SaveArg<1>(&reply_session_id_void),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
*reinterpret_cast<uint32_t *>(reply_session_id_void) = 501;
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
nano_metadata_sender(
|
||||||
|
attachment,
|
||||||
|
&http_meta_data,
|
||||||
|
&ctx,
|
||||||
|
session_data->session_id,
|
||||||
|
&session_data->remaining_messages_to_reply,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentIoTest, NanoMetadataSenderFailOnce)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
sendChunkedData(_, _, _, _)
|
||||||
|
).Times(2)
|
||||||
|
.WillOnce(Return(1))
|
||||||
|
.WillOnce(Return(0));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_poll,
|
||||||
|
poll(_, _, _)
|
||||||
|
).Times(2)
|
||||||
|
.WillOnce(Return(1))
|
||||||
|
.WillOnce(Return(2));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
write(_, _, _)
|
||||||
|
).WillOnce(Return(sizeof(SessionID)));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
read(_, _, _)
|
||||||
|
).WillOnce(
|
||||||
|
DoAll(
|
||||||
|
SaveArg<1>(&reply_session_id_void),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
*reinterpret_cast<uint32_t *>(reply_session_id_void) = 501;
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
nano_metadata_sender(
|
||||||
|
attachment,
|
||||||
|
&http_meta_data,
|
||||||
|
&ctx,
|
||||||
|
session_data->session_id,
|
||||||
|
&session_data->remaining_messages_to_reply,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentIoTest, NanoHeadersSender)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
sendChunkedData(_, _, _, _)
|
||||||
|
).WillOnce(Return(0));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
isDataAvailable(_)
|
||||||
|
).WillOnce(Return(1));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
receiveData(_, _, _)
|
||||||
|
).WillOnce(
|
||||||
|
DoAll(
|
||||||
|
SaveArg<2>(&replay_data_mock),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
*replay_data_mock = (const char *)reply_from_service_mock;
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_poll,
|
||||||
|
poll(_, _, _)
|
||||||
|
).Times(2)
|
||||||
|
.WillOnce(Return(1))
|
||||||
|
.WillOnce(Return(2));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
write(_, _, _)
|
||||||
|
).WillOnce(Return(sizeof(SessionID)));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
read(_, _, _)
|
||||||
|
).WillOnce(
|
||||||
|
DoAll(
|
||||||
|
SaveArg<1>(&reply_session_id_void),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
*reinterpret_cast<uint32_t *>(reply_session_id_void) = 501;
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
popData(_)
|
||||||
|
).WillOnce(Return(1));
|
||||||
|
|
||||||
|
nano_header_sender(
|
||||||
|
attachment,
|
||||||
|
&http_headers_data,
|
||||||
|
&ctx,
|
||||||
|
AttachmentDataType::REQUEST_HEADER,
|
||||||
|
session_data->session_id,
|
||||||
|
&session_data->remaining_messages_to_reply,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentIoTest, NanoBodySender)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
sendChunkedData(_, _, _, _)
|
||||||
|
).Times(3)
|
||||||
|
.WillOnce(Return(0))
|
||||||
|
.WillOnce(Return(0))
|
||||||
|
.WillOnce(Return(0));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
read(_, _, _)
|
||||||
|
).WillRepeatedly(
|
||||||
|
DoAll(
|
||||||
|
SaveArg<1>(&reply_session_id_void),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
*reinterpret_cast<uint32_t *>(reply_session_id_void) = 501;
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_poll,
|
||||||
|
poll(_, _, _)
|
||||||
|
).WillRepeatedly(Return(1));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
write(_, _, _)
|
||||||
|
).WillRepeatedly(Return(sizeof(SessionID)));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
close(_)
|
||||||
|
).WillRepeatedly(Return(0));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
connect(_, _, _)
|
||||||
|
).WillRepeatedly(Return(0));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
socket(_, _, _)
|
||||||
|
).WillRepeatedly(Return(0));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
initializer_mocker,
|
||||||
|
write_to_service(attachment, _, _, _, _)
|
||||||
|
).WillRepeatedly(Return(NanoCommunicationResult::NANO_OK));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
isDataAvailable(_)
|
||||||
|
).WillRepeatedly(Return(1));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
receiveData(_, _, _)
|
||||||
|
).WillRepeatedly(
|
||||||
|
DoAll(
|
||||||
|
SaveArg<2>(&replay_data_mock),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
*replay_data_mock = (const char *)reply_from_service_mock;
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
popData(_)
|
||||||
|
).WillRepeatedly(Return(1));
|
||||||
|
|
||||||
|
nano_body_sender(
|
||||||
|
attachment,
|
||||||
|
&http_body_data,
|
||||||
|
&ctx,
|
||||||
|
AttachmentDataType::REQUEST_BODY,
|
||||||
|
session_data->session_id,
|
||||||
|
&session_data->remaining_messages_to_reply
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentIoTest, NanoSendResponseContentLength)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
sendChunkedData(_, _, _, _)
|
||||||
|
).WillOnce(Return(0));
|
||||||
|
|
||||||
|
nano_send_response_content_length(
|
||||||
|
attachment,
|
||||||
|
332,
|
||||||
|
&ctx,
|
||||||
|
session_data->session_id,
|
||||||
|
&session_data->remaining_messages_to_reply
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_EQ(session_data->remaining_messages_to_reply, 1u);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentIoTest, NanoSendResponseCode)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
sendChunkedData(_, _, _, _)
|
||||||
|
).WillOnce(Return(0));
|
||||||
|
|
||||||
|
nano_send_response_code(
|
||||||
|
attachment,
|
||||||
|
443,
|
||||||
|
&ctx,
|
||||||
|
session_data->session_id,
|
||||||
|
&session_data->remaining_messages_to_reply
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_EQ(session_data->remaining_messages_to_reply, 1u);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentIoTest, NanoEndTransactionSender)
|
||||||
|
{
|
||||||
|
reply_from_service_mock->verdict = static_cast<uint16_t>(ServiceVerdict::TRAFFIC_VERDICT_ACCEPT);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
sendChunkedData(_, _, _, _)
|
||||||
|
).WillOnce(Return(0));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_poll,
|
||||||
|
poll(_, _, _)
|
||||||
|
).Times(2)
|
||||||
|
.WillOnce(Return(1))
|
||||||
|
.WillOnce(Return(2));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
write(_, _, _)
|
||||||
|
).WillOnce(Return(sizeof(SessionID)));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
read(_, _, _)
|
||||||
|
).WillOnce(
|
||||||
|
DoAll(
|
||||||
|
SaveArg<1>(&reply_session_id_void),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
*reinterpret_cast<uint32_t *>(reply_session_id_void) = 501;
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
isDataAvailable(_)
|
||||||
|
).WillOnce(Return(1));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
receiveData(_, _, _)
|
||||||
|
).WillOnce(
|
||||||
|
DoAll(
|
||||||
|
SaveArg<2>(&replay_data_mock),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
*replay_data_mock = reinterpret_cast<const char *>(reply_from_service_mock);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
popData(_)
|
||||||
|
).WillOnce(Return(1));
|
||||||
|
|
||||||
|
nano_end_transaction_sender(
|
||||||
|
attachment,
|
||||||
|
AttachmentDataType::REQUEST_END,
|
||||||
|
&ctx,
|
||||||
|
session_data->session_id,
|
||||||
|
&session_data->remaining_messages_to_reply
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_EQ(session_data->remaining_messages_to_reply, 0u);
|
||||||
|
EXPECT_EQ(session_data->verdict, ServiceVerdict::TRAFFIC_VERDICT_ACCEPT);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentIoTest, NanoDelayedTransactionSender)
|
||||||
|
{
|
||||||
|
reply_from_service_mock->verdict = static_cast<uint16_t>(ServiceVerdict::TRAFFIC_VERDICT_ACCEPT);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
sendChunkedData(_, _, _, _)
|
||||||
|
).WillOnce(Return(0));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_poll,
|
||||||
|
poll(_, _, _)
|
||||||
|
).Times(2)
|
||||||
|
.WillOnce(Return(1))
|
||||||
|
.WillOnce(Return(2));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
write(_, _, _)
|
||||||
|
).WillOnce(Return(sizeof(SessionID)));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
read(_, _, _)
|
||||||
|
).WillOnce(
|
||||||
|
DoAll(
|
||||||
|
SaveArg<1>(&reply_session_id_void),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
*reinterpret_cast<uint32_t *>(reply_session_id_void) = 501;
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
isDataAvailable(_)
|
||||||
|
).WillOnce(Return(1));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
receiveData(_, _, _)
|
||||||
|
).WillOnce(
|
||||||
|
DoAll(
|
||||||
|
SaveArg<2>(&replay_data_mock),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
*replay_data_mock = reinterpret_cast<const char *>(reply_from_service_mock);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
popData(_)
|
||||||
|
).WillOnce(Return(1));
|
||||||
|
|
||||||
|
nano_request_delayed_verdict(
|
||||||
|
attachment,
|
||||||
|
&ctx,
|
||||||
|
session_data->session_id,
|
||||||
|
&session_data->remaining_messages_to_reply
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_EQ(session_data->remaining_messages_to_reply, 0u);
|
||||||
|
EXPECT_EQ(session_data->verdict, ServiceVerdict::TRAFFIC_VERDICT_ACCEPT);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentIoTest, NanoDropResponseBadResponse)
|
||||||
|
{
|
||||||
|
web_response_data->web_response_type = static_cast<uint16_t>(NanoWebResponseType::NO_WEB_RESPONSE);
|
||||||
|
reply_from_service_mock->verdict = static_cast<uint16_t>(ServiceVerdict::TRAFFIC_VERDICT_DROP);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
sendChunkedData(_, _, _, _)
|
||||||
|
).WillOnce(Return(0));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_poll,
|
||||||
|
poll(_, _, _)
|
||||||
|
).Times(2)
|
||||||
|
.WillOnce(Return(1))
|
||||||
|
.WillOnce(Return(2));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
write(_, _, _)
|
||||||
|
).WillOnce(Return(sizeof(SessionID)));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
read(_, _, _)
|
||||||
|
).WillOnce(
|
||||||
|
DoAll(
|
||||||
|
SaveArg<1>(&reply_session_id_void),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
*reinterpret_cast<uint32_t *>(reply_session_id_void) = 501;
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
isDataAvailable(_)
|
||||||
|
).WillOnce(Return(1));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
receiveData(_, _, _)
|
||||||
|
).WillOnce(
|
||||||
|
DoAll(
|
||||||
|
SaveArg<2>(&replay_data_mock),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
*replay_data_mock = reinterpret_cast<const char *>(reply_from_service_mock);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
popData(_)
|
||||||
|
).WillOnce(Return(1));
|
||||||
|
|
||||||
|
nano_end_transaction_sender(
|
||||||
|
attachment,
|
||||||
|
AttachmentDataType::REQUEST_END,
|
||||||
|
&ctx,
|
||||||
|
session_data->session_id,
|
||||||
|
&session_data->remaining_messages_to_reply
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_EQ(session_data->remaining_messages_to_reply, 0u);
|
||||||
|
EXPECT_EQ(session_data->verdict, ServiceVerdict::TRAFFIC_VERDICT_DROP);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentIoTest, NanoDropCustomResponse)
|
||||||
|
{
|
||||||
|
web_response_data->web_response_type = static_cast<uint16_t>(NanoWebResponseType::CUSTOM_WEB_RESPONSE);
|
||||||
|
reply_from_service_mock->verdict = static_cast<uint16_t>(ServiceVerdict::TRAFFIC_VERDICT_DROP);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
sendChunkedData(_, _, _, _)
|
||||||
|
).WillOnce(Return(0));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_poll,
|
||||||
|
poll(_, _, _)
|
||||||
|
).Times(2)
|
||||||
|
.WillOnce(Return(1))
|
||||||
|
.WillOnce(Return(2));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
write(_, _, _)
|
||||||
|
).WillOnce(Return(sizeof(SessionID)));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
read(_, _, _)
|
||||||
|
).WillOnce(
|
||||||
|
DoAll(
|
||||||
|
SaveArg<1>(&reply_session_id_void),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
*reinterpret_cast<uint32_t *>(reply_session_id_void) = 501;
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
isDataAvailable(_)
|
||||||
|
).WillOnce(Return(1));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
receiveData(_, _, _)
|
||||||
|
).WillOnce(
|
||||||
|
DoAll(
|
||||||
|
SaveArg<2>(&replay_data_mock),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
*replay_data_mock = reinterpret_cast<const char *>(reply_from_service_mock);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
popData(_)
|
||||||
|
).WillOnce(Return(1));
|
||||||
|
|
||||||
|
nano_end_transaction_sender(
|
||||||
|
attachment,
|
||||||
|
AttachmentDataType::REQUEST_END,
|
||||||
|
&ctx,
|
||||||
|
session_data->session_id,
|
||||||
|
&session_data->remaining_messages_to_reply
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_EQ(session_data->remaining_messages_to_reply, 0u);
|
||||||
|
EXPECT_EQ(session_data->verdict, ServiceVerdict::TRAFFIC_VERDICT_DROP);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentIoTest, NanoDropRedirectResponse)
|
||||||
|
{
|
||||||
|
web_response_data->web_response_type = static_cast<uint16_t>(NanoWebResponseType::REDIRECT_WEB_RESPONSE);
|
||||||
|
reply_from_service_mock->verdict = static_cast<uint16_t>(ServiceVerdict::TRAFFIC_VERDICT_DROP);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
sendChunkedData(_, _, _, _)
|
||||||
|
).WillOnce(Return(0));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_poll,
|
||||||
|
poll(_, _, _)
|
||||||
|
).Times(2)
|
||||||
|
.WillOnce(Return(1))
|
||||||
|
.WillOnce(Return(2));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
write(_, _, _)
|
||||||
|
).WillOnce(Return(sizeof(SessionID)));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
read(_, _, _)
|
||||||
|
).WillOnce(
|
||||||
|
DoAll(
|
||||||
|
SaveArg<1>(&reply_session_id_void),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
*reinterpret_cast<uint32_t *>(reply_session_id_void) = 501;
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
isDataAvailable(_)
|
||||||
|
).WillOnce(Return(1));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
receiveData(_, _, _)
|
||||||
|
).WillOnce(
|
||||||
|
DoAll(
|
||||||
|
SaveArg<2>(&replay_data_mock),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
*replay_data_mock = reinterpret_cast<const char *>(reply_from_service_mock);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
popData(_)
|
||||||
|
).WillOnce(Return(1));
|
||||||
|
|
||||||
|
nano_end_transaction_sender(
|
||||||
|
attachment,
|
||||||
|
AttachmentDataType::REQUEST_END,
|
||||||
|
&ctx,
|
||||||
|
session_data->session_id,
|
||||||
|
&session_data->remaining_messages_to_reply
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_EQ(session_data->remaining_messages_to_reply, 0u);
|
||||||
|
EXPECT_EQ(session_data->verdict, ServiceVerdict::TRAFFIC_VERDICT_DROP);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentIoTest, NanoInjectResponse)
|
||||||
|
{
|
||||||
|
reply_from_service_mock->modification_count = 1;
|
||||||
|
reply_from_service_mock->verdict = static_cast<uint16_t>(ServiceVerdict::TRAFFIC_VERDICT_INJECT);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
sendChunkedData(_, _, _, _)
|
||||||
|
).WillOnce(Return(0));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_poll,
|
||||||
|
poll(_, _, _)
|
||||||
|
).Times(2)
|
||||||
|
.WillOnce(Return(1))
|
||||||
|
.WillOnce(Return(2));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
write(_, _, _)
|
||||||
|
).WillOnce(Return(sizeof(SessionID)));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_nano_socket,
|
||||||
|
read(_, _, _)
|
||||||
|
).WillOnce(
|
||||||
|
DoAll(
|
||||||
|
SaveArg<1>(&reply_session_id_void),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
*reinterpret_cast<uint32_t *>(reply_session_id_void) = 501;
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
isDataAvailable(_)
|
||||||
|
).WillOnce(Return(1));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
receiveData(_, _, _)
|
||||||
|
).WillOnce(
|
||||||
|
DoAll(
|
||||||
|
SaveArg<2>(&replay_data_mock),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
*replay_data_mock = reinterpret_cast<const char *>(reply_from_service_mock);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
popData(_)
|
||||||
|
).WillOnce(Return(1));
|
||||||
|
|
||||||
|
nano_end_transaction_sender(
|
||||||
|
attachment,
|
||||||
|
AttachmentDataType::REQUEST_END,
|
||||||
|
&ctx,
|
||||||
|
session_data->session_id,
|
||||||
|
&session_data->remaining_messages_to_reply
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_EQ(session_data->remaining_messages_to_reply, 0u);
|
||||||
|
EXPECT_EQ(session_data->verdict, ServiceVerdict::TRAFFIC_VERDICT_INSPECT);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentIoTest, NanoSendMetricData)
|
||||||
|
{
|
||||||
|
reply_from_service_mock->verdict = static_cast<uint16_t>(ServiceVerdict::TRAFFIC_VERDICT_ACCEPT);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mock_shmem_ipc,
|
||||||
|
sendChunkedData(_, _, _, _)
|
||||||
|
).WillOnce(Return(0));
|
||||||
|
|
||||||
|
nano_send_metric_data_sender(attachment);
|
||||||
|
|
||||||
|
EXPECT_EQ(session_data->remaining_messages_to_reply, 0u);
|
||||||
|
}
|
@ -0,0 +1,102 @@
|
|||||||
|
#include "cptest.h"
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "attachment_types.h"
|
||||||
|
|
||||||
|
#include "mock_nano_initializer.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "nano_attachment.h"
|
||||||
|
#include "nano_attachment_metric.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace testing;
|
||||||
|
|
||||||
|
class NanoAttachmentMetricTest : public Test
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void
|
||||||
|
SetUp() override
|
||||||
|
{
|
||||||
|
EXPECT_CALL(
|
||||||
|
initializer_mocker,
|
||||||
|
nano_attachment_init_process(_)
|
||||||
|
).WillOnce(
|
||||||
|
Return(NanoCommunicationResult::NANO_OK)
|
||||||
|
);
|
||||||
|
setenv("CLOUDGUARD_UID", "Testing", 1);
|
||||||
|
attachment = InitNanoAttachment(
|
||||||
|
static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID),
|
||||||
|
2,
|
||||||
|
4,
|
||||||
|
STDOUT_FILENO
|
||||||
|
);
|
||||||
|
EXPECT_NE(attachment, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TearDown() override
|
||||||
|
{
|
||||||
|
FiniNanoAttachment(attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
NanoAttachment *attachment;
|
||||||
|
StrictMock<NanoInitializerMocker> initializer_mocker;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentMetricTest, CheckMetricsFunctions)
|
||||||
|
{
|
||||||
|
updateMetricField(attachment, AttachmentMetricType::INJECT_VERDICTS_COUNT, 100u);
|
||||||
|
updateMetricField(attachment, AttachmentMetricType::DROP_VERDICTS_COUNT, 200u);
|
||||||
|
updateMetricField(attachment, AttachmentMetricType::ACCEPT_VERDICTS_COUNT, 300u);
|
||||||
|
updateMetricField(attachment, AttachmentMetricType::IRRELEVANT_VERDICTS_COUNT, 400u);
|
||||||
|
updateMetricField(attachment, AttachmentMetricType::MAX_RES_PPROCESSING_TIME_UNTIL_VERDICT, 400u);
|
||||||
|
updateMetricField(attachment, AttachmentMetricType::MAX_RES_PPROCESSING_TIME_UNTIL_VERDICT, 200u);
|
||||||
|
updateMetricField(attachment, AttachmentMetricType::MIN_RES_PPROCESSING_TIME_UNTIL_VERDICT, 50u);
|
||||||
|
updateMetricField(attachment, AttachmentMetricType::MIN_RES_PPROCESSING_TIME_UNTIL_VERDICT, 150u);
|
||||||
|
updateMetricField(attachment, AttachmentMetricType::AVERAGE_RES_PPROCESSING_TIME_UNTIL_VERDICT, 50u);
|
||||||
|
updateMetricField(attachment, AttachmentMetricType::AVERAGE_RES_PPROCESSING_TIME_UNTIL_VERDICT, 50u);
|
||||||
|
updateMetricField(attachment, AttachmentMetricType::AVERAGE_RES_PPROCESSING_TIME_UNTIL_VERDICT, 20u);
|
||||||
|
|
||||||
|
EXPECT_EQ(attachment->metric_data[static_cast<int>(AttachmentMetricType::INJECT_VERDICTS_COUNT)], 100u);
|
||||||
|
EXPECT_EQ(attachment->metric_data[static_cast<int>(AttachmentMetricType::DROP_VERDICTS_COUNT)], 200u);
|
||||||
|
EXPECT_EQ(attachment->metric_data[static_cast<int>(AttachmentMetricType::ACCEPT_VERDICTS_COUNT)], 300u);
|
||||||
|
EXPECT_EQ(attachment->metric_data[static_cast<int>(AttachmentMetricType::IRRELEVANT_VERDICTS_COUNT)], 400u);
|
||||||
|
|
||||||
|
EXPECT_EQ(
|
||||||
|
attachment->metric_data[static_cast<int>(AttachmentMetricType::MAX_RES_PPROCESSING_TIME_UNTIL_VERDICT)],
|
||||||
|
400u
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_EQ(
|
||||||
|
attachment->metric_data[static_cast<int>(AttachmentMetricType::MIN_RES_PPROCESSING_TIME_UNTIL_VERDICT)],
|
||||||
|
50u
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_EQ(
|
||||||
|
attachment->metric_data[static_cast<int>(AttachmentMetricType::AVERAGE_RES_PPROCESSING_TIME_UNTIL_VERDICT)],
|
||||||
|
40u
|
||||||
|
);
|
||||||
|
|
||||||
|
reset_metric_data(attachment);
|
||||||
|
|
||||||
|
EXPECT_EQ(attachment->metric_data[static_cast<int>(AttachmentMetricType::INJECT_VERDICTS_COUNT)], 0u);
|
||||||
|
EXPECT_EQ(attachment->metric_data[static_cast<int>(AttachmentMetricType::DROP_VERDICTS_COUNT)], 0u);
|
||||||
|
EXPECT_EQ(attachment->metric_data[static_cast<int>(AttachmentMetricType::ACCEPT_VERDICTS_COUNT)], 0u);
|
||||||
|
EXPECT_EQ(attachment->metric_data[static_cast<int>(AttachmentMetricType::IRRELEVANT_VERDICTS_COUNT)], 0u);
|
||||||
|
|
||||||
|
EXPECT_EQ(
|
||||||
|
attachment->metric_data[static_cast<int>(AttachmentMetricType::MAX_RES_PPROCESSING_TIME_UNTIL_VERDICT)],
|
||||||
|
0u
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_EQ(
|
||||||
|
attachment->metric_data[static_cast<int>(AttachmentMetricType::MIN_RES_PPROCESSING_TIME_UNTIL_VERDICT)],
|
||||||
|
0u
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_EQ(
|
||||||
|
attachment->metric_data[static_cast<int>(AttachmentMetricType::AVERAGE_RES_PPROCESSING_TIME_UNTIL_VERDICT)],
|
||||||
|
0u
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,737 @@
|
|||||||
|
#include "cptest.h"
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "attachment_types.h"
|
||||||
|
|
||||||
|
#include "mock_nano_initializer.h"
|
||||||
|
#include "mock_nano_attachment_thread.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "nano_attachment.h"
|
||||||
|
#include "nano_attachment_sender.h"
|
||||||
|
#include "nano_attachment_sender_thread.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace testing;
|
||||||
|
|
||||||
|
class NanoAttachmentSenderTest : public Test
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void
|
||||||
|
SetUp() override
|
||||||
|
{
|
||||||
|
EXPECT_CALL(
|
||||||
|
initializer_mocker,
|
||||||
|
nano_attachment_init_process(_)
|
||||||
|
).WillOnce(
|
||||||
|
Return(NanoCommunicationResult::NANO_OK)
|
||||||
|
);
|
||||||
|
setenv("CLOUDGUARD_UID", "Testing", 1);
|
||||||
|
attachment = InitNanoAttachment(
|
||||||
|
static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID),
|
||||||
|
2,
|
||||||
|
4,
|
||||||
|
STDOUT_FILENO
|
||||||
|
);
|
||||||
|
EXPECT_NE(attachment, nullptr);
|
||||||
|
attachment->dbg_level = nano_http_cp_debug_level_e::DBG_LEVEL_TRACE;
|
||||||
|
|
||||||
|
session_data = InitSessionData(attachment, 1);
|
||||||
|
EXPECT_NE(session_data, nullptr);
|
||||||
|
start_data.session_data = session_data;
|
||||||
|
req_header_data.session_data = session_data;
|
||||||
|
res_header_data.session_data = session_data;
|
||||||
|
req_body_data.session_data = session_data;
|
||||||
|
res_body_data.session_data = session_data;
|
||||||
|
req_end_data.session_data = session_data;
|
||||||
|
res_end_data.session_data = session_data;
|
||||||
|
req_filter_data.session_data = session_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TearDown() override
|
||||||
|
{
|
||||||
|
FiniSessionData(attachment, session_data);
|
||||||
|
FiniNanoAttachment(attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
nano_str_t
|
||||||
|
create_nano_str(const char *str)
|
||||||
|
{
|
||||||
|
nano_str_t nano_str;
|
||||||
|
nano_str.data = reinterpret_cast<unsigned char *>(const_cast<char *>(str));
|
||||||
|
nano_str.len = strlen(str);
|
||||||
|
return nano_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NanoRunInThreadTimeoutInvoker(
|
||||||
|
AttachmentData *data,
|
||||||
|
void *arg,
|
||||||
|
NanoCommunicationResult com_res,
|
||||||
|
ServiceVerdict verdict
|
||||||
|
)
|
||||||
|
{
|
||||||
|
|
||||||
|
HttpEventThreadCtx *ctx = (HttpEventThreadCtx *)arg;
|
||||||
|
init_thread_ctx(ctx, attachment, data);
|
||||||
|
|
||||||
|
ctx->session_data_p = data->session_data;
|
||||||
|
ctx->res = com_res;
|
||||||
|
ctx->session_data_p->verdict = verdict;
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpMetaData http_meta_data = {
|
||||||
|
create_nano_str("HTTP/1.1"),
|
||||||
|
create_nano_str("GET"),
|
||||||
|
create_nano_str("www.nanoattachmentut.com"),
|
||||||
|
create_nano_str("192.168.1.100"),
|
||||||
|
80,
|
||||||
|
create_nano_str("/dogs.html"),
|
||||||
|
create_nano_str("192.168.1.101"),
|
||||||
|
253,
|
||||||
|
create_nano_str("nanoattachmentut.com"),
|
||||||
|
create_nano_str("/dogs.html")
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpHeaderData http_headers[3] = {
|
||||||
|
{
|
||||||
|
create_nano_str("Host"),
|
||||||
|
create_nano_str("www.nanoattachmentut.com")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
create_nano_str("User-Agent"),
|
||||||
|
create_nano_str("Mozilla/5.0")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
create_nano_str("Accept"),
|
||||||
|
create_nano_str("text/html")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpHeaders http_headers_data = {
|
||||||
|
http_headers,
|
||||||
|
3
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpRequestFilterData request_filter_data = {
|
||||||
|
&http_meta_data,
|
||||||
|
&http_headers_data,
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
nano_str_t body[3] = {
|
||||||
|
create_nano_str("Hello"),
|
||||||
|
create_nano_str("World"),
|
||||||
|
create_nano_str("!")
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpBody http_body_data = {
|
||||||
|
body,
|
||||||
|
3
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentData start_data = {
|
||||||
|
1,
|
||||||
|
HttpChunkType::HTTP_REQUEST_METADATA,
|
||||||
|
session_data,
|
||||||
|
(DataBuffer)&http_meta_data
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentData req_filter_data = {
|
||||||
|
1,
|
||||||
|
HttpChunkType::HTTP_REQUEST_FILTER,
|
||||||
|
session_data,
|
||||||
|
(DataBuffer)&request_filter_data
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentData req_header_data = {
|
||||||
|
1,
|
||||||
|
HttpChunkType::HTTP_REQUEST_HEADER,
|
||||||
|
session_data,
|
||||||
|
(DataBuffer)&http_headers_data
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentData res_header_data = {
|
||||||
|
1,
|
||||||
|
HttpChunkType::HTTP_RESPONSE_HEADER,
|
||||||
|
session_data,
|
||||||
|
(DataBuffer)&http_headers_data
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentData req_body_data = {
|
||||||
|
1,
|
||||||
|
HttpChunkType::HTTP_REQUEST_BODY,
|
||||||
|
session_data,
|
||||||
|
(DataBuffer)&http_body_data
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentData res_body_data = {
|
||||||
|
1,
|
||||||
|
HttpChunkType::HTTP_RESPONSE_BODY,
|
||||||
|
session_data,
|
||||||
|
(DataBuffer)&http_body_data
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentData req_end_data = {
|
||||||
|
1,
|
||||||
|
HttpChunkType::HTTP_REQUEST_END,
|
||||||
|
session_data,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentData res_end_data = {
|
||||||
|
1,
|
||||||
|
HttpChunkType::HTTP_RESPONSE_END,
|
||||||
|
session_data,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
NanoAttachment *attachment;
|
||||||
|
HttpSessionData *session_data;
|
||||||
|
StrictMock<NanoInitializerMocker> initializer_mocker;
|
||||||
|
StrictMock<NanoAttachmentThreadMocker> thread_mocker;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderTest, SendRequestCorruptMemory)
|
||||||
|
{
|
||||||
|
AttachmentVerdictResponse response;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
initializer_mocker,
|
||||||
|
handle_shmem_corruption(attachment)).WillOnce(Return(NanoCommunicationResult::NANO_ERROR)
|
||||||
|
);
|
||||||
|
|
||||||
|
response = SendMetadata(attachment, &start_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_ACCEPT);
|
||||||
|
EXPECT_EQ(response.web_response_data, nullptr);
|
||||||
|
EXPECT_EQ(response.modifications, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderTest, SendRequestFailOpenDrop)
|
||||||
|
{
|
||||||
|
AttachmentVerdictResponse response;
|
||||||
|
CustomResponseData *custom_response_data;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
initializer_mocker,
|
||||||
|
handle_shmem_corruption(attachment)).WillOnce(Return(NanoCommunicationResult::NANO_ERROR)
|
||||||
|
);
|
||||||
|
|
||||||
|
attachment->fail_mode_verdict = static_cast<int>(NanoCommunicationResult::NANO_HTTP_FORBIDDEN);
|
||||||
|
response = SendMetadata(attachment, &start_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_DROP);
|
||||||
|
EXPECT_NE(response.web_response_data, nullptr);
|
||||||
|
EXPECT_EQ(response.web_response_data->web_response_type, NanoWebResponseType::CUSTOM_WEB_RESPONSE);
|
||||||
|
EXPECT_STREQ(
|
||||||
|
reinterpret_cast<const char *>(
|
||||||
|
response.web_response_data->uuid
|
||||||
|
),
|
||||||
|
"20118dba-81f7-4999-8e94-003cf242f5dd"
|
||||||
|
);
|
||||||
|
EXPECT_NE(response.web_response_data->data, nullptr);
|
||||||
|
EXPECT_EQ(response.modifications, nullptr);
|
||||||
|
|
||||||
|
custom_response_data = (CustomResponseData *)response.web_response_data->data;
|
||||||
|
EXPECT_EQ(custom_response_data->response_code, 403);
|
||||||
|
EXPECT_STREQ(reinterpret_cast<const char *>(custom_response_data->title), "Default Title");
|
||||||
|
EXPECT_STREQ(reinterpret_cast<const char *>(custom_response_data->body), "Default Body");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderTest, SendRequestTimeout)
|
||||||
|
{
|
||||||
|
AttachmentVerdictResponse response;
|
||||||
|
void *_ctx;
|
||||||
|
AttachmentData *_attachment_data;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
initializer_mocker,
|
||||||
|
handle_shmem_corruption(attachment)).WillOnce(Return(NanoCommunicationResult::NANO_OK)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
thread_mocker,
|
||||||
|
NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
&start_data,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
TransactionType::REQUEST
|
||||||
|
)
|
||||||
|
).WillOnce(DoAll(SaveArg<1>(&_attachment_data), SaveArg<3>(&_ctx),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
NanoRunInThreadTimeoutInvoker(
|
||||||
|
_attachment_data,
|
||||||
|
_ctx,
|
||||||
|
NanoCommunicationResult::NANO_TIMEOUT,
|
||||||
|
ServiceVerdict::TRAFFIC_VERDICT_INSPECT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(0))
|
||||||
|
);
|
||||||
|
|
||||||
|
response = SendMetadata(attachment, &start_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_ACCEPT);
|
||||||
|
EXPECT_EQ(response.web_response_data, nullptr);
|
||||||
|
EXPECT_EQ(response.modifications, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderTest, SendRequestIrrelevant)
|
||||||
|
{
|
||||||
|
AttachmentVerdictResponse response;
|
||||||
|
void *_ctx;
|
||||||
|
AttachmentData *_attachment_data;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
initializer_mocker,
|
||||||
|
handle_shmem_corruption(attachment)).WillOnce(Return(NanoCommunicationResult::NANO_OK)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
thread_mocker,
|
||||||
|
NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
&start_data,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
TransactionType::REQUEST
|
||||||
|
)
|
||||||
|
).WillOnce(DoAll(SaveArg<1>(&_attachment_data), SaveArg<3>(&_ctx),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
NanoRunInThreadTimeoutInvoker(
|
||||||
|
_attachment_data,
|
||||||
|
_ctx,
|
||||||
|
NanoCommunicationResult::NANO_DECLINED,
|
||||||
|
ServiceVerdict::TRAFFIC_VERDICT_ACCEPT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1))
|
||||||
|
);
|
||||||
|
|
||||||
|
response = SendMetadata(attachment, &start_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_ACCEPT);
|
||||||
|
EXPECT_EQ(response.web_response_data, nullptr);
|
||||||
|
EXPECT_EQ(response.modifications, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderTest, SendRequestFailed)
|
||||||
|
{
|
||||||
|
AttachmentVerdictResponse response;
|
||||||
|
void *_ctx;
|
||||||
|
AttachmentData *_attachment_data;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
initializer_mocker,
|
||||||
|
handle_shmem_corruption(attachment)).WillOnce(Return(NanoCommunicationResult::NANO_OK)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
thread_mocker,
|
||||||
|
NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
&start_data,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
TransactionType::REQUEST
|
||||||
|
)
|
||||||
|
).WillOnce(DoAll(SaveArg<1>(&_attachment_data), SaveArg<3>(&_ctx),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
NanoRunInThreadTimeoutInvoker(
|
||||||
|
_attachment_data,
|
||||||
|
_ctx,
|
||||||
|
NanoCommunicationResult::NANO_ERROR,
|
||||||
|
ServiceVerdict::TRAFFIC_VERDICT_INSPECT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1))
|
||||||
|
);
|
||||||
|
|
||||||
|
response = SendMetadata(attachment, &start_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_ACCEPT);
|
||||||
|
EXPECT_EQ(response.web_response_data, nullptr);
|
||||||
|
EXPECT_EQ(response.modifications, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderTest, SendRequestFilter)
|
||||||
|
{
|
||||||
|
AttachmentVerdictResponse response;
|
||||||
|
void *_ctx;
|
||||||
|
AttachmentData *_attachment_data;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
initializer_mocker,
|
||||||
|
handle_shmem_corruption(attachment)).WillOnce(Return(NanoCommunicationResult::NANO_OK)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
thread_mocker,
|
||||||
|
NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
&req_filter_data,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
TransactionType::REQUEST
|
||||||
|
)
|
||||||
|
).WillOnce(DoAll(SaveArg<1>(&_attachment_data), SaveArg<3>(&_ctx),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
NanoRunInThreadTimeoutInvoker(
|
||||||
|
_attachment_data,
|
||||||
|
_ctx,
|
||||||
|
NanoCommunicationResult::NANO_OK,
|
||||||
|
ServiceVerdict::TRAFFIC_VERDICT_INSPECT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1))
|
||||||
|
);
|
||||||
|
|
||||||
|
response = SendRequestFilter(attachment, &req_filter_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_INSPECT);
|
||||||
|
EXPECT_EQ(response.web_response_data, nullptr);
|
||||||
|
EXPECT_EQ(response.modifications, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderTest, SendMetadata)
|
||||||
|
{
|
||||||
|
AttachmentVerdictResponse response;
|
||||||
|
void *_ctx;
|
||||||
|
AttachmentData *_attachment_data;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
initializer_mocker,
|
||||||
|
handle_shmem_corruption(attachment)).WillOnce(Return(NanoCommunicationResult::NANO_OK)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
thread_mocker,
|
||||||
|
NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
&start_data,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
TransactionType::REQUEST
|
||||||
|
)
|
||||||
|
).WillOnce(DoAll(SaveArg<1>(&_attachment_data), SaveArg<3>(&_ctx),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
NanoRunInThreadTimeoutInvoker(
|
||||||
|
_attachment_data,
|
||||||
|
_ctx,
|
||||||
|
NanoCommunicationResult::NANO_OK,
|
||||||
|
ServiceVerdict::TRAFFIC_VERDICT_INSPECT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1))
|
||||||
|
);
|
||||||
|
|
||||||
|
response = SendMetadata(attachment, &start_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_INSPECT);
|
||||||
|
EXPECT_EQ(response.web_response_data, nullptr);
|
||||||
|
EXPECT_EQ(response.modifications, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderTest, SendRequestHeaders)
|
||||||
|
{
|
||||||
|
AttachmentVerdictResponse response;
|
||||||
|
void *_ctx;
|
||||||
|
AttachmentData *_attachment_data;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
initializer_mocker,
|
||||||
|
handle_shmem_corruption(attachment)).WillOnce(Return(NanoCommunicationResult::NANO_OK)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
thread_mocker,
|
||||||
|
NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
&req_header_data,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
TransactionType::REQUEST
|
||||||
|
)
|
||||||
|
).WillOnce(DoAll(SaveArg<1>(&_attachment_data), SaveArg<3>(&_ctx),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
NanoRunInThreadTimeoutInvoker(
|
||||||
|
_attachment_data,
|
||||||
|
_ctx,
|
||||||
|
NanoCommunicationResult::NANO_OK,
|
||||||
|
ServiceVerdict::TRAFFIC_VERDICT_INSPECT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1))
|
||||||
|
);
|
||||||
|
|
||||||
|
response = SendRequestHeaders(attachment, &req_header_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_INSPECT);
|
||||||
|
EXPECT_EQ(response.web_response_data, nullptr);
|
||||||
|
EXPECT_EQ(response.modifications, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderTest, SendResponseHeaders)
|
||||||
|
{
|
||||||
|
AttachmentVerdictResponse response;
|
||||||
|
void *_ctx;
|
||||||
|
AttachmentData *_attachment_data;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
initializer_mocker,
|
||||||
|
handle_shmem_corruption(attachment)).WillOnce(Return(NanoCommunicationResult::NANO_OK)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
thread_mocker,
|
||||||
|
NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
&res_header_data,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
TransactionType::RESPONSE
|
||||||
|
)
|
||||||
|
).WillOnce(DoAll(SaveArg<1>(&_attachment_data), SaveArg<3>(&_ctx),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
NanoRunInThreadTimeoutInvoker(
|
||||||
|
_attachment_data,
|
||||||
|
_ctx,
|
||||||
|
NanoCommunicationResult::NANO_OK,
|
||||||
|
ServiceVerdict::TRAFFIC_VERDICT_INSPECT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1))
|
||||||
|
);
|
||||||
|
|
||||||
|
response = SendResponseHeaders(attachment, &res_header_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_INSPECT);
|
||||||
|
EXPECT_EQ(response.web_response_data, nullptr);
|
||||||
|
EXPECT_EQ(response.modifications, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderTest, SendRequestBody)
|
||||||
|
{
|
||||||
|
AttachmentVerdictResponse response;
|
||||||
|
void *_ctx;
|
||||||
|
AttachmentData *_attachment_data;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
initializer_mocker,
|
||||||
|
handle_shmem_corruption(attachment)).WillOnce(Return(NanoCommunicationResult::NANO_OK)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
thread_mocker,
|
||||||
|
NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
&req_body_data,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
TransactionType::REQUEST
|
||||||
|
)
|
||||||
|
).WillOnce(DoAll(SaveArg<1>(&_attachment_data), SaveArg<3>(&_ctx),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
NanoRunInThreadTimeoutInvoker(
|
||||||
|
_attachment_data,
|
||||||
|
_ctx,
|
||||||
|
NanoCommunicationResult::NANO_OK,
|
||||||
|
ServiceVerdict::TRAFFIC_VERDICT_INSPECT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1))
|
||||||
|
);
|
||||||
|
|
||||||
|
response = SendRequestBody(attachment, &req_body_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_INSPECT);
|
||||||
|
EXPECT_EQ(response.web_response_data, nullptr);
|
||||||
|
EXPECT_EQ(response.modifications, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderTest, SendResponseBody)
|
||||||
|
{
|
||||||
|
AttachmentVerdictResponse response;
|
||||||
|
void *_ctx;
|
||||||
|
AttachmentData *_attachment_data;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
initializer_mocker,
|
||||||
|
handle_shmem_corruption(attachment)).WillOnce(Return(NanoCommunicationResult::NANO_OK)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
thread_mocker,
|
||||||
|
NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
&res_body_data,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
TransactionType::RESPONSE
|
||||||
|
)
|
||||||
|
).WillOnce(DoAll(SaveArg<1>(&_attachment_data), SaveArg<3>(&_ctx),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
NanoRunInThreadTimeoutInvoker(
|
||||||
|
_attachment_data,
|
||||||
|
_ctx,
|
||||||
|
NanoCommunicationResult::NANO_OK,
|
||||||
|
ServiceVerdict::TRAFFIC_VERDICT_INSPECT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1))
|
||||||
|
);
|
||||||
|
|
||||||
|
response = SendResponseBody(attachment, &res_body_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_INSPECT);
|
||||||
|
EXPECT_EQ(response.web_response_data, nullptr);
|
||||||
|
EXPECT_EQ(response.modifications, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderTest, SendRequestEnd)
|
||||||
|
{
|
||||||
|
AttachmentVerdictResponse response;
|
||||||
|
void *_ctx;
|
||||||
|
AttachmentData *_attachment_data;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
initializer_mocker,
|
||||||
|
handle_shmem_corruption(attachment)).WillOnce(Return(NanoCommunicationResult::NANO_OK)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
thread_mocker,
|
||||||
|
NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
&req_end_data,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
TransactionType::REQUEST
|
||||||
|
)
|
||||||
|
).WillOnce(DoAll(SaveArg<1>(&_attachment_data), SaveArg<3>(&_ctx),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
NanoRunInThreadTimeoutInvoker(
|
||||||
|
_attachment_data,
|
||||||
|
_ctx,
|
||||||
|
NanoCommunicationResult::NANO_OK,
|
||||||
|
ServiceVerdict::TRAFFIC_VERDICT_ACCEPT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1))
|
||||||
|
);
|
||||||
|
|
||||||
|
response = SendRequestEnd(attachment, &req_end_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_ACCEPT);
|
||||||
|
EXPECT_EQ(response.web_response_data, nullptr);
|
||||||
|
EXPECT_EQ(response.modifications, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderTest, SendResponseEnd)
|
||||||
|
{
|
||||||
|
AttachmentVerdictResponse response;
|
||||||
|
void *_ctx;
|
||||||
|
AttachmentData *_attachment_data;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
initializer_mocker,
|
||||||
|
handle_shmem_corruption(attachment)).WillOnce(Return(NanoCommunicationResult::NANO_OK)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
thread_mocker,
|
||||||
|
NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
&res_end_data,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
TransactionType::RESPONSE
|
||||||
|
)
|
||||||
|
).WillOnce(DoAll(SaveArg<1>(&_attachment_data), SaveArg<3>(&_ctx),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
NanoRunInThreadTimeoutInvoker(
|
||||||
|
_attachment_data,
|
||||||
|
_ctx,
|
||||||
|
NanoCommunicationResult::NANO_OK,
|
||||||
|
ServiceVerdict::TRAFFIC_VERDICT_ACCEPT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1))
|
||||||
|
);
|
||||||
|
|
||||||
|
response = SendResponseEnd(attachment, &res_end_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_ACCEPT);
|
||||||
|
EXPECT_EQ(response.web_response_data, nullptr);
|
||||||
|
EXPECT_EQ(response.modifications, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderTest, SendMetricData)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(
|
||||||
|
initializer_mocker,
|
||||||
|
handle_shmem_corruption(attachment)).WillOnce(Return(NanoCommunicationResult::NANO_OK)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
thread_mocker,
|
||||||
|
NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
TransactionType::METRICS
|
||||||
|
)
|
||||||
|
).WillOnce(Return(1));
|
||||||
|
|
||||||
|
SendMetricData(attachment);
|
||||||
|
}
|
@ -0,0 +1,452 @@
|
|||||||
|
#include "cptest.h"
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "attachment_types.h"
|
||||||
|
|
||||||
|
#include "mock_nano_socket.h"
|
||||||
|
#include "mock_nano_initializer.h"
|
||||||
|
#include "mock_nano_attachment_sender.h"
|
||||||
|
#include "mock_nano_configuration.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "nano_attachment.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace testing;
|
||||||
|
|
||||||
|
class NanoAttachmentTest : public Test
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void
|
||||||
|
SetUp() override
|
||||||
|
{
|
||||||
|
EXPECT_CALL(
|
||||||
|
initializer_mocker,
|
||||||
|
nano_attachment_init_process(_)
|
||||||
|
).WillOnce(
|
||||||
|
Return(NanoCommunicationResult::NANO_OK)
|
||||||
|
);
|
||||||
|
setenv("CLOUDGUARD_UID", "Testing", 1);
|
||||||
|
attachment = InitNanoAttachment(
|
||||||
|
static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID),
|
||||||
|
2,
|
||||||
|
4,
|
||||||
|
STDOUT_FILENO
|
||||||
|
);
|
||||||
|
EXPECT_NE(attachment, nullptr);
|
||||||
|
|
||||||
|
session_data = InitSessionData(attachment, 1);
|
||||||
|
EXPECT_NE(session_data, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TearDown() override
|
||||||
|
{
|
||||||
|
FiniSessionData(attachment, session_data);
|
||||||
|
FiniNanoAttachment(attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
nano_str_t
|
||||||
|
create_nano_str(const char *str)
|
||||||
|
{
|
||||||
|
nano_str_t nano_str;
|
||||||
|
nano_str.data = reinterpret_cast<unsigned char *>(const_cast<char *>(str));
|
||||||
|
nano_str.len = strlen(str);
|
||||||
|
return nano_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
WebResponseData *
|
||||||
|
create_custom_drop_response_data()
|
||||||
|
{
|
||||||
|
WebResponseData *web_response_data = (WebResponseData *)malloc(sizeof(WebResponseData));
|
||||||
|
web_response_data->web_response_type = NanoWebResponseType::CUSTOM_WEB_RESPONSE;
|
||||||
|
memcpy(web_response_data->uuid, "TestThisIsUuidTest\0", 20);
|
||||||
|
|
||||||
|
CustomResponseData *custom_response_data = (CustomResponseData *)malloc(sizeof(CustomResponseData));
|
||||||
|
custom_response_data->response_code = 502;
|
||||||
|
memcpy(custom_response_data->title, "Woof Woof\0", 10);
|
||||||
|
memcpy(custom_response_data->body, "This is Ruby's barking\0", 24);
|
||||||
|
|
||||||
|
web_response_data->data = custom_response_data;
|
||||||
|
|
||||||
|
return web_response_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
WebResponseData *
|
||||||
|
create_redirect_response_data()
|
||||||
|
{
|
||||||
|
WebResponseData *web_response_data = (WebResponseData *)malloc(sizeof(WebResponseData));
|
||||||
|
web_response_data->web_response_type = NanoWebResponseType::REDIRECT_WEB_RESPONSE;
|
||||||
|
memcpy(web_response_data->uuid, "TestThisIsUuidTest\0", 20);
|
||||||
|
|
||||||
|
RedirectData *redirect_response_data = (RedirectData *)malloc(sizeof(CustomResponseData));
|
||||||
|
memcpy(redirect_response_data->redirect_location, "Woowwwiee.com\0", 15);
|
||||||
|
|
||||||
|
web_response_data->data = redirect_response_data;
|
||||||
|
|
||||||
|
return web_response_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
NanoHttpModificationList *
|
||||||
|
create_modifications_data()
|
||||||
|
{
|
||||||
|
NanoHttpModificationList *modification_node =
|
||||||
|
(NanoHttpModificationList *)malloc(sizeof(NanoHttpModificationList));
|
||||||
|
|
||||||
|
modification_node->next = NULL;
|
||||||
|
modification_node->modification.mod_type = HttpModificationType::APPEND;
|
||||||
|
modification_node->modification_buffer = NULL;
|
||||||
|
|
||||||
|
return modification_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
AttachmentVerdictResponse inspect_response = {
|
||||||
|
AttachmentVerdict::ATTACHMENT_VERDICT_INSPECT,
|
||||||
|
1,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentVerdictResponse accept_response = {
|
||||||
|
AttachmentVerdict::ATTACHMENT_VERDICT_ACCEPT,
|
||||||
|
1,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentVerdictResponse custom_drop_response = {
|
||||||
|
AttachmentVerdict::ATTACHMENT_VERDICT_DROP,
|
||||||
|
1,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpMetaData http_meta_data = {
|
||||||
|
create_nano_str("HTTP/1.1"),
|
||||||
|
create_nano_str("GET"),
|
||||||
|
create_nano_str("www.nanoattachmentut.com"),
|
||||||
|
create_nano_str("192.168.1.100"),
|
||||||
|
80,
|
||||||
|
create_nano_str("/dogs.html"),
|
||||||
|
create_nano_str("192.168.1.101"),
|
||||||
|
253,
|
||||||
|
create_nano_str("nanoattachmentut.com"),
|
||||||
|
create_nano_str("/dogs.html")
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpHeaderData http_headers[3] = {
|
||||||
|
{
|
||||||
|
create_nano_str("Host"),
|
||||||
|
create_nano_str("www.nanoattachmentut.com")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
create_nano_str("User-Agent"),
|
||||||
|
create_nano_str("Mozilla/5.0")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
create_nano_str("Accept"),
|
||||||
|
create_nano_str("text/html")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpHeaders http_headers_data = {
|
||||||
|
http_headers,
|
||||||
|
3
|
||||||
|
};
|
||||||
|
|
||||||
|
nano_str_t body[3] = {
|
||||||
|
create_nano_str("Hello"),
|
||||||
|
create_nano_str("World"),
|
||||||
|
create_nano_str("!")
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpBody http_body_data = {
|
||||||
|
body,
|
||||||
|
3
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentData start_data = {
|
||||||
|
1,
|
||||||
|
HttpChunkType::HTTP_REQUEST_METADATA,
|
||||||
|
session_data,
|
||||||
|
(DataBuffer)&http_meta_data
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentData req_header_data = {
|
||||||
|
1,
|
||||||
|
HttpChunkType::HTTP_REQUEST_HEADER,
|
||||||
|
session_data,
|
||||||
|
(DataBuffer)&http_headers_data
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentData req_body_data = {
|
||||||
|
1,
|
||||||
|
HttpChunkType::HTTP_REQUEST_BODY,
|
||||||
|
session_data,
|
||||||
|
(DataBuffer)&http_body_data
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentData req_end_data = {
|
||||||
|
1,
|
||||||
|
HttpChunkType::HTTP_REQUEST_END,
|
||||||
|
session_data,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
NanoAttachment *attachment;
|
||||||
|
HttpSessionData *session_data;
|
||||||
|
StrictMock<NanoAttachmentSenderMocker> sender_mocker;
|
||||||
|
StrictMock<NanoInitializerMocker> initializer_mocker;
|
||||||
|
StrictMock<NanoSocketMocker> socket_mocker;
|
||||||
|
StrictMock<NanoConfigurationMocker> configuration_mocker;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentTest, InitNanoAttachment)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(strcmp(attachment->shared_verdict_signal_path, ""), 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(attachment->worker_id, 2);
|
||||||
|
EXPECT_EQ(attachment->num_of_workers, 4);
|
||||||
|
EXPECT_EQ(attachment->nano_user_id, getuid());
|
||||||
|
EXPECT_EQ(attachment->nano_group_id, getgid());
|
||||||
|
EXPECT_EQ(attachment->registration_socket, -1);
|
||||||
|
EXPECT_EQ(attachment->attachment_type, static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID));
|
||||||
|
EXPECT_EQ(attachment->comm_socket, -1);
|
||||||
|
EXPECT_EQ(attachment->logging_fd, STDOUT_FILENO);
|
||||||
|
|
||||||
|
EXPECT_EQ(attachment->is_configuration_updated, NanoCommunicationResult::NANO_ERROR);
|
||||||
|
EXPECT_EQ(attachment->current_config_version, 0u);
|
||||||
|
EXPECT_EQ(attachment->dbg_level, nano_http_cp_debug_level::DBG_LEVEL_INFO);
|
||||||
|
EXPECT_EQ(attachment->num_of_connection_attempts, 0);
|
||||||
|
EXPECT_EQ(attachment->fail_open_timeout, 50u);
|
||||||
|
EXPECT_EQ(attachment->fail_open_delayed_timeout, 150u);
|
||||||
|
EXPECT_EQ(attachment->sessions_per_minute_limit_verdict, AttachmentVerdict::ATTACHMENT_VERDICT_ACCEPT);
|
||||||
|
EXPECT_EQ(attachment->max_sessions_per_minute, 0u);
|
||||||
|
EXPECT_EQ(attachment->req_max_proccessing_ms_time, 3000u);
|
||||||
|
EXPECT_EQ(attachment->res_max_proccessing_ms_time, 3000u);
|
||||||
|
EXPECT_EQ(attachment->registration_thread_timeout_msec, 100u);
|
||||||
|
EXPECT_EQ(attachment->req_start_thread_timeout_msec, 100u);
|
||||||
|
EXPECT_EQ(attachment->req_header_thread_timeout_msec, 100u);
|
||||||
|
EXPECT_EQ(attachment->req_body_thread_timeout_msec, 150u);
|
||||||
|
EXPECT_EQ(attachment->res_header_thread_timeout_msec, 100u);
|
||||||
|
EXPECT_EQ(attachment->res_body_thread_timeout_msec, 150u);
|
||||||
|
EXPECT_EQ(attachment->waiting_for_verdict_thread_timeout_msec, 150u);
|
||||||
|
EXPECT_EQ(attachment->inspection_mode, NanoHttpInspectionMode::NON_BLOCKING_THREAD);
|
||||||
|
EXPECT_EQ(attachment->num_of_nano_ipc_elements, 200u);
|
||||||
|
EXPECT_EQ(attachment->keep_alive_interval_msec, DEFAULT_KEEP_ALIVE_INTERVAL_MSEC);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
configuration_mocker,
|
||||||
|
reset_attachment_config(_)
|
||||||
|
).WillOnce(
|
||||||
|
Return(NanoCommunicationResult::NANO_OK)
|
||||||
|
);
|
||||||
|
|
||||||
|
RestartAttachmentConfiguration(attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentTest, InitSessionData)
|
||||||
|
{
|
||||||
|
EXPECT_NE(session_data, nullptr);
|
||||||
|
EXPECT_EQ(session_data->was_request_fully_inspected, 0);
|
||||||
|
EXPECT_EQ(session_data->verdict, ServiceVerdict::TRAFFIC_VERDICT_INSPECT);
|
||||||
|
EXPECT_EQ(session_data->session_id, 1u);
|
||||||
|
EXPECT_EQ(session_data->remaining_messages_to_reply, 0u);
|
||||||
|
EXPECT_EQ(session_data->req_proccesing_time, 0u);
|
||||||
|
EXPECT_EQ(session_data->res_proccesing_time, 0u);
|
||||||
|
EXPECT_EQ(session_data->processed_req_body_size, 0u);
|
||||||
|
EXPECT_EQ(session_data->processed_res_body_size, 0u);
|
||||||
|
EXPECT_EQ(IsSessionFinalized(attachment, session_data), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentTest, AcceptFlow)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(sender_mocker, SendMetadata(attachment, &start_data)).WillOnce(Return(inspect_response));
|
||||||
|
EXPECT_CALL(sender_mocker, SendRequestHeaders(attachment, &req_header_data)).WillOnce(Return(inspect_response));
|
||||||
|
EXPECT_CALL(sender_mocker, SendRequestBody(attachment, &req_body_data)).WillOnce(Return(inspect_response));
|
||||||
|
EXPECT_CALL(sender_mocker, SendRequestEnd(attachment, &req_end_data)).WillOnce(Return(accept_response));
|
||||||
|
|
||||||
|
AttachmentVerdictResponse response = SendDataNanoAttachment(attachment, &start_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_INSPECT);
|
||||||
|
EXPECT_EQ(GetWebResponseType(attachment, session_data, &response), NanoWebResponseType::NO_WEB_RESPONSE);
|
||||||
|
FreeAttachmentResponseContent(attachment, session_data, &response);
|
||||||
|
|
||||||
|
response = SendDataNanoAttachment(attachment, &req_header_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_INSPECT);
|
||||||
|
EXPECT_EQ(GetWebResponseType(attachment, session_data, &response), NanoWebResponseType::NO_WEB_RESPONSE);
|
||||||
|
FreeAttachmentResponseContent(attachment, session_data, &response);
|
||||||
|
|
||||||
|
response = SendDataNanoAttachment(attachment, &req_body_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_INSPECT);
|
||||||
|
EXPECT_EQ(GetWebResponseType(attachment, session_data, &response), NanoWebResponseType::NO_WEB_RESPONSE);
|
||||||
|
FreeAttachmentResponseContent(attachment, session_data, &response);
|
||||||
|
|
||||||
|
response = SendDataNanoAttachment(attachment, &req_end_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_ACCEPT);
|
||||||
|
EXPECT_EQ(GetWebResponseType(attachment, session_data, &response), NanoWebResponseType::NO_WEB_RESPONSE);
|
||||||
|
FreeAttachmentResponseContent(attachment, session_data, &response);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentTest, DropFlow)
|
||||||
|
{
|
||||||
|
AttachmentVerdictResponse response;
|
||||||
|
BlockPageData block_page_data;
|
||||||
|
custom_drop_response.web_response_data = create_custom_drop_response_data();
|
||||||
|
|
||||||
|
EXPECT_CALL(sender_mocker, SendMetadata(attachment, &start_data)).WillOnce(Return(inspect_response));
|
||||||
|
EXPECT_CALL(sender_mocker, SendRequestHeaders(attachment, &req_header_data)).WillOnce(Return(inspect_response));
|
||||||
|
EXPECT_CALL(sender_mocker, SendRequestBody(attachment, &req_body_data)).WillOnce(Return(inspect_response));
|
||||||
|
EXPECT_CALL(sender_mocker, SendRequestEnd(attachment, &req_end_data)).WillOnce(Return(custom_drop_response));
|
||||||
|
|
||||||
|
response = SendDataNanoAttachment(attachment, &start_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_INSPECT);
|
||||||
|
EXPECT_EQ(GetWebResponseType(attachment, session_data, &response), NanoWebResponseType::NO_WEB_RESPONSE);
|
||||||
|
FreeAttachmentResponseContent(attachment, session_data, &response);
|
||||||
|
|
||||||
|
response = SendDataNanoAttachment(attachment, &req_header_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_INSPECT);
|
||||||
|
EXPECT_EQ(GetWebResponseType(attachment, session_data, &response), NanoWebResponseType::NO_WEB_RESPONSE);
|
||||||
|
FreeAttachmentResponseContent(attachment, session_data, &response);
|
||||||
|
|
||||||
|
response = SendDataNanoAttachment(attachment, &req_body_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_INSPECT);
|
||||||
|
EXPECT_EQ(GetWebResponseType(attachment, session_data, &response), NanoWebResponseType::NO_WEB_RESPONSE);
|
||||||
|
FreeAttachmentResponseContent(attachment, session_data, &response);
|
||||||
|
|
||||||
|
response = SendDataNanoAttachment(attachment, &req_end_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_DROP);
|
||||||
|
EXPECT_EQ(GetWebResponseType(attachment, session_data, &response), NanoWebResponseType::CUSTOM_WEB_RESPONSE);
|
||||||
|
|
||||||
|
block_page_data = GetBlockPage(attachment, session_data, &response);
|
||||||
|
EXPECT_EQ(block_page_data.response_code, 502);
|
||||||
|
EXPECT_EQ(strcmp((char *)block_page_data.uuid.data, "TestThisIsUuidTest"), 0);
|
||||||
|
EXPECT_EQ(strcmp((char *)block_page_data.title.data, "Woof Woof"), 0);
|
||||||
|
EXPECT_EQ(strcmp((char *)block_page_data.body.data, "This is Ruby's barking"), 0);
|
||||||
|
|
||||||
|
FreeAttachmentResponseContent(attachment, session_data, &response);
|
||||||
|
EXPECT_EQ(GetWebResponseType(attachment, session_data, &response), NanoWebResponseType::NO_WEB_RESPONSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentTest, RedirectFlow)
|
||||||
|
{
|
||||||
|
AttachmentVerdictResponse response;
|
||||||
|
RedirectPageData redirect_page_data;
|
||||||
|
custom_drop_response.web_response_data = create_redirect_response_data();
|
||||||
|
|
||||||
|
EXPECT_CALL(sender_mocker, SendMetadata(attachment, &start_data)).WillOnce(Return(inspect_response));
|
||||||
|
EXPECT_CALL(sender_mocker, SendRequestHeaders(attachment, &req_header_data)).WillOnce(Return(inspect_response));
|
||||||
|
EXPECT_CALL(sender_mocker, SendRequestBody(attachment, &req_body_data)).WillOnce(Return(inspect_response));
|
||||||
|
EXPECT_CALL(sender_mocker, SendRequestEnd(attachment, &req_end_data)).WillOnce(Return(custom_drop_response));
|
||||||
|
|
||||||
|
response = SendDataNanoAttachment(attachment, &start_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_INSPECT);
|
||||||
|
EXPECT_EQ(GetWebResponseType(attachment, session_data, &response), NanoWebResponseType::NO_WEB_RESPONSE);
|
||||||
|
FreeAttachmentResponseContent(attachment, session_data, &response);
|
||||||
|
|
||||||
|
response = SendDataNanoAttachment(attachment, &req_header_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_INSPECT);
|
||||||
|
EXPECT_EQ(GetWebResponseType(attachment, session_data, &response), NanoWebResponseType::NO_WEB_RESPONSE);
|
||||||
|
FreeAttachmentResponseContent(attachment, session_data, &response);
|
||||||
|
|
||||||
|
response = SendDataNanoAttachment(attachment, &req_body_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_INSPECT);
|
||||||
|
EXPECT_EQ(GetWebResponseType(attachment, session_data, &response), NanoWebResponseType::NO_WEB_RESPONSE);
|
||||||
|
FreeAttachmentResponseContent(attachment, session_data, &response);
|
||||||
|
|
||||||
|
response = SendDataNanoAttachment(attachment, &req_end_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_DROP);
|
||||||
|
EXPECT_EQ(GetWebResponseType(attachment, session_data, &response), NanoWebResponseType::REDIRECT_WEB_RESPONSE);
|
||||||
|
|
||||||
|
redirect_page_data = GetRedirectPage(attachment, session_data, &response);
|
||||||
|
EXPECT_EQ(strcmp((char *)redirect_page_data.redirect_location.data, "Woowwwiee.com"), 0);
|
||||||
|
|
||||||
|
FreeAttachmentResponseContent(attachment, session_data, &response);
|
||||||
|
EXPECT_EQ(GetWebResponseType(attachment, session_data, &response), NanoWebResponseType::NO_WEB_RESPONSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentTest, ModificationsFlow)
|
||||||
|
{
|
||||||
|
AttachmentVerdictResponse response;
|
||||||
|
NanoResponseModifications response_modifications;
|
||||||
|
accept_response.modifications = create_modifications_data();
|
||||||
|
|
||||||
|
EXPECT_CALL(sender_mocker, SendMetadata(attachment, &start_data)).WillOnce(Return(inspect_response));
|
||||||
|
EXPECT_CALL(sender_mocker, SendRequestHeaders(attachment, &req_header_data)).WillOnce(Return(inspect_response));
|
||||||
|
EXPECT_CALL(sender_mocker, SendRequestBody(attachment, &req_body_data)).WillOnce(Return(inspect_response));
|
||||||
|
EXPECT_CALL(sender_mocker, SendRequestEnd(attachment, &req_end_data)).WillOnce(Return(accept_response));
|
||||||
|
|
||||||
|
response = SendDataNanoAttachment(attachment, &start_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_INSPECT);
|
||||||
|
EXPECT_EQ(GetWebResponseType(attachment, session_data, &response), NanoWebResponseType::NO_WEB_RESPONSE);
|
||||||
|
FreeAttachmentResponseContent(attachment, session_data, &response);
|
||||||
|
|
||||||
|
response = SendDataNanoAttachment(attachment, &req_header_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_INSPECT);
|
||||||
|
EXPECT_EQ(GetWebResponseType(attachment, session_data, &response), NanoWebResponseType::NO_WEB_RESPONSE);
|
||||||
|
FreeAttachmentResponseContent(attachment, session_data, &response);
|
||||||
|
|
||||||
|
response = SendDataNanoAttachment(attachment, &req_body_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_INSPECT);
|
||||||
|
EXPECT_EQ(GetWebResponseType(attachment, session_data, &response), NanoWebResponseType::NO_WEB_RESPONSE);
|
||||||
|
FreeAttachmentResponseContent(attachment, session_data, &response);
|
||||||
|
|
||||||
|
response = SendDataNanoAttachment(attachment, &req_end_data);
|
||||||
|
EXPECT_EQ(response.session_id, 1u);
|
||||||
|
EXPECT_EQ(response.verdict, AttachmentVerdict::ATTACHMENT_VERDICT_ACCEPT);
|
||||||
|
EXPECT_EQ(GetWebResponseType(attachment, session_data, &response), NanoWebResponseType::NO_WEB_RESPONSE);
|
||||||
|
EXPECT_EQ(IsResponseWithModification(attachment, session_data, &response), 1);
|
||||||
|
response_modifications = GetResponseModifications(attachment, session_data, &response);
|
||||||
|
EXPECT_NE(response_modifications.modifications, nullptr);
|
||||||
|
EXPECT_EQ(response_modifications.modifications->next, nullptr);
|
||||||
|
EXPECT_EQ(response_modifications.modifications->modification.mod_type, HttpModificationType::APPEND);
|
||||||
|
|
||||||
|
FreeAttachmentResponseContent(attachment, session_data, &response);
|
||||||
|
EXPECT_EQ(GetWebResponseType(attachment, session_data, &response), NanoWebResponseType::NO_WEB_RESPONSE);
|
||||||
|
EXPECT_EQ(IsResponseWithModification(attachment, session_data, &response), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentTest, SendAlive)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(socket_mocker, socket(AF_UNIX, SOCK_STREAM, 0)).WillOnce(Return(34));
|
||||||
|
EXPECT_CALL(socket_mocker, connect(34, _, _)).WillOnce(Return(0));
|
||||||
|
EXPECT_CALL(initializer_mocker, write_to_service(attachment, _, _, _, _))
|
||||||
|
.WillRepeatedly(Return(NanoCommunicationResult::NANO_OK));
|
||||||
|
EXPECT_CALL(socket_mocker, close(34));
|
||||||
|
SendKeepAlive(attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentTest, SendAliveFail)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(socket_mocker, socket(AF_UNIX, SOCK_STREAM, 0)).WillOnce(Return(34));
|
||||||
|
EXPECT_CALL(socket_mocker, connect(34, _, _)).WillOnce(Return(-1));
|
||||||
|
EXPECT_CALL(socket_mocker, close(34));
|
||||||
|
SendKeepAlive(attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentTest, TestMetricUpdate)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(attachment->metric_data[static_cast<int>(AttachmentMetricType::INJECT_VERDICTS_COUNT)], 0u);
|
||||||
|
UpdateMetric(attachment, AttachmentMetricType::INJECT_VERDICTS_COUNT, 100);
|
||||||
|
EXPECT_EQ(attachment->metric_data[static_cast<int>(AttachmentMetricType::INJECT_VERDICTS_COUNT)], 100u);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentTest, SendAccumulatedMetricData)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(sender_mocker, SendMetricData(attachment)).WillOnce(Return(NanoCommunicationResult::NANO_OK));
|
||||||
|
SendAccumulatedMetricData(attachment);
|
||||||
|
}
|
@ -0,0 +1,129 @@
|
|||||||
|
#include "cptest.h"
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "attachment_types.h"
|
||||||
|
#include "http_configuration.h"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "nano_attachment.h"
|
||||||
|
#include "nano_configuration.h"
|
||||||
|
#include "nano_utils.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace testing;
|
||||||
|
|
||||||
|
class NanoConfigurationTest : public Test
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
string
|
||||||
|
createIPRangesString(const vector<string> &ip_ranges)
|
||||||
|
{
|
||||||
|
stringstream ip_ranges_string_stream;
|
||||||
|
ip_ranges_string_stream << "[";
|
||||||
|
for (auto iterator = ip_ranges.begin(); iterator < ip_ranges.end() - 1; iterator++) {
|
||||||
|
ip_ranges_string_stream << "\"" << *iterator << "\"" << ", ";
|
||||||
|
}
|
||||||
|
ip_ranges_string_stream << "\"" << ip_ranges.back() << "\"]";
|
||||||
|
|
||||||
|
return ip_ranges_string_stream.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
NanoAttachment attachment;
|
||||||
|
LoggingData logging_data;
|
||||||
|
const string static_resources_path = "/dev/shm/static_resources/";
|
||||||
|
const vector<string> ip_ranges = { "8.8.8.8", "9.9.9.9-10.10.10.10", "0:0:0:0:0:0:0:1-0:0:0:0:0:0:0:4"};
|
||||||
|
const string attachment_configuration_file_name = "cp_nano_http_attachment_conf";
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(NanoConfigurationTest, InitAttachmentConfiguration)
|
||||||
|
{
|
||||||
|
NanoCommunicationResult res;
|
||||||
|
string valid_configuration =
|
||||||
|
"{\n"
|
||||||
|
"\"context_values\": {"
|
||||||
|
"\"clientIp\": \"1.2.3.4\","
|
||||||
|
"\"listeningIp\": \"5.6.7.8\","
|
||||||
|
"\"uriPrefix\": \"/abc\","
|
||||||
|
"\"hostName\": \"test\","
|
||||||
|
"\"httpMethod\": \"GET\","
|
||||||
|
"\"listeningPort\": 80"
|
||||||
|
"},"
|
||||||
|
"\"is_fail_open_mode_enabled\": 0,\n"
|
||||||
|
"\"fail_open_timeout\": 1234,\n"
|
||||||
|
"\"is_fail_open_mode_hold_enabled\": 0,\n"
|
||||||
|
"\"fail_open_hold_timeout\": 4321,\n"
|
||||||
|
"\"sessions_per_minute_limit_verdict\": \"Accept\",\n"
|
||||||
|
"\"max_sessions_per_minute\": 0,\n"
|
||||||
|
"\"num_of_nginx_ipc_elements\": 200,\n"
|
||||||
|
"\"keep_alive_interval_msec\": 10000,\n"
|
||||||
|
"\"dbg_level\": 2,\n"
|
||||||
|
"\"nginx_inspection_mode\": 1,\n"
|
||||||
|
"\"operation_mode\": 0,\n"
|
||||||
|
"\"req_body_thread_timeout_msec\": 155,\n"
|
||||||
|
"\"req_proccessing_timeout_msec\": 42,\n"
|
||||||
|
"\"registration_thread_timeout_msec\": 101,\n"
|
||||||
|
"\"res_proccessing_timeout_msec\": 420,\n"
|
||||||
|
"\"res_header_thread_timeout_msec\": 1,\n"
|
||||||
|
"\"res_body_thread_timeout_msec\": 80,\n"
|
||||||
|
"\"waiting_for_verdict_thread_timeout_msec\": 60,\n"
|
||||||
|
"\"req_header_thread_timeout_msec\": 10,\n"
|
||||||
|
"\"ip_ranges\": " + createIPRangesString(ip_ranges) + ",\n"
|
||||||
|
"\"static_resources_path\": \"" + static_resources_path + "\""
|
||||||
|
"}\n";
|
||||||
|
ofstream valid_configuration_file(attachment_configuration_file_name);
|
||||||
|
valid_configuration_file << valid_configuration;
|
||||||
|
valid_configuration_file.close();
|
||||||
|
|
||||||
|
attachment.shared_verdict_signal_path[0] = '\0';
|
||||||
|
attachment.worker_id = 2;
|
||||||
|
attachment.num_of_workers = 4;
|
||||||
|
attachment.nano_user_id = getuid();
|
||||||
|
attachment.nano_group_id = getgid();
|
||||||
|
attachment.registration_socket = -1;
|
||||||
|
attachment.attachment_type = static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID);
|
||||||
|
attachment.nano_service_ipc = NULL;
|
||||||
|
attachment.comm_socket = -1;
|
||||||
|
attachment.logging_data = &logging_data;
|
||||||
|
|
||||||
|
res = set_logging_fd(&attachment, STDOUT_FILENO);
|
||||||
|
EXPECT_EQ(res, NanoCommunicationResult::NANO_OK);
|
||||||
|
|
||||||
|
setenv("CLOUDGUARD_UID", "Testing", 1);
|
||||||
|
res = set_docker_id(&attachment);
|
||||||
|
EXPECT_EQ(res, NanoCommunicationResult::NANO_OK);
|
||||||
|
|
||||||
|
res = set_unique_id(&attachment);
|
||||||
|
EXPECT_EQ(res, NanoCommunicationResult::NANO_OK);
|
||||||
|
|
||||||
|
attachment.is_configuration_updated = NanoCommunicationResult::NANO_ERROR;
|
||||||
|
attachment.current_config_version = 0;
|
||||||
|
attachment.dbg_level = nano_http_cp_debug_level_e::DBG_LEVEL_TRACE;
|
||||||
|
|
||||||
|
res = init_attachment_config(&attachment, attachment_configuration_file_name.c_str());
|
||||||
|
EXPECT_EQ(res, NanoCommunicationResult::NANO_OK);
|
||||||
|
|
||||||
|
EXPECT_EQ(attachment.is_configuration_updated, NanoCommunicationResult::NANO_OK);
|
||||||
|
EXPECT_EQ(attachment.dbg_level, nano_http_cp_debug_level_e::DBG_LEVEL_INFO);
|
||||||
|
EXPECT_EQ(attachment.fail_mode_verdict, 1);
|
||||||
|
EXPECT_EQ(attachment.fail_open_timeout, 1234u);
|
||||||
|
EXPECT_EQ(attachment.fail_mode_delayed_verdict, 1);
|
||||||
|
EXPECT_EQ(attachment.fail_open_delayed_timeout, 4321u);
|
||||||
|
EXPECT_EQ(attachment.sessions_per_minute_limit_verdict, AttachmentVerdict::ATTACHMENT_VERDICT_ACCEPT);
|
||||||
|
EXPECT_EQ(attachment.max_sessions_per_minute, 0u);
|
||||||
|
EXPECT_EQ(attachment.req_max_proccessing_ms_time, 42u);
|
||||||
|
EXPECT_EQ(attachment.res_max_proccessing_ms_time, 420u);
|
||||||
|
EXPECT_EQ(attachment.registration_thread_timeout_msec, 101u);
|
||||||
|
EXPECT_EQ(attachment.req_header_thread_timeout_msec, 10u);
|
||||||
|
EXPECT_EQ(attachment.req_body_thread_timeout_msec, 155u);
|
||||||
|
EXPECT_EQ(attachment.res_header_thread_timeout_msec, 1u);
|
||||||
|
EXPECT_EQ(attachment.res_body_thread_timeout_msec, 80u);
|
||||||
|
EXPECT_EQ(attachment.waiting_for_verdict_thread_timeout_msec, 60u);
|
||||||
|
EXPECT_EQ(attachment.num_of_nano_ipc_elements, 200u);
|
||||||
|
EXPECT_EQ(attachment.keep_alive_interval_msec, 10000u);
|
||||||
|
EXPECT_EQ(attachment.inspection_mode, NanoHttpInspectionMode::BLOCKING_THREAD);
|
||||||
|
|
||||||
|
res = reset_attachment_config(&attachment);
|
||||||
|
EXPECT_EQ(res, NanoCommunicationResult::NANO_ERROR);
|
||||||
|
}
|
@ -0,0 +1,373 @@
|
|||||||
|
#include "cptest.h"
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "attachment_types.h"
|
||||||
|
#include <poll.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "mock_nano_socket.h"
|
||||||
|
#include "mock_shmem_ipc.h"
|
||||||
|
#include "mock_nano_access.h"
|
||||||
|
#include "mock_nano_poll.h"
|
||||||
|
#include "mock_nano_configuration.h"
|
||||||
|
#include "mock_nano_stat.h"
|
||||||
|
#include "mock_nano_attachment_thread.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "nano_initializer.h"
|
||||||
|
#include "nano_attachment_sender_thread.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace testing;
|
||||||
|
|
||||||
|
class NanoInitializerTest : public Test
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void
|
||||||
|
SetUp() override
|
||||||
|
{
|
||||||
|
ipc_holder = make_unique<int>();
|
||||||
|
mock_ipc = reinterpret_cast<SharedMemoryIPC *>(ipc_holder.get());
|
||||||
|
|
||||||
|
set_logging_fd(&attachment, STDOUT_FILENO);
|
||||||
|
attachment.dbg_level = nano_http_cp_debug_level_e::DBG_LEVEL_TRACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NanoRunInThreadTimeoutInvoker(
|
||||||
|
AttachmentData *data,
|
||||||
|
void *arg,
|
||||||
|
int comm_socket,
|
||||||
|
NanoCommunicationResult com_res
|
||||||
|
)
|
||||||
|
{
|
||||||
|
|
||||||
|
HttpEventThreadCtx *ctx = (HttpEventThreadCtx *)arg;
|
||||||
|
init_thread_ctx(ctx, &attachment, data);
|
||||||
|
attachment.comm_socket = comm_socket;
|
||||||
|
attachment.registration_socket = comm_socket;
|
||||||
|
ctx->res = com_res;
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<int> ipc_holder;
|
||||||
|
NanoAttachment attachment;
|
||||||
|
SharedMemoryIPC *mock_ipc;
|
||||||
|
void *_ctx;
|
||||||
|
|
||||||
|
StrictMock<NanoSocketMocker> socket_mocker;
|
||||||
|
StrictMock<NanoShmemIPCMocker> ipc_mocker;
|
||||||
|
StrictMock<NanoAccessMocker> access_mocker;
|
||||||
|
StrictMock<NanoPollMocker> poll_mocker;
|
||||||
|
StrictMock<NanoConfigurationMocker> config_mocker;
|
||||||
|
StrictMock<NanoStatMocker> stat_mocker;
|
||||||
|
StrictMock<NanoAttachmentThreadMocker> thread_mocker;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(NanoInitializerTest, InitNanoAttachmentProcess)
|
||||||
|
{
|
||||||
|
NanoCommunicationResult res;
|
||||||
|
|
||||||
|
struct pollfd mock_s_poll;
|
||||||
|
struct pollfd *mock_s_poll_ptr = &mock_s_poll;
|
||||||
|
|
||||||
|
attachment.registration_state = nano_attachment_registration_state::REGISTERED;
|
||||||
|
attachment.comm_socket = -1;
|
||||||
|
attachment.nano_service_ipc = nullptr;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
poll_mocker,
|
||||||
|
poll(_, _, _)
|
||||||
|
).WillRepeatedly(
|
||||||
|
DoAll(
|
||||||
|
SaveArg<0>(&mock_s_poll_ptr),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
mock_s_poll_ptr->revents = POLLIN;
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
socket_mocker,
|
||||||
|
write(_, _, _)
|
||||||
|
).WillRepeatedly(Return(1));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
socket_mocker,
|
||||||
|
read(
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_
|
||||||
|
)
|
||||||
|
).Times(1)
|
||||||
|
.WillOnce(Return(sizeof(uint8_t)));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
thread_mocker,
|
||||||
|
NanoRunInThreadTimeout(
|
||||||
|
&attachment,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
TransactionType::REGISTRATION
|
||||||
|
)
|
||||||
|
).WillOnce(DoAll(SaveArg<3>(&_ctx),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
NanoRunInThreadTimeoutInvoker(
|
||||||
|
nullptr,
|
||||||
|
_ctx,
|
||||||
|
32,
|
||||||
|
NanoCommunicationResult::NANO_OK
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1))
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
config_mocker,
|
||||||
|
init_attachment_config(
|
||||||
|
&attachment,
|
||||||
|
_
|
||||||
|
)
|
||||||
|
).Times(2)
|
||||||
|
.WillOnce(Return(NanoCommunicationResult::NANO_ERROR))
|
||||||
|
.WillOnce(Return(NanoCommunicationResult::NANO_OK));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
access_mocker,
|
||||||
|
access(
|
||||||
|
_,
|
||||||
|
_
|
||||||
|
)
|
||||||
|
).WillOnce(Return(0));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
ipc_mocker,
|
||||||
|
initIpc(
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_
|
||||||
|
)
|
||||||
|
).WillOnce(Return(mock_ipc));
|
||||||
|
|
||||||
|
res = nano_attachment_init_process(&attachment);
|
||||||
|
EXPECT_EQ(res, NanoCommunicationResult::NANO_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoInitializerTest, RegisterToAttachment)
|
||||||
|
{
|
||||||
|
NanoCommunicationResult res;
|
||||||
|
struct pollfd mock_s_poll;
|
||||||
|
struct pollfd *mock_s_poll_ptr = &mock_s_poll;
|
||||||
|
|
||||||
|
attachment.comm_socket = 53;
|
||||||
|
attachment.registration_socket = 34;
|
||||||
|
attachment.nano_service_ipc = mock_ipc;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
socket_mocker,
|
||||||
|
close(34)
|
||||||
|
).WillOnce(Return(0));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
socket_mocker,
|
||||||
|
close(88)
|
||||||
|
).WillOnce(Return(0));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
thread_mocker,
|
||||||
|
NanoRunInThreadTimeout(
|
||||||
|
&attachment,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
TransactionType::REGISTRATION
|
||||||
|
)
|
||||||
|
).WillOnce(DoAll(SaveArg<3>(&_ctx),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
NanoRunInThreadTimeoutInvoker(
|
||||||
|
nullptr,
|
||||||
|
_ctx,
|
||||||
|
88,
|
||||||
|
NanoCommunicationResult::NANO_OK
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1))
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
socket_mocker,
|
||||||
|
write(_, _, _)
|
||||||
|
).WillRepeatedly(Return(1));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
poll_mocker,
|
||||||
|
poll(_, _, _)
|
||||||
|
).WillRepeatedly(
|
||||||
|
DoAll(
|
||||||
|
SaveArg<0>(&mock_s_poll_ptr),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
mock_s_poll_ptr->revents = POLLIN;
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
socket_mocker,
|
||||||
|
read(
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_
|
||||||
|
)
|
||||||
|
).Times(1)
|
||||||
|
.WillOnce(Return(sizeof(uint8_t)));
|
||||||
|
|
||||||
|
res = register_to_attachments_manager(&attachment);
|
||||||
|
EXPECT_EQ(res, NanoCommunicationResult::NANO_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoInitializerTest, DisconnectCommunication)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
attachment.comm_socket = 53;
|
||||||
|
attachment.nano_service_ipc = mock_ipc;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
socket_mocker,
|
||||||
|
close(53)
|
||||||
|
).WillOnce(Return(-1));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
ipc_mocker,
|
||||||
|
destroyIpc(mock_ipc, 0)
|
||||||
|
).WillOnce(Return());
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
ipc_mocker,
|
||||||
|
isCorruptedShmem(mock_ipc, 0)
|
||||||
|
).WillOnce(Return(0));
|
||||||
|
|
||||||
|
handle_shmem_corruption(&attachment);
|
||||||
|
|
||||||
|
disconnect_communication(&attachment);
|
||||||
|
|
||||||
|
EXPECT_EQ(attachment.comm_socket, -1);
|
||||||
|
EXPECT_EQ(attachment.nano_service_ipc, nullptr);
|
||||||
|
|
||||||
|
res = isIpcReady(&attachment);
|
||||||
|
EXPECT_EQ(res, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoInitializerTest, RestartCommunication)
|
||||||
|
{
|
||||||
|
NanoCommunicationResult res;
|
||||||
|
struct pollfd mock_s_poll;
|
||||||
|
struct pollfd *mock_s_poll_ptr = &mock_s_poll;
|
||||||
|
|
||||||
|
attachment.comm_socket = 53;
|
||||||
|
attachment.registration_socket = 34;
|
||||||
|
attachment.nano_service_ipc = mock_ipc;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
ipc_mocker,
|
||||||
|
destroyIpc(mock_ipc, 0)
|
||||||
|
).WillOnce(Return());
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
poll_mocker,
|
||||||
|
poll(_, _, _)
|
||||||
|
).WillRepeatedly(
|
||||||
|
DoAll(
|
||||||
|
SaveArg<0>(&mock_s_poll_ptr),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
mock_s_poll_ptr->revents = POLLIN;
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
socket_mocker,
|
||||||
|
write(_, _, _)
|
||||||
|
).WillRepeatedly(Return(1));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
socket_mocker,
|
||||||
|
read(
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_
|
||||||
|
)
|
||||||
|
).Times(1)
|
||||||
|
.WillOnce(Return(sizeof(uint8_t)));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
ipc_mocker,
|
||||||
|
initIpc(
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_
|
||||||
|
)
|
||||||
|
).WillOnce(Return(mock_ipc));
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
thread_mocker,
|
||||||
|
NanoRunInThreadTimeout(
|
||||||
|
&attachment,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
TransactionType::REGISTRATION
|
||||||
|
)
|
||||||
|
).WillOnce(DoAll(SaveArg<3>(&_ctx),
|
||||||
|
InvokeWithoutArgs(
|
||||||
|
[&] () {
|
||||||
|
NanoRunInThreadTimeoutInvoker(
|
||||||
|
nullptr,
|
||||||
|
_ctx,
|
||||||
|
53,
|
||||||
|
NanoCommunicationResult::NANO_OK
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Return(1))
|
||||||
|
);
|
||||||
|
|
||||||
|
res = restart_communication(&attachment);
|
||||||
|
EXPECT_EQ(res, NanoCommunicationResult::NANO_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoInitializerTest, SetLoggingFailure)
|
||||||
|
{
|
||||||
|
NanoCommunicationResult res;
|
||||||
|
EXPECT_CALL(stat_mocker, mkdir(_, _)).WillOnce(Return(-1));
|
||||||
|
|
||||||
|
res = set_logging_fd(&attachment, 0);
|
||||||
|
EXPECT_EQ(res, NanoCommunicationResult::NANO_ERROR);
|
||||||
|
}
|
@ -0,0 +1,466 @@
|
|||||||
|
#include "cptest.h"
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "attachment_types.h"
|
||||||
|
|
||||||
|
#include "mock_nano_initializer.h"
|
||||||
|
#include "mock_nano_attachment_io.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "nano_attachment.h"
|
||||||
|
#include "nano_attachment_sender_thread.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace testing;
|
||||||
|
|
||||||
|
class NanoAttachmentSenderThreadTest : public Test
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void
|
||||||
|
SetUp() override
|
||||||
|
{
|
||||||
|
EXPECT_CALL(
|
||||||
|
initializer_mocker,
|
||||||
|
nano_attachment_init_process(_)
|
||||||
|
).WillOnce(
|
||||||
|
Return(NanoCommunicationResult::NANO_OK)
|
||||||
|
);
|
||||||
|
setenv("CLOUDGUARD_UID", "Testing", 1);
|
||||||
|
attachment = InitNanoAttachment(
|
||||||
|
static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID),
|
||||||
|
2,
|
||||||
|
4,
|
||||||
|
STDOUT_FILENO
|
||||||
|
);
|
||||||
|
EXPECT_NE(attachment, nullptr);
|
||||||
|
attachment->dbg_level = nano_http_cp_debug_level::DBG_LEVEL_TRACE;
|
||||||
|
|
||||||
|
session_data = InitSessionData(attachment, 1);
|
||||||
|
EXPECT_NE(session_data, nullptr);
|
||||||
|
start_data.session_data = session_data;
|
||||||
|
req_header_data.session_data = session_data;
|
||||||
|
res_header_data.session_data = session_data;
|
||||||
|
req_body_data.session_data = session_data;
|
||||||
|
res_body_data.session_data = session_data;
|
||||||
|
req_end_data.session_data = session_data;
|
||||||
|
res_end_data.session_data = session_data;
|
||||||
|
delayed_verdict_data.session_data = session_data;
|
||||||
|
req_filter_data.session_data = session_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TearDown() override
|
||||||
|
{
|
||||||
|
FiniSessionData(attachment, session_data);
|
||||||
|
FiniNanoAttachment(attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
nano_str_t
|
||||||
|
create_nano_str(const char *str)
|
||||||
|
{
|
||||||
|
nano_str_t nano_str;
|
||||||
|
nano_str.data = reinterpret_cast<unsigned char *>(const_cast<char *>(str));
|
||||||
|
nano_str.len = strlen(str);
|
||||||
|
return nano_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpMetaData http_meta_data = {
|
||||||
|
create_nano_str("HTTP/1.1"),
|
||||||
|
create_nano_str("GET"),
|
||||||
|
create_nano_str("www.nanoattachmentut.com"),
|
||||||
|
create_nano_str("192.168.1.100"),
|
||||||
|
80,
|
||||||
|
create_nano_str("/dogs.html"),
|
||||||
|
create_nano_str("192.168.1.101"),
|
||||||
|
253,
|
||||||
|
create_nano_str("nanoattachmentut.com"),
|
||||||
|
create_nano_str("/dogs.html")
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpHeaderData http_headers[3] = {
|
||||||
|
{
|
||||||
|
create_nano_str("Host"),
|
||||||
|
create_nano_str("www.nanoattachmentut.com")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
create_nano_str("User-Agent"),
|
||||||
|
create_nano_str("Mozilla/5.0")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
create_nano_str("Accept"),
|
||||||
|
create_nano_str("text/html")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpHeaders http_headers_data = {
|
||||||
|
http_headers,
|
||||||
|
3
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpRequestFilterData request_filter_data = {
|
||||||
|
&http_meta_data,
|
||||||
|
&http_headers_data,
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
ResHttpHeaders res_http_headers_data = {
|
||||||
|
&http_headers_data,
|
||||||
|
static_cast<uint16_t>(522),
|
||||||
|
static_cast<uint64_t>(300)
|
||||||
|
};
|
||||||
|
|
||||||
|
nano_str_t body[3] = {
|
||||||
|
create_nano_str("Hello"),
|
||||||
|
create_nano_str("World"),
|
||||||
|
create_nano_str("!")
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpBody http_body_data = {
|
||||||
|
body,
|
||||||
|
3
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentData start_data = {
|
||||||
|
1,
|
||||||
|
HttpChunkType::HTTP_REQUEST_METADATA,
|
||||||
|
session_data,
|
||||||
|
(DataBuffer)&http_meta_data
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentData req_header_data = {
|
||||||
|
1,
|
||||||
|
HttpChunkType::HTTP_REQUEST_HEADER,
|
||||||
|
session_data,
|
||||||
|
(DataBuffer)&http_headers_data
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentData req_filter_data = {
|
||||||
|
1,
|
||||||
|
HttpChunkType::HTTP_REQUEST_FILTER,
|
||||||
|
session_data,
|
||||||
|
(DataBuffer)&request_filter_data
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentData res_header_data = {
|
||||||
|
1,
|
||||||
|
HttpChunkType::HTTP_RESPONSE_HEADER,
|
||||||
|
session_data,
|
||||||
|
(DataBuffer)&res_http_headers_data
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentData req_body_data = {
|
||||||
|
1,
|
||||||
|
HttpChunkType::HTTP_REQUEST_BODY,
|
||||||
|
session_data,
|
||||||
|
(DataBuffer)&http_body_data
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentData res_body_data = {
|
||||||
|
1,
|
||||||
|
HttpChunkType::HTTP_RESPONSE_BODY,
|
||||||
|
session_data,
|
||||||
|
(DataBuffer)&http_body_data
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentData req_end_data = {
|
||||||
|
1,
|
||||||
|
HttpChunkType::HTTP_REQUEST_END,
|
||||||
|
session_data,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentData res_end_data = {
|
||||||
|
1,
|
||||||
|
HttpChunkType::HTTP_RESPONSE_END,
|
||||||
|
session_data,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentData delayed_verdict_data = {
|
||||||
|
1,
|
||||||
|
HttpChunkType::HOLD_DATA,
|
||||||
|
session_data,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
NanoAttachment *attachment;
|
||||||
|
HttpSessionData *session_data;
|
||||||
|
StrictMock<NanoInitializerMocker> initializer_mocker;
|
||||||
|
StrictMock<NanoAttachmentIoMocker> io_mocker;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderThreadTest, InitThreadCtx)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx ctx;
|
||||||
|
init_thread_ctx(&ctx, attachment, &req_body_data);
|
||||||
|
EXPECT_EQ(ctx.attachment, attachment);
|
||||||
|
EXPECT_EQ(ctx.data, &req_body_data);
|
||||||
|
EXPECT_EQ(ctx.session_data_p, session_data);
|
||||||
|
EXPECT_EQ(ctx.res, NanoCommunicationResult::NANO_OK);
|
||||||
|
EXPECT_EQ(ctx.web_response_data, nullptr);
|
||||||
|
EXPECT_EQ(ctx.modifications, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderThreadTest, RegistrationCommSocketThread)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx ctx;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
io_mocker,
|
||||||
|
connect_to_comm_socket(attachment)
|
||||||
|
);
|
||||||
|
|
||||||
|
init_thread_ctx(&ctx, attachment, nullptr);
|
||||||
|
RegistrationCommSocketThread(&ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderThreadTest, RegistrationSocketThread)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx ctx;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
io_mocker,
|
||||||
|
connect_to_registration_socket(attachment)
|
||||||
|
);
|
||||||
|
|
||||||
|
init_thread_ctx(&ctx, attachment, nullptr);
|
||||||
|
RegistrationSocketThread(&ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderThreadTest, SendMetadataThread)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx ctx;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
io_mocker,
|
||||||
|
nano_metadata_sender(
|
||||||
|
attachment,
|
||||||
|
(HttpMetaData *)start_data.data,
|
||||||
|
&ctx,
|
||||||
|
session_data->session_id,
|
||||||
|
&session_data->remaining_messages_to_reply,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
init_thread_ctx(&ctx, attachment, &start_data);
|
||||||
|
SendMetadataThread(&ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderThreadTest, SendRequestFilterThread)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx ctx;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
io_mocker,
|
||||||
|
nano_metadata_sender(
|
||||||
|
attachment,
|
||||||
|
(HttpMetaData *)start_data.data,
|
||||||
|
&ctx,
|
||||||
|
session_data->session_id,
|
||||||
|
&session_data->remaining_messages_to_reply,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
io_mocker,
|
||||||
|
nano_header_sender(
|
||||||
|
attachment,
|
||||||
|
(HttpHeaders *)req_header_data.data,
|
||||||
|
&ctx,
|
||||||
|
AttachmentDataType::REQUEST_HEADER,
|
||||||
|
session_data->session_id,
|
||||||
|
&session_data->remaining_messages_to_reply,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
io_mocker,
|
||||||
|
nano_end_transaction_sender(
|
||||||
|
attachment,
|
||||||
|
AttachmentDataType::REQUEST_END,
|
||||||
|
&ctx,
|
||||||
|
session_data->session_id,
|
||||||
|
&session_data->remaining_messages_to_reply
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
init_thread_ctx(&ctx, attachment, &req_filter_data);
|
||||||
|
SendRequestFilterThread(&ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderThreadTest, SendRequestHeadersThread)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx ctx;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
io_mocker,
|
||||||
|
nano_header_sender(
|
||||||
|
attachment,
|
||||||
|
(HttpHeaders *)req_header_data.data,
|
||||||
|
&ctx,
|
||||||
|
AttachmentDataType::REQUEST_HEADER,
|
||||||
|
session_data->session_id,
|
||||||
|
&session_data->remaining_messages_to_reply,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
init_thread_ctx(&ctx, attachment, &req_header_data);
|
||||||
|
SendRequestHeadersThread(&ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderThreadTest, SendResponseHeadersThread)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx ctx;
|
||||||
|
ResHttpHeaders *res_headers = (ResHttpHeaders *)res_header_data.data;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
io_mocker,
|
||||||
|
nano_send_response_code(
|
||||||
|
attachment,
|
||||||
|
static_cast<uint16_t>(522),
|
||||||
|
&ctx,
|
||||||
|
session_data->session_id,
|
||||||
|
&session_data->remaining_messages_to_reply
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
io_mocker,
|
||||||
|
nano_send_response_content_length(
|
||||||
|
attachment,
|
||||||
|
static_cast<uint64_t>(300),
|
||||||
|
&ctx,
|
||||||
|
session_data->session_id,
|
||||||
|
&session_data->remaining_messages_to_reply
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
io_mocker,
|
||||||
|
nano_header_sender(
|
||||||
|
attachment,
|
||||||
|
(HttpHeaders *)res_headers->headers,
|
||||||
|
&ctx,
|
||||||
|
AttachmentDataType::RESPONSE_HEADER,
|
||||||
|
session_data->session_id,
|
||||||
|
&session_data->remaining_messages_to_reply,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
init_thread_ctx(&ctx, attachment, &res_header_data);
|
||||||
|
SendResponseHeadersThread(&ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderThreadTest, SendRequestBodyThread)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx ctx;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
io_mocker,
|
||||||
|
nano_body_sender(
|
||||||
|
attachment,
|
||||||
|
(HttpBody *)req_body_data.data,
|
||||||
|
&ctx,
|
||||||
|
AttachmentDataType::REQUEST_BODY,
|
||||||
|
session_data->session_id,
|
||||||
|
&session_data->remaining_messages_to_reply
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
init_thread_ctx(&ctx, attachment, &req_body_data);
|
||||||
|
SendRequestBodyThread(&ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderThreadTest, SendResponseBodyThread)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx ctx;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
io_mocker,
|
||||||
|
nano_body_sender(
|
||||||
|
attachment,
|
||||||
|
(HttpBody *)res_body_data.data,
|
||||||
|
&ctx,
|
||||||
|
AttachmentDataType::RESPONSE_BODY,
|
||||||
|
session_data->session_id,
|
||||||
|
&session_data->remaining_messages_to_reply
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
init_thread_ctx(&ctx, attachment, &res_body_data);
|
||||||
|
SendResponseBodyThread(&ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderThreadTest, SendRequestEndThread)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx ctx;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
io_mocker,
|
||||||
|
nano_end_transaction_sender(
|
||||||
|
attachment,
|
||||||
|
AttachmentDataType::REQUEST_END,
|
||||||
|
&ctx,
|
||||||
|
session_data->session_id,
|
||||||
|
&session_data->remaining_messages_to_reply
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
init_thread_ctx(&ctx, attachment, &req_end_data);
|
||||||
|
SendRequestEndThread(&ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderThreadTest, SendResponseEndThread)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx ctx;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
io_mocker,
|
||||||
|
nano_end_transaction_sender(
|
||||||
|
attachment,
|
||||||
|
AttachmentDataType::RESPONSE_END,
|
||||||
|
&ctx,
|
||||||
|
session_data->session_id,
|
||||||
|
&session_data->remaining_messages_to_reply
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
init_thread_ctx(&ctx, attachment, &res_end_data);
|
||||||
|
SendResponseEndThread(&ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderThreadTest, SendDelayedVerdictRequestThread)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx ctx;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
io_mocker,
|
||||||
|
nano_request_delayed_verdict(
|
||||||
|
attachment,
|
||||||
|
&ctx,
|
||||||
|
session_data->session_id,
|
||||||
|
&session_data->remaining_messages_to_reply
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
init_thread_ctx(&ctx, attachment, &delayed_verdict_data);
|
||||||
|
SendDelayedVerdictRequestThread(&ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoAttachmentSenderThreadTest, SendMetricToServiceThread)
|
||||||
|
{
|
||||||
|
HttpEventThreadCtx ctx;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
io_mocker,
|
||||||
|
nano_send_metric_data_sender(attachment)
|
||||||
|
);
|
||||||
|
|
||||||
|
init_thread_ctx(&ctx, attachment, &delayed_verdict_data);
|
||||||
|
SendMetricToServiceThread(&ctx);
|
||||||
|
}
|
129
attachments/nano_attachment/nano_attachment_ut/nano_thread_ut.cc
Normal file
129
attachments/nano_attachment/nano_attachment_ut/nano_thread_ut.cc
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
#include "cptest.h"
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "attachment_types.h"
|
||||||
|
|
||||||
|
#include "mock_nano_socket.h"
|
||||||
|
#include "mock_nano_initializer.h"
|
||||||
|
#include "mock_nano_sender_thread.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "nano_attachment.h"
|
||||||
|
#include "nano_attachment_thread.h"
|
||||||
|
#include "nano_attachment_sender_thread.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace testing;
|
||||||
|
|
||||||
|
class NanoThreadTest : public Test
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void
|
||||||
|
SetUp() override
|
||||||
|
{
|
||||||
|
EXPECT_CALL(
|
||||||
|
initializer_mocker,
|
||||||
|
nano_attachment_init_process(_)
|
||||||
|
).WillOnce(
|
||||||
|
Return(NanoCommunicationResult::NANO_OK)
|
||||||
|
);
|
||||||
|
setenv("CLOUDGUARD_UID", "Testing", 1);
|
||||||
|
attachment = InitNanoAttachment(
|
||||||
|
static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID),
|
||||||
|
2,
|
||||||
|
4,
|
||||||
|
STDOUT_FILENO
|
||||||
|
);
|
||||||
|
EXPECT_NE(attachment, nullptr);
|
||||||
|
attachment->dbg_level = nano_http_cp_debug_level_e::DBG_LEVEL_TRACE;
|
||||||
|
|
||||||
|
session_data = InitSessionData(attachment, 1);
|
||||||
|
EXPECT_NE(session_data, nullptr);
|
||||||
|
|
||||||
|
ctx_data.session_data = session_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TearDown() override
|
||||||
|
{
|
||||||
|
FiniSessionData(attachment, session_data);
|
||||||
|
FiniNanoAttachment(attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
nano_str_t
|
||||||
|
create_nano_str(const char *str)
|
||||||
|
{
|
||||||
|
nano_str_t nano_str;
|
||||||
|
nano_str.data = reinterpret_cast<unsigned char *>(const_cast<char *>(str));
|
||||||
|
nano_str.len = strlen(str);
|
||||||
|
return nano_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
AttachmentVerdictResponse accept_response = {
|
||||||
|
AttachmentVerdict::ATTACHMENT_VERDICT_ACCEPT,
|
||||||
|
1,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentData ctx_data = {
|
||||||
|
1,
|
||||||
|
HttpChunkType::HTTP_REQUEST_END,
|
||||||
|
session_data,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpEventThreadCtx ctx;
|
||||||
|
|
||||||
|
NanoAttachment *attachment;
|
||||||
|
HttpSessionData *session_data;
|
||||||
|
StrictMock<NanoSenderThreadMocker> sender_thread_mocker;
|
||||||
|
StrictMock<NanoInitializerMocker> initializer_mocker;
|
||||||
|
StrictMock<NanoSocketMocker> socket_mocker;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(NanoThreadTest, NanoRunInThreadTimeout)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
char func_name[] = "SendRequestEndThread";
|
||||||
|
EXPECT_CALL(
|
||||||
|
sender_thread_mocker,
|
||||||
|
SendRequestEndThread(&ctx)
|
||||||
|
).WillOnce(Return(nullptr));
|
||||||
|
|
||||||
|
res = NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
&ctx_data,
|
||||||
|
SendRequestEndThread,
|
||||||
|
(void *)&ctx,
|
||||||
|
attachment->req_header_thread_timeout_msec,
|
||||||
|
func_name,
|
||||||
|
REQUEST
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_EQ(res, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NanoThreadTest, NanoRunInThreadTimeoutNonThread)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
char func_name[] = "SendRequestEndThread";
|
||||||
|
attachment->inspection_mode = NanoHttpInspectionMode::NO_THREAD;
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
sender_thread_mocker,
|
||||||
|
SendRequestEndThread(&ctx)
|
||||||
|
).WillOnce(Return(nullptr));
|
||||||
|
|
||||||
|
res = NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
&ctx_data,
|
||||||
|
SendRequestEndThread,
|
||||||
|
(void *)&ctx,
|
||||||
|
attachment->req_header_thread_timeout_msec,
|
||||||
|
func_name,
|
||||||
|
REQUEST
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_EQ(res, 1);
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
add_definitions(-DUSERSPACE)
|
||||||
|
add_library(nano_attachment_util SHARED nano_attachment_util.cc)
|
||||||
|
target_link_libraries(nano_attachment_util http_configuration)
|
||||||
|
|
||||||
|
# add_subdirectory(nano_attachment_util_ut)
|
||||||
|
|
||||||
|
install(TARGETS nano_attachment_util DESTINATION lib)
|
||||||
|
install(TARGETS nano_attachment_util DESTINATION http_transaction_handler_service/lib/ PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ)
|
@ -0,0 +1,251 @@
|
|||||||
|
// 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 "nano_attachment_util.h"
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include "http_configuration.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
static HttpAttachmentConfiguration conf_data;
|
||||||
|
|
||||||
|
int
|
||||||
|
initAttachmentConfig(c_str conf_file)
|
||||||
|
{
|
||||||
|
return conf_data.init(conf_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
NanoHttpInspectionMode
|
||||||
|
getInspectionMode()
|
||||||
|
{
|
||||||
|
return static_cast<NanoHttpInspectionMode>(conf_data.getNumericalValue("nginx_inspection_mode"));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
getNumOfNginxIpcElements()
|
||||||
|
{
|
||||||
|
return conf_data.getNumericalValue("num_of_nginx_ipc_elements");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
getKeepAliveIntervalMsec()
|
||||||
|
{
|
||||||
|
return conf_data.getNumericalValue("keep_alive_interval_msec");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
getDbgLevel()
|
||||||
|
{
|
||||||
|
return conf_data.getNumericalValue("dbg_level");
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
isDebugContext(c_str client, c_str server, unsigned int port, c_str method, c_str host, c_str uri)
|
||||||
|
{
|
||||||
|
auto &ctx = conf_data.getDebugContext();
|
||||||
|
return
|
||||||
|
(ctx.client == "" || ctx.client == client) &&
|
||||||
|
(ctx.server == "" || ctx.server == server) &&
|
||||||
|
(ctx.port == 0 || ctx.port == port) &&
|
||||||
|
(ctx.method == "" || ctx.method == method) &&
|
||||||
|
(ctx.host == "" || ctx.host == host) &&
|
||||||
|
(ctx.uri == "" || ctx.uri == uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
c_str
|
||||||
|
getStaticResourcesPath()
|
||||||
|
{
|
||||||
|
return conf_data.getStringValue("static_resources_path").c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
isFailOpenMode()
|
||||||
|
{
|
||||||
|
return conf_data.getNumericalValue("is_fail_open_mode_enabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
getFailOpenTimeout()
|
||||||
|
{
|
||||||
|
return conf_data.getNumericalValue("fail_open_timeout");
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
isFailOpenHoldMode()
|
||||||
|
{
|
||||||
|
return conf_data.getNumericalValue("is_fail_open_mode_hold_enabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
getFailOpenHoldTimeout()
|
||||||
|
{
|
||||||
|
return conf_data.getNumericalValue("fail_open_hold_timeout");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
getMaxSessionsPerMinute()
|
||||||
|
{
|
||||||
|
return conf_data.getNumericalValue("max_sessions_per_minute");
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
isFailOpenOnSessionLimit()
|
||||||
|
{
|
||||||
|
return conf_data.getStringValue("sessions_per_minute_limit_verdict") == "Accept";
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
getRegistrationThreadTimeout()
|
||||||
|
{
|
||||||
|
return conf_data.getNumericalValue("registration_thread_timeout_msec");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
getReqProccessingTimeout()
|
||||||
|
{
|
||||||
|
return conf_data.getNumericalValue("req_proccessing_timeout_msec");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
getReqHeaderThreadTimeout()
|
||||||
|
{
|
||||||
|
return conf_data.getNumericalValue("req_header_thread_timeout_msec");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
getReqBodyThreadTimeout()
|
||||||
|
{
|
||||||
|
return conf_data.getNumericalValue("req_body_thread_timeout_msec");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
getResProccessingTimeout()
|
||||||
|
{
|
||||||
|
return conf_data.getNumericalValue("res_proccessing_timeout_msec");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
getResHeaderThreadTimeout()
|
||||||
|
{
|
||||||
|
return conf_data.getNumericalValue("res_header_thread_timeout_msec");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
getResBodyThreadTimeout()
|
||||||
|
{
|
||||||
|
return conf_data.getNumericalValue("res_body_thread_timeout_msec");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
getWaitingForVerdictThreadTimeout()
|
||||||
|
{
|
||||||
|
return conf_data.getNumericalValue("waiting_for_verdict_thread_timeout_msec");
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
isIPAddress(c_str ip_str)
|
||||||
|
{
|
||||||
|
int address_family = AF_INET;
|
||||||
|
for (int i = 0; ip_str[i]; ++i) {
|
||||||
|
if (ip_str[i] == ':') address_family = AF_INET6;
|
||||||
|
}
|
||||||
|
|
||||||
|
char placeholder[16];
|
||||||
|
return inet_pton(address_family, ip_str, placeholder);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct IpAddress
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
struct in_addr ipv4;
|
||||||
|
struct in6_addr ipv6;
|
||||||
|
} ip;
|
||||||
|
bool is_ipv4;
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator<(const IpAddress &other) const
|
||||||
|
{
|
||||||
|
if (is_ipv4 != other.is_ipv4) return is_ipv4 < other.is_ipv4;
|
||||||
|
if (is_ipv4) return memcmp(&ip.ipv4, &other.ip.ipv4, sizeof(struct in_addr)) < 0;
|
||||||
|
return memcmp(&ip.ipv6, &other.ip.ipv6, sizeof(struct in6_addr)) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator<=(const IpAddress &other) const
|
||||||
|
{
|
||||||
|
return !(other < *this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static IpAddress
|
||||||
|
createIPAddress(c_str ip_str)
|
||||||
|
{
|
||||||
|
IpAddress res;
|
||||||
|
|
||||||
|
for (int i = 0; ip_str[i]; ++i) {
|
||||||
|
if (ip_str[i] == ':') {
|
||||||
|
res.is_ipv4 = false;
|
||||||
|
inet_pton(AF_INET6, ip_str, &res.ip.ipv6);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.is_ipv4 = true;
|
||||||
|
inet_pton(AF_INET, ip_str, &res.ip.ipv4);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
isIPInRange(const IpAddress &ip, const IpAddress &start, const IpAddress &end)
|
||||||
|
{
|
||||||
|
if (ip.is_ipv4 != start.is_ipv4 || ip.is_ipv4 != end.is_ipv4) return false;
|
||||||
|
return start <= ip && ip <= end;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
isIPInRange(const IpAddress &ip, const string &range)
|
||||||
|
{
|
||||||
|
auto delimiter = range.find('-');
|
||||||
|
|
||||||
|
if (delimiter == string::npos) {
|
||||||
|
if (!isIPAddress(range.c_str())) return false;
|
||||||
|
auto address = createIPAddress(range.c_str());
|
||||||
|
return isIPInRange(ip, address, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto start_str = range.substr(0, delimiter);
|
||||||
|
if (!isIPAddress(start_str.c_str())) return false;
|
||||||
|
auto start_addr = createIPAddress(start_str.c_str());
|
||||||
|
|
||||||
|
auto end_str = range.substr(delimiter + 1);
|
||||||
|
if (!isIPAddress(end_str.c_str())) return false;
|
||||||
|
auto end_addr = createIPAddress(end_str.c_str());
|
||||||
|
|
||||||
|
return isIPInRange(ip, start_addr, end_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
isSkipSource(c_str ip_str)
|
||||||
|
{
|
||||||
|
if (!isIPAddress(ip_str)) return 0;
|
||||||
|
auto ip = createIPAddress(ip_str);
|
||||||
|
|
||||||
|
for (auto &range : conf_data.getExcludeSources()) {
|
||||||
|
if (isIPInRange(ip, range)) return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
include_directories(${Boost_INCLUDE_DIRS})
|
||||||
|
include_directories(${CMAKE_SOURCE_DIR}/attachments/nano_attachment/nano_attachment_util)
|
||||||
|
|
||||||
|
add_unit_test(
|
||||||
|
nano_attachment_util_ut
|
||||||
|
"nano_attachment_util_ut.cc"
|
||||||
|
"nano_attachment_util"
|
||||||
|
)
|
@ -0,0 +1,125 @@
|
|||||||
|
#include <fstream>
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include "nano_attachment_util.h"
|
||||||
|
#include "cptest.h"
|
||||||
|
#include "c_common/ip_common.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace testing;
|
||||||
|
|
||||||
|
class HttpAttachmentUtilTest : public Test
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
string
|
||||||
|
createIPRangesString(const vector<string> &ip_ranges)
|
||||||
|
{
|
||||||
|
stringstream ip_ranges_string_stream;
|
||||||
|
ip_ranges_string_stream << "[";
|
||||||
|
for (auto iterator = ip_ranges.begin(); iterator < ip_ranges.end() - 1; iterator++) {
|
||||||
|
ip_ranges_string_stream << "\"" << *iterator << "\"" << ", ";
|
||||||
|
}
|
||||||
|
ip_ranges_string_stream << "\"" << ip_ranges.back() << "\"]";
|
||||||
|
|
||||||
|
return ip_ranges_string_stream.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
const string attachment_configuration_file_name = "cp_nano_http_attachment_conf";
|
||||||
|
const vector<string> ip_ranges = { "8.8.8.8", "9.9.9.9-10.10.10.10", "0:0:0:0:0:0:0:2-0:0:0:0:0:0:0:5"};
|
||||||
|
const string static_resources_path = "/dev/shm/static_resources/";
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(HttpAttachmentUtilTest, GetValidAttachmentConfiguration)
|
||||||
|
{
|
||||||
|
string valid_configuration =
|
||||||
|
"{\n"
|
||||||
|
"\"context_values\": {"
|
||||||
|
"\"clientIp\": \"1.2.3.4\","
|
||||||
|
"\"listeningIp\": \"5.6.7.8\","
|
||||||
|
"\"uriPrefix\": \"/abc\","
|
||||||
|
"\"hostName\": \"test\","
|
||||||
|
"\"httpMethod\": \"GET\","
|
||||||
|
"\"listeningPort\": 80"
|
||||||
|
"},"
|
||||||
|
"\"is_fail_open_mode_enabled\": 0,\n"
|
||||||
|
"\"fail_open_timeout\": 1234,\n"
|
||||||
|
"\"is_fail_open_mode_hold_enabled\": 1,\n"
|
||||||
|
"\"fail_open_hold_timeout\": 4321,\n"
|
||||||
|
"\"sessions_per_minute_limit_verdict\": \"Accept\",\n"
|
||||||
|
"\"max_sessions_per_minute\": 0,\n"
|
||||||
|
"\"num_of_nginx_ipc_elements\": 200,\n"
|
||||||
|
"\"keep_alive_interval_msec\": 10000,\n"
|
||||||
|
"\"dbg_level\": 2,\n"
|
||||||
|
"\"nginx_inspection_mode\": 1,\n"
|
||||||
|
"\"operation_mode\": 0,\n"
|
||||||
|
"\"req_body_thread_timeout_msec\": 155,\n"
|
||||||
|
"\"req_proccessing_timeout_msec\": 42,\n"
|
||||||
|
"\"registration_thread_timeout_msec\": 101,\n"
|
||||||
|
"\"res_proccessing_timeout_msec\": 420,\n"
|
||||||
|
"\"res_header_thread_timeout_msec\": 1,\n"
|
||||||
|
"\"res_body_thread_timeout_msec\": 0,\n"
|
||||||
|
"\"waiting_for_verdict_thread_timeout_msec\": 75,\n"
|
||||||
|
"\"req_header_thread_timeout_msec\": 10,\n"
|
||||||
|
"\"ip_ranges\": " + createIPRangesString(ip_ranges) + ",\n"
|
||||||
|
"\"static_resources_path\": \"" + static_resources_path + "\""
|
||||||
|
"}\n";
|
||||||
|
ofstream valid_configuration_file(attachment_configuration_file_name);
|
||||||
|
valid_configuration_file << valid_configuration;
|
||||||
|
valid_configuration_file.close();
|
||||||
|
|
||||||
|
EXPECT_EQ(initAttachmentConfig(attachment_configuration_file_name.c_str()), 1);
|
||||||
|
EXPECT_EQ(getDbgLevel(), 2u);
|
||||||
|
EXPECT_EQ(getStaticResourcesPath(), static_resources_path);
|
||||||
|
EXPECT_EQ(isFailOpenMode(), 0);
|
||||||
|
EXPECT_EQ(getFailOpenTimeout(), 1234u);
|
||||||
|
EXPECT_EQ(isFailOpenHoldMode(), 1);
|
||||||
|
EXPECT_EQ(getFailOpenHoldTimeout(), 4321u);
|
||||||
|
EXPECT_EQ(isFailOpenOnSessionLimit(), 1);
|
||||||
|
EXPECT_EQ(getMaxSessionsPerMinute(), 0u);
|
||||||
|
EXPECT_EQ(getNumOfNginxIpcElements(), 200u);
|
||||||
|
EXPECT_EQ(getKeepAliveIntervalMsec(), 10000u);
|
||||||
|
EXPECT_EQ(getResProccessingTimeout(), 420u);
|
||||||
|
EXPECT_EQ(getReqProccessingTimeout(), 42u);
|
||||||
|
EXPECT_EQ(getRegistrationThreadTimeout(), 101u);
|
||||||
|
EXPECT_EQ(getReqHeaderThreadTimeout(), 10u);
|
||||||
|
EXPECT_EQ(getReqBodyThreadTimeout(), 155u);
|
||||||
|
EXPECT_EQ(getResHeaderThreadTimeout(), 1u);
|
||||||
|
EXPECT_EQ(getResBodyThreadTimeout(), 0u);
|
||||||
|
EXPECT_EQ(getWaitingForVerdictThreadTimeout(), 75u);
|
||||||
|
EXPECT_EQ(getInspectionMode(), NanoHttpInspectionMode::BLOCKING_THREAD);
|
||||||
|
|
||||||
|
EXPECT_EQ(isDebugContext("1.2.3.4", "5.6.7.8", 80, "GET", "test", "/abc"), 1);
|
||||||
|
EXPECT_EQ(isDebugContext("1.2.3.9", "5.6.7.8", 80, "GET", "test", "/abc"), 0);
|
||||||
|
EXPECT_EQ(isDebugContext("1.2.3.4", "5.6.7.9", 80, "GET", "test", "/abc"), 0);
|
||||||
|
EXPECT_EQ(isDebugContext("1.2.3.4", "5.6.7.8", 88, "GET", "test", "/abc"), 0);
|
||||||
|
EXPECT_EQ(isDebugContext("1.2.3.4", "5.6.7.8", 80, "POST", "test", "/abc"), 0);
|
||||||
|
EXPECT_EQ(isDebugContext("1.2.3.4", "5.6.7.8", 80, "GET", "est", "/abc"), 0);
|
||||||
|
EXPECT_EQ(isDebugContext("1.2.3.4", "5.6.7.8", 80, "GET", "test", "/ab"), 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(isSkipSource("8.8.8.8"), 1);
|
||||||
|
EXPECT_EQ(isSkipSource("8.8.8.9"), 0);
|
||||||
|
EXPECT_EQ(isSkipSource("8.8.8.10"), 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(isSkipSource("9.9.9.8"), 0);
|
||||||
|
EXPECT_EQ(isSkipSource("9.9.9.9"), 1);
|
||||||
|
EXPECT_EQ(isSkipSource("9.255.0.0"), 1);
|
||||||
|
EXPECT_EQ(isSkipSource("10.10.10.10"), 1);
|
||||||
|
EXPECT_EQ(isSkipSource("10.10.10.11"), 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(isSkipSource("0:0:0:0:0:0:0:1"), 0);
|
||||||
|
EXPECT_EQ(isSkipSource("0:0:0:0:0:0:0:2"), 1);
|
||||||
|
EXPECT_EQ(isSkipSource("0:0:0:0:0:0:0:4"), 1);
|
||||||
|
EXPECT_EQ(isSkipSource("0:0:0:0:0:0:0:5"), 1);
|
||||||
|
EXPECT_EQ(isSkipSource("0:0:0:0:0:0:0:6"), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(HttpAttachmentUtilTest, CheckIPAddrValidity)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(isIPAddress("10.0.0.1"), 1);
|
||||||
|
EXPECT_EQ(isIPAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334"), 1);
|
||||||
|
|
||||||
|
EXPECT_EQ(isIPAddress("333.0.0.1"), 0);
|
||||||
|
EXPECT_EQ(isIPAddress("2001:0gb8:85a3:0000:0000:8a2e:0370:7334"), 0);
|
||||||
|
}
|
24
attachments/nano_attachment/nano_blockpage.h
Normal file
24
attachments/nano_attachment/nano_blockpage.h
Normal file
File diff suppressed because one or more lines are too long
144
attachments/nano_attachment/nano_configuration.c
Normal file
144
attachments/nano_attachment/nano_configuration.c
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
#include "nano_configuration.h"
|
||||||
|
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "nano_utils.h"
|
||||||
|
#include "nano_attachment_util.h"
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
NanoCommunicationResult
|
||||||
|
init_attachment_config(NanoAttachment *attachment, const char *conf_path)
|
||||||
|
{
|
||||||
|
int new_dbg_level = DBG_LEVEL_COUNT;
|
||||||
|
|
||||||
|
if (access(conf_path, F_OK) != 0) return NANO_ERROR;
|
||||||
|
|
||||||
|
if (attachment->is_configuration_updated == NANO_OK) return NANO_OK;
|
||||||
|
|
||||||
|
// Initiate attachment using the file in the provided conf_path.
|
||||||
|
if (!initAttachmentConfig(conf_path)) {
|
||||||
|
write_dbg(attachment, attachment->worker_id, DBG_LEVEL_WARNING, "Failed to load the configuration");
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_dbg_level = getDbgLevel();
|
||||||
|
|
||||||
|
if (new_dbg_level >= DBG_LEVEL_COUNT) {
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
attachment->worker_id,
|
||||||
|
DBG_LEVEL_WARNING,
|
||||||
|
"Illegal debug level received: %d",
|
||||||
|
new_dbg_level
|
||||||
|
);
|
||||||
|
attachment->is_configuration_updated = NANO_ERROR;
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
write_dbg(attachment, attachment->worker_id, DBG_LEVEL_DEBUG, "Setting debug level to: %d", new_dbg_level);
|
||||||
|
// Setting a new debug level.
|
||||||
|
attachment->dbg_level = new_dbg_level;
|
||||||
|
|
||||||
|
// Setting fail open/close.
|
||||||
|
attachment->fail_mode_verdict = isFailOpenMode() == 1 ? NANO_OK : NANO_ERROR;
|
||||||
|
attachment->fail_open_timeout = getFailOpenTimeout();
|
||||||
|
|
||||||
|
// Setting fail delayed open/close
|
||||||
|
attachment->fail_mode_delayed_verdict = isFailOpenHoldMode() == 1 ? NANO_OK : NANO_ERROR;
|
||||||
|
attachment->fail_open_delayed_timeout = getFailOpenHoldTimeout();
|
||||||
|
|
||||||
|
// Setting attachment's variables.
|
||||||
|
attachment->sessions_per_minute_limit_verdict =
|
||||||
|
isFailOpenOnSessionLimit() ? ATTACHMENT_VERDICT_ACCEPT : ATTACHMENT_VERDICT_DROP;
|
||||||
|
attachment->max_sessions_per_minute = getMaxSessionsPerMinute();
|
||||||
|
attachment->inspection_mode = getInspectionMode();
|
||||||
|
if (attachment->inspection_mode >= INSPECTION_MODE_COUNT) {
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
attachment->worker_id,
|
||||||
|
DBG_LEVEL_WARNING,
|
||||||
|
"Illegal inspection mode received: %d",
|
||||||
|
attachment->inspection_mode
|
||||||
|
);
|
||||||
|
attachment->is_configuration_updated = NANO_ERROR;
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
attachment->req_max_proccessing_ms_time = getReqProccessingTimeout();
|
||||||
|
attachment->res_max_proccessing_ms_time = getResProccessingTimeout();
|
||||||
|
attachment->registration_thread_timeout_msec = getRegistrationThreadTimeout();
|
||||||
|
attachment->req_header_thread_timeout_msec = getReqHeaderThreadTimeout();
|
||||||
|
attachment->req_body_thread_timeout_msec = getReqBodyThreadTimeout();
|
||||||
|
attachment->res_header_thread_timeout_msec = getResHeaderThreadTimeout();
|
||||||
|
attachment->res_body_thread_timeout_msec = getResBodyThreadTimeout();
|
||||||
|
attachment->waiting_for_verdict_thread_timeout_msec = getWaitingForVerdictThreadTimeout();
|
||||||
|
|
||||||
|
attachment->num_of_nano_ipc_elements = getNumOfNginxIpcElements();
|
||||||
|
attachment->keep_alive_interval_msec = getKeepAliveIntervalMsec();
|
||||||
|
|
||||||
|
// set_static_resources_path(getStaticResourcesPath());
|
||||||
|
attachment->is_configuration_updated = NANO_OK;
|
||||||
|
|
||||||
|
attachment->logging_data->dbg_level = attachment->dbg_level;
|
||||||
|
attachment->logging_data->worker_id = attachment->worker_id;
|
||||||
|
attachment->logging_data->fd = attachment->logging_fd;
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
attachment->worker_id,
|
||||||
|
DBG_LEVEL_INFO,
|
||||||
|
"Successfully loaded configuration. "
|
||||||
|
"inspection mode: %d, "
|
||||||
|
"debug level: %d, "
|
||||||
|
"failure mode: %s, "
|
||||||
|
"fail mode timeout: %u msec, "
|
||||||
|
"failure delayed mode: %s, "
|
||||||
|
"fail mode delayed timeout: %u msec, "
|
||||||
|
"sessions per minute limit verdict: %s, "
|
||||||
|
"max sessions per minute: %u, "
|
||||||
|
"req max processing time: %u msec, "
|
||||||
|
"res max processing time: %u msec, "
|
||||||
|
"registration thread timeout: %u msec, "
|
||||||
|
"req start thread timeout: %u msec, "
|
||||||
|
"req header thread timeout: %u msec, "
|
||||||
|
"req body thread timeout: %u msec, "
|
||||||
|
"res header thread timeout: %u msec, "
|
||||||
|
"res body thread timeout: %u msec, "
|
||||||
|
"delayed thread timeout: %u msec, "
|
||||||
|
"static resources path: %s, "
|
||||||
|
"num of nginx ipc elements: %u, "
|
||||||
|
"keep alive interval msec: %u msec",
|
||||||
|
attachment->inspection_mode,
|
||||||
|
attachment->dbg_level,
|
||||||
|
(attachment->fail_mode_verdict == NANO_OK ? "fail-open" : "fail-close"),
|
||||||
|
attachment->fail_open_timeout,
|
||||||
|
(attachment->fail_mode_delayed_verdict == NANO_OK ? "fail-open" : "fail-close"),
|
||||||
|
attachment->fail_open_delayed_timeout,
|
||||||
|
attachment->sessions_per_minute_limit_verdict == ATTACHMENT_VERDICT_ACCEPT ? "Accept" : "Drop",
|
||||||
|
attachment->max_sessions_per_minute,
|
||||||
|
attachment->req_max_proccessing_ms_time,
|
||||||
|
attachment->res_max_proccessing_ms_time,
|
||||||
|
attachment->registration_thread_timeout_msec,
|
||||||
|
attachment->req_start_thread_timeout_msec,
|
||||||
|
attachment->req_header_thread_timeout_msec,
|
||||||
|
attachment->req_body_thread_timeout_msec,
|
||||||
|
attachment->res_header_thread_timeout_msec,
|
||||||
|
attachment->res_body_thread_timeout_msec,
|
||||||
|
attachment->waiting_for_verdict_thread_timeout_msec,
|
||||||
|
getStaticResourcesPath(),
|
||||||
|
attachment->num_of_nano_ipc_elements,
|
||||||
|
attachment->keep_alive_interval_msec
|
||||||
|
);
|
||||||
|
|
||||||
|
return NANO_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NanoCommunicationResult
|
||||||
|
reset_attachment_config(NanoAttachment *attachment)
|
||||||
|
{
|
||||||
|
write_dbg(attachment, attachment->worker_id, DBG_LEVEL_INFO, "Resetting attachment configuration");
|
||||||
|
|
||||||
|
attachment->is_configuration_updated = NANO_ERROR;
|
||||||
|
attachment->current_config_version++;
|
||||||
|
return init_attachment_config(attachment, SHARED_ATTACHMENT_CONF_PATH);
|
||||||
|
}
|
37
attachments/nano_attachment/nano_configuration.h
Normal file
37
attachments/nano_attachment/nano_configuration.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/// @file nano_configuration.h
|
||||||
|
#ifndef __NANO_CONFIGURATION_H__
|
||||||
|
#define __NANO_CONFIGURATION_H__
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "nano_initializer.h"
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Initializes the general configuration for a NanoAttachment object.
|
||||||
|
///
|
||||||
|
/// This function initializes the general configuration for the specified NanoAttachment object
|
||||||
|
/// using the configuration file located at the specified path. It updates various configuration
|
||||||
|
/// parameters such as debug level, fail-open/fail-close mode, session limits, timeouts, and others
|
||||||
|
/// based on the configuration file.
|
||||||
|
///
|
||||||
|
/// @param attachment A pointer to the NanoAttachment object to initialize the configuration for.
|
||||||
|
/// @param conf_path The path to the configuration file.
|
||||||
|
/// @return A NanoCommunicationResult indicating the result of the operation.
|
||||||
|
///
|
||||||
|
NanoCommunicationResult init_attachment_config(NanoAttachment *attachment, const char *conf_path);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Resets the configuration of a NanoAttachment object.
|
||||||
|
///
|
||||||
|
/// This function resets the configuration of the specified NanoAttachment object by
|
||||||
|
/// marking it as not updated, incrementing the current configuration version, and
|
||||||
|
/// reinitializing the general configuration using the specified configuration path.
|
||||||
|
///
|
||||||
|
/// @param attachment A pointer to the NanoAttachment object to reset the configuration for.
|
||||||
|
/// @return A NanoCommunicationResult indicating the result of the operation.
|
||||||
|
///
|
||||||
|
NanoCommunicationResult reset_attachment_config(NanoAttachment *attachment);
|
||||||
|
|
||||||
|
#endif // __NANO_CONFIGURATION_H__
|
860
attachments/nano_attachment/nano_initializer.c
Normal file
860
attachments/nano_attachment/nano_initializer.c
Normal file
@ -0,0 +1,860 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
/// @file nano_initializer.c
|
||||||
|
#include "nano_initializer.h"
|
||||||
|
|
||||||
|
#include <poll.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "attachment_types.h"
|
||||||
|
#include "nano_configuration.h"
|
||||||
|
#include "nano_attachment_io.h"
|
||||||
|
#include "shmem_ipc_2.h"
|
||||||
|
#include "nano_utils.h"
|
||||||
|
#include "nano_attachment_sender_thread.h"
|
||||||
|
#include "nano_attachment_thread.h"
|
||||||
|
|
||||||
|
NanoCommunicationResult
|
||||||
|
write_to_service(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
int *socket,
|
||||||
|
void *data,
|
||||||
|
uint32_t size,
|
||||||
|
struct timeval *absolute_end_time)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
// `remaining_size` and `cur_data_ptr` are used to keep track of where we are in the memory.
|
||||||
|
// This allows us to write to the socket in parts (if we need to).
|
||||||
|
uint32_t remaining_size = size;
|
||||||
|
char *cur_data_ptr = data;
|
||||||
|
|
||||||
|
while (remaining_size > 0) {
|
||||||
|
// If the operation exceeded the allowed time, treat it as a failure.
|
||||||
|
if (is_absolute_timeout_reached(absolute_end_time)) {
|
||||||
|
close(*socket);
|
||||||
|
*socket = -1;
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
0,
|
||||||
|
DBG_LEVEL_TRACE,
|
||||||
|
"Reached timeout while communicating with the socket"
|
||||||
|
);
|
||||||
|
return NANO_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = write(*socket, (void *)cur_data_ptr, remaining_size);
|
||||||
|
|
||||||
|
// `res` is -1 in case of an error: write functions failed or socket wasn't available.
|
||||||
|
if (res < 0) {
|
||||||
|
close(*socket);
|
||||||
|
*socket = -1;
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
0,
|
||||||
|
DBG_LEVEL_TRACE,
|
||||||
|
"Failed to communicate with the socket, Error: %s",
|
||||||
|
strerror(errno)
|
||||||
|
);
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
remaining_size -= res;
|
||||||
|
cur_data_ptr += res;
|
||||||
|
}
|
||||||
|
return NANO_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NanoCommunicationResult
|
||||||
|
read_from_service(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
int *socket,
|
||||||
|
void *data,
|
||||||
|
uint32_t size,
|
||||||
|
struct timeval *absolute_end_time)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
// `remaining_size` and `cur_data_ptr` are used to keep track of where we are in the memory.
|
||||||
|
// This allows us to read from the socket in parts (if we need to).
|
||||||
|
uint32_t remaining_size = size;
|
||||||
|
char *cur_data_ptr = data;
|
||||||
|
|
||||||
|
while (remaining_size > 0) {
|
||||||
|
// If the operation exceeded the allowed time, treat it as a failure.
|
||||||
|
if (is_absolute_timeout_reached(absolute_end_time)) {
|
||||||
|
close(*socket);
|
||||||
|
*socket = -1;
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
0,
|
||||||
|
DBG_LEVEL_TRACE,
|
||||||
|
"Reached timeout while communicating with the socket"
|
||||||
|
);
|
||||||
|
return NANO_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The read operation must not block the attachment indefinitely.
|
||||||
|
// To avoid that we check whether the socket has data to be read prior to the read operation.
|
||||||
|
// If the socket doesn't have data to be read from within a reasonable time, we treat this as an error.
|
||||||
|
struct pollfd s_poll;
|
||||||
|
s_poll.fd = *socket;
|
||||||
|
s_poll.events = POLLIN;
|
||||||
|
s_poll.revents = 0;
|
||||||
|
res = poll(&s_poll, 1, 3000);
|
||||||
|
|
||||||
|
if (res <= 0 || (s_poll.revents & POLLIN) == 0) {
|
||||||
|
close(*socket);
|
||||||
|
*socket = -1;
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
0,
|
||||||
|
DBG_LEVEL_TRACE,
|
||||||
|
"Failed to communicate with the socket, Error: %s",
|
||||||
|
strerror(errno)
|
||||||
|
);
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = read(*socket, (void *)cur_data_ptr, remaining_size);
|
||||||
|
remaining_size -= res;
|
||||||
|
cur_data_ptr += res;
|
||||||
|
}
|
||||||
|
return NANO_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Send communication data to the communication socket.
|
||||||
|
///
|
||||||
|
/// This function sends various data (unique identifier, process UID, process GID)
|
||||||
|
/// to the service through the communication socket. It sends the data in the
|
||||||
|
/// following order:
|
||||||
|
/// 1. The length of the unique identifier for this instance.
|
||||||
|
/// 2. The unique identifier for this instance.
|
||||||
|
/// 3. The process UID.
|
||||||
|
/// 4. The process GID.
|
||||||
|
///
|
||||||
|
/// @param[in] attachment The NanoAttachment struct containing the data to send.
|
||||||
|
/// @returns A NanoCommunicationResult indicating the success of the operation.
|
||||||
|
/// - #NANO_OK: The data was successfully sent.
|
||||||
|
/// - #NANO_ERROR: An error occurred during data transmission.
|
||||||
|
///
|
||||||
|
NanoCommunicationResult
|
||||||
|
send_comm_data_to_comm_socket(NanoAttachment *attachment)
|
||||||
|
{
|
||||||
|
NanoCommunicationResult res;
|
||||||
|
uint8_t uid_size_to_send = strlen(attachment->unique_id);
|
||||||
|
struct timeval timeout = get_absolute_timeout_val_sec(1);
|
||||||
|
|
||||||
|
res = write_to_service(
|
||||||
|
attachment,
|
||||||
|
&attachment->comm_socket,
|
||||||
|
&uid_size_to_send,
|
||||||
|
sizeof(uid_size_to_send),
|
||||||
|
&timeout
|
||||||
|
);
|
||||||
|
if (res != NANO_OK) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Failed to send unique id size");
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = write_to_service(
|
||||||
|
attachment,
|
||||||
|
&attachment->comm_socket,
|
||||||
|
attachment->unique_id,
|
||||||
|
uid_size_to_send,
|
||||||
|
&timeout
|
||||||
|
);
|
||||||
|
if (res != NANO_OK) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Failed to send unique id %s", attachment->unique_id);
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = write_to_service(
|
||||||
|
attachment,
|
||||||
|
&attachment->comm_socket,
|
||||||
|
&attachment->nano_user_id,
|
||||||
|
sizeof(uint32_t),
|
||||||
|
&timeout
|
||||||
|
);
|
||||||
|
if (res != NANO_OK) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Failed to send nano user id");
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = write_to_service(
|
||||||
|
attachment,
|
||||||
|
&attachment->comm_socket,
|
||||||
|
&attachment->nano_group_id,
|
||||||
|
sizeof(uint32_t),
|
||||||
|
&timeout
|
||||||
|
);
|
||||||
|
if (res != NANO_OK) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Failed to send nano group id");
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NANO_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Initialize the signaling socket for communication.
|
||||||
|
///
|
||||||
|
/// This function connects to the communication socket, sends communication data,
|
||||||
|
/// and waits for an acknowledgment from the service that communication has been
|
||||||
|
/// established. If any step fails, the function closes the communication socket
|
||||||
|
/// and returns an error.
|
||||||
|
///
|
||||||
|
/// @param[in] attachment The NanoAttachment struct containing socket information.
|
||||||
|
/// @returns A NanoCommunicationResult indicating the success of the operation.
|
||||||
|
///
|
||||||
|
/// - #NANO_OK: Signaling socket initialized successfully.
|
||||||
|
/// - #NANO_ERROR: An error occurred during initialization.
|
||||||
|
///
|
||||||
|
static NanoCommunicationResult
|
||||||
|
init_signaling_socket(NanoAttachment *attachment)
|
||||||
|
{
|
||||||
|
uint8_t initialization_ack;
|
||||||
|
HttpEventThreadCtx ctx;
|
||||||
|
int t_res;
|
||||||
|
NanoCommunicationResult res;
|
||||||
|
struct timeval timeout = get_absolute_timeout_val_sec(1);
|
||||||
|
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_DEBUG, "spawn RegistrationCommSocketThread");
|
||||||
|
t_res = NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
NULL,
|
||||||
|
RegistrationCommSocketThread,
|
||||||
|
(void *)&ctx,
|
||||||
|
attachment->registration_thread_timeout_msec,
|
||||||
|
"RegistrationCommSocketThread",
|
||||||
|
REGISTRATION
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!t_res || ctx.res != NANO_OK) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Failed to connect to connection socket");
|
||||||
|
close(attachment->comm_socket);
|
||||||
|
attachment->comm_socket = -1;
|
||||||
|
if (attachment->registration_state != PENDING) {
|
||||||
|
attachment->registration_state = NOT_REGISTERED;
|
||||||
|
}
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = send_comm_data_to_comm_socket(attachment);
|
||||||
|
if (res != NANO_OK) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Failed to send comm data");
|
||||||
|
close(attachment->comm_socket);
|
||||||
|
attachment->comm_socket = -1;
|
||||||
|
if (attachment->registration_state != PENDING) {
|
||||||
|
attachment->registration_state = NOT_REGISTERED;
|
||||||
|
}
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get an acknowledgement form the service that communication has been established.
|
||||||
|
res = read_from_service(
|
||||||
|
attachment,
|
||||||
|
&attachment->comm_socket,
|
||||||
|
&initialization_ack,
|
||||||
|
sizeof(initialization_ack),
|
||||||
|
&timeout
|
||||||
|
);
|
||||||
|
if (res != NANO_OK) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Failed to read communication ack");
|
||||||
|
close(attachment->comm_socket);
|
||||||
|
attachment->comm_socket = -1;
|
||||||
|
if (attachment->registration_state != PENDING) {
|
||||||
|
attachment->registration_state = NOT_REGISTERED;
|
||||||
|
}
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
0,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"Successfully connected on client socket %d",
|
||||||
|
attachment->comm_socket
|
||||||
|
);
|
||||||
|
return NANO_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NanoCommunicationResult
|
||||||
|
createDirectory(NanoAttachment *attachment, const char *path)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if (stat(path, &st) == 0) {
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
0,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"Nano attachment logging directory already exists"
|
||||||
|
);
|
||||||
|
return NANO_OK;
|
||||||
|
}
|
||||||
|
if (mkdir(path, 0755) == 0) {
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
0,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"Successfully created logging directory"
|
||||||
|
);
|
||||||
|
return NANO_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
0,
|
||||||
|
DBG_LEVEL_WARNING,
|
||||||
|
"Failed to create logging directory"
|
||||||
|
);
|
||||||
|
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
NanoCommunicationResult
|
||||||
|
set_docker_id(NanoAttachment *attachment)
|
||||||
|
{
|
||||||
|
size_t len = MAX_NGINX_UID_LEN;
|
||||||
|
char *line = NULL;
|
||||||
|
char *docker_ptr = NULL;
|
||||||
|
char *containerd_ptr = NULL;
|
||||||
|
FILE *file = fopen(CONTAINER_ID_FILE_PATH, "r");
|
||||||
|
if (file == NULL) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Failed to open %s", CONTAINER_ID_FILE_PATH);
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_DEBUG, "opened file %s", CONTAINER_ID_FILE_PATH);
|
||||||
|
|
||||||
|
line = malloc(MAX_NGINX_UID_LEN);
|
||||||
|
if (line == NULL) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_DEBUG, "Failed to allocate memory for reading docker id file");
|
||||||
|
fclose(file);
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reading the file line by line.
|
||||||
|
bool uid_read = false;
|
||||||
|
while (getline(&line, &len, file) != -1) {
|
||||||
|
docker_ptr = strstr(line, "docker/");
|
||||||
|
containerd_ptr = strstr(line, "cri-containerd-");
|
||||||
|
|
||||||
|
if (docker_ptr != NULL)
|
||||||
|
{
|
||||||
|
// We've found a line with "docker/" so the identifier will be right after that.
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_DEBUG, "checking for docker/");
|
||||||
|
docker_ptr += strlen("docker/");
|
||||||
|
strncpy(attachment->container_id, docker_ptr, MAX_CONTAINER_ID_LEN - 1);
|
||||||
|
attachment->container_id[MAX_CONTAINER_ID_LEN - 1] = '\0';
|
||||||
|
uid_read = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (containerd_ptr != NULL)
|
||||||
|
{
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_DEBUG, "checking for cri-containerd-");
|
||||||
|
containerd_ptr += strlen("cri-containerd-");
|
||||||
|
strncpy(attachment->container_id, containerd_ptr, MAX_CONTAINER_ID_LEN - 1);
|
||||||
|
attachment->container_id[MAX_CONTAINER_ID_LEN - 1] = '\0';
|
||||||
|
uid_read = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!uid_read) {
|
||||||
|
const char *env_var_name = "CLOUDGUARD_UID"; // Replace with your environment variable name
|
||||||
|
const char *env_value = getenv(env_var_name);
|
||||||
|
|
||||||
|
if (env_value) {
|
||||||
|
strncpy(attachment->container_id, env_value, MAX_CONTAINER_ID_LEN - 1);
|
||||||
|
attachment->container_id[MAX_CONTAINER_ID_LEN - 1] = '\0';
|
||||||
|
uid_read = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(line);
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
if (!uid_read) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Severe error - failed to get uid!");
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NANO_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
///@brief Sends registration data to the registration socket.
|
||||||
|
///
|
||||||
|
/// This function sends registration data to the registration socket of the given NanoAttachment.
|
||||||
|
/// It sends the attachment type, worker ID, total number of workers,
|
||||||
|
/// and the size and content of the container id (docker ID).
|
||||||
|
/// If any of the send operations fail, it returns NANO_ERROR; otherwise, it returns NANO_OK.
|
||||||
|
///
|
||||||
|
///@param attachment The NanoAttachment containing the registration socket and other necessary information.
|
||||||
|
///@return NanoCommunicationResult Returns NANO_OK if the registration data is successfully sent, otherwise NANO_ERROR.
|
||||||
|
///
|
||||||
|
NanoCommunicationResult
|
||||||
|
send_registration_data_to_registration_socket(NanoAttachment *attachment)
|
||||||
|
{
|
||||||
|
uint8_t attachment_type = attachment->attachment_type;
|
||||||
|
uint8_t worker_id = attachment->worker_id + 1;
|
||||||
|
uint8_t workers_amount = attachment->num_of_workers;
|
||||||
|
struct timeval absolute_timeout = get_absolute_timeout_val_sec(1);
|
||||||
|
uint8_t container_id_size = strlen(attachment->container_id);
|
||||||
|
NanoCommunicationResult res;
|
||||||
|
|
||||||
|
// Send to the attachment manager the following details:
|
||||||
|
// 1. The type of the attachment (fixed NGINX).
|
||||||
|
// 2. The number of this worker.
|
||||||
|
// 3. The total amount of workers.
|
||||||
|
// 4. The size of the docker ID.
|
||||||
|
// 5. If the docker ID isn't empty (size 0), the docker id itself.
|
||||||
|
// If any of these fail - return an error.
|
||||||
|
res = write_to_service(
|
||||||
|
attachment,
|
||||||
|
&attachment->registration_socket,
|
||||||
|
&attachment_type,
|
||||||
|
sizeof(attachment_type),
|
||||||
|
&absolute_timeout
|
||||||
|
);
|
||||||
|
if (res != NANO_OK) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Failed to send attachment type");
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = write_to_service(
|
||||||
|
attachment,
|
||||||
|
&attachment->registration_socket,
|
||||||
|
&worker_id,
|
||||||
|
sizeof(worker_id),
|
||||||
|
&absolute_timeout
|
||||||
|
);
|
||||||
|
if (res != NANO_OK) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Failed to send worker ID");
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = write_to_service(
|
||||||
|
attachment,
|
||||||
|
&attachment->registration_socket,
|
||||||
|
&workers_amount,
|
||||||
|
sizeof(workers_amount),
|
||||||
|
&absolute_timeout
|
||||||
|
);
|
||||||
|
if (res != NANO_OK) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Failed to send workers amount");
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = write_to_service(
|
||||||
|
attachment,
|
||||||
|
&attachment->registration_socket,
|
||||||
|
&container_id_size,
|
||||||
|
sizeof(container_id_size),
|
||||||
|
&absolute_timeout
|
||||||
|
);
|
||||||
|
if (res != NANO_OK) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Failed to send container id size");
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (container_id_size > 0) {
|
||||||
|
res = write_to_service(
|
||||||
|
attachment,
|
||||||
|
&attachment->registration_socket,
|
||||||
|
attachment->container_id,
|
||||||
|
container_id_size,
|
||||||
|
&absolute_timeout
|
||||||
|
);
|
||||||
|
if (res != NANO_OK) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Failed to send container id");
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NANO_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Reads the verdict signal path from the registration socket.
|
||||||
|
///
|
||||||
|
/// This function reads the verdict signal path from the registration socket of the given NanoAttachment.
|
||||||
|
/// It first reads the length of the signal path, then reads the signal path itself.
|
||||||
|
/// If the read operations fail or the path length exceeds the maximum allowed length, it returns NANO_ERROR;
|
||||||
|
/// otherwise, it returns NANO_OK.
|
||||||
|
///
|
||||||
|
/// @param attachment The NanoAttachment containing the registration socket and other necessary information.
|
||||||
|
/// @return NanoCommunicationResult Returns NANO_OK if the signal path is successfully read, otherwise NANO_ERROR.
|
||||||
|
///
|
||||||
|
NanoCommunicationResult
|
||||||
|
read_verdict_signal_path_from_registration_socket(NanoAttachment *attachment)
|
||||||
|
{
|
||||||
|
uint8_t path_length;
|
||||||
|
int registration_socket = attachment->registration_socket;
|
||||||
|
uint8_t worker_id = attachment->worker_id + 1;
|
||||||
|
uint8_t workers_amount = attachment->num_of_workers;
|
||||||
|
NanoCommunicationResult res;
|
||||||
|
struct timeval absolute_timeout = get_absolute_timeout_val_sec(1);
|
||||||
|
// Read from the attachment manager:
|
||||||
|
// 1. The length of signal path.
|
||||||
|
// 2. The signal path itself.
|
||||||
|
// If that fails - return an error.
|
||||||
|
res = read_from_service(
|
||||||
|
attachment,
|
||||||
|
&attachment->registration_socket,
|
||||||
|
&path_length,
|
||||||
|
sizeof(path_length),
|
||||||
|
&absolute_timeout
|
||||||
|
);
|
||||||
|
if (res != NANO_OK) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Failed to read path length");
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path_length >= MAX_SHARED_MEM_PATH_LEN) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Verdict path length is too long");
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = read_from_service(
|
||||||
|
attachment,
|
||||||
|
&attachment->registration_socket,
|
||||||
|
attachment->shared_verdict_signal_path,
|
||||||
|
path_length,
|
||||||
|
&absolute_timeout
|
||||||
|
);
|
||||||
|
if (res != NANO_OK) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Failed to read socket path");
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Successfully go the shared communication path - add null termination and exit.
|
||||||
|
attachment->shared_verdict_signal_path[path_length] = '\0';
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
0,
|
||||||
|
DBG_LEVEL_DEBUG,
|
||||||
|
"Successfully registered on client. socket: %d, instance ID: %u, instances amount: %u, received path: %s",
|
||||||
|
registration_socket,
|
||||||
|
(uint32_t)worker_id,
|
||||||
|
(uint32_t)workers_amount,
|
||||||
|
attachment->shared_verdict_signal_path
|
||||||
|
);
|
||||||
|
return NANO_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NanoCommunicationResult
|
||||||
|
register_to_attachments_manager(NanoAttachment *attachment)
|
||||||
|
{
|
||||||
|
NanoCommunicationResult res;
|
||||||
|
HttpEventThreadCtx ctx;
|
||||||
|
int t_res;
|
||||||
|
|
||||||
|
// If there was an old socket, close it.
|
||||||
|
if (attachment->registration_socket > 0) {
|
||||||
|
close(attachment->registration_socket);
|
||||||
|
attachment->registration_socket = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_DEBUG, "spawn RegistrationSocketThread");
|
||||||
|
t_res = NanoRunInThreadTimeout(
|
||||||
|
attachment,
|
||||||
|
NULL,
|
||||||
|
RegistrationSocketThread,
|
||||||
|
(void *)&ctx,
|
||||||
|
attachment->registration_thread_timeout_msec,
|
||||||
|
"RegistrationSocketThread",
|
||||||
|
REGISTRATION
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!t_res || ctx.res != NANO_OK) {
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
0,
|
||||||
|
DBG_LEVEL_WARNING,
|
||||||
|
"Failed to connect to registration socket"
|
||||||
|
);
|
||||||
|
close(attachment->registration_socket);
|
||||||
|
attachment->registration_socket = -1;
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = send_registration_data_to_registration_socket(attachment);
|
||||||
|
if (res != NANO_OK) {
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
0,
|
||||||
|
DBG_LEVEL_WARNING,
|
||||||
|
"Failed to send registration data"
|
||||||
|
);
|
||||||
|
close(attachment->registration_socket);
|
||||||
|
attachment->registration_socket = -1;
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = read_verdict_signal_path_from_registration_socket(attachment);
|
||||||
|
if (res != NANO_OK) {
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
0,
|
||||||
|
DBG_LEVEL_WARNING,
|
||||||
|
"Failed to read verdict signal path"
|
||||||
|
);
|
||||||
|
close(attachment->registration_socket);
|
||||||
|
attachment->registration_socket = -1;
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(attachment->registration_socket);
|
||||||
|
attachment->registration_socket = -1;
|
||||||
|
return NANO_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NanoCommunicationResult
|
||||||
|
set_unique_id(NanoAttachment *attachment)
|
||||||
|
{
|
||||||
|
unsigned int unique_id_size = 0;
|
||||||
|
long unsigned int nano_worker_id = attachment->worker_id + 1;
|
||||||
|
|
||||||
|
if (strlen(attachment->container_id) > 0) {
|
||||||
|
unique_id_size += snprintf(
|
||||||
|
attachment->unique_id,
|
||||||
|
MAX_NGINX_UID_LEN,
|
||||||
|
"%s_%lu",
|
||||||
|
attachment->container_id,
|
||||||
|
nano_worker_id);
|
||||||
|
} else {
|
||||||
|
unique_id_size += snprintf(attachment->unique_id, MAX_NGINX_UID_LEN, "%lu", nano_worker_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unique_id_size <= 0) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Failed to set attachment's unique_id");
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unique_id_size >= MAX_NGINX_UID_LEN) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_INFO, "Unique ID is too long, trancheated to: %s", attachment->unique_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_INFO, "Successfully set attachment's unique_id: '%s'", attachment->unique_id);
|
||||||
|
return NANO_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NanoCommunicationResult
|
||||||
|
set_logging_fd(NanoAttachment *attachment, int logging_fd)
|
||||||
|
{
|
||||||
|
char full_logging_path[128];
|
||||||
|
|
||||||
|
if (logging_fd > 0) {
|
||||||
|
attachment->is_default_fd = 0;
|
||||||
|
attachment->logging_fd = logging_fd;
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_DEBUG, "Successfully set provided logging_fd");
|
||||||
|
return NANO_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (createDirectory(attachment, LOGGING_DIRECTORY_PATH) != NANO_OK) {
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(full_logging_path, sizeof(full_logging_path), "%s-%s.dbg", LOGGING_FILE_PATH, attachment->container_id);
|
||||||
|
attachment->logging_fd = open(full_logging_path, O_WRONLY | O_CREAT | O_APPEND, 0644);
|
||||||
|
|
||||||
|
if (attachment->logging_fd < 0) {
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
attachment->is_default_fd = 1;
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Successfully opened logging file");
|
||||||
|
return NANO_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
close_logging_fd(NanoAttachment *attachment)
|
||||||
|
{
|
||||||
|
if (attachment->logging_fd > 0 && attachment->is_default_fd) {
|
||||||
|
close(attachment->logging_fd);
|
||||||
|
attachment->logging_fd = -1;
|
||||||
|
}
|
||||||
|
free(attachment->logging_data);
|
||||||
|
attachment->logging_data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
NanoCommunicationResult
|
||||||
|
nano_attachment_init_process(NanoAttachment *attachment)
|
||||||
|
{
|
||||||
|
attachment->nano_user_id = getuid();
|
||||||
|
attachment->nano_group_id = getgid();
|
||||||
|
attachment->num_of_connection_attempts++;
|
||||||
|
|
||||||
|
init_attachment_config(attachment, SHARED_ATTACHMENT_CONF_PATH);
|
||||||
|
|
||||||
|
if (access(SHARED_REGISTRATION_SIGNAL_PATH, F_OK) != 0) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_TRACE, "Attachment registration manager is turned off");
|
||||||
|
return NANO_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attachment->registration_state == PENDING) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_INFO, "Registration to the Attachments Manager is in process");
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attachment->registration_state == NOT_REGISTERED) {
|
||||||
|
// Register with the attachment manager.
|
||||||
|
if (register_to_attachments_manager(attachment) == NANO_ERROR) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_INFO, "Failed to register to Attachments Manager service");
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
attachment->registration_state = REGISTERED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (init_attachment_config(attachment, SHARED_ATTACHMENT_CONF_PATH) == NANO_ERROR) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Failed to initialize attachment's configuration");
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attachment->comm_socket < 0) {
|
||||||
|
// Signal to the service to start communication.
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_DEBUG, "Registering to nano service");
|
||||||
|
if (init_signaling_socket(attachment) == NANO_ERROR) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_DEBUG, "Failed to register to the Nano Service");
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initalize the the communication channel with the service.
|
||||||
|
if (attachment->nano_service_ipc == NULL) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_INFO, "Initializing IPC channel");
|
||||||
|
attachment->nano_service_ipc = initIpc(
|
||||||
|
attachment->unique_id,
|
||||||
|
attachment->nano_user_id,
|
||||||
|
attachment->nano_group_id,
|
||||||
|
0,
|
||||||
|
attachment->num_of_nano_ipc_elements,
|
||||||
|
attachment->logging_data,
|
||||||
|
write_dbg_impl
|
||||||
|
);
|
||||||
|
if (attachment->nano_service_ipc == NULL) {
|
||||||
|
restart_communication(attachment);
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_INFO, "Failed to initialize IPC with nano service");
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dbg(
|
||||||
|
attachment,
|
||||||
|
0,
|
||||||
|
DBG_LEVEL_INFO,
|
||||||
|
"NGINX attachment (UID='%s') successfully registered to nano service after %d attempts.",
|
||||||
|
attachment->unique_id,
|
||||||
|
attachment->num_of_connection_attempts
|
||||||
|
);
|
||||||
|
|
||||||
|
attachment->num_of_connection_attempts = 0;
|
||||||
|
|
||||||
|
return NANO_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NanoCommunicationResult
|
||||||
|
restart_communication(NanoAttachment *attachment)
|
||||||
|
{
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_TRACE, "Restarting communication channels with nano service");
|
||||||
|
if (attachment->nano_service_ipc != NULL) {
|
||||||
|
destroyIpc(attachment->nano_service_ipc, 0);
|
||||||
|
attachment->nano_service_ipc = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (init_signaling_socket(attachment) == NANO_ERROR) {
|
||||||
|
if (register_to_attachments_manager(attachment) == NANO_ERROR) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_DEBUG, "Failed to register to Attachments Manager service");
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (init_signaling_socket(attachment) == NANO_ERROR) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_DEBUG, "Failed to init the signaling socket");
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attachment->nano_service_ipc = initIpc(
|
||||||
|
attachment->unique_id,
|
||||||
|
attachment->nano_user_id,
|
||||||
|
attachment->nano_group_id,
|
||||||
|
0,
|
||||||
|
attachment->num_of_nano_ipc_elements,
|
||||||
|
attachment->logging_data,
|
||||||
|
write_dbg_impl
|
||||||
|
);
|
||||||
|
if (attachment->nano_service_ipc == NULL) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_DEBUG, "Failed to init IPC");
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
return NANO_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
disconnect_communication(NanoAttachment *attachment)
|
||||||
|
{
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_DEBUG, "Disconnecting communication channels with nano service");
|
||||||
|
|
||||||
|
if (attachment->comm_socket > 0) {
|
||||||
|
close(attachment->comm_socket);
|
||||||
|
attachment->comm_socket = -1;
|
||||||
|
}
|
||||||
|
if (attachment->nano_service_ipc != NULL) {
|
||||||
|
destroyIpc(attachment->nano_service_ipc, 0);
|
||||||
|
attachment->nano_service_ipc = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NanoCommunicationResult
|
||||||
|
handle_shmem_corruption(NanoAttachment *attachment)
|
||||||
|
{
|
||||||
|
NanoCommunicationResult res;
|
||||||
|
|
||||||
|
if (attachment->nano_service_ipc == NULL) {
|
||||||
|
disconnect_communication(attachment);
|
||||||
|
res = restart_communication(attachment);
|
||||||
|
if (res != NANO_OK) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Failed to restart communication");
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isCorruptedShmem(attachment->nano_service_ipc, 0)) {
|
||||||
|
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Shared memory is corrupted! restarting communication");
|
||||||
|
disconnect_communication(attachment);
|
||||||
|
return NANO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NANO_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
isIpcReady(NanoAttachment *attachment)
|
||||||
|
{
|
||||||
|
return attachment->nano_service_ipc != NULL && attachment->comm_socket > 0;
|
||||||
|
}
|
218
attachments/nano_attachment/nano_initializer.h
Normal file
218
attachments/nano_attachment/nano_initializer.h
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
/// @file nano_initializer.h
|
||||||
|
#ifndef __NANO_INITIALIZER_H__
|
||||||
|
#define __NANO_INITIALIZER_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "shmem_ipc_2.h"
|
||||||
|
|
||||||
|
#define LOGGING_DIRECTORY_PATH "/var/log/nano_attachment" ///< Default logging directory path.
|
||||||
|
#define LOGGING_FILE_NAME "nano_attachment" ///< Default logging file name.
|
||||||
|
#define LOGGING_FILE_PATH LOGGING_DIRECTORY_PATH "/" LOGGING_FILE_NAME
|
||||||
|
|
||||||
|
typedef enum nano_attachment_registration_state {
|
||||||
|
NOT_REGISTERED,
|
||||||
|
PENDING,
|
||||||
|
REGISTERED
|
||||||
|
} nano_attachment_registration_state; ///< Indicates the current attachment registation stage.
|
||||||
|
|
||||||
|
typedef struct NanoAttachment {
|
||||||
|
char unique_id[MAX_NGINX_UID_LEN]; // Holds the unique identifier for this instance.
|
||||||
|
char container_id[MAX_NGINX_UID_LEN]; // Holds the container id of the attachment.
|
||||||
|
char shared_verdict_signal_path[MAX_SHARED_MEM_PATH_LEN]; // Holds the path associating the attachment and service.
|
||||||
|
uint8_t worker_id; // Holds the worker number of the attachment.
|
||||||
|
uint8_t num_of_workers; // Holds the number of workers in the attachment.
|
||||||
|
uint32_t nano_user_id; // Holds the user id of the attachment.
|
||||||
|
uint32_t nano_group_id; // Holds the group id of the attachment.
|
||||||
|
int registration_socket; // Holds the file descriptor used for registering the instance.
|
||||||
|
nano_attachment_registration_state registration_state; // Holds the current attachment registation stage.
|
||||||
|
|
||||||
|
uint8_t attachment_type; // Holds the type of the attachment.
|
||||||
|
SharedMemoryIPC *nano_service_ipc; // Holds the shared memory IPC of the nano service.
|
||||||
|
int comm_socket; // Holds the communication socket of the attachment.
|
||||||
|
|
||||||
|
int is_default_fd; // Holds a value indicating if the logging file descriptor is the default one.
|
||||||
|
int logging_fd; // Holds the file descriptor for logging.
|
||||||
|
LoggingData *logging_data; // Holds the logging data of the attachment.
|
||||||
|
|
||||||
|
NanoCommunicationResult is_configuration_updated; // Holds the result of the configuration update.
|
||||||
|
unsigned int current_config_version; // Holds the current configuration version.
|
||||||
|
|
||||||
|
int fail_mode_verdict; ///< Fail open verdict incase of a timeout.
|
||||||
|
int fail_mode_delayed_verdict; ///< Fail open verdict incase of a timeout when waiting for delayed verdict.
|
||||||
|
nano_http_cp_debug_level_e dbg_level; ///< Default debug level.
|
||||||
|
int num_of_connection_attempts; ///< Maximum number of attempted connections.
|
||||||
|
unsigned int fail_open_timeout; ///< Fail open timeout in milliseconds.
|
||||||
|
unsigned int fail_open_delayed_timeout; ///< Fail open delayed timeout in milliseconds.
|
||||||
|
AttachmentVerdict sessions_per_minute_limit_verdict; ///< Session per minute limit verdict.
|
||||||
|
unsigned int max_sessions_per_minute; ///< Masimum session per minute.
|
||||||
|
unsigned int req_max_proccessing_ms_time; ///< Total Request processing timeout in milliseconds.
|
||||||
|
unsigned int res_max_proccessing_ms_time; ///< Total Response processing timeout in milliseconds.
|
||||||
|
unsigned int registration_thread_timeout_msec; ///< Registration timeout in milliseconds.
|
||||||
|
unsigned int req_start_thread_timeout_msec; ///< Request start processing timeout in milliseconds.
|
||||||
|
unsigned int req_header_thread_timeout_msec; ///< Request header processing timeout in milliseconds.
|
||||||
|
unsigned int req_body_thread_timeout_msec; ///< Request body processing timeout in milliseconds.
|
||||||
|
unsigned int res_header_thread_timeout_msec; ///< Response header processing timeout in milliseconds.
|
||||||
|
unsigned int res_body_thread_timeout_msec; ///< Response body processing timeout in milliseconds.
|
||||||
|
unsigned int waiting_for_verdict_thread_timeout_msec; ///< Wait thread processing timeout in milliseconds.
|
||||||
|
unsigned int metric_timeout_timeout; ///< Metric timeout in milliseconds.
|
||||||
|
NanoHttpInspectionMode inspection_mode; ///< Default inspection mode.
|
||||||
|
unsigned int num_of_nano_ipc_elements; ///< Number of NANO IPC elements.
|
||||||
|
uint64_t keep_alive_interval_msec; ///< Keep alive interval in milliseconds.
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
uint64_t metric_data[static_cast<int>(AttachmentMetricType::METRIC_TYPES_COUNT)];
|
||||||
|
uint64_t metric_average_data_divisor[static_cast<int>(AttachmentMetricType::METRIC_TYPES_COUNT)];
|
||||||
|
#else
|
||||||
|
uint64_t metric_data[METRIC_TYPES_COUNT];
|
||||||
|
uint64_t metric_average_data_divisor[METRIC_TYPES_COUNT];
|
||||||
|
#endif
|
||||||
|
} NanoAttachment;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Initialize all the attachments resources and communication channels.
|
||||||
|
/// @param[in] attachment Points to initiated NanoAttachment struct.
|
||||||
|
/// @returns NanoCommunicationResult
|
||||||
|
/// - #NANO_OK
|
||||||
|
/// - #NANO_ERROR
|
||||||
|
/// - #NANO_ABORT
|
||||||
|
///
|
||||||
|
NanoCommunicationResult nano_attachment_init_process(NanoAttachment *attachment);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Preforms send information to the service via a socket.
|
||||||
|
///
|
||||||
|
/// This function writes data to the socket associated with the given NanoAttachment.
|
||||||
|
/// It writes data in parts if necessary, keeping track of the remaining data to be written.
|
||||||
|
/// If the write operation fails or exceeds the allowed timeout, it returns NANO_ERROR;
|
||||||
|
/// otherwise, it returns NANO_OK.
|
||||||
|
///
|
||||||
|
/// @param Points to the NanoAttachment struct.
|
||||||
|
/// @param socket The socket to write to.
|
||||||
|
/// @param data The pointer to the data to be written.
|
||||||
|
/// @param size The size of the data to be written, excluding the null terminator.
|
||||||
|
/// @param absolute_end_time The absolute till the writing is allowed.
|
||||||
|
/// @return NanoCommunicationResult Returns NANO_OK if the write operation is successful, otherwise NANO_ERROR.
|
||||||
|
///
|
||||||
|
NanoCommunicationResult write_to_service(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
int *socket,
|
||||||
|
void *data,
|
||||||
|
uint32_t size,
|
||||||
|
struct timeval *absolute_end_time);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Preforms receive information from the service via a socket.
|
||||||
|
///
|
||||||
|
/// This function reads data from the socket associated with the given NanoAttachment.
|
||||||
|
/// It reads data in parts if necessary, keeping track of the remaining data to be read.
|
||||||
|
/// It checks if the socket has data to be read prior to the read operation to avoid blocking indefinitely.
|
||||||
|
/// If the read operation fails or exceeds the allowed timeout, it returns NANO_ERROR;
|
||||||
|
/// otherwise, it returns NANO_OK.
|
||||||
|
///
|
||||||
|
/// @param attachment Points to the NanoAttachment struct.
|
||||||
|
/// @param socket The socket to read from.
|
||||||
|
/// @param data The pointer to the buffer where the read data will be stored.
|
||||||
|
/// @param size The size of the data to be read.
|
||||||
|
/// @param absolute_end_time The absolute till the reading is allowed.
|
||||||
|
/// @return NanoCommunicationResult Returns NANO_OK if the read operation is successful, otherwise NANO_ERROR.
|
||||||
|
///
|
||||||
|
NanoCommunicationResult read_from_service(
|
||||||
|
NanoAttachment *attachment,
|
||||||
|
int *socket,
|
||||||
|
void *data,
|
||||||
|
uint32_t size,
|
||||||
|
struct timeval *absolute_end_time);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sets a unique identifier for the NanoAttachment based on its container ID and worker ID.
|
||||||
|
///
|
||||||
|
/// @param attachment Pointer to the NanoAttachment structure for which to set the unique ID.
|
||||||
|
/// @return NANO_OK if the unique ID was successfully set, otherwise an error code.
|
||||||
|
///
|
||||||
|
NanoCommunicationResult set_unique_id(NanoAttachment *attachment);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sets the container ID for the NanoAttachment by reading it from CONTAINER_ID_FILE_PATH value.
|
||||||
|
///
|
||||||
|
/// @param attachment Pointer to the NanoAttachment structure for which to set the container ID.
|
||||||
|
/// @return NANO_OK if the container ID was successfully set, otherwise an error code.
|
||||||
|
///
|
||||||
|
NanoCommunicationResult set_docker_id(NanoAttachment *attachment);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Sets the file descriptor for logging in the NanoAttachment structure.
|
||||||
|
///
|
||||||
|
/// If an invalid fd passed, the default logging file descriptor is set to write to LOGGING_FILE_PATH variable.
|
||||||
|
///
|
||||||
|
/// @param attachment Pointer to the NanoAttachment struct to set the logging file descriptor.
|
||||||
|
/// @param logging_fd The file descriptor to set.
|
||||||
|
/// @return NANO_OK if the logging file descriptor is set successfully, NANO_ERROR otherwise.
|
||||||
|
///
|
||||||
|
NanoCommunicationResult set_logging_fd(NanoAttachment *attachment, int logging_fd);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Closes the logging file descriptor in the NanoAttachment structure.
|
||||||
|
///
|
||||||
|
/// @param attachment Pointer to the NanoAttachment struct to close the logging file descriptor.
|
||||||
|
///
|
||||||
|
void close_logging_fd(NanoAttachment *attachment);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Closes any existing communication to the service and tries to open a new one.
|
||||||
|
/// @param[in] attachment Points to initiated NanoAttachment struct.
|
||||||
|
/// @returns NanoCommunicationResult
|
||||||
|
/// - #NANO_OK
|
||||||
|
/// - #NANO_ERROR
|
||||||
|
///
|
||||||
|
NanoCommunicationResult restart_communication(NanoAttachment *attachment);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Checks that the shared memory with the service isn't corrupted, disconnect if it is.
|
||||||
|
/// @param[in] attachment Points to initiated NanoAttachment struct.
|
||||||
|
/// @returns NanoCommunicationResult
|
||||||
|
/// - #NANO_OK
|
||||||
|
/// - #NANO_ERROR
|
||||||
|
///
|
||||||
|
NanoCommunicationResult handle_shmem_corruption(NanoAttachment *attachment);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Closes all the communication channels with the service.
|
||||||
|
/// @param[in] attachment Points to initiated NanoAttachment struct.
|
||||||
|
///
|
||||||
|
void disconnect_communication(NanoAttachment *attachment);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Checks if communication with the service is up and running.
|
||||||
|
/// @param[in] attachment Points to initiated NanoAttachment struct.
|
||||||
|
/// @returns NanoCommunicationResult - 1 if communication is active, otherwise 0.
|
||||||
|
///
|
||||||
|
int isIpcReady(NanoAttachment *attachment);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Register the attachment instance with the attachment manager to associate it with a service.
|
||||||
|
/// @param[in] attachment Points to initiated NanoAttachment struct.
|
||||||
|
/// @returns NanoCommunicationResult
|
||||||
|
/// - #NANO_OK
|
||||||
|
/// - #NANO_ERROR
|
||||||
|
///
|
||||||
|
NanoCommunicationResult register_to_attachments_manager(NanoAttachment *attachment);
|
||||||
|
|
||||||
|
#endif // __NANO_INITIALIZER_H__
|
131
attachments/nano_attachment/nano_utils.c
Normal file
131
attachments/nano_attachment/nano_utils.c
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
/// @file nano_utils.c
|
||||||
|
#include "nano_utils.h"
|
||||||
|
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Gets the current time using a fast, coarse-grained clock.
|
||||||
|
///
|
||||||
|
/// This function uses CLOCK_MONOTONIC_COARSE to retrieve the current time,
|
||||||
|
/// which provides a fast timestamp. The function returns
|
||||||
|
/// the current time as a struct timeval, which represents seconds and microseconds.
|
||||||
|
///
|
||||||
|
/// @return struct timeval The current time as seconds and microseconds.
|
||||||
|
///
|
||||||
|
static struct timeval
|
||||||
|
getCurrTimeFast()
|
||||||
|
{
|
||||||
|
struct timeval curr_time;
|
||||||
|
struct timespec curr_time_mono;
|
||||||
|
|
||||||
|
clock_gettime(CLOCK_MONOTONIC_COARSE, &curr_time_mono);
|
||||||
|
|
||||||
|
curr_time.tv_sec = curr_time_mono.tv_sec;
|
||||||
|
curr_time.tv_usec = curr_time_mono.tv_nsec/1000.0;
|
||||||
|
return curr_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
write_dbg_impl(
|
||||||
|
const LoggingData *logging_data,
|
||||||
|
uint32_t session_id,
|
||||||
|
int _dbg_level,
|
||||||
|
const char *func,
|
||||||
|
const char *file,
|
||||||
|
int line_num,
|
||||||
|
const char *fmt,
|
||||||
|
...
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (logging_data == NULL) return;
|
||||||
|
|
||||||
|
if (_dbg_level < logging_data->dbg_level) return;
|
||||||
|
|
||||||
|
char debug_str[2048] = {0};
|
||||||
|
char session_id_str[32] = {0};
|
||||||
|
char unique_id[32] = "uniqueId";
|
||||||
|
va_list args;
|
||||||
|
time_t ttime;
|
||||||
|
int millisec;
|
||||||
|
struct timeval tv;
|
||||||
|
char time_stamp[64];
|
||||||
|
char str_uid[140];
|
||||||
|
int pid = 0;
|
||||||
|
|
||||||
|
time(&ttime);
|
||||||
|
tv = getCurrTimeFast();
|
||||||
|
millisec = lrint(tv.tv_usec/1000.0);
|
||||||
|
if (millisec>=1000) {
|
||||||
|
// Allow for rounding up to nearest second
|
||||||
|
millisec -=1000;
|
||||||
|
tv.tv_sec++;
|
||||||
|
}
|
||||||
|
strftime(time_stamp, sizeof(time_stamp), "%FT%T", localtime(&ttime));
|
||||||
|
|
||||||
|
if (!pid) pid = getpid();
|
||||||
|
|
||||||
|
if (session_id > 0) {
|
||||||
|
snprintf(session_id_str, sizeof(session_id_str) - 1, "<session id %d> ", session_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints the debug given all the data and a formatter.
|
||||||
|
snprintf(
|
||||||
|
str_uid,
|
||||||
|
sizeof(str_uid) - 1,
|
||||||
|
"|%s.%03d: %s@%s:%d [uid %s | pid %d] %s| ",
|
||||||
|
time_stamp,
|
||||||
|
millisec,
|
||||||
|
func,
|
||||||
|
file,
|
||||||
|
line_num,
|
||||||
|
unique_id,
|
||||||
|
pid,
|
||||||
|
session_id_str
|
||||||
|
);
|
||||||
|
|
||||||
|
va_start(args, fmt);
|
||||||
|
vsnprintf(debug_str, sizeof(debug_str) - 1, fmt, args);
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
dprintf(logging_data->fd, "%s%s\n", str_uid, debug_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct timeval
|
||||||
|
get_absolute_timeout_val_sec(const int delta_time_in_sec)
|
||||||
|
{
|
||||||
|
struct timeval time;
|
||||||
|
|
||||||
|
time = getCurrTimeFast();
|
||||||
|
time.tv_sec += delta_time_in_sec;
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
is_absolute_timeout_reached(struct timeval *timeout)
|
||||||
|
{
|
||||||
|
struct timeval curr_time;
|
||||||
|
|
||||||
|
curr_time = getCurrTimeFast();
|
||||||
|
return (timercmp(timeout, &curr_time, <));
|
||||||
|
}
|
90
attachments/nano_attachment/nano_utils.h
Normal file
90
attachments/nano_attachment/nano_utils.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
/// @file nano_utils.h
|
||||||
|
#ifndef __NANO_UTILS_H__
|
||||||
|
#define __NANO_UTILS_H__
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "nano_initializer.h"
|
||||||
|
|
||||||
|
typedef struct LoggingData {
|
||||||
|
int dbg_level;
|
||||||
|
int worker_id;
|
||||||
|
int fd;
|
||||||
|
} LoggingData;
|
||||||
|
|
||||||
|
#ifndef __FILENAME__
|
||||||
|
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define write_dbg(attachment, session_id, _dbg_level, fmt, ...) \
|
||||||
|
{ \
|
||||||
|
write_dbg_impl( \
|
||||||
|
attachment->logging_data, \
|
||||||
|
session_id, \
|
||||||
|
_dbg_level, \
|
||||||
|
__func__, \
|
||||||
|
__FILENAME__, \
|
||||||
|
__LINE__, \
|
||||||
|
fmt, \
|
||||||
|
##__VA_ARGS__ \
|
||||||
|
); \
|
||||||
|
if ((_dbg_level) == DBG_LEVEL_ASSERT) assert(0); \
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Writing into debug implementation.
|
||||||
|
/// @param[in] LoggingData Logging data.
|
||||||
|
/// @param[in] session_id Session ID.
|
||||||
|
/// @param[in] _dbg_level Debug level to write into.
|
||||||
|
/// @param[in] func Function name from which the write debug was called from.
|
||||||
|
/// @param[in] file File from which the debug function was called from.
|
||||||
|
/// @param[in] line_num Line number of the write debug was called on.
|
||||||
|
/// @param[in] fmt Debug formatter.
|
||||||
|
/// @param[in] ... Extra values to write into the debug using the formatter.
|
||||||
|
///
|
||||||
|
void
|
||||||
|
write_dbg_impl(
|
||||||
|
const LoggingData *logging_data,
|
||||||
|
uint32_t session_id,
|
||||||
|
int _dbg_level,
|
||||||
|
const char *func,
|
||||||
|
const char *file,
|
||||||
|
int line_num,
|
||||||
|
const char *fmt,
|
||||||
|
...
|
||||||
|
);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Get delta current time + delta_time_in_sec value in seconds.
|
||||||
|
/// @param[in] delta_time_in_sec Delta time to return
|
||||||
|
/// @returns timeval struct with tv_sec value of += delta_time_in_sec.
|
||||||
|
///
|
||||||
|
struct timeval get_absolute_timeout_val_sec(const int delta_time_in_sec);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Check if a timeout has been reached.
|
||||||
|
///
|
||||||
|
/// This function compares the specified timeout value with the current time
|
||||||
|
/// to determine if the timeout has been reached.
|
||||||
|
///
|
||||||
|
/// @param[in] timeout A pointer to a struct timeval representing the timeout value.
|
||||||
|
/// @return 1 if the timeout has been reached, 0 otherwise.
|
||||||
|
///
|
||||||
|
int is_absolute_timeout_reached(struct timeval *timeout);
|
||||||
|
|
||||||
|
#endif // __NANO_UTILS_H__
|
@ -1,3 +1,4 @@
|
|||||||
add_subdirectory(shmem_ipc)
|
add_subdirectory(shmem_ipc)
|
||||||
|
add_subdirectory(shmem_ipc_2)
|
||||||
add_subdirectory(compression)
|
add_subdirectory(compression)
|
||||||
add_subdirectory(attachments)
|
add_subdirectory(attachments)
|
||||||
|
471
core/include/attachments/nano_attachment_common.h
Normal file
471
core/include/attachments/nano_attachment_common.h
Normal file
@ -0,0 +1,471 @@
|
|||||||
|
#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>
|
||||||
|
|
||||||
|
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 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_t 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 http_transaction_handler_service/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
|
Loading…
x
Reference in New Issue
Block a user