source: roaraudio/roard/clients.c @ 5653:a544ab772198

Last change on this file since 5653:a544ab772198 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
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
[5640]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
[5567]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)
[5640]58 {.proto = ROAR_PROTO_ESOUND, .lhandle = NULL, .type = ROARD_PROTO_TYPE_COMMON,
59 .impl = {.common = &__proto_common_esd}},
[4678]60#endif
61#ifndef ROAR_WITHOUT_DCOMP_EMUL_RPLAY
[5640]62 {.proto = ROAR_PROTO_RPLAY, .lhandle = NULL, .type = ROARD_PROTO_TYPE_COMMON,
63 .impl = {.common = &__proto_common_rplay}},
[4678]64#endif
[4703]65#ifndef ROAR_WITHOUT_DCOMP_EMUL_GOPHER
[5640]66 {.proto = ROAR_PROTO_GOPHER, .lhandle = NULL, .type = ROARD_PROTO_TYPE_COMMON,
67 .impl = {.common = &__proto_common_gopher}},
[4703]68#endif
[5567]69 {.proto = -1}
[4678]70};
71
[3910]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
[0]75int clients_init (void) {
76 int i;
77
78 for (i = 0; i < ROAR_CLIENTS_MAX; i++)
79  g_clients[i] = NULL;
80
[5567]81 for (i = 0; __protos[i].proto != -1; i++);
[5275]82
83 for (; i < MAX_PROTOS; i++)
[5567]84  __protos[i].proto = -1;
[5275]85
[0]86 return 0;
87}
88
89int clients_free (void) {
90 int i;
91
92 for (i = 0; i < ROAR_CLIENTS_MAX; i++)
[3910]93  if ( g_clients[i] != NULL )
[0]94   clients_delete(i);
95
96 return 0;
97}
98
99int clients_new (void) {
100 int i;
101 int s;
[4326]102 struct roar_client_server * ns;
[0]103 struct roar_client * n;
104
105 for (i = 0; i < ROAR_CLIENTS_MAX; i++) {
106  if ( g_clients[i] == NULL ) {
[4326]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
[0]112   if ( n != NULL ) {
113    n->pid    = -1;
[437]114    n->uid    = -1;
115    n->gid    = -1;
[0]116    n->fh     = -1;
117
118    *n->name = 0;
119
[2614]120    n->proto     = ROAR_PROTO_ROARAUDIO;
121    n->byteorder = ROAR_BYTEORDER_NETWORK;
[2517]122
[346]123    n->acl   = NULL;
124
[0]125    n->execed = -1;
126    for (s = 0; s < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; s++)
127     n->streams[s] = -1;
128
[2815]129    if ( roar_nnode_new(&(n->nnode), ROAR_SOCKET_TYPE_UNKNOWN) == -1 ) {
[3063]130     roar_mm_free(n);
[2815]131     return -1;
132    }
133
[4343]134    ns->blockc   = 0;
135    ns->waits    = NULL;
[4468]136    ns->acclev   = ACCLEV_NONE;
[4343]137
[4326]138    g_clients[i] = ns;
[0]139
[4101]140    counters_inc(clients, 1);
[4346]141    roar_notify_core_emit_snoargs(ROAR_OE_BASICS_NEW, -1, i, ROAR_OT_CLIENT);
[0]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
[3737]155int clients_new_from_fh(int fh, int proto, int byteorder, int update_nnode) {
[5571]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;
[5606]163 struct roar_dl_librarypara * pluginpara;
[5571]164 struct roar_vio_calls    vio;
[5576]165 struct roar_client_server * cs;
[5571]166 int supported = 0;
[3737]167 int client;
168
[5571]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 )
[3737]185  return -1;
186
187
[5571]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
[5576]195     fh = ROAR_CLIENT(cs)->fh;
[5571]196    break;
197  }
198#else
199  roar_err_set(ROAR_ERROR_PROTONOSUP);
[3737]200  return -1;
[5571]201#endif
202 } else {
203  client = clients_new();
[3737]204
[5571]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  }
[3737]218 }
219
[5576]220 if ( clients_get_server(client, &cs) == -1 ) {
221  clients_delete(client);
222  return -1;
223 }
224
[3737]225 if ( update_nnode ) {
[5576]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);
[3737]231   }
232  }
233 }
234
[5571]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 ) {
[5576]289     if ( protohandle->lhandle != NULL )
290      roar_dl_context_restore(protohandle->lhandle);
[5571]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;
[5576]297      case ROARD_PROTO_TYPE_COMMON:
298        supported = 1;
299        if ( protohandle->impl.common->set_proto != NULL ) {
[5606]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 ) {
[5576]302          supported = 0;
303         }
[5606]304         if ( pluginpara != NULL )
305          roar_dl_para_unref(pluginpara);
[5576]306        }
307       break;
[5571]308     }
[5576]309     if ( protohandle->lhandle != NULL )
310      roar_dl_context_store(protohandle->lhandle);
[5571]311    }
312
313    if ( !supported ) {
314     clients_delete(client);
315     //roar_vio_close(&vio);
316     return -1;
317    }
318   break;
319 }
320
321
[3737]322 return 0;
323}
324
[0]325int clients_delete (int id) {
[4394]326 struct roar_client_server * cs;
[5567]327 const struct roard_proto_handle * proto;
[5606]328 struct roar_dl_librarypara * pluginpara;
[5576]329 struct roar_vio_calls vio;
[0]330 int i;
[1164]331 int close_client_fh = 1;
[0]332
[2608]333 ROAR_DBG("clients_delete(id=%i) = ?", id);
334
[4394]335 _CHECK_CID(id);
336
337 cs = g_clients[id];
338
[5567]339 proto = clients_get_protohandle(ROAR_CLIENT(cs)->proto);
340 if ( proto != NULL ) {
[5576]341  if ( proto->lhandle != NULL )
342   roar_dl_context_restore(proto->lhandle);
[5567]343  switch (proto->type) {
344   case ROARD_PROTO_TYPE_BUILDIN:
345     /* noop */
346    break;
[5576]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));
[5606]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);
[5576]354     }
355    break;
[5452]356  }
[5576]357  if ( proto->lhandle != NULL )
358   roar_dl_context_store(proto->lhandle);
[5452]359 }
360
[4394]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
[4346]369 roar_notify_core_emit_snoargs(ROAR_OE_BASICS_DELETE, -1, id, ROAR_OT_CLIENT);
370
[4101]371 counters_inc(clients, -1);
372
[4395]373 if (ROAR_CLIENT(cs)->execed != -1) {
[0]374//  return streams_delete(g_clients[id]->execed);
[4395]375  ROAR_CLIENT(cs)->execed = -1;
[1164]376  close_client_fh = 0;
[0]377 }
378
379 for (i = 0; i < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; i++) {
[4395]380  streams_delete(ROAR_CLIENT(cs)->streams[i]);
[0]381 }
382
[4395]383 if ( ROAR_CLIENT(cs)->fh != -1 && close_client_fh )
384  close(ROAR_CLIENT(cs)->fh);
[0]385
[4395]386 roar_nnode_free(&(ROAR_CLIENT(cs)->nnode));
[2815]387
[4684]388 if ( cs->inbuf != NULL )
389  roar_buffer_free(cs->inbuf);
390
391 if ( cs->outbuf != NULL )
392  roar_buffer_free(cs->outbuf);
393
[5452]394 if ( cs->protoinst != NULL )
395  roar_mm_free(cs->protoinst);
396
[4395]397 roar_mm_free(cs);
[0]398 g_clients[id] = NULL;
399
400 ROAR_DBG("clients_delete(id=%i) = 0", id);
401 return 0;
402}
403
[3927]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
[4326]411 c = ROAR_CLIENT(g_clients[id]);
[3927]412
413 if ( c->fh == -1 ) {
414  ROAR_DBG("clients_delete(id=%i) = 0", id);
415  return 0;
416 }
417
[4326]418 if (nocheck_exec || c->execed != -1) {
[3927]419  close(c->fh);
420  c->fh = -1;
421 }
422
423 ROAR_DBG("clients_delete(id=%i) = 0", id);
424 return 0;
425}
426
[0]427int clients_get       (int id, struct roar_client ** client) {
[3910]428 _CHECK_CID(id);
429
[4326]430 *client = ROAR_CLIENT(g_clients[id]);
[0]431
432 if ( *client == NULL )
433  return -1;
434
435 return 0;
436}
437
[4468]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
[0]449int clients_set_fh    (int id, int    fh) {
[3713]450 struct roar_client * c;
451#ifdef SO_PEERCRED
452 struct ucred cred;
453 socklen_t cred_len = sizeof(cred);
454#endif
[501]455
[3910]456 _CHECK_CID(id);
457
[4326]458 if ( (c = ROAR_CLIENT(g_clients[id])) == NULL )
[0]459  return -1;
460
[3713]461 c->fh = fh;
462
[4947]463 if ( fh == -1 )
464  return 0;
465
[3713]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
[0]481
482 return 0;
483}
484
[755]485int clients_get_fh    (int id) {
[3910]486 _CHECK_CID(id);
[755]487
[4326]488 return ROAR_CLIENT(g_clients[id])->fh;
[755]489}
490
[0]491int clients_set_pid   (int id, int    pid) {
[3910]492 _CHECK_CID(id);
[0]493
[4326]494 ROAR_CLIENT(g_clients[id])->pid = pid;
[0]495
496 return 0;
497}
498
[439]499int clients_set_uid   (int id, int    uid) {
[3910]500 _CHECK_CID(id);
[439]501
[4326]502 ROAR_CLIENT(g_clients[id])->uid = uid;
[439]503
504 return 0;
505}
506
507int clients_set_gid   (int id, int    gid) {
[3910]508 _CHECK_CID(id);
[439]509
[4326]510 ROAR_CLIENT(g_clients[id])->gid = gid;
[439]511
512 return 0;
513}
514
[5607]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
[2517]524int clients_set_proto (int id, int    proto) {
[2614]525 int byteorder = ROAR_BYTEORDER_UNKNOWN;
526
[3910]527 _CHECK_CID(id);
[2517]528
[2614]529 switch (proto) {
530  case ROAR_PROTO_ROARAUDIO:
[2828]531  case ROAR_PROTO_ESOUND:
[3981]532  case ROAR_PROTO_RPLAY:
[3255]533  case ROAR_PROTO_SIMPLE:
[2614]534    byteorder = ROAR_BYTEORDER_NETWORK;
535   break;
536 }
537
[4326]538 ROAR_CLIENT(g_clients[id])->proto     = proto;
539 ROAR_CLIENT(g_clients[id])->byteorder = byteorder;
[2517]540
541 return 0;
542}
543
[4343]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
[498]557#define MAX_STREAMLESS 8
558
[0]559int clients_check_all (void) {
[1480]560#ifdef ROAR_HAVE_SELECT
[4326]561 struct roar_client * c;
[0]562 struct timeval tv;
[4686]563 fd_set r, w, e;
[66]564 int i, j;
[0]565 int ret;
566 int fh;
567 int max_fh = -1;
[71]568 int have = 0;
[498]569 struct {
570  int id;
571  int fh;
572 } streamless[MAX_STREAMLESS];
573 int have_streamless = 0;
574 int have_stream;
[0]575
[4815]576 ROAR_DBG("clients_check_all(void) = ?");
577
[0]578 FD_ZERO(&r);
[4686]579 FD_ZERO(&w);
[0]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++) {
[4326]586  if ( (c = ROAR_CLIENT(g_clients[i])) == NULL )
[0]587   continue;
588
[4815]589  ROAR_DBG("clients_check_all(void): i(client)=%i", i);
590
[4326]591  if ( (fh = c->fh) != -1 ) {
[71]592   have++;
593
[610]594   ROAR_DBG("clients_check_all(*): fh=%i", fh);
595
[66]596   FD_SET(fh, &r);
597   FD_SET(fh, &e);
598
[4686]599   if ( g_clients[i]->outbuf != NULL ) {
600    FD_SET(fh, &w);
601   }
602
[66]603   if ( fh > max_fh )
604    max_fh = fh;
[84]605  }
[0]606
[498]607  have_stream = 0;
608
[84]609  for (j = 0; j < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; j++) {
[4815]610   ROAR_DBG("clients_check_all(void): i(client)=%i, j(stream)=%i", i, j);
[4326]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);
[1504]613    if ( fh > -1 ) {
614     FD_SET(fh, &r);
[0]615
[1504]616     if ( fh > max_fh )
617      max_fh = fh;
[3579]618    } else if ( fh == -2 ) {
[4326]619     streams_check(c->streams[j]);
[1504]620    }
[498]621
622    have_stream = 1;
[66]623   }
[84]624   //printf("D: client=%i, stream=%i, fh=%i\n", i, j, fh);
[66]625  }
626
[498]627  if ( !have_stream && have_streamless < MAX_STREAMLESS ) {
628   streamless[have_streamless  ].id = i;
[4326]629   if ( (streamless[have_streamless++].fh = c->fh) == -1 )
[498]630    have_streamless--;
631  }
[0]632 }
633
[4815]634 ROAR_DBG("clients_check_all(void): max_fh=%i", max_fh);
635
[256]636 if ( max_fh == -1 )
637  return 0;
638
[4686]639 if ( (ret = select(max_fh + 1, &r, &w, &e, &tv)) < 1 ) {
[71]640  return ret < 0 ? ret : have;
[0]641 }
642
643 for (i = 0; i < ROAR_CLIENTS_MAX; i++) {
[4326]644  if ( (c = ROAR_CLIENT(g_clients[i])) == NULL )
[0]645   continue;
646
[4326]647  if ( (fh = c->fh) != -1 ) {
[66]648   if ( FD_ISSET(fh, &r) ) {
[4326]649    if ( c->execed == -1 ) {
[66]650     clients_check(i);
[4326]651     if ( g_clients[i] != NULL && ROAR_CLIENT(g_clients[i])->execed != -1 ) {
[1834]652      FD_CLR(fh, &r);
653     }
[255]654/*
[66]655    } else {
656     streams_check(g_clients[i]->execed);
[255]657*/
[66]658    }
659   }
[4686]660   if ( FD_ISSET(fh, &w) ) {
661    clients_flush(i);
662   }
[0]663
[84]664   if ( FD_ISSET(fh, &e) ) {
[66]665    clients_delete(i);
[84]666    continue;
667   }
668  }
669
[4326]670  if ( (c = ROAR_CLIENT(g_clients[i])) == NULL )
[84]671   continue;
672
673  for (j = 0; j < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; j++) {
[1611]674   ROAR_DBG("clients_check_all(*): D: client=%i, stream=%i, g_clients[i=%i] = %p", i, j, i, g_clients[i]);
[136]675   if ( g_clients[i] == NULL ) // streams_check() bellow can delete our client (why?)
676    break;
[1611]677
678   //ROAR_WARN("clients_check_all(*): client=%i: client exists", i);
[4326]679   ROAR_DBG("clients_check_all(*): client=%i, stream=%i: id=%i", i, j, c->streams[j]);
[1611]680
[4326]681   if ( (fh = streams_get_fh(c->streams[j])) != -1 ) {
[1611]682    ROAR_DBG("clients_check_all(*): client=%i, stream=%i: fh=%i", i, j, fh);
[3579]683    if ( fh > -1 && FD_ISSET(fh, &r) ) {
[4326]684     streams_check(c->streams[j]);
[66]685    }
[0]686   }
687  }
688 }
689
[498]690 if ( have_streamless ) {
691   FD_ZERO(&r);
[4686]692   FD_ZERO(&w);
[498]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++) {
[4326]700    if ( g_clients[j = streamless[i].id] == NULL )
[607]701     continue;
702
[4326]703    if ( ROAR_CLIENT(g_clients[j])->execed != -1 )
[601]704     continue;
705
[498]706    fh = streamless[i].fh;
707
708    ROAR_DBG("clients_check_all(void): fh=%i", fh);
709    FD_SET(fh, &r);
710
[4688]711    if ( g_clients[j]->outbuf != NULL ) {
[4686]712     FD_SET(fh, &w);
713    }
714
[498]715    if ( fh > max_fh )
716     max_fh = fh;
717   }
718
[4686]719   if ( (ret = select(max_fh + 1, &r, &w, NULL, &tv)) < 0 ) {
[498]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    }
[4686]727    if ( FD_ISSET(streamless[i].fh, &w) ) {
728     clients_flush(streamless[i].id);
729    }
[498]730   }
731 }
732
[71]733 ROAR_DBG("clients_check_all(void) = %i // have value", have);
734 return have;
[1480]735#else
[4815]736 ROAR_DBG("clients_check_all(void) = -1");
[1480]737 return -1;
738#endif
[0]739}
740
741int clients_check     (int id) {
[5576]742 struct roar_client_server * cs;
[0]743 struct roar_message    m;
744 struct roar_connection con;
[5190]745 struct roar_vio_calls  vio;
[5155]746 struct roar_error_state errstate;
[5567]747 const struct roard_proto_handle * proto;
[5606]748 struct roar_dl_librarypara * pluginpara;
[5155]749 int command_error;
[0]750 char * data = NULL;
751 int oldcmd;
752 int r;
[498]753 int rv = 0;
[3926]754 uint32_t flags[2] = {COMMAND_FLAG_NONE, COMMAND_FLAG_NONE};
[4325]755 uint32_t event;
[0]756
[4713]757 ROAR_DBG("clients_check(id=%i) = ?", id);
758
[3910]759 _CHECK_CID(id);
760
[5576]761 cs = g_clients[id];
[4326]762
[5576]763 if ( ROAR_CLIENT(cs)->fh == -1 )
[0]764  return -1;
765
[5608]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 }
[0]769
[5576]770 ROAR_DBG("clients_check(id=%i): c->proto=%i", id, ROAR_CLIENT(cs)->proto);
[4713]771
[5576]772 switch (ROAR_CLIENT(cs)->proto) {
[2517]773  case ROAR_PROTO_ROARAUDIO:
774    r = roar_recv_message(&con, &m, &data);
[0]775
[2517]776    if ( r == -1 ) { // should we drop the client?
777     clients_delete(id);
778     return -1;
779    }
[0]780
[4325]781    event = ROAR_NOTIFY_CMD2EVENT(m.cmd);
782
[2517]783    oldcmd = m.cmd;
[0]784
[5155]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.
[2517]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    }
[4298]806    ROAR_DBG("clients_check(*): data=%p", data);
807
[4347]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);
[5608]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     }
[4347]815    }
[3928]816
817    if ( flags[1] & COMMAND_FLAG_OUT_CLOSECON )
818     clients_close(id, 1);
819
[5608]820    if ( flags[1] & COMMAND_FLAG_OUT_DELETE )
821     clients_delete(id);
822
[2517]823   break;
[4020]824#ifndef ROAR_WITHOUT_DCOMP_EMUL_RSOUND
[3684]825  case ROAR_PROTO_RSOUND:
[3820]826    rv = emul_rsound_check_client(id, NULL);
[3825]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
[4131]832     if (
833#ifdef EAGAIN
[4153]834          errno != EAGAIN      &&
[4131]835#endif
836#ifdef EWOULDBLOCK
[4153]837          errno != EWOULDBLOCK &&
[4131]838#endif
839#ifdef EINTR
[4153]840          errno != EINTR       &&
[4131]841#endif
[4153]842          1 ) {
[4131]843      rv = clients_delete(id);
844     } else {
845      rv = 0;
846     }
[3825]847    }
[3684]848   break;
849#endif
[2517]850  default:
851    rv = -1;
[5576]852    proto = clients_get_protohandle(ROAR_CLIENT(cs)->proto);
[5567]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;
[5576]862      case ROARD_PROTO_TYPE_COMMON:
[5606]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        }
[5576]869        if ( rv == -1 )
870         rv = clients_delete(id);
871       break;
[4678]872     }
[5567]873
874     if ( proto->lhandle != NULL )
875      roar_dl_context_store(proto->lhandle);
[4678]876    }
[0]877 }
878
[4297]879 if ( data != NULL )
[5295]880  roar_mm_free(data);
[0]881
[2517]882 ROAR_DBG("clients_check(id=%i) = %i", id, rv);
[498]883 return rv;
[0]884}
885
[4686]886int clients_flush      (int id) {
[5567]887 struct roar_vio_calls             vio;
888 struct roar_client_server       * cs;
889 struct roar_client              * c;
890 const struct roard_proto_handle * p;
[5606]891 struct roar_dl_librarypara * pluginpara;
[4686]892 size_t len;
893 ssize_t ret;
894 void * buf;
[5567]895 int rv;
[4686]896
897 _CHECK_CID(id);
898
899 c = ROAR_CLIENT(cs = g_clients[id]);
900
[5567]901 p = clients_get_protohandle(c->proto);
[4686]902
903 if ( p == NULL )
904  return -1;
905
906 roar_vio_open_fh_socket(&vio, clients_get_fh(id));
907
[5567]908 switch (p->type) {
909  case ROARD_PROTO_TYPE_BUILDIN:
910    /* noop */
911   break;
[5576]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);
[5606]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);
[5576]918     if ( p->lhandle != NULL )
919      roar_dl_context_store(p->lhandle);
[5606]920     if ( pluginpara != NULL )
921      roar_dl_para_unref(pluginpara);
[5580]922     if ( rv == -1 )
923      rv = clients_delete(id);
[5576]924     return rv;
925    }
926   break;
[4686]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
[5586]942 if ( ret == (ssize_t)len ) {
[5242]943  if ( roar_buffer_next(&(cs->outbuf)) == -1 ) {
944   clients_delete(id);
945   return -1;
946  }
[4686]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 ) {
[5567]955  switch (p->type) {
956   case ROARD_PROTO_TYPE_BUILDIN:
957     /* noop */
958    break;
[5576]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);
[5606]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);
[5576]965      if ( p->lhandle != NULL )
966       roar_dl_context_store(p->lhandle);
[5606]967      if ( pluginpara != NULL )
968       roar_dl_para_unref(pluginpara);
[5580]969      if ( rv == -1 )
970       rv = clients_delete(id);
[5576]971      return rv;
972     }
973    break;
[4686]974  }
975 }
976
977 return 0;
978}
979
[5586]980int clients_send_mon  (struct roar_audio_info * sa) {
[0]981 int i;
[934]982// int fh;
983 int j;
[2715]984 int keep_going;
[0]985
986 for (i = 0; i < ROAR_CLIENTS_MAX; i++) {
987  if ( g_clients[i] == NULL )
988   continue;
989
[2715]990  keep_going = 1;
991
[934]992/*
[0]993  if ( (fh = g_clients[i]->fh) == -1 )
994   continue;
[934]995*/
[0]996
[4326]997  ROAR_DBG("clients_send_mon(*): client=%i, execed=%i", i, ROAR_CLIENT(g_clients[i])->execed);
[1905]998
[2706]999/*
[0]1000  if ( g_clients[i]->execed == -1 ) {
1001   // TODO: add some code to send a message to the client insetd of the raw data.
[2706]1002*/
[2715]1003   for (j = 0; keep_going && j < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; j++) {
[934]1004    //if ( (fh = streams_get_fh(g_clients[i]->streams[j])) != -1 ) {
[2715]1005    ROAR_DBG("clients_send_mon(*): client=%i, stream=%i -> ?", i, j);
[4326]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]);
[2715]1009
1010     // the client may be deleted here, check if it still exists:
1011     if ( g_clients[i] == NULL )
1012      keep_going = 0;
[1905]1013    }
[934]1014   }
[2706]1015/*
[0]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  }
[2706]1022*/
[0]1023 }
1024
[1902]1025 // TODO: FIXME: should this really be -1?
[0]1026 return -1;
1027}
1028
[5586]1029int clients_send_filter(struct roar_audio_info * sa) {
[4326]1030 struct roar_client * c;
[0]1031 int i;
1032 int fh;
1033
1034 for (i = 0; i < ROAR_CLIENTS_MAX; i++) {
[4326]1035  if ( (c = ROAR_CLIENT(g_clients[i])) == NULL )
[0]1036   continue;
1037
[4326]1038  if ( (fh = c->fh) == -1 )
[0]1039   continue;
1040
[4326]1041  if ( c->execed == -1 ) {
[0]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);
[4326]1045   streams_send_filter(c->execed);
[0]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
[5301]1054int clients_add_output (int id, struct roar_buffer ** buf) {
[4686]1055 struct roar_client_server   * cs;
1056
1057 _CHECK_CID(id);
1058 cs = g_clients[id];
1059
1060 if ( cs->outbuf == NULL ) {
[5301]1061  cs->outbuf = *buf;
[4686]1062 } else {
[5301]1063  return roar_buffer_moveinto(cs->outbuf, buf);
[4686]1064 }
1065
1066 return 0;
1067}
1068
[4679]1069// proto support
[5567]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
[5576]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
[5275]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
[5567]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;
[5275]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) {
[5567]1133 struct roard_proto_handle * p;
[5577]1134 char flags[5] = "    ";
[5275]1135 char subsys[7] = "      ";
[5567]1136 const char * description;
[5275]1137 size_t i;
1138
1139 switch (format) {
1140  case FORMAT_NATIVE:
1141    printf("  Protocol Flag Subsys - Description\n");
1142    printf("------------------------------------------------------\n");
[5590]1143    printf("  roar     bb   WM LRX - RoarAudio native protocol\n");
[5275]1144#ifndef ROAR_WITHOUT_DCOMP_EMUL_SIMPLE
[5590]1145    printf("  simple   bb   WM LRX - PulseAudio simple protocol\n");
[5275]1146#endif
1147#ifndef ROAR_WITHOUT_DCOMP_EMUL_RSOUND
[5590]1148    printf("  rsound   bb   W      - RSound emulation\n");
[5275]1149#endif
1150   break;
1151  case FORMAT_WIKI:
1152    printf("||=Protocol =||=Flag =||=Subsys =||=Description              =||\n");
[5590]1153    printf("||roar       ||bb     ||WM LRX   ||RoarAudio native protocol  ||\n");
[5275]1154#ifndef ROAR_WITHOUT_DCOMP_EMUL_SIMPLE
[5590]1155    printf("||simple     ||bb     ||WM LRX   ||PulseAudio simple protocol ||\n");
[5275]1156#endif
1157#ifndef ROAR_WITHOUT_DCOMP_EMUL_RSOUND
[5590]1158    printf("||rsound     ||bb     ||W        ||RSound emulation           ||\n");
[5275]1159#endif
1160   break;
1161  case FORMAT_CSV:
1162    printf("Protocol,Flag,Subsys,Description\n");
[5590]1163    printf("roar,bb,WM LRX,RoarAudio native protocol\n");
[5275]1164#ifndef ROAR_WITHOUT_DCOMP_EMUL_SIMPLE
[5590]1165    printf("simple,bb,WM LRX,PulseAudio simple protocol\n");
[5275]1166#endif
1167#ifndef ROAR_WITHOUT_DCOMP_EMUL_RSOUND
[5590]1168    printf("rsound,bb,W,RSound emulation\n");
[5275]1169#endif
1170   break;
1171  default:
1172    roar_err_set(ROAR_ERROR_NOTSUP);
1173    return;
1174 }
1175
[5567]1176 for (i = 0; i < (sizeof(__protos)/sizeof(*__protos)); i++) {
1177  p = &(__protos[i]);
[5275]1178  if ( p->proto == -1 )
1179   continue;
1180
[5577]1181  strncpy(flags, "    ", 4);
[5275]1182  strncpy(subsys, "      ", 6);
[5567]1183  description = "(none)";
[5275]1184
[5590]1185  if ( p->lhandle != NULL ) {
[5577]1186   flags[0] = 'P';
[5590]1187  } else {
1188   flags[0] = 'b';
1189  }
[5577]1190
[5576]1191  switch (p->type) {
1192   case ROARD_PROTO_TYPE_BUILDIN:
1193     continue;
1194    break;
1195   case ROARD_PROTO_TYPE_COMMON:
[5590]1196     flags[1] = 'C';
[5576]1197     description = p->impl.common->description;
1198    break;
[5567]1199  }
[5275]1200
1201  switch (format) {
1202   case FORMAT_NATIVE:
[5577]1203     printf("  %-8s %s %s - %s\n", roar_proto2str(p->proto), flags, subsys, description);
[5275]1204    break;
1205   case FORMAT_WIKI:
[5577]1206     printf("||%s ||%s ||%s ||%s ||\n", roar_proto2str(p->proto), flags, subsys, description);
[5275]1207    break;
1208   case FORMAT_CSV:
[5577]1209     printf("%s,%s,%s,%s\n", roar_proto2str(p->proto), flags, subsys, description);
[5275]1210    break;
1211  }
1212 }
1213}
[4679]1214
[0]1215int client_stream_exec   (int client, int stream) {
[4326]1216 struct roar_client * c;
[0]1217 int i;
[3920]1218 int fh;
[0]1219
[3910]1220 _CHECK_CID(client);
1221
1222#if 0
[1901]1223 if ( g_clients[client] == NULL ) {
1224  ROAR_WARN("client_stream_exec(client=%i, stream=%i) = -1 // client does not exist", client, stream);
[0]1225  return -1;
[1901]1226 }
[3910]1227#endif
[0]1228
[4326]1229 c = ROAR_CLIENT(g_clients[client]);
1230
[0]1231 for (i = 0; i < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; i++) {
[4326]1232  if ( c->streams[i] == stream ) {
1233   c->execed = stream;
[3921]1234   if ( streams_is_ready(stream) == 0 ) {
[4326]1235    streams_set_fh(stream, c->fh);
[3920]1236    streams_set_socktype(stream, ROAR_SOCKET_TYPE_GENSTR);
1237   } else {
[4254]1238    ROAR_DBG("client_stream_exec(client=%i, stream=%i): fh=?", client, stream);
[4326]1239    if ( (fh = c->fh) != -1 ) {
[3925]1240     close(fh);
[4326]1241     c->fh = -1;
[3925]1242    }
[3920]1243   }
[2815]1244   ROAR_DBG("client_stream_exec(client=%i, stream=%i) = 0", client, stream);
[0]1245   return 0;
1246  }
1247 }
1248
[1901]1249 ROAR_WARN("client_stream_exec(client=%i, stream=%i) = -1 // client does not own stream", client, stream);
[0]1250 return -1;
1251}
1252
[78]1253int client_stream_set_fh (int client, int stream, int fh) {
1254 int i;
1255
[4240]1256 ROAR_DBG("client_stream_set_fh(client=%i, stream=%i, fh=%i) = ?", client, stream, fh);
1257
[3910]1258 _CHECK_CID(client);
[78]1259
1260 for (i = 0; i < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; i++) {
[4326]1261  if ( ROAR_CLIENT(g_clients[client])->streams[i] == stream ) {
[4240]1262   ROAR_DBG("client_stream_set_fh(client=%i, stream=%i, fh=%i): stream found, index %i", client, stream, fh, i);
[4229]1263   return streams_set_fh(stream, fh);
[78]1264  }
1265 }
1266
[4240]1267 ROAR_WARN("client_stream_set_fh(client=%i, stream=%i, fh=%i) = -1 // client does not own stream", client, stream, fh);
[78]1268 return -1;
1269}
1270
[0]1271int client_stream_add    (int client, int stream) {
1272 int i;
1273
[3910]1274 _CHECK_CID(client);
[0]1275
1276 for (i = 0; i < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; i++) {
[4326]1277  if ( ROAR_CLIENT(g_clients[client])->streams[i] == -1 ) {
1278   ROAR_CLIENT(g_clients[client])->streams[i] = stream;
[0]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
[3910]1290 _CHECK_CID(client);
[0]1291
1292 for (i = 0; i < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; i++) {
[4326]1293  if ( ROAR_CLIENT(g_clients[client])->streams[i] == stream ) {
1294   ROAR_CLIENT(g_clients[client])->streams[i] = -1;
[0]1295
[4326]1296   if ( stream == ROAR_CLIENT(g_clients[client])->execed ) {
[0]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
[767]1310int client_stream_move   (int client, int stream) {
1311 int old_client = streams_get_client(stream);
1312
[771]1313 ROAR_DBG("client_stream_move(client=%i, stream=%i): old_client = %i", client, stream, old_client);
1314
[767]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
[4343]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
[4480]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
[5146]1426 return ACCLEV_ERROR;
[4480]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
[0]1439//ll
Note: See TracBrowser for help on using the repository browser.