Asterisk - The Open Source Telephony Project GIT-master-0bf3178
Typedefs | Functions
iostream.h File Reference

Generic abstraction for input/output streams. More...

#include "asterisk.h"
Include dependency graph for iostream.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Typedefs

typedef struct ssl_st SSL
 
typedef struct ssl_ctx_st SSL_CTX
 

Functions

int ast_iostream_close (struct ast_iostream *stream)
 Close an iostream. More...
 
ssize_t ast_iostream_discard (struct ast_iostream *stream, size_t count)
 Discard the specified number of bytes from an iostream. More...
 
struct ast_iostreamast_iostream_from_fd (int *fd)
 Create an iostream from a file descriptor. More...
 
int ast_iostream_get_fd (struct ast_iostream *stream)
 Get an iostream's file descriptor. More...
 
SSLast_iostream_get_ssl (struct ast_iostream *stream)
 Get a pointer to an iostream's OpenSSL SSL structure. More...
 
ssize_t ast_iostream_gets (struct ast_iostream *stream, char *buffer, size_t size)
 Read a LF-terminated string from an iostream. More...
 
void ast_iostream_nonblock (struct ast_iostream *stream)
 Make an iostream non-blocking. More...
 
ssize_t ast_iostream_printf (struct ast_iostream *stream, const char *format,...)
 Write a formatted string to an iostream. More...
 
ssize_t ast_iostream_read (struct ast_iostream *stream, void *buffer, size_t count)
 Read data from an iostream. More...
 
void ast_iostream_set_exclusive_input (struct ast_iostream *stream, int exclusive_input)
 Set the iostream if it can exclusively depend upon the set timeouts. More...
 
int ast_iostream_set_sni_hostname (struct ast_iostream *stream, const char *sni_hostname)
 Set the iostream's SNI hostname for TLS client connections. More...
 
void ast_iostream_set_timeout_disable (struct ast_iostream *stream)
 Disable the iostream timeout timer. More...
 
void ast_iostream_set_timeout_idle_inactivity (struct ast_iostream *stream, int timeout, int timeout_reset)
 Set the iostream inactivity & idle timeout timers. More...
 
void ast_iostream_set_timeout_inactivity (struct ast_iostream *stream, int timeout)
 Set the iostream inactivity timeout timer. More...
 
void ast_iostream_set_timeout_sequence (struct ast_iostream *stream, struct timeval start, int timeout)
 Set the iostream I/O sequence timeout timer. More...
 
int ast_iostream_start_tls (struct ast_iostream **stream, SSL_CTX *ctx, int client)
 Begin TLS on an iostream. More...
 
int ast_iostream_wait_for_input (struct ast_iostream *stream, int timeout)
 Wait for input on the iostream's file descriptor. More...
 
ssize_t ast_iostream_write (struct ast_iostream *stream, const void *buffer, size_t count)
 Write data to an iostream. More...
 

Detailed Description

Generic abstraction for input/output streams.

Definition in file iostream.h.

Typedef Documentation

◆ SSL

typedef struct ssl_st SSL

Definition at line 37 of file iostream.h.

◆ SSL_CTX

typedef struct ssl_ctx_st SSL_CTX

Definition at line 38 of file iostream.h.

Function Documentation

◆ ast_iostream_close()

int ast_iostream_close ( struct ast_iostream stream)

Close an iostream.

Parameters
streamA pointer to an iostream
Return values
0success
-1failure
Note
On failure, errno may be set providing additional information on why the failure occurred.

Definition at line 539 of file iostream.c.

