source: roaraudio/libroar/socket.c @ 754:c9679895bf19

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

let roar_socket_send_fh() and roar_socket_recv_fh() support (virtally) zero length packets

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