"Fossies" - the Fresh Open Source Software Archive

Member "monit-5.28.0/src/net/socket.c" (28 Mar 2021, 26082 Bytes) of package /linux/privat/monit-5.28.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "socket.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.27.2_vs_5.28.0.

    1 /*
    2  * Copyright (C) Tildeslash Ltd. All rights reserved.
    3  *
    4  * This program is free software: you can redistribute it and/or modify
    5  * it under the terms of the GNU Affero General Public License version 3.
    6  *
    7  * This program is distributed in the hope that it will be useful,
    8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   10  * GNU General Public License for more details.
   11  *
   12  * You should have received a copy of the GNU Affero General Public License
   13  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   14  *
   15  * In addition, as a special exception, the copyright holders give
   16  * permission to link the code of portions of this program with the
   17  * OpenSSL library under certain conditions as described in each
   18  * individual source file, and distribute linked combinations
   19  * including the two.
   20  *
   21  * You must obey the GNU Affero General Public License in all respects
   22  * for all of the code used other than OpenSSL.
   23  */
   24 
   25 #include "config.h"
   26 
   27 #ifdef HAVE_POLL_H
   28 #include <poll.h>
   29 #endif
   30 
   31 #ifdef HAVE_FCNTL_H
   32 #include <fcntl.h>
   33 #endif
   34 
   35 #ifdef HAVE_SYS_TYPES_H
   36 #include <sys/types.h>
   37 #endif
   38 
   39 #ifdef HAVE_STRING_H
   40 #include <string.h>
   41 #endif
   42 
   43 #ifdef HAVE_SYS_SOCKET_H
   44 #include <sys/socket.h>
   45 #endif
   46 
   47 #ifdef HAVE_STRINGS_H
   48 #include <strings.h>
   49 #endif
   50 
   51 #ifdef HAVE_UNISTD_H
   52 #include <unistd.h>
   53 #endif
   54 
   55 #ifdef HAVE_NETINET_IN_H
   56 #include <netinet/in.h>
   57 #endif
   58 
   59 #ifdef HAVE_SYS_UN_H
   60 #include <sys/un.h>
   61 #endif
   62 
   63 #ifdef HAVE_ARPA_INET_H
   64 #include <arpa/inet.h>
   65 #endif
   66 
   67 #ifdef HAVE_NETINET_TCP_H
   68 #include <netinet/tcp.h>
   69 #endif
   70 
   71 #ifdef HAVE_NETDB_H
   72 #include <netdb.h>
   73 #endif
   74 
   75 #include "net.h"
   76 #include "monit.h"
   77 #include "socket.h"
   78 #include "SslServer.h"
   79 
   80 // libmonit
   81 #include "exceptions/assert.h"
   82 #include "exceptions/IOException.h"
   83 #include "util/Str.h"
   84 #include "system/Net.h"
   85 #include "system/Time.h"
   86 
   87 
   88 
   89 /**
   90  * Implementation of the socket interface.
   91  *
   92  * @file
   93  */
   94 
   95 
   96 /* ------------------------------------------------------------- Definitions */
   97 
   98 
   99 typedef enum {
  100         Connection_Client = 0,
  101         Connection_Server
  102 } __attribute__((__packed__)) Connection_Type;
  103 
  104 
  105 // One TCP frame data size
  106 #define RBUFFER_SIZE 1460
  107 
  108 
  109 #define T Socket_T
  110 struct T {
  111         Socket_Type type;
  112         Socket_Family family;
  113         Connection_Type connection_type;
  114         int socket;
  115         int port;
  116         int timeout; // milliseconds
  117         int length;
  118         int offset;
  119         char *host;
  120         Port_T Port;
  121 #ifdef HAVE_OPENSSL
  122         Ssl_T ssl;
  123         SslServer_T sslserver;
  124 #endif
  125         unsigned char buffer[RBUFFER_SIZE + 1];
  126 };
  127 
  128 
  129 /* --------------------------------------------------------------- Private */
  130 
  131 
  132 /*
  133  * Fill the internal buffer. If an error occurs or if the read
  134  * operation timed out -1 is returned.
  135  * @param S A Socket object
  136  * @param timeout The number of milliseconds to wait for data to be read
  137  * @return the length of data read or -1 if an error occurred
  138  */
  139 static int _fill(T S, int timeout) {
  140         S->offset = 0;
  141         S->length = 0;
  142         if (S->type == Socket_Udp)
  143                 timeout = 500;
  144         int n;
  145 #ifdef HAVE_OPENSSL
  146         if (S->ssl)
  147                 n = Ssl_read(S->ssl, S->buffer + S->length, RBUFFER_SIZE - S->length, timeout);
  148         else
  149 #endif
  150                 n = (int)Net_read(S->socket, S->buffer + S->length,  RBUFFER_SIZE - S->length, timeout);
  151         if (n > 0)
  152                 S->length += n;
  153         else if (n < 0)
  154                 return -1;
  155         else if (! (errno == EAGAIN || errno == EWOULDBLOCK)) // Peer closed connection
  156                 return -1;
  157         return n;
  158 }
  159 
  160 
  161 static int _getPort(const struct sockaddr *addr) {
  162         if (addr->sa_family == AF_INET)
  163                 return ntohs(((struct sockaddr_in *)addr)->sin_port);
  164 #ifdef HAVE_IPV6
  165         else if (addr->sa_family == AF_INET6)
  166                 return ntohs(((struct sockaddr_in6 *)addr)->sin6_port);
  167 #endif
  168         else
  169                 return -1;
  170 }
  171 
  172 
  173 static char *_addressToString(const struct sockaddr *addr, socklen_t addrlen, char *buf, int buflen) {
  174         int oerrno = errno;
  175         if (addr->sa_family == AF_UNIX) {
  176                 snprintf(buf, buflen, "%s", ((struct sockaddr_un *)addr)->sun_path);
  177         } else {
  178                 char ip[NI_MAXHOST];
  179                 char port[NI_MAXSERV];
  180                 int status = getnameinfo(addr, addrlen, ip, sizeof(ip), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
  181                 if (status) {
  182                         Log_error("Cannot get address string -- %s\n", status == EAI_SYSTEM ? STRERROR : gai_strerror(status));
  183                         *buf = 0;
  184                 } else {
  185                         snprintf(buf, buflen, "[%s]:%s", ip, port);
  186                 }
  187         }
  188         errno = oerrno;
  189         return buf;
  190 }
  191 
  192 
  193 static bool _doConnect(int s, const struct sockaddr *addr, socklen_t addrlen, int timeout, char *error, int errorlen) {
  194         int rv = connect(s, addr, addrlen);
  195         if (! rv) {
  196                 return true;
  197         } else if (errno != EINPROGRESS) {
  198                 snprintf(error, errorlen, "%s", STRERROR);
  199                 return false;
  200         }
  201         struct pollfd fds[1];
  202         fds[0].fd = s;
  203         fds[0].events = POLLIN | POLLOUT;
  204         rv = poll(fds, 1, timeout);
  205         if (rv == 0) {
  206                 snprintf(error, errorlen, "Connection timed out");
  207                 return false;
  208         } else if (rv == -1) {
  209                 snprintf(error, errorlen, "Poll failed: %s", STRERROR);
  210                 return false;
  211         }
  212         if (fds[0].events & POLLIN || fds[0].events & POLLOUT) {
  213                 socklen_t rvlen = sizeof(rv);
  214                 if (getsockopt(s, SOL_SOCKET, SO_ERROR, &rv, &rvlen) < 0) {
  215                         snprintf(error, errorlen, "Read of error details failed: %s", STRERROR);
  216                         return false;
  217                 } else if (rv) {
  218                         snprintf(error, errorlen, "%s", strerror(rv));
  219                         return false;
  220                 }
  221         } else {
  222                 snprintf(error, errorlen, "Not ready for I/O");
  223                 return false;
  224         }
  225         return true;
  226 }
  227 
  228 
  229 static T _createIpSocket(const char *host, const struct sockaddr *addr, socklen_t addrlen, const struct sockaddr *localaddr, socklen_t localaddrlen, int family, int type, int protocol, int timeout) {
  230         ASSERT(host);
  231         char error[STRLEN];
  232         int s = socket(family, type, protocol);
  233         if (s >= 0) {
  234                 if (localaddr) {
  235                         if (bind(s, localaddr, localaddrlen) < 0) {
  236                                 snprintf(error, sizeof(error), "Cannot bind to outgoing address -- %s", STRERROR);
  237                                 goto error;
  238                         }
  239                 }
  240                 if (Net_setNonBlocking(s)) {
  241                         if (fcntl(s, F_SETFD, FD_CLOEXEC) != -1) {
  242                                 if (_doConnect(s, addr, addrlen, timeout, error, sizeof(error))) {
  243                                         T S;
  244                                         NEW(S);
  245                                         S->socket = s;
  246                                         S->type = type;
  247                                         S->family = family == AF_INET ? Socket_Ip4 : Socket_Ip6;
  248                                         S->timeout = timeout;
  249                                         S->host = Str_dup(host);
  250                                         S->port = _getPort(addr);
  251                                         S->connection_type = Connection_Client;
  252                                         return S;
  253                                 }
  254                         } else {
  255                                 snprintf(error, sizeof(error), "Cannot set socket close on exec -- %s", STRERROR);
  256                         }
  257                 } else {
  258                         snprintf(error, sizeof(error), "Cannot set nonblocking socket -- %s", STRERROR);
  259                 }
  260 error:
  261                 Net_close(s);
  262         } else {
  263                 snprintf(error, sizeof(error), "Cannot create socket to %s -- %s", _addressToString(addr, addrlen, (char[2048]){}, 2048), STRERROR);
  264         }
  265         THROW(IOException, "%s", error);
  266         return NULL;
  267 }
  268 
  269 
  270 static struct addrinfo *_resolve(const char *hostname, int port, Socket_Type type, Socket_Family family) {
  271         ASSERT(hostname);
  272         struct addrinfo *result, hints = {
  273                 .ai_socktype = type,
  274                 .ai_protocol = type == Socket_Udp ? IPPROTO_UDP : IPPROTO_TCP
  275         };
  276         switch (family) {
  277                 case Socket_Ip:
  278                         hints.ai_family = AF_UNSPEC;
  279                         break;
  280                 case Socket_Ip4:
  281                         hints.ai_family = AF_INET;
  282                         break;
  283 #ifdef HAVE_IPV6
  284                 case Socket_Ip6:
  285                         hints.ai_family = AF_INET6;
  286 #ifdef AI_ADDRCONFIG
  287                         hints.ai_flags = AI_ADDRCONFIG;
  288 #endif
  289                         break;
  290 #endif
  291                 default:
  292                         Log_error("Invalid socket family %d\n", family);
  293                         return NULL;
  294         }
  295         char _port[6];
  296         snprintf(_port, sizeof(_port), "%d", port);
  297         int status = getaddrinfo(hostname, _port, &hints, &result);
  298         if (status != 0) {
  299                 Log_error("Cannot translate '%s' to IP address -- %s\n", hostname, status == EAI_SYSTEM ? STRERROR : gai_strerror(status));
  300                 return NULL;
  301         }
  302         return result;
  303 }
  304 
  305 
  306 /* ------------------------------------------------------------------ Public */
  307 
  308 
  309 T Socket_new(const char *host, int port, Socket_Type type, Socket_Family family, Ssl_Flags flags, int timeout) {
  310         struct SslOptions_T options = {.flags = flags};
  311         return Socket_create(host, port, type, family, &options, timeout);
  312 }
  313 
  314 
  315 T Socket_create(const char *host, int port, Socket_Type type, Socket_Family family, SslOptions_T options, int timeout) {
  316         ASSERT(host);
  317         ASSERT(timeout > 0);
  318         volatile T S = NULL;
  319         struct addrinfo *result = _resolve(host, port, type, family);
  320         if (result) {
  321                 char error[512] = {};
  322                 // The host may resolve to multiple IPs and if at least one succeeded, we have no problem and don't have to flood the log with partial errors => log only the last error
  323                 for (struct addrinfo *r = result; r && S == NULL; r = r->ai_next) {
  324                         TRY
  325                         {
  326                                 S = _createIpSocket(host, r->ai_addr, r->ai_addrlen, NULL, 0, r->ai_family, r->ai_socktype, r->ai_protocol, timeout);
  327                                 if (options->flags == SSL_Enabled)
  328                                         Socket_enableSsl(S, options, host);
  329                         }
  330                         ELSE
  331                         {
  332                                 if (S)
  333                                         Socket_free((T *)&S);
  334                                 DEBUG("Info: Cannot connect to [%s]:%d -- %s\nTrying next address record\n", host, port, Exception_frame.message);
  335                                 snprintf(error, sizeof(error), "%s", Exception_frame.message);
  336                         }
  337                         END_TRY;
  338                 }
  339                 freeaddrinfo(result);
  340                 if (! S)
  341                         Log_error("Cannot connect to [%s]:%d -- %s\n", host, port, error);
  342         }
  343         return S;
  344 }
  345 
  346 
  347 T Socket_createUnix(const char *path, Socket_Type type, int timeout) {
  348         ASSERT(path);
  349         ASSERT(timeout > 0);
  350         int s = socket(PF_UNIX, type, 0);
  351         if (s >= 0) {
  352                 struct sockaddr_un unixsocket_client = {};
  353                 if (type == Socket_Udp) {
  354                         unixsocket_client.sun_family = AF_UNIX;
  355                         snprintf(unixsocket_client.sun_path, sizeof(unixsocket_client.sun_path), "/tmp/monit_%p.sock", &unixsocket_client);
  356                         if (bind(s, (struct sockaddr *) &unixsocket_client, sizeof(unixsocket_client)) != 0) {
  357                                 Log_error("Unix socket %s bind error -- %s\n", unixsocket_client.sun_path, STRERROR);
  358                                 goto error;
  359                         }
  360                 }
  361                 struct sockaddr_un unixsocket_server = {};
  362                 unixsocket_server.sun_family = AF_UNIX;
  363                 strncpy(unixsocket_server.sun_path, path, sizeof(unixsocket_server.sun_path) - 1);
  364                 if (Net_setNonBlocking(s)) {
  365                         char error[STRLEN];
  366                         if (_doConnect(s, (struct sockaddr *)&unixsocket_server, sizeof(unixsocket_server), timeout, error, sizeof(error))) {
  367                                 T S;
  368                                 NEW(S);
  369                                 S->connection_type = Connection_Client;
  370                                 S->family = Socket_Unix;
  371                                 S->type = type;
  372                                 S->socket = s;
  373                                 S->timeout = timeout;
  374                                 S->host = Str_dup(LOCALHOST);
  375                                 return S;
  376                         }
  377                         Log_error("Unix socket %s connection error -- %s\n", path, error);
  378                 } else {
  379                         Log_error("Cannot set nonblocking unix socket %s -- %s\n", path, STRERROR);
  380                 }
  381 error:
  382                 Net_close(s);
  383                 if (type == Socket_Udp)
  384                         unlink(unixsocket_client.sun_path);
  385         } else {
  386                 Log_error("Cannot create unix socket %s -- %s\n", path, STRERROR);
  387         }
  388         return NULL;
  389 }
  390 
  391 
  392 T Socket_createAccepted(int socket, struct sockaddr *addr, void *sslserver) {
  393         ASSERT(socket >= 0);
  394         ASSERT(addr);
  395         T S;
  396         NEW(S);
  397         S->socket = socket;
  398         S->timeout = Run.limits.networkTimeout;
  399         S->connection_type = Connection_Server;
  400         S->type = Socket_Tcp;
  401         if (addr->sa_family != AF_UNIX) {
  402                 if (addr->sa_family == AF_INET) {
  403                         struct sockaddr_in *a = (struct sockaddr_in *)addr;
  404                         S->family = Socket_Ip4;
  405                         S->host = Str_dup(inet_ntop(addr->sa_family, &a->sin_addr, (char[INET_ADDRSTRLEN]){}, INET_ADDRSTRLEN));
  406                 }
  407 #ifdef HAVE_IPV6
  408                 else {
  409                         struct sockaddr_in6 *a = (struct sockaddr_in6 *)addr;
  410                         S->family = Socket_Ip6;
  411                         S->host = Str_dup(inet_ntop(addr->sa_family, &a->sin6_addr, (char[INET6_ADDRSTRLEN]){}, INET6_ADDRSTRLEN));
  412                 }
  413 #endif
  414                 S->port = _getPort(addr);
  415 #ifdef HAVE_OPENSSL
  416                 if (sslserver) {
  417                         S->sslserver = sslserver;
  418                         if (! (S->ssl = SslServer_newConnection(S->sslserver)) || ! SslServer_accept(S->ssl, S->socket, S->timeout)) {
  419                                 Socket_free(&S);
  420                                 return NULL;
  421                         }
  422                 }
  423 #endif
  424         } else {
  425                 S->family = Socket_Unix;
  426         }
  427         return S;
  428 }
  429 
  430 
  431 void Socket_free(T *S) {
  432         ASSERT(S && *S);
  433 #ifdef HAVE_OPENSSL
  434         if ((*S)->ssl)
  435         {
  436                 if ((*S)->connection_type == Connection_Client) {
  437                         Ssl_close((*S)->ssl);
  438                         Ssl_free(&((*S)->ssl));
  439                 } else if ((*S)->connection_type == Connection_Server && (*S)->sslserver) {
  440                         SslServer_freeConnection((*S)->sslserver, &((*S)->ssl));
  441                 }
  442         }
  443         else
  444 #endif
  445         {
  446                 int type;
  447                 socklen_t length = sizeof(type);
  448                 int rv = getsockopt((*S)->socket, SOL_SOCKET, SO_TYPE, &type, &length);
  449                 if (rv) {
  450                         Log_error("Freeing socket -- getsockopt failed: %s\n", STRERROR);
  451                 } else if (type == SOCK_DGRAM) {
  452                         struct sockaddr_storage addr;
  453                         socklen_t addrlen = sizeof(addr);
  454                         if (getsockname((*S)->socket, (struct sockaddr *)&addr, &addrlen) == 0) {
  455                                 if (addr.ss_family == AF_UNIX) {
  456                                         struct sockaddr_un *_addr = (struct sockaddr_un *)&addr;
  457                                         unlink(_addr->sun_path);
  458                                 }
  459                         }
  460                 }
  461                 Net_shutdown((*S)->socket, SHUT_RDWR);
  462                 Net_close((*S)->socket);
  463         }
  464         FREE((*S)->host);
  465         FREE(*S);
  466 }
  467 
  468 
  469 /* ------------------------------------------------------------ Properties */
  470 
  471 
  472 void Socket_setTimeout(T S, int timeout) {
  473         ASSERT(S);
  474         S->timeout = timeout;
  475 }
  476 
  477 
  478 int Socket_getTimeout(T S) {
  479         ASSERT(S);
  480         return S->timeout;
  481 }
  482 
  483 
  484 bool Socket_isSecure(T S) {
  485         ASSERT(S);
  486 #ifdef HAVE_OPENSSL
  487         return (S->ssl != NULL);
  488 #else
  489         return false;
  490 #endif
  491 }
  492 
  493 
  494 int Socket_getSocket(T S) {
  495         ASSERT(S);
  496         return S->socket;
  497 }
  498 
  499 
  500 Socket_Type Socket_getType(T S) {
  501         ASSERT(S);
  502         return S->type;
  503 }
  504 
  505 
  506 void *Socket_getPort(T S) {
  507         ASSERT(S);
  508         return S->Port;
  509 }
  510 
  511 
  512 int Socket_getRemotePort(T S) {
  513         ASSERT(S);
  514         return S->port;
  515 }
  516 
  517 
  518 const char *Socket_getRemoteHost(T S) {
  519         ASSERT(S);
  520         return S->host;
  521 }
  522 
  523 
  524 int Socket_getLocalPort(T S) {
  525         ASSERT(S);
  526         struct sockaddr_storage addr;
  527         socklen_t addrlen = sizeof(addr);
  528         if (getsockname(S->socket, (struct sockaddr *)&addr, &addrlen) == 0)
  529                 return _getPort((struct sockaddr *)&addr);
  530         return -1;
  531 }
  532 
  533 
  534 const char *Socket_getLocalHost(T S, char *host, int hostlen) {
  535         ASSERT(S);
  536         ASSERT(host);
  537         ASSERT(hostlen);
  538         struct sockaddr_storage addr;
  539         socklen_t addrlen = sizeof(addr);
  540         if (! getsockname(S->socket, (struct sockaddr *)&addr, &addrlen)) {
  541                 int status = getnameinfo((struct sockaddr *)&addr, addrlen, host, hostlen, NULL, 0, NI_NUMERICHOST);
  542                 if (! status)
  543                         return host;
  544                 Log_error("Cannot translate address to hostname -- %s\n", status == EAI_SYSTEM ? STRERROR : gai_strerror(status));
  545         } else {
  546                 Log_error("Cannot translate address to hostname -- getsockname failed: %s\n", STRERROR);
  547         }
  548         return NULL;
  549 }
  550 
  551 
  552 static void _testUnix(Port_T p) {
  553         T S = Socket_createUnix(p->target.unix.pathname, p->type, p->timeout);
  554         if (S) {
  555                 S->Port = p;
  556                 TRY
  557                 {
  558                         p->protocol->check(S);
  559                 }
  560                 FINALLY
  561                 {
  562                         Socket_free(&S);
  563                 }
  564                 END_TRY;
  565         } else {
  566                 THROW(IOException, "Cannot create unix socket for %s", p->target.unix.pathname);
  567         }
  568 }
  569 
  570 
  571 static void _testIp(Port_T p) {
  572         char error[512];
  573         volatile Connection_State is_available = Connection_Failed;
  574         struct addrinfo *result = _resolve(p->hostname, p->target.net.port, p->type, p->family);
  575         if (result) {
  576                 // The host may resolve to multiple IPs and if at least one succeeded, we have no problem and don't have to flood the log with partial errors => log only the last error
  577                 for (struct addrinfo *r = result; r && is_available != Connection_Ok; r = r->ai_next) {
  578                         if (p->outgoing.addrlen == 0 || p->outgoing.addrlen == r->ai_addrlen) {
  579                                 volatile T S = NULL;
  580                                 TRY
  581                                 {
  582                                         S = _createIpSocket(p->hostname, r->ai_addr, r->ai_addrlen, p->outgoing.addrlen ? (struct sockaddr *)&(p->outgoing.addr) : NULL, p->outgoing.addrlen, r->ai_family, r->ai_socktype, r->ai_protocol, p->timeout);
  583                                         S->Port = p;
  584                                         TRY
  585                                         {
  586                                                 if (p->target.net.ssl.options.flags == SSL_Enabled) {
  587                                                         Socket_enableSsl(S, &(p->target.net.ssl.options), p->hostname);
  588                                                 }
  589                                                 p->protocol->check(S);
  590                                         }
  591                                         FINALLY
  592                                         {
  593                                                 // Set the minimum valid days past the protocol check as if the connection uses STARTTLS to switch plain->SSL, we have no SSL certificate information until the STARTTTLS is performed.
  594                                                 // Try to collect the certificate validDays even on protocol exception - the protocol test may fail on higher level (e.g. when HTTP returns 400), but we can still get certificate info
  595 #ifdef HAVE_OPENSSL
  596                                                 if (S->ssl)
  597                                                         p->target.net.ssl.certificate.validDays = Ssl_getCertificateValidDays(S->ssl);
  598 #endif
  599                                         }
  600                                         END_TRY;
  601                                         is_available = Connection_Ok;
  602 
  603                                 }
  604                                 ELSE
  605                                 {
  606                                         snprintf(error, sizeof(error), "%s", Exception_frame.message);
  607                                         DEBUG("Socket test failed for %s -- %s\n", _addressToString(r->ai_addr, r->ai_addrlen, (char[STRLEN]){}, STRLEN), error);
  608                                 }
  609                                 FINALLY
  610                                 {
  611                                         if (S) {
  612                                                 Socket_free((Socket_T *)&S);
  613                                         }
  614                                 }
  615                                 END_TRY;
  616                         } else {
  617                                 snprintf(error, sizeof(error), "No IP address matching '%s' was found", p->outgoing.ip);
  618                         }
  619                 }
  620                 freeaddrinfo(result);
  621                 if (is_available != Connection_Ok)
  622                         THROW(IOException, "%s", error);
  623         } else {
  624                 THROW(IOException, "Cannot resolve [%s]:%d", p->hostname, p->target.net.port);
  625         }
  626 }
  627 
  628 
  629 /* ---------------------------------------------------------------- Public */
  630 
  631 
  632 void Socket_test(void *P) {
  633         ASSERT(P);
  634         Port_T p = P;
  635         TRY
  636         {
  637                 long long start = Time_micro();
  638                 switch (p->family) {
  639                         case Socket_Unix:
  640                                 _testUnix(p);
  641                                 break;
  642                         case Socket_Ip:
  643                         case Socket_Ip4:
  644                         case Socket_Ip6:
  645                                 _testIp(p);
  646                                 break;
  647                         default:
  648                                 THROW(IOException, "Invalid socket family %d\n", p->family);
  649                                 break;
  650                 }
  651                 p->responsetime.current = (double)(Time_micro() - start) / 1000.; // Convert microseconds to milliseconds
  652                 p->is_available = Connection_Ok;
  653         }
  654         ELSE
  655         {
  656                 p->is_available = Connection_Failed;
  657                 p->responsetime.current = -1.;
  658                 RETHROW;
  659         }
  660         END_TRY;
  661 }
  662 
  663 
  664 void Socket_enableSsl(T S, SslOptions_T options, const char *name)  {
  665         assert(S);
  666 #ifdef HAVE_OPENSSL
  667         if ((S->ssl = Ssl_new(options)))
  668                 Ssl_connect(S->ssl, S->socket, S->timeout, name);
  669 #endif
  670 }
  671 
  672 
  673 int Socket_print(T S, const char *m, ...) {
  674         int n;
  675         va_list ap;
  676         char *buf = NULL;
  677         ASSERT(S);
  678         ASSERT(m);
  679         va_start(ap, m);
  680         buf = Str_vcat(m, ap);
  681         va_end(ap);
  682         n = Socket_write(S, buf, strlen(buf));
  683         FREE(buf);
  684         return n;
  685 }
  686 
  687 
  688 int Socket_write(T S, const void *b, size_t size) {
  689         ssize_t n = 0;
  690         const void *p = b;
  691         ASSERT(S);
  692         while (size > 0) {
  693 #ifdef HAVE_OPENSSL
  694                 if (S->ssl) {
  695                         n = Ssl_write(S->ssl, p, (int)size, S->timeout);
  696                 } else {
  697 #endif
  698                         n = Net_write(S->socket, p, size, S->timeout);
  699 #ifdef HAVE_OPENSSL
  700                 }
  701 #endif
  702                 if (n <= 0)
  703                         break;
  704                 p = (unsigned char *)p + n;
  705                 size -= n;
  706 
  707         }
  708         if (n < 0) {
  709                 /* No write or a partial write is an error */
  710                 return -1;
  711         }
  712         return  (int)((unsigned char *)p - (unsigned char *)b);
  713 }
  714 
  715 
  716 int Socket_readByte(T S) {
  717         ASSERT(S);
  718         if (S->offset >= S->length)
  719                 if (_fill(S, S->timeout) <= 0)
  720                         return -1;
  721         return S->buffer[S->offset++];
  722 }
  723 
  724 
  725 int Socket_read(T S, void *b, int size) {
  726         int c;
  727         unsigned char *p = b;
  728         ASSERT(S);
  729         while ((size-- > 0) && ((c = Socket_readByte(S)) >= 0))
  730                 *p++ = c;
  731         return (int)((long)p - (long)b);
  732 }
  733 
  734 
  735 char *Socket_readLine(T S, char *s, int size) {
  736         int c;
  737         unsigned char *p = (unsigned char *)s;
  738         ASSERT(S);
  739         while (--size && ((c = Socket_readByte(S)) > 0)) { // Stop when \0 is read
  740                 *p++ = c;
  741                 if (c == '\n')
  742                         break;
  743         }
  744         *p = 0;
  745         if (*s)
  746                 return s;
  747         return NULL;
  748 }
  749