コード例 #1
0
void
ngx_http_connection_pool_free(ngx_peer_connection_t *pc,
    void *data, ngx_uint_t state)
{
    ngx_http_connection_pool_t     *p = data;
    ngx_http_connection_pool_elt_t *item;

    ngx_uint_t         hash, bucket_id;
    ngx_queue_t       *q, *cache, *free;
    ngx_connection_t  *c;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "free keepalive peer");

    /* remember failed state - peer.free() may be called more than once */

    if (state & NGX_PEER_FAILED) {
        p->failed = 1;
    }

    /* cache valid connections */

    c = pc->connection;

    if (p->failed
        || c == NULL
        || c->read->eof
        || c->read->error
        || c->read->timedout
        || c->write->error
        || c->write->timedout)
    {
        return;
    }

    if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
        return;
    }

#if (NGX_DEBUG)
    p->count++;
#endif

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
                   "free keepalive peer: saving connection %p", c);

    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];

    if (ngx_queue_empty(free)) {
        q = ngx_queue_last(cache);
        ngx_queue_remove(q);

        item = ngx_queue_data(q, ngx_http_connection_pool_elt_t, queue);

        ngx_http_connection_pool_close(item->connection);

    } else {
        q = ngx_queue_head(free);
        ngx_queue_remove(q);

        item = ngx_queue_data(q, ngx_http_connection_pool_elt_t, queue);
    }

    item->connection = c;
    item->free = free;
    ngx_queue_insert_head(cache, q);

    pc->connection = NULL;

    if (c->read->timer_set) {
        ngx_del_timer(c->read);
    }

    if (c->write->timer_set) {
        ngx_del_timer(c->write);
    }

    c->write->handler = ngx_http_connection_pool_dummy_handler;
    c->read->handler = ngx_http_connection_pool_close_handler;

    c->data = item;
    c->idle = 1;
    c->log = ngx_cycle->log;
    c->read->log = ngx_cycle->log;
    c->write->log = ngx_cycle->log;
    c->pool->log = ngx_cycle->log;

    item->socklen = pc->socklen;
    ngx_memcpy(&item->sockaddr, pc->sockaddr, pc->socklen);

    if (c->read->ready) {
        ngx_http_connection_pool_close_handler(c->read);
    }
}
コード例 #2
0
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 */

    rc = kp->original_get_peer(pc, kp->data);

    if (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);

            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;
}
コード例 #3
0
static ngx_int_t
ngx_http_limit_req_handler(ngx_http_request_t *r)
{
    size_t                      len, n;
    uint32_t                    hash;
    ngx_int_t                   rc;
    ngx_uint_t                  excess;
    ngx_time_t                 *tp;
    ngx_rbtree_node_t          *node;
    ngx_http_variable_value_t  *vv;
    ngx_http_limit_req_ctx_t   *ctx;
    ngx_http_limit_req_node_t  *lr;
    ngx_http_limit_req_conf_t  *lrcf;

    if (r->main->limit_req_set) {
        return NGX_DECLINED;
    }

    lrcf = ngx_http_get_module_loc_conf(r, ngx_http_limit_req_module);

    if (lrcf->shm_zone == NULL) {
        return NGX_DECLINED;
    }

    ctx = lrcf->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 > 65535) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "the value of the \"%V\" variable "
                      "is more than 65535 bytes: \"%v\"",
                      &ctx->var, vv);
        return NGX_DECLINED;
    }

    r->main->limit_req_set = 1;

    hash = ngx_crc32_short(vv->data, len);

    ngx_shmtx_lock(&ctx->shpool->mutex);

    ngx_http_limit_req_expire(ctx, 1);

    rc = ngx_http_limit_req_lookup(lrcf, hash, vv->data, len, &lr);

    if (lr) {
        ngx_queue_remove(&lr->queue);

        ngx_queue_insert_head(&ctx->sh->queue, &lr->queue);

        excess = lr->excess;

    } else {
        excess = 0;
    }

    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "limit_req: %i %ui.%03ui", rc, excess / 1000, excess % 1000);

    if (rc == NGX_BUSY) {
        ngx_shmtx_unlock(&ctx->shpool->mutex);

        ngx_log_error(lrcf->limit_log_level, r->connection->log, 0,
                      "limiting requests, excess: %ui.%03ui by zone \"%V\"",
                      excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name);

        return NGX_HTTP_SERVICE_UNAVAILABLE;
    }

    if (rc == NGX_AGAIN) {
        ngx_shmtx_unlock(&ctx->shpool->mutex);

        if (lrcf->nodelay) {
            return NGX_DECLINED;
        }

        ngx_log_error(lrcf->delay_log_level, r->connection->log, 0,
                      "delaying request, excess: %ui.%03ui, by zone \"%V\"",
                      excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name);

        if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        r->read_event_handler = ngx_http_test_reading;
        r->write_event_handler = ngx_http_limit_req_delay;
        ngx_add_timer(r->connection->write, (ngx_msec_t) excess);

        return NGX_AGAIN;
    }

    if (rc == NGX_OK) {
        goto done;
    }

    /* rc == NGX_DECLINED */

    n = offsetof(ngx_rbtree_node_t, color)
        + offsetof(ngx_http_limit_req_node_t, data)
        + len;

    node = ngx_slab_alloc_locked(ctx->shpool, n);
    if (node == NULL) {

        ngx_http_limit_req_expire(ctx, 0);

        node = ngx_slab_alloc_locked(ctx->shpool, n);
        if (node == NULL) {
            ngx_shmtx_unlock(&ctx->shpool->mutex);
            return NGX_HTTP_SERVICE_UNAVAILABLE;
        }
    }

    lr = (ngx_http_limit_req_node_t *) &node->color;

    node->key = hash;
    lr->len = (u_char) len;

    tp = ngx_timeofday();
    lr->last = (ngx_msec_t) (tp->sec * 1000 + tp->msec);

    lr->excess = 0;
    ngx_memcpy(lr->data, vv->data, len);

    ngx_rbtree_insert(&ctx->sh->rbtree, node);

    ngx_queue_insert_head(&ctx->sh->queue, &lr->queue);

done:

    ngx_shmtx_unlock(&ctx->shpool->mutex);

    return NGX_DECLINED;
}
コード例 #4
0
ファイル: ngx_http_file_cache.c プロジェクト: heiher/nginx
static ngx_int_t
ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, ngx_http_cache_t *c)
{
    ngx_int_t                    rc;
    ngx_http_file_cache_node_t  *fcn;

    ngx_shmtx_lock(&cache->shpool->mutex);

    fcn = ngx_http_file_cache_lookup(cache, c->key);

    if (fcn) {
        ngx_queue_remove(&fcn->queue);

        fcn->uses++;
        fcn->count++;

        if (fcn->error) {

            if (fcn->valid_sec < ngx_time()) {
                goto renew;
            }

            rc = NGX_OK;

            goto done;
        }

        if (fcn->exists || fcn->uses >= c->min_uses) {

            c->exists = fcn->exists;
            if (fcn->body_start) {
                c->body_start = fcn->body_start;
            }

            rc = NGX_OK;

            goto done;
        }

        rc = NGX_AGAIN;

        goto done;
    }

    fcn = ngx_slab_alloc_locked(cache->shpool,
                                sizeof(ngx_http_file_cache_node_t));
    if (fcn == NULL) {
        ngx_shmtx_unlock(&cache->shpool->mutex);

        (void) ngx_http_file_cache_forced_expire(cache);

        ngx_shmtx_lock(&cache->shpool->mutex);

        fcn = ngx_slab_alloc_locked(cache->shpool,
                                    sizeof(ngx_http_file_cache_node_t));
        if (fcn == NULL) {
            rc = NGX_ERROR;
            goto failed;
        }
    }

    ngx_memcpy((u_char *) &fcn->node.key, c->key, sizeof(ngx_rbtree_key_t));

    ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)],
               NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t));

    ngx_rbtree_insert(&cache->sh->rbtree, &fcn->node);

    fcn->uses = 1;
    fcn->count = 1;
    fcn->updating = 0;
    fcn->deleting = 0;

renew:

    rc = NGX_DECLINED;

    fcn->valid_msec = 0;
    fcn->error = 0;
    fcn->exists = 0;
    fcn->valid_sec = 0;
    fcn->uniq = 0;
    fcn->body_start = 0;
    fcn->fs_size = 0;

done:

    fcn->expire = ngx_time() + cache->inactive;

    ngx_queue_insert_head(&cache->sh->queue, &fcn->queue);

    c->uniq = fcn->uniq;
    c->error = fcn->error;
    c->node = fcn;

