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
Line 
1//socket.c:
2
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
35#include "libroar.h"
36
37#define MODE_LISTEN  ROAR_SOCKET_MODE_LISTEN
38#define MODE_CONNECT ROAR_SOCKET_MODE_CONNECT
39
40int roar_socket_new_tcp (void) {
41 int fh;
42 int opt = IPTOS_LOWDELAY;
43
44 fh = socket(PF_INET, SOCK_STREAM, 0);
45
46 setsockopt(fh, IPPROTO_IP, IP_TOS, &opt, sizeof(int));
47
48 return fh;
49}
50
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
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
92int roar_socket_new_unix (void) {
93 int fh;
94#ifdef SO_PEERCRED
95 int opt = 1;
96#endif
97
98 fh = socket(AF_UNIX, SOCK_STREAM, 0);
99
100#ifdef SO_PEERCRED
101 setsockopt(fh, SOL_SOCKET, SO_PASSCRED, &opt, sizeof(int));
102#endif
103
104 return fh;
105}
106
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
132int roar_socket_new_ipxspx (void) {
133 return -1;
134}
135
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
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
169int roar_socket_dup_udp_local_end (int fh) {
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;
207}
208
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) {
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 }
221}
222
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
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
293int roar_socket_open (int mode, int type, char * host, int port) {
294// int type = ROAR_SOCKET_TYPE_INET;
295 int fh;
296#ifdef ROAR_HAVE_IPX
297#define _NEED_OBJ
298 int i;
299 int ret;
300#endif
301 union {
302  struct sockaddr_in  in;
303  struct sockaddr_un  un;
304  struct sockaddr_in6 in6;
305#ifdef ROAR_HAVE_IPX
306  struct sockaddr_ipx ipx;
307#endif
308 } socket_addr;
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
312#ifdef ROAR_HAVE_LIBDNET
313#define _NEED_OBJ
314#endif
315#ifdef _NEED_OBJ
316 char obj[80];
317 char * del;
318#endif
319
320 if ( mode == MODE_LISTEN )
321  mode_func = bind;
322
323 if ( type == ROAR_SOCKET_TYPE_UNKNOWN ) {
324  type = ROAR_SOCKET_TYPE_INET;
325  if ( *host == '/' ) {
326   type = ROAR_SOCKET_TYPE_UNIX;
327  } else if ( strcmp(host, "+fork") == 0 ) {
328   type = ROAR_SOCKET_TYPE_FORK;
329  } else if ( strstr(host, "::") != NULL ) {
330   type = ROAR_SOCKET_TYPE_DECNET;
331  } else if ( host[strlen(host)-1] == ')' ) {
332   type = ROAR_SOCKET_TYPE_IPX;
333  }
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
340 if ( type == ROAR_SOCKET_TYPE_DECNET ) {
341#ifdef ROAR_HAVE_LIBDNET
342   ROAR_DBG("roar_socket_open(*): hostname for DECnet: host(%p)=%s", host, host);
343   del = strstr(host, "::");
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
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
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.
371   fh = dnet_conn(host, obj, SOCK_STREAM, 0 ,0 ,0 , 0);
372   *del = ':';
373   return fh;
374  }
375#else
376  return -1; // no decnet support
377#endif
378 }
379
380 memset(&socket_addr,    0, sizeof(socket_addr));
381 memset(&he,             0, sizeof(he));               // FIXME: we have a valid pointer in here????
382
383
384 if ( type == ROAR_SOCKET_TYPE_INET || type == ROAR_SOCKET_TYPE_INET6 ) {
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
392   memcpy((struct in_addr *)&socket_addr.in.sin_addr, he->h_addr, sizeof(struct in_addr));
393
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();
399
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   }
405  // hey! we have a socket...
406 } else if ( type == ROAR_SOCKET_TYPE_UNIX ) {
407  socket_addr.un.sun_family = AF_UNIX;
408  strncpy(socket_addr.un.sun_path, host, sizeof(socket_addr.un.sun_path) - 1);
409
410  fh = roar_socket_new_unix();
411
412  if ( mode_func(fh, (struct sockaddr *)&socket_addr.un, sizeof(struct sockaddr_un)) == -1 ) {
413   ROAR_DBG("roar_socket_open(*): Can not connect/bind: %s", strerror(errno));
414   close(fh);
415   return -1;
416  }
417 } else if ( type == ROAR_SOCKET_TYPE_IPX ) {
418#ifdef ROAR_HAVE_IPX
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;
440#else
441  return -1;
442#endif
443 } else if ( type == ROAR_SOCKET_TYPE_FORK ) {
444  return roar_socket_open_fork(mode, host, port);
445 } else if ( type == ROAR_SOCKET_TYPE_FILE ) {
446  return roar_socket_open_file(mode, host, port);
447 } else {
448  return -1;
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
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
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
486  snprintf(fhstr, 7, "%i", socks[1]);
487
488  execlp("roard", "roard", "--no-listen", "--client-fh", fhstr, NULL);
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
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
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
597//ll
Note: See TracBrowser for help on using the repository browser.