From 33f252734ba54843c949f53c998a24b805e756a8 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Sat, 5 Jan 2019 12:29:10 +0000 Subject: [PATCH] Fix: move webserver in separate source files --- CMakeLists.txt | 12 +++- src/config.h.in | 34 ----------- src/{common.c => global.c} | 3 +- src/{common.h => global.h.in} | 24 +++++++- src/mpd_client.c | 12 ++-- src/mpd_client.h | 2 +- src/mympd.c | 106 +++++++++------------------------- src/tiny_queue.c | 12 ++++ src/tiny_queue.h | 1 + src/web_server.c | 97 ++++++++++++++++++++++++++++--- src/web_server.h | 10 +--- 11 files changed, 172 insertions(+), 141 deletions(-) delete mode 100644 src/config.h.in rename src/{common.c => global.c} (97%) rename src/{common.h => global.h.in} (75%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 21382a8..8b6810e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,10 +14,18 @@ else() set(DEBUG "ON") endif() +if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") + MESSAGE("++ 64 bit architecture") + set(PKGARCH64 "ON") +else() + MESSAGE("++ 32 bit architecture") + set(PKGARCH64 "OFF") +endif() + find_package(LibMPDClient REQUIRED) find_package(Threads REQUIRED) -configure_file(src/config.h.in ${PROJECT_BINARY_DIR}/config.h) +configure_file(src/global.h.in ${PROJECT_BINARY_DIR}/global.h) include_directories(${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR} ${LIBMPDCLIENT_INCLUDE_DIR}) include(CheckCSourceCompiles) @@ -35,7 +43,7 @@ set(SOURCES src/web_server.c src/list.c src/tiny_queue.c - src/common.c + src/global.c dist/src/mongoose/mongoose.c dist/src/frozen/frozen.c dist/src/inih/ini.c diff --git a/src/config.h.in b/src/config.h.in deleted file mode 100644 index d5c41cd..0000000 --- a/src/config.h.in +++ /dev/null @@ -1,34 +0,0 @@ -/* myMPD - (c) 2018 Juergen Mang - This project's homepage is: https://github.com/jcorporation/ympd - - myMPD ist fork of: - - ympd - (c) 2013-2014 Andrew Karpow - This project's homepage is: http://www.ympd.org - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ - -#ifndef __CONFIG_H__ -#define __CONFIG_H__ - -#define MYMPD_VERSION_MAJOR ${CPACK_PACKAGE_VERSION_MAJOR} -#define MYMPD_VERSION_MINOR ${CPACK_PACKAGE_VERSION_MINOR} -#define MYMPD_VERSION_PATCH ${CPACK_PACKAGE_VERSION_PATCH} -#define MYMPD_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}" -#define SRC_PATH "${ASSETS_PATH}" -#cmakedefine DEBUG -#endif diff --git a/src/common.c b/src/global.c similarity index 97% rename from src/common.c rename to src/global.c index d1e6a09..943402b 100644 --- a/src/common.c +++ b/src/global.c @@ -22,11 +22,10 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include #include #include #include -#include "common.h" +#include "global.h" void sanitize_string(const char *data) { static char ok_chars[] = "abcdefghijklmnopqrstuvwxyz" diff --git a/src/common.h b/src/global.h.in similarity index 75% rename from src/common.h rename to src/global.h.in index 6213976..025f2a0 100644 --- a/src/common.h +++ b/src/global.h.in @@ -22,19 +22,39 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef __COMMON_H__ -#define __COMMON_H__ +#ifndef __GLOBAL_H__ +#define __GLOBAL_H__ #include #include +#include +//architecture +#cmakedefine PKGARCH64 + +//myMPD version from cmake +#define MYMPD_VERSION_MAJOR ${CPACK_PACKAGE_VERSION_MAJOR} +#define MYMPD_VERSION_MINOR ${CPACK_PACKAGE_VERSION_MINOR} +#define MYMPD_VERSION_PATCH ${CPACK_PACKAGE_VERSION_PATCH} +#define MYMPD_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}" + +//Webserver document root +#define DOC_ROOT "${ASSETS_PATH}" + +//Max size of mpd_client response buffer #define MAX_SIZE 2048 * 400 #define MAX_ELEMENTS_PER_PAGE 400 +//central logging definition +#cmakedefine DEBUG #define LOG_INFO() if (config.loglevel >= 1) #define LOG_VERBOSE() if (config.loglevel >= 2) #define LOG_DEBUG() if (config.loglevel == 3) +//signal handler +sig_atomic_t s_signal_received; + +//myMPD configuration typedef struct { long mpdport; const char *mpdhost; diff --git a/src/mpd_client.c b/src/mpd_client.c index eb4b61a..17d95ab 100644 --- a/src/mpd_client.c +++ b/src/mpd_client.c @@ -30,12 +30,10 @@ #include #include #include +#include #include -#include "common.h" #include "mpd_client.h" -#include "web_server.h" -#include "config.h" #include "../dist/src/frozen/frozen.h" const char * mpd_cmd_strs[] = { @@ -820,7 +818,11 @@ void mympd_api(struct work_request_t *request) { #ifdef DEBUG clock_gettime(CLOCK_MONOTONIC_RAW, &end); uint64_t delta_us = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_nsec - start.tv_nsec) / 1000; + #ifdef PKGARCH44 fprintf(stderr, "DEBUG: Time used: %lu\n", delta_us); + #else + fprintf(stderr, "DEBUG: Time used: %llu\n", delta_us); + #endif #endif if (n == 0) { @@ -1835,7 +1837,7 @@ int mympd_get_cover(const char *uri, char *cover, int cover_len) { path += 8; replacechar(path, '/', '_'); replacechar(path, '.', '_'); - snprintf(cover, cover_len, "%s/pics/%s.png", SRC_PATH, path); + snprintf(cover, cover_len, "%s/pics/%s.png", DOC_ROOT, path); if (access(cover, F_OK ) == -1 ) len = snprintf(cover, cover_len, "/assets/coverimage-httpstream.png"); else @@ -1846,7 +1848,7 @@ int mympd_get_cover(const char *uri, char *cover, int cover_len) { else { if (mpd.feat_library) { dirname(path); - snprintf(cover, cover_len, "%s/library/%s/%s", SRC_PATH, path, config.coverimagename); + snprintf(cover, cover_len, "%s/library/%s/%s", DOC_ROOT, path, config.coverimagename); if (access(cover, F_OK ) == -1 ) len = snprintf(cover, cover_len, "/assets/coverimage-notavailable.png"); else diff --git a/src/mpd_client.h b/src/mpd_client.h index 6bab60b..59d13f3 100644 --- a/src/mpd_client.h +++ b/src/mpd_client.h @@ -25,7 +25,7 @@ #ifndef __MPD_CLIENT_H__ #define __MPD_CLIENT_H__ -#include "common.h" +#include "global.h" #include "web_server.h" #include "list.h" #include "tiny_queue.h" diff --git a/src/mympd.c b/src/mympd.c index 05919cb..21fc07f 100644 --- a/src/mympd.c +++ b/src/mympd.c @@ -31,16 +31,13 @@ #include #include #include +#include #include -#include "../dist/src/mongoose/mongoose.h" #include "../dist/src/inih/ini.h" -#include "common.h" +#include "global.h" #include "mpd_client.h" #include "web_server.h" -#include "config.h" - -static sig_atomic_t s_signal_received = 0; static void signal_handler(int sig_num) { signal(sig_num, signal_handler); // Reinstantiate signal handler @@ -307,33 +304,8 @@ void *mpd_client_thread() { return NULL; } -void *web_server_thread(void *arg) { - struct mg_mgr *mgr = (struct mg_mgr *) arg; - while (s_signal_received == 0) { - mg_mgr_poll(mgr, 10); - unsigned web_server_queue_length = tiny_queue_length(web_server_queue); - if (web_server_queue_length > 0) { - struct work_result_t *response = tiny_queue_shift(web_server_queue); - if (response->conn_id == 0) { - //Websocket notify from mpd idle - send_ws_notify(mgr, response); - } - else { - //api response - send_api_response(mgr, response); - } - } - } - mg_mgr_free(mgr); - return NULL; -} - int main(int argc, char **argv) { - struct mg_mgr mgr; - struct mg_connection *nc; - struct mg_connection *nc_http; - struct mg_bind_opts bind_opts; - const char *err; + s_signal_received = 0; char testdirname[400]; mpd_client_queue = tiny_queue_create(); web_server_queue = tiny_queue_create(); @@ -385,7 +357,7 @@ int main(int argc, char **argv) { } else { printf("myMPD %s\n" - "Copyright (C) 2018 Juergen Mang \n" + "Copyright (C) 2018-2019 Juergen Mang \n" "https://github.com/jcorporation/myMPD\n" "Built " __DATE__ " "__TIME__"\n\n" "Usage: %s /path/to/mympd.conf\n", @@ -405,67 +377,45 @@ int main(int argc, char **argv) { setvbuf(stdout, NULL, _IOLBF, 0); setvbuf(stderr, NULL, _IOLBF, 0); - mg_mgr_init(&mgr, NULL); - - if (config.ssl == true) { - nc_http = mg_bind(&mgr, config.webport, ev_handler_redirect); - if (nc_http == NULL) { - printf("Error listening on port %s\n", config.webport); - return EXIT_FAILURE; - } - memset(&bind_opts, 0, sizeof(bind_opts)); - bind_opts.ssl_cert = config.sslcert; - bind_opts.ssl_key = config.sslkey; - bind_opts.error_string = &err; - - nc = mg_bind_opt(&mgr, config.sslport, ev_handler, bind_opts); - if (nc == NULL) { - printf("Error listening on port %s: %s\n", config.sslport, err); - mg_mgr_free(&mgr); - return EXIT_FAILURE; - } - } - else { - nc = mg_bind(&mgr, config.webport, ev_handler); - if (nc == NULL) { - printf("Error listening on port %s\n", config.webport); - mg_mgr_free(&mgr); - return EXIT_FAILURE; - } + //init webserver + if (!web_server_init()) { + return EXIT_FAILURE; } + //drop privileges if (config.user != NULL) { LOG_INFO() printf("Droping privileges to %s\n", config.user); struct passwd *pw; if ((pw = getpwnam(config.user)) == NULL) { printf("getpwnam() failed, unknown user\n"); - mg_mgr_free(&mgr); + web_server_free(); return EXIT_FAILURE; } else if (setgroups(0, NULL) != 0) { printf("setgroups() failed\n"); - mg_mgr_free(&mgr); + web_server_free(); return EXIT_FAILURE; } else if (setgid(pw->pw_gid) != 0) { printf("setgid() failed\n"); - mg_mgr_free(&mgr); + web_server_free(); return EXIT_FAILURE; } else if (setuid(pw->pw_uid) != 0) { printf("setuid() failed\n"); - mg_mgr_free(&mgr); + web_server_free(); return EXIT_FAILURE; } } if (getuid() == 0) { printf("myMPD should not be run with root privileges\n"); - mg_mgr_free(&mgr); + web_server_free(); return EXIT_FAILURE; } - if (!testdir("Document root", SRC_PATH)) + //check needed directories + if (!testdir("Document root", DOC_ROOT)) return EXIT_FAILURE; - snprintf(testdirname, 400, "%s/library", SRC_PATH); + snprintf(testdirname, 400, "%s/library", DOC_ROOT); if (testdir("Link to mpd music_directory", testdirname)) { LOG_INFO() printf("Enabling featLibrary support\n"); mpd.feat_library = true; @@ -487,40 +437,38 @@ int main(int argc, char **argv) { if (!testdir("State dir", testdirname)) return EXIT_FAILURE; + //read myMPD states under config.varlibdir read_statefiles(); + //read system command files list_init(&syscmds); read_syscmds(); list_sort_by_value(&syscmds, true); + //init lists for tag handling list_init(&mpd_tags); list_init(&mympd_tags); + + //read last played songs history file list_init(&last_played); LOG_INFO() printf("Reading last played songs: %d\n", read_last_played()); - if (config.ssl == true) - mg_set_protocol_http_websocket(nc_http); - - mg_set_protocol_http_websocket(nc); - s_http_server_opts.document_root = SRC_PATH; - s_http_server_opts.enable_directory_listing = "no"; - - LOG_INFO() printf("Listening on http port %s\n", config.webport); - if (config.ssl == true) - LOG_INFO() printf("Listening on ssl port %s\n", config.sslport); - + //Create working threads pthread_t mpd_client, web_server; + //mpd connection pthread_create(&mpd_client, NULL, mpd_client_thread, NULL); - pthread_create(&web_server, NULL, web_server_thread, &mgr); + //webserver + pthread_create(&web_server, NULL, web_server_thread, NULL); //Do nothing... //clean up - //todo: destroy tiny queues pthread_join(mpd_client, NULL); pthread_join(web_server, NULL); list_free(&mpd_tags); list_free(&mympd_tags); + tiny_queue_free(web_server_queue); + tiny_queue_free(mpd_client_queue); return EXIT_SUCCESS; } diff --git a/src/tiny_queue.c b/src/tiny_queue.c index 0da15ee..2389bc0 100644 --- a/src/tiny_queue.c +++ b/src/tiny_queue.c @@ -34,6 +34,18 @@ tiny_queue_t* tiny_queue_create() { return queue; } +void tiny_queue_free(tiny_queue_t *queue) { + struct tiny_msg_t *current_head = queue->head, *tmp = NULL; + while (current_head != NULL) { + free(current_head->data); + tmp = current_head; + current_head = current_head->next; + free(tmp); + } + free(queue); +} + + void tiny_queue_push(tiny_queue_t *queue, void *data) { pthread_mutex_lock(&queue->mutex); struct tiny_msg_t* new_node = (struct tiny_msg_t*)malloc(sizeof(struct tiny_msg_t)); diff --git a/src/tiny_queue.h b/src/tiny_queue.h index 0adecb6..7a94124 100644 --- a/src/tiny_queue.h +++ b/src/tiny_queue.h @@ -34,6 +34,7 @@ typedef struct tiny_queue_t { } tiny_queue_t; tiny_queue_t* tiny_queue_create(); +void tiny_queue_free(tiny_queue_t *queue); void tiny_queue_push(struct tiny_queue_t *queue, void *data); void *tiny_queue_shift(struct tiny_queue_t *queue); int tiny_queue_length(struct tiny_queue_t *queue); diff --git a/src/web_server.c b/src/web_server.c index 3116f6b..3e3f457 100644 --- a/src/web_server.c +++ b/src/web_server.c @@ -22,18 +22,99 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "common.h" -#include "config.h" +#include "global.h" #include "web_server.h" #include "mpd_client.h" +#include "../dist/src/mongoose/mongoose.h" +//non-api definitions static unsigned long s_next_id = 1; +struct mg_mgr mgr; +static struct mg_serve_http_opts s_http_server_opts; -int is_websocket(const struct mg_connection *nc) { +static int is_websocket(const struct mg_connection *nc); +static void ev_handler(struct mg_connection *nc, int ev, void *ev_data); +static void ev_handler_redirect(struct mg_connection *nc_http, int ev, void *ev_data); +static void send_ws_notify(struct mg_mgr *mgr, struct work_result_t *response); +static void send_api_response(struct mg_mgr *mgr, struct work_result_t *response); + +//api functions +bool web_server_init() { + struct mg_connection *nc; + struct mg_connection *nc_http; + struct mg_bind_opts bind_opts; + const char *err; + + mg_mgr_init(&mgr, NULL); + + if (config.ssl == true) { + nc_http = mg_bind(&mgr, config.webport, ev_handler_redirect); + if (nc_http == NULL) { + printf("Error listening on port %s\n", config.webport); + mg_mgr_free(&mgr); + return false; + } + mg_set_protocol_http_websocket(nc_http); + LOG_INFO() printf("Listening on http port %s (redirect only).\n", config.webport); + + memset(&bind_opts, 0, sizeof(bind_opts)); + bind_opts.ssl_cert = config.sslcert; + bind_opts.ssl_key = config.sslkey; + bind_opts.error_string = &err; + nc = mg_bind_opt(&mgr, config.sslport, ev_handler, bind_opts); + if (nc == NULL) { + printf("Error listening on port %s: %s\n", config.sslport, err); + mg_mgr_free(&mgr); + return false; + } + LOG_INFO() printf("Listening on ssl port %s\n", config.sslport); + } + else { + nc = mg_bind(&mgr, config.webport, ev_handler); + if (nc == NULL) { + printf("Error listening on port %s\n", config.webport); + mg_mgr_free(&mgr); + return false; + } + LOG_INFO() printf("Listening on http port %s\n", config.webport); + } + + mg_set_protocol_http_websocket(nc); + s_http_server_opts.document_root = DOC_ROOT; + s_http_server_opts.enable_directory_listing = "no"; + return true; +} + +void web_server_free() { + mg_mgr_free(&mgr); +} + +void *web_server_thread() { + while (s_signal_received == 0) { + mg_mgr_poll(&mgr, 10); + unsigned web_server_queue_length = tiny_queue_length(web_server_queue); + if (web_server_queue_length > 0) { + struct work_result_t *response = tiny_queue_shift(web_server_queue); + if (response->conn_id == 0) { + //Websocket notify from mpd idle + send_ws_notify(&mgr, response); + } + else { + //api response + send_api_response(&mgr, response); + } + } + } + mg_mgr_free(&mgr); + return NULL; +} + +//non-api functions +static int is_websocket(const struct mg_connection *nc) { return nc->flags & MG_F_IS_WEBSOCKET; } -void send_ws_notify(struct mg_mgr *mgr, struct work_result_t *response) { +static void send_ws_notify(struct mg_mgr *mgr, struct work_result_t *response) { struct mg_connection *c; LOG_DEBUG() fprintf(stderr, "DEBUG: Got ws notify, broadcasting\n"); @@ -45,7 +126,7 @@ void send_ws_notify(struct mg_mgr *mgr, struct work_result_t *response) { free(response); } -void send_api_response(struct mg_mgr *mgr, struct work_result_t *response) { +static void send_api_response(struct mg_mgr *mgr, struct work_result_t *response) { struct mg_connection *c; LOG_DEBUG() fprintf(stderr, "DEBUG: Got API response for connection %lu.\n", response->conn_id); @@ -61,7 +142,7 @@ void send_api_response(struct mg_mgr *mgr, struct work_result_t *response) { free(response); } -void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { +static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { (void) nc; (void) ev_data; @@ -94,8 +175,6 @@ void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { struct work_request_t *request = (struct work_request_t*)malloc(sizeof(struct work_request_t)); request->conn_id = (unsigned long)nc->user_data; request->length = copy_string(request->data, hm->body.p, 1000, hm->body.len); - //sizeof(request->data) - 1 < hm->body.len ? sizeof(request->data) - 1 : hm->body.len; - //memcpy(request->data, hm->body.p, request->length); tiny_queue_push(mpd_client_queue, request); } else { @@ -119,7 +198,7 @@ void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { } } -void ev_handler_redirect(struct mg_connection *nc_http, int ev, void *ev_data) { +static void ev_handler_redirect(struct mg_connection *nc_http, int ev, void *ev_data) { char *host; char host_header[1024]; switch(ev) { diff --git a/src/web_server.h b/src/web_server.h index 740ae74..6e859ba 100644 --- a/src/web_server.h +++ b/src/web_server.h @@ -25,7 +25,6 @@ #ifndef __WEB_SERVER_H__ #define __WEB_SERVER_H__ -#include "../dist/src/mongoose/mongoose.h" #include "tiny_queue.h" tiny_queue_t *web_server_queue; @@ -42,11 +41,8 @@ struct work_result_t { int length; } work_result_t; -struct mg_serve_http_opts s_http_server_opts; +void *web_server_thread(); +bool web_server_init(); +void web_server_free(); -int is_websocket(const struct mg_connection *nc); -void ev_handler(struct mg_connection *nc, int ev, void *ev_data); -void ev_handler_redirect(struct mg_connection *nc_http, int ev, void *ev_data); -void send_ws_notify(struct mg_mgr *mgr, struct work_result_t *response); -void send_api_response(struct mg_mgr *mgr, struct work_result_t *response); #endif