failed:

    ngx_shmtx_unlock(&cache->shpool->mutex);

    return rc;
}
コード例 #5
0
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;
}
コード例 #6
0
void
ngx_http_drizzle_keepalive_free_peer(ngx_peer_connection_t *pc,
        ngx_http_upstream_drizzle_peer_data_t *dp,
        ngx_http_upstream_drizzle_srv_conf_t *dscf,
        ngx_uint_t  state)
{
    ngx_uint_t                               status;
    ngx_http_drizzle_keepalive_cache_t      *item;
    ngx_queue_t                             *q;
    ngx_connection_t                        *c;
    ngx_http_upstream_t                     *u;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
                   "drizzle: free keepalive peer");

    if (state & NGX_PEER_FAILED) {
        dp->failed = 1;
    }

    u = dp->upstream;
    status = u->headers_in.status_n;

    if (!dp->failed
        && pc->connection != NULL
        && (status == NGX_HTTP_NOT_FOUND
            || (status == NGX_HTTP_OK && u->header_sent && u->length == 0)))
    {
        c = pc->connection;

        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
                       "drizzle: free keepalive peer: saving connection %p",
                       c);

        if (ngx_queue_empty(&dscf->free)) {
            /* connection pool is already full */

            q = ngx_queue_last(&dscf->cache);
            ngx_queue_remove(q);

            item = ngx_queue_data(q, ngx_http_drizzle_keepalive_cache_t,
                                  queue);

            ngx_http_upstream_drizzle_free_connection(pc->log, item->connection,
                    item->drizzle_con, dscf);

        } else {
            q = ngx_queue_head(&dscf->free);
            ngx_queue_remove(q);

            item = ngx_queue_data(q, ngx_http_drizzle_keepalive_cache_t,
                                  queue);
        }

        item->connection = c;
        ngx_queue_insert_head(&dscf->cache, q);

        pc->connection = NULL;

        if (c->read->timer_set) {
            ngx_del_timer(c->read);
        }
        if (c->write->timer_set) {
            ngx_del_timer(c->write);
        }

        c->write->handler = ngx_http_drizzle_keepalive_dummy_handler;
        c->read->handler = ngx_http_drizzle_keepalive_close_handler;

        c->data = item;
        c->idle = 1;
        c->log = ngx_cycle->log;
        c->read->log = ngx_cycle->log;
        c->write->log = ngx_cycle->log;

        item->socklen = pc->socklen;
        ngx_memcpy(&item->sockaddr, pc->sockaddr, pc->socklen);

        item->drizzle_con = dp->drizzle_con;
    }
}
コード例 #7
0
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;
}
コード例 #8
0
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;
}
コード例 #9
0
static ngx_int_t
ngx_http_req_status_handler(ngx_http_request_t *r)
{
    size_t                              len;
    uint32_t                            hash;
    ngx_str_t                           key;
    ngx_uint_t                          i;
    ngx_time_t                         *tp;
    ngx_shm_zone_t                    **pzone;
    ngx_pool_cleanup_t                 *cln;
    ngx_http_req_status_ctx_t          *r_ctx;
    ngx_http_req_status_zone_t         *ctx;
    ngx_http_req_status_node_t         *ssn;
    ngx_http_req_status_loc_conf_t     *rlcf;
    ngx_http_req_status_zone_node_t    *pzn;

    r_ctx = ngx_http_get_module_ctx(r, ngx_http_req_status_module);

    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_req_status_module);

    do {
        pzone = rlcf->req_zones.elts;

        for (i = 0; i < rlcf->req_zones.nelts; i++) {
            ctx = pzone[i]->data;

            if (ngx_http_complex_value(r, &ctx->key, &key) != NGX_OK) {
                continue;
            }

            if (key.len == 0) {
                continue;
            }

            if (key.len > 65535) {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                        "req-status, the value of the \"%V\" variable "
                        "is more than 65535 bytes: \"%v\"",
                        &ctx->key.value, &key);
                continue;
            }

            if (r_ctx == NULL) {

                r_ctx = ngx_palloc(r->pool, sizeof(ngx_http_req_status_ctx_t));
                if (r_ctx == NULL) {
                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
                }

                if (ngx_array_init(&r_ctx->req_zones, r->pool, 2,
                            sizeof(ngx_http_req_status_zone_node_t))
                        != NGX_OK)
                {
                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
                }

                cln = ngx_pool_cleanup_add(r->pool, 0);
                if (cln == NULL) {
                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
                }

                cln->handler = ngx_http_req_status_cleanup;
                cln->data = r_ctx;

                ngx_http_set_ctx(r, r_ctx, ngx_http_req_status_module);
            }

            hash = ngx_crc32_short(key.data, key.len);

            ngx_shmtx_lock(&ctx->shpool->mutex);

            ssn = ngx_http_req_status_lookup(ctx, hash, &key);

            if (ssn == NULL) {
                len  = sizeof(ngx_http_req_status_node_t) + key.len + 1;

                ssn = ngx_slab_alloc_locked(ctx->shpool, len);
                if (ssn == NULL) {
                    ngx_http_req_status_expire(ctx);

                    ssn = ngx_slab_alloc_locked(ctx->shpool, len);
                    if (ssn == NULL) {
                        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                                "req-status, slab alloc fail, zone = \"%V\", "
                                "key = \"%V\", size = %uz",
                                &ctx->shm_zone->shm.name, &key, len);

                        ngx_shmtx_unlock(&ctx->shpool->mutex);

                        continue;
                    }
                }

                ssn->node.key = hash;
                ssn->len = key.len;
                ssn->count = 1;

                ngx_memzero(&ssn->data, sizeof(ssn->data));
                ngx_memcpy(ssn->key, key.data, key.len);
                ssn->key[key.len] = '\0';
                ssn->last_traffic_update = 0;

                ngx_rbtree_insert(&ctx->sh->rbtree, &ssn->node);
            }

            tp = ngx_timeofday();

            ssn->data.requests ++;
            ssn->active ++;
            if (ssn->active > ssn->data.max_active) {
                ssn->data.max_active = ssn->active;
            }

            ngx_queue_insert_head(&ctx->sh->queue, &ssn->queue);

            ngx_shmtx_unlock(&ctx->shpool->mutex);

            pzn = ngx_array_push(&r_ctx->req_zones);
            if (pzn == NULL) {
                return NGX_HTTP_INTERNAL_SERVER_ERROR;
            }

            pzn->node = ssn;
            pzn->zone = ctx;
        }

        rlcf = rlcf->parent;
    } while (rlcf);

    return NGX_DECLINED;
}
//ngx_http_upstream_free_keepalive_peer往kp->conf->cache中添加缓存ngx_connection_t,ngx_http_upstream_get_keepalive_peer从缓存中
//取出和后端的连接缓存ngx_connection_t,可以避免重复的建立和关闭TCP连接
static void
ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc, void *data,
    ngx_uint_t state)
{
    ngx_http_upstream_keepalive_peer_data_t  *kp = data;
    ngx_http_upstream_keepalive_cache_t      *item;

    ngx_queue_t          *q;
    ngx_connection_t     *c;
    ngx_http_upstream_t  *u;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
                   "free keepalive peer");

    /* cache valid connections */

    u = kp->upstream;
    c = pc->connection;

    if (state & NGX_PEER_FAILED
        || c == NULL
        || c->read->eof
        || c->read->error
        || c->read->timedout
        || c->write->error
        || c->write->timedout)
    {
        goto invalid;
    }

    if (!u->keepalive) { 
    //说明本次和后端的连接使用的是缓存cache(keepalive配置)connection的TCP连接,也就是使用的是之前已经和后端建立好的TCP连接ngx_connection_t
        goto invalid;
    }

    //通常设置keepalive后连接都是由后端web服务发起的,因此需要添加读事件
    if (ngx_handle_read_event(c->read, 0, NGX_FUNC_LINE) != NGX_OK) {
        goto invalid;
    }

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
                   "free keepalive peer: saving connection %p", c);

    //如果free队列中可用cache items为空,则从cache队列取一个最近最少使用item,
    //将该item对应的那个连接关闭,该item用于保存当前需要释放的连接
    if (ngx_queue_empty(&kp->conf->free)) { //free中已经没有节点信息了,因此把cache中最少使用的那个取出来,把该连接关闭,重新添加到cache

        q = ngx_queue_last(&kp->conf->cache);
        ngx_queue_remove(q);

        item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue);

        ngx_http_upstream_keepalive_close(item->connection);

    } else {
         //free队列不空则直接从队列头取一个item用于保存当前连接
        q = ngx_queue_head(&kp->conf->free);
        ngx_queue_remove(q);

        item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue);
    }

    ngx_queue_insert_head(&kp->conf->cache, q);
    
    //缓存当前连接,将item插入cache队列,然后将pc->connection置空,防止上层调用
    //ngx_http_upstream_finalize_request关闭该连接(详见该函数)
    item->connection = c;

    pc->connection = NULL;

    //关闭读写定时器,这样可以避免把后端服务器的tcp连接关闭掉
    if (c->read->timer_set) {
        ngx_del_timer(c->read, NGX_FUNC_LINE);
    }
    if (c->write->timer_set) {
        ngx_del_timer(c->write, NGX_FUNC_LINE);
    }

    
    //设置连接读写钩子。写钩子是一个假钩子(keepalive连接不会由客户端主动关闭)
    //读钩子处理关闭keepalive连接的操作(接收到来自后端web服务器的FIN分节)
    c->write->handler = ngx_http_upstream_keepalive_dummy_handler;
    c->read->handler = ngx_http_upstream_keepalive_close_handler;

    c->data = item;
    c->idle = 1;
    c->log = ngx_cycle->log;
    c->read->log = ngx_cycle->log;
    c->write->log = ngx_cycle->log;
    c->pool->log = ngx_cycle->log;

    // 保存socket地址相关信息,后续就是通过查找相同的socket地址来复用该连接
    item->socklen = pc->socklen;
    ngx_memcpy(&item->sockaddr, pc->sockaddr, pc->socklen);

    if (c->read->ready) {
        ngx_http_upstream_keepalive_close_handler(c->read);
    }

