aps.c (6170B)
1 /* 2 * Copyright 2021-2023 Jacob R. Edwards 3 * 4 * ap -- audio player 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <https://www.gnu.org/licenses/>. 18 */ 19 20 #include <sys/socket.h> 21 #include <sys/stat.h> 22 23 #include <ctype.h> 24 #include <errno.h> 25 #include <limits.h> 26 #include <poll.h> 27 #include <regex.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <unistd.h> 31 32 #include "aps.h" 33 #include "arg.h" 34 #include "buf.h" 35 #include "bug.h" 36 #include "command.h" 37 #include "find.h" 38 #include "log.h" 39 #include "queue.h" 40 #include "split.h" 41 #include "util.h" 42 43 struct aps * 44 aps_open(char *path, char **player) 45 { 46 int i; 47 struct aps *aps; 48 49 aps = calloc(1, sizeof(*aps)); 50 if (aps == NULL) 51 return NULL; 52 53 for (i = 0; i < LEN(aps->pfds); ++i) 54 aps->pfds[i].fd = -1; 55 56 aps->player = pnew(player); 57 if (aps->player == NULL) { 58 aps_close(aps); 59 return NULL; 60 } 61 62 aps->con = apopen(path, bind, SOCK_NONBLOCK); 63 if (aps->con == NULL || listen(aps->con->sock, 10)) { 64 aps_close(aps); 65 return NULL; 66 } 67 aps->pfds[aps->con->sock].fd = aps->con->sock; 68 aps->pfds[aps->con->sock].events = POLLIN; 69 70 aps->timeout = INFTIM; 71 72 return aps; 73 } 74 75 void 76 aps_close(struct aps *aps) 77 { 78 int i; 79 80 if (aps == NULL) 81 return; 82 83 while (aps->queue) 84 queue_remove(aps, aps->queue); 85 pfree(aps->player); 86 87 for (i = 0; i < LEN(aps->clients); ++i) 88 if (aps->clients[i].request) 89 aps_drop(aps, i); 90 apclose(aps->con); 91 92 free(aps); 93 } 94 95 int 96 aps_drop(struct aps *aps, int fd) 97 { 98 aps_log(aps, fd, INFO, logsubjects[LogConn], "dropping client"); 99 --aps->nfds; 100 aps->pfds[fd].fd = -1; 101 buffree(aps->clients[fd].response); 102 aps->clients[fd].response = NULL; 103 buffree(aps->clients[fd].request); 104 aps->clients[fd].request = NULL; 105 return sclose(fd); 106 } 107 108 int 109 aps_addfd(struct aps *aps, int fd) 110 { 111 if ((aps->clients[fd].request = bufnew()) == NULL) 112 return 1; 113 if ((aps->clients[fd].response = bufnew()) == NULL) { 114 buffree(aps->clients[fd].request); 115 return 1; 116 } 117 118 ++aps->nfds; 119 aps->pfds[fd].fd = fd; 120 aps->pfds[fd].events = POLLIN; 121 return 0; 122 } 123 124 int 125 aps_accept(struct aps *aps) 126 { 127 int s; 128 129 while ((s = accept4(aps->con->sock, NULL, NULL, 0)) >= 0) { 130 if (aps_addfd(aps, s)) 131 aps_log(aps, s, ERROR, logsubjects[LogConn], "unable to add client"); 132 else 133 aps_log(aps, s, INFO, logsubjects[LogConn], "client added"); 134 } 135 136 return errno != EWOULDBLOCK; 137 } 138 139 int 140 aps_respond(struct aps *aps, int fd) 141 { 142 ssize_t n; 143 struct buf *buf; 144 145 buf = aps->clients[fd].response; 146 n = send(fd, buf->data, buf->len, MSG_NOSIGNAL); 147 switch (n) { 148 case 0: 149 errno = ECONNRESET; 150 /* no break */ 151 case -1: 152 return 1; 153 default: 154 if ((buf->len - n) == 0) { 155 buf->len = 0; 156 aps->pfds[fd].events = POLLIN; 157 } else { 158 bufshift(buf, n); 159 } 160 return 0; 161 } 162 } 163 164 int 165 aps_handle(struct aps *aps, int fd) 166 { 167 if (aps->pfds[fd].revents & (POLLERR | POLLHUP | POLLNVAL)) { 168 return 1; 169 } else if (aps->pfds[fd].revents & POLLIN) { 170 if (aps_command(aps, fd)) 171 return 1; 172 } else if (aps->pfds[fd].revents & POLLOUT) { 173 if (aps_respond(aps, fd)) 174 return 1; 175 } else { 176 bug("impossible poll event"); 177 } 178 179 return 0; 180 } 181 182 int 183 aps_named(struct aps *aps) 184 { 185 struct stat sb; 186 187 return !stat(aps->con->path, &sb); 188 } 189 190 int 191 aps_update(struct aps *aps) 192 { 193 int i; 194 int re; 195 196 if ((re = poll(aps->pfds, LEN(aps->pfds), aps->timeout)) <= 0) 197 return re; 198 199 if (aps->pfds[aps->con->sock].revents) { 200 if ((aps->pfds[aps->con->sock].revents & POLLIN) && aps_accept(aps)) 201 return 1; 202 aps->pfds[aps->con->sock].revents = 0; 203 --re; 204 } 205 206 for (i = 0; re > 0 && i < LEN(aps->pfds); ++i) { 207 if (aps->pfds[i].revents) { 208 if (aps_handle(aps, i)) 209 aps_drop(aps, i); 210 --re; 211 } 212 } 213 214 if (!aps_named(aps) && !aps->nfds) 215 aps->close = 1; 216 217 return 0; 218 } 219 220 int 221 aps_read(struct aps *aps, int fd, char **command) 222 { 223 ssize_t len; 224 225 len = bufread(aps->clients[fd].request, fd, 4096); 226 if (len <= 0) 227 return -1; 228 return bufgetline(aps->clients[fd].request, command) < 0; 229 } 230 231 int 232 aps_command(struct aps *aps, int fd) 233 { 234 char *(*com)(struct aps *, int, int, char **); 235 char *buf, **argv; 236 char *status; 237 unsigned int i; 238 239 buf = NULL; 240 if (aps_read(aps, fd, &buf)) 241 return -1; 242 if (buf == NULL) 243 return 0; 244 245 aps_log(aps, fd, DEBUG, logsubjects[LogCommand], "raw '%s'", buf); 246 247 argv = split(buf, NULL); 248 if (argv == NULL) { 249 status = "Unable to split arguments"; 250 goto exit; 251 } 252 if (*argv == NULL) { 253 status = "No command"; 254 goto exit; 255 } 256 257 aps_log(aps, fd, INFO, logsubjects[LogCommand], "running '%s' command", *argv); 258 259 for (com = NULL, i = 0; com == NULL && i < aps->ncoms; ++i) 260 if (strcmp(*argv, aps->coms[i].name) == 0) 261 com = aps->coms[i].func; 262 263 if (com == NULL) 264 status = "Command not found"; 265 else 266 status = com(aps, fd, arglen(argv + 1), argv + 1); 267 268 exit: 269 free(argv); 270 free(buf); 271 return aps_bufstatus(aps, fd, status); 272 } 273 274 void 275 aps_errordrop(struct aps *aps, int fd, char *why) 276 { 277 /* One could send(2) the error aswell. */ 278 aps_log(aps, fd, ERROR, logsubjects[LogConn], why); 279 aps_drop(aps, fd); 280 } 281 282 char * 283 aps_seek(struct aps *aps, char *pattern) 284 { 285 char *err; 286 struct item *item; 287 struct search search; 288 289 if (!aps->queue) 290 return "Empty queue"; 291 292 if ((err = prepsearch(&search, aps->queue, pattern))) 293 return err; 294 295 item = findnext(&search); 296 if (item == aps->queue) 297 item = findnext(&search); 298 stopsearch(&search); 299 300 if (item == NULL) 301 return "No match"; 302 queue_set(aps, item); 303 return NULL; 304 } 305 306 int 307 aps_play(struct aps *aps, struct item *item) 308 { 309 queue_set(aps, item); 310 return pplay(aps->player, item->path); 311 } 312 313 int 314 aps_unname(struct aps *aps) 315 { 316 if (unlink(aps->con->path) == 0) 317 return 0; 318 aps_log(aps, 0, WARN, NULL, "%s: unable to remove socket", aps->con->path); 319 return 1; 320 }