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 */
_fill(T S,int timeout)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
_getPort(const struct sockaddr * addr)161 static int _getPort(const struct sockaddr *addr) {
162 if (addr->sa_family == AF_INET)
163 return ntohs(((const struct sockaddr_in *)addr)->sin_port);
164 #ifdef HAVE_IPV6
165 else if (addr->sa_family == AF_INET6)
166 return ntohs(((const struct sockaddr_in6 *)addr)->sin6_port);
167 #endif
168 else
169 return -1;
170 }
171
172
_addressToString(const struct sockaddr * addr,socklen_t addrlen,char * buf,int buflen)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", ((const 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
_doConnect(int s,const struct sockaddr * addr,socklen_t addrlen,int timeout,char * error,int errorlen)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
_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)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
_resolve(const char * hostname,int port,Socket_Type type,Socket_Family family)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
Socket_new(const char * host,int port,Socket_Type type,Socket_Family family,Ssl_Flags flags,int timeout)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
Socket_create(const char * host,int port,Socket_Type type,Socket_Family family,SslOptions_T options,int timeout)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
Socket_createUnix(const char * path,Socket_Type type,int timeout)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
Socket_createAccepted(int socket,struct sockaddr * addr,void * sslserver)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
Socket_free(T * S)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
Socket_setTimeout(T S,int timeout)472 void Socket_setTimeout(T S, int timeout) {
473 ASSERT(S);
474 S->timeout = timeout;
475 }
476
477
Socket_getTimeout(T S)478 int Socket_getTimeout(T S) {
479 ASSERT(S);
480 return S->timeout;
481 }
482
483
Socket_isSecure(T S)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
Socket_getSocket(T S)494 int Socket_getSocket(T S) {
495 ASSERT(S);
496 return S->socket;
497 }
498
499
Socket_getType(T S)500 Socket_Type Socket_getType(T S) {
501 ASSERT(S);
502 return S->type;
503 }
504
505
Socket_getPort(T S)506 void *Socket_getPort(T S) {
507 ASSERT(S);
508 return S->Port;
509 }
510
511
Socket_getRemotePort(T S)512 int Socket_getRemotePort(T S) {
513 ASSERT(S);
514 return S->port;
515 }
516
517
Socket_getRemoteHost(T S)518 const char *Socket_getRemoteHost(T S) {
519 ASSERT(S);
520 return S->host;
521 }
522
523
Socket_getLocalPort(T S)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
Socket_getLocalHost(T S,char * host,int hostlen)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
_testUnix(Port_T p)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
_testIp(Port_T p)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
Socket_test(void * P)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
Socket_enableSsl(T S,SslOptions_T options,const char * name)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
Socket_print(T S,const char * m,...)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
Socket_write(T S,const void * b,size_t size)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 = (const 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)((const unsigned char *)p - (const unsigned char *)b);
713 }
714
715
Socket_readByte(T S)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
Socket_read(T S,void * b,int size)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
Socket_readLine(T S,char * s,int size)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
750