diff options
author | Luke Shumaker <lukeshu@sbcglobal.net> | 2016-03-11 19:34:18 -0500 |
---|---|---|
committer | Luke Shumaker <lukeshu@sbcglobal.net> | 2016-03-11 19:34:18 -0500 |
commit | a0a8aaf5170eab149ee0fed4d7846e0df856a2e4 (patch) | |
tree | 8e301f0c0279bdd5b592f1c63004b650fab3470f /freenect-server--http.c | |
parent | 77f1df1a250d958317c930e6f3a36edf42f11d09 (diff) |
split into separate executables
Diffstat (limited to 'freenect-server--http.c')
-rw-r--r-- | freenect-server--http.c | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/freenect-server--http.c b/freenect-server--http.c new file mode 100644 index 0000000..d966e3b --- /dev/null +++ b/freenect-server--http.c @@ -0,0 +1,172 @@ +#include <error.h> +#include <errno.h> +#include <netdb.h> /* for {get,free}addrinfo() */ +#include <stdlib.h> /* for EXIT_FAILURE */ +#include <sys/socket.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/stat.h> /* for open */ +#include <fcntl.h> /* for open */ + +#include "util.h" +#include "mpjpeg.h" + +struct httpfile { + char name[256]; + struct mpjpeg_stream *stream; +}; + +size_t filec = 0; +struct httpfile *filev = NULL; + +struct reader_thread_args { + struct mpjpeg_stream *stream; + int fd; + const char *boundary; +}; + +void *reader_thread(void *args_anon) { + struct reader_thread_args *args = args_anon; + mpjpeg_reader(args->stream, args->fd, args->boundary); + return NULL; +} + +void start_mpjpeg_reader(struct mpjpeg_stream *s, int fd, const char *boundary) { + struct reader_thread_args *args = xrealloc(NULL, sizeof(struct reader_thread_args)); + args->stream = s; + args->fd = fd; + args->boundary = boundary; + pthread_t thread; + pthread_create(&thread, NULL, reader_thread, args); +} + +void file_add(const char *filename) { + struct mpjpeg_stream *stream = xrealloc(NULL, sizeof(struct mpjpeg_stream)); + init_mpjpeg_stream(stream); + int fd = open(filename, O_RDONLY); + if (fd < 0) + error(EXIT_FAILURE, errno, "opening file: %s", filename); + filev = xrealloc(NULL, (++filec)*sizeof(*filev)); + strncpy(filev[filec-1].name, filename, sizeof(filev[filec-1].name)); + filev[filec-1].stream = stream; + start_mpjpeg_reader(stream, fd, "ffserver" /* FIXME */); +} + +struct mpjpeg_stream *file_get(const char *filename) { + for (size_t i = 0; i < filec; i++) { + if (strncmp(filename, filev[i].name, sizeof(filev[i].name)) == 0) { + return filev[i].stream; + } + } + return NULL; +} + +int tcp4_parse_listen(const char *port) { + int r; + struct addrinfo *addr = NULL; + struct addrinfo hints = { 0 }; + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + + if ((r = getaddrinfo(NULL, port, &hints, &addr)) != 0) + error(EXIT_FAILURE, r, _("Could not resolve TCP4 port %s"), port); + + int sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); + if (sock < 0) + error(EXIT_FAILURE, errno, _("Could not create a TCP4 socket")); + + int yes = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); + + if (bind(sock, addr->ai_addr, addr->ai_addrlen) < 0) + error(EXIT_FAILURE, errno, _("Could not bind to TCP4 port %s"), port); + + if (listen(sock, 5) < 0) + error(EXIT_FAILURE, errno, _("Could not listen on TCP4 port %s"), port); + + freeaddrinfo(addr); + return sock; +} + +void connection_handler(int fd) { + FILE *netstream = fdopen(fd, "r"); + char *line_buf = NULL; + size_t line_cap = 0; + ssize_t line_len = 0; + + line_len = getline(&line_buf, &line_cap, netstream); + /* expect line to be "GET /path.mjpg HTTP/1.1" */ + if (strncmp(line_buf, "GET ", 4) != 0) { + dprintf(fd, + "HTTP/1.1 405 Method Not Allowed\r\n" + "Allow: GET\r\n" + "\r\n"); + close(fd); + return; + } + char *version = &line_buf[4]; + char *path = strsep(&version, " "); + if (strcmp(version, "HTTP/1.1\r\n") != 0 && strcmp(version, "HTTP/1.0\r\n")) { + close(fd); + return; + } + path = strdupa(path); + + /* run through the rest of the headers */ + while (strcmp(line_buf, "\r\n") != 0 && line_len >= 0) + line_len = getline(&line_buf, &line_cap, netstream); + + struct mpjpeg_stream *vidstream = file_get(path); + if (vidstream == NULL) { + dprintf(fd, + "HTTP/1.1 404 Not Found\r\n" + "\r\n"); + return; + } + + const char *boundary = "boundary" /* FIXME */; + dprintf(fd, + "HTTP/1.1 200 OK\r\n" + "Content-Type: multipart/x-mixed-replace;boundary=%s\r\n" + "\r\n", + boundary); + mpjpeg_writer(vidstream, fd, boundary); + close(fd); +} + +void *connection_thread(void *arg_anon) { + int fd = (int)(intptr_t)arg_anon; + connection_handler(fd); + return NULL; +} + +void usage() { + printf("Usage: %s [-h] PORT [FILENAME...]\n", program_invocation_name); +} + +int main(int argc, char *argv[]) { + if (argc < 2) { + dup2(2, 1); + usage(); + return EXIT_FAILURE; + } + if (strcmp(argv[1], "-h") == 0) { + usage(); + return EXIT_SUCCESS; + } + int sock = tcp4_parse_listen(argv[1]); + + for (int i = 2; i < argc; i++) + file_add(argv[i]); + + while (1) { + int conn = accept(sock, NULL, NULL); + if (conn < 0) + continue; + pthread_t thread; + pthread_create(&thread, NULL, connection_thread, (void*)(intptr_t)conn); + } + + return 0; +} |