From a1932b16c20353cafb96d3d8cf83e643bd92ef93 Mon Sep 17 00:00:00 2001 From: folkert van heusden Date: Fri, 17 May 2024 10:13:34 +0200 Subject: [PATCH] tcp socket client --- CMakeLists.txt | 2 + ESP32/comm_tcp_socket.cpp | 1 - ESP32/comm_tcp_socket.h | 1 - ESP32/comm_tcp_socket_client.cpp | 1 + ESP32/comm_tcp_socket_client.h | 1 + ESP32/comm_tcp_socket_server.cpp | 1 + ESP32/comm_tcp_socket_server.h | 1 + ESP32/main.ino | 5 +- comm_tcp_socket_client.cpp | 181 +++++++++++++++++++++++++++++++ comm_tcp_socket_client.h | 42 +++++++ 10 files changed, 232 insertions(+), 4 deletions(-) delete mode 120000 ESP32/comm_tcp_socket.cpp delete mode 120000 ESP32/comm_tcp_socket.h create mode 120000 ESP32/comm_tcp_socket_client.cpp create mode 120000 ESP32/comm_tcp_socket_client.h create mode 120000 ESP32/comm_tcp_socket_server.cpp create mode 120000 ESP32/comm_tcp_socket_server.h create mode 100644 comm_tcp_socket_client.cpp create mode 100644 comm_tcp_socket_client.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a429d9..5d6a1ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ add_executable( bus.cpp comm.cpp comm_posix_tty.cpp + comm_tcp_socket_client.cpp comm_tcp_socket_server.cpp console.cpp console_ncurses.cpp @@ -80,6 +81,7 @@ add_executable( bus.cpp comm.cpp comm_posix_tty.cpp + comm_tcp_socket_client.cpp comm_tcp_socket_server.cpp console.cpp console_posix.cpp diff --git a/ESP32/comm_tcp_socket.cpp b/ESP32/comm_tcp_socket.cpp deleted file mode 120000 index fabc9cf..0000000 --- a/ESP32/comm_tcp_socket.cpp +++ /dev/null @@ -1 +0,0 @@ -../comm_tcp_socket.cpp \ No newline at end of file diff --git a/ESP32/comm_tcp_socket.h b/ESP32/comm_tcp_socket.h deleted file mode 120000 index 26c9bed..0000000 --- a/ESP32/comm_tcp_socket.h +++ /dev/null @@ -1 +0,0 @@ -../comm_tcp_socket.h \ No newline at end of file diff --git a/ESP32/comm_tcp_socket_client.cpp b/ESP32/comm_tcp_socket_client.cpp new file mode 120000 index 0000000..6473ab9 --- /dev/null +++ b/ESP32/comm_tcp_socket_client.cpp @@ -0,0 +1 @@ +../comm_tcp_socket_client.cpp \ No newline at end of file diff --git a/ESP32/comm_tcp_socket_client.h b/ESP32/comm_tcp_socket_client.h new file mode 120000 index 0000000..6a29b44 --- /dev/null +++ b/ESP32/comm_tcp_socket_client.h @@ -0,0 +1 @@ +../comm_tcp_socket_client.h \ No newline at end of file diff --git a/ESP32/comm_tcp_socket_server.cpp b/ESP32/comm_tcp_socket_server.cpp new file mode 120000 index 0000000..70cce92 --- /dev/null +++ b/ESP32/comm_tcp_socket_server.cpp @@ -0,0 +1 @@ +../comm_tcp_socket_server.cpp \ No newline at end of file diff --git a/ESP32/comm_tcp_socket_server.h b/ESP32/comm_tcp_socket_server.h new file mode 120000 index 0000000..4be1606 --- /dev/null +++ b/ESP32/comm_tcp_socket_server.h @@ -0,0 +1 @@ +../comm_tcp_socket_server.h \ No newline at end of file diff --git a/ESP32/main.ino b/ESP32/main.ino index 1142725..2491d1e 100644 --- a/ESP32/main.ino +++ b/ESP32/main.ino @@ -24,7 +24,8 @@ #include "comm.h" #include "comm_esp32_hardwareserial.h" -#include "comm_tcp_socket.h" +#include "comm_tcp_socket_client.h" +#include "comm_tcp_socket_server.h" #if defined(SHA2017) #include "console_shabadge.h" #else @@ -220,7 +221,7 @@ void start_network(console *const c) for(size_t i=comm_interfaces.size(); i<4; i++) { int port = 1100 + i; - comm_interfaces.push_back(new comm_tcp_socket(port)); + comm_interfaces.push_back(new comm_tcp_socket_server(port)); DOLOG(info, false, "Configuring DC11 device for TCP socket on port %d", port); } diff --git a/comm_tcp_socket_client.cpp b/comm_tcp_socket_client.cpp new file mode 100644 index 0000000..68ef664 --- /dev/null +++ b/comm_tcp_socket_client.cpp @@ -0,0 +1,181 @@ +// (C) 2024 by Folkert van Heusden +// Released under MIT license + +#include "gen.h" + +#if defined(ESP32) +#include +#endif +#if defined(ESP32) +#include +#include +#include +#include +#include +#elif defined(_WIN32) +// from https://stackoverflow.com/questions/12765743/implicit-declaration-of-function-getaddrinfo-on-mingw +#define _NTDDI_VERSION_FROM_WIN32_WINNT2(ver) ver##0000 +#define _NTDDI_VERSION_FROM_WIN32_WINNT(ver) _NTDDI_VERSION_FROM_WIN32_WINNT2(ver) + +#ifndef _WIN32_WINNT +# define _WIN32_WINNT 0x501 +#endif +#ifndef NTDDI_VERSION +# define NTDDI_VERSION _NTDDI_VERSION_FROM_WIN32_WINNT(_WIN32_WINNT) +#endif +#include +#include +#else +#include +#include +#include +#include +#endif +#include +#if IS_POSIX +#include +#include +#include +#include +#endif + +#include "comm_tcp_socket_client.h" +#include "log.h" +#include "utils.h" + + +comm_tcp_socket_client::comm_tcp_socket_client(const std::string & host, const int port) : + host(host), + port(port) +{ + th = new std::thread(std::ref(*this)); +} + +comm_tcp_socket_client::~comm_tcp_socket_client() +{ + stop_flag = true; + + if (th) { + th->join(); + delete th; + } +} + +bool comm_tcp_socket_client::is_connected() +{ + std::unique_lock lck(cfd_lock); + + return cfd != INVALID_SOCKET; +} + +bool comm_tcp_socket_client::has_data() +{ + std::unique_lock lck(cfd_lock); +#if defined(_WIN32) + WSAPOLLFD fds[] { { cfd, POLLIN, 0 } }; + int rc = WSAPoll(fds, 1, 0); +#else + pollfd fds[] { { cfd, POLLIN, 0 } }; + int rc = poll(fds, 1, 0); +#endif + + return rc == 1; +} + +uint8_t comm_tcp_socket_client::get_byte() +{ + int use_fd = -1; + + { + std::unique_lock lck(cfd_lock); + use_fd = cfd; + } + + uint8_t c = 0; + if (read(use_fd, &c, 1) <= 0) { + DOLOG(warning, false, "comm_tcp_socket_client::get_byte: failed"); + std::unique_lock lck(cfd_lock); + close(cfd); + cfd = INVALID_SOCKET; + } + + return c; +} + +void comm_tcp_socket_client::send_data(const uint8_t *const in, const size_t n) +{ + const uint8_t *p = in; + size_t len = n; + + while(len > 0) { + std::unique_lock lck(cfd_lock); + int rc = write(cfd, p, len); + if (rc <= 0) { // TODO error checking + DOLOG(warning, false, "comm_tcp_socket_client::send_data: failed"); + close(cfd); + cfd = INVALID_SOCKET; + break; + } + + p += rc; + len -= rc; + } +} + +void comm_tcp_socket_client::operator()() +{ + set_thread_name("kek:COMMTCPC"); + + DOLOG(info, true, "TCP comm (client) thread started for %s:%d", host.c_str(), port); + + while(!stop_flag) { + myusleep(101000l); + std::unique_lock lck(cfd_lock); + if (cfd != INVALID_SOCKET) + continue; + + addrinfo *res = nullptr; + + addrinfo hints { }; + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + char port_str[8] { 0 }; + snprintf(port_str, sizeof port_str, "%u", port); + + int rc = getaddrinfo(host.c_str(), port_str, &hints, &res); + if (rc != 0) { +#ifdef ESP32 + DOLOG(ll_error, true, "comm_tcp_socket_client: cannot resolve \"%s\":%s", host.c_str(), port_str); +#else + DOLOG(ll_error, true, "comm_tcp_socket_client: cannot resolve \"%s\":%s: %s", host.c_str(), port_str, gai_strerror(rc)); +#endif + + myusleep(101000l); + continue; + } + + for(addrinfo *p = res; p != NULL; p = p->ai_next) { + if ((cfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) + continue; + + if (::connect(cfd, p->ai_addr, p->ai_addrlen) == -1) { + close(cfd); + cfd = INVALID_SOCKET; + DOLOG(ll_error, true, "comm_tcp_socket_client: cannot connect"); + continue; + } + + break; + } + + freeaddrinfo(res); + + if (cfd != INVALID_SOCKET) + set_nodelay(cfd); + } + + DOLOG(info, true, "comm_tcp_socket_client thread terminating"); + + close(cfd); +} diff --git a/comm_tcp_socket_client.h b/comm_tcp_socket_client.h new file mode 100644 index 0000000..e0ca49a --- /dev/null +++ b/comm_tcp_socket_client.h @@ -0,0 +1,42 @@ +// (C) 2024 by Folkert van Heusden +// Released under MIT license + +#include "gen.h" +#include +#include +#include +#include +#include "comm.h" + +#if defined(_WIN32) +#include +#include +#else +#define SOCKET int +#define INVALID_SOCKET -1 +#endif + + +class comm_tcp_socket_client: public comm +{ +private: + const std::string host; + const int port { -1 }; + std::atomic_bool stop_flag { false }; + SOCKET cfd { INVALID_SOCKET }; + std::mutex cfd_lock; + std::thread *th { nullptr }; + +public: + comm_tcp_socket_client(const std::string & host, const int port); + virtual ~comm_tcp_socket_client(); + + bool is_connected() override; + + bool has_data() override; + uint8_t get_byte() override; + + void send_data(const uint8_t *const in, const size_t n) override; + + void operator()(); +};