void http_client_wait(struct http_client *client) { struct ioloop *prev_ioloop = current_ioloop; i_assert(client->ioloop == NULL); if (client->requests_count == 0) return; client->ioloop = io_loop_create(); http_client_switch_ioloop(client); if (client->set.dns_client != NULL) dns_client_switch_ioloop(client->set.dns_client); /* either we're waiting for network I/O or we're getting out of a callback using timeout_add_short(0) */ i_assert(io_loop_have_ios(client->ioloop) || io_loop_have_immediate_timeouts(client->ioloop)); do { http_client_debug(client, "Waiting for %d requests to finish", client->requests_count); io_loop_run(client->ioloop); } while (client->requests_count > 0); http_client_debug(client, "All requests finished"); io_loop_set_current(prev_ioloop); http_client_switch_ioloop(client); if (client->set.dns_client != NULL) dns_client_switch_ioloop(client->set.dns_client); io_loop_set_current(client->ioloop); io_loop_destroy(&client->ioloop); }
static void imapc_mailbox_idle_notify(struct imapc_mailbox *mbox) { struct ioloop *old_ioloop = current_ioloop; if (mbox->box.notify_callback != NULL && mbox->to_idle_delay == NULL) { io_loop_set_current(mbox->storage->root_ioloop); mbox->to_idle_delay = timeout_add_short(NOTIFY_DELAY_MSECS, imapc_mailbox_idle_timeout, mbox); io_loop_set_current(old_ioloop); } }
void pop3c_client_run(struct pop3c_client *client) { struct ioloop *ioloop, *prev_ioloop = current_ioloop; bool timeout_added = FALSE, failed = FALSE; i_assert(client->fd != -1 || client->state == POP3C_CLIENT_STATE_CONNECTING); ioloop = io_loop_create(); pop3c_client_ioloop_changed(client); if (client->ip.family == 0) { /* we're connecting, start DNS lookup after our ioloop is created */ struct dns_lookup_settings dns_set; i_assert(client->state == POP3C_CLIENT_STATE_CONNECTING); memset(&dns_set, 0, sizeof(dns_set)); dns_set.dns_client_socket_path = client->set.dns_client_socket_path; dns_set.timeout_msecs = POP3C_DNS_LOOKUP_TIMEOUT_MSECS; if (dns_lookup(client->set.host, &dns_set, pop3c_dns_callback, client, &client->dns_lookup) < 0) failed = TRUE; } else if (client->to == NULL) { client->to = timeout_add(POP3C_COMMAND_TIMEOUT_MSECS, pop3c_client_timeout, client); timeout_added = TRUE; } if (!failed) { client->running = TRUE; io_loop_run(ioloop); client->running = FALSE; } if (timeout_added && client->to != NULL) timeout_remove(&client->to); io_loop_set_current(prev_ioloop); pop3c_client_ioloop_changed(client); io_loop_set_current(ioloop); io_loop_destroy(&ioloop); }
static int doveadm_cmd_handle(struct client_connection *conn, const char *cmd_name, const struct mail_storage_service_input *input, int argc, char *argv[]) { struct ioloop *ioloop, *prev_ioloop = current_ioloop; const struct doveadm_cmd *cmd; const struct doveadm_mail_cmd *mail_cmd; struct doveadm_mail_cmd_context *ctx; cmd = doveadm_cmd_find(cmd_name, &argc, &argv); if (cmd == NULL) { mail_cmd = doveadm_mail_cmd_find(cmd_name); if (mail_cmd == NULL) { i_error("doveadm: Client sent unknown command: %s", cmd_name); return -1; } if (doveadm_mail_cmd_server_parse(mail_cmd, conn->set, input, argc, argv, &ctx) < 0) return -1; } /* some commands will want to call io_loop_run(), but we're already running one and we can't call the original one recursively, so create a new ioloop. */ ioloop = io_loop_create(); lib_signals_reset_ioloop(); if (cmd != NULL) doveadm_cmd_server_run(conn, cmd, argc, argv); else doveadm_mail_cmd_server_run(conn, ctx, input); io_loop_set_current(prev_ioloop); lib_signals_reset_ioloop(); o_stream_switch_ioloop(conn->output); io_loop_set_current(ioloop); io_loop_destroy(&ioloop); /* clear all headers */ doveadm_print_deinit(); doveadm_print_init(DOVEADM_PRINT_TYPE_SERVER); return 0; }
static void fts_parser_tika_more(struct fts_parser *_parser, struct message_block *block) { struct tika_fts_parser *parser = (struct tika_fts_parser *)_parser; const unsigned char *data; size_t size; ssize_t ret; if (block->size > 0) { /* first we'll send everything to Tika */ if (!parser->failed && http_client_request_send_payload(&parser->http_req, block->data, block->size) < 0) parser->failed = TRUE; block->size = 0; return; } if (parser->payload == NULL) { /* read the result from Tika */ if (!parser->failed && http_client_request_finish_payload(&parser->http_req) < 0) parser->failed = TRUE; if (!parser->failed && parser->payload == NULL) http_client_wait(tika_http_client); if (parser->failed) return; i_assert(parser->payload != NULL); } /* continue returning data from Tika */ while ((ret = i_stream_read_data(parser->payload, &data, &size, 0)) == 0) { if (parser->failed) return; /* wait for more input from Tika */ if (parser->ioloop == NULL) { parser->ioloop = io_loop_create(); parser->io = io_add_istream(parser->payload, io_loop_stop, current_ioloop); } else { io_loop_set_current(parser->ioloop); } io_loop_run(current_ioloop); } if (size > 0) { i_assert(ret > 0); block->data = data; block->size = size; i_stream_skip(parser->payload, size); } else { /* finished */ i_assert(ret == -1); } }
static int fts_parser_tika_deinit(struct fts_parser *_parser) { struct tika_fts_parser *parser = (struct tika_fts_parser *)_parser; int ret = parser->failed ? -1 : 0; /* remove io before unrefing payload - otherwise lib-http adds another timeout to ioloop unnecessarily */ if (parser->payload != NULL) i_stream_unref(&parser->payload); if (parser->io != NULL) io_remove(&parser->io); if (parser->http_req != NULL) http_client_request_abort(&parser->http_req); if (parser->ioloop != NULL) { io_loop_set_current(parser->ioloop); io_loop_destroy(&parser->ioloop); } i_free(parser); return ret; }
static int http_client_request_continue_payload(struct http_client_request **_req, const unsigned char *data, size_t size) { struct ioloop *prev_ioloop = current_ioloop; struct http_client_request *req = *_req; struct http_client_connection *conn = req->conn; struct http_client *client = req->client; int ret; i_assert(req->state == HTTP_REQUEST_STATE_NEW || req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT); i_assert(req->payload_input == NULL); if (conn != NULL) http_client_connection_ref(conn); http_client_request_ref(req); req->payload_wait = TRUE; if (data == NULL) { req->payload_input = NULL; if (req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT) http_client_request_finish_payload_out(req); } else { req->payload_input = i_stream_create_from_data(data, size); i_stream_set_name(req->payload_input, "<HTTP request payload>"); } req->payload_size = 0; req->payload_chunked = TRUE; if (req->state == HTTP_REQUEST_STATE_NEW) http_client_request_submit(req); /* Wait for payload data to be written */ i_assert(client->ioloop == NULL); client->ioloop = io_loop_create(); http_client_switch_ioloop(client); if (client->set.dns_client != NULL) dns_client_switch_ioloop(client->set.dns_client); while (req->state < HTTP_REQUEST_STATE_PAYLOAD_IN) { http_client_request_debug(req, "Waiting for request to finish"); if (req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT) o_stream_set_flush_pending(req->payload_output, TRUE); io_loop_run(client->ioloop); if (req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT && req->payload_input->eof) { i_stream_unref(&req->payload_input); req->payload_input = NULL; break; } } io_loop_set_current(prev_ioloop); http_client_switch_ioloop(client); if (client->set.dns_client != NULL) dns_client_switch_ioloop(client->set.dns_client); io_loop_set_current(client->ioloop); io_loop_destroy(&client->ioloop); switch (req->state) { case HTTP_REQUEST_STATE_PAYLOAD_IN: case HTTP_REQUEST_STATE_FINISHED: ret = 1; break; case HTTP_REQUEST_STATE_ABORTED: ret = -1; break; default: ret = 0; break; } req->payload_wait = FALSE; /* callback may have messed with our pointer, so unref using local variable */ if (!http_client_request_unref(&req)) *_req = NULL; if (conn != NULL) http_client_connection_unref(&conn); /* Return status */ return ret; }
static ssize_t http_server_istream_read(struct istream_private *stream) { struct http_server_istream *hsristream = (struct http_server_istream *)stream; struct http_server_request *req = hsristream->req; struct http_server *server; struct http_server_connection *conn; bool blocking = stream->istream.blocking; ssize_t ret; if (req == NULL) { /* request already gone (we shouldn't get here) */ stream->istream.stream_errno = EINVAL; return -1; } i_stream_seek(stream->parent, stream->parent_start_offset + stream->istream.v_offset); server = hsristream->req->server; conn = hsristream->req->conn; ret = i_stream_read_copy_from_parent(&stream->istream); if (ret == 0 && blocking) { struct ioloop *prev_ioloop = current_ioloop; struct io *io; http_server_connection_ref(conn); http_server_request_ref(req); i_assert(server->ioloop == NULL); server->ioloop = io_loop_create(); http_server_connection_switch_ioloop(conn); if (blocking && req->req.expect_100_continue && !req->sent_100_continue) http_server_connection_trigger_responses(conn); hsristream->read_status = 0; io = io_add_istream(&stream->istream, http_server_istream_read_any, hsristream); while (req->state < HTTP_SERVER_REQUEST_STATE_FINISHED && hsristream->read_status == 0) { io_loop_run(server->ioloop); } io_remove(&io); io_loop_set_current(prev_ioloop); http_server_connection_switch_ioloop(conn); io_loop_set_current(server->ioloop); io_loop_destroy(&server->ioloop); ret = hsristream->read_status; if (!http_server_request_unref(&req)) hsristream->req = NULL; http_server_connection_unref(&conn); } return ret; }
static void fts_parser_tika_more(struct fts_parser *_parser, struct message_block *block) { struct tika_fts_parser *parser = (struct tika_fts_parser *)_parser; struct ioloop *prev_ioloop = current_ioloop; const unsigned char *data; size_t size; ssize_t ret; if (block->size > 0) { /* first we'll send everything to Tika */ if (!parser->failed && http_client_request_send_payload(&parser->http_req, block->data, block->size) < 0) parser->failed = TRUE; block->size = 0; return; } if (parser->payload == NULL) { /* read the result from Tika */ if (!parser->failed && http_client_request_finish_payload(&parser->http_req) < 0) parser->failed = TRUE; if (!parser->failed && parser->payload == NULL) http_client_wait(tika_http_client); if (parser->failed) return; i_assert(parser->payload != NULL); } /* continue returning data from Tika. we'll create a new ioloop just for reading this one payload. */ while ((ret = i_stream_read_data(parser->payload, &data, &size, 0)) == 0) { if (parser->failed) break; /* wait for more input from Tika */ if (parser->ioloop == NULL) { parser->ioloop = io_loop_create(); parser->io = io_add_istream(parser->payload, io_loop_stop, current_ioloop); } else { io_loop_set_current(parser->ioloop); } io_loop_run(current_ioloop); } /* switch back to original ioloop. */ io_loop_set_current(prev_ioloop); if (parser->failed) ; else if (size > 0) { i_assert(ret > 0); block->data = data; block->size = size; i_stream_skip(parser->payload, size); } else { /* finished */ i_assert(ret == -1); if (parser->payload->stream_errno != 0) { i_error("read(%s) failed: %s", i_stream_get_name(parser->payload), i_stream_get_error(parser->payload)); parser->failed = TRUE; } } }