source: roaraudio/roard/clients.c @ 5654:25b8ac2d3613

Last change on this file since 5654:25b8ac2d3613 was 5654:25b8ac2d3613, checked in by phi, 12 years ago

build CPI objects based on configure options

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