static void ngx_http_push_stream_send_old_messages(ngx_http_request_t *r, ngx_http_push_stream_channel_t *channel, ngx_uint_t backtrack, time_t if_modified_since, ngx_int_t tag, time_t greater_message_time, ngx_int_t greater_message_tag, ngx_str_t *last_event_id, ngx_int_t *message_count_had_send) { ngx_http_push_stream_msg_t *message; ngx_queue_t *cur; time_t next_greater_message_time = greater_message_time;//add by xinlu ngx_int_t next_greater_message_tag = greater_message_tag;//add by xinlu if (ngx_http_push_stream_has_old_messages_to_send(channel, backtrack, if_modified_since, tag, greater_message_time, greater_message_tag, last_event_id, &next_greater_message_time, &next_greater_message_tag) >= 2) { cur = &channel->message_queue; if ((last_event_id != NULL) || (if_modified_since >= 0)) { ngx_flag_t found = 0; while ((cur = ngx_queue_next(cur)) && (cur != NULL) && (cur != &channel->message_queue)) { message = (ngx_http_push_stream_msg_t *) ngx_queue_data(cur, ngx_http_push_stream_msg_t, queue); if (message->deleted) { break; } if ((!found) && (last_event_id != NULL) && (message->event_id != NULL) && (ngx_memn2cmp(message->event_id->data, last_event_id->data, message->event_id->len, last_event_id->len) == 0)) { found = 1; continue; } if ((!found) && (last_event_id == NULL) && (if_modified_since >= 0) && ((message->time > if_modified_since) || ((message->time == if_modified_since) && (tag >= 0) && (message->tag >= tag)))) { found = 1; if ((message->time == if_modified_since) && (message->tag == tag)) { continue; } } //if (found && (((greater_message_time == 0) && (greater_message_tag == -1)) || (greater_message_time > message->time) || ((greater_message_time == message->time) && (greater_message_tag >= message->tag)))) if (found && (greater_message_time == message->time) && (greater_message_tag == message->tag)) { ngx_http_push_stream_send_response_message(r, channel, message, 0, 1); (*message_count_had_send)++; return; } } } } }
static ngx_int_t ngx_http_limit_req_lookup(ngx_http_request_t *r, ngx_http_limit_req_t *limit_req, ngx_uint_t hash, ngx_uint_t *ep) { u_char *data, *last; ngx_int_t rc, excess; ngx_uint_t i; ngx_time_t *tp; ngx_msec_t now; ngx_msec_int_t ms; ngx_rbtree_node_t *node, *sentinel; ngx_http_limit_req_ctx_t *ctx; ngx_http_limit_req_node_t *lr; ngx_http_variable_value_t *vv; ngx_http_limit_req_variable_t *lrv; ctx = limit_req->shm_zone->data; node = ctx->sh->rbtree.root; sentinel = ctx->sh->rbtree.sentinel; rc = -1; lrv = ctx->limit_vars->elts; while (node != sentinel) { if (hash < node->key) { node = node->left; continue; } if (hash > node->key) { node = node->right; continue; } /* hash == node->key */ do { lr = (ngx_http_limit_req_node_t *) &node->color; data = lr->data; last = data + lr->len; for (i = 0; i < ctx->limit_vars->nelts; i++) { vv = ngx_http_get_indexed_variable(r, lrv[i].index); ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "limit_req vv is %i %v node is %s", lrv[i].index, vv, data); if ((rc = ngx_memn2cmp(data, vv->data, vv->len, vv->len)) != 0) { break; } data += vv->len; if (data > last) { rc = -1; break; } } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "limit_req lookup is : %i, size is %i", rc, ctx->limit_vars->nelts); if (rc == 0) { ngx_queue_remove(&lr->queue); ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); tp = ngx_timeofday(); now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); ms = (ngx_msec_int_t) (now - lr->last); excess = lr->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000; if (excess < 0) { excess = 0; } *ep = excess; if ((ngx_uint_t) excess > limit_req->burst) { return NGX_BUSY; } lr->excess = excess; lr->last = now; if (excess) { return NGX_AGAIN; } return NGX_OK; } node = (rc < 0) ? node->left : node->right; } while (node != sentinel && hash == node->key); break; } *ep = 0; return NGX_DECLINED; }
static ngx_int_t ngx_http_limit_speed_handler(ngx_http_request_t *r) { size_t len, n; uint32_t hash; ngx_int_t rc; ngx_uint_t speed; ngx_slab_pool_t *shpool; ngx_rbtree_node_t *node, *sentinel; ngx_pool_cleanup_t *cln; ngx_http_variable_value_t *vv; ngx_http_limit_speed_ctx_t *ctx; ngx_http_limit_speed_node_t *ls; ngx_http_limit_speed_conf_t *lscf; ngx_http_limit_speed_cleanup_t *lscln; ngx_http_limit_speed_req_ctx_t *rctx; lscf = ngx_http_get_module_loc_conf(r, ngx_http_limit_speed_module); if (lscf->shm_zone == NULL || lscf->speed == 0) { return NGX_DECLINED; } if (r->main->limit_rate) { return NGX_DECLINED; } ctx = lscf->shm_zone->data; vv = ngx_http_get_indexed_variable(r, ctx->index); if (vv == NULL || vv->not_found) { return NGX_DECLINED; } len = vv->len; if (len == 0) { return NGX_DECLINED; } if (lscf->var_max_len) { len = len > lscf->var_max_len ? lscf->var_max_len : len; } hash = ngx_crc32_short(vv->data, len); cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_limit_speed_cleanup_t)); if (cln == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } shpool = (ngx_slab_pool_t *) lscf->shm_zone->shm.addr; ngx_shmtx_lock(&shpool->mutex); node = ctx->rbtree->root; sentinel = ctx->rbtree->sentinel; while (node != sentinel) { if (hash < node->key) { node = node->left; continue; } if (hash > node->key) { node = node->right; continue; } /* hash == node->key */ do { ls = (ngx_http_limit_speed_node_t *) &node->color; rc = ngx_memn2cmp(vv->data, ls->data, len, (size_t) ls->len); if (rc == 0) { ls->conn++; goto done; } node = (rc < 0) ? node->left : node->right; } while (node != sentinel && hash == node->key); break; } n = offsetof(ngx_rbtree_node_t, color) + offsetof(ngx_http_limit_speed_node_t, data) + len; node = ngx_slab_alloc_locked(shpool, n); if (node == NULL) { ngx_shmtx_unlock(&shpool->mutex); return NGX_DECLINED; } ls = (ngx_http_limit_speed_node_t *) &node->color; node->key = hash; ls->len = (u_char) len; ls->conn = 1; ngx_memcpy(ls->data, vv->data, len); ngx_rbtree_insert(ctx->rbtree, node); done: speed = lscf->speed; r->main->limit_rate = speed / ls->conn; ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "limit speed zone: %08XD conn=%d, speed=%d", node->key, ls->conn, r->main->limit_rate); ngx_shmtx_unlock(&shpool->mutex); cln->handler = ngx_http_limit_speed_cleanup; lscln = cln->data; lscln->shm_zone = lscf->shm_zone; lscln->node = node; if (lscf->minimum && r->main->limit_rate <= lscf->minimum) { r->main->limit_rate = 0; if (lscf->rewrite.len == 0) { return NGX_HTTP_SERVICE_UNAVAILABLE; } if (lscf->rewrite.data[0] == '@') { (void) ngx_http_named_location(r, &lscf->rewrite); } else { (void) ngx_http_internal_redirect(r, &lscf->rewrite, &r->args); } ngx_http_finalize_request(r, NGX_DONE); return NGX_DONE; } if (ngx_http_limit_speed_get_ctx(r) != NGX_OK) { return NGX_DECLINED; } rctx = ngx_http_get_module_ctx(r, ngx_http_limit_speed_module); rctx->speed = speed; rctx->ls = ls; return NGX_DECLINED; }
// 发布的入口函数 static ngx_int_t ngx_http_push_stream_publisher_handler(ngx_http_request_t *r) { ngx_http_push_stream_channel_t *channel = NULL; ngx_http_push_stream_main_conf_t *mcf = ngx_http_get_module_main_conf(r, ngx_http_push_stream_module); ngx_http_push_stream_loc_conf_t *cf = ngx_http_get_module_loc_conf(r, ngx_http_push_stream_module); ngx_http_push_stream_module_ctx_t *ctx; ngx_http_push_stream_requested_channel_t *channels_ids, *cur; ngx_str_t vv_allowed_origins = ngx_null_string; ngx_http_push_stream_set_expires(r, NGX_HTTP_PUSH_STREAM_EXPIRES_EPOCH, 0); if (cf->allowed_origins != NULL) { ngx_http_push_stream_complex_value(r, cf->allowed_origins, &vv_allowed_origins); } if (vv_allowed_origins.len > 0) { ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, &vv_allowed_origins); const ngx_str_t *header_value = (cf->location_type == NGX_HTTP_PUSH_STREAM_PUBLISHER_MODE_ADMIN) ? &NGX_HTTP_PUSH_STREAM_ALLOW_GET_POST_PUT_DELETE_METHODS : &NGX_HTTP_PUSH_STREAM_ALLOW_GET_POST_PUT_METHODS; ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_ACCESS_CONTROL_ALLOW_METHODS, header_value); ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_ACCESS_CONTROL_ALLOW_HEADERS, &NGX_HTTP_PUSH_STREAM_ALLOWED_HEADERS); } if (r->method & NGX_HTTP_OPTIONS) { return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_OK, NULL); } // only accept GET, POST, PUT and DELETE methods if enable publisher administration if ((cf->location_type == NGX_HTTP_PUSH_STREAM_PUBLISHER_MODE_ADMIN) && !(r->method & (NGX_HTTP_GET|NGX_HTTP_POST|NGX_HTTP_PUT|NGX_HTTP_DELETE))) { ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_ALLOW, &NGX_HTTP_PUSH_STREAM_ALLOW_GET_POST_PUT_DELETE_METHODS); return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_NOT_ALLOWED, NULL); } // only accept GET, POST and PUT methods if NOT enable publisher administration if ((cf->location_type != NGX_HTTP_PUSH_STREAM_PUBLISHER_MODE_ADMIN) && !(r->method & (NGX_HTTP_GET|NGX_HTTP_POST|NGX_HTTP_PUT))) { ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_ALLOW, &NGX_HTTP_PUSH_STREAM_ALLOW_GET_POST_PUT_METHODS); return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_NOT_ALLOWED, NULL); } if ((ctx = ngx_http_push_stream_add_request_context(r)) == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "push stream module: unable to create request context"); return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_INTERNAL_SERVER_ERROR, NULL); } //get channels ids channels_ids = ngx_http_push_stream_parse_channels_ids_from_path(r, r->pool); if ((channels_ids == NULL) || ngx_queue_empty(&channels_ids->queue)) { ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "push stream module: the push_stream_channels_path is required but is not set"); return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_BAD_REQUEST, &NGX_HTTP_PUSH_STREAM_NO_CHANNEL_ID_MESSAGE); } cur = channels_ids; while ((cur = (ngx_http_push_stream_requested_channel_t *) ngx_queue_next(&cur->queue)) != channels_ids) { // check if channel id isn't equals to ALL or contain wildcard if ((ngx_memn2cmp(cur->id->data, NGX_HTTP_PUSH_STREAM_ALL_CHANNELS_INFO_ID.data, cur->id->len, NGX_HTTP_PUSH_STREAM_ALL_CHANNELS_INFO_ID.len) == 0) || (ngx_strchr(cur->id->data, '*') != NULL)) { return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_FORBIDDEN, &NGX_HTTP_PUSH_STREAM_CHANNEL_ID_NOT_AUTHORIZED_MESSAGE); } // could not have a large size if ((mcf->max_channel_id_length != NGX_CONF_UNSET_UINT) && (cur->id->len > mcf->max_channel_id_length)) { ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "push stream module: channel id is larger than allowed %d", cur->id->len); return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_BAD_REQUEST, &NGX_HTTP_PUSH_STREAM_TOO_LARGE_CHANNEL_ID_MESSAGE); } if (r->method & (NGX_HTTP_POST|NGX_HTTP_PUT)) { // create the channel if doesn't exist channel = ngx_http_push_stream_get_channel(cur->id, r->connection->log, cf, mcf); if (channel == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "push stream module: unable to allocate memory for new channel"); return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_INTERNAL_SERVER_ERROR, NULL); } if (channel == NGX_HTTP_PUSH_STREAM_NUMBER_OF_CHANNELS_EXCEEDED) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "push stream module: number of channels were exceeded"); return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_FORBIDDEN, &NGX_HTTP_PUSH_STREAM_NUMBER_OF_CHANNELS_EXCEEDED_MESSAGE); } } } ctx->requested_channels = channels_ids; // POST, PUT方法 if (r->method & (NGX_HTTP_POST|NGX_HTTP_PUT)) { return ngx_http_push_stream_publisher_handle_after_read_body(r, ngx_http_push_stream_publisher_body_handler); } if ((cf->location_type == NGX_HTTP_PUSH_STREAM_PUBLISHER_MODE_ADMIN) && (r->method == NGX_HTTP_DELETE)) { return ngx_http_push_stream_publisher_handle_after_read_body(r, ngx_http_push_stream_publisher_delete_handler); } return ngx_http_push_stream_send_response_channels_info_detailed(r, channels_ids); }
static ngx_int_t ngx_http_upstream_get_keepalive_peer(ngx_peer_connection_t *pc, void *data) { ngx_http_upstream_keepalive_peer_data_t *kp = data; ngx_http_upstream_keepalive_cache_t *item; ngx_int_t rc; ngx_queue_t *q, *cache; ngx_connection_t *c; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "get keepalive peer"); kp->failed = 0; /* single pool of cached connections */ if (kp->conf->single && !ngx_queue_empty(&kp->conf->cache)) { q = ngx_queue_head(&kp->conf->cache); item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue); c = item->connection; ngx_queue_remove(q); ngx_queue_insert_head(&kp->conf->free, q); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "get keepalive peer: using connection %p", c); c->idle = 0; c->log = pc->log; c->read->log = pc->log; c->write->log = pc->log; c->pool->log = pc->log; pc->connection = c; pc->cached = 1; return NGX_DONE; } rc = kp->original_get_peer(pc, kp->data); if (kp->conf->single || rc != NGX_OK) { return rc; } /* search cache for suitable connection */ cache = &kp->conf->cache; for (q = ngx_queue_head(cache); q != ngx_queue_sentinel(cache); q = ngx_queue_next(q)) { item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue); c = item->connection; if (ngx_memn2cmp((u_char *) &item->sockaddr, (u_char *) pc->sockaddr, item->socklen, pc->socklen) == 0) { ngx_queue_remove(q); ngx_queue_insert_head(&kp->conf->free, q); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "get keepalive peer: using connection %p", c); c->idle = 0; c->log = pc->log; c->read->log = pc->log; c->write->log = pc->log; c->pool->log = pc->log; pc->connection = c; pc->cached = 1; return NGX_DONE; } } return NGX_OK; }
static ngx_http_reqstat_rbnode_t * ngx_http_reqstat_rbtree_lookup(ngx_shm_zone_t *shm_zone, ngx_str_t *val) { size_t size; uint32_t hash; ngx_int_t rc; ngx_rbtree_node_t *node, *sentinel; ngx_http_reqstat_ctx_t *ctx; ngx_http_reqstat_rbnode_t *rs; ctx = shm_zone->data; hash = ngx_crc32_short(val->data, val->len); node = ctx->sh->rbtree.root; sentinel = ctx->sh->rbtree.sentinel; ngx_shmtx_lock(&ctx->shpool->mutex); while (node != sentinel) { if (hash < node->key) { node = node->left; continue; } if (hash > node->key) { node = node->right; continue; } /* hash == node->key */ rs = (ngx_http_reqstat_rbnode_t *) &node->color; rc = ngx_memn2cmp(val->data, rs->data, val->len, (size_t) rs->len); if (rc == 0) { ngx_shmtx_unlock(&ctx->shpool->mutex); return rs; } node = (rc < 0) ? node->left : node->right; } size = offsetof(ngx_rbtree_node_t, color) + offsetof(ngx_http_reqstat_rbnode_t, data) + val->len; node = ngx_slab_alloc_locked(ctx->shpool, size); if (node == NULL) { ngx_shmtx_unlock(&ctx->shpool->mutex); return NULL; } node->key = hash; rs = (ngx_http_reqstat_rbnode_t *) &node->color; rs->len = val->len; ngx_memcpy(rs->data, val->data, val->len); ngx_rbtree_insert(&ctx->sh->rbtree, node); ngx_queue_insert_head(&ctx->sh->queue, &rs->queue); ngx_shmtx_unlock(&ctx->shpool->mutex); return rs; }
static int ngx_mbedtls_get_cache(void *ctx, ssl_session *session) { ngx_shm_zone_t *shm_zone; ngx_slab_pool_t *shpool; ngx_ssl_session_cache_t *cache; ngx_rbtree_node_t *node, *sentinel; ngx_ssl_sess_id_t *sess_id; time_t expires; int rc; uint32_t hash; if (ctx == NULL) { /* NGX_SSL_NONE_SCACHE: Every search is a cache miss */ return 1; } hash = ngx_crc32_short(session->id, session->length); shm_zone = ctx; shpool = (ngx_slab_pool_t*) shm_zone->shm.addr; cache = shm_zone->data; ngx_shmtx_lock(&shpool->mutex); node = cache->session_rbtree.root; sentinel = cache->session_rbtree.sentinel; while (node != sentinel) { if (hash < node->key) { node = node->left; continue; } if (hash > node->key) { node = node->right; continue; } /* hash == node->key */ sess_id = (ngx_ssl_sess_id_t *) node; rc = ngx_memn2cmp(session->id, sess_id->session->id, session->length, node->data); if (rc == 0) { if (session->ciphersuite != sess_id->session->ciphersuite || session->compression != sess_id->session->compression || session->length != sess_id->session->length) { /* The ciphersuite/compression changed out from under us */ goto done; } /* Check the expiry time */ expires = (time_t) sess_id->session->peer_cert; if (expires > ngx_time()) { /* Cache hit */ ngx_memcpy(session->master, sess_id->session->master, 48); ngx_shmtx_unlock(&shpool->mutex); return 0; } /* Cache entry expired */ ngx_queue_remove(&sess_id->queue); ngx_rbtree_delete(&cache->session_rbtree, node); ngx_slab_free_locked(shpool, sess_id->session); ngx_slab_free_locked(shpool, sess_id); goto done; } node = (rc < 0) ? node->left : node->right; } done: ngx_shmtx_unlock(&shpool->mutex); return 1; }
static ngx_int_t ngx_http_limit_traffic_rate_filter_log_handler(ngx_http_request_t *r) { size_t len; uint32_t hash; ngx_int_t rc; ngx_slab_pool_t *shpool; ngx_rbtree_node_t *node, *sentinel; ngx_http_variable_value_t *vv; ngx_http_limit_traffic_rate_filter_ctx_t *ctx; ngx_http_limit_traffic_rate_filter_node_t *lir; ngx_http_limit_traffic_rate_filter_conf_t *lircf; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "limit traffic rate log phase handler"); lircf = ngx_http_get_module_loc_conf(r, ngx_http_limit_traffic_rate_filter_module); if (lircf->shm_zone == NULL) { return NGX_DECLINED; } ctx = lircf->shm_zone->data; vv = ngx_http_get_indexed_variable(r, ctx->index); if (vv == NULL || vv->not_found) { return NGX_DECLINED; } len = vv->len; if (len == 0) { return NGX_DECLINED; } if (len > 1024) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "the value of the \"%V\" variable " "is more than 1024 bytes: \"%v\"", &ctx->var, vv); return NGX_DECLINED; } hash = ngx_crc32_short(vv->data, len); shpool = (ngx_slab_pool_t *) lircf->shm_zone->shm.addr; ngx_shmtx_lock(&shpool->mutex); node = ctx->rbtree->root; sentinel = ctx->rbtree->sentinel; while (node != sentinel) { if (hash < node->key) { node = node->left; continue; } if (hash > node->key) { node = node->right; continue; } /* hash == node->key */ do { lir = (ngx_http_limit_traffic_rate_filter_node_t *) &node->color; rc = ngx_memn2cmp(vv->data, lir->data, len, (size_t) lir->len); if (rc == 0) { ngx_queue_t *p = lir->rq_top.next; ngx_http_limit_traffic_rate_filter_request_queue_t * tr; for(; p; ){ tr = ngx_queue_data(p, ngx_http_limit_traffic_rate_filter_request_queue_t, rq); if(tr->r == r){ tr->r = NULL; ngx_queue_remove(p); ngx_slab_free_locked(shpool, tr); goto done; } if(ngx_queue_last(&lir->rq_top) == p){ break; } p = ngx_queue_next(p); } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "queue search fail: %08XD", node->key); } node = (rc < 0) ? node->left : node->right; } while (node != sentinel && hash == node->key); break; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "rbtree search fail: %08XD %d", node->key, r->limit_rate); done: ngx_shmtx_unlock(&shpool->mutex); return NGX_DECLINED; }
static ngx_flag_t ngx_http_push_stream_has_old_messages_to_send(ngx_http_push_stream_channel_t *channel, ngx_uint_t backtrack, time_t if_modified_since, ngx_int_t tag, time_t greater_message_time, ngx_int_t greater_message_tag, ngx_str_t *last_event_id) { ngx_flag_t old_messages = 0; ngx_http_push_stream_msg_t *message, *message_sentinel; message_sentinel = &channel->message_queue; message = message_sentinel; if (channel->stored_messages > 0) { if (backtrack > 0) { old_messages = 1; } else if ((last_event_id != NULL) || (if_modified_since >= 0)) { ngx_flag_t found = 0; while ((!message->deleted) && ((message = (ngx_http_push_stream_msg_t *) ngx_queue_next(&message->queue)) != message_sentinel)) { if ((!found) && (last_event_id != NULL) && (message->event_id != NULL) && (ngx_memn2cmp(message->event_id->data, last_event_id->data, message->event_id->len, last_event_id->len) == 0)) { found = 1; continue; } if ((!found) && (last_event_id == NULL) && (if_modified_since >= 0) && ((message->time > if_modified_since) || ((message->time == if_modified_since) && (tag >= 0) && (message->tag >= tag)))) { found = 1; if ((message->time == if_modified_since) && (message->tag == tag)) { continue; } } if (found) { old_messages = 1; break; } } } } return old_messages; }
void ngx_ssl_remove_cached_session(ngx_ssl_t *ssl, ngx_ssl_session_t *sess) { ngx_shm_zone_t *shm_zone; ngx_slab_pool_t *shpool; ngx_ssl_session_cache_t *cache; ngx_rbtree_node_t *node, *sentinel; ngx_ssl_sess_id_t *sess_id; int rc; uint32_t hash; shm_zone = ssl->cache_shm_zone; if (shm_zone == NULL) { return; } shpool = (ngx_slab_pool_t*) shm_zone->shm.addr; cache = shm_zone->data; hash = ngx_crc32_short(sess->id, sess->length); ngx_shmtx_lock(&shpool->mutex); node = cache->session_rbtree.root; sentinel = cache->session_rbtree.sentinel; while (node != sentinel) { if (hash < node->key) { node = node->left; continue; } if (hash > node->key) { node = node->right; continue; } /* hash == node->key */ sess_id = (ngx_ssl_sess_id_t *) node; rc = ngx_memn2cmp(sess->id, sess_id->session->id, sess->length, node->data); if (rc == 0) { ngx_queue_remove(&sess_id->queue); ngx_rbtree_delete(&cache->session_rbtree, node); ngx_slab_free_locked(shpool, sess_id->session); ngx_slab_free_locked(shpool, sess_id); goto done; } node = (rc < 0) ? node->left : node->right; } done: ngx_shmtx_unlock(&shpool->mutex); }
static ngx_int_t ngx_http_push_stream_validate_channels(ngx_http_request_t *r, ngx_http_push_stream_requested_channel_t *channels_ids, ngx_int_t *status_code, ngx_str_t **explain_error_message) { ngx_http_push_stream_main_conf_t *mcf = ngx_http_push_stream_module_main_conf; ngx_http_push_stream_loc_conf_t *cf = ngx_http_get_module_loc_conf(r, ngx_http_push_stream_module); ngx_http_push_stream_requested_channel_t *cur = channels_ids; ngx_uint_t subscribed_channels_qtd = 0; ngx_uint_t subscribed_broadcast_channels_qtd = 0; ngx_flag_t is_broadcast_channel; ngx_http_push_stream_channel_t *channel; while ((cur = (ngx_http_push_stream_requested_channel_t *) ngx_queue_next(&cur->queue)) != channels_ids) { // could not be ALL channel or contain wildcard if ((ngx_memn2cmp(cur->id->data, NGX_HTTP_PUSH_STREAM_ALL_CHANNELS_INFO_ID.data, cur->id->len, NGX_HTTP_PUSH_STREAM_ALL_CHANNELS_INFO_ID.len) == 0) || (ngx_strchr(cur->id->data, '*') != NULL)) { *status_code = NGX_HTTP_FORBIDDEN; *explain_error_message = (ngx_str_t *) &NGX_HTTP_PUSH_STREAM_NO_CHANNEL_ID_NOT_AUTHORIZED_MESSAGE; return NGX_ERROR; } // could not have a large size if ((mcf->max_channel_id_length != NGX_CONF_UNSET_UINT) && (cur->id->len > mcf->max_channel_id_length)) { ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "push stream module: channel id is larger than allowed %d", cur->id->len); *status_code = NGX_HTTP_BAD_REQUEST; *explain_error_message = (ngx_str_t *) &NGX_HTTP_PUSH_STREAM_TOO_LARGE_CHANNEL_ID_MESSAGE; return NGX_ERROR; } // count subscribed channel and broadcasts subscribed_channels_qtd++; is_broadcast_channel = 0; if ((mcf->broadcast_channel_prefix.len > 0) && (ngx_strncmp(cur->id->data, mcf->broadcast_channel_prefix.data, mcf->broadcast_channel_prefix.len) == 0)) { is_broadcast_channel = 1; subscribed_broadcast_channels_qtd++; } // check if channel exists when authorized_channels_only is on if (cf->authorized_channels_only && !is_broadcast_channel && (((channel = ngx_http_push_stream_find_channel(cur->id, r->connection->log)) == NULL) || (channel->stored_messages == 0))) { *status_code = NGX_HTTP_FORBIDDEN; *explain_error_message = (ngx_str_t *) &NGX_HTTP_PUSH_STREAM_CANNOT_CREATE_CHANNELS; return NGX_ERROR; } // check if channel is full of subscribers if ((mcf->max_subscribers_per_channel != NGX_CONF_UNSET_UINT) && (((channel = ngx_http_push_stream_find_channel(cur->id, r->connection->log)) != NULL) && (channel->subscribers >= mcf->max_subscribers_per_channel))) { *status_code = NGX_HTTP_FORBIDDEN; *explain_error_message = (ngx_str_t *) &NGX_HTTP_PUSH_STREAM_TOO_SUBSCRIBERS_PER_CHANNEL; return NGX_ERROR; } } // check if number of subscribed broadcast channels is acceptable if ((cf->broadcast_channel_max_qtd != NGX_CONF_UNSET_UINT) && (subscribed_broadcast_channels_qtd > 0) && ((subscribed_broadcast_channels_qtd > cf->broadcast_channel_max_qtd) || (subscribed_broadcast_channels_qtd == subscribed_channels_qtd))) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "push stream module: max subscribed broadcast channels exceeded"); *status_code = NGX_HTTP_FORBIDDEN; *explain_error_message = (ngx_str_t *) &NGX_HTTP_PUSH_STREAM_TOO_MUCH_BROADCAST_CHANNELS; return NGX_ERROR; } // create the channels in advance, if doesn't exist, to ensure max number of channels in the server cur = channels_ids; while ((cur = (ngx_http_push_stream_requested_channel_t *) ngx_queue_next(&cur->queue)) != channels_ids) { channel = ngx_http_push_stream_get_channel(cur->id, r->connection->log, cf); if (channel == NULL) { ngx_log_error(NGX_LOG_ERR, (r)->connection->log, 0, "push stream module: unable to allocate memory for new channel"); *status_code = NGX_HTTP_INTERNAL_SERVER_ERROR; *explain_error_message = NULL; return NGX_ERROR; } if (channel == NGX_HTTP_PUSH_STREAM_NUMBER_OF_CHANNELS_EXCEEDED) { ngx_log_error(NGX_LOG_ERR, (r)->connection->log, 0, "push stream module: number of channels were exceeded"); *status_code = NGX_HTTP_FORBIDDEN; *explain_error_message = (ngx_str_t *) &NGX_HTTP_PUSH_STREAM_NUMBER_OF_CHANNELS_EXCEEDED_MESSAGE; return NGX_ERROR; } } return NGX_OK; }
static ngx_int_t ngx_limit_tcp_lookup(ngx_connection_t *c, ngx_limit_tcp_ctx_t *ctx, ngx_uint_t *ep, ngx_limit_tcp_node_t **rnode) { size_t n; uint32_t hash; ngx_str_t addr; ngx_int_t rc, excess; ngx_time_t *tp; ngx_msec_t now; ngx_msec_int_t ms; ngx_rbtree_node_t *node, *sentinel; ngx_limit_tcp_node_t *lr; addr = c->addr_text; hash = ngx_crc32_short(addr.data, addr.len); node = ctx->sh->rbtree.root; sentinel = ctx->sh->rbtree.sentinel; rc = -1; while (node != sentinel) { if (hash < node->key) { node = node->left; continue; } if (hash > node->key) { node = node->right; continue; } /* hash == node->key */ lr = (ngx_limit_tcp_node_t *) &node->color; rc = ngx_memn2cmp(addr.data, lr->data, addr.len, (size_t) lr->len); if (rc == 0) { *rnode = lr; ngx_queue_remove(&lr->queue); ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0, "limit tcp count %ui %p", lr->count, c); if (ctx->concurrent && lr->count >= ctx->concurrent) { ngx_log_error(NGX_LOG_WARN, c->log, 0, "limit tcp %V over concurrent: %ui", &c->addr_text, lr->count); return NGX_BUSY; } (void) ngx_atomic_fetch_add(&lr->count, 1); if (!ctx->rate) { return NGX_OK; } tp = ngx_timeofday(); now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); ms = (ngx_msec_int_t) (now - lr->last); excess = lr->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000; if (excess < 0) { excess = 0; } *ep = excess; if ((ngx_uint_t) excess > ctx->burst) { ngx_log_error(NGX_LOG_WARN, c->log, 0, "limit %V over rate: %i", &c->addr_text, excess); (void) ngx_atomic_fetch_add(&lr->count, -1); return NGX_BUSY; } lr->excess = excess; lr->last = now; if (excess) { return NGX_AGAIN; } return NGX_OK; } node = (rc < 0) ? node->left : node->right; } *ep = 0; n = offsetof(ngx_rbtree_node_t, color) + offsetof(ngx_limit_tcp_node_t, data) + addr.len; node = ngx_slab_alloc_locked(ctx->shpool, n); if (node == NULL) { ngx_limit_tcp_expire(c, ctx, 0); node = ngx_slab_alloc_locked(ctx->shpool, n); if (node == NULL) { ngx_shmtx_unlock(&ctx->shpool->mutex); return NGX_ERROR; } } tp = ngx_timeofday(); lr = (ngx_limit_tcp_node_t *) &node->color; node->key = hash; lr->len = (u_char) addr.len; lr->excess = 0; lr->count = 1; lr->last = (ngx_msec_t) (tp->sec * 1000 + tp->msec); ngx_memcpy(lr->data, addr.data, addr.len); ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); ngx_rbtree_insert(&ctx->sh->rbtree, node); ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0, "limit tcp new %ui %uV", lr->count, &addr); *rnode = lr; return NGX_OK; }
//ngx_http_upstream_free_keepalive_peer往kp->conf->cache中添加缓存ngx_connection_t,ngx_http_upstream_get_keepalive_peer从缓存中 //取出和后端的连接缓存ngx_connection_t,可以避免重复的建立和关闭TCP连接 static ngx_int_t ngx_http_upstream_get_keepalive_peer(ngx_peer_connection_t *pc, void *data) { ngx_http_upstream_keepalive_peer_data_t *kp = data; ngx_http_upstream_keepalive_cache_t *item; ngx_int_t rc; ngx_queue_t *q, *cache; ngx_connection_t *c; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "get keepalive peer"); /* ask balancer */ // 先调用原始getpeer钩子(ngx_http_upstream_get_round_robin_peer)选择后端 rc = kp->original_get_peer(pc, kp->data); if (rc != NGX_OK) { return rc; } /* search cache for suitable connection */ cache = &kp->conf->cache; // 根据socket地址查找连接cache池,找到直接返回NGX_DONE,上层调用就不会获取新的连接 for (q = ngx_queue_head(cache); q != ngx_queue_sentinel(cache); q = ngx_queue_next(q)) { item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue); c = item->connection; if (ngx_memn2cmp((u_char *) &item->sockaddr, (u_char *) pc->sockaddr, item->socklen, pc->socklen) == 0) { ngx_queue_remove(q); ngx_queue_insert_head(&kp->conf->free, q); goto found; } } return NGX_OK; found: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "get keepalive peer: using connection %p", c); c->idle = 0; c->sent = 0; c->log = pc->log; c->read->log = pc->log; c->write->log = pc->log; c->pool->log = pc->log; pc->connection = c; pc->cached = 1; return NGX_DONE; }
static ngx_int_t ngx_http_limit_traffic_rate_filter_handler(ngx_http_request_t *r) { size_t len, n; uint32_t hash; ngx_int_t rc; ngx_slab_pool_t *shpool; ngx_rbtree_node_t *node, *sentinel; ngx_pool_cleanup_t *cln; ngx_http_variable_value_t *vv; ngx_http_limit_traffic_rate_filter_ctx_t *ctx; ngx_http_limit_traffic_rate_filter_node_t *lir; ngx_http_limit_traffic_rate_filter_conf_t *lircf; ngx_http_limit_traffic_rate_filter_cleanup_t *lircln; ngx_http_core_loc_conf_t *clcf; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); lircf = ngx_http_get_module_loc_conf(r, ngx_http_limit_traffic_rate_filter_module); if (lircf->shm_zone == NULL) { return NGX_DECLINED; } ctx = lircf->shm_zone->data; vv = ngx_http_get_indexed_variable(r, ctx->index); if (vv == NULL || vv->not_found) { return NGX_DECLINED; } len = vv->len; if (len == 0) { return NGX_DECLINED; } if (len > 1024) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "the value of the \"%V\" variable " "is more than 1024 bytes: \"%v\"", &ctx->var, vv); return NGX_DECLINED; } hash = ngx_crc32_short(vv->data, len); cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_limit_traffic_rate_filter_cleanup_t)); if (cln == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } shpool = (ngx_slab_pool_t *) lircf->shm_zone->shm.addr; ngx_shmtx_lock(&shpool->mutex); node = ctx->rbtree->root; sentinel = ctx->rbtree->sentinel; while (node != sentinel) { if (hash < node->key) { node = node->left; continue; } if (hash > node->key) { node = node->right; continue; } /* hash == node->key */ do { lir = (ngx_http_limit_traffic_rate_filter_node_t *) &node->color; rc = ngx_memn2cmp(vv->data, lir->data, len, (size_t) lir->len); if (rc == 0) { lir->conn++; ngx_http_limit_traffic_rate_filter_request_queue_t *req; req = ngx_slab_alloc_locked(shpool, sizeof(ngx_http_limit_traffic_rate_filter_request_queue_t)); if (node == NULL) { ngx_shmtx_unlock(&shpool->mutex); return NGX_HTTP_SERVICE_UNAVAILABLE; } req->r = r; req->last_time = *ngx_cached_time; req->last_last_time = *ngx_cached_time; req->last_sent = 0; req->last_last_sent = 0; clcf->sendfile_max_chunk = lircf->limit_traffic_rate / lir->conn; ngx_queue_insert_tail(&(lir->rq_top), &req->rq); goto done; } node = (rc < 0) ? node->left : node->right; } while (node != sentinel && hash == node->key); break; } n = offsetof(ngx_rbtree_node_t, color) + offsetof(ngx_http_limit_traffic_rate_filter_node_t, data) + len; node = ngx_slab_alloc_locked(shpool, n); if (node == NULL) { ngx_shmtx_unlock(&shpool->mutex); return NGX_HTTP_SERVICE_UNAVAILABLE; } lir = (ngx_http_limit_traffic_rate_filter_node_t *) &node->color; node->key = hash; lir->len = (u_short) len; lir->conn = 1; lir->start_sec = r->start_sec; ngx_queue_init(&(lir->rq_top)); ngx_http_limit_traffic_rate_filter_request_queue_t *req; req = ngx_slab_alloc_locked(shpool, sizeof(ngx_http_limit_traffic_rate_filter_request_queue_t)); if (req == NULL) { ngx_shmtx_unlock(&shpool->mutex); return NGX_HTTP_SERVICE_UNAVAILABLE; } req->r = r; req->last_time = *ngx_cached_time; req->last_last_time = *ngx_cached_time; req->last_sent = 0; req->last_last_sent = 0; clcf->sendfile_max_chunk = lircf->limit_traffic_rate / lir->conn; ngx_queue_insert_tail(&(lir->rq_top), &req->rq); ngx_memcpy(lir->data, vv->data, len); ngx_rbtree_insert(ctx->rbtree, node); done: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "limit traffic rate: %08XD %d", node->key, lir->conn); ngx_shmtx_unlock(&shpool->mutex); cln->handler = ngx_http_limit_traffic_rate_filter_cleanup; lircln = cln->data; lircln->shm_zone = lircf->shm_zone; lircln->node = node; return NGX_DECLINED; }
static ngx_int_t ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lrcf, ngx_uint_t hash, u_char *data, size_t len, ngx_uint_t *ep) { ngx_int_t rc, excess; ngx_time_t *tp; ngx_msec_t now; ngx_msec_int_t ms; ngx_rbtree_node_t *node, *sentinel; ngx_http_limit_req_ctx_t *ctx; ngx_http_limit_req_node_t *lr; ctx = lrcf->shm_zone->data; node = ctx->sh->rbtree.root; sentinel = ctx->sh->rbtree.sentinel; while (node != sentinel) { if (hash < node->key) { node = node->left; continue; } if (hash > node->key) { node = node->right; continue; } /* hash == node->key */ lr = (ngx_http_limit_req_node_t *) &node->color; rc = ngx_memn2cmp(data, lr->data, len, (size_t) lr->len); if (rc == 0) { ngx_queue_remove(&lr->queue); ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); tp = ngx_timeofday(); now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); ms = (ngx_msec_int_t) (now - lr->last); excess = lr->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000; if (excess < 0) { excess = 0; } *ep = excess; if ((ngx_uint_t) excess > lrcf->burst) { return NGX_BUSY; } lr->excess = excess; lr->last = now; if (excess) { return NGX_AGAIN; } return NGX_OK; } node = (rc < 0) ? node->left : node->right; } *ep = 0; return NGX_DECLINED; }
static ngx_int_t ngx_http_limit_traffic_rate_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { size_t len; uint32_t hash; ngx_int_t rc; ngx_uint_t delta_msec; ngx_msec_t delay = 0; ngx_slab_pool_t *shpool; ngx_rbtree_node_t *node, *sentinel; ngx_http_variable_value_t *vv; ngx_http_limit_traffic_rate_filter_ctx_t *ctx; ngx_http_limit_traffic_rate_filter_node_t *lir; ngx_http_limit_traffic_rate_filter_conf_t *lircf; ngx_http_core_loc_conf_t *clcf; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "limit traffic rate filter"); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); lircf = ngx_http_get_module_loc_conf(r, ngx_http_limit_traffic_rate_filter_module); if (lircf->shm_zone == NULL) { return ngx_http_next_body_filter(r, in); } ctx = lircf->shm_zone->data; vv = ngx_http_get_indexed_variable(r, ctx->index); if (vv == NULL || vv->not_found) { return ngx_http_next_body_filter(r, in); } len = vv->len; if (len == 0) { return ngx_http_next_body_filter(r, in); } if (len > 1024) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "the value of the \"%V\" variable " "is more than 1024 bytes: \"%v\"", &ctx->var, vv); return ngx_http_next_body_filter(r, in); } hash = ngx_crc32_short(vv->data, len); shpool = (ngx_slab_pool_t *) lircf->shm_zone->shm.addr; ngx_shmtx_lock(&shpool->mutex); node = ctx->rbtree->root; sentinel = ctx->rbtree->sentinel; while (node != sentinel) { if (hash < node->key) { node = node->left; continue; } if (hash > node->key) { node = node->right; continue; } /* hash == node->key */ do { lir = (ngx_http_limit_traffic_rate_filter_node_t *) &node->color; rc = ngx_memn2cmp(vv->data, lir->data, len, (size_t) lir->len); if (rc == 0) { ngx_queue_t *p = lir->rq_top.next; ngx_http_limit_traffic_rate_filter_request_queue_t * tr; clcf->sendfile_max_chunk = lircf->limit_traffic_rate / lir->conn; for(; p; ){ tr = ngx_queue_data(p, ngx_http_limit_traffic_rate_filter_request_queue_t, rq); if(tr->r == r) { tr->last_last_sent = tr->last_sent; tr->last_last_time = tr->last_time; tr->last_sent = r->connection->sent; tr->last_time = *ngx_cached_time; delta_msec = tr->last_time.sec * 1000 + tr->last_time.msec - tr->last_last_time.sec * 1000 - tr->last_last_time.msec; if ( tr->last_sent - tr->last_last_sent > lircf->limit_traffic_rate/lir->conn ) { /* first second */ delay = (ngx_msec_t) ((tr->last_sent - tr->last_last_sent) *1000 / (lircf->limit_traffic_rate/lir->conn)); }else if (tr->last_time.sec == tr->last_last_time.sec && tr->last_time.msec == tr->last_last_time.msec){ /* first in, let download go */ break; } else if ( (tr->last_sent - tr->last_last_sent)*1000 / delta_msec > lircf->limit_traffic_rate/lir->conn ) { delay = (ngx_msec_t) ((tr->last_sent - tr->last_last_sent) *1000 / (lircf->limit_traffic_rate/lir->conn)); } break; } if(ngx_queue_last(&lir->rq_top) == p){ break; } p = ngx_queue_next(p); } goto done; } node = (rc < 0) ? node->left : node->right; } while (node != sentinel && hash == node->key); break; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "rbtree search fail: %08XD %d", node->key, r->limit_rate); done: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "limit traffic rate: %08XD %d", node->key, delay); ngx_shmtx_unlock(&shpool->mutex); if (delay > 0) { r->connection->write->delayed = 1; ngx_add_timer(r->connection->write, delay); return NGX_OK; } return ngx_http_next_body_filter(r, in); }
static void ngx_http_push_stream_send_old_messages(ngx_http_request_t *r, ngx_http_push_stream_channel_t *channel, ngx_uint_t backtrack, time_t if_modified_since, ngx_int_t tag, time_t greater_message_time, ngx_int_t greater_message_tag, ngx_str_t *last_event_id) { ngx_http_push_stream_msg_t *message; ngx_queue_t *cur; if (ngx_http_push_stream_has_old_messages_to_send(channel, backtrack, if_modified_since, tag, greater_message_time, greater_message_tag, last_event_id)) { cur = &channel->message_queue; if (backtrack > 0) { ngx_uint_t qtd = (backtrack > channel->stored_messages) ? channel->stored_messages : backtrack; ngx_uint_t start = channel->stored_messages - qtd; // positioning at first message, and send the others while ((qtd > 0) && (cur = ngx_queue_next(cur)) && (cur != NULL) && (cur != &channel->message_queue)) { message = (ngx_http_push_stream_msg_t *) ngx_queue_data(cur, ngx_http_push_stream_msg_t, queue); if (message->deleted) { break; } if (start == 0) { ngx_http_push_stream_send_response_message(r, channel, message, 0, 1); qtd--; } else { start--; } } } else if ((last_event_id != NULL) || (if_modified_since >= 0)) { ngx_flag_t found = 0; while ((cur = ngx_queue_next(cur)) && (cur != NULL) && (cur != &channel->message_queue)) { message = (ngx_http_push_stream_msg_t *) ngx_queue_data(cur, ngx_http_push_stream_msg_t, queue); if (message->deleted) { break; } if ((!found) && (last_event_id != NULL) && (message->event_id != NULL) && (ngx_memn2cmp(message->event_id->data, last_event_id->data, message->event_id->len, last_event_id->len) == 0)) { found = 1; continue; } if ((!found) && (if_modified_since >= 0) && ((message->time > if_modified_since) || ((message->time == if_modified_since) && (tag >= 0) && (message->tag >= tag)))) { found = 1; if ((message->time == if_modified_since) && (message->tag == tag)) { continue; } } if (found && (((greater_message_time == 0) && (greater_message_tag == -1)) || (greater_message_time > message->time) || ((greater_message_time == message->time) && (greater_message_tag >= message->tag)))) { ngx_http_push_stream_send_response_message(r, channel, message, 0, 1); } } } } }
static ngx_int_t ngx_http_limit_req_lookup(ngx_http_limit_req_limit_t *limit, ngx_uint_t hash, ngx_str_t *key, ngx_uint_t *ep, ngx_uint_t account) { size_t size; ngx_int_t rc, excess; ngx_time_t *tp; ngx_msec_t now; ngx_msec_int_t ms; ngx_rbtree_node_t *node, *sentinel; ngx_http_limit_req_ctx_t *ctx; ngx_http_limit_req_node_t *lr; tp = ngx_timeofday(); now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); ctx = limit->shm_zone->data; node = ctx->sh->rbtree.root; sentinel = ctx->sh->rbtree.sentinel; while (node != sentinel) { if (hash < node->key) { node = node->left; continue; } if (hash > node->key) { node = node->right; continue; } /* hash == node->key */ lr = (ngx_http_limit_req_node_t *) &node->color; rc = ngx_memn2cmp(key->data, lr->data, key->len, (size_t) lr->len); if (rc == 0) { ngx_queue_remove(&lr->queue); ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); ms = (ngx_msec_int_t) (now - lr->last); excess = lr->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000; if (excess < 0) { excess = 0; } *ep = excess; if ((ngx_uint_t) excess > limit->burst) { return NGX_BUSY; } if (account) { lr->excess = excess; lr->last = now; return NGX_OK; } lr->count++; ctx->node = lr; return NGX_AGAIN; } node = (rc < 0) ? node->left : node->right; } *ep = 0; size = offsetof(ngx_rbtree_node_t, color) + offsetof(ngx_http_limit_req_node_t, data) + key->len; ngx_http_limit_req_expire(ctx, 1); node = ngx_slab_alloc_locked(ctx->shpool, size); if (node == NULL) { ngx_http_limit_req_expire(ctx, 0); node = ngx_slab_alloc_locked(ctx->shpool, size); if (node == NULL) { ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "could not allocate node%s", ctx->shpool->log_ctx); return NGX_ERROR; } } node->key = hash; lr = (ngx_http_limit_req_node_t *) &node->color; lr->len = (u_short) key->len; lr->excess = 0; ngx_memcpy(lr->data, key->data, key->len); ngx_rbtree_insert(&ctx->sh->rbtree, node); ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); if (account) { lr->last = now; lr->count = 0; return NGX_OK; } lr->last = 0; lr->count = 1; ctx->node = lr; return NGX_AGAIN; }
static ngx_int_t ngx_http_limit_traffic_rate_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { size_t len; time_t sec; uint32_t hash; ngx_int_t rc, num; ngx_slab_pool_t *shpool; ngx_rbtree_node_t *node, *sentinel; ngx_http_variable_value_t *vv; ngx_http_limit_traffic_rate_filter_ctx_t *ctx; ngx_http_limit_traffic_rate_filter_node_t *lir; ngx_http_limit_traffic_rate_filter_conf_t *lircf; off_t sent_sum = 0; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "limit traffic rate filter"); lircf = ngx_http_get_module_loc_conf(r, ngx_http_limit_traffic_rate_filter_module); if (lircf->shm_zone == NULL) { return ngx_http_next_body_filter(r, in); } ctx = lircf->shm_zone->data; vv = ngx_http_get_indexed_variable(r, ctx->index); if (vv == NULL || vv->not_found) { return ngx_http_next_body_filter(r, in); } len = vv->len; if (len == 0) { return ngx_http_next_body_filter(r, in); } if (len > 1024) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "the value of the \"%V\" variable " "is more than 1024 bytes: \"%v\"", &ctx->var, vv); return ngx_http_next_body_filter(r, in); } hash = ngx_crc32_short(vv->data, len); shpool = (ngx_slab_pool_t *) lircf->shm_zone->shm.addr; ngx_shmtx_lock(&shpool->mutex); node = ctx->rbtree->root; sentinel = ctx->rbtree->sentinel; while (node != sentinel) { if (hash < node->key) { node = node->left; continue; } if (hash > node->key) { node = node->right; continue; } /* hash == node->key */ do { lir = (ngx_http_limit_traffic_rate_filter_node_t *) &node->color; rc = ngx_memn2cmp(vv->data, lir->data, len, (size_t) lir->len); if (rc == 0) { /* r->limit_rate = lircf->limit_traffic_rate / lir->conn; */ ngx_queue_t *p = lir->rq_top.next; ngx_http_limit_traffic_rate_filter_request_queue_t * tr; for(; p; ){ tr = ngx_queue_data(p, ngx_http_limit_traffic_rate_filter_request_queue_t, rq); if(tr->r == r) tr->sent = r->connection->sent; sent_sum += tr->sent; if(ngx_queue_last(&lir->rq_top) == p){ break; } p = ngx_queue_next(p); } sec = ngx_time() - lir->start_sec + 1; sec = sec > 0 ? sec : 1; num =lircf->limit_traffic_rate - sent_sum / sec; num =num / lir->conn + r->connection->sent / sec; num = num > 0 ? num : 1024; num = ((size_t)num >lircf->limit_traffic_rate) ? (ngx_int_t)lircf->limit_traffic_rate : num; r->limit_rate = num; ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "limit traffic d:%z n:%O c:%d r:%z:::%z", lircf->limit_traffic_rate, sent_sum, lir->conn, lir->start_sec,r->limit_rate); goto done; } node = (rc < 0) ? node->left : node->right; } while (node != sentinel && hash == node->key); break; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "rbtree search fail: %08XD %d", node->key, r->limit_rate); done: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "limit traffic rate: %08XD %d", node->key, r->limit_rate); ngx_shmtx_unlock(&shpool->mutex); return ngx_http_next_body_filter(r, in); }
static ngx_int_t ngx_http_limit_zone_handler(ngx_http_request_t *r) { size_t len, n; uint32_t hash; ngx_int_t rc; ngx_slab_pool_t *shpool; ngx_rbtree_node_t *node, *sentinel; ngx_pool_cleanup_t *cln; ngx_http_variable_value_t *vv; ngx_http_limit_zone_ctx_t *ctx; ngx_http_limit_zone_node_t *lz; ngx_http_limit_zone_conf_t *lzcf; ngx_http_limit_zone_cleanup_t *lzcln; if (r->main->limit_zone_set) { return NGX_DECLINED; } lzcf = ngx_http_get_module_loc_conf(r, ngx_http_limit_zone_module); if (lzcf->shm_zone == NULL) { return NGX_DECLINED; } ctx = lzcf->shm_zone->data; vv = ngx_http_get_indexed_variable(r, ctx->index); if (vv == NULL || vv->not_found) { return NGX_DECLINED; } len = vv->len; if (len == 0) { return NGX_DECLINED; } if (len > 255) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "the value of the \"%V\" variable " "is more than 255 bytes: \"%v\"", &ctx->var, vv); return NGX_DECLINED; } r->main->limit_zone_set = 1; hash = ngx_crc32_short(vv->data, len); cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_limit_zone_cleanup_t)); if (cln == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } shpool = (ngx_slab_pool_t *) lzcf->shm_zone->shm.addr; ngx_shmtx_lock(&shpool->mutex); node = ctx->rbtree->root; sentinel = ctx->rbtree->sentinel; while (node != sentinel) { if (hash < node->key) { node = node->left; continue; } if (hash > node->key) { node = node->right; continue; } /* hash == node->key */ do { lz = (ngx_http_limit_zone_node_t *) &node->color; rc = ngx_memn2cmp(vv->data, lz->data, len, (size_t) lz->len); if (rc == 0) { if ((ngx_uint_t) lz->conn < lzcf->conn) { lz->conn++; goto done; } ngx_shmtx_unlock(&shpool->mutex); ngx_log_error(lzcf->log_level, r->connection->log, 0, "limiting connections by zone \"%V\"", &lzcf->shm_zone->shm.name); return NGX_HTTP_SERVICE_UNAVAILABLE; } node = (rc < 0) ? node->left : node->right; } while (node != sentinel && hash == node->key); break; } n = offsetof(ngx_rbtree_node_t, color) + offsetof(ngx_http_limit_zone_node_t, data) + len; node = ngx_slab_alloc_locked(shpool, n); if (node == NULL) { ngx_shmtx_unlock(&shpool->mutex); return NGX_HTTP_SERVICE_UNAVAILABLE; } lz = (ngx_http_limit_zone_node_t *) &node->color; node->key = hash; lz->len = (u_char) len; lz->conn = 1; ngx_memcpy(lz->data, vv->data, len); ngx_rbtree_insert(ctx->rbtree, node); done: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "limit zone: %08XD %d", node->key, lz->conn); ngx_shmtx_unlock(&shpool->mutex); cln->handler = ngx_http_limit_zone_cleanup; lzcln = cln->data; lzcln->shm_zone = lzcf->shm_zone; lzcln->node = node; return NGX_DECLINED; }
static ngx_int_t ngx_http_push_stream_validate_channels(ngx_http_request_t *r, ngx_http_push_stream_requested_channel_t *requested_channels, ngx_int_t *status_code, ngx_str_t **explain_error_message) { ngx_http_push_stream_main_conf_t *mcf = ngx_http_get_module_main_conf(r, ngx_http_push_stream_module); ngx_http_push_stream_loc_conf_t *cf = ngx_http_get_module_loc_conf(r, ngx_http_push_stream_module); ngx_http_push_stream_requested_channel_t *requested_channel; ngx_queue_t *q; ngx_uint_t subscribed_channels_qtd = 0; ngx_uint_t subscribed_wildcard_channels_qtd = 0; ngx_flag_t is_wildcard_channel; for (q = ngx_queue_head(&requested_channels->queue); q != ngx_queue_sentinel(&requested_channels->queue); q = ngx_queue_next(q)) { requested_channel = ngx_queue_data(q, ngx_http_push_stream_requested_channel_t, queue); // could not be ALL channel or contain wildcard if ((ngx_memn2cmp(requested_channel->id->data, NGX_HTTP_PUSH_STREAM_ALL_CHANNELS_INFO_ID.data, requested_channel->id->len, NGX_HTTP_PUSH_STREAM_ALL_CHANNELS_INFO_ID.len) == 0) || (ngx_strchr(requested_channel->id->data, '*') != NULL)) { *status_code = NGX_HTTP_FORBIDDEN; *explain_error_message = (ngx_str_t *) &NGX_HTTP_PUSH_STREAM_CHANNEL_ID_NOT_AUTHORIZED_MESSAGE; return NGX_ERROR; } // could not have a large size if ((mcf->max_channel_id_length != NGX_CONF_UNSET_UINT) && (requested_channel->id->len > mcf->max_channel_id_length)) { ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "push stream module: channel id is larger than allowed %d", requested_channel->id->len); *status_code = NGX_HTTP_BAD_REQUEST; *explain_error_message = (ngx_str_t *) &NGX_HTTP_PUSH_STREAM_TOO_LARGE_CHANNEL_ID_MESSAGE; return NGX_ERROR; } // count subscribed normal and wildcard channels subscribed_channels_qtd++; is_wildcard_channel = 0; if ((mcf->wildcard_channel_prefix.len > 0) && (ngx_strncmp(requested_channel->id->data, mcf->wildcard_channel_prefix.data, mcf->wildcard_channel_prefix.len) == 0)) { is_wildcard_channel = 1; subscribed_wildcard_channels_qtd++; } requested_channel->channel = ngx_http_push_stream_find_channel(requested_channel->id, r->connection->log, mcf); // check if channel exists when authorized_channels_only is on if (cf->authorized_channels_only && !is_wildcard_channel && ((requested_channel->channel == NULL) || (requested_channel->channel->stored_messages == 0))) { *status_code = NGX_HTTP_FORBIDDEN; *explain_error_message = (ngx_str_t *) &NGX_HTTP_PUSH_STREAM_CANNOT_CREATE_CHANNELS; return NGX_ERROR; } // check if channel is full of subscribers if ((mcf->max_subscribers_per_channel != NGX_CONF_UNSET_UINT) && ((requested_channel->channel != NULL) && (requested_channel->channel->subscribers >= mcf->max_subscribers_per_channel))) { *status_code = NGX_HTTP_FORBIDDEN; *explain_error_message = (ngx_str_t *) &NGX_HTTP_PUSH_STREAM_TOO_SUBSCRIBERS_PER_CHANNEL; return NGX_ERROR; } // check if is allowed to connect to events channel if (!cf->allow_connections_to_events_channel && (requested_channel->channel != NULL) && requested_channel->channel->for_events) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "push stream module: subscription to events channel is not allowed"); *status_code = NGX_HTTP_FORBIDDEN; *explain_error_message = (ngx_str_t *) &NGX_HTTP_PUSH_STREAM_SUBSCRIPTION_EVENTS_CHANNEL_FORBIDDEN_MESSAGE; return NGX_ERROR; } } // check if number of subscribed wildcard channels is acceptable if ((cf->wildcard_channel_max_qtd != NGX_CONF_UNSET_UINT) && (subscribed_wildcard_channels_qtd > 0) && ((subscribed_wildcard_channels_qtd > cf->wildcard_channel_max_qtd) || (subscribed_wildcard_channels_qtd == subscribed_channels_qtd))) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "push stream module: max subscribed wildcard channels exceeded"); *status_code = NGX_HTTP_FORBIDDEN; *explain_error_message = (ngx_str_t *) &NGX_HTTP_PUSH_STREAM_TOO_MUCH_WILDCARD_CHANNELS; return NGX_ERROR; } // create the channels in advance, if doesn't exist, to ensure max number of channels in the server for (q = ngx_queue_head(&requested_channels->queue); q != ngx_queue_sentinel(&requested_channels->queue); q = ngx_queue_next(q)) { requested_channel = ngx_queue_data(q, ngx_http_push_stream_requested_channel_t, queue); if (requested_channel->channel != NULL) { continue; } requested_channel->channel = ngx_http_push_stream_get_channel(requested_channel->id, r->connection->log, mcf); if (requested_channel->channel == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "push stream module: unable to allocate memory for new channel"); *status_code = NGX_HTTP_INTERNAL_SERVER_ERROR; *explain_error_message = (ngx_str_t *) &NGX_HTTP_PUSH_STREAM_EMPTY; return NGX_ERROR; } if (requested_channel->channel == NGX_HTTP_PUSH_STREAM_NUMBER_OF_CHANNELS_EXCEEDED) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "push stream module: number of channels were exceeded"); *status_code = NGX_HTTP_FORBIDDEN; *explain_error_message = (ngx_str_t *) &NGX_HTTP_PUSH_STREAM_NUMBER_OF_CHANNELS_EXCEEDED_MESSAGE; return NGX_ERROR; } } return NGX_OK; }
static ngx_int_t ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lzcf, ngx_uint_t hash, u_char *data, size_t len, ngx_http_limit_req_node_t **lzp) { ngx_int_t rc, excess; ngx_time_t *tp; ngx_msec_t now; ngx_msec_int_t ms; ngx_rbtree_node_t *node, *sentinel; ngx_http_limit_req_ctx_t *ctx; ngx_http_limit_req_node_t *lz; ctx = lzcf->shm_zone->data; node = ctx->rbtree->root; sentinel = ctx->rbtree->sentinel; while (node != sentinel) { if (hash < node->key) { node = node->left; continue; } if (hash > node->key) { node = node->right; continue; } /* hash == node->key */ do { lz = (ngx_http_limit_req_node_t *) &node->color; rc = ngx_memn2cmp(data, lz->data, len, (size_t) lz->len); if (rc == 0) { tp = ngx_timeofday(); now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); ms = (ngx_msec_int_t) (now - lz->last); excess = lz->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000; if (excess < 0) { excess = 0; } lz->excess = excess; lz->last = now; *lzp = lz; if ((ngx_uint_t) excess > lzcf->burst) { return NGX_BUSY; } if (excess) { return NGX_AGAIN; } return NGX_OK; } node = (rc < 0) ? node->left : node->right; } while (node != sentinel && hash == node->key); break; } *lzp = NULL; return NGX_DECLINED; }
static ngx_flag_t ngx_http_push_stream_has_old_messages_to_send(ngx_http_push_stream_channel_t *channel, ngx_uint_t backtrack, time_t if_modified_since, ngx_int_t tag, time_t greater_message_time, ngx_int_t greater_message_tag, ngx_str_t *last_event_id) { ngx_flag_t old_messages = 0; ngx_http_push_stream_msg_t *message; ngx_queue_t *q; if (channel->stored_messages > 0) { if (backtrack > 0) { old_messages = 1; } else if ((last_event_id != NULL) || (if_modified_since >= 0)) { ngx_flag_t found = 0; ngx_shmtx_lock(channel->mutex); for (q = ngx_queue_head(&channel->message_queue); q != ngx_queue_sentinel(&channel->message_queue); q = ngx_queue_next(q)) { message = ngx_queue_data(q, ngx_http_push_stream_msg_t, queue); if (message->deleted) { break; } if ((!found) && (last_event_id != NULL) && (message->event_id != NULL) && (ngx_memn2cmp(message->event_id->data, last_event_id->data, message->event_id->len, last_event_id->len) == 0)) { found = 1; continue; } if ((!found) && (if_modified_since >= 0) && ((message->time > if_modified_since) || ((message->time == if_modified_since) && (tag >= 0) && (message->tag >= tag)))) { found = 1; if ((message->time == if_modified_since) && (message->tag == tag)) { continue; } } if (found) { old_messages = 1; break; } } ngx_shmtx_unlock(channel->mutex); } } return old_messages; }
static ngx_int_t ngx_http_lua_shdict_lookup(ngx_shm_zone_t *shm_zone, ngx_uint_t hash, u_char *kdata, size_t klen, ngx_http_lua_shdict_node_t **sdp) { ngx_int_t rc; ngx_time_t *tp; uint64_t now; int64_t ms; ngx_rbtree_node_t *node, *sentinel; ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; ctx = shm_zone->data; node = ctx->sh->rbtree.root; sentinel = ctx->sh->rbtree.sentinel; while (node != sentinel) { if (hash < node->key) { node = node->left; continue; } if (hash > node->key) { node = node->right; continue; } /* hash == node->key */ sd = (ngx_http_lua_shdict_node_t *) &node->color; rc = ngx_memn2cmp(kdata, sd->data, klen, (size_t) sd->key_len); if (rc == 0) { ngx_queue_remove(&sd->queue); ngx_queue_insert_head(&ctx->sh->queue, &sd->queue); *sdp = sd; dd("node expires: %lld", (long long) sd->expires); if (sd->expires != 0) { tp = ngx_timeofday(); now = (uint64_t) tp->sec * 1000 + tp->msec; ms = sd->expires - now; dd("time to live: %lld", (long long) ms); if (ms < 0) { dd("node already expired"); return NGX_DONE; } } return NGX_OK; } node = (rc < 0) ? node->left : node->right; } *sdp = NULL; return NGX_DECLINED; }
static void ngx_http_push_stream_send_old_messages(ngx_http_request_t *r, ngx_http_push_stream_channel_t *channel, ngx_uint_t backtrack, time_t if_modified_since, ngx_int_t tag, time_t greater_message_time, ngx_int_t greater_message_tag, ngx_str_t *last_event_id) { ngx_http_push_stream_module_ctx_t *ctx = ngx_http_get_module_ctx(r, ngx_http_push_stream_module); ngx_http_push_stream_msg_t *message; ngx_queue_t *q; if (ngx_http_push_stream_has_old_messages_to_send(channel, backtrack, if_modified_since, tag, greater_message_time, greater_message_tag, last_event_id)) { if (backtrack > 0) { ngx_uint_t qtd = (backtrack > channel->stored_messages) ? channel->stored_messages : backtrack; ngx_uint_t start = channel->stored_messages - qtd; ngx_shmtx_lock(channel->mutex); // positioning at first message, and send the others for (q = ngx_queue_head(&channel->message_queue); (qtd > 0) && q != ngx_queue_sentinel(&channel->message_queue); q = ngx_queue_next(q)) { message = ngx_queue_data(q, ngx_http_push_stream_msg_t, queue); if (message->deleted) { break; } if (start == 0) { qtd--; ngx_http_push_stream_send_response_message(r, channel, message, 0, ctx->message_sent); } else { start--; } } ngx_shmtx_unlock(channel->mutex); } else if ((last_event_id != NULL) || (if_modified_since >= 0)) { ngx_flag_t found = 0; ngx_shmtx_lock(channel->mutex); for (q = ngx_queue_head(&channel->message_queue); q != ngx_queue_sentinel(&channel->message_queue); q = ngx_queue_next(q)) { message = ngx_queue_data(q, ngx_http_push_stream_msg_t, queue); if (message->deleted) { break; } if ((!found) && (last_event_id != NULL) && (message->event_id != NULL) && (ngx_memn2cmp(message->event_id->data, last_event_id->data, message->event_id->len, last_event_id->len) == 0)) { found = 1; continue; } if ((!found) && (if_modified_since >= 0) && ((message->time > if_modified_since) || ((message->time == if_modified_since) && (tag >= 0) && (message->tag >= tag)))) { found = 1; if ((message->time == if_modified_since) && (message->tag == tag)) { continue; } } if (found && (((greater_message_time == 0) && (greater_message_tag == -1)) || (greater_message_time > message->time) || ((greater_message_time == message->time) && (greater_message_tag >= message->tag)))) { ngx_http_push_stream_send_response_message(r, channel, message, 0, ctx->message_sent); } } ngx_shmtx_unlock(channel->mutex); } } }
ngx_int_t ngx_http_connection_pool_get(ngx_peer_connection_t *pc, void *data) { u_char pc_addr[32] = {'\0'}; ngx_uint_t bucket_id, hash; ngx_queue_t *q, *cache, *free; ngx_connection_t *c; ngx_http_connection_pool_t *p; ngx_http_connection_pool_elt_t *item; p = data; #if (NGX_DEBUG) p->count--; #endif ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "get keepalive peer"); p->failed = 0; hash = ngx_murmur_hash2((u_char *) pc->sockaddr, pc->socklen); bucket_id = hash % p->bucket_count; cache = &p->cache[bucket_id]; free = &p->free[bucket_id]; ngx_sprintf(pc_addr, "%s:%d", inet_ntoa(((struct sockaddr_in*)(pc->sockaddr))->sin_addr), ntohs(((struct sockaddr_in*)(pc->sockaddr))->sin_port)); for (q = ngx_queue_head(cache); q != ngx_queue_sentinel(cache); q = ngx_queue_next(q)) { item = ngx_queue_data(q, ngx_http_connection_pool_elt_t, queue); c = item->connection; if (ngx_memn2cmp((u_char *) &item->sockaddr, (u_char *) pc->sockaddr, item->socklen, pc->socklen) == 0) { ngx_queue_remove(q); ngx_queue_insert_head(free, q); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "get keepalive peer: using connection %p", c); c->idle = 0; c->log = pc->log; c->read->log = pc->log; c->write->log = pc->log; c->pool->log = pc->log; pc->connection = c; pc->cached = 1; item->free = free; return NGX_DONE; } } return NGX_OK; }
static ngx_flag_t ngx_http_push_stream_has_old_messages_to_send(ngx_http_push_stream_channel_t *channel, ngx_uint_t backtrack, time_t if_modified_since, ngx_int_t tag, time_t greater_message_time, ngx_int_t greater_message_tag, ngx_str_t *last_event_id, time_t *next_greater_message_time, ngx_int_t *next_greater_message_tag) { ngx_flag_t old_messages = 0; ngx_http_push_stream_msg_t *message; ngx_queue_t *cur; if (channel->stored_messages > 0) { if ((last_event_id != NULL) || (if_modified_since >= 0)) { ngx_flag_t found = 0; cur = &channel->message_queue; while ((cur = ngx_queue_next(cur)) && (cur != NULL) && (cur != &channel->message_queue)) { message = (ngx_http_push_stream_msg_t *) ngx_queue_data(cur, ngx_http_push_stream_msg_t, queue); if (message->deleted) { break; } if ((!found) && (last_event_id != NULL) && (message->event_id != NULL) && (ngx_memn2cmp(message->event_id->data, last_event_id->data, message->event_id->len, last_event_id->len) == 0)) { found = 1; continue; } if ((!found) && (last_event_id == NULL) && (if_modified_since >= 0) && ((message->time > if_modified_since) || ((message->time == if_modified_since) && (tag >= 0) && (message->tag >= tag)))) { found = 1; if ((message->time == if_modified_since) && (message->tag == tag)) { old_messages = 1; continue; } } if (found) { old_messages = 2; *next_greater_message_tag = message->tag; *next_greater_message_time = message->time; break; } } } } return old_messages; }