~ubuntu-branches/ubuntu/trusty/haproxy/trusty-backports

« back to all changes in this revision

Viewing changes to src/backend.c

  • Committer: Bazaar Package Importer
  • Author(s): Arnaud Cornet
  • Date: 2009-06-26 00:11:01 UTC
  • mfrom: (1.1.6 upstream) (2.1.4 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090626001101-qo261ke2mjh3d8cn
* New Upstream Version (Closes: #534583).
* Add contrib directory in docs

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
#include <common/config.h>
23
23
#include <common/debug.h>
24
24
#include <common/eb32tree.h>
 
25
#include <common/ticks.h>
25
26
#include <common/time.h>
26
27
 
27
 
#include <types/acl.h>
28
 
#include <types/buffers.h>
29
28
#include <types/global.h>
30
 
#include <types/polling.h>
31
 
#include <types/proxy.h>
32
 
#include <types/server.h>
33
 
#include <types/session.h>
34
29
 
35
30
#include <proto/acl.h>
36
31
#include <proto/backend.h>
41
36
#include <proto/proto_http.h>
42
37
#include <proto/proto_tcp.h>
43
38
#include <proto/queue.h>
 
39
#include <proto/server.h>
44
40
#include <proto/session.h>
45
41
#include <proto/stream_sock.h>
46
42
#include <proto/task.h>
1214
1210
 
1215
1211
        /* if the message is chunked, we skip the chunk size, but use the value as len */
1216
1212
        http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx);
1217
 
        if ( ctx.idx && strncasecmp(ctx.line+ctx.val,"chunked",ctx.vlen)==0) {
 
1213
        if (ctx.idx && ctx.vlen >= 7 && strncasecmp(ctx.line+ctx.val, "chunked", 7) == 0) {
1218
1214
                unsigned int chunk = 0;
1219
 
                while ( params < req->rlim && !HTTP_IS_CRLF(*params)) {
 
1215
                while ( params < (req->data+req->max_len) && !HTTP_IS_CRLF(*params)) {
1220
1216
                        char c = *params;
1221
1217
                        if (ishex(c)) {
1222
1218
                                unsigned int hex = toupper(c) - '0';
1283
1279
 
1284
1280
 
1285
1281
/*
 
1282
 * This function tries to find a running server for the proxy <px> following
 
1283
 * the Header parameter hash method. It looks for a specific parameter in the
 
1284
 * URL and hashes it to compute the server ID. This is useful to optimize
 
1285
 * performance by avoiding bounces between servers in contexts where sessions
 
1286
 * are shared but cookies are not usable. If the parameter is not found, NULL
 
1287
 * is returned. If any server is found, it will be returned. If no valid server
 
1288
 * is found, NULL is returned.
 
1289
 */
 
1290
struct server *get_server_hh(struct session *s)
 
1291
{
 
1292
        unsigned long    hash = 0;
 
1293
        struct http_txn *txn  = &s->txn;
 
1294
        struct http_msg *msg  = &txn->req;
 
1295
        struct proxy    *px   = s->be;
 
1296
        unsigned int     plen = px->hh_len;
 
1297
        unsigned long    len;
 
1298
        struct hdr_ctx   ctx;
 
1299
        const char      *p;
 
1300
 
 
1301
        /* tot_weight appears to mean srv_count */
 
1302
        if (px->lbprm.tot_weight == 0)
 
1303
                return NULL;
 
1304
 
 
1305
        if (px->lbprm.map.state & PR_MAP_RECALC)
 
1306
                recalc_server_map(px);
 
1307
 
 
1308
        ctx.idx = 0;
 
1309
 
 
1310
        /* if the message is chunked, we skip the chunk size, but use the value as len */
 
1311
        http_find_header2(px->hh_name, plen, msg->sol, &txn->hdr_idx, &ctx);
 
1312
 
 
1313
        /* if the header is not found or empty, let's fallback to round robin */
 
1314
        if (!ctx.idx || !ctx.vlen)
 
1315
                return NULL;
 
1316
 
 
1317
        /* Found a the hh_name in the headers.
 
1318
         * we will compute the hash based on this value ctx.val.
 
1319
         */
 
1320
        len = ctx.vlen;
 
1321
        p = (char *)ctx.line + ctx.val;
 
1322
        if (!px->hh_match_domain) {
 
1323
                while (len) {
 
1324
                        hash = *p + (hash << 6) + (hash << 16) - hash;
 
1325
                        len--;
 
1326
                        p++;
 
1327
                }
 
1328
        } else {
 
1329
                int dohash = 0;
 
1330
                p += len - 1;
 
1331
                /* special computation, use only main domain name, not tld/host
 
1332
                 * going back from the end of string, start hashing at first
 
1333
                 * dot stop at next.
 
1334
                 * This is designed to work with the 'Host' header, and requires
 
1335
                 * a special option to activate this.
 
1336
                 */
 
1337
                while (len) {
 
1338
                        if (*p == '.') {
 
1339
                                if (!dohash)
 
1340
                                        dohash = 1;
 
1341
                                else
 
1342
                                        break;
 
1343
                        } else {
 
1344
                                if (dohash)
 
1345
                                        hash = *p + (hash << 6) + (hash << 16) - hash;
 
1346
                        }
 
1347
                        len--;
 
1348
                        p--;
 
1349
                }
 
1350
        }
 
1351
        return px->lbprm.map.srv[hash % px->lbprm.tot_weight];
 
1352
}
 
1353
 
 
1354
 
 
1355
/*
1286
1356
 * This function applies the load-balancing algorithm to the session, as
1287
1357
 * defined by the backend it is assigned to. The session is then marked as
1288
1358
 * 'assigned'.
1400
1470
                                }
1401
1471
                        }
1402
1472
                        break;
 
1473
                case BE_LB_ALGO_HH:
 
1474
                        /* Header Parameter hashing */
 
1475
                        s->srv = get_server_hh(s);
 
1476
 
 
1477
                        if (!s->srv) {
 
1478
                                /* parameter not found, fall back to round robin on the map */
 
1479
                                s->srv = get_server_rr_with_conns(s->be, s->prev_srv);
 
1480
                                if (!s->srv) {
 
1481
                                        err = SRV_STATUS_FULL;
 
1482
                                        goto out;
 
1483
                                }
 
1484
                        }
 
1485
                        break;
1403
1486
                default:
1404
1487
                        /* unknown balancing algorithm */
1405
1488
                        err = SRV_STATUS_INTERNAL;
1417
1500
                }
1418
1501
        }
1419
1502
        else if (!*(int *)&s->be->dispatch_addr.sin_addr &&
1420
 
                 !(s->fe->options & PR_O_TRANSP)) {
 
1503
                 !(s->be->options & PR_O_TRANSP)) {
1421
1504
                err = SRV_STATUS_NOSRV;
1422
1505
                goto out;
1423
1506
        }
1472
1555
                /* if this server remaps proxied ports, we'll use
1473
1556
                 * the port the client connected to with an offset. */
1474
1557
                if (s->srv->state & SRV_MAPPORTS) {
1475
 
                        if (!(s->fe->options & PR_O_TRANSP) && !(s->flags & SN_FRT_ADDR_SET))
 
1558
                        if (!(s->be->options & PR_O_TRANSP) && !(s->flags & SN_FRT_ADDR_SET))
1476
1559
                                get_frt_addr(s);
1477
1560
                        if (s->frt_addr.ss_family == AF_INET) {
1478
1561
                                s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) +
1487
1570
                /* connect to the defined dispatch addr */
1488
1571
                s->srv_addr = s->be->dispatch_addr;
1489
1572
        }
1490
 
        else if (s->fe->options & PR_O_TRANSP) {
 
1573
        else if (s->be->options & PR_O_TRANSP) {
1491
1574
                /* in transparent mode, use the original dest addr if no dispatch specified */
1492
1575
                if (!(s->flags & SN_FRT_ADDR_SET))
1493
1576
                        get_frt_addr(s);
1651
1734
                        return SN_ERR_INTERNAL;
1652
1735
        }
1653
1736
 
1654
 
        if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
 
1737
        if ((fd = s->req->cons->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
1655
1738
                qfprintf(stderr, "Cannot get a server socket.\n");
1656
1739
 
1657
1740
                if (errno == ENFILE)
1669
1752
                /* this is a resource error */
1670
1753
                return SN_ERR_RESOURCE;
1671
1754
        }
1672
 
        
 
1755
 
1673
1756
        if (fd >= global.maxsock) {
1674
1757
                /* do not log anything there, it's a normal condition when this option
1675
1758
                 * is used to serialize connections to a server !
1680
1763
        }
1681
1764
 
1682
1765
#ifdef CONFIG_HAP_TCPSPLICE
1683
 
        if ((s->fe->options & s->be->options) & PR_O_TCPSPLICE) {
 
1766
        if ((global.tune.options & GTUNE_USE_SPLICE) &&
 
1767
            (s->fe->options & s->be->options) & PR_O_TCPSPLICE) {
1684
1768
                /* TCP splicing supported by both FE and BE */
1685
 
                tcp_splice_initfd(s->cli_fd, fd);
 
1769
                tcp_splice_initfd(s->req->prod->fd, fd);
1686
1770
        }
1687
1771
#endif
1688
1772
 
1723
1807
                        break;
1724
1808
                }
1725
1809
#endif
 
1810
#ifdef SO_BINDTODEVICE
 
1811
                /* Note: this might fail if not CAP_NET_RAW */
 
1812
                if (s->srv->iface_name)
 
1813
                        setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, s->srv->iface_name, s->srv->iface_len + 1);
 
1814
#endif
1726
1815
                ret = tcpv4_bind_socket(fd, flags, &s->srv->source_addr, remote);
1727
1816
                if (ret) {
1728
1817
                        close(fd);
1762
1851
                        break;
1763
1852
                }
1764
1853
#endif
 
1854
#ifdef SO_BINDTODEVICE
 
1855
                /* Note: this might fail if not CAP_NET_RAW */
 
1856
                if (s->be->iface_name)
 
1857
                        setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, s->be->iface_name, s->be->iface_len + 1);
 
1858
#endif
1765
1859
                ret = tcpv4_bind_socket(fd, flags, &s->be->source_addr, remote);
1766
1860
                if (ret) {
1767
1861
                        close(fd);
1810
1904
                }
1811
1905
        }
1812
1906
 
1813
 
        fdtab[fd].owner = s->task;
 
1907
        fdtab[fd].owner = s->req->cons;
1814
1908
        fdtab[fd].state = FD_STCONN; /* connection in progress */
1815
1909
        fdtab[fd].cb[DIR_RD].f = &stream_sock_read;
1816
1910
        fdtab[fd].cb[DIR_RD].b = s->rep;
1820
1914
        fdtab[fd].peeraddr = (struct sockaddr *)&s->srv_addr;
1821
1915
        fdtab[fd].peerlen = sizeof(s->srv_addr);
1822
1916
 
 
1917
        fd_insert(fd);
1823
1918
        EV_FD_SET(fd, DIR_WR);  /* for connect status */
1824
 
    
1825
 
        fd_insert(fd);
 
1919
 
 
1920
        s->req->cons->state = SI_ST_CON;
1826
1921
        if (s->srv) {
 
1922
                s->flags |= SN_CURR_SESS;
1827
1923
                s->srv->cur_sess++;
1828
1924
                if (s->srv->cur_sess > s->srv->cur_sess_max)
1829
1925
                        s->srv->cur_sess_max = s->srv->cur_sess;
1831
1927
                        s->be->lbprm.server_take_conn(s->srv);
1832
1928
        }
1833
1929
 
1834
 
        if (!tv_add_ifset(&s->req->cex, &now, &s->be->timeout.connect))
1835
 
                tv_eternity(&s->req->cex);
 
1930
        s->req->cons->exp = tick_add_ifset(now_ms, s->be->timeout.connect);
1836
1931
        return SN_ERR_NONE;  /* connection is OK */
1837
1932
}
1838
1933
 
1839
1934
 
1840
 
/*
1841
 
 * This function checks the retry count during the connect() job.
1842
 
 * It updates the session's srv_state and retries, so that the caller knows
1843
 
 * what it has to do. It uses the last connection error to set the log when
1844
 
 * it expires. It returns 1 when it has expired, and 0 otherwise.
1845
 
 */
1846
 
int srv_count_retry_down(struct session *t, int conn_err)
1847
 
{
1848
 
        /* we are in front of a retryable error */
1849
 
        t->conn_retries--;
1850
 
 
1851
 
        if (t->conn_retries < 0) {
1852
 
                /* if not retryable anymore, let's abort */
1853
 
                tv_eternity(&t->req->cex);
1854
 
                srv_close_with_err(t, conn_err, SN_FINST_C,
1855
 
                                   503, error_message(t, HTTP_ERR_503));
1856
 
                if (t->srv)
1857
 
                        t->srv->failed_conns++;
1858
 
                t->be->failed_conns++;
1859
 
 
1860
 
                /* We used to have a free connection slot. Since we'll never use it,
1861
 
                 * we have to inform the server that it may be used by another session.
1862
 
                 */
1863
 
                if (may_dequeue_tasks(t->srv, t->be))
1864
 
                        process_srv_queue(t->srv);
1865
 
                return 1;
1866
 
        }
1867
 
        return 0;
1868
 
}
1869
 
 
1870
 
    
1871
 
/*
1872
 
 * This function performs the retryable part of the connect() job.
1873
 
 * It updates the session's srv_state and retries, so that the caller knows
1874
 
 * what it has to do. It returns 1 when it breaks out of the loop, or 0 if
1875
 
 * it needs to redispatch.
1876
 
 */
1877
 
int srv_retryable_connect(struct session *t)
1878
 
{
1879
 
        int conn_err;
1880
 
 
1881
 
        /* This loop ensures that we stop before the last retry in case of a
1882
 
         * redispatchable server.
1883
 
         */
1884
 
        do {
1885
 
                /* initiate a connection to the server */
1886
 
                conn_err = connect_server(t);
1887
 
                switch (conn_err) {
1888
 
        
1889
 
                case SN_ERR_NONE:
1890
 
                        //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
1891
 
                        t->srv_state = SV_STCONN;
1892
 
                        if (t->srv)
1893
 
                                t->srv->cum_sess++;
1894
 
                        return 1;
1895
 
            
1896
 
                case SN_ERR_INTERNAL:
1897
 
                        tv_eternity(&t->req->cex);
1898
 
                        srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
1899
 
                                           500, error_message(t, HTTP_ERR_500));
1900
 
                        if (t->srv)
1901
 
                                t->srv->cum_sess++;
1902
 
                        if (t->srv)
1903
 
                                t->srv->failed_conns++;
1904
 
                        t->be->failed_conns++;
1905
 
                        /* release other sessions waiting for this server */
1906
 
                        if (may_dequeue_tasks(t->srv, t->be))
1907
 
                                process_srv_queue(t->srv);
1908
 
                        return 1;
1909
 
                }
1910
 
                /* ensure that we have enough retries left */
1911
 
                if (srv_count_retry_down(t, conn_err)) {
1912
 
                        return 1;
1913
 
                }
1914
 
        } while (t->srv == NULL || t->conn_retries > 0 || !(t->be->options & PR_O_REDISP));
1915
 
 
1916
 
        /* We're on our last chance, and the REDISP option was specified.
1917
 
         * We will ignore cookie and force to balance or use the dispatcher.
1918
 
         */
1919
 
        /* let's try to offer this slot to anybody */
1920
 
        if (may_dequeue_tasks(t->srv, t->be))
1921
 
                process_srv_queue(t->srv);
1922
 
 
1923
 
        if (t->srv)
1924
 
                t->srv->cum_sess++;             //FIXME?
1925
 
 
1926
 
        /* it's left to the dispatcher to choose a server */
1927
 
        t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
1928
 
        t->prev_srv = t->srv;
1929
 
        return 0;
1930
 
}
1931
 
 
1932
 
    
1933
1935
/* This function performs the "redispatch" part of a connection attempt. It
1934
1936
 * will assign a server if required, queue the connection if required, and
1935
1937
 * handle errors that might arise at this level. It can change the server
1965
1967
                        goto redispatch;
1966
1968
                }
1967
1969
 
1968
 
                tv_eternity(&t->req->cex);
1969
 
                srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
1970
 
                                   503, error_message(t, HTTP_ERR_503));
 
1970
                if (!t->req->cons->err_type) {
 
1971
                        t->req->cons->err_type = SI_ET_QUEUE_ERR;
 
1972
                        t->req->cons->err_loc = t->srv;
 
1973
                }
1971
1974
 
1972
1975
                t->srv->failed_conns++;
1973
1976
                t->be->failed_conns++;
1975
1978
 
1976
1979
        case SRV_STATUS_NOSRV:
1977
1980
                /* note: it is guaranteed that t->srv == NULL here */
