source: roaraudio/libroar/socket.c @ 753:cb79175b94f9

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

added int roar_socket_recv_fh (int sock, char * mes, size_t * len);

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