From: ianmdlvl Date: Thu, 22 May 2003 17:34:47 +0000 (+0000) Subject: working on trivsoundd X-Git-Tag: branchpoint-trivsoundd X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=chiark-utils.git;a=commitdiff_plain;h=e483a046db5ff0972702a0dc29ba4e00b698d997 working on trivsoundd --- diff --git a/backup/Makefile b/backup/Makefile index 938dd27..084c6fb 100644 --- a/backup/Makefile +++ b/backup/Makefile @@ -21,16 +21,6 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -CC= gcc -CFLAGS= $(WARNINGS) $(OPTIMISE) $(DEBUG) -CPPFLAGS= -DRWBUFFER_SIZE_MB=$(RWBUFFER_SIZE_MB) - -WARNINGS= -Wall -Wwrite-strings -Wmissing-prototypes \ - -Wstrict-prototypes -Wpointer-arith -OPTIMISE= -O2 -DEBUG= -g -RWBUFFER_SIZE_MB=16 - SYSTEM_GROUP= root prefix=/usr/local @@ -52,28 +42,20 @@ INSTALL_SCRIPT= $(INSTALL) -m 755 -o root -g $(SYSTEM_GROUP) INSTALL_PROGRAM= $(INSTALL_SCRIPT) -s INSTALL_DIRECTORY= $(INSTALL) -m 2755 -o root -g $(SYSTEM_GROUP) -d -CTARGETS= readbuffer writebuffer BINSCRIPTS= checkallused loaded driver takedown whatsthis labeltape SHARESCRIPTS= bringup full increm SHAREFILES= backuplib.pl EXAMPLES= relativity chiark -all: $(CTARGETS) - -readbuffer: readbuffer.o rwbuffer.o -writebuffer: writebuffer.o rwbuffer.o -readbuffer.o writebuffer.o rwbuffer.o: rwbuffer.h +all: install: all $(INSTALL_DIRECTORY) $(confdir) $(bindir) $(sharedir) $(vardir) $(man1dir) - $(INSTALL_PROGRAM) $(CTARGETS) $(bindir) set -e; for s in $(BINSCRIPTS); do \ $(INSTALL_SCRIPT) $$s $(bindir)/backup-$$s; done $(INSTALL_SHARE) $(SHAREFILES) $(sharedir) $(INSTALL_SCRIPT) $(SHARESCRIPTS) $(sharedir) - $(INSTALL) -m 644 readbuffer.1 ${man1dir}/readbuffer.1 - $(INSTALL) -m 644 writebuffer.1 ${man1dir}/writebuffer.1 install-docs: $(INSTALL_DIRECTORY) $(txtdocdir) @@ -95,4 +77,3 @@ clean: rm -f *~ ./#*# *.o distclean realclean: clean - rm -f $(CTARGETS) diff --git a/cprogs/.cvsignore b/cprogs/.cvsignore index cf6c95c..ebfb6ab 100644 --- a/cprogs/.cvsignore +++ b/cprogs/.cvsignore @@ -1,2 +1,3 @@ readbuffer writebuffer +trivsoundd diff --git a/cprogs/Makefile b/cprogs/Makefile new file mode 100644 index 0000000..2066d60 --- /dev/null +++ b/cprogs/Makefile @@ -0,0 +1,77 @@ +# Makefile +# simple make settings +# +# This file is part of chiark backup, a system for backing up GNU/Linux and +# other UN*X-compatible machines, as used on chiark.greenend.org.uk. +# +# chiark backup is: +# Copyright (C) 1997-1998,2000-2001 Ian Jackson +# Copyright (C) 1999 Peter Maydell +# +# This 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 2, or (at your option) any later version. +# +# This 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, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +CC= gcc +CFLAGS= $(WARNINGS) $(OPTIMISE) $(DEBUG) +CPPFLAGS= -DRWBUFFER_SIZE_MB=$(RWBUFFER_SIZE_MB) + +WARNINGS= -Wall -Wwrite-strings -Wmissing-prototypes \ + -Wstrict-prototypes -Wpointer-arith +OPTIMISE= -O2 +DEBUG= -g +RWBUFFER_SIZE_MB=16 + +SYSTEM_GROUP= root + +prefix=/usr/local + +bindir=$(prefix)/bin +sbindir=$(prefix)/sbin +mandir=${prefix}/man +man1dir=${mandir}/man1 +man8dir=${mandir}/man8 + +INSTALL= install -c +INSTALL_PROGRAM= $(INSTALL_SCRIPT) -s + +PROGRAMS= readbuffer writebuffer +DAEMONS= trivsoundd +MAN1PAGES= readbuffer.1 writebuffer.1 +MAN8PAGES= trivsoundd.8 + +TARGETS= $(PROGRAMS) $(DAEMONS) + +all: $(TARGETS) + +readbuffer: readbuffer.o rwbuffer.o +writebuffer: writebuffer.o wrbufcore.o rwbuffer.o +trivsoundd: trivsoundd.o wrbufcore.o rwbuffer.o +readbuffer.o writebuffer.o rwbuffer.o wrbufcoore.o: rwbuffer.h + +install: all + $(INSTALL_DIRECTORY) $(bindir) $(sbindir) + $(INSTALL_PROGRAM) $(PROGRAMS) $(bindir) + $(INSTALL_PROGRAM) $(DAEMONS) $(sbindir) + +install-docs: + $(INSTALL_DIRECTORY) $(man1dir) $(man8dir) $(txtdocdir) + $(INSTALL) -m 644 $(MAN1PAGES) ${man1dir}/. + $(INSTALL) -m 644 $(MAN8PAGES) ${man8dir}/. + +install-examples: + +clean: + rm -f *~ ./#*# *.o + +distclean realclean: clean + rm -f $(TARGETS) diff --git a/cprogs/dlist.h b/cprogs/dlist.h new file mode 100644 index 0000000..44bf556 --- /dev/null +++ b/cprogs/dlist.h @@ -0,0 +1,53 @@ +/* + * dlist.h + * - macros for handling doubly linked lists + */ +/* + * This file is + * Copyright (C) 1997-1999 Ian Jackson + * + * It is part of adns, which is + * Copyright (C) 1997-2000 Ian Jackson + * Copyright (C) 1999 Tony Finch + * + * 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 2, 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, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef ADNS_DLIST_H_INCLUDED +#define ADNS_DLIST_H_INCLUDED + +#define LIST_INIT(list) ((list).head= (list).tail= 0) +#define LINK_INIT(link) ((link).next= (link).back= 0) + +#define LIST_UNLINK_PART(list,node,part) \ + do { \ + if ((node)->part back) (node)->part back->part next= (node)->part next; \ + else (list).head= (node)->part next; \ + if ((node)->part next) (node)->part next->part back= (node)->part back; \ + else (list).tail= (node)->part back; \ + } while(0) + +#define LIST_LINK_TAIL_PART(list,node,part) \ + do { \ + (node)->part next= 0; \ + (node)->part back= (list).tail; \ + if ((list).tail) (list).tail->part next= (node); else (list).head= (node); \ + (list).tail= (node); \ + } while(0) + +#define LIST_UNLINK(list,node) LIST_UNLINK_PART(list,node,) +#define LIST_LINK_TAIL(list,node) LIST_LINK_TAIL_PART(list,node,) + +#endif diff --git a/cprogs/readbuffer.c b/cprogs/readbuffer.c index e48e78c..2be121c 100644 --- a/cprogs/readbuffer.c +++ b/cprogs/readbuffer.c @@ -27,14 +27,6 @@ * */ -#include -#include -#include -#include -#include -#include -#include - #include "rwbuffer.h" const char *progname= "readbuffer"; diff --git a/cprogs/rwbuffer.c b/cprogs/rwbuffer.c index d91a96e..cb88027 100644 --- a/cprogs/rwbuffer.c +++ b/cprogs/rwbuffer.c @@ -27,17 +27,6 @@ * */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "rwbuffer.h" #ifndef RWBUFFER_SIZE_MB_DEF @@ -54,6 +43,8 @@ size_t buffersize; fd_set readfds; fd_set writefds; +static int opt_mlock=0; + int min(int a, int b) { return a<=b ? a : b; } static void usage(FILE *f) { @@ -67,7 +58,7 @@ static void usageerr(const char *what) { exit(12); } -static void nonblock(int fd, int yesno) { +void nonblock(int fd, int yesno) { int r; r= fcntl(fd,F_GETFL,0); if (r == -1) { perror("fcntl getfl"); exit(8); } if (yesno) r |= O_NDELAY; @@ -79,11 +70,21 @@ static void unnonblock(void) { nonblock(0,0); nonblock(1,0); } +void startupcore(void) { + buf= xmalloc(buffersize); + + if (opt_mlock) { + if (mlock(buf,buffersize)) { perror("mlock"); exit(2); } + } + + used=0; wp=rp=buf; seeneof=0; + if (atexit(unnonblock)) { perror("atexit"); exit(16); } +} + void startup(const char *const *argv) { const char *arg; char *ep; unsigned long opt_buffersize=RWBUFFER_SIZE_MB_DEF; - int opt_mlock=0; assert(argv[0]); @@ -100,14 +101,7 @@ void startup(const char *const *argv) { } buffersize= opt_buffersize*1024*1024; - buf= xmalloc(buffersize); - - if (opt_mlock) { - if (mlock(buf,buffersize)) { perror("mlock"); exit(2); } - } - - used=0; wp=rp=buf; seeneof=0; - if (atexit(unnonblock)) { perror("atexit"); exit(16); } + startupcore(); nonblock(0,1); nonblock(1,1); } diff --git a/cprogs/rwbuffer.h b/cprogs/rwbuffer.h index 3684c39..fe308c1 100644 --- a/cprogs/rwbuffer.h +++ b/cprogs/rwbuffer.h @@ -30,9 +30,28 @@ #ifndef RWBUFFER_H #define RWBUFFER_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dlist.h" + + int min(int a, int b); void callselect(void); void startup(const char *const *argv); +void startupcore(void); +void *xmalloc(size_t sz); +void nonblock(int fd, int yesno); extern const char *progname; /* must be defined by main .c file */ @@ -42,4 +61,10 @@ extern size_t buffersize; extern fd_set readfds; extern fd_set writefds; + +void wrbufcore_startup(void); +void wrbufcore_prepselect(int rdfd, int wrfd); +void wrbufcore_afterselect(int rdfd, int wrfd); + + #endif /*RWBUFFER_H*/ diff --git a/cprogs/trivsoundd-start b/cprogs/trivsoundd-start new file mode 100755 index 0000000..9b50700 --- /dev/null +++ b/cprogs/trivsoundd-start @@ -0,0 +1,12 @@ +#!/bin/bash +set -e +pf=`tempfile` +rm -f $pf +mknod -m600 $pf p +exec 3<>$pf +exec >$pf 4<$pf +rm -f $pf +exec 3>&- +(exec logger -p user.info -t trivsoundd <&4 >/dev/null 2>&1) & +exec 4<&- 2>&1 -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "rwbuffer.h" -const char *progname= "triv-sound-d"; +const char *progname= "trivsoundd"; -static int master; +static int maxstartdelay=60, maxbadaccept=10; -int main(int argc, const char *const *argv) { - const char *bindname; - union { - struct sockaddr sa; - struct sockaddr_in sin; - struct sockaddr_un sun; - } su; - socklen_t sulen; - - bindname= *++argv; - if (!bindname) usageerr("need bind argument"); - startup(argv); - - memset(&su,0,sizeof(su)); - - if (bindname[0]=='/' || bindname[0]='.') { - if (strlen(bindname) >= sizeof(su.sun.sun_path)) - usageerr("AF_UNIX bind path too long"); - sulen= sizeof(su.sun); - su.sun.sun_family= AF_UNIX; - strcpy(su.sun.sun_path, bindname); - } else if ((colon= strrchr(bindname,':'))) { - char *copy, *ep; - unsigned long portul; - - sulen= sizeof(su.sin); - su.sin.sin_family= AF_INET; - - copy= xmalloc(colon - bindname + 1); - memcpy(copy,bindname, colon - bindname + 1); - copy[colon - bindname]= 0; - portul= strtoul(colon+1,0,&ep); - if (!*ep) { - if (!portul || portul>=65536) usageerr("invalid port number"); - su.sin.sin_port= htons(portul); - } else { - struct servent *se= getservbyname(colon+1, "tcp"); - if (!se) { fprintf(stderr,"unknown service `%s'\n",colon+1); exit(4); } - su.sin.sin_port= htons(se->s_port); +struct inqnode { + struct inqnode *next, *back; + time_t accepted; + int fd; +}; + +static struct { struct inqnode *head, *tail; } inq; +static int sdev; +static time_t now; + +static void opensounddevice(void) { + int r; + char cbuf[200]; + + sdev= open("/dev/dsp", O_WRONLY); + if (sdev<0) { perror("open sound device"); exit(8); } + + snprintf(cbuf, sizeof(cbuf), "sox -t raw -s -w -r 44100 -c 2" + " - &%d", sdev); + r= system(cbuf); if (r) { fprintf(stderr,"sox gave %d\n",r); exit(5); } +} + +static void selectcopy(void) { + int slave= inq.head ? inq.head->fd : -1; + wrbufcore_prepselect(slave, sdev); + FD_SET(0,&readfds); + callselect(); + wrbufcore_afterselect(slave, sdev); +} + +static void expireoldconns(void) { + struct inqnode *searchold, *nextsearchold; + + for (searchold= inq.head ? inq.head->next : 0; + searchold; + searchold= nextsearchold) { + nextsearchold= searchold; + if (searchold->accepted < now-maxstartdelay) { + printf("expired %p\n",searchold); + LIST_UNLINK(inq,searchold); + free(searchold); } + } +} - if (!inet_aton(copy,&su.sin.sin_addr)) { - struct hostent *he= gethostbyname(copy); - if (!he) { herror(copy); exit(4); } - if (he->h_addrtype != AF_INET || - he->h_length != sizeof(su.sin.sin_addr) || - !he->h_addrs[0] || - he->h_addrs[1]) { - fprintf(stderr,"hostname lookup `%s' did not yield" - " exactly one IPv4 address\n",copy); +static void acceptnewconns(void) { + static int bad; + + int slave; + struct inqnode *new; + + if (!FD_ISSET(0,&readfds)) return; + + slave= accept(0,0,0); + if (slave < 0) { + if (!(errno == EINTR || + errno == EAGAIN || + errno == EWOULDBLOCK)) { + perror("accept"); + bad++; + if (bad > maxbadaccept) { + fprintf(stderr,"accept failures repeating\n"); exit(4); } - memcpy(su.sin.sin_addr, he->h_addrs[0], sizeof(su.sin.sin_addr)); } + /* any transient error will just send us round again via select */ + return; } - master= socket(su.sa.sa_family,SOCK_STREAM,0); - if (master<0) { perror("socket"); exit(8); } + bad= 0; + new= xmalloc(sizeof(struct inqnode)); + new->accepted= now; + new->fd= slave; + LIST_LINK_TAIL(inq,new); - - - if ( + printf("accepted %p\n",new); +} - sdigit((unsigned char)bindname[0])) { - +static void switchinput(void) { + struct inqnode *old; + if (!seeneof) return; + old= inq.head; + assert(old); + printf("finished %p\n",old); + close(old->fd); + LIST_UNLINK(inq,old); + free(old); + seeneof= 0; +} - if (argv[0] - - startup(argv); - writebuf_startup(); - writebuf_mainloop(); - exit(0); +int main(int argc, const char *const *argv) { + assert(argv[0]); + if (argv[1]) { fputs("no arguments allowed\n",stderr); exit(12); } + + buffersize= 44100*4* 5/*seconds*/; + + opensounddevice(); + nonblock(sdev,1); + nonblock(0,1); + + startupcore(); + wrbufcore_startup(); + + printf("started\n"); + for (;;) { + selectcopy(); + if (time(&now)==(time_t)-1) { perror("time(2)"); exit(4); } + expireoldconns(); + acceptnewconns(); + switchinput(); + } } diff --git a/cprogs/wrbufcore.c b/cprogs/wrbufcore.c index 260f6d2..417cb01 100644 --- a/cprogs/wrbufcore.c +++ b/cprogs/wrbufcore.c @@ -27,6 +27,8 @@ * */ +#include "rwbuffer.h" + static size_t waitfill; static int writing; @@ -35,44 +37,46 @@ void wrbufcore_startup(void) { writing=0; } -void wrbufcore_mainloop(void) { - int r; +void wrbufcore_prepselect(int rdfd, int wrfd) { + FD_ZERO(&readfds); + if (rdfd>=0 && !seeneof && used+1=0 && FD_ISSET(rdfd,&readfds)) && + !used) { + writing= 0; + FD_CLR(wrfd,&writefds); + } - if (FD_ISSET(0,&readfds)) { - r= read(0,rp,min(buffersize-1-used,buf+buffersize-rp)); - if (!r) { - seeneof=1; writing=1; - } else if (r<0) { - if (!(errno == EAGAIN || errno == EINTR)) { perror("read"); exit(1); } - } else { - used+= r; - rp+= r; - if (rp == buf+buffersize) rp=buf; - } - if (used > waitfill) writing=1; + if (rdfd>=0 && FD_ISSET(rdfd,&readfds)) { + r= read(rdfd,rp,min(buffersize-1-used,buf+buffersize-rp)); + if (!r) { + seeneof=1; writing=1; + } else if (r<0) { + if (!(errno == EAGAIN || errno == EINTR)) { perror("read"); exit(1); } + } else { + used+= r; + rp+= r; + if (rp == buf+buffersize) rp=buf; } + if (used > waitfill) writing=1; + } - if (FD_ISSET(1,&writefds) && used) { - r= write(1,wp,min(used,buf+buffersize-wp)); - if (r<=0) { - if (!(errno == EAGAIN || errno == EINTR)) { perror("write"); exit(1); } - } else { - used-= r; - wp+= r; - if (wp == buf+buffersize) wp=buf; - } + if (FD_ISSET(wrfd,&writefds) && used) { + r= write(wrfd,wp,min(used,buf+buffersize-wp)); + if (r<=0) { + if (!(errno == EAGAIN || errno == EINTR)) { perror("write"); exit(1); } + } else { + used-= r; + wp+= r; + if (wp == buf+buffersize) wp=buf; } } } diff --git a/cprogs/writebuffer.c b/cprogs/writebuffer.c index 9b1a368..f37edd1 100644 --- a/cprogs/writebuffer.c +++ b/cprogs/writebuffer.c @@ -27,22 +27,17 @@ * */ -#include -#include -#include -#include -#include -#include - #include "rwbuffer.h" const char *progname= "writebuffer"; int main(int argc, const char *const *argv) { - int r, writing; - startup(argv); - writebuf_startup(); - writebuf_mainloop(); + wrbufcore_startup(); + while (!seeneof || used) { + wrbufcore_prepselect(0,1); + callselect(); + wrbufcore_afterselect(0,1); + } exit(0); }