1978
 
                tv_eternity(&t->req->cex);
1979
 
                srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_C,
1980
 
                                   503, error_message(t, HTTP_ERR_503));
 
1981
                if (!t->req->cons->err_type) {
 
1982
                        t->req->cons->err_type = SI_ET_CONN_ERR;
 
1983
                        t->req->cons->err_loc = NULL;
 
1984
                }
1981
1985
 
1982
1986
                t->be->failed_conns++;
1983
1987
                return 1;
1984
1988
 
1985
1989
        case SRV_STATUS_QUEUED:
1986
 
                if (!tv_add_ifset(&t->req->cex, &now, &t->be->timeout.queue))
1987
 
                        tv_eternity(&t->req->cex);
1988
 
                t->srv_state = SV_STIDLE;
 
1990
                t->req->cons->exp = tick_add_ifset(now_ms, t->be->timeout.queue);
 
1991
                t->req->cons->state = SI_ST_QUE;
1989
1992
                /* do nothing else and do not wake any other session up */
1990
1993
                return 1;
1991
1994
 
1992
1995
        case SRV_STATUS_INTERNAL:
1993
1996
        default:
1994
 
                tv_eternity(&t->req->cex);
1995
 
                srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
1996
 
                                   500, error_message(t, HTTP_ERR_500));
 
