-
Notifications
You must be signed in to change notification settings - Fork 168
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(libsinsp_e2e): add unix_udp_client_server_read test
Signed-off-by: Roberto Scolaro <[email protected]>
- Loading branch information
1 parent
8362ae9
commit 38e20c8
Showing
4 changed files
with
296 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,292 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
/* | ||
Copyright (C) 2025 The Falco Authors. | ||
Licensed under the Apache License, Version 2.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 "event_capture.h" | ||
#include "sys_call_test.h" | ||
|
||
#include <gtest/gtest.h> | ||
|
||
#include <arpa/inet.h> | ||
#include <fcntl.h> | ||
#include <libsinsp/event.h> | ||
#include <libsinsp/sinsp.h> | ||
#include <libsinsp/sinsp_int.h> | ||
#include <netinet/in.h> | ||
#include <poll.h> | ||
|
||
#include <sys/socket.h> | ||
#include <sys/stat.h> | ||
#include <sys/syscall.h> | ||
#include <sys/types.h> | ||
#include <sys/un.h> | ||
|
||
#include <arpa/inet.h> | ||
#include <netdb.h> | ||
#include <netinet/in.h> | ||
#include <stdio.h> | ||
#include <string.h> | ||
|
||
#include <condition_variable> | ||
|
||
#include <sys/socket.h> | ||
#include <sys/syscall.h> | ||
#include <sys/types.h> | ||
#include <sys/un.h> | ||
|
||
#define NAME "/tmp/python_unix_udp_sockets_example" | ||
#define PAYLOAD "0123456789QWERTYUIOPASDFGHJKLZXCVBNM" | ||
|
||
class unix_udp_server { | ||
public: | ||
unix_udp_server(bool use_recvfrom) { m_use_recvfrom = use_recvfrom; } | ||
|
||
void run() { | ||
int sock; | ||
struct sockaddr_un name; | ||
struct sockaddr_un caddr; | ||
socklen_t address_length = sizeof(struct sockaddr_un); | ||
char buf[1024]; | ||
|
||
m_tid = syscall(SYS_gettid); | ||
|
||
/* Create socket from which to read. */ | ||
sock = socket(AF_UNIX, SOCK_DGRAM, 0); | ||
if(sock < 0) { | ||
perror("opening datagram socket"); | ||
exit(1); | ||
} | ||
|
||
/* Create name. */ | ||
name.sun_family = AF_UNIX; | ||
strcpy(name.sun_path, NAME); | ||
|
||
if(::bind(sock, (struct sockaddr*)&name, SUN_LEN(&name))) { | ||
perror("binding name to datagram socket"); | ||
exit(1); | ||
} | ||
|
||
{ | ||
std::unique_lock<std::mutex> lock(m_mutex); | ||
m_server_ready = true; | ||
m_condition_server_ready.notify_one(); | ||
} | ||
|
||
/* Read from the socket. */ | ||
if(m_use_recvfrom) { | ||
recvfrom(sock, buf, 1024, 0, (struct sockaddr*)&caddr, &address_length); | ||
|
||
recvfrom(sock, buf, 1024, 0, (struct sockaddr*)&caddr, &address_length); | ||
} else { | ||
ASSERT_TRUE(read(sock, buf, 1024) >= 0); | ||
|
||
ASSERT_TRUE(read(sock, buf, 1024) >= 0); | ||
} | ||
|
||
close(sock); | ||
|
||
unlink(NAME); | ||
} | ||
|
||
void wait_for_server_ready() { | ||
std::unique_lock<std::mutex> lock(m_mutex); | ||
m_condition_server_ready.wait(lock, [this]() { return m_server_ready; }); | ||
m_server_ready = false; | ||
} | ||
|
||
int64_t get_tid() { return m_tid; } | ||
|
||
private: | ||
std::mutex m_mutex; | ||
std::condition_variable m_condition_server_ready; | ||
bool m_server_ready = false; | ||
int64_t m_tid; | ||
bool m_use_recvfrom; | ||
}; | ||
|
||
class unix_udp_client { | ||
public: | ||
void run() { | ||
int sock; | ||
struct sockaddr_un name; | ||
|
||
/* Create socket on which to send. */ | ||
sock = socket(AF_UNIX, SOCK_DGRAM, 0); | ||
if(sock < 0) { | ||
perror("opening datagram socket"); | ||
exit(1); | ||
} | ||
|
||
/* Construct name of socket to send to. */ | ||
name.sun_family = AF_UNIX; | ||
strcpy(name.sun_path, NAME); | ||
/* Send message. */ | ||
|
||
sendto(sock, | ||
PAYLOAD, | ||
sizeof(PAYLOAD) - 1, | ||
0, | ||
(struct sockaddr*)&name, | ||
sizeof(struct sockaddr_un)); | ||
|
||
sendto(sock, | ||
PAYLOAD, | ||
sizeof(PAYLOAD) - 1, | ||
0, | ||
(struct sockaddr*)&name, | ||
sizeof(struct sockaddr_un)); | ||
|
||
close(sock); | ||
} | ||
}; | ||
|
||
TEST_F(sys_call_test, unix_udp_client_server_read) { | ||
int32_t callnum = 0; | ||
std::string sport; | ||
unix_udp_server server(false); | ||
|
||
// | ||
// FILTER | ||
// | ||
event_filter_t filter = [&](sinsp_evt* evt) { | ||
return evt->get_tid() == server.get_tid() || m_tid_filter(evt); | ||
}; | ||
|
||
// | ||
// INITIALIZATION | ||
// | ||
run_callback_t test = [&](sinsp* inspector) { | ||
std::thread server_thread(&unix_udp_server::run, &server); | ||
server.wait_for_server_ready(); | ||
|
||
unix_udp_client client; | ||
client.run(); | ||
|
||
server_thread.join(); | ||
}; | ||
|
||
// | ||
// OUTPUT VALDATION | ||
// | ||
captured_event_callback_t callback = [&](const callback_param& param) { | ||
sinsp_evt* evt = param.m_evt; | ||
if(evt->get_type() == PPME_SOCKET_BIND_X) { | ||
std::string ttuple = evt->get_param_value_str("addr"); | ||
|
||
EXPECT_EQ(NAME, ttuple); | ||
|
||
callnum++; | ||
} | ||
|
||
if(evt->get_type() == PPME_SOCKET_SENDTO_E) { | ||
std::string ttuple = evt->get_param_value_str("tuple"); | ||
std::stringstream taddrs(ttuple.substr(0, ttuple.find(" "))); | ||
std::string tfile = ttuple.substr(ttuple.find(" ") + 1); | ||
|
||
EXPECT_EQ(NAME, tfile); | ||
|
||
std::string token; | ||
std::vector<std::string> ttst; | ||
while(std::getline(taddrs, token, '>')) { | ||
ttst.push_back(token); | ||
} | ||
EXPECT_EQ(2, ttst.size()); | ||
std::string tsrcstr = ttst[0].substr(0, ttst[0].size() - 1); | ||
std::string tdststr = ttst[1]; | ||
|
||
if(evt->get_tid() == server.get_tid()) { | ||
EXPECT_NE("0", tsrcstr); | ||
EXPECT_EQ("0", tdststr); | ||
} else { | ||
EXPECT_EQ("0", tsrcstr); | ||
EXPECT_NE("0", tdststr); | ||
} | ||
|
||
std::string fdtuple = evt->get_param_value_str("fd"); | ||
|
||
if(fdtuple.length() > 3) { | ||
std::string fdfile = fdtuple.substr(fdtuple.find(" ") + 1); | ||
std::stringstream fdaddrs(fdtuple.substr(0, fdtuple.find(" "))); | ||
|
||
EXPECT_EQ(NAME, fdfile); | ||
|
||
std::vector<std::string> fdtst; | ||
while(std::getline(fdaddrs, token, '>')) { | ||
fdtst.push_back(token); | ||
} | ||
EXPECT_EQ(3, fdtst.size()); | ||
std::string fdsrcstr = fdtst[0].substr(0, fdtst[1].size() - 1); | ||
std::string fddststr = fdtst[1]; | ||
|
||
EXPECT_EQ('u', fdtuple[1]); | ||
|
||
if(evt->get_tid() == server.get_tid()) { | ||
EXPECT_NE("0", tsrcstr); | ||
EXPECT_EQ("0", tdststr); | ||
} else { | ||
EXPECT_EQ("0", tsrcstr); | ||
EXPECT_NE("0", tdststr); | ||
} | ||
} else { | ||
if(fdtuple.length() == 1) { | ||
EXPECT_EQ("u", fdtuple); | ||
} | ||
} | ||
|
||
if(evt->get_type() == PPME_SOCKET_SENDTO_X) { | ||
EXPECT_EQ(PAYLOAD, evt->get_param_value_str("data")); | ||
} | ||
|
||
callnum++; | ||
} else if(evt->get_type() == PPME_SYSCALL_READ_E) { | ||
if(callnum < 1) { | ||
return; | ||
} | ||
|
||
std::string fdtuple = evt->get_param_value_str("fd"); | ||
|
||
EXPECT_GT(fdtuple.length(), 1); | ||
|
||
if(fdtuple.length() > 1) { | ||
std::string ttype = fdtuple.substr(0, fdtuple.find(">")); | ||
std::string tfile = fdtuple.substr(fdtuple.find(">") + 1); | ||
|
||
if(ttype != "<u") { | ||
return; | ||
} | ||
EXPECT_EQ(NAME, tfile); | ||
} | ||
|
||
callnum++; | ||
} else if(evt->get_type() == PPME_SYSCALL_READ_X) { | ||
if(PAYLOAD == evt->get_param_value_str("data")) { | ||
callnum++; | ||
} | ||
} | ||
}; | ||
|
||
ASSERT_NO_FATAL_FAILURE({ | ||
event_capture::run(test, | ||
callback, | ||
filter, | ||
event_capture::do_nothing, | ||
event_capture::do_nothing, | ||
event_capture::do_nothing, | ||
libsinsp::events::all_sc_set()); | ||
}); | ||
EXPECT_EQ(7, callnum); | ||
} |