1c43e99fdSEd Maste /*
2c43e99fdSEd Maste A trivial static http webserver using Libevent's evhttp.
3c43e99fdSEd Maste
4c43e99fdSEd Maste This is not the best code in the world, and it does some fairly stupid stuff
5c43e99fdSEd Maste that you would never want to do in a production webserver. Caveat hackor!
6c43e99fdSEd Maste
7c43e99fdSEd Maste */
8c43e99fdSEd Maste
9c43e99fdSEd Maste /* Compatibility for possible missing IPv6 declarations */
10c43e99fdSEd Maste #include "../util-internal.h"
11c43e99fdSEd Maste
12c43e99fdSEd Maste #include <stdio.h>
13c43e99fdSEd Maste #include <stdlib.h>
14c43e99fdSEd Maste #include <string.h>
15c43e99fdSEd Maste
16c43e99fdSEd Maste #include <sys/types.h>
17c43e99fdSEd Maste #include <sys/stat.h>
18c43e99fdSEd Maste
19c43e99fdSEd Maste #ifdef _WIN32
20c43e99fdSEd Maste #include <winsock2.h>
21c43e99fdSEd Maste #include <ws2tcpip.h>
22c43e99fdSEd Maste #include <windows.h>
23*b50261e2SCy Schubert #include <getopt.h>
24c43e99fdSEd Maste #include <io.h>
25c43e99fdSEd Maste #include <fcntl.h>
26c43e99fdSEd Maste #ifndef S_ISDIR
27c43e99fdSEd Maste #define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR)
28c43e99fdSEd Maste #endif
29*b50261e2SCy Schubert #else /* !_WIN32 */
30c43e99fdSEd Maste #include <sys/stat.h>
31c43e99fdSEd Maste #include <sys/socket.h>
32c43e99fdSEd Maste #include <fcntl.h>
33c43e99fdSEd Maste #include <unistd.h>
34c43e99fdSEd Maste #include <dirent.h>
35*b50261e2SCy Schubert #endif /* _WIN32 */
36*b50261e2SCy Schubert #include <signal.h>
37*b50261e2SCy Schubert
38*b50261e2SCy Schubert #ifdef EVENT__HAVE_SYS_UN_H
39*b50261e2SCy Schubert #include <sys/un.h>
40*b50261e2SCy Schubert #endif
41*b50261e2SCy Schubert #ifdef EVENT__HAVE_AFUNIX_H
42*b50261e2SCy Schubert #include <afunix.h>
43c43e99fdSEd Maste #endif
44c43e99fdSEd Maste
45c43e99fdSEd Maste #include <event2/event.h>
46c43e99fdSEd Maste #include <event2/http.h>
47*b50261e2SCy Schubert #include <event2/listener.h>
48c43e99fdSEd Maste #include <event2/buffer.h>
49c43e99fdSEd Maste #include <event2/util.h>
50c43e99fdSEd Maste #include <event2/keyvalq_struct.h>
51c43e99fdSEd Maste
52*b50261e2SCy Schubert #ifdef _WIN32
53*b50261e2SCy Schubert #include <event2/thread.h>
54*b50261e2SCy Schubert #endif /* _WIN32 */
55*b50261e2SCy Schubert
56c43e99fdSEd Maste #ifdef EVENT__HAVE_NETINET_IN_H
57c43e99fdSEd Maste #include <netinet/in.h>
58c43e99fdSEd Maste # ifdef _XOPEN_SOURCE_EXTENDED
59c43e99fdSEd Maste # include <arpa/inet.h>
60c43e99fdSEd Maste # endif
61c43e99fdSEd Maste #endif
62c43e99fdSEd Maste
63c43e99fdSEd Maste #ifdef _WIN32
64c43e99fdSEd Maste #ifndef stat
65c43e99fdSEd Maste #define stat _stat
66c43e99fdSEd Maste #endif
67c43e99fdSEd Maste #ifndef fstat
68c43e99fdSEd Maste #define fstat _fstat
69c43e99fdSEd Maste #endif
70c43e99fdSEd Maste #ifndef open
71c43e99fdSEd Maste #define open _open
72c43e99fdSEd Maste #endif
73c43e99fdSEd Maste #ifndef close
74c43e99fdSEd Maste #define close _close
75c43e99fdSEd Maste #endif
76c43e99fdSEd Maste #ifndef O_RDONLY
77c43e99fdSEd Maste #define O_RDONLY _O_RDONLY
78c43e99fdSEd Maste #endif
79*b50261e2SCy Schubert #endif /* _WIN32 */
80c43e99fdSEd Maste
81c43e99fdSEd Maste char uri_root[512];
82c43e99fdSEd Maste
83c43e99fdSEd Maste static const struct table_entry {
84c43e99fdSEd Maste const char *extension;
85c43e99fdSEd Maste const char *content_type;
86c43e99fdSEd Maste } content_type_table[] = {
87c43e99fdSEd Maste { "txt", "text/plain" },
88c43e99fdSEd Maste { "c", "text/plain" },
89c43e99fdSEd Maste { "h", "text/plain" },
90c43e99fdSEd Maste { "html", "text/html" },
91c43e99fdSEd Maste { "htm", "text/htm" },
92c43e99fdSEd Maste { "css", "text/css" },
93c43e99fdSEd Maste { "gif", "image/gif" },
94c43e99fdSEd Maste { "jpg", "image/jpeg" },
95c43e99fdSEd Maste { "jpeg", "image/jpeg" },
96c43e99fdSEd Maste { "png", "image/png" },
97c43e99fdSEd Maste { "pdf", "application/pdf" },
98c43e99fdSEd Maste { "ps", "application/postscript" },
99c43e99fdSEd Maste { NULL, NULL },
100c43e99fdSEd Maste };
101c43e99fdSEd Maste
102*b50261e2SCy Schubert struct options {
103*b50261e2SCy Schubert int port;
104*b50261e2SCy Schubert int iocp;
105*b50261e2SCy Schubert int verbose;
106*b50261e2SCy Schubert
107*b50261e2SCy Schubert int unlink;
108*b50261e2SCy Schubert const char *unixsock;
109*b50261e2SCy Schubert const char *docroot;
110*b50261e2SCy Schubert };
111*b50261e2SCy Schubert
112c43e99fdSEd Maste /* Try to guess a good content-type for 'path' */
113c43e99fdSEd Maste static const char *
guess_content_type(const char * path)114c43e99fdSEd Maste guess_content_type(const char *path)
115c43e99fdSEd Maste {
116c43e99fdSEd Maste const char *last_period, *extension;
117c43e99fdSEd Maste const struct table_entry *ent;
118c43e99fdSEd Maste last_period = strrchr(path, '.');
119c43e99fdSEd Maste if (!last_period || strchr(last_period, '/'))
120c43e99fdSEd Maste goto not_found; /* no exension */
121c43e99fdSEd Maste extension = last_period + 1;
122c43e99fdSEd Maste for (ent = &content_type_table[0]; ent->extension; ++ent) {
123c43e99fdSEd Maste if (!evutil_ascii_strcasecmp(ent->extension, extension))
124c43e99fdSEd Maste return ent->content_type;
125c43e99fdSEd Maste }
126c43e99fdSEd Maste
127c43e99fdSEd Maste not_found:
128c43e99fdSEd Maste return "application/misc";
129c43e99fdSEd Maste }
130c43e99fdSEd Maste
131c43e99fdSEd Maste /* Callback used for the /dump URI, and for every non-GET request:
132c43e99fdSEd Maste * dumps all information to stdout and gives back a trivial 200 ok */
133c43e99fdSEd Maste static void
dump_request_cb(struct evhttp_request * req,void * arg)134c43e99fdSEd Maste dump_request_cb(struct evhttp_request *req, void *arg)
135c43e99fdSEd Maste {
136c43e99fdSEd Maste const char *cmdtype;
137c43e99fdSEd Maste struct evkeyvalq *headers;
138c43e99fdSEd Maste struct evkeyval *header;
139c43e99fdSEd Maste struct evbuffer *buf;
140c43e99fdSEd Maste
141c43e99fdSEd Maste switch (evhttp_request_get_command(req)) {
142c43e99fdSEd Maste case EVHTTP_REQ_GET: cmdtype = "GET"; break;
143c43e99fdSEd Maste case EVHTTP_REQ_POST: cmdtype = "POST"; break;
144c43e99fdSEd Maste case EVHTTP_REQ_HEAD: cmdtype = "HEAD"; break;
145c43e99fdSEd Maste case EVHTTP_REQ_PUT: cmdtype = "PUT"; break;
146c43e99fdSEd Maste case EVHTTP_REQ_DELETE: cmdtype = "DELETE"; break;
147c43e99fdSEd Maste case EVHTTP_REQ_OPTIONS: cmdtype = "OPTIONS"; break;
148c43e99fdSEd Maste case EVHTTP_REQ_TRACE: cmdtype = "TRACE"; break;
149c43e99fdSEd Maste case EVHTTP_REQ_CONNECT: cmdtype = "CONNECT"; break;
150c43e99fdSEd Maste case EVHTTP_REQ_PATCH: cmdtype = "PATCH"; break;
151c43e99fdSEd Maste default: cmdtype = "unknown"; break;
152c43e99fdSEd Maste }
153c43e99fdSEd Maste
154c43e99fdSEd Maste printf("Received a %s request for %s\nHeaders:\n",
155c43e99fdSEd Maste cmdtype, evhttp_request_get_uri(req));
156c43e99fdSEd Maste
157c43e99fdSEd Maste headers = evhttp_request_get_input_headers(req);
158c43e99fdSEd Maste for (header = headers->tqh_first; header;
159c43e99fdSEd Maste header = header->next.tqe_next) {
160c43e99fdSEd Maste printf(" %s: %s\n", header->key, header->value);
161c43e99fdSEd Maste }
162c43e99fdSEd Maste
163c43e99fdSEd Maste buf = evhttp_request_get_input_buffer(req);
164c43e99fdSEd Maste puts("Input data: <<<");
165c43e99fdSEd Maste while (evbuffer_get_length(buf)) {
166c43e99fdSEd Maste int n;
167c43e99fdSEd Maste char cbuf[128];
168c43e99fdSEd Maste n = evbuffer_remove(buf, cbuf, sizeof(cbuf));
169c43e99fdSEd Maste if (n > 0)
170c43e99fdSEd Maste (void) fwrite(cbuf, 1, n, stdout);
171c43e99fdSEd Maste }
172c43e99fdSEd Maste puts(">>>");
173c43e99fdSEd Maste
174c43e99fdSEd Maste evhttp_send_reply(req, 200, "OK", NULL);
175c43e99fdSEd Maste }
176c43e99fdSEd Maste
177c43e99fdSEd Maste /* This callback gets invoked when we get any http request that doesn't match
178c43e99fdSEd Maste * any other callback. Like any evhttp server callback, it has a simple job:
179c43e99fdSEd Maste * it must eventually call evhttp_send_error() or evhttp_send_reply().
180c43e99fdSEd Maste */
181c43e99fdSEd Maste static void
send_document_cb(struct evhttp_request * req,void * arg)182c43e99fdSEd Maste send_document_cb(struct evhttp_request *req, void *arg)
183c43e99fdSEd Maste {
184c43e99fdSEd Maste struct evbuffer *evb = NULL;
185*b50261e2SCy Schubert struct options *o = arg;
186c43e99fdSEd Maste const char *uri = evhttp_request_get_uri(req);
187c43e99fdSEd Maste struct evhttp_uri *decoded = NULL;
188c43e99fdSEd Maste const char *path;
189c43e99fdSEd Maste char *decoded_path;
190c43e99fdSEd Maste char *whole_path = NULL;
191c43e99fdSEd Maste size_t len;
192c43e99fdSEd Maste int fd = -1;
193c43e99fdSEd Maste struct stat st;
194c43e99fdSEd Maste
195c43e99fdSEd Maste if (evhttp_request_get_command(req) != EVHTTP_REQ_GET) {
196c43e99fdSEd Maste dump_request_cb(req, arg);
197c43e99fdSEd Maste return;
198c43e99fdSEd Maste }
199c43e99fdSEd Maste
200c43e99fdSEd Maste printf("Got a GET request for <%s>\n", uri);
201c43e99fdSEd Maste
202c43e99fdSEd Maste /* Decode the URI */
203c43e99fdSEd Maste decoded = evhttp_uri_parse(uri);
204c43e99fdSEd Maste if (!decoded) {
205c43e99fdSEd Maste printf("It's not a good URI. Sending BADREQUEST\n");
206c43e99fdSEd Maste evhttp_send_error(req, HTTP_BADREQUEST, 0);
207c43e99fdSEd Maste return;
208c43e99fdSEd Maste }
209c43e99fdSEd Maste
210c43e99fdSEd Maste /* Let's see what path the user asked for. */
211c43e99fdSEd Maste path = evhttp_uri_get_path(decoded);
212c43e99fdSEd Maste if (!path) path = "/";
213c43e99fdSEd Maste
214c43e99fdSEd Maste /* We need to decode it, to see what path the user really wanted. */
215c43e99fdSEd Maste decoded_path = evhttp_uridecode(path, 0, NULL);
216c43e99fdSEd Maste if (decoded_path == NULL)
217c43e99fdSEd Maste goto err;
218c43e99fdSEd Maste /* Don't allow any ".."s in the path, to avoid exposing stuff outside
219c43e99fdSEd Maste * of the docroot. This test is both overzealous and underzealous:
220c43e99fdSEd Maste * it forbids aceptable paths like "/this/one..here", but it doesn't
221c43e99fdSEd Maste * do anything to prevent symlink following." */
222c43e99fdSEd Maste if (strstr(decoded_path, ".."))
223c43e99fdSEd Maste goto err;
224c43e99fdSEd Maste
225*b50261e2SCy Schubert len = strlen(decoded_path)+strlen(o->docroot)+2;
226c43e99fdSEd Maste if (!(whole_path = malloc(len))) {
227c43e99fdSEd Maste perror("malloc");
228c43e99fdSEd Maste goto err;
229c43e99fdSEd Maste }
230*b50261e2SCy Schubert evutil_snprintf(whole_path, len, "%s/%s", o->docroot, decoded_path);
231c43e99fdSEd Maste
232c43e99fdSEd Maste if (stat(whole_path, &st)<0) {
233c43e99fdSEd Maste goto err;
234c43e99fdSEd Maste }
235c43e99fdSEd Maste
236c43e99fdSEd Maste /* This holds the content we're sending. */
237c43e99fdSEd Maste evb = evbuffer_new();
238c43e99fdSEd Maste
239c43e99fdSEd Maste if (S_ISDIR(st.st_mode)) {
240c43e99fdSEd Maste /* If it's a directory, read the comments and make a little
241c43e99fdSEd Maste * index page */
242c43e99fdSEd Maste #ifdef _WIN32
243c43e99fdSEd Maste HANDLE d;
244c43e99fdSEd Maste WIN32_FIND_DATAA ent;
245c43e99fdSEd Maste char *pattern;
246c43e99fdSEd Maste size_t dirlen;
247c43e99fdSEd Maste #else
248c43e99fdSEd Maste DIR *d;
249c43e99fdSEd Maste struct dirent *ent;
250c43e99fdSEd Maste #endif
251c43e99fdSEd Maste const char *trailing_slash = "";
252c43e99fdSEd Maste
253c43e99fdSEd Maste if (!strlen(path) || path[strlen(path)-1] != '/')
254c43e99fdSEd Maste trailing_slash = "/";
255c43e99fdSEd Maste
256c43e99fdSEd Maste #ifdef _WIN32
257c43e99fdSEd Maste dirlen = strlen(whole_path);
258c43e99fdSEd Maste pattern = malloc(dirlen+3);
259c43e99fdSEd Maste memcpy(pattern, whole_path, dirlen);
260c43e99fdSEd Maste pattern[dirlen] = '\\';
261c43e99fdSEd Maste pattern[dirlen+1] = '*';
262c43e99fdSEd Maste pattern[dirlen+2] = '\0';
263c43e99fdSEd Maste d = FindFirstFileA(pattern, &ent);
264c43e99fdSEd Maste free(pattern);
265c43e99fdSEd Maste if (d == INVALID_HANDLE_VALUE)
266c43e99fdSEd Maste goto err;
267c43e99fdSEd Maste #else
268c43e99fdSEd Maste if (!(d = opendir(whole_path)))
269c43e99fdSEd Maste goto err;
270c43e99fdSEd Maste #endif
271c43e99fdSEd Maste
272c43e99fdSEd Maste evbuffer_add_printf(evb,
273c43e99fdSEd Maste "<!DOCTYPE html>\n"
274c43e99fdSEd Maste "<html>\n <head>\n"
275c43e99fdSEd Maste " <meta charset='utf-8'>\n"
276c43e99fdSEd Maste " <title>%s</title>\n"
277c43e99fdSEd Maste " <base href='%s%s'>\n"
278c43e99fdSEd Maste " </head>\n"
279c43e99fdSEd Maste " <body>\n"
280c43e99fdSEd Maste " <h1>%s</h1>\n"
281c43e99fdSEd Maste " <ul>\n",
282c43e99fdSEd Maste decoded_path, /* XXX html-escape this. */
283c43e99fdSEd Maste path, /* XXX html-escape this? */
284c43e99fdSEd Maste trailing_slash,
285c43e99fdSEd Maste decoded_path /* XXX html-escape this */);
286c43e99fdSEd Maste #ifdef _WIN32
287c43e99fdSEd Maste do {
288c43e99fdSEd Maste const char *name = ent.cFileName;
289c43e99fdSEd Maste #else
290c43e99fdSEd Maste while ((ent = readdir(d))) {
291c43e99fdSEd Maste const char *name = ent->d_name;
292c43e99fdSEd Maste #endif
293c43e99fdSEd Maste evbuffer_add_printf(evb,
294c43e99fdSEd Maste " <li><a href=\"%s\">%s</a>\n",
295c43e99fdSEd Maste name, name);/* XXX escape this */
296c43e99fdSEd Maste #ifdef _WIN32
297c43e99fdSEd Maste } while (FindNextFileA(d, &ent));
298c43e99fdSEd Maste #else
299c43e99fdSEd Maste }
300c43e99fdSEd Maste #endif
301c43e99fdSEd Maste evbuffer_add_printf(evb, "</ul></body></html>\n");
302c43e99fdSEd Maste #ifdef _WIN32
303c43e99fdSEd Maste FindClose(d);
304c43e99fdSEd Maste #else
305c43e99fdSEd Maste closedir(d);
306c43e99fdSEd Maste #endif
307c43e99fdSEd Maste evhttp_add_header(evhttp_request_get_output_headers(req),
308c43e99fdSEd Maste "Content-Type", "text/html");
309c43e99fdSEd Maste } else {
310c43e99fdSEd Maste /* Otherwise it's a file; add it to the buffer to get
311c43e99fdSEd Maste * sent via sendfile */
312c43e99fdSEd Maste const char *type = guess_content_type(decoded_path);
313c43e99fdSEd Maste if ((fd = open(whole_path, O_RDONLY)) < 0) {
314c43e99fdSEd Maste perror("open");
315c43e99fdSEd Maste goto err;
316c43e99fdSEd Maste }
317c43e99fdSEd Maste
318c43e99fdSEd Maste if (fstat(fd, &st)<0) {
319c43e99fdSEd Maste /* Make sure the length still matches, now that we
320c43e99fdSEd Maste * opened the file :/ */
321c43e99fdSEd Maste perror("fstat");
322c43e99fdSEd Maste goto err;
323c43e99fdSEd Maste }
324c43e99fdSEd Maste evhttp_add_header(evhttp_request_get_output_headers(req),
325c43e99fdSEd Maste "Content-Type", type);
326c43e99fdSEd Maste evbuffer_add_file(evb, fd, 0, st.st_size);
327c43e99fdSEd Maste }
328c43e99fdSEd Maste
329c43e99fdSEd Maste evhttp_send_reply(req, 200, "OK", evb);
330c43e99fdSEd Maste goto done;
331c43e99fdSEd Maste err:
332c43e99fdSEd Maste evhttp_send_error(req, 404, "Document was not found");
333c43e99fdSEd Maste if (fd>=0)
334c43e99fdSEd Maste close(fd);
335c43e99fdSEd Maste done:
336c43e99fdSEd Maste if (decoded)
337c43e99fdSEd Maste evhttp_uri_free(decoded);
338c43e99fdSEd Maste if (decoded_path)
339c43e99fdSEd Maste free(decoded_path);
340c43e99fdSEd Maste if (whole_path)
341c43e99fdSEd Maste free(whole_path);
342c43e99fdSEd Maste if (evb)
343c43e99fdSEd Maste evbuffer_free(evb);
344c43e99fdSEd Maste }
345c43e99fdSEd Maste
346c43e99fdSEd Maste static void
print_usage(FILE * out,const char * prog,int exit_code)347*b50261e2SCy Schubert print_usage(FILE *out, const char *prog, int exit_code)
348c43e99fdSEd Maste {
349*b50261e2SCy Schubert fprintf(out,
350*b50261e2SCy Schubert "Syntax: %s [ OPTS ] <docroot>\n"
351*b50261e2SCy Schubert " -p - port\n"
352*b50261e2SCy Schubert " -U - bind to unix socket\n"
353*b50261e2SCy Schubert " -u - unlink unix socket before bind\n"
354*b50261e2SCy Schubert " -I - IOCP\n"
355*b50261e2SCy Schubert " -v - verbosity, enables libevent debug logging too\n", prog);
356*b50261e2SCy Schubert exit(exit_code);
357c43e99fdSEd Maste }
358*b50261e2SCy Schubert static struct options
parse_opts(int argc,char ** argv)359*b50261e2SCy Schubert parse_opts(int argc, char **argv)
360c43e99fdSEd Maste {
361*b50261e2SCy Schubert struct options o;
362*b50261e2SCy Schubert int opt;
363c43e99fdSEd Maste
364*b50261e2SCy Schubert memset(&o, 0, sizeof(o));
365*b50261e2SCy Schubert
366*b50261e2SCy Schubert while ((opt = getopt(argc, argv, "hp:U:uIv")) != -1) {
367*b50261e2SCy Schubert switch (opt) {
368*b50261e2SCy Schubert case 'p': o.port = atoi(optarg); break;
369*b50261e2SCy Schubert case 'U': o.unixsock = optarg; break;
370*b50261e2SCy Schubert case 'u': o.unlink = 1; break;
371*b50261e2SCy Schubert case 'I': o.iocp = 1; break;
372*b50261e2SCy Schubert case 'v': ++o.verbose; break;
373*b50261e2SCy Schubert case 'h': print_usage(stdout, argv[0], 0); break;
374*b50261e2SCy Schubert default : fprintf(stderr, "Unknown option %c\n", opt); break;
375*b50261e2SCy Schubert }
376c43e99fdSEd Maste }
377c43e99fdSEd Maste
378*b50261e2SCy Schubert if (optind >= argc || (argc - optind) > 1) {
379*b50261e2SCy Schubert print_usage(stdout, argv[0], 1);
380*b50261e2SCy Schubert }
381*b50261e2SCy Schubert o.docroot = argv[optind];
382*b50261e2SCy Schubert
383*b50261e2SCy Schubert return o;
384c43e99fdSEd Maste }
385c43e99fdSEd Maste
386*b50261e2SCy Schubert static void
do_term(int sig,short events,void * arg)387*b50261e2SCy Schubert do_term(int sig, short events, void *arg)
388c43e99fdSEd Maste {
389*b50261e2SCy Schubert struct event_base *base = arg;
390*b50261e2SCy Schubert event_base_loopbreak(base);
391*b50261e2SCy Schubert fprintf(stderr, "Got %i, Terminating\n", sig);
392*b50261e2SCy Schubert }
393*b50261e2SCy Schubert
394*b50261e2SCy Schubert static int
display_listen_sock(struct evhttp_bound_socket * handle)395*b50261e2SCy Schubert display_listen_sock(struct evhttp_bound_socket *handle)
396*b50261e2SCy Schubert {
397c43e99fdSEd Maste struct sockaddr_storage ss;
398c43e99fdSEd Maste evutil_socket_t fd;
399c43e99fdSEd Maste ev_socklen_t socklen = sizeof(ss);
400c43e99fdSEd Maste char addrbuf[128];
401c43e99fdSEd Maste void *inaddr;
402c43e99fdSEd Maste const char *addr;
403c43e99fdSEd Maste int got_port = -1;
404*b50261e2SCy Schubert
405c43e99fdSEd Maste fd = evhttp_bound_socket_get_fd(handle);
406c43e99fdSEd Maste memset(&ss, 0, sizeof(ss));
407c43e99fdSEd Maste if (getsockname(fd, (struct sockaddr *)&ss, &socklen)) {
408c43e99fdSEd Maste perror("getsockname() failed");
409c43e99fdSEd Maste return 1;
410c43e99fdSEd Maste }
411*b50261e2SCy Schubert
412c43e99fdSEd Maste if (ss.ss_family == AF_INET) {
413c43e99fdSEd Maste got_port = ntohs(((struct sockaddr_in*)&ss)->sin_port);
414c43e99fdSEd Maste inaddr = &((struct sockaddr_in*)&ss)->sin_addr;
415c43e99fdSEd Maste } else if (ss.ss_family == AF_INET6) {
416c43e99fdSEd Maste got_port = ntohs(((struct sockaddr_in6*)&ss)->sin6_port);
417c43e99fdSEd Maste inaddr = &((struct sockaddr_in6*)&ss)->sin6_addr;
418*b50261e2SCy Schubert }
419*b50261e2SCy Schubert #ifdef EVENT__HAVE_STRUCT_SOCKADDR_UN
420*b50261e2SCy Schubert else if (ss.ss_family == AF_UNIX) {
421*b50261e2SCy Schubert printf("Listening on <%s>\n", ((struct sockaddr_un*)&ss)->sun_path);
422*b50261e2SCy Schubert return 0;
423*b50261e2SCy Schubert }
424*b50261e2SCy Schubert #endif
425*b50261e2SCy Schubert else {
426c43e99fdSEd Maste fprintf(stderr, "Weird address family %d\n",
427c43e99fdSEd Maste ss.ss_family);
428c43e99fdSEd Maste return 1;
429c43e99fdSEd Maste }
430*b50261e2SCy Schubert
431c43e99fdSEd Maste addr = evutil_inet_ntop(ss.ss_family, inaddr, addrbuf,
432c43e99fdSEd Maste sizeof(addrbuf));
433c43e99fdSEd Maste if (addr) {
434c43e99fdSEd Maste printf("Listening on %s:%d\n", addr, got_port);
435c43e99fdSEd Maste evutil_snprintf(uri_root, sizeof(uri_root),
436c43e99fdSEd Maste "http://%s:%d",addr,got_port);
437c43e99fdSEd Maste } else {
438c43e99fdSEd Maste fprintf(stderr, "evutil_inet_ntop failed\n");
439c43e99fdSEd Maste return 1;
440c43e99fdSEd Maste }
441*b50261e2SCy Schubert
442*b50261e2SCy Schubert return 0;
443c43e99fdSEd Maste }
444c43e99fdSEd Maste
445*b50261e2SCy Schubert int
main(int argc,char ** argv)446*b50261e2SCy Schubert main(int argc, char **argv)
447*b50261e2SCy Schubert {
448*b50261e2SCy Schubert struct event_config *cfg = NULL;
449*b50261e2SCy Schubert struct event_base *base = NULL;
450*b50261e2SCy Schubert struct evhttp *http = NULL;
451*b50261e2SCy Schubert struct evhttp_bound_socket *handle = NULL;
452*b50261e2SCy Schubert struct evconnlistener *lev = NULL;
453*b50261e2SCy Schubert struct event *term = NULL;
454*b50261e2SCy Schubert struct options o = parse_opts(argc, argv);
455*b50261e2SCy Schubert int ret = 0;
456*b50261e2SCy Schubert
457*b50261e2SCy Schubert #ifdef _WIN32
458*b50261e2SCy Schubert {
459*b50261e2SCy Schubert WORD wVersionRequested;
460*b50261e2SCy Schubert WSADATA wsaData;
461*b50261e2SCy Schubert wVersionRequested = MAKEWORD(2, 2);
462*b50261e2SCy Schubert WSAStartup(wVersionRequested, &wsaData);
463*b50261e2SCy Schubert }
464*b50261e2SCy Schubert #else
465*b50261e2SCy Schubert if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
466*b50261e2SCy Schubert ret = 1;
467*b50261e2SCy Schubert goto err;
468*b50261e2SCy Schubert }
469*b50261e2SCy Schubert #endif
470*b50261e2SCy Schubert
471*b50261e2SCy Schubert setbuf(stdout, NULL);
472*b50261e2SCy Schubert setbuf(stderr, NULL);
473*b50261e2SCy Schubert
474*b50261e2SCy Schubert /** Read env like in regress */
475*b50261e2SCy Schubert if (o.verbose || getenv("EVENT_DEBUG_LOGGING_ALL"))
476*b50261e2SCy Schubert event_enable_debug_logging(EVENT_DBG_ALL);
477*b50261e2SCy Schubert
478*b50261e2SCy Schubert cfg = event_config_new();
479*b50261e2SCy Schubert #ifdef _WIN32
480*b50261e2SCy Schubert if (o.iocp) {
481*b50261e2SCy Schubert #ifdef EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED
482*b50261e2SCy Schubert evthread_use_windows_threads();
483*b50261e2SCy Schubert event_config_set_num_cpus_hint(cfg, 8);
484*b50261e2SCy Schubert #endif
485*b50261e2SCy Schubert event_config_set_flag(cfg, EVENT_BASE_FLAG_STARTUP_IOCP);
486*b50261e2SCy Schubert }
487*b50261e2SCy Schubert #endif
488*b50261e2SCy Schubert
489*b50261e2SCy Schubert base = event_base_new_with_config(cfg);
490*b50261e2SCy Schubert if (!base) {
491*b50261e2SCy Schubert fprintf(stderr, "Couldn't create an event_base: exiting\n");
492*b50261e2SCy Schubert ret = 1;
493*b50261e2SCy Schubert }
494*b50261e2SCy Schubert event_config_free(cfg);
495*b50261e2SCy Schubert cfg = NULL;
496*b50261e2SCy Schubert
497*b50261e2SCy Schubert /* Create a new evhttp object to handle requests. */
498*b50261e2SCy Schubert http = evhttp_new(base);
499*b50261e2SCy Schubert if (!http) {
500*b50261e2SCy Schubert fprintf(stderr, "couldn't create evhttp. Exiting.\n");
501*b50261e2SCy Schubert ret = 1;
502*b50261e2SCy Schubert }
503*b50261e2SCy Schubert
504*b50261e2SCy Schubert /* The /dump URI will dump all requests to stdout and say 200 ok. */
505*b50261e2SCy Schubert evhttp_set_cb(http, "/dump", dump_request_cb, NULL);
506*b50261e2SCy Schubert
507*b50261e2SCy Schubert /* We want to accept arbitrary requests, so we need to set a "generic"
508*b50261e2SCy Schubert * cb. We can also add callbacks for specific paths. */
509*b50261e2SCy Schubert evhttp_set_gencb(http, send_document_cb, &o);
510*b50261e2SCy Schubert
511*b50261e2SCy Schubert if (o.unixsock) {
512*b50261e2SCy Schubert #ifdef EVENT__HAVE_STRUCT_SOCKADDR_UN
513*b50261e2SCy Schubert struct sockaddr_un addr;
514*b50261e2SCy Schubert
515*b50261e2SCy Schubert if (o.unlink && (unlink(o.unixsock) && errno != ENOENT)) {
516*b50261e2SCy Schubert perror(o.unixsock);
517*b50261e2SCy Schubert ret = 1;
518*b50261e2SCy Schubert goto err;
519*b50261e2SCy Schubert }
520*b50261e2SCy Schubert
521*b50261e2SCy Schubert addr.sun_family = AF_UNIX;
522*b50261e2SCy Schubert strcpy(addr.sun_path, o.unixsock);
523*b50261e2SCy Schubert
524*b50261e2SCy Schubert lev = evconnlistener_new_bind(base, NULL, NULL,
525*b50261e2SCy Schubert LEV_OPT_CLOSE_ON_FREE, -1,
526*b50261e2SCy Schubert (struct sockaddr *)&addr, sizeof(addr));
527*b50261e2SCy Schubert if (!lev) {
528*b50261e2SCy Schubert perror("Cannot create listener");
529*b50261e2SCy Schubert ret = 1;
530*b50261e2SCy Schubert goto err;
531*b50261e2SCy Schubert }
532*b50261e2SCy Schubert
533*b50261e2SCy Schubert handle = evhttp_bind_listener(http, lev);
534*b50261e2SCy Schubert if (!handle) {
535*b50261e2SCy Schubert fprintf(stderr, "couldn't bind to %s. Exiting.\n", o.unixsock);
536*b50261e2SCy Schubert ret = 1;
537*b50261e2SCy Schubert goto err;
538*b50261e2SCy Schubert }
539*b50261e2SCy Schubert #else /* !EVENT__HAVE_STRUCT_SOCKADDR_UN */
540*b50261e2SCy Schubert fprintf(stderr, "-U is not supported on this platform. Exiting.\n");
541*b50261e2SCy Schubert ret = 1;
542*b50261e2SCy Schubert goto err;
543*b50261e2SCy Schubert #endif /* EVENT__HAVE_STRUCT_SOCKADDR_UN */
544*b50261e2SCy Schubert }
545*b50261e2SCy Schubert else {
546*b50261e2SCy Schubert handle = evhttp_bind_socket_with_handle(http, "0.0.0.0", o.port);
547*b50261e2SCy Schubert if (!handle) {
548*b50261e2SCy Schubert fprintf(stderr, "couldn't bind to port %d. Exiting.\n", o.port);
549*b50261e2SCy Schubert ret = 1;
550*b50261e2SCy Schubert goto err;
551*b50261e2SCy Schubert }
552*b50261e2SCy Schubert }
553*b50261e2SCy Schubert
554*b50261e2SCy Schubert if (display_listen_sock(handle)) {
555*b50261e2SCy Schubert ret = 1;
556*b50261e2SCy Schubert goto err;
557*b50261e2SCy Schubert }
558*b50261e2SCy Schubert
559*b50261e2SCy Schubert term = evsignal_new(base, SIGINT, do_term, base);
560*b50261e2SCy Schubert if (!term)
561*b50261e2SCy Schubert goto err;
562*b50261e2SCy Schubert if (event_add(term, NULL))
563*b50261e2SCy Schubert goto err;
564*b50261e2SCy Schubert
565c43e99fdSEd Maste event_base_dispatch(base);
566c43e99fdSEd Maste
567*b50261e2SCy Schubert #ifdef _WIN32
568*b50261e2SCy Schubert WSACleanup();
569*b50261e2SCy Schubert #endif
570*b50261e2SCy Schubert
571*b50261e2SCy Schubert err:
572*b50261e2SCy Schubert if (cfg)
573*b50261e2SCy Schubert event_config_free(cfg);
574*b50261e2SCy Schubert if (http)
575*b50261e2SCy Schubert evhttp_free(http);
576*b50261e2SCy Schubert if (term)
577*b50261e2SCy Schubert event_free(term);
578*b50261e2SCy Schubert if (base)
579*b50261e2SCy Schubert event_base_free(base);
580*b50261e2SCy Schubert
581*b50261e2SCy Schubert return ret;
582c43e99fdSEd Maste }
583