source: roaraudio/libroar/socket.c @ 759:be1544e081ad

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

added debug code, got roar_stream_passfh() working

File size: 15.5 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
213
214#define _SCMR_CONTROLLEN (sizeof(struct cmsghdr) + sizeof(int))
215int roar_socket_send_fh (int sock, int fh, char * mes, size_t len) {
216 struct iovec     iov[1];
217 struct msghdr    msg;
218 char             cmptr_buf[_SCMR_CONTROLLEN];
219 struct cmsghdr * cmptr = (struct cmsghdr *) cmptr_buf;
220 char             localmes[1] = {0};
221
222 ROAR_DBG("roar_socket_send_fh(sock=%i, fh=%i, mes=%p, len=%u) = ?", sock, fh, mes, len);
223
224 if ( sock < 0 || fh < 0 )
225  return -1;
226
227 if ( len == 0 ) {
228  len = 1;
229  mes = localmes;
230 }
231
232 memset(cmptr, 0, _SCMR_CONTROLLEN);
233
234 iov[0].iov_base = mes;
235 iov[0].iov_len  = len;
236 msg.msg_iov     = iov;
237 msg.msg_iovlen  = 1;
238 msg.msg_name    = NULL;
239 msg.msg_namelen = 0;
240
241 cmptr->cmsg_level        = SOL_SOCKET;
242 cmptr->cmsg_type         = SCM_RIGHTS;
243 cmptr->cmsg_len          = _SCMR_CONTROLLEN;
244 msg.msg_control          = (caddr_t) cmptr;
245 msg.msg_controllen       = _SCMR_CONTROLLEN;
246 *(int *)CMSG_DATA(cmptr) = fh;
247
248 return sendmsg(sock, &msg, 0);
249}
250
251int roar_socket_recv_fh (int sock,         char * mes, size_t * len) {
252 struct iovec     iov[1];
253 struct msghdr    msg;
254 char             cmptr_buf[_SCMR_CONTROLLEN];
255 struct cmsghdr * cmptr = (struct cmsghdr *) cmptr_buf;
256 char             localmes[1];
257 size_t           locallen[1] = {1};
258
259 if ( sock < 0 )
260  return -1;
261
262 if ( len == NULL ) {
263  len = locallen;
264  mes = localmes;
265 }
266
267 iov[0].iov_base = mes;
268 iov[0].iov_len  = *len;
269 msg.msg_iov     = iov;
270 msg.msg_iovlen  = 1;
271 msg.msg_name    = NULL;
272 msg.msg_namelen = 0;
273
274 msg.msg_control    = (caddr_t) cmptr;
275 msg.msg_controllen = _SCMR_CONTROLLEN;
276
277 if ( (*len = recvmsg(sock, &msg, 0)) == -1 )
278  return -1;
279
280 if ( msg.msg_controllen != _SCMR_CONTROLLEN )
281  return -1;
282
283 return *(int *)CMSG_DATA(cmptr);
284}
285
286int roar_socket_listen  (int type, char * host, int port) {
287 return roar_socket_open(MODE_LISTEN, type, host, port);
288}
289
290int roar_socket_connect (char * host, int port) {
291 char * proxy_type = getenv("ROAR_PROXY");
292
293 if ( proxy_type == NULL || strcmp(proxy_type, "") == 0 ) {
294  return roar_socket_open(MODE_CONNECT, ROAR_SOCKET_TYPE_UNKNOWN, host, port);
295 } else {
296  return roar_socket_open_proxy(MODE_CONNECT, ROAR_SOCKET_TYPE_UNKNOWN, host, port, proxy_type);
297 }
298}
299
300
301int roar_socket_listen_decnet (char * object, int num) {
302#ifdef ROAR_HAVE_LIBDNET
303 int fh = roar_socket_new_decnet_stream();
304 struct sockaddr_dn bind_sockaddr;
305
306 if ( fh == -1 )
307  return -1;
308
309 if ( !*object )
310  object = NULL;
311
312 if ( (object && num) || (!*object && !num) ) {
313  ROAR_WARN("roar_socket_listen_decnet(object='%s', num=%i): illegal address!", object, num);
314  close(fh);
315  return -1;
316 }
317
318 memset((void*)&bind_sockaddr, 0, sizeof(struct sockaddr_dn));
319
320 bind_sockaddr.sdn_family    = AF_DECnet;
321 bind_sockaddr.sdn_flags     = 0;
322 bind_sockaddr.sdn_objnum    = num;
323
324 if ( num ) {
325  bind_sockaddr.sdn_objnamel = 0;
326 } else {
327  bind_sockaddr.sdn_objnamel  = ROAR_dn_htons(strlen(object));
328  strcpy((char*)bind_sockaddr.sdn_objname, object); // FIXME: shouldn't we use strncpy()?
329 }
330
331 if ( bind(fh, (struct sockaddr *) &bind_sockaddr, sizeof(bind_sockaddr)) == -1 ) {
332  close(fh);
333  return -1;
334 }
335
336 if ( listen(fh, 8) == -1 ) {
337  close(fh);
338  return -1;
339 }
340
341 return fh;
342#else
343 return -1;
344#endif
345}
346
347char * roar_socket_get_local_nodename(void) {
348#ifdef ROAR_HAVE_LIBDNET
349 static char node[16] = {0};
350 struct dn_naddr      *binaddr;
351 struct nodeent       *dp;
352
353 if ( !node[0] ) {
354  if ( (binaddr=getnodeadd()) == NULL)
355   return NULL;
356
357  if ( (dp=getnodebyaddr((char*)binaddr->a_addr, binaddr->a_len, PF_DECnet)) == NULL )
358   return NULL;
359
360  strncpy(node, dp->n_name, 15);
361  node[15] = 0;
362 }
363
364 return node;
365#else
366 return NULL;
367#endif
368}
369
370int roar_socket_open (int mode, int type, char * host, int port) {
371// int type = ROAR_SOCKET_TYPE_INET;
372 int fh;
373#ifdef ROAR_HAVE_IPX
374#define _NEED_OBJ
375 int i;
376 int ret;
377#endif
378 union {
379  struct sockaddr_in  in;
380  struct sockaddr_un  un;
381  struct sockaddr_in6 in6;
382#ifdef ROAR_HAVE_IPX
383  struct sockaddr_ipx ipx;
384#endif
385 } socket_addr;
386 struct hostent     * he;
387 //unsigned int host_div = 0;
388 int (*mode_func)(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen) = connect; // default is to connect
389#ifdef ROAR_HAVE_LIBDNET
390#define _NEED_OBJ
391#endif
392#ifdef _NEED_OBJ
393 char obj[80];
394 char * del;
395#endif
396
397 if ( mode == MODE_LISTEN )
398  mode_func = bind;
399
400 if ( type == ROAR_SOCKET_TYPE_UNKNOWN ) {
401  type = ROAR_SOCKET_TYPE_INET;
402  if ( *host == '/' ) {
403   type = ROAR_SOCKET_TYPE_UNIX;
404  } else if ( strcmp(host, "+fork") == 0 ) {
405   type = ROAR_SOCKET_TYPE_FORK;
406  } else if ( strstr(host, "::") != NULL ) {
407   type = ROAR_SOCKET_TYPE_DECNET;
408  } else if ( host[strlen(host)-1] == ')' ) {
409   type = ROAR_SOCKET_TYPE_IPX;
410  }
411 }
412
413
414 ROAR_DBG("roar_socket_open(*): type=%s, host='%s', port=%i",
415             type == ROAR_SOCKET_TYPE_UNIX ? "UNIX" : "INET", host, port);
416
417 if ( type == ROAR_SOCKET_TYPE_DECNET ) {
418#ifdef ROAR_HAVE_LIBDNET
419   ROAR_DBG("roar_socket_open(*): hostname for DECnet: host(%p)=%s", host, host);
420   del = strstr(host, "::");
421   ROAR_DBG("roar_socket_open(*): hostname for DECnet: del(%p)=%s", del, del);
422
423   if ( del == NULL ) {
424    ROAR_WARN("roar_socket_open(*): invalid hostname for DECnet: %s", host);
425    return -1;
426   }
427
428   *del = 0;
429
430   if ( *(del+2) == '#' ) { // assume we have node::#num
431    port = atoi(del+2);
432   }
433
434   if ( port ) {
435    sprintf(obj, "%i", port); // no need for snprintf() as dec(port) is smaller than obj[]
436   } else {
437    *obj = 0;
438    strncat(obj, del+2, 79);
439   }
440
441  if ( mode == MODE_LISTEN ) {
442   fh = roar_socket_listen_decnet(obj, port);
443   *del = ':';
444   return fh;
445//   return -1; // listen sockets on DECnet are not supportet at the moment
446  } else {
447   // There is nothing wrong in this case to use dnet_conn() so we do.
448   fh = dnet_conn(host, obj, SOCK_STREAM, 0 ,0 ,0 , 0);
449   *del = ':';
450   return fh;
451  }
452#else
453  return -1; // no decnet support
454#endif
455 }
456
457 memset(&socket_addr,    0, sizeof(socket_addr));
458 memset(&he,             0, sizeof(he));               // FIXME: we have a valid pointer in here????
459
460
461 if ( type == ROAR_SOCKET_TYPE_INET || type == ROAR_SOCKET_TYPE_INET6 ) {
462
463  if ( (he = gethostbyname(host)) == NULL ) {
464   ROAR_ERR("roar_socket_open(*): Can\'t resolve host name '%s'",
465                     host);
466   return -1;
467  }
468
469   memcpy((struct in_addr *)&socket_addr.in.sin_addr, he->h_addr, sizeof(struct in_addr));
470
471   /* set the connect information */
472   socket_addr.in.sin_family = AF_INET;
473   socket_addr.in.sin_port   = ROAR_HOST2NET16(port);
474
475   fh = roar_socket_new_tcp();
476
477   if ( mode_func(fh, (struct sockaddr *)&socket_addr.in, sizeof(struct sockaddr_in)) == -1 ) {
478    ROAR_DBG("roar_socket_open(*): Can not connect/bind: %s", strerror(errno));
479    close(fh);
480    return -1;
481   }
482  // hey! we have a socket...
483 } else if ( type == ROAR_SOCKET_TYPE_UNIX ) {
484  socket_addr.un.sun_family = AF_UNIX;
485  strncpy(socket_addr.un.sun_path, host, sizeof(socket_addr.un.sun_path) - 1);
486
487  fh = roar_socket_new_unix();
488
489  if ( mode_func(fh, (struct sockaddr *)&socket_addr.un, sizeof(struct sockaddr_un)) == -1 ) {
490   ROAR_DBG("roar_socket_open(*): Can not connect/bind: %s", strerror(errno));
491   close(fh);
492   return -1;
493  }
494 } else if ( type == ROAR_SOCKET_TYPE_IPX ) {
495#ifdef ROAR_HAVE_IPX
496  socket_addr.ipx.sipx_family = AF_IPX;
497
498  obj[0] = 0;
499
500  if ( (ret = sscanf(host, "%8x.%12s(%x)", &socket_addr.ipx.sipx_network, obj,
501                               (unsigned int *)&socket_addr.ipx.sipx_port)) < 2 ) {
502   return -1;
503  } else if ( ret == 2 ) {
504   socket_addr.ipx.sipx_port = port; // Network Byte Order?
505  }
506
507  memset(socket_addr.ipx.sipx_node, 0, IPX_NODE_LEN);
508  ret = strlen(obj);
509
510  if ( ret % 2 )  // needs to be even at the moment
511   return -1;
512
513  fh = roar_socket_new_ipx();
514
515  close(fh);
516  return -1;
517#else
518  return -1;
519#endif
520 } else if ( type == ROAR_SOCKET_TYPE_FORK ) {
521  return roar_socket_open_fork(mode, host, port);
522 } else if ( type == ROAR_SOCKET_TYPE_FILE ) {
523  return roar_socket_open_file(mode, host, port);
524 } else {
525  return -1;
526 }
527
528 if ( mode == MODE_LISTEN )
529  if ( listen(fh, ROAR_SOCKET_QUEUE_LEN) == -1 ) {
530   close(fh);
531   return -1;
532  }
533
534 return fh;
535}
536
537int roar_socket_open_fork  (int mode, char * host, int port) {
538 int socks[2];
539 int r;
540 char fhstr[8];
541
542 if ( mode == MODE_LISTEN )
543  return -1;
544
545 if ( socketpair(AF_UNIX, SOCK_STREAM, 0, socks) == -1 ) {
546  return -1;
547 }
548
549 r = fork();
550
551 if ( r == -1 ) { // error!
552  ROAR_ERR("roar_socket_open_fork(*): Can not fork: %s", strerror(errno));
553  close(socks[0]);
554  close(socks[1]);
555  return -1;
556 } else if ( r == 0 ) { // we are the child
557  close(socks[0]);
558
559  close(ROAR_STDIN ); // we do not want roard to have any standard input
560  close(ROAR_STDOUT); // STDOUT is also not needed, so we close it,
561                      // but STDERR we keep open for error messages.
562
563  snprintf(fhstr, 7, "%i", socks[1]);
564
565  execlp("roard", "roard", "--no-listen", "--client-fh", fhstr, NULL);
566
567  // we are still alive?
568  ROAR_ERR("roar_socket_open_fork(*): alive after exec(), that's bad!");
569  _exit(1);
570 } else { // we are the parent
571  close(socks[1]);
572  return socks[0];
573 }
574
575 return -1;
576}
577
578int roar_socket_open_file  (int mode, char * host, int port) {
579 int fh;
580
581 if ( mode == MODE_LISTEN )
582  return -1;
583
584 if ( (fh = open(host, O_RDONLY, 0644)) == -1 ) {
585  ROAR_ERR("roar_socket_open_file(*): Can not open file %s: %s", host, strerror(errno));
586 }
587
588 return fh;
589}
590
591// --- [ PROXY CODE ] ---
592
593// generic proxy code:
594
595int roar_socket_open_proxy (int mode, int type, char * host, int port, char * proxy_type) {
596 int    proxy_port;
597 char   proxy_host[ROAR_SOCKET_MAX_HOSTNAMELEN];
598 char * proxy_addr;
599 int    i;
600 int    fh;
601
602 // TODO: change this so we support listen() proxys (ssh -R)
603 if ( mode != MODE_CONNECT )
604  return -1;
605
606 if ( !strcmp(proxy_type, "socks4a") ) { // for TOR, the only supported type at the moment
607  proxy_addr = getenv("socks_proxy");
608
609  proxy_port = 9050; // TOR's default port
610
611  if ( proxy_addr == NULL )
612   return -1;
613
614  for (i = 0; proxy_addr[i] != 0 && proxy_addr[i] != ':' && i < ROAR_SOCKET_MAX_HOSTNAMELEN; i++)
615   proxy_host[i] = proxy_addr[i];
616  proxy_host[i] = 0;
617
618  if ( i == 0 ) // no hostname found
619   return -1;
620
621  if ( proxy_addr[i] == ':' )
622   proxy_port = atoi(&proxy_addr[i+1]);
623
624  if ( (fh = roar_socket_open(mode, type, proxy_host, proxy_port)) == -1) {
625   return -1;
626  }
627
628  if ( roar_socket_open_socks4a(mode, fh, host, port) == -1 ) {
629   close(fh);
630   return -1;
631  }
632
633  return fh;
634 } else {
635  return -1; // unknown type
636 }
637}
638
639// protocoll dependet proxy code:
640
641int roar_socket_open_socks4a(int mode, int fh, char * host, int port) {
642 char buf[9];
643 int  len;
644
645 buf[0] = 0x04;
646 buf[1] = mode == MODE_CONNECT ? 0x01 : 0x02;
647 *((uint16_t*)&buf[2]) = htons(port);
648 buf[4] = 0x00;
649 buf[5] = 0x00;
650 buf[6] = 0x00;
651 buf[7] = 0x01;
652 buf[8] = 0x00;
653
654 if ( write(fh, buf, 9) != 9 )
655  return -1;
656
657 len = strlen(host);
658
659 if ( write(fh, host, len) != len )
660  return -1;
661
662 if ( write(fh, "\0", 1) != 1 )
663  return -1;
664
665 if ( read(fh, buf, 8) != 8 )
666  return -1;
667
668 if ( buf[1] != 0x5a )
669  return -1;
670
671 return 0;
672}
673
674//ll
Note: See TracBrowser for help on using the repository browser.