source: roaraudio/roard/clients.c @ 5452:bc99b9f05900

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

ported internal stuff to new internal API

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