source: roaraudio/libroar/basic.c @ 5846:21c98581c23b

Last change on this file since 5846:21c98581c23b was 5846:21c98581c23b, checked in by phi, 11 years ago

avoid possible problems with roar_env_get_home() outsite init phase. should also speed up roar_libroar_get_config_ptr() slightly

File size: 22.4 KB
Line 
1//basic.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2013
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
38enum mode {
39 NORMAL = 0,
40 SYSTEM = 1
41};
42
43static int _connect_server(struct roar_connection * con, const char * server, int type, int flags, uint_least32_t timeout);
44
45int __get_daemonimage(const char ** daemonimage, enum mode * mode, const char * server) {
46 *daemonimage = NULL;
47 *mode = NORMAL;
48
49 if ( !!strncmp(server, "+fork", 5) ) {
50  roar_err_set(ROAR_ERROR_INVAL);
51  return -1;
52 }
53
54 server += 5;
55
56 if ( server[0] == '=' ) {
57  server++;
58
59  if ( server[0] == 0 ) {
60   // no special case, we just ignore it.
61  } else if ( server[0] == 'd' && server[1] == ':' ) {
62   server += 2;
63   *daemonimage = server;
64   *mode = NORMAL;
65  } else if ( server[0] == '!' ) {
66   server += 1;
67   *daemonimage = server;
68   *mode = SYSTEM;
69  } else {
70   roar_err_set(ROAR_ERROR_ILLSEQ);
71   return -1;
72  }
73 }
74
75 if ( *daemonimage == NULL )
76  *daemonimage = roar_libroar_get_config()->daemonimage;
77
78 // we keep this step to be compatible with older versions.
79 if ( *daemonimage == NULL || **daemonimage == 0 ) {
80  *daemonimage = roar_env_get("ROAR_DAEMONIMAGE");
81  if ( *daemonimage != NULL ) {
82   ROAR_WARN("__get_daemonimage(*): Usage of $ROAR_DAEMONIMAGE is obsolete. Use ROAR_OPTIONS=daemonimage:...");
83  }
84 }
85
86 if ( *daemonimage == NULL || **daemonimage == 0 )
87  *daemonimage = roar_libroar_get_path_static("bin-default-daemonimage");
88
89 return 0;
90}
91
92#if defined(ROAR_TARGET_WIN32)
93#define NUM_TRIES 16
94static int _start_server_win32(struct roar_connection * con, const char * server, int type, int flags, uint_least32_t timeout) {
95 enum mode mode = NORMAL;
96 const char * daemonimage = NULL;
97 char buf[64];
98 int port;
99 size_t i;
100 int fh;
101 int ret;
102
103 if ( __get_daemonimage(&daemonimage, &mode, server) == -1 )
104  return -1;
105
106 if ( mode != NORMAL ) {
107  roar_err_set(ROAR_ERROR_NOSYS);
108  return -1;
109 }
110
111 for (i = 0; i < NUM_TRIES; i++) {
112  port = roar_random_uint16();
113  if ( port < 1 )
114   continue;
115
116  fh = roar_socket_connect(ROAR_SOCKET_TYPE_TCP, "localhost", port);
117  if ( fh == -1 )
118   break;
119
120  closesocket(fh);
121 }
122
123 if ( i == NUM_TRIES ) {
124  roar_err_set(ROAR_ERROR_LOOP);
125  return -1;
126 }
127
128 // port is the port to use. It seems to be 'free'.
129
130#if defined(_P_DETACH)
131#define MODE _P_DETACH
132#elif defined(_P_NOWAIT)
133#define MODE _P_NOWAIT
134#else
135#define MODE _P_NOWAITO
136#endif
137
138 snprintf(buf, sizeof(buf), "%i", port);
139 roar_err_clear_all();
140 if ( _spawnlp(MODE, daemonimage, daemonimage, "--tcp", "--bind", "localhost", "--port", buf, (const char*)NULL) < 0 ) {
141  roar_err_update();
142  ret = roar_error;
143  ROAR_ERR("_start_server_win32(server='%s', ...): Can not start server: %s: %s", server, daemonimage, roar_errorstring);
144  roar_error = ret;
145  ROAR_ERR("_start_server_win32(*): %s", roar_errorstring);
146  roar_error = ret;
147  ROAR_ERR("DUMMY");
148  ROAR_ERR("_start_server_win32(*): %s", roar_errorstring);
149  roar_error = ret;
150  (void)roar_errorstring;
151  ROAR_ERR("_start_server_win32(*): %s", roar_errorstring);
152  return -1;
153 }
154
155 snprintf(buf, sizeof(buf), "localhost:%i", port);
156
157 // give the daemon some time to come up:
158 roar_usleep(25000);
159
160 ret = -1;
161 for (i = 0; ret == -1 && i < NUM_TRIES; i++) {
162  ret = _connect_server(con, buf, type, flags, timeout);
163  if ( ret == -1 && i < NUM_TRIES )
164   roar_sleep(1);
165 }
166
167 ROAR_ERR("_start_server_win32(*): %s", roar_errorstring);
168
169 if ( ret == -1 )
170  return -1;
171
172 con->flags |= ROAR_CON_FLAGS_TERMINATE;
173
174 return 0;
175}
176#elif !defined(ROAR_TARGET_MICROCONTROLLER)
177static int _start_server_posix(struct roar_connection * con, const char * server, int type, int flags, uint_least32_t timeout) {
178 enum mode mode = NORMAL;
179 const char * daemonimage = NULL;
180 int socks[2];
181 int r;
182 char fhstr[12];
183 size_t len;
184
185 if ( __get_daemonimage(&daemonimage, &mode, server) == -1 )
186  return -1;
187
188 len = roar_mm_strlen(daemonimage) + 9; // 9 = '+fork=' + 'X:' + '\0'
189 con->server_name = roar_mm_malloc(len);
190 if ( con->server_name != NULL ) {
191  snprintf(con->server_name, len, "+fork=%s%s", mode == NORMAL ? "d:" : "!", daemonimage);
192 }
193
194 if ( socketpair(AF_UNIX, SOCK_STREAM, 0, socks) == -1 ) {
195  roar_err_from_errno();
196  return -1;
197 }
198
199 r = roar_fork(NULL);
200
201 if ( r == -1 ) { // error!
202  ROAR_ERR("_start_server(*): Can not fork: %s", roar_error2str(roar_error));
203  close(socks[0]);
204  close(socks[1]);
205  return -1;
206 } else if ( r == 0 ) { // we are the child
207  roar_watchdog_stop();
208
209  close(socks[0]);
210
211  close(ROAR_STDIN ); // we do not want roard to have any standard input
212  close(ROAR_STDOUT); // STDOUT is also not needed, so we close it,
213                      // but STDERR we keep open for error messages.
214
215  snprintf(fhstr, sizeof(fhstr), "%i", socks[1]);
216
217  switch (mode) {
218   case NORMAL:
219     execlp(daemonimage, daemonimage, "--no-listen", "--client-fh", fhstr, (_LIBROAR_GOOD_CAST char*)NULL);
220    break;
221   case SYSTEM:
222     dup2(socks[1], ROAR_STDIN );
223     dup2(socks[1], ROAR_STDOUT);
224     execl(roar_libroar_get_path_static("bin-sh"), roar_libroar_get_path_static("bin-sh"), "-c", daemonimage, (_LIBROAR_GOOD_CAST char*)NULL);
225     execlp("sh", "sh", "-c", daemonimage, (_LIBROAR_GOOD_CAST char*)NULL);
226    break;
227  }
228
229  // we are still alive?
230  ROAR_ERR("_start_server(*): alive after exec(), that's bad!");
231  ROAR_U_EXIT(1);
232 } else { // we are the parent
233  close(socks[1]);
234  if ( roar_vio_open_fh_socket(con->viocon, socks[0]) == -1 ) {
235   close(socks[0]);
236   return -1;
237  } else {
238   con->flags |= ROAR_CON_FLAGS_VIO;
239  }
240  return 0;
241 }
242
243 return -1;
244}
245#endif
246
247static int _start_server(struct roar_connection * con, const char * server, int type, int flags, uint_least32_t timeout) {
248#if defined(ROAR_TARGET_WIN32)
249 int ret;
250 ret = _start_server_win32(con, server, type, flags, timeout);
251 ROAR_ERR("_start_server(*): %s", roar_errorstring);
252 return ret;
253#elif !defined(ROAR_TARGET_MICROCONTROLLER)
254 return _start_server_posix(con, server, type, flags, timeout);
255#else
256 ROAR_ERR("_start_server(*): There is no UNIX Domain Socket, download a real OS.");
257 roar_err_set(ROAR_ERROR_NOSYS);
258 return -1;
259#endif
260}
261
262static int _connect_internal(struct roar_connection * con, const char * server, int type, int flags, uint_least32_t timeout) {
263 struct roar_libroar_config * config = roar_libroar_get_config();
264 struct roar_vio_calls * vio;
265
266 if ( config->connect_internal != NULL ) {
267  vio = config->connect_internal(con, server, type, flags, timeout);
268  if ( vio == NULL )
269   return -1;
270
271  con->viocon = vio;
272  con->flags |= ROAR_CON_FLAGS_VIO;
273
274  return 0;
275 }
276
277 roar_err_set(ROAR_ERROR_BADHOST);
278 return -1;
279}
280
281static int _connect_server(struct roar_connection * con, const char * server, int type, int flags, uint_least32_t timeout) {
282#if defined(ROAR_HAVE_STAT) && defined(ROAR_HAVE_H_SYS_STAT)
283 struct stat sockstat;
284#endif
285 const char * obj = NULL;
286 char user_sock[128];
287 int is_decnet = 0;
288 int port = 0;
289 int i = 0;
290 int fh = -1;
291 int err;
292 int ret;
293
294 if ( con == NULL || server == NULL ) {
295  roar_err_set(ROAR_ERROR_FAULT);
296  return -1;
297 }
298
299 if ( !strcmp(server, "+invalid") ) {
300  roar_err_set(ROAR_ERROR_CANCELED);
301  return -1;
302 } else if ( !strncmp(server, "+dstr=", 6) ) {
303  if ( roar_vio_open_dstr_simple(con->viocon, server+6, ROAR_VIOF_READWRITE) == -1 )
304   return -1;
305  con->flags |= ROAR_CON_FLAGS_VIO;
306  con->server_name = roar_mm_strdup(server);
307  return 0;
308 } else if ( !strcmp(server, "+fork") || !strncmp(server, "+fork=", 6) ) {
309  ret = _start_server(con, server, type, flags, timeout);
310  ROAR_ERR("_connect_server(*): %s", roar_errorstring);
311  return ret;
312 } else if ( !strcmp(server, "+internal") || !strncmp(server, "+internal=", 10) ) {
313  ret = _connect_internal(con, server, type, flags, timeout);
314  if ( ret == 0 )
315   con->server_name = roar_mm_strdup(server);
316  return ret;
317 }
318
319 strncpy(user_sock, server, sizeof(user_sock)-1);
320 user_sock[sizeof(user_sock)-1] = 0;
321
322
323 if ( *user_sock != '/' ) { // don't test AF_UNIX sockets for ports
324  for (i = 0; user_sock[i] != 0; i++) {
325   if ( user_sock[i] == ':' ) {
326    if ( user_sock[i+1] == ':' ) { // DECnet, leave unchanged
327     is_decnet = 1;
328     obj = &user_sock[i+2];
329     break;
330    }
331
332    port = atoi(&(user_sock[i+1]));
333    user_sock[i] = 0;
334    break;
335   }
336  }
337 }
338
339 if ( is_decnet ) {
340  if ( *user_sock == ':' ) {
341   if ( roar_socket_get_local_nodename() != NULL ) {
342    strncpy(user_sock, roar_socket_get_local_nodename(), sizeof(user_sock)-1);
343    user_sock[sizeof(user_sock)-1] = 0;
344    roar_mm_strlcat(user_sock, server, sizeof(user_sock)-1);
345    user_sock[sizeof(user_sock)-1] = 0;
346    obj  = strstr(user_sock, "::");
347    obj += 2;
348   }
349  }
350
351  if ( *obj == 0 ) {
352   roar_mm_strlcat(user_sock, ROAR_DEFAULT_OBJECT, sizeof(user_sock)-1);
353   user_sock[sizeof(user_sock)-1] = 0;
354  }
355
356  ROAR_DBG("roar_connect_raw(*): user_sock='%s'", user_sock);
357 }
358
359 if ( port || is_decnet ) {
360  fh = roar_socket_connect(type, user_sock, port);
361  // restore the original string
362  user_sock[i] = ':';
363 } else {
364#if defined(ROAR_HAVE_STAT) && defined(ROAR_HAVE_H_SYS_STAT)
365  if ( user_sock[0] == '/' ) {
366   if ( stat(user_sock, &sockstat) == 0 ) {
367    if ( S_ISCHR(sockstat.st_mode) ) {
368#ifdef O_NOCTTY
369     fh = open(user_sock, O_RDWR|O_NOCTTY, 0666);
370#else
371     fh = open(user_sock, O_RDWR, 0666);
372#endif
373    }
374   }
375  }
376#endif
377  if ( fh == -1 )
378   fh = roar_socket_connect(type, user_sock, ROAR_DEFAULT_PORT);
379 }
380
381 if ( fh == -1 )
382  return -1;
383
384 if ( roar_vio_open_fh_socket(con->viocon, fh) == -1 ) {
385  err = roar_error;
386#ifdef ROAR_TARGET_WIN32
387  closesocket(fh);
388#else
389  close(fh);
390#endif
391  roar_error = err;
392  return -1;
393 } else {
394  con->flags |= ROAR_CON_FLAGS_VIO;
395 }
396
397 con->server_name = roar_mm_strdup(server);
398
399 roar_err_set(ROAR_ERROR_NONE);
400 return 0;
401}
402
403static int roar_connect_raw (struct roar_connection * con, const char * server, int flags, uint_least32_t timeout) {
404#ifdef ROAR_HAVE_LIBSLP
405 struct roar_libroar_config * config = roar_libroar_get_config();
406#endif
407#if defined(ROAR_HAVE_UNIX)
408 char user_sock[128];
409 const char * roar_server;
410#endif
411#if defined(ROAR_HAVE_LIBSLP) || !defined(ROAR_TARGET_MICROCONTROLLER)
412 int i = 0;
413#endif
414#if !defined(ROAR_TARGET_WIN32) && !defined(ROAR_TARGET_MICROCONTROLLER)
415 struct passwd * pwd;
416#endif
417#ifdef ROAR_HAVE_LIBDNET
418 struct stat decnet_stat;
419#endif
420#ifdef ROAR_HAVE_LIBX11
421 struct roar_x11_connection * x11con;
422#endif
423#ifdef ROAR_HAVE_LIBSLP
424 struct roar_server * list;
425 int workarounds_store;
426#endif
427
428 roar_err_set(ROAR_ERROR_UNKNOWN);
429
430 if ( timeout != 0 ) {
431  roar_err_set(ROAR_ERROR_INVAL);
432  return -1;
433 }
434
435 if ( flags & ROAR_ENUM_FLAG_HARDNONBLOCK )
436  flags |= ROAR_ENUM_FLAG_NONBLOCK;
437
438
439 if ( server == NULL || *server == 0 )
440  server = roar_libroar_get_server();
441
442 if ( server == NULL || *server == 0 )
443  server = roar_env_get("ROAR_SERVER");
444
445#ifdef ROAR_HAVE_LIBX11
446 if ( server == NULL || *server == 0 ) {
447  if ( (x11con = roar_x11_connect(NULL)) != NULL ) {
448   server = roar_x11_get_prop(x11con, "ROAR_SERVER");
449   roar_x11_disconnect(x11con);
450  }
451 }
452#endif
453
454#if !defined(ROAR_TARGET_WIN32) && !defined(ROAR_TARGET_MICROCONTROLLER)
455 if ( (server == NULL || *server == 0) && (i = readlink(roar_libroar_get_path_static("sysconf-roarserver"), user_sock, sizeof(user_sock)-1)) != -1 ) {
456   user_sock[i] = 0;
457   server = user_sock;
458 }
459#endif
460
461 if ( server != NULL && !strcasecmp(server, "+slp") ) {
462  server = roar_slp_find_roard(0);
463  if ( server == NULL ) {
464   return -1;
465  }
466 }
467
468 // "+default" is an alias for NULL.
469 if ( server != NULL && !strcasecmp(server, "+default") ) {
470  server = NULL;
471 }
472
473 if ( server == NULL || *server == 0 ) {
474  /* connect via defaults */
475
476#ifdef ROAR_HAVE_UNIX
477#ifndef ROAR_TARGET_MICROCONTROLLER
478  roar_server = roar_env_get("HOME");
479#else
480  roar_server = NULL;
481#endif
482
483  if ( roar_server == NULL ) {
484#if !defined(ROAR_TARGET_WIN32) && !defined(ROAR_TARGET_MICROCONTROLLER)
485   if ( (pwd = getpwuid(getuid())) == NULL ) {
486    roar_server = roar_libroar_get_path_static("dir-nx-home");
487   } else {
488    roar_server = pwd->pw_dir;
489   }
490#else
491   roar_server = "/WIN32-SUCKS";
492#endif
493  }
494
495  snprintf(user_sock, sizeof(user_sock)-1, "%s/%s", roar_server, ROAR_DEFAULT_SOCK_USER);
496  user_sock[sizeof(user_sock)-1] = 0;
497
498  if ( _connect_server(con, user_sock, ROAR_SOCKET_TYPE_UNIX, flags, timeout) == 0 )
499   return 0;
500
501  if ( _connect_server(con, ROAR_DEFAULT_SOCK_GLOBAL, ROAR_SOCKET_TYPE_UNIX, flags, timeout) == 0 )
502   return 0;
503#endif
504
505  if ( _connect_server(con, ROAR_DEFAULT_HOSTPORT, ROAR_SOCKET_TYPE_TCP, flags, timeout) == 0 )
506   return 0;
507
508#ifdef ROAR_HAVE_LIBDNET
509  if ( stat(ROAR_PROC_NET_DECNET, &decnet_stat) == 0 ) {
510   if ( roar_socket_get_local_nodename() ) {
511    snprintf(user_sock, 79, "%s::%s", roar_socket_get_local_nodename(), ROAR_DEFAULT_OBJECT);
512    if ( _connect_server(con, user_sock, ROAR_SOCKET_TYPE_DECNET, flags, timeout) == 0 )
513     return 0;
514   }
515  }
516#endif
517
518  if ( _connect_server(con, "+abstract", ROAR_SOCKET_TYPE_UNKNOWN, flags, timeout) == 0 )
519   return 0;
520
521#ifdef ROAR_HAVE_LIBSLP
522 if ( !(config->workaround.workarounds & ROAR_LIBROAR_CONFIG_WAS_NO_SLP) &&
523      !(flags & ROAR_ENUM_FLAG_NONBLOCK) &&
524      !(flags & ROAR_ENUM_FLAG_LOCALONLY)
525    ) {
526  if ( (server = roar_slp_find_roard(0)) != NULL ) {
527   if ( _connect_server(con, server, ROAR_SOCKET_TYPE_UNKNOWN, 0, 0) == 0 )
528    return 0;
529
530   /* in case we can not connect to the server given this may be a cache problem,
531      we do a new lookup with the cache disabled in this case                     */
532   ROAR_WARN("roar_connect_raw(*): Can not connect to SLP located server, disabling cache");
533   if ( (server = roar_slp_find_roard(1)) != NULL )
534    if ( _connect_server(con, server, ROAR_SOCKET_TYPE_UNKNOWN, 0, 0) == 0 )
535     return 0;
536  }
537 }
538
539 workarounds_store = config->workaround.workarounds;
540 config->workaround.workarounds |= ROAR_LIBROAR_CONFIG_WAS_NO_SLP;
541 list = roar_enum_servers(flags, -1, -1);
542 config->workaround.workarounds = workarounds_store;
543 if ( list != NULL ) {
544  for (i = 0; list[i].server != NULL; i++) {
545   if ( _connect_server(con, list[i].server, ROAR_SOCKET_TYPE_UNKNOWN, 0, 0) == 0 ) {
546    roar_enum_servers_free(list);
547    return 0;
548   }
549  }
550  roar_enum_servers_free(list);
551 }
552#endif
553
554 return -1;
555
556 } else {
557  /* connect via (char*)server */
558  if ( _connect_server(con, server, ROAR_SOCKET_TYPE_UNKNOWN, flags, timeout) != 0 )
559   return -1;
560  return 0;
561 }
562
563 roar_err_set(ROAR_ERROR_NODEV);
564 ROAR_DBG("roar_connect_raw(*) = -1 // error=NODEV");
565 return -1;
566}
567
568int roar_connect     (struct roar_connection * con, const char * server, int flags, uint_least32_t timeout) {
569 struct roar_libroar_config * config = roar_libroar_get_config();
570
571 if ( con == NULL ) {
572  roar_err_set(ROAR_ERROR_FAULT);
573  return -1;
574 }
575
576 if ( roar_connect_none(con) == -1 )
577  return -1;
578
579 if ( roar_connect_raw(con, server, flags | config->serverflags, timeout) == -1 )
580  return -1;
581
582 return 0;
583}
584
585int roar_connect_none (struct roar_connection * con) {
586 struct roar_libroar_config * config = roar_libroar_get_config();
587
588 if ( con == NULL ) {
589  roar_err_set(ROAR_ERROR_INVAL);
590  return -1;
591 }
592
593 memset(con, 0, sizeof(struct roar_connection));
594 con->refc        = 1;
595 con->flags       = ROAR_CON_FLAGS_ISCLIENT;
596 con->version     = _ROAR_MESSAGE_VERSION;
597 con->cb_userdata = NULL;
598 con->cb          = NULL;
599 con->server_stds = NULL;
600 con->server_name = NULL;
601
602 roar_err_init(&(con->errorframe));
603
604 con->viocon = &(con->viocon_store);
605
606// con->flags |= ROAR_CON_FLAGS_VIO;
607
608 if ( config->protocolversion != -1 )
609  roar_set_connection_version(con, config->protocolversion);
610
611 roar_err_set(ROAR_ERROR_NONE);
612 return 0;
613}
614
615int roar_connect_vio (struct roar_connection * con, struct roar_vio_calls * vio) {
616 if ( con == NULL || vio == NULL ) {
617  roar_err_set(ROAR_ERROR_INVAL);
618  return -1;
619 }
620
621 if ( roar_connect_none(con) == -1 )
622  return -1;
623
624 con->viocon = vio;
625 con->flags |= ROAR_CON_FLAGS_VIO;
626
627 return -1;
628}
629
630int roar_connect_fh (struct roar_connection * con, int fh) {
631
632 if ( con == NULL || fh == -1 ) {
633  roar_err_set(ROAR_ERROR_INVAL);
634  return -1;
635 }
636
637 if ( roar_connect_none(con) == -1 )
638  return -1;
639
640 // special hack to set an illegal value used internally in libroar:
641 if ( fh == -2 )
642  fh = -1;
643
644 if ( roar_vio_open_fh_socket(con->viocon, fh) != -1 ) {
645  con->flags |= ROAR_CON_FLAGS_VIO;
646 } else {
647  return -1;
648 }
649
650 roar_err_set(ROAR_ERROR_NONE);
651 return 0;
652}
653
654int roar_get_connection_fh (struct roar_connection * con) {
655 int fh;
656
657 ROAR_DBG("roar_get_connection_fh(con=%p) = ?", con);
658
659 roar_debug_warn_sysio("roar_get_connection_fh", "roar_get_connection_vio2", NULL);
660
661 if ( con == NULL )
662  return -1;
663
664 ROAR_DBG("roar_get_connection_fh(con=%p) = ?", con);
665
666 if ( roar_vio_ctl(con->viocon, ROAR_VIO_CTL_GET_FH, &fh) == -1 ) {
667#ifdef ROAR_TARGET_WIN32
668  if ( roar_vio_ctl(con->viocon, ROAR_VIO_CTL_GET_SELECT_FH, &fh) == -1 )
669   return -1;
670#else
671  return -1;
672#endif
673 }
674
675 ROAR_DBG("roar_get_connection_fh(con=%p) = %i", con, fh);
676
677 return fh;
678}
679
680struct roar_vio_calls * roar_get_connection_vio2 (struct roar_connection * con) {
681 if ( con == NULL ) {
682  roar_err_set(ROAR_ERROR_FAULT);
683  return NULL;
684 }
685
686 if ( con->flags & ROAR_CON_FLAGS_VIO )
687  return con->viocon;
688
689// TODO: try to open the VIO.
690
691 roar_err_set(ROAR_ERROR_BADFH);
692 return NULL;
693}
694
695const char * roar_get_connection_server(struct roar_connection * con) {
696 if ( con == NULL ) {
697  roar_err_set(ROAR_ERROR_FAULT);
698  return NULL;
699 }
700
701 return con->server_name;
702}
703
704int roar_connectionref(struct roar_connection * con) {
705 if ( con == NULL ) {
706  roar_err_set(ROAR_ERROR_FAULT);
707  return -1;
708 }
709
710 con->refc++;
711
712 return 0;
713}
714
715int roar_connectionunref(struct roar_connection * con) {
716 struct roar_vio_calls * vio;
717 struct roar_message m;
718
719 if ( con == NULL ) {
720  roar_err_set(ROAR_ERROR_FAULT);
721  return -1;
722 }
723
724 con->refc--;
725
726 if ( con->refc )
727  return 0;
728
729 if ( con->flags & ROAR_CON_FLAGS_TERMINATE ) {
730  if ( roar_terminate(con, 1) == -1 ) {
731   ROAR_WARN("roar_connectionunref(con=%p{.server_name='%s'}): Can not terminate server as requested.", con, con->server_name);
732   if ( roar_terminate(con, 0) == -1 ) {
733    ROAR_ERR("roar_connectionunref(con=%p{.server_name='%s'}): Can not exit server. BAD.", con, con->server_name);
734   }
735  }
736 }
737
738 memset(&m, 0, sizeof(m));
739
740 m.datalen =  0;
741 m.stream  = -1;
742 m.pos     =  0;
743 m.cmd     = ROAR_CMD_QUIT;
744
745 roar_req(con, &m, NULL);
746
747 if ( (vio = roar_get_connection_vio2(con)) != NULL ) {
748  roar_vio_close(vio);
749 }
750
751 if ( con->server_stds != NULL ) {
752  roar_stds_free(con->server_stds);
753  con->server_stds = NULL;
754 }
755
756 if ( con->server_name != NULL ) {
757  roar_mm_free(con->server_name);
758  con->server_name = NULL;
759 }
760
761 if ( con->flags & ROAR_CON_FLAGS_FREESELF ) {
762  roar_mm_free(con);
763 } else {
764  roar_connect_fh(con, -2);
765 }
766
767 return 0;
768}
769
770int roar_set_connection_callback(struct roar_connection * con,
771                                 void (*cb)(struct roar_connection * con,
772                                            struct roar_message    * mes,
773                                            void                   * data,
774                                            void                   * userdata),
775                                 void * userdata) {
776 if ( con == NULL ) {
777  roar_err_set(ROAR_ERROR_FAULT);
778  return -1;
779 }
780
781 con->cb       = cb;
782 con->cb_userdata = userdata;
783
784 return 0;
785}
786
787int roar_set_connection_version(struct roar_connection * con, int version) {
788 if ( con == NULL ) {
789  roar_err_set(ROAR_ERROR_FAULT);
790  return -1;
791 }
792
793 if ( version == -1 )
794  version = _ROAR_MESSAGE_VERSION;
795
796 if ( version < 0 ) {
797  roar_err_set(ROAR_ERROR_INVAL);
798  return -1;
799 }
800
801 con->version = version;
802
803 if ( version == 2 ) {
804  con->flags |= ROAR_CON_FLAGS_SUPPORT_V2;
805 }
806
807 return 0;
808}
809
810int16_t roar_message_genseq(struct roar_connection * con, int is_client) {
811 static int16_t store = 0;
812 int16_t ret = 0;
813
814 ret = store++;
815
816 if ( ret == 0 )
817  ret = store++;
818
819 if ( is_client == -1 ) {
820  if ( con != NULL ) {
821   is_client = con->flags & ROAR_CON_FLAGS_ISCLIENT ? 1 : 0;
822  }
823 }
824
825 if ( is_client == -1 )
826  is_client = 1;
827
828 ret |= 0x8000U;
829 if ( !is_client )
830  ret -= 0x8000U;
831
832 return ret;
833}
834
835int roar_sync         (struct roar_connection * con) {
836 // wait for any non-client reqs
837 return roar_wait_msg(con, 0x0000, 0x8000);
838}
839
840int roar_wait_msg     (struct roar_connection * con, int16_t seq, int16_t seqmask) {
841 roar_err_set(ROAR_ERROR_NOSYS);
842 return -1;
843}
844
845int roar_noop         (struct roar_connection * con) {
846 struct roar_message mes;
847
848 if ( con == NULL ) {
849  roar_err_set(ROAR_ERROR_FAULT);
850  return -1;
851 }
852
853 memset(&mes, 0, sizeof(mes));
854
855 mes.cmd = ROAR_CMD_NOOP;
856 mes.stream = -1;
857
858 return roar_req3(con, &mes, NULL);
859}
860
861int roar_identify   (struct roar_connection * con, const char * name) {
862 struct roar_message mes;
863 uint32_t pid;
864 int max_len;
865
866 roar_err_set(ROAR_ERROR_UNKNOWN);
867
868 ROAR_DBG("roar_identify(*): try to identify myself...");
869
870 memset(&mes, 0, sizeof(mes));
871
872 mes.cmd    = ROAR_CMD_IDENTIFY;
873 mes.stream = -1;
874 mes.pos    =  0;
875
876 ROAR_DBG("roar_identify(*): name=%p", name);
877
878 if ( name == NULL )
879  name = "libroar client";
880
881 ROAR_DBG("roar_identify(*): name=%p", name);
882
883 max_len = roar_mm_strlen(name);
884 ROAR_DBG("roar_identify(*): strlen(name) = %i", max_len);
885
886 if ( max_len > (LIBROAR_BUFFER_MSGDATA - 5) )
887  max_len = LIBROAR_BUFFER_MSGDATA - 5;
888
889 mes.datalen = 5 + max_len;
890 mes.data[0] = 1;
891
892 pid = getpid();
893 mes.data[1] = (pid & 0xFF000000UL) >> 24;
894 mes.data[2] = (pid & 0x00FF0000UL) >> 16;
895 mes.data[3] = (pid & 0x0000FF00UL) >>  8;
896 mes.data[4] = (pid & 0x000000FFUL) >>  0;
897 ROAR_DBG("roar_identify(*): pid = %i", (int)pid);
898
899 strncpy(mes.data+5, name, max_len);
900
901 return roar_req3(con, &mes, NULL);
902}
903
904//ll
Note: See TracBrowser for help on using the repository browser.