1#define _POSIX_C_SOURCE 200809L
11#include <netinet/in.h>
15#include <sys/socket.h>
19#include "rte/oal/memory/rte_mem_util.h"
26 rte_netlink_config_t config;
27 struct sockaddr_in peer_addr;
28 socklen_t peer_addr_len;
32 uint64_t last_hello_ms;
36 sizeof(rte_channel_service_storage_t)) ? 1 : -1];
42#define RTE_POSIX_CHANNEL_REHELLO_MS 2000U
44static uint64_t channel_now_ms(
void)
48 (void)clock_gettime(CLOCK_MONOTONIC, &ts);
49 return ((uint64_t)ts.tv_sec * 1000U) + ((uint64_t)ts.tv_nsec / 1000000U);
53static void *s_resolver_context;
60static rte_status_t set_nonblocking(
int fd)
62 int flags = fcntl(fd, F_GETFL, 0);
65 return RTE_STATUS_INTERNAL_ERROR;
67 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
69 return RTE_STATUS_INTERNAL_ERROR;
78 struct sockaddr_in bind_addr;
85 fd = socket(AF_INET, SOCK_DGRAM, 0);
90 (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
94 return RTE_STATUS_INTERNAL_ERROR;
96 (void)setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse,
sizeof(reuse));
98 (void)setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &reuse,
sizeof(reuse));
101 rte_mem_set(&bind_addr, 0,
sizeof(bind_addr));
102 bind_addr.sin_family = AF_INET;
103 bind_addr.sin_port = htons(state->config.port);
104 if (state->config.host == NULL)
106 bind_addr.sin_addr.s_addr = INADDR_ANY;
108 else if (inet_pton(AF_INET, state->config.host, &bind_addr.sin_addr) != 1)
111 return RTE_STATUS_INVALID_PARAM;
114 if (bind(fd, (
struct sockaddr *)&bind_addr,
sizeof(bind_addr)) != 0)
117 return RTE_STATUS_INTERNAL_ERROR;
123 if (buf_status != RTE_STATUS_OK)
129 if (set_nonblocking(fd) != RTE_STATUS_OK)
132 return RTE_STATUS_INTERNAL_ERROR;
135 return RTE_STATUS_OK;
140 struct addrinfo hints;
141 struct addrinfo *resolved = NULL;
147 return RTE_STATUS_OK;
150 (void)snprintf(port_str,
sizeof(port_str),
"%u", (
unsigned int)state->config.port);
151 rte_mem_set(&hints, 0,
sizeof(hints));
152 hints.ai_family = AF_INET;
153 hints.ai_socktype = SOCK_DGRAM;
155 if (getaddrinfo(state->config.host, port_str, &hints, &resolved) != 0)
157 return RTE_STATUS_INVALID_PARAM;
160 fd = socket(resolved->ai_family, resolved->ai_socktype, resolved->ai_protocol);
165 (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
169 perror(
"init_connect_socket: socket");
170 freeaddrinfo(resolved);
171 return RTE_STATUS_INTERNAL_ERROR;
177 if (buf_status != RTE_STATUS_OK)
180 freeaddrinfo(resolved);
184 if (set_nonblocking(fd) != RTE_STATUS_OK)
186 perror(
"init_connect_socket: set_nonblocking");
188 freeaddrinfo(resolved);
189 return RTE_STATUS_INTERNAL_ERROR;
192 if (connect(fd, resolved->ai_addr, resolved->ai_addrlen) != 0)
194 perror(
"init_connect_socket: connect");
196 freeaddrinfo(resolved);
197 return RTE_STATUS_INTERNAL_ERROR;
199 freeaddrinfo(resolved);
202 uint8_t hello = 0xA5U;
203 (void)send(state->fd, &hello, 1, 0);
205 return RTE_STATUS_OK;
208static rte_status_t osadapter_setup(rte_channel_service_storage_t *storage,
const char *channel_name)
213 if ((storage == NULL) || (channel_name == NULL) || (s_resolver == NULL))
215 return RTE_STATUS_INVALID_PARAM;
217 state = channel_state(storage);
218 rte_mem_set(state, 0,
sizeof(*state));
220 status = s_resolver(channel_name, &state->config, s_resolver_context);
221 if (status != RTE_STATUS_OK)
225 state->initialized =
true;
226 if (state->config.role == RTE_NETLINK_ROLE_LISTEN)
228 return init_listen_socket(state);
230 return init_connect_socket(state);
238static rte_status_t do_read(rte_channel_service_storage_t *storage,
void *data,
size_t data_size,
239 rte_duration_ms_t timeout_ms,
size_t *out_actual_size)
244 if ((storage == NULL) || (data == NULL) || (data_size == 0U))
246 return RTE_STATUS_INVALID_PARAM;
248 state = channel_state(storage);
249 if (!state->initialized)
251 return RTE_STATUS_NOT_INITIALIZED;
255 if (state->config.role == RTE_NETLINK_ROLE_LISTEN)
257 if (init_listen_socket(state) != RTE_STATUS_OK)
259 return RTE_STATUS_TIMEOUT;
264 if (init_connect_socket(state) != RTE_STATUS_OK)
266 return RTE_STATUS_TIMEOUT;
279 rc = poll(&pfd, 1, posix_poll_timeout_ms(timeout_ms));
282 return RTE_STATUS_TIMEOUT;
288 return RTE_STATUS_TIMEOUT;
290 return RTE_STATUS_INTERNAL_ERROR;
294 if (state->config.role == RTE_NETLINK_ROLE_LISTEN)
298 struct sockaddr_in src_addr;
299 socklen_t addr_len = (socklen_t)
sizeof(src_addr);
300 rte_mem_set(&src_addr, 0,
sizeof(src_addr));
302 n = recvfrom(state->fd, data, data_size, 0, (
struct sockaddr *)&src_addr, &addr_len);
305 state->peer_addr = src_addr;
306 state->peer_addr_len = addr_len;
307 state->has_peer_addr =
true;
309 if ((n == 1) && (((
const uint8_t *)data)[0] == 0xA5U))
312 (void)sendto(state->fd, &ack, 1, 0, (
const struct sockaddr *)&src_addr, addr_len);
323 const uint64_t now_ms = channel_now_ms();
325 if (!state->has_peer_addr)
327 uint8_t hello = 0xA5U;
328 (void)send(state->fd, &hello, 1, 0);
329 state->last_hello_ms = now_ms;
333 if (state->last_rx_ms == 0U)
335 state->last_rx_ms = now_ms;
337 if (((now_ms - state->last_rx_ms) >= RTE_POSIX_CHANNEL_REHELLO_MS) &&
338 ((now_ms - state->last_hello_ms) >= RTE_POSIX_CHANNEL_REHELLO_MS))
340 uint8_t hello = 0xA5U;
341 (void)send(state->fd, &hello, 1, 0);
342 state->last_hello_ms = now_ms;
345 n = recv(state->fd, data, data_size, 0);
348 state->last_rx_ms = now_ms;
349 if ((n == 1) && (((
const uint8_t *)data)[0] == 0x5AU))
351 state->has_peer_addr =
true;
354 if ((n == 1) && (((
const uint8_t *)data)[0] == 0xA5U))
357 (void)send(state->fd, &ack, 1, 0);
358 state->has_peer_addr =
true;
368 if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINTR) || (errno == ECONNREFUSED) ||
369 (errno == ENOTCONN) || (errno == EHOSTUNREACH) || (errno == EPIPE))
371 return RTE_STATUS_TIMEOUT;
373 return RTE_STATUS_INTERNAL_ERROR;
377 return RTE_STATUS_TIMEOUT;
379 if (out_actual_size != NULL)
381 *out_actual_size = (size_t)n;
383 return RTE_STATUS_OK;
386static rte_status_t osadapter_read(rte_channel_service_storage_t *storage,
void *data,
size_t data_size,
387 rte_duration_ms_t timeout_ms)
389 return do_read(storage, data, data_size, timeout_ms, NULL);
392static rte_status_t osadapter_read_ex(rte_channel_service_storage_t *storage,
void *data,
size_t data_size,
393 rte_duration_ms_t timeout_ms,
size_t *out_actual_size)
395 if (out_actual_size == NULL)
397 return RTE_STATUS_INVALID_PARAM;
399 return do_read(storage, data, data_size, timeout_ms, out_actual_size);
402static rte_status_t backend_send(rte_channel_service_storage_t *storage,
const void *data,
size_t data_size,
403 rte_duration_ms_t timeout_ms)
408 if ((storage == NULL) || (data == NULL) || (data_size == 0U))
410 return RTE_STATUS_INVALID_PARAM;
412 state = channel_state(storage);
413 if (!state->initialized)
415 return RTE_STATUS_NOT_INITIALIZED;
419 if (state->config.role == RTE_NETLINK_ROLE_LISTEN)
421 if (init_listen_socket(state) != RTE_STATUS_OK)
423 return RTE_STATUS_TIMEOUT;
428 if (init_connect_socket(state) != RTE_STATUS_OK)
430 return RTE_STATUS_TIMEOUT;
441 pfd.events = POLLOUT;
443 rc = poll(&pfd, 1, posix_poll_timeout_ms(timeout_ms));
446 return RTE_STATUS_TIMEOUT;
452 return RTE_STATUS_TIMEOUT;
454 return RTE_STATUS_INTERNAL_ERROR;
458 if (state->config.role == RTE_NETLINK_ROLE_LISTEN)
460 if (!state->has_peer_addr)
464 return RTE_STATUS_NOT_CONNECTED;
466 n = sendto(state->fd, data, data_size, 0, (
const struct sockaddr *)&state->peer_addr, state->peer_addr_len);
470 n = send(state->fd, data, data_size, 0);
475 if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINTR) || (errno == ECONNREFUSED) ||
476 (errno == ENOTCONN) || (errno == EHOSTUNREACH) || (errno == EADDRNOTAVAIL) || (errno == EPIPE))
478 return RTE_STATUS_TIMEOUT;
480 return RTE_STATUS_INTERNAL_ERROR;
482 return RTE_STATUS_OK;
485static rte_status_t osadapter_close(rte_channel_service_storage_t *storage)
491 return RTE_STATUS_OK;
493 state = channel_state(storage);
494 if (!state->initialized)
496 return RTE_STATUS_OK;
498 state->initialized =
false;
501 (void)close(state->fd);
504 state->has_peer_addr =
false;
505 return RTE_STATUS_OK;
508static const rte_osadapter_channel_service_t s_osadapter = {
518 if (resolver == NULL)
520 return RTE_STATUS_INVALID_PARAM;
522 s_resolver = resolver;
523 s_resolver_context = context;
524 return rte_osadapter_channel_service_register(&s_osadapter);
POSIX named-channel adapter.
rte_status_t rte_posix_osadapter_channel_service_register_resolver(rte_posix_channel_resolve_fn resolver, void *context)
Registers the channel-name resolver and the POSIX channel service OSAdapter (ADR-005 seam).
const rte_osadapter_channel_service_t * rte_posix_osadapter_channel_service(void)
The POSIX channel service OSAdapter vtable (UDP; setup binds or dials and returns,...
rte_status_t(*) rte_posix_channel_resolve_fn(const char *channel_name, rte_netlink_config_t *out_config, void *context)
Resolves a channel name to its link configuration (integrator-supplied).
Private helpers: millisecond waits for poll()'s int timeout argument.
rte_status_t posix_socket_apply_buffers(int fd, const rte_netlink_config_t *config)
Sets and confirms config->rcvbuf_bytes (SO_RCVBUF) and config->sndbuf_bytes (SO_SNDBUF) on a socket.
Private helper: applies the socket buffer sizes of a link config (OSA rules R5, R6).