Ejemplo n.º 1
0
static int o_stream_mail_filter_flush(struct ostream_private *stream)
{
	struct mail_filter_ostream *mstream =
		(struct mail_filter_ostream *)stream;
	const unsigned char *data;
	size_t size;
	ssize_t ret;

	if (mstream->ext_out == NULL) {
		/* connect failed */
		return -1;
	}
	if (mstream->flushed)
		return 0;

	if (shutdown(mstream->fd, SHUT_WR) < 0)
		i_error("ext-filter: shutdown() failed: %m");

	while ((ret = i_stream_read_data(mstream->ext_in, &data, &size, 0)) > 0) {
		ret = o_stream_send(stream->parent, data, size);
		if (ret != (ssize_t)size) {
			i_assert(ret < 0);
			o_stream_copy_error_from_parent(stream);
			return -1;
		}
		i_stream_skip(mstream->ext_in, size);
	}
	i_assert(ret == -1);

	if (!i_stream_have_bytes_left(mstream->ext_in) &&
	    mstream->ext_in->v_offset == 0) {
		/* EOF without any input -> assume the script is repoting
		   failure. pretty ugly way, but currently there's no error
		   reporting channel. */
		stream->ostream.stream_errno = EIO;
		return -1;
	}
	if (mstream->ext_in->stream_errno != 0) {
		stream->ostream.stream_errno = mstream->ext_in->stream_errno;
		return -1;
	}

	ret = o_stream_flush(stream->parent);
	if (ret < 0)
		o_stream_copy_error_from_parent(stream);
	else
		mstream->flushed = TRUE;
	return ret;
}
Ejemplo n.º 2
0
static ssize_t
o_stream_hash_sendv(struct ostream_private *stream,
		    const struct const_iovec *iov, unsigned int iov_count)
{
	struct hash_ostream *hstream = (struct hash_ostream *)stream;
	unsigned int i;
	size_t bytes_left, block_len;
	ssize_t ret;

	if ((ret = o_stream_sendv(stream->parent, iov, iov_count)) < 0) {
		o_stream_copy_error_from_parent(stream);
		return -1;
	}
	if (ret > 0) {
		bytes_left = ret;
		for (i = 0; i < iov_count && bytes_left > 0; i++) {
			block_len = iov[i].iov_len <= bytes_left ?
				iov[i].iov_len : bytes_left;
			hstream->method->loop(hstream->hash_context,
					      iov[i].iov_base, block_len);
			bytes_left -= block_len;
		}
	}

	stream->ostream.offset += ret;
	return ret;
}
Ejemplo n.º 3
0
static ssize_t
o_stream_cmp_sendv(struct ostream_private *stream,
		   const struct const_iovec *iov, unsigned int iov_count)
{
	struct cmp_ostream *cstream = (struct cmp_ostream *)stream;
	unsigned int i;
	ssize_t ret;

	if (cstream->equals) {
		for (i = 0; i < iov_count; i++) {
			if (!stream_cmp_block(cstream->input, iov[i].iov_base,
					      iov[i].iov_len)) {
				cstream->equals = FALSE;
				break;
			}
		}
	}

	if ((ret = o_stream_sendv(stream->parent, iov, iov_count)) < 0) {
		o_stream_copy_error_from_parent(stream);
		return -1;
	}

	stream->ostream.offset += ret;
	return ret;
}
Ejemplo n.º 4
0
static int o_stream_default_flush(struct ostream_private *_stream)
{
	int ret;

	if (_stream->parent == NULL)
		return 1;

	if ((ret = o_stream_flush(_stream->parent)) < 0)
		o_stream_copy_error_from_parent(_stream);
	return ret;
}
Ejemplo n.º 5
0
static ssize_t
o_stream_failure_at_sendv(struct ostream_private *stream,
			  const struct const_iovec *iov, unsigned int iov_count)
{
	struct failure_at_ostream *fstream =
		(struct failure_at_ostream *)stream;
	unsigned int i;
	struct const_iovec *iov_dup;
	unsigned int iov_dup_count;
	uoff_t bytes_until_failure, blocking_bytes_count = 0;
	ssize_t ret;

	if (stream->ostream.blocking) {
		/* blocking ostream must return either a full success or a
		   failure. if the current write would go past failure_offset,
		   return a failure now before writing anything. */
		for (i = 0; i < iov_count; i++)
			blocking_bytes_count += iov[i].iov_len;
		if (blocking_bytes_count > 0) {
			/* if we're exactly at the failure offset after this
			   write, fail it only on the next write. */
			blocking_bytes_count--;
		}
	}

	if (fstream->failure_offset <= stream->ostream.offset + blocking_bytes_count) {
		io_stream_set_error(&stream->iostream, "%s",
				    fstream->error_string);
		stream->ostream.stream_errno = errno = EIO;
		fstream->failed = TRUE;
		return -1;
	}
	bytes_until_failure = fstream->failure_offset - stream->ostream.offset;

	iov_dup = i_new(struct const_iovec, iov_count);
	iov_dup_count = iov_count;
	for (i = 0; i < iov_count; i++) {
		iov_dup[i] = iov[i];
		if (iov_dup[i].iov_len >= bytes_until_failure) {
			iov_dup[i].iov_len = bytes_until_failure;
			iov_dup_count = i+1;
			break;
		}
	}
	ret = o_stream_sendv(stream->parent, iov_dup, iov_dup_count);
	i_free(iov_dup);

	if (ret < 0) {
		o_stream_copy_error_from_parent(stream);
		return -1;
	}
	stream->ostream.offset += ret;
	return ret;
}
Ejemplo n.º 6
0
static int
o_stream_escaped_flush(struct ostream_private *stream)
{
	struct escaped_ostream *estream = (struct escaped_ostream *)stream;
	int ret;

	if ((ret = o_stream_escaped_send_outbuf(estream)) <= 0)
		return ret;
	if ((ret = o_stream_flush(stream->parent)) < 0)
		o_stream_copy_error_from_parent(stream);
	return ret;
}
Ejemplo n.º 7
0
static int o_stream_lzma_flush(struct ostream_private *stream)
{
	struct lzma_ostream *zstream = (struct lzma_ostream *)stream;
	int ret;

	if (o_stream_lzma_send_flush(zstream) < 0)
		return -1;

	ret = o_stream_flush(stream->parent);
	if (ret < 0)
		o_stream_copy_error_from_parent(stream);
	return ret;
}
Ejemplo n.º 8
0
static ssize_t
o_stream_default_sendv(struct ostream_private *stream,
		       const struct const_iovec *iov, unsigned int iov_count)
{
	ssize_t ret;

	if ((ret = o_stream_sendv(stream->parent, iov, iov_count)) < 0) {
		o_stream_copy_error_from_parent(stream);
		return -1;
	}
	stream->ostream.offset += ret;
	return ret;
}
Ejemplo n.º 9
0
static int o_stream_zlib_send_gz_header(struct zlib_ostream *zstream)
{
	ssize_t ret;

	ret = o_stream_send(zstream->ostream.parent, zstream->gz_header,
			    sizeof(zstream->gz_header));
	if ((size_t)ret != sizeof(zstream->gz_header)) {
		o_stream_copy_error_from_parent(&zstream->ostream);
		return -1;
	}
	zstream->header_sent = TRUE;
	return 0;
}
Ejemplo n.º 10
0
static int o_stream_zlib_send_gz_trailer(struct zlib_ostream *zstream)
{
	struct ostream *output = zstream->ostream.parent;

	if (!zstream->gz)
		return 0;

	if (o_stream_zlib_lsb_uint32(output, zstream->crc) < 0 ||
	    o_stream_zlib_lsb_uint32(output, zstream->bytes32) < 0) {
		o_stream_copy_error_from_parent(&zstream->ostream);
		return -1;
	}
	return 0;
}
Ejemplo n.º 11
0
int o_stream_flush_parent_if_needed(struct ostream_private *_stream)
{
	if (o_stream_get_buffer_used_size(_stream->parent) >= IO_BLOCK_SIZE) {
		/* we already have quite a lot of data in parent stream.
		   unless we can flush it, don't add any more to it or we
		   could keep wasting memory by just increasing the buffer
		   size all the time. */
		if (o_stream_flush(_stream->parent) < 0) {
			o_stream_copy_error_from_parent(_stream);
			return -1;
		}
		if (o_stream_get_buffer_used_size(_stream->parent) >= IO_BLOCK_SIZE)
			return 0;
	}
	return 1;
}
Ejemplo n.º 12
0
static
int o_stream_encrypt_send(struct encrypt_ostream *stream,
			  const unsigned char *data, size_t size)
{
	ssize_t ec;

	ec = o_stream_send(stream->ostream.parent, data, size);
	if (ec == (ssize_t)size)
		return 0;
	else if (ec < 0) {
		o_stream_copy_error_from_parent(&stream->ostream);
		return -1;
	} else {
		io_stream_set_error(&stream->ostream.iostream,
			"ostream-encrypt: Unexpectedly short write to parent stream");
		stream->ostream.ostream.stream_errno = EINVAL;
		return -1;
	}
}
Ejemplo n.º 13
0
static ssize_t
o_stream_failure_at_sendv(struct ostream_private *stream,
			  const struct const_iovec *iov, unsigned int iov_count)
{
	struct failure_at_ostream *fstream =
		(struct failure_at_ostream *)stream;
	unsigned int i;
	struct const_iovec *iov_dup;
	unsigned int iov_dup_count;
	uoff_t bytes_until_failure;
	ssize_t ret;

	if (fstream->failure_offset <= stream->ostream.offset) {
		io_stream_set_error(&stream->iostream, "%s",
				    fstream->error_string);
		stream->ostream.stream_errno = errno = EIO;
		fstream->failed = TRUE;
		return -1;
	}
	bytes_until_failure = fstream->failure_offset - stream->ostream.offset;

	iov_dup = i_new(struct const_iovec, iov_count);
	iov_dup_count = iov_count;
	for (i = 0; i < iov_count; i++) {
		iov_dup[i] = iov[i];
		if (iov_dup[i].iov_len >= bytes_until_failure) {
			iov_dup[i].iov_len = bytes_until_failure;
			iov_dup_count = i+1;
			break;
		}
	}
	ret = o_stream_sendv(stream->parent, iov_dup, iov_dup_count);
	i_free(iov_dup);

	if (ret < 0) {
		o_stream_copy_error_from_parent(stream);
		return -1;
	}
	stream->ostream.offset += ret;
	return ret;
}
Ejemplo n.º 14
0
static ssize_t
o_stream_escaped_send_outbuf(struct escaped_ostream *estream)
{
	ssize_t ret;

	if (estream->flushed)
		return 1; /* nothing to send */
	ret = o_stream_send(estream->ostream.parent, str_data(estream->buf), str_len(estream->buf));
	if (ret < 0) {
		o_stream_copy_error_from_parent(&estream->ostream);
		return -1;
	}
	if ((size_t)ret != str_len(estream->buf)) {
		/* move data */
		str_delete(estream->buf, 0, ret);
		return 0;
	}
	str_truncate(estream->buf, 0);
	estream->flushed = TRUE;
	return 1;
}
Ejemplo n.º 15
0
static int o_stream_zlib_send_outbuf(struct lzma_ostream *zstream)
{
	ssize_t ret;
	size_t size;

	if (zstream->outbuf_used == 0)
		return 1;

	size = zstream->outbuf_used - zstream->outbuf_offset;
	i_assert(size > 0);
	ret = o_stream_send(zstream->ostream.parent,
			    zstream->outbuf + zstream->outbuf_offset, size);
	if (ret < 0) {
		o_stream_copy_error_from_parent(&zstream->ostream);
		return -1;
	}
	if ((size_t)ret != size) {
		zstream->outbuf_offset += ret;
		return 0;
	}
	zstream->outbuf_offset = 0;
	zstream->outbuf_used = 0;
	return 1;
}
Ejemplo n.º 16
0
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;
}