flac: Saner EOF handling
[cmus.git] / server.c
blob70fbafb5a98a6e94a54635aa08b8467b858ed26b
1 /*
2 * Copyright 2004-2005 Timo Hirvonen
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17 * 02111-1307, USA.
20 #include "server.h"
21 #include "prog.h"
22 #include "command_mode.h"
23 #include "search_mode.h"
24 #include "options.h"
25 #include "output.h"
26 #include "utils.h"
27 #include "xmalloc.h"
28 #include "player.h"
29 #include "file.h"
30 #include "compiler.h"
31 #include "debug.h"
32 #include "gbuf.h"
34 #include <unistd.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <sys/un.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
40 #include <netdb.h>
41 #include <errno.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <stdlib.h>
45 #include <unistd.h>
46 #include <fcntl.h>
47 #include <ctype.h>
49 int server_socket;
50 LIST_HEAD(client_head);
52 static union {
53 struct sockaddr sa;
54 struct sockaddr_un un;
55 struct sockaddr_in in;
56 } addr;
58 #define MAX_CLIENTS 10
60 static const char *escape(const char *str)
62 static char *buf = NULL;
63 static size_t alloc = 0;
64 size_t len = strlen(str);
65 size_t need = len * 2 + 1;
66 int s, d;
68 if (need > alloc) {
69 alloc = (need + 16) & ~(16 - 1);
70 buf = xrealloc(buf, alloc);
73 d = 0;
74 for (s = 0; str[s]; s++) {
75 if (str[s] == '\\') {
76 buf[d++] = '\\';
77 buf[d++] = '\\';
78 continue;
80 if (str[s] == '\n') {
81 buf[d++] = '\\';
82 buf[d++] = 'n';
83 continue;
85 buf[d++] = str[s];
87 buf[d] = 0;
88 return buf;
91 static int cmd_status(struct client *client)
93 const char *status[] = { "stopped", "playing", "paused" };
94 const char *export_options[] = {
95 "aaa_mode",
96 "continue",
97 "play_library",
98 "play_sorted",
99 "replaygain",
100 "replaygain_limit",
101 "replaygain_preamp",
102 "repeat",
103 "repeat_current",
104 "shuffle",
105 "softvol",
106 NULL
108 const struct track_info *ti;
109 struct cmus_opt *opt;
110 char optbuf[OPTION_MAX_SIZE];
111 GBUF(buf);
112 int vol_left, vol_right;
113 int i, ret;
115 player_info_lock();
116 gbuf_addf(&buf, "status %s\n", status[player_info.status]);
117 ti = player_info.ti;
118 if (ti) {
119 gbuf_addf(&buf, "file %s\n", escape(ti->filename));
120 gbuf_addf(&buf, "duration %d\n", ti->duration);
121 gbuf_addf(&buf, "position %d\n", player_info.pos);
122 for (i = 0; ti->comments[i].key; i++)
123 gbuf_addf(&buf, "tag %s %s\n",
124 ti->comments[i].key,
125 escape(ti->comments[i].val));
128 /* output options */
129 for (i = 0; export_options[i]; i++) {
130 opt = option_find(export_options[i]);
131 if (opt) {
132 opt->get(opt->id, optbuf);
133 gbuf_addf(&buf, "set %s %s\n", opt->name, optbuf);
137 /* get volume (copied from ui_curses.c) */
138 if (soft_vol) {
139 vol_left = soft_vol_l;
140 vol_right = soft_vol_r;
141 } else if (!volume_max) {
142 vol_left = vol_right = -1;
143 } else {
144 vol_left = scale_to_percentage(volume_l, volume_max);
145 vol_right = scale_to_percentage(volume_r, volume_max);
148 /* output volume */
149 gbuf_addf(&buf, "set vol_left %d\n", vol_left);
150 gbuf_addf(&buf, "set vol_right %d\n", vol_right);
152 gbuf_add_str(&buf, "\n");
153 player_info_unlock();
155 ret = write_all(client->fd, buf.buffer, buf.len);
156 gbuf_free(&buf);
157 return ret;
160 static void read_commands(struct client *client)
162 char buf[1024];
163 int pos = 0;
164 int authenticated = addr.sa.sa_family == AF_UNIX;
166 while (1) {
167 int rc, s, i;
169 rc = read(client->fd, buf + pos, sizeof(buf) - pos);
170 if (rc == -1) {
171 if (errno == EINTR)
172 continue;
173 if (errno == EAGAIN)
174 return;
175 goto close;
177 if (rc == 0)
178 goto close;
179 pos += rc;
181 s = 0;
182 for (i = 0; i < pos; i++) {
183 const char *line;
184 char *cmd, *arg;
185 int ret;
187 if (buf[i] != '\n')
188 continue;
190 buf[i] = 0;
191 line = buf + s;
192 s = i + 1;
194 if (!authenticated) {
195 if (!server_password) {
196 d_print("password is unset, tcp/ip disabled\n");
197 goto close;
199 authenticated = !strcmp(line, server_password);
200 if (!authenticated) {
201 d_print("authentication failed\n");
202 goto close;
204 continue;
207 while (isspace(*line))
208 line++;
210 if (*line == '/') {
211 int restricted = 0;
212 line++;
213 search_direction = SEARCH_FORWARD;
214 if (*line == '/') {
215 line++;
216 restricted = 1;
218 search_text(line, restricted, 1);
219 ret = write_all(client->fd, "\n", 1);
220 } else if (*line == '?') {
221 int restricted = 0;
222 line++;
223 search_direction = SEARCH_BACKWARD;
224 if (*line == '?') {
225 line++;
226 restricted = 1;
228 search_text(line, restricted, 1);
229 ret = write_all(client->fd, "\n", 1);
230 } else if (parse_command(line, &cmd, &arg)) {
231 if (!strcmp(cmd, "status")) {
232 ret = cmd_status(client);
233 } else {
234 run_parsed_command(cmd, arg);
235 ret = write_all(client->fd, "\n", 1);
237 free(cmd);
238 free(arg);
239 } else {
240 // don't hang cmus-remote
241 ret = write_all(client->fd, "\n", 1);
243 if (ret < 0) {
244 d_print("write: %s\n", strerror(errno));
245 goto close;
248 memmove(buf, buf + s, pos - s);
249 pos -= s;
251 return;
252 close:
253 close(client->fd);
254 list_del(&client->node);
255 free(client);
258 void server_accept(void)
260 struct client *client;
261 struct sockaddr saddr;
262 socklen_t saddr_size = sizeof(saddr);
263 int fd;
265 fd = accept(server_socket, &saddr, &saddr_size);
266 if (fd == -1)
267 return;
269 fcntl(fd, F_SETFL, O_NONBLOCK);
271 client = xnew(struct client, 1);
272 client->fd = fd;
273 list_add_tail(&client->node, &client_head);
276 void server_serve(struct client *client)
278 /* unix connection is secure, other insecure */
279 run_only_safe_commands = addr.sa.sa_family != AF_UNIX;
280 read_commands(client);
281 run_only_safe_commands = 0;
284 static void gethostbyname_failed(void)
286 const char *error = "Unknown error.";
288 switch (h_errno) {
289 case HOST_NOT_FOUND:
290 case NO_ADDRESS:
291 error = "Host not found.";
292 break;
293 case NO_RECOVERY:
294 error = "A non-recoverable name server error.";
295 break;
296 case TRY_AGAIN:
297 error = "A temporary error occurred on an authoritative name server.";
298 break;
300 die("gethostbyname: %s\n", error);
303 void server_init(char *address)
305 int port = DEFAULT_PORT;
306 int addrlen;
308 if (strchr(address, '/')) {
309 addr.sa.sa_family = AF_UNIX;
310 strncpy(addr.un.sun_path, address, sizeof(addr.un.sun_path) - 1);
312 addrlen = sizeof(struct sockaddr_un);
313 } else {
314 char *s = strchr(address, ':');
315 struct hostent *hent;
317 if (s) {
318 *s++ = 0;
319 port = atoi(s);
321 hent = gethostbyname(address);
322 if (!hent)
323 gethostbyname_failed();
325 addr.sa.sa_family = hent->h_addrtype;
326 switch (addr.sa.sa_family) {
327 case AF_INET:
328 memcpy(&addr.in.sin_addr, hent->h_addr_list[0], hent->h_length);
329 addr.in.sin_port = htons(port);
331 addrlen = sizeof(addr.in);
332 break;
333 default:
334 die("unsupported address type\n");
338 server_socket = socket(addr.sa.sa_family, SOCK_STREAM, 0);
339 if (server_socket == -1)
340 die_errno("socket");
342 if (bind(server_socket, &addr.sa, addrlen) == -1) {
343 int sock;
345 if (errno != EADDRINUSE)
346 die_errno("bind");
348 /* address already in use */
349 if (addr.sa.sa_family != AF_UNIX)
350 die("cmus is already listening on %s:%d\n", address, port);
352 /* try to connect to server */
353 sock = socket(AF_UNIX, SOCK_STREAM, 0);
354 if (sock == -1)
355 die_errno("socket");
357 if (connect(sock, &addr.sa, addrlen) == -1) {
358 if (errno != ENOENT && errno != ECONNREFUSED)
359 die_errno("connect");
361 /* server not running => dead socket */
363 /* try to remove dead socket */
364 if (unlink(addr.un.sun_path) == -1 && errno != ENOENT)
365 die_errno("unlink");
366 if (bind(server_socket, &addr.sa, addrlen) == -1)
367 die_errno("bind");
368 } else {
369 /* server already running */
370 die("cmus is already listening on socket %s\n", address);
372 close(sock);
375 if (listen(server_socket, MAX_CLIENTS) == -1)
376 die_errno("listen");
379 void server_exit(void)
381 close(server_socket);
382 if (addr.sa.sa_family == AF_UNIX)
383 unlink(addr.un.sun_path);