"Fossies" - the Fresh Open Source Software Archive

Member "Pound-3.0.2/src/backend.c" (28 Nov 2021, 22578 Bytes) of package /linux/www/Pound-3.0.2.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "backend.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.0.1_vs_3.0.2.

    1 /*
    2  * Pound - the reverse-proxy load-balancer
    3  * Copyright (C) 2002-2020 Apsis GmbH
    4  *
    5  * This file is part of Pound.
    6  *
    7  * Pound is free software; you can redistribute it and/or modify
    8  * it under the terms of the GNU General Public License as published by
    9  * the Free Software Foundation; either version 3 of the License, or
   10  * (at your option) any later version.
   11  *
   12  * Pound is distributed in the hope that it will be useful,
   13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15  * GNU General Public License for more details.
   16  *
   17  * You should have received a copy of the GNU General Public License
   18  * along with this program.  If not, see <http://www.gnu.org/licenses/> .
   19  *
   20  * Contact information:
   21  * Apsis GmbH
   22  * P.O.Box
   23  * 8707 Uetikon am See
   24  * Switzerland
   25  * EMail: roseg@apsis.ch
   26  */
   27 
   28 #include    "pound.h"
   29 
   30 #define EOF_LISTENER(S) {\
   31     char    *m;\
   32     int     f;\
   33 \
   34     nn_send((S), "", 0, 0);\
   35     f = 100;\
   36     nn_setsockopt(S, NN_SOL_SOCKET, NN_RCVTIMEO, &f, sizeof(f));\
   37     if(nn_recv((S), &m, NN_MSG, 0) >= 0)\
   38         nn_freemsg(m);\
   39     nn_close(S);\
   40 }
   41 
   42 static int
   43 backend_1(BACKEND *be, int s_listener, FILE *f_be, char *client_addr)
   44 {
   45     char    buf[MAXBUF + 1], request[MAXBUF + 1], *msg;
   46     int     no_content, is_chunked, reply_code, n;
   47     long    content_length, total;
   48     regmatch_t  match[2];
   49 
   50     logmsg(1, "%lX start backend_1 %s:%d", pthread_self(), __FILE__, __LINE__);
   51     no_content = is_chunked = 0;
   52     content_length = total = 0L;
   53     /* receive the request from the listener and keep it for logging */
   54     if(nn_recv(s_listener, &msg, NN_MSG, 0) <= 0) {
   55         logmsg(2, "%lX can't get request %s:%d", pthread_self(), __FILE__, __LINE__);
   56         EOF_LISTENER(s_listener);
   57         return -1;
   58     }
   59     strcpy(request, msg);
   60     nn_freemsg(msg);
   61     no_content = !strncasecmp("HEAD", request, 4);
   62     fputs(request, f_be);
   63     for(n = 0; n < MAXBUF && request[n]; n++)
   64         if(request[n] == '\r' || request[n] == '\n') {
   65             request[n] = '\0';
   66             break;
   67         }
   68     logmsg(4, "%lX request:%s %s:%d", pthread_self(), request, __FILE__, __LINE__);
   69 
   70     /* receive the other headers from the listener and pass them to the back-end */
   71     while(nn_recv(s_listener, &msg, NN_MSG, 0) > 0) {
   72         logmsg(4, "%lX header:%s %s:%d", pthread_self(), msg, __FILE__, __LINE__);
   73         fputs(msg, f_be);
   74         nn_freemsg(msg);
   75     }
   76     nn_freemsg(msg);
   77     logmsg(2, "%lX end request %s:%d", pthread_self(), __FILE__, __LINE__);
   78 
   79     fflush(f_be);
   80 
   81     total = 0L;
   82     if(fgets(buf, MAXBUF - 1, f_be) == NULL) {
   83         logmsg(2, "%lX no reply from backend %s:%d", pthread_self(), __FILE__, __LINE__);
   84         close(fileno(f_be));
   85         fclose(f_be);
   86         EOF_LISTENER(s_listener);
   87         return -1;
   88     }
   89     nn_send(s_listener, buf, strlen(buf), 0);
   90     logmsg(4, "%lX reply %s %s:%d", pthread_self(), buf, __FILE__, __LINE__);
   91 
   92     for(;;) {
   93         if(regexec(&rex_Response, buf, 2, match, REG_ICASE))
   94             continue;
   95         sscanf(buf + match[1].rm_so, "%d", &reply_code);
   96         if(reply_code >= 200)
   97             break;
   98         /* a 1xx reply - pass and skip */
   99         while(fgets(buf, MAXBUF - 1, f_be) != NULL) {
  100             logmsg(4, "%lX 100 pass through %s:%d", pthread_self(), buf, __FILE__, __LINE__);
  101             nn_send(s_listener, buf, strlen(buf), 0);
  102             if(buf[0] == '\r' || buf[0] == '\n')
  103                 break;
  104         }
  105         if(fgets(buf, MAXBUF, f_be) == NULL) {
  106             close(fileno(f_be));
  107             fclose(f_be);
  108             EOF_LISTENER(s_listener);
  109             time_stamp(buf);
  110             logmsg(0, "%s - - [%s] \"%s\" premature EOF", client_addr, buf, request);
  111             return -1;
  112         }
  113         logmsg(4, "%lX %s %s:%d", pthread_self(), buf, __FILE__, __LINE__);
  114         nn_send(s_listener, buf, strlen(buf), 0);
  115     }
  116 
  117     total += strlen(buf);
  118     /*
  119         * receive the reply headers
  120         * 
  121         * WARNING: we do not check here for malicious combinations, as we assume our servers to be OK!
  122         */
  123     if(be->add_header) {
  124         nn_send(s_listener, be->add_header, strlen(be->add_header), 0);
  125         logmsg(4, "%lX add header %s %s:%d", pthread_self(), be->add_header, __FILE__, __LINE__);
  126         nn_send(s_listener, "\r\n", 2, 0);
  127         total += strlen(be->add_header) + 2;
  128     }
  129     while(fgets(buf, MAXBUF, f_be) != NULL) {
  130         logmsg(4, "%lX header %s %s:%d", pthread_self, buf, __FILE__, __LINE__);
  131         nn_send(s_listener, buf, strlen(buf), 0);
  132         total += strlen(buf);
  133         if(buf[0] == '\r' || buf[0] == '\n')
  134             break;
  135         if(!no_content) {
  136             if(!regexec(&rex_Chunked, buf, 0, NULL, REG_ICASE))
  137                 is_chunked = 1;
  138             else if(!regexec(&rex_ContentLength, buf, 2, match, REG_ICASE))
  139                 sscanf(buf + match[1].rm_so, "%ld", &content_length);
  140         }
  141     }
  142 
  143     logmsg(3, "%lX no_content %d, is_chunked %d, content_length %d %s:%d", pthread_self, no_content, is_chunked, content_length, __FILE__, __LINE__);
  144 
  145     if(!no_content) {
  146         if(is_chunked) {
  147             for(;;) {
  148                 if(fgets(buf, MAXBUF, f_be) == NULL)
  149                     break;
  150                 nn_send(s_listener, buf, strlen(buf), 0);
  151                 total += strlen(buf);
  152                 sscanf(buf, "%lx", &content_length);
  153                 logmsg(4, "%lX chunk %d %s:%d", pthread_self(), content_length, __FILE__, __LINE__);
  154                 if(content_length == 0L)
  155                     break;
  156                 while(content_length > 0L) {
  157                     if((n = fread(buf, sizeof(char), content_length > MAXBUF? MAXBUF: content_length, f_be)) > 0) {
  158                         logmsg(4, "%lX read %d %s:%d", pthread_self(), n, __FILE__, __LINE__);
  159                         nn_send(s_listener, buf, n, 0);
  160                         content_length -= n;
  161                         total += n;
  162                     } else {
  163                         content_length = -1L;
  164                         logmsg(4, "%lX read return %d %s:%d", pthread_self(), n, __FILE__, __LINE__);
  165                     }
  166                     
  167                 }
  168                 /* CR/LF separator */
  169                 fgets(buf, MAXBUF, f_be);
  170             }
  171 
  172             /* possibly some more headers */
  173             while(fgets(buf, MAXBUF, f_be) != NULL) {
  174                 nn_send(s_listener, buf, strlen(buf), 0);
  175                 logmsg(4, "%lX additional header %s %s:%d", pthread_self(), buf, __FILE__, __LINE__);
  176                 total += strlen(buf);
  177                 if(buf[0] == '\r' || buf[0] == '\n')
  178                     break;
  179             }
  180         } else while(content_length > 0L) {
  181             memset(buf, '\0', MAXBUF + 1);
  182             if((n = fread(buf, sizeof(char), content_length > MAXBUF? MAXBUF: content_length, f_be)) > 0) {
  183                 logmsg(4, "%lX read %d %s:%d", pthread_self(), n, __FILE__, __LINE__);
  184                 nn_send(s_listener, buf, n, 0);
  185                 content_length -= n;
  186                 total += n;
  187             } else {
  188                 logmsg(4, "%lX read return %d %s:%d", pthread_self(), n, __FILE__, __LINE__);
  189                 content_length = -1L;
  190             }
  191         }
  192     }
  193 
  194     EOF_LISTENER(s_listener);
  195     time_stamp(buf);
  196     logmsg(0, "%s - - [%s] \"%s\" %d %ld", client_addr, buf, request, reply_code, total);
  197     return fileno(f_be);
  198 }
  199 
  200 static int
  201 backend_2(BACKEND *be, int s_listener, FILE *f_be, char *client_addr)
  202 {
  203     struct hpack_headerblock    *headers, *r_headers;
  204     struct hpack_header         *h;
  205     struct hpack_table          *tab;
  206     int                         TABSIZE, FRAMESIZE, n, no_content, is_chunked, reply_code;
  207     long                        content_length, total;
  208     size_t                      h_len;
  209     char                        buf[MAXBUF], *method, *path, *authority, *cp, *tp, *ttp, request[MAXBUF];
  210     unsigned char               *msg, *content;
  211     regmatch_t                  match[2];
  212 
  213     logmsg(1, "%lX start backend_2 %s:%d", pthread_self(), __FILE__, __LINE__);
  214     if(nn_recv(s_listener, &msg, NN_MSG, 0) != sizeof(int)) {
  215         logmsg(2, "%lX can't get FRAMESIZE %s:%d", pthread_self(), __FILE__, __LINE__);
  216         EOF_LISTENER(s_listener);
  217         return -1;
  218     }
  219     memcpy(&FRAMESIZE, msg, sizeof(int));
  220     nn_freemsg(msg);
  221     if(nn_recv(s_listener, &msg, NN_MSG, 0) != sizeof(int)) {
  222         logmsg(2, "%lX can't get TABSIZE %s:%d", pthread_self(), __FILE__, __LINE__);
  223         EOF_LISTENER(s_listener);
  224         return -1;
  225     }
  226     memcpy(&TABSIZE, msg, sizeof(int));
  227     nn_freemsg(msg);
  228     if(nn_recv(s_listener, &msg, NN_MSG, 0) != sizeof(struct hpack_headerblock *)) {
  229         logmsg(2, "%lX can't get headers %s:%d", pthread_self(), __FILE__, __LINE__);
  230         EOF_LISTENER(s_listener);
  231         return -1;
  232     }
  233     memcpy(&headers, msg, sizeof(struct hpack_headerblock *));
  234     nn_freemsg(msg);
  235     logmsg(3, "%lX FRAMESIZE %d, TABSIZE %d %s:%d", pthread_self(), FRAMESIZE, TABSIZE, __FILE__, __LINE__);
  236 
  237     method = path = authority = NULL;
  238     TAILQ_FOREACH(h, headers, hdr_entry) {
  239         if(!strcmp(h->hdr_name, ":method"))
  240             method = h->hdr_value;
  241         else if(!strcmp(h->hdr_name, ":authority"))
  242             authority = h->hdr_value;
  243         else if(!strcmp(h->hdr_name, ":path"))
  244             path = h->hdr_value;
  245     }
  246     if(method == NULL || path == NULL || authority == NULL) {
  247         logmsg(2, "%lX can't find method/path/authority %s:%d", pthread_self(), __FILE__, __LINE__);
  248         EOF_LISTENER(s_listener);
  249         return -1;
  250     }
  251     is_chunked = 0;
  252     snprintf(request, MAXBUF, "%s %s HTTP/1.1", method, path);
  253     fprintf(f_be, "%s\r\n", request);
  254     logmsg(4, "%lX %s %s HTTP/1.1 %s:%d", pthread_self(), method, path, __FILE__, __LINE__);
  255     fprintf(f_be, "host: %s\r\n", authority);
  256     logmsg(4, "%lX host: %s %s:%d", pthread_self(), authority, __FILE__, __LINE__);
  257     TAILQ_FOREACH(h, headers, hdr_entry) {
  258         if(!strcasecmp(h->hdr_name, ":method") || !strcasecmp(h->hdr_name, ":authority") || !strcasecmp(h->hdr_name, ":path") || !strcasecmp(h->hdr_name, ":scheme"))
  259             continue;
  260         if(!strcmp(h->hdr_name, "te") || !strcasecmp(h->hdr_name, "transfer-encoding")) {
  261             fprintf(f_be, "%s: %s, chunked\r\n", h->hdr_name, h->hdr_value);
  262             logmsg(4, "%lX %s: %s, chunked %s:%d", pthread_self(), h->hdr_name, h->hdr_value, __FILE__, __LINE__);
  263             is_chunked = 1;
  264         } if(!strcasecmp(h->hdr_name, "upgrade") || !strcasecmp(h->hdr_name, "upgrade-insecure-requests")) {
  265             logmsg(4, "%lX %s: skipped %s:%d", pthread_self(), h->hdr_name, __FILE__, __LINE__);
  266         } else {
  267             fprintf(f_be, "%s: %s\r\n", h->hdr_name, h->hdr_value);
  268             logmsg(4, "%lX %s: %s %s:%d", pthread_self(), h->hdr_name, h->hdr_value, __FILE__, __LINE__);
  269         }
  270     }
  271     if(!is_chunked) {
  272         fprintf(f_be, "te: chunked\r\n");
  273         logmsg(4, "%lX te: chunked %s:%d", pthread_self(), __FILE__, __LINE__);
  274     }
  275     fprintf(f_be, "\r\n");
  276     logmsg(4, "%lX ---end of headers--- %s:%d", pthread_self(), __FILE__, __LINE__);
  277 
  278     while((n = nn_recv(s_listener, &msg, NN_MSG, 0)) > 0) {
  279         logmsg(4, "%lX chunk %d %s:%d", pthread_self(), n, __FILE__, __LINE__);
  280         fprintf(f_be, "%X\r\n", n);
  281         fwrite(msg, 1, n, f_be);
  282         fwrite("\r\n", 1, 2, f_be);
  283         nn_freemsg(msg);
  284     }
  285     fprintf(f_be, "0\r\n");
  286     logmsg(4, "%lX ---end of content--- %s:%d", pthread_self(), __FILE__, __LINE__);
  287     if(nn_recv(s_listener, &msg, NN_MSG, 0) == sizeof(struct hpack_headerblock *)) {
  288         memcpy(&headers, msg, sizeof(struct hpack_headerblock *));
  289         TAILQ_FOREACH(h, headers, hdr_entry) {
  290             if(!strcasecmp(h->hdr_name, ":method") || !strcasecmp(h->hdr_name, ":authority") || !strcasecmp(h->hdr_name, ":path") || !strcasecmp(h->hdr_name, ":scheme"))
  291                 continue;
  292             fprintf(f_be, "%s: %s\r\n", h->hdr_name, h->hdr_value);
  293             logmsg(4, "%lX trailing header %s: %s %s:%d", pthread_self(), h->hdr_name, h->hdr_value, __FILE__, __LINE__);
  294         }
  295     } else {
  296         logmsg(2, "%lX no trailing headers %s:%d", pthread_self(), __FILE__, __LINE__);
  297     }
  298     nn_freemsg(msg);
  299     fprintf(f_be, "\r\n");
  300     logmsg(4, "%lX ---end of trailing headers --- %s:%d", pthread_self(), __FILE__, __LINE__);
  301 
  302     no_content = !strncasecmp("HEAD", method, 4);
  303     total = 0L;
  304     r_headers = hpack_headerblock_new();
  305     tab = hpack_table_new(TABSIZE);
  306 
  307     for(;;) {
  308         do {
  309             if(fgets(buf, MAXBUF - 1, f_be) == NULL) {
  310                 logmsg(2, "%lX no reply from backend %s:%d", pthread_self(), __FILE__, __LINE__);
  311                 hpack_headerblock_free(r_headers);
  312                 hpack_table_free(tab);
  313                 close(fileno(f_be));
  314                 fclose(f_be);
  315                 EOF_LISTENER(s_listener);
  316                 return -1;
  317             } else
  318                 logmsg(4, "%lX read %s %s:%d", pthread_self(), buf, __FILE__, __LINE__);
  319         } while(regexec(&rex_Response, buf, 2, match, REG_ICASE));
  320         sscanf(buf + match[1].rm_so, "%d", &reply_code);
  321         logmsg(4, "%lX reply code %d %s:%d", pthread_self(), reply_code, __FILE__, __LINE__);
  322         if(reply_code >= 200) {
  323             sprintf(buf, "%d", reply_code);
  324             hpack_header_add(r_headers, ":status", buf, HPACK_INDEX);
  325             logmsg(4, "%lX reply header :status %s %s:%d", pthread_self(), buf, __FILE__, __LINE__);
  326             total += strlen(":status") + strlen(buf);
  327             break;
  328         }
  329     }
  330 
  331     if(be->add_header) {
  332         strncpy(buf, be->add_header, MAXBUF);
  333         cp = strtok_r(buf, ":", &tp);
  334         if((ttp = strtok_r(NULL, "\r", &tp)) != NULL)
  335             while(*ttp == ' ')
  336                 ttp++;
  337         else
  338             ttp = "";
  339         hpack_header_add(r_headers, cp, ttp, HPACK_INDEX);
  340         logmsg(4, "%lX add header %s %s:%d", pthread_self(), be->add_header, __FILE__, __LINE__);
  341         total += strlen(cp) + strlen(ttp);
  342     }
  343 
  344     is_chunked = 0;
  345     content_length = 0L;
  346     while(fgets(buf, MAXBUF, f_be) != NULL) {
  347         if(buf[0] == '\r' || buf[0] == '\n')
  348             break;
  349         if(!no_content) {
  350             if(!regexec(&rex_Chunked, buf, 0, NULL, REG_ICASE))
  351                 is_chunked = 1;
  352             else if(!regexec(&rex_ContentLength, buf, 2, match, REG_ICASE))
  353                 sscanf(buf + match[1].rm_so, "%ld", &content_length);
  354         }
  355         cp = strtok_r(buf, ":", &tp);
  356         if(!strcasecmp(cp, "connection") || !strcasecmp(cp, "keep-alive") || !strcasecmp(cp, "proxy-connection") || !strcasecmp(cp, "transfer-encoding")
  357         || !strcasecmp(cp, "te") || !strcasecmp(cp, "content-length") || !strcasecmp(cp, "upgrade")) {
  358             logmsg(4, "%lX header %s skipped %s:%d", pthread_self(), buf, __FILE__, __LINE__);
  359             continue;
  360         }
  361         if((ttp = strtok_r(NULL, "\r", &tp)) != NULL)
  362             while(*ttp == ' ')
  363                 ttp++;
  364         else
  365             ttp = "";
  366         hpack_header_add(r_headers, cp, ttp, HPACK_INDEX);
  367         logmsg(4, "%lX header %s => %s: %s %s:%d", pthread_self(), buf, cp, ttp, __FILE__, __LINE__);
  368         total += strlen(cp) + strlen(ttp);
  369     }
  370     if((content = hpack_encode(r_headers, &h_len, tab)) == NULL) {
  371         logmsg(4, "%lX failed encode %s:%d", pthread_self(), __FILE__, __LINE__);
  372         hpack_headerblock_free(r_headers);
  373         hpack_table_free(tab);
  374         close(fileno(f_be));
  375         fclose(f_be);
  376         EOF_LISTENER(s_listener);
  377         return -1;
  378     }
  379     for(n = 0; h_len > 0; ) {
  380         nn_send(s_listener, content + n, h_len > FRAMESIZE? FRAMESIZE: h_len, 0);
  381         n += (h_len > FRAMESIZE? FRAMESIZE: h_len);
  382         h_len -= (h_len > FRAMESIZE? FRAMESIZE: h_len);
  383     }
  384     free(content);
  385     hpack_headerblock_free(r_headers);
  386 
  387     /* end of headers */
  388     nn_send(s_listener, "", 0, 0);
  389     logmsg(3, "%lX no_content %d, is_chunked %d, content_length %d %s:%d", pthread_self(), no_content, is_chunked, content_length, __FILE__, __LINE__);
  390 
  391     if(!no_content) {
  392         if((content = malloc(FRAMESIZE)) == NULL) {
  393             logmsg(4, "%lX out of memory for content %s:%d", pthread_self(), __FILE__, __LINE__);
  394             hpack_table_free(tab);
  395             close(fileno(f_be));
  396             fclose(f_be);
  397             EOF_LISTENER(s_listener);
  398             return -1;
  399         }
  400 
  401         if(is_chunked) {
  402             for(;;) {
  403                 if(fgets(buf, MAXBUF, f_be) == NULL)
  404                     break;
  405                 sscanf(buf, "%lx", &content_length);
  406                 logmsg(4, "%lX chunk %d (%s) %s:%d", pthread_self(), content_length, buf, __FILE__, __LINE__);
  407                 if(content_length == 0L)
  408                     break;
  409                 while(content_length > 0L) {
  410                     if((n = fread(content, sizeof(char), content_length > FRAMESIZE? FRAMESIZE: content_length, f_be)) > 0) {
  411                         logmsg(4, "%lX read %d %s:%d", pthread_self(), n, __FILE__, __LINE__);
  412                         nn_send(s_listener, content, n, 0);
  413                         content_length -= n;
  414                         total += n;
  415                     } else {
  416                         content_length = -1L;
  417                         logmsg(4, "%lX read return %d %s:%d", pthread_self(), n, __FILE__, __LINE__);
  418                     }
  419                     
  420                 }
  421                 /* CR/LF separator */
  422                 fgets(buf, MAXBUF, f_be);
  423             }
  424         } else while(content_length > 0L) {
  425             if((n = fread(content, sizeof(char), content_length > FRAMESIZE? FRAMESIZE: content_length, f_be)) > 0) {
  426                 logmsg(4, "%lX read %d %s:%d", pthread_self(), n, __FILE__, __LINE__);
  427                 nn_send(s_listener, content, n, 0);
  428                 content_length -= n;
  429                 total += n;
  430             } else {
  431                 logmsg(4, "%lX read return %d %s:%d", pthread_self(), n, __FILE__, __LINE__);
  432                 content_length = -1L;
  433             }
  434         }
  435 
  436         free(content);
  437     }
  438     /* end of data */
  439     nn_send(s_listener, "", 0, 0);
  440     logmsg(4, "%lX sent end-of-content %s:%d", pthread_self(), __FILE__, __LINE__);
  441 
  442     EOF_LISTENER(s_listener);
  443     time_stamp(buf);
  444     logmsg(0, "%s - - [%s] \"%s\" %d %ld", client_addr, buf, request, reply_code, total);
  445     return fileno(f_be);
  446 }
  447 
  448 void *
  449 thr_backend(void *arg)
  450 {
  451     BACKEND *be;
  452     int     s_listener, s_be, res, flags, http_ver;
  453     char    *msg, client_addr[NI_MAXHOST], *cp, *saveptr;
  454     struct pollfd    be_poll;
  455     struct linger   s_linger;
  456     struct timeval  s_time;
  457     FILE    *f_be;
  458     regmatch_t  match[2];
  459 
  460     be = (BACKEND *)arg;
  461     sem_post(&sem_start);
  462     s_be = -1;
  463     for(;;) {
  464         msg = NULL;
  465 
  466         if(nn_recv(be->sock, &msg, NN_MSG, 0) <= 0) {
  467             logmsg(0, "Backend: can't receive from queue socket");
  468             continue;
  469         }
  470         if((s_listener = nn_socket(AF_SP, NN_PAIR)) < 0) {
  471             logmsg(0, "Backend: can't create direct socket");
  472             continue;
  473         }
  474         if(nn_connect(s_listener, msg) < 0) {
  475             logmsg(0, "Backend: can't connect to direct socket");
  476             continue;
  477         }
  478         nn_freemsg(msg);
  479         
  480         /* prepare the back-end socket */
  481         if(s_be >= 0) {
  482             be_poll.fd = s_be;
  483             be_poll.events = POLLIN;
  484             if(poll(&be_poll, 1, 1) == 1) {
  485                 /* only EOF can be read! */
  486                 close(s_be);
  487                 s_be = -1;
  488             }
  489         }
  490         if(s_be < 0) {
  491             /* open the socket to the backend */
  492             if((s_be = socket(be->addr->ai_family, SOCK_STREAM, 0)) < 0) {
  493                 logmsg(0, "Backend: can't create socket");
  494                 s_be = -1;
  495                 EOF_LISTENER(s_listener);
  496                 continue;
  497             }
  498 
  499             /* wait at most 'timeout' seconds for the connection */
  500             flags = fcntl(s_be, F_GETFL, &flags);
  501             fcntl(s_be, F_SETFL, flags | O_NONBLOCK);
  502             if(connect(s_be, be->addr->ai_addr, be->addr->ai_addrlen)) {
  503                 if(errno != EINPROGRESS) {
  504                     logmsg(0, "Backend: can't connect socket");
  505                     close(s_be);
  506                     s_be = -1;
  507                     EOF_LISTENER(s_listener);
  508                     continue;
  509                 }
  510                 be_poll.fd = s_be;
  511                 be_poll.events = POLLOUT;
  512                 if(poll(&be_poll, 1, be->timeout * 1000) != 1) {
  513                     logmsg(0, "Backend: can't connect");
  514                     close(s_be);
  515                     be->is_dead = 1;
  516                     s_be = -1;
  517                     EOF_LISTENER(s_listener);
  518                     continue;
  519                 }
  520             }
  521             fcntl(s_be, F_SETFL, flags);
  522             s_linger.l_onoff = 1;
  523             s_linger.l_linger = 0;
  524             setsockopt(s_be, SOL_SOCKET, SO_LINGER, &s_linger, sizeof(s_linger));
  525             s_time.tv_sec = be->timeout;
  526             s_time.tv_usec = 0;
  527             setsockopt(s_be, SOL_SOCKET, SO_RCVTIMEO, &s_time, sizeof(s_time));
  528             setsockopt(s_be, SOL_SOCKET, SO_SNDTIMEO, &s_time, sizeof(s_time));
  529             f_be = fdopen(s_be, "r+");
  530         }
  531 
  532         /* received the protocol information from the listener */
  533         if(nn_recv(s_listener, &msg, NN_MSG, 0) != sizeof(int)) {
  534             logmsg(2, "%lX can't get protocol version %s:%d", pthread_self(), __FILE__, __LINE__);
  535             EOF_LISTENER(s_listener);
  536             continue;
  537         }
  538         memcpy(&http_ver, msg, sizeof(int));
  539         nn_freemsg(msg);
  540         logmsg(4, "%lX http_ver %d %s:%d", pthread_self(), http_ver, __FILE__, __LINE__);
  541 
  542         /* receive the client address from the listener and keep it for logging */
  543         if(nn_recv(s_listener, &msg, NN_MSG, 0) <= 0) {
  544             logmsg(2, "thr_backend: can't get client address %s:%d", pthread_self(), __FILE__, __LINE__);
  545             EOF_LISTENER(s_listener);
  546             continue;
  547         }
  548         strcpy(client_addr, msg);
  549         nn_freemsg(msg);
  550         logmsg(4, "%lX client_addr:%s %s:%d", pthread_self(), client_addr, __FILE__, __LINE__);
  551 
  552         /* receive the reply from the back-end and pass it to the listener  in the appropriate protocol */
  553         if(http_ver == 2)
  554             s_be = backend_2(be, s_listener, f_be, client_addr);
  555         else
  556             s_be = backend_1(be, s_listener, f_be, client_addr);
  557     }
  558 }