source: roaraudio/libroar/socket.c @ 534:e649f09f8e0e

roaraudio_0_1_testing5_janus
Last change on this file since 534:e649f09f8e0e was 534:e649f09f8e0e, checked in by phi, 16 years ago

#ifdef ROAR_HAVE_IPX around IPX block...

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