You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

943 lines
21 KiB

20 years ago
20 years ago
20 years ago
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2006 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$ */
  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 _WIN32
  27. #include <windows.h>
  28. typedef unsigned int size_t;
  29. struct sockaddr_un {
  30. short sun_family;
  31. char sun_path[MAXPATHLEN];
  32. };
  33. static HANDLE fcgi_accept_mutex = INVALID_HANDLE_VALUE;
  34. static int is_impersonate = 0;
  35. #define FCGI_LOCK(fd) \
  36. if (fcgi_accept_mutex != INVALID_HANDLE_VALUE) { \
  37. DWORD ret; \
  38. while ((ret = WaitForSingleObject(fcgi_accept_mutex, 1000)) == WAIT_TIMEOUT) { \
  39. if (in_shutdown) return -1; \
  40. } \
  41. if (ret == WAIT_FAILED) { \
  42. fprintf(stderr, "WaitForSingleObject() failed\n"); \
  43. return -1; \
  44. } \
  45. }
  46. #define FCGI_UNLOCK(fd) \
  47. if (fcgi_accept_mutex != INVALID_HANDLE_VALUE) { \
  48. ReleaseMutex(fcgi_accept_mutex); \
  49. }
  50. #else
  51. # include <sys/types.h>
  52. # include <sys/stat.h>
  53. # include <unistd.h>
  54. # include <fcntl.h>
  55. # include <sys/socket.h>
  56. # include <sys/un.h>
  57. # include <netinet/in.h>
  58. # include <arpa/inet.h>
  59. # include <netdb.h>
  60. # include <signal.h>
  61. #ifndef INADDR_NONE
  62. #define INADDR_NONE ((unsigned long) -1)
  63. #endif
  64. # ifndef HAVE_SOCKLEN_T
  65. typedef unsigned int socklen_t;
  66. # endif
  67. # ifdef USE_LOCKING
  68. # define FCGI_LOCK(fd) \
  69. do { \
  70. struct flock lock; \
  71. lock.l_type = F_WRLCK; \
  72. lock.l_start = 0; \
  73. lock.l_whence = SEEK_SET; \
  74. lock.l_len = 0; \
  75. if (fcntl(fd, F_SETLKW, &lock) != -1) { \
  76. break; \
  77. } else if (errno != EINTR || in_shutdown) { \
  78. return -1; \
  79. } \
  80. } while (1)
  81. # define FCGI_UNLOCK(fd) \
  82. do { \
  83. int orig_errno = errno; \
  84. while (1) { \
  85. struct flock lock; \
  86. lock.l_type = F_UNLCK; \
  87. lock.l_start = 0; \
  88. lock.l_whence = SEEK_SET; \
  89. lock.l_len = 0; \
  90. if (fcntl(fd, F_SETLK, &lock) != -1) { \
  91. break; \
  92. } else if (errno != EINTR) { \
  93. return -1; \
  94. } \
  95. } \
  96. errno = orig_errno; \
  97. } while (0)
  98. # else
  99. # define FCGI_LOCK(fd)
  100. # define FCGI_UNLOCK(fd)
  101. # endif
  102. #endif
  103. typedef union _sa_t {
  104. struct sockaddr sa;
  105. struct sockaddr_un sa_unix;
  106. struct sockaddr_in sa_inet;
  107. } sa_t;
  108. typedef struct _fcgi_mgmt_rec {
  109. char* name;
  110. size_t name_len;
  111. char val;
  112. } fcgi_mgmt_rec;
  113. static const fcgi_mgmt_rec fcgi_mgmt_vars[] = {
  114. {"FCGI_MAX_CONNS", sizeof("FCGI_MAX_CONNS")-1, 1},
  115. {"FCGI_MAX_REQS", sizeof("FCGI_MAX_REQS")-1, 1},
  116. {"FCGI_MPXS_CONNS", sizeof("FCGI_MPXS_CONNS")-1, 0}
  117. };
  118. static int is_initialized = 0;
  119. static int is_fastcgi = 0;
  120. static int in_shutdown = 0;
  121. #ifdef _WIN32
  122. static DWORD WINAPI fcgi_shutdown_thread(LPVOID arg)
  123. {
  124. HANDLE shutdown_event = (HANDLE) arg;
  125. WaitForSingleObject(shutdown_event, INFINITE);
  126. in_shutdown = 1;
  127. return 0;
  128. }
  129. #else
  130. static void fcgi_signal_handler(int signo)
  131. {
  132. if (signo == SIGUSR1 || signo == SIGTERM) {
  133. in_shutdown = 1;
  134. }
  135. }
  136. #endif
  137. int fcgi_init(void)
  138. {
  139. if (!is_initialized) {
  140. #ifdef _WIN32
  141. # if 0
  142. /* TODO: Support for TCP sockets */
  143. WSADATA wsaData;
  144. if (WSAStartup(MAKEWORD(2,0), &wsaData)) {
  145. fprintf(stderr, "Error starting Windows Sockets. Error: %d", WSAGetLastError());
  146. return 0;
  147. }
  148. # endif
  149. is_initialized = 1;
  150. if ((GetStdHandle(STD_OUTPUT_HANDLE) == INVALID_HANDLE_VALUE) &&
  151. (GetStdHandle(STD_ERROR_HANDLE) == INVALID_HANDLE_VALUE) &&
  152. (GetStdHandle(STD_INPUT_HANDLE) != INVALID_HANDLE_VALUE)) {
  153. char *str;
  154. DWORD pipe_mode = PIPE_READMODE_BYTE | PIPE_WAIT;
  155. HANDLE pipe = GetStdHandle(STD_INPUT_HANDLE);
  156. SetNamedPipeHandleState(pipe, &pipe_mode, NULL, NULL);
  157. str = getenv("_FCGI_SHUTDOWN_EVENT_");
  158. if (str != NULL) {
  159. HANDLE shutdown_event = (HANDLE) atoi(str);
  160. if (!CreateThread(NULL, 0, fcgi_shutdown_thread,
  161. shutdown_event, 0, NULL)) {
  162. return -1;
  163. }
  164. }
  165. str = getenv("_FCGI_MUTEX_");
  166. if (str != NULL) {
  167. fcgi_accept_mutex = (HANDLE) atoi(str);
  168. }
  169. return is_fastcgi = 1;
  170. } else {
  171. return is_fastcgi = 0;
  172. }
  173. #else
  174. sa_t sa;
  175. socklen_t len = sizeof(sa);
  176. is_initialized = 1;
  177. errno = 0;
  178. if (getpeername(0, (struct sockaddr *)&sa, &len) != 0 && errno == ENOTCONN) {
  179. struct sigaction new_sa, old_sa;
  180. sigemptyset(&new_sa.sa_mask);
  181. new_sa.sa_flags = 0;
  182. new_sa.sa_handler = fcgi_signal_handler;
  183. sigaction(SIGUSR1, &new_sa, NULL);
  184. sigaction(SIGTERM, &new_sa, NULL);
  185. sigaction(SIGPIPE, NULL, &old_sa);
  186. if (old_sa.sa_handler == SIG_DFL) {
  187. sigaction(SIGPIPE, &new_sa, NULL);
  188. }
  189. return is_fastcgi = 1;
  190. } else {
  191. return is_fastcgi = 0;
  192. }
  193. #endif
  194. }
  195. return is_fastcgi;
  196. }
  197. int fcgi_is_fastcgi(void)
  198. {
  199. if (!is_initialized) {
  200. return fcgi_init();
  201. } else {
  202. return is_fastcgi;
  203. }
  204. }
  205. int fcgi_listen(const char *path, int backlog)
  206. {
  207. #ifdef _WIN32
  208. /* TODO: Support for manual binding on TCP sockets (php -b <port>) */
  209. return -1;
  210. #else
  211. char *s;
  212. int tcp = 0;
  213. char host[MAXPATHLEN];
  214. short port = 0;
  215. int listen_socket;
  216. sa_t sa;
  217. socklen_t sock_len;
  218. if ((s = strchr(path, ':'))) {
  219. port = atoi(s+1);
  220. if (port != 0 && (s-path) < MAXPATHLEN) {
  221. strncpy(host, path, s-path);
  222. host[s-path] = '\0';
  223. tcp = 1;
  224. }
  225. }
  226. /* Prepare socket address */
  227. if (tcp) {
  228. memset(&sa.sa_inet, 0, sizeof(sa.sa_inet));
  229. sa.sa_inet.sin_family = AF_INET;
  230. sa.sa_inet.sin_port = htons(port);
  231. sock_len = sizeof(sa.sa_inet);
  232. if (!*host || !strncmp(host, "*", sizeof("*")-1)) {
  233. sa.sa_inet.sin_addr.s_addr = htonl(INADDR_ANY);
  234. } else {
  235. sa.sa_inet.sin_addr.s_addr = inet_addr(host);
  236. if (sa.sa_inet.sin_addr.s_addr == INADDR_NONE) {
  237. struct hostent *hep;
  238. hep = gethostbyname(host);
  239. if (!hep || hep->h_addrtype != AF_INET || !hep->h_addr_list[0]) {
  240. fprintf(stderr, "Cannot resolve host name '%s'!\n", host);
  241. return -1;
  242. } else if (hep->h_addr_list[1]) {
  243. fprintf(stderr, "Host '%s' has multiple addresses. You must choose one explicitly!\n", host);
  244. return -1;
  245. }
  246. sa.sa_inet.sin_addr.s_addr = ((struct in_addr*)hep->h_addr_list[0])->s_addr;
  247. }
  248. }
  249. } else {
  250. int path_len = strlen(path);
  251. if (path_len >= sizeof(sa.sa_unix.sun_path)) {
  252. fprintf(stderr, "Listening socket's path name is too long.\n");
  253. return -1;
  254. }
  255. memset(&sa.sa_unix, 0, sizeof(sa.sa_unix));
  256. sa.sa_unix.sun_family = AF_UNIX;
  257. memcpy(sa.sa_unix.sun_path, path, path_len + 1);
  258. sock_len = (size_t)(((struct sockaddr_un *)0)->sun_path) + path_len;
  259. #ifdef HAVE_SOCKADDR_UN_SUN_LEN
  260. sa.sa_unix.sun_len = sock_len;
  261. #endif
  262. unlink(path);
  263. }
  264. /* Create, bind socket and start listen on it */
  265. if ((listen_socket = socket(sa.sa.sa_family, SOCK_STREAM, 0)) < 0 ||
  266. bind(listen_socket, (struct sockaddr *) &sa, sock_len) < 0 ||
  267. listen(listen_socket, backlog) < 0) {
  268. fprintf(stderr, "Cannot bind/listen socket - [%d] %s.\n",errno, strerror(errno));
  269. return -1;
  270. }
  271. if (!tcp) {
  272. chmod(path, 0777);
  273. }
  274. if (!is_initialized) {
  275. fcgi_init();
  276. }
  277. is_fastcgi = 1;
  278. return listen_socket;
  279. #endif
  280. }
  281. void fcgi_init_request(fcgi_request *req, int listen_socket)
  282. {
  283. memset(req, 0, sizeof(fcgi_request));
  284. req->listen_socket = listen_socket;
  285. req->fd = -1;
  286. req->id = -1;
  287. req->in_len = 0;
  288. req->in_pad = 0;
  289. req->out_hdr = NULL;
  290. req->out_pos = req->out_buf;
  291. }
  292. static inline ssize_t safe_write(fcgi_request *req, const void *buf, size_t count)
  293. {
  294. int ret;
  295. size_t n = 0;
  296. do {
  297. ret = write(req->fd, ((char*)buf)+n, count-n);
  298. if (ret > 0) {
  299. n += ret;
  300. } else if (ret <= 0 && errno != 0 && errno != EINTR) {
  301. return ret;
  302. }
  303. } while (n != count);
  304. return n;
  305. }
  306. static inline ssize_t safe_read(fcgi_request *req, const void *buf, size_t count)
  307. {
  308. int ret;
  309. size_t n = 0;
  310. do {
  311. ret = read(req->fd, ((char*)buf)+n, count-n);
  312. if (ret > 0) {
  313. n += ret;
  314. } else if (ret == 0 && errno == 0) {
  315. return n;
  316. } else if (ret <= 0 && errno != 0 && errno != EINTR) {
  317. return ret;
  318. }
  319. } while (n != count);
  320. return n;
  321. }
  322. static inline int fcgi_make_header(fcgi_header *hdr, fcgi_request_type type, int req_id, int len)
  323. {
  324. int pad = ((len + 7) & ~7) - len;
  325. hdr->contentLengthB0 = (unsigned char)(len & 0xff);
  326. hdr->contentLengthB1 = (unsigned char)((len >> 8) & 0xff);
  327. hdr->paddingLength = (unsigned char)pad;
  328. hdr->requestIdB0 = (unsigned char)(req_id & 0xff);
  329. hdr->requestIdB1 = (unsigned char)((req_id >> 8) & 0xff);
  330. hdr->reserved = 0;
  331. hdr->type = type;
  332. hdr->version = FCGI_VERSION_1;
  333. return pad;
  334. }
  335. static int fcgi_get_params(fcgi_request *req, unsigned char *p, unsigned char *end)
  336. {
  337. char buf[128];
  338. char *tmp = buf;
  339. int buf_size = sizeof(buf);
  340. int name_len, val_len;
  341. char *s;
  342. int ret = 1;
  343. while (p < end) {
  344. name_len = *p++;
  345. if (name_len >= 128) {
  346. name_len = ((name_len & 0x7f) << 24);
  347. name_len |= (*p++ << 16);
  348. name_len |= (*p++ << 8);
  349. name_len |= *p++;
  350. }
  351. val_len = *p++;
  352. if (val_len >= 128) {
  353. val_len = ((val_len & 0x7f) << 24);
  354. val_len |= (*p++ << 16);
  355. val_len |= (*p++ << 8);
  356. val_len |= *p++;
  357. }
  358. if (p + name_len + val_len > end) {
  359. /* Malformated request */
  360. ret = 0;
  361. break;
  362. }
  363. if (name_len+1 >= buf_size) {
  364. buf_size = name_len + 64;
  365. tmp = (tmp == buf ? emalloc(buf_size): erealloc(tmp, buf_size));
  366. }
  367. memcpy(tmp, p, name_len);
  368. tmp[name_len] = 0;
  369. s = zend_strndup((char*)p + name_len, val_len);
  370. zend_hash_update(&req->env, tmp, name_len+1, &s, sizeof(char*), NULL);
  371. p += name_len + val_len;
  372. }
  373. if (tmp != buf && tmp != NULL) {
  374. efree(tmp);
  375. }
  376. return ret;
  377. }
  378. static void fcgi_free_var(char **s)
  379. {
  380. free(*s);
  381. }
  382. static int fcgi_read_request(fcgi_request *req)
  383. {
  384. fcgi_header hdr;
  385. int len, padding;
  386. unsigned char buf[FCGI_MAX_LENGTH+8];
  387. req->keep = 0;
  388. req->in_len = 0;
  389. req->out_hdr = NULL;
  390. req->out_pos = req->out_buf;
  391. zend_hash_init(&req->env, 0, NULL, (void (*)(void *)) fcgi_free_var, 1);
  392. if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
  393. hdr.version < FCGI_VERSION_1) {
  394. return 0;
  395. }
  396. len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
  397. padding = hdr.paddingLength;
  398. while (hdr.type == FCGI_STDIN && len == 0) {
  399. if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
  400. hdr.version < FCGI_VERSION_1) {
  401. return 0;
  402. }
  403. len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
  404. padding = hdr.paddingLength;
  405. }
  406. req->id = (hdr.requestIdB1 << 8) + hdr.requestIdB0;
  407. if (hdr.type == FCGI_BEGIN_REQUEST && len == sizeof(fcgi_begin_request)) {
  408. char *val;
  409. if (safe_read(req, buf, len+padding) != len+padding) {
  410. return 0;
  411. }
  412. req->keep = (((fcgi_begin_request*)buf)->flags & FCGI_KEEP_CONN);
  413. switch ((((fcgi_begin_request*)buf)->roleB1 << 8) + ((fcgi_begin_request*)buf)->roleB0) {
  414. case FCGI_RESPONDER:
  415. val = strdup("RESPONDER");
  416. zend_hash_update(&req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
  417. break;
  418. case FCGI_AUTHORIZER:
  419. val = strdup("AUTHORIZER");
  420. zend_hash_update(&req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
  421. break;
  422. case FCGI_FILTER:
  423. val = strdup("FILTER");
  424. zend_hash_update(&req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
  425. break;
  426. default:
  427. return 0;
  428. }
  429. if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
  430. hdr.version < FCGI_VERSION_1) {
  431. return 0;
  432. }
  433. len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
  434. padding = hdr.paddingLength;
  435. while (hdr.type == FCGI_PARAMS && len > 0) {
  436. if (safe_read(req, buf, len+padding) != len+padding) {
  437. req->keep = 0;
  438. return 0;
  439. }
  440. if (!fcgi_get_params(req, buf, buf+len)) {
  441. req->keep = 0;
  442. return 0;
  443. }
  444. if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
  445. hdr.version < FCGI_VERSION_1) {
  446. req->keep = 0;
  447. return 0;
  448. }
  449. len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
  450. padding = hdr.paddingLength;
  451. }
  452. } else if (hdr.type == FCGI_GET_VALUES) {
  453. int j;
  454. unsigned char *p = buf + sizeof(fcgi_header);
  455. if (safe_read(req, buf, len+padding) != len+padding) {
  456. req->keep = 0;
  457. return 0;
  458. }
  459. if (!fcgi_get_params(req, buf, buf+len)) {
  460. req->keep = 0;
  461. return 0;
  462. }
  463. for (j = 0; j < sizeof(fcgi_mgmt_vars)/sizeof(fcgi_mgmt_vars[0]); j++) {
  464. if (zend_hash_exists(&req->env, fcgi_mgmt_vars[j].name, fcgi_mgmt_vars[j].name_len+1) == 0) {
  465. sprintf((char*)p, "%c%c%s%c", fcgi_mgmt_vars[j].name_len, 1, fcgi_mgmt_vars[j].name, fcgi_mgmt_vars[j].val);
  466. p += fcgi_mgmt_vars[j].name_len + 3;
  467. }
  468. }
  469. len = p - buf - sizeof(fcgi_header);
  470. len += fcgi_make_header((fcgi_header*)buf, FCGI_GET_VALUES_RESULT, 0, len);
  471. if (safe_write(req, buf, sizeof(fcgi_header)+len) != (int)sizeof(fcgi_header)+len) {
  472. req->keep = 0;
  473. return 0;
  474. }
  475. return 0;
  476. } else {
  477. return 0;
  478. }
  479. return 1;
  480. }
  481. int fcgi_read(fcgi_request *req, char *str, int len)
  482. {
  483. int ret, n, rest;
  484. fcgi_header hdr;
  485. unsigned char buf[8];
  486. n = 0;
  487. rest = len;
  488. while (rest > 0) {
  489. if (req->in_len == 0) {
  490. if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
  491. hdr.version < FCGI_VERSION_1 ||
  492. hdr.type != FCGI_STDIN) {
  493. req->keep = 0;
  494. return 0;
  495. }
  496. req->in_len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
  497. req->in_pad = hdr.paddingLength;
  498. if (req->in_len == 0) {
  499. return n;
  500. }
  501. }
  502. if (req->in_len >= rest) {
  503. ret = safe_read(req, str, rest);
  504. } else {
  505. ret = safe_read(req, str, req->in_len);
  506. }
  507. if (ret < 0) {
  508. req->keep = 0;
  509. return ret;
  510. } else if (ret > 0) {
  511. req->in_len -= ret;
  512. rest -= ret;
  513. n += ret;
  514. str += ret;
  515. if (req->in_len == 0) {
  516. if (req->in_pad) {
  517. if (safe_read(req, buf, req->in_pad) != req->in_pad) {
  518. req->keep = 0;
  519. return ret;
  520. }
  521. }
  522. } else {
  523. return n;
  524. }
  525. } else {
  526. return n;
  527. }
  528. }
  529. return n;
  530. }
  531. static inline void fcgi_close(fcgi_request *req, int force, int destroy)
  532. {
  533. if (destroy) {
  534. zend_hash_destroy(&req->env);
  535. }
  536. if ((force || !req->keep) && req->fd >= 0) {
  537. #ifdef _WIN32
  538. HANDLE pipe = (HANDLE)_get_osfhandle(req->fd);
  539. if (!force) {
  540. FlushFileBuffers(pipe);
  541. }
  542. DisconnectNamedPipe(pipe);
  543. if (is_impersonate) {
  544. RevertToSelf();
  545. }
  546. #else
  547. if (!force) {
  548. char buf[8];
  549. shutdown(req->fd, 1);
  550. while (recv(req->fd, buf, sizeof(buf), 0) > 0) {}
  551. }
  552. close(req->fd);
  553. #endif
  554. req->fd = -1;
  555. }
  556. }
  557. int fcgi_accept_request(fcgi_request *req)
  558. {
  559. #ifdef _WIN32
  560. HANDLE pipe;
  561. OVERLAPPED ov;
  562. #endif
  563. fcgi_finish_request(req);
  564. while (1) {
  565. if (req->fd < 0) {
  566. while (1) {
  567. if (in_shutdown) {
  568. return -1;
  569. }
  570. #ifdef _WIN32
  571. pipe = (HANDLE)_get_osfhandle(req->listen_socket);
  572. FCGI_LOCK(req->listen_socket);
  573. ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  574. if (!ConnectNamedPipe(pipe, &ov)) {
  575. errno = GetLastError();
  576. if (errno == ERROR_IO_PENDING) {
  577. while (WaitForSingleObject(ov.hEvent, 1000) == WAIT_TIMEOUT) {
  578. if (in_shutdown) {
  579. CloseHandle(ov.hEvent);
  580. FCGI_UNLOCK(req->listen_socket);
  581. return -1;
  582. }
  583. }
  584. } else if (errno != ERROR_PIPE_CONNECTED) {
  585. }
  586. }
  587. CloseHandle(ov.hEvent);
  588. if (is_impersonate && !ImpersonateNamedPipeClient(pipe)) {
  589. DisconnectNamedPipe(pipe);
  590. req->fd = -1;
  591. } else {
  592. req->fd = req->listen_socket;
  593. }
  594. FCGI_UNLOCK(req->listen_socket);
  595. #else
  596. {
  597. sa_t sa;
  598. socklen_t len = sizeof(sa);
  599. FCGI_LOCK(req->listen_socket);
  600. req->fd = accept(req->listen_socket, (struct sockaddr *)&sa, &len);
  601. FCGI_UNLOCK(req->listen_socket);
  602. }
  603. #endif
  604. if (req->fd < 0 && (in_shutdown || errno != EINTR)) {
  605. return -1;
  606. }
  607. #ifdef _WIN32
  608. break;
  609. #else
  610. if (req->fd >= 0) {
  611. struct timeval tv = {5,0};
  612. fd_set set;
  613. FD_ZERO(&set);
  614. FD_SET(req->fd, &set);
  615. try_again:
  616. errno = 0;
  617. if (select(req->fd + 1, &set, NULL, NULL, &tv) >= 0 && FD_ISSET(req->fd, &set)) {
  618. break;
  619. }
  620. if (errno == EINTR) goto try_again;
  621. fcgi_close(req, 1, 0);
  622. }
  623. #endif
  624. }
  625. } else if (in_shutdown) {
  626. return -1;
  627. }
  628. if (fcgi_read_request(req)) {
  629. return req->fd;
  630. } else {
  631. fcgi_close(req, 1, 1);
  632. }
  633. }
  634. }
  635. static inline fcgi_header* open_packet(fcgi_request *req, fcgi_request_type type)
  636. {
  637. req->out_hdr = (fcgi_header*) req->out_pos;
  638. req->out_hdr->type = type;
  639. req->out_pos += sizeof(fcgi_header);
  640. return req->out_hdr;
  641. }
  642. static inline void close_packet(fcgi_request *req)
  643. {
  644. if (req->out_hdr) {
  645. int len = req->out_pos - ((unsigned char*)req->out_hdr + sizeof(fcgi_header));
  646. req->out_pos += fcgi_make_header(req->out_hdr, (fcgi_request_type)req->out_hdr->type, req->id, len);
  647. req->out_hdr = NULL;
  648. }
  649. }
  650. int fcgi_flush(fcgi_request *req, int close)
  651. {
  652. int len;
  653. close_packet(req);
  654. len = req->out_pos - req->out_buf;
  655. if (close) {
  656. fcgi_end_request_rec *rec = (fcgi_end_request_rec*)(req->out_pos);
  657. fcgi_make_header(&rec->hdr, FCGI_END_REQUEST, req->id, sizeof(fcgi_end_request));
  658. rec->body.appStatusB3 = 0;
  659. rec->body.appStatusB2 = 0;
  660. rec->body.appStatusB1 = 0;
  661. rec->body.appStatusB0 = 0;
  662. rec->body.protocolStatus = FCGI_REQUEST_COMPLETE;
  663. len += sizeof(fcgi_end_request_rec);
  664. }
  665. if (safe_write(req, req->out_buf, len) != len) {
  666. req->keep = 0;
  667. return 0;
  668. }
  669. req->out_pos = req->out_buf;
  670. return 1;
  671. }
  672. int fcgi_write(fcgi_request *req, fcgi_request_type type, const char *str, int len)
  673. {
  674. int limit, rest;
  675. if (len <= 0) {
  676. return 0;
  677. }
  678. if (req->out_hdr && req->out_hdr->type != type) {
  679. close_packet(req);
  680. }
  681. #if 0
  682. /* Unoptimized, but clear version */
  683. rest = len;
  684. while (rest > 0) {
  685. limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
  686. if (!req->out_hdr) {
  687. if (limit < sizeof(fcgi_header)) {
  688. if (!fcgi_flush(req, 0)) {
  689. return -1;
  690. }
  691. }
  692. open_packet(req, type);
  693. }
  694. limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
  695. if (rest < limit) {
  696. memcpy(req->out_pos, str, rest);
  697. req->out_pos += rest;
  698. return len;
  699. } else {
  700. memcpy(req->out_pos, str, limit);
  701. req->out_pos += limit;
  702. rest -= limit;
  703. str += limit;
  704. if (!fcgi_flush(req, 0)) {
  705. return -1;
  706. }
  707. }
  708. }
  709. #else
  710. /* Optimized version */
  711. limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
  712. if (!req->out_hdr) {
  713. limit -= sizeof(fcgi_header);
  714. if (limit < 0) limit = 0;
  715. }
  716. if (len < limit) {
  717. if (!req->out_hdr) {
  718. open_packet(req, type);
  719. }
  720. memcpy(req->out_pos, str, len);
  721. req->out_pos += len;
  722. } else if (len - limit < sizeof(req->out_buf) - sizeof(fcgi_header)) {
  723. if (!req->out_hdr) {
  724. open_packet(req, type);
  725. }
  726. if (limit > 0) {
  727. memcpy(req->out_pos, str, limit);
  728. req->out_pos += limit;
  729. }
  730. if (!fcgi_flush(req, 0)) {
  731. return -1;
  732. }
  733. if (len > limit) {
  734. open_packet(req, type);
  735. memcpy(req->out_pos, str + limit, len - limit);
  736. req->out_pos += len - limit;
  737. }
  738. } else {
  739. int pos = 0;
  740. int pad;
  741. close_packet(req);
  742. while ((len - pos) > 0xffff) {
  743. open_packet(req, type);
  744. fcgi_make_header(req->out_hdr, type, req->id, 0xfff8);
  745. req->out_hdr = NULL;
  746. if (!fcgi_flush(req, 0)) {
  747. return -1;
  748. }
  749. if (safe_write(req, str + pos, 0xfff8) != 0xfff8) {
  750. req->keep = 0;
  751. return -1;
  752. }
  753. pos += 0xfff8;
  754. }
  755. pad = (((len - pos) + 7) & ~7) - (len - pos);
  756. rest = pad ? 8 - pad : 0;
  757. open_packet(req, type);
  758. fcgi_make_header(req->out_hdr, type, req->id, (len - pos) - rest);
  759. req->out_hdr = NULL;
  760. if (!fcgi_flush(req, 0)) {
  761. return -1;
  762. }
  763. if (safe_write(req, str + pos, (len - pos) - rest) != (len - pos) - rest) {
  764. req->keep = 0;
  765. return -1;
  766. }
  767. if (pad) {
  768. open_packet(req, type);
  769. memcpy(req->out_pos, str + len - rest, rest);
  770. req->out_pos += rest;
  771. }
  772. }
  773. #endif
  774. return len;
  775. }
  776. int fcgi_finish_request(fcgi_request *req)
  777. {
  778. if (req->fd >= 0) {
  779. fcgi_flush(req, 1);
  780. fcgi_close(req, 0, 1);
  781. }
  782. return 1;
  783. }
  784. char* fcgi_getenv(fcgi_request *req, const char* var, int var_len)
  785. {
  786. char **val;
  787. if (!req) return NULL;
  788. if (zend_hash_find(&req->env, (char*)var, var_len+1, (void**)&val) == SUCCESS) {
  789. return *val;
  790. }
  791. return NULL;
  792. }
  793. char* fcgi_putenv(fcgi_request *req, char* var, int var_len, char* val)
  794. {
  795. if (var && req) {
  796. char **ret;
  797. if (val == NULL) {
  798. val = "";
  799. }
  800. val = strdup(val);
  801. if (zend_hash_update(&req->env, var, var_len+1, &val, sizeof(char*), (void**)&ret) == SUCCESS) {
  802. return *ret;
  803. }
  804. }
  805. return NULL;
  806. }
  807. #ifdef _WIN32
  808. void fcgi_impersonate(void)
  809. {
  810. char *os_name;
  811. os_name = getenv("OS");
  812. if (os_name && stricmp(os_name, "Windows_NT") == 0) {
  813. is_impersonate = 1;
  814. }
  815. }
  816. #endif
  817. /*
  818. * Local variables:
  819. * tab-width: 4
  820. * c-basic-offset: 4
  821. * End:
  822. * vim600: sw=4 ts=4 fdm=marker
  823. * vim<600: sw=4 ts=4
  824. */