invalid:

    kp->original_free_peer(pc, kp->data, state); //指向原负载均衡算法对应的free
}
コード例 #11
0
ファイル: ngx_http_file_cache.c プロジェクト: alazyer/nginx
static time_t
ngx_http_file_cache_expire(ngx_http_file_cache_t *cache)
{
    u_char                      *name, *p;
    size_t                       len;
    time_t                       now, wait;
    ngx_path_t                  *path;
    ngx_queue_t                 *q;
    ngx_http_file_cache_node_t  *fcn;
    u_char                       key[2 * NGX_HTTP_CACHE_KEY_LEN];

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
                   "http file cache expire");

    path = cache->path;
    len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN;

    name = ngx_alloc(len + 1, ngx_cycle->log);
    if (name == NULL) {
        return 10;
    }

    ngx_memcpy(name, path->name.data, path->name.len);

    now = ngx_time();

    ngx_shmtx_lock(&cache->shpool->mutex);

    for ( ;; ) {

        if (ngx_quit || ngx_terminate) {
            wait = 1;
            break;
        }

        if (ngx_queue_empty(&cache->sh->queue)) {
            wait = 10;
            break;
        }

        q = ngx_queue_last(&cache->sh->queue);

        fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue);

        wait = fcn->expire - now;

        if (wait > 0) {
            wait = wait > 10 ? 10 : wait;
            break;
        }

        ngx_log_debug6(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
                       "http file cache expire: #%d %d %02xd%02xd%02xd%02xd",
                       fcn->count, fcn->exists,
                       fcn->key[0], fcn->key[1], fcn->key[2], fcn->key[3]);

        if (fcn->count == 0) {
            ngx_http_file_cache_delete(cache, q, name);
            continue;
        }

        if (fcn->deleting) {
            wait = 1;
            break;
        }

        p = ngx_hex_dump(key, (u_char *) &fcn->node.key,
                         sizeof(ngx_rbtree_key_t));
        len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t);
        (void) ngx_hex_dump(p, fcn->key, len);

        /*
         * abnormally exited workers may leave locked cache entries,
         * and although it may be safe to remove them completely,
         * we prefer to just move them to the top of the inactive queue
         */

        ngx_queue_remove(q);
        fcn->expire = ngx_time() + cache->inactive;
        ngx_queue_insert_head(&cache->sh->queue, &fcn->queue);

        ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
                      "ignore long locked inactive cache entry %*s, count:%d",
                      2 * NGX_HTTP_CACHE_KEY_LEN, key, fcn->count);
    }

    ngx_shmtx_unlock(&cache->shpool->mutex);

    ngx_free(name);

    return wait;
}
コード例 #12
0
ファイル: ngx_shmap.c プロジェクト: love320/echo_iad
static int ngx_shmap_set_helper(ngx_shm_zone_t* zone, ngx_str_t* key, ngx_str_t* value,
			uint8_t value_type, uint32_t exptime, uint32_t user_flags, int flags)
{
    int                          i, n;
   // ngx_str_t                    name;
    uint32_t                     hash;
    ngx_int_t                    rc;
    ngx_shmap_ctx_t   *ctx;
    ngx_shmap_node_t  *sd;
    u_char                      *p;
    ngx_rbtree_node_t           *node;
    ngx_time_t                  *tp;
    //int                          forcible = 0;
                         /* indicates whether to foricibly override other
                          * valid entries */

    ctx = zone->data;
 

	

    if (key->len == 0 || key->len > 65535) {
        return -1;
    }

    hash = ngx_shmap_crc32(key->data, key->len);

    //dd("looking up key %s in shared dict %s", key->data, name.data);

    ngx_shmtx_lock(&ctx->shpool->mutex);

#if 1
    ngx_shmap_expire(ctx, 1);
#endif

    rc = ngx_shmap_lookup(zone, hash, key->data, key->len, &sd);

    //NLOG_DEBUG("shdict lookup returned %d", (int) rc);

	if (flags & NGX_SHARED_MAP_DELETE) {
		if (rc == NGX_DECLINED || rc == NGX_DONE) {
            ngx_shmtx_unlock(&ctx->shpool->mutex);
			//not exists
			return 0;
		}
	}

    if (flags & NGX_SHARED_MAP_REPLACE) {

        if (rc == NGX_DECLINED || rc == NGX_DONE) {
            ngx_shmtx_unlock(&ctx->shpool->mutex);
			//not exists
			return -1;
        }

        /* rc == NGX_OK */

        goto replace;
    }

    if (flags & NGX_SHARED_MAP_ADD) {

        if (rc == NGX_OK) {
            ngx_shmtx_unlock(&ctx->shpool->mutex);
			//exists
            return -1;
        }

        if (rc == NGX_DONE) {
            /* exists but expired */
            //dd("go to replace");
            goto replace;
        }

        /* rc == NGX_DECLINED */
        //dd("go to insert");
        goto insert;
    }

    if (rc == NGX_OK || rc == NGX_DONE) {

        if (value_type == VT_NULL) {
            goto remove;
        }

replace:
        if (value->data && value->len == (size_t) sd->value_len) {
            //NLOG_DEBUG("shmap set: found old entry and value size matched, reusing it");

            ngx_queue_remove(&sd->queue);
            ngx_queue_insert_head(&ctx->sh->queue, &sd->queue);

            sd->key_len = key->len;

            if (exptime > 0) {
                tp = ngx_timeofday();
                sd->expires = (uint64_t) tp->sec * 1000 + tp->msec
                              + exptime * 1000;
            } else {
                sd->expires = 0;
            }
			//NLOG_DEBUG("sd->expires: %u", sd->expires);
            sd->user_flags = user_flags;

            sd->value_len = (uint32_t) value->len;

            //dd("setting value type to %d", value_type);

            sd->value_type = value_type;

            p = ngx_copy(sd->data, key->data, key->len);
            ngx_memcpy(p, value->data, value->len);

            ngx_shmtx_unlock(&ctx->shpool->mutex);

            return 0;
        }

        //NLOG_DEBUG("shmap set: found old entry but value size ""NOT matched, removing it first");

remove:
        ngx_queue_remove(&sd->queue);

        node = (ngx_rbtree_node_t *)
                   ((u_char *) sd - offsetof(ngx_rbtree_node_t, color));

        ngx_rbtree_delete(&ctx->sh->rbtree, node);

        ngx_slab_free_locked(ctx->shpool, node);
        if (value_type == VT_NULL) {
			ngx_shmtx_unlock(&ctx->shpool->mutex);
			return 0;
        }
    }

insert:
    /* rc == NGX_DECLINED or value size unmatch */

    if (value == NULL || value->data == NULL) {
        ngx_shmtx_unlock(&ctx->shpool->mutex);
		//NLOG_ERROR("shmap add failed! value is null!");
        return -1;
    }

    n = offsetof(ngx_rbtree_node_t, color)
        + offsetof(ngx_shmap_node_t, data)
        + key->len
        + value->len;

    //NLOG_DEBUG("shmap set: creating a new entry(size=%d)", n);

    node = ngx_slab_alloc_locked(ctx->shpool, n);

    if (node == NULL) {

        if (flags & NGX_SHARED_MAP_SAFE_STORE) {
            ngx_shmtx_unlock(&ctx->shpool->mutex);

			//NLOG_ERROR("shmap add failed! no memory!");
			return -1;
        }

        //NLOG_DEBUG("shmap set: overriding non-expired items ""due to memory shortage for entry \"%V\"", &name);

        for (i = 0; i < 30; i++) {
            if (ngx_shmap_expire(ctx, 0) == 0) {
                break;
            }

            //forcible = 1;
			
			//DD("found raw arg %d", forcible);
			//DD("found raw arg %s", name);

            node = ngx_slab_alloc_locked(ctx->shpool, n);
            if (node != NULL) {
                goto allocated;
            }
        }

        ngx_shmtx_unlock(&ctx->shpool->mutex);

		//NLOG_ERROR("shmap add failed! no memory!");
		return -1;
    }

allocated:
    sd = (ngx_shmap_node_t *) &node->color;
 
    node->key = hash;
    sd->key_len = key->len;

    if (exptime > 0) {
        tp = ngx_timeofday();
        sd->expires = (uint64_t) tp->sec * 1000 + tp->msec
                      + exptime * 1000;

    } else {
        sd->expires = 0;
    }

    sd->user_flags = user_flags;

    sd->value_len = (uint32_t) value->len;

    sd->value_type = value_type;

    p = ngx_copy(sd->data, key->data, key->len);
    ngx_memcpy(p, value->data, value->len);

    ngx_rbtree_insert(&ctx->sh->rbtree, node);

    ngx_queue_insert_head(&ctx->sh->queue, &sd->queue);

    ngx_shmtx_unlock(&ctx->shpool->mutex);

    return 0;
}
コード例 #13
0
static int ngx_proc_luashm_backup_recover(ngx_http_lua_shdict_ctx_t *ctx,ngx_http_lua_shdict_node_ext_t *extsd){
    ngx_http_lua_shdict_node_t  *sd;
	ngx_rbtree_node_t           *node;
	int                          i, n;
	uint32_t                     hash;
	int32_t                      user_flags = 0;
	u_char                      *p,*key,*value;
	int 						key_len,value_len;
	int  						value_type;
	double						*num_value;

	key = extsd->data;
	key_len=extsd->key_len;
	value = extsd->data+key_len;
	value_len=extsd->value_len;
	value_type=extsd->value_type;
	user_flags=extsd->user_flags;

	switch (extsd->value_type) {
	case LUA_TSTRING:
		dd("key:%s, key_len:%d,value:%s,value_len:%d,exptime:%lu",key,key_len,value,value_len,extsd->expires);
		break;
	case LUA_TNUMBER:
		num_value=value;
		dd("key:%s, key_len:%d,value:%f,value_len:%d,exptime:%lu",key,key_len,*num_value,value_len,extsd->expires);
		break;
	case LUA_TBOOLEAN:
		dd("key:%s, key_len:%d,value:%c,value_len:%d,exptime:%lu",key,key_len,value[0],value_len,extsd->expires);
		break;
	}

	hash = ngx_crc32_short(key, key_len);
	    /* rc == NGX_DECLINED or value size unmatch */

    //dd("lua shared dict set: creating a new entry");

    n = offsetof(ngx_rbtree_node_t, color)
        + offsetof(ngx_http_lua_shdict_node_t, data)
        + key_len
        + value_len;

	ngx_shmtx_lock(&ctx->shpool->mutex);

    node = ngx_slab_alloc_locked(ctx->shpool, n);

    if (node == NULL) {

        dd("lua shared dict set: overriding non-expired items "
                       "due to memory shortage for entry \"%s\"", key);

        for (i = 0; i < 30; i++) {
            if (ngx_http_lua_shdict_expire(ctx, 0) == 0) {
                break;
            }

            node = ngx_slab_alloc_locked(ctx->shpool, n);
            if (node != NULL) {
                goto allocated;
            }
        }

        ngx_shmtx_unlock(&ctx->shpool->mutex);
		ngx_log_error(NGX_LOG_EMERG, ctx->log, 0, "no memory");
        return NGX_ERROR;
    }

allocated:

    sd = (ngx_http_lua_shdict_node_t *) &node->color;

    node->key = hash;
    sd->key_len = (u_short) key_len;

    sd->expires = extsd->expires;

    sd->user_flags = user_flags;
    sd->value_len = (uint32_t) value_len;
    //dd("setting value type to %d", value_type);
    sd->value_type = (uint8_t) value_type;
    p = ngx_copy(sd->data, key, key_len);
    ngx_memcpy(p, value, value_len);
    ngx_rbtree_insert(&ctx->sh->rbtree, node);
    ngx_queue_insert_head(&ctx->sh->queue, &sd->queue);
    ngx_shmtx_unlock(&ctx->shpool->mutex);

    return NGX_OK;
}
コード例 #14
0
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;
}
コード例 #15
0
ファイル: ngx_resolver.c プロジェクト: steveh/nginx-ppa
static ngx_int_t
ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
{
    uint32_t              hash;
    in_addr_t             addr, *addrs;
    ngx_int_t             rc;
    ngx_uint_t            naddrs;
    ngx_resolver_ctx_t   *next;
    ngx_resolver_node_t  *rn;

    hash = ngx_crc32_short(ctx->name.data, ctx->name.len);

    rn = ngx_resolver_lookup_name(r, &ctx->name, hash);

    if (rn) {

        if (rn->valid >= ngx_time()) {

            ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached");

            ngx_queue_remove(&rn->queue);

            rn->expire = ngx_time() + r->expire;

            ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);

            naddrs = rn->naddrs;

            if (naddrs) {

                /* NGX_RESOLVE_A answer */

                if (naddrs != 1) {
                    addr = 0;
                    addrs = ngx_resolver_dup(r, rn->u.addrs,
                                             naddrs * sizeof(in_addr_t));
                    if (addrs == NULL) {
                        return NGX_ERROR;
                    }

                } else {
                    addr = rn->u.addr;
                    addrs = NULL;
                }

                ctx->next = rn->waiting;
                rn->waiting = NULL;

                /* unlock name mutex */

                do {
                    ctx->state = NGX_OK;
                    ctx->naddrs = naddrs;
                    ctx->addrs = (naddrs == 1) ? &ctx->addr : addrs;
                    ctx->addr = addr;
                    next = ctx->next;

                    ctx->handler(ctx);

                    ctx = next;
                } while (ctx);

                if (addrs) {
                    ngx_resolver_free(r, addrs);
                }

                return NGX_OK;
            }

            /* NGX_RESOLVE_CNAME */

            if (ctx->recursion++ < NGX_RESOLVER_MAX_RECURSION) {

                ctx->name.len = rn->cnlen;
                ctx->name.data = rn->u.cname;

                return ngx_resolve_name_locked(r, ctx);
            }

            ctx->next = rn->waiting;
            rn->waiting = NULL;

            /* unlock name mutex */

            do {
                ctx->state = NGX_RESOLVE_NXDOMAIN;
                next = ctx->next;

                ctx->handler(ctx);

                ctx = next;
            } while (ctx);

            return NGX_OK;
        }

        if (rn->waiting) {

            ctx->next = rn->waiting;
            rn->waiting = ctx;
            ctx->state = NGX_AGAIN;

            return NGX_AGAIN;
        }

        ngx_queue_remove(&rn->queue);

        /* lock alloc mutex */

        ngx_resolver_free_locked(r, rn->query);
        rn->query = NULL;

        if (rn->cnlen) {
            ngx_resolver_free_locked(r, rn->u.cname);
        }

        if (rn->naddrs > 1) {
            ngx_resolver_free_locked(r, rn->u.addrs);
        }

        /* unlock alloc mutex */

    } else {

        rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t));
        if (rn == NULL) {
            return NGX_ERROR;
        }

        rn->name = ngx_resolver_dup(r, ctx->name.data, ctx->name.len);
        if (rn->name == NULL) {
            ngx_resolver_free(r, rn);
            return NGX_ERROR;
        }

        rn->node.key = hash;
        rn->nlen = (u_short) ctx->name.len;
        rn->query = NULL;

        ngx_rbtree_insert(&r->name_rbtree, &rn->node);
    }

    rc = ngx_resolver_create_name_query(rn, ctx);

    if (rc == NGX_ERROR) {
        goto failed;
    }

    if (rc == NGX_DECLINED) {
        ngx_rbtree_delete(&r->name_rbtree, &rn->node);

        ngx_resolver_free(r, rn->query);
        ngx_resolver_free(r, rn->name);
        ngx_resolver_free(r, rn);

        ctx->state = NGX_RESOLVE_NXDOMAIN;
        ctx->handler(ctx);

        return NGX_OK;
    }

    if (ngx_resolver_send_query(r, rn) != NGX_OK) {
        goto failed;
    }

    if (ctx->event == NULL) {
        ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
        if (ctx->event == NULL) {
            goto failed;
        }

        ctx->event->handler = ngx_resolver_timeout_handler;
        ctx->event->data = ctx;
        ctx->event->log = r->log;
        ctx->ident = -1;

        ngx_add_timer(ctx->event, ctx->timeout);
    }

    if (ngx_queue_empty(&r->name_resend_queue)) {
        ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000));
    }

    rn->expire = ngx_time() + r->resend_timeout;

    ngx_queue_insert_head(&r->name_resend_queue, &rn->queue);

    rn->cnlen = 0;
    rn->naddrs = 0;
    rn->valid = 0;
    rn->waiting = ctx;

    ctx->state = NGX_AGAIN;

    return NGX_AGAIN;

