"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 }