source: trunk/third/esound/clients.c @ 15363

Revision 15363, 8.1 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r15362, which included commits to RCS files with non-trunk default branches.
Line 
1#include "esd-server.h"
2
3#ifdef HAVE_SYS_IOCTL_H
4# include <sys/ioctl.h>
5#endif
6#ifdef HAVE_SYS_FILIO_H
7# include <sys/filio.h>
8#endif
9
10#ifdef USE_LIBWRAP
11#include <tcpd.h>
12#include <syslog.h>
13
14int allow_severity = LOG_INFO;
15int deny_severity = LOG_WARNING;
16#endif
17
18/*******************************************************************/
19/* globals */
20
21/* the list of the currently connected clients */
22esd_client_t *esd_clients_list;
23
24/*******************************************************************/
25/* prototypes */
26void dump_clients(void);
27void free_client( esd_client_t *client );
28
29
30/*******************************************************************/
31/* for debugging purposes, dump the list of the clients and data */
32
33
34void dump_clients()
35{
36    long addr;
37    short port;
38    esd_client_t *clients = esd_clients_list;
39
40    if ( !esdbg_trace ) return;
41
42    while ( clients != NULL ) {
43        port = ntohs( clients->source.sin_port );
44        addr = ntohl( clients->source.sin_addr.s_addr );
45
46        printf( "(%02d) client from: %03u.%03u.%03u.%03u:%05d [%p]\n",
47                clients->fd, (unsigned int) addr >> 24,
48                (unsigned int) (addr >> 16) % 256,
49                (unsigned int) (addr >> 8) % 256,
50                (unsigned int) addr % 256, port, clients );
51
52        clients = clients->next;
53    }
54    return;
55}
56
57/*******************************************************************/
58/* deallocate memory for the client */
59void free_client( esd_client_t *client )
60{
61    /* free the client memory */
62    free( client );
63    return;
64}
65
66/*******************************************************************/
67/* add a complete new client into the list of clients at head */
68void add_new_client( esd_client_t *new_client )
69{
70    /* printf ( "adding client 0x%08x\n", new_client ); */
71    new_client->next = esd_clients_list;
72    esd_clients_list = new_client;
73    return;
74}
75
76/*******************************************************************/
77/* erase a client from the client list */
78void erase_client( esd_client_t *client )
79{
80    esd_client_t *previous = NULL;
81    esd_client_t *current = esd_clients_list;
82
83    /* iterate until we hit a NULL */
84    while ( current != NULL )
85    {
86        /* see if we hit the target client */
87        if ( current == client ) {
88            if( previous != NULL ){
89                /* we are deleting in the middle of the list */
90                previous->next = current->next;
91            } else {
92                /* we are deleting the head of the list */
93                esd_clients_list = current->next;
94            }
95
96            ESDBG_TRACE( printf ( "(%02d) closing client connection\n",
97                                  client->fd ); );
98
99            close( client->fd );
100            free_client( client );
101
102            return;
103        }
104
105        /* iterate through the list */
106        previous = current;
107        current = current->next;
108    }
109
110    /* hmm, we didn't find the desired client, just get on with life */
111    ESDBG_TRACE( printf( "(%02d) client not found\n", client->fd ); );
112    return;
113}
114
115
116/*******************************************************************/
117/* checks for new connections at listener - zero when done */
118int get_new_clients( int listen )
119{
120    int fd, nbl;
121    struct sockaddr_in incoming;
122    size_t size_in = sizeof(struct sockaddr_in);
123    esd_client_t *new_client = NULL;
124   
125    unsigned long addr;
126    short port;
127
128    /* see who awakened us */
129    do {
130        fd = accept( listen, (struct sockaddr*) &incoming, &size_in );
131        if ( fd > 0 ) {
132            port = ntohs( incoming.sin_port );
133            addr = ntohl( incoming.sin_addr.s_addr );
134
135            ESDBG_TRACE(
136                printf( "(%02d) new client from: %03u.%03u.%03u.%03u:%05d\n",
137                        fd, (unsigned int) addr >> 24,
138                        (unsigned int) (addr >> 16) % 256,
139                        (unsigned int) (addr >> 8) % 256,
140                        (unsigned int) addr % 256, port ); );
141
142#ifdef USE_LIBWRAP
143            {
144                struct request_info req;
145                struct servent *serv;
146
147                request_init( &req, RQ_DAEMON, "esound", RQ_FILE, fd, NULL );
148                fromhost( &req );
149
150                if ( !hosts_access( &req )) {
151                    ESDBG_TRACE(
152                        printf( "connection from %s refused by tcp_wrappers\n",
153                                eval_client( &req ) ); );
154
155                    close( fd );
156                    continue;
157                }
158            }
159#endif
160
161            ESDBG_COMMS( printf( "================================\n" ); );
162
163            /* make sure we have the memory to save the client... */
164            new_client = (esd_client_t*) malloc( sizeof(esd_client_t) );
165            if ( new_client == NULL ) {
166                close( fd );
167                return -1;
168            }
169
170            /* It appears that not all systems construct the new socket in
171             * a blocking mode, if the listening socket is non-blocking, so
172             * let's set that here...
173             */
174            nbl = 0;
175            if ( ioctl( fd, FIONBIO, &nbl ) < 0 )
176            {
177                ESDBG_TRACE( printf( "(%02d) couldn't turn on blocking for client\n",
178                                     fd ); );
179                close( fd );
180                return -1;
181            }
182
183            /* Reduce buffers on sockets to the minimum needed */
184            esd_set_socket_buffers( fd, ESD_BITS16, 44100, esd_audio_rate );
185
186            /* fill in the new_client structure - sockaddr = works!? */
187            new_client->next = NULL;
188            new_client->state = ESD_NEEDS_REQDATA;
189            new_client->request = ESD_PROTO_CONNECT;
190            new_client->fd = fd;
191            new_client->source = incoming;
192            new_client->proto_data_length = 0;
193           
194            add_new_client( new_client );
195        }
196    } while ( fd > 0 );
197
198    return 0;
199}
200
201static int is_paused_here = 0;
202/*******************************************************************/
203/* blocks waiting for data from the listener, and client conns. */
204int wait_for_clients_and_data( int listen )
205{
206    fd_set rd_fds;
207    struct timeval timeout;
208    struct timeval *timeout_ptr = NULL;
209    esd_client_t *client = esd_clients_list;
210    int max_fd = listen, ready;
211
212    /* add the listener to the file descriptor list */
213    FD_ZERO( &rd_fds );
214    FD_SET( listen, &rd_fds );
215
216    /* add the clients to the list, too */
217    while ( client != NULL )
218    {
219        /* add this client, but only if it's not monitoring */
220        if ( client->state == ESD_STREAMING_DATA &&
221             client->request == ESD_PROTO_STREAM_MON )
222        {
223            client = client->next;
224            continue;
225        }
226
227        FD_SET( client->fd, &rd_fds );
228
229        /* update the maximum fd for the select() */
230        if ( client->fd > max_fd )
231            max_fd = client->fd;
232
233        /* next client */
234        client = client->next;
235    }
236
237    /* if we're doing something useful, make sure we return immediately */
238    if ( esd_recorder_list || esd_playing_samples ) {
239        timeout.tv_sec = 0;
240        timeout.tv_usec = 0;
241        timeout_ptr = &timeout;
242    } else {
243
244        /* TODO: any reason not to pause indefinitely here? */
245        /* sample players that's why, if no players, can pause indefinitely */
246        /* if ( esd_on_autostandby
247                || (esd_autostandby_secs < 0 && !esd_playing_samples ) )
248               timeout_ptr = NULL; else { ... } */
249
250        if ( is_paused_here ) {
251
252            ESDBG_TRACE( printf( "paused, awaiting instructions.\n" ); );
253            timeout_ptr = NULL;
254
255        } else {
256
257            timeout.tv_sec = 0;
258            /* funky math to make sure a long can hold it all, calulate in ms */
259            timeout.tv_usec = (long) esd_buf_size_samples * 1000L
260                / (long) esd_audio_rate / 4L;   /* divide by two for stereo */
261            timeout.tv_usec *= 1000L;           /* convert to microseconds */
262            timeout_ptr = &timeout;
263
264        }
265    }
266
267    ready = select( max_fd+1, &rd_fds, NULL, NULL, timeout_ptr );
268
269    ESDBG_COMMS( printf(
270        "paused=%d, samples=%d, auto=%d, standby=%d, record=%d, ready=%d\n",
271        is_paused_here, esd_playing_samples,
272        esd_autostandby_secs, esd_on_standby,
273        (esd_recorder != 0), ready ); );
274
275    /* TODO: return ready, and do this in esd.c */
276    if ( ready <= 0 ) {
277        /* if < 0, something horrible happened:
278           EBADF   invalid file descriptor - let individual read sort it out
279           EINTR   non blocked signal caught - o well, no big deal
280           EINVAL  n is negative - not bloody likely
281           ENOMEM  unable to allocate internal tables - o well, no big deal */
282
283        if ( !is_paused_here && !esd_playing_samples && (esd_autostandby_secs<0) ) {
284            ESDBG_TRACE( printf( "doing nothing, pausing server.\n" ); );
285            esd_audio_flush();
286            esd_audio_pause();
287            esd_last_activity = time( NULL );
288            is_paused_here = 1;
289        }
290
291        if ( !is_paused_here && !esd_playing_samples && !esd_recorder_list ) {
292
293            if ( esd_autostandby_secs >= 0
294                 && ( time(NULL) > esd_last_activity + esd_autostandby_secs ) ) {
295                ESDBG_TRACE( printf( "bored, going to standby mode.\n" ); );
296                esd_server_standby();
297                esd_on_autostandby = 1;
298                is_paused_here = 1;
299            }
300
301        }
302
303    } else {
304
305        is_paused_here = 0;
306
307    }
308
309    return ready;
310}
Note: See TracBrowser for help on using the repository browser.