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 2,
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, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32 const char *progname= "trivsoundd";
34 static int maxstartdelay=60, maxbadaccept=10;
37 struct inqnode *next, *back;
42 static struct { struct inqnode *head, *tail; } inq;
43 static int master, sdev;
46 static void usageerr(const char *m) {
47 fprintf(stderr,"bad usage: %s\n",m);
51 static void bindmaster(const char *bindname) {
54 struct sockaddr_in sin;
55 struct sockaddr_un sun;
65 memset(&su,0,sizeof(su));
67 if (bindname[0]=='/' || bindname[0]=='.') {
69 if (strlen(bindname) >= sizeof(su.sun.sun_path))
70 usageerr("AF_UNIX bind path too long");
71 sulen= sizeof(su.sun);
72 su.sun.sun_family= AF_UNIX;
73 strcpy(su.sun.sun_path, bindname);
75 } else if (bindname[0] != ':' && (colon= strrchr(bindname,':'))) {
77 sulen= sizeof(su.sin);
78 su.sin.sin_family= AF_INET;
80 copy= xmalloc(colon - bindname + 1);
81 memcpy(copy,bindname, colon - bindname + 1);
82 copy[colon - bindname]= 0;
83 portul= strtoul(colon+1,&ep,0);
86 if (!portul || portul>=65536) usageerr("invalid port number");
87 su.sin.sin_port= htons(portul);
89 se= getservbyname(colon+1, "tcp");
90 if (!se) { fprintf(stderr,"unknown service `%s'\n",colon+1); exit(4); }
91 su.sin.sin_port= htons(se->s_port);
94 if (!strcmp(copy,"any")) {
95 su.sin.sin_addr.s_addr= INADDR_ANY;
96 } else if (!inet_aton(copy,&su.sin.sin_addr)) {
97 he= gethostbyname(copy);
98 if (!he) { herror(copy); exit(4); }
99 if (he->h_addrtype != AF_INET ||
100 he->h_length != sizeof(su.sin.sin_addr) ||
101 !he->h_addr_list[0] ||
102 he->h_addr_list[1]) {
103 fprintf(stderr,"hostname lookup `%s' did not yield"
104 " exactly one IPv4 address\n",copy);
107 memcpy(&su.sin.sin_addr, he->h_addr_list[0], sizeof(su.sin.sin_addr));
111 usageerr("unknown bind name");
115 master= socket(su.sa.sa_family,SOCK_STREAM,0);
116 if (master<0) { perror("socket"); exit(8); }
118 r= bind(master, &su.sa, sulen);
119 if (r) { perror("bind"); exit(8); }
121 r= listen(master, 5);
122 if (r) { perror("listen"); exit(8); }
125 static void opensounddevice(void) {
129 sdev= open("/dev/dsp", O_WRONLY);
130 if (sdev<0) { perror("open sound device"); exit(8); }
132 snprintf(cbuf, sizeof(cbuf), "sox -t raw -s -w -r 44100 -c 2"
133 " - </dev/null -t ossdsp - >&%d", sdev);
134 r= system(cbuf); if (r) { fprintf(stderr,"sox gave %d\n",r); exit(5); }
137 void wrbuf_report(const char *m) {
138 printf("writing %s\n", m);
141 static void selectcopy(void) {
142 int slave= inq.head ? inq.head->fd : -1;
143 wrbufcore_prepselect(slave, sdev);
144 fdsetset(master,&readfds);
146 wrbufcore_afterselect(slave, sdev);
149 static void expireoldconns(void) {
150 struct inqnode *searchold, *nextsearchold;
152 for (searchold= inq.head ? inq.head->next : 0;
154 searchold= nextsearchold) {
155 nextsearchold= searchold->next;
156 if (searchold->accepted < now-maxstartdelay) {
157 printf("expired %p\n",searchold);
158 LIST_UNLINK(inq,searchold);
164 static void acceptnewconns(void) {
170 if (!FD_ISSET(master,&readfds)) return;
172 slave= accept(master,0,0);
174 if (!(errno == EINTR ||
176 errno == EWOULDBLOCK)) {
179 if (bad > maxbadaccept) {
180 fprintf(stderr,"accept failures repeating\n");
184 /* any transient error will just send us round again via select */
189 new= xmalloc(sizeof(struct inqnode));
192 LIST_LINK_TAIL(inq,new);
194 printf("accepted %p\n",new);
197 static void switchinput(void) {
199 if (!seeneof) return;
202 printf("finished %p\n",old);
204 LIST_UNLINK(inq,old);
209 int main(int argc, const char *const *argv) {
211 if (!argv[1] || argv[2] || argv[1][0]=='-')
212 usageerr("no options allowed, must have one argument (bindname)");
214 buffersize= 44100*4* 5/*seconds*/;
227 if (time(&now)==(time_t)-1) { perror("time(2)"); exit(4); }