SCGI application to run cgi applications https://redmine.lighttpd.net/projects/scgi-cgi
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.
 
 
 
 
 
 

1264 lines
36 KiB

  1. #ifdef HAVE_CONFIG_H
  2. #include "config.h"
  3. #endif
  4. #include <errno.h>
  5. #include <fcntl.h>
  6. #include <limits.h>
  7. #include <signal.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <sys/socket.h>
  12. #include <sys/stat.h>
  13. #include <sys/types.h>
  14. #include <sys/wait.h>
  15. #include <unistd.h>
  16. #include <event2/event.h>
  17. #define MAX_BUFFER_SIZE (64u*1024u)
  18. #define MAX_STRING_BUFFER_SIZE (64u*1024u) /* env keys and values */
  19. #define CONST_STR_LEN(x) (x), sizeof(x) - 1
  20. #define GSTR_LEN(x) (x) ? (x)->str : "", (x) ? (x)->len : 0
  21. #define UNUSED(x) ((void)(x))
  22. #ifdef __GNUC__
  23. #define ATTR_WARN_UNUSED_RESULT \
  24. __attribute__((warn_unused_result))
  25. #define ATTR_FORMAT(fmt, args) \
  26. __attribute__(( format(printf, fmt, args) ))
  27. #else
  28. #define ATTR_WARN_UNUSED_RESULT
  29. #define ATTR_FORMAT(fmt, args)
  30. #endif
  31. #define ERROR(...) printerr(__LINE__, __VA_ARGS__)
  32. #ifdef NDEBUG
  33. # define DEBUG(...) do { } while (0)
  34. #else
  35. # define DEBUG(...) printerr(__LINE__, "DEBUG: " __VA_ARGS__)
  36. #endif
  37. #define PACKAGE_DESC PACKAGE_NAME " v" PACKAGE_VERSION " - SCGI application to run normal cgi applications"
  38. /* force asserts to be enabled */
  39. #undef NDEBUG
  40. #include <assert.h>
  41. /****************************************************************************
  42. * logging *
  43. ***************************************************************************/
  44. static void printerr(unsigned int line, const char *fmt, ...) ATTR_FORMAT(2, 3);
  45. static void printerr(unsigned int line, const char *fmt, ...) {
  46. va_list ap;
  47. fprintf(stderr, "scgi-cgi.c:%u:", line);
  48. va_start(ap, fmt);
  49. vfprintf(stderr, fmt, ap);
  50. va_end(ap);
  51. fprintf(stderr, "\n");
  52. }
  53. /****************************************************************************
  54. * STRING BUFFER *
  55. ***************************************************************************/
  56. typedef struct string_buffer string_buffer;
  57. struct string_buffer {
  58. /* always 0-terminated string (unless data == NULL), but don't count terminating 0 in `used' */
  59. unsigned char *data;
  60. unsigned int used, size;
  61. };
  62. static void string_buffer_init(string_buffer *buf);
  63. static void string_buffer_clear(string_buffer *buf);
  64. static unsigned char* string_buffer_extract(string_buffer *buf) ATTR_WARN_UNUSED_RESULT; /* resets buffer, returns string. free string with free() */
  65. static int string_buffer_reserve(string_buffer *buf, unsigned int len) ATTR_WARN_UNUSED_RESULT;
  66. static int string_buffer_append(string_buffer *buf, const unsigned char *data, unsigned int len) ATTR_WARN_UNUSED_RESULT;
  67. static int string_buffer_append_char(string_buffer *buf, unsigned char c) ATTR_WARN_UNUSED_RESULT;
  68. static int string_buffer_equal(string_buffer *buf, const char *data, unsigned int len);
  69. #define STRING_BUFFER_EQUAL(buf, str) string_buffer_equal(buf, str, sizeof(str) - 1)
  70. static void string_buffer_init(string_buffer *buf) {
  71. buf->data = NULL;
  72. buf->used = buf->size = 0;
  73. }
  74. static void string_buffer_clear(string_buffer *buf) {
  75. if (NULL != buf->data) free(buf->data);
  76. buf->data = NULL;
  77. buf->used = buf->size = 0;
  78. }
  79. static unsigned char* string_buffer_extract(string_buffer *buf) {
  80. unsigned char *str = buf->data;
  81. string_buffer_init(buf);
  82. return str;
  83. }
  84. static int string_buffer_reserve(string_buffer *buf, unsigned int len) {
  85. assert(buf->used <= buf->size);
  86. assert(buf->size <= MAX_STRING_BUFFER_SIZE);
  87. if (1 > UINT_MAX - len || len + 1 > MAX_STRING_BUFFER_SIZE - buf->used) {
  88. DEBUG("string buffer: overflow");
  89. return 0;
  90. }
  91. unsigned int newlen = buf->used + len;
  92. if (newlen + 1 > buf->size) {
  93. unsigned int need_size = newlen + 1;
  94. unsigned int want_size = (need_size + 127) & ~127; /* round up to next multiple of 128 */
  95. unsigned char *newdata;
  96. if (want_size < need_size) want_size = need_size; /* overflow handling */
  97. newdata = (unsigned char*) realloc(buf->data, want_size);
  98. if (NULL == newdata) {
  99. DEBUG("string buffer: realloc failed");
  100. return 0;
  101. }
  102. buf->data = newdata;
  103. buf->size = want_size;
  104. }
  105. return 1;
  106. }
  107. static int string_buffer_append(string_buffer *buf, const unsigned char *data, unsigned int len) {
  108. if (!string_buffer_reserve(buf, len)) return 0;
  109. if (len > 0) memcpy(buf->data + buf->used, data, len);
  110. buf->used += len;
  111. buf->data[buf->used] = '\0';
  112. return 1;
  113. }
  114. static int string_buffer_append_char(string_buffer *buf, unsigned char c) {
  115. if (!string_buffer_reserve(buf, 1)) return 0;
  116. buf->data[buf->used++] = c;
  117. buf->data[buf->used] = '\0';
  118. return 1;
  119. }
  120. static int string_buffer_equal(string_buffer *buf, const char *data, unsigned int len) {
  121. if (buf->used != len) return 0;
  122. if (0 == len) return 1;
  123. return 0 == memcmp(buf->data, data, len);
  124. }
  125. /****************************************************************************
  126. * SCGI PARSER *
  127. ***************************************************************************/
  128. typedef enum scgi_req_parser_state {
  129. SCGI_REQ_PARSER_HEADER_LEN,
  130. SCGI_REQ_PARSER_HEADER_ENV_KEY,
  131. SCGI_REQ_PARSER_HEADER_ENV_VALUE,
  132. SCGI_REQ_PARSER_HEADER_DONE,
  133. SCGI_REQ_PARSER_HEADER_ERROR
  134. } scgi_req_parser_state;
  135. typedef struct scgi_req_parser scgi_req_parser;
  136. struct scgi_req_parser {
  137. scgi_req_parser_state state;
  138. unsigned int header_length, is_scgi;
  139. unsigned long long content_length;
  140. unsigned char **environ; /* list terminated by NULL entry */
  141. unsigned int environ_used, environ_size;
  142. string_buffer key_value;
  143. unsigned int key_length;
  144. };
  145. static int key_value_has_key(scgi_req_parser *parser, char *key, unsigned int keylen);
  146. static void scgi_parser_init(scgi_req_parser *parser);
  147. static void scgi_parser_clear(scgi_req_parser *parser);
  148. static void scgi_parser_clear_environment(scgi_req_parser *parser);
  149. static int scgi_parser_environ_reserve(scgi_req_parser *parser);
  150. static int scgi_parser_environ_append(scgi_req_parser *parser, unsigned char *kvstr, int keylength);
  151. static int scgi_parser_environ_copy(scgi_req_parser *parser, const char *key, unsigned int keylength);
  152. static const char* scgi_parser_environ_get(scgi_req_parser *parser, const char *key, unsigned int keylength);
  153. static int scgi_parse(scgi_req_parser *parser, unsigned char *data, int len) ATTR_WARN_UNUSED_RESULT;
  154. static int key_value_has_key(scgi_req_parser *parser, char *key, unsigned int keylen) {
  155. if (parser->key_length != keylen) return 0;
  156. return 0 == memcmp(parser->key_value.data, key, keylen);
  157. }
  158. #define KEY_VALUE_HAS_KEY(parser, key) key_value_has_key(parser, key, sizeof(key) - 1)
  159. static void scgi_parser_init(scgi_req_parser *parser) {
  160. parser->state = SCGI_REQ_PARSER_HEADER_LEN;
  161. parser->header_length = parser->content_length = parser->is_scgi = 0;
  162. parser->environ = NULL;
  163. parser->environ_used = parser->environ_size = 0;
  164. string_buffer_init(&parser->key_value);
  165. parser->key_length = 0;
  166. }
  167. static void scgi_parser_clear(scgi_req_parser *parser) {
  168. unsigned int i;
  169. for (i = 0; i < parser->environ_used; ++i) {
  170. free(parser->environ[i]);
  171. }
  172. free(parser->environ);
  173. string_buffer_clear(&parser->key_value);
  174. parser->state = SCGI_REQ_PARSER_HEADER_LEN;
  175. parser->header_length = parser->content_length = parser->is_scgi = 0;
  176. parser->environ = NULL;
  177. parser->environ_used = parser->environ_size = 0;
  178. parser->key_length = 0;
  179. }
  180. static void scgi_parser_clear_environment(scgi_req_parser *parser) {
  181. unsigned int i;
  182. for (i = 0; i < parser->environ_used; ++i) {
  183. free(parser->environ[i]);
  184. }
  185. free(parser->environ);
  186. parser->environ = NULL;
  187. parser->environ_used = parser->environ_size = 0;
  188. }
  189. static int scgi_parser_environ_reserve(scgi_req_parser *parser) {
  190. if (2 > UINT_MAX/sizeof(unsigned char*) - parser->environ_used) {
  191. DEBUG("scgi environment: entries overflow");
  192. return 0; /* overflow: can't append */
  193. }
  194. if (parser->environ_used + 2 > parser->environ_size) {
  195. unsigned int need_size = sizeof(unsigned char*) * (parser->environ_used + 2);
  196. unsigned int want_size = (need_size + 1024) & ~1023; /* round up to next multiple of 1023 (for 8-byte pointers: 128 entries) */
  197. unsigned char **newdata;
  198. if (want_size < need_size) want_size = need_size; /* overflow handling */
  199. newdata = (unsigned char**) realloc(parser->environ, want_size);
  200. if (NULL == newdata) {
  201. DEBUG("scgi environment: realloc failed");
  202. return 0; /* ENOMEM */
  203. }
  204. parser->environ = newdata;
  205. parser->environ_size = want_size / sizeof(unsigned char*);
  206. }
  207. return 1;
  208. }
  209. /* kvstr: "KEY=VALUE", keylength = strlen("KEY")
  210. * return values: 0: not appended: key already exists (not overwriting), or some other error; 1: appended
  211. * kvstr is free()d if it wasn't appended.
  212. */
  213. static int scgi_parser_environ_append(scgi_req_parser *parser, unsigned char *kvstr, int keylength) {
  214. unsigned int i;
  215. for (i = 0; i < parser->environ_used; ++i) {
  216. const char *e = (const char*) parser->environ[i];
  217. if (0 == strncmp(e, (const char *) kvstr, keylength + 1)) {
  218. DEBUG("scgi req header: duplicate key for entry '%s', already have '%s'", kvstr, e);
  219. goto fail; /* found */
  220. }
  221. }
  222. if (!scgi_parser_environ_reserve(parser)) goto fail;
  223. parser->environ[parser->environ_used++] = kvstr;
  224. parser->environ[parser->environ_used] = NULL;
  225. return 1;
  226. fail:
  227. free(kvstr);
  228. return 0;
  229. }
  230. static int scgi_parser_environ_copy(scgi_req_parser *parser, const char *key, unsigned int keylength) {
  231. const char *val = getenv(key);
  232. unsigned int vallen;
  233. unsigned char *kvstr;
  234. unsigned int i;
  235. if (NULL == val) return 1;
  236. vallen = strlen(val);
  237. kvstr = malloc(keylength + 2 + vallen);
  238. if (NULL == kvstr) return 0;
  239. memcpy(kvstr, key, keylength);
  240. kvstr[keylength] = '=';
  241. memcpy(kvstr + keylength + 1, val, vallen + 1);
  242. for (i = 0; i < parser->environ_used; ++i) {
  243. const char *e = (const char*) parser->environ[i];
  244. if (0 == strncmp(e, (const char *) kvstr, keylength + 1)) {
  245. /* found. overwrite: */
  246. free(parser->environ[i]);
  247. parser->environ[i] = kvstr;
  248. }
  249. }
  250. if (!scgi_parser_environ_reserve(parser)) {
  251. free(kvstr);
  252. return 0;
  253. }
  254. parser->environ[parser->environ_used++] = kvstr;
  255. parser->environ[parser->environ_used] = NULL;
  256. return 1;
  257. }
  258. static const char* scgi_parser_environ_get(scgi_req_parser *parser, const char *key, unsigned int keylength) {
  259. unsigned int i;
  260. for (i = 0; i < parser->environ_used; ++i) {
  261. const char *e = (const char*) parser->environ[i];
  262. if (0 == strncmp(e, (const char *) key, keylength) && '=' == e[keylength]) {
  263. return (const char*) e + keylength + 1;
  264. }
  265. }
  266. return NULL;
  267. }
  268. /* return values:
  269. * -2: error
  270. * -1: need more data for header
  271. * l>=0: trailing l bytes of data are request body data; header finished.
  272. */
  273. static int scgi_parse(scgi_req_parser *parser, unsigned char *data, int len) {
  274. assert(len > 0);
  275. for (; len > 0; ++data, --len) {
  276. unsigned char c = *data;
  277. switch (parser->state) {
  278. case SCGI_REQ_PARSER_HEADER_LEN:
  279. {
  280. unsigned int digit;
  281. if (c == ':') {
  282. /* require at least 'CONTENT_LENGTH=0;SCGI=1;' in header ('=' and ';' encoded as '\0') */
  283. if (parser->header_length < 24) {
  284. DEBUG("scgi req header too small: %u", parser->header_length);
  285. goto fail;
  286. }
  287. parser->state = SCGI_REQ_PARSER_HEADER_ENV_KEY;
  288. break;
  289. }
  290. if (c < '0' || c > '9') {
  291. DEBUG("scgi req header: expected digit or ':' in header length, got '%c'", c);
  292. goto fail;
  293. }
  294. if (0 == parser->header_length && c == '0') {
  295. /* extra leading zeroes are prohibited; zero header length is not permitted either:
  296. * require CONTENT_LENGTH and SCGI vars
  297. * => starting 0 digit is never allowed
  298. */
  299. DEBUG("scgi req header: header length starting with 0");
  300. goto fail;
  301. }
  302. digit = c - '0';
  303. if (parser->header_length > UINT_MAX / 10 - digit) {
  304. DEBUG("scgi req header: header length overflow");
  305. goto fail; /* overflow */
  306. }
  307. parser->header_length = 10*parser->header_length + digit;
  308. }
  309. break;
  310. case SCGI_REQ_PARSER_HEADER_ENV_KEY:
  311. if (0 == parser->header_length) {
  312. if (',' != c) {
  313. DEBUG("scgi req header: require ',' before request body, got '%c'", c);
  314. goto fail; /* after header require a ',' */
  315. }
  316. if (0 != parser->key_value.used) {
  317. DEBUG("scgi req header: headers ended with partial key '%s'", parser->key_value.data);
  318. goto fail; /* partial header on headers end */
  319. }
  320. if (!parser->is_scgi) {
  321. DEBUG("scgi req header: missing SCGI=1");
  322. goto fail; /* is_scgi is only set after CONTENT_LENGTH (always first header) is parsed, and then SCGI=1 was found */
  323. }
  324. parser->state = SCGI_REQ_PARSER_HEADER_DONE;
  325. return len - 1;
  326. }
  327. --parser->header_length;
  328. if (0 != c) {
  329. if ('=' == c) {
  330. DEBUG("scgi req header: key must not include '='");
  331. goto fail; /* '=' can't be allowed in keys */
  332. }
  333. if (!string_buffer_append_char(&parser->key_value, c)) goto fail;
  334. break;
  335. }
  336. /* key end */
  337. parser->key_length = parser->key_value.used;
  338. if (!string_buffer_append_char(&parser->key_value, '=')) goto fail;
  339. parser->state = SCGI_REQ_PARSER_HEADER_ENV_VALUE;
  340. break;
  341. case SCGI_REQ_PARSER_HEADER_ENV_VALUE:
  342. if (0 == parser->header_length) {
  343. DEBUG("scgi req header: headers ended with partial value '%s'", parser->key_value.data);
  344. goto fail; /* partial header on headers end */
  345. }
  346. --parser->header_length;
  347. if (0 != c) {
  348. int vallen = 1;
  349. while (vallen < len && 0 != data[vallen]) ++vallen;
  350. if (!string_buffer_append(&parser->key_value, data, vallen)) goto fail;
  351. data += (vallen - 1);
  352. len -= (vallen - 1);
  353. parser->header_length -= (vallen - 1);
  354. break;
  355. }
  356. /* value end */
  357. if (0 == parser->environ_used) {
  358. long long clen;
  359. char *endptr = NULL, *startptr = (char*) parser->key_value.data + parser->key_length + 1;
  360. if (!KEY_VALUE_HAS_KEY(parser, "CONTENT_LENGTH")) {
  361. DEBUG("scgi req header: first header isn't CONTENT_LENGTH: '%s'", parser->key_value.data);
  362. goto fail; /* first entry must be CONTENT_LENGTH */
  363. }
  364. if (parser->key_value.used == parser->key_length + 1) {
  365. DEBUG("scgi req header: CONTENT_LENGTH is empty");
  366. goto fail; /* empty CONTENT_LENGTH */
  367. }
  368. errno = 0;
  369. clen = strtoll(startptr, &endptr, 10);
  370. if (0 != errno) {
  371. DEBUG("scgi req header: parsing '%s' failed: %s", parser->key_value.data, strerror(errno));
  372. goto fail;
  373. }
  374. if (endptr != (char*) parser->key_value.data + parser->key_value.used) {
  375. DEBUG("scgi req header: parsing '%s' failed: contained more than number", parser->key_value.data);
  376. goto fail; /* number didn't cover complete value */
  377. }
  378. if (clen < 0) {
  379. DEBUG("scgi req header: parsing '%s' failed: negative length", parser->key_value.data);
  380. goto fail; /* number didn't cover complete value */
  381. }
  382. parser->content_length = (unsigned long long) clen;
  383. } else if (KEY_VALUE_HAS_KEY(parser, "SCGI")) {
  384. if (STRING_BUFFER_EQUAL(&parser->key_value, "SCGI=1")) {
  385. parser->is_scgi = 1;
  386. } else {
  387. DEBUG("scgi req header: SCGI is not 1: '%s'", parser->key_value.data);
  388. goto fail; /* SCGI must be 1 */
  389. }
  390. }
  391. if (!scgi_parser_environ_append(parser, string_buffer_extract(&parser->key_value), parser->key_length)) goto fail; /* duplicate key / ENOMEM */
  392. parser->key_length = 0;
  393. parser->state = SCGI_REQ_PARSER_HEADER_ENV_KEY;
  394. break;
  395. case SCGI_REQ_PARSER_HEADER_DONE:
  396. return len;
  397. case SCGI_REQ_PARSER_HEADER_ERROR:
  398. goto fail;
  399. }
  400. }
  401. return -1;
  402. fail:
  403. parser->state = SCGI_REQ_PARSER_HEADER_ERROR;
  404. return -2;
  405. }
  406. /****************************************************************************
  407. * SCGI RING BUFFERS *
  408. ***************************************************************************/
  409. /* ring buffer */
  410. typedef struct scgi_cgi_buffer scgi_cgi_buffer;
  411. struct scgi_cgi_buffer {
  412. unsigned int pos, len;
  413. unsigned char data[MAX_BUFFER_SIZE];
  414. };
  415. static void scgi_buffer_input_location(scgi_cgi_buffer *buf, unsigned char **location, ssize_t *location_size);
  416. static void scgi_buffer_fill(scgi_cgi_buffer *buf, ssize_t n);
  417. static void scgi_buffer_output_location(scgi_cgi_buffer *buf, unsigned char **location, ssize_t *location_size);
  418. static void scgi_buffer_drain(scgi_cgi_buffer *buf, ssize_t n);
  419. static int scgi_buffer_is_input_open(scgi_cgi_buffer *buf);
  420. static void scgi_buffer_set(scgi_cgi_buffer *buf, const char *data, ssize_t len);
  421. #define SCGI_BUFFER_SET(buf, str) scgi_buffer_set(buf, str, sizeof(str)-1)
  422. static void scgi_buffer_input_location(scgi_cgi_buffer *buf, unsigned char **location, ssize_t *location_size) {
  423. if (buf->pos + buf->len >= MAX_BUFFER_SIZE) {
  424. *location = buf->data + (buf->pos + buf->len - MAX_BUFFER_SIZE);
  425. *location_size = MAX_BUFFER_SIZE - buf->len;
  426. } else {
  427. *location = buf->data + (buf->pos + buf->len);
  428. *location_size = MAX_BUFFER_SIZE - (buf->pos + buf->len);
  429. }
  430. }
  431. static void scgi_buffer_fill(scgi_cgi_buffer *buf, ssize_t n) {
  432. assert(n >= 0 && (unsigned int) n <= MAX_BUFFER_SIZE - buf->len);
  433. buf->len += n;
  434. }
  435. static void scgi_buffer_output_location(scgi_cgi_buffer *buf, unsigned char **location, ssize_t *location_size) {
  436. *location = buf->data + buf->pos;
  437. if (buf->pos + buf->len >= MAX_BUFFER_SIZE) {
  438. *location_size = MAX_BUFFER_SIZE - buf->pos;
  439. } else {
  440. *location_size = buf->len;
  441. }
  442. }
  443. static void scgi_buffer_drain(scgi_cgi_buffer *buf, ssize_t n) {
  444. assert(n >= 0 && (unsigned int) n <= buf->len);
  445. buf->pos = (buf->pos + n) % MAX_BUFFER_SIZE;
  446. buf->len -= n;
  447. if (0 == buf->len) buf->pos = 0;
  448. }
  449. static int scgi_buffer_is_input_open(scgi_cgi_buffer *buf) {
  450. return buf->len < MAX_BUFFER_SIZE;
  451. }
  452. static void scgi_buffer_set(scgi_cgi_buffer *buf, const char *data, ssize_t len) {
  453. assert(len >= 0 && len <= MAX_BUFFER_SIZE);
  454. memcpy(buf->data, data, len);
  455. buf->pos = 0;
  456. buf->len = len;
  457. }
  458. /****************************************************************************
  459. * SCGI CHILD + SERVER *
  460. ***************************************************************************/
  461. typedef struct scgi_cgi_server scgi_cgi_server;
  462. typedef struct scgi_cgi_child scgi_cgi_child;
  463. struct scgi_cgi_server {
  464. struct event_base *base;
  465. struct event *listen_watcher;
  466. struct event
  467. *sig_w_CHLD,
  468. *sig_w_INT,
  469. *sig_w_TERM,
  470. *sig_w_HUP;
  471. const char *binary;
  472. unsigned int children_used, children_size;
  473. scgi_cgi_child **children;
  474. };
  475. struct scgi_cgi_child {
  476. unsigned int ndx;
  477. scgi_cgi_server *srv;
  478. struct event *sock_in_watcher, *sock_out_watcher;
  479. scgi_req_parser req_parser;
  480. pid_t pid;
  481. int child_stdout, child_stdin;
  482. struct event *pipe_in_watcher, *pipe_out_watcher;
  483. scgi_cgi_buffer request_buf;
  484. scgi_cgi_buffer response_buf;
  485. };
  486. static void fd_init(int fd);
  487. static void _my_event_free_with_fd(struct event **event);
  488. static void _my_event_free(struct event **event);
  489. #define MY_EVENT_FREE_WITH_FD(event) _my_event_free_with_fd(&(event))
  490. #define MY_EVENT_FREE(event) _my_event_free(&(event))
  491. static scgi_cgi_child* scgi_cgi_child_create(scgi_cgi_server *srv, int fd);
  492. static void scgi_cgi_child_free(scgi_cgi_child *cld);
  493. static void scgi_cgi_child_check_done(scgi_cgi_child *cld);
  494. static void scgi_cgi_child_exec(scgi_cgi_child *cld);
  495. static void scgi_cgi_child_start(scgi_cgi_child *cld);
  496. static void scgi_cgi_close_socket(scgi_cgi_child *cld);
  497. static void scgi_cgi_child_sock_in_cb(evutil_socket_t fd, short what, void *arg);
  498. static void scgi_cgi_child_sock_out_cb(evutil_socket_t fd, short what, void *arg);
  499. static void scgi_cgi_child_pipe_in_cb(evutil_socket_t fd, short what, void *arg);
  500. static void scgi_cgi_child_pipe_out_cb(evutil_socket_t fd, short what, void *arg);
  501. static scgi_cgi_server* scgi_cgi_server_create(int fd, const char *binary, unsigned int maxconns);
  502. static void scgi_cgi_server_free(scgi_cgi_server* srv);
  503. static void scgi_cgi_server_child_finished(scgi_cgi_server *srv, scgi_cgi_child *cld);
  504. static void scgi_cgi_server_accept(evutil_socket_t fd, short what, void *arg);
  505. static void sigint_cb(evutil_socket_t fd, short what, void *arg);
  506. static void sigchld_cb(evutil_socket_t fd, short what, void *arg);
  507. /****************************************************************************
  508. * SCGI utils implementation *
  509. ***************************************************************************/
  510. static void fd_init(int fd) {
  511. #ifdef _WIN32
  512. int i = 1;
  513. #endif
  514. #ifdef FD_CLOEXEC
  515. /* close fd on exec (cgi) */
  516. fcntl(fd, F_SETFD, FD_CLOEXEC);
  517. #endif
  518. #ifdef O_NONBLOCK
  519. fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
  520. #elif defined _WIN32
  521. ioctlsocket(fd, FIONBIO, &i);
  522. #endif
  523. }
  524. static void _my_event_free_with_fd(struct event **event) {
  525. int fd;
  526. if (NULL == *event) return;
  527. fd = event_get_fd(*event);
  528. event_free(*event);
  529. *event = NULL;
  530. if (-1 != fd) close(fd);
  531. }
  532. static void _my_event_free(struct event **event) {
  533. if (NULL == *event) return;
  534. event_free(*event);
  535. *event = NULL;
  536. }
  537. /****************************************************************************
  538. * SCGI CHILD implementation *
  539. ***************************************************************************/
  540. static scgi_cgi_child* scgi_cgi_child_create(scgi_cgi_server *srv, int fd) {
  541. struct event_base *base = srv->base;
  542. scgi_cgi_child *cld;
  543. int pipe_stdout[2], pipe_stdin[2];
  544. if (-1 == pipe(pipe_stdout)) {
  545. ERROR("couldn't create pipe: %s", strerror(errno));
  546. return NULL;
  547. }
  548. if (-1 == pipe(pipe_stdin)) {
  549. ERROR("couldn't create pipe: %s", strerror(errno));
  550. close(pipe_stdout[0]); close(pipe_stdout[1]); return NULL;
  551. }
  552. cld = calloc(1, sizeof(scgi_cgi_child));
  553. if (NULL == cld) {
  554. ERROR("couldn't alloc: %s", strerror(errno));
  555. close(pipe_stdout[0]); close(pipe_stdout[1]); close(pipe_stdin[0]); close(pipe_stdin[1]); return NULL;
  556. }
  557. cld->srv = srv;
  558. cld->pid = -1;
  559. cld->child_stdin = pipe_stdin[0];
  560. cld->child_stdout = pipe_stdout[1];
  561. scgi_parser_init(&cld->req_parser);
  562. cld->sock_in_watcher = event_new(base, fd, EV_READ | EV_PERSIST, scgi_cgi_child_sock_in_cb, cld);
  563. cld->sock_out_watcher = event_new(base, fd, EV_WRITE | EV_PERSIST, scgi_cgi_child_sock_out_cb, cld);
  564. fd_init(pipe_stdin[1]);
  565. cld->pipe_out_watcher = event_new(base, pipe_stdin[1], EV_WRITE | EV_PERSIST, scgi_cgi_child_pipe_out_cb, cld);
  566. fd_init(pipe_stdout[0]);
  567. cld->pipe_in_watcher = event_new(base, pipe_stdout[0], EV_READ | EV_PERSIST, scgi_cgi_child_pipe_in_cb, cld);
  568. if (NULL == cld->sock_in_watcher || NULL == cld->sock_out_watcher || NULL == cld->pipe_in_watcher || NULL == cld->pipe_out_watcher) {
  569. ERROR("couldn't alloc: %s", strerror(errno));
  570. if (NULL == cld->pipe_in_watcher) close(pipe_stdin[1]);
  571. if (NULL == cld->pipe_out_watcher) close(pipe_stdout[0]);
  572. scgi_cgi_child_free(cld);
  573. return NULL;
  574. }
  575. /* start handling */
  576. event_add(cld->sock_in_watcher, NULL);
  577. return cld;
  578. }
  579. static void scgi_cgi_child_free(scgi_cgi_child *cld) {
  580. /* shared fd */
  581. if (NULL != cld->sock_in_watcher) {
  582. MY_EVENT_FREE(cld->sock_out_watcher);
  583. MY_EVENT_FREE_WITH_FD(cld->sock_in_watcher);
  584. } else {
  585. MY_EVENT_FREE_WITH_FD(cld->sock_out_watcher);
  586. }
  587. MY_EVENT_FREE_WITH_FD(cld->pipe_in_watcher);
  588. MY_EVENT_FREE_WITH_FD(cld->pipe_out_watcher);
  589. if (-1 != cld->child_stdin) {
  590. close(cld->child_stdin);
  591. cld->child_stdin = -1;
  592. }
  593. if (-1 != cld->child_stdout) {
  594. close(cld->child_stdout);
  595. cld->child_stdout = -1;
  596. }
  597. scgi_parser_clear(&cld->req_parser);
  598. if (-1 != cld->pid) {
  599. kill(cld->pid, SIGTERM);
  600. cld->pid = -1;
  601. }
  602. free(cld);
  603. }
  604. static void scgi_cgi_child_check_done(scgi_cgi_child *cld) {
  605. if (-1 == cld->pid && NULL == cld->sock_out_watcher) {
  606. MY_EVENT_FREE_WITH_FD(cld->sock_in_watcher);
  607. MY_EVENT_FREE_WITH_FD(cld->pipe_in_watcher);
  608. MY_EVENT_FREE_WITH_FD(cld->pipe_out_watcher);
  609. }
  610. if (-1 != cld->pid || NULL != cld->sock_out_watcher || NULL != cld->sock_in_watcher || NULL != cld->pipe_in_watcher || NULL != cld->pipe_out_watcher) return;
  611. scgi_cgi_server_child_finished(cld->srv, cld);
  612. }
  613. static const char http_503_message[] =
  614. "Status: 503 Service Unavailable\r\n"
  615. "Content-Length: 0\r\n"
  616. "\r\n"
  617. ;
  618. static void scgi_cgi_child_exec(scgi_cgi_child *cld) {
  619. char **newenv;
  620. const char *path = cld->srv->binary;
  621. char * args[] = { NULL, NULL };
  622. if (cld->child_stdin != 0) {
  623. dup2(cld->child_stdin, 0);
  624. close(cld->child_stdin);
  625. }
  626. if (cld->child_stdout != 1) {
  627. dup2(cld->child_stdout, 1);
  628. close(cld->child_stdout);
  629. }
  630. #ifdef FD_CLOEXEC
  631. /* UNDO close fd on exec (cgi) */
  632. fcntl(0, F_SETFD, 0);
  633. fcntl(1, F_SETFD, 0);
  634. #endif
  635. if (NULL == path) path = scgi_parser_environ_get(&cld->req_parser, CONST_STR_LEN("INTERPRETER"));
  636. if (NULL == path) path = scgi_parser_environ_get(&cld->req_parser, CONST_STR_LEN("SCRIPT_FILENAME"));
  637. args[0] = (char*) path;
  638. /* try changing the directory. don't care about memleaks, execve() coming soon :) */
  639. {
  640. char *dir = strdup(path), *sep;
  641. if (NULL == (sep = strrchr(dir, '/'))) {
  642. chdir("/");
  643. } else {
  644. *sep = '\0';
  645. chdir(dir);
  646. }
  647. }
  648. scgi_parser_environ_copy(&cld->req_parser, CONST_STR_LEN("PATH"));
  649. newenv = (char**) cld->req_parser.environ;
  650. execve(path, args, newenv);
  651. fprintf(stderr, "couldn't execve '%s': %s\n", path, strerror(errno));
  652. write(1, http_503_message, sizeof(http_503_message));
  653. exit(-1);
  654. }
  655. static void scgi_cgi_child_start(scgi_cgi_child *cld) {
  656. cld->pid = fork();
  657. switch (cld->pid) {
  658. case 0:
  659. /* child process */
  660. scgi_cgi_child_exec(cld);
  661. break;
  662. case -1:
  663. /* error */
  664. fprintf(stderr, "couldn't fork: %s\n", strerror(errno));
  665. SCGI_BUFFER_SET(&cld->response_buf, http_503_message);
  666. if (NULL != cld->sock_out_watcher) event_add(cld->sock_out_watcher, NULL);
  667. /* don't need those anymore */
  668. scgi_parser_clear_environment(&cld->req_parser);
  669. close(cld->child_stdout); cld->child_stdout = -1;
  670. close(cld->child_stdin); cld->child_stdin = -1;
  671. /* close pipe stuff */
  672. MY_EVENT_FREE_WITH_FD(cld->pipe_in_watcher);
  673. MY_EVENT_FREE_WITH_FD(cld->pipe_out_watcher);
  674. break;
  675. default:
  676. /* don't need those anymore */
  677. scgi_parser_clear_environment(&cld->req_parser);
  678. close(cld->child_stdout); cld->child_stdout = -1;
  679. close(cld->child_stdin); cld->child_stdin = -1;
  680. /* start reading */
  681. event_add(cld->pipe_in_watcher, NULL);
  682. break;
  683. }
  684. }
  685. static void scgi_cgi_close_socket(scgi_cgi_child *cld) {
  686. cld->response_buf.pos = cld->response_buf.len = 0;
  687. /* shared fd */
  688. if (NULL != cld->sock_in_watcher) {
  689. MY_EVENT_FREE(cld->sock_out_watcher);
  690. MY_EVENT_FREE_WITH_FD(cld->sock_in_watcher);
  691. } else {
  692. MY_EVENT_FREE_WITH_FD(cld->sock_out_watcher);
  693. }
  694. if (NULL != cld->pipe_out_watcher) event_add(cld->pipe_out_watcher, NULL);
  695. if (NULL != cld->pipe_in_watcher) event_add(cld->pipe_in_watcher, NULL);
  696. scgi_cgi_child_check_done(cld);
  697. }
  698. static void scgi_cgi_child_sock_in_cb(evutil_socket_t fd, short what, void *arg) {
  699. scgi_cgi_child *cld = (scgi_cgi_child*) arg;
  700. UNUSED(what);
  701. assert(NULL != cld->sock_in_watcher);
  702. for (;;) {
  703. unsigned char *buf;
  704. ssize_t r;
  705. scgi_buffer_input_location(&cld->request_buf, &buf, &r);
  706. if (0 == r) { /* buffer is full */
  707. event_del(cld->sock_in_watcher);
  708. break;
  709. }
  710. r = read(fd, buf, r);
  711. if (0 == r) { /* eof */
  712. /* shared fd */
  713. if (NULL == cld->sock_out_watcher) {
  714. MY_EVENT_FREE_WITH_FD(cld->sock_in_watcher);
  715. } else {
  716. MY_EVENT_FREE(cld->sock_in_watcher);
  717. }
  718. break;
  719. } else if (0 > r) {
  720. switch (errno) {
  721. case EINTR:
  722. case EAGAIN:
  723. #if EWOULDBLOCK != EAGAIN
  724. case EWOULDBLOCK:
  725. #endif
  726. break; /* try again later */
  727. default:
  728. goto close_sock;
  729. }
  730. break;
  731. } else {
  732. if (SCGI_REQ_PARSER_HEADER_DONE != cld->req_parser.state) {
  733. ssize_t result;
  734. assert(0 == cld->request_buf.len);
  735. result = scgi_parse(&cld->req_parser, buf, r);
  736. DEBUG("scgi req parse result: %i", (int) result);
  737. if (result >= 0) {
  738. assert(SCGI_REQ_PARSER_HEADER_DONE == cld->req_parser.state);
  739. if (result > 0) {
  740. cld->request_buf.pos = r - result;
  741. cld->request_buf.len = result;
  742. }
  743. scgi_cgi_child_start(cld);
  744. } else if (result < -1) {
  745. goto close_sock;
  746. }
  747. } else if (NULL != cld->pipe_out_watcher) {
  748. scgi_buffer_fill(&cld->request_buf, r);
  749. } else {
  750. goto close_sock;
  751. }
  752. }
  753. }
  754. if (cld->request_buf.len > cld->req_parser.content_length) {
  755. cld->request_buf.len = cld->req_parser.content_length;
  756. goto close_sock;
  757. }
  758. if (NULL == cld->sock_in_watcher || 0 < cld->request_buf.len || 0 == cld->req_parser.content_length) {
  759. if (NULL != cld->pipe_out_watcher) event_add(cld->pipe_out_watcher, NULL);
  760. }
  761. scgi_cgi_child_check_done(cld);
  762. return;
  763. close_sock:
  764. scgi_cgi_close_socket(cld);
  765. }
  766. static void scgi_cgi_child_sock_out_cb(evutil_socket_t fd, short what, void *arg) {
  767. scgi_cgi_child *cld = (scgi_cgi_child*) arg;
  768. UNUSED(what);
  769. assert(NULL != cld->sock_out_watcher);
  770. for (;;) {
  771. unsigned char *buf;
  772. ssize_t r;
  773. scgi_buffer_output_location(&cld->response_buf, &buf, &r);
  774. if (0 == r) { /* buffer empty */
  775. event_del(cld->sock_out_watcher);
  776. break;
  777. }
  778. r = write(fd, buf, r);
  779. if (0 >= r) {
  780. switch (errno) {
  781. case EINTR:
  782. case EAGAIN:
  783. #if EWOULDBLOCK != EAGAIN
  784. case EWOULDBLOCK:
  785. #endif
  786. break; /* try again later */
  787. default:
  788. goto close_sock;
  789. }
  790. break;
  791. }
  792. scgi_buffer_drain(&cld->response_buf, r);
  793. }
  794. if (0 == cld->response_buf.len && NULL == cld->pipe_in_watcher) {
  795. shutdown(fd, SHUT_RDWR);
  796. goto close_sock;
  797. } else if (NULL != cld->pipe_in_watcher && scgi_buffer_is_input_open(&cld->response_buf)) {
  798. event_add(cld->pipe_in_watcher, NULL);
  799. }
  800. scgi_cgi_child_check_done(cld);
  801. return;
  802. close_sock:
  803. scgi_cgi_close_socket(cld);
  804. }
  805. static void scgi_cgi_child_pipe_in_cb(evutil_socket_t fd, short what, void *arg) {
  806. scgi_cgi_child *cld = (scgi_cgi_child*) arg;
  807. UNUSED(what);
  808. assert(NULL != cld->pipe_in_watcher);
  809. for (;;) {
  810. unsigned char *buf;
  811. ssize_t r;
  812. scgi_buffer_input_location(&cld->response_buf, &buf, &r);
  813. if (0 == r) { /* buffer full */
  814. event_del(cld->pipe_in_watcher);
  815. break;
  816. }
  817. r = read(fd, buf, r);
  818. if (0 == r) { /* eof */
  819. MY_EVENT_FREE_WITH_FD(cld->pipe_in_watcher);
  820. break;
  821. } else if (0 > r) {
  822. switch (errno) {
  823. case EINTR:
  824. case EAGAIN:
  825. #if EWOULDBLOCK != EAGAIN
  826. case EWOULDBLOCK:
  827. #endif
  828. break; /* try again later */
  829. default:
  830. MY_EVENT_FREE_WITH_FD(cld->pipe_in_watcher);
  831. break;
  832. }
  833. break;
  834. } else {
  835. if (NULL != cld->sock_out_watcher) {
  836. scgi_buffer_fill(&cld->response_buf, r);
  837. }
  838. }
  839. }
  840. if (NULL == cld->pipe_in_watcher || cld->response_buf.len > 0) {
  841. if (NULL != cld->sock_out_watcher) event_add(cld->sock_out_watcher, NULL);
  842. }
  843. scgi_cgi_child_check_done(cld);
  844. }
  845. static void scgi_cgi_child_pipe_out_cb(evutil_socket_t fd, short what, void *arg) {
  846. scgi_cgi_child *cld = (scgi_cgi_child*) arg;
  847. UNUSED(what);
  848. assert(NULL != cld->pipe_out_watcher);
  849. for (;;) {
  850. unsigned char *buf;
  851. ssize_t r;
  852. scgi_buffer_output_location(&cld->request_buf, &buf, &r);
  853. assert(cld->req_parser.content_length >= (size_t) r);
  854. if (0 == r) { /* buffer empty */
  855. event_del(cld->pipe_out_watcher);
  856. break;
  857. }
  858. r = write(fd, buf, r);
  859. if (0 >= r) {
  860. switch (errno) {
  861. case EINTR:
  862. case EAGAIN:
  863. #if EWOULDBLOCK != EAGAIN
  864. case EWOULDBLOCK:
  865. #endif
  866. break; /* try again later */
  867. default:
  868. goto close_pipe;
  869. }
  870. break;
  871. }
  872. cld->req_parser.content_length -= r;
  873. scgi_buffer_drain(&cld->request_buf, r);
  874. }
  875. if (0 == cld->req_parser.content_length || (0 == cld->request_buf.len && NULL == cld->sock_in_watcher)) {
  876. goto close_pipe;
  877. } else if (NULL != cld->sock_in_watcher && scgi_buffer_is_input_open(&cld->request_buf)) {
  878. event_add(cld->sock_in_watcher, NULL);
  879. }
  880. scgi_cgi_child_check_done(cld);
  881. return;
  882. close_pipe:
  883. MY_EVENT_FREE_WITH_FD(cld->pipe_out_watcher);
  884. cld->request_buf.pos = cld->request_buf.len = 0;
  885. if (NULL != cld->sock_in_watcher) event_add(cld->sock_in_watcher, NULL);
  886. scgi_cgi_child_check_done(cld);
  887. }
  888. /****************************************************************************
  889. * SCGI SERVER implementation *
  890. ***************************************************************************/
  891. #define CATCH_SIGNAL(cb, n) do { \
  892. srv->sig_w_##n = event_new(srv->base, SIG##n, EV_SIGNAL|EV_PERSIST, cb, srv); \
  893. assert(NULL != srv->sig_w_##n); \
  894. event_add(srv->sig_w_##n, NULL); \
  895. } while (0)
  896. #define UNCATCH_SIGNAL(n) MY_EVENT_FREE(srv->sig_w_##n)
  897. static scgi_cgi_server* scgi_cgi_server_create(int fd, const char *binary, unsigned int maxconns) {
  898. scgi_cgi_server* srv = calloc(1, sizeof(scgi_cgi_server));
  899. srv->children = (scgi_cgi_child**) calloc(maxconns, sizeof(scgi_cgi_child*));
  900. assert(NULL != srv->children);
  901. srv->children_used = 0;
  902. srv->children_size = maxconns;
  903. srv->binary = binary;
  904. srv->base = event_base_new();
  905. fd_init(fd);
  906. srv->listen_watcher = event_new(srv->base, fd, EV_READ | EV_PERSIST, scgi_cgi_server_accept, srv);
  907. event_add(srv->listen_watcher, NULL);
  908. CATCH_SIGNAL(sigint_cb, INT);
  909. CATCH_SIGNAL(sigint_cb, TERM);
  910. CATCH_SIGNAL(sigint_cb, HUP);
  911. CATCH_SIGNAL(sigchld_cb, CHLD);
  912. return srv;
  913. }
  914. static void scgi_cgi_server_free(scgi_cgi_server* srv) {
  915. while (srv->children_used > 0) {
  916. scgi_cgi_server_child_finished(srv, srv->children[0]);
  917. }
  918. MY_EVENT_FREE_WITH_FD(srv->listen_watcher);
  919. UNCATCH_SIGNAL(INT);
  920. UNCATCH_SIGNAL(TERM);
  921. UNCATCH_SIGNAL(HUP);
  922. UNCATCH_SIGNAL(CHLD);
  923. free(srv->children);
  924. srv->children = NULL;
  925. srv->children_size = 0;
  926. free(srv);
  927. }
  928. static void scgi_cgi_server_child_finished(scgi_cgi_server *srv, scgi_cgi_child *cld) {
  929. unsigned int ndx = cld->ndx;
  930. assert(srv->children[ndx] == cld);
  931. assert(ndx < srv->children_used);
  932. DEBUG("Child %i finished", ndx);
  933. --srv->children_used;
  934. if (ndx != srv->children_used) {
  935. srv->children[ndx] = srv->children[srv->children_used];
  936. srv->children[ndx]->ndx = ndx;
  937. }
  938. srv->children[srv->children_used] = NULL;
  939. scgi_cgi_child_free(cld);
  940. if (NULL == srv->listen_watcher && 0 == srv->children_used) UNCATCH_SIGNAL(CHLD); /* shutdown */
  941. if (NULL != srv->listen_watcher) event_add(srv->listen_watcher, NULL);
  942. }
  943. static void scgi_cgi_server_accept(evutil_socket_t fd, short what, void *arg) {
  944. scgi_cgi_server *srv = (scgi_cgi_server*) arg;
  945. int confd;
  946. UNUSED(what);
  947. if (srv->children_used == srv->children_size) {
  948. event_del(srv->listen_watcher);
  949. return;
  950. }
  951. while (srv->children_used < srv->children_size) {
  952. if (-1 != (confd = accept(fd, NULL, NULL))) {
  953. scgi_cgi_child *cld;
  954. fd_init(confd);
  955. cld = scgi_cgi_child_create(srv, confd);
  956. if (NULL == cld) {
  957. if (0 == srv->children_used) {
  958. ERROR("no children running, and child creation failed. abort.");
  959. exit(-2);
  960. }
  961. ERROR("child creation failed, disable listening temporarily until next child finishes");
  962. close(confd);
  963. event_del(srv->listen_watcher);
  964. return;
  965. }
  966. srv->children[srv->children_used++] = cld;
  967. } else {
  968. break;
  969. }
  970. }
  971. }
  972. static void sigint_cb(evutil_socket_t fd, short what, void *arg) {
  973. scgi_cgi_server *srv = (scgi_cgi_server*) arg;
  974. UNUSED(fd);
  975. UNUSED(what);
  976. UNCATCH_SIGNAL(INT);
  977. UNCATCH_SIGNAL(TERM);
  978. UNCATCH_SIGNAL(HUP);
  979. MY_EVENT_FREE_WITH_FD(srv->listen_watcher);
  980. if (0 == srv->children_used) UNCATCH_SIGNAL(CHLD);
  981. fprintf(stderr, "Got signal, shutdown (%i children remaining)\n", srv->children_used);
  982. }
  983. static void sigchld_cb(evutil_socket_t fd, short what, void *arg) {
  984. scgi_cgi_server *srv = (scgi_cgi_server*) arg;
  985. pid_t pid;
  986. int status;
  987. UNUSED(fd);
  988. UNUSED(what);
  989. while (srv->children_used > 0) {
  990. if (-1 != (pid = waitpid(-1, &status, WNOHANG))) {
  991. unsigned int i;
  992. for (i = 0; i < srv->children_used; ++i) {
  993. scgi_cgi_child *cld = srv->children[i];
  994. if (cld->pid == pid) {
  995. DEBUG("child %i terminated with status %i", i, status);
  996. cld->pid = -1;
  997. scgi_cgi_child_check_done(cld);
  998. break;
  999. }
  1000. }
  1001. } else {
  1002. break;
  1003. }
  1004. }
  1005. }
  1006. static void show_help() {
  1007. fprintf(stderr, PACKAGE_DESC "\n");
  1008. fprintf(stderr,
  1009. "Usage: scgi-cgi [-b binary] [-c maxconns] [-h] [-v] -- [binary]\n"
  1010. "Options:\n"
  1011. " -b binary the executable to call instead of INTERPRETER\n"
  1012. " or SCRIPT_FILENAME from SCGI environment (default: none)\n"
  1013. " -c maxconns how many connections to accept at the same time (default: 16)\n"
  1014. " -v show version\n"
  1015. " -h show this help\n"
  1016. );
  1017. }
  1018. int main (int argc, char **argv) {
  1019. scgi_cgi_server *srv;
  1020. const char *binary = NULL;
  1021. unsigned int maxconn = 16;
  1022. int o;
  1023. while(-1 != (o = getopt(argc, argv, "b:c:hv"))) {
  1024. switch(o) {
  1025. case 'b':
  1026. binary = optarg;
  1027. break;
  1028. case 'c':
  1029. maxconn = atoi(optarg);
  1030. break;
  1031. case 'v':
  1032. fprintf(stderr, PACKAGE_DESC "\n");
  1033. return 0;
  1034. case 'h':
  1035. show_help();
  1036. return 0;
  1037. default:
  1038. show_help();
  1039. return -1;
  1040. }
  1041. }
  1042. if (optind < argc && argv[optind] && NULL == binary) binary = argv[optind];
  1043. srv = scgi_cgi_server_create(0, binary, maxconn);
  1044. event_base_loop(srv->base, 0);
  1045. scgi_cgi_server_free(srv);
  1046. return 0;
  1047. }