failed:

    ngx_rbtree_delete(&r->name_rbtree, &rn->node);

    if (rn->query) {
        ngx_resolver_free(r, rn->query);
    }

    ngx_resolver_free(r, rn->name);

    ngx_resolver_free(r, rn);

    return NGX_ERROR;
}
コード例 #16
0
ファイル: ngx_event_mbedtls.c プロジェクト: sbagmeijer/nginx
static int
ngx_mbedtls_set_cache(void *ctx, const ssl_session *session)
{
    ngx_shm_zone_t           *shm_zone;
    ngx_slab_pool_t          *shpool;
    ngx_ssl_session_cache_t  *cache;
    ngx_ssl_sess_id_t        *sess_id;
    ngx_ssl_session_t        *cached_sess;
    uint32_t                  hash;

    if (ctx == NULL) {
        /* NGX_SSL_NONE_SCACHE: Never cache any entries, but pretend to do so. */
        return 0;
    }

    shm_zone = ctx;
    shpool = (ngx_slab_pool_t*) shm_zone->shm.addr;
    cache = shm_zone->data;

    ngx_shmtx_lock(&shpool->mutex);

    /*
     * Because we need to store the entire ssl_session, in the cache we allocate
     * the entry and the ssl_session separately.  The entry is 64 bytes in size
     * on 64 bit architectures, and ssl_session is 112 bytes.
     *
     * Since we explicitly do not cache the peer certificate (requires a deep
     * copy), we hijack session.peer_cert and use that to store the expiration
     * time.  As far as I know sizeof(void *) == sizeof(time_t) is a reasonable
     * assumption to make.  This doesn't actually save anything on 64 bit
     * systems, but it *may* on 32 bit and it's not practical to break up a
     * ssl_session without being vulnerable to PolarSSL code changes.
     */

    /* Prune some sessions from the cache to ensure the allocation succeds */
    
    ngx_ssl_expire_sessions(cache, shpool, 1);

    cached_sess = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_session_t));
    if (cached_sess == NULL) {

        /* Prune the oldest non-expired session, and try again */

        ngx_ssl_expire_sessions(cache, shpool, 0);

        cached_sess = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_session_t));
        if (cached_sess == NULL) {
            goto failed;
        }
    }

    sess_id = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_sess_id_t));
    if (sess_id == NULL) {
        goto failed;
    }

    memcpy(cached_sess, session, sizeof(ngx_ssl_session_t));
    cached_sess->peer_cert = (x509_cert *) (ngx_time() + cache->ttl);

    hash = ngx_crc32_short(cached_sess->id, cached_sess->length);

    sess_id->node.key = hash;
    sess_id->node.data = (u_char) cached_sess->length;
    sess_id->session = cached_sess;

    ngx_queue_insert_head(&cache->expire_queue, &sess_id->queue);

    ngx_rbtree_insert(&cache->session_rbtree, &sess_id->node);

    ngx_shmtx_unlock(&shpool->mutex);

    return 0;

failed:
    ngx_shmtx_unlock(&shpool->mutex);

    return 1;
}
コード例 #17
0
ファイル: ngx_resolver.c プロジェクト: steveh/nginx-ppa
ngx_int_t
ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
{
    u_char               *name;
    ngx_resolver_t       *r;
    ngx_resolver_node_t  *rn;

    r = ctx->resolver;

    ctx->addr = ntohl(ctx->addr);

    /* lock addr mutex */

    rn = ngx_resolver_lookup_addr(r, ctx->addr);

    if (rn) {

        if (rn->valid >= ngx_time()) {

            ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached");

            ngx_queue_remove(&rn->queue);

            rn->expire = ngx_time() + r->expire;

            ngx_queue_insert_head(&r->addr_expire_queue, &rn->queue);

            name = ngx_resolver_dup(r, rn->name, rn->nlen);
            if (name == NULL) {
                goto failed;
            }

            ctx->name.len = rn->nlen;
            ctx->name.data = name;

            /* unlock addr mutex */

            ctx->state = NGX_OK;

            ctx->handler(ctx);

            ngx_resolver_free(r, name);

            return NGX_OK;
        }

        if (rn->waiting) {

            ctx->next = rn->waiting;
            rn->waiting = ctx;
            ctx->state = NGX_AGAIN;

            /* unlock addr mutex */

            return NGX_OK;
        }

        ngx_queue_remove(&rn->queue);

        ngx_resolver_free(r, rn->query);
        rn->query = NULL;

    } else {
        rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t));
        if (rn == NULL) {
            goto failed;
        }

        rn->node.key = ctx->addr;
        rn->query = NULL;

        ngx_rbtree_insert(&r->addr_rbtree, &rn->node);
    }

    if (ngx_resolver_create_addr_query(rn, ctx) != NGX_OK) {
        goto failed;
    }

    if (ngx_resolver_send_query(r, rn) != NGX_OK) {
        goto failed;
    }

    ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
    if (ctx->event == NULL) {
        goto failed;
    }

    ctx->event->handler = ngx_resolver_timeout_handler;
    ctx->event->data = ctx;
    ctx->event->log = r->log;
    ctx->ident = -1;

    ngx_add_timer(ctx->event, ctx->timeout);

    if (ngx_queue_empty(&r->addr_resend_queue)) {
        ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000));
    }

    rn->expire = ngx_time() + r->resend_timeout;

    ngx_queue_insert_head(&r->addr_resend_queue, &rn->queue);

    rn->cnlen = 0;
    rn->naddrs = 0;
    rn->name = NULL;
    rn->nlen = 0;
    rn->valid = 0;
    rn->waiting = ctx;

    /* unlock addr mutex */

    ctx->state = NGX_AGAIN;

    return NGX_OK;

