chiark / gitweb /
Override lintian warning about start-stop-daemon
[disorder] / server / state.c
CommitLineData
460b9539 1/*
2 * This file is part of DisOrder.
b50cfb8a 3 * Copyright (C) 2004, 2005, 2007-2009 Richard Kettlewell
460b9539 4 *
e7eb3a27 5 * This program is free software: you can redistribute it and/or modify
460b9539 6 * it under the terms of the GNU General Public License as published by
e7eb3a27 7 * the Free Software Foundation, either version 3 of the License, or
460b9539 8 * (at your option) any later version.
9 *
e7eb3a27
RK
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
460b9539 15 * You should have received a copy of the GNU General Public License
e7eb3a27 16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
460b9539 17 */
132a5a4a
RK
18/** @file server/state.c
19 * @brief Global server state
20 */
05b75f8d 21#include "disorder-server.h"
460b9539 22
23static const char *current_unix;
24static int current_unix_fd;
25
80dc2c5f
RK
26/** @brief TCP listener definition */
27struct listener {
28 struct listener *next;
29 struct sockaddr *sa;
30 int fd;
31};
32
33/** @brief Current listeners */
34static struct listener *listeners;
460b9539 35
b50cfb8a
RK
36/** @brief Current audio API */
37const struct uaudio *api;
38
460b9539 39void quit(ev_source *ev) {
4363757e 40 info("shutting down...");
460b9539 41 quitting(ev);
42 trackdb_close();
43 trackdb_deinit();
4363757e 44 info("exiting");
445a0f66 45 exit(0);
460b9539 46}
47
80dc2c5f
RK
48static struct sockaddr *copy_sockaddr(const struct addrinfo *addr) {
49 struct sockaddr *sa = xmalloc_noptr(addr->ai_addrlen);
50 memcpy(sa, addr->ai_addr, addr->ai_addrlen);
51 return sa;
52}
53
460b9539 54static void reset_socket(ev_source *ev) {
55 const char *new_unix;
80dc2c5f
RK
56 struct addrinfo *res, *r;
57 struct listener *l, **ll;
460b9539 58 struct sockaddr_un sun;
460b9539 59
60 /* unix first */
61 new_unix = config_get_file("socket");
62 if(!current_unix || strcmp(current_unix, new_unix)) {
63 /* either there was no socket, or there was but a different path */
64 if(current_unix) {
65 /* stop the old one and remove it from the filesystem */
66 server_stop(ev, current_unix_fd);
67 if(unlink(current_unix) < 0)
68 fatal(errno, "unlink %s", current_unix);
69 }
70 /* start the new one */
71 if(strlen(new_unix) >= sizeof sun.sun_path)
72 fatal(0, "socket path %s is too long", new_unix);
73 memset(&sun, 0, sizeof sun);
74 sun.sun_family = AF_UNIX;
75 strcpy(sun.sun_path, new_unix);
76 if(unlink(new_unix) < 0 && errno != ENOENT)
77 fatal(errno, "unlink %s", new_unix);
78 if((current_unix_fd = server_start(ev, PF_UNIX, sizeof sun,
79 (const struct sockaddr *)&sun,
80 new_unix)) >= 0) {
81 current_unix = new_unix;
82 if(chmod(new_unix, 0777) < 0)
83 fatal(errno, "error calling chmod %s", new_unix);
84 } else
85 current_unix = 0;
86 }
87
88 /* get the new listen config */
80dc2c5f
RK
89 if(config->listen.af != -1)
90 res = netaddress_resolve(&config->listen, 1, IPPROTO_TCP);
460b9539 91 else
92 res = 0;
93
80dc2c5f
RK
94 /* Close any current listeners that aren't required any more */
95 ll = &listeners;
96 while((l = *ll)) {
97 for(r = res; r; r = r->ai_next)
98 if(!sockaddrcmp(r->ai_addr, l->sa))
99 break;
100 if(!r) {
101 /* Didn't find a match, remove this one */
102 server_stop(ev, l->fd);
103 *ll = l->next;
104 } else {
105 /* This address is still wanted */
106 ll = &l->next;
460b9539 107 }
80dc2c5f
RK
108 }
109
110 /* Open any new listeners that are required */
111 for(r = res; r; r = r->ai_next) {
112 for(l = listeners; l; l = l->next)
113 if(!sockaddrcmp(r->ai_addr, l->sa))
114 break;
115 if(!l) {
116 /* Didn't find a match, need a new listener */
117 int fd = server_start(ev, r->ai_family, r->ai_addrlen, r->ai_addr,
118 format_sockaddr(r->ai_addr));
119 if(fd >= 0) {
120 l = xmalloc(sizeof *l);
121 l->next = listeners;
122 l->sa = copy_sockaddr(r);
123 l->fd = fd;
124 listeners = l;
460b9539 125 }
126 }
127 }
128 /* if res is still set it needs freeing */
129 if(res)
130 freeaddrinfo(res);
131}
132
133int reconfigure(ev_source *ev, int reload) {
134 int need_another_rescan = 0;
135 int ret = 0;
136
137 D(("reconfigure(%d)", reload));
b50cfb8a
RK
138 if(api) {
139 if(api->close_mixer)
140 api->close_mixer();
141 api = NULL;
142 }
460b9539 143 if(reload) {
144 need_another_rescan = trackdb_rescan_cancel();
145 trackdb_close();
c00fce3a 146 if(config_read(1))
460b9539 147 ret = -1;
148 else {
149 /* Tell the speaker it needs to reload its config too. */
150 speaker_reload();
151 info("%s: installed new configuration", configfile);
152 }
d25c4615
RK
153 trackdb_open(TRACKDB_NO_UPGRADE);
154 } else
155 /* We only allow for upgrade at startup */
156 trackdb_open(TRACKDB_CAN_UPGRADE);
b50cfb8a 157 api = uaudio_find(config->api);
ba70caca
RK
158 if(api->configure)
159 api->configure();
b50cfb8a
RK
160 if(api->open_mixer)
161 api->open_mixer();
460b9539 162 if(need_another_rescan)
dd9af5cb 163 trackdb_rescan(ev, 1/*check*/, 0, 0);
fdca70ee
RK
164 /* Arrange timeouts for schedule actions */
165 schedule_init(ev);
460b9539 166 if(!ret) {
167 queue_read();
168 recent_read();
169 reset_socket(ev);
170 }
171 return ret;
172}
173
174/*
175Local Variables:
176c-basic-offset:2
177comment-column:40
178End:
179*/