Return to fastcgi.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / sapi / cgi |
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
1.1.1.3 ! misho 5: | Copyright (c) 1997-2013 The PHP Group |
1.1 misho 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:
1.1.1.2 misho 19: /* $Id$ */
1.1 misho 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:
30: #ifdef _WIN32
31:
32: #include <windows.h>
33:
34: typedef unsigned int in_addr_t;
35:
36: struct sockaddr_un {
37: short sun_family;
38: char sun_path[MAXPATHLEN];
39: };
40:
41: static HANDLE fcgi_accept_mutex = INVALID_HANDLE_VALUE;
42: static int is_impersonate = 0;
43:
44: #define FCGI_LOCK(fd) \
45: if (fcgi_accept_mutex != INVALID_HANDLE_VALUE) { \
46: DWORD ret; \
47: while ((ret = WaitForSingleObject(fcgi_accept_mutex, 1000)) == WAIT_TIMEOUT) { \
48: if (in_shutdown) return -1; \
49: } \
50: if (ret == WAIT_FAILED) { \
51: fprintf(stderr, "WaitForSingleObject() failed\n"); \
52: return -1; \
53: } \
54: }
55:
56: #define FCGI_UNLOCK(fd) \
57: if (fcgi_accept_mutex != INVALID_HANDLE_VALUE) { \
58: ReleaseMutex(fcgi_accept_mutex); \
59: }
60:
61: #else
62:
63: # include <sys/types.h>
64: # include <sys/stat.h>
65: # include <unistd.h>
66: # include <fcntl.h>
67: # include <sys/socket.h>
68: # include <sys/un.h>
69: # include <netinet/in.h>
1.1.1.2 misho 70: # include <netinet/tcp.h>
1.1 misho 71: # include <arpa/inet.h>
72: # include <netdb.h>
73: # include <signal.h>
74:
75: # define closesocket(s) close(s)
76:
77: # if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
78: # include <sys/poll.h>
79: # endif
80: # if defined(HAVE_SYS_SELECT_H)
81: # include <sys/select.h>
82: # endif
83:
84: #ifndef INADDR_NONE
85: #define INADDR_NONE ((unsigned long) -1)
86: #endif
87:
88: # ifndef HAVE_SOCKLEN_T
89: typedef unsigned int socklen_t;
90: # endif
91:
92: # ifdef USE_LOCKING
93: # define FCGI_LOCK(fd) \
94: do { \
95: struct flock lock; \
96: lock.l_type = F_WRLCK; \
97: lock.l_start = 0; \
98: lock.l_whence = SEEK_SET; \
99: lock.l_len = 0; \
100: if (fcntl(fd, F_SETLKW, &lock) != -1) { \
101: break; \
102: } else if (errno != EINTR || in_shutdown) { \
103: return -1; \
104: } \
105: } while (1)
106:
107: # define FCGI_UNLOCK(fd) \
108: do { \
109: int orig_errno = errno; \
110: while (1) { \
111: struct flock lock; \
112: lock.l_type = F_UNLCK; \
113: lock.l_start = 0; \
114: lock.l_whence = SEEK_SET; \
115: lock.l_len = 0; \
116: if (fcntl(fd, F_SETLK, &lock) != -1) { \
117: break; \
118: } else if (errno != EINTR) { \
119: return -1; \
120: } \
121: } \
122: errno = orig_errno; \
123: } while (0)
124: # else
125: # define FCGI_LOCK(fd)
126: # define FCGI_UNLOCK(fd)
127: # endif
128:
129: #endif
130:
131: typedef union _sa_t {
132: struct sockaddr sa;
133: struct sockaddr_un sa_unix;
134: struct sockaddr_in sa_inet;
135: } sa_t;
136:
137: static HashTable fcgi_mgmt_vars;
138:
139: static int is_initialized = 0;
140: static int is_fastcgi = 0;
141: static int in_shutdown = 0;
142: static in_addr_t *allowed_clients = NULL;
143:
1.1.1.2 misho 144: /* hash table */
145:
146: #define FCGI_HASH_TABLE_SIZE 128
147: #define FCGI_HASH_TABLE_MASK (FCGI_HASH_TABLE_SIZE - 1)
148: #define FCGI_HASH_SEG_SIZE 4096
149:
150: typedef struct _fcgi_hash_bucket {
151: unsigned int hash_value;
152: unsigned int var_len;
153: char *var;
154: unsigned int val_len;
155: char *val;
156: struct _fcgi_hash_bucket *next;
157: struct _fcgi_hash_bucket *list_next;
158: } fcgi_hash_bucket;
159:
160: typedef struct _fcgi_hash_buckets {
161: unsigned int idx;
162: struct _fcgi_hash_buckets *next;
163: struct _fcgi_hash_bucket data[FCGI_HASH_TABLE_SIZE];
164: } fcgi_hash_buckets;
165:
166: typedef struct _fcgi_data_seg {
167: char *pos;
168: char *end;
169: struct _fcgi_data_seg *next;
170: char data[1];
171: } fcgi_data_seg;
172:
173: typedef struct _fcgi_hash {
174: fcgi_hash_bucket *hash_table[FCGI_HASH_TABLE_SIZE];
175: fcgi_hash_bucket *list;
176: fcgi_hash_buckets *buckets;
177: fcgi_data_seg *data;
178: } fcgi_hash;
179:
180: static void fcgi_hash_init(fcgi_hash *h)
181: {
182: memset(h->hash_table, 0, sizeof(h->hash_table));
183: h->list = NULL;
184: h->buckets = (fcgi_hash_buckets*)malloc(sizeof(fcgi_hash_buckets));
185: h->buckets->idx = 0;
186: h->buckets->next = NULL;
187: h->data = (fcgi_data_seg*)malloc(sizeof(fcgi_data_seg) - 1 + FCGI_HASH_SEG_SIZE);
188: h->data->pos = h->data->data;
189: h->data->end = h->data->pos + FCGI_HASH_SEG_SIZE;
190: h->data->next = NULL;
191: }
192:
193: static void fcgi_hash_destroy(fcgi_hash *h)
194: {
195: fcgi_hash_buckets *b;
196: fcgi_data_seg *p;
197:
198: b = h->buckets;
199: while (b) {
200: fcgi_hash_buckets *q = b;
201: b = b->next;
202: free(q);
203: }
204: p = h->data;
205: while (p) {
206: fcgi_data_seg *q = p;
207: p = p->next;
208: free(q);
209: }
210: }
211:
212: static void fcgi_hash_clean(fcgi_hash *h)
213: {
214: memset(h->hash_table, 0, sizeof(h->hash_table));
215: h->list = NULL;
216: /* delete all bucket blocks except the first one */
217: while (h->buckets->next) {
218: fcgi_hash_buckets *q = h->buckets;
219:
220: h->buckets = h->buckets->next;
221: free(q);
222: }
223: h->buckets->idx = 0;
224: /* delete all data segments except the first one */
225: while (h->data->next) {
226: fcgi_data_seg *q = h->data;
227:
228: h->data = h->data->next;
229: free(q);
230: }
231: h->data->pos = h->data->data;
232: }
233:
234: static inline char* fcgi_hash_strndup(fcgi_hash *h, char *str, unsigned int str_len)
235: {
236: char *ret;
237:
238: if (UNEXPECTED(h->data->pos + str_len + 1 >= h->data->end)) {
239: unsigned int seg_size = (str_len + 1 > FCGI_HASH_SEG_SIZE) ? str_len + 1 : FCGI_HASH_SEG_SIZE;
240: fcgi_data_seg *p = (fcgi_data_seg*)malloc(sizeof(fcgi_data_seg) - 1 + seg_size);
241:
242: p->pos = p->data;
243: p->end = p->pos + seg_size;
244: p->next = h->data;
245: h->data = p;
246: }
247: ret = h->data->pos;
248: memcpy(ret, str, str_len);
249: ret[str_len] = 0;
250: h->data->pos += str_len + 1;
251: return ret;
252: }
253:
254: static char* fcgi_hash_set(fcgi_hash *h, unsigned int hash_value, char *var, unsigned int var_len, char *val, unsigned int val_len)
255: {
256: unsigned int idx = hash_value & FCGI_HASH_TABLE_MASK;
257: fcgi_hash_bucket *p = h->hash_table[idx];
258:
259: while (UNEXPECTED(p != NULL)) {
260: if (UNEXPECTED(p->hash_value == hash_value) &&
261: p->var_len == var_len &&
262: memcmp(p->var, var, var_len) == 0) {
263:
264: p->val_len = val_len;
265: p->val = fcgi_hash_strndup(h, val, val_len);
266: return p->val;
267: }
268: p = p->next;
269: }
270:
271: if (UNEXPECTED(h->buckets->idx >= FCGI_HASH_TABLE_SIZE)) {
272: fcgi_hash_buckets *b = (fcgi_hash_buckets*)malloc(sizeof(fcgi_hash_buckets));
273: b->idx = 0;
274: b->next = h->buckets;
275: h->buckets = b;
276: }
277: p = h->buckets->data + h->buckets->idx;
278: h->buckets->idx++;
279: p->next = h->hash_table[idx];
280: h->hash_table[idx] = p;
281: p->list_next = h->list;
282: h->list = p;
283: p->hash_value = hash_value;
284: p->var_len = var_len;
285: p->var = fcgi_hash_strndup(h, var, var_len);
286: p->val_len = val_len;
287: p->val = fcgi_hash_strndup(h, val, val_len);
288: return p->val;
289: }
290:
291: static void fcgi_hash_del(fcgi_hash *h, unsigned int hash_value, char *var, unsigned int var_len)
292: {
293: unsigned int idx = hash_value & FCGI_HASH_TABLE_MASK;
294: fcgi_hash_bucket **p = &h->hash_table[idx];
295:
296: while (*p != NULL) {
297: if ((*p)->hash_value == hash_value &&
298: (*p)->var_len == var_len &&
299: memcmp((*p)->var, var, var_len) == 0) {
300:
301: (*p)->val = NULL; /* NULL value means deleted */
302: (*p)->val_len = 0;
303: *p = (*p)->next;
304: return;
305: }
306: p = &(*p)->next;
307: }
308: }
309:
310: static char *fcgi_hash_get(fcgi_hash *h, unsigned int hash_value, char *var, unsigned int var_len, unsigned int *val_len)
311: {
312: unsigned int idx = hash_value & FCGI_HASH_TABLE_MASK;
313: fcgi_hash_bucket *p = h->hash_table[idx];
314:
315: while (p != NULL) {
316: if (p->hash_value == hash_value &&
317: p->var_len == var_len &&
318: memcmp(p->var, var, var_len) == 0) {
319: *val_len = p->val_len;
320: return p->val;
321: }
322: p = p->next;
323: }
324: return NULL;
325: }
326:
327: static void fcgi_hash_apply(fcgi_hash *h, fcgi_apply_func func, void *arg TSRMLS_DC)
328: {
329: fcgi_hash_bucket *p = h->list;
330:
331: while (p) {
332: if (EXPECTED(p->val != NULL)) {
333: func(p->var, p->var_len, p->val, p->val_len, arg TSRMLS_CC);
334: }
335: p = p->list_next;
336: }
337: }
338:
339: struct _fcgi_request {
340: int listen_socket;
341: int tcp;
342: int fd;
343: int id;
344: int keep;
345: #ifdef TCP_NODELAY
346: int nodelay;
347: #endif
348: int closed;
349:
350: int in_len;
351: int in_pad;
352:
353: fcgi_header *out_hdr;
354: unsigned char *out_pos;
355: unsigned char out_buf[1024*8];
356: unsigned char reserved[sizeof(fcgi_end_request_rec)];
357:
358: int has_env;
359: fcgi_hash env;
360: };
361:
1.1 misho 362: #ifdef _WIN32
363:
364: static DWORD WINAPI fcgi_shutdown_thread(LPVOID arg)
365: {
366: HANDLE shutdown_event = (HANDLE) arg;
367: WaitForSingleObject(shutdown_event, INFINITE);
368: in_shutdown = 1;
369: return 0;
370: }
371:
372: #else
373:
374: static void fcgi_signal_handler(int signo)
375: {
376: if (signo == SIGUSR1 || signo == SIGTERM) {
377: in_shutdown = 1;
378: }
379: }
380:
381: static void fcgi_setup_signals(void)
382: {
383: struct sigaction new_sa, old_sa;
384:
385: sigemptyset(&new_sa.sa_mask);
386: new_sa.sa_flags = 0;
387: new_sa.sa_handler = fcgi_signal_handler;
388: sigaction(SIGUSR1, &new_sa, NULL);
389: sigaction(SIGTERM, &new_sa, NULL);
390: sigaction(SIGPIPE, NULL, &old_sa);
391: if (old_sa.sa_handler == SIG_DFL) {
392: sigaction(SIGPIPE, &new_sa, NULL);
393: }
394: }
395: #endif
396:
397: int fcgi_in_shutdown(void)
398: {
399: return in_shutdown;
400: }
401:
1.1.1.2 misho 402: void fcgi_terminate(void)
403: {
404: in_shutdown = 1;
405: }
406:
1.1 misho 407: int fcgi_init(void)
408: {
409: if (!is_initialized) {
410: #ifndef _WIN32
411: sa_t sa;
412: socklen_t len = sizeof(sa);
413: #endif
414: zend_hash_init(&fcgi_mgmt_vars, 0, NULL, fcgi_free_mgmt_var_cb, 1);
415: fcgi_set_mgmt_var("FCGI_MPXS_CONNS", sizeof("FCGI_MPXS_CONNS")-1, "0", sizeof("0")-1);
416:
417: is_initialized = 1;
418: #ifdef _WIN32
419: # if 0
420: /* TODO: Support for TCP sockets */
421: WSADATA wsaData;
422:
423: if (WSAStartup(MAKEWORD(2,0), &wsaData)) {
424: fprintf(stderr, "Error starting Windows Sockets. Error: %d", WSAGetLastError());
425: return 0;
426: }
427: # endif
428: if ((GetStdHandle(STD_OUTPUT_HANDLE) == INVALID_HANDLE_VALUE) &&
429: (GetStdHandle(STD_ERROR_HANDLE) == INVALID_HANDLE_VALUE) &&
430: (GetStdHandle(STD_INPUT_HANDLE) != INVALID_HANDLE_VALUE)) {
431: char *str;
432: DWORD pipe_mode = PIPE_READMODE_BYTE | PIPE_WAIT;
433: HANDLE pipe = GetStdHandle(STD_INPUT_HANDLE);
434:
435: SetNamedPipeHandleState(pipe, &pipe_mode, NULL, NULL);
436:
437: str = getenv("_FCGI_SHUTDOWN_EVENT_");
438: if (str != NULL) {
439: HANDLE shutdown_event = (HANDLE) atoi(str);
440: if (!CreateThread(NULL, 0, fcgi_shutdown_thread,
441: shutdown_event, 0, NULL)) {
442: return -1;
443: }
444: }
445: str = getenv("_FCGI_MUTEX_");
446: if (str != NULL) {
447: fcgi_accept_mutex = (HANDLE) atoi(str);
448: }
449: return is_fastcgi = 1;
450: } else {
451: return is_fastcgi = 0;
452: }
453: #else
454: errno = 0;
455: if (getpeername(0, (struct sockaddr *)&sa, &len) != 0 && errno == ENOTCONN) {
456: fcgi_setup_signals();
457: return is_fastcgi = 1;
458: } else {
459: return is_fastcgi = 0;
460: }
461: #endif
462: }
463: return is_fastcgi;
464: }
465:
466:
467: int fcgi_is_fastcgi(void)
468: {
469: if (!is_initialized) {
470: return fcgi_init();
471: } else {
472: return is_fastcgi;
473: }
474: }
475:
476: void fcgi_shutdown(void)
477: {
478: if (is_initialized) {
479: zend_hash_destroy(&fcgi_mgmt_vars);
480: }
481: is_fastcgi = 0;
482: if (allowed_clients) {
483: free(allowed_clients);
484: }
485: }
486:
487: #ifdef _WIN32
488: /* Do some black magic with the NT security API.
489: * We prepare a DACL (Discretionary Access Control List) so that
490: * we, the creator, are allowed all access, while "Everyone Else"
491: * is only allowed to read and write to the pipe.
492: * This avoids security issues on shared hosts where a luser messes
493: * with the lower-level pipe settings and screws up the FastCGI service.
494: */
495: static PACL prepare_named_pipe_acl(PSECURITY_DESCRIPTOR sd, LPSECURITY_ATTRIBUTES sa)
496: {
497: DWORD req_acl_size;
498: char everyone_buf[32], owner_buf[32];
499: PSID sid_everyone, sid_owner;
500: SID_IDENTIFIER_AUTHORITY
501: siaWorld = SECURITY_WORLD_SID_AUTHORITY,
502: siaCreator = SECURITY_CREATOR_SID_AUTHORITY;
503: PACL acl;
504:
505: sid_everyone = (PSID)&everyone_buf;
506: sid_owner = (PSID)&owner_buf;
507:
508: req_acl_size = sizeof(ACL) +
509: (2 * ((sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) + GetSidLengthRequired(1)));
510:
511: acl = malloc(req_acl_size);
512:
513: if (acl == NULL) {
514: return NULL;
515: }
516:
517: if (!InitializeSid(sid_everyone, &siaWorld, 1)) {
518: goto out_fail;
519: }
520: *GetSidSubAuthority(sid_everyone, 0) = SECURITY_WORLD_RID;
521:
522: if (!InitializeSid(sid_owner, &siaCreator, 1)) {
523: goto out_fail;
524: }
525: *GetSidSubAuthority(sid_owner, 0) = SECURITY_CREATOR_OWNER_RID;
526:
527: if (!InitializeAcl(acl, req_acl_size, ACL_REVISION)) {
528: goto out_fail;
529: }
530:
531: if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_GENERIC_READ | FILE_GENERIC_WRITE, sid_everyone)) {
532: goto out_fail;
533: }
534:
535: if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_ALL_ACCESS, sid_owner)) {
536: goto out_fail;
537: }
538:
539: if (!InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION)) {
540: goto out_fail;
541: }
542:
543: if (!SetSecurityDescriptorDacl(sd, TRUE, acl, FALSE)) {
544: goto out_fail;
545: }
546:
547: sa->lpSecurityDescriptor = sd;
548:
549: return acl;
550:
551: out_fail:
552: free(acl);
553: return NULL;
554: }
555: #endif
556:
557: static int is_port_number(const char *bindpath)
558: {
559: while (*bindpath) {
560: if (*bindpath < '0' || *bindpath > '9') {
561: return 0;
562: }
563: bindpath++;
564: }
565: return 1;
566: }
567:
568: int fcgi_listen(const char *path, int backlog)
569: {
570: char *s;
571: int tcp = 0;
572: char host[MAXPATHLEN];
573: short port = 0;
574: int listen_socket;
575: sa_t sa;
576: socklen_t sock_len;
577: #ifdef SO_REUSEADDR
578: # ifdef _WIN32
579: BOOL reuse = 1;
580: # else
581: int reuse = 1;
582: # endif
583: #endif
584:
585: if ((s = strchr(path, ':'))) {
586: port = atoi(s+1);
587: if (port != 0 && (s-path) < MAXPATHLEN) {
588: strncpy(host, path, s-path);
589: host[s-path] = '\0';
590: tcp = 1;
591: }
592: } else if (is_port_number(path)) {
593: port = atoi(path);
594: if (port != 0) {
595: host[0] = '\0';
596: tcp = 1;
597: }
598: }
599:
600: /* Prepare socket address */
601: if (tcp) {
602: memset(&sa.sa_inet, 0, sizeof(sa.sa_inet));
603: sa.sa_inet.sin_family = AF_INET;
604: sa.sa_inet.sin_port = htons(port);
605: sock_len = sizeof(sa.sa_inet);
606:
607: if (!*host || !strncmp(host, "*", sizeof("*")-1)) {
608: sa.sa_inet.sin_addr.s_addr = htonl(INADDR_ANY);
609: } else {
610: sa.sa_inet.sin_addr.s_addr = inet_addr(host);
611: if (sa.sa_inet.sin_addr.s_addr == INADDR_NONE) {
612: struct hostent *hep;
613:
614: hep = gethostbyname(host);
615: if (!hep || hep->h_addrtype != AF_INET || !hep->h_addr_list[0]) {
616: fprintf(stderr, "Cannot resolve host name '%s'!\n", host);
617: return -1;
618: } else if (hep->h_addr_list[1]) {
619: fprintf(stderr, "Host '%s' has multiple addresses. You must choose one explicitly!\n", host);
620: return -1;
621: }
622: sa.sa_inet.sin_addr.s_addr = ((struct in_addr*)hep->h_addr_list[0])->s_addr;
623: }
624: }
625: } else {
626: #ifdef _WIN32
627: SECURITY_DESCRIPTOR sd;
628: SECURITY_ATTRIBUTES saw;
629: PACL acl;
630: HANDLE namedPipe;
631:
632: memset(&sa, 0, sizeof(saw));
633: saw.nLength = sizeof(saw);
634: saw.bInheritHandle = FALSE;
635: acl = prepare_named_pipe_acl(&sd, &saw);
636:
637: namedPipe = CreateNamedPipe(path,
638: PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
639: PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_READMODE_BYTE,
640: PIPE_UNLIMITED_INSTANCES,
641: 8192, 8192, 0, &saw);
642: if (namedPipe == INVALID_HANDLE_VALUE) {
643: return -1;
1.1.1.2 misho 644: }
1.1 misho 645: listen_socket = _open_osfhandle((long)namedPipe, 0);
646: if (!is_initialized) {
647: fcgi_init();
648: }
649: is_fastcgi = 1;
650: return listen_socket;
651:
652: #else
653: int path_len = strlen(path);
654:
655: if (path_len >= sizeof(sa.sa_unix.sun_path)) {
656: fprintf(stderr, "Listening socket's path name is too long.\n");
657: return -1;
658: }
659:
660: memset(&sa.sa_unix, 0, sizeof(sa.sa_unix));
661: sa.sa_unix.sun_family = AF_UNIX;
662: memcpy(sa.sa_unix.sun_path, path, path_len + 1);
663: sock_len = (size_t)(((struct sockaddr_un *)0)->sun_path) + path_len;
664: #ifdef HAVE_SOCKADDR_UN_SUN_LEN
665: sa.sa_unix.sun_len = sock_len;
666: #endif
667: unlink(path);
668: #endif
669: }
670:
671: /* Create, bind socket and start listen on it */
672: if ((listen_socket = socket(sa.sa.sa_family, SOCK_STREAM, 0)) < 0 ||
673: #ifdef SO_REUSEADDR
674: setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse)) < 0 ||
675: #endif
676: bind(listen_socket, (struct sockaddr *) &sa, sock_len) < 0 ||
677: listen(listen_socket, backlog) < 0) {
678:
679: fprintf(stderr, "Cannot bind/listen socket - [%d] %s.\n",errno, strerror(errno));
680: return -1;
681: }
682:
683: if (!tcp) {
684: chmod(path, 0777);
685: } else {
1.1.1.2 misho 686: char *ip = getenv("FCGI_WEB_SERVER_ADDRS");
687: char *cur, *end;
688: int n;
689:
690: if (ip) {
691: ip = strdup(ip);
692: cur = ip;
693: n = 0;
694: while (*cur) {
695: if (*cur == ',') n++;
696: cur++;
697: }
698: allowed_clients = malloc(sizeof(in_addr_t) * (n+2));
699: n = 0;
700: cur = ip;
701: while (cur) {
702: end = strchr(cur, ',');
703: if (end) {
704: *end = 0;
705: end++;
1.1 misho 706: }
1.1.1.2 misho 707: allowed_clients[n] = inet_addr(cur);
708: if (allowed_clients[n] == INADDR_NONE) {
1.1 misho 709: fprintf(stderr, "Wrong IP address '%s' in FCGI_WEB_SERVER_ADDRS\n", cur);
710: }
1.1.1.2 misho 711: n++;
712: cur = end;
713: }
714: allowed_clients[n] = INADDR_NONE;
1.1 misho 715: free(ip);
716: }
717: }
718:
719: if (!is_initialized) {
720: fcgi_init();
721: }
722: is_fastcgi = 1;
723:
724: #ifdef _WIN32
725: if (tcp) {
726: listen_socket = _open_osfhandle((long)listen_socket, 0);
727: }
728: #else
729: fcgi_setup_signals();
730: #endif
731: return listen_socket;
732: }
733:
1.1.1.2 misho 734: fcgi_request *fcgi_init_request(int listen_socket)
1.1 misho 735: {
1.1.1.2 misho 736: fcgi_request *req = (fcgi_request*)calloc(1, sizeof(fcgi_request));
1.1 misho 737: req->listen_socket = listen_socket;
738: req->fd = -1;
739: req->id = -1;
740:
741: req->in_len = 0;
742: req->in_pad = 0;
743:
744: req->out_hdr = NULL;
745: req->out_pos = req->out_buf;
746:
747: #ifdef _WIN32
748: req->tcp = !GetNamedPipeInfo((HANDLE)_get_osfhandle(req->listen_socket), NULL, NULL, NULL, NULL);
749: #endif
1.1.1.2 misho 750:
751: #ifdef TCP_NODELAY
752: req->nodelay = 0;
753: #endif
754:
755: fcgi_hash_init(&req->env);
756:
757: return req;
758: }
759:
760: void fcgi_destroy_request(fcgi_request *req)
761: {
762: fcgi_hash_destroy(&req->env);
763: free(req);
1.1 misho 764: }
765:
766: static inline ssize_t safe_write(fcgi_request *req, const void *buf, size_t count)
767: {
768: int ret;
769: size_t n = 0;
770:
771: do {
772: errno = 0;
773: #ifdef _WIN32
774: if (!req->tcp) {
775: ret = write(req->fd, ((char*)buf)+n, count-n);
776: } else {
777: ret = send(req->fd, ((char*)buf)+n, count-n, 0);
778: if (ret <= 0) {
779: errno = WSAGetLastError();
780: }
781: }
782: #else
783: ret = write(req->fd, ((char*)buf)+n, count-n);
784: #endif
785: if (ret > 0) {
786: n += ret;
787: } else if (ret <= 0 && errno != 0 && errno != EINTR) {
788: return ret;
789: }
790: } while (n != count);
791: return n;
792: }
793:
794: static inline ssize_t safe_read(fcgi_request *req, const void *buf, size_t count)
795: {
796: int ret;
797: size_t n = 0;
798:
799: do {
800: errno = 0;
801: #ifdef _WIN32
802: if (!req->tcp) {
803: ret = read(req->fd, ((char*)buf)+n, count-n);
804: } else {
805: ret = recv(req->fd, ((char*)buf)+n, count-n, 0);
806: if (ret <= 0) {
807: errno = WSAGetLastError();
808: }
809: }
810: #else
811: ret = read(req->fd, ((char*)buf)+n, count-n);
812: #endif
813: if (ret > 0) {
814: n += ret;
815: } else if (ret == 0 && errno == 0) {
816: return n;
817: } else if (ret <= 0 && errno != 0 && errno != EINTR) {
818: return ret;
819: }
820: } while (n != count);
821: return n;
822: }
823:
824: static inline int fcgi_make_header(fcgi_header *hdr, fcgi_request_type type, int req_id, int len)
825: {
826: int pad = ((len + 7) & ~7) - len;
827:
828: hdr->contentLengthB0 = (unsigned char)(len & 0xff);
829: hdr->contentLengthB1 = (unsigned char)((len >> 8) & 0xff);
830: hdr->paddingLength = (unsigned char)pad;
831: hdr->requestIdB0 = (unsigned char)(req_id & 0xff);
832: hdr->requestIdB1 = (unsigned char)((req_id >> 8) & 0xff);
833: hdr->reserved = 0;
834: hdr->type = type;
835: hdr->version = FCGI_VERSION_1;
836: if (pad) {
837: memset(((unsigned char*)hdr) + sizeof(fcgi_header) + len, 0, pad);
838: }
839: return pad;
840: }
841:
842: static int fcgi_get_params(fcgi_request *req, unsigned char *p, unsigned char *end)
843: {
844: unsigned int name_len, val_len;
845:
846: while (p < end) {
847: name_len = *p++;
1.1.1.2 misho 848: if (UNEXPECTED(name_len >= 128)) {
849: if (UNEXPECTED(p + 3 >= end)) return 0;
1.1 misho 850: name_len = ((name_len & 0x7f) << 24);
851: name_len |= (*p++ << 16);
852: name_len |= (*p++ << 8);
853: name_len |= *p++;
854: }
1.1.1.2 misho 855: if (UNEXPECTED(p >= end)) return 0;
1.1 misho 856: val_len = *p++;
1.1.1.2 misho 857: if (UNEXPECTED(val_len >= 128)) {
858: if (UNEXPECTED(p + 3 >= end)) return 0;
1.1 misho 859: val_len = ((val_len & 0x7f) << 24);
860: val_len |= (*p++ << 16);
861: val_len |= (*p++ << 8);
862: val_len |= *p++;
863: }
1.1.1.2 misho 864: if (UNEXPECTED(name_len + val_len > (unsigned int) (end - p))) {
1.1 misho 865: /* Malformated request */
1.1.1.2 misho 866: return 0;
1.1 misho 867: }
1.1.1.2 misho 868: fcgi_hash_set(&req->env, FCGI_HASH_FUNC(p, name_len), (char*)p, name_len, (char*)p + name_len, val_len);
1.1 misho 869: p += name_len + val_len;
870: }
1.1.1.2 misho 871: return 1;
1.1 misho 872: }
873:
874: static int fcgi_read_request(fcgi_request *req)
875: {
876: fcgi_header hdr;
877: int len, padding;
878: unsigned char buf[FCGI_MAX_LENGTH+8];
879:
880: req->keep = 0;
881: req->closed = 0;
882: req->in_len = 0;
883: req->out_hdr = NULL;
884: req->out_pos = req->out_buf;
1.1.1.2 misho 885: req->has_env = 1;
1.1 misho 886:
887: if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
888: hdr.version < FCGI_VERSION_1) {
889: return 0;
890: }
891:
892: len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
893: padding = hdr.paddingLength;
894:
895: while (hdr.type == FCGI_STDIN && len == 0) {
896: if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
897: hdr.version < FCGI_VERSION_1) {
898: return 0;
899: }
900:
901: len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
902: padding = hdr.paddingLength;
903: }
904:
905: if (len + padding > FCGI_MAX_LENGTH) {
906: return 0;
907: }
908:
909: req->id = (hdr.requestIdB1 << 8) + hdr.requestIdB0;
910:
911: if (hdr.type == FCGI_BEGIN_REQUEST && len == sizeof(fcgi_begin_request)) {
912: if (safe_read(req, buf, len+padding) != len+padding) {
913: return 0;
914: }
915:
916: req->keep = (((fcgi_begin_request*)buf)->flags & FCGI_KEEP_CONN);
1.1.1.2 misho 917: #ifdef TCP_NODELAY
918: if (req->keep && req->tcp && !req->nodelay) {
919: # ifdef _WIN32
920: BOOL on = 1;
921: # else
922: int on = 1;
923: # endif
924:
925: setsockopt(req->fd, IPPROTO_TCP, TCP_NODELAY, (char*)&on, sizeof(on));
926: req->nodelay = 1;
927: }
928: #endif
1.1 misho 929: switch ((((fcgi_begin_request*)buf)->roleB1 << 8) + ((fcgi_begin_request*)buf)->roleB0) {
930: case FCGI_RESPONDER:
1.1.1.2 misho 931: fcgi_hash_set(&req->env, FCGI_HASH_FUNC("FCGI_ROLE", sizeof("FCGI_ROLE")-1), "FCGI_ROLE", sizeof("FCGI_ROLE")-1, "RESPONDER", sizeof("RESPONDER")-1);
1.1 misho 932: break;
933: case FCGI_AUTHORIZER:
1.1.1.2 misho 934: fcgi_hash_set(&req->env, FCGI_HASH_FUNC("FCGI_ROLE", sizeof("FCGI_ROLE")-1), "FCGI_ROLE", sizeof("FCGI_ROLE")-1, "AUTHORIZER", sizeof("AUTHORIZER")-1);
1.1 misho 935: break;
936: case FCGI_FILTER:
1.1.1.2 misho 937: fcgi_hash_set(&req->env, FCGI_HASH_FUNC("FCGI_ROLE", sizeof("FCGI_ROLE")-1), "FCGI_ROLE", sizeof("FCGI_ROLE")-1, "FILTER", sizeof("FILTER")-1);
1.1 misho 938: break;
939: default:
940: return 0;
941: }
942:
943: if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
944: hdr.version < FCGI_VERSION_1) {
945: return 0;
946: }
947:
948: len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
949: padding = hdr.paddingLength;
950:
951: while (hdr.type == FCGI_PARAMS && len > 0) {
952: if (len + padding > FCGI_MAX_LENGTH) {
953: return 0;
954: }
955:
956: if (safe_read(req, buf, len+padding) != len+padding) {
957: req->keep = 0;
958: return 0;
959: }
960:
961: if (!fcgi_get_params(req, buf, buf+len)) {
962: req->keep = 0;
963: return 0;
964: }
965:
966: if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
967: hdr.version < FCGI_VERSION_1) {
968: req->keep = 0;
969: return 0;
970: }
971: len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
972: padding = hdr.paddingLength;
973: }
974: } else if (hdr.type == FCGI_GET_VALUES) {
975: unsigned char *p = buf + sizeof(fcgi_header);
976: zval ** value;
1.1.1.2 misho 977: unsigned int zlen;
978: fcgi_hash_bucket *q;
1.1 misho 979:
980: if (safe_read(req, buf, len+padding) != len+padding) {
981: req->keep = 0;
982: return 0;
983: }
984:
985: if (!fcgi_get_params(req, buf, buf+len)) {
986: req->keep = 0;
987: return 0;
988: }
989:
1.1.1.2 misho 990: q = req->env.list;
991: while (q != NULL) {
992: if (zend_hash_find(&fcgi_mgmt_vars, q->var, q->var_len, (void**) &value) != SUCCESS) {
1.1 misho 993: continue;
994: }
995: zlen = Z_STRLEN_PP(value);
1.1.1.2 misho 996: if ((p + 4 + 4 + q->var_len + zlen) >= (buf + sizeof(buf))) {
1.1 misho 997: break;
998: }
1.1.1.2 misho 999: if (q->var_len < 0x80) {
1000: *p++ = q->var_len;
1.1 misho 1001: } else {
1.1.1.2 misho 1002: *p++ = ((q->var_len >> 24) & 0xff) | 0x80;
1003: *p++ = (q->var_len >> 16) & 0xff;
1004: *p++ = (q->var_len >> 8) & 0xff;
1005: *p++ = q->var_len & 0xff;
1.1 misho 1006: }
1007: if (zlen < 0x80) {
1008: *p++ = zlen;
1009: } else {
1010: *p++ = ((zlen >> 24) & 0xff) | 0x80;
1011: *p++ = (zlen >> 16) & 0xff;
1012: *p++ = (zlen >> 8) & 0xff;
1013: *p++ = zlen & 0xff;
1014: }
1.1.1.2 misho 1015: memcpy(p, q->var, q->var_len);
1016: p += q->var_len;
1.1 misho 1017: memcpy(p, Z_STRVAL_PP(value), zlen);
1018: p += zlen;
1019: }
1020: len = p - buf - sizeof(fcgi_header);
1021: len += fcgi_make_header((fcgi_header*)buf, FCGI_GET_VALUES_RESULT, 0, len);
1022: if (safe_write(req, buf, sizeof(fcgi_header)+len) != (int)sizeof(fcgi_header)+len) {
1023: req->keep = 0;
1024: return 0;
1025: }
1026: return 0;
1027: } else {
1028: return 0;
1029: }
1030:
1031: return 1;
1032: }
1033:
1034: int fcgi_read(fcgi_request *req, char *str, int len)
1035: {
1036: int ret, n, rest;
1037: fcgi_header hdr;
1038: unsigned char buf[255];
1039:
1040: n = 0;
1041: rest = len;
1042: while (rest > 0) {
1043: if (req->in_len == 0) {
1044: if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
1045: hdr.version < FCGI_VERSION_1 ||
1046: hdr.type != FCGI_STDIN) {
1047: req->keep = 0;
1048: return 0;
1049: }
1050: req->in_len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
1051: req->in_pad = hdr.paddingLength;
1052: if (req->in_len == 0) {
1053: return n;
1054: }
1055: }
1056:
1057: if (req->in_len >= rest) {
1058: ret = safe_read(req, str, rest);
1059: } else {
1060: ret = safe_read(req, str, req->in_len);
1061: }
1062: if (ret < 0) {
1063: req->keep = 0;
1064: return ret;
1065: } else if (ret > 0) {
1066: req->in_len -= ret;
1067: rest -= ret;
1068: n += ret;
1069: str += ret;
1070: if (req->in_len == 0) {
1071: if (req->in_pad) {
1072: if (safe_read(req, buf, req->in_pad) != req->in_pad) {
1073: req->keep = 0;
1074: return ret;
1075: }
1076: }
1077: } else {
1078: return n;
1079: }
1080: } else {
1081: return n;
1082: }
1083: }
1084: return n;
1085: }
1086:
1087: static inline void fcgi_close(fcgi_request *req, int force, int destroy)
1088: {
1.1.1.2 misho 1089: if (destroy && req->has_env) {
1090: fcgi_hash_clean(&req->env);
1091: req->has_env = 0;
1.1 misho 1092: }
1093:
1094: #ifdef _WIN32
1095: if (is_impersonate && !req->tcp) {
1096: RevertToSelf();
1097: }
1098: #endif
1099:
1100: if ((force || !req->keep) && req->fd >= 0) {
1101: #ifdef _WIN32
1102: if (!req->tcp) {
1103: HANDLE pipe = (HANDLE)_get_osfhandle(req->fd);
1104:
1105: if (!force) {
1106: FlushFileBuffers(pipe);
1107: }
1108: DisconnectNamedPipe(pipe);
1109: } else {
1110: if (!force) {
1.1.1.2 misho 1111: fcgi_header buf;
1.1 misho 1112:
1113: shutdown(req->fd, 1);
1.1.1.2 misho 1114: /* read the last FCGI_STDIN header (it may be omitted) */
1115: recv(req->fd, &buf, sizeof(buf), 0);
1.1 misho 1116: }
1117: closesocket(req->fd);
1118: }
1119: #else
1120: if (!force) {
1.1.1.2 misho 1121: fcgi_header buf;
1.1 misho 1122:
1123: shutdown(req->fd, 1);
1.1.1.2 misho 1124: /* read the last FCGI_STDIN header (it may be omitted) */
1125: recv(req->fd, &buf, sizeof(buf), 0);
1.1 misho 1126: }
1127: close(req->fd);
1128: #endif
1.1.1.2 misho 1129: #ifdef TCP_NODELAY
1130: req->nodelay = 0;
1131: #endif
1.1 misho 1132: req->fd = -1;
1133: }
1134: }
1135:
1136: int fcgi_accept_request(fcgi_request *req)
1137: {
1138: #ifdef _WIN32
1139: HANDLE pipe;
1140: OVERLAPPED ov;
1141: #endif
1142:
1143: while (1) {
1144: if (req->fd < 0) {
1145: while (1) {
1146: if (in_shutdown) {
1147: return -1;
1148: }
1149: #ifdef _WIN32
1150: if (!req->tcp) {
1151: pipe = (HANDLE)_get_osfhandle(req->listen_socket);
1152: FCGI_LOCK(req->listen_socket);
1153: ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
1154: if (!ConnectNamedPipe(pipe, &ov)) {
1155: errno = GetLastError();
1156: if (errno == ERROR_IO_PENDING) {
1157: while (WaitForSingleObject(ov.hEvent, 1000) == WAIT_TIMEOUT) {
1158: if (in_shutdown) {
1159: CloseHandle(ov.hEvent);
1160: FCGI_UNLOCK(req->listen_socket);
1161: return -1;
1162: }
1163: }
1164: } else if (errno != ERROR_PIPE_CONNECTED) {
1165: }
1166: }
1167: CloseHandle(ov.hEvent);
1168: req->fd = req->listen_socket;
1169: FCGI_UNLOCK(req->listen_socket);
1170: } else {
1171: SOCKET listen_socket = (SOCKET)_get_osfhandle(req->listen_socket);
1172: #else
1173: {
1174: int listen_socket = req->listen_socket;
1175: #endif
1176: sa_t sa;
1177: socklen_t len = sizeof(sa);
1178:
1179: FCGI_LOCK(req->listen_socket);
1180: req->fd = accept(listen_socket, (struct sockaddr *)&sa, &len);
1181: FCGI_UNLOCK(req->listen_socket);
1.1.1.2 misho 1182: if (req->fd >= 0) {
1183: if (((struct sockaddr *)&sa)->sa_family == AF_INET) {
1184: #ifndef _WIN32
1185: req->tcp = 1;
1186: #endif
1187: if (allowed_clients) {
1188: int n = 0;
1189: int allowed = 0;
1190:
1191: while (allowed_clients[n] != INADDR_NONE) {
1192: if (allowed_clients[n] == sa.sa_inet.sin_addr.s_addr) {
1193: allowed = 1;
1194: break;
1195: }
1196: n++;
1197: }
1198: if (!allowed) {
1199: fprintf(stderr, "Connection from disallowed IP address '%s' is dropped.\n", inet_ntoa(sa.sa_inet.sin_addr));
1200: closesocket(req->fd);
1201: req->fd = -1;
1202: continue;
1.1 misho 1203: }
1204: }
1.1.1.2 misho 1205: #ifndef _WIN32
1206: } else {
1207: req->tcp = 0;
1208: #endif
1.1 misho 1209: }
1210: }
1211: }
1212:
1213: #ifdef _WIN32
1214: if (req->fd < 0 && (in_shutdown || errno != EINTR)) {
1215: #else
1216: if (req->fd < 0 && (in_shutdown || (errno != EINTR && errno != ECONNABORTED))) {
1217: #endif
1218: return -1;
1219: }
1220:
1221: #ifdef _WIN32
1222: break;
1223: #else
1224: if (req->fd >= 0) {
1225: #if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
1226: struct pollfd fds;
1227: int ret;
1228:
1229: fds.fd = req->fd;
1230: fds.events = POLLIN;
1231: fds.revents = 0;
1232: do {
1233: errno = 0;
1234: ret = poll(&fds, 1, 5000);
1235: } while (ret < 0 && errno == EINTR);
1236: if (ret > 0 && (fds.revents & POLLIN)) {
1237: break;
1238: }
1239: fcgi_close(req, 1, 0);
1240: #else
1241: if (req->fd < FD_SETSIZE) {
1242: struct timeval tv = {5,0};
1243: fd_set set;
1244: int ret;
1245:
1246: FD_ZERO(&set);
1247: FD_SET(req->fd, &set);
1248: do {
1249: errno = 0;
1250: ret = select(req->fd + 1, &set, NULL, NULL, &tv) >= 0;
1251: } while (ret < 0 && errno == EINTR);
1252: if (ret > 0 && FD_ISSET(req->fd, &set)) {
1253: break;
1254: }
1255: fcgi_close(req, 1, 0);
1256: } else {
1257: fprintf(stderr, "Too many open file descriptors. FD_SETSIZE limit exceeded.");
1258: fcgi_close(req, 1, 0);
1259: }
1260: #endif
1261: }
1262: #endif
1263: }
1264: } else if (in_shutdown) {
1265: return -1;
1266: }
1267: if (fcgi_read_request(req)) {
1268: #ifdef _WIN32
1269: if (is_impersonate && !req->tcp) {
1270: pipe = (HANDLE)_get_osfhandle(req->fd);
1271: if (!ImpersonateNamedPipeClient(pipe)) {
1272: fcgi_close(req, 1, 1);
1273: continue;
1274: }
1275: }
1276: #endif
1277: return req->fd;
1278: } else {
1279: fcgi_close(req, 1, 1);
1280: }
1281: }
1282: }
1283:
1284: static inline fcgi_header* open_packet(fcgi_request *req, fcgi_request_type type)
1285: {
1286: req->out_hdr = (fcgi_header*) req->out_pos;
1287: req->out_hdr->type = type;
1288: req->out_pos += sizeof(fcgi_header);
1289: return req->out_hdr;
1290: }
1291:
1292: static inline void close_packet(fcgi_request *req)
1293: {
1294: if (req->out_hdr) {
1295: int len = req->out_pos - ((unsigned char*)req->out_hdr + sizeof(fcgi_header));
1296:
1297: req->out_pos += fcgi_make_header(req->out_hdr, (fcgi_request_type)req->out_hdr->type, req->id, len);
1298: req->out_hdr = NULL;
1299: }
1300: }
1301:
1302: int fcgi_flush(fcgi_request *req, int close)
1303: {
1304: int len;
1305:
1306: close_packet(req);
1307:
1308: len = req->out_pos - req->out_buf;
1309:
1310: if (close) {
1311: fcgi_end_request_rec *rec = (fcgi_end_request_rec*)(req->out_pos);
1312:
1313: fcgi_make_header(&rec->hdr, FCGI_END_REQUEST, req->id, sizeof(fcgi_end_request));
1314: rec->body.appStatusB3 = 0;
1315: rec->body.appStatusB2 = 0;
1316: rec->body.appStatusB1 = 0;
1317: rec->body.appStatusB0 = 0;
1318: rec->body.protocolStatus = FCGI_REQUEST_COMPLETE;
1319: len += sizeof(fcgi_end_request_rec);
1320: }
1321:
1322: if (safe_write(req, req->out_buf, len) != len) {
1323: req->keep = 0;
1324: return 0;
1325: }
1326:
1327: req->out_pos = req->out_buf;
1328: return 1;
1329: }
1330:
1331: int fcgi_write(fcgi_request *req, fcgi_request_type type, const char *str, int len)
1332: {
1333: int limit, rest;
1334:
1335: if (len <= 0) {
1336: return 0;
1337: }
1338:
1339: if (req->out_hdr && req->out_hdr->type != type) {
1340: close_packet(req);
1341: }
1342: #if 0
1343: /* Unoptimized, but clear version */
1344: rest = len;
1345: while (rest > 0) {
1346: limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
1347:
1348: if (!req->out_hdr) {
1349: if (limit < sizeof(fcgi_header)) {
1350: if (!fcgi_flush(req, 0)) {
1351: return -1;
1352: }
1353: }
1354: open_packet(req, type);
1355: }
1356: limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
1357: if (rest < limit) {
1358: memcpy(req->out_pos, str, rest);
1359: req->out_pos += rest;
1360: return len;
1361: } else {
1362: memcpy(req->out_pos, str, limit);
1363: req->out_pos += limit;
1364: rest -= limit;
1365: str += limit;
1366: if (!fcgi_flush(req, 0)) {
1367: return -1;
1368: }
1369: }
1370: }
1371: #else
1372: /* Optimized version */
1373: limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
1374: if (!req->out_hdr) {
1375: limit -= sizeof(fcgi_header);
1376: if (limit < 0) limit = 0;
1377: }
1378:
1379: if (len < limit) {
1380: if (!req->out_hdr) {
1381: open_packet(req, type);
1382: }
1383: memcpy(req->out_pos, str, len);
1384: req->out_pos += len;
1385: } else if (len - limit < sizeof(req->out_buf) - sizeof(fcgi_header)) {
1386: if (!req->out_hdr) {
1387: open_packet(req, type);
1388: }
1389: if (limit > 0) {
1390: memcpy(req->out_pos, str, limit);
1391: req->out_pos += limit;
1392: }
1393: if (!fcgi_flush(req, 0)) {
1394: return -1;
1395: }
1396: if (len > limit) {
1397: open_packet(req, type);
1398: memcpy(req->out_pos, str + limit, len - limit);
1399: req->out_pos += len - limit;
1400: }
1401: } else {
1402: int pos = 0;
1403: int pad;
1404:
1405: close_packet(req);
1406: while ((len - pos) > 0xffff) {
1407: open_packet(req, type);
1408: fcgi_make_header(req->out_hdr, type, req->id, 0xfff8);
1409: req->out_hdr = NULL;
1410: if (!fcgi_flush(req, 0)) {
1411: return -1;
1412: }
1413: if (safe_write(req, str + pos, 0xfff8) != 0xfff8) {
1414: req->keep = 0;
1415: return -1;
1416: }
1417: pos += 0xfff8;
1.1.1.2 misho 1418: }
1419:
1.1 misho 1420: pad = (((len - pos) + 7) & ~7) - (len - pos);
1421: rest = pad ? 8 - pad : 0;
1422:
1423: open_packet(req, type);
1424: fcgi_make_header(req->out_hdr, type, req->id, (len - pos) - rest);
1425: req->out_hdr = NULL;
1426: if (!fcgi_flush(req, 0)) {
1427: return -1;
1428: }
1429: if (safe_write(req, str + pos, (len - pos) - rest) != (len - pos) - rest) {
1430: req->keep = 0;
1431: return -1;
1432: }
1433: if (pad) {
1434: open_packet(req, type);
1435: memcpy(req->out_pos, str + len - rest, rest);
1436: req->out_pos += rest;
1437: }
1438: }
1439: #endif
1440: return len;
1441: }
1442:
1443: int fcgi_finish_request(fcgi_request *req, int force_close)
1444: {
1445: int ret = 1;
1446:
1447: if (req->fd >= 0) {
1448: if (!req->closed) {
1449: ret = fcgi_flush(req, 1);
1450: req->closed = 1;
1451: }
1452: fcgi_close(req, force_close, 1);
1453: }
1454: return ret;
1455: }
1456:
1457: char* fcgi_getenv(fcgi_request *req, const char* var, int var_len)
1458: {
1.1.1.2 misho 1459: unsigned int val_len;
1.1 misho 1460:
1461: if (!req) return NULL;
1462:
1.1.1.2 misho 1463: return fcgi_hash_get(&req->env, FCGI_HASH_FUNC(var, var_len), (char*)var, var_len, &val_len);
1464: }
1465:
1466: char* fcgi_quick_getenv(fcgi_request *req, const char* var, int var_len, unsigned int hash_value)
1467: {
1468: unsigned int val_len;
1469:
1470: return fcgi_hash_get(&req->env, hash_value, (char*)var, var_len, &val_len);
1.1 misho 1471: }
1472:
1473: char* fcgi_putenv(fcgi_request *req, char* var, int var_len, char* val)
1474: {
1.1.1.2 misho 1475: if (!req) return NULL;
1476: if (val == NULL) {
1477: fcgi_hash_del(&req->env, FCGI_HASH_FUNC(var, var_len), var, var_len);
1478: return NULL;
1479: } else {
1480: return fcgi_hash_set(&req->env, FCGI_HASH_FUNC(var, var_len), var, var_len, val, strlen(val));
1481: }
1482: }
1.1 misho 1483:
1.1.1.2 misho 1484: char* fcgi_quick_putenv(fcgi_request *req, char* var, int var_len, unsigned int hash_value, char* val)
1485: {
1486: if (val == NULL) {
1487: fcgi_hash_del(&req->env, hash_value, var, var_len);
1488: return NULL;
1489: } else {
1490: return fcgi_hash_set(&req->env, hash_value, var, var_len, val, strlen(val));
1.1 misho 1491: }
1.1.1.2 misho 1492: }
1493:
1494: void fcgi_loadenv(fcgi_request *req, fcgi_apply_func func, zval *array TSRMLS_DC)
1495: {
1496: fcgi_hash_apply(&req->env, func, array TSRMLS_CC);
1.1 misho 1497: }
1498:
1499: #ifdef _WIN32
1500: void fcgi_impersonate(void)
1501: {
1502: char *os_name;
1503:
1504: os_name = getenv("OS");
1505: if (os_name && stricmp(os_name, "Windows_NT") == 0) {
1506: is_impersonate = 1;
1507: }
1508: }
1509: #endif
1510:
1511: void fcgi_set_mgmt_var(const char * name, size_t name_len, const char * value, size_t value_len)
1512: {
1513: zval * zvalue;
1514: zvalue = pemalloc(sizeof(*zvalue), 1);
1515: Z_TYPE_P(zvalue) = IS_STRING;
1516: Z_STRVAL_P(zvalue) = pestrndup(value, value_len, 1);
1517: Z_STRLEN_P(zvalue) = value_len;
1.1.1.2 misho 1518: zend_hash_add(&fcgi_mgmt_vars, name, name_len, &zvalue, sizeof(zvalue), NULL);
1.1 misho 1519: }
1520:
1521: void fcgi_free_mgmt_var_cb(void * ptr)
1522: {
1523: zval ** var = (zval **)ptr;
1524: pefree(Z_STRVAL_PP(var), 1);
1525: pefree(*var, 1);
1526: }
1527:
1528: /*
1529: * Local variables:
1530: * tab-width: 4
1531: * c-basic-offset: 4
1532: * End:
1533: * vim600: sw=4 ts=4 fdm=marker
1534: * vim<600: sw=4 ts=4
1535: */