void ngx_postgres_upstream_finalize_request(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_int_t rc) { ngx_time_t *tp; dd("entering"); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "finalize http upstream request: %i", rc); if (u->cleanup) { *u->cleanup = NULL; } if (u->resolved && u->resolved->ctx) { ngx_resolve_name_done(u->resolved->ctx); u->resolved->ctx = NULL; } if (u->state && u->state->response_sec) { tp = ngx_timeofday(); u->state->response_sec = tp->sec - u->state->response_sec; u->state->response_msec = tp->msec - u->state->response_msec; if (u->pipe) { u->state->response_length = u->pipe->read_length; } } if (u->finalize_request) { u->finalize_request(r, rc); } if (u->peer.free) { u->peer.free(&u->peer, u->peer.data, 0); } if (u->peer.connection) { #if 0 /* we don't support SSL at this time, was: (NGX_HTTP_SSL) */ /* TODO: do not shutdown persistent connection */ if (u->peer.connection->ssl) { /* * We send the "close notify" shutdown alert to the upstream only * and do not wait its "close notify" shutdown alert. * It is acceptable according to the TLS standard. */ u->peer.connection->ssl->no_wait_shutdown = 1; (void) ngx_ssl_shutdown(u->peer.connection); } #endif ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "close http upstream connection: %d", u->peer.connection->fd); #if defined(nginx_version) && (nginx_version >= 1001004) if (u->peer.connection->pool) { ngx_destroy_pool(u->peer.connection->pool); } #endif ngx_close_connection(u->peer.connection); } u->peer.connection = NULL; if (u->pipe && u->pipe->temp_file) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http upstream temp fd: %d", u->pipe->temp_file->file.fd); } #if (NGX_HTTP_CACHE) if (u->cacheable && r->cache) { time_t valid; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http upstream cache fd: %d", r->cache->file.fd); if (rc == NGX_HTTP_BAD_GATEWAY || rc == NGX_HTTP_GATEWAY_TIME_OUT) { valid = ngx_http_file_cache_valid(u->conf->cache_valid, rc); if (valid) { r->cache->valid_sec = ngx_time() + valid; r->cache->error = rc; } } # if defined(nginx_version) && (nginx_version >= 8047) ngx_http_file_cache_free(r->cache, u->pipe->temp_file); # else ngx_http_file_cache_free(r, u->pipe->temp_file); # endif } #endif if (u->header_sent && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE)) { rc = 0; } if (rc == NGX_DECLINED) { dd("returning"); return; } r->connection->log->action = "sending to client"; if (rc == 0) { rc = ngx_http_send_special(r, NGX_HTTP_LAST); } ngx_http_finalize_request(r, rc); dd("returning"); }
//子进程管道可读事件捉捕函数 static void ngx_channel_handler(ngx_event_t *ev) { ngx_int_t n; ngx_channel_t ch; ngx_connection_t *c; if (ev->timedout) { ev->timedout = 0; return; } c = ev->data; ngx_log_debug0(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel handler"); for ( ;; ) { //读取channel,赋值ch n = ngx_read_channel(c->fd, &ch, sizeof(ngx_channel_t), ev->log); ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel: %i", n); if (n == NGX_ERROR) { if (ngx_event_flags & NGX_USE_EPOLL_EVENT) { ngx_del_conn(c, 0); } ngx_close_connection(c); return; } if (ngx_event_flags & NGX_USE_EVENTPORT_EVENT) { if (ngx_add_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) { return; } } if (n == NGX_AGAIN) { return; } ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel command: %d", ch.command); switch (ch.command) { case NGX_CMD_QUIT: ngx_quit = 1; break; case NGX_CMD_TERMINATE: ngx_terminate = 1; break; case NGX_CMD_REOPEN: ngx_reopen = 1; break; case NGX_CMD_OPEN_CHANNEL: ngx_log_debug3(NGX_LOG_DEBUG_CORE, ev->log, 0, "get channel s:%i pid:%P fd:%d", ch.slot, ch.pid, ch.fd); //对ngx_processes全局进程表进行赋值 ngx_processes[ch.slot].pid = ch.pid; ngx_processes[ch.slot].channel[0] = ch.fd; break; case NGX_CMD_CLOSE_CHANNEL: ngx_log_debug4(NGX_LOG_DEBUG_CORE, ev->log, 0, "close channel s:%i pid:%P our:%P fd:%d", ch.slot, ch.pid, ngx_processes[ch.slot].pid, ngx_processes[ch.slot].channel[0]); if (close(ngx_processes[ch.slot].channel[0]) == -1) { ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "close() channel failed"); } ngx_processes[ch.slot].channel[0] = -1; break; } } }
void ngx_http_php_socket_tcp_finalize_request(ngx_http_request_t *r, ngx_int_t rc) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_http_php_socket_tcp finalize_request"); ngx_http_php_ctx_t *ctx = ngx_http_get_module_ctx(r, ngx_http_php_module); // close keep-alive r->keepalive = 0; if (rc == 0){ ngx_http_php_socket_tcp_handler(r); } else { pthread_cancel(ctx->pthread_id); for ( ;; ){ usleep(1); if (ctx->enable_thread == 0){ break; } } pthread_cond_destroy(&(ctx->cond)); pthread_mutex_destroy(&(ctx->mutex)); ngx_event_t *rev; ngx_connection_t *c; c = r->connection; rev = c->read; ngx_http_upstream_t *u; u = r->upstream; if (u->peer.connection) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "close http upstream connection: %d", u->peer.connection->fd); if (u->peer.connection->pool) { ngx_destroy_pool(u->peer.connection->pool); } ngx_close_connection(u->peer.connection); } u->peer.connection = NULL; if (rev->timer_set) { ngx_del_timer(rev); } //ngx_http_set_ctx(r, ctx, ngx_http_php_module); ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST); } return ; }
void ngx_postgres_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_int_t ft_type) { ngx_uint_t status, state; dd("entering"); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http next upstream, %xi", ft_type); #if 0 ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock); #endif if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404) { state = NGX_PEER_NEXT; } else { state = NGX_PEER_FAILED; } if (ft_type != NGX_HTTP_UPSTREAM_FT_NOLIVE) { u->peer.free(&u->peer, u->peer.data, state); } if (ft_type == NGX_HTTP_UPSTREAM_FT_TIMEOUT) { ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ETIMEDOUT, "upstream timed out"); } if (u->peer.cached && ft_type == NGX_HTTP_UPSTREAM_FT_ERROR) { status = 0; } else { switch(ft_type) { case NGX_HTTP_UPSTREAM_FT_TIMEOUT: status = NGX_HTTP_GATEWAY_TIME_OUT; break; case NGX_HTTP_UPSTREAM_FT_HTTP_500: status = NGX_HTTP_INTERNAL_SERVER_ERROR; break; case NGX_HTTP_UPSTREAM_FT_HTTP_404: status = NGX_HTTP_NOT_FOUND; break; /* * NGX_HTTP_UPSTREAM_FT_BUSY_LOCK and NGX_HTTP_UPSTREAM_FT_MAX_WAITING * never reach here */ default: status = NGX_HTTP_BAD_GATEWAY; } } if (r->connection->error) { ngx_postgres_upstream_finalize_request(r, u, NGX_HTTP_CLIENT_CLOSED_REQUEST); dd("returning"); return; } if (status) { u->state->status = status; if (u->peer.tries == 0 || !(u->conf->next_upstream & ft_type)) { ngx_postgres_upstream_finalize_request(r, u, status); dd("returning"); return; } } if (u->peer.connection) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "close http upstream connection: %d", u->peer.connection->fd); #if 0 /* we don't support SSL at this time, was: (NGX_HTTP_SSL) */ if (u->peer.connection->ssl) { u->peer.connection->ssl->no_wait_shutdown = 1; u->peer.connection->ssl->no_send_shutdown = 1; (void) ngx_ssl_shutdown(u->peer.connection); } #endif #if defined(nginx_version) && (nginx_version >= 1001004) if (u->peer.connection->pool) { ngx_destroy_pool(u->peer.connection->pool); } #endif ngx_close_connection(u->peer.connection); } #if 0 if (u->conf->busy_lock && !u->busy_locked) { ngx_http_upstream_busy_lock(p); return; } #endif /* TODO: ngx_http_upstream_connect(r, u); */ if (status == 0) { status = NGX_HTTP_INTERNAL_SERVER_ERROR; } dd("returning"); return ngx_postgres_upstream_finalize_request(r, u, status); }
/* 子进程收到后来新建子进程的相关信息,并根据通道的命令完成相应的动作 */ static void ngx_channel_handler(ngx_event_t *ev) { ngx_int_t n; ngx_channel_t ch; ngx_connection_t *c; if (ev->timedout) { ev->timedout = 0; return; } c = ev->data; ngx_log_debug0(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel handler"); for ( ;; ) { /* 从连接中的socket文件描述符中读取通道数据 */ n = ngx_read_channel(c->fd, &ch, sizeof(ngx_channel_t), ev->log); ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel: %i", n); if (n == NGX_ERROR) { if (ngx_event_flags & NGX_USE_EPOLL_EVENT) { ngx_del_conn(c, 0); } ngx_close_connection(c); return; } if (ngx_event_flags & NGX_USE_EVENTPORT_EVENT) { if (ngx_add_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) { return; } } if (n == NGX_AGAIN) { return; } ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel command: %d", ch.command); switch (ch.command) { case NGX_CMD_QUIT: ngx_quit = 1; /* 如果worker进程通过通道接收到退出命令,则设置全局变量ngx_quit为1 */ break; case NGX_CMD_TERMINATE: ngx_terminate = 1; break; case NGX_CMD_REOPEN: ngx_reopen = 1; break; /* 子进程之间的通信打开通道,如master进程将后续创建的子进程的 * pid,fd,以及slot发送过来,高速之前创建的进程怎么和后续创建的进程通信 */ case NGX_CMD_OPEN_CHANNEL: ngx_log_debug3(NGX_LOG_DEBUG_CORE, ev->log, 0, "get channel s:%i pid:%P fd:%d", ch.slot, ch.pid, ch.fd); ngx_processes[ch.slot].pid = ch.pid; /* 设置进程的0通道,在刚创建的时候,子进程的0通道是从父进程继承的 */ ngx_processes[ch.slot].channel[0] = ch.fd; break; case NGX_CMD_CLOSE_CHANNEL: /* 关闭与相应进程(也就是索引为ch.slot的这个进程的通信信道 */ ngx_log_debug4(NGX_LOG_DEBUG_CORE, ev->log, 0, "close channel s:%i pid:%P our:%P fd:%d", ch.slot, ch.pid, ngx_processes[ch.slot].pid, ngx_processes[ch.slot].channel[0]); if (close(ngx_processes[ch.slot].channel[0]) == -1) { ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "close() channel failed"); } ngx_processes[ch.slot].channel[0] = -1; break; } } }
static void ngx_lua_http_finalize(ngx_lua_http_ctx_t *ctx, char *errstr) { ngx_int_t rc; ngx_uint_t i; ngx_keyval_t *headers; ngx_lua_thread_t *thr; ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "lua http finalize"); if (ctx->cln_ctx != NULL) { ctx->cln_ctx->ctx = NULL; } thr = ctx->thr; if (thr == NULL) { if (ctx->peer.connection) { ngx_close_connection(ctx->peer.connection); } ngx_destroy_pool(ctx->pool); return; } ctx->rc = 1; if (errstr == NULL) { lua_createtable(thr->l, 1, 3); lua_createtable(thr->l, 0, ctx->headers.nelts); headers = ctx->headers.elts; for (i = 0; i < ctx->headers.nelts; i++) { lua_pushlstring(thr->l, (char *) headers[i].value.data, headers[i].value.len); lua_setfield(thr->l, -2, (char *) headers[i].key.data); } lua_setfield(thr->l, -2, "headers"); lua_pushnumber(thr->l, ctx->status_code); lua_setfield(thr->l, -2, "status"); if (ctx->header == NULL) { lua_pushlstring(thr->l, (char *) ctx->body_start, ctx->response->last - ctx->body_start); } else { lua_pushlstring(thr->l, (char *) ctx->body_start, ctx->header->last - ctx->body_start); lua_pushlstring(thr->l, (char *) ctx->response->start, ctx->response->last - ctx->response->start); lua_concat(thr->l, 2); } lua_setfield(thr->l, -2, "body"); } else { lua_pushboolean(thr->l, 0); lua_pushstring(thr->l, errstr); ctx->rc++; } if (ctx->peer.connection) { ngx_close_connection(ctx->peer.connection); } if (ctx->not_event) { return; } rc = ctx->rc; ngx_destroy_pool(ctx->pool); rc = ngx_lua_thread_run(thr, rc); if (rc == NGX_AGAIN) { return; } ngx_lua_finalize(thr, rc); }
static void ngx_http_cloudrouter_peer_preconnect_read(ngx_event_t *rev) { ngx_connection_t *c; ngx_http_cloudrouter_peer_preconnect_data_t *pcd; ngx_http_upstream_t *u; ngx_http_request_t *r; int i; hs_route_t *route; c = rev->data; pcd = c->data; r = pcd->r; u = pcd->u; route = &pcd->route; ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "preconnect: read"); if (pcd->done>0) { return; } if (r->main==NULL||r->request_complete||r->pool==NULL||r!=r->main) { ngx_close_connection(c); c->destroyed = 1; return; } if (rev->timedout) { ngx_log_error(NGX_LOG_ERR, rev->log, NGX_ETIMEDOUT, "cloudrouter preconnect server timed out"); return ngx_http_cloudrouter_peer_preconnect_close(c, pcd, NGX_ERROR); } if (pcd->buf==NULL) { int size = sizeof(char)*1000; ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "creating buf"); pcd->buf = ngx_pcalloc(r->pool, size); pcd->bufend = pcd->buf+size; pcd->bufpos = pcd->buf; if (pcd->buf==NULL) { ngx_log_error(NGX_LOG_ERR, rev->log, NGX_ENOMEM, "preconnect: read: could not allocate buf"); return ngx_http_cloudrouter_peer_preconnect_close(c, pcd, NGX_ERROR); } } /* * Protocol format: * IP1\nPORT1\n * (optional) IPz\nPORTz\n * -- */ int bufsize = pcd->bufend - pcd->bufpos; ngx_int_t received; if (bufsize > 0) { received = ngx_recv(c, pcd->bufpos, bufsize); } else { received = 0; } if (received==NGX_AGAIN) { return; } else if (received>=0) { pcd->bufpos += received; for (i=0;i<(pcd->bufpos-pcd->buf);i++) { if (*(pcd->buf + i )=='-') { pcd->end_marker_count++; } } if (pcd->end_marker_count>=2) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "CloudRouter preconnect: message complete"); ngx_http_cloudrouter_peer_t *peer = (ngx_http_cloudrouter_peer_t *)u->peer.data; unsigned char* next = pcd->buf; int new_node = 0; ngx_shmtx_lock(&ngx_http_cloudrouter_shpool->mutex); ngx_http_cloudrouter_node_t *e = ngx_http_cloudrouter_get_locked(route); if (e == NULL) { /* likely() */ e = ngx_slab_alloc_locked(ngx_http_cloudrouter_shpool, sizeof *e); new_node = 1; e->node.key = ngx_http_cloudrouter_hash_route(route); (void)ngx_copy(e->di_name, route->di_name, sizeof(route->di_name)); e->di_nlen = route->di_nlen; } else { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "CloudRouter preconnect: reusing existing node"); } e->timestamp = time(NULL); ngx_http_cloudrouter_clear_remotes_locked(e, rev->log); while (next < pcd->bufpos) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "CloudRouter preconnect: parsing message"); unsigned char *ip = NULL; unsigned char *port = NULL; ip = next; while (++next < pcd->bufpos) { if (*(next-1) == '\n') { if (ip && port) break; port = next; } } if (ip && port) { ngx_http_cloudrouter_remote_t *remote = ngx_http_cloudrouter_add_remote_locked(e); int iplen = port-ip-1; iplen = iplen > 16 ? 16 : iplen; remote->inet_addr = ngx_inet_addr(ip, iplen); if (remote->inet_addr == INADDR_NONE) { ngx_log_error(NGX_LOG_ERR, rev->log, NGX_EINVAL, "CloudRouter preconnect: IP address from Agent invalid for route %s", e->di_name); goto failure; } int portlen = next-port-1; remote->port_n = htons(ngx_atoi(port,portlen)); ngx_log_debug7(NGX_LOG_DEBUG_HTTP, rev->log, 0, "CloudRouter preconnect: cached values SET: e=%p rem=%p ts=%d %s[%d] %uxD:%d", e, remote, e->timestamp, e->di_name, e->di_nlen, remote->inet_addr, remote->port_n); } } if (!e->remote) { ngx_log_debug(NGX_LOG_DEBUG_HTTP, rev->log, 0, "CloudRouter preconnect: Agent sent no remotes"); goto failure; } ngx_http_cloudrouter_set_hostandport(r, peer, e); if (new_node) { ngx_rbtree_insert(ngx_http_cloudrouter_rbtree, &e->node); } ngx_shmtx_unlock(&ngx_http_cloudrouter_shpool->mutex); return ngx_http_cloudrouter_peer_preconnect_close(c, pcd, NGX_OK); failure: if (!new_node) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pcd->r->connection->log, 0, "peer_preconnect_read: calling rbtree_delete"); ngx_rbtree_delete(ngx_http_cloudrouter_rbtree, &e->node); } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pcd->r->connection->log, 0, "peer_preconnect_read: calling free_node_locked"); ngx_http_cloudrouter_free_node_locked(e, rev->log); ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pcd->r->connection->log, 0, "peer_preconnect_read: calling shmtx_unlock"); ngx_shmtx_unlock(&ngx_http_cloudrouter_shpool->mutex); ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pcd->r->connection->log, 0, "peer_preconnect_read: calling peer_preconnect_close"); return ngx_http_cloudrouter_peer_preconnect_close(c, pcd, NGX_ERROR); } return; } /* unknown error condition from ngx_recv */ return; }
static void ngx_mail_auth_http_ignore_status_line(ngx_mail_session_t *s, ngx_mail_auth_http_ctx_t *ctx) { u_char *p, ch; enum { sw_start = 0, sw_H, sw_HT, sw_HTT, sw_HTTP, sw_skip, sw_almost_done } state; ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, "mail auth http process status line"); state = ctx->state; for (p = ctx->response->pos; p < ctx->response->last; p++) { ch = *p; switch (state) { /* "HTTP/" */ case sw_start: if (ch == 'H') { state = sw_H; break; } goto next; case sw_H: if (ch == 'T') { state = sw_HT; break; } goto next; case sw_HT: if (ch == 'T') { state = sw_HTT; break; } goto next; case sw_HTT: if (ch == 'P') { state = sw_HTTP; break; } goto next; case sw_HTTP: if (ch == '/') { state = sw_skip; break; } goto next; /* any text until end of line */ case sw_skip: switch (ch) { case CR: state = sw_almost_done; break; case LF: goto done; } break; /* end of status line */ case sw_almost_done: if (ch == LF) { goto done; } ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "auth http server %V sent invalid response", ctx->peer.name); ngx_close_connection(ctx->peer.connection); ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } } ctx->response->pos = p; ctx->state = state; return; next: p = ctx->response->start - 1; done: ctx->response->pos = p + 1; ctx->state = 0; ctx->handler = ngx_mail_auth_http_process_headers; ctx->handler(s, ctx); }
static void ngx_nats_close_connection(ngx_nats_connection_t *nc, ngx_int_t reason, ngx_int_t reconnect) { ngx_connection_t *c = nc->pc.connection; ngx_nats_data_t *nd = nc->nd; ngx_nats_client_t **pclient; ngx_int_t i, n, immediate; if (nc->ping_timer.timer_set) { ngx_del_timer(&nc->ping_timer); } if (c->fd != -1) { ngx_close_connection(c); } if (c->read->timer_set) { ngx_event_del_timer(c->read); } if (c->write->timer_set) { ngx_event_del_timer(c->write); } immediate = 0; if (!(nc->state & NGX_NATS_STATE_BYTES_EXCHANGED)) { /* reconnect immediately because we simply could not connect */ immediate = 1; ngx_log_error(NGX_LOG_DEBUG, nc->nd->log, 0, "cannot connect to NATS at '%V'", &nc->server->url); } else if (nc->state == NGX_NATS_STATE_READY) { ngx_log_error(NGX_LOG_WARN, nc->nd->log, 0, "disconnected from NATS at '%V'", &nc->server->url); /* Call disconnected in clients */ n = nd->cd.clients.nelts; pclient = nd->cd.clients.elts; for (i = 0; i < n; i++, pclient++) { if ((*pclient)->disconnected) { (*pclient)->disconnected(*pclient); } } } else { /* TODO: handle partial connect */ } nd->cd.subs.nelts = 0; /* remove all subscriptions */ nd->cd.next_id = 0; nd->nc = NULL; /* clear buffers */ ngx_nats_buf_reset(nd->nc_read_buf); ngx_nats_buf_reset(nd->nc_write_buf); if (reconnect != 0) { /* * if we could not connect at all or simply disconnected * then try to reconnect immediately. * If we did connect and connection broke because of the internal * error or bad message from NATS then wait before reconnecting * so a poison pill message, or we're out of memory, do not put * us into a tight connection loop. */ if (reason == NGX_NATS_REASON_DISCONNECTED || immediate) { /* this reconnects immediately */ ngx_nats_process_reconnect(nd); } else { /* this runs timer, then reconnects */ ngx_nats_add_reconnect_timer(nd); } } }
ngx_int_t ngx_rtmp_netcall_create(ngx_rtmp_session_t *s, ngx_rtmp_netcall_init_t *ci) { ngx_rtmp_netcall_ctx_t *ctx; ngx_peer_connection_t *pc; ngx_rtmp_netcall_session_t *cs; ngx_rtmp_netcall_app_conf_t *cacf; ngx_connection_t *c, *cc; ngx_pool_t *pool; ngx_int_t rc; pool = NULL; c = s->connection; cacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_netcall_module); if (cacf == NULL) { goto error; } /* get module context */ ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_netcall_module); if (ctx == NULL) { ctx = ngx_pcalloc(c->pool, sizeof(ngx_rtmp_netcall_ctx_t)); if (ctx == NULL) { return NGX_ERROR; } ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_netcall_module); } /* Create netcall pool, connection, session. * Note we use shared (app-wide) log because * s->connection->log might be unavailable * in detached netcall when it's being closed */ pool = ngx_create_pool(4096, cacf->log); if (pool == NULL) { goto error; } pc = ngx_pcalloc(pool, sizeof(ngx_peer_connection_t)); if (pc == NULL) { goto error; } cs = ngx_pcalloc(pool, sizeof(ngx_rtmp_netcall_session_t)); if (cs == NULL) { goto error; } /* copy arg to connection pool */ if (ci->argsize) { cs->arg = ngx_pcalloc(pool, ci->argsize); if (cs->arg == NULL) { goto error; } ngx_memcpy(cs->arg, ci->arg, ci->argsize); } cs->timeout = cacf->timeout; cs->bufsize = cacf->bufsize; cs->url = ci->url; cs->session = s; cs->filter = ci->filter; cs->sink = ci->sink; cs->handle = ci->handle; if (cs->handle == NULL) { cs->detached = 1; } pc->log = cacf->log; pc->get = ngx_rtmp_netcall_get_peer; pc->free = ngx_rtmp_netcall_free_peer; pc->data = cs; /* connect */ rc = ngx_event_connect_peer(pc); if (rc != NGX_OK && rc != NGX_AGAIN ) { ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "netcall: connection failed"); goto error; } cc = pc->connection; cc->data = cs; cc->pool = pool; cs->pc = pc; cs->out = ci->create(s, ci->arg, pool); if (cs->out == NULL) { ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "netcall: creation failed"); ngx_close_connection(pc->connection); goto error; } cc->write->handler = ngx_rtmp_netcall_send; cc->read->handler = ngx_rtmp_netcall_recv; if (!cs->detached) { cs->next = ctx->cs; ctx->cs = cs; } ngx_rtmp_netcall_send(cc->write); return c->destroyed ? NGX_ERROR : NGX_OK; error: if (pool) { ngx_destroy_pool(pool); } return NGX_ERROR; }
void ngx_http_upstream_drizzle_finalize_request(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_int_t rc) { #if !defined(nginx_version) || nginx_version < 1009001 ngx_time_t *tp; #endif dd("enter"); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "finalize http upstream request: %i", rc); if (u->cleanup) { *u->cleanup = NULL; } if (u->resolved && u->resolved->ctx) { ngx_resolve_name_done(u->resolved->ctx); u->resolved->ctx = NULL; } #if defined(nginx_version) && nginx_version >= 1009001 if (u->state && u->state->response_time) { u->state->response_time = ngx_current_msec - u->state->response_time; #else if (u->state && u->state->response_sec) { tp = ngx_timeofday(); u->state->response_sec = tp->sec - u->state->response_sec; u->state->response_msec = tp->msec - u->state->response_msec; #endif if (u->pipe) { u->state->response_length = u->pipe->read_length; } } if (u->finalize_request) { u->finalize_request(r, rc); } if (u->peer.free) { dd("before free peer"); u->peer.free(&u->peer, u->peer.data, 0); dd("after free peer"); } dd("about to free peer 2, c: %p, r pool: %p", u->peer.connection, r->pool); if (u->peer.connection) { #if 0 /* libdrizzle doesn't support SSL, was: (NGX_HTTP_SSL) */ /* TODO: do not shutdown persistent connection */ if (u->peer.connection->ssl) { /* * We send the "close notify" shutdown alert to the upstream only * and do not wait its "close notify" shutdown alert. * It is acceptable according to the TLS standard. */ u->peer.connection->ssl->no_wait_shutdown = 1; (void) ngx_ssl_shutdown(u->peer.connection); } #endif ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "drizzle close http upstream connection: %d", u->peer.connection->fd); dd("r pool: %p, c pool: %p", r->pool, u->peer.connection->pool); ngx_close_connection(u->peer.connection); } u->peer.connection = NULL; if (u->pipe && u->pipe->temp_file) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http upstream temp fd: %d", u->pipe->temp_file->file.fd); } if (u->header_sent && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE)) { rc = 0; } if (rc == NGX_DECLINED) { return; } r->connection->log->action = "sending to client"; if (rc == 0) { rc = ngx_http_send_special(r, NGX_HTTP_LAST); } ngx_http_finalize_request(r, rc); } void ngx_http_upstream_drizzle_next(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_int_t ft_type) { ngx_uint_t status, state; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http next upstream, %xi", ft_type); #if 0 ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock); #endif if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404) { state = NGX_PEER_NEXT; } else { state = NGX_PEER_FAILED; } if (ft_type != NGX_HTTP_UPSTREAM_FT_NOLIVE) { u->peer.free(&u->peer, u->peer.data, state); } if (ft_type == NGX_HTTP_UPSTREAM_FT_TIMEOUT) { ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ETIMEDOUT, "upstream timed out"); } if (u->peer.cached && ft_type == NGX_HTTP_UPSTREAM_FT_ERROR) { status = 0; } else { switch (ft_type) { case NGX_HTTP_UPSTREAM_FT_TIMEOUT: status = NGX_HTTP_GATEWAY_TIME_OUT; break; case NGX_HTTP_UPSTREAM_FT_HTTP_500: status = NGX_HTTP_INTERNAL_SERVER_ERROR; break; case NGX_HTTP_UPSTREAM_FT_HTTP_404: status = NGX_HTTP_NOT_FOUND; break; /* * NGX_HTTP_UPSTREAM_FT_BUSY_LOCK and NGX_HTTP_UPSTREAM_FT_MAX_WAITING * never reach here */ default: status = NGX_HTTP_BAD_GATEWAY; } } if (r->connection->error) { ngx_http_upstream_drizzle_finalize_request(r, u, NGX_HTTP_CLIENT_CLOSED_REQUEST); return; } if (status) { u->state->status = status; if (u->peer.tries == 0 || !(u->conf->next_upstream & ft_type)) { ngx_http_upstream_drizzle_finalize_request(r, u, status); return; } } if (u->peer.connection) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "close http upstream connection: %d", u->peer.connection->fd); #if 0 /* libdrizzle doesn't support SSL, was: (NGX_HTTP_SSL) */ if (u->peer.connection->ssl) { u->peer.connection->ssl->no_wait_shutdown = 1; u->peer.connection->ssl->no_send_shutdown = 1; (void) ngx_ssl_shutdown(u->peer.connection); } #endif dd("r pool: %p, c pool: %p", r->pool, u->peer.connection->pool); ngx_close_connection(u->peer.connection); } #if 0 if (u->conf->busy_lock && !u->busy_locked) { ngx_http_upstream_busy_lock(p); return; } #endif /* TODO: ngx_http_upstream_connect(r, u); */ if (status == 0) { status = NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_http_upstream_drizzle_finalize_request(r, u, status); }
ngx_int_t ngx_event_connect_peer(ngx_peer_connection_t *pc) { int rc, type; #if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT || NGX_LINUX) in_port_t port; #endif ngx_int_t event; ngx_err_t err; ngx_uint_t level; ngx_socket_t s; ngx_event_t *rev, *wev; ngx_connection_t *c; rc = pc->get(pc, pc->data); if (rc != NGX_OK) { return rc; } type = (pc->type ? pc->type : SOCK_STREAM); s = ngx_socket(pc->sockaddr->sa_family, type, 0); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pc->log, 0, "%s socket %d", (type == SOCK_STREAM) ? "stream" : "dgram", s); if (s == (ngx_socket_t) -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_socket_n " failed"); return NGX_ERROR; } c = ngx_get_connection(s, pc->log); if (c == NULL) { if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_close_socket_n " failed"); } return NGX_ERROR; } c->type = type; if (pc->rcvbuf) { if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (const void *) &pc->rcvbuf, sizeof(int)) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, "setsockopt(SO_RCVBUF) failed"); goto failed; } } if (ngx_nonblocking(s) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_nonblocking_n " failed"); goto failed; } if (pc->local) { #if (NGX_HAVE_TRANSPARENT_PROXY) if (pc->transparent) { if (ngx_event_connect_set_transparent(pc, s) != NGX_OK) { goto failed; } } #endif #if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT || NGX_LINUX) port = ngx_inet_get_port(pc->local->sockaddr); #endif #if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT) if (pc->sockaddr->sa_family != AF_UNIX && port == 0) { static int bind_address_no_port = 1; if (bind_address_no_port) { if (setsockopt(s, IPPROTO_IP, IP_BIND_ADDRESS_NO_PORT, (const void *) &bind_address_no_port, sizeof(int)) == -1) { err = ngx_socket_errno; if (err != NGX_EOPNOTSUPP && err != NGX_ENOPROTOOPT) { ngx_log_error(NGX_LOG_ALERT, pc->log, err, "setsockopt(IP_BIND_ADDRESS_NO_PORT) " "failed, ignored"); } else { bind_address_no_port = 0; } } } } #endif #if (NGX_LINUX) if (pc->type == SOCK_DGRAM && port != 0) { int reuse_addr = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse_addr, sizeof(int)) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, "setsockopt(SO_REUSEADDR) failed"); goto failed; } } #endif if (bind(s, pc->local->sockaddr, pc->local->socklen) == -1) { ngx_log_error(NGX_LOG_CRIT, pc->log, ngx_socket_errno, "bind(%V) failed", &pc->local->name); goto failed; } } if (type == SOCK_STREAM) { c->recv = ngx_recv; c->send = ngx_send; c->recv_chain = ngx_recv_chain; c->send_chain = ngx_send_chain; c->sendfile = 1; if (pc->sockaddr->sa_family == AF_UNIX) { c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED; c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED; #if (NGX_SOLARIS) /* Solaris's sendfilev() supports AF_NCA, AF_INET, and AF_INET6 */ c->sendfile = 0; #endif } } else { /* type == SOCK_DGRAM */ c->recv = ngx_udp_recv; c->send = ngx_send; c->send_chain = ngx_udp_send_chain; } c->log_error = pc->log_error; rev = c->read; wev = c->write; rev->log = pc->log; wev->log = pc->log; pc->connection = c; c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); if (ngx_add_conn) { if (ngx_add_conn(c) == NGX_ERROR) { goto failed; } } ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connect to %V, fd:%d #%uA", pc->name, s, c->number); rc = connect(s, pc->sockaddr, pc->socklen); if (rc == -1) { err = ngx_socket_errno; if (err != NGX_EINPROGRESS #if (NGX_WIN32) /* Winsock returns WSAEWOULDBLOCK (NGX_EAGAIN) */ && err != NGX_EAGAIN #endif ) { if (err == NGX_ECONNREFUSED #if (NGX_LINUX) /* * Linux returns EAGAIN instead of ECONNREFUSED * for unix sockets if listen queue is full */ || err == NGX_EAGAIN #endif || err == NGX_ECONNRESET || err == NGX_ENETDOWN || err == NGX_ENETUNREACH || err == NGX_EHOSTDOWN || err == NGX_EHOSTUNREACH) { level = NGX_LOG_ERR; } else { level = NGX_LOG_CRIT; } ngx_log_error(level, c->log, err, "connect() to %V failed", pc->name); ngx_close_connection(c); pc->connection = NULL; return NGX_DECLINED; } } if (ngx_add_conn) { if (rc == -1) { /* NGX_EINPROGRESS */ return NGX_AGAIN; } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connected"); wev->ready = 1; return NGX_OK; } if (ngx_event_flags & NGX_USE_IOCP_EVENT) { ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, ngx_socket_errno, "connect(): %d", rc); if (ngx_blocking(s) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_blocking_n " failed"); goto failed; } /* * FreeBSD's aio allows to post an operation on non-connected socket. * NT does not support it. * * TODO: check in Win32, etc. As workaround we can use NGX_ONESHOT_EVENT */ rev->ready = 1; wev->ready = 1; return NGX_OK; } if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { /* kqueue */ event = NGX_CLEAR_EVENT; } else { /* select, poll, /dev/poll */ event = NGX_LEVEL_EVENT; } if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) { goto failed; } if (rc == -1) { /* NGX_EINPROGRESS */ if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) { goto failed; } return NGX_AGAIN; } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connected"); wev->ready = 1; return NGX_OK; failed: ngx_close_connection(c); pc->connection = NULL; return NGX_ERROR; }
ngx_int_t ngx_event_connect_peer(ngx_peer_connection_t *pc) { int rc; ngx_int_t event; ngx_err_t err; ngx_uint_t level; ngx_socket_t s; ngx_event_t *rev, *wev; ngx_connection_t *c; //调用pc->get钩子。如前面所述,若是keepalive upstream,则该钩子是 //ngx_http_upstream_get_keepalive_peer,此时如果存在缓存长连接该函数调用返回的是 //NGX_DONE,直接返回上层调用而不会继续往下执行获取新的连接并创建socket, //如果不存在缓存的长连接,则会返回NGX_OK. //若是非keepalive upstream,该钩子是ngx_http_upstream_get_round_robin_peer。 rc = pc->get(pc, pc->data); if (rc != NGX_OK) { return rc; } // 非keepalive upstream或者keepalive upstream未找到缓存连接,则创建socket s = ngx_socket(pc->sockaddr->sa_family, SOCK_STREAM, 0); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, 0, "socket %d", s); if (s == (ngx_socket_t) -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_socket_n " failed"); return NGX_ERROR; } //由于Nginx的事件框架要求每个连接都由一个ngx_connection_t结构体来承载,因此这一步调用ngx_get_connection //方法获取到一个结构体,作为承载Nginx与上游服务器间的TCP连接 c = ngx_get_connection(s, pc->log); if (c == NULL) { if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_close_socket_n "failed"); } return NGX_ERROR; } if (pc->rcvbuf) { if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (const void *) &pc->rcvbuf, sizeof(int)) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, "setsockopt(SO_RCVBUF) failed"); goto failed; } } if (ngx_nonblocking(s) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_nonblocking_n " failed"); goto failed; } if (pc->local) { if (bind(s, pc->local->sockaddr, pc->local->socklen) == -1) { ngx_log_error(NGX_LOG_CRIT, pc->log, ngx_socket_errno, "bind(%V) failed", &pc->local->name); goto failed; } } c->recv = ngx_recv; c->send = ngx_send; c->recv_chain = ngx_recv_chain; c->send_chain = ngx_send_chain; c->sendfile = 1; c->log_error = pc->log_error; if (pc->sockaddr->sa_family == AF_UNIX) { c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED; c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED; #if (NGX_SOLARIS) /* Solaris's sendfilev() supports AF_NCA, AF_INET, and AF_INET6 */ c->sendfile = 0; #endif } rev = c->read; wev = c->write; rev->log = pc->log; wev->log = pc->log; pc->connection = c; c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); //把套接字以期待EPOLLIN|EPOLLOUT事件的方式加入epoll中,表示如果这个套接字上出现了预期的网络事件, //则希望epoll能够回调它的handler方法 if (ngx_add_conn) { if (ngx_add_conn(c) == NGX_ERROR) { goto failed; } } ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connect to %V, fd:%d #%uA", pc->name, s, c->number); //调用connect方法向上游服务器发起TCP连接,作为非阻塞套接字,connect方法可能立即返回连接建立成功, //也可能告诉用户继续等待上游服务器的响应 rc = connect(s, pc->sockaddr, pc->socklen); if (rc == -1) { err = ngx_socket_errno; if (err != NGX_EINPROGRESS #if (NGX_WIN32) && err != NGX_EAGAIN /* Winsock returns WSAEWOULDBLOCK (NGX_EAGAIN) */ #endif ) { if (err == NGX_ECONNREFUSED #if (NGX_LINUX) /*Linux returns EAGAIN instead of ECONNREFUSED for unix sockets if listen queue is full */ || err == NGX_EAGAIN #endif || err == NGX_ECONNRESET || err == NGX_ENETDOWN || err == NGX_ENETUNREACH || err == NGX_EHOSTDOWN || err == NGX_EHOSTUNREACH) { level = NGX_LOG_ERR; } else { level = NGX_LOG_CRIT; } ngx_log_error(level, c->log, err, "connect() to %V failed", pc->name); ngx_close_connection(c); pc->connection = NULL; return NGX_DECLINED; } } if (ngx_add_conn) { if (rc == -1) { /* NGX_EINPROGRESS */ return NGX_AGAIN; } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connected"); wev->ready = 1; return NGX_OK; } if (ngx_event_flags & NGX_USE_IOCP_EVENT) { ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, ngx_socket_errno, "connect(): %d", rc); if (ngx_blocking(s) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_blocking_n " failed"); goto failed; } /* * FreeBSD's aio allows to post an operation on non-connected socket. * NT does not support it. * * TODO: check in Win32, etc. As workaround we can use NGX_ONESHOT_EVENT */ rev->ready = 1; wev->ready = 1; return NGX_OK; } if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { /* kqueue */ event = NGX_CLEAR_EVENT; } else { /* select, poll, /dev/poll */ event = NGX_LEVEL_EVENT; } if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) { goto failed; } if (rc == -1) { /* NGX_EINPROGRESS */ if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) { goto failed; } return NGX_AGAIN; } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connected"); wev->ready = 1; return NGX_OK; failed: ngx_close_connection(c); pc->connection = NULL; return NGX_ERROR; }
void ngx_mail_auth_http_init(ngx_mail_session_t *s) { ngx_int_t rc; ngx_pool_t *pool; ngx_mail_auth_http_ctx_t *ctx; ngx_mail_auth_http_conf_t *ahcf; s->connection->log->action = "in http auth state"; pool = ngx_create_pool(2048, s->connection->log); if (pool == NULL) { ngx_mail_session_internal_server_error(s); return; } ctx = ngx_pcalloc(pool, sizeof(ngx_mail_auth_http_ctx_t)); if (ctx == NULL) { ngx_destroy_pool(pool); ngx_mail_session_internal_server_error(s); return; } ctx->pool = pool; ahcf = ngx_mail_get_module_srv_conf(s, ngx_mail_auth_http_module); ctx->request = ngx_mail_auth_http_create_request(s, pool, ahcf); if (ctx->request == NULL) { ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } ngx_mail_set_ctx(s, ctx, ngx_mail_auth_http_module); ctx->peer.sockaddr = ahcf->peer->sockaddr; ctx->peer.socklen = ahcf->peer->socklen; ctx->peer.name = &ahcf->peer->name; ctx->peer.get = ngx_event_get_peer; ctx->peer.log = s->connection->log; ctx->peer.log_error = NGX_ERROR_ERR; rc = ngx_event_connect_peer(&ctx->peer); if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) { if (ctx->peer.connection) { ngx_close_connection(ctx->peer.connection); } ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } ctx->peer.connection->data = s; ctx->peer.connection->pool = s->connection->pool; s->connection->read->handler = ngx_mail_auth_http_block_read; ctx->peer.connection->read->handler = ngx_mail_auth_http_read_handler; ctx->peer.connection->write->handler = ngx_mail_auth_http_write_handler; ctx->handler = ngx_mail_auth_http_ignore_status_line; ngx_add_timer(ctx->peer.connection->read, ahcf->timeout); ngx_add_timer(ctx->peer.connection->write, ahcf->timeout); if (rc == NGX_OK) { ngx_mail_auth_http_write_handler(ctx->peer.connection->write); return; } }
void ngx_http_cloudrouter_peer_preconnect(ngx_http_request_t *r, ngx_http_upstream_t *u) { ngx_int_t rc; ngx_peer_connection_t *c; struct sockaddr_in *sin; ngx_http_cloudrouter_peer_preconnect_data_t *pcd; ngx_http_cleanup_t *cln; ngx_http_cloudrouter_peer_t *peer; r->connection->log->action = "connecting to cloudrouter agent"; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "preconnect"); c = ngx_pcalloc(r->connection->pool, sizeof(ngx_peer_connection_t)); sin = ngx_pcalloc(r->connection->pool, sizeof(struct sockaddr_in)); pcd = ngx_pcalloc(r->connection->pool, sizeof(ngx_http_cloudrouter_peer_preconnect_data_t)); peer = (ngx_http_cloudrouter_peer_t*)u->peer.data; if (sin==NULL || c==NULL || pcd==NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "preconnect: cannot allocate sin/c/pcd"); return; } /* FIXME: should cache this */ sin->sin_family = AF_INET; sin->sin_port = htons(9091); ngx_str_t localhost; ngx_str_set(&localhost, "127.0.0.1"); sin->sin_addr.s_addr = ngx_inet_addr(localhost.data, localhost.len); c->sockaddr = (struct sockaddr *)sin; c->socklen = sizeof(struct sockaddr_in); c->get = ngx_event_get_peer; // dummy method returning the peer itself. c->log = r->connection->log; c->log_error = r->connection->log_error; c->name = ngx_pcalloc(r->connection->pool, sizeof *c->name); if (c->name == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "preconnect: cannot allocate c->name"); return; } ngx_str_set(c->name, "127.0.0.1:9091"); rc = ngx_event_connect_peer(c); if (rc==NGX_ERROR || rc==NGX_BUSY || rc==NGX_DECLINED) { ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "preconnect very much unsuccessful."); if (c->connection) { ngx_close_connection(c->connection); c->connection->destroyed = 1; } ngx_http_upstream_next(r,u,NGX_HTTP_UPSTREAM_FT_ERROR); return; } r->main->count++; pcd->r = r; pcd->u = u; pcd->sendbufpos = 0; if (peer->route==NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ROUTE is null in preconnect!"); ngx_log_debug(NGX_LOG_ERR, r->connection->log, 0, "ROUTE is null in preconnect!"); ngx_http_upstream_next(r,u,NGX_HTTP_UPSTREAM_FT_ERROR); return; } (void)ngx_copy(&pcd->route,peer->route, sizeof(hs_route_t)); pcd->c = c->connection; c->connection->data = pcd; c->connection->pool = r->connection->pool; c->connection->read->handler = ngx_http_cloudrouter_peer_preconnect_read; c->connection->write->handler = ngx_http_cloudrouter_peer_preconnect_write; ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "preconnect successful."); ngx_add_timer(c->connection->read, 10000); ngx_add_timer(c->connection->write, 10000); cln = ngx_http_cleanup_add(r, 0); cln->data = pcd; cln->handler = ngx_http_cloudrouter_preconnect_cleanup; }
static void ngx_mail_auth_http_write_handler(ngx_event_t *wev) { ssize_t n, size; ngx_connection_t *c; ngx_mail_session_t *s; ngx_mail_auth_http_ctx_t *ctx; ngx_mail_auth_http_conf_t *ahcf; c = wev->data; s = c->data; ctx = ngx_mail_get_module_ctx(s, ngx_mail_auth_http_module); ngx_log_debug0(NGX_LOG_DEBUG_MAIL, wev->log, 0, "mail auth http write handler"); if (wev->timedout) { ngx_log_error(NGX_LOG_ERR, wev->log, NGX_ETIMEDOUT, "auth http server %V timed out", ctx->peer.name); ngx_close_connection(c); ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } size = ctx->request->last - ctx->request->pos; n = ngx_send(c, ctx->request->pos, size); if (n == NGX_ERROR) { ngx_close_connection(c); ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } if (n > 0) { ctx->request->pos += n; if (n == size) { wev->handler = ngx_mail_auth_http_dummy_handler; if (wev->timer_set) { ngx_del_timer(wev); } if (ngx_handle_write_event(wev, 0) != NGX_OK) { ngx_close_connection(c); ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); } return; } } if (!wev->timer_set) { ahcf = ngx_mail_get_module_srv_conf(s, ngx_mail_auth_http_module); ngx_add_timer(wev, ahcf->timeout); } }
ngx_int_t ngx_event_connect_peer(ngx_peer_connection_t *pc) { int rc; ngx_int_t event; ngx_err_t err; ngx_uint_t level; ngx_socket_t s; ngx_event_t *rev, *wev; ngx_connection_t *c; if(pc->get){ rc = pc->get(pc, pc->data); if (rc != NGX_OK) { return rc; } } s = ngx_socket(pc->sockaddr->sa_family, SOCK_STREAM, 0); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, 0, "socket %d", s); if (s == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_socket_n " failed"); return NGX_ERROR; } c = ngx_get_connection(s, pc->log); if (c == NULL) { if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_close_socket_n "failed"); } return NGX_ERROR; } if (pc->rcvbuf) { if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (const void *) &pc->rcvbuf, sizeof(int)) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, "setsockopt(SO_RCVBUF) failed"); goto failed; } } if (ngx_nonblocking(s) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_nonblocking_n " failed"); goto failed; } if (pc->local) { if (bind(s, pc->local->sockaddr, pc->local->socklen) == -1) { ngx_log_error(NGX_LOG_CRIT, pc->log, ngx_socket_errno, "bind(%V) failed", &pc->local->name); goto failed; } } c->recv = ngx_recv; c->send = ngx_send; c->recv_chain = ngx_recv_chain; c->send_chain = ngx_send_chain; c->sendfile = 1; c->log_error = pc->log_error; if (pc->sockaddr->sa_family != AF_INET) { c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED; c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED; #if (NGX_SOLARIS) /* Solaris's sendfilev() supports AF_NCA, AF_INET, and AF_INET6 */ c->sendfile = 0; #endif } rev = c->read; wev = c->write; rev->log = pc->log; wev->log = pc->log; pc->connection = c; c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); #if (NGX_THREADS) /* TODO: lock event when call completion handler */ rev->lock = pc->lock; wev->lock = pc->lock; rev->own_lock = &c->lock; wev->own_lock = &c->lock; #endif if (ngx_add_conn) { if (ngx_add_conn(c) == NGX_ERROR) { goto failed; } } ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connect to %V, fd:%d #%d", pc->name, s, c->number); rc = connect(s, pc->sockaddr, pc->socklen); if (rc == -1) { err = ngx_socket_errno; if (err != NGX_EINPROGRESS #if (NGX_WIN32) /* Winsock returns WSAEWOULDBLOCK (NGX_EAGAIN) */ && err != NGX_EAGAIN #endif ) { if (err == NGX_ECONNREFUSED #if (NGX_LINUX) /* * Linux returns EAGAIN instead of ECONNREFUSED * for unix sockets if listen queue is full */ || err == NGX_EAGAIN #endif || err == NGX_ECONNRESET || err == NGX_ENETDOWN || err == NGX_ENETUNREACH || err == NGX_EHOSTDOWN || err == NGX_EHOSTUNREACH) { level = NGX_LOG_ERR; } else { level = NGX_LOG_CRIT; } ngx_log_error(level, c->log, err, "connect() to %V failed", pc->name); ngx_close_connection(c); pc->connection = NULL; return NGX_DECLINED; } } if (ngx_add_conn) { if (rc == -1) { /* NGX_EINPROGRESS */ return NGX_AGAIN; } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connected"); wev->ready = 1; return NGX_OK; } if (ngx_event_flags & NGX_USE_AIO_EVENT) { ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, ngx_socket_errno, "connect(): %d", rc); /* aio, iocp */ if (ngx_blocking(s) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_blocking_n " failed"); goto failed; } /* * FreeBSD's aio allows to post an operation on non-connected socket. * NT does not support it. * * TODO: check in Win32, etc. As workaround we can use NGX_ONESHOT_EVENT */ rev->ready = 1; wev->ready = 1; return NGX_OK; } if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { /* kqueue */ event = NGX_CLEAR_EVENT; } else { /* select, poll, /dev/poll */ event = NGX_LEVEL_EVENT; } if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) { goto failed; } if (rc == -1) { /* NGX_EINPROGRESS */ if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) { goto failed; } return NGX_AGAIN; } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connected"); wev->ready = 1; return NGX_OK; failed: ngx_close_connection(c); pc->connection = NULL; return NGX_ERROR; }
static void ngx_mail_auth_http_process_headers(ngx_mail_session_t *s, ngx_mail_auth_http_ctx_t *ctx) { u_char *p; time_t timer; size_t len, size; ngx_int_t rc, port, n; ngx_addr_t *peer; ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, "mail auth http process headers"); for ( ;; ) { rc = ngx_mail_auth_http_parse_header_line(s, ctx); if (rc == NGX_OK) { #if (NGX_DEBUG) { ngx_str_t key, value; key.len = ctx->header_name_end - ctx->header_name_start; key.data = ctx->header_name_start; value.len = ctx->header_end - ctx->header_start; value.data = ctx->header_start; ngx_log_debug2(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, "mail auth http header: \"%V: %V\"", &key, &value); } #endif len = ctx->header_name_end - ctx->header_name_start; if (len == sizeof("Auth-Status") - 1 && ngx_strncasecmp(ctx->header_name_start, (u_char *) "Auth-Status", sizeof("Auth-Status") - 1) == 0) { len = ctx->header_end - ctx->header_start; if (len == 2 && ctx->header_start[0] == 'O' && ctx->header_start[1] == 'K') { continue; } if (len == 4 && ctx->header_start[0] == 'W' && ctx->header_start[1] == 'A' && ctx->header_start[2] == 'I' && ctx->header_start[3] == 'T') { s->auth_wait = 1; continue; } ctx->errmsg.len = len; ctx->errmsg.data = ctx->header_start; switch (s->protocol) { case NGX_MAIL_POP3_PROTOCOL: size = sizeof("-ERR ") - 1 + len + sizeof(CRLF) - 1; break; case NGX_MAIL_IMAP_PROTOCOL: size = s->tag.len + sizeof("NO ") - 1 + len + sizeof(CRLF) - 1; break; default: /* NGX_MAIL_SMTP_PROTOCOL */ ctx->err = ctx->errmsg; continue; } p = ngx_pnalloc(s->connection->pool, size); if (p == NULL) { ngx_close_connection(ctx->peer.connection); ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } ctx->err.data = p; switch (s->protocol) { case NGX_MAIL_POP3_PROTOCOL: *p++ = '-'; *p++ = 'E'; *p++ = 'R'; *p++ = 'R'; *p++ = ' '; break; case NGX_MAIL_IMAP_PROTOCOL: p = ngx_cpymem(p, s->tag.data, s->tag.len); *p++ = 'N'; *p++ = 'O'; *p++ = ' '; break; default: /* NGX_MAIL_SMTP_PROTOCOL */ break; } p = ngx_cpymem(p, ctx->header_start, len); *p++ = CR; *p++ = LF; ctx->err.len = p - ctx->err.data; continue; } if (len == sizeof("Auth-Server") - 1 && ngx_strncasecmp(ctx->header_name_start, (u_char *) "Auth-Server", sizeof("Auth-Server") - 1) == 0) { ctx->addr.len = ctx->header_end - ctx->header_start; ctx->addr.data = ctx->header_start; continue; } if (len == sizeof("Auth-Port") - 1 && ngx_strncasecmp(ctx->header_name_start, (u_char *) "Auth-Port", sizeof("Auth-Port") - 1) == 0) { ctx->port.len = ctx->header_end - ctx->header_start; ctx->port.data = ctx->header_start; continue; } if (len == sizeof("Auth-User") - 1 && ngx_strncasecmp(ctx->header_name_start, (u_char *) "Auth-User", sizeof("Auth-User") - 1) == 0) { s->login.len = ctx->header_end - ctx->header_start; s->login.data = ngx_pnalloc(s->connection->pool, s->login.len); if (s->login.data == NULL) { ngx_close_connection(ctx->peer.connection); ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } ngx_memcpy(s->login.data, ctx->header_start, s->login.len); continue; } if (len == sizeof("Auth-Pass") - 1 && ngx_strncasecmp(ctx->header_name_start, (u_char *) "Auth-Pass", sizeof("Auth-Pass") - 1) == 0) { s->passwd.len = ctx->header_end - ctx->header_start; s->passwd.data = ngx_pnalloc(s->connection->pool, s->passwd.len); if (s->passwd.data == NULL) { ngx_close_connection(ctx->peer.connection); ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } ngx_memcpy(s->passwd.data, ctx->header_start, s->passwd.len); continue; } if (len == sizeof("Auth-Wait") - 1 && ngx_strncasecmp(ctx->header_name_start, (u_char *) "Auth-Wait", sizeof("Auth-Wait") - 1) == 0) { n = ngx_atoi(ctx->header_start, ctx->header_end - ctx->header_start); if (n != NGX_ERROR) { ctx->sleep = n; } continue; } if (len == sizeof("Auth-Error-Code") - 1 && ngx_strncasecmp(ctx->header_name_start, (u_char *) "Auth-Error-Code", sizeof("Auth-Error-Code") - 1) == 0) { ctx->errcode.len = ctx->header_end - ctx->header_start; ctx->errcode.data = ngx_pnalloc(s->connection->pool, ctx->errcode.len); if (ctx->errcode.data == NULL) { ngx_close_connection(ctx->peer.connection); ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } ngx_memcpy(ctx->errcode.data, ctx->header_start, ctx->errcode.len); continue; } /* ignore other headers */ continue; } if (rc == NGX_DONE) { ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, "mail auth http header done"); ngx_close_connection(ctx->peer.connection); if (ctx->err.len) { ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, "client login failed: \"%V\"", &ctx->errmsg); if (s->protocol == NGX_MAIL_SMTP_PROTOCOL) { if (ctx->errcode.len == 0) { ctx->errcode = ngx_mail_smtp_errcode; } ctx->err.len = ctx->errcode.len + ctx->errmsg.len + sizeof(" " CRLF) - 1; p = ngx_pnalloc(s->connection->pool, ctx->err.len); if (p == NULL) { ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } ctx->err.data = p; p = ngx_cpymem(p, ctx->errcode.data, ctx->errcode.len); *p++ = ' '; p = ngx_cpymem(p, ctx->errmsg.data, ctx->errmsg.len); *p++ = CR; *p = LF; } s->out = ctx->err; timer = ctx->sleep; ngx_destroy_pool(ctx->pool); if (timer == 0) { s->quit = 1; ngx_mail_send(s->connection->write); return; } ngx_add_timer(s->connection->read, (ngx_msec_t) (timer * 1000)); s->connection->read->handler = ngx_mail_auth_sleep_handler; return; } if (s->auth_wait) { timer = ctx->sleep; ngx_destroy_pool(ctx->pool); if (timer == 0) { ngx_mail_auth_http_init(s); return; } ngx_add_timer(s->connection->read, (ngx_msec_t) (timer * 1000)); s->connection->read->handler = ngx_mail_auth_sleep_handler; return; } if (ctx->addr.len == 0 || ctx->port.len == 0) { ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "auth http server %V did not send server or port", ctx->peer.name); ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } if (s->passwd.data == NULL && s->protocol != NGX_MAIL_SMTP_PROTOCOL) { ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "auth http server %V did not send password", ctx->peer.name); ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } peer = ngx_pcalloc(s->connection->pool, sizeof(ngx_addr_t)); if (peer == NULL) { ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } rc = ngx_parse_addr(s->connection->pool, peer, ctx->addr.data, ctx->addr.len); switch (rc) { case NGX_OK: break; case NGX_DECLINED: ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "auth http server %V sent invalid server " "address:\"%V\"", ctx->peer.name, &ctx->addr); /* fall through */ default: ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } port = ngx_atoi(ctx->port.data, ctx->port.len); if (port == NGX_ERROR || port < 1 || port > 65535) { ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "auth http server %V sent invalid server " "port:\"%V\"", ctx->peer.name, &ctx->port); ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } ngx_inet_set_port(peer->sockaddr, (in_port_t) port); len = ctx->addr.len + 1 + ctx->port.len; peer->name.len = len; peer->name.data = ngx_pnalloc(s->connection->pool, len); if (peer->name.data == NULL) { ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } len = ctx->addr.len; ngx_memcpy(peer->name.data, ctx->addr.data, len); peer->name.data[len++] = ':'; ngx_memcpy(peer->name.data + len, ctx->port.data, ctx->port.len); ngx_destroy_pool(ctx->pool); ngx_mail_proxy_init(s, peer); return; } if (rc == NGX_AGAIN ) { return; } /* rc == NGX_ERROR */ ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "auth http server %V sent invalid header in response", ctx->peer.name); ngx_close_connection(ctx->peer.connection); ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } }
static void ngx_http_healthcheck_begin_healthcheck(ngx_event_t *event) { ngx_http_healthcheck_status_t * stat; ngx_connection_t *c; ngx_int_t rc; stat = event->data; if (stat->state != NGX_HEALTH_WAITING) { ngx_log_error(NGX_LOG_WARN, event->log, 0, "healthcheck: State not waiting, is %d", stat->state); } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, event->log, 0, "healthcheck: begun healthcheck of index %i", stat->index); ngx_memzero(stat->pc, sizeof(ngx_peer_connection_t)); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, event->log, 0, "healthcheck: Memzero done", stat->index); stat->pc->get = ngx_event_get_peer; stat->pc->sockaddr = stat->peer->sockaddr; stat->pc->socklen = stat->peer->socklen; stat->pc->name = &stat->peer->name; stat->pc->log = event->log; stat->pc->log_error = NGX_ERROR_ERR; // Um I guess (???) stat->pc->cached = 0; stat->pc->connection = NULL; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, event->log, 0, "healthcheck: Connecting peer", stat->index); rc = ngx_event_connect_peer(stat->pc); if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) { ngx_log_error(NGX_LOG_CRIT, event->log, 0, "healthcheck: Could not connect to peer. This is" " pretty bad and probably means your health checks won't" " work anymore: %i", rc); if (stat->pc->connection) { ngx_close_connection(stat->pc->connection); } // Try to do it again later, but if you're getting errors when you // try to connect to a peer, this probably won't work ngx_add_timer(&stat->health_ev, stat->conf->health_delay); return; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, event->log, 0, "healthcheck: connected so far"); c = stat->pc->connection; c->data = stat; c->log = stat->pc->log; c->write->handler = ngx_http_healthcheck_write_handler; c->read->handler = ngx_http_healthcheck_read_handler; c->sendfile = 0; c->read->log = c->log; c->write->log = c->log; stat->state = NGX_HEALTH_SENDING_CHECK; stat->shm->action_time = ngx_current_msec; stat->read_pos = 0; stat->send_pos = 0; stat->body_read_pos = 0; stat->read_buffer->pos = stat->read_buffer->start; stat->read_buffer->last = stat->read_buffer->start; stat->check_start_time = ngx_current_msec; ngx_add_timer(c->read, stat->conf->health_timeout); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, event->log, 0, "healthcheck: Peer connected", stat->index); ngx_http_healthcheck_send_request(c); }