source: roaraudio/roard/clients.c @ 5571:b46ece5b30bf

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

Improved support in roard for client passing.

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