static void ngx_tcp_check_finish_handler(ngx_event_t *event) { if (ngx_tcp_check_need_exit()) { return; } }
static void ngx_tcp_check_connect_handler(ngx_event_t *event) { ngx_int_t rc; ngx_connection_t *c; ngx_tcp_check_peer_conf_t *peer_conf; ngx_tcp_upstream_srv_conf_t *uscf; if (ngx_tcp_check_need_exit()) { return; } peer_conf = event->data; uscf = peer_conf->conf; ngx_memzero(&peer_conf->pc, sizeof(ngx_peer_connection_t)); peer_conf->pc.sockaddr = peer_conf->peer->sockaddr; peer_conf->pc.socklen = peer_conf->peer->socklen; peer_conf->pc.name = &peer_conf->peer->name; peer_conf->pc.get = ngx_event_get_peer; peer_conf->pc.log = event->log; peer_conf->pc.log_error = NGX_ERROR_ERR; peer_conf->pc.cached = 0; peer_conf->pc.connection = NULL; rc = ngx_event_connect_peer(&peer_conf->pc); if (rc == NGX_ERROR || rc == NGX_DECLINED) { ngx_tcp_check_status_update(peer_conf, 0); return; } /*NGX_OK or NGX_AGAIN*/ c = peer_conf->pc.connection; c->data = peer_conf; c->log = peer_conf->pc.log; c->sendfile = 0; c->read->log = c->log; c->write->log = c->log; c->pool = peer_conf->pool; peer_conf->state = NGX_TCP_CHECK_CONNECT_DONE; c->write->handler = peer_conf->send_handler; c->read->handler = peer_conf->recv_handler; ngx_add_timer(&peer_conf->check_timeout_ev, uscf->check_timeout); /* The kqueue's loop interface need it. */ if (rc == NGX_OK) { c->write->handler(c->write); } }
static void ngx_tcp_check_timeout_handler(ngx_event_t *event) { ngx_tcp_check_peer_conf_t *peer_conf; if (ngx_tcp_check_need_exit()) { return; } peer_conf = event->data; ngx_log_error(NGX_LOG_ERR, event->log, 0, "check time out with peer: %V ", &peer_conf->peer->name); ngx_tcp_check_status_update(peer_conf, 0); ngx_tcp_check_clean_event(peer_conf); }
static void ngx_tcp_check_begin_handler(ngx_event_t *event) { ngx_tcp_check_peer_conf_t *peer_conf; ngx_tcp_upstream_srv_conf_t *uscf; if (ngx_tcp_check_need_exit()) { return; } peer_conf = event->data; uscf = peer_conf->conf; ngx_add_timer(event, uscf->check_interval/2); /* This process are processing the event now. */ if (peer_conf->shm->owner == ngx_pid) { return; } ngx_log_debug4(NGX_LOG_DEBUG_TCP, event->log, 0, "tcp check begin handler index:%ud, owner: %d, " "ngx_pid: %ud, time:%d", peer_conf->index, peer_conf->shm->owner, ngx_pid, (ngx_current_msec - peer_conf->shm->access_time)); ngx_spinlock(&peer_conf->shm->lock, ngx_pid, 1024); if (((ngx_current_msec - peer_conf->shm->access_time) >= uscf->check_interval) && peer_conf->shm->owner == NGX_INVALID_PID) { peer_conf->shm->owner = ngx_pid; } ngx_spinlock_unlock(&peer_conf->shm->lock); if (peer_conf->shm->owner == ngx_pid) { ngx_tcp_check_connect_handler(event); } }
static void ngx_tcp_check_peek_handler(ngx_event_t *event) { char buf[1]; ngx_int_t n; ngx_err_t err; ngx_connection_t *c; ngx_tcp_check_peer_conf_t *peer_conf; if (ngx_tcp_check_need_exit()) { return; } c = event->data; peer_conf = c->data; n = recv(c->fd, buf, 1, MSG_PEEK); err = ngx_socket_errno; ngx_log_debug2(NGX_LOG_DEBUG_TCP, c->log, err, "tcp check upstream recv(): %d, fd: %d", n, c->fd); if (n >= 0 || err == NGX_EAGAIN) { ngx_tcp_check_status_update(peer_conf, 1); } else { c->error = 1; ngx_tcp_check_status_update(peer_conf, 0); } ngx_tcp_check_clean_event(peer_conf); /*dummy*/ ngx_tcp_check_finish_handler(event); }
static void ngx_tcp_check_recv_handler(ngx_event_t *event) { ssize_t size, n, rc; u_char *new_buf; ngx_connection_t *c; ngx_tcp_check_peer_conf_t *peer_conf; ngx_tcp_check_ctx *ctx; if (ngx_tcp_check_need_exit()) { return; } c = event->data; peer_conf = c->data; if (peer_conf->state != NGX_TCP_CHECK_SEND_DONE) { if (ngx_handle_read_event(c->read, 0) != NGX_OK) { goto check_recv_fail; } return; } ctx = peer_conf->check_data; if (ctx->recv.start == NULL) { /* 2048, is it enough? */ ctx->recv.start = ngx_palloc(c->pool, ngx_pagesize/2); if (ctx->recv.start == NULL) { goto check_recv_fail; } ctx->recv.last = ctx->recv.pos = ctx->recv.start; ctx->recv.end = ctx->recv.start + ngx_pagesize/2; } while (1) { n = ctx->recv.end - ctx->recv.last; /*Not enough buffer? Enlarge twice*/ if (n == 0) { size = ctx->recv.end - ctx->recv.start; new_buf = ngx_palloc(c->pool, size * 2); if (new_buf == NULL) { goto check_recv_fail; } ngx_memcpy(new_buf, ctx->recv.start, size); ctx->recv.pos = ctx->recv.start = new_buf; ctx->recv.last = new_buf + size; ctx->recv.end = new_buf + size * 2; n = ctx->recv.end - ctx->recv.last; } size = c->recv(c, ctx->recv.last, n); #if (NGX_DEBUG) ngx_err_t err; err = (size >= 0) ? 0 : ngx_socket_errno; ngx_log_debug2(NGX_LOG_DEBUG_TCP, c->log, err, "tcp check recv size: %d, peer: %V", size, &peer_conf->peer->name); #endif if (size > 0) { ctx->recv.last += size; continue; } else if (size == 0 || size == NGX_AGAIN) { break; } else { c->error = 1; goto check_recv_fail; } } rc = peer_conf->parse(peer_conf); ngx_log_debug2(NGX_LOG_DEBUG_TCP, c->log, 0, "tcp check parse rc: %d, peer: %V", rc, &peer_conf->peer->name); switch (rc) { case NGX_AGAIN: return; case NGX_ERROR: ngx_log_error(NGX_LOG_ERR, event->log, 0, "check protocol %s error with peer: %V ", peer_conf->conf->check_type_conf->name, &peer_conf->peer->name); ngx_tcp_check_status_update(peer_conf, 0); break; case NGX_OK: default: ngx_tcp_check_status_update(peer_conf, 1); } peer_conf->state = NGX_TCP_CHECK_RECV_DONE; ngx_tcp_check_clean_event(peer_conf); return; check_recv_fail: ngx_tcp_check_status_update(peer_conf, 0); ngx_tcp_check_clean_event(peer_conf); return; }
static void ngx_tcp_check_send_handler(ngx_event_t *event) { ssize_t size; ngx_connection_t *c; ngx_tcp_check_ctx *ctx; ngx_tcp_check_peer_conf_t *peer_conf; if (ngx_tcp_check_need_exit()) { return; } c = event->data; peer_conf = c->data; if (c->pool == NULL) { ngx_log_error(NGX_LOG_ERR, event->log, 0, "check pool NULL with peer: %V ", &peer_conf->peer->name); goto check_send_fail; } if (peer_conf->state != NGX_TCP_CHECK_CONNECT_DONE) { if (ngx_handle_write_event(c->write, 0) != NGX_OK) { goto check_send_fail; } return; } if (peer_conf->check_data == NULL) { peer_conf->check_data = ngx_pcalloc(c->pool, sizeof(ngx_tcp_check_ctx)); if (peer_conf->check_data == NULL) { goto check_send_fail; } if (peer_conf->init == NULL || peer_conf->init(peer_conf) != NGX_OK) { ngx_log_error(NGX_LOG_ERR, event->log, 0, "check init error with peer: %V ", &peer_conf->peer->name); goto check_send_fail; } } ctx = peer_conf->check_data; while (ctx->send.pos < ctx->send.last) { size = c->send(c, ctx->send.pos, ctx->send.last - ctx->send.pos); #if (NGX_DEBUG) ngx_err_t err; err = (size >=0) ? 0 : ngx_socket_errno; ngx_log_debug2(NGX_LOG_DEBUG_TCP, c->log, err, "tcp check send size: %d, total: %d", size, ctx->send.last - ctx->send.pos); #endif if (size >= 0) { ctx->send.pos += size; } else if (size == NGX_AGAIN) { return; } else { c->error = 1; goto check_send_fail; } } if (ctx->send.pos == ctx->send.last) { ngx_log_debug0(NGX_LOG_DEBUG_TCP, c->log, 0, "tcp check send done."); peer_conf->state = NGX_TCP_CHECK_SEND_DONE; } return; check_send_fail: ngx_tcp_check_status_update(peer_conf, 0); ngx_tcp_check_clean_event(peer_conf); return; }