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

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

build CPI objects based on configure options

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