PageRenderTime 104ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 1ms

/cgi/fastcgi.c

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