예제 #1
0
파일: ostream-cmp.c 프로젝트: Raffprta/core
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;
}
예제 #2
0
static ssize_t
o_stream_mail_filter_sendv(struct ostream_private *stream,
			   const struct const_iovec *iov,
			   unsigned int iov_count)
{
	struct mail_filter_ostream *mstream =
		(struct mail_filter_ostream *)stream;
	ssize_t ret;

	if (mstream->ext_out == NULL) {
		/* connect failed */
		mstream->ostream.ostream.stream_errno = EIO;
		return -1;
	}

	/* send the data to the filter */
	ret = o_stream_sendv(mstream->ext_out, iov, iov_count);
	if (ret < 0) {
		stream->ostream.stream_errno =
			mstream->ext_out->stream_errno;
		return -1;
	}
	stream->ostream.offset += ret;
	return ret;
}
예제 #3
0
파일: ostream.c 프로젝트: LTD-Beget/dovecot
off_t io_stream_copy(struct ostream *outstream, struct istream *instream)
{
	uoff_t start_offset;
	struct const_iovec iov;
	const unsigned char *data;
	ssize_t ret;

	start_offset = instream->v_offset;
	do {
		(void)i_stream_read_data(instream, &data, &iov.iov_len, 0);
		if (iov.iov_len == 0) {
			/* all sent */
			if (instream->stream_errno != 0)
				return -1;
			break;
		}

		iov.iov_base = data;
		ret = o_stream_sendv(outstream, &iov, 1);
		if (ret <= 0) {
			if (ret == 0)
				break;
			return -1;
		}
		i_stream_skip(instream, ret);
	} while ((size_t)ret == iov.iov_len);

	return (off_t)(instream->v_offset - start_offset);
}
예제 #4
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;
}
예제 #5
0
파일: ostream.c 프로젝트: LTD-Beget/dovecot
void o_stream_nsendv(struct ostream *stream, const struct const_iovec *iov,
		     unsigned int iov_count)
{
	if (unlikely(stream->closed || stream->stream_errno != 0))
		return;
	(void)o_stream_sendv(stream, iov, iov_count);
	stream->real_stream->last_errors_not_checked = TRUE;
}
예제 #6
0
파일: ostream.c 프로젝트: LTD-Beget/dovecot
ssize_t o_stream_send(struct ostream *stream, const void *data, size_t size)
{
	struct const_iovec iov;

	memset(&iov, 0, sizeof(iov));
	iov.iov_base = data;
	iov.iov_len = size;

 	return o_stream_sendv(stream, &iov, 1);
}
예제 #7
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;
}
예제 #8
0
파일: ostream.c 프로젝트: LTD-Beget/dovecot
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;
}
예제 #9
0
void auth_client_request_continue(struct auth_client_request *request,
                                  const char *data_base64)
{
	struct const_iovec iov[3];
	const char *prefix;

	prefix = t_strdup_printf("CONT\t%u\t", request->id);

	iov[0].iov_base = prefix;
	iov[0].iov_len = strlen(prefix);
	iov[1].iov_base = data_base64;
	iov[1].iov_len = strlen(data_base64);
	iov[2].iov_base = "\n";
	iov[2].iov_len = 1;

	if (o_stream_sendv(request->conn->output, iov, 3) < 0)
		i_error("Error sending continue request to auth server: %m");
}
예제 #10
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;
}
예제 #11
0
int client_send_line_next(struct client *client, const char *data)
{
	struct const_iovec iov[2];

	if (client->output->closed)
		return -1;

	iov[0].iov_base = data;
	iov[0].iov_len = strlen(data);
	iov[1].iov_base = "\r\n";
	iov[1].iov_len = 2;

	if (o_stream_sendv(client->output, iov, 2) < 0)
		return -1;
	client->last_output = ioloop_time;

	if (o_stream_get_buffer_used_size(client->output) >=
	    CLIENT_OUTPUT_OPTIMAL_SIZE) {
		/* buffer full, try flushing */
		return o_stream_flush(client->output);
	}
	return 1;
}
예제 #12
0
static int http_client_request_send_real(struct http_client_request *req,
					 bool pipelined, const char **error_r)
{
	const struct http_client_settings *set = &req->client->set;
	struct http_client_connection *conn = req->conn;
	struct ostream *output = conn->conn.output;
	string_t *rtext = t_str_new(256);
	struct const_iovec iov[3];
	int ret = 0;

	i_assert(!req->conn->output_locked);
	i_assert(req->payload_output == NULL);

	/* create request line */
	str_append(rtext, req->method);
	str_append(rtext, " ");
	str_append(rtext, req->target);
	str_append(rtext, " HTTP/1.1\r\n");

	/* create special headers implicitly if not set explicitly using
	   http_client_request_add_header() */
	if (!req->have_hdr_host) {
		str_append(rtext, "Host: ");
		str_append(rtext, req->authority);
		str_append(rtext, "\r\n");
	}
	if (!req->have_hdr_date) {
		str_append(rtext, "Date: ");
		str_append(rtext, http_date_create(req->date));
		str_append(rtext, "\r\n");
	}
	if (!req->have_hdr_authorization &&
		req->username != NULL && req->password != NULL) {
		struct http_auth_credentials auth_creds;

		http_auth_basic_credentials_init(&auth_creds,
			req->username, req->password);

		str_append(rtext, "Authorization: ");
		http_auth_create_credentials(rtext, &auth_creds);
		str_append(rtext, "\r\n");
	}
	if (http_client_request_to_proxy(req) &&
		set->proxy_username != NULL && set->proxy_password != NULL) {
		struct http_auth_credentials auth_creds;

		http_auth_basic_credentials_init(&auth_creds,
			set->proxy_username, set->proxy_password);

		str_append(rtext, "Proxy-Authorization: ");
		http_auth_create_credentials(rtext, &auth_creds);
		str_append(rtext, "\r\n");
	}
	if (!req->have_hdr_user_agent && req->client->set.user_agent != NULL) {
		str_printfa(rtext, "User-Agent: %s\r\n",
			    req->client->set.user_agent);
	}
	if (!req->have_hdr_expect && req->payload_sync) {
		str_append(rtext, "Expect: 100-continue\r\n");
	}
	if (req->payload_input != NULL) {
		if (req->payload_chunked) {
			// FIXME: can't do this for a HTTP/1.0 server
			if (!req->have_hdr_body_spec)
				str_append(rtext, "Transfer-Encoding: chunked\r\n");
			req->payload_output =
				http_transfer_chunked_ostream_create(output);
		} else {
			/* send Content-Length if we have specified a payload,
				 even if it's 0 bytes. */
			if (!req->have_hdr_body_spec) {
				str_printfa(rtext, "Content-Length: %"PRIuUOFF_T"\r\n",
					req->payload_size);
			}
			req->payload_output = output;
			o_stream_ref(output);
		}
	}
	if (!req->have_hdr_connection &&
		!http_client_request_to_proxy(req)) {
		/* https://tools.ietf.org/html/rfc2068
		     Section 19.7.1:

		   A client MUST NOT send the Keep-Alive connection token to a proxy
		   server as HTTP/1.0 proxy servers do not obey the rules of HTTP/1.1
		   for parsing the Connection header field.
		 */
		str_append(rtext, "Connection: Keep-Alive\r\n");
	}

	/* request line + implicit headers */
	iov[0].iov_base = str_data(rtext);
	iov[0].iov_len = str_len(rtext);	
	/* explicit headers */
	if (req->headers != NULL) {
		iov[1].iov_base = str_data(req->headers);
		iov[1].iov_len = str_len(req->headers);
	} else {
		iov[1].iov_base = "";
		iov[1].iov_len = 0;
	}
	/* end of header */
	iov[2].iov_base = "\r\n";
	iov[2].iov_len = 2;

	req->state = HTTP_REQUEST_STATE_PAYLOAD_OUT;
	req->sent_time = ioloop_timeval;
	o_stream_cork(output);
	if (o_stream_sendv(output, iov, N_ELEMENTS(iov)) < 0) {
		*error_r = t_strdup_printf("write(%s) failed: %s",
					   o_stream_get_name(output),
					   o_stream_get_error(output));
		ret = -1;
	} else {
		http_client_request_debug(req, "Sent header");

		if (req->payload_output != NULL) {
			if (!req->payload_sync) {
				if (http_client_request_send_more
					(req, pipelined, error_r) < 0)
					ret = -1;
			} else {
				http_client_request_debug(req, "Waiting for 100-continue");
				conn->output_locked = TRUE;
			}
		} else {
			req->state = HTTP_REQUEST_STATE_WAITING;
			if (!pipelined)
				http_client_connection_start_request_timeout(req->conn);
			conn->output_locked = FALSE;
		}
		if (ret >= 0 && o_stream_flush(output) < 0) {
			*error_r = t_strdup_printf("flush(%s) failed: %s",
   	                   o_stream_get_name(output),
           	           o_stream_get_error(output));
			ret = -1;
		}
	}
	o_stream_uncork(output);
	return ret;
}
예제 #13
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;
}