1#define _POSIX_C_SOURCE 200809L
11#include <netinet/in.h>
14#include <sys/socket.h>
18#include "safeapi/oal/memory/sapi_mem_util.h"
23 sapi_netlink_config_t config;
24 struct sockaddr_in peer_addr;
25 socklen_t peer_addr_len;
31 sizeof(sapi_channel_service_storage_t)) ? 1 : -1];
33static sapi_posix_channel_resolve_fn s_resolver;
34static void *s_resolver_context;
41static sapi_status_t set_nonblocking(
int fd)
43 int flags = fcntl(fd, F_GETFL, 0);
46 return SAPI_STATUS_INTERNAL_ERROR;
48 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
50 return SAPI_STATUS_INTERNAL_ERROR;
52 return SAPI_STATUS_OK;
59 struct sockaddr_in bind_addr;
63 return SAPI_STATUS_OK;
66 fd = socket(AF_INET, SOCK_DGRAM, 0);
69 return SAPI_STATUS_INTERNAL_ERROR;
71 (void)setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse,
sizeof(reuse));
73 (void)setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &reuse,
sizeof(reuse));
76 sapi_mem_set(&bind_addr, 0,
sizeof(bind_addr));
77 bind_addr.sin_family = AF_INET;
78 bind_addr.sin_port = htons(state->config.port);
79 if (state->config.host == NULL)
81 bind_addr.sin_addr.s_addr = INADDR_ANY;
83 else if (inet_pton(AF_INET, state->config.host, &bind_addr.sin_addr) != 1)
86 return SAPI_STATUS_INVALID_PARAM;
89 if (bind(fd, (
struct sockaddr *)&bind_addr,
sizeof(bind_addr)) != 0)
92 return SAPI_STATUS_INTERNAL_ERROR;
94 if (set_nonblocking(fd) != SAPI_STATUS_OK)
97 return SAPI_STATUS_INTERNAL_ERROR;
100 return SAPI_STATUS_OK;
105 struct addrinfo hints;
106 struct addrinfo *resolved = NULL;
112 return SAPI_STATUS_OK;
115 (void)snprintf(port_str,
sizeof(port_str),
"%u", (
unsigned int)state->config.port);
116 sapi_mem_set(&hints, 0,
sizeof(hints));
117 hints.ai_family = AF_INET;
118 hints.ai_socktype = SOCK_DGRAM;
120 if (getaddrinfo(state->config.host, port_str, &hints, &resolved) != 0)
122 return SAPI_STATUS_INVALID_PARAM;
125 fd = socket(resolved->ai_family, resolved->ai_socktype, resolved->ai_protocol);
128 perror(
"init_connect_socket: socket");
129 freeaddrinfo(resolved);
130 return SAPI_STATUS_INTERNAL_ERROR;
132 if (set_nonblocking(fd) != SAPI_STATUS_OK)
134 perror(
"init_connect_socket: set_nonblocking");
136 freeaddrinfo(resolved);
137 return SAPI_STATUS_INTERNAL_ERROR;
140 if (connect(fd, resolved->ai_addr, resolved->ai_addrlen) != 0)
142 perror(
"init_connect_socket: connect");
144 freeaddrinfo(resolved);
145 return SAPI_STATUS_INTERNAL_ERROR;
147 freeaddrinfo(resolved);
150 uint8_t hello = 0xA5U;
151 (void)send(state->fd, &hello, 1, 0);
153 return SAPI_STATUS_OK;
156static sapi_status_t backend_setup(sapi_channel_service_storage_t *storage,
const char *channel_name)
159 sapi_status_t status;
161 if ((storage == NULL) || (channel_name == NULL) || (s_resolver == NULL))
163 return SAPI_STATUS_INVALID_PARAM;
165 state = channel_state(storage);
166 sapi_mem_set(state, 0,
sizeof(*state));
168 status = s_resolver(channel_name, &state->config, s_resolver_context);
169 if (status != SAPI_STATUS_OK)
173 state->initialized =
true;
174 if (state->config.role == SAPI_NETLINK_ROLE_LISTEN)
176 return init_listen_socket(state);
178 return init_connect_socket(state);
181static sapi_status_t backend_read(sapi_channel_service_storage_t *storage,
void *data,
size_t data_size,
182 sapi_duration_ms_t timeout_ms)
187 if ((storage == NULL) || (data == NULL) || (data_size == 0U))
189 return SAPI_STATUS_INVALID_PARAM;
191 state = channel_state(storage);
192 if (!state->initialized)
194 return SAPI_STATUS_NOT_INITIALIZED;
198 if (state->config.role == SAPI_NETLINK_ROLE_LISTEN)
200 if (init_listen_socket(state) != SAPI_STATUS_OK)
202 return SAPI_STATUS_TIMEOUT;
207 if (init_connect_socket(state) != SAPI_STATUS_OK)
209 return SAPI_STATUS_TIMEOUT;
222 rc = poll(&pfd, 1, (
int)timeout_ms);
225 return SAPI_STATUS_TIMEOUT;
231 return SAPI_STATUS_TIMEOUT;
233 return SAPI_STATUS_INTERNAL_ERROR;
237 if (state->config.role == SAPI_NETLINK_ROLE_LISTEN)
241 struct sockaddr_in src_addr;
242 socklen_t addr_len = (socklen_t)
sizeof(src_addr);
243 sapi_mem_set(&src_addr, 0,
sizeof(src_addr));
245 n = recvfrom(state->fd, data, data_size, 0, (
struct sockaddr *)&src_addr, &addr_len);
248 state->peer_addr = src_addr;
249 state->peer_addr_len = addr_len;
250 state->has_peer_addr =
true;
252 if ((n == 1) && (((
const uint8_t *)data)[0] == 0xA5U))
255 (void)sendto(state->fd, &ack, 1, 0, (
const struct sockaddr *)&src_addr, addr_len);
266 if (!state->has_peer_addr)
268 uint8_t hello = 0xA5U;
269 (void)send(state->fd, &hello, 1, 0);
271 n = recv(state->fd, data, data_size, 0);
274 if ((n == 1) && (((
const uint8_t *)data)[0] == 0x5AU))
276 state->has_peer_addr =
true;
279 if ((n == 1) && (((
const uint8_t *)data)[0] == 0xA5U))
282 (void)send(state->fd, &ack, 1, 0);
283 state->has_peer_addr =
true;
293 if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINTR) || (errno == ECONNREFUSED) ||
294 (errno == ENOTCONN) || (errno == EHOSTUNREACH) || (errno == EPIPE))
296 return SAPI_STATUS_TIMEOUT;
298 return SAPI_STATUS_INTERNAL_ERROR;
302 return SAPI_STATUS_TIMEOUT;
304 return SAPI_STATUS_OK;
307static sapi_status_t backend_send(sapi_channel_service_storage_t *storage,
const void *data,
size_t data_size,
308 sapi_duration_ms_t timeout_ms)
313 if ((storage == NULL) || (data == NULL) || (data_size == 0U))
315 return SAPI_STATUS_INVALID_PARAM;
317 state = channel_state(storage);
318 if (!state->initialized)
320 return SAPI_STATUS_NOT_INITIALIZED;
324 if (state->config.role == SAPI_NETLINK_ROLE_LISTEN)
326 if (init_listen_socket(state) != SAPI_STATUS_OK)
328 return SAPI_STATUS_TIMEOUT;
333 if (init_connect_socket(state) != SAPI_STATUS_OK)
335 return SAPI_STATUS_TIMEOUT;
346 pfd.events = POLLOUT;
348 rc = poll(&pfd, 1, (
int)timeout_ms);
351 return SAPI_STATUS_TIMEOUT;
357 return SAPI_STATUS_TIMEOUT;
359 return SAPI_STATUS_INTERNAL_ERROR;
363 if (state->config.role == SAPI_NETLINK_ROLE_LISTEN)
365 if (!state->has_peer_addr)
368 return SAPI_STATUS_OK;
370 n = sendto(state->fd, data, data_size, 0, (
const struct sockaddr *)&state->peer_addr, state->peer_addr_len);
374 n = send(state->fd, data, data_size, 0);
379 if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINTR) || (errno == ECONNREFUSED) ||
380 (errno == ENOTCONN) || (errno == EHOSTUNREACH) || (errno == EADDRNOTAVAIL) || (errno == EPIPE))
382 return SAPI_STATUS_TIMEOUT;
384 return SAPI_STATUS_INTERNAL_ERROR;
386 return SAPI_STATUS_OK;
389static sapi_status_t backend_close(sapi_channel_service_storage_t *storage)
395 return SAPI_STATUS_OK;
397 state = channel_state(storage);
398 if (!state->initialized)
400 return SAPI_STATUS_OK;
402 state->initialized =
false;
405 (void)close(state->fd);
408 state->has_peer_addr =
false;
409 return SAPI_STATUS_OK;
412static const sapi_channel_service_backend_t s_backend = {
419sapi_status_t sapi_posix_backend_channel_service_register_resolver(sapi_posix_channel_resolve_fn resolver,
void *context)
421 if (resolver == NULL)
423 return SAPI_STATUS_INVALID_PARAM;
425 s_resolver = resolver;
426 s_resolver_context = context;
427 return sapi_channel_service_register_backend(&s_backend);
430const sapi_channel_service_backend_t *sapi_posix_backend_channel_service(
void)
POSIX named-channel adapter.