Bug Summary

File:server.c
Location:line 491, column 3
Description:Null pointer passed as an argument to a 'nonnull' parameter

Annotated Source Code

1/*
2 * MOC - music on console
3 * Copyright (C) 2003 - 2005 Damian Pietras <daper@daper.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 */
11
12#ifdef HAVE_CONFIG_H1
13# include "config.h"
14#endif
15
16#include <stdio.h>
17#include <sys/types.h>
18#include <sys/socket.h>
19#ifdef HAVE_SYS_SELECT_H1
20# include <sys/select.h>
21#endif
22#include <sys/time.h>
23#include <sys/un.h>
24#include <time.h>
25#include <sys/stat.h>
26#include <fcntl.h>
27#include <stdlib.h>
28#include <unistd.h>
29#include <string.h>
30#include <strings.h>
31#include <signal.h>
32#include <errno(*__errno_location ()).h>
33#include <stdarg.h>
34#include <pthread.h>
35#include <assert.h>
36
37#define DEBUG
38
39#include "log.h"
40#include "protocol.h"
41#include "common.h"
42#include "audio.h"
43#include "oss.h"
44#include "options.h"
45#include "server.h"
46#include "playlist.h"
47#include "tags_cache.h"
48#include "files.h"
49#include "softmixer.h"
50#include "equalizer.h"
51
52#define SERVER_LOG"mocp_server_log" "mocp_server_log"
53#define PID_FILE"pid" "pid"
54
55struct client
56{
57 int socket; /* -1 if inactive */
58 int wants_events; /* requested events? */
59 struct event_queue events;
60 pthread_mutex_t events_mutex;
61 int requests_plist; /* is the client waiting for the playlist? */
62 int can_send_plist; /* can this client send a playlist? */
63 int lock; /* is this client locking us? */
64 int serial; /* used for generating unique serial numbers */
65};
66
67static struct client clients[CLIENTS_MAX10];
68
69/* Thread ID of the server thread. */
70static pthread_t server_tid;
71
72/* Pipe used to wake up the server from select() from another thread. */
73static int wake_up_pipe[2];
74
75/* Set to 1 when a signal arrived causing the program to exit. */
76static volatile int server_quit = 0;
77
78static char err_msg[265] = "";
79
80/* Information about currently played file */
81static struct {
82 int avg_bitrate;
83 int bitrate;
84 int rate;
85 int channels;
86} sound_info = {
87 -1,
88 -1,
89 -1,
90 -1
91};
92
93static struct tags_cache tags_cache;
94
95extern char **environ;
96
97static void write_pid_file ()
98{
99 char *fname = create_file_name (PID_FILE"pid");
100 FILE *file;
101
102 if ((file = fopen(fname, "w")) == NULL((void*)0))
103 fatal ("Can't write pid file.");
104 fprintf (file, "%d\n", getpid());
105 fclose (file);
106}
107
108/* Check if there is a pid file and if it is valid, return the pid, else 0 */
109static int check_pid_file ()
110{
111 FILE *file;
112 pid_t pid;
113 char *fname = create_file_name (PID_FILE"pid");
114
115 /* Read the pid file */
116 if ((file = fopen(fname, "r")) == NULL((void*)0))
117 return 0;
118 if (fscanf(file, "%d", &pid) != 1) {
119 fclose (file);
120 return 0;
121 }
122 fclose (file);
123
124 return pid;
125}
126
127static void sig_exit (int sig)
128{
129 logit ("Got signal %d", sig)internal_logit ("server.c", 129, __FUNCTION__, "Got signal %d"
, sig)
;
130 server_quit = 1;
131
132 if (server_tid != pthread_self())
133 pthread_kill (server_tid, sig);
134}
135
136static void clients_init ()
137{
138 int i;
139
140 for (i = 0; i < CLIENTS_MAX10; i++) {
141 clients[i].socket = -1;
142 pthread_mutex_init (&clients[i].events_mutex, NULL((void*)0));
143 }
144}
145
146static void clients_cleanup ()
147{
148 int i;
149
150 for (i = 0; i < CLIENTS_MAX10; i++) {
151 clients[i].socket = -1;
152 if (pthread_mutex_destroy(&clients[i].events_mutex))
153 logit ("Can't destroy events mutex: %s",internal_logit ("server.c", 154, __FUNCTION__, "Can't destroy events mutex: %s"
, strerror((*__errno_location ())))
154 strerror(errno))internal_logit ("server.c", 154, __FUNCTION__, "Can't destroy events mutex: %s"
, strerror((*__errno_location ())))
;
155
156 }
157}
158
159/* Add a client to the list, return 1 if ok, 0 on error (max clients exceeded) */
160static int add_client (int sock)
161{
162 int i;
163
164 for (i = 0; i < CLIENTS_MAX10; i++)
165 if (clients[i].socket == -1) {
166 clients[i].wants_events = 0;
167 LOCK (clients[i].events_mutex)pthread_mutex_lock (&clients[i].events_mutex);
168 event_queue_free (&clients[i].events);
169 event_queue_init (&clients[i].events);
170 UNLOCK (clients[i].events_mutex)pthread_mutex_unlock (&clients[i].events_mutex);
171 clients[i].socket = sock;
172 clients[i].requests_plist = 0;
173 clients[i].can_send_plist = 0;
174 clients[i].lock = 0;
175 tags_cache_clear_queue (&tags_cache, i);
176 return 1;
177 }
178
179 return 0;
180}
181
182/* Return index of a client that has a lock acquired. Return -1 if there is no
183 * lock. */
184static int locking_client ()
185{
186 int i;
187
188 for (i = 0; i < CLIENTS_MAX10; i++)
189 if (clients[i].socket != -1 && clients[i].lock)
190 return i;
191 return -1;
192}
193
194/* Acquire a lock for this client. Return 0 on error. */
195static int client_lock (struct client *cli)
196{
197 if (cli->lock) {
198 logit ("Client wants deadlock.")internal_logit ("server.c", 198, __FUNCTION__, "Client wants deadlock."
)
;
199 return 0;
200 }
201
202 assert (locking_client() == -1)((locking_client() == -1) ? (void) (0) : __assert_fail ("locking_client() == -1"
, "server.c", 202, __PRETTY_FUNCTION__))
;
203
204 cli->lock = 1;
205 logit ("Lock acquired for client with fd %d", cli->socket)internal_logit ("server.c", 205, __FUNCTION__, "Lock acquired for client with fd %d"
, cli->socket)
;
206 return 1;
207}
208
209/* Return != 0 if this client holds a lock. */
210static int is_locking (const struct client *cli)
211{
212 return cli->lock;
213}
214
215/* Release the lock hold by the client. Return 0 on error. */
216static int client_unlock (struct client *cli)
217{
218 if (!cli->lock) {
219 logit ("Client wants to unlock when there is no lock.")internal_logit ("server.c", 219, __FUNCTION__, "Client wants to unlock when there is no lock."
)
;
220 return 0;
221 }
222
223 cli->lock = 0;
224 logit ("Lock released by client with fd %d", cli->socket)internal_logit ("server.c", 224, __FUNCTION__, "Lock released by client with fd %d"
, cli->socket)
;
225 return 1;
226}
227
228/* Return the client index from tht clients table. */
229static int client_index (const struct client *cli)
230{
231 int i;
232
233 for (i = 0; i < CLIENTS_MAX10; i++)
234 if (clients[i].socket == cli->socket)
235 return i;
236 return -1;
237}
238
239static void del_client (struct client *cli)
240{
241 cli->socket = -1;
242 LOCK (cli->events_mutex)pthread_mutex_lock (&cli->events_mutex);
243 event_queue_free (&cli->events);
244 tags_cache_clear_queue (&tags_cache, client_index(cli));
245 UNLOCK (cli->events_mutex)pthread_mutex_unlock (&cli->events_mutex);
246}
247
248/* Check if the process with given PID exists. Return != 0 if so. */
249static int valid_pid (const int pid)
250{
251 return kill(pid, 0) == 0 ? 1 : 0;
252}
253
254static void wake_up_server ()
255{
256 int w = 1;
257
258 debug ("Waking up the server")internal_logit ("server.c", 258, __FUNCTION__, "Waking up the server"
)
;
259
260 if (write(wake_up_pipe[1], &w, sizeof(w)) < 0)
261 logit ("Can't wake up the server: (write() failed) %s",internal_logit ("server.c", 262, __FUNCTION__, "Can't wake up the server: (write() failed) %s"
, strerror((*__errno_location ())))
262 strerror(errno))internal_logit ("server.c", 262, __FUNCTION__, "Can't wake up the server: (write() failed) %s"
, strerror((*__errno_location ())))
;
263}
264
265/* Thread-safe signal() version */
266static void thread_signal (const int signum, void (*func)(int))
267{
268 struct sigaction act;
269
270 act.sa_handler__sigaction_handler.sa_handler = func;
271 act.sa_flags = 0;
272 sigemptyset (&act.sa_mask);
273
274 if (sigaction(signum, &act, 0) == -1)
275 fatal ("sigaction() failed: %s", strerror(errno(*__errno_location ())));
276}
277
278static void redirect_output (int out_fd)
279{
280 int fd;
281
282 fd = open ("/dev/null", O_WRONLY01);
283 if (fd == -1)
284 fatal ("Can't open /dev/null: %s", strerror(errno(*__errno_location ())));
285
286 if (dup2(fd, out_fd) == -1)
287 fatal ("dup2() failed: %s", strerror(errno(*__errno_location ())));
288}
289
290/* Initialize the server - return fd of the listening socket or -1 on error */
291int server_init (int debuglogit, int foreground)
292{
293 struct sockaddr_un sock_name;
294 int server_sock;
295 int pid;
296
297 pid = check_pid_file ();
298 if (pid && valid_pid(pid)) {
299 fprintf (stderrstderr, "\nIt seems that the server is already running"
300 " with pid %d.\n", pid);
301 fprintf (stderrstderr, "If it is not true, remove the pid file (%s)"
302 " and try again.\n",
303 create_file_name(PID_FILE"pid"));
304 fatal ("Exiting.");
305 }
306
307 if (foreground)
308 log_init_stream (stdoutstdout);
309 else if (debuglogit) {
310 FILE *logf;
311 if (!(logf = fopen(SERVER_LOG"mocp_server_log", "a")))
312 fatal ("Can't open log file.");
313 log_init_stream (logf);
314 }
315
316 if (pipe(wake_up_pipe) < 0)
317 fatal ("pipe() failed: %s", strerror(errno(*__errno_location ())));
318
319 unlink (socket_name());
320
321 /* Create a socket */
322 if ((server_sock = socket (PF_LOCAL1, SOCK_STREAMSOCK_STREAM, 0)) == -1)
323 fatal ("Can't create socket: %s.", strerror(errno(*__errno_location ())));
324 sock_name.sun_family = AF_LOCAL1;
325 strcpy (sock_name.sun_path, socket_name());
326
327 /* Bind to socket */
328 if (bind(server_sock, (struct sockaddr *)&sock_name, SUN_LEN(&sock_name)((size_t) (((struct sockaddr_un *) 0)->sun_path) + strlen (
(&sock_name)->sun_path))
) == -1)
329 fatal ("Can't bind() to the socket: %s", strerror(errno(*__errno_location ())));
330
331 if (listen(server_sock, 1) == -1)
332 fatal ("listen() failed: %s", strerror(errno(*__errno_location ())));
333
334 audio_initialize ();
335 tags_cache_init (&tags_cache, options_get_int("TagsCacheSize"));
336 tags_cache_load (&tags_cache, create_file_name("cache"));
337 clients_init ();
338
339 server_tid = pthread_self ();
340 thread_signal (SIGTERM15, sig_exit);
341 thread_signal (SIGINT2, foreground ? sig_exit : SIG_IGN((__sighandler_t) 1));
342 thread_signal (SIGHUP1, SIG_IGN((__sighandler_t) 1));
343 thread_signal (SIGQUIT3, sig_exit);
344 thread_signal (SIGPIPE13, SIG_IGN((__sighandler_t) 1));
345
346 write_pid_file ();
347
348 if (!foreground) {
349 setsid ();
350 redirect_output (STDOUT_FILENO1);
351 redirect_output (STDERR_FILENO2);
352 }
353
354 return server_sock;
355}
356
357/* Send EV_DATA and the integer value. Return 0 on error. */
358static int send_data_int (const struct client *cli, const int data)
359{
360 assert (cli->socket != -1)((cli->socket != -1) ? (void) (0) : __assert_fail ("cli->socket != -1"
, "server.c", 360, __PRETTY_FUNCTION__))
;
361
362 if (!send_int(cli->socket, EV_DATA0x06) || !send_int(cli->socket, data))
363 return 0;
364
365 return 1;
366}
367
368/* Send EV_DATA and the string value. Return 0 on error. */
369static int send_data_str (const struct client *cli, const char *str) {
370 if (!send_int(cli->socket, EV_DATA0x06) || !send_str(cli->socket, str))
371 return 0;
372 return 1;
373}
374
375/* Add event to the client's queue */
376static void add_event (struct client *cli, const int event, void *data)
377{
378 LOCK (cli->events_mutex)pthread_mutex_lock (&cli->events_mutex);
379 event_push (&cli->events, event, data);
380 UNLOCK (cli->events_mutex)pthread_mutex_unlock (&cli->events_mutex);
381}
382
383static void on_song_change ()
384{
385 static char *last_file = NULL((void*)0);
386 static lists_t_strs *on_song_change = NULL((void*)0);
387
388 int ix;
389 char *curr_file;
390 char **args;
391 struct file_tags *curr_tags;
392 lists_t_strs *arg_list;
393
394 /* We only need to do OnSongChange tokenisation once. */
395 if (on_song_change == NULL((void*)0)) {
1
Taking true branch
396 char *command;
397
398 on_song_change = lists_strs_new (5);
399 command = options_get_str ("OnSongChange");
400
401 if (command)
2
Taking false branch
402 lists_strs_tokenise (on_song_change, command);
403 }
404
405 if (lists_strs_empty (on_song_change))
3
Taking false branch
406 return;
407
408 curr_file = audio_get_sname ();
409
410 if (curr_file == NULL((void*)0))
4
Taking false branch
411 return;
412
413 if (!options_get_bool ("RepeatSongChange")) {
5
Taking false branch
414 if (last_file && strcmp (last_file, curr_file) == 0) {
415 free (curr_file);
416 return;
417 }
418 }
419
420 curr_tags = tags_cache_get_immediate (&tags_cache, curr_file,
421 TAGS_COMMENTS | TAGS_TIME);
422 arg_list = lists_strs_new (5);
423 for (ix = 0; ix < lists_strs_size (on_song_change); ix += 1) {
6
Loop condition is false. Execution continues on line 480
424 char *arg, *str;
425
426 arg = lists_strs_at (on_song_change, ix);
427 if (arg[0] != '%')
428 lists_strs_append (arg_list, arg);
429 else if (!curr_tags)
430 lists_strs_append (arg_list, "");
431 else {
432 switch (arg[1]) {
433 case 'a':
434 str = curr_tags->artist ? curr_tags->artist : "";
435 lists_strs_append (arg_list, str);
436 break;
437 case 'r':
438 str = curr_tags->album ? curr_tags->album : "";
439 lists_strs_append (arg_list, str);
440 break;
441 case 't':
442 str = curr_tags->title ? curr_tags->title : "";
443 lists_strs_append (arg_list, str);
444 break;
445 case 'n':
446 if (curr_tags->track >= 0) {
447 str = (char *) xmalloc (sizeof (char) * 4);
448 snprintf (str, 4, "%d", curr_tags->track);
449 lists_strs_push (arg_list, str);
450 }
451 else
452 lists_strs_append (arg_list, "");
453 break;
454 case 'f':
455 lists_strs_append (arg_list, curr_file);
456 break;
457 case 'D':
458 if (curr_tags->time >= 0) {
459 str = (char *) xmalloc (sizeof (char) * 10);
460 snprintf (str, 10, "%d", curr_tags->time);
461 lists_strs_push (arg_list, str);
462 }
463 else
464 lists_strs_append (arg_list, "");
465 break;
466 case 'd':
467 if (curr_tags->time >= 0) {
468 str = (char *) xmalloc (sizeof (char) * 12);
469 sec_to_min (str, curr_tags->time);
470 lists_strs_push (arg_list, str);
471 }
472 else
473 lists_strs_append (arg_list, "");
474 break;
475 default:
476 lists_strs_append (arg_list, arg);
477 }
478 }
479 }
480 tags_free (curr_tags);
481
482 debug ("Running command:")internal_logit ("server.c", 482, __FUNCTION__, "Running command:"
)
;
483 args = (char **) xmalloc (sizeof (char *) * (lists_strs_size (arg_list) + 1));
484 for (ix = 0; ix < lists_strs_size (arg_list); ix += 1) {
7
Loop condition is false. Execution continues on line 488
485 args[ix] = lists_strs_at (arg_list, ix);
486 debug (" '%s'", args[ix])internal_logit ("server.c", 486, __FUNCTION__, " '%s'", args
[ix])
;
487 }
488 args[ix] = NULL((void*)0);
489
490 if (fork () == 0) {
8
Taking true branch
491 execve (args[0], args, environ);
9
Null pointer passed as an argument to a 'nonnull' parameter
492 exit (-1);
493 }
494
495 lists_strs_free (arg_list);
496 free (args);
497 free (last_file);
498 last_file = curr_file;
499}
500
501/* Handle running external command on Stop event. */
502static void on_stop ()
503{
504 char *command;
505
506 command = xstrdup (options_get_str("OnStop"));
507
508 if (command) {
509 char *args[2];
510
511 args[0] = xstrdup (command);
512 args[1] = NULL((void*)0);
513
514 switch (fork()) {
515 case 0:
516 execve (command, args, environ);
517 exit (0);
518 case -1:
519 logit ("Error when running OnStop command '%s': %s",internal_logit ("server.c", 520, __FUNCTION__, "Error when running OnStop command '%s': %s"
, command, strerror((*__errno_location ())))
520 command, strerror(errno))internal_logit ("server.c", 520, __FUNCTION__, "Error when running OnStop command '%s': %s"
, command, strerror((*__errno_location ())))
;
521 break;
522 }
523
524 free (command);
525 free (args[0]);
526 }
527}
528
529static void add_event_all (const int event, const void *data)
530{
531 int i;
532 int added = 0;
533
534 if (event == EV_STATE0x01) {
535 switch (audio_get_state()) {
536 case STATE_PLAY0x01:
537 on_song_change ();
538 break;
539 case STATE_STOP0x02:
540 on_stop ();
541 break;
542 }
543 }
544
545 for (i = 0; i < CLIENTS_MAX10; i++)
546 if (clients[i].socket != -1 && clients[i].wants_events) {
547 void *data_copy = NULL((void*)0);
548
549 if (data) {
550 if (event == EV_PLIST_ADD0x50
551 || event == EV_QUEUE_ADD0x54) {
552 data_copy = plist_new_item ();
553 plist_item_copy (data_copy, data);
554 }
555 else if (event == EV_PLIST_DEL0x51
556 || event == EV_QUEUE_DEL0x55
557 || event == EV_STATUS_MSG0x0f) {
558 data_copy = xstrdup (data);
559 }
560 else if (event == EV_PLIST_MOVE0x52
561 || event == EV_QUEUE_MOVE0x56)
562 data_copy = move_ev_data_dup (
563 (struct move_ev_data *)
564 data);
565 else
566 logit ("Unhandled data!")internal_logit ("server.c", 566, __FUNCTION__, "Unhandled data!"
)
;
567 }
568
569
570 add_event (&clients[i], event, data_copy);
571 added++;
572 }
573
574 if (added)
575 wake_up_server ();
576 else
577 debug ("No events have been added because there are no "internal_logit ("server.c", 578, __FUNCTION__, "No events have been added because there are no "
"clients.")
578 "clients.")internal_logit ("server.c", 578, __FUNCTION__, "No events have been added because there are no "
"clients.")
;
579}
580
581/* Send events from the queue. Return 0 on error. */
582static int flush_events (struct client *cli)
583{
584 enum noblock_io_status st = NB_IO_OK;
585
586 LOCK (cli->events_mutex)pthread_mutex_lock (&cli->events_mutex);
587 while (!event_queue_empty(&cli->events)
588 && (st = event_send_noblock(cli->socket, &cli->events))
589 == NB_IO_OK)
590 ;
591 UNLOCK (cli->events_mutex)pthread_mutex_unlock (&cli->events_mutex);
592
593 return st != NB_IO_ERR ? 1 : 0;
594}
595
596/* Send events to clients that are ready to write. */
597static void send_events (fd_set *fds)
598{
599 int i;
600
601 for (i = 0; i < CLIENTS_MAX10; i++)
602 if (clients[i].socket != -1
603 && FD_ISSET(clients[i].socket, fds)((((fds)->__fds_bits)[((clients[i].socket) / (8 * (int) sizeof
(__fd_mask)))] & ((__fd_mask) 1 << ((clients[i].socket
) % (8 * (int) sizeof (__fd_mask))))) != 0)
) {
604 debug ("Flushing events for client %d", i)internal_logit ("server.c", 604, __FUNCTION__, "Flushing events for client %d"
, i)
;
605 if (!flush_events(&clients[i])) {
606 close (clients[i].socket);
607 del_client (&clients[i]);
608 }
609 }
610}
611
612/* End playing and cleanup. */
613static void server_shutdown ()
614{
615
616 logit ("Server exiting...")internal_logit ("server.c", 616, __FUNCTION__, "Server exiting..."
)
;
617 audio_exit ();
618 tags_cache_save (&tags_cache, create_file_name("tags_cache"));
619 tags_cache_destroy (&tags_cache);
620 unlink (socket_name());
621 unlink (create_file_name(PID_FILE"pid"));
622 close (wake_up_pipe[0]);
623 close (wake_up_pipe[1]);
624 logit ("Server exited")internal_logit ("server.c", 624, __FUNCTION__, "Server exited"
)
;
625}
626
627/* Send EV_BUSY message and close the connection. */
628static void busy (int sock)
629{
630 logit ("Closing connection due to maximum number of clients reached.")internal_logit ("server.c", 630, __FUNCTION__, "Closing connection due to maximum number of clients reached."
)
;
631 send_int (sock, EV_BUSY0x05);
632 close (sock);
633}
634
635/* Handle CMD_LIST_ADD, return 1 if ok or 0 on error. */
636static int req_list_add (struct client *cli)
637{
638 char *file;
639
640 file = get_str (cli->socket);
641 if (!file)
642 return 0;
643
644 logit ("Adding '%s' to the list", file)internal_logit ("server.c", 644, __FUNCTION__, "Adding '%s' to the list"
, file)
;
645
646 audio_plist_add (file);
647 free (file);
648
649 return 1;
650}
651
652/* Handle CMD_QUEUE_ADD, return 1 if ok or 0 on error. */
653static int req_queue_add (const struct client *cli)
654{
655 char *file;
656 struct plist_item *item;
657
658 file = get_str (cli->socket);
659 if (!file)
660 return 0;
661
662 logit ("Adding '%s' to the queue", file)internal_logit ("server.c", 662, __FUNCTION__, "Adding '%s' to the queue"
, file)
;
663
664 audio_queue_add (file);
665
666 /* Wrap the filename in struct plist_item.
667 * We don't need tags, because the player gets them
668 * when playing the file. This may change if there is
669 * support for viewing/reordering the queue and here
670 * is the place to read the tags and fill them into
671 * the item. */
672
673 item = plist_new_item ();
674 item->file = xstrdup (file);
675 item->type = file_type (file);
676 item->mtime = get_mtime (file);
677
678 add_event_all (EV_QUEUE_ADD0x54, item);
679
680 plist_free_item_fields (item);
681 free (item);
682 free (file);
683
684 return 1;
685}
686
687/* Handle CMD_PLAY, return 1 if ok or 0 on error. */
688static int req_play (struct client *cli)
689{
690 char *file;
691
692 if (!(file = get_str(cli->socket)))
693 return 0;
694
695 logit ("Playing %s", *file ? file : "first element on the list")internal_logit ("server.c", 695, __FUNCTION__, "Playing %s", *
file ? file : "first element on the list")
;
696 audio_play (file);
697 free (file);
698
699 return 1;
700}
701
702/* Handle CMD_SEEK, return 1 if ok or 0 on error */
703static int req_seek (struct client *cli)
704{
705 int sec;
706
707 if (!get_int(cli->socket, &sec))
708 return 0;
709
710 logit ("Seeking %ds", sec)internal_logit ("server.c", 710, __FUNCTION__, "Seeking %ds",
sec)
;
711 audio_seek (sec);
712
713 return 1;
714}
715/* Handle CMD_JUMP_TO, return 1 if ok or 0 on error */
716static int req_jump_to (struct client *cli)
717{
718 int sec;
719
720 if (!get_int(cli->socket, &sec))
721 return 0;
722 logit ("Jumping to %ds", sec)internal_logit ("server.c", 722, __FUNCTION__, "Jumping to %ds"
, sec)
;
723 audio_jump_to (sec);
724
725 return 1;
726}
727
728/* Report an error logging it and sending a message to the client. */
729void server_error (const char *msg)
730{
731 strncpy (err_msg, msg, sizeof(err_msg) - 1);
732 err_msg[sizeof(err_msg) - 1] = 0;
733 logit ("ERROR: %s", err_msg)internal_logit ("server.c", 733, __FUNCTION__, "ERROR: %s", err_msg
)
;
734 add_event_all (EV_SRV_ERROR0x04, NULL((void*)0));
735}
736
737/* Send the song name to the client. Return 0 on error. */
738static int send_sname (struct client *cli)
739{
740 int status = 1;
741 char *sname = audio_get_sname ();
742
743 if (!send_data_str(cli, sname ? sname : ""))
744 status = 0;
745 free (sname);
746
747 return status;
748}
749
750/* Return 0 if an option is valid when getting/setting with the client. */
751static int valid_sync_option (const char *name)
752{
753 return !strcasecmp(name, "ShowStreamErrors")
754 || !strcasecmp(name, "Repeat")
755 || !strcasecmp(name, "Shuffle")
756 || !strcasecmp(name, "AutoNext");
757}
758
759/* Send requested option value to the client. Return 1 if OK. */
760static int send_option (struct client *cli)
761{
762 char *name;
763
764 if (!(name = get_str(cli->socket)))
765 return 0;
766
767 /* We can send only a few options, others make no sense here. */
768 if (!valid_sync_option(name)) {
769 logit ("Client wantetd to get not supported option '%s'",internal_logit ("server.c", 770, __FUNCTION__, "Client wantetd to get not supported option '%s'"
, name)
770 name)internal_logit ("server.c", 770, __FUNCTION__, "Client wantetd to get not supported option '%s'"
, name)
;
771 free (name);
772 return 0;
773 }
774
775 /* All supported options are integer type. */
776 if (!send_data_int(cli, options_get_int(name))) {
777 free (name);
778 return 0;
779 }
780
781 free (name);
782 return 1;
783}
784
785/* Get and set an option from the client. Return 1 on error. */
786static int get_set_option (struct client *cli)
787{
788 char *name;
789 int val;
790
791 if (!(name = get_str(cli->socket)))
792 return 0;
793 if (!valid_sync_option(name)) {
794 logit ("Client requested setting invalid option '%s'", name)internal_logit ("server.c", 794, __FUNCTION__, "Client requested setting invalid option '%s'"
, name)
;
795 return 0;
796 }
797 if (!get_int(cli->socket, &val)) {
798 free (name);
799 return 0;
800 }
801
802 option_set_int (name, val);
803 free (name);
804
805 add_event_all (EV_OPTIONS0x0c, NULL((void*)0));
806
807 return 1;
808}
809
810/* Set the mixer to the value provided by the client. Return 0 on error. */
811static int set_mixer (struct client *cli)
812{
813 int val;
814
815 if (!get_int(cli->socket, &val))
816 return 0;
817
818 audio_set_mixer (val);
819 return 1;
820}
821
822/* Delete an item from the playlist. Return 0 on error. */
823static int delete_item (struct client *cli)
824{
825 char *file;
826
827 if (!(file = get_str(cli->socket)))
828 return 0;
829
830 debug ("Request for deleting %s", file)internal_logit ("server.c", 830, __FUNCTION__, "Request for deleting %s"
, file)
;
831
832 audio_plist_delete (file);
833 free (file);
834 return 1;
835}
836
837static int req_queue_del (const struct client *cli)
838{
839 char *file;
840
841 if (!(file = get_str(cli->socket)))
842 return 0;
843
844 debug ("Deleting '%s' from queue", file)internal_logit ("server.c", 844, __FUNCTION__, "Deleting '%s' from queue"
, file)
;
845
846 audio_queue_delete (file);
847 add_event_all (EV_QUEUE_DEL0x55, file);
848 free (file);
849
850 return 1;
851}
852
853/* Return the index of the first client able to send the playlist or -1 if
854 * there isn't any. */
855static int find_sending_plist ()
856{
857 int i;
858
859 for (i = 0; i < CLIENTS_MAX10; i++)
860 if (clients[i].socket != -1 && clients[i].can_send_plist)
861 return i;
862 return -1;
863}
864
865/* Handle CMD_GET_PLIST. Return 0 on error. */
866static int get_client_plist (struct client *cli)
867{
868 int first;
869
870 debug ("Client with fd %d requests the playlist.", cli->socket)internal_logit ("server.c", 870, __FUNCTION__, "Client with fd %d requests the playlist."
, cli->socket)
;
871
872 /* Find the first connected client, and ask it to send the playlist.
873 * Here, send 1 if there is a client with the playlist, or 0 if there
874 * isn't. */
875
876 cli->requests_plist = 1;
877
878 first = find_sending_plist ();
879 if (first == -1) {
880 debug ("No clients with the playlist.")internal_logit ("server.c", 880, __FUNCTION__, "No clients with the playlist."
)
;
881 cli->requests_plist = 0;
882 if (!send_data_int(cli, 0))
883 return 0;
884 return 1;
885 }
886
887 if (!send_data_int(cli, 1))
888 return 0;
889
890 if (!send_int(clients[first].socket, EV_SEND_PLIST0x0d))
891 return 0;
892
893 return 1;
894}
895
896/* Find the client requesting the playlist. */
897static int find_cli_requesting_plist ()
898{
899 int i;
900
901 for (i = 0; i < CLIENTS_MAX10; i++)
902 if (clients[i].requests_plist)
903 return i;
904 return -1;
905}
906
907/* Handle CMD_SEND_PLIST. Some client requested to get the playlist, so we asked
908 * another client to send it (EV_SEND_PLIST). */
909static int req_send_plist (struct client *cli)
910{
911 int requesting = find_cli_requesting_plist ();
912 int send_fd;
913 struct plist_item *item;
914 int serial;
915
916 debug ("Client with fd %d wants to send its playlists", cli->socket)internal_logit ("server.c", 916, __FUNCTION__, "Client with fd %d wants to send its playlists"
, cli->socket)
;
917
918 if (requesting == -1) {
919 logit ("No clients are requesting the playlist.")internal_logit ("server.c", 919, __FUNCTION__, "No clients are requesting the playlist."
)
;
920 send_fd = -1;
921 }
922 else {
923 send_fd = clients[requesting].socket;
924 if (!send_int(send_fd, EV_DATA0x06)) {
925 logit ("Error while sending response, disconnecting"internal_logit ("server.c", 926, __FUNCTION__, "Error while sending response, disconnecting"
" the client")
926 " the client")internal_logit ("server.c", 926, __FUNCTION__, "Error while sending response, disconnecting"
" the client")
;
927 close (send_fd);
928 del_client (&clients[requesting]);
929 send_fd = -1;
930 }
931 }
932
933 if (!get_int(cli->socket, &serial)) {
934 logit ("Error while getting serial")internal_logit ("server.c", 934, __FUNCTION__, "Error while getting serial"
)
;
935 return 0;
936 }
937
938 if (send_fd != -1 && !send_int(send_fd, serial)) {
939 error ("Error while sending serial, disconnecting the client");
940 close (send_fd);
941 del_client (&clients[requesting]);
942 send_fd = -1;
943 }
944
945 /* Even if no clients are requesting the playlist, we must read it,
946 * because there is no way to say that we don't need it. */
947 while ((item = recv_item(cli->socket)) && item->file[0]) {
948 if (send_fd != -1 && !send_item(send_fd, item)) {
949 logit ("Error while sending item, disconnecting the"internal_logit ("server.c", 950, __FUNCTION__, "Error while sending item, disconnecting the"
" client")
950 " client")internal_logit ("server.c", 950, __FUNCTION__, "Error while sending item, disconnecting the"
" client")
;
951 close (send_fd);
952 del_client (&clients[requesting]);
953 send_fd = -1;
954 }
955 plist_free_item_fields (item);
956 free (item);
957 }
958
959 if (item) {
960 plist_free_item_fields (item);
961 free (item);
962 logit ("Playlist sent")internal_logit ("server.c", 962, __FUNCTION__, "Playlist sent"
)
;
963 }
964 else
965 logit ("Error while receiving item")internal_logit ("server.c", 965, __FUNCTION__, "Error while receiving item"
)
;
966
967 if (send_fd != -1 && !send_item (send_fd, NULL((void*)0))) {
968 logit ("Error while sending end of playlist mark, disconnecting"internal_logit ("server.c", 969, __FUNCTION__, "Error while sending end of playlist mark, disconnecting"
" the client.")
969 " the client.")internal_logit ("server.c", 969, __FUNCTION__, "Error while sending end of playlist mark, disconnecting"
" the client.")
;
970 close (send_fd);
971 del_client (&clients[requesting]);
972 return 0;
973 }
974
975 if (requesting != -1)
976 clients[requesting].requests_plist = 0;
977
978 return item ? 1 : 0;
979}
980
981/* Client requested we send the queue so we get it from audio.c and
982 * send it to the client. */
983static int req_send_queue (struct client *cli)
984{
985 int i;
986 struct plist *queue;
987
988 logit ("Client with fd %d wants queue ... sending it", cli->socket)internal_logit ("server.c", 988, __FUNCTION__, "Client with fd %d wants queue ... sending it"
, cli->socket)
;
989
990 if (!send_int(cli->socket, EV_DATA0x06)) {
991 logit ("Error while sending response, disconnecting"internal_logit ("server.c", 992, __FUNCTION__, "Error while sending response, disconnecting"
" the client.")
992 " the client.")internal_logit ("server.c", 992, __FUNCTION__, "Error while sending response, disconnecting"
" the client.")
;
993 close (cli->socket);
994 del_client (cli);
995 return 0;
996 }
997
998 queue = audio_queue_get_contents ();
999
1000 for (i = 0; i < queue->num; i++)
1001 if (!plist_deleted(queue, i)) {
1002 if(!send_item(cli->socket, &queue->items[i])){
1003 logit ("Error sending queue, disconnecting"internal_logit ("server.c", 1004, __FUNCTION__, "Error sending queue, disconnecting"
" the client.")
1004 " the client.")internal_logit ("server.c", 1004, __FUNCTION__, "Error sending queue, disconnecting"
" the client.")
;
1005 close (cli->socket);
1006 del_client (cli);
1007 return 0;
1008 }
1009 }
1010
1011 plist_free (queue);
1012
1013 if (!send_item (cli->socket, NULL((void*)0))) {
1014 logit ("Error while sending end of playlist mark, disconnecting"internal_logit ("server.c", 1015, __FUNCTION__, "Error while sending end of playlist mark, disconnecting"
" the client.")
1015 " the client.")internal_logit ("server.c", 1015, __FUNCTION__, "Error while sending end of playlist mark, disconnecting"
" the client.")
;
1016 close (cli->socket);
1017 del_client (cli);
1018 return 0;
1019 }
1020
1021 logit ("Queue sent")internal_logit ("server.c", 1021, __FUNCTION__, "Queue sent");
1022 return 1;
1023}
1024
1025/* Handle command that synchronises the playlists between interfaces
1026 * (except forwarding the whole list). Return 0 on error. */
1027static int plist_sync_cmd (struct client *cli, const int cmd)
1028{
1029 if (cmd == CMD_CLI_PLIST_ADD0x24) {
1030 struct plist_item *item;
1031
1032 debug ("Sending EV_PLIST_ADD")internal_logit ("server.c", 1032, __FUNCTION__, "Sending EV_PLIST_ADD"
)
;
1033
1034 if (!(item = recv_item(cli->socket))) {
1035 logit ("Error while receiving item")internal_logit ("server.c", 1035, __FUNCTION__, "Error while receiving item"
)
;
1036 return 0;
1037 }
1038
1039 add_event_all (EV_PLIST_ADD0x50, item);
1040 plist_free_item_fields (item);
1041 free (item);
1042 }
1043 else if (cmd == CMD_CLI_PLIST_DEL0x25) {
1044 char *file;
1045
1046 debug ("Sending EV_PLIST_DEL")internal_logit ("server.c", 1046, __FUNCTION__, "Sending EV_PLIST_DEL"
)
;
1047
1048 if (!(file = get_str(cli->socket))) {
1049 logit ("Error while receiving file")internal_logit ("server.c", 1049, __FUNCTION__, "Error while receiving file"
)
;
1050 return 0;
1051 }
1052
1053 add_event_all (EV_PLIST_DEL0x51, file);
1054 free (file);
1055 }
1056 else if (cmd == CMD_CLI_PLIST_MOVE0x31) {
1057 struct move_ev_data m;
1058
1059 if (!(m.from = get_str(cli->socket))
1060 || !(m.to = get_str(cli->socket))) {
1061 logit ("Error while receiving file")internal_logit ("server.c", 1061, __FUNCTION__, "Error while receiving file"
)
;
1062 return 0;
1063 }
1064
1065 add_event_all (EV_PLIST_MOVE0x52, &m);
1066
1067 free (m.from);
1068 free (m.to);
1069 }
1070 else { /* it can be only CMD_CLI_PLIST_CLEAR */
1071 debug ("Sending EV_PLIST_CLEAR")internal_logit ("server.c", 1071, __FUNCTION__, "Sending EV_PLIST_CLEAR"
)
;
1072 add_event_all (EV_PLIST_CLEAR0x53, NULL((void*)0));
1073 }
1074
1075 return 1;
1076}
1077
1078/* Handle CMD_PLIST_GET_SERIAL. Return 0 on error. */
1079static int req_plist_get_serial (struct client *cli)
1080{
1081 if (!send_data_int(cli, audio_plist_get_serial()))
1082 return 0;
1083 return 1;
1084}
1085
1086/* Handle CMD_PLIST_SET_SERIAL. Return 0 on error. */
1087static int req_plist_set_serial (struct client *cli)
1088{
1089 int serial;
1090
1091 if (!get_int(cli->socket, &serial))
1092 return 0;
1093
1094 if (serial < 0) {
1095 logit ("Client wants to set bad serial number")internal_logit ("server.c", 1095, __FUNCTION__, "Client wants to set bad serial number"
)
;
1096 return 0;
1097 }
1098
1099 debug ("Setting the playlist serial number to %d", serial)internal_logit ("server.c", 1099, __FUNCTION__, "Setting the playlist serial number to %d"
, serial)
;
1100 audio_plist_set_serial (serial);
1101
1102 return 1;
1103}
1104
1105/* Generate a unique playlist serial number. */
1106static int gen_serial (const struct client *cli)
1107{
1108 static int seed = 0;
1109 int serial;
1110
1111 /* Each client must always get a different serial number, so we use
1112 * also the client index to generate it. It must also not be used by
1113 * our playlist to not confuse clients.
1114 * There can be 256 different serial number per client, but it's
1115 * enough since clients use only two playlists. */
1116
1117 do {
1118 serial = (seed << 8) | client_index(cli);
1119 seed = (seed + 1) & 0xFF;
1120 } while (serial == audio_plist_get_serial());
1121
1122 debug ("Generated serial %d for client with fd %d", serial,internal_logit ("server.c", 1123, __FUNCTION__, "Generated serial %d for client with fd %d"
, serial, cli->socket)
1123 cli->socket)internal_logit ("server.c", 1123, __FUNCTION__, "Generated serial %d for client with fd %d"
, serial, cli->socket)
;
1124
1125 return serial;
1126}
1127
1128/* Send the unique number to the client. Return 0 on error. */
1129static int send_serial (struct client *cli)
1130{
1131 if (!send_data_int(cli, gen_serial(cli))) {
1132 logit ("Error when sending serial")internal_logit ("server.c", 1132, __FUNCTION__, "Error when sending serial"
)
;
1133 return 0;
1134 }
1135 return 1;
1136}
1137
1138/* Send tags to the client. Return 0 on error. */
1139static int req_get_tags (struct client *cli)
1140{
1141 struct file_tags *tags;
1142 int res = 1;
1143
1144 debug ("Sending tags to client with fd %d...", cli->socket)internal_logit ("server.c", 1144, __FUNCTION__, "Sending tags to client with fd %d..."
, cli->socket)
;
1145
1146 if (!send_int(cli->socket, EV_DATA0x06)) {
1147 logit ("Error when sending EV_DATA")internal_logit ("server.c", 1147, __FUNCTION__, "Error when sending EV_DATA"
)
;
1148 return 0;
1149 }
1150
1151 tags = audio_get_curr_tags ();
1152 if (!send_tags(cli->socket, tags)) {
1153 logit ("Error when sending tags")internal_logit ("server.c", 1153, __FUNCTION__, "Error when sending tags"
)
;
1154 res = 0;
1155 }
1156
1157 if (tags)
1158 tags_free (tags);
1159
1160 return res;
1161}
1162
1163/* Handle CMD_GET_MIXER_CHANNEL_NAME. Return 0 on error. */
1164int req_get_mixer_channel_name (struct client *cli)
1165{
1166 int status = 1;
1167 char *name = audio_get_mixer_channel_name ();
1168
1169 if (!send_data_str(cli, name ? name : ""))
1170 status = 0;
1171 free (name);
1172
1173 return status;
1174}
1175
1176/* Handle CMD_TOGGLE_MIXER_CHANNEL. */
1177void req_toggle_mixer_channel ()
1178{
1179 audio_toggle_mixer_channel ();
1180 add_event_all (EV_MIXER_CHANGE0x10, NULL((void*)0));
1181}
1182
1183/* Handle CMD_TOGGLE_SOFTMIXER. */
1184void req_toggle_softmixer ()
1185{
1186 softmixer_set_active(!softmixer_is_active());
1187 add_event_all (EV_MIXER_CHANGE0x10, NULL((void*)0));
1188}
1189
1190void update_eq_name()
1191{
1192 char buffer[27];
1193
1194 char *n = equalizer_current_eqname();
1195
1196 int l = strlen(n);
1197
1198 /* Status message can only take strings up to 25 chars
1199 * (Without terminating zero).
1200 * The message header has 11 chars (EQ set to...).
1201 */
1202 if (l > 14)
1203 {
1204 n[14] = 0;
1205 n[13] = '.';
1206 n[12] = '.';
1207 n[11] = '.';
1208 }
1209
1210 sprintf(buffer, "EQ set to: %s", n);
1211
1212 logit("%s", buffer)internal_logit ("server.c", 1212, __FUNCTION__, "%s", buffer);
1213
1214 free(n);
1215
1216 status_msg(buffer);
1217}
1218
1219void req_toggle_equalizer ()
1220{
1221 equalizer_set_active(!equalizer_is_active());
1222
1223 update_eq_name();
1224}
1225
1226void req_equalizer_refresh()
1227{
1228 equalizer_refresh();
1229
1230 status_msg("Equalizer refreshed");
1231
1232 logit("Equalizer refreshed")internal_logit ("server.c", 1232, __FUNCTION__, "Equalizer refreshed"
)
;
1233}
1234
1235void req_equalizer_prev()
1236{
1237 equalizer_prev();
1238
1239 update_eq_name();
1240}
1241
1242void req_equalizer_next()
1243{
1244 equalizer_next();
1245
1246 update_eq_name();
1247}
1248
1249void req_toggle_make_mono()
1250{
1251 char buffer[128];
1252
1253 softmixer_set_mono(!softmixer_is_mono());
1254
1255 sprintf(buffer, "Mono-Mixing set to: %s", softmixer_is_mono()?"on":"off");
1256
1257 status_msg(buffer);
1258}
1259
1260/* Handle CMD_GET_FILE_TAGS. Return 0 on error. */
1261static int get_file_tags (const int cli_id)
1262{
1263 char *file;
1264 int tags_sel;
1265
1266 if (!(file = get_str(clients[cli_id].socket)))
1267 return 0;
1268 if (!get_int(clients[cli_id].socket, &tags_sel)) {
1269 free (file);
1270 return 0;
1271 }
1272
1273 tags_cache_add_request (&tags_cache, file, tags_sel, cli_id);
1274 free (file);
1275
1276 return 1;
1277}
1278
1279static int abort_tags_requests (const int cli_id)
1280{
1281 char *file;
1282
1283 if (!(file = get_str(clients[cli_id].socket)))
1284 return 0;
1285
1286 tags_cache_clear_up_to (&tags_cache, file, cli_id);
1287 free (file);
1288
1289 return 1;
1290}
1291
1292/* Handle CMD_LIST_MOVE. Return 0 on error. */
1293static int req_list_move (struct client *cli)
1294{
1295 char *from;
1296 char *to;
1297
1298 if (!(from = get_str(cli->socket)))
1299 return 0;
1300 if (!(to = get_str(cli->socket))) {
1301 free (from);
1302 return 0;
1303 }
1304
1305 audio_plist_move (from, to);
1306
1307 free (from);
1308 free (to);
1309
1310 return 1;
1311}
1312
1313/* Handle CMD_QUEUE_MOVE. Return 0 on error. */
1314static int req_queue_move (const struct client *cli)
1315{
1316 /*char *from;
1317 char *to;
1318 */
1319 struct move_ev_data m;
1320
1321 if (!(m.from = get_str(cli->socket)))
1322 return 0;
1323 if (!(m.to = get_str(cli->socket))) {
1324 free (m.from);
1325 return 0;
1326 }
1327
1328 audio_queue_move (m.from, m.to);
1329
1330 logit ("Swapping %s with %s in the queue", m.from, m.to)internal_logit ("server.c", 1330, __FUNCTION__, "Swapping %s with %s in the queue"
, m.from, m.to)
;
1331
1332 /* Broadcast the event to clients */
1333 add_event_all (EV_QUEUE_MOVE0x56, &m);
1334
1335 free (m.from);
1336 free (m.to);
1337
1338 return 1;
1339}
1340
1341/* Reveive a command from the client and execute it. */
1342static void handle_command (const int client_id)
1343{
1344 int cmd;
1345 int err = 0;
1346 struct client *cli = &clients[client_id];
1347
1348 if (!get_int(cli->socket, &cmd)) {
1349 logit ("Failed to get command from the client")internal_logit ("server.c", 1349, __FUNCTION__, "Failed to get command from the client"
)
;
1350 close (cli->socket);
1351 del_client (cli);
1352 return;
1353 }
1354
1355 switch (cmd) {
1356 case CMD_QUIT0x11:
1357 logit ("Exit request from the client")internal_logit ("server.c", 1357, __FUNCTION__, "Exit request from the client"
)
;
1358 server_quit = 1;
1359 break;
1360 case CMD_LIST_CLEAR0x01:
1361 logit ("Clearing the list")internal_logit ("server.c", 1361, __FUNCTION__, "Clearing the list"
)
;
1362 audio_plist_clear ();
1363 break;
1364 case CMD_LIST_ADD0x02:
1365 if (!req_list_add(cli))
1366 err = 1;
1367 break;
1368 case CMD_PLAY0x00:
1369 if (!req_play(cli))
1370 err = 1;
1371 break;
1372 case CMD_DISCONNECT0x15:
1373 logit ("Client disconnected")internal_logit ("server.c", 1373, __FUNCTION__, "Client disconnected"
)
;
1374 close (cli->socket);
1375 del_client (cli);
1376 break;
1377 case CMD_PAUSE0x05:
1378 audio_pause ();
1379 break;
1380 case CMD_UNPAUSE0x06:
1381 audio_unpause ();
1382 break;
1383 case CMD_STOP0x04:
1384 audio_stop ();
1385 break;
1386 case CMD_GET_CTIME0x0d:
1387 if (!send_data_int(cli, audio_get_time()))
1388 err = 1;
1389 break;
1390 case CMD_SEEK0x12:
1391 if (!req_seek(cli))
1392 err = 1;
1393 break;
1394 case CMD_JUMP_TO0x3a:
1395 if (!req_jump_to(cli))
1396 err = 1;
1397 break;
1398 case CMD_GET_SNAME0x0f:
1399 if (!send_sname(cli))
1400 err = 1;
1401 break;
1402 case CMD_GET_STATE0x13:
1403 if (!send_data_int(cli, audio_get_state()))
1404 err = 1;
1405 break;
1406 case CMD_GET_BITRATE0x16:
1407 if (!send_data_int(cli, sound_info.bitrate))
1408 err = 1;
1409 break;
1410 case CMD_GET_AVG_BITRATE0x33:
1411 if (!send_data_int(cli, sound_info.avg_bitrate))
1412 err = 1;
1413 break;
1414 case CMD_GET_RATE0x17:
1415 if (!send_data_int(cli, sound_info.rate))
1416 err = 1;
1417 break;
1418 case CMD_GET_CHANNELS0x18:
1419 if (!send_data_int(cli, sound_info.channels))
1420 err = 1;
1421 break;
1422 case CMD_NEXT0x10:
1423 audio_next ();
1424 break;
1425 case CMD_PREV0x20:
1426 audio_prev ();
1427 break;
1428 case CMD_PING0x19:
1429 if (!send_int(cli->socket, EV_PONG0x0b))
1430 err = 1;
1431 break;
1432 case CMD_GET_OPTION0x08:
1433 if (!send_option(cli))
1434 err = 1;
1435 break;
1436 case CMD_SET_OPTION0x07:
1437 if (!get_set_option(cli))
1438 err = 1;
1439 break;
1440 case CMD_GET_MIXER0x1a:
1441 if (!send_data_int(cli, audio_get_mixer()))
1442 err = 1;
1443 break;
1444 case CMD_SET_MIXER0x1b:
1445 if (!set_mixer(cli))
1446 err = 1;
1447 break;
1448 case CMD_DELETE0x1c:
1449 if (!delete_item(cli))
1450 err = 1;
1451 break;
1452 case CMD_SEND_EVENTS0x1d:
1453 cli->wants_events = 1;
1454 logit ("Request for events")internal_logit ("server.c", 1454, __FUNCTION__, "Request for events"
)
;
1455 break;
1456 case CMD_GET_ERROR0x1e:
1457 if (!send_data_str(cli, err_msg))
1458 err = 1;
1459 break;
1460 case CMD_GET_PLIST0x22:
1461 if (!get_client_plist(cli))
1462 err = 1;
1463 break;
1464 case CMD_SEND_PLIST0x21:
1465 if (!req_send_plist(cli))
1466 err = 1;
1467 break;
1468 case CMD_CAN_SEND_PLIST0x23:
1469 cli->can_send_plist = 1;
1470 break;
1471 case CMD_CLI_PLIST_ADD0x24:
1472 case CMD_CLI_PLIST_DEL0x25:
1473 case CMD_CLI_PLIST_CLEAR0x26:
1474 case CMD_CLI_PLIST_MOVE0x31:
1475 if (!plist_sync_cmd(cli, cmd))
1476 err = 1;
1477 break;
1478 case CMD_LOCK0x29:
1479 if (!client_lock(cli))
1480 err = 1;
1481 break;
1482 case CMD_UNLOCK0x2a:
1483 if (!client_unlock(cli))
1484 err = 1;
1485 break;
1486 case CMD_GET_SERIAL0x27:
1487 if (!send_serial(cli))
1488 err = 1;
1489 break;
1490 case CMD_PLIST_GET_SERIAL0x2b:
1491 if (!req_plist_get_serial(cli))
1492 err = 1;
1493 break;
1494 case CMD_PLIST_SET_SERIAL0x28:
1495 if (!req_plist_set_serial(cli))
1496 err = 1;
1497 break;
1498 case CMD_GET_TAGS0x2c:
1499 if (!req_get_tags(cli))
1500 err = 1;
1501 break;
1502 case CMD_TOGGLE_MIXER_CHANNEL0x2d:
1503 req_toggle_mixer_channel ();
1504 break;
1505 case CMD_TOGGLE_SOFTMIXER0x34:
1506 req_toggle_softmixer ();
1507 break;
1508 case CMD_GET_MIXER_CHANNEL_NAME0x2e:
1509 if (!req_get_mixer_channel_name(cli))
1510 err = 1;
1511 break;
1512 case CMD_GET_FILE_TAGS0x2f:
1513 if (!get_file_tags(client_id))
1514 err = 1;
1515 break;
1516 case CMD_ABORT_TAGS_REQUESTS0x30:
1517 if (!abort_tags_requests(client_id))
1518 err = 1;
1519 break;
1520 case CMD_LIST_MOVE0x32:
1521 if (!req_list_move(cli))
1522 err = 1;
1523 break;
1524 case CMD_TOGGLE_EQUALIZER0x35:
1525 req_toggle_equalizer();
1526 break;
1527 case CMD_EQUALIZER_REFRESH0x36:
1528 req_equalizer_refresh();
1529 break;
1530 case CMD_EQUALIZER_PREV0x37:
1531 req_equalizer_prev();
1532 break;
1533 case CMD_EQUALIZER_NEXT0x38:
1534 req_equalizer_next();
1535 break;
1536 case CMD_TOGGLE_MAKE_MONO0x39:
1537 req_toggle_make_mono();
1538 break;
1539 case CMD_QUEUE_ADD0x3b:
1540 if (!req_queue_add(cli))
1541 err = 1;
1542 break;
1543 case CMD_QUEUE_DEL0x3c:
1544 if (!req_queue_del(cli))
1545 err = 1;
1546 break;
1547 case CMD_QUEUE_CLEAR0x3e:
1548 logit ("Clearing the queue")internal_logit ("server.c", 1548, __FUNCTION__, "Clearing the queue"
)
;
1549 audio_queue_clear ();
1550 add_event_all (EV_QUEUE_CLEAR0x57, NULL((void*)0));
1551 break;
1552 case CMD_QUEUE_MOVE0x3d:
1553 if (!req_queue_move(cli))
1554 err = 1;
1555 break;
1556 case CMD_GET_QUEUE0x3f:
1557 if (!req_send_queue(cli))
1558 err = 1;
1559 break;
1560 default:
1561 logit ("Bad command (0x%x) from the client.", cmd)internal_logit ("server.c", 1561, __FUNCTION__, "Bad command (0x%x) from the client."
, cmd)
;
1562 err = 1;
1563 }
1564
1565 if (err) {
1566 logit ("Closing client connection due to error.")internal_logit ("server.c", 1566, __FUNCTION__, "Closing client connection due to error."
)
;
1567 close (cli->socket);
1568 del_client (cli);
1569 }
1570}
1571
1572/* Add clients file descriptors to fds. */
1573static void add_clients_fds (fd_set *read, fd_set *write)
1574{
1575 int i;
1576
1577 for (i = 0; i < CLIENTS_MAX10; i++)
1578 if (clients[i].socket != -1) {
1579 if (locking_client() == -1 || is_locking(&clients[i]))
1580 FD_SET (clients[i].socket, read)(((read)->__fds_bits)[((clients[i].socket) / (8 * (int) sizeof
(__fd_mask)))] |= ((__fd_mask) 1 << ((clients[i].socket
) % (8 * (int) sizeof (__fd_mask)))))
;
1581
1582 LOCK (clients[i].events_mutex)pthread_mutex_lock (&clients[i].events_mutex);
1583 if (!event_queue_empty(&clients[i].events))
1584 FD_SET (clients[i].socket, write)(((write)->__fds_bits)[((clients[i].socket) / (8 * (int) sizeof
(__fd_mask)))] |= ((__fd_mask) 1 << ((clients[i].socket
) % (8 * (int) sizeof (__fd_mask)))))
;
1585 UNLOCK (clients[i].events_mutex)pthread_mutex_unlock (&clients[i].events_mutex);
1586 }
1587}
1588
1589/* Return the maximum fd from clients and the argument. */
1590static int max_fd (int max)
1591{
1592 int i;
1593
1594 if (wake_up_pipe[0] > max)
1595 max = wake_up_pipe[0];
1596
1597 for (i = 0; i < CLIENTS_MAX10; i++)
1598 if (clients[i].socket > max)
1599 max = clients[i].socket;
1600 return max;
1601}
1602
1603/* Handle clients whose fds are ready to read. */
1604static void handle_clients (fd_set *fds)
1605{
1606 int i;
1607
1608 for (i = 0; i < CLIENTS_MAX10; i++)
1609 if (clients[i].socket != -1
1610 && FD_ISSET(clients[i].socket, fds)((((fds)->__fds_bits)[((clients[i].socket) / (8 * (int) sizeof
(__fd_mask)))] & ((__fd_mask) 1 << ((clients[i].socket
) % (8 * (int) sizeof (__fd_mask))))) != 0)
) {
1611 if (locking_client() == -1
1612 || is_locking(&clients[i]))
1613 handle_command (i);
1614 else
1615 debug ("Not getting a command from client with"internal_logit ("server.c", 1617, __FUNCTION__, "Not getting a command from client with"
" fd %d because of lock", clients[i].socket)
1616 " fd %d because of lock",internal_logit ("server.c", 1617, __FUNCTION__, "Not getting a command from client with"
" fd %d because of lock", clients[i].socket)
1617 clients[i].socket)internal_logit ("server.c", 1617, __FUNCTION__, "Not getting a command from client with"
" fd %d because of lock", clients[i].socket)
;
1618 }
1619}
1620
1621/* Close all client connections sending EV_EXIT. */
1622static void close_clients ()
1623{
1624 int i;
1625
1626 for (i = 0; i < CLIENTS_MAX10; i++)
1627 if (clients[i].socket != -1) {
1628 send_int (clients[i].socket, EV_EXIT0x0a);
1629 close (clients[i].socket);
1630 del_client (&clients[i]);
1631 }
1632}
1633
1634/* Handle incoming connections */
1635void server_loop (int list_sock)
1636{
1637 struct sockaddr_un client_name;
1638 socklen_t name_len = sizeof (client_name);
1639 int end = 0;
1640
1641 logit ("MOC server started, pid: %d", getpid())internal_logit ("server.c", 1641, __FUNCTION__, "MOC server started, pid: %d"
, getpid())
;
1642
1643 do {
1644 int res;
1645 fd_set fds_write, fds_read;
1646
1647 FD_ZERO (&fds_read)do { int __d0, __d1; __asm__ __volatile__ ("cld; rep; " "stosl"
: "=c" (__d0), "=D" (__d1) : "a" (0), "0" (sizeof (fd_set) /
sizeof (__fd_mask)), "1" (&((&fds_read)->__fds_bits
)[0]) : "memory"); } while (0)
;
1648 FD_ZERO (&fds_write)do { int __d0, __d1; __asm__ __volatile__ ("cld; rep; " "stosl"
: "=c" (__d0), "=D" (__d1) : "a" (0), "0" (sizeof (fd_set) /
sizeof (__fd_mask)), "1" (&((&fds_write)->__fds_bits
)[0]) : "memory"); } while (0)
;
1649 FD_SET (list_sock, &fds_read)(((&fds_read)->__fds_bits)[((list_sock) / (8 * (int) sizeof
(__fd_mask)))] |= ((__fd_mask) 1 << ((list_sock) % (8 *
(int) sizeof (__fd_mask)))))
;
1650 FD_SET (wake_up_pipe[0], &fds_read)(((&fds_read)->__fds_bits)[((wake_up_pipe[0]) / (8 * (
int) sizeof (__fd_mask)))] |= ((__fd_mask) 1 << ((wake_up_pipe
[0]) % (8 * (int) sizeof (__fd_mask)))))
;
1651 add_clients_fds (&fds_read, &fds_write);
1652
1653 if (!server_quit)
1654 res = select (max_fd(list_sock)+1, &fds_read,
1655 &fds_write, NULL((void*)0), NULL((void*)0));
1656 else
1657 res = 0;
1658
1659 if (res == -1 && errno(*__errno_location ()) != EINTR4 && !server_quit) {
1660 logit ("select() failed: %s", strerror(errno))internal_logit ("server.c", 1660, __FUNCTION__, "select() failed: %s"
, strerror((*__errno_location ())))
;
1661 fatal ("select() failed");
1662 }
1663 else if (!server_quit && res >= 0) {
1664 if (FD_ISSET(list_sock, &fds_read)((((&fds_read)->__fds_bits)[((list_sock) / (8 * (int) sizeof
(__fd_mask)))] & ((__fd_mask) 1 << ((list_sock) % (
8 * (int) sizeof (__fd_mask))))) != 0)
) {
1665 int client_sock;
1666
1667 debug ("accept()ing connection...")internal_logit ("server.c", 1667, __FUNCTION__, "accept()ing connection..."
)
;
1668 client_sock = accept (list_sock,
1669 (struct sockaddr *)&client_name,
1670 &name_len);
1671
1672 if (client_sock == -1)
1673 fatal ("accept() failed: %s",
1674 strerror(errno(*__errno_location ())));
1675 logit ("Incoming connection")internal_logit ("server.c", 1675, __FUNCTION__, "Incoming connection"
)
;
1676 if (!add_client(client_sock))
1677 busy (client_sock);
1678 }
1679
1680 if (FD_ISSET(wake_up_pipe[0], &fds_read)((((&fds_read)->__fds_bits)[((wake_up_pipe[0]) / (8 * (
int) sizeof (__fd_mask)))] & ((__fd_mask) 1 << ((wake_up_pipe
[0]) % (8 * (int) sizeof (__fd_mask))))) != 0)
) {
1681 int w;
1682
1683 logit ("Got 'wake up'")internal_logit ("server.c", 1683, __FUNCTION__, "Got 'wake up'"
)
;
1684
1685 if (read(wake_up_pipe[0], &w, sizeof(w)) < 0)
1686 fatal ("Can't read wake up signal: %s",
1687 strerror(errno(*__errno_location ())));
1688 }
1689
1690 send_events (&fds_write);
1691 handle_clients (&fds_read);
1692 }
1693
1694 if (server_quit)
1695 logit ("Exiting...")internal_logit ("server.c", 1695, __FUNCTION__, "Exiting...");
1696
1697 } while (!end && !server_quit);
1698
1699 close_clients ();
1700 clients_cleanup ();
1701 close (list_sock);
1702 server_shutdown ();
1703}
1704
1705void set_info_bitrate (const int bitrate)
1706{
1707 sound_info.bitrate = bitrate;
1708 add_event_all (EV_BITRATE0x07, NULL((void*)0));
1709}
1710
1711void set_info_channels (const int channels)
1712{
1713 sound_info.channels = channels;
1714 add_event_all (EV_CHANNELS0x09, NULL((void*)0));
1715}
1716
1717void set_info_rate (const int rate)
1718{
1719 sound_info.rate = rate;
1720 add_event_all (EV_RATE0x08, NULL((void*)0));
1721}
1722
1723void set_info_avg_bitrate (const int avg_bitrate)
1724{
1725 sound_info.avg_bitrate = avg_bitrate;
1726 add_event_all (EV_AVG_BITRATE0x12, NULL((void*)0));
1727}
1728
1729/* Notify the client about change of the player state. */
1730void state_change ()
1731{
1732 add_event_all (EV_STATE0x01, NULL((void*)0));
1733}
1734
1735void ctime_change ()
1736{
1737 add_event_all (EV_CTIME0x02, NULL((void*)0));
1738}
1739
1740void tags_change ()
1741{
1742 add_event_all (EV_TAGS0x0e, NULL((void*)0));
1743}
1744
1745void status_msg (const char *msg)
1746{
1747 add_event_all (EV_STATUS_MSG0x0f, msg);
1748}
1749
1750void tags_response (const int client_id, const char *file,
1751 const struct file_tags *tags)
1752{
1753 assert (file != NULL)((file != ((void*)0)) ? (void) (0) : __assert_fail ("file != ((void*)0)"
, "server.c", 1753, __PRETTY_FUNCTION__))
;
1754 assert (tags != NULL)((tags != ((void*)0)) ? (void) (0) : __assert_fail ("tags != ((void*)0)"
, "server.c", 1754, __PRETTY_FUNCTION__))
;
1755 assert (client_id >= 0 && client_id < CLIENTS_MAX)((client_id >= 0 && client_id < 10) ? (void) (0
) : __assert_fail ("client_id >= 0 && client_id < 10"
, "server.c", 1755, __PRETTY_FUNCTION__))
;
1756
1757 if (clients[client_id].socket != -1) {
1758 struct tag_ev_response *data
1759 = (struct tag_ev_response *)xmalloc (
1760 sizeof(struct tag_ev_response));
1761
1762 data->file = xstrdup (file);
1763 data->tags = tags_dup (tags);
1764
1765 add_event (&clients[client_id], EV_FILE_TAGS0x11, data);
1766 wake_up_server ();
1767 }
1768}
1769
1770void ev_audio_start ()
1771{
1772 add_event_all (EV_AUDIO_START0x13, NULL((void*)0));
1773}
1774
1775void ev_audio_stop ()
1776{
1777 add_event_all (EV_AUDIO_STOP0x14, NULL((void*)0));
1778}
1779
1780/* Announce to clients that first file from the queue is being played
1781 * and therefore needs to be removed from it */
1782/* XXX: this function is called from player thread and add_event_all
1783 * imho doesn't properly lock all shared variables -- possible
1784 * race condition??? */
1785void server_queue_pop (const char *filename)
1786{
1787 debug ("Queue pop -- broadcasting EV_QUEUE_DEL")internal_logit ("server.c", 1787, __FUNCTION__, "Queue pop -- broadcasting EV_QUEUE_DEL"
)
;
1788 add_event_all (EV_QUEUE_DEL0x55, filename);
1789}