src/backend.c
int assign_server(struct session *s)
{

	struct server *conn_slot;
	struct server *srv, *prev_srv;
	int err;

	DPRINTF(stderr,"assign_server : s=%p\n",s);

	err = SRV_STATUS_INTERNAL;
	if (unlikely(s->pend_pos || s->flags & SN_ASSIGNED))
		goto out_err;

	prev_srv  = objt_server(s->target);
	conn_slot = s->srv_conn;

	/* We have to release any connection slot before applying any LB algo,
	 * otherwise we may erroneously end up with no available slot.
	 */
	if (conn_slot)
		sess_change_server(s, NULL);

	/* We will now try to find the good server and store it into <objt_server(s->target)>.
	 * Note that <objt_server(s->target)> may be NULL in case of dispatch or proxy mode,
	 * as well as if no server is available (check error code).
	 */

	srv = NULL;
	s->target = NULL;

	if (s->be->lbprm.algo & BE_LB_KIND) {
		/* we must check if we have at least one server available */
		if (!s->be->lbprm.tot_weight) {
			err = SRV_STATUS_NOSRV;
			goto out;
		}

		/* First check whether we need to fetch some data or simply call
		 * the LB lookup function. Only the hashing functions will need
		 * some input data in fact, and will support multiple algorithms.
		 */
		switch (s->be->lbprm.algo & BE_LB_LKUP) {
		case BE_LB_LKUP_RRTREE:
			srv = fwrr_get_next_server(s->be, prev_srv);
			break;

		case BE_LB_LKUP_FSTREE:
			srv = fas_get_next_server(s->be, prev_srv);
			break;

		case BE_LB_LKUP_LCTREE:
			srv = fwlc_get_next_server(s->be, prev_srv);
			break;

		case BE_LB_LKUP_CHTREE:
		case BE_LB_LKUP_MAP:
			if ((s->be->lbprm.algo & BE_LB_KIND) == BE_LB_KIND_RR) {
				if (s->be->lbprm.algo & BE_LB_LKUP_CHTREE)
					srv = chash_get_next_server(s->be, prev_srv);
				else
					srv = map_get_server_rr(s->be, prev_srv);
				break;
			}
			else if ((s->be->lbprm.algo & BE_LB_KIND) != BE_LB_KIND_HI) {
				/* unknown balancing algorithm */
				err = SRV_STATUS_INTERNAL;
				goto out;
			}

			switch (s->be->lbprm.algo & BE_LB_PARM) {
			case BE_LB_HASH_SRC:
				if (s->req->prod->conn->addr.from.ss_family == AF_INET) {
					srv = get_server_sh(s->be,
							    (void *)&((struct sockaddr_in *)&s->req->prod->conn->addr.from)->sin_addr,
							    4);
				}
				else if (s->req->prod->conn->addr.from.ss_family == AF_INET6) {
					srv = get_server_sh(s->be,
							    (void *)&((struct sockaddr_in6 *)&s->req->prod->conn->addr.from)->sin6_addr,
							    16);
				}
				else {
					/* unknown IP family */
					err = SRV_STATUS_INTERNAL;
					goto out;
				}
				break;

			case BE_LB_HASH_URI:
				/* URI hashing */
				if (s->txn.req.msg_state < HTTP_MSG_BODY)
					break;
				srv = get_server_uh(s->be,
						    b_ptr(s->req->buf, (int)(s->txn.req.sl.rq.u - s->req->buf->o)),
						    s->txn.req.sl.rq.u_l);
				break;

			case BE_LB_HASH_PRM:
				/* URL Parameter hashing */
				if (s->txn.req.msg_state < HTTP_MSG_BODY)
					break;

				srv = get_server_ph(s->be,
						    b_ptr(s->req->buf, (int)(s->txn.req.sl.rq.u - s->req->buf->o)),
						    s->txn.req.sl.rq.u_l);

				if (!srv && s->txn.meth == HTTP_METH_POST)
					srv = get_server_ph_post(s);
				break;

			case BE_LB_HASH_HDR:
				/* Header Parameter hashing */
				if (s->txn.req.msg_state < HTTP_MSG_BODY)
					break;
				srv = get_server_hh(s);
				break;

			case BE_LB_HASH_RDP:
				/* RDP Cookie hashing */
				srv = get_server_rch(s);
				break;

			default:
				/* unknown balancing algorithm */
				err = SRV_STATUS_INTERNAL;
				goto out;
			}

			/* If the hashing parameter was not found, let's fall
			 * back to round robin on the map.
			 */
			if (!srv) {
				if (s->be->lbprm.algo & BE_LB_LKUP_CHTREE)
					srv = chash_get_next_server(s->be, prev_srv);
				else
					srv = map_get_server_rr(s->be, prev_srv);
			}

			/* end of map-based LB */
			break;

		default:
			/* unknown balancing algorithm */
			err = SRV_STATUS_INTERNAL;
			goto out;
		}

		if (!srv) {
			err = SRV_STATUS_FULL;
			goto out;
		}
		else if (srv != prev_srv) {
			s->be->be_counters.cum_lbconn++;
			srv->counters.cum_lbconn++;
		}
		s->target = &srv->obj_type;
	}
	else if (s->be->options & (PR_O_DISPATCH | PR_O_TRANSP)) {
		s->target = &s->be->obj_type;
	}
	else if ((s->be->options & PR_O_HTTP_PROXY) &&
		 is_addr(&s->req->cons->conn->addr.to)) {
		/* in proxy mode, we need a valid destination address */
		s->target = &s->be->obj_type;
	}
	else {
		err = SRV_STATUS_NOSRV;
		goto out;
	}

	s->flags |= SN_ASSIGNED;
	err = SRV_STATUS_OK;
 out:

	/* Either we take back our connection slot, or we offer it to someone
	 * else if we don't need it anymore.
	 */
	if (conn_slot) {
		if (conn_slot == srv) {
			sess_change_server(s, srv);
		} else {
			if (may_dequeue_tasks(conn_slot, s->be))
				process_srv_queue(conn_slot);
		}
	}

 out_err:
	return err;
}
/*
 * This function applies the load-balancing algorithm to the session, as
 * defined by the backend it is assigned to. The session is then marked as
 * 'assigned'.
 *
 * This function MAY NOT be called with SN_ASSIGNED already set. If the session
 * had a server previously assigned, it is rebalanced, trying to avoid the same
 * server, which should still be present in target_srv(&s->target) before the call.
 * The function tries to keep the original connection slot if it reconnects to
 * the same server, otherwise it releases it and tries to offer it.
 *
 * It is illegal to call this function with a session in a queue.
 *
 * It may return :
 *   SRV_STATUS_OK       if everything is OK. ->srv and ->target are assigned.
 *   SRV_STATUS_NOSRV    if no server is available. Session is not ASSIGNED
 *   SRV_STATUS_FULL     if all servers are saturated. Session is not ASSIGNED
 *   SRV_STATUS_INTERNAL for other unrecoverable errors.
 *
 * Upon successful return, the session flag SN_ASSIGNED is set to indicate that
 * it does not need to be called anymore. This means that target_srv(&s->target)
 * can be trusted in balance and direct modes.
 *
 */
