TEC
A lightweight C++ library enabling safe, efficient execution in multithreaded and concurrent systems.
Loading...
Searching...
No Matches
tec_socket.hpp
Go to the documentation of this file.
1// Time-stamp: <Last changed 2026-02-05 01:48:09 by magnolia>
2/*----------------------------------------------------------------------
3------------------------------------------------------------------------
4Copyright (c) 2020-2026 The Emacs Cat (https://github.com/olddeuteronomy/tec).
5
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17------------------------------------------------------------------------
18----------------------------------------------------------------------*/
19
28#pragma once
29
30#include <cstddef>
31#include <cstdio>
32#include <sys/types.h>
33#ifndef _POSIX_C_SOURCE
34// This line fixes the "storage size of 'hints' isn't known" issue.
35#define _POSIX_C_SOURCE 200809L
36#endif
37
38#include <sys/socket.h>
39#include <unistd.h>
40#include <netdb.h>
41
42#include <cstring>
43#include <thread>
44
45#include "tec/tec_def.hpp" // IWYU pragma: keep
46#include "tec/tec_trace.hpp"
47#include "tec/tec_status.hpp"
48#include "tec/tec_memfile.hpp"
50
51
52namespace tec {
53
63 static constexpr char kAnyAddr[]{"0.0.0.0"};
64
66 static constexpr char kLocalAddr[]{"127.0.0.1"};
67
69 static constexpr char kLocalURI[]{"localhost"};
70
72 static constexpr char kAnyAddrIP6[]{"::"};
73
75 static constexpr char kLocalAddrIP6[]{"::1"};
76
78 static constexpr int kDefaultPort{4321};
79
81 static constexpr int kDefaultFamily{AF_UNSPEC};
82
84 static constexpr int kDefaultSockType{SOCK_STREAM};
85
87 static constexpr int kDefaultProtocol{0};
88
90 static constexpr int kDefaultServerFlags{AI_PASSIVE};
91
93 static constexpr int kDefaultClientFlags{0};
94
96 static constexpr char kNullChar{0};
97
99 static constexpr size_t kDefaultBufSize{BUFSIZ};
100
102 std::string addr;
103
104 int port;
105 int family;
108 int flags;
112 size_t buffer_size;
113
131};
132
133/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
134*
135* Client parameters
136*
137 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
138
156
157/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
158*
159* Server parameters
160*
161 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
162
171
173 static constexpr int kOptReuseAddress{0};
174
176 static constexpr int kOptReusePort{1};
177
179 static constexpr int kModeCharStream{0};
180
182 static constexpr int kModeNetData{1};
183
185 static constexpr int kDefaultMode{kModeCharStream};
186
188 static constexpr int kDefaultMaxThreads{16};
189
196 static constexpr int kDefaultConnQueueSize{SOMAXCONN};
197
199 static constexpr bool kUseThreadPool{false};
200
201 int mode;
207
222 {
223 addr = kAnyAddr; // IPv4, use kAnyAddrIP6 to accept from both IPv4 and IPv6.
225 thread_pool_size = std::thread::hardware_concurrency();
226 }
227};
228
229/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
230*
231* Character stream request
232*
233 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
234
244 const std::string* str;
245};
246
256 std::string* str;
257};
258
259/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
260*
261* Socket helpers
262*
263 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
264
272struct Socket {
273 int fd;
274 char addr[INET6_ADDRSTRLEN];
275 int port;
276 char* buffer;
277 size_t buffer_size;
278
287 Socket(int _fd, const char* _addr, int _port)
288 : fd{_fd}
289 , port{_port}
290 , buffer{nullptr}
291 , buffer_size{SocketParams::kDefaultBufSize}
292 {
293 std::strncpy(addr, _addr, INET6_ADDRSTRLEN);
294 addr[INET6_ADDRSTRLEN-1] = '\0';
295 }
296
297
307 Socket(int _fd, const char* _addr, int _port, char* _buffer, size_t _buffer_size)
308 : fd{_fd}
309 , port{_port}
310 , buffer{_buffer}
311 , buffer_size{_buffer_size}
312 {
313 std::strncpy(addr, _addr, INET6_ADDRSTRLEN);
314 addr[INET6_ADDRSTRLEN-1] = '\0';
315 }
316
329 static Status recv(Bytes& data, const Socket* sock, size_t length) {
330 TEC_ENTER("Socket::recv");
331 size_t total_received{0};
332 ssize_t received{0};
333 bool eot{false}; // End of transfer.
334 //
335 // Read data from the socket.
336 //
337 while ((received = read(sock->fd, sock->buffer, sock->buffer_size)) > 0) {
338 if (length == 0 && received > 0) {
339 // Length is unknown -- check for null-terminated char stream.
340 if (sock->buffer[received-1] == '\0') {
341 TEC_TRACE("{}:{} EOT received.", sock->addr, sock->port);
342 eot = true;
343 }
344 }
345 if (received > 0) {
346 data.write(sock->buffer, received);
347 TEC_TRACE("{}:{} --> RECV {} bytes.", sock->addr, sock->port, received);
348 total_received += received;
349 if (length > 0 && length == total_received) {
350 break;
351 }
352 }
353 if (eot || received < static_cast<ssize_t>(sock->buffer_size)) {
354 break;
355 }
356 }
357 //
358 // Check for errors.
359 //
360 if (length > 0 && total_received == length) {
361 // OK
362 return {};
363 }
364 else if (received == 0) {
365 auto errmsg = format("{}:{} Peer closed the connection.", sock->addr, sock->port);
366 TEC_TRACE(errmsg);
367 return {EIO, errmsg, Error::Kind::NetErr};
368 }
369 else if (received < 0) {
370 auto errmsg = format("{}:{} socket read error {}.", sock->addr, sock->port, errno);
371 TEC_TRACE(errmsg);
372 return {errno, errmsg, Error::Kind::NetErr};
373 }
374 else if (length > 0 && total_received != length) {
375 auto errmsg = format("{}:{} socket partial read: {} bytes of {}.",
376 sock->addr, sock->port, total_received, length);
377 TEC_TRACE(errmsg);
378 return {EIO, errmsg, Error::Kind::NetErr};
379 }
380
381 // OK
382 return {};
383 }
384
395 static Status send(const Bytes& data, const Socket* sock) {
396 TEC_ENTER("Socket::send");
397 ssize_t sent{0};
398 //
399 // Write data to the socket.
400 //
401 if (data.size() > 0) {
402 sent = write(sock->fd, data.ptr(0), data.size());
403 //
404 // Check for errors.
405 //
406 if (sent < 0) {
407 auto errmsg = format("{}:{} socket write error {}.", sock->addr, sock->port, errno);
408 TEC_TRACE(errmsg.c_str());
409 return {errno, errmsg, Error::Kind::NetErr};
410 }
411 else if (data.size() != static_cast<size_t>(sent)) {
412 auto errmsg = format("{}:{} socket partial write: {} bytes of {}.",
413 sock->addr, sock->port, sent, data.size());
414 return {EIO, errmsg, Error::Kind::NetErr};
415 }
416
417 }
418 TEC_TRACE("{}:{} <-- SEND {} bytes.", sock->addr, sock->port, sent);
419 return {};
420 }
421
422}; // struct Socket
423
424} // namespace tec
A byte buffer class with stream-like read/write semantics.
Definition tec_memfile.hpp:50
size_t write(const void *src, size_t len)
Writes data into the buffer at the current position.
Definition tec_memfile.hpp:382
const char * ptr(long pos) const
Returns a const pointer to a specific position in the buffer.
Definition tec_memfile.hpp:273
size_t size() const noexcept
Returns the logical size of the data in the buffer.
Definition tec_memfile.hpp:304
#define TEC_ENTER(name)
Logs an entry message for a named context (e.g., function).
Definition tec_trace.hpp:211
#define TEC_TRACE(...)
Logs a formatted trace message.
Definition tec_trace.hpp:222
Definition tec_compression.hpp:34
@ NetErr
Network-related error.
Input descriptor for character stream mode.
Definition tec_socket.hpp:242
const std::string * str
Pointer to the received null-terminated string.
Definition tec_socket.hpp:244
Output descriptor for character stream mode.
Definition tec_socket.hpp:254
std::string * str
Pointer to the string that will receive the response.
Definition tec_socket.hpp:256
Parameters specific to client-side socket connections.
Definition tec_socket.hpp:145
SocketClientParams()
Default constructor.
Definition tec_socket.hpp:152
Common parameters used for both client and server socket configuration.
Definition tec_socket.hpp:61
size_t compression_min_size
Minimum size of data to apply compression (bytes).
Definition tec_socket.hpp:111
static constexpr char kLocalURI[]
Hostname that resolves to localhost for both IPv4 and IPv6.
Definition tec_socket.hpp:69
static constexpr int kDefaultProtocol
Default protocol: 0 means "any appropriate protocol".
Definition tec_socket.hpp:87
int family
Address family (AF_INET, AF_INET6, AF_UNSPEC, ...).
Definition tec_socket.hpp:105
static constexpr size_t kDefaultBufSize
Default buffer size as defined in stdio.h (8192).
Definition tec_socket.hpp:99
int socktype
Socket type (SOCK_STREAM, SOCK_DGRAM, ...).
Definition tec_socket.hpp:106
SocketParams()
Default constructor.
Definition tec_socket.hpp:119
size_t buffer_size
Buffer size for using in send/recv operations (bytes).
Definition tec_socket.hpp:112
static constexpr int kDefaultSockType
Default socket type: TCP stream socket.
Definition tec_socket.hpp:84
int port
Port number to connect to or bind.
Definition tec_socket.hpp:104
int flags
Flags passed to getaddrinfo().
Definition tec_socket.hpp:108
int protocol
Protocol (usually 0).
Definition tec_socket.hpp:107
std::string addr
Target address or hostname.
Definition tec_socket.hpp:102
static constexpr int kDefaultClientFlags
Default addrinfo flags for client sockets (no special behaviour).
Definition tec_socket.hpp:93
static constexpr int kDefaultFamily
Default address family: AF_UNSPEC allows both IPv4 and IPv6.
Definition tec_socket.hpp:81
static constexpr char kLocalAddr[]
IPv4 loopback address (localhost).
Definition tec_socket.hpp:66
static constexpr char kLocalAddrIP6[]
IPv6 loopback address (localhost).
Definition tec_socket.hpp:75
int compression
Compression algorithm to use (see CompressionParams).
Definition tec_socket.hpp:109
static constexpr char kAnyAddrIP6[]
IPv6 address to bind/accept connections from any interface.
Definition tec_socket.hpp:72
int compression_level
Compression level [0..9] (higher = better compression, slower).
Definition tec_socket.hpp:110
static constexpr char kAnyAddr[]
IPv4 address to bind/accept connections from any interface.
Definition tec_socket.hpp:63
static constexpr char kNullChar
Null character constant (for internal use).
Definition tec_socket.hpp:96
static constexpr int kDefaultServerFlags
Default addrinfo flags for server sockets (bind to local address).
Definition tec_socket.hpp:90
static constexpr int kDefaultPort
Default port number used for testing and examples.
Definition tec_socket.hpp:78
Parameters specific to server-side socket configuration.
Definition tec_socket.hpp:170
static constexpr int kDefaultMode
Default data handling mode.
Definition tec_socket.hpp:185
static constexpr int kModeNetData
Treat incoming data as length-prefixed binary network messages.
Definition tec_socket.hpp:182
size_t thread_pool_size
Number of threads in the thread pool.
Definition tec_socket.hpp:206
static constexpr int kModeCharStream
Treat incoming data as null-terminated character streams.
Definition tec_socket.hpp:179
int mode
Data handling mode (character stream or binary network data).
Definition tec_socket.hpp:201
static constexpr int kOptReuseAddress
Disable SO_REUSEADDR option.
Definition tec_socket.hpp:173
static constexpr bool kUseThreadPool
Whether to use a fixed-size thread pool instead of one-thread-per-connection.
Definition tec_socket.hpp:199
int opt_reuse_addr
Whether to set SO_REUSEADDR (0 = no, 1 = yes).
Definition tec_socket.hpp:203
static constexpr int kDefaultConnQueueSize
Maximum length of the pending connections queue for listen(). Usually 4096.
Definition tec_socket.hpp:196
static constexpr int kDefaultMaxThreads
Default maximum number of threads in a custom thread pool.
Definition tec_socket.hpp:188
bool use_thread_pool
Use the thread pool for handling accepted connections.
Definition tec_socket.hpp:205
SocketServerParams()
Default constructor.
Definition tec_socket.hpp:216
int opt_reuse_port
Whether to set SO_REUSEPORT (if available).
Definition tec_socket.hpp:204
static constexpr int kOptReusePort
Enable SO_REUSEADDR and SO_REUSEPORT (if supported).
Definition tec_socket.hpp:176
int queue_size
Maximum backlog for listen().
Definition tec_socket.hpp:202
Lightweight wrapper around a connected socket file descriptor.
Definition tec_socket.hpp:272
static Status recv(Bytes &data, const Socket *sock, size_t length)
Receive data from a socket into a MemFile (Bytes).
Definition tec_socket.hpp:329
Socket(int _fd, const char *_addr, int _port)
Construct a Socket wrapper from an accepted or connected fd.
Definition tec_socket.hpp:287
static Status send(const Bytes &data, const Socket *sock)
Send the entire contents of a MemFile (Bytes) through a socket.
Definition tec_socket.hpp:395
char * buffer
Buffer used in send/recv operations.
Definition tec_socket.hpp:276
int port
Peer port number.
Definition tec_socket.hpp:275
Socket(int _fd, const char *_addr, int _port, char *_buffer, size_t _buffer_size)
Construct a Socket wrapper from an accepted or connected fd.
Definition tec_socket.hpp:307
size_t buffer_size
Size of the buffer.
Definition tec_socket.hpp:277
int fd
Underlying socket file descriptor.
Definition tec_socket.hpp:273
char addr[INET6_ADDRSTRLEN]
Peer address as a null-terminated string (IPv4 or IPv6).
Definition tec_socket.hpp:274
Compression parameters.
Common definitions and utilities for the tec namespace.
A byte buffer class with stream-like read/write semantics.
std::string format(const T &arg)
Formats a single argument into a string.
Definition tec_print.hpp:171
Defines error handling types and utilities for the tec namespace.
Provides a thread-safe tracing utility for debugging in the tec namespace.