8 #include <hal_posix/tcp_socket.h>
10 #include <satcat5/ip_core.h>
17 #define CLOSE_SOCKET(x) {closesocket(x); x = -1;}
20 #include <arpa/inet.h>
23 #include <sys/socket.h>
24 #include <sys/types.h>
26 #define CLOSE_SOCKET(x) {::close(x); x = -1;}
36 static inline fd_set make_fdset(
int fd) {
44 static bool can_read(
int fd) {
45 if (fd < 0)
return false;
46 auto query = make_fdset(fd);
47 timeval right_now = {0, 0};
48 int count = select(fd+1, &query,
nullptr,
nullptr, &right_now);
52 static bool can_write(
int fd) {
53 if (fd < 0)
return false;
54 auto query = make_fdset(fd);
55 timeval right_now = {0, 0};
56 int count = select(fd+1,
nullptr, &query,
nullptr, &right_now);
60 static bool got_event(
int fd) {
61 if (fd < 0)
return false;
62 auto query = make_fdset(fd);
63 timeval right_now = {0, 0};
64 int count = select(fd+1,
nullptr,
nullptr, &query, &right_now);
69 static int set_nonblock(
int fd) {
72 return ioctlsocket(fd, FIONBIO, &enable);
74 int flags = fcntl(fd, F_GETFL, 0);
75 return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
80 static int get_error() {
82 return WSAGetLastError();
90 static bool is_error(
int err) {
91 if (err >= 0)
return false;
92 int sub_code = get_error();
94 return sub_code != WSAEINPROGRESS
95 && sub_code != WSAEWOULDBLOCK;
97 return sub_code != EAGAIN
98 && sub_code != EINPROGRESS
99 && sub_code != EWOULDBLOCK;
104 static void log_socket_error(
const char* label) {
105 int err_code = get_error();
106 const char* err_msg = strerror(err_code);
112 constexpr u32 FLAG_WSA_CLEANUP = (1u << 0);
114 SocketPosix::SocketPosix(
unsigned txbytes,
unsigned rxbytes)
116 new u8[txbytes], txbytes, 0,
117 new u8[rxbytes], rxbytes, 0)
119 , m_last_rx(SATCAT5_CLOCK->now())
120 , m_last_tx(SATCAT5_CLOCK->now())
131 int err = WSAStartup(MAKEWORD(2, 2), &wsadata);
132 if (err) log_socket_error(
"ctor");
133 else m_flags |= FLAG_WSA_CLEANUP;
137 SocketPosix::~SocketPosix() {
143 if (
m_flags & FLAG_WSA_CLEANUP) WSACleanup();
169 struct sockaddr_in request;
170 request.sin_family = AF_INET;
171 request.sin_addr.s_addr = INADDR_ANY;
172 request.sin_port = htons(port.value);
180 const int enable = 1;
181 setsockopt(
m_sock_listen, SOL_SOCKET, SO_REUSEADDR, (
const char*)&enable,
sizeof(enable));
186 log_socket_error(
"bind");
187 close();
return false;
193 log_socket_error(
"listen");
194 close();
return false;
206 struct addrinfo hints;
207 memset(&hints, 0,
sizeof(hints));
208 hints.ai_family = AF_INET;
209 hints.ai_socktype = SOCK_STREAM;
210 hints.ai_protocol = IPPROTO_TCP;
212 struct addrinfo *result =
nullptr;
213 int err = getaddrinfo(hostname,
nullptr, &hints, &result);
215 log_socket_error(
"addr");
222 struct sockaddr_in* tmp = (
struct sockaddr_in*)result->ai_addr;
223 Addr addr(ntohl(tmp->sin_addr.s_addr));
228 freeaddrinfo(result);
238 struct sockaddr_in request;
239 request.sin_family = AF_INET;
240 request.sin_addr.s_addr = htonl(addr.
value);
241 request.sin_port = htons(port.value);
250 log_socket_error(
"connect");
251 close();
return false;
269 const char* tmp = (
const char*)
m_tx.
peek(len);
271 if (sent < 0) log_socket_error(
"send");
272 if (sent <= 0)
break;
275 if (
unsigned(sent) < len)
break;
287 unsigned rmax = min_unsigned(
sizeof(tmp), limit);
290 if (is_error(rcvd)) log_socket_error(
"recv");
291 if (rcvd <= 0)
break;
294 if (
unsigned(rcvd) == rmax)
break;
299 log_socket_error(
"poll");
305 log_socket_error(
"listen");
312 log_socket_error(
"accept");
317 log_socket_error(
"server");
322 int SocketPosix::open_nonblock_socket() {
324 int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
326 log_socket_error(
"socket");
331 int err = set_nonblock(sock);
333 log_socket_error(
"nonblk");
339 unsigned SocketPosix::rate_limit(
TimeVal& tv) {
satcat5::io::PacketBuffer m_tx
Transmit data (user writes, child reads)
satcat5::io::PacketBuffer m_rx
Receive data (user reads, child writes)
const u8 * peek(unsigned nbytes) const
Peek nbytes into the circular buffer.
unsigned get_peek_ready() const
Find the longest available contiguous segment that can be requested by peek().
bool write_finalize() override
Mark end of frame and release temporary working data.
unsigned get_write_space() const override
How many bytes can be written without blocking?
void write_bytes(unsigned nbytes, const void *src) override
Write 0 or more bytes from a buffer.
u8 * get_buff_dtor() const
Accessor for children that need to delete underlying buffer.
bool read_consume(unsigned nbytes) override
Read and discard 0 or more bytes.
Abstract API for reading byte-streams and packets.
The Log class creates and formats one log message.
Log & write10(s32 val)
Print integer as a decimal value with no leading zeros.
Log & write(const char *str)
Formatting methods for various data types.
void timer_stop()
Stop all future notifications.
void timer_every(unsigned msec)
Configure a repeating notification every X milliseconds.
Connect a SatCat5 byte-stream to a Linux or Windows TCP socket.
bool ready()
Is this connection ready to send and receive data?
void close()
Close any open sockets and return to idle.
int m_sock_data
Socket for data transfer, if connected.
util::TimeVal m_last_rx
Time since last receive event.
unsigned m_rate_kbps
Maximum bytes/msec, if applicable.
bool bind(const satcat5::ip::Port &port)
Prepare to accept connection from a remote client endpoint.
u32 m_flags
Additional status flags.
void data_rcvd(satcat5::io::Readable *src) override
The data_rcvd() callback is polled whenever data is available.
void timer_event() override
Child class MUST override this method.
bool connect(const char *hostname, const satcat5::ip::Port &port)
Attempt connection to a remote server endpoint.
int m_sock_listen
Socket for accept/bind, if applicable.
util::TimeVal m_last_tx
Time since last transmit event.
Diagnostic logging to UART and/or Ethernet ports.
Miscellaneous POSIX wrappers (e.g., heap allocation, log to console...)
IPv4 address is a 32-bit unsigned integer.
u32 value
Raw access to the underlying representation.
bool is_unicast() const
Any normal single-destination address.
UDP and TCP ports are both 16-bit unsigned integers.
Timestamp for measuring elapsed time.
unsigned increment_msec()
Measure elapsed time in milliseconds, then increment by the returned quantized value.
Miscellaneous mathematical utility functions.
constexpr unsigned min_unsigned(unsigned a, unsigned b)
Min and max functions.