source: roaraudio/roard/clients.c @ 5155:420e4f980a8e

Last change on this file since 5155:420e4f980a8e was 5155:420e4f980a8e, checked in by phi, 13 years ago

run protocol functions in clear error context

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