diff options
Diffstat (limited to 'libnetdata/socket/socket.c')
-rw-r--r-- | libnetdata/socket/socket.c | 169 |
1 files changed, 136 insertions, 33 deletions
diff --git a/libnetdata/socket/socket.c b/libnetdata/socket/socket.c index df6d3148..40271b62 100644 --- a/libnetdata/socket/socket.c +++ b/libnetdata/socket/socket.c @@ -779,6 +779,10 @@ int connect_to_this(const char *definition, int default_port, struct timeval *ti char *path = host + 5; return connect_to_unix(path, timeout); } + else if(*host == '/') { + char *path = host; + return connect_to_unix(path, timeout); + } char *e = host; if(*e == '[') { @@ -826,43 +830,141 @@ int connect_to_this(const char *definition, int default_port, struct timeval *ti return connect_to_this_ip46(protocol, socktype, host, scope_id, service, timeout); } -int connect_to_one_of(const char *destination, int default_port, struct timeval *timeout, size_t *reconnects_counter, char *connected_to, size_t connected_to_size) { - int sock = -1; - +void foreach_entry_in_connection_string(const char *destination, bool (*callback)(char *entry, void *data), void *data) { const char *s = destination; while(*s) { const char *e = s; - // skip path, moving both s(tart) and e(nd) - if(*e == '/') - while(!isspace(*e) && *e != ',') s = ++e; - // skip separators, moving both s(tart) and e(nd) while(isspace(*e) || *e == ',') s = ++e; // move e(nd) to the first separator - while(*e && !isspace(*e) && *e != ',' && *e != '/') e++; + while(*e && !isspace(*e) && *e != ',') e++; // is there anything? if(!*s || s == e) break; char buf[e - s + 1]; strncpyz(buf, s, e - s); - if(reconnects_counter) *reconnects_counter += 1; - sock = connect_to_this(buf, default_port, timeout); - if(sock != -1) { - if(connected_to && connected_to_size) { - strncpy(connected_to, buf, connected_to_size); - connected_to[connected_to_size - 1] = '\0'; - } - break; - } + + if(callback(buf, data)) break; + s = e; } +} - return sock; +struct connect_to_one_of_data { + int default_port; + struct timeval *timeout; + size_t *reconnects_counter; + char *connected_to; + size_t connected_to_size; + int sock; +}; + +static bool connect_to_one_of_callback(char *entry, void *data) { + struct connect_to_one_of_data *t = data; + + if(t->reconnects_counter) + t->reconnects_counter++; + + t->sock = connect_to_this(entry, t->default_port, t->timeout); + if(t->sock != -1) { + if(t->connected_to && t->connected_to_size) { + strncpyz(t->connected_to, entry, t->connected_to_size); + t->connected_to[t->connected_to_size - 1] = '\0'; + } + + return true; + } + + return false; +} + +int connect_to_one_of(const char *destination, int default_port, struct timeval *timeout, size_t *reconnects_counter, char *connected_to, size_t connected_to_size) { + struct connect_to_one_of_data t = { + .default_port = default_port, + .timeout = timeout, + .reconnects_counter = reconnects_counter, + .connected_to = connected_to, + .connected_to_size = connected_to_size, + .sock = -1, + }; + + foreach_entry_in_connection_string(destination, connect_to_one_of_callback, &t); + + return t.sock; +} + +static bool connect_to_one_of_urls_callback(char *entry, void *data) { + char *s = strchr(entry, '/'); + if(s) *s = '\0'; + + return connect_to_one_of_callback(entry, data); } +int connect_to_one_of_urls(const char *destination, int default_port, struct timeval *timeout, size_t *reconnects_counter, char *connected_to, size_t connected_to_size) { + struct connect_to_one_of_data t = { + .default_port = default_port, + .timeout = timeout, + .reconnects_counter = reconnects_counter, + .connected_to = connected_to, + .connected_to_size = connected_to_size, + .sock = -1, + }; + + foreach_entry_in_connection_string(destination, connect_to_one_of_urls_callback, &t); + + return t.sock; +} + + +#ifdef ENABLE_HTTPS +ssize_t netdata_ssl_read(SSL *ssl, void *buf, size_t num) { + error_limit_static_thread_var(erl, 1, 0); + + int bytes, err, retries = 0; + + //do { + bytes = SSL_read(ssl, buf, (int)num); + err = SSL_get_error(ssl, bytes); + retries++; + //} while (bytes <= 0 && (err == SSL_ERROR_WANT_READ)); + + if(unlikely(bytes <= 0)) + error("SSL_read() returned %d bytes, SSL error %d", bytes, err); + + if(retries > 1) + error_limit(&erl, "SSL_read() retried %d times", retries); + + return bytes; +} + +ssize_t netdata_ssl_write(SSL *ssl, const void *buf, size_t num) { + error_limit_static_thread_var(erl, 1, 0); + + int bytes, err, retries = 0; + size_t total = 0; + + //do { + bytes = SSL_write(ssl, (uint8_t *)buf + total, (int)(num - total)); + err = SSL_get_error(ssl, bytes); + retries++; + + if(bytes > 0) + total += bytes; + + //} while ((bytes <= 0 && (err == SSL_ERROR_WANT_WRITE)) || (bytes > 0 && total < num)); + + if(unlikely(bytes <= 0)) + error("SSL_write() returned %d bytes, SSL error %d", bytes, err); + + if(retries > 1) + error_limit(&erl, "SSL_write() retried %d times", retries); + + return bytes; +} +#endif // -------------------------------------------------------------------------------------------------------------------- // helpers to send/receive data in one call, in blocking mode, with a timeout @@ -901,12 +1003,10 @@ ssize_t recv_timeout(int sockfd, void *buf, size_t len, int flags, int timeout) } #ifdef ENABLE_HTTPS - if (ssl->conn) { - if (!ssl->flags) { - return SSL_read(ssl->conn,buf,len); - } - } + if (ssl->conn && ssl->flags == NETDATA_SSL_HANDSHAKE_COMPLETE) + return netdata_ssl_read(ssl->conn, buf, len); #endif + return recv(sockfd, buf, len, flags); } @@ -945,8 +1045,12 @@ ssize_t send_timeout(int sockfd, void *buf, size_t len, int flags, int timeout) #ifdef ENABLE_HTTPS if(ssl->conn) { - if (!ssl->flags) { - return SSL_write(ssl->conn, buf, len); + if (ssl->flags == NETDATA_SSL_HANDSHAKE_COMPLETE) { + return netdata_ssl_write(ssl->conn, buf, len); + } + else { + error("cannot write to SSL connection - connection is not ready."); + return -1; } } #endif @@ -1087,12 +1191,11 @@ int accept_socket(int fd, int flags, char *client_ip, size_t ipsize, char *clien if (getnameinfo((struct sockaddr *)&sadr, addrlen, client_ip, (socklen_t)ipsize, client_port, (socklen_t)portsize, NI_NUMERICHOST | NI_NUMERICSERV) != 0) { error("LISTENER: cannot getnameinfo() on received client connection."); - strncpyz(client_ip, "UNKNOWN", ipsize - 1); - strncpyz(client_port, "UNKNOWN", portsize - 1); + strncpyz(client_ip, "UNKNOWN", ipsize); + strncpyz(client_port, "UNKNOWN", portsize); } if (!strcmp(client_ip, "127.0.0.1") || !strcmp(client_ip, "::1")) { - strncpy(client_ip, "localhost", ipsize); - client_ip[ipsize - 1] = '\0'; + strncpyz(client_ip, "localhost", ipsize); } #ifdef __FreeBSD__ @@ -1107,8 +1210,7 @@ int accept_socket(int fd, int flags, char *client_ip, size_t ipsize, char *clien case AF_UNIX: debug(D_LISTENER, "New UNIX domain web client from %s on socket %d.", client_ip, fd); // set the port - certain versions of libc return garbage on unix sockets - strncpy(client_port, "UNIX", portsize); - client_port[portsize - 1] = '\0'; + strncpyz(client_port, "UNIX", portsize); break; case AF_INET: @@ -1490,8 +1592,9 @@ static int poll_process_new_tcp_connection(POLLJOB *p, POLLINFO *pi, struct poll debug(D_POLLFD, "POLLFD: LISTENER: accept4() slot %zu (fd %d) failed.", pi->slot, pf->fd); if(unlikely(errno == EMFILE)) { - error("POLLFD: LISTENER: too many open files - sleeping for 1ms - used by this thread %zu, max for this thread %zu", p->used, p->limit); - usleep(1000); // 1ms + error_limit_static_global_var(erl, 10, 1000); + error_limit(&erl, "POLLFD: LISTENER: too many open files - used by this thread %zu, max for this thread %zu", + p->used, p->limit); } else if(unlikely(errno != EWOULDBLOCK && errno != EAGAIN)) error("POLLFD: LISTENER: accept() failed."); |