X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/1c95530676f55d612383883ff383e24ecc7dc17d..784744a808c4620e2c1eec59fc3baf147fe8710e:/server/state.c diff --git a/server/state.c b/server/state.c index cfcca1c..bd74b14 100644 --- a/server/state.c +++ b/server/state.c @@ -20,15 +20,31 @@ */ #include "disorder-server.h" +/** @brief Current AF_UNIX socket path */ static const char *current_unix; + +/** @brief Current AF_UNIX socket */ static int current_unix_fd; -static struct addrinfo *current_listen_addrinfo; -static int current_listen_fd; +/** @brief TCP listener definition */ +struct listener { + /** @brief Next listener */ + struct listener *next; + + /** @brief Local socket address */ + struct sockaddr *sa; + + /** @brief File descriptor */ + int fd; +}; + +/** @brief Current listeners */ +static struct listener *listeners; /** @brief Current audio API */ const struct uaudio *api; +/** @brief Quit DisOrder */ void quit(ev_source *ev) { info("shutting down..."); quitting(ev); @@ -38,18 +54,19 @@ void quit(ev_source *ev) { exit(0); } -static void reset_socket(ev_source *ev) { +/** @brief Create a copy of an @c addrinfo structure */ +static struct sockaddr *copy_sockaddr(const struct addrinfo *addr) { + struct sockaddr *sa = xmalloc_noptr(addr->ai_addrlen); + memcpy(sa, addr->ai_addr, addr->ai_addrlen); + return sa; +} + +/** @brief Create and destroy sockets to set current configuration */ +void reset_sockets(ev_source *ev) { const char *new_unix; - struct addrinfo *res; + struct addrinfo *res, *r; + struct listener *l, **ll; struct sockaddr_un sun; - char *name; - - static const struct addrinfo pref = { - .ai_flags = AI_PASSIVE, - .ai_family = PF_INET, - .ai_socktype = SOCK_STREAM, - .ai_protocol = IPPROTO_TCP, - }; /* unix first */ new_unix = config_get_file("socket"); @@ -80,29 +97,45 @@ static void reset_socket(ev_source *ev) { } /* get the new listen config */ - if(config->listen.n) - res = get_address(&config->listen, &pref, &name); + if(config->listen.af != -1) + res = netaddress_resolve(&config->listen, 1, IPPROTO_TCP); else res = 0; - if((res && !current_listen_addrinfo) - || (current_listen_addrinfo - && (!res - || addrinfocmp(res, current_listen_addrinfo)))) { - /* something has to change */ - if(current_listen_addrinfo) { - /* delete the old listener */ - server_stop(ev, current_listen_fd); - freeaddrinfo(current_listen_addrinfo); - current_listen_addrinfo = 0; + /* Close any current listeners that aren't required any more */ + ll = &listeners; + while((l = *ll)) { + for(r = res; r; r = r->ai_next) + if(!sockaddrcmp(r->ai_addr, l->sa)) + break; + if(!r) { + /* Didn't find a match, remove this one */ + server_stop(ev, l->fd); + *ll = l->next; + } else { + /* This address is still wanted */ + ll = &l->next; } - if(res) { - /* start the new listener */ - if((current_listen_fd = server_start(ev, res->ai_family, res->ai_addrlen, - res->ai_addr, name)) >= 0) { - current_listen_addrinfo = res; - res = 0; + } + + /* Open any new listeners that are required */ + for(r = res; r; r = r->ai_next) { + for(l = listeners; l; l = l->next) + if(!sockaddrcmp(r->ai_addr, l->sa)) + break; + if(!l) { + /* Didn't find a match, need a new listener */ + int fd = server_start(ev, r->ai_family, r->ai_addrlen, r->ai_addr, + format_sockaddr(r->ai_addr)); + if(fd >= 0) { + l = xmalloc(sizeof *l); + l->next = listeners; + l->sa = copy_sockaddr(r); + l->fd = fd; + listeners = l; } + /* We ignore any failures (though server_start() will have + * logged them). */ } } /* if res is still set it needs freeing */ @@ -110,43 +143,46 @@ static void reset_socket(ev_source *ev) { freeaddrinfo(res); } -int reconfigure(ev_source *ev, int reload) { +/** @brief Reconfigure the server + * @param flags Flags + * @return As config_read(); 0 on success, -1 if could not (re-)read config + */ +int reconfigure(ev_source *ev, unsigned flags) { int need_another_rescan = 0; int ret = 0; - D(("reconfigure(%d)", reload)); + D(("reconfigure(%x)", flags)); + /* Deconfigure the old audio API if there is one */ if(api) { if(api->close_mixer) api->close_mixer(); api = NULL; } - if(reload) { + if(flags & RECONFIGURE_RELOADING) { + /* If there's a rescan in progress, cancel it but remember to start a fresh + * one after the reload. */ need_another_rescan = trackdb_rescan_cancel(); - trackdb_close(); - if(config_read(1)) + /* (Re-)read the configuration */ + if(config_read(1/*server*/, config)) ret = -1; else { /* Tell the speaker it needs to reload its config too. */ speaker_reload(); info("%s: installed new configuration", configfile); } - trackdb_open(TRACKDB_NO_UPGRADE); - } else - /* We only allow for upgrade at startup */ - trackdb_open(TRACKDB_CAN_UPGRADE); + } + /* New audio API */ api = uaudio_find(config->api); if(api->configure) api->configure(); if(api->open_mixer) api->open_mixer(); + /* If we interrupted a rescan of all the tracks, start a new one */ if(need_another_rescan) trackdb_rescan(ev, 1/*check*/, 0, 0); - /* Arrange timeouts for schedule actions */ - schedule_init(ev); - if(!ret) { - queue_read(); - recent_read(); - reset_socket(ev); + if(!ret && !(flags & RECONFIGURE_FIRST)) { + /* Open/close sockets */ + reset_sockets(ev); } return ret; } @@ -155,5 +191,7 @@ int reconfigure(ev_source *ev, int reload) { Local Variables: c-basic-offset:2 comment-column:40 +fill-column:79 +indent-tabs-mode:nil End: */