source: roaraudio/roard/clients.c @ 5606:f7617b41972e

Last change on this file since 5606:f7617b41972e was 5606:f7617b41972e, checked in by phi, 12 years ago

Updated common protocol interface (Closes: #257, #256)

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