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