sad.c (3296B)
1 #include <sys/select.h> 2 #include <sys/socket.h> 3 #include <sys/types.h> 4 #include <sys/un.h> 5 6 #include <err.h> 7 #include <errno.h> 8 #include <fcntl.h> 9 #include <limits.h> 10 #include <signal.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <string.h> 14 #include <unistd.h> 15 16 #include "arg.h" 17 #include "sad.h" 18 19 fd_set master; 20 fd_set rfds; 21 int fdmax; 22 char *argv0; 23 24 static int listenfd = -1; 25 static volatile sig_atomic_t isrunning = 1; 26 static char *socketpath = "/tmp/sad-sock"; 27 28 static int servlisten(const char *name) { 29 struct sockaddr_un sun; 30 int fd, r; 31 socklen_t len; 32 33 fd = socket(AF_UNIX, SOCK_STREAM, 0); 34 if (fd < 0) 35 err(1, "socket"); 36 37 unlink(name); 38 39 memset(&sun, 0, sizeof(sun)); 40 sun.sun_family = AF_UNIX; 41 strlcpy(sun.sun_path, name, sizeof(sun.sun_path)); 42 43 len = sizeof(sun); 44 r = bind(fd, (struct sockaddr *)&sun, len); 45 if (r < 0) 46 err(1, "bind"); 47 48 r = listen(fd, 5); 49 if (r < 0) 50 err(1, "listen"); 51 52 return fd; 53 } 54 55 static int servaccept(int listenfd) { 56 struct sockaddr_un sun; 57 int clifd; 58 socklen_t len; 59 60 len = sizeof(sun); 61 clifd = accept(listenfd, (struct sockaddr *)&sun, &len); 62 if (clifd < 0) 63 err(1, "accept"); 64 return clifd; 65 } 66 67 static void playaudio(void) { 68 Song *s; 69 unsigned char buf[4096]; 70 int nbytes; 71 72 s = getcursong(); 73 if (!s) 74 return; 75 76 switch (s->state) { 77 case PREPARE: 78 if (s->decoder->open(&s->fmt, s->path) < 0) { 79 s->state = NONE; 80 return; 81 } 82 s->state = PLAYING; 83 break; 84 case PLAYING: 85 if ((nbytes = s->decoder->decode(buf, sizeof(buf))) <= 0) { 86 playsong(picknextsong()); 87 notify(EVSONGFINISHED); 88 } else { 89 playoutputs(&s->fmt, buf, nbytes); 90 } 91 break; 92 } 93 } 94 95 static void sighandler(int signum) { 96 if (signum == SIGINT || signum == SIGTERM) 97 isrunning = 0; 98 } 99 100 static void usage(void) { 101 fprintf(stderr, "usage: %s [-f sock]\n", argv0); 102 exit(1); 103 } 104 105 int main(int argc, char *argv[]) { 106 struct sigaction sa; 107 struct timeval tv; 108 int clifd, n, i; 109 110 ARGBEGIN { 111 case 'f': 112 socketpath = EARGF(usage()); 113 break; 114 default: 115 usage(); 116 } 117 ARGEND; 118 119 memset(&sa, 0, sizeof(sa)); 120 sa.sa_flags = SA_RESTART; 121 sa.sa_handler = sighandler; 122 sigaction(SIGTERM, &sa, NULL); 123 sigaction(SIGINT, &sa, NULL); 124 125 FD_ZERO(&master); 126 FD_ZERO(&rfds); 127 128 listenfd = servlisten(socketpath); 129 FD_SET(listenfd, &master); 130 fdmax = listenfd; 131 132 initoutputs(); 133 openoutputs(); 134 initnotifier(); 135 136 playlistmode(REPEAT); 137 138 while (isrunning) { 139 rfds = master; 140 tv.tv_sec = 0; 141 tv.tv_usec = 10000; 142 n = select(fdmax + 1, &rfds, NULL, NULL, &tv); 143 if (n < 0) { 144 if (errno == EINTR) 145 goto fini; 146 err(1, "select"); 147 } 148 149 playaudio(); 150 151 for (i = 0; i <= fdmax; i++) { 152 if (!FD_ISSET(i, &rfds)) 153 continue; 154 if (i == listenfd) { 155 clifd = servaccept(listenfd); 156 FD_SET(clifd, &master); 157 if (clifd > fdmax) 158 fdmax = clifd; 159 } else { 160 if (docmd(i) < 0) { 161 close(i); 162 FD_CLR(i, &master); 163 removesubscriber(i); 164 } 165 } 166 } 167 } 168 fini: 169 for (i = 0; i <= fdmax; i++) { 170 if (FD_ISSET(i, &master)) { 171 close(i); 172 FD_CLR(i, &master); 173 removesubscriber(i); 174 } 175 } 176 if (listenfd != -1) 177 unlink(socketpath); 178 return 0; 179 }