540{
541 if (!stream) {
542 errno = EBADF;
543 return -1;
544 }
545
546 if (stream->fd != -1) {
547#if defined(DO_SSL)
548 if (stream->ssl) {
549 int res;
550
551 /*
552 * According to the TLS standard, it is acceptable for an
553 * application to only send its shutdown alert and then
554 * close the underlying connection without waiting for
555 * the peer's response (this way resources can be saved,
556 * as the process can already terminate or serve another
557 * connection).
558 */
559 res = SSL_shutdown(stream->ssl);
560 if (res < 0) {
561 int sslerr = SSL_get_error(stream->ssl, res);
562 char err[256];
563 ast_log(LOG_ERROR, "SSL_shutdown() failed: %s, %s\n",
564 ERR_error_string(sslerr, err), ssl_error_to_string(sslerr, res));
565 }
566
567#if !(defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x2070000L)) && (OPENSSL_VERSION_NUMBER >= 0x10100000L)
568 if (!SSL_is_server(stream->ssl)) {
569#else
570 if (!stream->ssl->server) {
571#endif
572 /* For client threads, ensure that the error stack is cleared */
573#if defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x10100000L)
574#if OPENSSL_VERSION_NUMBER >= 0x10000000L
575 ERR_remove_thread_state(NULL);
576#else
577 ERR_remove_state(0);
578#endif /* OPENSSL_VERSION_NUMBER >= 0x10000000L */
579#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
580 }
581
582 SSL_free(stream->ssl);
583 stream->ssl = NULL;
584 }
585#endif /* defined(DO_SSL) */
586
587 /*
588 * Issuing shutdown() is necessary here to avoid a race
589 * condition where the last data written may not appear
590 * in the TCP stream. See ASTERISK-23548
591 */
592 shutdown(stream->fd, SHUT_RDWR);
593 if (close(stream->fd)) {
594 ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno));
595 }
596 stream->fd = -1;
597 }
598 ao2_t_ref(stream, -1, "Closed ast_iostream");
599
600 return 0;
601}
#define ast_log
Definition: astobj2.c:42
#define ao2_t_ref(o, delta, tag)
Definition: astobj2.h:460
#define LOG_ERROR
int errno
#define NULL
Definition: resample.c:96
SSL * ssl
Definition: iostream.c:40

References ao2_t_ref, ast_log, errno, ast_iostream::fd, LOG_ERROR, NULL, and ast_iostream::ssl.

Referenced by app_exec(), ast_tcptls_close_session_file(), ast_websocket_close(), auth_http_callback(), close_mansession_file(), generic_http_callback(), session_destroy_fn(), and session_instance_destructor().

◆ ast_iostream_discard()

ssize_t ast_iostream_discard ( struct ast_iostream stream,
size_t  count 
)

Discard the specified number of bytes from an iostream.

Parameters
streamA pointer to an iostream
countThe number of bytes to discard.
Returns
Upon successful completion, returns the number of bytes discarded. Otherwise, -1 is returned and errno may be set indicating the error.

Definition at line 368 of file iostream.c.

369{
370 char buf[1024];
371 size_t remaining = size;
372 ssize_t ret;
373
374 while (remaining) {
375 ret = ast_iostream_read(stream, buf, remaining > sizeof(buf) ? sizeof(buf) : remaining);
376 if (ret <= 0) {
377 return ret;
378 }
379 remaining -= ret;
380 }
381
382 return size;
383}
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
ssize_t ast_iostream_read(struct ast_iostream *stream, void *buffer, size_t count)
Read data from an iostream.
Definition: iostream.c:284

References ast_iostream_read(), and buf.

Referenced by http_body_discard_contents().

◆ ast_iostream_from_fd()

struct ast_iostream * ast_iostream_from_fd ( int *  fd)

Create an iostream from a file descriptor.

Parameters
fdA pointer to an open file descriptor
Returns
A newly allocated iostream or NULL if allocation fails.

Definition at line 611 of file iostream.c.

