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
Line 
1//simple.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2011
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
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
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
36#include "libroar.h"
37
38int roar_simple_connect (struct roar_connection * con, char * server, char * name) {
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) {
43
44 ROAR_DBG("roar_simple_connect(*): trying to connect...");
45
46 if ( roar_connect2(con, server, flags, timeout) == -1 ) {
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) {
65 struct roar_stream     s;
66
67 roar_debug_warn_sysio("roar_simple_stream", "roar_vio_simple_stream", NULL);
68
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) {
73 struct roar_connection con;
74 int ret;
75
76 roar_debug_warn_sysio("roar_simple_stream_obj", NULL, NULL);
77
78 if ( roar_simple_connect(&con, server, name) == -1 ) {
79  ROAR_DBG("roar_simple_play(*): roar_simple_connect() faild!");
80  ROAR_ERR("roar_simple_stream(*): Can not connect to server");
81  return -1;
82 }
83
84 if ( roar_stream_new(s, rate, channels, bits, codec) == -1 ) {
85  roar_disconnect(&con);
86  return -1;
87 }
88
89 if ( roar_stream_connect(&con, s, dir) == -1 ) {
90  roar_disconnect(&con);
91  return -1;
92 }
93
94 if ( roar_stream_exec(&con, s) == -1 ) {
95  roar_disconnect(&con);
96  return -1;
97 }
98
99 roar_libroar_nowarn();
100 if ( (ret = roar_get_connection_fh(&con)) == -1 ) {
101  roar_libroar_warn();
102  roar_disconnect(&con);
103  return -1;
104 }
105 roar_libroar_warn();
106
107 if ( dir == ROAR_DIR_PLAY ) {
108  (void)ROAR_SHUTDOWN(ret, SHUT_RD);
109 } else if ( dir == ROAR_DIR_MONITOR || dir == ROAR_DIR_RECORD ) {
110  (void)ROAR_SHUTDOWN(ret, SHUT_WR);
111 }
112
113 return ret;
114}
115
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
119 if ( (fh = roar_simple_stream_obj(s, rate, channels, bits, codec, NULL /* server, we hope this is ok here... */,
120                                   dir, "libroar temp stream")) == -1 )
121  return -1;
122
123 if ( roar_stream_attach_simple(con, s, roar_get_clientid(con)) == -1 ) {
124#ifdef ROAR_HAVE_IO_POSIX
125  close(fh);
126#endif /* no else as we return -1 anyway */
127  return -1;
128 }
129
130 s->fh = fh;
131
132 return fh;
133}
134
135int roar_simple_new_stream (struct roar_connection * con, int rate, int channels, int bits, int codec, int dir) {
136 struct roar_stream     s;
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;
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) {
149 struct roar_libroar_config * config = roar_libroar_get_config();
150 char file[80] = {0};
151 int fh = -1, listen = -1;
152 static int count = 0;
153 int    type = ROAR_SOCKET_TYPE_UNIX;
154 int    port = 0;
155#if defined(ROAR_HAVE_IPV4) || defined(ROAR_HAVE_LIBDNET)
156 int    opt  = 1;
157#endif
158#ifdef ROAR_HAVE_IPV4
159 struct sockaddr_in   socket_addr;
160 socklen_t            len            = sizeof(struct sockaddr_in);
161#else
162 struct sockaddr      socket_addr;
163 socklen_t            len            = sizeof(struct sockaddr);
164#endif
165#ifdef ROAR_HAVE_SELECT
166 int confh;
167 fd_set fds;
168 struct timeval timeout = {10, 0};
169 struct roar_message    mes;
170#endif
171#ifdef ROAR_HAVE_UNIX
172 int socks[2]; // for socketpair()
173#endif
174
175 // make valgrind happy
176 memset(&socket_addr, 0, sizeof(socket_addr));
177#ifdef ROAR_HAVE_SELECT
178 memset(&mes,         0, sizeof(mes));
179#endif
180
181 roar_debug_warn_sysio("roar_simple_new_stream_obj", "roar_vio_simple_new_stream_obj", NULL);
182
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
189#ifdef ROAR_HAVE_BSDSOCKETS
190 roar_libroar_nowarn();
191 if ( getsockname(roar_get_connection_fh(con), (struct sockaddr *)&socket_addr, &len) == -1 ) {
192  roar_libroar_warn();
193  return -1;
194 }
195 roar_libroar_warn();
196#else
197 return -1;
198#endif
199
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");
203  ((struct sockaddr*)&socket_addr)->sa_family = AF_UNIX;
204#else
205  return -1;
206#endif
207 }
208
209 switch (((struct sockaddr*)&socket_addr)->sa_family) {
210#ifdef ROAR_HAVE_UNIX
211  case AF_UNIX:   type = ROAR_SOCKET_TYPE_UNIX; break;
212#endif
213#ifdef ROAR_HAVE_IPV4
214  case AF_INET:   type = ROAR_SOCKET_TYPE_INET; break;
215#endif
216#ifdef ROAR_HAVE_LIBDNET
217  case AF_DECnet: type = ROAR_SOCKET_TYPE_DECNET; break;
218#endif
219  default:
220    return -1;
221   break;
222 }
223
224 if ( type == ROAR_SOCKET_TYPE_DECNET ) {
225  if ( roar_socket_get_local_nodename() ) {
226   snprintf(file, 24, "%s::roar$TMP%04x%02x", roar_socket_get_local_nodename(), getpid(), count++);
227  } else {
228   return -1;
229  }
230#ifdef ROAR_HAVE_IPV4
231 } else {
232  strncpy(file, inet_ntoa(socket_addr.sin_addr), sizeof(file) - 1);
233#endif
234 }
235
236 if ( type != ROAR_SOCKET_TYPE_UNIX ) {
237  if ( (listen = roar_socket_listen(type, file, port)) == -1 ) {
238   return -1;
239  }
240 }
241
242 if ( type == ROAR_SOCKET_TYPE_INET ) {
243#ifdef ROAR_HAVE_IPV4
244  len = sizeof(struct sockaddr_in);
245  setsockopt(listen, SOL_SOCKET, SO_REUSEADDR, (void*)&opt, sizeof(int));
246
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);
252#else
253  return -1;
254#endif
255 } else if ( type == ROAR_SOCKET_TYPE_DECNET ) {
256#ifdef ROAR_HAVE_LIBDNET
257  len = sizeof(struct sockaddr_in);
258  setsockopt(listen, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int));
259#else
260  return -1;
261#endif
262 }
263
264 if ( roar_stream_new(s, rate, channels, bits, codec) == -1 ) {
265  return -1;
266 }
267
268 if ( roar_stream_connect(con, s, dir) == -1 ) {
269  return -1;
270 }
271
272 if ( type != ROAR_SOCKET_TYPE_UNIX ) {
273#ifdef ROAR_HAVE_SELECT
274  if ( roar_stream_connect_to_ask(con, s, type, file, port) != -1 ) {
275
276   FD_ZERO(&fds);
277   FD_SET(listen, &fds);
278
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 ) {
286    close(listen);
287
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;
291
292    if ( roar_kick(con, ROAR_OT_STREAM, s->id) == -1 )
293     return -1;
294
295    return roar_simple_new_stream_attachexeced_obj(con, s, rate, channels, bits, codec, dir);
296   }
297
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);
311   }
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   }
319  }
320
321  close(listen);
322#else
323  return -1;
324#endif
325 } else { // this is type == ROAR_SOCKET_TYPE_UNIX
326#ifdef ROAR_HAVE_UNIX
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
335                                          // as we return -1 anyway.
336   close(socks[0]);
337   close(socks[1]);
338   return -1;
339  }
340
341  close(socks[0]);
342  fh = socks[1];
343#else
344  roar_kick(con, ROAR_OT_STREAM, s->id);
345  return -1;
346#endif
347 }
348
349/*
350 if ( type == ROAR_SOCKET_TYPE_UNIX ) {
351  unlink(file);
352 }
353*/
354
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  }
361 }
362
363 s->fh = fh;
364
365 return fh;
366}
367
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
379int roar_simple_play(int rate, int channels, int bits, int codec, char * server, char * name) {
380 roar_debug_warn_sysio("roar_simple_play", "roar_vio_simple_stream", NULL);
381
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) {
386 roar_debug_warn_sysio("roar_simple_monitor", "roar_vio_simple_stream", NULL);
387
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) {
392 roar_debug_warn_sysio("roar_simple_record", "roar_vio_simple_stream", NULL);
393
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) {
398 roar_debug_warn_sysio("roar_simple_filter", "roar_vio_simple_stream", NULL);
399
400 return roar_simple_stream(rate, channels, bits, codec, server, ROAR_DIR_FILTER, name);
401}
402
403int roar_simple_connect_virtual(struct roar_connection * con, struct roar_stream * s, int parent, int dir) {
404 struct roar_stream parent_stream;
405
406 if ( con == NULL || s == NULL || parent < 0 )
407  return -1;
408
409 if ( dir == -1 ) {
410  if ( roar_get_stream(con, &parent_stream, parent) == -1 )
411   return -1;
412
413  if ( (dir = roar_stream_get_dir(&parent_stream)) == -1 )
414   return -1;
415 }
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;
429}
430
431int roar_simple_close(int fh) {
432 roar_debug_warn_sysio("roar_simple_close", "roar_vio_close", NULL);
433
434#ifdef ROAR_TARGET_WIN32
435 closesocket(fh);
436 return 0;
437#else
438
439#ifdef ROAR_HAVE_IO_POSIX
440 return close(fh);
441#else
442 return -1;
443#endif
444
445#endif
446}
447
448int roar_simple_get_standby (int fh) {
449 struct roar_connection con;
450
451 roar_debug_warn_sysio("roar_simple_get_standby", "roar_get_standby", NULL);
452
453 if ( roar_connect_fh(&con, fh) == -1 )
454  return -1;
455
456 return roar_get_standby(&con);
457}
458
459//ll
Note: See TracBrowser for help on using the repository browser.