source: roaraudio/roard/clients.c @ 5586:5b82b3417705

Last change on this file since 5586:5b82b3417705 was 5586:5b82b3417705, checked in by phi, 12 years ago

general cleanup for -Wextra

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