*
*/
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <assert.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <sys/mman.h>
-
#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"
+ " - </dev/null -t ossdsp - >&%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();
+ }
}