~ubuntu-branches/ubuntu/precise/haproxy/precise-proposed

« back to all changes in this revision

Viewing changes to src/checks.c

  • Committer: Bazaar Package Importer
  • Author(s): Christo Buschek
  • Date: 2011-03-11 12:41:59 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20110311124159-9foyp4juf1ilqipo
Tags: 1.4.13-1
* New maintainer upload (Closes: #615246)
* New upstream release
* Standards-version goes 3.9.1 (no change)
* Added patch bashism (Closes: #581109)
* Added a README.source file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
47
47
#include <proto/server.h>
48
48
#include <proto/task.h>
49
49
 
 
50
static int httpchk_expect(struct server *s, int done);
 
51
 
50
52
const struct check_status check_statuses[HCHK_STATUS_SIZE] = {
51
53
        [HCHK_STATUS_UNKNOWN]   = { SRV_CHK_UNKNOWN,                   "UNK",     "Unknown" },
52
54
        [HCHK_STATUS_INI]       = { SRV_CHK_UNKNOWN,                   "INI",     "Initializing" },
170
172
                        chunk_printf(msg, ", check duration: %ldms", s->check_duration);
171
173
        }
172
174
 
173
 
        if (xferred > 0) {
 
175
        if (xferred >= 0) {
174
176
                if (!(s->state & SRV_RUNNING))
175
177
                        chunk_printf(msg, ". %d active and %d backup servers left.%s"
176
178
                                " %d sessions active, %d requeued, %d remaining in queue",
371
373
 
372
374
        if (s->health == s->rise || s->tracked) {
373
375
                int srv_was_paused = s->state & SRV_GOINGDOWN;
 
376
                int prev_srv_count = s->proxy->srv_bck + s->proxy->srv_act;
374
377
 
375
378
                s->last_change = now.tv_sec;
376
379
                s->state &= ~(SRV_RUNNING | SRV_GOINGDOWN);
405
408
                else
406
409
                        send_log(s->proxy, LOG_ALERT, "%s.\n", trash);
407
410
 
408
 
                if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0)
 
411
                if (prev_srv_count && s->proxy->srv_bck == 0 && s->proxy->srv_act == 0)
409
412
                        set_backend_down(s->proxy);
410
413
 
411
414
                s->counters.down_trans++;
743
746
                if ((s->proxy->options & PR_O_HTTP_CHK) ||
744
747
                    (s->proxy->options & PR_O_SMTP_CHK) ||
745
748
                    (s->proxy->options2 & PR_O2_SSL3_CHK) ||
746
 
                    (s->proxy->options2 & PR_O2_MYSQL_CHK)) {
 
749
                    (s->proxy->options2 & PR_O2_MYSQL_CHK) ||
 
750
                    (s->proxy->options2 & PR_O2_LDAP_CHK)) {
747
751
                        int ret;
748
752
                        const char *check_req = s->proxy->check_req;
749
753
                        int check_len = s->proxy->check_len;
844
848
 
845
849
/*
846
850
 * This function is used only for server health-checks. It handles the server's
847
 
 * reply to an HTTP request or SSL HELLO. It calls set_server_check_status() to
848
 
 * update s->check_status, s->check_duration and s->result.
 
851
 * reply to an HTTP request, SSL HELLO or MySQL client Auth. It calls
 
852
 * set_server_check_status() to update s->check_status, s->check_duration
 
853
 * and s->result.
849
854
 
850
855
 * The set_server_check_status function is called with HCHK_STATUS_L7OKD if
851
856
 * an HTTP server replies HTTP 2xx or 3xx (valid responses), if an SMTP server
866
871
        struct server *s = t->context;
867
872
        char *desc;
868
873
        int done;
 
874
        unsigned short msglen;
869
875
 
870
876
        if (unlikely((s->result & SRV_CHK_ERROR) || (fdtab[fd].state == FD_STERROR))) {
871
877
                /* in case of TCP only, this tells us if the connection failed */
886
892
         */
887
893
 
888
894
        done = 0;
889
 
        for (len = 0; s->check_data_len < BUFSIZE; s->check_data_len += len) {
890
 
                len = recv(fd, s->check_data + s->check_data_len, BUFSIZE - s->check_data_len, 0);
 
895
        for (len = 0; s->check_data_len < global.tune.chksize; s->check_data_len += len) {
 
896
                len = recv(fd, s->check_data + s->check_data_len, global.tune.chksize - s->check_data_len, 0);
891
897
                if (len <= 0)
892
898
                        break;
893
899
        }
911
917
        /* Intermediate or complete response received.
912
918
         * Terminate string in check_data buffer.
913
919
         */
914
 
        if (s->check_data_len < BUFSIZE)
 
920
        if (s->check_data_len < global.tune.chksize)
915
921
                s->check_data[s->check_data_len] = '\0';
916
922
        else {
917
923
                s->check_data[s->check_data_len - 1] = '\0';
936
942
                }
937
943
 
938
944
                s->check_code = str2uic(s->check_data + 9);
939
 
 
940
945
                desc = ltrim(s->check_data + 12, ' ');
941
946
                
942
 
                /* check the reply : HTTP/1.X 2xx and 3xx are OK */
943
 
                if (*(s->check_data + 9) == '2' || *(s->check_data + 9) == '3') {
944
 
                        cut_crlf(desc);
945
 
                        set_server_check_status(s, HCHK_STATUS_L7OKD, desc);
946
 
                }
947
 
                else if ((s->proxy->options & PR_O_DISABLE404) &&
948
 
                         (s->state & SRV_RUNNING) &&
949
 
                         (s->check_code == 404)) {
 
947
                if ((s->proxy->options & PR_O_DISABLE404) &&
 
948
                         (s->state & SRV_RUNNING) && (s->check_code == 404)) {
950
949
                        /* 404 may be accepted as "stopping" only if the server was up */
951
950
                        cut_crlf(desc);
952
951
                        set_server_check_status(s, HCHK_STATUS_L7OKCD, desc);
953
952
                }
 
953
                else if (s->proxy->options2 & PR_O2_EXP_TYPE) {
 
954
                        /* Run content verification check... We know we have at least 13 chars */
 
955
                        if (!httpchk_expect(s, done))
 
956
                                goto wait_more_data;
 
957
                }
 
958
                /* check the reply : HTTP/1.X 2xx and 3xx are OK */
 
959
                else if (*(s->check_data + 9) == '2' || *(s->check_data + 9) == '3') {
 
960
                        cut_crlf(desc);
 
961
                        set_server_check_status(s, HCHK_STATUS_L7OKD, desc);
 
962
                }
954
963
                else {
955
964
                        cut_crlf(desc);
956
965
                        set_server_check_status(s, HCHK_STATUS_L7STS, desc);
993
1002
                        set_server_check_status(s, HCHK_STATUS_L7STS, desc);
994
1003
        }
995
1004
        else if (s->proxy->options2 & PR_O2_MYSQL_CHK) {
996
 
                /* MySQL Error packet always begin with field_count = 0xff
997
 
                 * contrary to OK Packet who always begin whith 0x00 */
998
1005
                if (!done && s->check_data_len < 5)
999
1006
                        goto wait_more_data;
1000
1007
 
1001
 
                if (*(s->check_data + 4) != '\xff') {
1002
 
                        /* We set the MySQL Version in description for information purpose
1003
 
                         * FIXME : it can be cool to use MySQL Version for other purpose,
1004
 
                         * like mark as down old MySQL server.
1005
 
                         */
1006
 
                        if (s->check_data_len > 51) {
1007
 
                                desc = ltrim(s->check_data + 5, ' ');
1008
 
                                set_server_check_status(s, HCHK_STATUS_L7OKD, desc);
 
1008
                if (s->proxy->check_len == 0) { // old mode
 
1009
                        if (*(s->check_data + 4) != '\xff') {
 
1010
                                /* We set the MySQL Version in description for information purpose
 
1011
                                 * FIXME : it can be cool to use MySQL Version for other purpose,
 
1012
                                 * like mark as down old MySQL server.
 
1013
                                 */
 
1014
                                if (s->check_data_len > 51) {
 
1015
                                        desc = ltrim(s->check_data + 5, ' ');
 
1016
                                        set_server_check_status(s, HCHK_STATUS_L7OKD, desc);
 
1017
                                }
 
1018
                                else {
 
1019
                                        if (!done)
 
1020
                                                goto wait_more_data;
 
1021
                                        /* it seems we have a OK packet but without a valid length,
 
1022
                                         * it must be a protocol error
 
1023
                                         */
 
1024
                                        set_server_check_status(s, HCHK_STATUS_L7RSP, s->check_data);
 
1025
                                }
 
1026
                        }
 
1027
                        else {
 
1028
                                /* An error message is attached in the Error packet */
 
1029
                                desc = ltrim(s->check_data + 7, ' ');
 
1030
                                set_server_check_status(s, HCHK_STATUS_L7STS, desc);
 
1031
                        }
 
1032
                } else {
 
1033
                        unsigned int first_packet_len = ((unsigned int) *s->check_data) +
 
1034
                                                        (((unsigned int) *(s->check_data + 1)) << 8) +
 
1035
                                                        (((unsigned int) *(s->check_data + 2)) << 16);
 
1036
 
 
1037
                        if (s->check_data_len == first_packet_len + 4) {
 
1038
                                /* MySQL Error packet always begin with field_count = 0xff */
 
1039
                                if (*(s->check_data + 4) != '\xff') {
 
1040
                                        /* We have only one MySQL packet and it is a Handshake Initialization packet
 
1041
                                        * but we need to have a second packet to know if it is alright
 
1042
                                        */
 
1043
                                        if (!done && s->check_data_len < first_packet_len + 5)
 
1044
                                                goto wait_more_data;
 
1045
                                }
 
1046
                                else {
 
1047
                                        /* We have only one packet and it is an Error packet,
 
1048
                                        * an error message is attached, so we can display it
 
1049
                                        */
 
1050
                                        desc = &s->check_data[7];
 
1051
                                        //Warning("onlyoneERR: %s\n", desc);
 
1052
                                        set_server_check_status(s, HCHK_STATUS_L7STS, desc);
 
1053
                                }
 
1054
                        } else if (s->check_data_len > first_packet_len + 4) {
 
1055
                                unsigned int second_packet_len = ((unsigned int) *(s->check_data + first_packet_len + 4)) +
 
1056
                                                                 (((unsigned int) *(s->check_data + first_packet_len + 5)) << 8) +
 
1057
                                                                 (((unsigned int) *(s->check_data + first_packet_len + 6)) << 16);
 
1058
 
 
1059
                                if (s->check_data_len == first_packet_len + 4 + second_packet_len + 4 ) {
 
1060
                                        /* We have 2 packets and that's good */
 
1061
                                        /* Check if the second packet is a MySQL Error packet or not */
 
1062
                                        if (*(s->check_data + first_packet_len + 8) != '\xff') {
 
1063
                                                /* No error packet */
 
1064
                                                /* We set the MySQL Version in description for information purpose */
 
1065
                                                desc = &s->check_data[5];
 
1066
                                                //Warning("2packetOK: %s\n", desc);
 
1067
                                                set_server_check_status(s, HCHK_STATUS_L7OKD, desc);
 
1068
                                        }
 
1069
                                        else {
 
1070
                                                /* An error message is attached in the Error packet
 
1071
                                                * so we can display it ! :)
 
1072
                                                */
 
1073
                                                desc = &s->check_data[first_packet_len+11];
 
1074
                                                //Warning("2packetERR: %s\n", desc);
 
1075
                                                set_server_check_status(s, HCHK_STATUS_L7STS, desc);
 
1076
                                        }
 
1077
                                }
1009
1078
                        }
1010
1079
                        else {
1011
1080
                                if (!done)
1012
1081
                                        goto wait_more_data;
1013
 
                                /* it seems we have a OK packet but without a valid length,
 
1082
                                /* it seems we have a Handshake Initialization packet but without a valid length,
1014
1083
                                 * it must be a protocol error
1015
1084
                                 */
1016
 
                                set_server_check_status(s, HCHK_STATUS_L7RSP, s->check_data);
 
1085
                                desc = &s->check_data[5];
 
1086
                                //Warning("protoerr: %s\n", desc);
 
1087
                                set_server_check_status(s, HCHK_STATUS_L7RSP, desc);
1017
1088
                        }
1018
1089
                }
 
1090
        }
 
1091
        else if (s->proxy->options2 & PR_O2_LDAP_CHK) {
 
1092
                if (!done && s->check_data_len < 14)
 
1093
                        goto wait_more_data;
 
1094
 
 
1095
                /* Check if the server speaks LDAP (ASN.1/BER)
 
1096
                 * http://en.wikipedia.org/wiki/Basic_Encoding_Rules
 
1097
                 * http://tools.ietf.org/html/rfc4511
 
1098
                 */
 
1099
 
 
1100
                /* http://tools.ietf.org/html/rfc4511#section-4.1.1
 
1101
                 *   LDAPMessage: 0x30: SEQUENCE
 
1102
                 */
 
1103
                if ((s->check_data_len < 14) || (*(s->check_data) != '\x30')) {
 
1104
                        set_server_check_status(s, HCHK_STATUS_L7RSP, "Not LDAPv3 protocol");
 
1105
                }
1019
1106
                else {
1020
 
                        /* An error message is attached in the Error packet,
1021
 
                         * so we can display it ! :)
1022
 
                         */
1023
 
                        desc = ltrim(s->check_data + 7, ' ');
1024
 
                        set_server_check_status(s, HCHK_STATUS_L7STS, desc);
 
1107
                         /* size of LDAPMessage */
 
1108
                        msglen = (*(s->check_data + 1) & 0x80) ? (*(s->check_data + 1) & 0x7f) : 0;
 
1109
 
 
1110
                        /* http://tools.ietf.org/html/rfc4511#section-4.2.2
 
1111
                         *   messageID: 0x02 0x01 0x01: INTEGER 1
 
1112
                         *   protocolOp: 0x61: bindResponse
 
1113
                         */
 
1114
                        if ((msglen > 2) ||
 
1115
                            (memcmp(s->check_data + 2 + msglen, "\x02\x01\x01\x61", 4) != 0)) {
 
1116
                                set_server_check_status(s, HCHK_STATUS_L7RSP, "Not LDAPv3 protocol");
 
1117
 
 
1118
                                goto out_wakeup;
 
1119
                        }
 
1120
 
 
1121
                        /* size of bindResponse */
 
1122
                        msglen += (*(s->check_data + msglen + 6) & 0x80) ? (*(s->check_data + msglen + 6) & 0x7f) : 0;
 
1123
 
 
1124
                        /* http://tools.ietf.org/html/rfc4511#section-4.1.9
 
1125
                         *   ldapResult: 0x0a 0x01: ENUMERATION
 
1126
                         */
 
1127
                        if ((msglen > 4) ||
 
1128
                            (memcmp(s->check_data + 7 + msglen, "\x0a\x01", 2) != 0)) {
 
1129
                                set_server_check_status(s, HCHK_STATUS_L7RSP, "Not LDAPv3 protocol");
 
1130
 
 
1131
                                goto out_wakeup;
 
1132
                        }
 
1133
 
 
1134
                        /* http://tools.ietf.org/html/rfc4511#section-4.1.9
 
1135
                         *   resultCode
 
1136
                         */
 
1137
                        s->check_code = *(s->check_data + msglen + 9);
 
1138
                        if (s->check_code) {
 
1139
                                set_server_check_status(s, HCHK_STATUS_L7STS, "See RFC: http://tools.ietf.org/html/rfc4511#section-4.1.9");
 
1140
                        } else {
 
1141
                                set_server_check_status(s, HCHK_STATUS_L7OKD, "Success");
 
1142
                        }
1025
1143
                }
1026
1144
        }
1027
1145
        else {
1462
1580
}
1463
1581
 
1464
1582
/*
 
1583
 * Perform content verification check on data in s->check_data buffer.
 
1584
 * The buffer MUST be terminated by a null byte before calling this function.
 
1585
 * Sets server status appropriately. The caller is responsible for ensuring
 
1586
 * that the buffer contains at least 13 characters. If <done> is zero, we may
 
1587
 * return 0 to indicate that data is required to decide of a match.
 
1588
 */
 
1589
static int httpchk_expect(struct server *s, int done)
 
1590
{
 
1591
        static char status_msg[] = "HTTP status check returned code <000>";
 
1592
        char status_code[] = "000";
 
1593
        char *contentptr;
 
1594
        int crlf;
 
1595
        int ret;
 
1596
 
 
1597
        switch (s->proxy->options2 & PR_O2_EXP_TYPE) {
 
1598
        case PR_O2_EXP_STS:
 
1599
        case PR_O2_EXP_RSTS:
 
1600
                memcpy(status_code, s->check_data + 9, 3);
 
1601
                memcpy(status_msg + strlen(status_msg) - 4, s->check_data + 9, 3);
 
1602
 
 
1603
                if ((s->proxy->options2 & PR_O2_EXP_TYPE) == PR_O2_EXP_STS)
 
1604
                        ret = strncmp(s->proxy->expect_str, status_code, 3) == 0;
 
1605
                else
 
1606
                        ret = regexec(s->proxy->expect_regex, status_code, MAX_MATCH, pmatch, 0) == 0;
 
1607
 
 
1608
                /* we necessarily have the response, so there are no partial failures */
 
1609
                if (s->proxy->options2 & PR_O2_EXP_INV)
 
1610
                        ret = !ret;
 
1611
 
 
1612
                set_server_check_status(s, ret ? HCHK_STATUS_L7OKD : HCHK_STATUS_L7STS, status_msg);
 
1613
                break;
 
1614
 
 
1615
        case PR_O2_EXP_STR:
 
1616
        case PR_O2_EXP_RSTR:
 
1617
                /* very simple response parser: ignore CR and only count consecutive LFs,
 
1618
                 * stop with contentptr pointing to first char after the double CRLF or
 
1619
                 * to '\0' if crlf < 2.
 
1620
                 */
 
1621
                crlf = 0;
 
1622
                for (contentptr = s->check_data; *contentptr; contentptr++) {
 
1623
                        if (crlf >= 2)
 
1624
                                break;
 
1625
                        if (*contentptr == '\r')
 
1626
                                continue;
 
1627
                        else if (*contentptr == '\n')
 
1628
                                crlf++;
 
1629
                        else
 
1630
                                crlf = 0;
 
1631
                }
 
1632
 
 
1633
                /* Check that response contains a body... */
 
1634
                if (crlf < 2) {
 
1635
                        if (!done)
 
1636
                                return 0;
 
1637
 
 
1638
                        set_server_check_status(s, HCHK_STATUS_L7RSP,
 
1639
                                                "HTTP content check could not find a response body");
 
1640
                        return 1;
 
1641
                }
 
1642
 
 
1643
                /* Check that response body is not empty... */
 
1644
                if (*contentptr == '\0') {
 
1645
                        set_server_check_status(s, HCHK_STATUS_L7RSP,
 
1646
                                                "HTTP content check found empty response body");
 
1647
                        return 1;
 
1648
                }
 
1649
 
 
1650
                /* Check the response content against the supplied string
 
1651
                 * or regex... */
 
1652
                if ((s->proxy->options2 & PR_O2_EXP_TYPE) == PR_O2_EXP_STR)
 
1653
                        ret = strstr(contentptr, s->proxy->expect_str) != NULL;
 
1654
                else
 
1655
                        ret = regexec(s->proxy->expect_regex, contentptr, MAX_MATCH, pmatch, 0) == 0;
 
1656
 
 
1657
                /* if we don't match, we may need to wait more */
 
1658
                if (!ret && !done)
 
1659
                        return 0;
 
1660
 
 
1661
                if (ret) {
 
1662
                        /* content matched */
 
1663
                        if (s->proxy->options2 & PR_O2_EXP_INV)
 
1664
                                set_server_check_status(s, HCHK_STATUS_L7RSP,
 
1665
                                                        "HTTP check matched unwanted content");
 
1666
                        else
 
1667
                                set_server_check_status(s, HCHK_STATUS_L7OKD,
 
1668
                                                        "HTTP content check matched");
 
1669
                }
 
1670
                else {
 
1671
                        if (s->proxy->options2 & PR_O2_EXP_INV)
 
1672
                                set_server_check_status(s, HCHK_STATUS_L7OKD,
 
1673
                                                        "HTTP check did not match unwanted content");
 
1674
                        else
 
1675
                                set_server_check_status(s, HCHK_STATUS_L7RSP,
 
1676
                                                        "HTTP content check did not match");
 
1677
                }
 
1678
                break;
 
1679
        }
 
1680
        return 1;
 
1681
}
 
1682
 
 
1683
/*
1465
1684
 * Local variables:
1466
1685
 *  c-indent-level: 8
1467
1686
 *  c-basic-offset: 8