source: gutenbach/debian/lib/voldaemon.c @ b1d66d4

debianmacno-cupsnodebathenaweb
Last change on this file since b1d66d4 was 283d671f, checked in by root <root>, 16 years ago

Initial revision

  • Property mode set to 100644
File size: 6.4 KB
Line 
1/*
2 * $Id: voldaemon.c,v 1.1 2008-09-27 08:49:10 root Exp $
3 * $Source: /tmp/tmp.UFBNno9997/RCS/voldaemon.c,v $
4 */
5
6#include <stdio.h>
7#include <fcntl.h>
8#include <unistd.h>
9#include <stdlib.h>
10#include <string.h>
11#include <sys/types.h>
12#include <sys/socket.h>
13#include <arpa/inet.h>
14#include <sys/ioctl.h>
15#include <sys/time.h>
16#include <errno.h>
17#include <assert.h>
18#include <netinet/in.h>
19
20
21#define LISTEN_PORT 8930
22#define MULTI_PORT 8931
23#define MULTI_ADDR "224.0.1.20"
24
25/* Block queries from off this subnet net 18.*/
26#define OUR_SUBNET      187
27
28typedef struct volmessage{
29  char A;
30  char request;
31  char value;
32  unsigned char ip_3;
33  unsigned char ip_2;
34  unsigned char ip_1;
35  unsigned char ip_0;
36  char ZE;
37} volmessage;
38
39#define MESSAGE_SIZE (sizeof(volmessage))
40
41/* The client makes requests using the following packets.  Responses
42   to queries and status reports from the server follow the same
43   pattern
44
45  Request/Response
46
47  'AVxiiiiZ'     Volume
48  'AMxiiiiZ'     Mute
49  'AQQiiiiZ'     Query
50
51  Response Only
52  'AVeiiiiE'     Volume Set Error
53  'AMeiiiiE'     Mute Set Error
54  'AEeiiiiE'     Unknown error
55
56   e=1  Permission denied (invalid IP)
57   e=2  Invalid request (Bad Packet)
58   
59*/
60
61void message(char *m){
62  write(STDERR_FILENO,m,strlen(m));
63}
64
65void abortm(char *m){
66  message(m);
67  message("Errno = ");
68  message(strerror(errno));
69  message("\n");
70  exit(1);
71}
72
73struct in_addr multiaddr={0};
74
75int multicast(volmessage *m){
76  static int sockfd=-1;
77  static struct sockaddr_in dest;
78  int destlen=sizeof(dest);
79
80  if(sockfd==-1)
81    if((sockfd=socket(AF_INET,SOCK_DGRAM,0))<0)
82      abortm("Could not open multicast socket\n");
83
84  if(multiaddr.s_addr==0)
85    multiaddr.s_addr = inet_addr(MULTI_ADDR);
86      /*inet_aton(MULTI_ADDR,&multiaddr);*/
87
88  memset(&dest,0,sizeof(dest));
89  dest.sin_family=AF_INET;
90  dest.sin_addr.s_addr=multiaddr.s_addr;
91  dest.sin_port=htons(MULTI_PORT);
92
93  if(sendto(sockfd,m,MESSAGE_SIZE,0,(struct sockaddr *)&dest,destlen)<0){
94    message("Multicast send error\n");
95    return(1);
96  }
97  return(0);
98}
99
100int sockfd=-1,volfd;
101static struct sockaddr_in me,you;
102static int youlen=sizeof(you);
103struct in_addr multiaddr;
104
105int opensock(){
106  if((sockfd=socket(AF_INET,SOCK_DGRAM,0))<0)
107    abortm("Could not open listen socket\n");
108
109  memset(&me,0,sizeof(me));
110  me.sin_family=AF_INET;
111  me.sin_addr.s_addr=htonl(INADDR_ANY);
112  me.sin_port=htons(LISTEN_PORT);
113
114  if(bind(sockfd,(struct sockaddr *)&me,sizeof(me))<0)
115    abortm("Could not bind to listen port\n");
116
117  listen(sockfd,5);
118  return(sockfd);
119}
120
121/*  -1 blocks
122    0  nonblocking
123    +n timeout
124*/
125
126int
127fetch (int usec, volmessage *m) {
128  fd_set fdset;
129  int retval;
130  struct timeval tv;
131  if(sockfd==-1)
132    opensock();
133
134  FD_ZERO(&fdset);
135  FD_SET(sockfd, &fdset);
136
137  tv.tv_sec = 0;
138  tv.tv_usec = usec;
139  retval = select(sockfd+1,
140                  &fdset, NULL, NULL,
141                  ((usec == -1) ? NULL : &tv));
142  if (retval == 1) {
143    /* Select got us a single descriptor to play with, as we
144     * expected. Pull a message from it. */
145    int youlen = sizeof(you);
146    retval = recvfrom(sockfd,
147                      m, MESSAGE_SIZE,
148                      0,
149                      (struct sockaddr *)&you, &youlen);
150    if(retval < MESSAGE_SIZE || m->A != 'A' || m->ZE != 'Z') {
151      message("Packet receive error\n");
152      return(0);
153    } else {
154      return(1);
155    }
156  } else {
157    if (retval == 0) {
158      /* This means the timeout finished. */
159    } else if (retval == -1) {
160      fprintf(stderr, "Select error. errno = %d (%s).\n",
161              errno, strerror(errno));
162    } else {
163      fprintf(stderr, "Select returned unexpected value %d.\n", retval);
164    }
165    /* Whatever error we get, we just return 0. */
166    return(0);
167  }
168}
169
170
171int
172reply (volmessage *m) {
173  int retval;
174  assert(sockfd != -1);
175 
176  retval = sendto(sockfd,
177                  m, MESSAGE_SIZE,
178                  0,
179                  (struct sockaddr *)&you, youlen);
180  if(retval < 0){
181    message("Reply error\n");
182    return(1);
183  }
184  return(0);
185}
186 
187int vol_iterate(int newval){
188  static int val=0;
189  char command[100];
190 
191
192  if (val==newval)
193    return(0);
194
195  if (val<newval) {
196    val+=8;
197    if(val>newval)
198      val=newval;
199  } else {
200    val-=8;
201    if(val<newval)
202      val=newval;
203  }
204  sprintf(command,"/usr/bin/aumix -v %d",val);
205  fprintf(stderr,"Setting volume to %d\n",val);
206  system(command);
207  return(1);
208}
209
210int main(){
211  unsigned char volume=32,mute=0,ip_3=0,ip_2=0,ip_1=0,ip_0=0;
212  int messagestatus=1,volstatus=1;
213  volmessage m;
214
215  system("/usr/bin/aumix -v 0");
216  system("/usr/bin/aumix -i 100");
217  system("/usr/bin/aumix -l 100");
218
219  message("\nSIPB volume daemon running\n");
220
221  /* We want to process messages quickly, then get to the business of
222     controlling ther hardware when no messages are in the queue.
223     The select on the message fetch also does our timing for volume
224     iteration */
225
226  while(1){
227    if(messagestatus==1)
228      /* Messages likely pending.  Process quickly */
229      messagestatus=fetch(0,&m);
230    else
231      if(volstatus==1){
232        /* No messages, but volume to be updated */
233        messagestatus=fetch(50,&m);
234        if(messagestatus==0)volstatus=vol_iterate(mute?0:volume);
235      }else{
236        /* Steady state.  Wait (almost) forever until a message */
237        m.ip_0=ip_0;
238        m.ip_1=ip_1;
239        m.ip_2=ip_2;
240        m.ip_3=ip_3;
241        m.A='A';
242        m.request='V';
243        m.value=volume;
244        m.ZE='Z';
245        multicast(&m);
246        m.A='A';
247        m.request='M';
248        m.value=mute;
249        m.ZE='Z';
250        multicast(&m);
251        messagestatus=fetch(400000,&m);
252      }
253
254    if(messagestatus){
255      int error=0;
256      m.ip_3=(ntohl(you.sin_addr.s_addr)>>24)&0xff;
257      m.ip_2=(ntohl(you.sin_addr.s_addr)>>16)&0xff;
258      m.ip_1=(ntohl(you.sin_addr.s_addr)>>8)&0xff;
259      m.ip_0=ntohl(you.sin_addr.s_addr)&0xff;
260
261      if(m.ip_3!=18 || m.ip_2!=OUR_SUBNET){
262        error=1;
263      }
264
265      switch(m.request){
266      case 'V':
267        if(error){
268          m.value=error;
269          m.ZE='E';
270          reply(&m);
271          message("Request from off subnet rejected\n");
272        }else{
273          ip_0=m.ip_0;
274          ip_1=m.ip_1;
275          ip_2=m.ip_2;
276          ip_3=m.ip_3;
277          volume=m.value;
278          reply(&m);
279          multicast(&m);
280          volstatus=1;
281        }
282        break;
283      case 'M':
284        if(error){
285          m.value=error;
286          m.ZE='E';
287          reply(&m);     
288          message("Request from off subnet rejected\n");
289        }else{
290          ip_0=m.ip_0;
291          ip_1=m.ip_1;
292          ip_2=m.ip_2;
293          ip_3=m.ip_3;
294          mute=(m.value?1:0);
295          m.value=mute;
296          reply(&m);
297          multicast(&m);
298          volstatus=1;
299        }
300        break;
301      case 'Q':
302        m.ip_0=ip_0;
303        m.ip_1=ip_1;
304        m.ip_2=ip_2;
305        m.ip_3=ip_3;
306        m.request='V';
307        m.value=volume;
308        reply(&m);
309        m.request='M';
310        m.value=mute;
311        reply(&m);
312        break;
313      default:
314        reply((volmessage *)"AE20000E");
315        break;
316      }
317    }
318  }
319}
Note: See TracBrowser for help on using the repository browser.