source: roaraudio/libroar/simple.c @ 5061:df215e585134

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

added control connection to select() to detect errors without waiting for the timeout

File size: 12.3 KB
RevLine 
[0]1//simple.c:
2
[690]3/*
[4708]4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2011
[690]5 *
6 *  This file is part of libroar 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 *  libroar 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.
[690]23 *
24 *  NOTE for everyone want's to change something and send patches:
25 *  read README and HACKING! There a addition information on
26 *  the license of this document you need to read before you send
27 *  any patches.
28 *
29 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
30 *  or libpulse*:
31 *  The libs libroaresd, libroararts and libroarpulse link this lib
32 *  and are therefore GPL. Because of this it may be illigal to use
33 *  them with any software that uses libesd, libartsc or libpulse*.
34 */
35
[0]36#include "libroar.h"
37
38int roar_simple_connect (struct roar_connection * con, char * server, char * name) {
[4806]39 return roar_simple_connect2(con, server, name, 0, 0);
40}
41
42int roar_simple_connect2(struct roar_connection * con, char * server, char * name, int flags, uint_least32_t timeout) {
[0]43
44 ROAR_DBG("roar_simple_connect(*): trying to connect...");
45
[4806]46 if ( roar_connect2(con, server, flags, timeout) == -1 ) {
[0]47  ROAR_DBG("roar_simple_connect(*): roar_connect() faild!");
48  return -1;
49 }
50
51 if ( roar_identify(con, name) == -1 ) {
52  ROAR_DBG("roar_simple_connect(*): roar_identify() faild!");
53  return -1;
54 }
55
56 if ( roar_auth(con) == -1 ) {
57  ROAR_DBG("roar_simple_connect(*): roar_auth() faild!");
58  return -1;
59 }
60
61 return 0;
62}
63
64int roar_simple_stream(int rate, int channels, int bits, int codec, char * server, int dir, char * name) {
[1158]65 struct roar_stream     s;
66
[2818]67 roar_debug_warn_sysio("roar_simple_stream", "roar_vio_simple_stream", NULL);
68
[1158]69 return roar_simple_stream_obj(&s, rate, channels, bits, codec, server, dir, name);
70}
71
72int roar_simple_stream_obj  (struct roar_stream * s, int rate, int channels, int bits, int codec, char * server, int dir, char * name) {
[0]73 struct roar_connection con;
[1660]74 int ret;
[0]75
[2818]76 roar_debug_warn_sysio("roar_simple_stream_obj", NULL, NULL);
77
[0]78 if ( roar_simple_connect(&con, server, name) == -1 ) {
79  ROAR_DBG("roar_simple_play(*): roar_simple_connect() faild!");
[1094]80  ROAR_ERR("roar_simple_stream(*): Can not connect to server");
[0]81  return -1;
82 }
83
[1158]84 if ( roar_stream_new(s, rate, channels, bits, codec) == -1 ) {
[0]85  roar_disconnect(&con);
86  return -1;
87 }
88
[1158]89 if ( roar_stream_connect(&con, s, dir) == -1 ) {
[0]90  roar_disconnect(&con);
91  return -1;
92 }
93
[1158]94 if ( roar_stream_exec(&con, s) == -1 ) {
[0]95  roar_disconnect(&con);
96  return -1;
97 }
98
[3857]99 roar_libroar_nowarn();
[1660]100 if ( (ret = roar_get_connection_fh(&con)) == -1 ) {
[3857]101  roar_libroar_warn();
[1660]102  roar_disconnect(&con);
103  return -1;
[54]104 }
[3857]105 roar_libroar_warn();
[54]106
[1660]107 if ( dir == ROAR_DIR_PLAY ) {
[5017]108  (void)ROAR_SHUTDOWN(ret, SHUT_RD);
[1660]109 } else if ( dir == ROAR_DIR_MONITOR || dir == ROAR_DIR_RECORD ) {
[5017]110  (void)ROAR_SHUTDOWN(ret, SHUT_WR);
[1660]111 }
112
113 return ret;
[0]114}
115
[1163]116int roar_simple_new_stream_attachexeced_obj (struct roar_connection * con, struct roar_stream * s, int rate, int channels, int bits, int codec, int dir) {
117 int fh;
118
[1476]119 if ( (fh = roar_simple_stream_obj(s, rate, channels, bits, codec, NULL /* server, we hope this is ok here... */,
[1163]120                                   dir, "libroar temp stream")) == -1 )
121  return -1;
122
123 if ( roar_stream_attach_simple(con, s, roar_get_clientid(con)) == -1 ) {
[1476]124#ifdef ROAR_HAVE_IO_POSIX
[1163]125  close(fh);
[1476]126#endif /* no else as we return -1 anyway */
[1163]127  return -1;
128 }
129
[1166]130 s->fh = fh;
131
[1163]132 return fh;
133}
134
[82]135int roar_simple_new_stream (struct roar_connection * con, int rate, int channels, int bits, int codec, int dir) {
136 struct roar_stream     s;
[3857]137 int ret;
138
139 roar_debug_warn_sysio("roar_simple_new_stream", "roar_vio_simple_new_stream_obj", NULL);
140
141 roar_libroar_nowarn();
142 ret = roar_simple_new_stream_obj(con, &s, rate, channels, bits, codec, dir);
143 roar_libroar_warn();
144
145 return ret;
[119]146}
147
148int roar_simple_new_stream_obj (struct roar_connection * con, struct roar_stream * s, int rate, int channels, int bits, int codec, int dir) {
[2481]149 struct roar_libroar_config * config = roar_libroar_get_config();
[1168]150 char file[80] = {0};
151 int fh = -1, listen = -1;
[82]152 static int count = 0;
[487]153 int    type = ROAR_SOCKET_TYPE_UNIX;
154 int    port = 0;
[1396]155#if defined(ROAR_HAVE_IPV4) || defined(ROAR_HAVE_LIBDNET)
[493]156 int    opt  = 1;
[1396]157#endif
[1466]158#ifdef ROAR_HAVE_IPV4
[487]159 struct sockaddr_in   socket_addr;
160 socklen_t            len            = sizeof(struct sockaddr_in);
[1466]161#else
162 struct sockaddr      socket_addr;
163 socklen_t            len            = sizeof(struct sockaddr);
164#endif
[1465]165#ifdef ROAR_HAVE_SELECT
[5061]166 int confh;
[1161]167 fd_set fds;
168 struct timeval timeout = {10, 0};
[1465]169 struct roar_message    mes;
170#endif
[1396]171#ifdef ROAR_HAVE_UNIX
[1168]172 int socks[2]; // for socketpair()
[1396]173#endif
[82]174
[3479]175 // make valgrind happy
176 memset(&socket_addr, 0, sizeof(socket_addr));
[3897]177#ifdef ROAR_HAVE_SELECT
[3479]178 memset(&mes,         0, sizeof(mes));
[3897]179#endif
[3479]180
[3012]181 roar_debug_warn_sysio("roar_simple_new_stream_obj", "roar_vio_simple_new_stream_obj", NULL);
182
[2481]183 if ( config != NULL ) {
184  if ( config->workaround.workarounds & ROAR_LIBROAR_CONFIG_WAS_USE_EXECED ) {
185   return roar_simple_new_stream_attachexeced_obj(con, s, rate, channels, bits, codec, dir);
186  }
187 }
188
[1476]189#ifdef ROAR_HAVE_BSDSOCKETS
[3857]190 roar_libroar_nowarn();
[1660]191 if ( getsockname(roar_get_connection_fh(con), (struct sockaddr *)&socket_addr, &len) == -1 ) {
[3857]192  roar_libroar_warn();
[82]193  return -1;
194 }
[3857]195 roar_libroar_warn();
[1476]196#else
197 return -1;
198#endif
[82]199
[1178]200 if ( len == 0 ) {
201#ifdef ROAR_OS_OPENBSD
202  ROAR_WARN("roar_simple_new_stream_obj(*): Unknown address family: guess AF_UNIX because OS is OpenBSD");
[1466]203  ((struct sockaddr*)&socket_addr)->sa_family = AF_UNIX;
[1178]204#else
[505]205  return -1;
[1178]206#endif
207 }
208
[1466]209 switch (((struct sockaddr*)&socket_addr)->sa_family) {
[1359]210#ifdef ROAR_HAVE_UNIX
[1178]211  case AF_UNIX:   type = ROAR_SOCKET_TYPE_UNIX; break;
[1359]212#endif
213#ifdef ROAR_HAVE_IPV4
[1178]214  case AF_INET:   type = ROAR_SOCKET_TYPE_INET; break;
[1359]215#endif
216#ifdef ROAR_HAVE_LIBDNET
[1178]217  case AF_DECnet: type = ROAR_SOCKET_TYPE_DECNET; break;
[1359]218#endif
[1178]219  default:
220    return -1;
221   break;
[487]222 }
223
[1187]224 if ( type == ROAR_SOCKET_TYPE_DECNET ) {
[526]225  if ( roar_socket_get_local_nodename() ) {
[5024]226   snprintf(file, 24, "%s::roar$TMP%04x%02x", roar_socket_get_local_nodename(), getpid(), count++);
[526]227  } else {
228   return -1;
229  }
[1380]230#ifdef ROAR_HAVE_IPV4
[487]231 } else {
[5024]232  strncpy(file, inet_ntoa(socket_addr.sin_addr), sizeof(file) - 1);
[1380]233#endif
[487]234 }
235
[1168]236 if ( type != ROAR_SOCKET_TYPE_UNIX ) {
237  if ( (listen = roar_socket_listen(type, file, port)) == -1 ) {
238   return -1;
239  }
[487]240 }
[451]241
[487]242 if ( type == ROAR_SOCKET_TYPE_INET ) {
[1380]243#ifdef ROAR_HAVE_IPV4
[487]244  len = sizeof(struct sockaddr_in);
[3905]245  setsockopt(listen, SOL_SOCKET, SO_REUSEADDR, (void*)&opt, sizeof(int));
[493]246
[487]247  if ( getsockname(listen, (struct sockaddr *)&socket_addr, &len) == -1 ) {
248   return -1;
249  }
250  port = ROAR_NET2HOST16(socket_addr.sin_port);
251  ROAR_DBG("roar_simple_new_stream_obj(*): port=%i", port);
[1380]252#else
253  return -1;
254#endif
[532]255 } else if ( type == ROAR_SOCKET_TYPE_DECNET ) {
[1395]256#ifdef ROAR_HAVE_LIBDNET
[532]257  len = sizeof(struct sockaddr_in);
258  setsockopt(listen, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int));
[1395]259#else
260  return -1;
261#endif
[487]262 }
[451]263
[119]264 if ( roar_stream_new(s, rate, channels, bits, codec) == -1 ) {
[82]265  return -1;
266 }
267
[119]268 if ( roar_stream_connect(con, s, dir) == -1 ) {
[82]269  return -1;
270 }
271
[1168]272 if ( type != ROAR_SOCKET_TYPE_UNIX ) {
[1465]273#ifdef ROAR_HAVE_SELECT
[1168]274  if ( roar_stream_connect_to_ask(con, s, type, file, port) != -1 ) {
[1161]275
[1168]276   FD_ZERO(&fds);
277   FD_SET(listen, &fds);
[1163]278
[5061]279   confh = roar_get_connection_fh(con);
280
281   if ( confh != -1 ) {
282    FD_SET(confh, &fds);
283   }
284
285   if ( select((confh > listen ? confh : listen) + 1, &fds, &fds, &fds, &timeout) < 1 ) {
[1168]286    close(listen);
[1163]287
[1168]288    // we don't need to check the content as we know it failed...
289    if ( roar_recv_message(con, &mes, NULL) == -1 )
290     return -1;
[1161]291
[1168]292    if ( roar_kick(con, ROAR_OT_STREAM, s->id) == -1 )
293     return -1;
[1161]294
[1168]295    return roar_simple_new_stream_attachexeced_obj(con, s, rate, channels, bits, codec, dir);
[82]296   }
[1168]297
[5061]298   if ( FD_ISSET(listen, &fds) ) {
299    if ( (fh = accept(listen, NULL, NULL)) != -1 ) {
300     /* errr, do we need we any error handling here? */
301    }
302   } else {
303    // we don't need to check the content as we know it failed...
304    if ( roar_recv_message(con, &mes, NULL) == -1 )
305     return -1;
306
307    if ( roar_kick(con, ROAR_OT_STREAM, s->id) == -1 )
308     return -1;
309
310    return roar_simple_new_stream_attachexeced_obj(con, s, rate, channels, bits, codec, dir);
[1168]311   }
[82]312   if ( roar_recv_message(con, &mes, NULL) == -1 ) {
313    close(fh);
314    fh = -1;
315   } else if ( mes.cmd != ROAR_CMD_OK ) {
316    close(fh);
317    fh = -1;
318   }
[1168]319  }
320
321  close(listen);
[1465]322#else
323  return -1;
324#endif
[1168]325 } else { // this is type == ROAR_SOCKET_TYPE_UNIX
[1395]326#ifdef ROAR_HAVE_UNIX
[1168]327  if ( socketpair(AF_UNIX, SOCK_STREAM, 0, socks) == -1 ) {
328   roar_kick(con, ROAR_OT_STREAM, s->id); // we do not need to check for errors
329                                          // as we return -1 in both whys
330   return -1;
331  }
332
333  if ( roar_stream_passfh(con, s, socks[0]) == -1 ) {
334   roar_kick(con, ROAR_OT_STREAM, s->id); // we do not need to check for errors
[3651]335                                          // as we return -1 anyway.
336   close(socks[0]);
337   close(socks[1]);
[1168]338   return -1;
339  }
340
341  close(socks[0]);
342  fh = socks[1];
[1395]343#else
344  roar_kick(con, ROAR_OT_STREAM, s->id);
345  return -1;
346#endif
[82]347 }
348
[1168]349/*
[487]350 if ( type == ROAR_SOCKET_TYPE_UNIX ) {
351  unlink(file);
352 }
[1168]353*/
354
[5061]355 if ( fh != -1 ) {
356  if ( dir == ROAR_DIR_PLAY ) {
357   (void)ROAR_SHUTDOWN(fh, SHUT_RD);
358  } else if ( dir == ROAR_DIR_MONITOR || dir == ROAR_DIR_RECORD ) {
359   (void)ROAR_SHUTDOWN(fh, SHUT_WR);
360  }
[1168]361 }
[82]362
[505]363 s->fh = fh;
364
[82]365 return fh;
366}
367
[235]368
369int roar_simple_play_file(char * file, char * server, char * name) {
370 struct roar_connection con;
371
372 if ( roar_simple_connect(&con, server, name) == -1 ) {
373  return -1;
374 }
375
376 return roar_file_play(&con, file, 1); // con is closed by this as this stream will be an execed one.
377}
378
[0]379int roar_simple_play(int rate, int channels, int bits, int codec, char * server, char * name) {
[2655]380 roar_debug_warn_sysio("roar_simple_play", "roar_vio_simple_stream", NULL);
381
[0]382 return roar_simple_stream(rate, channels, bits, codec, server, ROAR_DIR_PLAY, name);
383}
384
385int roar_simple_monitor(int rate, int channels, int bits, int codec, char * server, char * name) {
[2655]386 roar_debug_warn_sysio("roar_simple_monitor", "roar_vio_simple_stream", NULL);
387
[0]388 return roar_simple_stream(rate, channels, bits, codec, server, ROAR_DIR_MONITOR, name);
389}
390
391int roar_simple_record(int rate, int channels, int bits, int codec, char * server, char * name) {
[2655]392 roar_debug_warn_sysio("roar_simple_record", "roar_vio_simple_stream", NULL);
393
[0]394 return roar_simple_stream(rate, channels, bits, codec, server, ROAR_DIR_RECORD, name);
395}
396
397int roar_simple_filter(int rate, int channels, int bits, int codec, char * server, char * name) {
[2655]398 roar_debug_warn_sysio("roar_simple_filter", "roar_vio_simple_stream", NULL);
399
[0]400 return roar_simple_stream(rate, channels, bits, codec, server, ROAR_DIR_FILTER, name);
401}
402
[2697]403int roar_simple_connect_virtual(struct roar_connection * con, struct roar_stream * s, int parent, int dir) {
[2656]404 struct roar_stream parent_stream;
405
406 if ( con == NULL || s == NULL || parent < 0 )
407  return -1;
408
[2697]409 if ( dir == -1 ) {
410  if ( roar_get_stream(con, &parent_stream, parent) == -1 )
411   return -1;
[2656]412
[2697]413  if ( (dir = roar_stream_get_dir(&parent_stream)) == -1 )
414   return -1;
415 }
[2656]416
417 if ( roar_stream_set_rel_id(s, parent) == -1 )
418  return -1;
419
420 if ( roar_stream_connect(con, s, dir) == -1 )
421  return -1;
422
423 if ( roar_stream_set_flags(con, s, ROAR_FLAG_VIRTUAL, 0) == -1 ) {
424  roar_kick(con, ROAR_OT_STREAM, roar_stream_get_id(s));
425  return -1;
426 }
427
428 return 0;
[2647]429}
[0]430
431int roar_simple_close(int fh) {
[2655]432 roar_debug_warn_sysio("roar_simple_close", "roar_vio_close", NULL);
433
[1763]434#ifdef ROAR_TARGET_WIN32
435 closesocket(fh);
436 return 0;
437#else
438
[1476]439#ifdef ROAR_HAVE_IO_POSIX
[0]440 return close(fh);
[1476]441#else
442 return -1;
443#endif
[1763]444
445#endif
[0]446}
447
448int roar_simple_get_standby (int fh) {
449 struct roar_connection con;
450
[2809]451 roar_debug_warn_sysio("roar_simple_get_standby", "roar_get_standby", NULL);
[2655]452
[1660]453 if ( roar_connect_fh(&con, fh) == -1 )
454  return -1;
[0]455
456 return roar_get_standby(&con);
457}
458
459//ll
Note: See TracBrowser for help on using the repository browser.