failed:

    if (rn) {
        ngx_rbtree_delete(&r->addr_rbtree, &rn->node);

        if (rn->query) {
            ngx_resolver_free(r, rn->query);
        }

        ngx_resolver_free(r, rn);
    }

    /* unlock addr mutex */

    if (ctx->event) {
        ngx_resolver_free(r, ctx->event);
    }

    ngx_resolver_free(r, ctx);

    return NGX_ERROR;
}
コード例 #18
0
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;
}
コード例 #19
0
static ngx_int_t
ngx_http_limit_req_handler(ngx_http_request_t *r)
{
    size_t                         n, total_len;
    uint32_t                       hash;
    ngx_int_t                      rc;
    ngx_msec_t                     delay_time;
    ngx_uint_t                     excess, delay_excess, delay_postion,
                                   nodelay, i;
    ngx_time_t                    *tp;
    ngx_rbtree_node_t             *node;
    ngx_http_limit_req_t          *limit_req;
    ngx_http_limit_req_ctx_t      *ctx;
    ngx_http_limit_req_node_t     *lr;
    ngx_http_limit_req_conf_t     *lrcf;

    delay_excess = 0;
    delay_postion = 0;
    nodelay = 0;
    ctx = NULL;
    rc = 0;

    if (r->main->limit_req_set) {
        return NGX_DECLINED;
    }

    lrcf = ngx_http_get_module_loc_conf(r, ngx_http_limit_req_module);
    if (lrcf->rules == NULL) {
        return NGX_DECLINED;
    }

    if (!lrcf->enable) {
        return NGX_DECLINED;
    }

    /* filter whitelist */
    if (ngx_http_limit_req_ip_filter(r, lrcf) == NGX_OK) {
        return NGX_DECLINED;
    }

    /* to match limit_req rule*/
    limit_req = lrcf->rules->elts;
    for (i = 0; i < lrcf->rules->nelts; i++) {
        ctx = limit_req[i].shm_zone->data;

        ngx_crc32_init(hash);
        total_len = 0;

        total_len = ngx_http_limit_req_copy_variables(r, &hash, ctx, NULL);
        if (total_len == 0) {
            continue;
        }

        ngx_crc32_final(hash);

        r->main->limit_req_set = 1;

        ngx_shmtx_lock(&ctx->shpool->mutex);

        ngx_http_limit_req_expire(r, ctx, 1);
        rc = ngx_http_limit_req_lookup(r, &limit_req[i], hash, &excess);
        ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "limit_req module: %i %ui.%03ui "
                       "hash is %ui total_len is %i",
                       rc, excess / 1000, excess % 1000, hash, total_len);

        /* first limit_req */
        if (rc == NGX_DECLINED) {

            n = offsetof(ngx_rbtree_node_t, color)
                + offsetof(ngx_http_limit_req_node_t, data)
                + total_len;

            node = ngx_slab_alloc_locked(ctx->shpool, n);
            if (node == NULL) {
                ngx_http_limit_req_expire(r, ctx, 0);
                node = ngx_slab_alloc_locked(ctx->shpool, n);
                if (node == NULL) {
                    ngx_shmtx_unlock(&ctx->shpool->mutex);
                    return NGX_HTTP_SERVICE_UNAVAILABLE;
                }
            }

            lr = (ngx_http_limit_req_node_t *) &node->color;

            node->key = hash;
            lr->len = (u_char) total_len;

            tp = ngx_timeofday();
            lr->last = (ngx_msec_t) (tp->sec * 1000 + tp->msec);

            lr->excess = 0;
            ngx_http_limit_req_copy_variables(r, &hash, ctx, lr);

            ngx_queue_insert_head(&ctx->sh->queue, &lr->queue);
            ngx_rbtree_insert(&ctx->sh->rbtree, node);

            ngx_shmtx_unlock(&ctx->shpool->mutex);

            continue;
        }

        ngx_shmtx_unlock(&ctx->shpool->mutex);

        if (rc == NGX_OK) {
            continue;
        }

        /* need limit request */
        if (rc == NGX_BUSY) {
            ngx_log_error(lrcf->limit_log_level, r->connection->log, 0,
                          "limit_req limiting requests, "
                          "excess: %ui.%03ui by zone \"%V\"",
                          excess / 1000, excess % 1000,
                         &limit_req[i].shm_zone->shm.name);

            if (limit_req[i].forbid_action.len == 0) {

                return NGX_HTTP_SERVICE_UNAVAILABLE;
            } else if (limit_req[i].forbid_action.data[0] == '@') {

                ngx_log_error(lrcf->limit_log_level, r->connection->log, 0,
                              "limiting requests, forbid_action is %V",
                              &limit_req[i].forbid_action);
                (void) ngx_http_named_location(r, &limit_req[i].forbid_action);

            } else {

                ngx_log_error(lrcf->limit_log_level, r->connection->log, 0,
                              "limiting requests, forbid_action is %V",
                              &limit_req[i].forbid_action);
                (void) ngx_http_internal_redirect(r,
                                                  &limit_req[i].forbid_action,
                                                  &r->args);
            }

            ngx_http_finalize_request(r, NGX_DONE);
            return NGX_DONE;

        }

        if (rc == NGX_AGAIN) {
            if (delay_excess < excess) {
                delay_excess = excess;
                nodelay = limit_req[i].nodelay;
                delay_postion = i;
            }
        }
    }

    if (rc == 0) {
        return NGX_DECLINED;
    }

    /* rc = NGX_AGAIN */
    if (delay_excess != 0) {

        if (nodelay) {
            return NGX_DECLINED;
        }

        delay_time = (ngx_msec_t) delay_excess * 1000 / ctx->rate;
        ngx_log_error(lrcf->delay_log_level, r->connection->log, 0,
                      "delaying request,"
                      "excess: %ui.%03ui, by zone \"%V\", delay \"%ui\" s",
                      delay_excess / 1000, delay_excess % 1000,
                      &limit_req[delay_postion].shm_zone->shm.name, delay_time);

        if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        r->read_event_handler = ngx_http_test_reading;
        r->write_event_handler = ngx_http_limit_req_delay;
        ngx_add_timer(r->connection->write, delay_time);

        return NGX_AGAIN;
    }

    /* rc == NGX_OK or rc == NGX_DECLINED */

    return NGX_DECLINED;
}
コード例 #20
0
ngx_int_t
ngx_open_cached_file(ngx_open_file_cache_t *cache, ngx_str_t *name,
                     ngx_open_file_info_t *of, ngx_pool_t *pool)
{
    time_t                          now;
    uint32_t                        hash;
    ngx_int_t                       rc;
    ngx_file_info_t                 fi;
    ngx_pool_cleanup_t             *cln;
    ngx_cached_open_file_t         *file;
    ngx_pool_cleanup_file_t        *clnf;
    ngx_open_file_cache_cleanup_t  *ofcln;

    of->fd = NGX_INVALID_FILE;
    of->err = 0;

    if (cache == NULL) {

        if (of->test_only) {

            if (ngx_file_info_wrapper(name, of, &fi, pool->log)
                    == NGX_FILE_ERROR)
            {
                return NGX_ERROR;
            }

            of->uniq = ngx_file_uniq(&fi);
            of->mtime = ngx_file_mtime(&fi);
            of->size = ngx_file_size(&fi);
            of->fs_size = ngx_file_fs_size(&fi);
            of->is_dir = ngx_is_dir(&fi);
            of->is_file = ngx_is_file(&fi);
            of->is_link = ngx_is_link(&fi);
            of->is_exec = ngx_is_exec(&fi);

            return NGX_OK;
        }

        cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t));
        if (cln == NULL) {
            return NGX_ERROR;
        }

        rc = ngx_open_and_stat_file(name, of, pool->log);

        if (rc == NGX_OK && !of->is_dir) {
            cln->handler = ngx_pool_cleanup_file;
            clnf = cln->data;

            clnf->fd = of->fd;
            clnf->name = name->data;
            clnf->log = pool->log;
        }

        return rc;
    }

    cln = ngx_pool_cleanup_add(pool, sizeof(ngx_open_file_cache_cleanup_t));
    if (cln == NULL) {
        return NGX_ERROR;
    }

    now = ngx_time();

    hash = ngx_crc32_long(name->data, name->len);

    file = ngx_open_file_lookup(cache, name, hash);

    if (file) {

        file->uses++;

        ngx_queue_remove(&file->queue);

        if (file->fd == NGX_INVALID_FILE && file->err == 0 && !file->is_dir) {

            /* file was not used often enough to keep open */

            rc = ngx_open_and_stat_file(name, of, pool->log);

            if (rc != NGX_OK && (of->err == 0 || !of->errors)) {
                goto failed;
            }

            goto add_event;
        }

        if (file->use_event
                || (file->event == NULL
                    && (of->uniq == 0 || of->uniq == file->uniq)
                    && now - file->created < of->valid
#if (NGX_HAVE_OPENAT)
                    && of->disable_symlinks == file->disable_symlinks
                    && of->disable_symlinks_from == file->disable_symlinks_from
#endif
                   ))
        {
            if (file->err == 0) {

                of->fd = file->fd;
                of->uniq = file->uniq;
                of->mtime = file->mtime;
                of->size = file->size;

                of->is_dir = file->is_dir;
                of->is_file = file->is_file;
                of->is_link = file->is_link;
                of->is_exec = file->is_exec;
                of->is_directio = file->is_directio;

                if (!file->is_dir) {
                    file->count++;
                    ngx_open_file_add_event(cache, file, of, pool->log);
                }

            } else {
                of->err = file->err;
#if (NGX_HAVE_OPENAT)
                of->failed = file->disable_symlinks ? ngx_openat_file_n
                             : ngx_open_file_n;
#else
                of->failed = ngx_open_file_n;
#endif
            }

            goto found;
        }

        ngx_log_debug4(NGX_LOG_DEBUG_CORE, pool->log, 0,
                       "retest open file: %s, fd:%d, c:%d, e:%d",
                       file->name, file->fd, file->count, file->err);

        if (file->is_dir) {

            /*
             * chances that directory became file are very small
             * so test_dir flag allows to use a single syscall
             * in ngx_file_info() instead of three syscalls
             */

            of->test_dir = 1;
        }

        of->fd = file->fd;
        of->uniq = file->uniq;

        rc = ngx_open_and_stat_file(name, of, pool->log);

        if (rc != NGX_OK && (of->err == 0 || !of->errors)) {
            goto failed;
        }

        if (of->is_dir) {

            if (file->is_dir || file->err) {
                goto update;
            }

            /* file became directory */

        } else if (of->err == 0) {  /* file */

            if (file->is_dir || file->err) {
                goto add_event;
            }

            if (of->uniq == file->uniq) {

                if (file->event) {
                    file->use_event = 1;
                }

                of->is_directio = file->is_directio;

                goto update;
            }

            /* file was changed */

        } else { /* error to cache */

            if (file->err || file->is_dir) {
                goto update;
            }

            /* file was removed, etc. */
        }

        if (file->count == 0) {

            ngx_open_file_del_event(file);

            if (ngx_close_file(file->fd) == NGX_FILE_ERROR) {
                ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno,
                              ngx_close_file_n " \"%V\" failed", name);
            }

            goto add_event;
        }

        ngx_rbtree_delete(&cache->rbtree, &file->node);

        cache->current--;

        file->close = 1;

        goto create;
    }

    /* not found */

    rc = ngx_open_and_stat_file(name, of, pool->log);

    if (rc != NGX_OK && (of->err == 0 || !of->errors)) {
        goto failed;
    }

