source: roaraudio/libroar/socket.c @ 752:57e8c837e50f

Last change on this file since 752:57e8c837e50f was 752:57e8c837e50f, checked in by phi, 16 years ago

seems that we do not need to set SO_PASSCRED

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