1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2013 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, val_len;
430 uint eff_name_len;
431 char *s;
432 int ret = 1;
433 size_t bytes_consumed;
434
435 while (p < end) {
436 bytes_consumed = fcgi_get_params_len(&name_len, p, end);
437 if (!bytes_consumed) {
438 /* Malformated request */
439 ret = 0;
440 break;
441 }
442 p += bytes_consumed;
443 bytes_consumed = fcgi_get_params_len(&val_len, p, end);
444 if (!bytes_consumed) {
445 /* Malformated request */
446 ret = 0;
447 break;
448 }
449 p += bytes_consumed;
450 if (name_len > (INT_MAX - val_len) || /* would the addition overflow? */
451 name_len + val_len > end - p) { /* would we exceed the buffer? */
452 /* Malformated request */
453 ret = 0;
454 break;
455 }
456
457 /*
458 * get the effective length of the name in case it's not a valid string
459 * don't do this on the value because it can be binary data
460 */
461 if (!fcgi_param_get_eff_len(p, p+name_len, &eff_name_len)){
462 /* Malicious request */
463 ret = 0;
464 break;
465 }
466 if (eff_name_len >= buf_size-1) {
467 if (eff_name_len > ((uint)-1)-64) {
468 ret = 0;
469 break;
470 }
471 buf_size = eff_name_len + 64;
472 tmp = (tmp == buf ? emalloc(buf_size): erealloc(tmp, buf_size));
473 if (tmp == NULL) {
474 ret = 0;
475 break;
476 }
477 }
478 memcpy(tmp, p, eff_name_len);
479 tmp[eff_name_len] = 0;
480 s = estrndup((char*)p + name_len, val_len);
481 if (s == NULL) {
482 ret = 0;
483 break;
484 }
485 zend_hash_update(req->env, tmp, eff_name_len+1, &s, sizeof(char*), NULL);
486 p += name_len + val_len;
487 }
488 if (tmp != buf && tmp != NULL) {
489 efree(tmp);
490 }
491 return ret;
492 }
493
fcgi_free_var(char ** s)494 static void fcgi_free_var(char **s)
495 {
496 efree(*s);
497 }
498
fcgi_read_request(fcgi_request * req)499 static int fcgi_read_request(fcgi_request *req)
500 {
501 fcgi_header hdr;
502 int len, padding;
503 unsigned char buf[FCGI_MAX_LENGTH+8];
504
505 req->keep = 0;
506 req->closed = 0;
507 req->in_len = 0;
508 req->out_hdr = NULL;
509 req->out_pos = req->out_buf;
510 ALLOC_HASHTABLE(req->env);
511 zend_hash_init(req->env, 0, NULL, (void (*)(void *)) fcgi_free_var, 0);
512
513 if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
514 hdr.version < FCGI_VERSION_1) {
515 return 0;
516 }
517
518 len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
519 padding = hdr.paddingLength;
520
521 while (hdr.type == FCGI_STDIN && len == 0) {
522 if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
523 hdr.version < FCGI_VERSION_1) {
524 return 0;
525 }
526
527 len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
528 padding = hdr.paddingLength;
529 }
530
531 if (len + padding > FCGI_MAX_LENGTH) {
532 return 0;
533 }
534
535 req->id = (hdr.requestIdB1 << 8) + hdr.requestIdB0;
536
537 if (hdr.type == FCGI_BEGIN_REQUEST && len == sizeof(fcgi_begin_request)) {
538 char *val;
539
540 if (safe_read(req, buf, len+padding) != len+padding) {
541 return 0;
542 }
543
544 req->keep = (((fcgi_begin_request*)buf)->flags & FCGI_KEEP_CONN);
545 switch ((((fcgi_begin_request*)buf)->roleB1 << 8) + ((fcgi_begin_request*)buf)->roleB0) {
546 case FCGI_RESPONDER:
547 val = estrdup("RESPONDER");
548 zend_hash_update(req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
549 break;
550 case FCGI_AUTHORIZER:
551 val = estrdup("AUTHORIZER");
552 zend_hash_update(req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
553 break;
554 case FCGI_FILTER:
555 val = estrdup("FILTER");
556 zend_hash_update(req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
557 break;
558 default:
559 return 0;
560 }
561
562 if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
563 hdr.version < FCGI_VERSION_1) {
564 return 0;
565 }
566
567 len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
568 padding = hdr.paddingLength;
569
570 while (hdr.type == FCGI_PARAMS && len > 0) {
571 if (len + padding > FCGI_MAX_LENGTH) {
572 return 0;
573 }
574
575 if (safe_read(req, buf, len+padding) != len+padding) {
576 req->keep = 0;
577 return 0;
578 }
579
580 if (!fcgi_get_params(req, buf, buf+len)) {
581 req->keep = 0;
582 return 0;
583 }
584
585 if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
586 hdr.version < FCGI_VERSION_1) {
587 req->keep = 0;
588 return 0;
589 }
590 len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
591 padding = hdr.paddingLength;
592 }
593 } else if (hdr.type == FCGI_GET_VALUES) {
594 unsigned char *p = buf + sizeof(fcgi_header);
595 HashPosition pos;
596 char * str_index;
597 uint str_length;
598 ulong num_index;
599 int key_type;
600 zval ** value;
601
602 if (safe_read(req, buf, len+padding) != len+padding) {
603 req->keep = 0;
604 return 0;
605 }
606
607 if (!fcgi_get_params(req, buf, buf+len)) {
608 req->keep = 0;
609 return 0;
610 }
611
612 zend_hash_internal_pointer_reset_ex(req->env, &pos);
613 while ((key_type = zend_hash_get_current_key_ex(req->env, &str_index, &str_length, &num_index, 0, &pos)) != HASH_KEY_NON_EXISTANT) {
614 int zlen;
615 zend_hash_move_forward_ex(req->env, &pos);
616 if (key_type != HASH_KEY_IS_STRING) {
617 continue;
618 }
619 if (zend_hash_find(&fcgi_mgmt_vars, str_index, str_length, (void**) &value) != SUCCESS) {
620 continue;
621 }
622 --str_length;
623 zlen = Z_STRLEN_PP(value);
624 if ((p + 4 + 4 + str_length + zlen) >= (buf + sizeof(buf))) {
625 break;
626 }
627 if (str_length < 0x80) {
628 *p++ = str_length;
629 } else {
630 *p++ = ((str_length >> 24) & 0xff) | 0x80;
631 *p++ = (str_length >> 16) & 0xff;
632 *p++ = (str_length >> 8) & 0xff;
633 *p++ = str_length & 0xff;
634 }
635 if (zlen < 0x80) {
636 *p++ = zlen;
637 } else {
638 *p++ = ((zlen >> 24) & 0xff) | 0x80;
639 *p++ = (zlen >> 16) & 0xff;
640 *p++ = (zlen >> 8) & 0xff;
641 *p++ = zlen & 0xff;
642 }
643 memcpy(p, str_index, str_length);
644 p += str_length;
645 memcpy(p, Z_STRVAL_PP(value), zlen);
646 p += zlen;
647 }
648 len = p - buf - sizeof(fcgi_header);
649 len += fcgi_make_header((fcgi_header*)buf, FCGI_GET_VALUES_RESULT, 0, len);
650 if (safe_write(req, buf, sizeof(fcgi_header)+len) != (int)sizeof(fcgi_header)+len) {
651 req->keep = 0;
652 return 0;
653 }
654 return 0;
655 } else {
656 return 0;
657 }
658
659 return 1;
660 }
661
fcgi_read(fcgi_request * req,char * str,int len)662 int fcgi_read(fcgi_request *req, char *str, int len)
663 {
664 int ret, n, rest;
665 fcgi_header hdr;
666 unsigned char buf[255];
667
668 n = 0;
669 rest = len;
670 while (rest > 0) {
671 if (req->in_len == 0) {
672 if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
673 hdr.version < FCGI_VERSION_1 ||
674 hdr.type != FCGI_STDIN) {
675 req->keep = 0;
676 return 0;
677 }
678 req->in_len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
679 req->in_pad = hdr.paddingLength;
680 if (req->in_len == 0) {
681 return n;
682 }
683 }
684
685 if (req->in_len >= rest) {
686 ret = safe_read(req, str, rest);
687 } else {
688 ret = safe_read(req, str, req->in_len);
689 }
690 if (ret < 0) {
691 req->keep = 0;
692 return ret;
693 } else if (ret > 0) {
694 req->in_len -= ret;
695 rest -= ret;
696 n += ret;
697 str += ret;
698 if (req->in_len == 0) {
699 if (req->in_pad) {
700 if (safe_read(req, buf, req->in_pad) != req->in_pad) {
701 req->keep = 0;
702 return ret;
703 }
704 }
705 } else {
706 return n;
707 }
708 } else {
709 return n;
710 }
711 }
712 return n;
713 }
714
fcgi_close(fcgi_request * req,int force,int destroy)715 void fcgi_close(fcgi_request *req, int force, int destroy)
716 {
717 if (destroy && req->env) {
718 zend_hash_destroy(req->env);
719 FREE_HASHTABLE(req->env);
720 req->env = NULL;
721 }
722
723 #ifdef _WIN32
724 if (is_impersonate && !req->tcp) {
725 RevertToSelf();
726 }
727 #endif
728
729 if ((force || !req->keep) && req->fd >= 0) {
730 #ifdef _WIN32
731 if (!req->tcp) {
732 HANDLE pipe = (HANDLE)_get_osfhandle(req->fd);
733
734 if (!force) {
735 FlushFileBuffers(pipe);
736 }
737 DisconnectNamedPipe(pipe);
738 } else {
739 if (!force) {
740 char buf[8];
741
742 shutdown(req->fd, 1);
743 while (recv(req->fd, buf, sizeof(buf), 0) > 0) {}
744 }
745 closesocket(req->fd);
746 }
747 #else
748 if (!force) {
749 char buf[8];
750
751 shutdown(req->fd, 1);
752 while (recv(req->fd, buf, sizeof(buf), 0) > 0) {}
753 }
754 close(req->fd);
755 #endif
756 req->fd = -1;
757 fpm_request_finished();
758 }
759 }
760
fcgi_accept_request(fcgi_request * req)761 int fcgi_accept_request(fcgi_request *req)
762 {
763 #ifdef _WIN32
764 HANDLE pipe;
765 OVERLAPPED ov;
766 #endif
767
768 while (1) {
769 if (req->fd < 0) {
770 while (1) {
771 if (in_shutdown) {
772 return -1;
773 }
774 #ifdef _WIN32
775 if (!req->tcp) {
776 pipe = (HANDLE)_get_osfhandle(req->listen_socket);
777 FCGI_LOCK(req->listen_socket);
778 ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
779 if (!ConnectNamedPipe(pipe, &ov)) {
780 errno = GetLastError();
781 if (errno == ERROR_IO_PENDING) {
782 while (WaitForSingleObject(ov.hEvent, 1000) == WAIT_TIMEOUT) {
783 if (in_shutdown) {
784 CloseHandle(ov.hEvent);
785 FCGI_UNLOCK(req->listen_socket);
786 return -1;
787 }
788 }
789 } else if (errno != ERROR_PIPE_CONNECTED) {
790 }
791 }
792 CloseHandle(ov.hEvent);
793 req->fd = req->listen_socket;
794 FCGI_UNLOCK(req->listen_socket);
795 } else {
796 SOCKET listen_socket = (SOCKET)_get_osfhandle(req->listen_socket);
797 #else
798 {
799 int listen_socket = req->listen_socket;
800 #endif
801 sa_t sa;
802 socklen_t len = sizeof(sa);
803
804 fpm_request_accepting();
805
806 FCGI_LOCK(req->listen_socket);
807 req->fd = accept(listen_socket, (struct sockaddr *)&sa, &len);
808 FCGI_UNLOCK(req->listen_socket);
809
810 client_sa = sa;
811 if (sa.sa.sa_family == AF_INET && req->fd >= 0 && allowed_clients) {
812 int n = 0;
813 int allowed = 0;
814
815 while (allowed_clients[n] != INADDR_NONE) {
816 if (allowed_clients[n] == sa.sa_inet.sin_addr.s_addr) {
817 allowed = 1;
818 break;
819 }
820 n++;
821 }
822 if (!allowed) {
823 zlog(ZLOG_ERROR, "Connection disallowed: IP address '%s' has been dropped.", inet_ntoa(sa.sa_inet.sin_addr));
824 closesocket(req->fd);
825 req->fd = -1;
826 continue;
827 }
828 }
829 }
830
831 #ifdef _WIN32
832 if (req->fd < 0 && (in_shutdown || errno != EINTR)) {
833 #else
834 if (req->fd < 0 && (in_shutdown || (errno != EINTR && errno != ECONNABORTED))) {
835 #endif
836 return -1;
837 }
838
839 #ifdef _WIN32
840 break;
841 #else
842 if (req->fd >= 0) {
843 #if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
844 struct pollfd fds;
845 int ret;
846
847 fpm_request_reading_headers();
848
849 fds.fd = req->fd;
850 fds.events = POLLIN;
851 fds.revents = 0;
852 do {
853 errno = 0;
854 ret = poll(&fds, 1, 5000);
855 } while (ret < 0 && errno == EINTR);
856 if (ret > 0 && (fds.revents & POLLIN)) {
857 break;
858 }
859 fcgi_close(req, 1, 0);
860 #else
861 fpm_request_reading_headers();
862
863 if (req->fd < FD_SETSIZE) {
864 struct timeval tv = {5,0};
865 fd_set set;
866 int ret;
867
868 FD_ZERO(&set);
869 FD_SET(req->fd, &set);
870 do {
871 errno = 0;
872 ret = select(req->fd + 1, &set, NULL, NULL, &tv) >= 0;
873 } while (ret < 0 && errno == EINTR);
874 if (ret > 0 && FD_ISSET(req->fd, &set)) {
875 break;
876 }
877 fcgi_close(req, 1, 0);
878 } else {
879 zlog(ZLOG_ERROR, "Too many open file descriptors. FD_SETSIZE limit exceeded.");
880 fcgi_close(req, 1, 0);
881 }
882 #endif
883 }
884 #endif
885 }
886 } else if (in_shutdown) {
887 return -1;
888 }
889 if (fcgi_read_request(req)) {
890 #ifdef _WIN32
891 if (is_impersonate && !req->tcp) {
892 pipe = (HANDLE)_get_osfhandle(req->fd);
893 if (!ImpersonateNamedPipeClient(pipe)) {
894 fcgi_close(req, 1, 1);
895 continue;
896 }
897 }
898 #endif
899 return req->fd;
900 } else {
901 fcgi_close(req, 1, 1);
902 }
903 }
904 }
905
906 static inline fcgi_header* open_packet(fcgi_request *req, fcgi_request_type type)
907 {
908 req->out_hdr = (fcgi_header*) req->out_pos;
909 req->out_hdr->type = type;
910 req->out_pos += sizeof(fcgi_header);
911 return req->out_hdr;
912 }
913
914 static inline void close_packet(fcgi_request *req)
915 {
916 if (req->out_hdr) {
917 int len = req->out_pos - ((unsigned char*)req->out_hdr + sizeof(fcgi_header));
918
919 req->out_pos += fcgi_make_header(req->out_hdr, (fcgi_request_type)req->out_hdr->type, req->id, len);
920 req->out_hdr = NULL;
921 }
922 }
923
924 int fcgi_flush(fcgi_request *req, int close)
925 {
926 int len;
927
928 close_packet(req);
929
930 len = req->out_pos - req->out_buf;
931
932 if (close) {
933 fcgi_end_request_rec *rec = (fcgi_end_request_rec*)(req->out_pos);
934
935 fcgi_make_header(&rec->hdr, FCGI_END_REQUEST, req->id, sizeof(fcgi_end_request));
936 rec->body.appStatusB3 = 0;
937 rec->body.appStatusB2 = 0;
938 rec->body.appStatusB1 = 0;
939 rec->body.appStatusB0 = 0;
940 rec->body.protocolStatus = FCGI_REQUEST_COMPLETE;
941 len += sizeof(fcgi_end_request_rec);
942 }
943
944 if (safe_write(req, req->out_buf, len) != len) {
945 req->keep = 0;
946 return 0;
947 }
948
949 req->out_pos = req->out_buf;
950 return 1;
951 }
952
953 ssize_t fcgi_write(fcgi_request *req, fcgi_request_type type, const char *str, int len)
954 {
955 int limit, rest;
956
957 if (len <= 0) {
958 return 0;
959 }
960
961 if (req->out_hdr && req->out_hdr->type != type) {
962 close_packet(req);
963 }
964
965 /* Optimized version */
966 limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
967 if (!req->out_hdr) {
968 limit -= sizeof(fcgi_header);
969 if (limit < 0) limit = 0;
970 }
971
972 if (len < limit) {
973 if (!req->out_hdr) {
974 open_packet(req, type);
975 }
976 memcpy(req->out_pos, str, len);
977 req->out_pos += len;
978 } else if (len - limit < sizeof(req->out_buf) - sizeof(fcgi_header)) {
979 if (!req->out_hdr) {
980 open_packet(req, type);
981 }
982 if (limit > 0) {
983 memcpy(req->out_pos, str, limit);
984 req->out_pos += limit;
985 }
986 if (!fcgi_flush(req, 0)) {
987 return -1;
988 }
989 if (len > limit) {
990 open_packet(req, type);
991 memcpy(req->out_pos, str + limit, len - limit);
992 req->out_pos += len - limit;
993 }
994 } else {
995 int pos = 0;
996 int pad;
997
998 close_packet(req);
999 while ((len - pos) > 0xffff) {
1000 open_packet(req, type);
1001 fcgi_make_header(req->out_hdr, type, req->id, 0xfff8);
1002 req->out_hdr = NULL;
1003 if (!fcgi_flush(req, 0)) {
1004 return -1;
1005 }
1006 if (safe_write(req, str + pos, 0xfff8) != 0xfff8) {
1007 req->keep = 0;
1008 return -1;
1009 }
1010 pos += 0xfff8;
1011 }
1012
1013 pad = (((len - pos) + 7) & ~7) - (len - pos);
1014 rest = pad ? 8 - pad : 0;
1015
1016 open_packet(req, type);
1017 fcgi_make_header(req->out_hdr, type, req->id, (len - pos) - rest);
1018 req->out_hdr = NULL;
1019 if (!fcgi_flush(req, 0)) {
1020 return -1;
1021 }
1022 if (safe_write(req, str + pos, (len - pos) - rest) != (len - pos) - rest) {
1023 req->keep = 0;
1024 return -1;
1025 }
1026 if (pad) {
1027 open_packet(req, type);
1028 memcpy(req->out_pos, str + len - rest, rest);
1029 req->out_pos += rest;
1030 }
1031 }
1032
1033 return len;
1034 }
1035
1036 int fcgi_finish_request(fcgi_request *req, int force_close)
1037 {
1038 int ret = 1;
1039
1040 if (req->fd >= 0) {
1041 if (!req->closed) {
1042 ret = fcgi_flush(req, 1);
1043 req->closed = 1;
1044 }
1045 fcgi_close(req, force_close, 1);
1046 }
1047 return ret;
1048 }
1049
1050 char* fcgi_getenv(fcgi_request *req, const char* var, int var_len)
1051 {
1052 char **val;
1053
1054 if (!req) return NULL;
1055
1056 if (zend_hash_find(req->env, (char*)var, var_len+1, (void**)&val) == SUCCESS) {
1057 return *val;
1058 }
1059 return NULL;
1060 }
1061
1062 char* fcgi_putenv(fcgi_request *req, char* var, int var_len, char* val)
1063 {
1064 if (var && req) {
1065 if (val == NULL) {
1066 zend_hash_del(req->env, var, var_len+1);
1067 } else {
1068 char **ret;
1069
1070 val = estrdup(val);
1071 if (zend_hash_update(req->env, var, var_len+1, &val, sizeof(char*), (void**)&ret) == SUCCESS) {
1072 return *ret;
1073 }
1074 }
1075 }
1076 return NULL;
1077 }
1078
1079 void fcgi_set_mgmt_var(const char * name, size_t name_len, const char * value, size_t value_len)
1080 {
1081 zval * zvalue;
1082 zvalue = pemalloc(sizeof(*zvalue), 1);
1083 Z_TYPE_P(zvalue) = IS_STRING;
1084 Z_STRVAL_P(zvalue) = pestrndup(value, value_len, 1);
1085 Z_STRLEN_P(zvalue) = value_len;
1086 zend_hash_add(&fcgi_mgmt_vars, name, name_len + 1, &zvalue, sizeof(zvalue), NULL);
1087 }
1088
1089 void fcgi_free_mgmt_var_cb(void * ptr)
1090 {
1091 zval ** var = (zval **)ptr;
1092 pefree(Z_STRVAL_PP(var), 1);
1093 pefree(*var, 1);
1094 }
1095
1096 char *fcgi_get_last_client_ip() /* {{{ */
1097 {
1098 if (client_sa.sa.sa_family == AF_UNIX) {
1099 return NULL;
1100 }
1101 return inet_ntoa(client_sa.sa_inet.sin_addr);
1102 }
1103 /* }}} */
1104 /*
1105 * Local variables:
1106 * tab-width: 4
1107 * c-basic-offset: 4
1108 * End:
1109 * vim600: sw=4 ts=4 fdm=marker
1110 * vim<600: sw=4 ts=4
1111 */
1112