ngx_int_t 
ngx_tcp_upstream_init_main_check_conf(ngx_conf_t *cf, void*conf) 
{
    ngx_tcp_upstream_main_conf_t   *umcf = conf;

    ngx_uint_t                      i, shm_size, need_check;
    ngx_str_t                      *shm_name;
    ngx_shm_zone_t                 *shm_zone;
    ngx_tcp_upstream_srv_conf_t   **uscfp;

    uscfp = umcf->upstreams.elts;

    need_check = 0;
    for (i = 0; i < umcf->upstreams.nelts; i++) {
        if (uscfp[i]->check_interval) {

            ngx_tcp_upstream_init_check_conf(uscfp[i]);
            
            need_check = 1;
        }
    }

    if (need_check) {
        ngx_tcp_check_shm_generation++;

        shm_name = &umcf->peers_conf->check_shm_name;

        if (ngx_tcp_check_get_shm_name(shm_name, cf->pool) == NGX_ERROR) {
            return NGX_ERROR;
        }

        /*the default check shmare memory size*/
        shm_size = (umcf->upstreams.nelts + 1 )* ngx_pagesize;

        shm_size = shm_size < umcf->check_shm_size 
                   ? umcf->check_shm_size : shm_size;

        shm_zone = ngx_shared_memory_add(cf, shm_name, shm_size,
                                         &ngx_tcp_upstream_module);

        ngx_log_debug2(NGX_LOG_DEBUG_TCP, cf->log, 0,
                       "[tcp_upstream] upsteam:%V, shm_zone size:%ui",
                       shm_name, shm_size);

        shm_zone->data = umcf->peers_conf;
        check_peers_ctx = umcf->peers_conf;

        shm_zone->init = ngx_tcp_upstream_check_init_shm_zone;

    } else {
        check_peers_ctx = NULL;
    }

    return NGX_OK;
}
static ngx_int_t 
ngx_tcp_upstream_check_status_handler(ngx_http_request_t *r) 
{
    ngx_buf_t                     *b;
    ngx_str_t                      shm_name;
    ngx_int_t                      rc;
    ngx_uint_t                     i;
    ngx_chain_t                    out;
    ngx_shm_zone_t                *shm_zone;
    ngx_tcp_check_peer_shm_t      *peer_shm;
    ngx_tcp_check_peers_shm_t     *peers_shm;
    ngx_tcp_check_peer_conf_t     *peer_conf;
    ngx_tcp_check_peers_conf_t    *peers_conf;


    if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {
        return NGX_HTTP_NOT_ALLOWED;
    }

    rc = ngx_http_discard_request_body(r);

    if (rc != NGX_OK) {
        return rc;
    }

    r->headers_out.content_type.len = sizeof("text/html; charset=utf-8") - 1;
    r->headers_out.content_type.data = (u_char *) "text/html; charset=utf-8";

    if (r->method == NGX_HTTP_HEAD) {
        r->headers_out.status = NGX_HTTP_OK;

        rc = ngx_http_send_header(r);

        if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
            return rc;
        }
    }

    if (ngx_tcp_check_get_shm_name(&shm_name, r->pool) == NGX_ERROR) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    shm_zone = ngx_shared_memory_find((ngx_cycle_t *)ngx_cycle, &shm_name, 
            &ngx_tcp_upstream_module);

    if (shm_zone == NULL || shm_zone->data == NULL) {

        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                "[tcp upstream check] can not find the shared memory zone \"%V\" ", &shm_name);

        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    peers_conf = shm_zone->data;
    peers_shm = peers_conf->peers_shm;

    peer_conf = peers_conf->peers.elts;
    peer_shm = peers_shm->peers;

    b = ngx_create_temp_buf(r->pool, ngx_pagesize);
    if (b == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    out.buf = b;
    out.next = NULL;

    b->last = ngx_sprintf(b->last, 
            "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\n"
            "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
            "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
            "<head>\n"
            "  <title>Nginx tcp upstream check status</title>\n"
            "</head>\n"
            "<body>\n"
            "<h1>Nginx tcp upstream check status</h1>\n"
            "<h2>Check upstream server number: %ui, shm_name: %V</h2>\n"
            "<table style=\"background-color:white\" cellspacing=\"0\" cellpadding=\"3\" border=\"1\">\n"
            "  <tr bgcolor=\"#C0C0C0\">\n"
            "    <th>Index</th>\n"
            "    <th>Name</th>\n"
            "    <th>Status</th>\n"
            "    <th>Business</th>\n"
            "    <th>Rise counts</th>\n"
            "    <th>Fall counts</th>\n"
            "    <th>Access counts</th>\n"
            "    <th>Check type</th>\n"
            "  </tr>\n",
            peers_conf->peers.nelts, &shm_name);

    for (i = 0; i < peers_conf->peers.nelts; i++) {
        b->last = ngx_sprintf(b->last, 
                "  <tr%s>\n"
                "    <td>%ui</td>\n" 
                "    <td>%V</td>\n" 
                "    <td>%s</td>\n" 
                "    <td>%ui</td>\n" 
                "    <td>%ui</td>\n" 
                "    <td>%ui</td>\n" 
                "    <td>%ui</td>\n" 
                "    <td>%s</td>\n" 
                "  </tr>\n",
                peer_shm[i].down ? " bgcolor=\"#FF0000\"" : "",
                i, 
                &peer_conf[i].peer->name, 
                peer_shm[i].down ? "down" : "up",
                peer_shm[i].business,
                peer_shm[i].rise_count, 
                peer_shm[i].fall_count, 
                peer_shm[i].access_count, 
                peer_conf[i].conf->check_type_conf->name);
    }

    b->last = ngx_sprintf(b->last, 
            "</table>\n"
            "</body>\n"
            "</html>\n");

    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = b->last - b->pos;

    b->last_buf = 1;

    rc = ngx_http_send_header(r);

    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
        return rc;
    }

    return ngx_http_output_filter(r, &out);
}
static ngx_int_t 
ngx_tcp_check_init_process(ngx_cycle_t *cycle) 
{
    ngx_str_t                      shm_name;
    ngx_uint_t                     i;
    ngx_msec_t                     t, delay;
    check_conf_t                  *cf;
    ngx_shm_zone_t                *shm_zone;
    ngx_tcp_check_peer_shm_t      *peer_shm;
    ngx_tcp_check_peers_shm_t     *peers_shm;
    ngx_tcp_check_peer_conf_t     *peer_conf;
    ngx_tcp_check_peers_conf_t    *peers_conf;
    ngx_tcp_upstream_srv_conf_t   *uscf;

    if (ngx_tcp_check_get_shm_name(&shm_name, cycle->pool) == NGX_ERROR) {
        return NGX_ERROR;
    }

    shm_zone = ngx_shared_memory_find(cycle, &shm_name, &ngx_tcp_upstream_module);

    if (shm_zone == NULL || shm_zone->data == NULL) {
        return NGX_OK;
    }

    peers_conf = shm_zone->data;
    peers_shm = peers_conf->peers_shm;

    ngx_log_debug2(NGX_LOG_DEBUG_TCP, cycle->log, 0, 
            "tcp check upstream init_process, shm_name: %V, peer number: %ud",
            &shm_name, peers_conf->peers.nelts);

    srand(ngx_pid);

    peer_conf = peers_conf->peers.elts;
    peer_shm = peers_shm->peers;

    for (i = 0; i < peers_conf->peers.nelts; i++) {
        peer_conf[i].shm = &peer_shm[i];

        peer_conf[i].check_ev.handler = ngx_tcp_check_begin_handler;
        peer_conf[i].check_ev.log = cycle->log;
        peer_conf[i].check_ev.data = &peer_conf[i];
        peer_conf[i].check_ev.timer_set = 0;

        peer_conf[i].check_timeout_ev.handler = ngx_tcp_check_timeout_handler;
        peer_conf[i].check_timeout_ev.log = cycle->log;
        peer_conf[i].check_timeout_ev.data = &peer_conf[i];
        peer_conf[i].check_timeout_ev.timer_set = 0;

        uscf = peer_conf[i].conf;
        cf = uscf->check_type_conf;

        if (cf->need_pool) {
            peer_conf[i].pool = ngx_create_pool(ngx_pagesize, cycle->log);
            if (peer_conf[i].pool == NULL) {
                return NGX_ERROR;
            }
        }

        peer_conf[i].send_handler = cf->send_handler;
        peer_conf[i].recv_handler = cf->recv_handler;

        peer_conf[i].init = cf->init;
        peer_conf[i].parse = cf->parse;
        peer_conf[i].reinit = cf->reinit;

        /* Default delay interval is 1 second. 
           I don't want to trigger the check event too close. */
        delay = uscf->check_interval > 1000 ? uscf->check_interval : 1000;
        t = ngx_random() % delay;

        ngx_add_timer(&peer_conf[i].check_ev, t);
    }

    return NGX_OK;
}