ap

An audio player suited to my tastes
Log | Files | Refs | README | LICENSE

commit b149d26ec695922c2a2f0606e15df7377ce6642d
parent 08349a15e62f64514098e77be9109de3edb4ef87
Author: Jacob R. Edwards <jacobouno@protonmail.com>
Date:   Tue, 29 Jun 2021 19:26:10 -0700

Organize into subdirectories

Diffstat:
Dap.h | 4----
Dapc.c | 169-------------------------------------------------------------------------------
Aapc/apc | 0
Aapc/apc.c | 168+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aapc/mkfile | 16++++++++++++++++
Dapcon.c | 65-----------------------------------------------------------------
Daps.c | 218-------------------------------------------------------------------------------
Aaps/aps | 0
Aaps/aps.c | 217+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Raps.h -> aps/aps.h | 0
Aaps/command.c | 360+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rcommand.h -> aps/command.h | 0
Aaps/mkfile | 16++++++++++++++++
Rplayer.c -> aps/player.c | 0
Rplayer.h -> aps/player.h | 0
Rqueue.c -> aps/queue.c | 0
Rqueue.h -> aps/queue.h | 0
Aaps/response.c | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rresponse.h -> aps/response.h | 0
Rutil.c -> aps/util.c | 0
Rutil.h -> aps/util.h | 0
Dcommand.c | 360-------------------------------------------------------------------------------
Dconfig.def.h | 11-----------
Alib/ap.h | 6++++++
Alib/apcon.c | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rapcon.h -> lib/apcon.h | 0
Alib/libap.a | 0
Alib/mkfile | 12++++++++++++
Rsock.c -> lib/sock.c | 0
Rsock.h -> lib/sock.h | 0
Amk/clean.mk | 4++++
Amk/config.mk | 12++++++++++++
Amk/lib.mk | 4++++
Amk/obj.mk | 4++++
Amk/prog.mk | 12++++++++++++
Mmkfile | 40+++++-----------------------------------
Dresponse.c | 117-------------------------------------------------------------------------------
37 files changed, 1017 insertions(+), 979 deletions(-)