create:

    if (cache->current >= cache->max) {
        ngx_expire_old_cached_files(cache, 0, pool->log);
    }

    file = ngx_alloc(sizeof(ngx_cached_open_file_t), pool->log);

    if (file == NULL) {
        goto failed;
    }

    file->name = ngx_alloc(name->len + 1, pool->log);

    if (file->name == NULL) {
        ngx_free(file);
        file = NULL;
        goto failed;
    }

    ngx_cpystrn(file->name, name->data, name->len + 1);

    file->node.key = hash;

    ngx_rbtree_insert(&cache->rbtree, &file->node);

    cache->current++;

    file->uses = 1;
    file->count = 0;
    file->use_event = 0;
    file->event = NULL;

add_event:

    ngx_open_file_add_event(cache, file, of, pool->log);

update:

    file->fd = of->fd;
    file->err = of->err;
#if (NGX_HAVE_OPENAT)
    file->disable_symlinks = of->disable_symlinks;
    file->disable_symlinks_from = of->disable_symlinks_from;
#endif

    if (of->err == 0) {
        file->uniq = of->uniq;
        file->mtime = of->mtime;
        file->size = of->size;

        file->close = 0;

        file->is_dir = of->is_dir;
        file->is_file = of->is_file;
        file->is_link = of->is_link;
        file->is_exec = of->is_exec;
        file->is_directio = of->is_directio;

        if (!of->is_dir) {
            file->count++;
        }
    }

    file->created = now;

found:

    file->accessed = now;

    ngx_queue_insert_head(&cache->expire_queue, &file->queue);

    ngx_log_debug5(NGX_LOG_DEBUG_CORE, pool->log, 0,
                   "cached open file: %s, fd:%d, c:%d, e:%d, u:%d",
                   file->name, file->fd, file->count, file->err, file->uses);

    if (of->err == 0) {

        if (!of->is_dir) {
            cln->handler = ngx_open_file_cleanup;
            ofcln = cln->data;

            ofcln->cache = cache;
            ofcln->file = file;
            ofcln->min_uses = of->min_uses;
            ofcln->log = pool->log;
        }

        return NGX_OK;
    }

    return NGX_ERROR;

failed:

    if (file) {
        ngx_rbtree_delete(&cache->rbtree, &file->node);

        cache->current--;

        if (file->count == 0) {

            if (file->fd != NGX_INVALID_FILE) {
                if (ngx_close_file(file->fd) == NGX_FILE_ERROR) {
                    ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno,
                                  ngx_close_file_n " \"%s\" failed",
                                  file->name);
                }
            }

            ngx_free(file->name);
            ngx_free(file);

        } else {
            file->close = 1;
        }
    }

    if (of->fd != NGX_INVALID_FILE) {
        if (ngx_close_file(of->fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno,
                          ngx_close_file_n " \"%V\" failed", name);
        }
    }

    return NGX_ERROR;
}
コード例 #21
0
ファイル: ngx_http_statistics.c プロジェクト: 0x08e/SENginx
/* APIs */
ngx_http_statistics_server_t *
ngx_http_statistics_server_add(ngx_cycle_t *cycle, ngx_str_t *name)
{
    ngx_http_statistics_ctx_t       *ctx;
    ngx_http_statistics_conf_t      *smcf;
    ngx_http_statistics_server_t    *server;
    uint32_t                         hash;

    smcf = ngx_http_cycle_get_module_main_conf(cycle,
           ngx_http_statistics_module);

    if (smcf->enabled == 0) {
        return NULL;
    }

    ctx = statistics_shm_zone->data;

    ngx_shmtx_lock(&ctx->shpool->mutex);

    hash = ngx_crc32_short(name->data, name->len);
    ngx_log_error(NGX_LOG_DEBUG, cycle->log, 0,
         "stats server add, hash: %ui", hash);

    server = (ngx_http_statistics_server_t *) ngx_http_statistics_lookup(
            &ctx->sh->server_tree, name, hash);

    ngx_log_error(NGX_LOG_DEBUG, cycle->log, 0,
         "stats server add, server: %p", server);

    if (server == NULL) {
        /* create a new server node */
        ngx_log_error(NGX_LOG_DEBUG, cycle->log, 0,
             "create new node");

        server = ngx_slab_alloc_locked(ctx->shpool,
                sizeof(ngx_http_statistics_server_t));
        if (server == NULL) {
            ngx_shmtx_unlock(&ctx->shpool->mutex);
            return NULL;
        }

        memset(server, 0, sizeof(ngx_http_statistics_server_t));

        server->name.data = ngx_slab_alloc_locked(ctx->shpool, name->len);
        if (server->name.data == NULL) {
            ngx_shmtx_unlock(&ctx->shpool->mutex);
            return NULL;
        }

        memcpy(server->name.data, name->data, name->len);
        server->name.len = name->len;

        server->node.key = hash;

        ngx_rbtree_insert(&ctx->sh->server_tree, &server->node);
        ngx_queue_insert_head(&ctx->sh->server_queue, &server->queue);

        server->ref++;
    } else {
        /* found an exist server node */
        server->ref++;
    }

    ngx_shmtx_unlock(&ctx->shpool->mutex);

    return server;
}
コード例 #22
0
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;
}
コード例 #23
0
static int
ngx_http_lua_shdict_incr(lua_State *L)
{
    int                          n;
    ngx_str_t                    key;
    uint32_t                     hash;
    ngx_int_t                    rc;
    ngx_http_lua_shdict_ctx_t   *ctx;
    ngx_http_lua_shdict_node_t  *sd;
    lua_Number                   num;
    u_char                      *p;
    ngx_shm_zone_t              *zone;
    lua_Number                   value;

    n = lua_gettop(L);

    if (n != 3) {
        return luaL_error(L, "expecting 3 arguments, "
                "but only seen %d", n);
    }

    luaL_checktype(L, 1, LUA_TLIGHTUSERDATA);

    zone = lua_touserdata(L, 1);
    if (zone == NULL) {
        return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer");
    }

    ctx = zone->data;

    key.data = (u_char *) luaL_checklstring(L, 2, &key.len);

    if (key.len == 0) {
        return luaL_error(L, "attempt to use empty keys");
    }

    if (key.len > 65535) {
        return luaL_error(L,
                      "the key argument is more than 65535 bytes: %d",
                      (int) key.len);
    }

    hash = ngx_crc32_short(key.data, key.len);

    value = luaL_checknumber(L, 3);

    dd("looking up key %.*s in shared dict %.*s", (int) key.len, key.data,
       (int) ctx->name.len, ctx->name.data);

    ngx_shmtx_lock(&ctx->shpool->mutex);

#if 1
    ngx_http_lua_shdict_expire(ctx, 1);
#endif

    rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd);

    dd("shdict lookup returned %d", (int) rc);

    if (rc == NGX_DECLINED || rc == NGX_DONE) {
        ngx_shmtx_unlock(&ctx->shpool->mutex);

        lua_pushnil(L);
        lua_pushliteral(L, "not found");
        return 2;
    }

    /* rc == NGX_OK */

    if (sd->value_type != LUA_TNUMBER || sd->value_len != sizeof(lua_Number)) {
        ngx_shmtx_unlock(&ctx->shpool->mutex);

        lua_pushnil(L);
        lua_pushliteral(L, "not a number");
        return 2;
    }

    ngx_queue_remove(&sd->queue);
    ngx_queue_insert_head(&ctx->sh->queue, &sd->queue);

    dd("setting value type to %d", (int) sd->value_type);

    p = sd->data + key.len;

    num = *(lua_Number *) p;

    num += value;

    ngx_memcpy(p, (lua_Number *) &num, sizeof(lua_Number));

    ngx_shmtx_unlock(&ctx->shpool->mutex);

    lua_pushnumber(L, num);
    lua_pushnil(L);
    return 2;
}
コード例 #24
0
void
ngx_postgres_keepalive_free_peer(ngx_peer_connection_t *pc,
    ngx_postgres_upstream_peer_data_t *pgp,
    ngx_postgres_upstream_srv_conf_t *pgscf, ngx_uint_t  state)
{
    ngx_postgres_keepalive_cache_t  *item;
    ngx_queue_t                     *q;
    ngx_connection_t                *c;
    ngx_http_upstream_t             *u;

    dd("entering");

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
                   "postgres: free keepalive peer");

    if (state & NGX_PEER_FAILED) {
        pgp->failed = 1;
    }

    u = pgp->upstream;

    if ((!pgp->failed) && (pc->connection != NULL)
        && (u->headers_in.status_n == NGX_HTTP_OK))
    {
        c = pc->connection;

        if (c->read->timer_set) {
            ngx_del_timer(c->read);
        }

        if (c->write->timer_set) {
            ngx_del_timer(c->write);
        }

        if (c->write->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) {
            if (ngx_del_event(c->write, NGX_WRITE_EVENT, 0) != NGX_OK) {
                return;
            }
        }

        pc->connection = NULL;

        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
                       "postgres: free keepalive peer: saving connection %p",
                       c);

        if (ngx_queue_empty(&pgscf->free)) {
            /* connection pool is already full */

            q = ngx_queue_last(&pgscf->cache);
            ngx_queue_remove(q);

            item = ngx_queue_data(q, ngx_postgres_keepalive_cache_t,
                                  queue);

            ngx_postgres_upstream_free_connection(pc->log, item->connection,
                                                  item->pgconn, pgscf);

        } else {
            q = ngx_queue_head(&pgscf->free);
            ngx_queue_remove(q);

            item = ngx_queue_data(q, ngx_postgres_keepalive_cache_t,
                                  queue);
        }

        item->connection = c;
        ngx_queue_insert_head(&pgscf->cache, q);

        c->write->handler = ngx_postgres_keepalive_dummy_handler;
        c->read->handler = ngx_postgres_keepalive_close_handler;

        c->data = item;
        c->idle = 1;
        c->log = ngx_cycle->log;
