static bool proxy_client_worker_next_reply(struct proxy_client_dsync_worker *worker, const char *line) { const struct proxy_client_request *requests; struct proxy_client_request request; bool ret = TRUE; i_assert(worker->msg_get_data.input == NULL); if (aqueue_count(worker->request_queue) == 0) { i_error("Unexpected reply from server: %s", line); proxy_client_fail(worker); return FALSE; } requests = array_idx(&worker->request_array, 0); request = requests[aqueue_idx(worker->request_queue, 0)]; aqueue_delete_tail(worker->request_queue); switch (request.type) { case PROXY_CLIENT_REQUEST_TYPE_COPY: ret = proxy_client_worker_next_copy(worker, &request, line); break; case PROXY_CLIENT_REQUEST_TYPE_GET: ret = proxy_client_worker_next_msg_get(worker, &request, line); break; case PROXY_CLIENT_REQUEST_TYPE_FINISH: proxy_client_worker_next_finish(worker, &request, line); break; } return ret; }
static void worker_connection_disconnect(struct worker_connection *conn) { unsigned int i, count = aqueue_count(conn->request_queue); if (conn->fd != -1) { io_remove(&conn->io); i_stream_destroy(&conn->input); o_stream_destroy(&conn->output); if (close(conn->fd) < 0) i_error("close(%s) failed: %m", conn->socket_path); conn->fd = -1; } /* cancel any pending requests */ if (count > 0) { i_error("Indexer worker disconnected, " "discarding %u requests for %s", count, conn->request_username); } /* conn->callback() can try to destroy us */ conn->refcount++; for (i = 0; i < count; i++) { void *const *contextp = array_idx(&conn->request_contexts, aqueue_idx(conn->request_queue, 0)); void *context = *contextp; aqueue_delete_tail(conn->request_queue); conn->callback(-1, context); } i_free_and_null(conn->request_username); worker_connection_unref(conn); }
void auth_request_handler_flush_failures(bool flush_all) { struct auth_request **auth_requests, *auth_request; unsigned int i, count; time_t diff; count = aqueue_count(auth_failures); if (count == 0) { if (to_auth_failures != NULL) timeout_remove(&to_auth_failures); return; } auth_requests = array_idx_modifiable(&auth_failures_arr, 0); for (i = 0; i < count; i++) { auth_request = auth_requests[aqueue_idx(auth_failures, 0)]; /* FIXME: assumess that failure_delay is always the same. */ diff = ioloop_time - auth_request->last_access; if (diff < (time_t)auth_request->set->failure_delay && !flush_all) break; aqueue_delete_tail(auth_failures); i_assert(auth_request->state == AUTH_REQUEST_STATE_FINISHED); auth_request_handler_reply(auth_request, AUTH_CLIENT_RESULT_FAILURE, &uchar_nul, 0); auth_request_unref(&auth_request); } }
static void ldap_connection_abort_request(struct ldap_op_queue_entry *req) { struct ldap_result res; /* too bad */ if (req->to_abort != NULL) timeout_remove(&req->to_abort); if (req->msgid > -1) ldap_abandon_ext(req->conn->conn, req->msgid, NULL, NULL); memset(&res, 0, sizeof(res)); res.openldap_ret = LDAP_TIMEOUT; res.error_string = "Aborting LDAP request after timeout"; if (req->result_callback != NULL) req->result_callback(&res, req->result_callback_ctx); unsigned int n = aqueue_count(req->conn->request_queue); for (unsigned int i = 0; i < n; i++) { struct ldap_op_queue_entry *const *reqp = array_idx(&(req->conn->request_array), aqueue_idx(req->conn->request_queue, i)); if (req == *reqp) { aqueue_delete(req->conn->request_queue, i); ldap_connection_request_destroy(&req); return; } } i_unreached(); }
static int worker_connection_input_line(struct worker_connection *conn, const char *line) { void *const *contextp, *context; int percentage; if (aqueue_count(conn->request_queue) == 0) { i_error("Input from worker without pending requests: %s", line); return -1; } if (str_to_int(line, &percentage) < 0 || percentage < -1 || percentage > 100) { i_error("Invalid input from worker: %s", line); return -1; } contextp = array_idx(&conn->request_contexts, aqueue_idx(conn->request_queue, 0)); context = *contextp; if (percentage < 0 || percentage == 100) { /* the request is finished */ aqueue_delete_tail(conn->request_queue); if (aqueue_count(conn->request_queue) == 0) i_free_and_null(conn->request_username); } conn->callback(percentage, context); return 0; }
void ldap_connection_kill(struct ldap_connection *conn) { if (conn->io != NULL) io_remove_closed(&(conn->io)); if (conn->to_disconnect != NULL) timeout_remove(&(conn->to_disconnect)); if (conn->to_reconnect != NULL) timeout_remove(&(conn->to_reconnect)); if (conn->request_queue != NULL) { unsigned int n = aqueue_count(conn->request_queue); for (unsigned int i = 0; i < n; i++) { struct ldap_op_queue_entry *const *reqp = array_idx(&(conn->request_array), aqueue_idx(conn->request_queue, i)); if ((*reqp)->msgid > -1) ldap_abandon_ext(conn->conn, (*reqp)->msgid, NULL, NULL); (*reqp)->msgid = -1; } } if (conn->conn != NULL) { ldap_unbind_ext(conn->conn, NULL, NULL); ldap_memfree(conn->scred); } conn->conn = NULL; conn->state = LDAP_STATE_DISCONNECT; }
static void ldap_connection_send_next(struct ldap_connection *conn) { unsigned int i = 0, n; struct ldap_op_queue_entry *req; if (conn->to_reconnect != NULL) timeout_remove(&(conn->to_reconnect)); if (conn->state == LDAP_STATE_DISCONNECT) { if (ldap_connection_connect(conn) == -1) conn->to_reconnect = timeout_add(1000, ldap_connection_send_next, conn); return; } if (conn->state != LDAP_STATE_CONNECT) { return; } if (conn->pending > 10) return; /* try again later */ req = NULL; /* get next request */ n = aqueue_count(conn->request_queue); for(i=0; i < n; i++) { struct ldap_op_queue_entry *const *reqp = array_idx(&(conn->request_array), aqueue_idx(conn->request_queue, i)); if ((*reqp)->msgid > -1) break; req = *reqp; } i--; /* nothing to actually send */ if (req == NULL) return; i_assert(req->msgid == -1); const char *error; int ret; if ((ret = req->send_request_cb(conn, req, &error)) != LDAP_SUCCESS) { /* did not succeed */ struct ldap_result res; memset(&res, 0, sizeof(res)); res.openldap_ret = ret; if (req->result_callback != NULL) req->result_callback(&res, req->result_callback_ctx); ldap_connection_request_destroy(&req); aqueue_delete(conn->request_queue, i); } else conn->pending++; }
static bool aqueue_is_ok(struct aqueue *aqueue, unsigned int deleted_n) { const unsigned int *p; unsigned int n, i, count; count = aqueue_count(aqueue); for (i = 0, n = 1; i < count; i++, n++) { p = array_idx_i(aqueue->arr, aqueue_idx(aqueue, i)); if (i == deleted_n) n++; if (*p != n) return FALSE; } return TRUE; }
static struct ldap_op_queue_entry * ldap_connection_find_req_by_msgid(struct ldap_connection *conn, int msgid, unsigned int *idx_r) { unsigned int i, n = aqueue_count(conn->request_queue); for (i = 0; i < n; i++) { struct ldap_op_queue_entry *const *reqp = array_idx(&(conn->request_array), aqueue_idx(conn->request_queue, i)); if ((*reqp)->msgid == msgid) { *idx_r = i; return *reqp; } } return NULL; }
void ldap_connection_deinit(struct ldap_connection **_conn) { struct ldap_connection *conn = *_conn; *_conn = NULL; ldap_connection_kill(conn); unsigned int n = aqueue_count(conn->request_queue); for (unsigned int i = 0; i < n; i++) { struct ldap_op_queue_entry *const *reqp = array_idx(&(conn->request_array), aqueue_idx(conn->request_queue, i)); if ((*reqp)->to_abort != NULL) timeout_remove(&(*reqp)->to_abort); } pool_unref(&conn->pool); }
void ldap_connection_switch_ioloop(struct ldap_connection *conn) { if (conn->io != NULL) conn->io = io_loop_move_io(&conn->io); if (conn->to_disconnect != NULL) conn->to_disconnect = io_loop_move_timeout(&conn->to_disconnect); if (conn->to_reconnect != NULL) conn->to_reconnect = io_loop_move_timeout(&conn->to_reconnect); unsigned int n = aqueue_count(conn->request_queue); for (unsigned int i = 0; i < n; i++) { struct ldap_op_queue_entry *const *reqp = array_idx(&(conn->request_array), aqueue_idx(conn->request_queue, i)); if ((*reqp)->to_abort != NULL) (*reqp)->to_abort = io_loop_move_timeout(&((*reqp)->to_abort)); } }
static bool dsync_mailbox_tree_bfs_iter_next(struct dsync_mailbox_tree_bfs_iter *iter, struct dsync_mailbox_node **node_r) { struct dsync_mailbox_node *const *nodep; if (iter->cur == NULL) { if (aqueue_count(iter->queue) == 0) return FALSE; nodep = array_idx(&iter->queue_arr, aqueue_idx(iter->queue, 0)); iter->cur = *nodep; aqueue_delete_tail(iter->queue); } *node_r = iter->cur; if (iter->cur->first_child != NULL) aqueue_append(iter->queue, &iter->cur->first_child); iter->cur = iter->cur->next; return TRUE; }
void aqueue_delete(struct aqueue *aqueue, unsigned int n) { unsigned int idx, count = aqueue_count(aqueue); i_assert(n < count); aqueue->full = FALSE; if (n == 0) { /* optimized deletion from tail */ aqueue->tail = (aqueue->tail + 1) % aqueue->area_size; return; } if (n == count-1) { /* optimized deletion from head */ aqueue->head = (aqueue->head + aqueue->area_size - 1) % aqueue->area_size; return; } idx = aqueue_idx(aqueue, n); if ((n < count/2 || idx > aqueue->head) && idx > aqueue->tail) { /* move tail forward. ..tail##idx##head.. or ##head..tail##idx## */ array_copy(aqueue->arr, aqueue->tail + 1, aqueue->arr, aqueue->tail, idx - aqueue->tail); aqueue->tail++; i_assert(aqueue->tail < aqueue->area_size); } else { /* move head backward. ..tail##idx##head.. or ##idx##head..tail## */ i_assert(idx < aqueue->head); array_copy(aqueue->arr, idx, aqueue->arr, idx + 1, aqueue->head - idx); aqueue->head = (aqueue->head + aqueue->area_size - 1) % aqueue->area_size; } i_assert(aqueue->head < aqueue->area_size && aqueue->head != aqueue->tail); }
static void ldap_connection_abort_all_requests(struct ldap_connection *conn) { struct ldap_result res; memset(&res, 0, sizeof(res)); res.openldap_ret = LDAP_TIMEOUT; res.error_string = "Aborting LDAP requests due to failure"; unsigned int n = aqueue_count(conn->request_queue); for (unsigned int i = 0; i < n; i++) { struct ldap_op_queue_entry **reqp = array_idx_modifiable(&(conn->request_array), aqueue_idx(conn->request_queue, i)); if ((*reqp)->to_abort != NULL) timeout_remove(&(*reqp)->to_abort); if ((*reqp)->result_callback != NULL) (*reqp)->result_callback(&res, (*reqp)->result_callback_ctx); ldap_connection_request_destroy(reqp); } aqueue_clear(conn->request_queue); }