diff --git a/ap.h b/ap.h @@ -1,4 +0,0 @@ -#define AP_LINE_MAX (PATH_MAX * 2) -#define AP_ARGV_MAX 128 - -static char *argseps = "\t"; diff --git a/apc.c b/apc.c @@ -1,169 +0,0 @@ -/* Copyright 2021 Jacob R. Edwards - * - * ap -- audio player - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - */ - -#include <sys/socket.h> - -#include <errno.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "ap.h" -#include "apcon.h" - -void -die(char *s) -{ - perror(s); - exit(1); -} - -int -apc_send(struct apcon *c, char **argv) -{ - char buf[AP_LINE_MAX]; - int i; - int len; - int tmp; - - len = 0; - for (i = 0; argv[i] != NULL; ++i) { - tmp = strlen(argv[i]); - if (len + tmp + 1 > sizeof(buf)) { - errno = ENOBUFS; - return 1; - } - memcpy(buf + len, argv[i], tmp); - len += tmp; - buf[len++] = *argseps; - } - buf[len - 1] = '\n'; - - return send(c->s, buf, len, 0) != len; -} - -int -dupstatus(char **bufp, char *responce) -{ - if (*bufp) - *bufp = NULL; - - if (strcmp(responce, "ok") == 0) - return 0; - if (strncmp(responce, "error: ", 7) == 0) { - if (bufp) - return (*bufp = strdup(responce + 7)) == NULL; - return 0; - } - - errno = EBADMSG; - return 1; -} - -int -apc_recv(struct apcon *c, char **err, int (*item)(char *)) -{ - char *end; - char buf[AP_LINE_MAX]; - int error; - int len; - int tmp; - - error = 0; - len = 0; - - while ((tmp = recv(c->s, buf + len, sizeof(buf) - len, 0)) > 0) { - len += tmp; - while ((end = memchr(buf, '\n', len))) { - *end = 0; - if (dupstatus(err, buf) == 0) - return error; - else if (errno != EBADMSG) - return 1; - if (!error) - error = item(buf); - len -= end - buf + 1; - memmove(buf, end + 1, len); - } - } - - if (tmp == 0) - errno = ECONNRESET; - return 1; -} - -int -apc_run(struct apcon *con, char **err, int (*item)(char *), char **argv) -{ - if (*err) - *err = NULL; - if (apc_send(con, argv) || apc_recv(con, err, item)) - return 1; - return 0; -} - -int -print(char *item) -{ - return puts(item) < 0; -} - -int -main(int argc, char **argv) -{ - char *p; - int i; - char buf[AP_LINE_MAX]; - struct apcon con; - int sub; - -#ifdef __OpenBSD__ - if (pledge("stdio rpath unix", NULL)) - die("pledge"); -#endif - - if (argc <= 1) - die("no command"); - - if (apcon_open(&con, NULL, connect, 0)) - die("unable to open connection"); - - sub = 0; - for (i = 1; !sub && i < argc; ++i) - if (strcmp(argv[i], "-") == 0) - sub = i; - if (!sub) { - if (apc_run(&con, &p, print, argv + 1) || p) - die(p); - } else { - while (fgets(buf, sizeof(buf), stdin) != NULL) { - if ((p = strchr(buf, '\n')) == NULL) - die("message too long"); - *p = 0; - - argv[sub] = buf; - if (apc_run(&con, &p, print, argv + 1) || p) - die(p); - } - } - - apcon_close(&con); - return 0; -} diff --git a/apc/apc b/apc/apc Binary files differ. diff --git a/apc/apc.c b/apc/apc.c @@ -0,0 +1,168 @@ +/* Copyright 2021 Jacob R. Edwards + * + * ap -- audio player + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <sys/socket.h> + +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <ap.h> + +void +die(char *s) +{ + perror(s); + exit(1); +} + +int +apc_send(struct apcon *c, char **argv) +{ + char buf[AP_LINE_MAX]; + int i; + int len; + int tmp; + + len = 0; + for (i = 0; argv[i] != NULL; ++i) { + tmp = strlen(argv[i]); + if (len + tmp + 1 > sizeof(buf)) { + errno = ENOBUFS; + return 1; + } + memcpy(buf + len, argv[i], tmp); + len += tmp; + buf[len++] = *AP_ARG_SEPS; + } + buf[len - 1] = '\n'; + + return send(c->s, buf, len, 0) != len; +} + +int +dupstatus(char **bufp, char *responce) +{ + if (*bufp) + *bufp = NULL; + + if (strcmp(responce, "ok") == 0) + return 0; + if (strncmp(responce, "error: ", 7) == 0) { + if (bufp) + return (*bufp = strdup(responce + 7)) == NULL; + return 0; + } + + errno = EBADMSG; + return 1; +} + +int +apc_recv(struct apcon *c, char **err, int (*item)(char *)) +{ + char *end; + char buf[AP_LINE_MAX]; + int error; + int len; + int tmp; + + error = 0; + len = 0; + + while ((tmp = recv(c->s, buf + len, sizeof(buf) - len, 0)) > 0) { + len += tmp; + while ((end = memchr(buf, '\n', len))) { + *end = 0; + if (dupstatus(err, buf) == 0) + return error; + else if (errno != EBADMSG) + return 1; + if (!error) + error = item(buf); + len -= end - buf + 1; + memmove(buf, end + 1, len); + } + } + + if (tmp == 0) + errno = ECONNRESET; + return 1; +} + +int +apc_run(struct apcon *con, char **err, int (*item)(char *), char **argv) +{ + if (*err) + *err = NULL; + if (apc_send(con, argv) || apc_recv(con, err, item)) + return 1; + return 0; +} + +int +print(char *item) +{ + return puts(item) < 0; +} + +int +main(int argc, char **argv) +{ + char *p; + int i; + char buf[AP_LINE_MAX]; + struct apcon con; + int sub; + +#ifdef __OpenBSD__ + if (pledge("stdio rpath unix", NULL)) + die("pledge"); +#endif + + if (argc <= 1) + die("no command"); + + if (apcon_open(&con, NULL, connect, 0)) + die("unable to open connection"); + + sub = 0; + for (i = 1; !sub && i < argc; ++i) + if (strcmp(argv[i], "-") == 0) + sub = i; + if (!sub) { + if (apc_run(&con, &p, print, argv + 1) || p) + die(p); + } else { + while (fgets(buf, sizeof(buf), stdin) != NULL) { + if ((p = strchr(buf, '\n')) == NULL) + die("message too long"); + *p = 0; + + argv[sub] = buf; + if (apc_run(&con, &p, print, argv + 1) || p) + die(p); + } + } + + apcon_close(&con); + return 0; +} diff --git a/apc/mkfile b/apc/mkfile @@ -0,0 +1,16 @@ +# Copyright 2021 Jacob R. Edwards + +name = apc +src = apc.c +obj = ${src:%.c=%.o} + +cppflags = -I../lib +ldflags = -L../lib +ldlibs = -lap + +all:V: $name + +< ../mk/config.mk +< ../mk/clean.mk +< ../mk/obj.mk +< ../mk/prog.mk diff --git a/apcon.c b/apcon.c @@ -1,65 +0,0 @@ -/* Copyright 2021 Jacob R. Edwards - * - * ap -- audio player - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - */ - -#include <sys/socket.h> - -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "apcon.h" -#include "config.h" -#include "sock.h" - -char * -apcon_getpath(char *path) -{ - if (path == NULL) { - path = getenv("APSOCK"); - if (path == NULL) - path = "/tmp/aps"; - } - return strdup(path); -} - -int -apcon_open(struct apcon *apc, char *path, - int (*init)(int, const struct sockaddr *, socklen_t), int flags) -{ - apc->path = apcon_getpath(path); - if (apc->path == NULL) - return 1; - - apc->s = sopen(apc->path, init, SOCK_STREAM | flags); - if (apc->s == -1) { - free(apc->path); - return 1; - } - - apc->init = init; - return 0; -} - -void -apcon_close(struct apcon *apc) -{ - sclose(apc->s); - if (apc->init == bind) - unlink(apc->path); - free(apc->path); -} diff --git a/aps.c b/aps.c @@ -1,218 +0,0 @@ -/* Copyright 2021 Jacob R. Edwards - * - * ap -- audio player - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - */ - -#include <sys/socket.h> -#include <sys/un.h> - -#include <sys/wait.h> - -#include <errno.h> -#include <limits.h> -#include <poll.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "ap.h" -#include "apcon.h" -#include "command.h" -#include "config.h" -#include "player.h" -#include "queue.h" -#include "response.h" -#include "sock.h" -#include "util.h" - -#include "aps.h" - -static struct aps aps; - -void -die(char *s) -{ - perror(s); - exit(1); -} - -void -sigclose(int sig) -{ - aps.close = 1; -} - -void -sigchld(int sig) -{ - int status; - pid_t pid; - - while ((pid = - waitpid(-1, &status, WCONTINUED | WNOHANG | WUNTRACED)) > 0) { - if (pid == aps.player.pid) - pupdate(&aps.player, status); - } -} - -int -aps_accept(struct aps *aps) -{ - int s; - struct pollfd pfd; - int r; - - pfd.events = POLLIN; - pfd.fd = aps->con.s; - - r = poll(&pfd, 1, aps->nfds ? 0 : INFTIM); - if (r <= 0) - return r; - - while ((s = accept4(aps->con.s, NULL, NULL, 0)) >= 0) { - aps->pfds[s].fd = s; - ++aps->nfds; - } - - return errno != EWOULDBLOCK; -} - -int -aps_drop(struct aps *aps, int fd) -{ - aps->pfds[fd].fd = -1; - resp_free(aps, fd); - --aps->nfds; - return sclose(fd); -} - -int -aps_handle(struct aps *aps, int fd) -{ - if (aps->pfds[fd].revents & (POLLERR | POLLHUP | POLLNVAL)) { - return 1; - } else if (aps->pfds[fd].revents & POLLIN) { - if (aps_command(aps, fd)) - return 1; - } else if (aps->pfds[fd].revents & POLLOUT) { - if (aps->clients[fd].response.lock && resp_send(aps, fd)) - return 1; - } else { - die("unhandled poll revent"); - } - - return 0; -} - -int -aps_update(struct aps *aps) -{ - int i; - int re; - - if ((re = poll(aps->pfds, LEN(aps->pfds), timeout)) == -1) - return 1; - - for (i = 0; re > 0 && i < LEN(aps->pfds); ++i) { - if (aps->pfds[i].revents && aps_handle(aps, i)) { - aps_drop(aps, i); - --re; - } - } - - return 0; -} - -int -run(struct aps *aps) -{ - while (!aps->close) { - if (!aps->player.state && aps->queue.pos) - aps_next(aps, -1, 0, NULL); - if ((aps_accept(aps) || aps_update(aps)) && errno != EINTR) - return 1; - } - return 0; -} - -int -aps_open(struct aps *aps) -{ - int i; - - if (apcon_open(&aps->con, NULL, bind, SOCK_NONBLOCK) || - listen(aps->con.s, 10)) - return 1; - - for (i = 0; i < LEN(aps->pfds); ++i) { - aps->pfds[i].fd = -1; - aps->pfds[i].events = POLLIN | POLLOUT; - } - return 0; -} - -void -aps_close(struct aps *aps) -{ - int i; - - for (i = 0; i < LEN(aps->next); ++i) - free(aps->next[i]); - for (i = 0; i < LEN(aps->pfds); ++i) - if (aps->pfds[i].fd != -1) - aps_drop(aps, i); - apcon_close(&aps->con); - pstop(&aps->player); -} - -int -main(int argc, char *argv[]) -{ - int i; - -#ifdef __OpenBSD__ - if (pledge("stdio rpath cpath proc exec unix", NULL)) - die("pledge"); -#endif - - signal(SIGCHLD, sigchld); - signal(SIGINT, sigclose); - signal(SIGTERM, sigclose); - - for (i = 1; player[i]; ++i) - if (!player[i][0]) - player[i] = aps.player.path; - - if (aps_next(&aps, -1, LEN(next), next)) - die("aps_next"); - - aps.player.argv = player + 1; - aps.player.prog = player[0]; - aps.player.state = STOPPED; - - if (aps_open(&aps)) - die("open connection"); - if (run(&aps)) { - perror("error"); - aps_close(&aps); - return 1; - } - - aps_close(&aps); - return 0; -} diff --git a/aps/aps b/aps/aps Binary files differ. diff --git a/aps/aps.c b/aps/aps.c @@ -0,0 +1,217 @@ +/* Copyright 2021 Jacob R. Edwards + * + * ap -- audio player + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <sys/socket.h> +#include <sys/un.h> + +#include <sys/wait.h> + +#include <errno.h> +#include <limits.h> +#include <poll.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <ap.h> + +#include "command.h" +#include "config.h" +#include "player.h" +#include "queue.h" +#include "response.h" +#include "util.h" + +#include "aps.h" + +static struct aps aps; + +void +die(char *s) +{ + perror(s); + exit(1); +} + +void +sigclose(int sig) +{ + aps.close = 1; +} + +void +sigchld(int sig) +{ + int status; + pid_t pid; + + while ((pid = + waitpid(-1, &status, WCONTINUED | WNOHANG | WUNTRACED)) > 0) { + if (pid == aps.player.pid) + pupdate(&aps.player, status); + } +} + +int +aps_accept(struct aps *aps) +{ + int s; + struct pollfd pfd; + int r; + + pfd.events = POLLIN; + pfd.fd = aps->con.s; + + r = poll(&pfd, 1, aps->nfds ? 0 : INFTIM); + if (r <= 0) + return r; + + while ((s = accept4(aps->con.s, NULL, NULL, 0)) >= 0) { + aps->pfds[s].fd = s; + ++aps->nfds; + } + + return errno != EWOULDBLOCK; +} + +int +aps_drop(struct aps *aps, int fd) +{ + aps->pfds[fd].fd = -1; + resp_free(aps, fd); + --aps->nfds; + return sclose(fd); +} + +int +aps_handle(struct aps *aps, int fd) +{ + if (aps->pfds[fd].revents & (POLLERR | POLLHUP | POLLNVAL)) { + return 1; + } else if (aps->pfds[fd].revents & POLLIN) { + if (aps_command(aps, fd)) + return 1; + } else if (aps->pfds[fd].revents & POLLOUT) { + if (aps->clients[fd].response.lock && resp_send(aps, fd)) + return 1; + } else { + die("unhandled poll revent"); + } + + return 0; +} + +int +aps_update(struct aps *aps) +{ + int i; + int re; + + if ((re = poll(aps->pfds, LEN(aps->pfds), timeout)) == -1) + return 1; + + for (i = 0; re > 0 && i < LEN(aps->pfds); ++i) { + if (aps->pfds[i].revents && aps_handle(aps, i)) { + aps_drop(aps, i); + --re; + } + } + + return 0; +} + +int +run(struct aps *aps) +{ + while (!aps->close) { + if (!aps->player.state && aps->queue.pos) + aps_next(aps, -1, 0, NULL); + if ((aps_accept(aps) || aps_update(aps)) && errno != EINTR) + return 1; + } + return 0; +} + +int +aps_open(struct aps *aps) +{ + int i; + + if (apcon_open(&aps->con, NULL, bind, SOCK_NONBLOCK) || + listen(aps->con.s, 10)) + return 1; + + for (i = 0; i < LEN(aps->pfds); ++i) { + aps->pfds[i].fd = -1; + aps->pfds[i].events = POLLIN | POLLOUT; + } + return 0; +} + +void +aps_close(struct aps *aps) +{ + int i; + + for (i = 0; i < LEN(aps->next); ++i) + free(aps->next[i]); + for (i = 0; i < LEN(aps->pfds); ++i) + if (aps->pfds[i].fd != -1) + aps_drop(aps, i); + apcon_close(&aps->con); + pstop(&aps->player); +} + +int +main(int argc, char *argv[]) +{ + int i; + +#ifdef __OpenBSD__ + if (pledge("stdio rpath cpath proc exec unix", NULL)) + die("pledge"); +#endif + + signal(SIGCHLD, sigchld); + signal(SIGINT, sigclose); + signal(SIGTERM, sigclose); + + for (i = 1; player[i]; ++i) + if (!player[i][0]) + player[i] = aps.player.path; + + if (aps_next(&aps, -1, LEN(next), next)) + die("aps_next"); + + aps.player.argv = player + 1; + aps.player.prog = player[0]; + aps.player.state = STOPPED; + + if (aps_open(&aps)) + die("open connection"); + if (run(&aps)) { + perror("error"); + aps_close(&aps); + return 1; + } + + aps_close(&aps); + return 0; +} diff --git a/aps.h b/aps/aps.h diff --git a/aps/command.c b/aps/command.c @@ -0,0 +1,360 @@ +/* Copyright 2021 Jacob R. Edwards + * + * ap -- audio player + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <sys/socket.h> + +#include <ctype.h> +#include <errno.h> +#include <fnmatch.h> +#include <limits.h> +#include <poll.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <ap.h> + +#include "player.h" +#include "queue.h" +#include "response.h" +#include "util.h" + +#include "aps.h" + +static char *earg = "Invalid number of arguments"; +static char *enotfound = "Not found"; +static char *eposition = "No position in queue"; +static char *etoofew = "Too few arguments"; + +int +resp_finish(struct aps *aps, int s, char *error) +{ + char buf[AP_LINE_MAX]; + int len; + + if (error) { + len = snprintf(buf, sizeof(buf), "error: %s\n", error); + } else { + len = 3; + memcpy(buf, "ok\n", len); + } + + if (len >= sizeof(buf)) + ERET(EMSGSIZE); + if (resp_add(aps, s, buf, len)) + return 1; + resp_end(aps, s); + return 0; +} + +int +resp_additem(struct aps *aps, int s, char *item) +{ + char buf[AP_LINE_MAX]; + int n; + + n = snprintf(buf, sizeof(buf), "%s\n", item); + if (n >= sizeof(buf)) + ERET(EMSGSIZE); + return resp_add(aps, s, buf, n); +} + +int +match(char *pattern, struct item *item) +{ + return fnmatch(pattern, item->path, 0) == 0; +} + +struct item * +nextmatch(struct item *(*incr)(struct item *), struct item *item, + char **patterns, int len, int noneall) +{ + int i; + + if (len == 0 || !item) + return (noneall ? item : NULL); + for (; item; item = incr(item)) { + for (i = 0; i < len; ++i) { + if (match(patterns[i], item)) + return item; + } + } + return item; +} + +char * +aps_add(struct aps *aps, int s, int argc, char **argv) +{ + int i; + + for (i = 1; i < argc; ++i) { + if (queue_add(&aps->queue, argv[i])) + return strerror(errno); + } + return NULL; +} + +char * +aps_remove(struct aps *aps, int s, int argc, char **argv) +{ + struct item *item, *next; + + if (argc == 1) { + if (aps->queue.pos == NULL) + return eposition; + queue_remove(&aps->queue, aps->queue.pos); + } + + next = aps->queue.head; + while ((item = nextmatch(item_next, next, argv + 1, argc - 1, 0))) { + next = item->next; + queue_remove(&aps->queue, item); + } + + return NULL; +} + +char * +aps_list(struct aps *aps, int s, int argc, char **argv) +{ + struct item *item; + + item = aps->queue.head; + while ((item = nextmatch(item_next, item, argv + 1, argc - 1, 1))) { + if (resp_additem(aps, s, item->path)) + return strerror(errno); + item = item->next; + } + + return NULL; +} + +struct item * +findnum(struct item *(*incr)(struct item *), struct item *item, char *num, + char **err) +{ + int n; + + n = strtonum(num, 0, INT_MAX, err); + if (*err) + return NULL; + *err = enotfound; + return item_seek(incr, item, n); +} + +struct item * +findpat(struct item *(*incr)(struct item *), struct item *item, + char **patterns, int len, char **err) +{ + *err = enotfound; + return nextmatch(incr, item, patterns, len, 0); +} + +struct item * +find(struct aps *aps, int argc, char **argv, char **err) +{ + char *e; + struct item *(*incr)(struct item *); + struct item *item; + + ++argv; + --argc; + if (argc < 1) { +earg: + *err = earg; + return NULL; + } + + incr = item_next; + item = aps->queue.pos; + if (argc > 1 && strchr("+-^", **argv) && !argv[0][1]) { + switch (**argv) { + case '-': + incr = item_prev; + break; + case '^': + item = aps->queue.head; + break; + } + ++argv; + --argc; + } + + if (!isdigit(**argv)) { + return findpat(incr, incr(item), argv, argc, err); + } else { + if (argc != 1) + goto earg; + return findnum(incr, item, *argv, err); + } +} + +char * +aps_seek(struct aps *aps, int s, int argc, char **argv) +{ + char *err; + struct item *item; + + item = find(aps, argc, argv, &err); + if (item == NULL) + return err; + aps->queue.pos = item; + return NULL; +} + +char * +aps_play(struct aps *aps, int s, int argc, char **argv) +{ + char *err; + + if (argc <= 1) { + if (aps->queue.pos == NULL) + return eposition; + } else if ((err = aps_seek(aps, s, argc, argv))) { + return err; + } + + if (pplay(&aps->player, aps->queue.pos->path)) + return strerror(errno); + return NULL; +} + +char * +aps_pause(struct aps *aps, int s, int argc, char **argv) +{ + if (psuspend(&aps->player)) + return strerror(errno); + return NULL; +} + +char * +aps_stop(struct aps *aps, int s, int argc, char **argv) +{ + if (pstop(&aps->player)) + return strerror(errno); + return NULL; +} + +char * +aps_toggle(struct aps *aps, int s, int argc, char **argv) +{ + if (ptoggle(&aps->player)) + return strerror(errno); + return NULL; +} + +char * +aps_name(struct aps *aps, int s, int argc, char **argv) +{ + struct item *item; + char *err; + + if (argc < 2) + item = aps->queue.pos; + else + item = find(aps, argc, argv, &err); + if (item == NULL) + return err; + + if (resp_additem(aps, s, item->path)) + return strerror(errno); + return NULL; +} + +char * +aps_next(struct aps *aps, int s, int argc, char **argv) +{ + int i; + + if (argc > 1) { + for (i = 0; i < argc; ++i) { + free(aps->next[i]); + aps->next[i] = strdup(argv[i]); + if (aps->next[i] == NULL) + return strerror(errno); + } + aps->nextlen = i; + return NULL; + } + + pstop(&aps->player); + return aps_play(aps, -1, aps->nextlen, aps->next); +} + +int +aps_command(struct aps *aps, int s) +{ + char *end; + char buf[AP_LINE_MAX]; + int argc; + struct client *c; + char *argv[AP_ARGV_MAX]; + int i; + int len; + struct command { + char *name; + char *(*func)(struct aps *, int, int, char **); + } commands[] = { + { "add", aps_add }, + { "list", aps_list }, + { "name", aps_name }, + { "next", aps_next }, + { "pause", aps_pause }, + { "play", aps_play }, + { "remove", aps_remove }, + { "seek", aps_seek }, + { "stop", aps_stop }, + { "toggle", aps_toggle } + }; + + c = &aps->clients[s]; + if (c->request.len == sizeof(c->request.buf)) { + c->request.len = 0; + return resp_finish(aps, s, strerror(EMSGSIZE)); + } + + len = recv(s, c->request.buf + c->request.len, LEN(c->request.buf) - c->request.len, 0); + if (len == -1) + return 1; + + end = memchr(c->request.buf + c->request.len, '\n', len); + c->request.len += len; + if (end == NULL) + return 0; /* not a full command yet */ + + *end = 0; + len = end - c->request.buf + 1; + memcpy(buf, c->request.buf, len); + memmove(c->request.buf, c->request.buf + len, c->request.len - len); + c->request.len -= len; + + argc = split(argv, LEN(argv), buf, AP_ARG_SEPS); + if (!argc) + return resp_finish(aps, s, "No command"); + if (argc < 0) + return resp_finish(aps, s, strerror(E2BIG)); + + for (i = 0; i < LEN(commands); ++i) { + if (strcmp(*argv, commands[i].name) == 0) + return resp_finish(aps, s, + commands[i].func(aps, s, argc, argv)); + } + + return resp_finish(aps, s, "Command not found"); +} diff --git a/command.h b/aps/command.h diff --git a/aps/mkfile b/aps/mkfile @@ -0,0 +1,16 @@ +# Copyright 2021 Jacob R. Edwards + +name = aps +src = aps.c command.c player.c queue.c response.c util.c +obj = ${src:%.c=%.o} + +cppflags = -I../lib +ldflags = -L../lib +ldlibs = -lap + +all:V: $name + +< ../mk/config.mk +< ../mk/clean.mk +< ../mk/obj.mk +< ../mk/prog.mk diff --git a/player.c b/aps/player.c diff --git a/player.h b/aps/player.h diff --git a/queue.c b/aps/queue.c diff --git a/queue.h b/aps/queue.h diff --git a/aps/response.c b/aps/response.c @@ -0,0 +1,117 @@ +/* Copyright 2021 Jacob R. Edwards + * + * ap -- audio player + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <sys/socket.h> + +#include <errno.h> +#include <limits.h> +#include <poll.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <ap.h> + +#include "player.h" +#include "queue.h" +#include "response.h" +#include "util.h" + +#include "aps.h" + +int +resp_enlarge(struct aps *aps, int fd, unsigned int more) +{ + struct response *resp; + unsigned int newsiz; + void *tmp; + + resp = &aps->clients[fd].response; + if (resp->len + more < resp->len) + ERET(EOVERFLOW); + + newsiz = (resp->siz ? resp->siz * 2 : BUFSIZ); + while (newsiz < resp->len + more) { + if (newsiz *= 2 < resp->siz) + ERET(EOVERFLOW); + } + + tmp = realloc(resp->buf, newsiz); + if (tmp == NULL) { + resp_free(aps, fd); + return 1; + } + + resp->buf = tmp; + resp->siz = newsiz; + return 0; +} + +int +resp_add(struct aps *aps, int fd, void *data, unsigned int len) +{ + struct response *resp; + + resp = &aps->clients[fd].response; + if (resp->len + len > resp->siz && resp_enlarge(aps, fd, len)) + return 1; + + memcpy(resp->buf + resp->len, data, len); + resp->len += len; + return 0; +} + +int +resp_send(struct aps *aps, int fd) +{ + ssize_t n; + struct response *resp; + + resp = &aps->clients[fd].response; + if (!resp->lock || resp->len - resp->sent == 0) + return 1; + + n = send(fd, resp->buf + resp->sent, resp->len - resp->sent, + MSG_NOSIGNAL); + switch (n) { + case -1: + return 1; + case 0: + ERET(ECONNRESET); + default: + if (resp->sent += n == resp->len) + resp_free(aps, fd); + return 0; + } +} + +void +resp_end(struct aps *aps, int fd) +{ + aps->clients[fd].response.lock = 1; +} + +void +resp_free(struct aps *aps, int fd) +{ + struct response *resp; + + resp = &aps->clients[fd].response; + free(resp->buf); + memset(resp, 0, sizeof(*resp)); +} diff --git a/response.h b/aps/response.h diff --git a/util.c b/aps/util.c diff --git a/util.h b/aps/util.h diff --git a/command.c b/command.c @@ -1,360 +0,0 @@ -/* Copyright 2021 Jacob R. Edwards - * - * ap -- audio player - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - */ - -#include <sys/socket.h> - -#include <ctype.h> -#include <errno.h> -#include <fnmatch.h> -#include <limits.h> -#include <poll.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "ap.h" -#include "apcon.h" -#include "player.h" -#include "queue.h" -#include "response.h" -#include "util.h" - -#include "aps.h" - -static char *earg = "Invalid number of arguments"; -static char *enotfound = "Not found"; -static char *eposition = "No position in queue"; -static char *etoofew = "Too few arguments"; - -int -resp_finish(struct aps *aps, int s, char *error) -{ - char buf[AP_LINE_MAX]; - int len; - - if (error) { - len = snprintf(buf, sizeof(buf), "error: %s\n", error); - } else { - len = 3; - memcpy(buf, "ok\n", len); - } - - if (len >= sizeof(buf)) - ERET(EMSGSIZE); - if (resp_add(aps, s, buf, len)) - return 1; - resp_end(aps, s); - return 0; -} - -int -resp_additem(struct aps *aps, int s, char *item) -{ - char buf[AP_LINE_MAX]; - int n; - - n = snprintf(buf, sizeof(buf), "%s\n", item); - if (n >= sizeof(buf)) - ERET(EMSGSIZE); - return resp_add(aps, s, buf, n); -} - -int -match(char *pattern, struct item *item) -{ - return fnmatch(pattern, item->path, 0) == 0; -} - -struct item * -nextmatch(struct item *(*incr)(struct item *), struct item *item, - char **patterns, int len, int noneall) -{ - int i; - - if (len == 0 || !item) - return (noneall ? item : NULL); - for (; item; item = incr(item)) { - for (i = 0; i < len; ++i) { - if (match(patterns[i], item)) - return item; - } - } - return item; -} - -char * -aps_add(struct aps *aps, int s, int argc, char **argv) -{ - int i; - - for (i = 1; i < argc; ++i) { - if (queue_add(&aps->queue, argv[i])) - return strerror(errno); - } - return NULL; -} - -char * -aps_remove(struct aps *aps, int s, int argc, char **argv) -{ - struct item *item, *next; - - if (argc == 1) { - if (aps->queue.pos == NULL) - return eposition; - queue_remove(&aps->queue, aps->queue.pos); - } - - next = aps->queue.head; - while ((item = nextmatch(item_next, next, argv + 1, argc - 1, 0))) { - next = item->next; - queue_remove(&aps->queue, item); - } - - return NULL; -} - -char * -aps_list(struct aps *aps, int s, int argc, char **argv) -{ - struct item *item; - - item = aps->queue.head; - while ((item = nextmatch(item_next, item, argv + 1, argc - 1, 1))) { - if (resp_additem(aps, s, item->path)) - return strerror(errno); - item = item->next; - } - - return NULL; -} - -struct item * -findnum(struct item *(*incr)(struct item *), struct item *item, char *num, - char **err) -{ - int n; - - n = strtonum(num, 0, INT_MAX, err); - if (*err) - return NULL; - *err = enotfound; - return item_seek(incr, item, n); -} - -struct item * -findpat(struct item *(*incr)(struct item *), struct item *item, - char **patterns, int len, char **err) -{ - *err = enotfound; - return nextmatch(incr, item, patterns, len, 0); -} - -struct item * -find(struct aps *aps, int argc, char **argv, char **err) -{ - char *e; - struct item *(*incr)(struct item *); - struct item *item; - - ++argv; - --argc; - if (argc < 1) { -earg: - *err = earg; - return NULL; - } - - incr = item_next; - item = aps->queue.pos; - if (argc > 1 && strchr("+-^", **argv) && !argv[0][1]) { - switch (**argv) { - case '-': - incr = item_prev; - break; - case '^': - item = aps->queue.head; - break; - } - ++argv; - --argc; - } - - if (!isdigit(**argv)) { - return findpat(incr, incr(item), argv, argc, err); - } else { - if (argc != 1) - goto earg; - return findnum(incr, item, *argv, err); - } -} - -char * -aps_seek(struct aps *aps, int s, int argc, char **argv) -{ - char *err; - struct item *item; - - item = find(aps, argc, argv, &err); - if (item == NULL) - return err; - aps->queue.pos = item; - return NULL; -} - -char * -aps_play(struct aps *aps, int s, int argc, char **argv) -{ - char *err; - - if (argc <= 1) { - if (aps->queue.pos == NULL) - return eposition; - } else if ((err = aps_seek(aps, s, argc, argv))) { - return err; - } - - if (pplay(&aps->player, aps->queue.pos->path)) - return strerror(errno); - return NULL; -} - -char * -aps_pause(struct aps *aps, int s, int argc, char **argv) -{ - if (psuspend(&aps->player)) - return strerror(errno); - return NULL; -} - -char * -aps_stop(struct aps *aps, int s, int argc, char **argv) -{ - if (pstop(&aps->player)) - return strerror(errno); - return NULL; -} - -char * -aps_toggle(struct aps *aps, int s, int argc, char **argv) -{ - if (ptoggle(&aps->player)) - return strerror(errno); - return NULL; -} - -char * -aps_name(struct aps *aps, int s, int argc, char **argv) -{ - struct item *item; - char *err; - - if (argc < 2) - item = aps->queue.pos; - else - item = find(aps, argc, argv, &err); - if (item == NULL) - return err; - - if (resp_additem(aps, s, item->path)) - return strerror(errno); - return NULL; -} - -char * -aps_next(struct aps *aps, int s, int argc, char **argv) -{ - int i; - - if (argc > 1) { - for (i = 0; i < argc; ++i) { - free(aps->next[i]); - aps->next[i] = strdup(argv[i]); - if (aps->next[i] == NULL) - return strerror(errno); - } - aps->nextlen = i; - return NULL; - } - - pstop(&aps->player); - return aps_play(aps, -1, aps->nextlen, aps->next); -} - -int -aps_command(struct aps *aps, int s) -{ - char *end; - char buf[AP_LINE_MAX]; - int argc; - struct client *c; - char *argv[AP_ARGV_MAX]; - int i; - int len; - struct command { - char *name; - char *(*func)(struct aps *, int, int, char **); - } commands[] = { - { "add", aps_add }, - { "list", aps_list }, - { "name", aps_name }, - { "next", aps_next }, - { "pause", aps_pause }, - { "play", aps_play }, - { "remove", aps_remove }, - { "seek", aps_seek }, - { "stop", aps_stop }, - { "toggle", aps_toggle } - }; - - c = &aps->clients[s]; - if (c->request.len == sizeof(c->request.buf)) { - c->request.len = 0; - return resp_finish(aps, s, strerror(EMSGSIZE)); - } - - len = recv(s, c->request.buf + c->request.len, LEN(c->request.buf) - c->request.len, 0); - if (len == -1) - return 1; - - end = memchr(c->request.buf + c->request.len, '\n', len); - c->request.len += len; - if (end == NULL) - return 0; /* not a full command yet */ - - *end = 0; - len = end - c->request.buf + 1; - memcpy(buf, c->request.buf, len); - memmove(c->request.buf, c->request.buf + len, c->request.len - len); - c->request.len -= len; - - argc = split(argv, LEN(argv), buf, argseps); - if (!argc) - return resp_finish(aps, s, "No command"); - if (argc < 0) - return resp_finish(aps, s, strerror(E2BIG)); - - for (i = 0; i < LEN(commands); ++i) { - if (strcmp(*argv, commands[i].name) == 0) - return resp_finish(aps, s, - commands[i].func(aps, s, argc, argv)); - } - - return resp_finish(aps, s, "Command not found"); -} diff --git a/config.def.h b/config.def.h @@ -1,11 +0,0 @@ -static char *player[] = { - /* "" = path */ - /* prog, arg, ... */ - "ffplay", "apsplayer", "-loglevel", "error", "-nodisp", "-autoexit", "", NULL -}; - -static char *next[] = { - "config.h", "+", "1" -}; - -static int timeout = 250; diff --git a/lib/ap.h b/lib/ap.h @@ -0,0 +1,6 @@ +#define AP_LINE_MAX (PATH_MAX * 2) +#define AP_ARGV_MAX 128 +#define AP_ARG_SEPS "\t" + +#include "sock.h" +#include "apcon.h" diff --git a/lib/apcon.c b/lib/apcon.c @@ -0,0 +1,64 @@ +/* Copyright 2021 Jacob R. Edwards + * + * ap -- audio player + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <sys/socket.h> + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "apcon.h" +#include "sock.h" + +char * +apcon_getpath(char *path) +{ + if (path == NULL) { + path = getenv("APSOCK"); + if (path == NULL) + path = "/tmp/aps"; + } + return strdup(path); +} + +int +apcon_open(struct apcon *apc, char *path, + int (*init)(int, const struct sockaddr *, socklen_t), int flags) +{ + apc->path = apcon_getpath(path); + if (apc->path == NULL) + return 1; + + apc->s = sopen(apc->path, init, SOCK_STREAM | flags); + if (apc->s == -1) { + free(apc->path); + return 1; + } + + apc->init = init; + return 0; +} + +void +apcon_close(struct apcon *apc) +{ + sclose(apc->s); + if (apc->init == bind) + unlink(apc->path); + free(apc->path); +} diff --git a/apcon.h b/lib/apcon.h diff --git a/lib/libap.a b/lib/libap.a Binary files differ. diff --git a/lib/mkfile b/lib/mkfile @@ -0,0 +1,12 @@ +# Copyright 2021 Jacob R. Edwards + +name = libap.a +src = apcon.c sock.c +obj = ${src:%.c=%.o} + +all:V: $name + +< ../mk/config.mk +< ../mk/clean.mk +< ../mk/obj.mk +< ../mk/lib.mk diff --git a/sock.c b/lib/sock.c diff --git a/sock.h b/lib/sock.h diff --git a/mk/clean.mk b/mk/clean.mk @@ -0,0 +1,4 @@ +# Copyright 2021 Jacob R. Edwards + +clean:V: + rm -f $name $obj diff --git a/mk/config.mk b/mk/config.mk @@ -0,0 +1,12 @@ +# Copyright 2021 Jacob R. Edwards + +ar = ar +cc = tcc + +cflags = $cflags -Wall -Wno-write-strings -static +cppflags = $cppflags -I/usr/include +ldflags = $ldflags -L/usr/lib +ldlibs = $ldlibs -lc + +prefix = /usr/local +manprefix = $prefix/man diff --git a/mk/lib.mk b/mk/lib.mk @@ -0,0 +1,4 @@ +# Copyright 2021 Jacob R. Edwards + +$name: $obj + $ar rcs $target $newprereq diff --git a/mk/obj.mk b/mk/obj.mk @@ -0,0 +1,4 @@ +# Copyright 2021 Jacob R. Edwards + +%.o: %.c + $cc $cppflags $cflags -c -o $stem.o $stem.c diff --git a/mk/prog.mk b/mk/prog.mk @@ -0,0 +1,12 @@ +# Copyright 2021 Jacob R. Edwards + +$name: $obj + $cc $ldflags -o $target $prereq $ldlibs + +install:V: $name + cp -f $name $prefix/bin + cp -f $name.1 $manprefix/man1 + +uninstall:V: + rm -f $prefix/bin/$name + rm -f $manprefix/man1/$name.1 diff --git a/mkfile b/mkfile @@ -1,40 +1,10 @@ # Copyright 2021 Jacob R. Edwards -cc = tcc -cflags = -Wall -Wno-write-strings -static -cppflags = -I/usr/include -ldflags = -L/usr/lib -ldlibs = -lc +subdirs = lib aps apc +targets = install uninstall clean -prefix = /usr/local - -names = aps apc -src = sock.c apcon.c util.c command.c queue.c player.c response.c - -mainobj = ${names:%=%.o} -obj = ${src:%.c=%.o} - -all:V: $names - -%.o: %.c - $cc $cppflags $cflags -c -o $stem.o $stem.c - -config.h: config.def.h - cp $prereq $target - -$mainobj $obj: config.h - -$names: $mainobj $obj - for t in $target +$targets: + for dir in $subdirs do - $cc $ldflags -o $t $t.o $obj $ldlibs + (cd $dir && mk $MKFLAGS $MKARGS) done - -clean:V: - rm -f $names $mainobj $obj - -install:V: $names - cp -f $names $prefix/bin - -uninstall:V: - (cd $prefix/bin && rm -f $names) diff --git a/response.c b/response.c @@ -1,117 +0,0 @@ -/* Copyright 2021 Jacob R. Edwards - * - * ap -- audio player - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - */ - -#include <sys/socket.h> - -#include <errno.h> -#include <limits.h> -#include <poll.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "ap.h" -#include "apcon.h" -#include "player.h" -#include "queue.h" -#include "response.h" -#include "util.h" - -#include "aps.h" - -int -resp_enlarge(struct aps *aps, int fd, unsigned int more) -{ - struct response *resp; - unsigned int newsiz; - void *tmp; - - resp = &aps->clients[fd].response; - if (resp->len + more < resp->len) - ERET(EOVERFLOW); - - newsiz = (resp->siz ? resp->siz * 2 : BUFSIZ); - while (newsiz < resp->len + more) { - if (newsiz *= 2 < resp->siz) - ERET(EOVERFLOW); - } - - tmp = realloc(resp->buf, newsiz); - if (tmp == NULL) { - resp_free(aps, fd); - return 1; - } - - resp->buf = tmp; - resp->siz = newsiz; - return 0; -} - -int -resp_add(struct aps *aps, int fd, void *data, unsigned int len) -{ - struct response *resp; - - resp = &aps->clients[fd].response; - if (resp->len + len > resp->siz && resp_enlarge(aps, fd, len)) - return 1; - - memcpy(resp->buf + resp->len, data, len); - resp->len += len; - return 0; -} - -int -resp_send(struct aps *aps, int fd) -{ - ssize_t n; - struct response *resp; - - resp = &aps->clients[fd].response; - if (!resp->lock || resp->len - resp->sent == 0) - return 1; - - n = send(fd, resp->buf + resp->sent, resp->len - resp->sent, - MSG_NOSIGNAL); - switch (n) { - case -1: - return 1; - case 0: - ERET(ECONNRESET); - default: - if (resp->sent += n == resp->len) - resp_free(aps, fd); - return 0; - } -} - -void -resp_end(struct aps *aps, int fd) -{ - aps->clients[fd].response.lock = 1; -} - -void -resp_free(struct aps *aps, int fd) -{ - struct response *resp; - - resp = &aps->clients[fd].response; - free(resp->buf); - memset(resp, 0, sizeof(*resp)); -}