source: roaraudio/roard/clients.c @ 5804:8321b4018c95

Last change on this file since 5804:8321b4018c95 was 5804:8321b4018c95, checked in by phi, 11 years ago

honor ROAR_BROKEN_PEERCRED

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