#if defined(nginx_version) && (nginx_version >= 1001004)
        c->pool->log = ngx_cycle->log;
#endif
        c->read->log = ngx_cycle->log;
        c->write->log = ngx_cycle->log;

        item->socklen = pc->socklen;
        ngx_memcpy(&item->sockaddr, pc->sockaddr, pc->socklen);

        item->pgconn = pgp->pgconn;

        item->name.data = pgp->name.data;
        item->name.len = pgp->name.len;
    }

    dd("returning");
}
コード例 #25
0
static int
ngx_http_lua_shdict_set_helper(lua_State *L, int flags)
{
    int                          i, n;
    ngx_str_t                    name;
    ngx_str_t                    key;
    uint32_t                     hash;
    ngx_int_t                    rc;
    ngx_http_lua_shdict_ctx_t   *ctx;
    ngx_http_lua_shdict_node_t  *sd;
    ngx_str_t                    value;
    int                          value_type;
    lua_Number                   num;
    u_char                       c;
    lua_Number                   exptime = 0;
    u_char                      *p;
    ngx_rbtree_node_t           *node;
    ngx_time_t                  *tp;
    ngx_shm_zone_t              *zone;
    int                          forcible = 0;
                         /* indicates whether to foricibly override other
                          * valid entries */
    int32_t                      user_flags = 0;

    n = lua_gettop(L);

    if (n != 3 && n != 4 && n != 5) {
        return luaL_error(L, "expecting 3, 4 or 5 arguments, "
                "but only seen %d", n);
    }

    luaL_checktype(L, 1, LUA_TLIGHTUSERDATA);

    zone = lua_touserdata(L, 1);
    if (zone == NULL) {
        return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer");
    }

    ctx = zone->data;

    name = ctx->name;

    key.data = (u_char *) luaL_checklstring(L, 2, &key.len);

    if (key.len == 0) {
        return luaL_error(L, "attempt to use empty keys");
    }

    if (key.len > 65535) {
        return luaL_error(L,
                      "the key argument is more than 65535 bytes: %d",
                      (int) key.len);
    }

    hash = ngx_crc32_short(key.data, key.len);

    value_type = lua_type(L, 3);

    switch (value_type) {
    case LUA_TSTRING:
        value.data = (u_char *) lua_tolstring(L, 3, &value.len);
        break;

    case LUA_TNUMBER:
        value.len = sizeof(lua_Number);
        num = lua_tonumber(L, 3);
        value.data = (u_char *) &num;
        break;

    case LUA_TBOOLEAN:
        value.len = sizeof(u_char);
        c = lua_toboolean(L, 3) ? 1 : 0;
        value.data = &c;
        break;

    case LUA_TNIL:
        if (flags & (NGX_HTTP_LUA_SHDICT_ADD|NGX_HTTP_LUA_SHDICT_REPLACE)) {
            return luaL_error(L, "attempt to add or replace nil values");
        }

        value.len = 0;
        value.data = NULL;
        break;

    default:
        return luaL_error(L, "unsupported value type for key \"%s\" in "
                "shared_dict \"%s\": %s", key.data, name.data,
                lua_typename(L, value_type));
    }

    if (n >= 4) {
        exptime = luaL_checknumber(L, 4);
        if (exptime < 0) {
            exptime = 0;
        }
    }

    if (n == 5) {
        user_flags = (uint32_t) luaL_checkinteger(L, 5);
    }

    dd("looking up key %s in shared dict %s", key.data, name.data);

    ngx_shmtx_lock(&ctx->shpool->mutex);

#if 1
    ngx_http_lua_shdict_expire(ctx, 1);
#endif

    rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd);

    dd("shdict lookup returned %d", (int) rc);

    if (flags & NGX_HTTP_LUA_SHDICT_REPLACE) {

        if (rc == NGX_DECLINED || rc == NGX_DONE) {
            ngx_shmtx_unlock(&ctx->shpool->mutex);

            lua_pushboolean(L, 0);
            lua_pushliteral(L, "not found");
            lua_pushboolean(L, forcible);
            return 3;
        }

        /* rc == NGX_OK */

        goto replace;
    }

    if (flags & NGX_HTTP_LUA_SHDICT_ADD) {

        if (rc == NGX_OK) {
            ngx_shmtx_unlock(&ctx->shpool->mutex);

            lua_pushboolean(L, 0);
            lua_pushliteral(L, "exists");
            lua_pushboolean(L, forcible);
            return 3;
        }

        if (rc == NGX_DONE) {
            /* exists but expired */

            dd("go to replace");
            goto replace;
        }

        /* rc == NGX_DECLINED */

        dd("go to insert");
        goto insert;
    }

    if (rc == NGX_OK || rc == NGX_DONE) {

        if (value_type == LUA_TNIL) {
            goto remove;
        }

replace:
        if (value.data && value.len == (size_t) sd->value_len) {

            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
                "lua shared dict set: found old entry and value size matched, "
                "reusing it");

            ngx_queue_remove(&sd->queue);
            ngx_queue_insert_head(&ctx->sh->queue, &sd->queue);

            sd->key_len = key.len;

            if (exptime > 0) {
                tp = ngx_timeofday();
                sd->expires = (uint64_t) tp->sec * 1000 + tp->msec
                        + exptime * 1000;

            } else {
                sd->expires = 0;
            }

            sd->user_flags = user_flags;

            sd->value_len = (uint32_t) value.len;

            dd("setting value type to %d", value_type);

            sd->value_type = value_type;

            p = ngx_copy(sd->data, key.data, key.len);
            ngx_memcpy(p, value.data, value.len);

            ngx_shmtx_unlock(&ctx->shpool->mutex);

            lua_pushboolean(L, 1);
            lua_pushnil(L);
            lua_pushboolean(L, forcible);
            return 3;
        }

        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
            "lua shared dict set: found old entry bug value size NOT matched, "
            "removing it first");

remove:
        ngx_queue_remove(&sd->queue);

        node = (ngx_rbtree_node_t *)
                   ((u_char *) sd - offsetof(ngx_rbtree_node_t, color));

        ngx_rbtree_delete(&ctx->sh->rbtree, node);

        ngx_slab_free_locked(ctx->shpool, node);

    }

insert:
    /* rc == NGX_DECLINED or value size unmatch */

    if (value.data == NULL) {
        ngx_shmtx_unlock(&ctx->shpool->mutex);

        lua_pushboolean(L, 1);
        lua_pushnil(L);
        lua_pushboolean(L, 0);
        return 3;
    }

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
        "lua shared dict set: creating a new entry");

    n = offsetof(ngx_rbtree_node_t, color)
        + offsetof(ngx_http_lua_shdict_node_t, data)
        + key.len
        + value.len;

    node = ngx_slab_alloc_locked(ctx->shpool, n);

    if (node == NULL) {

        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
            "lua shared dict set: overriding non-expired items due to memory "
            "shortage for entry \"%V\"", &name);

        for (i = 0; i < 30; i++) {
            if (ngx_http_lua_shdict_expire(ctx, 0) == 0) {
                break;
            }

            forcible = 1;

            node = ngx_slab_alloc_locked(ctx->shpool, n);
            if (node != NULL) {
                goto allocated;
            }
        }

        ngx_shmtx_unlock(&ctx->shpool->mutex);

        lua_pushboolean(L, 0);
        lua_pushliteral(L, "no memory");
        lua_pushboolean(L, forcible);
        return 3;
    }

allocated:
    sd = (ngx_http_lua_shdict_node_t *) &node->color;

    node->key = hash;
    sd->key_len = key.len;

    if (exptime > 0) {
        tp = ngx_timeofday();
        sd->expires = (uint64_t) tp->sec * 1000 + tp->msec
                + exptime * 1000;

    } else {
        sd->expires = 0;
    }

    sd->user_flags = user_flags;

    sd->value_len = (uint32_t) value.len;

    dd("setting value type to %d", value_type);

    sd->value_type = value_type;

    p = ngx_copy(sd->data, key.data, key.len);
    ngx_memcpy(p, value.data, value.len);

    ngx_rbtree_insert(&ctx->sh->rbtree, node);

    ngx_queue_insert_head(&ctx->sh->queue, &sd->queue);

    ngx_shmtx_unlock(&ctx->shpool->mutex);

    lua_pushboolean(L, 1);
    lua_pushnil(L);
    lua_pushboolean(L, forcible);
    return 3;
}
コード例 #26
0
static void
ngx_btt_free_peer_info(ngx_btt_conf_t *bcf, ngx_btt_ctx_t *ctx,
    ngx_btt_peer_info_t *pi)
{
    ngx_queue_insert_head(&bcf->btt->free_peer_infos, &pi->queue);
}
コード例 #27
0
static void
ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc, void *data,
    ngx_uint_t state)
{
    ngx_http_upstream_keepalive_peer_data_t  *kp = data;
    ngx_http_upstream_keepalive_cache_t      *item;

    ngx_queue_t          *q;
    ngx_connection_t     *c;
    ngx_http_upstream_t  *u;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
                   "free keepalive peer");

    /* cache valid connections */

    u = kp->upstream;
    c = pc->connection;

    if (state & NGX_PEER_FAILED
        || c == NULL
        || c->read->eof
        || c->read->error
        || c->read->timedout
        || c->write->error
        || c->write->timedout)
    {
        goto invalid;
    }

    if (!u->keepalive) {
        goto invalid;
    }

    if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
        goto invalid;
    }

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
                   "free keepalive peer: saving connection %p", c);

    if (ngx_queue_empty(&kp->conf->free)) {

        q = ngx_queue_last(&kp->conf->cache);
        ngx_queue_remove(q);

        item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue);

        ngx_http_upstream_keepalive_close(item->connection);

    } else {
        q = ngx_queue_head(&kp->conf->free);
        ngx_queue_remove(q);

        item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue);
    }

    ngx_queue_insert_head(&kp->conf->cache, q);

    item->connection = c;

    pc->connection = NULL;

    if (c->read->timer_set) {
        ngx_del_timer(c->read);
    }
    if (c->write->timer_set) {
        ngx_del_timer(c->write);
    }

    c->write->handler = ngx_http_upstream_keepalive_dummy_handler;
    c->read->handler = ngx_http_upstream_keepalive_close_handler;

    c->data = item;
    c->idle = 1;
    c->log = ngx_cycle->log;
    c->read->log = ngx_cycle->log;
    c->write->log = ngx_cycle->log;
    c->pool->log = ngx_cycle->log;

    item->socklen = pc->socklen;
    ngx_memcpy(&item->sockaddr, pc->sockaddr, pc->socklen);

    if (c->read->ready) {
        ngx_http_upstream_keepalive_close_handler(c->read);
    }

