static size_t o_stream_lzma_get_buffer_avail_size(const struct ostream_private *stream) { /* FIXME: not correct - this is counting compressed size, which may be too larger than uncompressed size in some situations. Fixing would require some kind of additional buffering. */ return o_stream_get_buffer_avail_size(stream->parent); }
static bool openssl_iostream_bio_output(struct ssl_iostream *ssl_io) { size_t bytes, max_bytes; ssize_t sent; unsigned char buffer[IO_BLOCK_SIZE]; bool bytes_sent = FALSE; int ret; o_stream_cork(ssl_io->plain_output); while ((bytes = BIO_ctrl_pending(ssl_io->bio_ext)) > 0) { /* bytes contains how many SSL encrypted bytes we should be sending out */ max_bytes = o_stream_get_buffer_avail_size(ssl_io->plain_output); if (bytes > max_bytes) { if (max_bytes == 0) { /* wait until output buffer clears */ o_stream_set_flush_pending(ssl_io->plain_output, TRUE); break; } bytes = max_bytes; } if (bytes > sizeof(buffer)) bytes = sizeof(buffer); /* BIO_read() is guaranteed to return all the bytes that BIO_ctrl_pending() returned */ ret = BIO_read(ssl_io->bio_ext, buffer, bytes); i_assert(ret == (int)bytes); /* we limited number of read bytes to plain_output's available size. this send() is guaranteed to either fully succeed or completely fail due to some error. */ sent = o_stream_send(ssl_io->plain_output, buffer, bytes); if (sent < 0) { i_assert(ssl_io->plain_output->closed || ssl_io->plain_output->stream_errno != 0); i_free(ssl_io->plain_stream_errstr); ssl_io->plain_stream_errstr = i_strdup(o_stream_get_error(ssl_io->plain_output)); ssl_io->plain_stream_errno = ssl_io->plain_output->stream_errno; ssl_io->closed = TRUE; break; } i_assert(sent == (ssize_t)bytes); bytes_sent = TRUE; } o_stream_uncork(ssl_io->plain_output); return bytes_sent; }
static ssize_t http_transfer_chunked_ostream_sendv(struct ostream_private *stream, const struct const_iovec *iov, unsigned int iov_count) { struct http_transfer_chunked_ostream *tcstream = (struct http_transfer_chunked_ostream *)stream; struct const_iovec *iov_new; unsigned int iov_count_new, i; size_t bytes = 0, max_bytes; ssize_t ret; const char *prefix; i_assert(stream->parent->real_stream->max_buffer_size >= MIN_CHUNK_SIZE_WITH_EXTRA); if ((ret=o_stream_flush(stream->parent)) <= 0) { /* error / we still couldn't flush existing data to parent stream. */ o_stream_copy_error_from_parent(stream); return ret; } /* check how many bytes we want to send */ bytes = 0; for (i = 0; i < iov_count; i++) { bytes += iov[i].iov_len; } /* check if we have room to send at least one byte */ max_bytes = o_stream_get_buffer_avail_size(stream->parent); max_bytes = _max_chunk_size(max_bytes); if (max_bytes < MIN_CHUNK_SIZE_WITH_EXTRA) return 0; tcstream->chunk_size = bytes > max_bytes ? max_bytes : bytes; /* determine what to send */ bytes = tcstream->chunk_size; iov_count_new = 1; for (i = 0; i < iov_count && bytes > 0; i++) { if (bytes <= iov[i].iov_len) break; bytes -= iov[i].iov_len; iov_count_new++; } /* create new iovec */ prefix = t_strdup_printf("%llx\r\n", (unsigned long long)tcstream->chunk_size); iov_count = iov_count_new + 2; iov_new = t_malloc(sizeof(struct const_iovec) * iov_count); iov_new[0].iov_base = prefix; iov_new[0].iov_len = strlen(prefix); memcpy(&iov_new[1], iov, sizeof(struct const_iovec) * iov_count_new); iov_new[iov_count-2].iov_len = bytes; iov_new[iov_count-1].iov_base = "\r\n"; iov_new[iov_count-1].iov_len = 2; /* send */ if ((ret=o_stream_sendv(stream->parent, iov_new, iov_count)) <= 0) { i_assert(ret < 0); o_stream_copy_error_from_parent(stream); return -1; } /* all must be sent */ i_assert((size_t)ret == (tcstream->chunk_size + iov_new[0].iov_len + iov_new[iov_count-1].iov_len)); stream->ostream.offset += tcstream->chunk_size; return tcstream->chunk_size; }