1997
                if (!t->req->cons->err_type) {
 
1998
                        t->req->cons->err_type = SI_ET_CONN_OTHER;
 
1999
                        t->req->cons->err_loc = t->srv;
 
2000
                }
 
2001
 
1997
2002
                if (t->srv)
1998
 
                        t->srv->cum_sess++;
 
2003
                        srv_inc_sess_ctr(t->srv);
1999
2004
                if (t->srv)
2000
2005
                        t->srv->failed_conns++;
2001
2006
                t->be->failed_conns++;
2047
2052
                curproxy->lbprm.algo |= BE_LB_ALGO_SH;
2048
2053
        }
2049
2054
        else if (!strcmp(args[0], "uri")) {
 
2055
                int arg = 1;
 
2056
 
2050
2057
                curproxy->lbprm.algo &= ~BE_LB_ALGO;
2051
2058
                curproxy->lbprm.algo |= BE_LB_ALGO_UH;
 
2059
 
 
2060
                while (*args[arg]) {
 
2061
                        if (!strcmp(args[arg], "len")) {
 
2062
                                if (!*args[arg+1] || (atoi(args[arg+1]) <= 0)) {
 
2063
                                        snprintf(err, errlen, "'balance uri len' expects a positive integer (got '%s').", args[arg+1]);
 
2064
                                        return -1;
 
2065
                                }
 
2066
                                curproxy->uri_len_limit = atoi(args[arg+1]);
 
2067
                                arg += 2;
 
2068
                        }
 
2069
                        else if (!strcmp(args[arg], "depth")) {
 
2070
                                if (!*args[arg+1] || (atoi(args[arg+1]) <= 0)) {
 
2071
                                        snprintf(err, errlen, "'balance uri depth' expects a positive integer (got '%s').", args[arg+1]);
 
2072
                                        return -1;
 
2073
                                }
 
2074
                                /* hint: we store the position of the ending '/' (depth+1) so
 
2075
                                 * that we avoid a comparison while computing the hash.
 
2076
                                 */
 
2077
                                curproxy->uri_dirs_depth1 = atoi(args[arg+1]) + 1;
 
2078
                                arg += 2;
 
2079
                        }
 
2080
                        else {
 
2081
                                snprintf(err, errlen, "'balance uri' only accepts parameters 'len' and 'depth' (got '%s').", args[arg]);
 
2082
                                return -1;
 
2083
                        }
 
2084
                }
2052
2085
        }
