source: roaraudio/roard/clients.c @ 5608:584b36c566e2

Last change on this file since 5608:584b36c566e2 was 5608:584b36c566e2, checked in by phi, 12 years ago

Handle super long client names well (Closes: #286)

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