source: roaraudio/roard/clients.c @ 5312:27ec111dc8c5

Last change on this file since 5312:27ec111dc8c5 was 5312:27ec111dc8c5, checked in by phi, 12 years ago

added support for seperate contextes for roardl/plugins. Currently incudes error state and a global per handle data segment. This does not work for statically linked librarys (yet). support for per-context notify core needs to be added/completed.

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