invalid:

    kp->original_free_peer(pc, kp->data, state);
}
コード例 #28
0
ファイル: ngx_resolver.c プロジェクト: steveh/nginx-ppa
static void
ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
                       ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan, ngx_uint_t ans)
{
    char                 *err;
    u_char               *cname;
    size_t                len;
    int32_t               ttl;
    uint32_t              hash;
    in_addr_t             addr, *addrs;
    ngx_str_t             name;
    ngx_uint_t            qtype, qident, naddrs, a, i, n, start;
    ngx_resolver_an_t    *an;
    ngx_resolver_ctx_t   *ctx, *next;
    ngx_resolver_node_t  *rn;

    if (ngx_resolver_copy(r, &name, buf, &buf[12], &buf[last]) != NGX_OK) {
        return;
    }

    ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver qs:%V", &name);

    hash = ngx_crc32_short(name.data, name.len);

    /* lock name mutex */

    rn = ngx_resolver_lookup_name(r, &name, hash);

    if (rn == NULL || rn->query == NULL) {
        ngx_log_error(r->log_level, r->log, 0,
                      "unexpected response for %V", &name);
        goto failed;
    }

    qident = (rn->query[0] << 8) + rn->query[1];

    if (ident != qident) {
        ngx_log_error(r->log_level, r->log, 0,
                      "wrong ident %ui response for %V, expect %ui",
                      ident, &name, qident);
        goto failed;
    }

    ngx_resolver_free(r, name.data);

    if (code == 0 && nan == 0) {
        code = 3; /* NXDOMAIN */
    }

    if (code) {
        next = rn->waiting;
        rn->waiting = NULL;

        ngx_queue_remove(&rn->queue);

        ngx_rbtree_delete(&r->name_rbtree, &rn->node);

        ngx_resolver_free_node(r, rn);

        /* unlock name mutex */

        while (next) {
            ctx = next;
            ctx->state = code;
            next = ctx->next;

            ctx->handler(ctx);
        }

        return;
    }

    i = ans;
    naddrs = 0;
    addr = 0;
    addrs = NULL;
    cname = NULL;
    qtype = 0;
    ttl = 0;

    for (a = 0; a < nan; a++) {

        start = i;

        while (i < last) {

            if (buf[i] & 0xc0) {
                i += 2;
                goto found;
            }

            if (buf[i] == 0) {
                i++;
                goto test_length;
            }

            i += 1 + buf[i];
        }

        goto short_response;

test_length:

        if (i - start < 2) {
            err = "invalid name in dns response";
            goto invalid;
        }

found:

        if (i + sizeof(ngx_resolver_an_t) >= last) {
            goto short_response;
        }

        an = (ngx_resolver_an_t *) &buf[i];

        qtype = (an->type_hi << 8) + an->type_lo;
        len = (an->len_hi << 8) + an->len_lo;
        ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16)
              + (an->ttl[2] << 8) + (an->ttl[3]);

        if (ttl < 0) {
            ttl = 0;
        }

        if (qtype == NGX_RESOLVE_A) {

            i += sizeof(ngx_resolver_an_t);

            if (i + len > last) {
                goto short_response;
            }

            addr = htonl((buf[i] << 24) + (buf[i + 1] << 16)
                         + (buf[i + 2] << 8) + (buf[i + 3]));

            naddrs++;

            i += len;

        } else if (qtype == NGX_RESOLVE_CNAME) {
            cname = &buf[i] + sizeof(ngx_resolver_an_t);
            i += sizeof(ngx_resolver_an_t) + len;

        } else if (qtype == NGX_RESOLVE_DNAME) {
            i += sizeof(ngx_resolver_an_t) + len;

        } else {
            ngx_log_error(r->log_level, r->log, 0,
                          "unexpected qtype %ui", qtype);
        }
    }

    ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
                   "resolver naddrs:%ui cname:%p ttl:%d",
                   naddrs, cname, ttl);

    if (naddrs) {

        if (naddrs == 1) {
            rn->u.addr = addr;

        } else {

            addrs = ngx_resolver_alloc(r, naddrs * sizeof(in_addr_t));
            if (addrs == NULL) {
                return;
            }

            n = 0;
            i = ans;

            for (a = 0; a < nan; a++) {

                for ( ;; ) {

                    if (buf[i] & 0xc0) {
                        i += 2;
                        goto ok;
                    }

                    if (buf[i] == 0) {
                        i++;
                        goto ok;
                    }

                    i += 1 + buf[i];
                }

ok:

                an = (ngx_resolver_an_t *) &buf[i];

                qtype = (an->type_hi << 8) + an->type_lo;
                len = (an->len_hi << 8) + an->len_lo;

                i += sizeof(ngx_resolver_an_t);

                if (qtype == NGX_RESOLVE_A) {

                    addrs[n++] = htonl((buf[i] << 24) + (buf[i + 1] << 16)
                                       + (buf[i + 2] << 8) + (buf[i + 3]));

                    if (n == naddrs) {
                        break;
                    }
                }

                i += len;
            }

            rn->u.addrs = addrs;

            addrs = ngx_resolver_dup(r, rn->u.addrs,
                                     naddrs * sizeof(in_addr_t));
            if (addrs == NULL) {
                return;
            }
        }

        rn->naddrs = (u_short) naddrs;

        ngx_queue_remove(&rn->queue);

        rn->valid = ngx_time() + (r->valid ? r->valid : ttl);
        rn->expire = ngx_time() + r->expire;

        ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);

        next = rn->waiting;
        rn->waiting = NULL;

        /* unlock name mutex */

        while (next) {
            ctx = next;
            ctx->state = NGX_OK;
            ctx->naddrs = naddrs;
            ctx->addrs = (naddrs == 1) ? &ctx->addr : addrs;
            ctx->addr = addr;
            next = ctx->next;

            ctx->handler(ctx);
        }

        if (naddrs > 1) {
            ngx_resolver_free(r, addrs);
        }

        return;

    } else if (cname) {

        /* CNAME only */

        if (ngx_resolver_copy(r, &name, buf, cname, &buf[last]) != NGX_OK) {
            return;
        }

        ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
                       "resolver cname:\"%V\"", &name);

        ngx_queue_remove(&rn->queue);

        rn->cnlen = (u_short) name.len;
        rn->u.cname = name.data;

        rn->valid = ngx_time() + (r->valid ? r->valid : ttl);
        rn->expire = ngx_time() + r->expire;

        ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);

        ctx = rn->waiting;
        rn->waiting = NULL;

        if (ctx) {
            ctx->name = name;

            (void) ngx_resolve_name_locked(r, ctx);
        }

        return;
    }

    ngx_log_error(r->log_level, r->log, 0,
                  "no A or CNAME types in DNS responses, unknown query type: %ui",
                  qtype);
    return;

short_response:

    err = "short dns response";

invalid:

    /* unlock name mutex */

    ngx_log_error(r->log_level, r->log, 0, err);

    return;

failed:

    /* unlock name mutex */

    ngx_resolver_free(r, name.data);

    return;
}
コード例 #29
0
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;
}
コード例 #30
0
static ngx_int_t
ngx_http_limit_req_lookup(ngx_http_request_t *r,
    ngx_http_limit_req_limit_t *limit, ngx_uint_t hash,
    size_t len, 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;
    u_char                          *lr_data, *lr_last;
    ngx_http_variable_value_t       *vv;
    ngx_http_limit_req_variable_t   *lrv;
    size_t                           lr_vv_len;
    ngx_uint_t                       i;
    ngx_http_limit_req_variable_t   *cond;
    ngx_http_variable_value_t       *cond_vv;

    tp = ngx_timeofday();
    now = (ngx_msec_t) (tp->sec * 1000 + tp->msec);

    ctx = limit->shm_zone->data;
    cond = &limit->condition;

    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 */

        lr = (ngx_http_limit_req_node_t *) &node->color;

        lr_data = lr->data;
        lr_last = lr_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 vv is %i %v node is %s",
                           lrv[i].index, vv, lr_data);

            lr_vv_len = ngx_min(lr_last - lr_data, vv->len);

            if ((rc = ngx_memcmp(vv->data, lr_data, lr_vv_len)) != 0) {
                break;
            }

            if (lr_vv_len != vv->len) {
                rc = 1;
                break;
            }

            /* lr_vv_len == vv->len */
            lr_data += lr_vv_len;
        }

        if (rc == 0 && lr_last > lr_data) {
            rc = -1;
        }

        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "limit lookup is : %i, size is %ui",
                       rc, ctx->limit_vars->nelts);

        if (rc == 0) {
            if (cond->index != -1) {
                /* need to check condition */
                cond_vv = ngx_http_get_indexed_variable(r, cond->index);
                if (cond_vv == NULL || cond_vv->not_found) {
                    goto out;
                }

                if (cond_vv->len == 0) {
                    goto out;
                }

                if (ngx_memcmp(cond_vv->data, "1", 1) != 0) {
                    goto out;
                }
            }

            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;

out:
            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)
           + 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_char) len;
    lr->excess = 0;

    ngx_http_limit_req_copy_variables(r, (uint32_t *)&hash, ctx, lr);

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