This function applies the load-balancing algorithm to the session, as
defined by the backend it is assigned to. The session is then marked as
'assigned'.

This function MAY NOT be called with SN_ASSIGNED already set. If the session
had a server previously assigned, it is rebalanced, trying to avoid the same
server, which should still be present in target_srv(&s->target) before the call.
The function tries to keep the original connection slot if it reconnects to
the same server, otherwise it releases it and tries to offer it.

It is illegal to call this function with a session in a queue.

It may return :
SRV_STATUS_OK       if everything is OK. ->srv and ->target are assigned.
SRV_STATUS_NOSRV    if no server is available. Session is not ASSIGNED
SRV_STATUS_FULL     if all servers are saturated. Session is not ASSIGNED
SRV_STATUS_INTERNAL for other unrecoverable errors.

Upon successful return, the session flag SN_ASSIGNED is set to indicate that
it does not need to be called anymore. This means that target_srv(&s->target)
can be trusted in balance and direct modes.
This function applies the load - balancing algorithm to the session as defined by the backend it is assigned to . The session is then marked as ' assigned ' . This function MAY NOT be called with SN_ASSIGNED already set . If the session had a server previously assigned it is rebalanced trying to avoid the same server which should still be present in target_srv ( &s - > target ) before the call . The function tries to keep the original connection slot if it reconnects to the same server otherwise it releases it and tries to offer it . It is illegal to call this function with a session in a queue . It may return : SRV_STATUS_OK if everything is OK . - > srv and - > target are assigned . SRV_STATUS_NOSRV if no server is available . Session is not ASSIGNED SRV_STATUS_FULL if all servers are saturated . Session is not ASSIGNED SRV_STATUS_INTERNAL for other unrecoverable errors . Upon successful return the session flag SN_ASSIGNED is set to indicate that it does not need to be called anymore . This means that target_srv ( &s - > target ) can be trusted in balance and direct modes .
int assign_server(struct session *s)
{
	struct server *conn_slot;
	struct server *srv, *prev_srv;
	int err;
	DPRINTF(stderr,"assign_server : s=%p\n",s);
	err = SRV_STATUS_INTERNAL;
	if (unlikely(s->pend_pos || s->flags & SN_ASSIGNED))
		goto out_err;
	prev_srv  = objt_server(s->target);
	conn_slot = s->srv_conn;
	if (conn_slot)
		sess_change_server(s, NULL);
	srv = NULL;
	s->target = NULL;
	if (s->be->lbprm.algo & BE_LB_KIND) {
		if (!s->be->lbprm.tot_weight) {
			err = SRV_STATUS_NOSRV;
			goto out;
		}
		switch (s->be->lbprm.algo & BE_LB_LKUP) {
		case BE_LB_LKUP_RRTREE:
			srv = fwrr_get_next_server(s->be, prev_srv);
			break;
		case BE_LB_LKUP_FSTREE:
			srv = fas_get_next_server(s->be, prev_srv);
			break;
		case BE_LB_LKUP_LCTREE:
			srv = fwlc_get_next_server(s->be, prev_srv);
			break;
		case BE_LB_LKUP_CHTREE:
		case BE_LB_LKUP_MAP:
			if ((s->be->lbprm.algo & BE_LB_KIND) == BE_LB_KIND_RR) {
				if (s->be->lbprm.algo & BE_LB_LKUP_CHTREE)
					srv = chash_get_next_server(s->be, prev_srv);
				else
					srv = map_get_server_rr(s->be, prev_srv);
				break;
			}
			else if ((s->be->lbprm.algo & BE_LB_KIND) != BE_LB_KIND_HI) {
				err = SRV_STATUS_INTERNAL;
				goto out;
			}
			switch (s->be->lbprm.algo & BE_LB_PARM) {
			case BE_LB_HASH_SRC:
				if (s->req->prod->conn->addr.from.ss_family == AF_INET) {
					srv = get_server_sh(s->be,
							    (void *)&((struct sockaddr_in *)&s->req->prod->conn->addr.from)->sin_addr,
							    4);
				}
				else if (s->req->prod->conn->addr.from.ss_family == AF_INET6) {
					srv = get_server_sh(s->be,
							    (void *)&((struct sockaddr_in6 *)&s->req->prod->conn->addr.from)->sin6_addr,
							    16);
				}
				else {
					err = SRV_STATUS_INTERNAL;
					goto out;
				}
				break;
			case BE_LB_HASH_URI:
				if (s->txn.req.msg_state < HTTP_MSG_BODY)
					break;
				srv = get_server_uh(s->be,
						    b_ptr(s->req->buf, (int)(s->txn.req.sl.rq.u - s->req->buf->o)),
						    s->txn.req.sl.rq.u_l);
				break;
			case BE_LB_HASH_PRM:
				if (s->txn.req.msg_state < HTTP_MSG_BODY)
					break;
				srv = get_server_ph(s->be,
						    b_ptr(s->req->buf, (int)(s->txn.req.sl.rq.u - s->req->buf->o)),
						    s->txn.req.sl.rq.u_l);
				if (!srv && s->txn.meth == HTTP_METH_POST)
					srv = get_server_ph_post(s);
				break;
			case BE_LB_HASH_HDR:
				if (s->txn.req.msg_state < HTTP_MSG_BODY)
					break;
				srv = get_server_hh(s);
				break;
			case BE_LB_HASH_RDP:
				srv = get_server_rch(s);
				break;
			default:
				err = SRV_STATUS_INTERNAL;
				goto out;
			}
			if (!srv) {
				if (s->be->lbprm.algo & BE_LB_LKUP_CHTREE)
					srv = chash_get_next_server(s->be, prev_srv);
				else
					srv = map_get_server_rr(s->be, prev_srv);
			}
			break;
		default:
			err = SRV_STATUS_INTERNAL;
			goto out;
		}
		if (!srv) {
			err = SRV_STATUS_FULL;
			goto out;
		}
		else if (srv != prev_srv) {
			s->be->be_counters.cum_lbconn++;
			srv->counters.cum_lbconn++;
		}
		s->target = &srv->obj_type;
	}
	else if (s->be->options & (PR_O_DISPATCH | PR_O_TRANSP)) {
		s->target = &s->be->obj_type;
	}
	else if ((s->be->options & PR_O_HTTP_PROXY) &&
		 is_addr(&s->req->cons->conn->addr.to)) {
		s->target = &s->be->obj_type;
	}
	else {
		err = SRV_STATUS_NOSRV;
		goto out;
	}
	s->flags |= SN_ASSIGNED;
	err = SRV_STATUS_OK;
 out:
	if (conn_slot) {
		if (conn_slot == srv) {
			sess_change_server(s, srv);
		} else {
			if (may_dequeue_tasks(conn_slot, s->be))
				process_srv_queue(conn_slot);
		}
	}
 out_err:
	return err;
}
int assign_server ( struct session * s ) { struct server * conn_slot ; struct server * srv , * prev_srv ; int err ; DPRINTF ( stderr , " \n " , s ) ; err = SRV_STATUS_INTERNAL ; if ( unlikely ( s -> pend_pos || s -> flags & SN_ASSIGNED ) ) goto out_err ; prev_srv = objt_server ( s -> target ) ; conn_slot = s -> srv_conn ; if ( conn_slot ) sess_change_server ( s , NULL ) ; srv = NULL ; s -> target = NULL ; if ( s -> be -> lbprm . algo & BE_LB_KIND ) { if ( ! s -> be -> lbprm . tot_weight ) { err = SRV_STATUS_NOSRV ; goto out ; } switch ( s -> be -> lbprm . algo & BE_LB_LKUP ) { case BE_LB_LKUP_RRTREE : srv = fwrr_get_next_server ( s -> be , prev_srv ) ; break ; case BE_LB_LKUP_FSTREE : srv = fas_get_next_server ( s -> be , prev_srv ) ; break ; case BE_LB_LKUP_LCTREE : srv = fwlc_get_next_server ( s -> be , prev_srv ) ; break ; case BE_LB_LKUP_CHTREE : case BE_LB_LKUP_MAP : if ( ( s -> be -> lbprm . algo & BE_LB_KIND ) == BE_LB_KIND_RR ) { if ( s -> be -> lbprm . algo & BE_LB_LKUP_CHTREE ) srv = chash_get_next_server ( s -> be , prev_srv ) ; else srv = map_get_server_rr ( s -> be , prev_srv ) ; break ; } else if ( ( s -> be -> lbprm . algo & BE_LB_KIND ) != BE_LB_KIND_HI ) { err = SRV_STATUS_INTERNAL ; goto out ; } switch ( s -> be -> lbprm . algo & BE_LB_PARM ) { case BE_LB_HASH_SRC : if ( s -> req -> prod -> conn -> addr . from . ss_family == AF_INET ) { srv = get_server_sh ( s -> be , ( void * ) & ( ( struct sockaddr_in * ) & s -> req -> prod -> conn -> addr . from ) -> sin_addr , 4 ) ; } else if ( s -> req -> prod -> conn -> addr . from . ss_family == AF_INET6 ) { srv = get_server_sh ( s -> be , ( void * ) & ( ( struct sockaddr_in6 * ) & s -> req -> prod -> conn -> addr . from ) -> sin6_addr , 16 ) ; } else { err = SRV_STATUS_INTERNAL ; goto out ; } break ; case BE_LB_HASH_URI : if ( s -> txn . req . msg_state < HTTP_MSG_BODY ) break ; srv = get_server_uh ( s -> be , b_ptr ( s -> req -> buf , ( int ) ( s -> txn . req . sl . rq . u - s -> req -> buf -> o ) ) , s -> txn . req . sl . rq . u_l ) ; break ; case BE_LB_HASH_PRM : if ( s -> txn . req . msg_state < HTTP_MSG_BODY ) break ; srv = get_server_ph ( s -> be , b_ptr ( s -> req -> buf , ( int ) ( s -> txn . req . sl . rq . u - s -> req -> buf -> o ) ) , s -> txn . req . sl . rq . u_l ) ; if ( ! srv && s -> txn . meth == HTTP_METH_POST ) srv = get_server_ph_post ( s ) ; break ; case BE_LB_HASH_HDR : if ( s -> txn . req . msg_state < HTTP_MSG_BODY ) break ; srv = get_server_hh ( s ) ; break ; case BE_LB_HASH_RDP : srv = get_server_rch ( s ) ; break ; default : err = SRV_STATUS_INTERNAL ; goto out ; } if ( ! srv ) { if ( s -> be -> lbprm . algo & BE_LB_LKUP_CHTREE ) srv = chash_get_next_server ( s -> be , prev_srv ) ; else srv = map_get_server_rr ( s -> be , prev_srv ) ; } break ; default : err = SRV_STATUS_INTERNAL ; goto out ; } if ( ! srv ) { err = SRV_STATUS_FULL ; goto out ; } else if ( srv != prev_srv ) { s -> be -> be_counters . cum_lbconn ++ ; srv -> counters . cum_lbconn ++ ; } s -> target = & srv -> obj_type ; } else if ( s -> be -> options & ( PR_O_DISPATCH | PR_O_TRANSP ) ) { s -> target = & s -> be -> obj_type ; } else if ( ( s -> be -> options & PR_O_HTTP_PROXY ) && is_addr ( & s -> req -> cons -> conn -> addr . to ) ) { s -> target = & s -> be -> obj_type ; } else { err = SRV_STATUS_NOSRV ; goto out ; } s -> flags |= SN_ASSIGNED ; err = SRV_STATUS_OK ; out : if ( conn_slot ) { if ( conn_slot == srv ) { sess_change_server ( s , srv ) ; } else { if ( may_dequeue_tasks ( conn_slot , s -> be ) ) process_srv_queue ( conn_slot ) ; } } out_err : return err ; }
This function applies the load-balancing algorithm to the session, as
 defined by the backend it is assigned to.
This function applies the load - balancing algorithm to the session as defined by the backend it is assigned to .
/* We have to release any connection slot before applying any LB algo,
	 * otherwise we may erroneously end up with no available slot.
	 */ /* We will now try to find the good server and store it into <objt_server(s->target)>.
	 * Note that <objt_server(s->target)> may be NULL in case of dispatch or proxy mode,
	 * as well as if no server is available (check error code).
	 */ /* we must check if we have at least one server available */ /* First check whether we need to fetch some data or simply call
		 * the LB lookup function. Only the hashing functions will need
		 * some input data in fact, and will support multiple algorithms.
		 */ /* unknown balancing algorithm */ /* unknown IP family */ /* URI hashing */ /* URL Parameter hashing */ /* Header Parameter hashing */ /* RDP Cookie hashing */ /* unknown balancing algorithm */ /* If the hashing parameter was not found, let's fall
			 * back to round robin on the map.
			 */ /* end of map-based LB */ /* unknown balancing algorithm */ /* in proxy mode, we need a valid destination address */ /* Either we take back our connection slot, or we offer it to someone
	 * else if we don't need it anymore.
	 */