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; }
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; }
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); }
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; }
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; }
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); }
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; }
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; }
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"); }
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; }
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; }
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; }
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; }