source: roaraudio/roard/clients.c @ 6052:d48765b2475e

Last change on this file since 6052:d48765b2475e was 6052:d48765b2475e, checked in by phi, 9 years ago

updated copyright headers

File size: 33.1 KB
Line 
1//clients.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2015
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];
34
35static struct roard_proto_handle __protos[MAX_PROTOS] = {
36 {.proto = ROAR_PROTO_ROARAUDIO, .lhandle = NULL, .type = ROARD_PROTO_TYPE_BUILDIN,
37 .impl = {.buildin = 0}},
38 {.proto = -1}
39};
40
41#define _CHECK_CID_RET(id,ret) if ( (id) < 0 || (id) > ROAR_CLIENTS_MAX || g_clients[(id)] == NULL ) return (ret)
42#define _CHECK_CID(id)         _CHECK_CID_RET((id), -1)
43
44int clients_init (void) {
45 int i;
46
47 for (i = 0; i < ROAR_CLIENTS_MAX; i++)
48  g_clients[i] = NULL;
49
50 for (i = 0; __protos[i].proto != -1; i++);
51
52 for (; i < MAX_PROTOS; i++)
53  __protos[i].proto = -1;
54
55 return 0;
56}
57
58int clients_free (void) {
59 int i;
60
61 for (i = 0; i < ROAR_CLIENTS_MAX; i++)
62  if ( g_clients[i] != NULL )
63   clients_delete(i);
64
65 return 0;
66}
67
68int clients_new (void) {
69 int i;
70 int s;
71 struct roar_client_server * ns;
72 struct roar_client * n;
73
74 for (i = 0; i < ROAR_CLIENTS_MAX; i++) {
75  if ( g_clients[i] == NULL ) {
76   ns = roar_mm_malloc(sizeof(struct roar_client_server));
77   n = ROAR_CLIENT(ns);
78
79   memset(ns, 0, sizeof(struct roar_client_server));
80
81   if ( n != NULL ) {
82    n->pid    = -1;
83    n->uid    = -1;
84    n->gid    = -1;
85    n->fh     = -1;
86
87    *n->name = 0;
88
89    n->proto     = ROAR_PROTO_ROARAUDIO;
90    n->byteorder = ROAR_BYTEORDER_NETWORK;
91
92    n->acl   = NULL;
93
94    n->execed = -1;
95    for (s = 0; s < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; s++)
96     n->streams[s] = -1;
97
98    if ( roar_nnode_new(&(n->nnode), ROAR_SOCKET_TYPE_UNKNOWN) == -1 ) {
99     roar_mm_free(n);
100     return -1;
101    }
102
103    ns->blockc   = 0;
104    ns->waits    = NULL;
105    ns->acclev   = ACCLEV_NONE;
106
107    g_clients[i] = ns;
108
109    counters_inc(clients, 1);
110    roar_notify_core_emit_snoargs(ROAR_OE_BASICS_NEW, -1, i, ROAR_OT_CLIENT);
111    ROAR_DBG("clients_new(void) = %i", i);
112    return i;
113   } else {
114    ROAR_ERR("clients_new(void): Can not alloc memory for new client: %s", strerror(errno));
115    ROAR_ERR("clients_new(void) = -1");
116    return -1;
117   }
118  }
119 }
120
121 return -1;
122}
123
124int clients_new_from_fh(int fh, int proto, int byteorder, int update_nnode) {
125 return clients_new_from_fh2(fh, proto, byteorder, update_nnode, NULL, NULL, 0);
126}
127
128int clients_new_from_fh2(int fh, int proto, int byteorder,
129                         int update_nnode,
130                         struct roard_listen * lsock, struct sockaddr * sockaddr, socklen_t addrlen) {
131 const struct roard_proto_handle * protohandle;
132 struct roar_dl_librarypara * pluginpara;
133 struct roar_vio_calls    vio;
134 struct roar_client_server * cs;
135 int supported = 0;
136 int client;
137
138 if ( fh == -1 ) {
139  roar_err_set(ROAR_ERROR_BADFH);
140  return -1;
141 }
142
143 if ( lsock == NULL ) {
144  switch (proto) {
145   case ROAR_PROTO_RSOUND:
146   case ROAR_PROTO_SIMPLE:
147     roar_err_set(ROAR_ERROR_FAULT);
148     return -1;
149    break;
150  }
151 }
152
153 if ( byteorder != ROAR_BYTEORDER_NETWORK )
154  return -1;
155
156
157 if ( proto == ROAR_PROTO_RSOUND ) {
158#ifndef ROAR_WITHOUT_DCOMP_EMUL_RSOUND
159  client = emul_rsound_on_connect(fh, lsock);
160  switch (client) {
161   case -1: return -1; break;
162   case -2: return  0; break;
163   default: // TODO: write error handling
164     if ( clients_get_server(client, &cs) == -1 ) {
165      clients_delete(client);
166      return -1;
167     }
168
169     fh = ROAR_CLIENT(cs)->fh;
170    break;
171  }
172#else
173  roar_err_set(ROAR_ERROR_PROTONOSUP);
174  return -1;
175#endif
176 } else {
177  client = clients_new();
178
179  if ( client == -1 ) {
180   ROAR_DBG("clients_new_from_fh2(*) = -1 // can not create new client");
181   return -1;
182  }
183
184  if ( clients_set_fh(client, fh) == -1 ) {
185   ROAR_ERR("clients_new_from_fh2(*): Can not set client's fh");
186
187   clients_delete(client);
188
189   ROAR_DBG("clients_new_from_fh2(*) = -1");
190   return -1;
191  }
192 }
193
194 if ( clients_get_server(client, &cs) == -1 ) {
195  clients_delete(client);
196  return -1;
197 }
198
199 if ( update_nnode ) {
200  if ( roar_nnode_free(&(ROAR_CLIENT(cs)->nnode)) != -1 ) {
201   if ( sockaddr != NULL && addrlen != 0 ) {
202    roar_nnode_new_from_sockaddr(&(ROAR_CLIENT(cs)->nnode), sockaddr, addrlen);
203   } else {
204    roar_nnode_new_from_fh(&(ROAR_CLIENT(cs)->nnode), fh, 1);
205   }
206  }
207 }
208
209 if ( clients_set_proto(client, proto) == -1 ) {
210  ROAR_WARN("clients_new_from_fh2(*): Setting proto(0x%.4x) of client %i failed.", proto, client);
211  clients_delete(client);
212  return -1;
213 }
214
215 switch (proto) {
216  case ROAR_PROTO_ROARAUDIO:
217    // nothing needed to be done here
218   break;
219#ifndef ROAR_WITHOUT_DCOMP_EMUL_SIMPLE
220  case ROAR_PROTO_SIMPLE:
221    if ( emul_simple_on_connect(client, lsock) == -1 )
222     return -1;
223   break;
224#endif
225#ifndef ROAR_WITHOUT_DCOMP_EMUL_RSOUND
226  case ROAR_PROTO_RSOUND: // nothing to do here.
227   break;
228#endif
229  default:
230    // OS independiend code to close the socket:
231    if ( roar_vio_open_fh_socket(&vio, fh) == -1 )
232     return -1;
233
234    protohandle = clients_get_protohandle(proto);
235    supported = 0;
236    if ( protohandle != NULL ) {
237     if ( protohandle->lhandle != NULL )
238      roar_dl_context_restore(protohandle->lhandle);
239     switch (protohandle->type) {
240      case ROARD_PROTO_TYPE_BUILDIN:
241        //this should not end up here.
242        ROAR_WARN("net_get_new_client(lsock=%p): proto(%i) marked as buildin but isn't. BAD.", lsock, proto);
243        supported = 0;
244       break;
245      case ROARD_PROTO_TYPE_COMMON:
246        supported = 1;
247        if ( protohandle->impl.common->set_proto != NULL ) {
248         pluginpara = roar_dl_getpara(protohandle->lhandle); // will return NULL in case protohandle->lhandle is NULL.
249         if ( protohandle->impl.common->set_proto(client, &vio, &(cs->outbuf), &(cs->protoinst), protohandle->para, protohandle->paralen, pluginpara) == -1 ) {
250          supported = 0;
251         }
252         if ( pluginpara != NULL )
253          roar_dl_para_unref(pluginpara);
254        }
255       break;
256     }
257     if ( protohandle->lhandle != NULL )
258      roar_dl_context_store(protohandle->lhandle);
259    }
260
261    if ( !supported ) {
262     clients_delete(client);
263     //roar_vio_close(&vio);
264     return -1;
265    }
266   break;
267 }
268
269
270 return 0;
271}
272
273int clients_delete (int id) {
274 struct roar_client_server * cs;
275 const struct roard_proto_handle * proto;
276 struct roar_dl_librarypara * pluginpara;
277 struct roar_vio_calls vio;
278 int i;
279 int close_client_fh = 1;
280
281 ROAR_DBG("clients_delete(id=%i) = ?", id);
282
283 _CHECK_CID(id);
284
285 cs = g_clients[id];
286
287 proto = clients_get_protohandle(ROAR_CLIENT(cs)->proto);
288 if ( proto != NULL ) {
289  if ( proto->lhandle != NULL )
290   roar_dl_context_restore(proto->lhandle);
291  switch (proto->type) {
292   case ROARD_PROTO_TYPE_BUILDIN:
293     /* noop */
294    break;
295   case ROARD_PROTO_TYPE_COMMON:
296     if ( proto->impl.common->unset_proto != NULL ) {
297      roar_vio_open_fh_socket(&vio, clients_get_fh(id));
298      pluginpara = roar_dl_getpara(proto->lhandle); // will return NULL in case protohandle->lhandle is NULL.
299      proto->impl.common->unset_proto(id, &vio, &(cs->outbuf), &(cs->protoinst), proto->para, proto->paralen, pluginpara);
300      if ( pluginpara != NULL )
301       roar_dl_para_unref(pluginpara);
302     }
303    break;
304  }
305  if ( proto->lhandle != NULL )
306   roar_dl_context_store(proto->lhandle);
307 }
308
309 if ( cs->waits != NULL ) {
310  for (i = 0; cs->waits[i] != NULL; i++)
311   roar_notify_core_unsubscribe(NULL, cs->waits[i]);
312
313  roar_mm_free(cs->waits);
314  cs->waits = NULL;
315 }
316
317 roar_notify_core_emit_snoargs(ROAR_OE_BASICS_DELETE, -1, id, ROAR_OT_CLIENT);
318
319 counters_inc(clients, -1);
320
321 if (ROAR_CLIENT(cs)->execed != -1) {
322//  return streams_delete(g_clients[id]->execed);
323  ROAR_CLIENT(cs)->execed = -1;
324  close_client_fh = 0;
325 }
326
327 for (i = 0; i < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; i++) {
328  streams_delete(ROAR_CLIENT(cs)->streams[i]);
329 }
330
331 if ( ROAR_CLIENT(cs)->fh != -1 && close_client_fh )
332  close(ROAR_CLIENT(cs)->fh);
333
334 roar_nnode_free(&(ROAR_CLIENT(cs)->nnode));
335
336 if ( cs->inbuf != NULL )
337  roar_buffer_free(cs->inbuf);
338
339 if ( cs->outbuf != NULL )
340  roar_buffer_free(cs->outbuf);
341
342 if ( cs->protoinst != NULL )
343  roar_mm_free(cs->protoinst);
344
345 roar_mm_free(cs);
346 g_clients[id] = NULL;
347
348 ROAR_DBG("clients_delete(id=%i) = 0", id);
349 return 0;
350}
351
352int clients_close      (int id, int nocheck_exec) {
353 struct roar_client * c;
354
355 ROAR_DBG("clients_close(id=%i) = ?", id);
356
357 _CHECK_CID(id);
358
359 c = ROAR_CLIENT(g_clients[id]);
360
361 if ( c->fh == -1 ) {
362  ROAR_DBG("clients_delete(id=%i) = 0", id);
363  return 0;
364 }
365
366 if (nocheck_exec || c->execed != -1) {
367  close(c->fh);
368  c->fh = -1;
369 }
370
371 ROAR_DBG("clients_delete(id=%i) = 0", id);
372 return 0;
373}
374
375int clients_get       (int id, struct roar_client ** client) {
376 _CHECK_CID(id);
377
378 *client = ROAR_CLIENT(g_clients[id]);
379
380 if ( *client == NULL )
381  return -1;
382
383 return 0;
384}
385
386int clients_get_server (int id, struct roar_client_server ** client) {
387 _CHECK_CID(id);
388
389 *client = g_clients[id];
390
391 if ( *client == NULL )
392  return -1;
393
394 return 0;
395}
396
397int clients_set_fh    (int id, int    fh) {
398 struct roar_client * c;
399#if defined(SO_PEERCRED) && !defined(ROAR_BROKEN_PEERCRED)
400 struct ucred cred;
401 socklen_t cred_len = sizeof(cred);
402#endif
403
404 _CHECK_CID(id);
405
406 if ( (c = ROAR_CLIENT(g_clients[id])) == NULL )
407  return -1;
408
409 c->fh = fh;
410
411 if ( fh == -1 )
412  return 0;
413
414#if defined(SO_PEERCRED) && !defined(ROAR_BROKEN_PEERCRED)
415 if (getsockopt(fh, SOL_SOCKET, SO_PEERCRED, &cred, &cred_len) != -1) {
416  if ( cred.pid != 0 ) {
417   c->pid = cred.pid;
418   c->uid = cred.uid;
419   c->gid = cred.gid;
420  }
421 } else {
422  ROAR_DBG("req_on_identify(): Can't get creds via SO_PEERCRED: %s", strerror(errno));
423 }
424#elif defined(ROAR_HAVE_GETPEEREID)
425 if (getpeereid(fh, &(c->uid), &(c->gid)) == -1) {
426  ROAR_DBG("req_on_identify(): Can't get creds via getpeereid(): %s", strerror(errno));
427 }
428#endif
429
430 return 0;
431}
432
433int clients_get_fh    (int id) {
434 _CHECK_CID(id);
435
436 return ROAR_CLIENT(g_clients[id])->fh;
437}
438
439int clients_set_pid   (int id, int    pid) {
440 _CHECK_CID(id);
441
442 ROAR_CLIENT(g_clients[id])->pid = pid;
443
444 return 0;
445}
446
447int clients_set_uid   (int id, int    uid) {
448 _CHECK_CID(id);
449
450 ROAR_CLIENT(g_clients[id])->uid = uid;
451
452 return 0;
453}
454
455int clients_set_gid   (int id, int    gid) {
456 _CHECK_CID(id);
457
458 ROAR_CLIENT(g_clients[id])->gid = gid;
459
460 return 0;
461}
462
463int clients_set_name   (int id, const char * name) {
464 _CHECK_CID(id);
465
466 strncpy(ROAR_CLIENT(g_clients[id])->name, name, ROAR_BUFFER_NAME-1);
467 ROAR_CLIENT(g_clients[id])->name[ROAR_BUFFER_NAME-1] = 0;
468
469 return 0;
470}
471
472int clients_set_proto (int id, int    proto) {
473 int byteorder = ROAR_BYTEORDER_UNKNOWN;
474
475 _CHECK_CID(id);
476
477 switch (proto) {
478  case ROAR_PROTO_ROARAUDIO:
479  case ROAR_PROTO_ESOUND:
480  case ROAR_PROTO_RPLAY:
481  case ROAR_PROTO_SIMPLE:
482    byteorder = ROAR_BYTEORDER_NETWORK;
483   break;
484 }
485
486 ROAR_CLIENT(g_clients[id])->proto     = proto;
487 ROAR_CLIENT(g_clients[id])->byteorder = byteorder;
488
489 return 0;
490}
491
492int clients_block      (int id, int unblock) {
493 _CHECK_CID(id);
494
495 if ( unblock ) {
496  g_clients[id]->blockc--;
497 } else {
498  g_clients[id]->blockc++;
499 }
500
501 return 0;
502}
503
504
505#define MAX_STREAMLESS 8
506
507int clients_check_all (void) {
508#ifdef ROAR_HAVE_SELECT
509 struct roar_client * c;
510 struct timeval tv;
511 fd_set r, w, e;
512 int i, j;
513 int ret;
514 int fh;
515 int max_fh = -1;
516 int have = 0;
517 struct {
518  int id;
519  int fh;
520 } streamless[MAX_STREAMLESS];
521 int have_streamless = 0;
522 int have_stream;
523
524 ROAR_DBG("clients_check_all(void) = ?");
525
526 FD_ZERO(&r);
527 FD_ZERO(&w);
528 FD_ZERO(&e);
529
530 tv.tv_sec  = 0;
531 tv.tv_usec = 1;
532
533 for (i = 0; i < ROAR_CLIENTS_MAX; i++) {
534  if ( (c = ROAR_CLIENT(g_clients[i])) == NULL )
535   continue;
536
537  ROAR_DBG("clients_check_all(void): i(client)=%i", i);
538
539  if ( (fh = c->fh) != -1 ) {
540   have++;
541
542   ROAR_DBG("clients_check_all(*): fh=%i", fh);
543
544   FD_SET(fh, &r);
545   FD_SET(fh, &e);
546
547   if ( g_clients[i]->outbuf != NULL ) {
548    FD_SET(fh, &w);
549   }
550
551   if ( fh > max_fh )
552    max_fh = fh;
553  }
554
555  have_stream = 0;
556
557  for (j = 0; j < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; j++) {
558   ROAR_DBG("clients_check_all(void): i(client)=%i, j(stream)=%i", i, j);
559   if ( (fh = streams_get_fh(c->streams[j])) != -1 ) {
560    ROAR_DBG("clients_check_all(*): g_clients[i=%i]->streams[j=%i] = %i, fh = %i", i, j, c->streams[j], fh);
561    if ( fh > -1 ) {
562     FD_SET(fh, &r);
563
564     if ( fh > max_fh )
565      max_fh = fh;
566    } else if ( fh == -2 ) {
567     streams_check(c->streams[j]);
568    }
569
570    have_stream = 1;
571   }
572   //printf("D: client=%i, stream=%i, fh=%i\n", i, j, fh);
573  }
574
575  if ( !have_stream && have_streamless < MAX_STREAMLESS ) {
576   streamless[have_streamless  ].id = i;
577   if ( (streamless[have_streamless++].fh = c->fh) == -1 )
578    have_streamless--;
579  }
580 }
581
582 ROAR_DBG("clients_check_all(void): max_fh=%i", max_fh);
583
584 if ( max_fh == -1 )
585  return 0;
586
587 if ( (ret = select(max_fh + 1, &r, &w, &e, &tv)) < 1 ) {
588  return ret < 0 ? ret : have;
589 }
590
591 for (i = 0; i < ROAR_CLIENTS_MAX; i++) {
592  if ( (c = ROAR_CLIENT(g_clients[i])) == NULL )
593   continue;
594
595  if ( (fh = c->fh) != -1 ) {
596   if ( FD_ISSET(fh, &r) ) {
597    if ( c->execed == -1 ) {
598     clients_check(i);
599     if ( g_clients[i] != NULL && ROAR_CLIENT(g_clients[i])->execed != -1 ) {
600      FD_CLR(fh, &r);
601     }
602/*
603    } else {
604     streams_check(g_clients[i]->execed);
605*/
606    }
607   }
608   if ( FD_ISSET(fh, &w) ) {
609    clients_flush(i);
610   }
611
612   if ( FD_ISSET(fh, &e) ) {
613    clients_delete(i);
614    continue;
615   }
616  }
617
618  if ( (c = ROAR_CLIENT(g_clients[i])) == NULL )
619   continue;
620
621  for (j = 0; j < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; j++) {
622   ROAR_DBG("clients_check_all(*): D: client=%i, stream=%i, g_clients[i=%i] = %p", i, j, i, g_clients[i]);
623   if ( g_clients[i] == NULL ) // streams_check() bellow can delete our client (why?)
624    break;
625
626   //ROAR_WARN("clients_check_all(*): client=%i: client exists", i);
627   ROAR_DBG("clients_check_all(*): client=%i, stream=%i: id=%i", i, j, c->streams[j]);
628
629   if ( (fh = streams_get_fh(c->streams[j])) != -1 ) {
630    ROAR_DBG("clients_check_all(*): client=%i, stream=%i: fh=%i", i, j, fh);
631    if ( fh > -1 && FD_ISSET(fh, &r) ) {
632     streams_check(c->streams[j]);
633    }
634   }
635  }
636 }
637
638 if ( have_streamless ) {
639   FD_ZERO(&r);
640   FD_ZERO(&w);
641
642   tv.tv_sec  = 0;
643   tv.tv_usec = 1;
644
645   max_fh = -1;
646
647   for (i = 0; i < have_streamless; i++) {
648    if ( g_clients[j = streamless[i].id] == NULL )
649     continue;
650
651    if ( ROAR_CLIENT(g_clients[j])->execed != -1 )
652     continue;
653
654    fh = streamless[i].fh;
655
656    ROAR_DBG("clients_check_all(void): fh=%i", fh);
657    FD_SET(fh, &r);
658
659    if ( g_clients[j]->outbuf != NULL ) {
660     FD_SET(fh, &w);
661    }
662
663    if ( fh > max_fh )
664     max_fh = fh;
665   }
666
667   if ( (ret = select(max_fh + 1, &r, &w, NULL, &tv)) < 0 ) {
668    return ret;
669   }
670
671   for (i = 0; i < have_streamless; i++) {
672    if ( FD_ISSET(streamless[i].fh, &r) ) {
673     clients_check(streamless[i].id);
674    }
675    if ( FD_ISSET(streamless[i].fh, &w) ) {
676     clients_flush(streamless[i].id);
677    }
678   }
679 }
680
681 ROAR_DBG("clients_check_all(void) = %i // have value", have);
682 return have;
683#else
684 ROAR_DBG("clients_check_all(void) = -1");
685 return -1;
686#endif
687}
688
689int clients_check     (int id) {
690 struct roar_client_server * cs;
691 struct roar_message    m;
692 struct roar_connection con;
693 struct roar_vio_calls  vio;
694 struct roar_error_state errstate;
695 const struct roard_proto_handle * proto;
696 struct roar_dl_librarypara * pluginpara;
697 int command_error;
698 char * data = NULL;
699 int oldcmd;
700 int r;
701 int rv = 0;
702 uint32_t flags[2] = {COMMAND_FLAG_NONE, COMMAND_FLAG_NONE};
703 uint32_t event;
704
705 ROAR_DBG("clients_check(id=%i) = ?", id);
706
707 _CHECK_CID(id);
708
709 cs = g_clients[id];
710
711 if ( ROAR_CLIENT(cs)->fh == -1 )
712  return -1;
713
714 if ( roar_connect_fh(&con, ROAR_CLIENT(cs)->fh) == -1 ) {
715  ROAR_WARN("clients_check(id=%i): Can not create con object for client: %s", id, roar_errorstring);
716 }
717
718 ROAR_DBG("clients_check(id=%i): c->proto=%i", id, ROAR_CLIENT(cs)->proto);
719
720 switch (ROAR_CLIENT(cs)->proto) {
721  case ROAR_PROTO_ROARAUDIO:
722    r = roar_recv_message(&con, &m, &data);
723
724    if ( r == -1 ) { // should we drop the client?
725     clients_delete(id);
726     return -1;
727    }
728
729    event = ROAR_NOTIFY_CMD2EVENT(m.cmd);
730
731    oldcmd = m.cmd;
732
733    roar_err_store(&errstate);
734    roar_err_clear_all();
735    r = command_exec(id, &m, &data, flags);
736    roar_err_update();
737    command_error = roar_error;
738    roar_err_restore(&errstate);
739
740    if ( r == -1 ) {
741     // use command_error to create an error frame here as soon as this is supported.
742     m.cmd     = ROAR_CMD_ERROR;
743     m.datalen = 0;
744     ROAR_DBG("clients_check(*): Exec of command faild!");
745    } else {
746     if ( m.cmd == oldcmd ) {
747      m.cmd     = ROAR_CMD_OK;
748      m.datalen = 0;
749     } else if ( m.cmd == ROAR_CMD_OK_STOP ) {
750      m.cmd     = ROAR_CMD_OK;
751      rv        = 1;
752     }
753    }
754    ROAR_DBG("clients_check(*): data=%p", data);
755
756    if ( flags[1] & COMMAND_FLAG_OUT_NOSEND ) {
757     roar_notify_core_emit_simple(event, id, -1, -1, -1, -1, NULL, 0);
758    } else {
759     roar_notify_core_emit_simple(event, id, -1, -1, m.cmd, -1, NULL, 0);
760     if ( roar_send_message(&con, &m, flags[1] & COMMAND_FLAG_OUT_LONGDATA ? data : NULL) == -1 ) {
761      ROAR_WARN("clients_check(id=%i): Can not send answer to client: %s", id, roar_errorstring);
762     }
763    }
764
765    if ( flags[1] & COMMAND_FLAG_OUT_CLOSECON )
766     clients_close(id, 1);
767
768    if ( flags[1] & COMMAND_FLAG_OUT_DELETE )
769     clients_delete(id);
770
771   break;
772#ifndef ROAR_WITHOUT_DCOMP_EMUL_RSOUND
773  case ROAR_PROTO_RSOUND:
774    rv = emul_rsound_check_client(id, NULL);
775    if ( rv == 0 ) { // loop as long as we don't get an error.
776     while (rv == 0)
777      rv = emul_rsound_check_client(id, NULL);
778     rv = 0; // restore
779    } else { // in case of error delete the client
780     if (
781#ifdef EAGAIN
782          errno != EAGAIN      &&
783#endif
784#ifdef EWOULDBLOCK
785          errno != EWOULDBLOCK &&
786#endif
787#ifdef EINTR
788          errno != EINTR       &&
789#endif
790          1 ) {
791      rv = clients_delete(id);
792     } else {
793      rv = 0;
794     }
795    }
796   break;
797#endif
798  default:
799    rv = -1;
800    proto = clients_get_protohandle(ROAR_CLIENT(cs)->proto);
801    if ( proto != NULL ) {
802     roar_vio_open_fh_socket(&vio, clients_get_fh(id));
803     if ( proto->lhandle != NULL )
804      roar_dl_context_restore(proto->lhandle);
805
806     switch (proto->type) {
807      case ROARD_PROTO_TYPE_BUILDIN:
808        ROAR_WARN("clients_check(id=%i): proto(%i) marked as buildin but isn't. BAD.", id, proto->proto);
809       break;
810      case ROARD_PROTO_TYPE_COMMON:
811        if ( proto->impl.common->handle != NULL ) {
812         pluginpara = roar_dl_getpara(proto->lhandle); // will return NULL in case protohandle->lhandle is NULL.
813         rv = proto->impl.common->handle(id, &vio, &(cs->outbuf), &(cs->protoinst), proto->para, proto->paralen, pluginpara);
814         if ( pluginpara != NULL )
815          roar_dl_para_unref(pluginpara);
816        }
817        if ( rv == -1 )
818         rv = clients_delete(id);
819       break;
820     }
821
822     if ( proto->lhandle != NULL )
823      roar_dl_context_store(proto->lhandle);
824    }
825 }
826
827 if ( data != NULL )
828  roar_mm_free(data);
829
830 ROAR_DBG("clients_check(id=%i) = %i", id, rv);
831 return rv;
832}
833
834int clients_flush      (int id) {
835 struct roar_vio_calls             vio;
836 struct roar_client_server       * cs;
837 struct roar_client              * c;
838 const struct roard_proto_handle * p;
839 struct roar_dl_librarypara * pluginpara;
840 size_t len;
841 ssize_t ret;
842 void * buf;
843 int rv;
844
845 _CHECK_CID(id);
846
847 c = ROAR_CLIENT(cs = g_clients[id]);
848
849 p = clients_get_protohandle(c->proto);
850
851 if ( p == NULL )
852  return -1;
853
854 roar_vio_open_fh_socket(&vio, clients_get_fh(id));
855
856 switch (p->type) {
857  case ROARD_PROTO_TYPE_BUILDIN:
858    /* noop */
859   break;
860  case ROARD_PROTO_TYPE_COMMON:
861    if ( p->impl.common->flush != NULL ) {
862     if ( p->lhandle != NULL )
863      roar_dl_context_restore(p->lhandle);
864     pluginpara = roar_dl_getpara(p->lhandle); // will return NULL in case protohandle->lhandle is NULL.
865     rv = p->impl.common->flush(id, &vio, &(cs->outbuf), &(cs->protoinst), p->para, p->paralen, pluginpara);
866     if ( p->lhandle != NULL )
867      roar_dl_context_store(p->lhandle);
868     if ( pluginpara != NULL )
869      roar_dl_para_unref(pluginpara);
870     if ( rv == -1 )
871      rv = clients_delete(id);
872     return rv;
873    }
874   break;
875 }
876
877 if ( roar_buffer_get_len(cs->outbuf, &len) == -1 )
878  return -1;
879
880 if ( roar_buffer_get_data(cs->outbuf, &buf) == -1 )
881  return -1;
882
883 ret = roar_vio_write(&vio, buf, len);
884
885 if ( ret < 1 && !(len == 0 && ret == 0) ) {
886  clients_delete(id);
887  return -1;
888 }
889
890 if ( ret == (ssize_t)len ) {
891  if ( roar_buffer_next(&(cs->outbuf)) == -1 ) {
892   clients_delete(id);
893   return -1;
894  }
895 } else {
896  if ( roar_buffer_set_offset(cs->outbuf, ret) == -1 ) {
897   clients_delete(id);
898   return -1;
899  }
900 }
901
902 if ( cs->outbuf == NULL ) {
903  switch (p->type) {
904   case ROARD_PROTO_TYPE_BUILDIN:
905     /* noop */
906    break;
907   case ROARD_PROTO_TYPE_COMMON:
908     if ( p->impl.common->flushed != NULL ) {
909      if ( p->lhandle != NULL )
910       roar_dl_context_restore(p->lhandle);
911      pluginpara = roar_dl_getpara(p->lhandle); // will return NULL in case protohandle->lhandle is NULL.
912      rv = p->impl.common->flushed(id, &vio, &(cs->outbuf), &(cs->protoinst), p->para, p->paralen, pluginpara);
913      if ( p->lhandle != NULL )
914       roar_dl_context_store(p->lhandle);
915      if ( pluginpara != NULL )
916       roar_dl_para_unref(pluginpara);
917      if ( rv == -1 )
918       rv = clients_delete(id);
919      return rv;
920     }
921    break;
922  }
923 }
924
925 return 0;
926}
927
928int clients_send_mon  (struct roar_audio_info * sa) {
929 int i;
930// int fh;
931 int j;
932 int keep_going;
933
934 for (i = 0; i < ROAR_CLIENTS_MAX; i++) {
935  if ( g_clients[i] == NULL )
936   continue;
937
938  keep_going = 1;
939
940/*
941  if ( (fh = g_clients[i]->fh) == -1 )
942   continue;
943*/
944
945  ROAR_DBG("clients_send_mon(*): client=%i, execed=%i", i, ROAR_CLIENT(g_clients[i])->execed);
946
947/*
948  if ( g_clients[i]->execed == -1 ) {
949   // TODO: add some code to send a message to the client insetd of the raw data.
950*/
951   for (j = 0; keep_going && j < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; j++) {
952    //if ( (fh = streams_get_fh(g_clients[i]->streams[j])) != -1 ) {
953    ROAR_DBG("clients_send_mon(*): client=%i, stream=%i -> ?", i, j);
954    if ( ROAR_CLIENT(g_clients[i])->streams[j] != -1 ) {
955     ROAR_DBG("clients_send_mon(*): client=%i, stream=%i -> %i", i, j, ROAR_CLIENT(g_clients[i])->streams[j]);
956     streams_send_mon(ROAR_CLIENT(g_clients[i])->streams[j]);
957
958     // the client may be deleted here, check if it still exists:
959     if ( g_clients[i] == NULL )
960      keep_going = 0;
961    }
962   }
963/*
964  } else {
965//   streams_check(g_clients[i]->execed);
966   streams_send_mon(g_clients[i]->execed);
967//   if ( streams_send_mon(g_clients[i]->execed) == -1 )
968//    clients_delete(i); // delete client in case we could not write
969  }
970*/
971 }
972
973 // TODO: FIXME: should this really be -1?
974 return -1;
975}
976
977int clients_send_filter(struct roar_audio_info * sa) {
978 struct roar_client * c;
979 int i;
980 int fh;
981
982 for (i = 0; i < ROAR_CLIENTS_MAX; i++) {
983  if ( (c = ROAR_CLIENT(g_clients[i])) == NULL )
984   continue;
985
986  if ( (fh = c->fh) == -1 )
987   continue;
988
989  if ( c->execed == -1 ) {
990   // TODO: add some code to send a message to the client insetd of the raw data.
991  } else {
992//   streams_check(g_clients[i]->execed);
993   streams_send_filter(c->execed);
994//   if ( streams_send_mon(g_clients[i]->execed) == -1 )
995//    clients_delete(i); // delete client in case we could not write
996  }
997 }
998
999 return -1;
1000}
1001
1002int clients_add_output (int id, struct roar_buffer ** buf) {
1003 struct roar_client_server   * cs;
1004
1005 _CHECK_CID(id);
1006 cs = g_clients[id];
1007
1008 if ( cs->outbuf == NULL ) {
1009  cs->outbuf = *buf;
1010 } else {
1011  return roar_buffer_moveinto(cs->outbuf, buf);
1012 }
1013
1014 return 0;
1015}
1016
1017// proto support
1018const struct roard_proto_handle * clients_get_protohandle(const int proto) {
1019 size_t i;
1020
1021 if ( proto < 0 ) {
1022  roar_err_set(ROAR_ERROR_INVAL);
1023  return NULL;
1024 }
1025
1026 for (i = 0; i < (sizeof(__protos)/sizeof(*__protos)); i++)
1027  if ( __protos[i].proto == proto )
1028   return &(__protos[i]);
1029
1030 roar_err_set(ROAR_ERROR_NOENT);
1031 return NULL;
1032}
1033
1034int clients_register_proto_common(const struct roar_dl_proto * proto, struct roar_dl_lhandle * lhandle) {
1035 const size_t len = sizeof(__protos)/sizeof(*__protos);
1036 size_t i;
1037
1038 ROAR_DBG("clients_register_proto_common(proto=%p, lhandle=%p) = ?", proto, lhandle);
1039
1040 if ( proto == NULL )
1041  return -1;
1042
1043 for (i = 0; __protos[i].proto != -1; i++);
1044
1045 // i is now at pos of current EOS entry.
1046
1047 // test if we have space for one more entry:
1048 if ( (i+1) >= len )
1049  return -1;
1050
1051 __protos[i].impl.common = proto;
1052
1053 __protos[i].proto   = proto->proto;
1054 __protos[i].type    = ROARD_PROTO_TYPE_COMMON;
1055 __protos[i].lhandle = lhandle;
1056
1057 return 0;
1058}
1059
1060int clients_unregister_proto(int proto) {
1061 size_t i;
1062
1063 if ( proto < 0 ) {
1064  roar_err_set(ROAR_ERROR_RANGE);
1065  return -1;
1066 }
1067
1068 for (i = 0; i < (sizeof(__protos)/sizeof(*__protos)); i++) {
1069  if ( __protos[i].proto == proto ) {
1070   memset(&(__protos[i]), 0, sizeof(*__protos));
1071   __protos[i].proto = -1;
1072   return 0;
1073  }
1074 }
1075
1076 roar_err_set(ROAR_ERROR_NOENT);
1077 return -1;
1078}
1079
1080void print_protolist        (enum output_format format) {
1081 struct roard_proto_handle * p;
1082 char flags[5] = "    ";
1083 char subsys[7] = "      ";
1084 const char * description;
1085 size_t i;
1086
1087 switch (format) {
1088  case FORMAT_NATIVE:
1089    printf("  Protocol Flag Subsys - Description\n");
1090    printf("------------------------------------------------------\n");
1091    printf("  roar     bb   WM LRX - RoarAudio native protocol\n");
1092#ifndef ROAR_WITHOUT_DCOMP_EMUL_SIMPLE
1093    printf("  simple   bb   WM LRX - PulseAudio simple protocol\n");
1094#endif
1095#ifndef ROAR_WITHOUT_DCOMP_EMUL_RSOUND
1096    printf("  rsound   bb   W      - RSound emulation\n");
1097#endif
1098   break;
1099  case FORMAT_WIKI:
1100    printf("||=Protocol =||=Flag =||=Subsys =||=Description              =||\n");
1101    printf("||roar       ||bb     ||WM LRX   ||RoarAudio native protocol  ||\n");
1102#ifndef ROAR_WITHOUT_DCOMP_EMUL_SIMPLE
1103    printf("||simple     ||bb     ||WM LRX   ||PulseAudio simple protocol ||\n");
1104#endif
1105#ifndef ROAR_WITHOUT_DCOMP_EMUL_RSOUND
1106    printf("||rsound     ||bb     ||W        ||RSound emulation           ||\n");
1107#endif
1108   break;
1109  case FORMAT_CSV:
1110    printf("Protocol,Flag,Subsys,Description\n");
1111    printf("roar,bb,WM LRX,RoarAudio native protocol\n");
1112#ifndef ROAR_WITHOUT_DCOMP_EMUL_SIMPLE
1113    printf("simple,bb,WM LRX,PulseAudio simple protocol\n");
1114#endif
1115#ifndef ROAR_WITHOUT_DCOMP_EMUL_RSOUND
1116    printf("rsound,bb,W,RSound emulation\n");
1117#endif
1118   break;
1119  default:
1120    roar_err_set(ROAR_ERROR_NOTSUP);
1121    return;
1122 }
1123
1124 for (i = 0; i < (sizeof(__protos)/sizeof(*__protos)); i++) {
1125  p = &(__protos[i]);
1126  if ( p->proto == -1 )
1127   continue;
1128
1129  strncpy(flags, "    ", 4);
1130  strncpy(subsys, "      ", 6);
1131  description = "(none)";
1132
1133  if ( p->lhandle != NULL ) {
1134   flags[0] = 'P';
1135  } else {
1136   flags[0] = 'b';
1137  }
1138
1139  switch (p->type) {
1140   case ROARD_PROTO_TYPE_BUILDIN:
1141     continue;
1142    break;
1143   case ROARD_PROTO_TYPE_COMMON:
1144     flags[1] = 'C';
1145     description = p->impl.common->description;
1146    break;
1147  }
1148
1149  switch (format) {
1150   case FORMAT_NATIVE:
1151     printf("  %-8s %s %s - %s\n", roar_proto2str(p->proto), flags, subsys, description);
1152    break;
1153   case FORMAT_WIKI:
1154     printf("||%s ||%s ||%s ||%s ||\n", roar_proto2str(p->proto), flags, subsys, description);
1155    break;
1156   case FORMAT_CSV:
1157     printf("%s,%s,%s,%s\n", roar_proto2str(p->proto), flags, subsys, description);
1158    break;
1159  }
1160 }
1161}
1162
1163int client_stream_exec   (int client, int stream) {
1164 struct roar_client * c;
1165 int i;
1166 int fh;
1167
1168 _CHECK_CID(client);
1169
1170#if 0
1171 if ( g_clients[client] == NULL ) {
1172  ROAR_WARN("client_stream_exec(client=%i, stream=%i) = -1 // client does not exist", client, stream);
1173  return -1;
1174 }
1175#endif
1176
1177 c = ROAR_CLIENT(g_clients[client]);
1178
1179 for (i = 0; i < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; i++) {
1180  if ( c->streams[i] == stream ) {
1181   c->execed = stream;
1182   if ( streams_is_ready(stream) == 0 ) {
1183    streams_set_fh(stream, c->fh);
1184    streams_set_socktype(stream, ROAR_SOCKET_TYPE_GENSTR);
1185   } else {
1186    ROAR_DBG("client_stream_exec(client=%i, stream=%i): fh=?", client, stream);
1187    if ( (fh = c->fh) != -1 ) {
1188     close(fh);
1189     c->fh = -1;
1190    }
1191   }
1192   ROAR_DBG("client_stream_exec(client=%i, stream=%i) = 0", client, stream);
1193   return 0;
1194  }
1195 }
1196
1197 ROAR_WARN("client_stream_exec(client=%i, stream=%i) = -1 // client does not own stream", client, stream);
1198 return -1;
1199}
1200
1201int client_stream_set_fh (int client, int stream, int fh) {
1202 int i;
1203
1204 ROAR_DBG("client_stream_set_fh(client=%i, stream=%i, fh=%i) = ?", client, stream, fh);
1205
1206 _CHECK_CID(client);
1207
1208 for (i = 0; i < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; i++) {
1209  if ( ROAR_CLIENT(g_clients[client])->streams[i] == stream ) {
1210   ROAR_DBG("client_stream_set_fh(client=%i, stream=%i, fh=%i): stream found, index %i", client, stream, fh, i);
1211   return streams_set_fh(stream, fh);
1212  }
1213 }
1214
1215 ROAR_WARN("client_stream_set_fh(client=%i, stream=%i, fh=%i) = -1 // client does not own stream", client, stream, fh);
1216 return -1;
1217}
1218
1219int client_stream_add    (int client, int stream) {
1220 int i;
1221
1222 _CHECK_CID(client);
1223
1224 for (i = 0; i < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; i++) {
1225  if ( ROAR_CLIENT(g_clients[client])->streams[i] == -1 ) {
1226   ROAR_CLIENT(g_clients[client])->streams[i] = stream;
1227   streams_set_client(stream, client);
1228   return 0;
1229  }
1230 }
1231
1232 return -1;
1233}
1234
1235int client_stream_delete (int client, int stream) {
1236 int i;
1237
1238 _CHECK_CID(client);
1239
1240 for (i = 0; i < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; i++) {
1241  if ( ROAR_CLIENT(g_clients[client])->streams[i] == stream ) {
1242   ROAR_CLIENT(g_clients[client])->streams[i] = -1;
1243
1244   if ( stream == ROAR_CLIENT(g_clients[client])->execed ) {
1245    ROAR_DBG("client_stream_delete(client=%i, stream=%i): stream is execed one, deleting client!", client, stream);
1246    clients_delete(client);
1247   }
1248
1249   ROAR_DBG("client_stream_delete(client=%i, stream=%i) = 0", client, stream);
1250   return 0;
1251  }
1252 }
1253
1254 ROAR_DBG("client_stream_delete(client=%i, stream=%i) = -1", client, stream);
1255 return -1;
1256}
1257
1258int client_stream_move   (int client, int stream) {
1259 int old_client = streams_get_client(stream);
1260
1261 ROAR_DBG("client_stream_move(client=%i, stream=%i): old_client = %i", client, stream, old_client);
1262
1263 if ( old_client != -1 )
1264  if ( client_stream_delete(old_client, stream) == -1 )
1265   return -1;
1266
1267 return client_stream_add(client, stream);
1268}
1269
1270
1271// notify thingys
1272int clients_wait    (int client, struct roar_event * events, size_t num) {
1273 struct roar_client_server * cs;
1274 size_t i, c;
1275
1276 ROAR_DBG("clients_wait(client=%i, events=%p, num=%llu) = ?", client, events, (long long unsigned int)num);
1277
1278 _CHECK_CID(client);
1279
1280 cs = g_clients[client];
1281
1282 if ( cs->waits != NULL )
1283  return -1;
1284
1285 cs->waits = roar_mm_malloc((num+1) * sizeof(struct roar_subscriber *));
1286
1287 if ( cs->waits == NULL )
1288  return -1;
1289
1290 if ( clients_block(client, 0) != 0 )
1291  return -1;
1292
1293 for (i = 0; i < num; i++) {
1294#if defined(DEBUG) && 0
1295  dbg_notify_cb(NULL, &(events[i]), cs);
1296#endif
1297  cs->waits[i] = roar_notify_core_subscribe(NULL, &(events[i]), clients_ncb_wait, cs);
1298  if ( cs->waits[i] == NULL ) {
1299   for (c = 0; c < i; c++)
1300    roar_notify_core_unsubscribe(NULL, cs->waits[c]);
1301   roar_mm_free(cs->waits);
1302   cs->waits = NULL;
1303   clients_block(client, 1);
1304   return -1;
1305  }
1306 }
1307
1308 cs->waits[num] = NULL;
1309
1310 ROAR_DBG("clients_wait(client=%i, events=%p, num=%llu) = 0", client, events, (long long unsigned int)num);
1311 return 0;
1312}
1313
1314void clients_ncb_wait(struct roar_notify_core * core, struct roar_event * event, void * userdata) {
1315 struct roar_client_server * cs = userdata;
1316 struct roar_message m;
1317 struct roar_connection con;
1318 uint16_t * u16 = (uint16_t *) m.data;
1319 size_t tmp;
1320 size_t i;
1321
1322 ROAR_DBG("clients_ncb_wait(core=%p, event=%p, userdata=%p) = ?", core, event, userdata);
1323
1324 for (i = 0; cs->waits[i] != NULL; i++)
1325  roar_notify_core_unsubscribe(NULL, cs->waits[i]);
1326
1327 roar_mm_free(cs->waits);
1328 cs->waits = NULL;
1329
1330 // protocol depended handling...
1331 memset(&m, 0, sizeof(m));
1332 m.cmd = ROAR_CMD_OK;
1333 u16[0] = ROAR_HOST2NET16(0); // Version
1334 u16[1] = ROAR_HOST2NET16(0); // flags
1335
1336 tmp = sizeof(m.data) - 4;
1337
1338 roar_event_to_blob(event, m.data + 4, &tmp);
1339
1340 m.datalen = tmp + 4;
1341
1342 roar_connect_fh(&con, ROAR_CLIENT(cs)->fh);
1343 roar_send_message(&con, &m, NULL);
1344 // ...end of protocol depended handling.
1345
1346// clients_block(, 1);
1347 // TODO: FIXME: bad hack...
1348 cs->blockc--;
1349}
1350
1351
1352// acclev:
1353static struct {
1354 const enum roard_client_acclev acclev;
1355 const char *                   name;
1356} _g_acclevs[] = {
1357 {ACCLEV_NONE,    "none"   },
1358 {ACCLEV_IDENTED, "idented"},
1359 {ACCLEV_CONCTL,  "conctl" },
1360 {ACCLEV_GUEST,   "guest"  },
1361 {ACCLEV_USER,    "user"   },
1362 {ACCLEV_PWRUSER, "pwruser"},
1363 {ACCLEV_ALL,     "all"    },
1364 {-1, NULL}
1365};
1366
1367enum roard_client_acclev clients_str2acclev(const char * acclev) {
1368 int i;
1369
1370 for (i = 0; _g_acclevs[i].name != NULL; i++)
1371  if ( !strcasecmp(_g_acclevs[i].name, acclev) )
1372   return _g_acclevs[i].acclev;
1373
1374 return ACCLEV_ERROR;
1375}
1376
1377const char * clients_acclev2str(const enum roard_client_acclev acclev) {
1378 int i;
1379
1380 for (i = 0; _g_acclevs[i].name != NULL; i++)
1381  if ( _g_acclevs[i].acclev == acclev )
1382   return _g_acclevs[i].name;
1383
1384 return NULL;
1385}
1386
1387//ll
Note: See TracBrowser for help on using the repository browser.