static void ngx_stream_proxy_downstream_handler(ngx_event_t *ev) { ngx_connection_t *c; ngx_stream_session_t *s; ngx_stream_upstream_t *u; c = ev->data; s = c->data; if (ev->timedout) { ngx_connection_error(c, NGX_ETIMEDOUT, "connection timed out"); ngx_stream_proxy_finalize(s, NGX_DECLINED); return; } u = s->upstream; if (!ev->write) { ngx_stream_proxy_process(s, 0, 0); } else if (u->upstream_buf.start) { ngx_stream_proxy_process(s, 1, 1); } }
static void ngx_stream_proxy_upstream_handler(ngx_event_t *ev) { ngx_connection_t *c; ngx_stream_session_t *s; ngx_stream_upstream_t *u; c = ev->data; s = c->data; u = s->upstream; if (ev->write) { ngx_stream_proxy_process(s, 0, 1); } else if (u->upstream_buf.start) { ngx_stream_proxy_process(s, 1, 0); } }
static void ngx_stream_proxy_process_connection(ngx_event_t *ev, ngx_uint_t from_upstream) { ngx_connection_t *c, *pc; ngx_stream_session_t *s; ngx_stream_upstream_t *u; ngx_stream_proxy_srv_conf_t *pscf; c = ev->data; s = c->data; u = s->upstream; if (ev->timedout) { if (ev->delayed) { ev->timedout = 0; ev->delayed = 0; if (!ev->ready) { if (ngx_handle_read_event(ev, 0) != NGX_OK) { ngx_stream_proxy_finalize(s, NGX_ERROR); return; } if (u->connected) { pc = u->peer.connection; if (!c->read->delayed && !pc->read->delayed) { pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); ngx_add_timer(c->write, pscf->timeout); } } return; } } else { ngx_connection_error(c, NGX_ETIMEDOUT, "connection timed out"); ngx_stream_proxy_finalize(s, NGX_DECLINED); return; } } else if (ev->delayed) { ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, "stream connection delayed"); if (ngx_handle_read_event(ev, 0) != NGX_OK) { ngx_stream_proxy_finalize(s, NGX_ERROR); } return; } if (from_upstream && !u->connected) { return; } ngx_stream_proxy_process(s, from_upstream, ev->write); }
static void ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) { u_char *p; ngx_connection_t *c, *pc; ngx_log_handler_pt handler; ngx_stream_upstream_t *u; ngx_stream_proxy_srv_conf_t *pscf; u = s->upstream; if (u->proxy_protocol) { if (ngx_stream_proxy_send_proxy_protocol(s) != NGX_OK) { return; } u->proxy_protocol = 0; } pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); pc = u->peer.connection; #if (NGX_STREAM_SSL) if (pscf->ssl && pc->ssl == NULL) { ngx_stream_proxy_ssl_init_connection(s); return; } #endif c = s->connection; if (c->log->log_level >= NGX_LOG_INFO) { ngx_str_t s; u_char addr[NGX_SOCKADDR_STRLEN]; s.len = NGX_SOCKADDR_STRLEN; s.data = addr; if (ngx_connection_local_sockaddr(pc, &s, 1) == NGX_OK) { handler = c->log->handler; c->log->handler = NULL; ngx_log_error(NGX_LOG_INFO, c->log, 0, "proxy %V connected to %V", &s, u->peer.name); c->log->handler = handler; } } c->log->action = "proxying connection"; p = ngx_pnalloc(c->pool, pscf->buffer_size); if (p == NULL) { ngx_stream_proxy_finalize(s, NGX_ERROR); return; } u->upstream_buf.start = p; u->upstream_buf.end = p + pscf->buffer_size; u->upstream_buf.pos = p; u->upstream_buf.last = p; u->connected = 1; pc->read->handler = ngx_stream_proxy_upstream_handler; pc->write->handler = ngx_stream_proxy_upstream_handler; if (ngx_stream_proxy_process(s, 1, 0) != NGX_OK) { return; } ngx_stream_proxy_process(s, 0, 1); }
static void ngx_stream_proxy_handler(ngx_stream_session_t *s) { u_char *p; ngx_connection_t *c; ngx_stream_upstream_t *u; ngx_stream_proxy_srv_conf_t *pscf; ngx_stream_upstream_srv_conf_t *uscf; c = s->connection; pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, "proxy connection handler"); u = ngx_pcalloc(c->pool, sizeof(ngx_stream_upstream_t)); if (u == NULL) { ngx_stream_proxy_finalize(s, NGX_ERROR); return; } s->upstream = u; s->log_handler = ngx_stream_proxy_log_error; u->peer.log = c->log; u->peer.log_error = NGX_ERROR_ERR; u->peer.local = pscf->local; uscf = pscf->upstream; if (uscf->peer.init(s, uscf) != NGX_OK) { ngx_stream_proxy_finalize(s, NGX_ERROR); return; } u->peer.start_time = ngx_current_msec; if (pscf->next_upstream_tries && u->peer.tries > pscf->next_upstream_tries) { u->peer.tries = pscf->next_upstream_tries; } u->proxy_protocol = pscf->proxy_protocol; u->start_sec = ngx_time(); p = ngx_pnalloc(c->pool, pscf->buffer_size); if (p == NULL) { ngx_stream_proxy_finalize(s, NGX_ERROR); return; } u->downstream_buf.start = p; u->downstream_buf.end = p + pscf->buffer_size; u->downstream_buf.pos = p; u->downstream_buf.last = p; c->write->handler = ngx_stream_proxy_downstream_handler; c->read->handler = ngx_stream_proxy_downstream_handler; if (u->proxy_protocol #if (NGX_STREAM_SSL) && pscf->ssl == NULL #endif && pscf->buffer_size >= NGX_PROXY_PROTOCOL_MAX_HEADER) { /* optimization for a typical case */ ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, "stream proxy send PROXY protocol header"); p = ngx_proxy_protocol_write(c, u->downstream_buf.last, u->downstream_buf.end); if (p == NULL) { ngx_stream_proxy_finalize(s, NGX_ERROR); return; } u->downstream_buf.last = p; u->proxy_protocol = 0; } if (ngx_stream_proxy_process(s, 0, 0) != NGX_OK) { return; } ngx_stream_proxy_connect(s); }
static void ngx_stream_proxy_process_connection(ngx_event_t *ev, ngx_uint_t from_upstream) { ngx_connection_t *c, *pc; ngx_stream_session_t *s; ngx_stream_upstream_t *u; ngx_stream_proxy_srv_conf_t *pscf; c = ev->data; s = c->data; u = s->upstream; c = s->connection; pc = u->peer.connection; pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); if (ev->timedout) { ev->timedout = 0; if (ev->delayed) { ev->delayed = 0; if (!ev->ready) { if (ngx_handle_read_event(ev, 0) != NGX_OK) { ngx_stream_proxy_finalize(s, NGX_ERROR); return; } if (u->connected && !c->read->delayed && !pc->read->delayed) { ngx_add_timer(c->write, pscf->timeout); } return; } } else { if (s->connection->type == SOCK_DGRAM) { if (pscf->responses == NGX_MAX_INT32_VALUE) { /* * successfully terminate timed out UDP session * with unspecified number of responses */ pc->read->ready = 0; pc->read->eof = 1; ngx_stream_proxy_process(s, 1, 0); return; } if (u->received == 0) { ngx_stream_proxy_next_upstream(s); return; } } ngx_connection_error(c, NGX_ETIMEDOUT, "connection timed out"); ngx_stream_proxy_finalize(s, NGX_DECLINED); return; } } else if (ev->delayed) { ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, "stream connection delayed"); if (ngx_handle_read_event(ev, 0) != NGX_OK) { ngx_stream_proxy_finalize(s, NGX_ERROR); } return; } if (from_upstream && !u->connected) { return; } ngx_stream_proxy_process(s, from_upstream, ev->write); }
static void ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) { int tcp_nodelay; u_char *p; ngx_connection_t *c, *pc; ngx_log_handler_pt handler; ngx_stream_upstream_t *u; ngx_stream_core_srv_conf_t *cscf; ngx_stream_proxy_srv_conf_t *pscf; u = s->upstream; pc = u->peer.connection; cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module); if (pc->type == SOCK_STREAM && cscf->tcp_nodelay && pc->tcp_nodelay == NGX_TCP_NODELAY_UNSET) { ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0, "tcp_nodelay"); tcp_nodelay = 1; if (setsockopt(pc->fd, IPPROTO_TCP, TCP_NODELAY, (const void *) &tcp_nodelay, sizeof(int)) == -1) { ngx_connection_error(pc, ngx_socket_errno, "setsockopt(TCP_NODELAY) failed"); ngx_stream_proxy_next_upstream(s); return; } pc->tcp_nodelay = NGX_TCP_NODELAY_SET; } if (u->proxy_protocol) { if (ngx_stream_proxy_send_proxy_protocol(s) != NGX_OK) { return; } u->proxy_protocol = 0; } pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); #if (NGX_STREAM_SSL) if (pc->type == SOCK_STREAM && pscf->ssl && pc->ssl == NULL) { ngx_stream_proxy_ssl_init_connection(s); return; } #endif c = s->connection; if (c->log->log_level >= NGX_LOG_INFO) { ngx_str_t str; u_char addr[NGX_SOCKADDR_STRLEN]; str.len = NGX_SOCKADDR_STRLEN; str.data = addr; if (ngx_connection_local_sockaddr(pc, &str, 1) == NGX_OK) { handler = c->log->handler; c->log->handler = NULL; ngx_log_error(NGX_LOG_INFO, c->log, 0, "%sproxy %V connected to %V", pc->type == SOCK_DGRAM ? "udp " : "", &str, u->peer.name); c->log->handler = handler; } } c->log->action = "proxying connection"; if (u->upstream_buf.start == NULL) { p = ngx_pnalloc(c->pool, pscf->buffer_size); if (p == NULL) { ngx_stream_proxy_finalize(s, NGX_ERROR); return; } u->upstream_buf.start = p; u->upstream_buf.end = p + pscf->buffer_size; u->upstream_buf.pos = p; u->upstream_buf.last = p; } if (c->type == SOCK_DGRAM) { s->received = c->buffer->last - c->buffer->pos; u->downstream_buf = *c->buffer; if (pscf->responses == 0) { pc->read->ready = 0; pc->read->eof = 1; } } u->connected = 1; pc->read->handler = ngx_stream_proxy_upstream_handler; pc->write->handler = ngx_stream_proxy_upstream_handler; if (pc->read->ready || pc->read->eof) { ngx_post_event(pc->read, &ngx_posted_events); } ngx_stream_proxy_process(s, 0, 1); }