1*0a6a1f1dSLionel Sambuc /* $NetBSD: http-server.c,v 1.1.1.2 2015/01/29 06:38:19 spz Exp $ */
2e985b929SDavid van Moolenbroek /*
3e985b929SDavid van Moolenbroek A trivial static http webserver using Libevent's evhttp.
4e985b929SDavid van Moolenbroek
5e985b929SDavid van Moolenbroek This is not the best code in the world, and it does some fairly stupid stuff
6e985b929SDavid van Moolenbroek that you would never want to do in a production webserver. Caveat hackor!
7e985b929SDavid van Moolenbroek
8e985b929SDavid van Moolenbroek */
9e985b929SDavid van Moolenbroek
10e985b929SDavid van Moolenbroek #include <stdio.h>
11e985b929SDavid van Moolenbroek #include <stdlib.h>
12e985b929SDavid van Moolenbroek #include <string.h>
13e985b929SDavid van Moolenbroek
14e985b929SDavid van Moolenbroek #include <sys/types.h>
15e985b929SDavid van Moolenbroek #include <sys/stat.h>
16e985b929SDavid van Moolenbroek
17e985b929SDavid van Moolenbroek #ifdef WIN32
18e985b929SDavid van Moolenbroek #include <winsock2.h>
19e985b929SDavid van Moolenbroek #include <ws2tcpip.h>
20e985b929SDavid van Moolenbroek #include <windows.h>
21e985b929SDavid van Moolenbroek #include <io.h>
22e985b929SDavid van Moolenbroek #include <fcntl.h>
23e985b929SDavid van Moolenbroek #ifndef S_ISDIR
24e985b929SDavid van Moolenbroek #define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR)
25e985b929SDavid van Moolenbroek #endif
26e985b929SDavid van Moolenbroek #else
27e985b929SDavid van Moolenbroek #include <sys/stat.h>
28e985b929SDavid van Moolenbroek #include <sys/socket.h>
29e985b929SDavid van Moolenbroek #include <signal.h>
30e985b929SDavid van Moolenbroek #include <fcntl.h>
31e985b929SDavid van Moolenbroek #include <unistd.h>
32e985b929SDavid van Moolenbroek #include <dirent.h>
33e985b929SDavid van Moolenbroek #endif
34e985b929SDavid van Moolenbroek
35e985b929SDavid van Moolenbroek #include <event2/event.h>
36e985b929SDavid van Moolenbroek #include <event2/http.h>
37e985b929SDavid van Moolenbroek #include <event2/buffer.h>
38e985b929SDavid van Moolenbroek #include <event2/util.h>
39e985b929SDavid van Moolenbroek #include <event2/keyvalq_struct.h>
40e985b929SDavid van Moolenbroek
41e985b929SDavid van Moolenbroek #ifdef _EVENT_HAVE_NETINET_IN_H
42e985b929SDavid van Moolenbroek #include <netinet/in.h>
43e985b929SDavid van Moolenbroek # ifdef _XOPEN_SOURCE_EXTENDED
44e985b929SDavid van Moolenbroek # include <arpa/inet.h>
45e985b929SDavid van Moolenbroek # endif
46e985b929SDavid van Moolenbroek #endif
47e985b929SDavid van Moolenbroek
48e985b929SDavid van Moolenbroek /* Compatibility for possible missing IPv6 declarations */
49e985b929SDavid van Moolenbroek #include "../util-internal.h"
50e985b929SDavid van Moolenbroek
51e985b929SDavid van Moolenbroek #ifdef WIN32
52e985b929SDavid van Moolenbroek #define stat _stat
53e985b929SDavid van Moolenbroek #define fstat _fstat
54e985b929SDavid van Moolenbroek #define open _open
55e985b929SDavid van Moolenbroek #define close _close
56e985b929SDavid van Moolenbroek #define O_RDONLY _O_RDONLY
57e985b929SDavid van Moolenbroek #endif
58e985b929SDavid van Moolenbroek
59e985b929SDavid van Moolenbroek char uri_root[512];
60e985b929SDavid van Moolenbroek
61e985b929SDavid van Moolenbroek static const struct table_entry {
62e985b929SDavid van Moolenbroek const char *extension;
63e985b929SDavid van Moolenbroek const char *content_type;
64e985b929SDavid van Moolenbroek } content_type_table[] = {
65e985b929SDavid van Moolenbroek { "txt", "text/plain" },
66e985b929SDavid van Moolenbroek { "c", "text/plain" },
67e985b929SDavid van Moolenbroek { "h", "text/plain" },
68e985b929SDavid van Moolenbroek { "html", "text/html" },
69e985b929SDavid van Moolenbroek { "htm", "text/htm" },
70e985b929SDavid van Moolenbroek { "css", "text/css" },
71e985b929SDavid van Moolenbroek { "gif", "image/gif" },
72e985b929SDavid van Moolenbroek { "jpg", "image/jpeg" },
73e985b929SDavid van Moolenbroek { "jpeg", "image/jpeg" },
74e985b929SDavid van Moolenbroek { "png", "image/png" },
75e985b929SDavid van Moolenbroek { "pdf", "application/pdf" },
76e985b929SDavid van Moolenbroek { "ps", "application/postsript" },
77e985b929SDavid van Moolenbroek { NULL, NULL },
78e985b929SDavid van Moolenbroek };
79e985b929SDavid van Moolenbroek
80e985b929SDavid van Moolenbroek /* Try to guess a good content-type for 'path' */
81e985b929SDavid van Moolenbroek static const char *
guess_content_type(const char * path)82e985b929SDavid van Moolenbroek guess_content_type(const char *path)
83e985b929SDavid van Moolenbroek {
84e985b929SDavid van Moolenbroek const char *last_period, *extension;
85e985b929SDavid van Moolenbroek const struct table_entry *ent;
86e985b929SDavid van Moolenbroek last_period = strrchr(path, '.');
87e985b929SDavid van Moolenbroek if (!last_period || strchr(last_period, '/'))
88e985b929SDavid van Moolenbroek goto not_found; /* no exension */
89e985b929SDavid van Moolenbroek extension = last_period + 1;
90e985b929SDavid van Moolenbroek for (ent = &content_type_table[0]; ent->extension; ++ent) {
91e985b929SDavid van Moolenbroek if (!evutil_ascii_strcasecmp(ent->extension, extension))
92e985b929SDavid van Moolenbroek return ent->content_type;
93e985b929SDavid van Moolenbroek }
94e985b929SDavid van Moolenbroek
95e985b929SDavid van Moolenbroek not_found:
96e985b929SDavid van Moolenbroek return "application/misc";
97e985b929SDavid van Moolenbroek }
98e985b929SDavid van Moolenbroek
99e985b929SDavid van Moolenbroek /* Callback used for the /dump URI, and for every non-GET request:
100e985b929SDavid van Moolenbroek * dumps all information to stdout and gives back a trivial 200 ok */
101e985b929SDavid van Moolenbroek static void
dump_request_cb(struct evhttp_request * req,void * arg)102e985b929SDavid van Moolenbroek dump_request_cb(struct evhttp_request *req, void *arg)
103e985b929SDavid van Moolenbroek {
104e985b929SDavid van Moolenbroek const char *cmdtype;
105e985b929SDavid van Moolenbroek struct evkeyvalq *headers;
106e985b929SDavid van Moolenbroek struct evkeyval *header;
107e985b929SDavid van Moolenbroek struct evbuffer *buf;
108e985b929SDavid van Moolenbroek
109e985b929SDavid van Moolenbroek switch (evhttp_request_get_command(req)) {
110e985b929SDavid van Moolenbroek case EVHTTP_REQ_GET: cmdtype = "GET"; break;
111e985b929SDavid van Moolenbroek case EVHTTP_REQ_POST: cmdtype = "POST"; break;
112e985b929SDavid van Moolenbroek case EVHTTP_REQ_HEAD: cmdtype = "HEAD"; break;
113e985b929SDavid van Moolenbroek case EVHTTP_REQ_PUT: cmdtype = "PUT"; break;
114e985b929SDavid van Moolenbroek case EVHTTP_REQ_DELETE: cmdtype = "DELETE"; break;
115e985b929SDavid van Moolenbroek case EVHTTP_REQ_OPTIONS: cmdtype = "OPTIONS"; break;
116e985b929SDavid van Moolenbroek case EVHTTP_REQ_TRACE: cmdtype = "TRACE"; break;
117e985b929SDavid van Moolenbroek case EVHTTP_REQ_CONNECT: cmdtype = "CONNECT"; break;
118e985b929SDavid van Moolenbroek case EVHTTP_REQ_PATCH: cmdtype = "PATCH"; break;
119e985b929SDavid van Moolenbroek default: cmdtype = "unknown"; break;
120e985b929SDavid van Moolenbroek }
121e985b929SDavid van Moolenbroek
122e985b929SDavid van Moolenbroek printf("Received a %s request for %s\nHeaders:\n",
123e985b929SDavid van Moolenbroek cmdtype, evhttp_request_get_uri(req));
124e985b929SDavid van Moolenbroek
125e985b929SDavid van Moolenbroek headers = evhttp_request_get_input_headers(req);
126e985b929SDavid van Moolenbroek for (header = headers->tqh_first; header;
127e985b929SDavid van Moolenbroek header = header->next.tqe_next) {
128e985b929SDavid van Moolenbroek printf(" %s: %s\n", header->key, header->value);
129e985b929SDavid van Moolenbroek }
130e985b929SDavid van Moolenbroek
131e985b929SDavid van Moolenbroek buf = evhttp_request_get_input_buffer(req);
132e985b929SDavid van Moolenbroek puts("Input data: <<<");
133e985b929SDavid van Moolenbroek while (evbuffer_get_length(buf)) {
134e985b929SDavid van Moolenbroek int n;
135e985b929SDavid van Moolenbroek char cbuf[128];
136*0a6a1f1dSLionel Sambuc n = evbuffer_remove(buf, cbuf, sizeof(cbuf));
137e985b929SDavid van Moolenbroek if (n > 0)
138e985b929SDavid van Moolenbroek (void) fwrite(cbuf, 1, n, stdout);
139e985b929SDavid van Moolenbroek }
140e985b929SDavid van Moolenbroek puts(">>>");
141e985b929SDavid van Moolenbroek
142e985b929SDavid van Moolenbroek evhttp_send_reply(req, 200, "OK", NULL);
143e985b929SDavid van Moolenbroek }
144e985b929SDavid van Moolenbroek
145e985b929SDavid van Moolenbroek /* This callback gets invoked when we get any http request that doesn't match
146e985b929SDavid van Moolenbroek * any other callback. Like any evhttp server callback, it has a simple job:
147e985b929SDavid van Moolenbroek * it must eventually call evhttp_send_error() or evhttp_send_reply().
148e985b929SDavid van Moolenbroek */
149e985b929SDavid van Moolenbroek static void
send_document_cb(struct evhttp_request * req,void * arg)150e985b929SDavid van Moolenbroek send_document_cb(struct evhttp_request *req, void *arg)
151e985b929SDavid van Moolenbroek {
152e985b929SDavid van Moolenbroek struct evbuffer *evb = NULL;
153e985b929SDavid van Moolenbroek const char *docroot = arg;
154e985b929SDavid van Moolenbroek const char *uri = evhttp_request_get_uri(req);
155e985b929SDavid van Moolenbroek struct evhttp_uri *decoded = NULL;
156e985b929SDavid van Moolenbroek const char *path;
157e985b929SDavid van Moolenbroek char *decoded_path;
158e985b929SDavid van Moolenbroek char *whole_path = NULL;
159e985b929SDavid van Moolenbroek size_t len;
160e985b929SDavid van Moolenbroek int fd = -1;
161e985b929SDavid van Moolenbroek struct stat st;
162e985b929SDavid van Moolenbroek
163e985b929SDavid van Moolenbroek if (evhttp_request_get_command(req) != EVHTTP_REQ_GET) {
164e985b929SDavid van Moolenbroek dump_request_cb(req, arg);
165e985b929SDavid van Moolenbroek return;
166e985b929SDavid van Moolenbroek }
167e985b929SDavid van Moolenbroek
168e985b929SDavid van Moolenbroek printf("Got a GET request for <%s>\n", uri);
169e985b929SDavid van Moolenbroek
170e985b929SDavid van Moolenbroek /* Decode the URI */
171e985b929SDavid van Moolenbroek decoded = evhttp_uri_parse(uri);
172e985b929SDavid van Moolenbroek if (!decoded) {
173e985b929SDavid van Moolenbroek printf("It's not a good URI. Sending BADREQUEST\n");
174e985b929SDavid van Moolenbroek evhttp_send_error(req, HTTP_BADREQUEST, 0);
175e985b929SDavid van Moolenbroek return;
176e985b929SDavid van Moolenbroek }
177e985b929SDavid van Moolenbroek
178e985b929SDavid van Moolenbroek /* Let's see what path the user asked for. */
179e985b929SDavid van Moolenbroek path = evhttp_uri_get_path(decoded);
180e985b929SDavid van Moolenbroek if (!path) path = "/";
181e985b929SDavid van Moolenbroek
182e985b929SDavid van Moolenbroek /* We need to decode it, to see what path the user really wanted. */
183e985b929SDavid van Moolenbroek decoded_path = evhttp_uridecode(path, 0, NULL);
184e985b929SDavid van Moolenbroek if (decoded_path == NULL)
185e985b929SDavid van Moolenbroek goto err;
186e985b929SDavid van Moolenbroek /* Don't allow any ".."s in the path, to avoid exposing stuff outside
187e985b929SDavid van Moolenbroek * of the docroot. This test is both overzealous and underzealous:
188e985b929SDavid van Moolenbroek * it forbids aceptable paths like "/this/one..here", but it doesn't
189e985b929SDavid van Moolenbroek * do anything to prevent symlink following." */
190e985b929SDavid van Moolenbroek if (strstr(decoded_path, ".."))
191e985b929SDavid van Moolenbroek goto err;
192e985b929SDavid van Moolenbroek
193e985b929SDavid van Moolenbroek len = strlen(decoded_path)+strlen(docroot)+2;
194e985b929SDavid van Moolenbroek if (!(whole_path = malloc(len))) {
195e985b929SDavid van Moolenbroek perror("malloc");
196e985b929SDavid van Moolenbroek goto err;
197e985b929SDavid van Moolenbroek }
198e985b929SDavid van Moolenbroek evutil_snprintf(whole_path, len, "%s/%s", docroot, decoded_path);
199e985b929SDavid van Moolenbroek
200e985b929SDavid van Moolenbroek if (stat(whole_path, &st)<0) {
201e985b929SDavid van Moolenbroek goto err;
202e985b929SDavid van Moolenbroek }
203e985b929SDavid van Moolenbroek
204e985b929SDavid van Moolenbroek /* This holds the content we're sending. */
205e985b929SDavid van Moolenbroek evb = evbuffer_new();
206e985b929SDavid van Moolenbroek
207e985b929SDavid van Moolenbroek if (S_ISDIR(st.st_mode)) {
208e985b929SDavid van Moolenbroek /* If it's a directory, read the comments and make a little
209e985b929SDavid van Moolenbroek * index page */
210e985b929SDavid van Moolenbroek #ifdef WIN32
211e985b929SDavid van Moolenbroek HANDLE d;
212e985b929SDavid van Moolenbroek WIN32_FIND_DATAA ent;
213e985b929SDavid van Moolenbroek char *pattern;
214e985b929SDavid van Moolenbroek size_t dirlen;
215e985b929SDavid van Moolenbroek #else
216e985b929SDavid van Moolenbroek DIR *d;
217e985b929SDavid van Moolenbroek struct dirent *ent;
218e985b929SDavid van Moolenbroek #endif
219e985b929SDavid van Moolenbroek const char *trailing_slash = "";
220e985b929SDavid van Moolenbroek
221e985b929SDavid van Moolenbroek if (!strlen(path) || path[strlen(path)-1] != '/')
222e985b929SDavid van Moolenbroek trailing_slash = "/";
223e985b929SDavid van Moolenbroek
224e985b929SDavid van Moolenbroek #ifdef WIN32
225e985b929SDavid van Moolenbroek dirlen = strlen(whole_path);
226e985b929SDavid van Moolenbroek pattern = malloc(dirlen+3);
227e985b929SDavid van Moolenbroek memcpy(pattern, whole_path, dirlen);
228e985b929SDavid van Moolenbroek pattern[dirlen] = '\\';
229e985b929SDavid van Moolenbroek pattern[dirlen+1] = '*';
230e985b929SDavid van Moolenbroek pattern[dirlen+2] = '\0';
231e985b929SDavid van Moolenbroek d = FindFirstFileA(pattern, &ent);
232e985b929SDavid van Moolenbroek free(pattern);
233e985b929SDavid van Moolenbroek if (d == INVALID_HANDLE_VALUE)
234e985b929SDavid van Moolenbroek goto err;
235e985b929SDavid van Moolenbroek #else
236e985b929SDavid van Moolenbroek if (!(d = opendir(whole_path)))
237e985b929SDavid van Moolenbroek goto err;
238e985b929SDavid van Moolenbroek #endif
239e985b929SDavid van Moolenbroek
240e985b929SDavid van Moolenbroek evbuffer_add_printf(evb, "<html>\n <head>\n"
241e985b929SDavid van Moolenbroek " <title>%s</title>\n"
242e985b929SDavid van Moolenbroek " <base href='%s%s%s'>\n"
243e985b929SDavid van Moolenbroek " </head>\n"
244e985b929SDavid van Moolenbroek " <body>\n"
245e985b929SDavid van Moolenbroek " <h1>%s</h1>\n"
246e985b929SDavid van Moolenbroek " <ul>\n",
247e985b929SDavid van Moolenbroek decoded_path, /* XXX html-escape this. */
248e985b929SDavid van Moolenbroek uri_root, path, /* XXX html-escape this? */
249e985b929SDavid van Moolenbroek trailing_slash,
250e985b929SDavid van Moolenbroek decoded_path /* XXX html-escape this */);
251e985b929SDavid van Moolenbroek #ifdef WIN32
252e985b929SDavid van Moolenbroek do {
253e985b929SDavid van Moolenbroek const char *name = ent.cFileName;
254e985b929SDavid van Moolenbroek #else
255e985b929SDavid van Moolenbroek while ((ent = readdir(d))) {
256e985b929SDavid van Moolenbroek const char *name = ent->d_name;
257e985b929SDavid van Moolenbroek #endif
258e985b929SDavid van Moolenbroek evbuffer_add_printf(evb,
259e985b929SDavid van Moolenbroek " <li><a href=\"%s\">%s</a>\n",
260e985b929SDavid van Moolenbroek name, name);/* XXX escape this */
261e985b929SDavid van Moolenbroek #ifdef WIN32
262e985b929SDavid van Moolenbroek } while (FindNextFileA(d, &ent));
263e985b929SDavid van Moolenbroek #else
264e985b929SDavid van Moolenbroek }
265e985b929SDavid van Moolenbroek #endif
266e985b929SDavid van Moolenbroek evbuffer_add_printf(evb, "</ul></body></html>\n");
267e985b929SDavid van Moolenbroek #ifdef WIN32
268*0a6a1f1dSLionel Sambuc FindClose(d);
269e985b929SDavid van Moolenbroek #else
270e985b929SDavid van Moolenbroek closedir(d);
271e985b929SDavid van Moolenbroek #endif
272e985b929SDavid van Moolenbroek evhttp_add_header(evhttp_request_get_output_headers(req),
273e985b929SDavid van Moolenbroek "Content-Type", "text/html");
274e985b929SDavid van Moolenbroek } else {
275e985b929SDavid van Moolenbroek /* Otherwise it's a file; add it to the buffer to get
276e985b929SDavid van Moolenbroek * sent via sendfile */
277e985b929SDavid van Moolenbroek const char *type = guess_content_type(decoded_path);
278e985b929SDavid van Moolenbroek if ((fd = open(whole_path, O_RDONLY)) < 0) {
279e985b929SDavid van Moolenbroek perror("open");
280e985b929SDavid van Moolenbroek goto err;
281e985b929SDavid van Moolenbroek }
282e985b929SDavid van Moolenbroek
283e985b929SDavid van Moolenbroek if (fstat(fd, &st)<0) {
284e985b929SDavid van Moolenbroek /* Make sure the length still matches, now that we
285e985b929SDavid van Moolenbroek * opened the file :/ */
286e985b929SDavid van Moolenbroek perror("fstat");
287e985b929SDavid van Moolenbroek goto err;
288e985b929SDavid van Moolenbroek }
289e985b929SDavid van Moolenbroek evhttp_add_header(evhttp_request_get_output_headers(req),
290e985b929SDavid van Moolenbroek "Content-Type", type);
291e985b929SDavid van Moolenbroek evbuffer_add_file(evb, fd, 0, st.st_size);
292e985b929SDavid van Moolenbroek }
293e985b929SDavid van Moolenbroek
294e985b929SDavid van Moolenbroek evhttp_send_reply(req, 200, "OK", evb);
295e985b929SDavid van Moolenbroek goto done;
296e985b929SDavid van Moolenbroek err:
297e985b929SDavid van Moolenbroek evhttp_send_error(req, 404, "Document was not found");
298e985b929SDavid van Moolenbroek if (fd>=0)
299e985b929SDavid van Moolenbroek close(fd);
300e985b929SDavid van Moolenbroek done:
301e985b929SDavid van Moolenbroek if (decoded)
302e985b929SDavid van Moolenbroek evhttp_uri_free(decoded);
303e985b929SDavid van Moolenbroek if (decoded_path)
304e985b929SDavid van Moolenbroek free(decoded_path);
305e985b929SDavid van Moolenbroek if (whole_path)
306e985b929SDavid van Moolenbroek free(whole_path);
307e985b929SDavid van Moolenbroek if (evb)
308e985b929SDavid van Moolenbroek evbuffer_free(evb);
309e985b929SDavid van Moolenbroek }
310e985b929SDavid van Moolenbroek
311e985b929SDavid van Moolenbroek static void
syntax(void)312e985b929SDavid van Moolenbroek syntax(void)
313e985b929SDavid van Moolenbroek {
314e985b929SDavid van Moolenbroek fprintf(stdout, "Syntax: http-server <docroot>\n");
315e985b929SDavid van Moolenbroek }
316e985b929SDavid van Moolenbroek
317e985b929SDavid van Moolenbroek int
main(int argc,char ** argv)318e985b929SDavid van Moolenbroek main(int argc, char **argv)
319e985b929SDavid van Moolenbroek {
320e985b929SDavid van Moolenbroek struct event_base *base;
321e985b929SDavid van Moolenbroek struct evhttp *http;
322e985b929SDavid van Moolenbroek struct evhttp_bound_socket *handle;
323e985b929SDavid van Moolenbroek
324e985b929SDavid van Moolenbroek unsigned short port = 0;
325e985b929SDavid van Moolenbroek #ifdef WIN32
326e985b929SDavid van Moolenbroek WSADATA WSAData;
327e985b929SDavid van Moolenbroek WSAStartup(0x101, &WSAData);
328e985b929SDavid van Moolenbroek #else
329e985b929SDavid van Moolenbroek if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
330e985b929SDavid van Moolenbroek return (1);
331e985b929SDavid van Moolenbroek #endif
332e985b929SDavid van Moolenbroek if (argc < 2) {
333e985b929SDavid van Moolenbroek syntax();
334e985b929SDavid van Moolenbroek return 1;
335e985b929SDavid van Moolenbroek }
336e985b929SDavid van Moolenbroek
337e985b929SDavid van Moolenbroek base = event_base_new();
338e985b929SDavid van Moolenbroek if (!base) {
339e985b929SDavid van Moolenbroek fprintf(stderr, "Couldn't create an event_base: exiting\n");
340e985b929SDavid van Moolenbroek return 1;
341e985b929SDavid van Moolenbroek }
342e985b929SDavid van Moolenbroek
343e985b929SDavid van Moolenbroek /* Create a new evhttp object to handle requests. */
344e985b929SDavid van Moolenbroek http = evhttp_new(base);
345e985b929SDavid van Moolenbroek if (!http) {
346e985b929SDavid van Moolenbroek fprintf(stderr, "couldn't create evhttp. Exiting.\n");
347e985b929SDavid van Moolenbroek return 1;
348e985b929SDavid van Moolenbroek }
349e985b929SDavid van Moolenbroek
350e985b929SDavid van Moolenbroek /* The /dump URI will dump all requests to stdout and say 200 ok. */
351e985b929SDavid van Moolenbroek evhttp_set_cb(http, "/dump", dump_request_cb, NULL);
352e985b929SDavid van Moolenbroek
353e985b929SDavid van Moolenbroek /* We want to accept arbitrary requests, so we need to set a "generic"
354e985b929SDavid van Moolenbroek * cb. We can also add callbacks for specific paths. */
355e985b929SDavid van Moolenbroek evhttp_set_gencb(http, send_document_cb, argv[1]);
356e985b929SDavid van Moolenbroek
357e985b929SDavid van Moolenbroek /* Now we tell the evhttp what port to listen on */
358e985b929SDavid van Moolenbroek handle = evhttp_bind_socket_with_handle(http, "0.0.0.0", port);
359e985b929SDavid van Moolenbroek if (!handle) {
360e985b929SDavid van Moolenbroek fprintf(stderr, "couldn't bind to port %d. Exiting.\n",
361e985b929SDavid van Moolenbroek (int)port);
362e985b929SDavid van Moolenbroek return 1;
363e985b929SDavid van Moolenbroek }
364e985b929SDavid van Moolenbroek
365e985b929SDavid van Moolenbroek {
366e985b929SDavid van Moolenbroek /* Extract and display the address we're listening on. */
367e985b929SDavid van Moolenbroek struct sockaddr_storage ss;
368e985b929SDavid van Moolenbroek evutil_socket_t fd;
369e985b929SDavid van Moolenbroek ev_socklen_t socklen = sizeof(ss);
370e985b929SDavid van Moolenbroek char addrbuf[128];
371e985b929SDavid van Moolenbroek void *inaddr;
372e985b929SDavid van Moolenbroek const char *addr;
373e985b929SDavid van Moolenbroek int got_port = -1;
374e985b929SDavid van Moolenbroek fd = evhttp_bound_socket_get_fd(handle);
375e985b929SDavid van Moolenbroek memset(&ss, 0, sizeof(ss));
376e985b929SDavid van Moolenbroek if (getsockname(fd, (struct sockaddr *)&ss, &socklen)) {
377e985b929SDavid van Moolenbroek perror("getsockname() failed");
378e985b929SDavid van Moolenbroek return 1;
379e985b929SDavid van Moolenbroek }
380e985b929SDavid van Moolenbroek if (ss.ss_family == AF_INET) {
381e985b929SDavid van Moolenbroek got_port = ntohs(((struct sockaddr_in*)&ss)->sin_port);
382e985b929SDavid van Moolenbroek inaddr = &((struct sockaddr_in*)&ss)->sin_addr;
383e985b929SDavid van Moolenbroek } else if (ss.ss_family == AF_INET6) {
384e985b929SDavid van Moolenbroek got_port = ntohs(((struct sockaddr_in6*)&ss)->sin6_port);
385e985b929SDavid van Moolenbroek inaddr = &((struct sockaddr_in6*)&ss)->sin6_addr;
386e985b929SDavid van Moolenbroek } else {
387e985b929SDavid van Moolenbroek fprintf(stderr, "Weird address family %d\n",
388e985b929SDavid van Moolenbroek ss.ss_family);
389e985b929SDavid van Moolenbroek return 1;
390e985b929SDavid van Moolenbroek }
391e985b929SDavid van Moolenbroek addr = evutil_inet_ntop(ss.ss_family, inaddr, addrbuf,
392e985b929SDavid van Moolenbroek sizeof(addrbuf));
393e985b929SDavid van Moolenbroek if (addr) {
394e985b929SDavid van Moolenbroek printf("Listening on %s:%d\n", addr, got_port);
395e985b929SDavid van Moolenbroek evutil_snprintf(uri_root, sizeof(uri_root),
396e985b929SDavid van Moolenbroek "http://%s:%d",addr,got_port);
397e985b929SDavid van Moolenbroek } else {
398e985b929SDavid van Moolenbroek fprintf(stderr, "evutil_inet_ntop failed\n");
399e985b929SDavid van Moolenbroek return 1;
400e985b929SDavid van Moolenbroek }
401e985b929SDavid van Moolenbroek }
402e985b929SDavid van Moolenbroek
403e985b929SDavid van Moolenbroek event_base_dispatch(base);
404e985b929SDavid van Moolenbroek
405e985b929SDavid van Moolenbroek return 0;
406e985b929SDavid van Moolenbroek }
407