source: roaraudio/roard/clients.c @ 5295:5914c84e72be

Last change on this file since 5295:5914c84e72be was 5295:5914c84e72be, checked in by phi, 12 years ago

converted message (protocol) rutunes to use roar_mm_*() (Closes: #129)

File size: 26.1 KB
Line 
1//clients.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2011
5 *
6 *  This file is part of roard a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  RoarAudio is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 */
25
26/* ckport options:
27 * ckport: ignore-symbol: roar_event_to_blob of target libroar0
28 */
29
30#include "roard.h"
31
32// declared 'extern'
33struct roar_client_server * g_clients[ROAR_CLIENTS_MAX];
34struct roard_proto g_proto[MAX_PROTOS];
35
36
37struct roard_proto g_proto[MAX_PROTOS] = {
38#ifndef ROAR_WITHOUT_DCOMP_EMUL_ESD
39#ifdef ROAR_HAVE_H_ESD
40 {ROAR_PROTO_ESOUND, ROAR_SUBSYS_WAVEFORM, "EsounD emulation", NULL, emul_esd_check_client, NULL, NULL},
41#endif
42#endif
43#ifndef ROAR_WITHOUT_DCOMP_EMUL_RPLAY
44 {ROAR_PROTO_RPLAY, ROAR_SUBSYS_WAVEFORM, "RPlay emulation", NULL, emul_rplay_check_client, NULL, NULL},
45#endif
46#ifndef ROAR_WITHOUT_DCOMP_EMUL_GOPHER
47 {ROAR_PROTO_GOPHER, ROAR_SUBSYS_WAVEFORM, "The Internet Gopher Protocol", NULL, emul_gopher_check_client, NULL, emul_gopher_flushed_client},
48#endif
49 {-1, 0, NULL, NULL, NULL, NULL, NULL}
50};
51
52#define _CHECK_CID_RET(id,ret) if ( (id) < 0 || (id) > ROAR_CLIENTS_MAX || g_clients[(id)] == NULL ) return (ret)
53#define _CHECK_CID(id)         _CHECK_CID_RET((id), -1)
54
55int clients_init (void) {
56 int i;
57
58 for (i = 0; i < ROAR_CLIENTS_MAX; i++)
59  g_clients[i] = NULL;
60
61 for (i = 0; g_proto[i].proto != -1; i++);
62
63 for (; i < MAX_PROTOS; i++)
64  g_proto[i].proto = -1;
65
66 return 0;
67}
68
69int clients_free (void) {
70 int i;
71
72 for (i = 0; i < ROAR_CLIENTS_MAX; i++)
73  if ( g_clients[i] != NULL )
74   clients_delete(i);
75
76 return 0;
77}
78
79int clients_new (void) {
80 int i;
81 int s;
82 struct roar_client_server * ns;
83 struct roar_client * n;
84
85 for (i = 0; i < ROAR_CLIENTS_MAX; i++) {
86  if ( g_clients[i] == NULL ) {
87   ns = roar_mm_malloc(sizeof(struct roar_client_server));
88   n = ROAR_CLIENT(ns);
89
90   memset(ns, 0, sizeof(struct roar_client_server));
91
92   if ( n != NULL ) {
93    n->pid    = -1;
94    n->uid    = -1;
95    n->gid    = -1;
96    n->fh     = -1;
97
98    *n->name = 0;
99    *n->host = 0;
100
101    n->proto     = ROAR_PROTO_ROARAUDIO;
102    n->byteorder = ROAR_BYTEORDER_NETWORK;
103
104    n->acl   = NULL;
105
106    n->execed = -1;
107    for (s = 0; s < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; s++)
108     n->streams[s] = -1;
109
110    if ( roar_nnode_new(&(n->nnode), ROAR_SOCKET_TYPE_UNKNOWN) == -1 ) {
111     roar_mm_free(n);
112     return -1;
113    }
114
115    ns->blockc   = 0;
116    ns->waits    = NULL;
117    ns->acclev   = ACCLEV_NONE;
118
119    g_clients[i] = ns;
120
121    counters_inc(clients, 1);
122    roar_notify_core_emit_snoargs(ROAR_OE_BASICS_NEW, -1, i, ROAR_OT_CLIENT);
123    ROAR_DBG("clients_new(void) = %i", i);
124    return i;
125   } else {
126    ROAR_ERR("clients_new(void): Can not alloc memory for new client: %s", strerror(errno));
127    ROAR_ERR("clients_new(void) = -1");
128    return -1;
129   }
130  }
131 }
132
133 return -1;
134}
135
136int clients_new_from_fh(int fh, int proto, int byteorder, int update_nnode) {
137 struct roar_client * c;
138 int client;
139
140 if ( fh == -1 )
141  return -1;
142
143 if ( proto != ROAR_PROTO_ROARAUDIO || byteorder != ROAR_BYTEORDER_NETWORK )
144  return -1;
145
146 if ( (client = clients_new()) == -1 )
147  return -1;
148
149 if ( clients_set_fh(client, fh) == -1 ) {
150  clients_delete(client);
151  return -1;
152 }
153
154 if ( update_nnode ) {
155  if ( clients_get(client, &c) != -1 ) {
156   if ( roar_nnode_free(&(c->nnode)) != -1 ) {
157    roar_nnode_new_from_fh(&(c->nnode), fh, 1);
158   }
159  }
160 }
161
162 return 0;
163}
164
165int clients_delete (int id) {
166 struct roar_client_server * cs;
167 int i;
168 int close_client_fh = 1;
169
170 ROAR_DBG("clients_delete(id=%i) = ?", id);
171
172 _CHECK_CID(id);
173
174 cs = g_clients[id];
175
176 if ( cs->waits != NULL ) {
177  for (i = 0; cs->waits[i] != NULL; i++)
178   roar_notify_core_unsubscribe(NULL, cs->waits[i]);
179
180  roar_mm_free(cs->waits);
181  cs->waits = NULL;
182 }
183
184 roar_notify_core_emit_snoargs(ROAR_OE_BASICS_DELETE, -1, id, ROAR_OT_CLIENT);
185
186 counters_inc(clients, -1);
187
188 if (ROAR_CLIENT(cs)->execed != -1) {
189//  return streams_delete(g_clients[id]->execed);
190  ROAR_CLIENT(cs)->execed = -1;
191  close_client_fh = 0;
192 }
193
194 for (i = 0; i < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; i++) {
195  streams_delete(ROAR_CLIENT(cs)->streams[i]);
196 }
197
198 if ( ROAR_CLIENT(cs)->fh != -1 && close_client_fh )
199  close(ROAR_CLIENT(cs)->fh);
200
201 roar_nnode_free(&(ROAR_CLIENT(cs)->nnode));
202
203 if ( cs->inbuf != NULL )
204  roar_buffer_free(cs->inbuf);
205
206 if ( cs->outbuf != NULL )
207  roar_buffer_free(cs->outbuf);
208
209 roar_mm_free(cs);
210 g_clients[id] = NULL;
211
212 ROAR_DBG("clients_delete(id=%i) = 0", id);
213 return 0;
214}
215
216int clients_close      (int id, int nocheck_exec) {
217 struct roar_client * c;
218
219 ROAR_DBG("clients_close(id=%i) = ?", id);
220
221 _CHECK_CID(id);
222
223 c = ROAR_CLIENT(g_clients[id]);
224
225 if ( c->fh == -1 ) {
226  ROAR_DBG("clients_delete(id=%i) = 0", id);
227  return 0;
228 }
229
230 if (nocheck_exec || c->execed != -1) {
231  close(c->fh);
232  c->fh = -1;
233 }
234
235 ROAR_DBG("clients_delete(id=%i) = 0", id);
236 return 0;
237}
238
239int clients_get       (int id, struct roar_client ** client) {
240 _CHECK_CID(id);
241
242 *client = ROAR_CLIENT(g_clients[id]);
243
244 if ( *client == NULL )
245  return -1;
246
247 return 0;
248}
249
250int clients_get_server (int id, struct roar_client_server ** client) {
251 _CHECK_CID(id);
252
253 *client = g_clients[id];
254
255 if ( *client == NULL )
256  return -1;
257
258 return 0;
259}
260
261int clients_set_fh    (int id, int    fh) {
262 struct roar_client * c;
263#ifdef SO_PEERCRED
264 struct ucred cred;
265 socklen_t cred_len = sizeof(cred);
266#endif
267
268 _CHECK_CID(id);
269
270 if ( (c = ROAR_CLIENT(g_clients[id])) == NULL )
271  return -1;
272
273 c->fh = fh;
274
275 if ( fh == -1 )
276  return 0;
277
278#ifdef SO_PEERCRED
279 if (getsockopt(fh, SOL_SOCKET, SO_PEERCRED, &cred, &cred_len) != -1) {
280  if ( cred.pid != 0 ) {
281   c->pid = cred.pid;
282   c->uid = cred.uid;
283   c->gid = cred.gid;
284  }
285 } else {
286  ROAR_DBG("req_on_identify(): Can't get creds via SO_PEERCRED: %s", strerror(errno));
287 }
288#elif defined(ROAR_HAVE_GETPEEREID)
289 if (getpeereid(fh, &(c->uid), &(c->gid)) == -1) {
290  ROAR_DBG("req_on_identify(): Can't get creds via getpeereid(): %s", strerror(errno));
291 }
292#endif
293
294 return 0;
295}
296
297int clients_get_fh    (int id) {
298 _CHECK_CID(id);
299
300 return ROAR_CLIENT(g_clients[id])->fh;
301}
302
303int clients_set_pid   (int id, int    pid) {
304 _CHECK_CID(id);
305
306 ROAR_CLIENT(g_clients[id])->pid = pid;
307
308 return 0;
309}
310
311int clients_set_uid   (int id, int    uid) {
312 _CHECK_CID(id);
313
314 ROAR_CLIENT(g_clients[id])->uid = uid;
315
316 return 0;
317}
318
319int clients_set_gid   (int id, int    gid) {
320 _CHECK_CID(id);
321
322 ROAR_CLIENT(g_clients[id])->gid = gid;
323
324 return 0;
325}
326
327int clients_set_proto (int id, int    proto) {
328 int byteorder = ROAR_BYTEORDER_UNKNOWN;
329
330 _CHECK_CID(id);
331
332 switch (proto) {
333  case ROAR_PROTO_ROARAUDIO:
334  case ROAR_PROTO_ESOUND:
335  case ROAR_PROTO_RPLAY:
336  case ROAR_PROTO_SIMPLE:
337    byteorder = ROAR_BYTEORDER_NETWORK;
338   break;
339 }
340
341 ROAR_CLIENT(g_clients[id])->proto     = proto;
342 ROAR_CLIENT(g_clients[id])->byteorder = byteorder;
343
344 return 0;
345}
346
347int clients_block      (int id, int unblock) {
348 _CHECK_CID(id);
349
350 if ( unblock ) {
351  g_clients[id]->blockc--;
352 } else {
353  g_clients[id]->blockc++;
354 }
355
356 return 0;
357}
358
359
360#define MAX_STREAMLESS 8
361
362int clients_check_all (void) {
363#ifdef ROAR_HAVE_SELECT
364 struct roar_client * c;
365 struct timeval tv;
366 fd_set r, w, e;
367 int i, j;
368 int ret;
369 int fh;
370 int max_fh = -1;
371 int have = 0;
372 struct {
373  int id;
374  int fh;
375 } streamless[MAX_STREAMLESS];
376 int have_streamless = 0;
377 int have_stream;
378
379 ROAR_DBG("clients_check_all(void) = ?");
380
381 FD_ZERO(&r);
382 FD_ZERO(&w);
383 FD_ZERO(&e);
384
385 tv.tv_sec  = 0;
386 tv.tv_usec = 1;
387
388 for (i = 0; i < ROAR_CLIENTS_MAX; i++) {
389  if ( (c = ROAR_CLIENT(g_clients[i])) == NULL )
390   continue;
391
392  ROAR_DBG("clients_check_all(void): i(client)=%i", i);
393
394  if ( (fh = c->fh) != -1 ) {
395   have++;
396
397   ROAR_DBG("clients_check_all(*): fh=%i", fh);
398
399   FD_SET(fh, &r);
400   FD_SET(fh, &e);
401
402   if ( g_clients[i]->outbuf != NULL ) {
403    FD_SET(fh, &w);
404   }
405
406   if ( fh > max_fh )
407    max_fh = fh;
408  }
409
410  have_stream = 0;
411
412  for (j = 0; j < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; j++) {
413   ROAR_DBG("clients_check_all(void): i(client)=%i, j(stream)=%i", i, j);
414   if ( (fh = streams_get_fh(c->streams[j])) != -1 ) {
415    ROAR_DBG("clients_check_all(*): g_clients[i=%i]->streams[j=%i] = %i, fh = %i", i, j, c->streams[j], fh);
416    if ( fh > -1 ) {
417     FD_SET(fh, &r);
418
419     if ( fh > max_fh )
420      max_fh = fh;
421    } else if ( fh == -2 ) {
422     streams_check(c->streams[j]);
423    }
424
425    have_stream = 1;
426   }
427   //printf("D: client=%i, stream=%i, fh=%i\n", i, j, fh);
428  }
429
430  if ( !have_stream && have_streamless < MAX_STREAMLESS ) {
431   streamless[have_streamless  ].id = i;
432   if ( (streamless[have_streamless++].fh = c->fh) == -1 )
433    have_streamless--;
434  }
435 }
436
437 ROAR_DBG("clients_check_all(void): max_fh=%i", max_fh);
438
439 if ( max_fh == -1 )
440  return 0;
441
442 if ( (ret = select(max_fh + 1, &r, &w, &e, &tv)) < 1 ) {
443  return ret < 0 ? ret : have;
444 }
445
446 for (i = 0; i < ROAR_CLIENTS_MAX; i++) {
447  if ( (c = ROAR_CLIENT(g_clients[i])) == NULL )
448   continue;
449
450  if ( (fh = c->fh) != -1 ) {
451   if ( FD_ISSET(fh, &r) ) {
452    if ( c->execed == -1 ) {
453     clients_check(i);
454     if ( g_clients[i] != NULL && ROAR_CLIENT(g_clients[i])->execed != -1 ) {
455      FD_CLR(fh, &r);
456     }
457/*
458    } else {
459     streams_check(g_clients[i]->execed);
460*/
461    }
462   }
463   if ( FD_ISSET(fh, &w) ) {
464    clients_flush(i);
465   }
466
467   if ( FD_ISSET(fh, &e) ) {
468    clients_delete(i);
469    continue;
470   }
471  }
472
473  if ( (c = ROAR_CLIENT(g_clients[i])) == NULL )
474   continue;
475
476  for (j = 0; j < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; j++) {
477   ROAR_DBG("clients_check_all(*): D: client=%i, stream=%i, g_clients[i=%i] = %p", i, j, i, g_clients[i]);
478   if ( g_clients[i] == NULL ) // streams_check() bellow can delete our client (why?)
479    break;
480
481   //ROAR_WARN("clients_check_all(*): client=%i: client exists", i);
482   ROAR_DBG("clients_check_all(*): client=%i, stream=%i: id=%i", i, j, c->streams[j]);
483
484   if ( (fh = streams_get_fh(c->streams[j])) != -1 ) {
485    ROAR_DBG("clients_check_all(*): client=%i, stream=%i: fh=%i", i, j, fh);
486    if ( fh > -1 && FD_ISSET(fh, &r) ) {
487     streams_check(c->streams[j]);
488    }
489   }
490  }
491 }
492
493 if ( have_streamless ) {
494   FD_ZERO(&r);
495   FD_ZERO(&w);
496
497   tv.tv_sec  = 0;
498   tv.tv_usec = 1;
499
500   max_fh = -1;
501
502   for (i = 0; i < have_streamless; i++) {
503    if ( g_clients[j = streamless[i].id] == NULL )
504     continue;
505
506    if ( ROAR_CLIENT(g_clients[j])->execed != -1 )
507     continue;
508
509    fh = streamless[i].fh;
510
511    ROAR_DBG("clients_check_all(void): fh=%i", fh);
512    FD_SET(fh, &r);
513
514    if ( g_clients[j]->outbuf != NULL ) {
515     FD_SET(fh, &w);
516    }
517
518    if ( fh > max_fh )
519     max_fh = fh;
520   }
521
522   if ( (ret = select(max_fh + 1, &r, &w, NULL, &tv)) < 0 ) {
523    return ret;
524   }
525
526   for (i = 0; i < have_streamless; i++) {
527    if ( FD_ISSET(streamless[i].fh, &r) ) {
528     clients_check(streamless[i].id);
529    }
530    if ( FD_ISSET(streamless[i].fh, &w) ) {
531     clients_flush(streamless[i].id);
532    }
533   }
534 }
535
536 ROAR_DBG("clients_check_all(void) = %i // have value", have);
537 return have;
538#else
539 ROAR_DBG("clients_check_all(void) = -1");
540 return -1;
541#endif
542}
543
544int clients_check     (int id) {
545 struct roar_client   * c;
546 struct roar_message    m;
547 struct roar_connection con;
548 struct roar_vio_calls  vio;
549 struct roar_error_state errstate;
550 int command_error;
551 char * data = NULL;
552 int oldcmd;
553 int r;
554 int rv = 0;
555 uint32_t flags[2] = {COMMAND_FLAG_NONE, COMMAND_FLAG_NONE};
556 uint32_t event;
557 size_t i;
558
559 ROAR_DBG("clients_check(id=%i) = ?", id);
560
561 _CHECK_CID(id);
562
563 c = ROAR_CLIENT(g_clients[id]);
564
565 if ( c->fh == -1 )
566  return -1;
567
568 roar_connect_fh(&con, c->fh);
569
570 ROAR_DBG("clients_check(id=%i): c->proto=%i", id, c->proto);
571
572 switch (c->proto) {
573  case ROAR_PROTO_ROARAUDIO:
574    r = roar_recv_message(&con, &m, &data);
575
576    if ( r == -1 ) { // should we drop the client?
577     clients_delete(id);
578     return -1;
579    }
580
581    event = ROAR_NOTIFY_CMD2EVENT(m.cmd);
582
583    oldcmd = m.cmd;
584
585    roar_err_store(&errstate);
586    roar_err_clear_all();
587    r = command_exec(id, &m, &data, flags);
588    roar_err_update();
589    command_error = roar_error;
590    roar_err_restore(&errstate);
591
592    if ( r == -1 ) {
593     // use command_error to create an error frame here as soon as this is supported.
594     m.cmd     = ROAR_CMD_ERROR;
595     m.datalen = 0;
596     ROAR_DBG("clients_check(*): Exec of command faild!");
597    } else {
598     if ( m.cmd == oldcmd ) {
599      m.cmd     = ROAR_CMD_OK;
600      m.datalen = 0;
601     } else if ( m.cmd == ROAR_CMD_OK_STOP ) {
602      m.cmd     = ROAR_CMD_OK;
603      rv        = 1;
604     }
605    }
606    ROAR_DBG("clients_check(*): data=%p", data);
607
608    if ( flags[1] & COMMAND_FLAG_OUT_NOSEND ) {
609     roar_notify_core_emit_simple(event, id, -1, -1, -1, -1, NULL, 0);
610    } else {
611     roar_notify_core_emit_simple(event, id, -1, -1, m.cmd, -1, NULL, 0);
612     roar_send_message(&con, &m, flags[1] & COMMAND_FLAG_OUT_LONGDATA ? data : NULL);
613    }
614
615    if ( flags[1] & COMMAND_FLAG_OUT_CLOSECON )
616     clients_close(id, 1);
617
618   break;
619#ifndef ROAR_WITHOUT_DCOMP_EMUL_RSOUND
620  case ROAR_PROTO_RSOUND:
621    rv = emul_rsound_check_client(id, NULL);
622    if ( rv == 0 ) { // loop as long as we don't get an error.
623     while (rv == 0)
624      rv = emul_rsound_check_client(id, NULL);
625     rv = 0; // restore
626    } else { // in case of error delete the client
627     if (
628#ifdef EAGAIN
629          errno != EAGAIN      &&
630#endif
631#ifdef EWOULDBLOCK
632          errno != EWOULDBLOCK &&
633#endif
634#ifdef EINTR
635          errno != EINTR       &&
636#endif
637          1 ) {
638      rv = clients_delete(id);
639     } else {
640      rv = 0;
641     }
642    }
643   break;
644#endif
645  default:
646    rv = -1;
647    for (i = 0; g_proto[i].proto != -1; i++) {
648     if ( g_proto[i].proto == c->proto ) {
649      roar_vio_open_fh_socket(&vio, clients_get_fh(id));
650      rv = g_proto[i].check_client(id, &vio);
651     }
652    }
653 }
654
655 if ( data != NULL )
656  roar_mm_free(data);
657
658 ROAR_DBG("clients_check(id=%i) = %i", id, rv);
659 return rv;
660}
661
662int clients_flush      (int id) {
663 struct roar_vio_calls         vio;
664 struct roar_client_server   * cs;
665 struct roar_client          * c;
666 struct roard_proto          * p = NULL;
667 size_t i;
668 size_t len;
669 ssize_t ret;
670 void * buf;
671
672 _CHECK_CID(id);
673
674 c = ROAR_CLIENT(cs = g_clients[id]);
675
676 for (i = 0; g_proto[i].proto != -1; i++) {
677  if ( g_proto[i].proto == c->proto ) {
678   p = &(g_proto[i]);
679   break;
680  }
681 }
682
683 if ( p == NULL )
684  return -1;
685
686 roar_vio_open_fh_socket(&vio, clients_get_fh(id));
687
688 if ( p->flush_client != NULL ) {
689  return p->flush_client(id, &vio);
690 }
691
692 if ( roar_buffer_get_len(cs->outbuf, &len) == -1 )
693  return -1;
694
695 if ( roar_buffer_get_data(cs->outbuf, &buf) == -1 )
696  return -1;
697
698 ret = roar_vio_write(&vio, buf, len);
699
700 if ( ret < 1 ) {
701  clients_delete(id);
702  return -1;
703 }
704
705 if ( ret == len ) {
706  if ( roar_buffer_next(&(cs->outbuf)) == -1 ) {
707   clients_delete(id);
708   return -1;
709  }
710 } else {
711  if ( roar_buffer_set_offset(cs->outbuf, ret) == -1 ) {
712   clients_delete(id);
713   return -1;
714  }
715 }
716
717 if ( cs->outbuf == NULL ) {
718  if ( p->flushed_client != NULL ) {
719   return p->flushed_client(id, &vio);
720  }
721 }
722
723 return 0;
724}
725
726int clients_send_mon  (struct roar_audio_info * sa, uint32_t pos) {
727 int i;
728// int fh;
729 int j;
730 int keep_going;
731
732 for (i = 0; i < ROAR_CLIENTS_MAX; i++) {
733  if ( g_clients[i] == NULL )
734   continue;
735
736  keep_going = 1;
737
738/*
739  if ( (fh = g_clients[i]->fh) == -1 )
740   continue;
741*/
742
743  ROAR_DBG("clients_send_mon(*): client=%i, execed=%i", i, ROAR_CLIENT(g_clients[i])->execed);
744
745/*
746  if ( g_clients[i]->execed == -1 ) {
747   // TODO: add some code to send a message to the client insetd of the raw data.
748*/
749   for (j = 0; keep_going && j < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; j++) {
750    //if ( (fh = streams_get_fh(g_clients[i]->streams[j])) != -1 ) {
751    ROAR_DBG("clients_send_mon(*): client=%i, stream=%i -> ?", i, j);
752    if ( ROAR_CLIENT(g_clients[i])->streams[j] != -1 ) {
753     ROAR_DBG("clients_send_mon(*): client=%i, stream=%i -> %i", i, j, ROAR_CLIENT(g_clients[i])->streams[j]);
754     streams_send_mon(ROAR_CLIENT(g_clients[i])->streams[j]);
755
756     // the client may be deleted here, check if it still exists:
757     if ( g_clients[i] == NULL )
758      keep_going = 0;
759    }
760   }
761/*
762  } else {
763//   streams_check(g_clients[i]->execed);
764   streams_send_mon(g_clients[i]->execed);
765//   if ( streams_send_mon(g_clients[i]->execed) == -1 )
766//    clients_delete(i); // delete client in case we could not write
767  }
768*/
769 }
770
771 // TODO: FIXME: should this really be -1?
772 return -1;
773}
774
775int clients_send_filter(struct roar_audio_info * sa, uint32_t pos) {
776 struct roar_client * c;
777 int i;
778 int fh;
779
780 for (i = 0; i < ROAR_CLIENTS_MAX; i++) {
781  if ( (c = ROAR_CLIENT(g_clients[i])) == NULL )
782   continue;
783
784  if ( (fh = c->fh) == -1 )
785   continue;
786
787  if ( c->execed == -1 ) {
788   // TODO: add some code to send a message to the client insetd of the raw data.
789  } else {
790//   streams_check(g_clients[i]->execed);
791   streams_send_filter(c->execed);
792//   if ( streams_send_mon(g_clients[i]->execed) == -1 )
793//    clients_delete(i); // delete client in case we could not write
794  }
795 }
796
797 return -1;
798}
799
800int clients_add_output (int id, struct roar_buffer * buf) {
801 struct roar_client_server   * cs;
802
803 _CHECK_CID(id);
804 cs = g_clients[id];
805
806 if ( cs->outbuf == NULL ) {
807  cs->outbuf = buf;
808 } else {
809  return roar_buffer_add(cs->outbuf, buf);
810 }
811
812 return 0;
813}
814
815// proto support
816int clients_register_proto(struct roard_proto * proto) {
817 const size_t len = sizeof(g_proto)/sizeof(*g_proto);
818 size_t i;
819
820 if ( proto == NULL )
821  return -1;
822
823 for (i = 0; g_proto[i].proto != -1; i++);
824
825 // i is now at pos of current EOS entry.
826
827 // test if we have space for one more entry:
828 if ( (i+1) >= len )
829  return -1;
830
831 memcpy(&(g_proto[i]), proto, sizeof(*g_proto));
832
833 return 0;
834}
835
836int clients_unregister_proto(int proto) {
837 const size_t len = sizeof(g_proto)/sizeof(*g_proto);
838 size_t i;
839
840 if ( proto < 0 ) {
841  roar_err_set(ROAR_ERROR_RANGE);
842  return -1;
843 }
844
845 for (i = 0; i < len; i++) {
846  if ( g_proto[i].proto == proto ) {
847   memset(&(g_proto[i]), 0, sizeof(*g_proto));
848   g_proto[i].proto = -1;
849   return 0;
850  }
851 }
852
853 roar_err_set(ROAR_ERROR_NOENT);
854 return -1;
855}
856
857void print_protolist        (enum output_format format) {
858 const size_t len = sizeof(g_proto)/sizeof(*g_proto);
859 struct roard_proto * p;
860 char subsys[7] = "      ";
861 size_t i;
862
863 switch (format) {
864  case FORMAT_NATIVE:
865    printf("  Protocol Flag Subsys - Description\n");
866    printf("------------------------------------------------------\n");
867    printf("  roar          WM LRX - RoarAudio native protocol\n");
868#ifndef ROAR_WITHOUT_DCOMP_EMUL_SIMPLE
869    printf("  simple        WM LRX - PulseAudio simple protocol\n");
870#endif
871#ifndef ROAR_WITHOUT_DCOMP_EMUL_RSOUND
872    printf("  rsound        W      - RSound emulation\n");
873#endif
874   break;
875  case FORMAT_WIKI:
876    printf("||=Protocol =||=Flag =||=Subsys =||=Description              =||\n");
877    printf("||roar       ||       ||WM LRX   ||RoarAudio native protocol  ||\n");
878#ifndef ROAR_WITHOUT_DCOMP_EMUL_SIMPLE
879    printf("||simple     ||       ||WM LRX   ||PulseAudio simple protocol ||\n");
880#endif
881#ifndef ROAR_WITHOUT_DCOMP_EMUL_RSOUND
882    printf("||rsound     ||       ||W        ||RSound emulation           ||\n");
883#endif
884   break;
885  case FORMAT_CSV:
886    printf("Protocol,Flag,Subsys,Description\n");
887    printf("roar,,WM LRX,RoarAudio native protocol\n");
888#ifndef ROAR_WITHOUT_DCOMP_EMUL_SIMPLE
889    printf("simple,,WM LRX,PulseAudio simple protocol\n");
890#endif
891#ifndef ROAR_WITHOUT_DCOMP_EMUL_RSOUND
892    printf("rsound,,W,RSound emulation\n");
893#endif
894   break;
895  default:
896    roar_err_set(ROAR_ERROR_NOTSUP);
897    return;
898 }
899
900 for (i = 0; i < len; i++) {
901  p = &(g_proto[i]);
902  if ( p->proto == -1 )
903   continue;
904
905  strncpy(subsys, "      ", 6);
906
907  if ( p->subsystems & ROAR_SUBSYS_WAVEFORM )
908   subsys[0] = 'W';
909  if ( p->subsystems & ROAR_SUBSYS_MIDI )
910   subsys[1] = 'M';
911  if ( p->subsystems & ROAR_SUBSYS_CB )
912   subsys[2] = 'C';
913  if ( p->subsystems & ROAR_SUBSYS_LIGHT )
914   subsys[3] = 'L';
915  if ( p->subsystems & ROAR_SUBSYS_RAW )
916   subsys[4] = 'R';
917  if ( p->subsystems & ROAR_SUBSYS_COMPLEX )
918   subsys[5] = 'X';
919
920  switch (format) {
921   case FORMAT_NATIVE:
922     printf("  %-13s %s - %s\n", roar_proto2str(p->proto), subsys, p->description);
923    break;
924   case FORMAT_WIKI:
925     printf("||%s || ||%s ||%s ||\n", roar_proto2str(p->proto), subsys, p->description);
926    break;
927   case FORMAT_CSV:
928     printf("%s,,%s,%s\n", roar_proto2str(p->proto), subsys, p->description);
929    break;
930  }
931 }
932}
933
934int client_stream_exec   (int client, int stream) {
935 struct roar_client * c;
936 int i;
937 int fh;
938
939 _CHECK_CID(client);
940
941#if 0
942 if ( g_clients[client] == NULL ) {
943  ROAR_WARN("client_stream_exec(client=%i, stream=%i) = -1 // client does not exist", client, stream);
944  return -1;
945 }
946#endif
947
948 c = ROAR_CLIENT(g_clients[client]);
949
950 for (i = 0; i < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; i++) {
951  if ( c->streams[i] == stream ) {
952   c->execed = stream;
953   if ( streams_is_ready(stream) == 0 ) {
954    streams_set_fh(stream, c->fh);
955    streams_set_socktype(stream, ROAR_SOCKET_TYPE_GENSTR);
956   } else {
957    ROAR_DBG("client_stream_exec(client=%i, stream=%i): fh=?", client, stream);
958    if ( (fh = c->fh) != -1 ) {
959     close(fh);
960     c->fh = -1;
961    }
962   }
963   ROAR_DBG("client_stream_exec(client=%i, stream=%i) = 0", client, stream);
964   return 0;
965  }
966 }
967
968 ROAR_WARN("client_stream_exec(client=%i, stream=%i) = -1 // client does not own stream", client, stream);
969 return -1;
970}
971
972int client_stream_set_fh (int client, int stream, int fh) {
973 int i;
974
975 ROAR_DBG("client_stream_set_fh(client=%i, stream=%i, fh=%i) = ?", client, stream, fh);
976
977 _CHECK_CID(client);
978
979 for (i = 0; i < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; i++) {
980  if ( ROAR_CLIENT(g_clients[client])->streams[i] == stream ) {
981   ROAR_DBG("client_stream_set_fh(client=%i, stream=%i, fh=%i): stream found, index %i", client, stream, fh, i);
982   return streams_set_fh(stream, fh);
983  }
984 }
985
986 ROAR_WARN("client_stream_set_fh(client=%i, stream=%i, fh=%i) = -1 // client does not own stream", client, stream, fh);
987 return -1;
988}
989
990int client_stream_add    (int client, int stream) {
991 int i;
992
993 _CHECK_CID(client);
994
995 for (i = 0; i < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; i++) {
996  if ( ROAR_CLIENT(g_clients[client])->streams[i] == -1 ) {
997   ROAR_CLIENT(g_clients[client])->streams[i] = stream;
998   streams_set_client(stream, client);
999   return 0;
1000  }
1001 }
1002
1003 return -1;
1004}
1005
1006int client_stream_delete (int client, int stream) {
1007 int i;
1008
1009 _CHECK_CID(client);
1010
1011 for (i = 0; i < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; i++) {
1012  if ( ROAR_CLIENT(g_clients[client])->streams[i] == stream ) {
1013   ROAR_CLIENT(g_clients[client])->streams[i] = -1;
1014
1015   if ( stream == ROAR_CLIENT(g_clients[client])->execed ) {
1016    ROAR_DBG("client_stream_delete(client=%i, stream=%i): stream is execed one, deleting client!", client, stream);
1017    clients_delete(client);
1018   }
1019
1020   ROAR_DBG("client_stream_delete(client=%i, stream=%i) = 0", client, stream);
1021   return 0;
1022  }
1023 }
1024
1025 ROAR_DBG("client_stream_delete(client=%i, stream=%i) = -1", client, stream);
1026 return -1;
1027}
1028
1029int client_stream_move   (int client, int stream) {
1030 int old_client = streams_get_client(stream);
1031
1032 ROAR_DBG("client_stream_move(client=%i, stream=%i): old_client = %i", client, stream, old_client);
1033
1034 if ( old_client != -1 )
1035  if ( client_stream_delete(old_client, stream) == -1 )
1036   return -1;
1037
1038 return client_stream_add(client, stream);
1039}
1040
1041
1042// notify thingys
1043int clients_wait    (int client, struct roar_event * events, size_t num) {
1044 struct roar_client_server * cs;
1045 size_t i, c;
1046
1047 ROAR_DBG("clients_wait(client=%i, events=%p, num=%llu) = ?", client, events, (long long unsigned int)num);
1048
1049 _CHECK_CID(client);
1050
1051 cs = g_clients[client];
1052
1053 if ( cs->waits != NULL )
1054  return -1;
1055
1056 cs->waits = roar_mm_malloc((num+1) * sizeof(struct roar_subscriber *));
1057
1058 if ( cs->waits == NULL )
1059  return -1;
1060
1061 if ( clients_block(client, 0) != 0 )
1062  return -1;
1063
1064 for (i = 0; i < num; i++) {
1065#if defined(DEBUG) && 0
1066  dbg_notify_cb(NULL, &(events[i]), cs);
1067#endif
1068  cs->waits[i] = roar_notify_core_subscribe(NULL, &(events[i]), clients_ncb_wait, cs);
1069  if ( cs->waits[i] == NULL ) {
1070   for (c = 0; c < i; c++)
1071    roar_notify_core_unsubscribe(NULL, cs->waits[c]);
1072   roar_mm_free(cs->waits);
1073   cs->waits = NULL;
1074   clients_block(client, 1);
1075   return -1;
1076  }
1077 }
1078
1079 cs->waits[num] = NULL;
1080
1081 ROAR_DBG("clients_wait(client=%i, events=%p, num=%llu) = 0", client, events, (long long unsigned int)num);
1082 return 0;
1083}
1084
1085void clients_ncb_wait(struct roar_notify_core * core, struct roar_event * event, void * userdata) {
1086 struct roar_client_server * cs = userdata;
1087 struct roar_message m;
1088 struct roar_connection con;
1089 uint16_t * u16 = (uint16_t *) m.data;
1090 size_t tmp;
1091 size_t i;
1092
1093 ROAR_DBG("clients_ncb_wait(core=%p, event=%p, userdata=%p) = ?", core, event, userdata);
1094
1095 for (i = 0; cs->waits[i] != NULL; i++)
1096  roar_notify_core_unsubscribe(NULL, cs->waits[i]);
1097
1098 roar_mm_free(cs->waits);
1099 cs->waits = NULL;
1100
1101 // protocol depended handling...
1102 memset(&m, 0, sizeof(m));
1103 m.cmd = ROAR_CMD_OK;
1104 u16[0] = ROAR_HOST2NET16(0); // Version
1105 u16[1] = ROAR_HOST2NET16(0); // flags
1106
1107 tmp = sizeof(m.data) - 4;
1108
1109 roar_event_to_blob(event, m.data + 4, &tmp);
1110
1111 m.datalen = tmp + 4;
1112
1113 roar_connect_fh(&con, ROAR_CLIENT(cs)->fh);
1114 roar_send_message(&con, &m, NULL);
1115 // ...end of protocol depended handling.
1116
1117// clients_block(, 1);
1118 // TODO: FIXME: bad hack...
1119 cs->blockc--;
1120}
1121
1122
1123// acclev:
1124static struct {
1125 const enum roard_client_acclev acclev;
1126 const char *                   name;
1127} _g_acclevs[] = {
1128 {ACCLEV_NONE,    "none"   },
1129 {ACCLEV_IDENTED, "idented"},
1130 {ACCLEV_CONCTL,  "conctl" },
1131 {ACCLEV_GUEST,   "guest"  },
1132 {ACCLEV_USER,    "user"   },
1133 {ACCLEV_PWRUSER, "pwruser"},
1134 {ACCLEV_ALL,     "all"    },
1135 {-1, NULL}
1136};
1137
1138enum roard_client_acclev clients_str2acclev(const char * acclev) {
1139 int i;
1140
1141 for (i = 0; _g_acclevs[i].name != NULL; i++)
1142  if ( !strcasecmp(_g_acclevs[i].name, acclev) )
1143   return _g_acclevs[i].acclev;
1144
1145 return ACCLEV_ERROR;
1146}
1147
1148const char * clients_acclev2str(const enum roard_client_acclev acclev) {
1149 int i;
1150
1151 for (i = 0; _g_acclevs[i].name != NULL; i++)
1152  if ( _g_acclevs[i].acclev == acclev )
1153   return _g_acclevs[i].name;
1154
1155 return NULL;
1156}
1157
1158//ll
Note: See TracBrowser for help on using the repository browser.