"Fossies" - the Fresh Open Source Software Archive

Member "Pound-3.0.2/src/pound.c" (28 Nov 2021, 10486 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 "pound.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 3.0c_vs_3.0d.

    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 GLOBAL  global;
   31 
   32 BACKEND *backends;
   33 int     backends_len;
   34 
   35 HTTP_LISTENER   *http_listeners;
   36 int             http_len;
   37 
   38 mbedtls_ctr_drbg_context    tls_ctr_drbg;
   39 
   40 regex_t rex_Expect, rex_Response, rex_ContentLength, rex_Chunked, rex_Connection_Closed, rex_Connection_HTTP2, rex_Upgrade_HTTP2;
   41 
   42 sem_t   sem_start;
   43 
   44 int
   45 main(const int argc, char **argv)
   46 {
   47     int             i, j, n, s_in, s_listener;
   48     HTTP_LISTENER   **listeners;
   49     struct pollfd   *listener_poll;
   50     struct addrinfo *listener_addr;
   51     BACKEND         *be;
   52     char            name[NI_MAXHOST], port[NI_MAXSERV], *msg;
   53     pthread_t       thr;
   54     pthread_attr_t  attr;
   55     FILE            *f_pid;
   56     mbedtls_entropy_context     tls_entropy;
   57 
   58     memset(&global, 0, sizeof(global));
   59     global.log_facility = LOG_FACILITY;
   60     openlog("pound", LOG_CONS | LOG_NDELAY, global.log_facility);
   61     mbedtls_entropy_init(&tls_entropy);
   62     mbedtls_ctr_drbg_init(&tls_ctr_drbg);
   63     getentropy(name, 16);
   64     mbedtls_ctr_drbg_seed(&tls_ctr_drbg, mbedtls_entropy_func, &tls_entropy, (const unsigned char *)name, 16);
   65     hpack_init();
   66     config(argc, argv);
   67 
   68     /* These are handled elsewhere */
   69     (void)signal(SIGHUP, SIG_IGN);
   70     (void)signal(SIGPIPE, SIG_IGN);
   71 
   72     /* Common regex */
   73     regcomp(&rex_Response, "HTTP[^ \t]*[ \t]+([0-9]+).*", REG_ICASE | REG_EXTENDED);
   74     regcomp(&rex_Expect, "Expect:[ \t]*100-continue", REG_ICASE | REG_EXTENDED);
   75     regcomp(&rex_ContentLength, "Content-Length:[ \t]*([0-9]+)", REG_ICASE | REG_EXTENDED);
   76     regcomp(&rex_Chunked, "Transfer-Encoding:.*chunked", REG_ICASE | REG_EXTENDED | REG_NOSUB);
   77     regcomp(&rex_Connection_Closed, "Connection:.*close", REG_ICASE | REG_EXTENDED | REG_NOSUB);
   78     regcomp(&rex_Connection_HTTP2, "Connection:.*upgrade", REG_ICASE | REG_EXTENDED | REG_NOSUB);
   79     regcomp(&rex_Upgrade_HTTP2, "Upgrade:.*h2c", REG_ICASE | REG_EXTENDED | REG_NOSUB);
   80 
   81     /* preamble */
   82     global.http2_preamble[0] = "PRI * HTTP/2.0\r\n";
   83     global.http2_preamble[1] = "\r\n";
   84     global.http2_preamble[2] = "SM\r\n";
   85     global.http2_preamble[3] = "\r\n";
   86     global.http2_preamble[4] = NULL;
   87 
   88     /* Daemonize if needed */
   89     if(global.log_level == 0) {
   90         switch(fork()) {
   91             case 0:
   92                 close(0);
   93                 close(1);
   94                 close(2);
   95                 if(setsid() < 0) {
   96                     logmsg(0, "Failed setsid");
   97                     exit(1);
   98                 }
   99                 break;
  100             case -1:
  101                 logmsg(0, "Can't fork");
  102                 exit(1);
  103                 break;
  104             default:
  105                 exit(0);
  106         }
  107         switch(fork()) {
  108             case 0:
  109                 break;
  110             case -1:
  111                 logmsg(0, "Can't fork");
  112                 exit(1);
  113                 break;
  114             default:
  115                 exit(0);
  116         }
  117     }
  118 
  119     if((f_pid = fopen(global.pid, "w")) == NULL)
  120         logmsg(0, "Can't open pid file %s", global.pid);
  121     else {
  122         fprintf(f_pid, "%d", getpid());
  123         fclose(f_pid);
  124     }
  125 
  126     /* chroot, set[ug]id */
  127     if(global.root_jail)
  128         if(chroot(global.root_jail)) {
  129             logmsg(0, "Can't chroot to %s", global.root_jail);
  130             exit(1);
  131         }
  132     if(global.group > 0)
  133         if(setgid(global.group)) {
  134             logmsg(0, "Can't setgid %d", global.group);
  135             exit(1);
  136         }
  137     if(global.user > 0)
  138         if(setuid(global.user)) {
  139             logmsg(0, "Can't setuid %d", global.user);
  140             exit(1);
  141         }
  142 
  143     /* prepare threads */
  144     pthread_attr_init(&attr);
  145     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  146 
  147     /* resurrector */
  148     if(pthread_create(&thr, &attr, thr_resurrect, NULL)) {
  149         logmsg(0, "Resurrector: can't start thread");
  150         exit(1);
  151     }
  152 
  153     logmsg(2, "Prepare backends %s:%d", __FILE__, __LINE__);
  154     /* prepare back-ends */
  155     for(i = 0; i < backends_len; i++) {
  156         snprintf(name, NI_MAXHOST, "inproc://BE_%d", i);
  157         if((backends[i].sock = nn_socket(AF_SP, NN_PULL)) < 0) {
  158             logmsg(0, "Backend %d: can't create queue socket", i);
  159             exit(1);
  160         }
  161         if(nn_bind(backends[i].sock, name) < 0) {
  162             logmsg(0, "Backend %d: can't bind queue socket", i);
  163             exit(1);
  164         }
  165         if((backends[i].sock_in = nn_socket(AF_SP, NN_PUSH)) < 0) {
  166             logmsg(0, "Backend %d: can't create queue socket", i);
  167             exit(1);
  168         }
  169         if(nn_connect(backends[i].sock_in, name) < 0) {
  170             logmsg(0, "Backend %d: can't connect queue socket", i);
  171             exit(1);
  172         }
  173         sem_init(&sem_start, 0, 0);
  174         for(j = 0; j < backends[i].threads; j++)
  175             if(pthread_create(&thr, &attr, thr_backend, (void *)&backends[i])) {
  176                 logmsg(0, "Backend %d: can't start threads %d", i);
  177                 exit(1);
  178             }
  179         for(j = 0; j < backends[i].threads; j++)
  180             sem_wait(&sem_start);
  181         sem_destroy(&sem_start);
  182     }
  183 
  184     /* prepare listeners */
  185     logmsg(2, "Prepare listeners %s:%d", __FILE__, __LINE__);
  186     for(i = 0, n = 0; i < http_len; i++) {
  187         /* prepare the services */
  188         logmsg(3, "Prepare services for listener %d %s:%d", i, __FILE__, __LINE__);
  189         for(j = 0; j < http_listeners[i].services_len; j++) {
  190             snprintf(name, NI_MAXHOST, "inproc://SVC_%d_%d", i, j);
  191             if((http_listeners[i].services[j]->sock = nn_socket(AF_SP, NN_REP)) < 0) {
  192                 logmsg(0, "Service %d/%d: can't create queue socket", i, j);
  193                 exit(1);
  194             }
  195             if(nn_bind(http_listeners[i].services[j]->sock, name) < 0) {
  196                 logmsg(0, "Service %d/%d: can't bind queue socket", i, j);
  197                 exit(1);
  198             }
  199             if((http_listeners[i].services[j]->sock_in = nn_socket(AF_SP, NN_REQ)) < 0) {
  200                 logmsg(0, "Service %d/%d: can't create queue socket", i, j);
  201                 exit(1);
  202             }
  203             if(nn_connect(http_listeners[i].services[j]->sock_in, name) < 0) {
  204                 logmsg(0, "Service %d/%d: can't connect queue socket", i, j);
  205                 exit(1);
  206             }
  207             sem_init(&sem_start, 0, 0);
  208             if(pthread_create(&thr, &attr, thr_service, (void *)http_listeners[i].services[j])) {
  209                 logmsg(0, "Service %d/%d: can't start thread", i, j);
  210                 exit(1);
  211             }
  212             sem_wait(&sem_start);
  213             sem_destroy(&sem_start);
  214         }
  215         /* prepare the listeners */
  216         snprintf(name, NI_MAXHOST, "inproc://HTTP%d", i);
  217         if((http_listeners[i].sock_fan = nn_socket(AF_SP, NN_PULL)) < 0) {
  218             logmsg(0, "Listener %d: can't create fan socket", i);
  219             exit(1);
  220         }
  221         if(nn_bind(http_listeners[i].sock_fan, name) < 0) {
  222             logmsg(0, "Listener %d: can't bind fan socket", i);
  223             exit(1);
  224         }
  225         if((http_listeners[i].sock_in = nn_socket(AF_SP, NN_PUSH)) < 0) {
  226             logmsg(0, "Listener %d: can't create in socket", i);
  227             exit(1);
  228         }
  229         if(nn_connect(http_listeners[i].sock_in, name) < 0) {
  230             logmsg(0, "Listener %d: can't connect in socket", i);
  231             exit(1);
  232         }
  233         sem_init(&sem_start, 0, 0);
  234         for(j = 0; j < http_listeners[i].threads; j++)
  235             if(pthread_create(&thr, &attr, thr_http, (void *)&http_listeners[i])) {
  236                 logmsg(0, "Http %d: can't start listener threads %d", i, j);
  237                 exit(1);
  238             }
  239         for(j = 0; j < http_listeners[i].threads; j++)
  240             sem_wait(&sem_start);
  241         sem_destroy(&sem_start);
  242         for(listener_addr = http_listeners[i].addr; listener_addr != NULL; listener_addr = listener_addr->ai_next)
  243             n++;
  244     }
  245 
  246     if((listeners = calloc(n, sizeof(HTTP_LISTENER *))) == NULL || (listener_poll = calloc(n, sizeof(struct pollfd))) == NULL) {
  247             logmsg(0, "Listener poll: out of memory");
  248             exit(1);
  249     }
  250     for(i = 0, n = 0; i < http_len; i++)
  251         for(listener_addr = http_listeners[i].addr; listener_addr != NULL; listener_addr = listener_addr->ai_next) {
  252             getnameinfo(listener_addr->ai_addr, listener_addr->ai_addrlen, name, NI_MAXHOST, port, NI_MAXSERV, NI_NUMERICHOST);
  253             if((listener_poll[n].fd = socket(listener_addr->ai_family, SOCK_STREAM, 0)) < 0) {
  254                 logmsg(0, "Listener %s:%s: can't open socket", name, port);
  255                 continue;
  256             }
  257             if(bind(listener_poll[n].fd, listener_addr->ai_addr, listener_addr->ai_addrlen)) {
  258                 close(listener_poll[n].fd);
  259                 logmsg(0, "Listener %s:%s: can't bind socket", name, port);
  260                 continue;
  261             }
  262             if(listen(listener_poll[n].fd, http_listeners[i].threads * 2)) {
  263                 close(listener_poll[n].fd);
  264                 logmsg(0, "Listener %s:%s: can't listen to socket", name, port);
  265                 continue;
  266             }
  267             listener_poll[n].events = POLLIN;
  268             listeners[n++] = &http_listeners[i];
  269         }
  270     
  271     for(;;) {
  272         poll(listener_poll, n, -1);
  273         for(i = 0; i < n; i++)
  274             if(listener_poll[i].revents & POLLIN) {
  275                 listener_poll[i].revents = 0;
  276                 if((s_in = accept(listener_poll[i].fd, NULL, NULL)) < 0) {
  277                     logmsg(0, "Bad accept");
  278                     continue;
  279                 }
  280 
  281                 nn_send(listeners[i]->sock_in, &s_in, sizeof(s_in), 0);
  282             }
  283     }
  284 }