diff options
Diffstat (limited to '')
-rw-r--r-- | src/net_udp.c | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/src/net_udp.c b/src/net_udp.c new file mode 100644 index 0000000..03e0ae1 --- /dev/null +++ b/src/net_udp.c @@ -0,0 +1,123 @@ +/* + * Copyright 2019-2021 OARC, Inc. + * Copyright 2017-2018 Akamai Technologies + * Copyright 2006-2016 Nominum, Inc. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "config.h" + +#include "net.h" + +#include "log.h" +#include "strerror.h" + +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/socket.h> +#include <netinet/in.h> + +#define self ((struct perf__udp_socket*)sock) + +struct perf__udp_socket { + struct perf_net_socket base; +}; + +static ssize_t perf__udp_recv(struct perf_net_socket* sock, void* buf, size_t len, int flags) +{ + return recv(sock->fd, buf, len, flags); +} + +static ssize_t perf__udp_sendto(struct perf_net_socket* sock, uint16_t qid, const void* buf, size_t len, int flags, const struct sockaddr* dest_addr, socklen_t addrlen) +{ + return sendto(sock->fd, buf, len, flags, dest_addr, addrlen); +} + +static int perf__udp_close(struct perf_net_socket* sock) +{ + return close(sock->fd); +} + +static int perf__udp_sockeq(struct perf_net_socket* sock_a, struct perf_net_socket* sock_b) +{ + return sock_a->fd == sock_b->fd; +} + +static int perf__udp_sockready(struct perf_net_socket* sock, int pipe_fd, int64_t timeout) +{ + return 1; +} + +struct perf_net_socket* perf_net_udp_opensocket(const perf_sockaddr_t* server, const perf_sockaddr_t* local, size_t bufsize) +{ + struct perf__udp_socket* tmp = calloc(1, sizeof(struct perf__udp_socket)); // clang scan-build + struct perf_net_socket* sock = (struct perf_net_socket*)tmp; + + int ret, flags; + + if (!sock) { + perf_log_fatal("perf_net_udp_opensocket() out of memory"); + return 0; // needed for clang scan build + } + + sock->recv = perf__udp_recv; + sock->sendto = perf__udp_sendto; + sock->close = perf__udp_close; + sock->sockeq = perf__udp_sockeq; + sock->sockready = perf__udp_sockready; + + sock->fd = socket(server->sa.sa.sa_family, SOCK_DGRAM, 0); + if (sock->fd == -1) { + char __s[256]; + perf_log_fatal("socket: %s", perf_strerror_r(errno, __s, sizeof(__s))); + } + + if (server->sa.sa.sa_family == AF_INET6) { + int on = 1; + + if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) == -1) { + perf_log_warning("setsockopt(IPV6_V6ONLY) failed"); + } + } + + if (bind(sock->fd, &local->sa.sa, local->length) == -1) { + char __s[256]; + perf_log_fatal("bind: %s", perf_strerror_r(errno, __s, sizeof(__s))); + } + + if (bufsize > 0) { + bufsize *= 1024; + + ret = setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF, + &bufsize, sizeof(bufsize)); + if (ret < 0) + perf_log_warning("setsockbuf(SO_RCVBUF) failed"); + + ret = setsockopt(sock->fd, SOL_SOCKET, SO_SNDBUF, + &bufsize, sizeof(bufsize)); + if (ret < 0) + perf_log_warning("setsockbuf(SO_SNDBUF) failed"); + } + + flags = fcntl(sock->fd, F_GETFL, 0); + if (flags < 0) + perf_log_fatal("fcntl(F_GETFL)"); + ret = fcntl(sock->fd, F_SETFL, flags | O_NONBLOCK); + if (ret < 0) + perf_log_fatal("fcntl(F_SETFL)"); + + return sock; +} |