A clone of btpd with my configuration changes.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

1633 lignes
37 KiB

  1. /*
  2. * Copyright (c) 2002-2006 Niels Provos <provos@citi.umich.edu>
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. The name of the author may not be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  17. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  18. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  19. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  20. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  21. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  22. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  23. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  25. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. #include <sys/param.h>
  28. #include <sys/types.h>
  29. #ifdef HAVE_CONFIG_H
  30. #include "config.h"
  31. #endif
  32. #ifdef HAVE_SYS_TIME_H
  33. #include <sys/time.h>
  34. #endif
  35. #ifdef HAVE_SYS_IOCCOM_H
  36. #include <sys/ioccom.h>
  37. #endif
  38. #include <sys/resource.h>
  39. #include <sys/socket.h>
  40. #include <sys/stat.h>
  41. #include <sys/tree.h>
  42. #include <sys/wait.h>
  43. #include <sys/queue.h>
  44. #include <netinet/in.h>
  45. #include <netdb.h>
  46. #include <assert.h>
  47. #include <errno.h>
  48. #include <stdio.h>
  49. #include <stdlib.h>
  50. #include <string.h>
  51. #include <syslog.h>
  52. #include <signal.h>
  53. #ifdef HAVE_TIME_H
  54. #include <time.h>
  55. #endif
  56. #include <unistd.h>
  57. #include <getopt.h>
  58. #include <fcntl.h>
  59. #undef timeout_pending
  60. #undef timeout_initialized
  61. #include "event.h"
  62. #include "evhttp.h"
  63. #include "log.h"
  64. #include "http-internal.h"
  65. extern int debug;
  66. static int make_socket_ai(int (*f)(int, const struct sockaddr *, socklen_t),
  67. struct addrinfo *);
  68. static int make_socket(int (*)(int, const struct sockaddr *, socklen_t),
  69. const char *, short);
  70. static void name_from_addr(struct sockaddr *, socklen_t, char **, char **);
  71. void evhttp_write(int, short, void *);
  72. static const char *
  73. html_replace(char ch)
  74. {
  75. static char buf[2];
  76. switch (ch) {
  77. case '<':
  78. return "&lt;";
  79. case '>':
  80. return "&gt;";
  81. case '"':
  82. return "&quot;";
  83. case '\'':
  84. return "&#039;";
  85. case '&':
  86. return "&amp;";
  87. default:
  88. break;
  89. }
  90. /* Echo the character back */
  91. buf[0] = ch;
  92. buf[1] = '\0';
  93. return buf;
  94. }
  95. /*
  96. * Replaces <, >, ", ' and & with &lt;, &gt;, &quot;,
  97. * &#039; and &amp; correspondingly.
  98. *
  99. * The returned string needs to be freed by the caller.
  100. */
  101. char *
  102. evhttp_htmlescape(const char *html)
  103. {
  104. int i, new_size = 0;
  105. char *escaped_html, *p;
  106. for (i = 0; i < strlen(html); ++i)
  107. new_size += strlen(html_replace(html[i]));
  108. p = escaped_html = malloc(new_size + 1);
  109. if (escaped_html == NULL)
  110. event_err(1, "%s: malloc(%d)", __func__, new_size + 1);
  111. for (i = 0; i < strlen(html); ++i) {
  112. const char *replaced = html_replace(html[i]);
  113. /* this is length checked */
  114. strcpy(p, replaced);
  115. p += strlen(replaced);
  116. }
  117. *p = '\0';
  118. return (escaped_html);
  119. }
  120. const char *
  121. evhttp_method(enum evhttp_cmd_type type)
  122. {
  123. const char *method;
  124. switch (type) {
  125. case EVHTTP_REQ_GET:
  126. method = "GET";
  127. break;
  128. case EVHTTP_REQ_POST:
  129. method = "POST";
  130. break;
  131. case EVHTTP_REQ_HEAD:
  132. method = "HEAD";
  133. break;
  134. default:
  135. method = NULL;
  136. break;
  137. }
  138. return (method);
  139. }
  140. void
  141. evhttp_write_buffer(struct evhttp_connection *evcon,
  142. void (*cb)(struct evhttp_connection *, void *), void *arg)
  143. {
  144. struct timeval tv;
  145. event_debug(("%s: preparing to write buffer\n", __func__));
  146. /* Set call back */
  147. evcon->cb = cb;
  148. evcon->cb_arg = arg;
  149. /* xxx: maybe check if the event is still pending? */
  150. event_set(&evcon->ev, evcon->fd, EV_WRITE, evhttp_write, evcon);
  151. timerclear(&tv);
  152. tv.tv_sec = HTTP_WRITE_TIMEOUT;
  153. event_add(&evcon->ev, &tv);
  154. }
  155. /*
  156. * Create the headers need for an HTTP reply
  157. */
  158. static void
  159. evhttp_make_header_request(struct evhttp_connection *evcon,
  160. struct evhttp_request *req)
  161. {
  162. static char line[1024];
  163. const char *method;
  164. evhttp_remove_header(req->output_headers, "Accept-Encoding");
  165. evhttp_remove_header(req->output_headers, "Proxy-Connection");
  166. evhttp_remove_header(req->output_headers, "Connection");
  167. evhttp_add_header(req->output_headers, "Connection", "close");
  168. req->minor = 0;
  169. /* Generate request line */
  170. method = evhttp_method(req->type);
  171. snprintf(line, sizeof(line), "%s %s HTTP/%d.%d\r\n",
  172. method, req->uri, req->major, req->minor);
  173. evbuffer_add(evcon->output_buffer, line, strlen(line));
  174. /* Add the content length on a post request if missing */
  175. if (req->type == EVHTTP_REQ_POST &&
  176. evhttp_find_header(req->output_headers, "Content-Length") == NULL){
  177. char size[12];
  178. snprintf(size, sizeof(size), "%ld",
  179. EVBUFFER_LENGTH(req->output_buffer));
  180. evhttp_add_header(req->output_headers, "Content-Length", size);
  181. }
  182. }
  183. /*
  184. * Create the headers needed for an HTTP reply
  185. */
  186. static void
  187. evhttp_make_header_response(struct evhttp_connection *evcon,
  188. struct evhttp_request *req)
  189. {
  190. static char line[1024];
  191. snprintf(line, sizeof(line), "HTTP/%d.%d %d %s\r\n",
  192. req->major, req->minor, req->response_code,
  193. req->response_code_line);
  194. evbuffer_add(evcon->output_buffer, line, strlen(line));
  195. /* Potentially add headers */
  196. if (evhttp_find_header(req->output_headers, "Content-Type") == NULL) {
  197. evhttp_add_header(req->output_headers,
  198. "Content-Type", "text/html; charset=ISO-8859-1");
  199. }
  200. }
  201. void
  202. evhttp_make_header(struct evhttp_connection *evcon, struct evhttp_request *req)
  203. {
  204. static char line[1024];
  205. struct evkeyval *header;
  206. /*
  207. * Depending if this is a HTTP request or response, we might need to
  208. * add some new headers or remove existing headers.
  209. */
  210. if (req->kind == EVHTTP_REQUEST) {
  211. evhttp_make_header_request(evcon, req);
  212. } else {
  213. evhttp_make_header_response(evcon, req);
  214. }
  215. TAILQ_FOREACH(header, req->output_headers, next) {
  216. snprintf(line, sizeof(line), "%s: %s\r\n",
  217. header->key, header->value);
  218. evbuffer_add(evcon->output_buffer, line, strlen(line));
  219. }
  220. evbuffer_add(evcon->output_buffer, "\r\n", 2);
  221. if (EVBUFFER_LENGTH(req->output_buffer) >= 0) {
  222. /*
  223. * For a request, we add the POST data, for a reply, this
  224. * is the regular data.
  225. */
  226. evbuffer_add_buffer(evcon->output_buffer, req->output_buffer);
  227. }
  228. }
  229. /* Separated host, port and file from URI */
  230. int
  231. evhttp_hostportfile(char *url, char **phost, u_short *pport, char **pfile)
  232. {
  233. static char host[1024];
  234. static char file[1024];
  235. char *p, *p2;
  236. int len;
  237. u_short port;
  238. len = strlen(HTTP_PREFIX);
  239. if (strncasecmp(url, HTTP_PREFIX, len))
  240. return (-1);
  241. url += len;
  242. /* We might overrun */
  243. if (strlcpy(host, url, sizeof (host)) >= sizeof(host))
  244. return (-1);
  245. p = strchr(host, '/');
  246. if (p != NULL) {
  247. *p = '\0';
  248. p2 = p + 1;
  249. } else
  250. p2 = NULL;
  251. if (pfile != NULL) {
  252. /* Generate request file */
  253. if (p2 == NULL)
  254. p2 = "";
  255. snprintf(file, sizeof(file), "/%s", p2);
  256. }
  257. p = strchr(host, ':');
  258. if (p != NULL) {
  259. *p = '\0';
  260. port = atoi(p + 1);
  261. if (port == 0)
  262. return (-1);
  263. } else
  264. port = HTTP_DEFAULTPORT;
  265. if (phost != NULL)
  266. *phost = host;
  267. if (pport != NULL)
  268. *pport = port;
  269. if (pfile != NULL)
  270. *pfile = file;
  271. return (0);
  272. }
  273. void
  274. evhttp_connection_fail(struct evhttp_connection *evcon)
  275. {
  276. struct evhttp_request* req = TAILQ_FIRST(&evcon->requests);
  277. assert(req != NULL);
  278. /* reset the connection */
  279. evhttp_connection_reset(evcon);
  280. if (req->cb != NULL) {
  281. /* xxx: maybe we need to pass the request here? */
  282. (*req->cb)(NULL, req->cb_arg);
  283. }
  284. TAILQ_REMOVE(&evcon->requests, req, next);
  285. evhttp_request_free(req);
  286. /* xxx: maybe we should fail all requests??? */
  287. /* We are trying the next request that was queued on us */
  288. if (TAILQ_FIRST(&evcon->requests) != NULL)
  289. evhttp_connection_connect(evcon);
  290. }
  291. void
  292. evhttp_write(int fd, short what, void *arg)
  293. {
  294. struct evhttp_connection *evcon = arg;
  295. struct timeval tv;
  296. int n;
  297. if (what == EV_TIMEOUT) {
  298. evhttp_connection_fail(evcon);
  299. return;
  300. }
  301. n = evbuffer_write(evcon->output_buffer, fd);
  302. if (n == -1) {
  303. event_warn("%s: evbuffer_write", __func__);
  304. evhttp_connection_fail(evcon);
  305. return;
  306. }
  307. if (n == 0) {
  308. event_warnx("%s: write nothing\n", __func__);
  309. evhttp_connection_fail(evcon);
  310. return;
  311. }
  312. if (EVBUFFER_LENGTH(evcon->output_buffer) != 0) {
  313. timerclear(&tv);
  314. tv.tv_sec = HTTP_WRITE_TIMEOUT;
  315. event_add(&evcon->ev, &tv);
  316. return;
  317. }
  318. /* Activate our call back */
  319. (*evcon->cb)(evcon, evcon->cb_arg);
  320. }
  321. void
  322. evhttp_connection_done(struct evhttp_connection *evcon)
  323. {
  324. struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
  325. /*
  326. * if this is an incoming connection, we need to leave the request
  327. * on the connection, so that we can reply to it.
  328. */
  329. if (evcon->flags & EVHTTP_CON_OUTGOING) {
  330. TAILQ_REMOVE(&evcon->requests, req, next);
  331. req->evcon = NULL;
  332. if (TAILQ_FIRST(&evcon->requests) != NULL) {
  333. /*
  334. * We have more requests; reset the connection
  335. * and deal with the next request. xxx: no
  336. * persistent connection right now
  337. */
  338. evhttp_connection_connect(evcon);
  339. }
  340. }
  341. /* hand what ever we read over to the request */
  342. evbuffer_add_buffer(req->input_buffer, evcon->input_buffer);
  343. /* notify the user of the request */
  344. (*req->cb)(req, req->cb_arg);
  345. /* if this was an outgoing request, we own and it's done. so free it */
  346. if (evcon->flags & EVHTTP_CON_OUTGOING) {
  347. evhttp_request_free(req);
  348. }
  349. }
  350. /*
  351. * Reads data into a buffer structure until no more data
  352. * can be read on the file descriptor or we have read all
  353. * the data that we wanted to read.
  354. * Execute callback when done.
  355. */
  356. void
  357. evhttp_read(int fd, short what, void *arg)
  358. {
  359. struct evhttp_connection *evcon = arg;
  360. struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
  361. struct timeval tv;
  362. int n;
  363. if (what == EV_TIMEOUT) {
  364. evhttp_connection_fail(evcon);
  365. return;
  366. }
  367. n = evbuffer_read(req->input_buffer, fd, req->ntoread);
  368. event_debug(("%s: got %d on %d\n", __func__, n, req->fd));
  369. if (n == -1) {
  370. event_warn("%s: evbuffer_read", __func__);
  371. evhttp_connection_fail(evcon);
  372. return;
  373. }
  374. /* Adjust the amount of data that we have left to read */
  375. if (req->ntoread > 0)
  376. req->ntoread -= n;
  377. if (n == 0 || req->ntoread == 0) {
  378. evhttp_connection_done(evcon);
  379. return;
  380. }
  381. timerclear(&tv);
  382. tv.tv_sec = HTTP_READ_TIMEOUT;
  383. event_add(&evcon->ev, &tv);
  384. }
  385. void
  386. evhttp_write_connectioncb(struct evhttp_connection *evcon, void *arg)
  387. {
  388. /* This is after writing the request to the server */
  389. struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
  390. assert(req != NULL);
  391. /* We are done writing our header and are now expecting the response */
  392. req->kind = EVHTTP_RESPONSE;
  393. evhttp_start_read(evcon);
  394. }
  395. /*
  396. * Clean up a connection object
  397. */
  398. void
  399. evhttp_connection_free(struct evhttp_connection *evcon)
  400. {
  401. if (event_initialized(&evcon->ev))
  402. event_del(&evcon->ev);
  403. if (evcon->fd != -1)
  404. close(evcon->fd);
  405. if (evcon->address != NULL)
  406. free(evcon->address);
  407. if (evcon->input_buffer != NULL)
  408. evbuffer_free(evcon->input_buffer);
  409. if (evcon->output_buffer != NULL)
  410. evbuffer_free(evcon->output_buffer);
  411. free(evcon);
  412. }
  413. void
  414. evhttp_request_dispatch(struct evhttp_connection* evcon)
  415. {
  416. struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
  417. /* this should not usually happy but it's possible */
  418. if (req == NULL)
  419. return;
  420. /* we assume that the connection is connected already */
  421. assert(evcon->state = EVCON_CONNECTED);
  422. /* Create the header from the store arguments */
  423. evhttp_make_header(evcon, req);
  424. evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL);
  425. }
  426. /* Reset our connection state */
  427. void
  428. evhttp_connection_reset(struct evhttp_connection *evcon)
  429. {
  430. if (event_initialized(&evcon->ev))
  431. event_del(&evcon->ev);
  432. if (evcon->fd != -1) {
  433. close(evcon->fd);
  434. evcon->fd = -1;
  435. }
  436. evcon->state = EVCON_DISCONNECTED;
  437. }
  438. /*
  439. * Call back for asynchronous connection attempt.
  440. */
  441. void
  442. evhttp_connectioncb(int fd, short what, void *arg)
  443. {
  444. struct evhttp_connection *evcon = arg;
  445. int error;
  446. socklen_t errsz = sizeof(error);
  447. if (what == EV_TIMEOUT) {
  448. event_warnx("%s: connection timeout for \"%s:%d\" on %d\n",
  449. __func__, evcon->address, evcon->port, evcon->fd);
  450. goto cleanup;
  451. }
  452. /* Check if the connection completed */
  453. if (getsockopt(evcon->fd, SOL_SOCKET, SO_ERROR, &error,
  454. &errsz) == -1) {
  455. event_warn("%s: getsockopt for \"%s:%d\" on %d",
  456. __func__, evcon->address, evcon->port, evcon->fd);
  457. goto cleanup;
  458. }
  459. if (error) {
  460. event_warnx("%s: connect failed for \"%s:%d\" on %d: %s\n",
  461. __func__, evcon->address, evcon->port, evcon->fd,
  462. strerror(error));
  463. goto cleanup;
  464. }
  465. /* We are connected to the server now */
  466. event_debug(("%s: connected to \"%s:%d\" on %d\n",
  467. __func__, evcon->address, evcon->port, evcon->fd));
  468. evcon->state = EVCON_CONNECTED;
  469. /* try to start requests that have queued up on this connection */
  470. evhttp_request_dispatch(evcon);
  471. return;
  472. cleanup:
  473. evhttp_connection_reset(evcon);
  474. /* for now, we just signal all requests by executing their callbacks */
  475. while (TAILQ_FIRST(&evcon->requests) != NULL) {
  476. struct evhttp_request *request = TAILQ_FIRST(&evcon->requests);
  477. TAILQ_REMOVE(&evcon->requests, request, next);
  478. request->evcon = NULL;
  479. /* we might want to set an error here */
  480. request->cb(request, request->cb_arg);
  481. }
  482. }
  483. /*
  484. * Check if we got a valid response code.
  485. */
  486. int
  487. evhttp_valid_response_code(int code)
  488. {
  489. if (code == 0)
  490. return (0);
  491. return (1);
  492. }
  493. /* Parses the status line of a web server */
  494. int
  495. evhttp_parse_response_line(struct evhttp_request *req, char *line)
  496. {
  497. char *protocol;
  498. char *number;
  499. char *readable;
  500. protocol = strsep(&line, " ");
  501. if (line == NULL)
  502. return (-1);
  503. number = strsep(&line, " ");
  504. if (line == NULL)
  505. return (-1);
  506. readable = line;
  507. if (strcmp(protocol, "HTTP/1.0") == 0) {
  508. req->major = 1;
  509. req->minor = 0;
  510. } else if (strcmp(protocol, "HTTP/1.1") == 0) {
  511. req->major = 1;
  512. req->minor = 1;
  513. } else {
  514. event_warnx("%s: bad protocol \"%s\"\n",
  515. __func__, protocol);
  516. return (-1);
  517. }
  518. req->response_code = atoi(number);
  519. if (!evhttp_valid_response_code(req->response_code)) {
  520. event_warnx("%s: bad response code \"%s\"\n",
  521. __func__, number);
  522. return (-1);
  523. }
  524. if ((req->response_code_line = strdup(readable)) == NULL)
  525. event_err(1, "%s: strdup", __func__);
  526. return (0);
  527. }
  528. /* Parse the first line of a HTTP request */
  529. int
  530. evhttp_parse_request_line(struct evhttp_request *req, char *line)
  531. {
  532. char *method;
  533. char *uri;
  534. char *version;
  535. /* Parse the request line */
  536. method = strsep(&line, " ");
  537. if (line == NULL)
  538. return (-1);
  539. uri = strsep(&line, " ");
  540. if (line == NULL)
  541. return (-1);
  542. version = strsep(&line, " ");
  543. if (line != NULL)
  544. return (-1);
  545. /* First line */
  546. if (strcmp(method, "GET") == 0) {
  547. req->type = EVHTTP_REQ_GET;
  548. } else if (strcmp(method, "POST") == 0) {
  549. req->type = EVHTTP_REQ_POST;
  550. } else if (strcmp(method, "HEAD") == 0) {
  551. req->type = EVHTTP_REQ_HEAD;
  552. } else {
  553. event_warnx("%s: bad method %s on request %p\n",
  554. __func__, method, req);
  555. return (-1);
  556. }
  557. if (strcmp(version, "HTTP/1.0") == 0) {
  558. req->major = 1;
  559. req->minor = 0;
  560. } else if (strcmp(version, "HTTP/1.1") == 0) {
  561. req->major = 1;
  562. req->minor = 1;
  563. } else {
  564. event_warnx("%s: bad version %s on request %p\n",
  565. __func__, version, req);
  566. return (-1);
  567. }
  568. if ((req->uri = strdup(uri)) == NULL) {
  569. event_warn("%s: strdup", __func__);
  570. return (-1);
  571. }
  572. return (0);
  573. }
  574. const char *
  575. evhttp_find_header(struct evkeyvalq *headers, const char *key)
  576. {
  577. struct evkeyval *header;
  578. TAILQ_FOREACH(header, headers, next) {
  579. if (strcasecmp(header->key, key) == 0)
  580. return (header->value);
  581. }
  582. return (NULL);
  583. }
  584. void
  585. evhttp_clear_headers(struct evkeyvalq *headers)
  586. {
  587. struct evkeyval *header;
  588. for (header = TAILQ_FIRST(headers);
  589. header != NULL;
  590. header = TAILQ_FIRST(headers)) {
  591. TAILQ_REMOVE(headers, header, next);
  592. free(header->key);
  593. free(header->value);
  594. free(header);
  595. }
  596. }
  597. /*
  598. * Returns 0, if the header was successfully removed.
  599. * Returns -1, if the header could not be found.
  600. */
  601. int
  602. evhttp_remove_header(struct evkeyvalq *headers, const char *key)
  603. {
  604. struct evkeyval *header;
  605. TAILQ_FOREACH(header, headers, next) {
  606. if (strcasecmp(header->key, key) == 0)
  607. break;
  608. }
  609. if (header == NULL)
  610. return (-1);
  611. /* Free and remove the header that we found */
  612. TAILQ_REMOVE(headers, header, next);
  613. free(header->key);
  614. free(header->value);
  615. free(header);
  616. return (0);
  617. }
  618. int
  619. evhttp_add_header(struct evkeyvalq *headers, const char *key, const char *value)
  620. {
  621. struct evkeyval *header;
  622. header = calloc(1, sizeof(struct evkeyval));
  623. if (header == NULL) {
  624. event_warn("%s: calloc", __func__);
  625. return (-1);
  626. }
  627. if ((header->key = strdup(key)) == NULL) {
  628. free(header);
  629. event_warn("%s: strdup", __func__);
  630. return (-1);
  631. }
  632. if ((header->value = strdup(value)) == NULL) {
  633. free(header->key);
  634. free(header);
  635. event_warn("%s: strdup", __func__);
  636. return (-1);
  637. }
  638. TAILQ_INSERT_TAIL(headers, header, next);
  639. return (0);
  640. }
  641. /*
  642. * Parses header lines from a request or a response into the specified
  643. * request object given an event buffer.
  644. *
  645. * Returns
  646. * -1 on error
  647. * 0 when we need to read more headers
  648. * 1 when all headers have been read.
  649. */
  650. int
  651. evhttp_parse_lines(struct evhttp_request *req, struct evbuffer* buffer)
  652. {
  653. u_char *endp;
  654. int done = 0;
  655. struct evkeyvalq* headers = req->input_headers;
  656. while ((endp = evbuffer_find(buffer, "\r\n", 2)) != NULL) {
  657. char *skey, *svalue;
  658. if (strncmp(EVBUFFER_DATA(buffer), "\r\n", 2) == 0) {
  659. evbuffer_drain(buffer, 2);
  660. /* Last header - Done */
  661. done = 1;
  662. break;
  663. }
  664. *endp = '\0';
  665. endp += 2;
  666. event_debug(("%s: Got: %s\n", __func__, EVBUFFER_DATA(buffer)));
  667. /* Processing of header lines */
  668. if (req->got_firstline == 0) {
  669. switch (req->kind) {
  670. case EVHTTP_REQUEST:
  671. if (evhttp_parse_request_line(req, EVBUFFER_DATA(buffer)) == -1)
  672. return (-1);
  673. break;
  674. case EVHTTP_RESPONSE:
  675. if (evhttp_parse_response_line(req, EVBUFFER_DATA(buffer)) == -1)
  676. return (-1);
  677. break;
  678. default:
  679. return (-1);
  680. }
  681. req->got_firstline = 1;
  682. } else {
  683. /* Regular header */
  684. svalue = EVBUFFER_DATA(buffer);
  685. skey = strsep(&svalue, ":");
  686. if (svalue == NULL)
  687. return (-1);
  688. svalue += strspn(svalue, " ");
  689. if (evhttp_add_header(headers, skey, svalue) == -1)
  690. return (-1);
  691. }
  692. /* Move the uncompleted headers forward */
  693. evbuffer_drain(buffer, endp - EVBUFFER_DATA(buffer));
  694. }
  695. return (done);
  696. }
  697. void
  698. evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req)
  699. {
  700. struct timeval tv;
  701. const char *content_length;
  702. const char *connection;
  703. struct evkeyvalq *headers = req->input_headers;
  704. /* If this is a request without a body, then we are done */
  705. if (req->kind == EVHTTP_REQUEST && req->type != EVHTTP_REQ_POST) {
  706. evhttp_connection_done(evcon);
  707. return;
  708. }
  709. content_length = evhttp_find_header(headers, "Content-Length");
  710. connection = evhttp_find_header(headers, "Connection");
  711. if (content_length == NULL && connection == NULL)
  712. req->ntoread = -1;
  713. else if (content_length == NULL &&
  714. strcasecmp(connection, "Close") != 0) {
  715. /* Bad combination, we don't know when it will end */
  716. event_warnx("%s: we got no content length, but the server"
  717. " wants to keep the connection open: %s.\n",
  718. __func__, connection);
  719. evhttp_connection_fail(evcon);
  720. return;
  721. } else if (content_length == NULL)
  722. req->ntoread = -1;
  723. else
  724. req->ntoread = atoi(content_length);
  725. event_debug(("%s: bytes to read: %d (in buffer %d)\n",
  726. __func__, req->ntoread, EVBUFFER_LENGTH(evcon->buffer)));
  727. if (req->ntoread > 0)
  728. req->ntoread -= EVBUFFER_LENGTH(evcon->input_buffer);
  729. if (req->ntoread == 0) {
  730. evhttp_connection_done(evcon);
  731. return;
  732. }
  733. event_set(&evcon->ev, evcon->fd, EV_READ, evhttp_read, evcon);
  734. timerclear(&tv);
  735. tv.tv_sec = HTTP_READ_TIMEOUT;
  736. event_add(&evcon->ev, &tv);
  737. return;
  738. }
  739. void
  740. evhttp_read_header(int fd, short what, void *arg)
  741. {
  742. struct timeval tv;
  743. struct evhttp_connection *evcon = arg;
  744. struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
  745. int n, res;
  746. if (what == EV_TIMEOUT) {
  747. event_warnx("%s: timeout on %d\n", __func__, fd);
  748. evhttp_connection_fail(evcon);
  749. return;
  750. }
  751. n = evbuffer_read(evcon->input_buffer, fd, -1);
  752. if (n == 0) {
  753. event_warnx("%s: no more data on %d\n", __func__, fd);
  754. evhttp_connection_fail(evcon);
  755. return;
  756. }
  757. if (n == -1) {
  758. event_warnx("%s: bad read on %d\n", __func__, fd);
  759. evhttp_connection_fail(evcon);
  760. return;
  761. }
  762. res = evhttp_parse_lines(req, evcon->input_buffer);
  763. if (res == -1) {
  764. /* Error while reading, terminate */
  765. event_warnx("%s: bad header lines on %d\n", __func__, fd);
  766. evhttp_connection_fail(evcon);
  767. return;
  768. } else if (res == 0) {
  769. /* Need more header lines */
  770. timerclear(&tv);
  771. tv.tv_sec = HTTP_READ_TIMEOUT;
  772. event_add(&evcon->ev, &tv);
  773. return;
  774. }
  775. /* Done reading headers, do the real work */
  776. switch (req->kind) {
  777. case EVHTTP_REQUEST:
  778. event_debug(("%s: checking for post data on %d\n",
  779. __func__, fd));
  780. evhttp_get_body(evcon, req);
  781. break;
  782. case EVHTTP_RESPONSE:
  783. event_debug(("%s: starting to read body for \"%s\" on %d\n",
  784. __func__, req->remote_host, fd));
  785. evhttp_get_body(evcon, req);
  786. break;
  787. default:
  788. event_warnx("%s: bad header on %d\n", __func__, fd);
  789. evhttp_connection_fail(evcon);
  790. break;
  791. }
  792. }
  793. /*
  794. * Creates a TCP connection to the specified port and executes a callback
  795. * when finished. Failure or sucess is indicate by the passed connection
  796. * object.
  797. *
  798. * Although this interface accepts a hostname, it is intended to take
  799. * only numeric hostnames so that non-blocking DNS resolution can
  800. * happen elsewhere.
  801. */
  802. struct evhttp_connection *
  803. evhttp_connection_new(const char *address, unsigned short port)
  804. {
  805. struct evhttp_connection *evcon = NULL;
  806. event_debug(("Attempting connection to %s:%d\n", address, port));
  807. if ((evcon = calloc(1, sizeof(struct evhttp_connection))) == NULL) {
  808. event_warn("%s: calloc failed", __func__);
  809. goto error;
  810. }
  811. evcon->fd = -1;
  812. evcon->port = port;
  813. if ((evcon->address = strdup(address)) == NULL) {
  814. event_warn("%s: strdup failed", __func__);
  815. goto error;
  816. }
  817. if ((evcon->input_buffer = evbuffer_new()) == NULL) {
  818. event_warn("%s: evbuffer_new failed", __func__);
  819. goto error;
  820. }
  821. if ((evcon->output_buffer = evbuffer_new()) == NULL) {
  822. event_warn("%s: evbuffer_new failed", __func__);
  823. goto error;
  824. }
  825. evcon->state = EVCON_DISCONNECTED;
  826. TAILQ_INIT(&evcon->requests);
  827. return (evcon);
  828. error:
  829. if (evcon != NULL)
  830. evhttp_connection_free(evcon);
  831. return (NULL);
  832. }
  833. int
  834. evhttp_connection_connect(struct evhttp_connection *evcon)
  835. {
  836. struct timeval tv;
  837. if (evcon->state == EVCON_CONNECTING)
  838. return (0);
  839. evhttp_connection_reset(evcon);
  840. assert(!(evcon->flags & EVHTTP_CON_INCOMING));
  841. evcon->flags |= EVHTTP_CON_OUTGOING;
  842. /* Do async connection to HTTP server */
  843. if ((evcon->fd = make_socket(
  844. connect, evcon->address, evcon->port)) == -1) {
  845. event_warn("%s: failed to connect to \"%s:%d\"",
  846. __func__, evcon->address, evcon->port);
  847. return (-1);
  848. }
  849. /* Set up a callback for successful connection setup */
  850. event_set(&evcon->ev, evcon->fd, EV_WRITE, evhttp_connectioncb, evcon);
  851. timerclear(&tv);
  852. tv.tv_sec = HTTP_CONNECT_TIMEOUT;
  853. event_add(&evcon->ev, &tv);
  854. evcon->state = EVCON_CONNECTING;
  855. return (0);
  856. }
  857. /*
  858. * Starts an HTTP request on the provided evhttp_connection object.
  859. * If the connection object is not connected to the web server already,
  860. * this will start the connection.
  861. */
  862. int
  863. evhttp_make_request(struct evhttp_connection *evcon,
  864. struct evhttp_request *req,
  865. enum evhttp_cmd_type type, const char *uri)
  866. {
  867. /* We are making a request */
  868. req->kind = EVHTTP_REQUEST;
  869. req->type = type;
  870. if (req->uri != NULL)
  871. free(req->uri);
  872. if ((req->uri = strdup(uri)) == NULL)
  873. event_err(1, "%s: strdup", __func__);
  874. /* Set the protocol version if it is not supplied */
  875. if (!req->major && !req->minor) {
  876. req->major = 1;
  877. req->minor = 1;
  878. }
  879. assert(req->evcon == NULL);
  880. req->evcon = evcon;
  881. assert(!(req->flags && EVHTTP_REQ_OWN_CONNECTION));
  882. TAILQ_INSERT_TAIL(&evcon->requests, req, next);
  883. /* If the connection object is not connected; make it so */
  884. if (evcon->state != EVCON_CONNECTED)
  885. return (evhttp_connection_connect(evcon));
  886. /*
  887. * If it's connected already and we are the first in the queue,
  888. * then we can dispatch this request immediately. Otherwise, it
  889. * will be dispatched once the pending requests are completed.
  890. */
  891. if (TAILQ_FIRST(&evcon->requests) == req)
  892. evhttp_request_dispatch(evcon);
  893. return (0);
  894. }
  895. /*
  896. * Reads data from file descriptor into request structure
  897. * Request structure needs to be set up correctly.
  898. */
  899. void
  900. evhttp_start_read(struct evhttp_connection *evcon)
  901. {
  902. struct timeval tv;
  903. /* Set up an event to read the headers */
  904. if (event_initialized(&evcon->ev))
  905. event_del(&evcon->ev);
  906. event_set(&evcon->ev, evcon->fd, EV_READ, evhttp_read_header, evcon);
  907. timerclear(&tv);
  908. tv.tv_sec = HTTP_READ_TIMEOUT;
  909. event_add(&evcon->ev, &tv);
  910. }
  911. void
  912. evhttp_send_done(struct evhttp_connection *evcon, void *arg)
  913. {
  914. struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
  915. TAILQ_REMOVE(&evcon->requests, req, next);
  916. if (req->flags & EVHTTP_REQ_OWN_CONNECTION)
  917. evhttp_connection_free(evcon);
  918. evhttp_request_free(req);
  919. }
  920. /*
  921. * Returns an error page.
  922. */
  923. void
  924. evhttp_send_error(struct evhttp_request *req, int error, const char *reason)
  925. {
  926. char *fmt = "<HTML><HEAD>\n"
  927. "<TITLE>%d %s</TITLE>\n"
  928. "</HEAD><BODY>\n"
  929. "<H1>Method Not Implemented</H1>\n"
  930. "Invalid method in request<P>\n"
  931. "</BODY></HTML>\n";
  932. struct evbuffer *buf = evbuffer_new();
  933. evhttp_response_code(req, error, reason);
  934. evbuffer_add_printf(buf, fmt, error, reason);
  935. evhttp_send_page(req, buf);
  936. evbuffer_free(buf);
  937. }
  938. /* Requires that headers and response code are already set up */
  939. static __inline void
  940. evhttp_send(struct evhttp_request *req, struct evbuffer *databuf)
  941. {
  942. struct evhttp_connection *evcon = req->evcon;
  943. assert(TAILQ_FIRST(&evcon->requests) == req);
  944. /* xxx: not sure if we really should expost the data buffer this way */
  945. evbuffer_add_buffer(req->output_buffer, databuf);
  946. /* Adds headers to the response */
  947. evhttp_make_header(evcon, req);
  948. evhttp_write_buffer(evcon, evhttp_send_done, NULL);
  949. }
  950. void
  951. evhttp_send_reply(struct evhttp_request *req, int code, const char *reason,
  952. struct evbuffer *databuf)
  953. {
  954. evhttp_response_code(req, code, reason);
  955. evhttp_send(req, databuf);
  956. }
  957. void
  958. evhttp_response_code(struct evhttp_request *req, int code, const char *reason)
  959. {
  960. req->kind = EVHTTP_RESPONSE;
  961. req->response_code = code;
  962. if (req->response_code_line != NULL)
  963. free(req->response_code_line);
  964. req->response_code_line = strdup(reason);
  965. }
  966. void
  967. evhttp_send_page(struct evhttp_request *req, struct evbuffer *databuf)
  968. {
  969. if (req->kind != EVHTTP_RESPONSE)
  970. evhttp_response_code(req, 200, "OK");
  971. evhttp_clear_headers(req->output_headers);
  972. evhttp_add_header(req->output_headers, "Content-Type", "text/html");
  973. evhttp_add_header(req->output_headers, "Connection", "close");
  974. evhttp_send(req, databuf);
  975. }
  976. /*
  977. * Helper function to parse out arguments in a query.
  978. * The arguments are separated by key and value.
  979. */
  980. void
  981. evhttp_parse_query(const char *uri, struct evkeyvalq *headers)
  982. {
  983. char *line;
  984. char *argument;
  985. char *p;
  986. TAILQ_INIT(headers);
  987. /* No arguments - we are done */
  988. if (strchr(uri, '?') == NULL)
  989. return;
  990. if ((line = strdup(uri)) == NULL)
  991. event_err(1, "%s: strdup", __func__);
  992. argument = line;
  993. /* We already know that there has to be a ? */
  994. strsep(&argument, "?");
  995. p = argument;
  996. while (p != NULL && *p != '\0') {
  997. char *key, *value;
  998. argument = strsep(&p, "&");
  999. value = argument;
  1000. key = strsep(&value, "=");
  1001. if (value == NULL)
  1002. goto error;
  1003. event_warnx("Got: %s -> %s\n", key, value);
  1004. evhttp_add_header(headers, key, value);
  1005. }
  1006. error:
  1007. free(line);
  1008. }
  1009. void
  1010. evhttp_handle_request(struct evhttp_request *req, void *arg)
  1011. {
  1012. struct evhttp *http = arg;
  1013. struct evhttp_cb *cb;
  1014. /* Test for different URLs */
  1015. TAILQ_FOREACH(cb, &http->callbacks, next) {
  1016. int res;
  1017. char *p = strchr(req->uri, '?');
  1018. if (p == NULL)
  1019. res = strcmp(cb->what, req->uri) == 0;
  1020. else
  1021. res = strncmp(cb->what, req->uri,
  1022. (size_t)(p - req->uri)) == 0;
  1023. if (res) {
  1024. (*cb->cb)(req, cb->cbarg);
  1025. return;
  1026. }
  1027. }
  1028. /* Generic call back */
  1029. if (http->gencb) {
  1030. (*http->gencb)(req, http->gencbarg);
  1031. return;
  1032. } else {
  1033. /* We need to send a 404 here */
  1034. char *fmt = "<html><head>"
  1035. "<title>404 Not Found</title>"
  1036. "</head><body>"
  1037. "<h1>Not Found</h1>"
  1038. "<p>The requested URL %s was not found on this server.</p>"
  1039. "</body></html>\n";
  1040. char *escaped_html = evhttp_htmlescape(req->uri);
  1041. struct evbuffer *buf = evbuffer_new();
  1042. evhttp_response_code(req, HTTP_NOTFOUND, "Not Found");
  1043. evbuffer_add_printf(buf, fmt, escaped_html);
  1044. free(escaped_html);
  1045. evhttp_send_page(req, buf);
  1046. evbuffer_free(buf);
  1047. }
  1048. }
  1049. static void
  1050. accept_socket(int fd, short what, void *arg)
  1051. {
  1052. struct evhttp *http = arg;
  1053. struct sockaddr_storage ss;
  1054. socklen_t addrlen = sizeof(ss);
  1055. int nfd;
  1056. if ((nfd = accept(fd, (struct sockaddr *)&ss, &addrlen)) == -1) {
  1057. event_warn("%s: bad accept", __func__);
  1058. return;
  1059. }
  1060. evhttp_get_request(nfd, (struct sockaddr *)&ss, addrlen,
  1061. evhttp_handle_request, http);
  1062. }
  1063. static int
  1064. bind_socket(struct evhttp *http, const char *address, u_short port)
  1065. {
  1066. struct event *ev = &http->bind_ev;
  1067. int fd;
  1068. if ((fd = make_socket(bind, address, port)) == -1)
  1069. return (-1);
  1070. if (listen(fd, 10) == -1) {
  1071. event_warn("%s: listen", __func__);
  1072. return (-1);
  1073. }
  1074. /* Schedule the socket for accepting */
  1075. event_set(ev, fd, EV_READ | EV_PERSIST, accept_socket, http);
  1076. event_add(ev, NULL);
  1077. event_debug(("Bound to port %d - Awaiting connections ... ", port));
  1078. return (0);
  1079. }
  1080. /*
  1081. * Start a web server on the specified address and port.
  1082. */
  1083. struct evhttp *
  1084. evhttp_start(const char *address, u_short port)
  1085. {
  1086. struct evhttp *http;
  1087. if ((http = calloc(1, sizeof(struct evhttp))) == NULL) {
  1088. event_warn("%s: calloc", __func__);
  1089. return (NULL);
  1090. }
  1091. TAILQ_INIT(&http->callbacks);
  1092. if (bind_socket(http, address, port) == -1) {
  1093. free(http);
  1094. return (NULL);
  1095. }
  1096. return (http);
  1097. }
  1098. void
  1099. evhttp_free(struct evhttp* http)
  1100. {
  1101. struct evhttp_cb *http_cb;
  1102. int fd = http->bind_ev.ev_fd;
  1103. /* Remove the accepting part */
  1104. event_del(&http->bind_ev);
  1105. close(fd);
  1106. while ((http_cb = TAILQ_FIRST(&http->callbacks)) != NULL) {
  1107. TAILQ_REMOVE(&http->callbacks, http_cb, next);
  1108. free(http_cb->what);
  1109. free(http_cb);
  1110. }
  1111. free(http);
  1112. }
  1113. void
  1114. evhttp_set_cb(struct evhttp *http, const char *uri,
  1115. void (*cb)(struct evhttp_request *, void *), void *cbarg)
  1116. {
  1117. struct evhttp_cb *http_cb;
  1118. if ((http_cb = calloc(1, sizeof(struct evhttp_cb))) == NULL)
  1119. event_err(1, "%s: calloc", __func__);
  1120. http_cb->what = strdup(uri);
  1121. http_cb->cb = cb;
  1122. http_cb->cbarg = cbarg;
  1123. TAILQ_INSERT_TAIL(&http->callbacks, http_cb, next);
  1124. }
  1125. void
  1126. evhttp_set_gencb(struct evhttp *http,
  1127. void (*cb)(struct evhttp_request *, void *), void *cbarg)
  1128. {
  1129. http->gencb = cb;
  1130. http->gencbarg = cbarg;
  1131. }
  1132. /*
  1133. * Request related functions
  1134. */
  1135. struct evhttp_request *
  1136. evhttp_request_new(void (*cb)(struct evhttp_request *, void *), void *arg)
  1137. {
  1138. struct evhttp_request *req = NULL;
  1139. /* Allocate request structure */
  1140. if ((req = calloc(1, sizeof(struct evhttp_request))) == NULL) {
  1141. event_warn("%s: calloc", __func__);
  1142. goto error;
  1143. }
  1144. req->kind = EVHTTP_RESPONSE;
  1145. req->input_headers = calloc(1, sizeof(struct evkeyvalq));
  1146. if (req->input_headers == NULL) {
  1147. event_warn("%s: calloc", __func__);
  1148. goto error;
  1149. }
  1150. TAILQ_INIT(req->input_headers);
  1151. req->output_headers = calloc(1, sizeof(struct evkeyvalq));
  1152. if (req->output_headers == NULL) {
  1153. event_warn("%s: calloc", __func__);
  1154. goto error;
  1155. }
  1156. TAILQ_INIT(req->output_headers);
  1157. if ((req->input_buffer = evbuffer_new()) == NULL) {
  1158. event_warn("%s: evbuffer_new", __func__);
  1159. goto error;
  1160. }
  1161. if ((req->output_buffer = evbuffer_new()) == NULL) {
  1162. event_warn("%s: evbuffer_new", __func__);
  1163. goto error;
  1164. }
  1165. req->cb = cb;
  1166. req->cb_arg = arg;
  1167. return (req);
  1168. error:
  1169. if (req != NULL)
  1170. evhttp_request_free(req);
  1171. return (NULL);
  1172. }
  1173. void
  1174. evhttp_request_free(struct evhttp_request *req)
  1175. {
  1176. if (req->remote_host != NULL)
  1177. free(req->remote_host);
  1178. if (req->uri != NULL)
  1179. free(req->uri);
  1180. if (req->response_code_line != NULL)
  1181. free(req->response_code_line);
  1182. evhttp_clear_headers(req->input_headers);
  1183. free(req->input_headers);
  1184. evhttp_clear_headers(req->output_headers);
  1185. free(req->output_headers);
  1186. if (req->input_buffer != NULL)
  1187. evbuffer_free(req->input_buffer);
  1188. if (req->output_buffer != NULL)
  1189. evbuffer_free(req->output_buffer);
  1190. free(req);
  1191. }
  1192. /*
  1193. * Allows for inspection of the request URI
  1194. */
  1195. const char *
  1196. evhttp_request_uri(struct evhttp_request *req) {
  1197. if (req->uri == NULL)
  1198. event_debug(("%s: request %p has no uri\n", req));
  1199. return (req->uri);
  1200. }
  1201. /*
  1202. * Takes a file descriptor to read a request from.
  1203. * The callback is executed once the whole request has been read.
  1204. */
  1205. void
  1206. evhttp_get_request(int fd, struct sockaddr *sa, socklen_t salen,
  1207. void (*cb)(struct evhttp_request *, void *), void *arg)
  1208. {
  1209. struct evhttp_connection *evcon;
  1210. struct evhttp_request *req;
  1211. char *hostname, *portname;
  1212. name_from_addr(sa, salen, &hostname, &portname);
  1213. event_debug(("%s: new request from %s:%s on %d\n",
  1214. __func__, hostname, portname, fd));
  1215. /* we need a connection object to put the http request on */
  1216. if ((evcon = evhttp_connection_new(hostname, atoi(portname))) == NULL)
  1217. return;
  1218. evcon->flags |= EVHTTP_CON_INCOMING;
  1219. evcon->state = EVCON_CONNECTED;
  1220. if ((req = evhttp_request_new(cb, arg)) == NULL) {
  1221. evhttp_connection_free(evcon);
  1222. return;
  1223. }
  1224. evcon->fd = fd;
  1225. req->evcon = evcon; /* the request ends up owning the connection */
  1226. req->flags |= EVHTTP_REQ_OWN_CONNECTION;
  1227. TAILQ_INSERT_TAIL(&evcon->requests, req, next);
  1228. req->kind = EVHTTP_REQUEST;
  1229. if ((req->remote_host = strdup(hostname)) == NULL)
  1230. event_err(1, "%s: strdup", __func__);
  1231. req->remote_port = atoi(portname);
  1232. evhttp_start_read(evcon);
  1233. }
  1234. /*
  1235. * Network helper functions that we do not want to export to the rest of
  1236. * the world.
  1237. */
  1238. static struct addrinfo *
  1239. addr_from_name(char *address)
  1240. {
  1241. struct addrinfo ai, *aitop;
  1242. memset(&ai, 0, sizeof (ai));
  1243. ai.ai_family = AF_INET;
  1244. ai.ai_socktype = SOCK_RAW;
  1245. ai.ai_flags = 0;
  1246. if (getaddrinfo(address, NULL, &ai, &aitop) != 0) {
  1247. event_warn("getaddrinfo");
  1248. return (NULL);
  1249. }
  1250. return (aitop);
  1251. }
  1252. static void
  1253. name_from_addr(struct sockaddr *sa, socklen_t salen,
  1254. char **phost, char **pport)
  1255. {
  1256. static char ntop[NI_MAXHOST];
  1257. static char strport[NI_MAXSERV];
  1258. if (getnameinfo(sa, salen,
  1259. ntop, sizeof(ntop), strport, sizeof(strport),
  1260. NI_NUMERICHOST|NI_NUMERICSERV) != 0)
  1261. event_err(1, "getnameinfo failed");
  1262. *phost = ntop;
  1263. *pport = strport;
  1264. }
  1265. /* Either connect or bind */
  1266. static int
  1267. make_socket_ai(int (*f)(int, const struct sockaddr *, socklen_t),
  1268. struct addrinfo *ai)
  1269. {
  1270. struct linger linger;
  1271. int fd, on = 1;
  1272. int serrno;
  1273. /* Create listen socket */
  1274. fd = socket(AF_INET, SOCK_STREAM, 0);
  1275. if (fd == -1) {
  1276. event_warn("socket");
  1277. return (-1);
  1278. }
  1279. if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
  1280. event_warn("fcntl(O_NONBLOCK)");
  1281. goto out;
  1282. }
  1283. if (fcntl(fd, F_SETFD, 1) == -1) {
  1284. event_warn("fcntl(F_SETFD)");
  1285. goto out;
  1286. }
  1287. setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on));
  1288. setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on));
  1289. linger.l_onoff = 1;
  1290. linger.l_linger = 5;
  1291. setsockopt(fd, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger));
  1292. if ((f)(fd, ai->ai_addr, ai->ai_addrlen) == -1) {
  1293. if (errno != EINPROGRESS) {
  1294. goto out;
  1295. }
  1296. }
  1297. return (fd);
  1298. out:
  1299. serrno = errno;
  1300. close(fd);
  1301. errno = serrno;
  1302. return (-1);
  1303. }
  1304. static int
  1305. make_socket(int (*f)(int, const struct sockaddr *, socklen_t),
  1306. const char *address, short port)
  1307. {
  1308. struct addrinfo ai, *aitop;
  1309. char strport[NI_MAXSERV];
  1310. int fd;
  1311. memset(&ai, 0, sizeof (ai));
  1312. ai.ai_family = AF_INET;
  1313. ai.ai_socktype = SOCK_STREAM;
  1314. ai.ai_flags = f != connect ? AI_PASSIVE : 0;
  1315. snprintf(strport, sizeof (strport), "%d", port);
  1316. if (getaddrinfo(address, strport, &ai, &aitop) != 0) {
  1317. event_warn("getaddrinfo");
  1318. return (-1);
  1319. }
  1320. fd = make_socket_ai(f, aitop);
  1321. freeaddrinfo(aitop);
  1322. return (fd);
  1323. }