source: roaraudio/libroar/socket.c @ 690:cee9bf5fa456

Last change on this file since 690:cee9bf5fa456 was 690:cee9bf5fa456, checked in by phi, 16 years ago

added copyright statements

File size: 13.7 KB
RevLine 
[0]1//socket.c:
2
[690]3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008
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, 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 *  NOTE for everyone want's to change something and send patches:
24 *  read README and HACKING! There a addition information on
25 *  the license of this document you need to read before you send
26 *  any patches.
27 *
28 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
29 *  or libpulse*:
30 *  The libs libroaresd, libroararts and libroarpulse link this lib
31 *  and are therefore GPL. Because of this it may be illigal to use
32 *  them with any software that uses libesd, libartsc or libpulse*.
33 */
34
[0]35#include "libroar.h"
36
[81]37#define MODE_LISTEN  ROAR_SOCKET_MODE_LISTEN
38#define MODE_CONNECT ROAR_SOCKET_MODE_CONNECT
[0]39
40int roar_socket_new_tcp (void) {
41 int fh;
[234]42 int opt = IPTOS_LOWDELAY;
[0]43
44 fh = socket(PF_INET, SOCK_STREAM, 0);
45
[234]46 setsockopt(fh, IPPROTO_IP, IP_TOS, &opt, sizeof(int));
47
[0]48 return fh;
49}
50
[374]51int roar_socket_new_udp (void) {
52 int fh;
53 int opt = IPTOS_LOWDELAY;
54
55 fh = socket(PF_INET, SOCK_DGRAM, 0);
56
57 setsockopt(fh, IPPROTO_IP, IP_TOS, &opt, sizeof(int));
58
59 return fh;
60}
61
[509]62int roar_socket_new_tcp6 (void) {
63#ifdef PF_INET6
64 int fh;
65 int opt = IPTOS_LOWDELAY;
66
67 fh = socket(PF_INET6, SOCK_STREAM, 0);
68
69 setsockopt(fh, IPPROTO_IP, IP_TOS, &opt, sizeof(int));
70
71 return fh;
72#else
73 return -1;
74#endif
75}
76
77int roar_socket_new_udp6 (void) {
78#ifdef PF_INET6
79 int fh;
80 int opt = IPTOS_LOWDELAY;
81
82 fh = socket(PF_INET6, SOCK_DGRAM, 0);
83
84 setsockopt(fh, IPPROTO_IP, IP_TOS, &opt, sizeof(int));
85
86 return fh;
87#else
88 return -1;
89#endif
90}
91
[0]92int roar_socket_new_unix (void) {
93 int fh;
[442]94#ifdef SO_PEERCRED
95 int opt = 1;
96#endif
[0]97
98 fh = socket(AF_UNIX, SOCK_STREAM, 0);
99
[442]100#ifdef SO_PEERCRED
101 setsockopt(fh, SOL_SOCKET, SO_PASSCRED, &opt, sizeof(int));
102#endif
103
[0]104 return fh;
105}
106
[508]107int roar_socket_new_decnet_seqpacket (void) {
108#ifdef ROAR_HAVE_LIBDNET
109 int fh;
110
111 fh = socket(AF_DECnet, SOCK_SEQPACKET, DNPROTO_NSP);
112
113 return fh;
114#else
115 return -1;
116#endif
117}
118
119
120int roar_socket_new_decnet_stream (void) {
121#ifdef ROAR_HAVE_LIBDNET
122 int fh;
123
124 fh = socket(AF_DECnet, SOCK_STREAM, DNPROTO_NSP);
125
126 return fh;
127#else
128 return -1;
129#endif
130}
131
[528]132int roar_socket_new_ipxspx (void) {
133 return -1;
134}
[508]135
[530]136int roar_socket_new_ipx    (void) {
137#ifdef ROAR_HAVE_IPX
138 return socket(AF_IPX, SOCK_DGRAM, AF_IPX);
139#else
140 return -1;
141#endif
142}
143
144
[0]145int roar_socket_nonblock(int fh, int state) {
146 int flags;
147
148 if ( (flags = fcntl(fh, F_GETFL, 0)) == -1 ) {
149  ROAR_ERR("roar_socket_nonblock(fh=%i, state=%i): Can not read flags: %s", fh, state, strerror(errno));
150  ROAR_DBG("roar_socket_nonblock(fh=%i, state=%i) = -1", fh, state);
151  return -1;
152 }
153
154 flags |= O_NONBLOCK;
155
156 if ( state == ROAR_SOCKET_BLOCK )
157  flags -= O_NONBLOCK;
158
159 if ( fcntl(fh, F_SETFL, flags) == -1 ) {
160  ROAR_ERR("roar_socket_nonblock(fh=%i, state=%i): Can not set flags: %s", fh, state, strerror(errno));
161  ROAR_DBG("roar_socket_nonblock(fh=%i, state=%i) = -1", fh, state);
162  return -1;
163 }
164
165 ROAR_DBG("roar_socket_nonblock(fh=%i, state=%i) = 0", fh, state);
166 return 0;
167}
168
[375]169int roar_socket_dup_udp_local_end (int fh) {
[376]170 int                  n              = -1;
171 int                  flags          = -1;
172 struct sockaddr_in   socket_addr;
173 socklen_t            len            = sizeof(struct sockaddr_in);
174
175 if ( (flags = fcntl(fh, F_GETFL, 0)) == -1 ) {
176  ROAR_WARN("roar_socket_dup_udp_local_end(fh=%i): Can not read flags: %s", fh, strerror(errno));
177 }
178
179 if ( getsockname(fh, (struct sockaddr *)&socket_addr, &len) == -1 ) {
180  return -1;
181 }
182
183 if ( socket_addr.sin_family != AF_INET ) {
184  return -1;
185 }
186
187 n = roar_socket_new_udp();
188
189 if ( n == -1 )
190  return -1;
191
192//  if ( mode_func(fh, (struct sockaddr *)&socket_addr, sizeof(struct sockaddr_in)) == -1 ) {
193 if ( bind(n, (struct sockaddr *)&socket_addr, len) == -1 ) {
194  close(n);
195  return -1;
196 }
197
198 if ( flags != -1 ) {
199  if ( fcntl(fh, F_SETFL, flags) == -1 ) {
200   ROAR_WARN("roar_socket_dup_udp_local_end(fh=%i): Can not set flags: %s", fh, strerror(errno));
201   return -1;
202  }
203 }
204
205
206 return n;
[375]207}
208
[0]209int roar_socket_listen  (int type, char * host, int port) {
210 return roar_socket_open(MODE_LISTEN, type, host, port);
211}
212
213int roar_socket_connect (char * host, int port) {
[2]214 char * proxy_type = getenv("ROAR_PROXY");
215
216 if ( proxy_type == NULL || strcmp(proxy_type, "") == 0 ) {
217  return roar_socket_open(MODE_CONNECT, ROAR_SOCKET_TYPE_UNKNOWN, host, port);
218 } else {
219  return roar_socket_open_proxy(MODE_CONNECT, ROAR_SOCKET_TYPE_UNKNOWN, host, port, proxy_type);
220 }
[0]221}
222
[508]223
224int roar_socket_listen_decnet (char * object, int num) {
225#ifdef ROAR_HAVE_LIBDNET
226 int fh = roar_socket_new_decnet_stream();
227 struct sockaddr_dn bind_sockaddr;
228
229 if ( fh == -1 )
230  return -1;
231
232 if ( !*object )
233  object = NULL;
234
235 if ( (object && num) || (!*object && !num) ) {
236  ROAR_WARN("roar_socket_listen_decnet(object='%s', num=%i): illegal address!", object, num);
237  close(fh);
238  return -1;
239 }
240
241 memset((void*)&bind_sockaddr, 0, sizeof(struct sockaddr_dn));
242
243 bind_sockaddr.sdn_family    = AF_DECnet;
244 bind_sockaddr.sdn_flags     = 0;
245 bind_sockaddr.sdn_objnum    = num;
246
247 if ( num ) {
248  bind_sockaddr.sdn_objnamel = 0;
249 } else {
250  bind_sockaddr.sdn_objnamel  = ROAR_dn_htons(strlen(object));
251  strcpy((char*)bind_sockaddr.sdn_objname, object); // FIXME: shouldn't we use strncpy()?
252 }
253
254 if ( bind(fh, (struct sockaddr *) &bind_sockaddr, sizeof(bind_sockaddr)) == -1 ) {
255  close(fh);
256  return -1;
257 }
258
259 if ( listen(fh, 8) == -1 ) {
260  close(fh);
261  return -1;
262 }
263
264 return fh;
265#else
266 return -1;
267#endif
268}
269
[521]270char * roar_socket_get_local_nodename(void) {
271#ifdef ROAR_HAVE_LIBDNET
272 static char node[16] = {0};
273 struct dn_naddr      *binaddr;
274 struct nodeent       *dp;
275
276 if ( !node[0] ) {
277  if ( (binaddr=getnodeadd()) == NULL)
278   return NULL;
279
280  if ( (dp=getnodebyaddr((char*)binaddr->a_addr, binaddr->a_len, PF_DECnet)) == NULL )
281   return NULL;
282
283  strncpy(node, dp->n_name, 15);
284  node[15] = 0;
285 }
286
287 return node;
288#else
289 return NULL;
290#endif
291}
292
[0]293int roar_socket_open (int mode, int type, char * host, int port) {
294// int type = ROAR_SOCKET_TYPE_INET;
295 int fh;
[531]296#ifdef ROAR_HAVE_IPX
297#define _NEED_OBJ
298 int i;
299 int ret;
300#endif
[512]301 union {
302  struct sockaddr_in  in;
303  struct sockaddr_un  un;
[514]304  struct sockaddr_in6 in6;
[531]305#ifdef ROAR_HAVE_IPX
306  struct sockaddr_ipx ipx;
307#endif
[512]308 } socket_addr;
[0]309 struct hostent     * he;
310 //unsigned int host_div = 0;
311 int (*mode_func)(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen) = connect; // default is to connect
[501]312#ifdef ROAR_HAVE_LIBDNET
[531]313#define _NEED_OBJ
314#endif
315#ifdef _NEED_OBJ
[501]316 char obj[80];
317 char * del;
318#endif
[0]319
320 if ( mode == MODE_LISTEN )
321  mode_func = bind;
322
323 if ( type == ROAR_SOCKET_TYPE_UNKNOWN ) {
324  type = ROAR_SOCKET_TYPE_INET;
[69]325  if ( *host == '/' ) {
[0]326   type = ROAR_SOCKET_TYPE_UNIX;
[69]327  } else if ( strcmp(host, "+fork") == 0 ) {
328   type = ROAR_SOCKET_TYPE_FORK;
[501]329  } else if ( strstr(host, "::") != NULL ) {
330   type = ROAR_SOCKET_TYPE_DECNET;
[531]331  } else if ( host[strlen(host)-1] == ')' ) {
332   type = ROAR_SOCKET_TYPE_IPX;
[69]333  }
[0]334 }
335
336
337 ROAR_DBG("roar_socket_open(*): type=%s, host='%s', port=%i",
338             type == ROAR_SOCKET_TYPE_UNIX ? "UNIX" : "INET", host, port);
339
[501]340 if ( type == ROAR_SOCKET_TYPE_DECNET ) {
341#ifdef ROAR_HAVE_LIBDNET
[508]342   ROAR_DBG("roar_socket_open(*): hostname for DECnet: host(%p)=%s", host, host);
[501]343   del = strstr(host, "::");
[508]344   ROAR_DBG("roar_socket_open(*): hostname for DECnet: del(%p)=%s", del, del);
345
346   if ( del == NULL ) {
347    ROAR_WARN("roar_socket_open(*): invalid hostname for DECnet: %s", host);
348    return -1;
349   }
350
[501]351   *del = 0;
352
353   if ( *(del+2) == '#' ) { // assume we have node::#num
354    port = atoi(del+2);
355   }
356
357   if ( port ) {
358    sprintf(obj, "%i", port); // no need for snprintf() as dec(port) is smaller than obj[]
359   } else {
360    *obj = 0;
361    strncat(obj, del+2, 79);
362   }
363
[508]364  if ( mode == MODE_LISTEN ) {
365   fh = roar_socket_listen_decnet(obj, port);
366   *del = ':';
367   return fh;
368//   return -1; // listen sockets on DECnet are not supportet at the moment
369  } else {
370   // There is nothing wrong in this case to use dnet_conn() so we do.
[501]371   fh = dnet_conn(host, obj, SOCK_STREAM, 0 ,0 ,0 , 0);
372   *del = ':';
373   return fh;
[533]374  }
[501]375#else
[533]376  return -1; // no decnet support
[501]377#endif
378 }
379
[512]380 memset(&socket_addr,    0, sizeof(socket_addr));
[60]381 memset(&he,             0, sizeof(he));               // FIXME: we have a valid pointer in here????
[0]382
383
[520]384 if ( type == ROAR_SOCKET_TYPE_INET || type == ROAR_SOCKET_TYPE_INET6 ) {
[0]385
386  if ( (he = gethostbyname(host)) == NULL ) {
387   ROAR_ERR("roar_socket_open(*): Can\'t resolve host name '%s'",
388                     host);
389   return -1;
390  }
391
[520]392   memcpy((struct in_addr *)&socket_addr.in.sin_addr, he->h_addr, sizeof(struct in_addr));
[0]393
[520]394   /* set the connect information */
395   socket_addr.in.sin_family = AF_INET;
396   socket_addr.in.sin_port   = ROAR_HOST2NET16(port);
397
398   fh = roar_socket_new_tcp();
[0]399
[520]400   if ( mode_func(fh, (struct sockaddr *)&socket_addr.in, sizeof(struct sockaddr_in)) == -1 ) {
401    ROAR_DBG("roar_socket_open(*): Can not connect/bind: %s", strerror(errno));
402    close(fh);
403    return -1;
404   }
[0]405  // hey! we have a socket...
[69]406 } else if ( type == ROAR_SOCKET_TYPE_UNIX ) {
[512]407  socket_addr.un.sun_family = AF_UNIX;
408  strncpy(socket_addr.un.sun_path, host, sizeof(socket_addr.un.sun_path) - 1);
[60]409
[0]410  fh = roar_socket_new_unix();
[60]411
[512]412  if ( mode_func(fh, (struct sockaddr *)&socket_addr.un, sizeof(struct sockaddr_un)) == -1 ) {
[60]413   ROAR_DBG("roar_socket_open(*): Can not connect/bind: %s", strerror(errno));
414   close(fh);
415   return -1;
416  }
[531]417 } else if ( type == ROAR_SOCKET_TYPE_IPX ) {
[534]418#ifdef ROAR_HAVE_IPX
[531]419  socket_addr.ipx.sipx_family = AF_IPX;
420
421  obj[0] = 0;
422
423  if ( (ret = sscanf(host, "%8x.%12s(%x)", &socket_addr.ipx.sipx_network, obj,
424                               (unsigned int *)&socket_addr.ipx.sipx_port)) < 2 ) {
425   return -1;
426  } else if ( ret == 2 ) {
427   socket_addr.ipx.sipx_port = port; // Network Byte Order?
428  }
429
430  memset(socket_addr.ipx.sipx_node, 0, IPX_NODE_LEN);
431  ret = strlen(obj);
432
433  if ( ret % 2 )  // needs to be even at the moment
434   return -1;
435
436  fh = roar_socket_new_ipx();
437
438  close(fh);
439  return -1;
[534]440#else
441  return -1;
442#endif
[69]443 } else if ( type == ROAR_SOCKET_TYPE_FORK ) {
444  return roar_socket_open_fork(mode, host, port);
[75]445 } else if ( type == ROAR_SOCKET_TYPE_FILE ) {
446  return roar_socket_open_file(mode, host, port);
[69]447 } else {
448  return -1;
[0]449 }
450
451 if ( mode == MODE_LISTEN )
452  if ( listen(fh, ROAR_SOCKET_QUEUE_LEN) == -1 ) {
453   close(fh);
454   return -1;
455  }
456
457 return fh;
458}
459
[69]460int roar_socket_open_fork  (int mode, char * host, int port) {
461 int socks[2];
462 int r;
463 char fhstr[8];
464
465 if ( mode == MODE_LISTEN )
466  return -1;
467
468 if ( socketpair(AF_UNIX, SOCK_STREAM, 0, socks) == -1 ) {
469  return -1;
470 }
471
472 r = fork();
473
474 if ( r == -1 ) { // error!
475  ROAR_ERR("roar_socket_open_fork(*): Can not fork: %s", strerror(errno));
476  close(socks[0]);
477  close(socks[1]);
478  return -1;
479 } else if ( r == 0 ) { // we are the child
480  close(socks[0]);
481
[70]482  close(ROAR_STDIN ); // we do not want roard to have any standard input
483  close(ROAR_STDOUT); // STDOUT is also not needed, so we close it,
484                      // but STDERR we keep open for error messages.
485
[69]486  snprintf(fhstr, 7, "%i", socks[1]);
487
[548]488  execlp("roard", "roard", "--no-listen", "--client-fh", fhstr, NULL);
[69]489
490  // we are still alive?
491  ROAR_ERR("roar_socket_open_fork(*): alive after exec(), that's bad!");
492  _exit(1);
493 } else { // we are the parent
494  close(socks[1]);
495  return socks[0];
496 }
497
498 return -1;
499}
500
[75]501int roar_socket_open_file  (int mode, char * host, int port) {
502 int fh;
503
504 if ( mode == MODE_LISTEN )
505  return -1;
506
507 if ( (fh = open(host, O_RDONLY, 0644)) == -1 ) {
508  ROAR_ERR("roar_socket_open_file(*): Can not open file %s: %s", host, strerror(errno));
509 }
510
511 return fh;
512}
513
[2]514// --- [ PROXY CODE ] ---
515
516// generic proxy code:
517
518int roar_socket_open_proxy (int mode, int type, char * host, int port, char * proxy_type) {
519 int    proxy_port;
520 char   proxy_host[ROAR_SOCKET_MAX_HOSTNAMELEN];
521 char * proxy_addr;
522 int    i;
523 int    fh;
524
525 // TODO: change this so we support listen() proxys (ssh -R)
526 if ( mode != MODE_CONNECT )
527  return -1;
528
529 if ( !strcmp(proxy_type, "socks4a") ) { // for TOR, the only supported type at the moment
530  proxy_addr = getenv("socks_proxy");
531
532  proxy_port = 9050; // TOR's default port
533
534  if ( proxy_addr == NULL )
535   return -1;
536
537  for (i = 0; proxy_addr[i] != 0 && proxy_addr[i] != ':' && i < ROAR_SOCKET_MAX_HOSTNAMELEN; i++)
538   proxy_host[i] = proxy_addr[i];
539  proxy_host[i] = 0;
540
541  if ( i == 0 ) // no hostname found
542   return -1;
543
544  if ( proxy_addr[i] == ':' )
545   proxy_port = atoi(&proxy_addr[i+1]);
546
547  if ( (fh = roar_socket_open(mode, type, proxy_host, proxy_port)) == -1) {
548   return -1;
549  }
550
551  if ( roar_socket_open_socks4a(mode, fh, host, port) == -1 ) {
552   close(fh);
553   return -1;
554  }
555
556  return fh;
557 } else {
558  return -1; // unknown type
559 }
560}
561
562// protocoll dependet proxy code:
563
564int roar_socket_open_socks4a(int mode, int fh, char * host, int port) {
565 char buf[9];
566 int  len;
567
568 buf[0] = 0x04;
569 buf[1] = mode == MODE_CONNECT ? 0x01 : 0x02;
570 *((uint16_t*)&buf[2]) = htons(port);
571 buf[4] = 0x00;
572 buf[5] = 0x00;
573 buf[6] = 0x00;
574 buf[7] = 0x01;
575 buf[8] = 0x00;
576
577 if ( write(fh, buf, 9) != 9 )
578  return -1;
579
580 len = strlen(host);
581
582 if ( write(fh, host, len) != len )
583  return -1;
584
585 if ( write(fh, "\0", 1) != 1 )
586  return -1;
587
588 if ( read(fh, buf, 8) != 8 )
589  return -1;
590
591 if ( buf[1] != 0x5a )
592  return -1;
593
594 return 0;
595}
596
[0]597//ll
Note: See TracBrowser for help on using the repository browser.