3 * writebuffer adapted for sound-playing
5 * readbuffer and writebuffer are:
6 * Copyright (C) 1997-1998,2000-2001 Ian Jackson <ian@chiark.greenend.org.uk>
8 * readbuffer is part of chiark backup, a system for backing up GNU/Linux and
9 * other UN*X-compatible machines, as used on chiark.greenend.org.uk.
11 * Copyright (C) 1997-1998,2000-2001 Ian Jackson <ian@chiark.greenend.org.uk>
12 * Copyright (C) 1999 Peter Maydell <pmaydell@chiark.greenend.org.uk>
14 * This is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as
16 * published by the Free Software Foundation; either version 3,
17 * or (at your option) any later version.
19 * This is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public
25 * License along with this file; if not, consult the Free Software
26 * Foundation's website at www.fsf.org, or the GNU Project website at
33 const char *progname= "trivsoundd";
35 static int maxstartdelay=60, maxbadaccept=10;
38 struct inqnode *next, *back;
43 static struct { struct inqnode *head, *tail; } inq;
44 static int master, sdev;
47 static void usageerr(const char *m) {
48 fprintf(stderr,"bad usage: %s\n",m);
52 static void bindmaster(const char *bindname) {
55 struct sockaddr_in sin;
56 struct sockaddr_un sun;
66 memset(&su,0,sizeof(su));
68 if (bindname[0]=='/' || bindname[0]=='.') {
70 if (strlen(bindname) >= sizeof(su.sun.sun_path))
71 usageerr("AF_UNIX bind path too long");
72 sulen= sizeof(su.sun);
73 su.sun.sun_family= AF_UNIX;
74 strcpy(su.sun.sun_path, bindname);
76 } else if (bindname[0] != ':' && (colon= strrchr(bindname,':'))) {
78 sulen= sizeof(su.sin);
79 su.sin.sin_family= AF_INET;
81 copy= xmalloc(colon - bindname + 1);
82 memcpy(copy,bindname, colon - bindname + 1);
83 copy[colon - bindname]= 0;
84 portul= strtoul(colon+1,&ep,0);
87 if (!portul || portul>=65536) usageerr("invalid port number");
88 su.sin.sin_port= htons(portul);
90 se= getservbyname(colon+1, "tcp");
91 if (!se) { fprintf(stderr,"unknown service `%s'\n",colon+1); exit(4); }
92 su.sin.sin_port= htons(se->s_port);
95 if (!strcmp(copy,"any")) {
96 su.sin.sin_addr.s_addr= INADDR_ANY;
97 } else if (!inet_aton(copy,&su.sin.sin_addr)) {
98 he= gethostbyname(copy);
99 if (!he) { herror(copy); exit(4); }
100 if (he->h_addrtype != AF_INET ||
101 he->h_length != sizeof(su.sin.sin_addr) ||
102 !he->h_addr_list[0] ||
103 he->h_addr_list[1]) {
104 fprintf(stderr,"hostname lookup `%s' did not yield"
105 " exactly one IPv4 address\n",copy);
108 memcpy(&su.sin.sin_addr, he->h_addr_list[0], sizeof(su.sin.sin_addr));
112 usageerr("unknown bind name");
116 master= socket(su.sa.sa_family,SOCK_STREAM,0);
117 if (master<0) { perror("socket"); exit(8); }
119 r= bind(master, &su.sa, sulen);
120 if (r) { perror("bind"); exit(8); }
122 r= listen(master, 5);
123 if (r) { perror("listen"); exit(8); }
126 static void opensounddevice(void) {
130 sdev= open("/dev/dsp", O_WRONLY);
131 if (sdev<0) { perror("open sound device"); exit(8); }
133 snprintf(cbuf, sizeof(cbuf), "sox -t raw -s -w -r 44100 -c 2"
134 " - </dev/null -t ossdsp - >&%d", sdev);
135 r= system(cbuf); if (r) { fprintf(stderr,"sox gave %d\n",r); exit(5); }
138 void wrbuf_report(const char *m) {
139 printf("writing %s\n", m);
142 static void selectcopy(void) {
143 int slave= inq.head ? inq.head->fd : -1;
144 wrbufcore_prepselect(slave, sdev);
145 fdsetset(master,&readfds);
147 wrbufcore_afterselect(slave, sdev);
150 static void expireoldconns(void) {
151 struct inqnode *searchold, *nextsearchold;
153 for (searchold= inq.head ? inq.head->next : 0;
155 searchold= nextsearchold) {
156 nextsearchold= searchold->next;
157 if (searchold->accepted < now-maxstartdelay) {
158 printf("expired %p\n",searchold);
159 LIST_UNLINK(inq,searchold);
165 static void acceptnewconns(void) {
171 if (!FD_ISSET(master,&readfds)) return;
173 slave= accept(master,0,0);
175 if (!(errno == EINTR ||
177 errno == EWOULDBLOCK)) {
180 if (bad > maxbadaccept) {
181 fprintf(stderr,"accept failures repeating\n");
185 /* any transient error will just send us round again via select */
190 new= xmalloc(sizeof(struct inqnode));
193 LIST_LINK_TAIL(inq,new);
195 printf("accepted %p\n",new);
198 static void switchinput(void) {
200 if (!seeneof) return;
203 printf("finished %p\n",old);
205 LIST_UNLINK(inq,old);
210 int main(int argc, const char *const *argv) {
212 if (!argv[1] || argv[2] || argv[1][0]=='-')
213 usageerr("no options allowed, must have one argument (bindname)");
215 buffersize= 44100*4* 5/*seconds*/;
228 if (time(&now)==(time_t)-1) { perror("time(2)"); exit(4); }