diff --git a/.gitignore b/.gitignore index 4052be0..349bd00 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ /ustreamer-*.pkg.tar.xz /vgcore.* /ustreamer +/*.sock *.o diff --git a/Makefile b/Makefile index 670d437..4ca0604 100644 --- a/Makefile +++ b/Makefile @@ -59,5 +59,5 @@ push: clean-all: clean clean: - rm -f src/*.o src/{jpeg,omx}/*.o vgcore.* $(PROG) + rm -f src/*.o src/{jpeg,omx}/*.o vgcore.* *.sock $(PROG) rm -rf pkg src/$(PROG)-* src/v*.tar.gz v*.tar.gz $(PROG)-*.pkg.tar.xz diff --git a/src/http.c b/src/http.c index 5b500d6..0cb102b 100644 --- a/src/http.c +++ b/src/http.c @@ -23,8 +23,13 @@ #include #include #include +#include +#include #include +#include +#include + #include #include #include @@ -105,6 +110,9 @@ void http_server_destroy(struct http_server_t *server) { } evhttp_free(server->run->http); + if (server->run->unix_fd) { + close(server->run->unix_fd); + } event_base_free(server->run->base); libevent_global_shutdown(); @@ -128,15 +136,53 @@ int http_server_listen(struct http_server_t *server) { server->run->drop_same_frames_blank = max_u(server->drop_same_frames, server->run->drop_same_frames_blank); - LOG_DEBUG("Binding HTTP to [%s]:%d ...", server->host, server->port); evhttp_set_timeout(server->run->http, server->timeout); - if (evhttp_bind_socket(server->run->http, server->host, server->port) < 0) { - LOG_PERROR("Can't listen HTTP on [%s]:%d", server->host, server->port) - return -1; + if (server->unix_path) { + struct sockaddr_un unix_addr; + int unix_fd_flags; + + LOG_DEBUG("Binding HTTP to UNIX socket '%s' ...", server->unix_path); + + assert((server->run->unix_fd = socket(AF_UNIX, SOCK_STREAM, 0))); + assert((unix_fd_flags = fcntl(server->run->unix_fd, F_GETFL)) >= 0); + unix_fd_flags |= O_NONBLOCK; + assert(fcntl(server->run->unix_fd, F_SETFL, unix_fd_flags) >= 0); + + strncpy(unix_addr.sun_path, server->unix_path, 107); + unix_addr.sun_path[107] = '\0'; + unix_addr.sun_family = AF_UNIX; + + if (server->unix_path && server->unix_rm && unlink(server->unix_path) < 0) { + if (errno != ENOENT) { + LOG_PERROR("Can't remove old UNIX socket '%s'", server->unix_path); + return -1; + } + } + if (bind(server->run->unix_fd, (struct sockaddr *)&unix_addr, sizeof(struct sockaddr_un)) < 0) { + LOG_PERROR("Can't bind HTTP to UNIX socket '%s'", server->unix_path); + return -1; + } + if (listen(server->run->unix_fd, 128) < 0) { + LOG_PERROR("Can't listen UNIX socket '%s'", server->unix_path); + return -1; + } + if (evhttp_accept_socket(server->run->http, server->run->unix_fd) < 0) { + LOG_PERROR("Can't evhttp_accept_socket() UNIX socket '%s'", server->unix_path); + return -1; + } + + LOG_INFO("Listening HTTP on UNIX socket '%s'", server->unix_path); + + } else { + LOG_DEBUG("Binding HTTP to [%s]:%d ...", server->host, server->port); + if (evhttp_bind_socket(server->run->http, server->host, server->port) < 0) { + LOG_PERROR("Can't bind HTTP on [%s]:%d", server->host, server->port) + return -1; + } + LOG_INFO("Listening HTTP on [%s]:%d", server->host, server->port); } - LOG_INFO("Listening HTTP on [%s]:%d", server->host, server->port); return 0; } diff --git a/src/http.h b/src/http.h index 658341d..50d8d19 100644 --- a/src/http.h +++ b/src/http.h @@ -23,6 +23,7 @@ #include #include +#include #include "tools.h" #include "stream.h" @@ -65,6 +66,7 @@ struct exposed_t { struct http_server_runtime_t { struct event_base *base; struct evhttp *http; + evutil_socket_t unix_fd; struct event *refresh; struct stream_t *stream; struct exposed_t *exposed; @@ -76,6 +78,8 @@ struct http_server_runtime_t { struct http_server_t { char *host; unsigned port; + char *unix_path; + bool unix_rm; unsigned drop_same_frames; unsigned fake_width; unsigned fake_height; diff --git a/src/main.c b/src/main.c index 1fb0473..b67f0b7 100644 --- a/src/main.c +++ b/src/main.c @@ -40,7 +40,7 @@ #include "http.h" -static const char _short_opts[] = "d:i:x:y:f:a:z:tn:w:q:c:s:p:r:h"; +static const char _short_opts[] = "d:i:x:y:f:a:z:tn:w:q:c:s:p:u:er:h"; static const struct option _long_opts[] = { {"device", required_argument, NULL, 'd'}, {"input", required_argument, NULL, 'i'}, @@ -61,6 +61,8 @@ static const struct option _long_opts[] = { {"host", required_argument, NULL, 's'}, {"port", required_argument, NULL, 'p'}, + {"unix", required_argument, NULL, 'u'}, + {"unix-rm", no_argument, NULL, 'e'}, {"drop-same-frames", required_argument, NULL, 'r'}, {"fake-width", required_argument, NULL, 2001}, {"fake-height", required_argument, NULL, 2002}, @@ -122,6 +124,8 @@ static void _help(struct device_t *dev, struct encoder_t *encoder, struct http_s printf("--------------------\n"); printf(" --host
-- Listen on Hostname or IP. Default: %s\n\n", server->host); printf(" --port -- Bind to this TCP port. Default: %d\n\n", server->port); + printf(" --unix -- Bind to UNIX domain socket. Default: disabled\n\n"); + printf(" --unix-rm -- Try to remove old UNIX socket file before binding. Default: disabled\n\n"); printf(" --drop-same-frames -- Don't send same frames to clients, but no more than specified number.\n"); printf(" It can significantly reduce the outgoing traffic, but will increase\n"); printf(" the CPU loading. Don't use this option with analog signal sources\n"); @@ -184,6 +188,8 @@ static int _parse_options(int argc, char *argv[], struct device_t *dev, struct e case 's': OPT_SET(server->host, optarg); case 'p': OPT_UNSIGNED(server->port, "--port", 1, 65535); + case 'u': OPT_SET(server->unix_path, optarg); + case 'e': OPT_SET(server->unix_rm, true); case 'r': OPT_UNSIGNED(server->drop_same_frames, "--drop-same-frames", 0, 30); case 2001: OPT_UNSIGNED(server->fake_width, "--fake-width", 0, 1920); case 2002: OPT_UNSIGNED(server->fake_height, "--fake-height", 0, 1200);