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; }
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_http_upstream_check_init_shm_zone(ngx_shm_zone_t *shm_zone, void *data) { size_t size; ngx_str_t oshm_name = ngx_null_string; ngx_uint_t i, same, number; ngx_shm_zone_t *oshm_zone; ngx_slab_pool_t *shpool; ngx_http_check_peer_t *peer; ngx_http_check_peers_t *peers; ngx_http_check_peer_shm_t *peer_shm, *opeer_shm; ngx_http_check_peers_shm_t *peers_shm, *opeers_shm; ngx_http_upstream_check_srv_conf_t *ucscf; opeers_shm = NULL; peers_shm = NULL; same = 0; peers = check_peers_ctx; number = peers->peers.nelts; shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; if (peers == NULL || number == 0) { return NGX_OK; } if (data) { opeers_shm = data; if (opeers_shm->number == number && opeers_shm->checksum == peers->checksum) { peers_shm = data; same = 1; } } if (!same) { if (ngx_http_check_shm_generation > 1) { ngx_http_check_get_shm_name(&oshm_name, ngx_cycle->pool, ngx_http_check_shm_generation - 1); /* The global variable ngx_cycle still points to the old version */ oshm_zone = ngx_shared_memory_find((ngx_cycle_t *)ngx_cycle, &oshm_name, &ngx_http_upstream_check_module); if (oshm_zone) { opeers_shm = oshm_zone->data; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, shm_zone->shm.log, 0, "http upstream check, find oshm_zone:%p, " "opeers_shm: %p", oshm_zone, opeers_shm); } } size = sizeof(*peers_shm) + (number - 1) * sizeof(ngx_http_check_peer_shm_t); peers_shm = ngx_slab_alloc(shpool, size); if (peers_shm == NULL) { goto failure; } ngx_memzero(peers_shm, size); } peers_shm->generation = ngx_http_check_shm_generation; peers_shm->checksum = peers->checksum; peers_shm->number = number; peer = peers->peers.elts; for (i = 0; i < number; i++) { peer_shm = &peers_shm->peers[i]; /* This function may be triggered before the old stale * work process exits. The owner may stick to the old * pid. */ peer_shm->owner = NGX_INVALID_PID; if (same) { continue; } peer_shm->socklen = peer[i].peer_addr->socklen; peer_shm->sockaddr = ngx_slab_alloc(shpool, peer_shm->socklen); if (peer_shm->sockaddr == NULL) { goto failure; } ngx_memcpy(peer_shm->sockaddr, peer[i].peer_addr->sockaddr, peer_shm->socklen); if (opeers_shm) { opeer_shm = ngx_http_check_find_shm_peer(opeers_shm, peer[i].peer_addr); if (opeer_shm) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, shm_zone->shm.log, 0, "http upstream check: inherit opeer:%V", &peer[i].peer_addr->name); ngx_http_check_set_shm_peer(peer_shm, opeer_shm, 0); continue; } } ucscf = peer[i].conf; ngx_http_check_set_shm_peer(peer_shm, NULL, ucscf->default_down); } peers->peers_shm = peers_shm; shm_zone->data = peers_shm; return NGX_OK; failure: ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, "http upstream check_shm_size is too small, " "you should specify a larger size."); return NGX_ERROR; }