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.

924 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 sa_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. sa_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. sa_len = (size_t)(((struct sockaddr_un *)0)->sun_path) + path_len;
  259. #ifdef HAVE_SOCKADDR_UN_SUN_LEN
  260. sa.sa_unix.sun_len = sa_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, sa_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 void fcgi_get_params(fcgi_request *req, unsigned char *p, unsigned char *end)
  336. {
  337. char buf[128];
  338. char *tmp = buf;
  339. size_t buf_size = sizeof(buf);
  340. int name_len, val_len;
  341. char *s;
  342. while (p < end) {
  343. name_len = *p++;
  344. if (name_len >= 128) {
  345. name_len = ((name_len & 0x7f) << 24);
  346. name_len |= (*p++ << 16);
  347. name_len |= (*p++ << 8);
  348. name_len |= *p++;
  349. }
  350. val_len = *p++;
  351. if (val_len >= 128) {
  352. val_len = ((val_len & 0x7f) << 24);
  353. val_len |= (*p++ << 16);
  354. val_len |= (*p++ << 8);
  355. val_len |= *p++;
  356. }
  357. if (name_len+1 >= buf_size) {
  358. buf_size = name_len + 64;
  359. tmp = (tmp == buf ? emalloc(buf_size): erealloc(tmp, buf_size));
  360. }
  361. memcpy(tmp, p, name_len);
  362. tmp[name_len] = 0;
  363. s = zend_strndup((char*)p + name_len, val_len);
  364. zend_hash_update(&req->env, tmp, name_len+1, &s, sizeof(char*), NULL);
  365. p += name_len + val_len;
  366. }
  367. if (tmp != buf && tmp != NULL) {
  368. efree(tmp);
  369. }
  370. }
  371. static void fcgi_free_var(char **s)
  372. {
  373. free(*s);
  374. }
  375. static int fcgi_read_request(fcgi_request *req)
  376. {
  377. fcgi_header hdr;
  378. int len, padding;
  379. unsigned char buf[FCGI_MAX_LENGTH+8];
  380. req->keep = 0;
  381. req->in_len = 0;
  382. req->out_hdr = NULL;
  383. req->out_pos = req->out_buf;
  384. zend_hash_init(&req->env, 0, NULL, (void (*)(void *)) fcgi_free_var, 1);
  385. if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
  386. hdr.version < FCGI_VERSION_1) {
  387. return 0;
  388. }
  389. len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
  390. padding = hdr.paddingLength;
  391. while (hdr.type == FCGI_STDIN && len == 0) {
  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. }
  399. req->id = (hdr.requestIdB1 << 8) + hdr.requestIdB0;
  400. if (hdr.type == FCGI_BEGIN_REQUEST && len == sizeof(fcgi_begin_request)) {
  401. char *val;
  402. if (safe_read(req, buf, len+padding) != len+padding) {
  403. return 0;
  404. }
  405. req->keep = (((fcgi_begin_request*)buf)->flags & FCGI_KEEP_CONN);
  406. switch ((((fcgi_begin_request*)buf)->roleB1 << 8) + ((fcgi_begin_request*)buf)->roleB0) {
  407. case FCGI_RESPONDER:
  408. val = strdup("RESPONDER");
  409. zend_hash_update(&req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
  410. break;
  411. case FCGI_AUTHORIZER:
  412. val = strdup("AUTHORIZER");
  413. zend_hash_update(&req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
  414. break;
  415. case FCGI_FILTER:
  416. val = strdup("FILTER");
  417. zend_hash_update(&req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
  418. break;
  419. default:
  420. return 0;
  421. }
  422. if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
  423. hdr.version < FCGI_VERSION_1) {
  424. return 0;
  425. }
  426. len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
  427. padding = hdr.paddingLength;
  428. while (hdr.type == FCGI_PARAMS && len > 0) {
  429. if (safe_read(req, buf, len+padding) != len+padding) {
  430. req->keep = 0;
  431. return 0;
  432. }
  433. fcgi_get_params(req, buf, buf+len);
  434. if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
  435. hdr.version < FCGI_VERSION_1) {
  436. req->keep = 0;
  437. return 0;
  438. }
  439. len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
  440. padding = hdr.paddingLength;
  441. }
  442. } else if (hdr.type == FCGI_GET_VALUES) {
  443. int j;
  444. unsigned char *p = buf + sizeof(fcgi_header);
  445. if (safe_read(req, buf, len+padding) != len+padding) {
  446. return 0;
  447. }
  448. fcgi_get_params(req, buf, buf+len);
  449. for (j = 0; j < sizeof(fcgi_mgmt_vars)/sizeof(fcgi_mgmt_vars[0]); j++) {
  450. if (zend_hash_exists(&req->env, fcgi_mgmt_vars[j].name, fcgi_mgmt_vars[j].name_len+1) == 0) {
  451. sprintf((char*)p, "%c%c%s%c", fcgi_mgmt_vars[j].name_len, 1, fcgi_mgmt_vars[j].name, fcgi_mgmt_vars[j].val);
  452. p += fcgi_mgmt_vars[j].name_len + 3;
  453. }
  454. }
  455. len = p - buf - sizeof(fcgi_header);
  456. len += fcgi_make_header((fcgi_header*)buf, FCGI_GET_VALUES_RESULT, 0, len);
  457. if (safe_write(req, buf, sizeof(fcgi_header)+len) != (int)sizeof(fcgi_header)+len) {
  458. return 0;
  459. }
  460. return 0;
  461. } else {
  462. return 0;
  463. }
  464. return 1;
  465. }
  466. int fcgi_read(fcgi_request *req, char *str, int len)
  467. {
  468. int ret, n, rest;
  469. fcgi_header hdr;
  470. unsigned char buf[8];
  471. n = 0;
  472. rest = len;
  473. while (rest > 0) {
  474. if (req->in_len == 0) {
  475. if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
  476. hdr.version < FCGI_VERSION_1 ||
  477. hdr.type != FCGI_STDIN) {
  478. req->keep = 0;
  479. return 0;
  480. }
  481. req->in_len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
  482. req->in_pad = hdr.paddingLength;
  483. if (req->in_len == 0) {
  484. return n;
  485. }
  486. }
  487. if (req->in_len >= rest) {
  488. ret = safe_read(req, str, rest);
  489. } else {
  490. ret = safe_read(req, str, req->in_len);
  491. }
  492. if (ret < 0) {
  493. req->keep = 0;
  494. return ret;
  495. } else if (ret > 0) {
  496. req->in_len -= ret;
  497. rest -= ret;
  498. n += ret;
  499. str += ret;
  500. if (req->in_len == 0) {
  501. if (req->in_pad) {
  502. if (safe_read(req, buf, req->in_pad) != req->in_pad) {
  503. req->keep = 0;
  504. return ret;
  505. }
  506. }
  507. } else {
  508. return n;
  509. }
  510. } else {
  511. return n;
  512. }
  513. }
  514. return n;
  515. }
  516. static inline void fcgi_close(fcgi_request *req, int force, int destroy)
  517. {
  518. if (destroy) {
  519. zend_hash_destroy(&req->env);
  520. }
  521. if ((force || !req->keep) && req->fd >= 0) {
  522. #ifdef _WIN32
  523. HANDLE pipe = (HANDLE)_get_osfhandle(req->fd);
  524. if (!force) {
  525. FlushFileBuffers(pipe);
  526. }
  527. DisconnectNamedPipe(pipe);
  528. if (is_impersonate) {
  529. RevertToSelf();
  530. }
  531. #else
  532. char buf[8];
  533. shutdown(req->fd, 1);
  534. while (recv(req->fd, buf, sizeof(buf), 0) > 0) {}
  535. close(req->fd);
  536. #endif
  537. req->fd = -1;
  538. }
  539. }
  540. int fcgi_accept_request(fcgi_request *req)
  541. {
  542. #ifdef _WIN32
  543. HANDLE pipe;
  544. OVERLAPPED ov;
  545. #endif
  546. fcgi_finish_request(req);
  547. while (1) {
  548. if (req->fd < 0) {
  549. while (1) {
  550. if (in_shutdown) {
  551. return -1;
  552. }
  553. #ifdef _WIN32
  554. pipe = (HANDLE)_get_osfhandle(req->listen_socket);
  555. FCGI_LOCK(req->listen_socket);
  556. ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  557. if (!ConnectNamedPipe(pipe, &ov)) {
  558. errno = GetLastError();
  559. if (errno == ERROR_IO_PENDING) {
  560. while (WaitForSingleObject(ov.hEvent, 1000) == WAIT_TIMEOUT) {
  561. if (in_shutdown) {
  562. CloseHandle(ov.hEvent);
  563. FCGI_UNLOCK(req->listen_socket);
  564. return -1;
  565. }
  566. }
  567. } else if (errno != ERROR_PIPE_CONNECTED) {
  568. }
  569. }
  570. CloseHandle(ov.hEvent);
  571. if (is_impersonate && !ImpersonateNamedPipeClient(pipe)) {
  572. DisconnectNamedPipe(pipe);
  573. req->fd = -1;
  574. } else {
  575. req->fd = req->listen_socket;
  576. }
  577. FCGI_UNLOCK(req->listen_socket);
  578. #else
  579. {
  580. sa_t sa;
  581. socklen_t len = sizeof(sa);
  582. FCGI_LOCK(req->listen_socket);
  583. req->fd = accept(req->listen_socket, (struct sockaddr *)&sa, &len);
  584. FCGI_UNLOCK(req->listen_socket);
  585. }
  586. #endif
  587. if (req->fd < 0 && (in_shutdown || errno != EINTR)) {
  588. return -1;
  589. }
  590. #ifdef _WIN32
  591. break;
  592. #else
  593. if (req->fd >= 0) {
  594. struct timeval tv = {1,0};
  595. fd_set set;
  596. FD_ZERO(&set);
  597. FD_SET(req->fd, &set);
  598. try_again:
  599. errno = 0;
  600. if (select(req->fd + 1, &set, NULL, NULL, &tv) >= 0 && FD_ISSET(req->fd, &set)) {
  601. break;
  602. }
  603. if (errno == EINTR) goto try_again;
  604. fcgi_close(req, 1, 0);
  605. }
  606. #endif
  607. }
  608. } else if (in_shutdown) {
  609. return -1;
  610. }
  611. if (fcgi_read_request(req)) {
  612. return req->fd;
  613. } else {
  614. fcgi_close(req, 1, 1);
  615. }
  616. }
  617. }
  618. static inline fcgi_header* open_packet(fcgi_request *req, fcgi_request_type type)
  619. {
  620. req->out_hdr = (fcgi_header*) req->out_pos;
  621. req->out_hdr->type = type;
  622. req->out_pos += sizeof(fcgi_header);
  623. return req->out_hdr;
  624. }
  625. static inline void close_packet(fcgi_request *req)
  626. {
  627. if (req->out_hdr) {
  628. int len = req->out_pos - ((unsigned char*)req->out_hdr + sizeof(fcgi_header));
  629. req->out_pos += fcgi_make_header(req->out_hdr, (fcgi_request_type)req->out_hdr->type, req->id, len);
  630. req->out_hdr = NULL;
  631. }
  632. }
  633. int fcgi_flush(fcgi_request *req, int close)
  634. {
  635. int len;
  636. close_packet(req);
  637. len = req->out_pos - req->out_buf;
  638. if (close) {
  639. fcgi_end_request_rec *rec = (fcgi_end_request_rec*)(req->out_pos);
  640. fcgi_make_header(&rec->hdr, FCGI_END_REQUEST, req->id, sizeof(fcgi_end_request));
  641. rec->body.appStatusB3 = 0;
  642. rec->body.appStatusB2 = 0;
  643. rec->body.appStatusB1 = 0;
  644. rec->body.appStatusB0 = 0;
  645. rec->body.protocolStatus = FCGI_REQUEST_COMPLETE;
  646. len += sizeof(fcgi_end_request_rec);
  647. }
  648. if (safe_write(req, req->out_buf, len) != len) {
  649. req->keep = 0;
  650. return 0;
  651. }
  652. req->out_pos = req->out_buf;
  653. return 1;
  654. }
  655. int fcgi_write(fcgi_request *req, fcgi_request_type type, const char *str, int len)
  656. {
  657. int limit, rest;
  658. if (len <= 0) {
  659. return 0;
  660. }
  661. if (req->out_hdr && req->out_hdr->type != type) {
  662. close_packet(req);
  663. }
  664. #if 0
  665. /* Unoptimized, but clear version */
  666. rest = len;
  667. while (rest > 0) {
  668. limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
  669. if (!req->out_hdr) {
  670. if (limit < sizeof(fcgi_header)) {
  671. if (!fcgi_flush(req, 0)) {
  672. return -1;
  673. }
  674. }
  675. open_packet(req, type);
  676. }
  677. limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
  678. if (rest < limit) {
  679. memcpy(req->out_pos, str, rest);
  680. req->out_pos += rest;
  681. return len;
  682. } else {
  683. memcpy(req->out_pos, str, limit);
  684. req->out_pos += limit;
  685. rest -= limit;
  686. str += limit;
  687. if (!fcgi_flush(req, 0)) {
  688. return -1;
  689. }
  690. }
  691. }
  692. #else
  693. /* Optimized version */
  694. limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
  695. if (!req->out_hdr) {
  696. limit -= sizeof(fcgi_header);
  697. if (limit < 0) limit = 0;
  698. }
  699. if (len < limit) {
  700. if (!req->out_hdr) {
  701. open_packet(req, type);
  702. }
  703. memcpy(req->out_pos, str, len);
  704. req->out_pos += len;
  705. } else if (len - limit < sizeof(req->out_buf) - sizeof(fcgi_header)) {
  706. if (!req->out_hdr) {
  707. open_packet(req, type);
  708. }
  709. if (limit > 0) {
  710. memcpy(req->out_pos, str, limit);
  711. req->out_pos += limit;
  712. }
  713. if (!fcgi_flush(req, 0)) {
  714. return -1;
  715. }
  716. if (len > limit) {
  717. open_packet(req, type);
  718. memcpy(req->out_pos, str + limit, len - limit);
  719. req->out_pos += len - limit;
  720. }
  721. } else {
  722. int pos = 0;
  723. int pad;
  724. close_packet(req);
  725. while ((len - pos) > 0xffff) {
  726. open_packet(req, type);
  727. fcgi_make_header(req->out_hdr, type, req->id, 0xfff8);
  728. req->out_hdr = NULL;
  729. if (!fcgi_flush(req, 0)) {
  730. return -1;
  731. }
  732. if (safe_write(req, str + pos, 0xfff8) != 0xfff8) {
  733. req->keep = 0;
  734. return -1;
  735. }
  736. pos += 0xfff8;
  737. }
  738. pad = (((len - pos) + 7) & ~7) - (len - pos);
  739. rest = pad ? 8 - pad : 0;
  740. open_packet(req, type);
  741. fcgi_make_header(req->out_hdr, type, req->id, (len - pos) - rest);
  742. req->out_hdr = NULL;
  743. if (!fcgi_flush(req, 0)) {
  744. return -1;
  745. }
  746. if (safe_write(req, str + pos, (len - pos) - rest) != (len - pos) - rest) {
  747. req->keep = 0;
  748. return -1;
  749. }
  750. if (pad) {
  751. open_packet(req, type);
  752. memcpy(req->out_pos, str + len - rest, rest);
  753. req->out_pos += rest;
  754. }
  755. }
  756. #endif
  757. return len;
  758. }
  759. int fcgi_finish_request(fcgi_request *req)
  760. {
  761. if (req->fd >= 0) {
  762. fcgi_flush(req, 1);
  763. fcgi_close(req, 0, 1);
  764. }
  765. return 1;
  766. }
  767. char* fcgi_getenv(fcgi_request *req, const char* var, int var_len)
  768. {
  769. char **val;
  770. if (!req) return NULL;
  771. if (zend_hash_find(&req->env, (char*)var, var_len+1, (void**)&val) == SUCCESS) {
  772. return *val;
  773. }
  774. return NULL;
  775. }
  776. char* fcgi_putenv(fcgi_request *req, char* var, int var_len, char* val)
  777. {
  778. if (var && req) {
  779. char **ret;
  780. if (val == NULL) {
  781. val = "";
  782. }
  783. val = strdup(val);
  784. if (zend_hash_update(&req->env, var, var_len+1, &val, sizeof(char*), (void**)&ret) == SUCCESS) {
  785. return *ret;
  786. }
  787. }
  788. return NULL;
  789. }
  790. #ifdef _WIN32
  791. void fcgi_impersonate(void)
  792. {
  793. char *os_name;
  794. os_name = getenv("OS");
  795. if (os_name && stricmp(os_name, "Windows_NT") == 0) {
  796. is_impersonate = 1;
  797. }
  798. }
  799. #endif
  800. /*
  801. * Local variables:
  802. * tab-width: 4
  803. * c-basic-offset: 4
  804. * End:
  805. * vim600: sw=4 ts=4 fdm=marker
  806. * vim<600: sw=4 ts=4
  807. */