612{
613 struct ast_iostream *stream;
614
615 stream = ao2_alloc_options(sizeof(*stream), iostream_dtor,
617 if (stream) {
618 stream->timeout = -1;
619 stream->timeout_reset = -1;
620 stream->fd = *fd;
621 *fd = -1;
622 }
623
624 return stream;
625}
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
static void iostream_dtor(void *cookie)
Definition: iostream.c:603
int timeout
Definition: iostream.c:43
int timeout_reset
Definition: iostream.c:44

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ast_iostream::fd, iostream_dtor(), ast_iostream::timeout, and ast_iostream::timeout_reset.

Referenced by app_exec(), ast_tcptls_client_create(), ast_tcptls_server_root(), auth_http_callback(), and generic_http_callback().

◆ ast_iostream_get_fd()

int ast_iostream_get_fd ( struct ast_iostream stream)

Get an iostream's file descriptor.

Parameters
streamA pointer to an iostream
Returns
The file descriptor for the given iostream
Return values
-1if the iostream has no open file descriptor.

Definition at line 85 of file iostream.c.

86{
87 return stream->fd;
88}

References ast_iostream::fd.

Referenced by action_waitevent(), ast_websocket_fd(), ast_websocket_uri_cb(), auth_http_callback(), eivr_comm(), get_input(), handle_kickmanconn(), handle_showmanconn(), httpd_helper_thread(), phoneprov_callback(), process_output(), and session_do().

◆ ast_iostream_get_ssl()

SSL * ast_iostream_get_ssl ( struct ast_iostream stream)

Get a pointer to an iostream's OpenSSL SSL structure.

Parameters
streamA pointer to an iostream
Returns
A pointer to the OpenSSL SSL structure for the given iostream
Return values
NULLif TLS has not been initiated.
Note
If OpenSSL support is not included in the build, this will always return NULL.

Definition at line 109 of file iostream.c.

110{
111 return stream->ssl;
112}

References ast_iostream::ssl.

Referenced by ast_websocket_uri_cb(), handle_tcptls_connection(), and websocket_client_connect().

◆ ast_iostream_gets()

ssize_t ast_iostream_gets ( struct ast_iostream stream,
char *  buffer,
size_t  size 
)

Read a LF-terminated string from an iostream.

Parameters
streamA pointer to an iostream
bufferPointer to a buffer to store the read bytes.
sizeThe total size of buffer in bytes.
Returns
The number of bytes stored in buffer, excluding the null byte used to terminate the string. If the size of buffer (indicated by the caller with the size argument) is not sufficient to store the entire line it will be truncated to fit the available space. The contents of buffer will always be terminated with a null byte. In the case of an error, -1 will be returned and errno may be set indicating the error.

Definition at line 311 of file iostream.c.

312{
313 size_t remaining = size;
314 ssize_t accum_size = 0;
315 ssize_t len;
316 char *newline;
317
318 for (;;) {
319 /* Search for newline */
320 newline = memchr(stream->rbufhead, '\n', stream->rbuflen);
321 if (newline) {
322 len = newline - stream->rbufhead + 1;
323 if (len > remaining - 1) {
324 len = remaining - 1;
325 }
326 break;
327 }
328
329 /* Enough buffered line data to fill request buffer? */
330 if (stream->rbuflen >= remaining - 1) {
331 len = remaining - 1;
332 break;
333 }
334 if (stream->rbuflen) {
335 /* Put leftover buffered line data into request buffer */
336 memcpy(buffer + accum_size, stream->rbufhead, stream->rbuflen);
337 remaining -= stream->rbuflen;
338 accum_size += stream->rbuflen;
339 stream->rbuflen = 0;
340 }
341 stream->rbufhead = stream->rbuf;
342
343 len = iostream_read(stream, stream->rbuf, sizeof(stream->rbuf));
344 if (len == 0) {
345 /* Nothing new was read. Return whatever we have accumulated. */
346 break;
347 }
348 if (len < 0) {
349 if (accum_size) {
350 /* We have an accumulated buffer so return that instead. */
351 len = 0;
352 break;
353 }
354 return len;
355 }
356 stream->rbuflen += len;
357 }
358
359 /* Return read buffer string length */
360 memcpy(buffer + accum_size, stream->rbufhead, len);
361 buffer[accum_size + len] = 0;
362 stream->rbuflen -= len;
363 stream->rbufhead += len;
364
365 return accum_size + len;
366}
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
static ssize_t iostream_read(struct ast_iostream *stream, void *buf, size_t size)
Definition: iostream.c:166
int rbuflen
Definition: iostream.c:46
char * rbufhead
Definition: iostream.c:47
char rbuf[2048]
Definition: iostream.c:48

References iostream_read(), len(), ast_iostream::rbuf, ast_iostream::rbufhead, and ast_iostream::rbuflen.

Referenced by eivr_comm(), http_body_discard_chunk_trailer_headers(), http_body_get_chunk_length(), http_request_headers_get(), httpd_process_request(), and websocket_client_handshake_get_response().

◆ ast_iostream_nonblock()

void ast_iostream_nonblock ( struct ast_iostream stream)

Make an iostream non-blocking.

Parameters
streamA pointer to an iostream

Definition at line 104 of file iostream.c.

105{
106 ast_fd_set_flags(stream->fd, O_NONBLOCK);
107}
#define ast_fd_set_flags(fd, flags)
Set flags on the given file descriptor.
Definition: utils.h:1039

References ast_fd_set_flags, and ast_iostream::fd.

Referenced by ast_websocket_set_nonblock(), httpd_helper_thread(), and session_do().

◆ ast_iostream_printf()

ssize_t ast_iostream_printf ( struct ast_iostream stream,
const char *  format,
  ... 
)

Write a formatted string to an iostream.

Parameters
streamA pointer to an iostream
formatA format string, as documented by printf(3)
...Arguments for the provided format string
Returns
The number of bytes written, or -1 if an error occurs. Note that if -1 is returned, the number of bytes written to the iostream is unspecified.

Definition at line 502 of file iostream.c.

503{
504 char sbuf[512], *buf = sbuf;
505 int len, len2, ret = -1;
506 va_list va;
507
508 va_start(va, format);
509 len = vsnprintf(buf, sizeof(sbuf), format, va);
510 va_end(va);
511
512 if (len > sizeof(sbuf) - 1) {
513 /* Add one to the string length to accommodate the NULL byte */
514 size_t buf_len = len + 1;
515
516 buf = ast_malloc(buf_len);
517 if (!buf) {
518 return -1;
519 }
520 va_start(va, format);
521 len2 = vsnprintf(buf, buf_len, format, va);
522 va_end(va);
523 if (len2 != len) {
524 goto error;
525 }
526 }
527
528 if (ast_iostream_write(stream, buf, len) == len)
529 ret = len;
530
531error:
532 if (buf != sbuf) {
533 ast_free(buf);
534 }
535
536 return ret;
537}
#define ast_free(a)
Definition: astmm.h:180
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
ssize_t ast_iostream_write(struct ast_iostream *stream, const void *buffer, size_t size)
Write data to an iostream.
Definition: iostream.c:385
int error(const char *format,...)
Definition: utils/frame.c:999

References ast_free, ast_iostream_write(), ast_malloc, buf, error(), and len().

Referenced by ast_http_send(), ast_websocket_uri_cb(), and websocket_client_handshake().

◆ ast_iostream_read()

ssize_t ast_iostream_read ( struct ast_iostream stream,
void *  buffer,
size_t  count 
)

Read data from an iostream.

Parameters
streamA pointer to an iostream
bufferPointer to a buffer to store the read bytes.
countThe number of bytes to read.
Returns
Upon successful completion, returns a non-negative integer indicating the number of bytes actually read. Otherwise, returns -1 and may set errno to indicate the error.

Definition at line 284 of file iostream.c.

285{
286 if (!count) {
287 /* You asked for no data you got no data. */
288 return 0;
289 }
290
291 if (!stream || stream->fd == -1) {
292 errno = EBADF;
293 return -1;
294 }
295
296 /* Get any remains from the read buffer */
297 if (stream->rbuflen) {
298 size_t r = count;
299 if (r > stream->rbuflen) {
300 r = stream->rbuflen;
301 }
302 memcpy(buffer, stream->rbufhead, r);
303 stream->rbuflen -= r;
304 stream->rbufhead += r;
305 return r;
306 }
307
308 return iostream_read(stream, buffer, count);
309}

References errno, ast_iostream::fd, iostream_read(), ast_iostream::rbufhead, and ast_iostream::rbuflen.

Referenced by ast_iostream_discard(), get_input(), http_body_check_chunk_sync(), http_body_read_contents(), readmimefile(), and ws_safe_read().

◆ ast_iostream_set_exclusive_input()

void ast_iostream_set_exclusive_input ( struct ast_iostream stream,
int  exclusive_input 
)

Set the iostream if it can exclusively depend upon the set timeouts.

Parameters
streamA pointer to an iostream
exclusive_inputTRUE if stream can exclusively wait for fd input. Otherwise, the stream will not wait for fd input. It will wait while trying to send data.
Note
The stream timeouts still need to be set.

Definition at line 149 of file iostream.c.

150{
151 ast_assert(stream != NULL);
152
153 stream->exclusive_input = exclusive_input;
154}
int exclusive_input
Definition: iostream.c:45
#define ast_assert(a)
Definition: utils.h:739

References ast_assert, ast_iostream::exclusive_input, and NULL.

Referenced by ast_websocket_set_nonblock(), ast_websocket_uri_cb(), httpd_helper_thread(), and session_do().

◆ ast_iostream_set_sni_hostname()

int ast_iostream_set_sni_hostname ( struct ast_iostream stream,
const char *  sni_hostname 
)

Set the iostream's SNI hostname for TLS client connections.

Parameters
streamA pointer to an iostream
sni_hostnameThe hostname to use for SNI when in client mode
Return values
0if the hostname was set successfully.
-1if memory could not be allocated for the hostname.

Definition at line 156 of file iostream.c.

157{
158 ast_assert(stream != NULL);
159
160 ast_free(stream->sni_hostname);
161 stream->sni_hostname = ast_strdup(sni_hostname);
162
163 return stream->sni_hostname ? 0 : -1;
164}
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
char * sni_hostname
Definition: iostream.c:49

References ast_assert, ast_free, ast_strdup, NULL, and ast_iostream::sni_hostname.

Referenced by ast_tcptls_client_create().

◆ ast_iostream_set_timeout_disable()

void ast_iostream_set_timeout_disable ( struct ast_iostream stream)

Disable the iostream timeout timer.

Parameters
streamA pointer to an iostream

Definition at line 114 of file iostream.c.

115{
116 ast_assert(stream != NULL);
117
118 stream->timeout = -1;
119 stream->timeout_reset = -1;
120}

References ast_assert, NULL, ast_iostream::timeout, and ast_iostream::timeout_reset.

Referenced by ast_websocket_close(), ast_websocket_write(), send_string(), and session_do().

◆ ast_iostream_set_timeout_idle_inactivity()

void ast_iostream_set_timeout_idle_inactivity ( struct ast_iostream stream,
int  timeout,
int  timeout_reset 
)

Set the iostream inactivity & idle timeout timers.

Parameters
streamA pointer to an iostream
timeoutNumber of milliseconds to wait for initial data transfer with the peer.
timeout_resetNumber of milliseconds to wait for subsequent data transfer with the peer.

As an example, if you want to timeout a peer if they do not send an initial message within 5 seconds or if they do not send a message at least every 30 seconds, you would set timeout to 5000 and timeout_reset to 30000.

Note
Setting either of these timeouts to -1 will disable them.

Definition at line 131 of file iostream.c.

132{
133 ast_assert(stream != NULL);
134
135 stream->start.tv_sec = 0;
136 stream->timeout = timeout;
137 stream->timeout_reset = timeout_reset;
138}
struct timeval start
Definition: iostream.c:41

References ast_assert, NULL, ast_iostream::start, ast_iostream::timeout, and ast_iostream::timeout_reset.

Referenced by httpd_helper_thread().

◆ ast_iostream_set_timeout_inactivity()

void ast_iostream_set_timeout_inactivity ( struct ast_iostream stream,
int  timeout 
)

Set the iostream inactivity timeout timer.

Parameters
streamA pointer to an iostream
timeoutNumber of milliseconds to wait for data transfer with the peer.

This is basically how much time we are willing to spend in an I/O call before we declare the peer unresponsive.

Note
Setting timeout to -1 disables the timeout.
Setting this timeout replaces the I/O sequence timeout timer.

Definition at line 122 of file iostream.c.

123{
124 ast_assert(stream != NULL);
125
126 stream->start.tv_sec = 0;
127 stream->timeout = timeout;
128 stream->timeout_reset = timeout;
129}

References ast_assert, NULL, ast_iostream::start, ast_iostream::timeout, and ast_iostream::timeout_reset.

Referenced by ast_websocket_close(), and send_string().

◆ ast_iostream_set_timeout_sequence()

void ast_iostream_set_timeout_sequence ( struct ast_iostream stream,
struct timeval  start,
int  timeout 
)

Set the iostream I/O sequence timeout timer.

Parameters
streamA pointer to an iostream
startTime the I/O sequence timer starts.
timeoutNumber of milliseconds from the start time before timeout.

This is how much time are we willing to allow the peer to complete an operation that can take several I/O calls. The main use is as an authentication timer with us.

Note
Setting timeout to -1 disables the timeout.
Setting this timeout replaces the inactivity timeout timer.

Definition at line 140 of file iostream.c.

141{
142 ast_assert(stream != NULL);
143
144 stream->start = start;
145 stream->timeout = timeout;
146 stream->timeout_reset = timeout;
147}

References ast_assert, NULL, ast_iostream::start, ast_iostream::timeout, and ast_iostream::timeout_reset.

Referenced by ast_websocket_write(), and session_do().

◆ ast_iostream_start_tls()

int ast_iostream_start_tls ( struct ast_iostream **  stream,
SSL_CTX ctx,
int  client 
)

Begin TLS on an iostream.

Parameters
streamA pointer to an iostream pointer
ctxA pointer to an SSL_CTX which will be passed to SSL_new()
clientNon-zero to indicate that we are the client, zero to indicate that we are the server.
Return values
0success
-1failure
Note
The iostream that is passed in stream may be replaced with a different one before this function returns.
On failure, errno may be set providing additional information on why the failure occurred.

Definition at line 627 of file iostream.c.

628{
629#ifdef DO_SSL
630 struct ast_iostream *stream = *pstream;
631 int (*ssl_setup)(SSL *) = client ? SSL_connect : SSL_accept;
632 int res;
633
634 stream->ssl = SSL_new(ssl_ctx);
635 if (!stream->ssl) {
636 ast_log(LOG_ERROR, "Unable to create new SSL connection\n");
637 errno = ENOMEM;
638 return -1;
639 }
640
641 /*
642 * This function takes struct ast_iostream **, so it can chain
643 * SSL over any ast_iostream. For now we assume it's a file descriptor.
644 * But later this should instead use BIO wrapper to tie SSL to another
645 * ast_iostream.
646 */
647 SSL_set_fd(stream->ssl, stream->fd);
648
649 if (client && !ast_strlen_zero(stream->sni_hostname)) {
650 if (!SSL_set_tlsext_host_name(stream->ssl, stream->sni_hostname)) {
651 ast_log(LOG_ERROR, "Unable to set SNI hostname '%s'\n",
652 stream->sni_hostname);
653 errno = EIO;
654 return -1;
655 }
656 }
657
658 res = ssl_setup(stream->ssl);
659 if (res <= 0) {
660 int sslerr = SSL_get_error(stream->ssl, res);
661 char err[256];
662
663 ast_log(LOG_ERROR, "Problem setting up ssl connection: %s, %s\n",
664 ERR_error_string(sslerr, err), ssl_error_to_string(sslerr, res));
665 errno = EIO;
666 return -1;
667 }
668
669 return 0;
670#else
671 ast_log(LOG_ERROR, "SSL not enabled in this build\n");
672 errno = ENOTSUP;
673 return -1;
674#endif
675}
struct ssl_st SSL
Definition: iostream.h:37
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65

References ast_log, ast_strlen_zero(), errno, ast_iostream::fd, LOG_ERROR, ast_iostream::sni_hostname, and ast_iostream::ssl.

Referenced by handle_tcptls_connection().

◆ ast_iostream_wait_for_input()

int ast_iostream_wait_for_input ( struct ast_iostream stream,
int  timeout 
)

Wait for input on the iostream's file descriptor.

Since
16.8.0
17.2.0
Parameters
streamA pointer to an iostream
timeoutthe number of milliseconds to wait
Return values
-1if error occurred
0if the timeout expired
1if the stream is ready for reading

Definition at line 90 of file iostream.c.

91{
92#if defined(DO_SSL)
93 /* Because SSL is read in blocks, it's possible that the last time we read we
94 got more than we asked for and it is now buffered inside OpenSSL. If that
95 is the case, calling ast_wait_for_input() will block until the fd is ready
96 for reading again, which might never happen. */
97 if (stream->ssl && SSL_pending(stream->ssl)) {
98 return 1;
99 }
100#endif
101 return ast_wait_for_input(stream->fd, timeout);
102}
int ast_wait_for_input(int fd, int ms)
Definition: utils.c:1698

References ast_wait_for_input(), ast_iostream::fd, and ast_iostream::ssl.

Referenced by ast_websocket_wait_for_input(), and ws_safe_read().

◆ ast_iostream_write()

ssize_t ast_iostream_write ( struct ast_iostream stream,
const void *  buffer,
size_t  count 
)

Write data to an iostream.

Parameters
streamA pointer to an iostream
bufferPointer to a buffer from which to read bytes.
countThe number of bytes from buffer to write.
Returns
Upon successful completion, returns the number of bytes actually written to the iostream. This number shall never be greater than count. Otherwise, returns -1 and may set errno to indicate the error.

Definition at line 385 of file iostream.c.

386{
387 struct timeval start;
388 int ms;
389 int res;
390 int written;
391 int remaining;
392
393 if (!size) {
394 /* You asked to write no data you wrote no data. */
395 return 0;
396 }
397
398 if (!stream || stream->fd == -1) {
399 errno = EBADF;
400 return -1;
401 }
402
403 if (stream->start.tv_sec) {
404 start = stream->start;
405 } else {
406 start = ast_tvnow();
407 }
408
409#if defined(DO_SSL)
410 if (stream->ssl) {
411 written = 0;
412 remaining = size;
413 for (;;) {
414 int sslerr;
415 char err[256];
416 res = SSL_write(stream->ssl, buffer + written, remaining);
417 if (res == remaining) {
418 /* Everything was written. */
419 return size;
420 }
421 if (0 < res) {
422 /* Successfully wrote part of the buffer. Try to write the rest. */
423 written += res;
424 remaining -= res;
425 continue;
426 }
427 sslerr = SSL_get_error(stream->ssl, res);
428 switch (sslerr) {
429 case SSL_ERROR_ZERO_RETURN:
430 ast_debug(1, "TLS clean shutdown alert writing data\n");
431 if (written) {
432 /* Report partial write. */
433 return written;
434 }
435 errno = EBADF;
436 return -1;
437 case SSL_ERROR_WANT_READ:
438 ms = ast_remaining_ms(start, stream->timeout);
439 if (!ms) {
440 /* Report partial write. */
441 ast_debug(1, "TLS timeout writing data (want read)\n");
442 return written;
443 }
444 ast_wait_for_input(stream->fd, ms);
445 break;
446 case SSL_ERROR_WANT_WRITE:
447 ms = ast_remaining_ms(start, stream->timeout);
448 if (!ms) {
449 /* Report partial write. */
450 ast_debug(1, "TLS timeout writing data (want write)\n");
451 return written;
452 }
453 ast_wait_for_output(stream->fd, ms);
454 break;
455 default:
456 /* Undecoded SSL or transport error. */
457 ast_debug(1, "TLS transport or SSL error writing data: %s, %s\n", ERR_error_string(sslerr, err),
458 ssl_error_to_string(sslerr, res));
459 if (written) {
460 /* Report partial write. */
461 return written;
462 }
463 errno = EBADF;
464 return -1;
465 }
466 }
467 }
468#endif /* defined(DO_SSL) */
469
470 written = 0;
471 remaining = size;
472 for (;;) {
473 res = write(stream->fd, buffer + written, remaining);
474 if (res == remaining) {
475 /* Yay everything was written. */
476 return size;
477 }
478 if (0 < res) {
479 /* Successfully wrote part of the buffer. Try to write the rest. */
480 written += res;
481 remaining -= res;
482 continue;
483 }
484 if (errno != EINTR && errno != EAGAIN) {
485 /* Not a retryable error. */
486 ast_debug(1, "TCP socket error writing: %s\n", strerror(errno));
487 if (written) {
488 return written;
489 }
490 return -1;
491 }
492 ms = ast_remaining_ms(start, stream->timeout);
493 if (!ms) {
494 /* Report partial write. */
495 ast_debug(1, "TCP timeout writing data\n");
496 return written;
497 }
498 ast_wait_for_output(stream->fd, ms);
499 }
500}
#define ast_debug(level,...)
Log a DEBUG message.
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition: utils.c:2281
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
int ast_wait_for_output(int fd, int ms)
Definition: utils.c:1708

References ast_debug, ast_remaining_ms(), ast_tvnow(), ast_wait_for_input(), ast_wait_for_output(), errno, ast_iostream::fd, ast_iostream::ssl, ast_iostream::start, and ast_iostream::timeout.

Referenced by ast_http_send(), ast_iostream_printf(), ast_websocket_close(), ast_websocket_write(), process_output(), send_eivr_event(), and send_string().