source: roaraudio/roard/clients.c @ 5192:4237437ca526

Last change on this file since 5192:4237437ca526 was 5192:4237437ca526, checked in by phi, 12 years ago

declare some stuff 'extern', this saves like 5.3KB of diskspace in plugin files and make them more resistant against changes in roard

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