static unsigned int login_proxy_delay_disconnect(struct login_proxy *proxy) { struct login_proxy_record *rec = proxy->state_rec; const unsigned int max_delay = proxy->client->set->login_proxy_max_disconnect_delay; struct timeval disconnect_time_offset; unsigned int max_disconnects_per_sec, delay_msecs_since_ts, max_conns; int delay_msecs; if (rec->num_disconnects_since_ts == 0) { rec->disconnect_timestamp = ioloop_timeval; /* start from a slightly random timestamp. this way all proxy processes will disconnect at slightly different times to spread the load. */ timeval_add_msecs(&rec->disconnect_timestamp, rand() % PROXY_DISCONNECT_INTERVAL_MSECS); } rec->num_disconnects_since_ts++; if (proxy->to != NULL) { /* we were already lazily disconnecting this */ return 0; } if (max_delay == 0) { /* delaying is disabled */ return 0; } max_conns = rec->num_proxying_connections + rec->num_disconnects_since_ts; max_disconnects_per_sec = (max_conns + max_delay-1) / max_delay; if (rec->num_disconnects_since_ts <= max_disconnects_per_sec && rec->num_delayed_client_disconnects == 0) { /* wait delaying until we have 1 second's worth of clients disconnected */ return 0; } /* see at which time we should be disconnecting the client. do it in 100ms intervals so the timeouts are triggered together. */ disconnect_time_offset = rec->disconnect_timestamp; delay_msecs_since_ts = PROXY_DISCONNECT_INTERVAL_MSECS * (max_delay * rec->num_disconnects_since_ts * (1000/PROXY_DISCONNECT_INTERVAL_MSECS) / max_conns); timeval_add_msecs(&disconnect_time_offset, delay_msecs_since_ts); delay_msecs = timeval_diff_msecs(&disconnect_time_offset, &ioloop_timeval); if (delay_msecs <= 0) { /* we already reached the time */ return 0; } rec->num_delayed_client_disconnects++; proxy->delayed_disconnect = TRUE; proxy->to = timeout_add(delay_msecs, login_proxy_free_final, proxy); DLLIST_PREPEND(&login_proxies_disconnecting, proxy); return delay_msecs; }
static void http_client_request_do_submit(struct http_client_request *req) { struct http_client *client = req->client; struct http_client_host *host; const char *proxy_socket_path = client->set.proxy_socket_path; const struct http_url *proxy_url = client->set.proxy_url; bool have_proxy = (proxy_socket_path != NULL) || (proxy_url != NULL) || (req->host_socket != NULL) || (req->host_url != NULL); const char *authority, *target; i_assert(req->state == HTTP_REQUEST_STATE_NEW); authority = http_url_create_authority(&req->origin_url); if (req->connect_tunnel) { /* connect requests require authority form for request target */ target = authority; } else { /* absolute target url */ target = t_strconcat (http_url_create_host(&req->origin_url), req->target, NULL); } /* determine what host to contact to submit this request */ if (have_proxy) { if (req->host_socket != NULL) { /* specific socket proxy */ req->host_url = NULL; } else if (req->host_url != NULL) { /* specific normal proxy */ req->host_socket = NULL; } else if (req->origin_url.have_ssl && !client->set.no_ssl_tunnel && !req->connect_tunnel) { req->host_url = &req->origin_url; /* tunnel to origin server */ req->ssl_tunnel = TRUE; } else if (proxy_socket_path != NULL) { req->host_socket = proxy_socket_path; /* proxy on unix socket */ req->host_url = NULL; } else { req->host_url = proxy_url; /* normal proxy server */ req->host_socket = NULL; } } else { req->host_url = &req->origin_url; /* origin server */ } /* use submission date if no date is set explicitly */ if (req->date == (time_t)-1) req->date = ioloop_time; /* prepare value for Host header */ req->authority = p_strdup(req->pool, authority); /* debug label */ req->label = p_strdup_printf(req->pool, "[Req%u: %s %s]", req->id, req->method, target); /* update request target */ if (req->connect_tunnel || have_proxy) req->target = p_strdup(req->pool, target); if (!have_proxy) { /* if we don't have a proxy, CONNECT requests are handled by creating the requested connection directly */ req->connect_direct = req->connect_tunnel; if (req->connect_direct) req->urgent = TRUE; } if (req->timeout_time.tv_sec == 0) { if (req->timeout_msecs > 0) { req->timeout_time = ioloop_timeval; timeval_add_msecs(&req->timeout_time, req->timeout_msecs); } else if ( client->set.request_absolute_timeout_msecs > 0) { req->timeout_time = ioloop_timeval; timeval_add_msecs(&req->timeout_time, client->set.request_absolute_timeout_msecs); } } host = http_client_host_get(req->client, req->host_url); req->state = HTTP_REQUEST_STATE_QUEUED; http_client_host_submit_request(host, req); }
void http_client_request_delay_msecs(struct http_client_request *req, unsigned int msecs) { req->release_time = ioloop_timeval; timeval_add_msecs(&req->release_time, msecs); }