1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2014 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Dmitry Stogov <dmitry@zend.com> |
16 +----------------------------------------------------------------------+
17 */
18
19 /* $Id: fastcgi.c 287777 2009-08-26 19:17:32Z pajoye $ */
20
21 #include "php.h"
22 #include "fastcgi.h"
23
24 #include <string.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <stdarg.h>
28 #include <errno.h>
29 #include <limits.h>
30
31 #include <php_config.h>
32 #include "fpm.h"
33 #include "fpm_request.h"
34 #include "zlog.h"
35
36 #ifdef _WIN32
37
38 #include <windows.h>
39
40 typedef unsigned int in_addr_t;
41
42 struct sockaddr_un {
43 short sun_family;
44 char sun_path[MAXPATHLEN];
45 };
46
47 static HANDLE fcgi_accept_mutex = INVALID_HANDLE_VALUE;
48 static int is_impersonate = 0;
49
50 #define FCGI_LOCK(fd) \
51 if (fcgi_accept_mutex != INVALID_HANDLE_VALUE) { \
52 DWORD ret; \
53 while ((ret = WaitForSingleObject(fcgi_accept_mutex, 1000)) == WAIT_TIMEOUT) { \
54 if (in_shutdown) return -1; \
55 } \
56 if (ret == WAIT_FAILED) { \
57 fprintf(stderr, "WaitForSingleObject() failed\n"); \
58 return -1; \
59 } \
60 }
61
62 #define FCGI_UNLOCK(fd) \
63 if (fcgi_accept_mutex != INVALID_HANDLE_VALUE) { \
64 ReleaseMutex(fcgi_accept_mutex); \
65 }
66
67 #else
68
69 # include <sys/types.h>
70 # include <sys/stat.h>
71 # include <unistd.h>
72 # include <fcntl.h>
73 # include <sys/socket.h>
74 # include <sys/un.h>
75 # include <netinet/in.h>
76 # include <arpa/inet.h>
77 # include <netdb.h>
78 # include <signal.h>
79
80 # define closesocket(s) close(s)
81
82 # if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
83 # include <sys/poll.h>
84 # endif
85 # if defined(HAVE_SYS_SELECT_H)
86 # include <sys/select.h>
87 # endif
88
89 #ifndef INADDR_NONE
90 #define INADDR_NONE ((unsigned long) -1)
91 #endif
92
93 # ifndef HAVE_SOCKLEN_T
94 typedef unsigned int socklen_t;
95 # endif
96
97 # ifdef USE_LOCKING
98 # define FCGI_LOCK(fd) \
99 do { \
100 struct flock lock; \
101 lock.l_type = F_WRLCK; \
102 lock.l_start = 0; \
103 lock.l_whence = SEEK_SET; \
104 lock.l_len = 0; \
105 if (fcntl(fd, F_SETLKW, &lock) != -1) { \
106 break; \
107 } else if (errno != EINTR || in_shutdown) { \
108 return -1; \
109 } \
110 } while (1)
111
112 # define FCGI_UNLOCK(fd) \
113 do { \
114 int orig_errno = errno; \
115 while (1) { \
116 struct flock lock; \
117 lock.l_type = F_UNLCK; \
118 lock.l_start = 0; \
119 lock.l_whence = SEEK_SET; \
120 lock.l_len = 0; \
121 if (fcntl(fd, F_SETLK, &lock) != -1) { \
122 break; \
123 } else if (errno != EINTR) { \
124 return -1; \
125 } \
126 } \
127 errno = orig_errno; \
128 } while (0)
129 # else
130 # define FCGI_LOCK(fd)
131 # define FCGI_UNLOCK(fd)
132 # endif
133
134 #endif
135
136 typedef union _sa_t {
137 struct sockaddr sa;
138 struct sockaddr_un sa_unix;
139 struct sockaddr_in sa_inet;
140 } sa_t;
141
142 static HashTable fcgi_mgmt_vars;
143
144 static int is_initialized = 0;
145 static int in_shutdown = 0;
146 static in_addr_t *allowed_clients = NULL;
147
148 static sa_t client_sa;
149
150 #ifdef _WIN32
151
fcgi_shutdown_thread(LPVOID arg)152 static DWORD WINAPI fcgi_shutdown_thread(LPVOID arg)
153 {
154 HANDLE shutdown_event = (HANDLE) arg;
155 WaitForSingleObject(shutdown_event, INFINITE);
156 in_shutdown = 1;
157 return 0;
158 }
159
160 #else
161
fcgi_signal_handler(int signo)162 static void fcgi_signal_handler(int signo)
163 {
164 if (signo == SIGUSR1 || signo == SIGTERM) {
165 in_shutdown = 1;
166 }
167 }
168
fcgi_setup_signals(void)169 static void fcgi_setup_signals(void)
170 {
171 struct sigaction new_sa, old_sa;
172
173 sigemptyset(&new_sa.sa_mask);
174 new_sa.sa_flags = 0;
175 new_sa.sa_handler = fcgi_signal_handler;
176 sigaction(SIGUSR1, &new_sa, NULL);
177 sigaction(SIGTERM, &new_sa, NULL);
178 sigaction(SIGPIPE, NULL, &old_sa);
179 if (old_sa.sa_handler == SIG_DFL) {
180 sigaction(SIGPIPE, &new_sa, NULL);
181 }
182 }
183 #endif
184
fcgi_init(void)185 int fcgi_init(void)
186 {
187 if (!is_initialized) {
188 zend_hash_init(&fcgi_mgmt_vars, 0, NULL, fcgi_free_mgmt_var_cb, 1);
189 fcgi_set_mgmt_var("FCGI_MPXS_CONNS", sizeof("FCGI_MPXS_CONNS") - 1, "0", sizeof("0")-1);
190
191 is_initialized = 1;
192 #ifdef _WIN32
193 # if 0
194 /* TODO: Support for TCP sockets */
195 WSADATA wsaData;
196
197 if (WSAStartup(MAKEWORD(2,0), &wsaData)) {
198 fprintf(stderr, "Error starting Windows Sockets. Error: %d", WSAGetLastError());
199 return 0;
200 }
201 # endif
202 {
203 char *str;
204 DWORD pipe_mode = PIPE_READMODE_BYTE | PIPE_WAIT;
205 HANDLE pipe = GetStdHandle(STD_INPUT_HANDLE);
206
207 SetNamedPipeHandleState(pipe, &pipe_mode, NULL, NULL);
208
209 str = getenv("_FCGI_SHUTDOWN_EVENT_");
210 if (str != NULL) {
211 HANDLE shutdown_event = (HANDLE) atoi(str);
212 if (!CreateThread(NULL, 0, fcgi_shutdown_thread,
213 shutdown_event, 0, NULL)) {
214 return -1;
215 }
216 }
217 str = getenv("_FCGI_MUTEX_");
218 if (str != NULL) {
219 fcgi_accept_mutex = (HANDLE) atoi(str);
220 }
221 return 1;
222 }
223 #else
224 fcgi_setup_signals();
225 return 1;
226 #endif
227 }
228 return 1;
229 }
230
fcgi_set_in_shutdown(int new_value)231 void fcgi_set_in_shutdown(int new_value)
232 {
233 in_shutdown = new_value;
234 }
235
fcgi_shutdown(void)236 void fcgi_shutdown(void)
237 {
238 if (is_initialized) {
239 zend_hash_destroy(&fcgi_mgmt_vars);
240 }
241 if (allowed_clients) {
242 free(allowed_clients);
243 }
244 }
245
fcgi_set_allowed_clients(char * ip)246 void fcgi_set_allowed_clients(char *ip)
247 {
248 char *cur, *end;
249 int n;
250
251 if (ip) {
252 ip = strdup(ip);
253 cur = ip;
254 n = 0;
255 while (*cur) {
256 if (*cur == ',') n++;
257 cur++;
258 }
259 if (allowed_clients) free(allowed_clients);
260 allowed_clients = malloc(sizeof(in_addr_t) * (n+2));
261 n = 0;
262 cur = ip;
263 while (cur) {
264 end = strchr(cur, ',');
265 if (end) {
266 *end = 0;
267 end++;
268 }
269 allowed_clients[n] = inet_addr(cur);
270 if (allowed_clients[n] == INADDR_NONE) {
271 zlog(ZLOG_ERROR, "Wrong IP address '%s' in listen.allowed_clients", cur);
272 }
273 n++;
274 cur = end;
275 }
276 allowed_clients[n] = INADDR_NONE;
277 free(ip);
278 }
279 }
280
fcgi_init_request(fcgi_request * req,int listen_socket)281 void fcgi_init_request(fcgi_request *req, int listen_socket)
282 {
283 memset(req, 0, sizeof(fcgi_request));
284 req->listen_socket = listen_socket;
285 req->fd = -1;
286 req->id = -1;
287
288 req->in_len = 0;
289 req->in_pad = 0;
290
291 req->out_hdr = NULL;
292 req->out_pos = req->out_buf;
293
294 #ifdef _WIN32
295 req->tcp = !GetNamedPipeInfo((HANDLE)_get_osfhandle(req->listen_socket), NULL, NULL, NULL, NULL);
296 #endif
297 }
298
safe_write(fcgi_request * req,const void * buf,size_t count)299 static inline ssize_t safe_write(fcgi_request *req, const void *buf, size_t count)
300 {
301 int ret;
302 size_t n = 0;
303
304 do {
305 errno = 0;
306 #ifdef _WIN32
307 if (!req->tcp) {
308 ret = write(req->fd, ((char*)buf)+n, count-n);
309 } else {
310 ret = send(req->fd, ((char*)buf)+n, count-n, 0);
311 if (ret <= 0) {
312 errno = WSAGetLastError();
313 }
314 }
315 #else
316 ret = write(req->fd, ((char*)buf)+n, count-n);
317 #endif
318 if (ret > 0) {
319 n += ret;
320 } else if (ret <= 0 && errno != 0 && errno != EINTR) {
321 return ret;
322 }
323 } while (n != count);
324 return n;
325 }
326
safe_read(fcgi_request * req,const void * buf,size_t count)327 static inline ssize_t safe_read(fcgi_request *req, const void *buf, size_t count)
328 {
329 int ret;
330 size_t n = 0;
331
332 do {
333 errno = 0;
334 #ifdef _WIN32
335 if (!req->tcp) {
336 ret = read(req->fd, ((char*)buf)+n, count-n);
337 } else {
338 ret = recv(req->fd, ((char*)buf)+n, count-n, 0);
339 if (ret <= 0) {
340 errno = WSAGetLastError();
341 }
342 }
343 #else
344 ret = read(req->fd, ((char*)buf)+n, count-n);
345 #endif
346 if (ret > 0) {
347 n += ret;
348 } else if (ret == 0 && errno == 0) {
349 return n;
350 } else if (ret <= 0 && errno != 0 && errno != EINTR) {
351 return ret;
352 }
353 } while (n != count);
354 return n;
355 }
356
fcgi_make_header(fcgi_header * hdr,fcgi_request_type type,int req_id,int len)357 static inline int fcgi_make_header(fcgi_header *hdr, fcgi_request_type type, int req_id, int len)
358 {
359 int pad = ((len + 7) & ~7) - len;
360
361 hdr->contentLengthB0 = (unsigned char)(len & 0xff);
362 hdr->contentLengthB1 = (unsigned char)((len >> 8) & 0xff);
363 hdr->paddingLength = (unsigned char)pad;
364 hdr->requestIdB0 = (unsigned char)(req_id & 0xff);
365 hdr->requestIdB1 = (unsigned char)((req_id >> 8) & 0xff);
366 hdr->reserved = 0;
367 hdr->type = type;
368 hdr->version = FCGI_VERSION_1;
369 if (pad) {
370 memset(((unsigned char*)hdr) + sizeof(fcgi_header) + len, 0, pad);
371 }
372 return pad;
373 }
374
fcgi_get_params_len(int * result,unsigned char * p,unsigned char * end)375 static inline size_t fcgi_get_params_len( int *result, unsigned char *p, unsigned char *end)
376 {
377 size_t ret = 0;
378
379 if (p < end) {
380 *result = p[0];
381 if (*result < 128) {
382 ret = 1;
383 }
384 else if (p + 3 < end) {
385 *result = ((*result & 0x7f) << 24);
386 *result |= (p[1] << 16);
387 *result |= (p[2] << 8);
388 *result |= p[3];
389 ret = 4;
390 }
391 }
392 if (*result < 0) {
393 ret = 0;
394 }
395 return ret;
396 }
397
fcgi_param_get_eff_len(unsigned char * p,unsigned char * end,uint * eff_len)398 static inline int fcgi_param_get_eff_len( unsigned char *p, unsigned char *end, uint *eff_len)
399 {
400 int ret = 1;
401 int zero_found = 0;
402 *eff_len = 0;
403 for (; p != end; ++p) {
404 if (*p == '\0') {
405 zero_found = 1;
406 }
407 else {
408 if (zero_found) {
409 ret = 0;
410 break;
411 }
412 if (*eff_len < ((uint)-1)) {
413 ++*eff_len;
414 }
415 else {
416 ret = 0;
417 break;
418 }
419 }
420 }
421 return ret;
422 }
423
fcgi_get_params(fcgi_request * req,unsigned char * p,unsigned char * end)424 static int fcgi_get_params(fcgi_request *req, unsigned char *p, unsigned char *end)
425 {
426 char buf[128];
427 char *tmp = buf;
428 size_t buf_size = sizeof(buf);
429 int name_len = 0;
430 int val_len = 0;
431 uint eff_name_len = 0;
432 char *s;
433 int ret = 1;
434 size_t bytes_consumed;
435
436 while (p < end) {
437 bytes_consumed = fcgi_get_params_len(&name_len, p, end);
438 if (!bytes_consumed) {
439 /* Malformated request */
440 ret = 0;
441 break;
442 }
443 p += bytes_consumed;
444 bytes_consumed = fcgi_get_params_len(&val_len, p, end);
445 if (!bytes_consumed) {
446 /* Malformated request */
447 ret = 0;
448 break;
449 }
450 p += bytes_consumed;
451 if (name_len > (INT_MAX - val_len) || /* would the addition overflow? */
452 name_len + val_len > end - p) { /* would we exceed the buffer? */
453 /* Malformated request */
454 ret = 0;
455 break;
456 }
457
458 /*
459 * get the effective length of the name in case it's not a valid string
460 * don't do this on the value because it can be binary data
461 */
462 if (!fcgi_param_get_eff_len(p, p+name_len, &eff_name_len)){
463 /* Malicious request */
464 ret = 0;
465 break;
466 }
467 if (eff_name_len >= buf_size-1) {
468 if (eff_name_len > ((uint)-1)-64) {
469 ret = 0;
470 break;
471 }
472 buf_size = eff_name_len + 64;
473 tmp = (tmp == buf ? emalloc(buf_size): erealloc(tmp, buf_size));
474 if (tmp == NULL) {
475 ret = 0;
476 break;
477 }
478 }
479 memcpy(tmp, p, eff_name_len);
480 tmp[eff_name_len] = 0;
481 s = estrndup((char*)p + name_len, val_len);
482 if (s == NULL) {
483 ret = 0;
484 break;
485 }
486 zend_hash_update(req->env, tmp, eff_name_len+1, &s, sizeof(char*), NULL);
487 p += name_len + val_len;
488 }
489 if (tmp != buf && tmp != NULL) {
490 efree(tmp);
491 }
492 return ret;
493 }
494
fcgi_free_var(char ** s)495 static void fcgi_free_var(char **s)
496 {
497 efree(*s);
498 }
499
fcgi_read_request(fcgi_request * req)500 static int fcgi_read_request(fcgi_request *req)
501 {
502 fcgi_header hdr;
503 int len, padding;
504 unsigned char buf[FCGI_MAX_LENGTH+8];
505
506 req->keep = 0;
507 req->closed = 0;
508 req->in_len = 0;
509 req->out_hdr = NULL;
510 req->out_pos = req->out_buf;
511 ALLOC_HASHTABLE(req->env);
512 zend_hash_init(req->env, 0, NULL, (void (*)(void *)) fcgi_free_var, 0);
513
514 if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
515 hdr.version < FCGI_VERSION_1) {
516 return 0;
517 }
518
519 len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
520 padding = hdr.paddingLength;
521
522 while (hdr.type == FCGI_STDIN && len == 0) {
523 if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
524 hdr.version < FCGI_VERSION_1) {
525 return 0;
526 }
527
528 len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
529 padding = hdr.paddingLength;
530 }
531
532 if (len + padding > FCGI_MAX_LENGTH) {
533 return 0;
534 }
535
536 req->id = (hdr.requestIdB1 << 8) + hdr.requestIdB0;
537
538 if (hdr.type == FCGI_BEGIN_REQUEST && len == sizeof(fcgi_begin_request)) {
539 char *val;
540
541 if (safe_read(req, buf, len+padding) != len+padding) {
542 return 0;
543 }
544
545 req->keep = (((fcgi_begin_request*)buf)->flags & FCGI_KEEP_CONN);
546 switch ((((fcgi_begin_request*)buf)->roleB1 << 8) + ((fcgi_begin_request*)buf)->roleB0) {
547 case FCGI_RESPONDER:
548 val = estrdup("RESPONDER");
549 zend_hash_update(req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
550 break;
551 case FCGI_AUTHORIZER:
552 val = estrdup("AUTHORIZER");
553 zend_hash_update(req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
554 break;
555 case FCGI_FILTER:
556 val = estrdup("FILTER");
557 zend_hash_update(req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
558 break;
559 default:
560 return 0;
561 }
562
563 if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
564 hdr.version < FCGI_VERSION_1) {
565 return 0;
566 }
567
568 len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
569 padding = hdr.paddingLength;
570
571 while (hdr.type == FCGI_PARAMS && len > 0) {
572 if (len + padding > FCGI_MAX_LENGTH) {
573 return 0;
574 }
575
576 if (safe_read(req, buf, len+padding) != len+padding) {
577 req->keep = 0;
578 return 0;
579 }
580
581 if (!fcgi_get_params(req, buf, buf+len)) {
582 req->keep = 0;
583 return 0;
584 }
585
586 if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
587 hdr.version < FCGI_VERSION_1) {
588 req->keep = 0;
589 return 0;
590 }
591 len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
592 padding = hdr.paddingLength;
593 }
594 } else if (hdr.type == FCGI_GET_VALUES) {
595 unsigned char *p = buf + sizeof(fcgi_header);
596 HashPosition pos;
597 char * str_index;
598 uint str_length;
599 ulong num_index;
600 int key_type;
601 zval ** value;
602
603 if (safe_read(req, buf, len+padding) != len+padding) {
604 req->keep = 0;
605 return 0;
606 }
607
608 if (!fcgi_get_params(req, buf, buf+len)) {
609 req->keep = 0;
610 return 0;
611 }
612
613 zend_hash_internal_pointer_reset_ex(req->env, &pos);
614 while ((key_type = zend_hash_get_current_key_ex(req->env, &str_index, &str_length, &num_index, 0, &pos)) != HASH_KEY_NON_EXISTANT) {
615 int zlen;
616 zend_hash_move_forward_ex(req->env, &pos);
617 if (key_type != HASH_KEY_IS_STRING) {
618 continue;
619 }
620 if (zend_hash_find(&fcgi_mgmt_vars, str_index, str_length, (void**) &value) != SUCCESS) {
621 continue;
622 }
623 --str_length;
624 zlen = Z_STRLEN_PP(value);
625 if ((p + 4 + 4 + str_length + zlen) >= (buf + sizeof(buf))) {
626 break;
627 }
628 if (str_length < 0x80) {
629 *p++ = str_length;
630 } else {
631 *p++ = ((str_length >> 24) & 0xff) | 0x80;
632 *p++ = (str_length >> 16) & 0xff;
633 *p++ = (str_length >> 8) & 0xff;
634 *p++ = str_length & 0xff;
635 }
636 if (zlen < 0x80) {
637 *p++ = zlen;
638 } else {
639 *p++ = ((zlen >> 24) & 0xff) | 0x80;
640 *p++ = (zlen >> 16) & 0xff;
641 *p++ = (zlen >> 8) & 0xff;
642 *p++ = zlen & 0xff;
643 }
644 memcpy(p, str_index, str_length);
645 p += str_length;
646 memcpy(p, Z_STRVAL_PP(value), zlen);
647 p += zlen;
648 }
649 len = p - buf - sizeof(fcgi_header);
650 len += fcgi_make_header((fcgi_header*)buf, FCGI_GET_VALUES_RESULT, 0, len);
651 if (safe_write(req, buf, sizeof(fcgi_header)+len) != (int)sizeof(fcgi_header)+len) {
652 req->keep = 0;
653 return 0;
654 }
655 return 0;
656 } else {
657 return 0;
658 }
659
660 return 1;
661 }
662
fcgi_read(fcgi_request * req,char * str,int len)663 int fcgi_read(fcgi_request *req, char *str, int len)
664 {
665 int ret, n, rest;
666 fcgi_header hdr;
667 unsigned char buf[255];
668
669 n = 0;
670 rest = len;
671 while (rest > 0) {
672 if (req->in_len == 0) {
673 if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
674 hdr.version < FCGI_VERSION_1 ||
675 hdr.type != FCGI_STDIN) {
676 req->keep = 0;
677 return 0;
678 }
679 req->in_len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
680 req->in_pad = hdr.paddingLength;
681 if (req->in_len == 0) {
682 return n;
683 }
684 }
685
686 if (req->in_len >= rest) {
687 ret = safe_read(req, str, rest);
688 } else {
689 ret = safe_read(req, str, req->in_len);
690 }
691 if (ret < 0) {
692 req->keep = 0;
693 return ret;
694 } else if (ret > 0) {
695 req->in_len -= ret;
696 rest -= ret;
697 n += ret;
698 str += ret;
699 if (req->in_len == 0) {
700 if (req->in_pad) {
701 if (safe_read(req, buf, req->in_pad) != req->in_pad) {
702 req->keep = 0;
703 return ret;
704 }
705 }
706 } else {
707 return n;
708 }
709 } else {
710 return n;
711 }
712 }
713 return n;
714 }
715
fcgi_close(fcgi_request * req,int force,int destroy)716 void fcgi_close(fcgi_request *req, int force, int destroy)
717 {
718 if (destroy && req->env) {
719 zend_hash_destroy(req->env);
720 FREE_HASHTABLE(req->env);
721 req->env = NULL;
722 }
723
724 #ifdef _WIN32
725 if (is_impersonate && !req->tcp) {
726 RevertToSelf();
727 }
728 #endif
729
730 if ((force || !req->keep) && req->fd >= 0) {
731 #ifdef _WIN32
732 if (!req->tcp) {
733 HANDLE pipe = (HANDLE)_get_osfhandle(req->fd);
734
735 if (!force) {
736 FlushFileBuffers(pipe);
737 }
738 DisconnectNamedPipe(pipe);
739 } else {
740 if (!force) {
741 char buf[8];
742
743 shutdown(req->fd, 1);
744 while (recv(req->fd, buf, sizeof(buf), 0) > 0) {}
745 }
746 closesocket(req->fd);
747 }
748 #else
749 if (!force) {
750 char buf[8];
751
752 shutdown(req->fd, 1);
753 while (recv(req->fd, buf, sizeof(buf), 0) > 0) {}
754 }
755 close(req->fd);
756 #endif
757 req->fd = -1;
758 fpm_request_finished();
759 }
760 }
761
fcgi_accept_request(fcgi_request * req)762 int fcgi_accept_request(fcgi_request *req)
763 {
764 #ifdef _WIN32
765 HANDLE pipe;
766 OVERLAPPED ov;
767 #endif
768
769 while (1) {
770 if (req->fd < 0) {
771 while (1) {
772 if (in_shutdown) {
773 return -1;
774 }
775 #ifdef _WIN32
776 if (!req->tcp) {
777 pipe = (HANDLE)_get_osfhandle(req->listen_socket);
778 FCGI_LOCK(req->listen_socket);
779 ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
780 if (!ConnectNamedPipe(pipe, &ov)) {
781 errno = GetLastError();
782 if (errno == ERROR_IO_PENDING) {
783 while (WaitForSingleObject(ov.hEvent, 1000) == WAIT_TIMEOUT) {
784 if (in_shutdown) {
785 CloseHandle(ov.hEvent);
786 FCGI_UNLOCK(req->listen_socket);
787 return -1;
788 }
789 }
790 } else if (errno != ERROR_PIPE_CONNECTED) {
791 }
792 }
793 CloseHandle(ov.hEvent);
794 req->fd = req->listen_socket;
795 FCGI_UNLOCK(req->listen_socket);
796 } else {
797 SOCKET listen_socket = (SOCKET)_get_osfhandle(req->listen_socket);
798 #else
799 {
800 int listen_socket = req->listen_socket;
801 #endif
802 sa_t sa;
803 socklen_t len = sizeof(sa);
804
805 fpm_request_accepting();
806
807 FCGI_LOCK(req->listen_socket);
808 req->fd = accept(listen_socket, (struct sockaddr *)&sa, &len);
809 FCGI_UNLOCK(req->listen_socket);
810
811 client_sa = sa;
812 if (sa.sa.sa_family == AF_INET && req->fd >= 0 && allowed_clients) {
813 int n = 0;
814 int allowed = 0;
815
816 while (allowed_clients[n] != INADDR_NONE) {
817 if (allowed_clients[n] == sa.sa_inet.sin_addr.s_addr) {
818 allowed = 1;
819 break;
820 }
821 n++;
822 }
823 if (!allowed) {
824 zlog(ZLOG_ERROR, "Connection disallowed: IP address '%s' has been dropped.", inet_ntoa(sa.sa_inet.sin_addr));
825 closesocket(req->fd);
826 req->fd = -1;
827 continue;
828 }
829 }
830 }
831
832 #ifdef _WIN32
833 if (req->fd < 0 && (in_shutdown || errno != EINTR)) {
834 #else
835 if (req->fd < 0 && (in_shutdown || (errno != EINTR && errno != ECONNABORTED))) {
836 #endif
837 return -1;
838 }
839
840 #ifdef _WIN32
841 break;
842 #else
843 if (req->fd >= 0) {
844 #if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
845 struct pollfd fds;
846 int ret;
847
848 fpm_request_reading_headers();
849
850 fds.fd = req->fd;
851 fds.events = POLLIN;
852 fds.revents = 0;
853 do {
854 errno = 0;
855 ret = poll(&fds, 1, 5000);
856 } while (ret < 0 && errno == EINTR);
857 if (ret > 0 && (fds.revents & POLLIN)) {
858 break;
859 }
860 fcgi_close(req, 1, 0);
861 #else
862 fpm_request_reading_headers();
863
864 if (req->fd < FD_SETSIZE) {
865 struct timeval tv = {5,0};
866 fd_set set;
867 int ret;
868
869 FD_ZERO(&set);
870 FD_SET(req->fd, &set);
871 do {
872 errno = 0;
873 ret = select(req->fd + 1, &set, NULL, NULL, &tv) >= 0;
874 } while (ret < 0 && errno == EINTR);
875 if (ret > 0 && FD_ISSET(req->fd, &set)) {
876 break;
877 }
878 fcgi_close(req, 1, 0);
879 } else {
880 zlog(ZLOG_ERROR, "Too many open file descriptors. FD_SETSIZE limit exceeded.");
881 fcgi_close(req, 1, 0);
882 }
883 #endif
884 }
885 #endif
886 }
887 } else if (in_shutdown) {
888 return -1;
889 }
890 if (fcgi_read_request(req)) {
891 #ifdef _WIN32
892 if (is_impersonate && !req->tcp) {
893 pipe = (HANDLE)_get_osfhandle(req->fd);
894 if (!ImpersonateNamedPipeClient(pipe)) {
895 fcgi_close(req, 1, 1);
896 continue;
897 }
898 }
899 #endif
900 return req->fd;
901 } else {
902 fcgi_close(req, 1, 1);
903 }
904 }
905 }
906
907 static inline fcgi_header* open_packet(fcgi_request *req, fcgi_request_type type)
908 {
909 req->out_hdr = (fcgi_header*) req->out_pos;
910 req->out_hdr->type = type;
911 req->out_pos += sizeof(fcgi_header);
912 return req->out_hdr;
913 }
914
915 static inline void close_packet(fcgi_request *req)
916 {
917 if (req->out_hdr) {
918 int len = req->out_pos - ((unsigned char*)req->out_hdr + sizeof(fcgi_header));
919
920 req->out_pos += fcgi_make_header(req->out_hdr, (fcgi_request_type)req->out_hdr->type, req->id, len);
921 req->out_hdr = NULL;
922 }
923 }
924
925 int fcgi_flush(fcgi_request *req, int close)
926 {
927 int len;
928
929 close_packet(req);
930
931 len = req->out_pos - req->out_buf;
932
933 if (close) {
934 fcgi_end_request_rec *rec = (fcgi_end_request_rec*)(req->out_pos);
935
936 fcgi_make_header(&rec->hdr, FCGI_END_REQUEST, req->id, sizeof(fcgi_end_request));
937 rec->body.appStatusB3 = 0;
938 rec->body.appStatusB2 = 0;
939 rec->body.appStatusB1 = 0;
940 rec->body.appStatusB0 = 0;
941 rec->body.protocolStatus = FCGI_REQUEST_COMPLETE;
942 len += sizeof(fcgi_end_request_rec);
943 }
944
945 if (safe_write(req, req->out_buf, len) != len) {
946 req->keep = 0;
947 return 0;
948 }
949
950 req->out_pos = req->out_buf;
951 return 1;
952 }
953
954 ssize_t fcgi_write(fcgi_request *req, fcgi_request_type type, const char *str, int len)
955 {
956 int limit, rest;
957
958 if (len <= 0) {
959 return 0;
960 }
961
962 if (req->out_hdr && req->out_hdr->type != type) {
963 close_packet(req);
964 }
965
966 /* Optimized version */
967 limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
968 if (!req->out_hdr) {
969 limit -= sizeof(fcgi_header);
970 if (limit < 0) limit = 0;
971 }
972
973 if (len < limit) {
974 if (!req->out_hdr) {
975 open_packet(req, type);
976 }
977 memcpy(req->out_pos, str, len);
978 req->out_pos += len;
979 } else if (len - limit < sizeof(req->out_buf) - sizeof(fcgi_header)) {
980 if (!req->out_hdr) {
981 open_packet(req, type);
982 }
983 if (limit > 0) {
984 memcpy(req->out_pos, str, limit);
985 req->out_pos += limit;
986 }
987 if (!fcgi_flush(req, 0)) {
988 return -1;
989 }
990 if (len > limit) {
991 open_packet(req, type);
992 memcpy(req->out_pos, str + limit, len - limit);
993 req->out_pos += len - limit;
994 }
995 } else {
996 int pos = 0;
997 int pad;
998
999 close_packet(req);
1000 while ((len - pos) > 0xffff) {
1001 open_packet(req, type);
1002 fcgi_make_header(req->out_hdr, type, req->id, 0xfff8);
1003 req->out_hdr = NULL;
1004 if (!fcgi_flush(req, 0)) {
1005 return -1;
1006 }
1007 if (safe_write(req, str + pos, 0xfff8) != 0xfff8) {
1008 req->keep = 0;
1009 return -1;
1010 }
1011 pos += 0xfff8;
1012 }
1013
1014 pad = (((len - pos) + 7) & ~7) - (len - pos);
1015 rest = pad ? 8 - pad : 0;
1016
1017 open_packet(req, type);
1018 fcgi_make_header(req->out_hdr, type, req->id, (len - pos) - rest);
1019 req->out_hdr = NULL;
1020 if (!fcgi_flush(req, 0)) {
1021 return -1;
1022 }
1023 if (safe_write(req, str + pos, (len - pos) - rest) != (len - pos) - rest) {
1024 req->keep = 0;
1025 return -1;
1026 }
1027 if (pad) {
1028 open_packet(req, type);
1029 memcpy(req->out_pos, str + len - rest, rest);
1030 req->out_pos += rest;
1031 }
1032 }
1033
1034 return len;
1035 }
1036
1037 int fcgi_finish_request(fcgi_request *req, int force_close)
1038 {
1039 int ret = 1;
1040
1041 if (req->fd >= 0) {
1042 if (!req->closed) {
1043 ret = fcgi_flush(req, 1);
1044 req->closed = 1;
1045 }
1046 fcgi_close(req, force_close, 1);
1047 }
1048 return ret;
1049 }
1050
1051 char* fcgi_getenv(fcgi_request *req, const char* var, int var_len)
1052 {
1053 char **val;
1054
1055 if (!req) return NULL;
1056
1057 if (zend_hash_find(req->env, (char*)var, var_len+1, (void**)&val) == SUCCESS) {
1058 return *val;
1059 }
1060 return NULL;
1061 }
1062
1063 char* fcgi_putenv(fcgi_request *req, char* var, int var_len, char* val)
1064 {
1065 if (var && req) {
1066 if (val == NULL) {
1067 zend_hash_del(req->env, var, var_len+1);
1068 } else {
1069 char **ret;
1070
1071 val = estrdup(val);
1072 if (zend_hash_update(req->env, var, var_len+1, &val, sizeof(char*), (void**)&ret) == SUCCESS) {
1073 return *ret;
1074 }
1075 }
1076 }
1077 return NULL;
1078 }
1079
1080 void fcgi_set_mgmt_var(const char * name, size_t name_len, const char * value, size_t value_len)
1081 {
1082 zval * zvalue;
1083 zvalue = pemalloc(sizeof(*zvalue), 1);
1084 Z_TYPE_P(zvalue) = IS_STRING;
1085 Z_STRVAL_P(zvalue) = pestrndup(value, value_len, 1);
1086 Z_STRLEN_P(zvalue) = value_len;
1087 zend_hash_add(&fcgi_mgmt_vars, name, name_len + 1, &zvalue, sizeof(zvalue), NULL);
1088 }
1089
1090 void fcgi_free_mgmt_var_cb(void * ptr)
1091 {
1092 zval ** var = (zval **)ptr;
1093 pefree(Z_STRVAL_PP(var), 1);
1094 pefree(*var, 1);
1095 }
1096
1097 char *fcgi_get_last_client_ip() /* {{{ */
1098 {
1099 if (client_sa.sa.sa_family == AF_UNIX) {
1100 return NULL;
1101 }
1102 return inet_ntoa(client_sa.sa_inet.sin_addr);
1103 }
1104 /* }}} */
1105 /*
1106 * Local variables:
1107 * tab-width: 4
1108 * c-basic-offset: 4
1109 * End:
1110 * vim600: sw=4 ts=4 fdm=marker
1111 * vim<600: sw=4 ts=4
1112 */
1113