2053
2086
        else if (!strcmp(args[0], "url_param")) {
2054
2087
                if (!*args[1]) {
2057
2090
                }
2058
2091
                curproxy->lbprm.algo &= ~BE_LB_ALGO;
2059
2092
                curproxy->lbprm.algo |= BE_LB_ALGO_PH;
2060
 
                if (curproxy->url_param_name)
2061
 
                        free(curproxy->url_param_name);
 
2093
 
 
2094
                free(curproxy->url_param_name);
2062
2095
                curproxy->url_param_name = strdup(args[1]);
2063
 
                curproxy->url_param_len = strlen(args[1]);
2064
 
                if ( *args[2] ) {
 
2096
                curproxy->url_param_len  = strlen(args[1]);
 
2097
                if (*args[2]) {
2065
2098
                        if (strcmp(args[2], "check_post")) {
2066
2099
                                snprintf(err, errlen, "'balance url_param' only accepts check_post modifier.");
2067
2100
                                return -1;
2077
2110
                                curproxy->url_param_post_limit = 3; /* minimum example: S=3 or \r\nS=6& */
2078
2111
                }
2079
2112
        }
 
2113
        else if (!strncmp(args[0], "hdr(", 4)) {
 
2114
                const char *beg, *end;
 
2115
 
 
2116
                beg = args[0] + 4;
 
2117
                end = strchr(beg, ')');
 
2118
 
 
2119
                if (!end || end == beg) {
 
2120
                        snprintf(err, errlen, "'balance hdr(name)' requires an http header field name.");
 
2121
                        return -1;
 
2122
                }
 
2123
 
 
2124
                curproxy->lbprm.algo &= ~BE_LB_ALGO;
 
2125
                curproxy->lbprm.algo |= BE_LB_ALGO_HH;
 
2126
 
 
2127
                free(curproxy->hh_name);
 
2128
                curproxy->hh_len  = end - beg;
 
2129
                curproxy->hh_name = my_strndup(beg, end - beg);
 
2130
                curproxy->hh_match_domain = 0;
 
2131
 
 
2132
                if (*args[1]) {
 
2133
                        if (strcmp(args[1], "use_domain_only")) {
 
2134
                                snprintf(err, errlen, "'balance hdr(name)' only accepts 'use_domain_only' modifier.");
 
2135
                                return -1;
 
2136
                        }
 
2137
                        curproxy->hh_match_domain = 1;
 
2138
                }
 
2139
 
 
2140
        }
2080
2141
        else {
2081
 
                snprintf(err, errlen, "'balance' only supports 'roundrobin', 'leastconn', 'source', 'uri' and 'url_param' options.");
 
2142
                snprintf(err, errlen, "'balance' only supports 'roundrobin', 'leastconn', 'source', 'uri', 'url_param' and 'hdr(name)' options.");
2082
2143
                return -1;
2083
2144
        }
2084
2145
        return 0;
2114
2175
        return 1;
2115
2176
}
2116
2177
 
 
2178
/* set test->i to the number of enabled servers on the proxy */
 
2179
static int
 
2180
acl_fetch_connslots(struct proxy *px, struct session *l4, void *l7, int dir,
 
2181
                    struct acl_expr *expr, struct acl_test *test)
 
2182
{
 
2183
        struct server *iterator;
 
2184
        test->flags = ACL_TEST_F_VOL_TEST;
 
2185
        if (expr->arg_len) {
 
2186
                /* another proxy was designated, we must look for it */
 
2187
                for (px = proxy; px; px = px->next)
 
2188
                        if ((px->cap & PR_CAP_BE) && !strcmp(px->id, expr->arg.str))
 
2189
                                break;
 
2190
        }
 
2191
        if (!px)
 
2192
                return 0;
 
2193
 
 
2194
        test->i = 0;
 
2195
        iterator = px->srv;
 
2196
        while (iterator) {
 
2197
                if ((iterator->state & 1) == 0) {
 
2198
                        iterator = iterator->next;
 
2199
                        continue;
 
2200
                }
 
2201
                if (iterator->maxconn == 0 || iterator->maxqueue == 0) {
 
2202
                        test->i = -1;
 
2203
                        return 1;
 
2204
                }
 
2205
 
 
2206
                test->i += (iterator->maxconn - iterator->cur_sess)
 
2207
                        +  (iterator->maxqueue - iterator->nbpend);
 
2208
                iterator = iterator->next;
 
2209
        }
 
2210
 
 
2211
        return 1;
 
2212
}
 
2213
 
 
2214
/* set test->i to the number of connections per second reaching the frontend */
 
2215
static int
 
2216
acl_fetch_fe_sess_rate(struct proxy *px, struct session *l4, void *l7, int dir,
 
2217
                       struct acl_expr *expr, struct acl_test *test)
 
2218
{
 
2219
        test->flags = ACL_TEST_F_VOL_TEST;
 
2220
        if (expr->arg_len) {
 
2221
                /* another proxy was designated, we must look for it */
 
2222
                for (px = proxy; px; px = px->next)
 
2223
                        if ((px->cap & PR_CAP_FE) && !strcmp(px->id, expr->arg.str))
 
2224
                                break;
 
2225
        }
 
2226
        if (!px)
 
2227
                return 0;
 
2228
 
 
2229
        test->i = read_freq_ctr(&px->fe_sess_per_sec);
 
2230
        return 1;
 
2231
}
 
2232
 
 
2233
/* set test->i to the number of connections per second reaching the backend */
 
2234
static int
 
2235
acl_fetch_be_sess_rate(struct proxy *px, struct session *l4, void *l7, int dir,
 
2236
                       struct acl_expr *expr, struct acl_test *test)
 
2237
{
 
2238
        test->flags = ACL_TEST_F_VOL_TEST;
 
2239
        if (expr->arg_len) {
 
2240
                /* another proxy was designated, we must look for it */
 
2241
                for (px = proxy; px; px = px->next)
 
2242
                        if ((px->cap & PR_CAP_BE) && !strcmp(px->id, expr->arg.str))
 
2243
                                break;
 
2244
        }
 
2245
        if (!px)
 
2246
                return 0;
 
2247
 
 
2248
        test->i = read_freq_ctr(&px->be_sess_per_sec);
 
2249
        return 1;
 
2250
}
 
2251
 
2117
2252
 
2118
2253
/* Note: must not be declared <const> as its list will be overwritten */
2119
2254
static struct acl_kw_list acl_kws = {{ },{
2120
 
        { "nbsrv",   acl_parse_int,   acl_fetch_nbsrv,    acl_match_int },
 
2255
        { "nbsrv",    acl_parse_int,   acl_fetch_nbsrv,     acl_match_int, ACL_USE_NOTHING },
 
2256
        { "connslots", acl_parse_int,   acl_fetch_connslots, acl_match_int, ACL_USE_NOTHING },
 
2257
        { "fe_sess_rate", acl_parse_int, acl_fetch_fe_sess_rate, acl_match_int, ACL_USE_NOTHING },
 
2258
        { "be_sess_rate", acl_parse_int, acl_fetch_be_sess_rate, acl_match_int, ACL_USE_NOTHING },
2121
2259
        { NULL, NULL, NULL, NULL },
2122
2260
}};
2123
2261