/* * This function initiates a connection to the server assigned to this session * (s->srv, s->srv_addr). It will assign a server if none is assigned yet. * It can return one of : * - SN_ERR_NONE if everything's OK * - SN_ERR_SRVTO if there are no more servers * - SN_ERR_SRVCL if the connection was refused by the server * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn) * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...) * - SN_ERR_INTERNAL for any other purely internal errors * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted. */ int connect_server(struct session *s) { int err; if (!(s->flags & SN_ADDR_SET)) { err = assign_server_address(s); if (err != SRV_STATUS_OK) return SN_ERR_INTERNAL; } if (!s->req->cons->connect) return SN_ERR_INTERNAL; assign_tproxy_address(s); err = s->req->cons->connect(s->req->cons, s->be, s->srv, (struct sockaddr *)&s->srv_addr, (struct sockaddr *)&s->from_addr); if (err != SN_ERR_NONE) return err; if (s->srv) { s->flags |= SN_CURR_SESS; s->srv->cur_sess++; if (s->srv->cur_sess > s->srv->counters.cur_sess_max) s->srv->counters.cur_sess_max = s->srv->cur_sess; if (s->be->lbprm.server_take_conn) s->be->lbprm.server_take_conn(s->srv); } return SN_ERR_NONE; /* connection is OK */ }
/* * This function initiates a connection to the server assigned to this session * (s->target, s->si[1].addr.to). It will assign a server if none * is assigned yet. * It can return one of : * - SN_ERR_NONE if everything's OK * - SN_ERR_SRVTO if there are no more servers * - SN_ERR_SRVCL if the connection was refused by the server * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn) * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...) * - SN_ERR_INTERNAL for any other purely internal errors * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted. * The server-facing stream interface is expected to hold a pre-allocated connection * in s->si[1].conn. */ int connect_server(struct session *s) { struct connection *cli_conn; struct connection *srv_conn; struct server *srv; int reuse = 0; int err; srv_conn = objt_conn(s->si[1].end); if (srv_conn) reuse = s->target == srv_conn->target; if (reuse) { /* Disable connection reuse if a dynamic source is used. * As long as we don't share connections between servers, * we don't need to disable connection reuse on no-idempotent * requests nor when PROXY protocol is used. */ srv = objt_server(s->target); if (srv && srv->conn_src.opts & CO_SRC_BIND) { if ((srv->conn_src.opts & CO_SRC_TPROXY_MASK) == CO_SRC_TPROXY_DYN) reuse = 0; } else if (s->be->conn_src.opts & CO_SRC_BIND) { if ((s->be->conn_src.opts & CO_SRC_TPROXY_MASK) == CO_SRC_TPROXY_DYN) reuse = 0; } } srv_conn = si_alloc_conn(&s->si[1], reuse); if (!srv_conn) return SN_ERR_RESOURCE; if (!(s->flags & SN_ADDR_SET)) { err = assign_server_address(s); if (err != SRV_STATUS_OK) return SN_ERR_INTERNAL; } if (!conn_xprt_ready(srv_conn)) { /* the target was only on the session, assign it to the SI now */ srv_conn->target = s->target; /* set the correct protocol on the output stream interface */ if (objt_server(s->target)) { conn_prepare(srv_conn, protocol_by_family(srv_conn->addr.to.ss_family), objt_server(s->target)->xprt); } else if (obj_type(s->target) == OBJ_TYPE_PROXY) { /* proxies exclusively run on raw_sock right now */ conn_prepare(srv_conn, protocol_by_family(srv_conn->addr.to.ss_family), &raw_sock); if (!objt_conn(s->si[1].end) || !objt_conn(s->si[1].end)->ctrl) return SN_ERR_INTERNAL; } else return SN_ERR_INTERNAL; /* how did we get there ? */ /* process the case where the server requires the PROXY protocol to be sent */ srv_conn->send_proxy_ofs = 0; if (objt_server(s->target) && objt_server(s->target)->pp_opts) { srv_conn->send_proxy_ofs = 1; /* must compute size */ cli_conn = objt_conn(s->si[0].end); if (cli_conn) conn_get_to_addr(cli_conn); } si_attach_conn(&s->si[1], srv_conn); assign_tproxy_address(s); } else { /* the connection is being reused, just re-attach it */ si_attach_conn(&s->si[1], srv_conn); s->flags |= SN_SRV_REUSED; } /* flag for logging source ip/port */ if (s->fe->options2 & PR_O2_SRC_ADDR) s->si[1].flags |= SI_FL_SRC_ADDR; /* disable lingering */ if (s->be->options & PR_O_TCP_NOLING) s->si[1].flags |= SI_FL_NOLINGER; err = si_connect(&s->si[1]); if (err != SN_ERR_NONE) return err; /* set connect timeout */ s->si[1].exp = tick_add_ifset(now_ms, s->be->timeout.connect); srv = objt_server(s->target); if (srv) { s->flags |= SN_CURR_SESS; srv->cur_sess++; if (srv->cur_sess > srv->counters.cur_sess_max) srv->counters.cur_sess_max = srv->cur_sess; if (s->be->lbprm.server_take_conn) s->be->lbprm.server_take_conn(srv); } return SN_ERR_NONE; /* connection is OK */ }