source: roaraudio/roard/clients.c @ 4703:be4d84be6f04

Last change on this file since 4703:be4d84be6f04 was 4703:be4d84be6f04, checked in by phi, 13 years ago

added basic gopher support

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