source: roaraudio/roard/clients.c @ 5640:00dd1147ce70

Last change on this file since 5640:00dd1147ce70 was 5640:00dd1147ce70, checked in by phi, 12 years ago

Removed support for roard's proto support (replaced by CPI) (Closes: #278)

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