From 3b9faa6f9f009a0087286947e8a2b651de4dd36f Mon Sep 17 00:00:00 2001 From: Kevin Martel Date: Sun, 9 Jun 2024 13:36:22 -0700 Subject: [PATCH 1/6] add code coverage --- .github/workflows/coverage.yml | 22 ++++++ VERSION | 2 +- test/CMakeLists.txt | 5 +- test/Testcppsocket.cpp | 119 ++++++++++++++++++++++++++++++++- 4 files changed, 144 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/coverage.yml diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 0000000..b1c536a --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,22 @@ +on: pull_request + +name: Continuous Integration + +jobs: + coverage_report: + name: Generate coverage report + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + # ... Generate LCOV files or download it from a different job + - name: Setup LCOV + uses: hrishikesh-kadam/setup-lcov@v1 + - name: Report code coverage + uses: zgosalvez/github-actions-report-lcov@v3 + with: + coverage-files: coverage/lcov.*.info + minimum-coverage: 90 + artifact-name: code-coverage-report + github-token: ${{ secrets.GITHUB_TOKEN }} + update-comment: true \ No newline at end of file diff --git a/VERSION b/VERSION index 1750564..5a5831a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.0.6 +0.0.7 diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8822fc6..4c34b1d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,8 +1,9 @@ if(CMAKE_COMPILER_IS_GNUCXX) if(CMAKE_BUILD_TYPE STREQUAL "Coverage") message(STATUS "Code Coverage") - set(CMAKE_CXX_FLAGS "-g -O0 -Wall -Werror --coverage") - set(CMAKE_C_FLAGS "-g -O0 -Wall -Werror --coverage") + + set(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage --coverage") + set(CMAKE_C_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage --coverage") elseif(CMAKE_BUILD_TYPE STREQUAL "ASAN") message(STATUS "Address sanitization") set(CMAKE_CXX_FLAGS "-O3 -Wall -Werror -fsanitize=address -static-libasan") diff --git a/test/Testcppsocket.cpp b/test/Testcppsocket.cpp index 937785f..8219f60 100644 --- a/test/Testcppsocket.cpp +++ b/test/Testcppsocket.cpp @@ -27,6 +27,7 @@ static int gargc{0}; static char** gargv = nullptr; #endif +using com::github::socket::Socket; using com::github::socket::TcpClient; using com::github::socket::TcpServer; using com::github::socket::UdpClient; @@ -74,8 +75,16 @@ TEST(Unsecure, TCP) ASSERT_EQ(TEST_STRING2.compare(buffer.data()), 0); }); + std::string clientIp; + uint16_t clientPort = 0; std::cout << "Accepting" << std::endl; - TcpClient client = server.accept(); + Socket& serverSocket = static_cast(server); + auto acceptSocket = serverSocket.accept(clientIp, clientPort); + ASSERT_GT(acceptSocket, 0); + TcpClient client(acceptSocket); + + ASSERT_STREQ(clientIp.c_str(), IP_ADDR.c_str()); + ASSERT_GT(clientPort, 0); std::cout << "Server accepted" << std::endl; @@ -97,6 +106,57 @@ TEST(Unsecure, TCP) std::cout << "********************** TCP Unsecure Test PASSED *******************" << std::endl; } +// NOLINTNEXTLINE +TEST(Unsecure2, TCP) +{ + std::cout << "Start TCP Test 1" << std::endl; + TcpServer server("0.0.0.0", TCP_TEST1_SERVER_PORT, 5); + ASSERT_EQ(server.listen(1), 0); + + auto testThread = std::jthread([]{ + TcpClient client(IP_ADDR, TCP_TEST1_SERVER_PORT); + + std::cout << "Client connected" << std::endl; + + auto ret = client.send(TEST_STRING1.c_str(), TEST_STRING1.length()); + ASSERT_EQ(ret, static_cast(TEST_STRING1.length())); + + std::cout << "Client sent: " << TEST_STRING1 << std::endl; + + std::array buffer = {}; + ret = client.read(buffer.data(), buffer.size()); + ASSERT_EQ(ret, static_cast(TEST_STRING2.length())); + + buffer[ret] = '\0'; + + std::cout << "Client received: " << buffer.data() << std::endl; + + ASSERT_EQ(TEST_STRING2.compare(buffer.data()), 0); + }); + + std::cout << "Accepting" << std::endl; + TcpClient client = server.accept(); + + std::cout << "Server accepted" << std::endl; + + std::array buffer = {}; + auto ret = client.read(buffer.data(), buffer.size()); + ASSERT_EQ(ret, static_cast(TEST_STRING1.length())); + + buffer[ret] = '\0'; + + std::cout << "Server received: " << buffer.data() << std::endl; + + ASSERT_EQ(TEST_STRING1.compare(buffer.data()), 0); + + ret = client.send(TEST_STRING2.c_str(), TEST_STRING2.length()); + ASSERT_EQ(ret, static_cast(TEST_STRING2.length())); + + std::cout << "Server sent: " << TEST_STRING2 << std::endl; + + std::cout << "********************** TCP Unsecure Test 2 PASSED *******************" << std::endl; +} + // NOLINTNEXTLINE TEST(Unsecure, UDP) { @@ -148,6 +208,63 @@ TEST(Unsecure, UDP) std::cout << "********************** UDP Unsecure Test PASSED *******************" << std::endl; } +// NOLINTNEXTLINE +TEST(Unsecure2, UDP) +{ + std::cout << "Start UDP Test 1" << std::endl; + + UdpServer server(UDP_TEST1_SERVER_PORT, IP_ADDR); + + auto testThread = std::jthread([]{ + UdpClient client; + + std::cout << "Client connected" << std::endl; + + auto ret = client.sendto(TEST_STRING1.c_str(), TEST_STRING1.length(), IP_ADDR, UDP_TEST1_SERVER_PORT); + ASSERT_EQ(ret, static_cast(TEST_STRING1.length())); + + std::cout << "Client sent: " << TEST_STRING1 << std::endl; + + std::string readfromIp; + uint16_t readfromPort; + std::array buffer = {}; + ret = client.readfrom(buffer.data(), buffer.size(), readfromIp, readfromPort); + ASSERT_EQ(ret, static_cast(TEST_STRING2.length())); + ASSERT_STREQ(readfromIp.c_str(), IP_ADDR.c_str()); + ASSERT_GT(readfromPort, 0); + + buffer[ret] = '\0'; + + std::cout << "Client received: " << buffer.data() << std::endl; + + ASSERT_EQ(TEST_STRING2.compare(buffer.data()), 0); + }); + + // wait for client to start + std::this_thread::sleep_for(std::chrono::milliseconds(ONE_HUNDRED_MSECS)); + + sockaddr_in readAddr = {}; + socklen_t len = sizeof(readAddr); + std::array buffer = {}; + auto ret = server.readfrom(buffer.data(), buffer.size(), reinterpret_cast(&readAddr), &len); + ASSERT_EQ(ret, static_cast(TEST_STRING1.length())); + + buffer[ret] = '\0'; + + std::cout << "Server received: " << buffer.data() << std::endl; + + ASSERT_EQ(TEST_STRING1.compare(buffer.data()), 0); + + ret = server.sendto(TEST_STRING2.c_str(), TEST_STRING2.length(), reinterpret_cast(&readAddr), len); + ASSERT_EQ(ret, static_cast(TEST_STRING2.length())); + + std::cout << "Server sent: " << TEST_STRING2 << std::endl; + + testThread.join(); + + std::cout << "********************** UDP Unsecure Test 2 PASSED *******************" << std::endl; +} + // NOLINTNEXTLINE TEST(Secure, TCP) { From 609efccc0c3e6320aa62a8e7de039eec10764c8d Mon Sep 17 00:00:00 2001 From: Kevin Martel Date: Sun, 9 Jun 2024 13:48:09 -0700 Subject: [PATCH 2/6] update coverage action --- .github/workflows/coverage.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index b1c536a..41ad545 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -12,6 +12,27 @@ jobs: # ... Generate LCOV files or download it from a different job - name: Setup LCOV uses: hrishikesh-kadam/setup-lcov@v1 + - name: Install gtest + run: sudo apt-get install libgtest-dev && cd /usr/src/gtest && sudo cmake CMakeLists.txt && sudo make && sudo cp lib/*.a /usr/lib && sudo ln -s /usr/lib/libgtest.a /usr/local/lib/libgtest.a && sudo ln -s /usr/lib/libgtest_main.a /usr/local/lib/libgtest_main.a + + - name: Write files + env: + FILE_ONE: ${{ secrets.KRM_MAIN_FILE }} + FILE_TWO: ${{ secrets.KRM_SCND_FILE }} + run: | + echo "${FILE_ONE}" | base64 --decode > ${HOME}/key.pem | + echo "${FILE_TWO}" | base64 --decode > ${HOME}/scert.crt + + - name: Build and test + run: | + cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=Release + cmake --build ${{github.workspace}}/build --config Release + ctest -VV --test-dir ${{github.workspace}}/build -C Release + + - name: Run lcov + run: | + lcov -c -d . -o lcov.info + - name: Report code coverage uses: zgosalvez/github-actions-report-lcov@v3 with: From 451ff2d0b9037c82a6b6f50f43e79b8b14954c0e Mon Sep 17 00:00:00 2001 From: Kevin Martel Date: Mon, 10 Jun 2024 22:26:26 -0700 Subject: [PATCH 3/6] add more testing and move to embedded compiler flags --- .github/workflows/coverage.yml | 3 +- CMakeLists.txt | 6 -- inc/cppsocket.hpp | 114 ++++++++++++------------- test/Testcppsocket.cpp | 152 ++++++++++++++++++++++++++++++++- 4 files changed, 204 insertions(+), 71 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 41ad545..9c83d90 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -12,7 +12,8 @@ jobs: # ... Generate LCOV files or download it from a different job - name: Setup LCOV uses: hrishikesh-kadam/setup-lcov@v1 - - name: Install gtest + + - name: Install gtest run: sudo apt-get install libgtest-dev && cd /usr/src/gtest && sudo cmake CMakeLists.txt && sudo make && sudo cp lib/*.a /usr/lib && sudo ln -s /usr/lib/libgtest.a /usr/local/lib/libgtest.a && sudo ln -s /usr/lib/libgtest_main.a /usr/local/lib/libgtest_main.a - name: Write files diff --git a/CMakeLists.txt b/CMakeLists.txt index 81c6f24..e618181 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,12 +11,6 @@ SET(LICENSE "MIT") project(cppsocket VERSION ${project_version} LANGUAGES CXX) -if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - add_definitions(-DLINUX) -else() - add_definitions(-DWINDOWS) -endif() - include_directories(inc) enable_testing() diff --git a/inc/cppsocket.hpp b/inc/cppsocket.hpp index 7568826..9ccca0b 100644 --- a/inc/cppsocket.hpp +++ b/inc/cppsocket.hpp @@ -1,5 +1,5 @@ -#ifdef LINUX +#ifdef __GNUC__ #include #include @@ -46,7 +46,7 @@ namespace com::github::socket Socket(Socket&) = delete; Socket() noexcept(false) -#ifdef LINUX +#ifdef __GNUC__ : m_fd(-1) #else : m_fd(INVALID_SOCKET) @@ -55,7 +55,7 @@ namespace com::github::socket init(); } -#ifdef LINUX +#ifdef __GNUC__ explicit Socket(const int filedescriptor) noexcept #else explicit Socket(SOCKET filedescriptor) noexcept @@ -72,7 +72,7 @@ namespace com::github::socket virtual ~Socket() { -#ifdef LINUX +#ifdef __GNUC__ static_cast(::shutdown(m_fd, SHUT_RDWR)); static_cast(::close(m_fd)); #else @@ -84,7 +84,7 @@ namespace com::github::socket void initSocket(const int domain, const int type, const int protocol) noexcept(false) { m_fd = ::socket(domain, type, protocol); -#ifdef LINUX +#ifdef __GNUC__ if (m_fd < 0) #else if (m_fd == INVALID_SOCKET) @@ -94,7 +94,7 @@ namespace com::github::socket } } -#ifdef LINUX +#ifdef __GNUC__ auto accept(sockaddr* address, socklen_t* addrlen) const noexcept -> int #else auto accept(sockaddr* address, socklen_t* addrlen) const noexcept -> SOCKET @@ -103,7 +103,7 @@ namespace com::github::socket return ::accept(m_fd, address, addrlen); } -#ifdef LINUX +#ifdef __GNUC__ [[nodiscard]] auto accept(std::string& ipAddr, uint16_t& port) const noexcept(false) -> int #else [[nodiscard]] auto accept(std::string& ipAddr, uint16_t& port) const noexcept(false) -> SOCKET @@ -112,7 +112,7 @@ namespace com::github::socket sockaddr_in addr = {}; socklen_t length = sizeof(addr); auto retval = accept(reinterpret_cast(&addr), &length); -#ifdef LINUX +#ifdef __GNUC__ if (retval > 0) #else if (retval != INVALID_SOCKET) @@ -169,7 +169,7 @@ namespace com::github::socket [[nodiscard]] auto read(void* buffer, size_t length) const noexcept -> ssize_t { -#ifdef LINUX +#ifdef __GNUC__ return ::read(m_fd, buffer, length); #else return ::recv(m_fd, reinterpret_cast(buffer), length, 0); @@ -178,7 +178,7 @@ namespace com::github::socket [[nodiscard]] auto readfrom(void* buffer, size_t length, sockaddr* from, socklen_t* fromlength) const noexcept -> ssize_t { -#ifdef LINUX +#ifdef __GNUC__ return ::recvfrom(m_fd, buffer, length, 0, from, fromlength); #else return ::recvfrom(m_fd, reinterpret_cast(buffer), length, 0, from, fromlength); @@ -201,7 +201,7 @@ namespace com::github::socket auto send(const void* buffer, size_t length) const noexcept -> ssize_t { -#ifdef LINUX +#ifdef __GNUC__ return ::send(m_fd, buffer, length, 0); #else return ::send(m_fd, reinterpret_cast(buffer), length, 0); @@ -210,7 +210,7 @@ namespace com::github::socket auto sendto(const void* buffer, size_t length, const sockaddr* toaddr, int tolength) const noexcept -> ssize_t { -#ifdef LINUX +#ifdef __GNUC__ return ::sendto(m_fd, buffer, length, 0, toaddr, tolength); #else return ::sendto(m_fd, reinterpret_cast(buffer), length, 0, toaddr, tolength); @@ -224,40 +224,23 @@ namespace com::github::socket return sendto(buffer, length, reinterpret_cast(&addr), sizeof(addr)); } - [[nodiscard]] auto select(fd_set* readfds, fd_set* writefds, fd_set* exceptfds, timeval* timeout) const noexcept -> ssize_t + [[nodiscard]] auto selectWrite(timeval& timeout) const noexcept -> bool { - return ::select(m_fd, readfds, writefds, exceptfds, timeout); + fd_set set; + FD_SET(m_fd, &set); + return ::select(m_fd+1, nullptr, &set, nullptr, &timeout); } - [[nodiscard]] auto select(fd_set& readfds, fd_set& writefds, fd_set& exceptfds, timeval& timeout) const noexcept -> ssize_t + [[nodiscard]] auto selectRead(timeval& timeout) const noexcept -> bool { - return ::select(m_fd, &readfds, &writefds, &exceptfds, &timeout); - } - - [[nodiscard]] auto select(fd_set& readfds, fd_set& writefds, fd_set& exceptfds, const int milliseconds) const noexcept -> ssize_t - { - ssize_t retval; - if (milliseconds < 0) - { - retval = ::select(m_fd, &readfds, &writefds, &exceptfds, nullptr); - } - else - { - timeval timeout - { - .tv_sec = static_cast(milliseconds * MILLISECONDS_PER_SECOND), - .tv_usec = static_cast(milliseconds / MILLISECONDS_PER_SECOND) - }; - - retval = select(readfds, writefds, exceptfds, timeout); - } - - return retval; + fd_set set; + FD_SET(m_fd, &set); + return ::select(m_fd+1, &set, nullptr, nullptr, &timeout); } auto getsockopt(const int level, const int optname, void *optval, socklen_t* optlen) const noexcept -> ssize_t { -#ifdef LINUX +#ifdef __GNUC__ return ::getsockopt(m_fd, level, optname, optval, optlen); #else return ::getsockopt(m_fd, level, optname, reinterpret_cast(optval), optlen); @@ -266,13 +249,22 @@ namespace com::github::socket auto setsockopt(const int level, const int optname, const void *optval, const int optlen) const noexcept -> ssize_t { -#ifdef LINUX +#ifdef __GNUC__ return ::setsockopt(m_fd, level, optname, optval, optlen); #else return ::setsockopt(m_fd, level, optname, reinterpret_cast(optval), optlen); #endif } +#ifdef __GNUC__ + auto getFd() const noexcept -> int +#else + auto getFd() const noexcept -> SOCKET +#endif + { + return m_fd; + } + protected: [[nodiscard]] static auto getIpAddress(const in_addr inaddr) noexcept(false) -> std::string @@ -292,7 +284,7 @@ namespace com::github::socket */ void init() noexcept(false) { -#ifdef WINDOWS +#ifdef __MSC_VER std::call_once(m_onetime, [this]() { if (::WSAStartup(MAKEWORD(2, 2), &m_wsaData) != 0) @@ -414,7 +406,7 @@ namespace com::github::socket constexpr static unsigned int FIVE_SECONDS = 5; // NOLINT static std::array m_cookie; // NOLINT -#ifdef LINUX +#ifdef __GNUC__ int m_fd; // NOLINT #else SOCKET m_fd; // NOLINT @@ -456,7 +448,7 @@ namespace com::github::socket initAddr(ipAddr, port, addr); auto ret = ::connect(m_fd, reinterpret_cast(&addr), sizeof(addr)); -#ifdef LINUX +#ifdef __GNUC__ if (ret < 0) #else if (ret == SOCKET_ERROR) @@ -471,7 +463,7 @@ namespace com::github::socket void init() noexcept(false) { int flag = 1; -#ifdef LINUX +#ifdef __GNUC__ if (setsockopt(IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)) != 0) #else if (setsockopt(IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&flag), sizeof(flag)) == SOCKET_ERROR) @@ -524,7 +516,7 @@ namespace com::github::socket sockaddr_in client = {}; socklen_t clientLen = sizeof(client); auto fileD = Socket::accept(reinterpret_cast(&client), &clientLen); -#ifdef LINUX +#ifdef __GNUC__ if (fileD < 0) #else if (fileD == INVALID_SOCKET) @@ -541,7 +533,7 @@ namespace com::github::socket void init() noexcept(false) { int opt = 1; -#ifdef LINUX +#ifdef __GNUC__ if (setsockopt(SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)) != 0) #else if (setsockopt(SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&opt), sizeof(opt)) == SOCKET_ERROR) @@ -590,7 +582,7 @@ namespace com::github::socket [[nodiscard]] auto read(void* buffer, size_t length) noexcept -> ssize_t { socklen_t fromlength = sizeof(m_serverAddr); -#ifdef LINUX +#ifdef __GNUC__ return ::recvfrom(m_fd, buffer, length, 0, reinterpret_cast(&m_serverAddr), &fromlength); #else return ::recvfrom(m_fd, reinterpret_cast(buffer), length, 0, reinterpret_cast(&m_serverAddr), &fromlength); @@ -599,7 +591,7 @@ namespace com::github::socket auto send(const void* buffer, size_t length) noexcept -> ssize_t { -#ifdef LINUX +#ifdef __GNUC__ return ::sendto(m_fd, buffer, length, 0, reinterpret_cast(&m_serverAddr), sizeof(m_serverAddr)); #else return ::sendto(m_fd, reinterpret_cast(buffer), length, 0, reinterpret_cast(&m_serverAddr), sizeof(m_serverAddr)); @@ -637,7 +629,7 @@ namespace com::github::socket [[nodiscard]] auto read(void* buffer, size_t length) noexcept -> ssize_t { socklen_t fromlength = sizeof(m_clientAddr); -#ifdef LINUX +#ifdef __GNUC__ return ::recvfrom(m_fd, buffer, length, 0, reinterpret_cast(&m_clientAddr), &fromlength); #else return ::recvfrom(m_fd, reinterpret_cast(buffer), length, 0, reinterpret_cast(&m_clientAddr), &fromlength); @@ -646,7 +638,7 @@ namespace com::github::socket auto send(const void* buffer, size_t length) noexcept -> ssize_t { -#ifdef LINUX +#ifdef __GNUC__ return ::sendto(m_fd, buffer, length, 0, reinterpret_cast(&m_clientAddr), sizeof(m_clientAddr)); #else return ::sendto(m_fd, reinterpret_cast(buffer), length, 0, reinterpret_cast(&m_clientAddr), sizeof(m_clientAddr)); @@ -658,7 +650,7 @@ namespace com::github::socket void init() noexcept(false) { int opt = 1; -#ifdef LINUX +#ifdef __GNUC__ if (setsockopt(SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)) != 0) #else if (setsockopt(SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&opt), sizeof(opt)) == SOCKET_ERROR) @@ -679,7 +671,7 @@ namespace com::github::socket auto operator=(SecureTcpClient&&) -> SecureTcpClient& = delete; SecureTcpClient(SecureTcpClient&) = delete; -#ifdef LINUX +#ifdef __GNUC__ SecureTcpClient(const int filedescriptor, SSL_CTX* sslctx) noexcept(false) #else SecureTcpClient(SOCKET filedescriptor, SSL_CTX *sslctx) noexcept(false) @@ -717,7 +709,7 @@ namespace com::github::socket initAddr(ipAddr, port, addr); auto ret = connect(reinterpret_cast(&addr), sizeof(addr)); -#ifdef LINUX +#ifdef __GNUC__ if (ret < 0) #else if (ret == SOCKET_ERROR) @@ -765,7 +757,7 @@ namespace com::github::socket void init() noexcept(false) { m_fd = ::socket(AF_INET, SOCK_STREAM, 0); -#ifdef LINUX +#ifdef __GNUC__ if (m_fd < 0) #else if (m_fd == INVALID_SOCKET) @@ -775,7 +767,7 @@ namespace com::github::socket } int flag = 1; -#ifdef LINUX +#ifdef __GNUC__ if (setsockopt(IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)) != 0) #else if (setsockopt(IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&flag), sizeof(flag)) == SOCKET_ERROR) @@ -861,7 +853,7 @@ namespace com::github::socket [[nodiscard]] auto accept(std::string& ipAddr, uint16_t& port) noexcept(false) -> SecureTcpClient { auto fileD = Socket::accept(ipAddr, port); -#ifdef LINUX +#ifdef __GNUC__ if (fileD < 0) #else if (fileD == INVALID_SOCKET) @@ -885,7 +877,7 @@ namespace com::github::socket sockaddr_in client = {}; socklen_t clientLen = sizeof(client); auto fileD = Socket::accept(reinterpret_cast(&client), &clientLen); -#ifdef LINUX +#ifdef __GNUC__ if (fileD < 0) #else if (fileD == INVALID_SOCKET) @@ -906,7 +898,7 @@ namespace com::github::socket Socket::init(); m_fd = ::socket(AF_INET, SOCK_STREAM, 0); -#ifdef LINUX +#ifdef __GNUC__ if (m_fd < 0) #else if (m_fd == INVALID_SOCKET) @@ -916,7 +908,7 @@ namespace com::github::socket } int opt = 1; -#ifdef LINUX +#ifdef __GNUC__ if (setsockopt(SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)) != 0) #else if (setsockopt(SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&opt), sizeof(opt)) == SOCKET_ERROR) @@ -1034,7 +1026,7 @@ namespace com::github::socket void init(const std::string& keyFile, const std::string& certFile) noexcept(false) { m_fd = ::socket(AF_INET, SOCK_DGRAM, 0); -#ifdef LINUX +#ifdef __GNUC__ if (m_fd < 0) #else if (m_fd == INVALID_SOCKET) @@ -1185,7 +1177,7 @@ namespace com::github::socket SSL_CTX_set_cookie_verify_cb(m_sslctx, &Socket::verifyCookie); m_fd = ::socket(AF_INET, SOCK_DGRAM, 0); -#ifdef LINUX +#ifdef __GNUC__ if (m_fd < 0) #else if (m_fd == INVALID_SOCKET) @@ -1195,7 +1187,7 @@ namespace com::github::socket } int opt = 1; -#ifdef LINUX +#ifdef __GNUC__ if (setsockopt(SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)) != 0) #else if (setsockopt(SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&opt), sizeof(opt)) == SOCKET_ERROR) diff --git a/test/Testcppsocket.cpp b/test/Testcppsocket.cpp index 8219f60..1e58cd0 100644 --- a/test/Testcppsocket.cpp +++ b/test/Testcppsocket.cpp @@ -1,3 +1,7 @@ +#if __cplusplus < 202002L +#error "Requires C++20 or greater" +#endif + #include #include "cppsocket.hpp" @@ -6,7 +10,7 @@ #include #include -#ifdef LINUX +#ifdef __GNUC__ #include #include @@ -57,6 +61,12 @@ TEST(Unsecure, TCP) auto testThread = std::jthread([]{ TcpClient client(IP_ADDR, TCP_TEST1_SERVER_PORT); + int flag = 0; + socklen_t len = sizeof(flag); + ASSERT_EQ(client.getsockopt(IPPROTO_TCP, TCP_NODELAY, &flag, &len), 0); + ASSERT_EQ(flag, 1); + ASSERT_EQ(len, sizeof(flag)); + std::cout << "Client connected" << std::endl; auto ret = client.send(TEST_STRING1.c_str(), TEST_STRING1.length()); @@ -88,6 +98,9 @@ TEST(Unsecure, TCP) std::cout << "Server accepted" << std::endl; + timeval timeout {.tv_sec = 1, .tv_usec = 0}; + ASSERT_TRUE(client.selectRead(timeout)); + std::array buffer = {}; auto ret = client.read(buffer.data(), buffer.size()); ASSERT_EQ(ret, static_cast(TEST_STRING1.length())); @@ -98,6 +111,8 @@ TEST(Unsecure, TCP) ASSERT_EQ(TEST_STRING1.compare(buffer.data()), 0); + ASSERT_TRUE(client.selectWrite(timeout)); + ret = client.send(TEST_STRING2.c_str(), TEST_STRING2.length()); ASSERT_EQ(ret, static_cast(TEST_STRING2.length())); @@ -211,7 +226,7 @@ TEST(Unsecure, UDP) // NOLINTNEXTLINE TEST(Unsecure2, UDP) { - std::cout << "Start UDP Test 1" << std::endl; + std::cout << "Start UDP Test 2" << std::endl; UdpServer server(UDP_TEST1_SERVER_PORT, IP_ADDR); @@ -265,11 +280,70 @@ TEST(Unsecure2, UDP) std::cout << "********************** UDP Unsecure Test 2 PASSED *******************" << std::endl; } +// NOLINTNEXTLINE +TEST(Unsecure3, UDP) +{ + std::cout << "Start UDP Test 3" << std::endl; + + UdpServer server(UDP_TEST1_SERVER_PORT, IP_ADDR); + + auto testThread = std::jthread([]{ + UdpClient client; //(IP_ADDR, UDP_TEST1_SERVER_PORT); + sockaddr_in addr; + addr.sin_family = AF_INET; + ASSERT_GT(::inet_pton(AF_INET, IP_ADDR.c_str(), &addr.sin_addr), 0); + addr.sin_port = ::htons(UDP_TEST1_SERVER_PORT); + + ASSERT_EQ(client.connect(reinterpret_cast(&addr), sizeof(addr)), 0); + + std::cout << "Client connected" << std::endl; + + auto ret = client.send(TEST_STRING1.c_str(), TEST_STRING1.length()); + ASSERT_EQ(ret, static_cast(TEST_STRING1.length())); + + std::cout << "Client sent: " << TEST_STRING1 << std::endl; + + std::array buffer = {}; + ret = client.read(buffer.data(), buffer.size()); + ASSERT_EQ(ret, static_cast(TEST_STRING2.length())); + + buffer[ret] = '\0'; + + std::cout << "Client received: " << buffer.data() << std::endl; + + ASSERT_EQ(TEST_STRING2.compare(buffer.data()), 0); + }); + + // wait for client to start + std::this_thread::sleep_for(std::chrono::milliseconds(ONE_HUNDRED_MSECS)); + + std::array buffer = {}; + auto ret = server.read(buffer.data(), buffer.size()); + ASSERT_EQ(ret, static_cast(TEST_STRING1.length())); + + buffer[ret] = '\0'; + + std::cout << "Server received: " << buffer.data() << std::endl; + + ASSERT_EQ(TEST_STRING1.compare(buffer.data()), 0); + + ret = server.send(TEST_STRING2.c_str(), TEST_STRING2.length()); + ASSERT_EQ(ret, static_cast(TEST_STRING2.length())); + + std::cout << "Server sent: " << TEST_STRING2 << std::endl; + + testThread.join(); + + std::cout << "********************** UDP Unsecure Test 3 PASSED *******************" << std::endl; +} + // NOLINTNEXTLINE TEST(Secure, TCP) { std::cout << "Start TCP Test 2" << std::endl; + ASSERT_THROW(SecureTcpServer("", ""), std::runtime_error); + SecureTcpServer server(KEY_FILE, CERT_FILE); ASSERT_EQ(server.bind(IP_ADDR, TCP_TEST2_SERVER_PORT), true); @@ -305,7 +379,11 @@ TEST(Secure, TCP) // wait for server to set itself up std::this_thread::sleep_for(std::chrono::seconds(1)); std::cout << "Accepting" << std::endl; - SecureTcpClient client = server.accept(); + std::string acceptIp; + uint16_t acceptPort; + SecureTcpClient client = server.accept(acceptIp, acceptPort); + ASSERT_STREQ(acceptIp.c_str(), IP_ADDR.c_str()); + ASSERT_GT(acceptPort, 0); std::cout << "Server accepted" << std::endl; @@ -332,6 +410,74 @@ TEST(Secure, TCP) std::cout << "****************** TCP SSL Test PASSED *************************" << std::endl; } +// NOLINTNEXTLINE +TEST(Secure2, TCP) +{ + std::cout << "Start TCP Test 2" << std::endl; + + ASSERT_THROW(SecureTcpServer("", ""), std::runtime_error); + + SecureTcpServer server(KEY_FILE, CERT_FILE, TCP_TEST2_SERVER_PORT, IP_ADDR); + + ASSERT_EQ(server.listen(1), 0); + + auto testThread = std::jthread([]{ + SecureTcpClient client(IP_ADDR, TCP_TEST2_SERVER_PORT); + + std::cout << "Client connected" << std::endl; + // wait for server to accept SSL connection + std::this_thread::sleep_for(std::chrono::seconds(1)); + + auto ret = client.send(TEST_STRING1.c_str(), TEST_STRING1.length()); + ASSERT_EQ(ret, static_cast(TEST_STRING1.length())); + + std::cout << "Client sent: " << TEST_STRING1 << std::endl; + + std::array buffer = {}; + ret = client.read(buffer.data(), buffer.size()); + ASSERT_EQ(ret, static_cast(TEST_STRING2.length())); + + buffer[ret] = '\0'; + + std::cout << "Client received: " << buffer.data() << std::endl; + + ASSERT_EQ(TEST_STRING2.compare(buffer.data()), 0); + + std::cout << "Client received correct data!" << std::endl; + // wait for message to flow thru + std::this_thread::sleep_for(std::chrono::seconds(1)); + }); + + // wait for server to set itself up + std::this_thread::sleep_for(std::chrono::seconds(1)); + std::cout << "Accepting" << std::endl; + SecureTcpClient client = server.accept(); + + std::cout << "Server accepted" << std::endl; + + std::array buffer = {}; + auto ret = client.read(buffer.data(), buffer.size()); + if (ret != static_cast(TEST_STRING1.length())) + { + assert(false); + } + + buffer[ret] = '\0'; + + std::cout << "Server received: " << buffer.data() << std::endl; + + ASSERT_EQ(TEST_STRING1.compare(buffer.data()), 0); + + std::cout << "Server received correct data!" << std::endl; + + ret = client.send(TEST_STRING2.c_str(), TEST_STRING2.length()); + ASSERT_EQ(ret, static_cast(TEST_STRING2.length())); + + std::cout << "Server sent: " << TEST_STRING2 << std::endl; + + std::cout << "****************** TCP SSL Test 2 PASSED *************************" << std::endl; +} + // NOLINTNEXTLINE TEST(Secure, UDP) { From 9b003e3b041a260163a6461e00a8cd0279c73322 Mon Sep 17 00:00:00 2001 From: Kevin Martel Date: Mon, 10 Jun 2024 22:28:53 -0700 Subject: [PATCH 4/6] remove unused workflow --- .github/workflows/coverage.yml | 44 ---------------------------------- 1 file changed, 44 deletions(-) delete mode 100644 .github/workflows/coverage.yml diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml deleted file mode 100644 index 9c83d90..0000000 --- a/.github/workflows/coverage.yml +++ /dev/null @@ -1,44 +0,0 @@ -on: pull_request - -name: Continuous Integration - -jobs: - coverage_report: - name: Generate coverage report - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v2 - # ... Generate LCOV files or download it from a different job - - name: Setup LCOV - uses: hrishikesh-kadam/setup-lcov@v1 - - - name: Install gtest - run: sudo apt-get install libgtest-dev && cd /usr/src/gtest && sudo cmake CMakeLists.txt && sudo make && sudo cp lib/*.a /usr/lib && sudo ln -s /usr/lib/libgtest.a /usr/local/lib/libgtest.a && sudo ln -s /usr/lib/libgtest_main.a /usr/local/lib/libgtest_main.a - - - name: Write files - env: - FILE_ONE: ${{ secrets.KRM_MAIN_FILE }} - FILE_TWO: ${{ secrets.KRM_SCND_FILE }} - run: | - echo "${FILE_ONE}" | base64 --decode > ${HOME}/key.pem | - echo "${FILE_TWO}" | base64 --decode > ${HOME}/scert.crt - - - name: Build and test - run: | - cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=Release - cmake --build ${{github.workspace}}/build --config Release - ctest -VV --test-dir ${{github.workspace}}/build -C Release - - - name: Run lcov - run: | - lcov -c -d . -o lcov.info - - - name: Report code coverage - uses: zgosalvez/github-actions-report-lcov@v3 - with: - coverage-files: coverage/lcov.*.info - minimum-coverage: 90 - artifact-name: code-coverage-report - github-token: ${{ secrets.GITHUB_TOKEN }} - update-comment: true \ No newline at end of file From 92b339fbafee8373ff7db2b59525a704ec85050e Mon Sep 17 00:00:00 2001 From: Kevin Martel Date: Tue, 11 Jun 2024 21:45:10 -0700 Subject: [PATCH 5/6] try to fix windows testing --- inc/cppsocket.hpp | 2 +- test/CMakeLists.txt | 8 ++++---- test/Testcppsocket.cpp | 5 ----- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/inc/cppsocket.hpp b/inc/cppsocket.hpp index 9ccca0b..8d656de 100644 --- a/inc/cppsocket.hpp +++ b/inc/cppsocket.hpp @@ -284,7 +284,7 @@ namespace com::github::socket */ void init() noexcept(false) { -#ifdef __MSC_VER +#if (defined __MSC_VER) || (defined _WIN32) std::call_once(m_onetime, [this]() { if (::WSAStartup(MAKEWORD(2, 2), &m_wsaData) != 0) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4c34b1d..5199e19 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -9,19 +9,19 @@ if(CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "-O3 -Wall -Werror -fsanitize=address -static-libasan") elseif(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "debug") message(STATUS "Base GCC Debug") - set(CMAKE_CXX_FLAGS "-g -O0 -Wall -Werror") + set(CMAKE_CXX_FLAGS "-g -O0 -Wall -Werror -std=c++20") else() message(STATUS "Base GCC Release") - set(CMAKE_CXX_FLAGS "-O3 -Wall -Werror") + set(CMAKE_CXX_FLAGS "-O3 -Wall -Werror -std=c++20") endif() find_package(OpenSSL REQUIRED) find_package(GTest REQUIRED) elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded") if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "debug") - set(CMAKE_CXX_FLAGS "-Wall /O0 -g") + set(CMAKE_CXX_FLAGS "-Wall /O0 -g /std:c++20") else() - set(CMAKE_CXX_FLAGS "-Wall /O2 -g") + set(CMAKE_CXX_FLAGS "-Wall /O2 -g /std:c++20") endif() if(DEFINED ENV{CI}) message(STATUS "MSVC Action") diff --git a/test/Testcppsocket.cpp b/test/Testcppsocket.cpp index 1e58cd0..44cf49d 100644 --- a/test/Testcppsocket.cpp +++ b/test/Testcppsocket.cpp @@ -1,7 +1,3 @@ -#if __cplusplus < 202002L -#error "Requires C++20 or greater" -#endif - #include #include "cppsocket.hpp" @@ -65,7 +61,6 @@ TEST(Unsecure, TCP) socklen_t len = sizeof(flag); ASSERT_EQ(client.getsockopt(IPPROTO_TCP, TCP_NODELAY, &flag, &len), 0); ASSERT_EQ(flag, 1); - ASSERT_EQ(len, sizeof(flag)); std::cout << "Client connected" << std::endl; From 72361362fcd3cb525df4ee045a2f561762cc23c2 Mon Sep 17 00:00:00 2001 From: Kevin Martel Date: Tue, 11 Jun 2024 22:17:03 -0700 Subject: [PATCH 6/6] fix window action --- inc/cppsocket.hpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/inc/cppsocket.hpp b/inc/cppsocket.hpp index 8d656de..3719cbb 100644 --- a/inc/cppsocket.hpp +++ b/inc/cppsocket.hpp @@ -227,15 +227,17 @@ namespace com::github::socket [[nodiscard]] auto selectWrite(timeval& timeout) const noexcept -> bool { fd_set set; + FD_ZERO(&set); FD_SET(m_fd, &set); - return ::select(m_fd+1, nullptr, &set, nullptr, &timeout); + return (::select(m_fd+1, nullptr, &set, nullptr, &timeout) == 1); } [[nodiscard]] auto selectRead(timeval& timeout) const noexcept -> bool { fd_set set; + FD_ZERO(&set); FD_SET(m_fd, &set); - return ::select(m_fd+1, &set, nullptr, nullptr, &timeout); + return (::select(m_fd+1, &set, nullptr, nullptr, &timeout) == 1); } auto getsockopt(const int level, const int optname, void *optval, socklen_t* optlen) const noexcept -> ssize_t @@ -284,7 +286,7 @@ namespace com::github::socket */ void init() noexcept(false) { -#if (defined __MSC_VER) || (defined _WIN32) +#ifdef _WIN32 std::call_once(m_onetime, [this]() { if (::WSAStartup(MAKEWORD(2, 2), &m_wsaData) != 0)