INSTALL: Add two links to related information.
[paraslash.git] / server.c
1 /*
2  * Copyright (C) 1997-2007 Andre Noll <maan@systemlinux.org>
3  *
4  * Licensed under the GPL v2. For licencing details see COPYING.
5  */
6
7 /** \file server.c Paraslash's main server. */
8
9
10 /** \mainpage Paraslash API Reference
11  *
12  * Starting points for getting an overview are
13  *
14  * probably:
15  *
16  *      - The main programs: \ref server.c, \ref audiod.c, \ref client.c,
17  *        \ref audioc.c, \ref fsck.c,
18  *      - Server: \ref server_command, \ref sender,
19  *      - Audio file selector: \ref audio_format_handler, \ref mood, \ref afs_table,
20  *      - Client: \ref receiver, \ref receiver_node, \ref filter, \ref filter_node.
21  *
22  *
23  * The gory details, listed by topic:
24  *
25  *      - Audio format handlers: \ref mp3_afh.c, \ref ogg_afh.c \ref aac_afh.c
26  *      - Decoders: \ref mp3dec.c, \ref \ref oggdec.c, \ref aacdec.c
27  *      - Volume normalizer: \ref compress.c
28  *      - Output: \ref alsa_write.c, \ref osx_write.c
29  *      - http: \ref http_recv.c, \ref http_send.c
30  *      - ortp: \ref ortp_recv.c, \ref ortp_send.c
31  *      - dccp: \ref dccp_recv.c, \ref dccp_send.c
32  *      - Audio file selector: \ref afs.c, \ref aft.c, \ref mood.c
33  *      - Afs structures: \ref afs_table, \ref audio_file_data,
34  *        \ref afs_info \ref audio_format_info,
35  *      - Afs tables: \ref aft.c, \ref mood.c, \ref playlist.c,
36  *        \ref attribute.c, \ref score.c.
37  *
38  * Lower levels:
39  *
40  *      - Scheduling: \ref sched.c, \ref sched.h,
41  *      - Networking: \ref net.c,
42  *      - File descriptors: \ref fd.c,
43  *      - Signals: \ref signal.c,
44  *      - Daemons: \ref daemon.c,
45  *      - Strings: \ref string.c, \ref string.h,
46  *      - Time: \ref time.c,
47  *      - Spawning processes: \ref exec.c
48  *      - Inter process communication: \ref ipc.c,
49  *      - The object storage layer: \ref osl.c,
50  *      - Blob tables: \ref blob.c,
51  *      - Queueing chunks of audio data: \ref chunk_queue.c,
52  *      - The error subssystem: \ref error.h.
53  *
54  * Lov-level data structures:
55  *
56  *      - Doubly linked lists: \ref list.h,
57  *      - Red-black trees: \ref rbtree.h, \ref rbtree.c,
58  *      - Ring buffer: \ref ringbuffer.c, \ref ringbuffer.h,
59  *      - Hashing: \ref hash.h, \ref sha1.h, \ref sha1.c,
60  *      - Crypto: \ref crypt.c.
61  *
62  */
63
64 #include <signal.h>
65 #include <sys/types.h>
66 #include <dirent.h>
67
68 #include "para.h"
69 #include "error.h"
70 #include "server.cmdline.h"
71 #include "afh.h"
72 #include "string.h"
73 #include "afs.h"
74 #include "server.h"
75 #include "vss.h"
76 #include "config.h"
77 #include "close_on_fork.h"
78 #include "send.h"
79 #include "net.h"
80 #include "daemon.h"
81 #include "ipc.h"
82 #include "fd.h"
83 #include "list.h"
84 #include "sched.h"
85 #include "signal.h"
86 #include "user_list.h"
87
88 /** define the array of error lists needed by para_server */
89 INIT_SERVER_ERRLISTS;
90
91 /** shut down non-authorized connections after that many seconds */
92 #define ALARM_TIMEOUT 10
93
94 /**
95  * Pointer to shared memory area for communication between para_server
96  * and its children. Exported to vss.c. command.c and to afs.
97  */
98 struct misc_meta_data *mmd;
99
100 /**
101  * the configuration of para_server
102  *
103  * It also contains the options for the audio file selector, audio format
104  * handler and all supported senders.
105  */
106 struct server_args_info conf;
107
108 /** the file containing user information (public key, permissions) */
109 char *user_list_file = NULL;
110
111 extern void dccp_send_init(struct sender *);
112 extern void http_send_init(struct sender *);
113 extern void ortp_send_init(struct sender *);
114
115 /** the list of supported senders */
116 struct sender senders[] = {
117         {
118                 .name = "http",
119                 .init = http_send_init,
120         },
121         {
122                 .name = "dccp",
123                 .init = dccp_send_init,
124         },
125 #ifdef HAVE_ORTP
126         {
127                 .name = "ortp",
128                 .init = ortp_send_init,
129         },
130 #endif
131         {
132                 .name = NULL,
133         }
134 };
135
136
137 /* global variables for server-internal use */
138 static FILE *logfile;
139 static int mmd_mutex, mmd_shm_id;
140 static int signal_pipe;
141
142 /**
143  * para_server's log function
144  *
145  * \param ll the log level
146  * \param fmt the format string describing the log message
147  */
148 void para_log(int ll, const char* fmt,...)
149 {
150         va_list argp;
151         FILE *outfd;
152         struct tm *tm;
153         time_t t1;
154         char str[MAXLINE] = "";
155         pid_t mypid;
156
157         if (ll < conf.loglevel_arg)
158                 return;
159         outfd = logfile? logfile : stderr;
160         time(&t1);
161         tm = localtime(&t1);
162         strftime(str, MAXLINE, "%b %d %H:%M:%S", tm);
163         fprintf(outfd, "%s ", str);
164         if (conf.loglevel_arg <= INFO)
165                 fprintf(outfd, "%i: ", ll);
166         mypid = getpid();
167         if (conf.loglevel_arg <= INFO)
168                 fprintf(outfd, "(%d) ", mypid);
169         va_start(argp, fmt);
170         vfprintf(outfd, fmt, argp);
171         va_end(argp);
172 }
173
174 /*
175  * setup shared memory area and get mutex for locking
176  */
177 static void shm_init(void)
178 {
179         void *shm;
180         int ret = shm_new(sizeof(struct misc_meta_data));
181
182         if (ret < 0)
183                 goto err_out;
184
185         ret = shm_attach(ret, ATTACH_RW, &shm);
186         if (ret < 0)
187                 goto err_out;
188         mmd = shm;
189         mmd_shm_id = ret;
190
191         ret = mutex_new();
192         if (ret < 0)
193                 goto err_out;
194         mmd_mutex = ret;
195
196         mmd->num_played = 0;
197         mmd->num_commands = 0;
198         mmd->events = 0;
199         mmd->num_connects = 0;
200         mmd->active_connections = 0;
201         strcpy(mmd->afd.path, "(none)");
202         mmd->vss_status_flags = VSS_NEXT;
203         mmd->new_vss_status_flags = VSS_NEXT;
204         mmd->sender_cmd_data.cmd_num = -1;
205         return;
206 err_out:
207         PARA_EMERG_LOG("%s", PARA_STRERROR(-ret));
208         exit(EXIT_FAILURE);
209 }
210
211 /**
212  * lock the shared memory area containing the mmd struct
213  *
214  * \sa semop(2), struct misc_meta_data.
215  */
216 void mmd_lock(void)
217 {
218         mutex_lock(mmd_mutex);
219 }
220
221 /**
222  * unlock the shared memory area containing the mmd struct
223  *
224  * \sa semop(2), struct misc_meta_data
225  */
226
227 void mmd_unlock(void)
228 {
229         mutex_unlock(mmd_mutex);
230 }
231
232 static void parse_config(int override)
233 {
234         char *home = para_homedir();
235         struct stat statbuf;
236         int ret;
237         char *cf;
238
239         if (conf.config_file_given)
240                 cf = para_strdup(conf.config_file_arg);
241         else
242                 cf = make_message("%s/.paraslash/server.conf", home);
243         free(user_list_file);
244         if (!conf.user_list_given)
245                 user_list_file = make_message("%s/.paraslash/server.users", home);
246         else
247                 user_list_file = para_strdup(conf.user_list_arg);
248         ret = stat(cf, &statbuf);
249         if (ret && conf.config_file_given) {
250                 ret = -1;
251                 PARA_EMERG_LOG("can not stat config file %s\n", cf);
252                 goto out;
253         }
254         if (!ret) {
255                 int tmp = conf.daemon_given;
256                 struct server_cmdline_parser_params params = {
257                         .override = override,
258                         .initialize = 0,
259                         .check_required = 0,
260                         .check_ambiguity = 0
261                 };
262                 server_cmdline_parser_config_file(cf, &conf, &params);
263                 conf.daemon_given = tmp;
264         }
265         /* logfile */
266         if (!conf.logfile_given && conf.daemon_given) {
267                 ret = -1;
268                 PARA_EMERG_LOG("%s", "daemon, but no log file\n");
269                 goto out;
270         }
271         if (conf.logfile_given)
272                 logfile = open_log(conf.logfile_arg);
273         ret = 1;
274 out:
275         free(cf);
276         free(home);
277         if (ret > 0)
278                 return;
279         free(user_list_file);
280         user_list_file = NULL;
281         exit(EXIT_FAILURE);
282 }
283
284 static void setup_signal_handling(void)
285 {
286         int ret = 0;
287
288         signal_pipe = para_signal_init();
289         PARA_NOTICE_LOG("%s", "setting up signal handlers\n");
290         ret += para_install_sighandler(SIGINT);
291         ret += para_install_sighandler(SIGTERM);
292         ret += para_install_sighandler(SIGHUP);
293         ret += para_install_sighandler(SIGCHLD);
294         ret += para_install_sighandler(SIGUSR1);
295         signal(SIGPIPE, SIG_IGN);
296         if (ret != 5) {
297                 PARA_EMERG_LOG("%s", "could not install signal handlers\n");
298                 exit(EXIT_FAILURE);
299         }
300 }
301
302 static unsigned init_network(void)
303 {
304         int fd, ret = init_tcp_socket(conf.port_arg);
305
306         if (ret < 0)
307                 goto err;
308         fd = ret;
309         ret = mark_fd_nonblock(fd);
310         if (ret < 0)
311                 goto err;
312         return fd;
313 err:
314         PARA_EMERG_LOG("%s\n", PARA_STRERROR(-ret));
315         exit(EXIT_FAILURE);
316 }
317
318 static void init_random_seed(void)
319 {
320         int fd, ret = -1;
321         unsigned int seed;
322         size_t len = sizeof(unsigned int);
323
324         fd = open("/dev/urandom", O_RDONLY);
325         if (fd < 0)
326                 goto out;
327         ret = -2;
328         if (read(fd, &seed, len) != len)
329                 goto out;
330         srandom(seed);
331         ret = 1;
332 out:
333         if (fd >= 0)
334                 close(fd);
335         if (ret > 0)
336                 return;
337         PARA_EMERG_LOG("can not seed pseudo random generator (ret = %d)\n",
338                 ret);
339         exit(EXIT_FAILURE);
340 }
341
342 uint32_t afs_socket_cookie;
343 int afs_socket;
344 static pid_t afs_pid;
345
346 static void init_afs(void)
347 {
348         int ret, afs_server_socket[2];
349
350         ret = socketpair(PF_UNIX, SOCK_DGRAM, 0, afs_server_socket);
351         if (ret < 0)
352                 exit(EXIT_FAILURE);
353         afs_socket_cookie = para_random((uint32_t)-1);
354         afs_pid = fork();
355         if (afs_pid < 0)
356                 exit(EXIT_FAILURE);
357         if (!afs_pid) { /* child (afs) */
358                 close(afs_server_socket[0]);
359                 afs_init(afs_socket_cookie, afs_server_socket[1]);
360         }
361         close(afs_server_socket[1]);
362         afs_socket = afs_server_socket[0];
363         ret = mark_fd_nonblock(afs_socket);
364         if (ret < 0)
365                 exit(EXIT_FAILURE);
366         add_close_on_fork_list(afs_socket);
367         PARA_INFO_LOG("afs_socket: %d, afs_socket_cookie: %u\n", afs_socket,
368                 (unsigned) afs_socket_cookie);
369 }
370
371
372 static unsigned do_inits(int argc, char **argv)
373 {
374         /* connector's address information */
375         int sockfd;
376
377         init_random_seed();
378         /* parse command line options */
379         server_cmdline_parser(argc, argv, &conf);
380         HANDLE_VERSION_FLAG("server", conf);
381         para_drop_privileges(conf.user_arg, conf.group_arg);
382         /* parse config file, open log and set defaults */
383         parse_config(0);
384         log_welcome("para_server", conf.loglevel_arg);
385         shm_init(); /* init mmd struct */
386         server_uptime(UPTIME_SET); /* reset server uptime */
387         init_user_list(user_list_file);
388         /* become daemon */
389         if (conf.daemon_given)
390                 daemon_init();
391         PARA_NOTICE_LOG("%s", "initializing virtual streaming system\n");
392         afh_init();
393         vss_init();
394         mmd->server_pid = getpid();
395         setup_signal_handling();
396         init_afs();
397         mmd_lock();
398         /* init network socket */
399         PARA_NOTICE_LOG("%s", "initializing tcp command socket\n");
400         sockfd = init_network();
401         PARA_NOTICE_LOG("%s", "init complete\n");
402         return sockfd;
403 }
404
405 /*
406  * called when server gets SIGHUP or when client invokes hup command.
407  */
408 static void handle_sighup(void)
409 {
410         PARA_NOTICE_LOG("%s", "SIGHUP\n");
411         close_log(logfile); /* gets reopened if necessary by parse_config */
412         logfile = NULL;
413         parse_config(1); /* reopens log */
414         init_user_list(user_list_file); /* reload user list */
415         if (afs_pid)
416                 kill(afs_pid, SIGHUP);
417 }
418
419 static void status_refresh(void)
420 {
421         static int prev_uptime = -1, prev_events = -1;
422         int uptime = server_uptime(UPTIME_GET), ret = 1;
423
424         if (prev_events != mmd->events)
425                 goto out;
426         if (mmd->new_vss_status_flags != mmd->vss_status_flags)
427                 goto out;
428         if (uptime / 60 != prev_uptime / 60)
429                 goto out;
430         ret = 0;
431 out:
432         prev_uptime = uptime;
433         prev_events = mmd->events;
434         mmd->vss_status_flags = mmd->new_vss_status_flags;
435         if (ret) {
436                 PARA_DEBUG_LOG("%d events, forcing status update\n",
437                         mmd->events);
438                 killpg(0, SIGUSR1);
439         }
440 }
441
442 /**
443  * the main function of para_server
444  *
445  * \param argc usual argument count
446  * \param argv usual argument vector
447  *
448  * \return EXIT_SUCCESS or EXIT_FAILURE
449  *
450  */
451 int main(int argc, char *argv[])
452 {
453         /* listen on sock_fd, new connection on new_fd */
454         int sockfd, new_fd;
455         struct sockaddr_in their_addr;
456         int i, max_fileno, ret;
457         pid_t chld_pid;
458         fd_set rfds, wfds;
459         struct timeval *timeout;
460
461         valid_fd_012();
462         sockfd = do_inits(argc, argv);
463 repeat:
464         FD_ZERO(&rfds);
465         FD_ZERO(&wfds);
466         max_fileno = -1;
467         /* check socket and signal pipe in any case */
468         para_fd_set(sockfd, &rfds, &max_fileno);
469         para_fd_set(signal_pipe, &rfds, &max_fileno);
470         timeout = vss_preselect(&rfds, &wfds, &max_fileno);
471         status_refresh();
472         for (i = 0; senders[i].name; i++) {
473                 if (senders[i].status != SENDER_ON)
474                         continue;
475                 if (!senders[i].pre_select)
476                         continue;
477                 senders[i].pre_select(&max_fileno, &rfds, &wfds);
478         }
479         mmd_unlock();
480         ret = para_select(max_fileno + 1, &rfds, &wfds, timeout);
481         mmd_lock();
482         vss_post_select(&rfds, &wfds);
483         if (ret < 0)
484                 goto repeat;
485         for (i = 0; senders[i].name; i++) {
486                 if (senders[i].status != SENDER_ON)
487                         continue;
488                 if (!senders[i].post_select)
489                         continue;
490                 senders[i].post_select(&rfds, &wfds);
491         }
492         vss_send_chunk();
493         status_refresh();
494         if (FD_ISSET(signal_pipe, &rfds)) {
495                 int sig;
496                 pid_t pid;
497                 sig = para_next_signal();
498                 switch (sig) {
499                 case SIGHUP:
500                         handle_sighup();
501                         break;
502                 case SIGCHLD:
503                         for (;;) {
504                                 ret = para_reap_child(&pid);
505                                 if (ret <= 0)
506                                         break;
507                                 if (pid != afs_pid)
508                                         continue;
509                                 PARA_EMERG_LOG("fatal: afs died\n");
510                                 goto genocide;
511                         }
512                         break;
513                 /* die on sigint/sigterm. Kill all children too. */
514                 case SIGINT:
515                 case SIGTERM:
516                         PARA_EMERG_LOG("terminating on signal %d\n", sig);
517 genocide:
518                         kill(0, SIGTERM);
519                         mutex_destroy(mmd_mutex);
520                         shm_detach(mmd);
521                         shm_destroy(mmd_shm_id);
522
523                         exit(EXIT_FAILURE);
524                 }
525         }
526         if (mmd->sender_cmd_data.cmd_num >= 0) {
527                 int num = mmd->sender_cmd_data.cmd_num,
528                         s = mmd->sender_cmd_data.sender_num;
529
530                 if (senders[s].client_cmds[num])
531                         senders[s].client_cmds[num](&mmd->sender_cmd_data);
532                 mmd->sender_cmd_data.cmd_num = -1;
533         }
534         if (!FD_ISSET(sockfd, &rfds))
535                 goto repeat;
536
537         new_fd = para_accept(sockfd, &their_addr, sizeof(struct sockaddr_in));
538         if (new_fd < 0)
539                 goto repeat;
540         PARA_INFO_LOG("got connection from %s, forking\n",
541                 inet_ntoa(their_addr.sin_addr));
542         mmd->num_connects++;
543         mmd->active_connections++;
544         random();
545         chld_pid = fork();
546         if (chld_pid < 0) {
547                 PARA_CRIT_LOG("%s", "fork failed\n");
548                 goto repeat;
549         }
550         if (chld_pid) {
551                 close(new_fd);
552                 /* parent keeps accepting connections */
553                 goto repeat;
554         }
555         alarm(ALARM_TIMEOUT);
556         close_listed_fds();
557         close(sockfd); /* child doesn't need the listener */
558         /*
559          * put info on who we are serving into argv[0] to make
560          * client ip visible in top/ps
561          */
562         for (i = argc - 1; i >= 0; i--)
563                 memset(argv[i], 0, strlen(argv[i]));
564         sprintf(argv[0], "para_server (serving %s)",
565                 inet_ntoa(their_addr.sin_addr));
566         return handle_connect(new_fd, &their_addr);
567 }