diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 02:57:58 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 02:57:58 +0000 |
commit | be1c7e50e1e8809ea56f2c9d472eccd8ffd73a97 (patch) | |
tree | 9754ff1ca740f6346cf8483ec915d4054bc5da2d /web/server/h2o/libh2o/deps/libyrmcds/connect.c | |
parent | Initial commit. (diff) | |
download | netdata-be1c7e50e1e8809ea56f2c9d472eccd8ffd73a97.tar.xz netdata-be1c7e50e1e8809ea56f2c9d472eccd8ffd73a97.zip |
Adding upstream version 1.44.3.upstream/1.44.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'web/server/h2o/libh2o/deps/libyrmcds/connect.c')
-rw-r--r-- | web/server/h2o/libh2o/deps/libyrmcds/connect.c | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/web/server/h2o/libh2o/deps/libyrmcds/connect.c b/web/server/h2o/libh2o/deps/libyrmcds/connect.c new file mode 100644 index 00000000..8ddf770c --- /dev/null +++ b/web/server/h2o/libh2o/deps/libyrmcds/connect.c @@ -0,0 +1,199 @@ +// (C) 2013, 2016 Cybozu. + +#include "yrmcds.h" + +#include <errno.h> +#include <fcntl.h> +#include <netdb.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <poll.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <unistd.h> + +// workaround for a known-bug in NetBSD, from https://lists.gnu.org/archive/html/bug-gnulib/2010-02/msg00071.html +#ifndef AI_V4MAPPED +#define AI_V4MAPPED 0 +#endif + +static yrmcds_error connect_to_server(const char* node, uint16_t port, int* server_fd) { + if( node == NULL ) + return YRMCDS_BAD_ARGUMENT; + + long fl; + char sport[8]; + snprintf(sport, sizeof(sport), "%u", (unsigned int)port); + + struct addrinfo hint, *res; + memset(&hint, 0, sizeof(hint)); + hint.ai_family = AF_INET; // prefer IPv4 + hint.ai_socktype = SOCK_STREAM; + hint.ai_flags = AI_NUMERICSERV|AI_ADDRCONFIG; + int e = getaddrinfo(node, sport, &hint, &res); + if( e == EAI_FAMILY || e == EAI_NONAME +#ifdef EAI_ADDRFAMILY + || e == EAI_ADDRFAMILY +#endif +#ifdef EAI_NODATA + || e == EAI_NODATA +#endif + ) { + hint.ai_family = AF_INET6; + // intentionally drop AI_ADDRCONFIG to support IPv6 link-local address. + // see https://github.com/cybozu/yrmcds/issues/40 + hint.ai_flags = AI_NUMERICSERV|AI_V4MAPPED; + e = getaddrinfo(node, sport, &hint, &res); + } + if( e == EAI_SYSTEM ) { + return YRMCDS_SYSTEM_ERROR; + } else if( e != 0 ) { + return YRMCDS_NOT_RESOLVED; + } + + int s = socket(res->ai_family, + res->ai_socktype +#ifdef __linux__ + | SOCK_NONBLOCK | SOCK_CLOEXEC +#endif + , res->ai_protocol); + if( s == -1 ) { + e = errno; + freeaddrinfo(res); + errno = e; + return YRMCDS_SYSTEM_ERROR; + } +#ifndef __linux__ + fl = fcntl(s, F_GETFD, 0); + fcntl(s, F_SETFD, fl | FD_CLOEXEC); + fl = fcntl(s, F_GETFL, 0); + fcntl(s, F_SETFL, fl | O_NONBLOCK); +#endif + e = connect(s, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + if( e == -1 && errno != EINPROGRESS ) { + e = errno; + close(s); + errno = e; + return YRMCDS_SYSTEM_ERROR; + } + + if( e != 0 ) { + struct pollfd fds; + fds.fd = s; + fds.events = POLLOUT; + int n = poll(&fds, 1, 5000); + if( n == 0 ) { // timeout + close(s); + return YRMCDS_TIMEOUT; + } + if( n == -1 ) { + e = errno; + close(s); + errno = e; + return YRMCDS_SYSTEM_ERROR; + } + + if( fds.revents & (POLLERR|POLLHUP|POLLNVAL) ) { + close(s); + return YRMCDS_DISCONNECTED; + } + socklen_t l = sizeof(e); + if( getsockopt(s, SOL_SOCKET, SO_ERROR, &e, &l) == -1 ) { + close(s); + return YRMCDS_SYSTEM_ERROR; + } + if( e != 0 ) { + close(s); + errno = e; + return YRMCDS_SYSTEM_ERROR; + } + } + fl = fcntl(s, F_GETFL, 0); + if( fcntl(s, F_SETFL, fl & ~O_NONBLOCK) == -1 ) { + e = errno; + close(s); + errno = e; + return YRMCDS_SYSTEM_ERROR; + } + int ok = 1; + if( setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &ok, sizeof(ok)) == -1 ) { + e = errno; + close(s); + errno = e; + return YRMCDS_SYSTEM_ERROR; + } + *server_fd = s; + return YRMCDS_OK; +} + +yrmcds_error yrmcds_connect(yrmcds* c, const char* node, uint16_t port) { + if( c == NULL ) + return YRMCDS_BAD_ARGUMENT; +#ifndef LIBYRMCDS_NO_INTERNAL_LOCK + int e = pthread_mutex_init(&(c->lock), NULL); + if( e != 0 ) { + errno = e; + return YRMCDS_SYSTEM_ERROR; + } +#endif // ! LIBYRMCDS_NO_INTERNAL_LOCK + int server_fd; + yrmcds_error err = connect_to_server(node, port, &server_fd); + if( err != YRMCDS_OK ) + return err; + c->sock = server_fd; + c->serial = 0; + c->compress_size = 0; + c->recvbuf = (char*)malloc(1 << 20); + if( c->recvbuf == NULL ) { + close(server_fd); +#ifndef LIBYRMCDS_NO_INTERNAL_LOCK + pthread_mutex_destroy(&(c->lock)); +#endif + return YRMCDS_OUT_OF_MEMORY; + } + c->capacity = 1 << 20; + c->used = 0; + c->last_size = 0; + c->decompressed = NULL; + c->invalid = 0; + c->text_mode = 0; + c->rserial = 0; + return YRMCDS_OK; +} + +yrmcds_error yrmcds_cnt_connect(yrmcds_cnt* c, const char* node, uint16_t port) { + if( c == NULL ) + return YRMCDS_BAD_ARGUMENT; +#ifndef LIBYRMCDS_NO_INTERNAL_LOCK + int e = pthread_mutex_init(&(c->lock), NULL); + if( e != 0 ) { + errno = e; + return YRMCDS_SYSTEM_ERROR; + } +#endif // ! LIBYRMCDS_NO_INTERNAL_LOCK + int server_fd; + yrmcds_error err = connect_to_server(node, port, &server_fd); + if( err != YRMCDS_OK ) + return err; + c->sock = server_fd; + c->serial = 0; + c->recvbuf = (char*)malloc(4096); + if( c->recvbuf == NULL ) { + close(server_fd); +#ifndef LIBYRMCDS_NO_INTERNAL_LOCK + pthread_mutex_destroy(&(c->lock)); +#endif + return YRMCDS_OUT_OF_MEMORY; + } + c->capacity = 4096; + c->used = 0; + c->last_size = 0; + c->invalid = 0; + c->stats.count = c->stats.capacity = 0; + c->stats.records = NULL; + return YRMCDS_OK; +} |