source: roaraudio/libroar/socket.c @ 533:bcfbd2933d39

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

move } to where it belongs to

File size: 13.0 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  socket_addr.ipx.sipx_family = AF_IPX;
411
412  obj[0] = 0;
413
414  if ( (ret = sscanf(host, "%8x.%12s(%x)", &socket_addr.ipx.sipx_network, obj,
415                               (unsigned int *)&socket_addr.ipx.sipx_port)) < 2 ) {
416   return -1;
417  } else if ( ret == 2 ) {
418   socket_addr.ipx.sipx_port = port; // Network Byte Order?
419  }
420
421  memset(socket_addr.ipx.sipx_node, 0, IPX_NODE_LEN);
422  ret = strlen(obj);
423
424  if ( ret % 2 )  // needs to be even at the moment
425   return -1;
426
427  fh = roar_socket_new_ipx();
428
429  close(fh);
430  return -1;
431 } else if ( type == ROAR_SOCKET_TYPE_FORK ) {
432  return roar_socket_open_fork(mode, host, port);
433 } else if ( type == ROAR_SOCKET_TYPE_FILE ) {
434  return roar_socket_open_file(mode, host, port);
435 } else {
436  return -1;
437 }
438
439 if ( mode == MODE_LISTEN )
440  if ( listen(fh, ROAR_SOCKET_QUEUE_LEN) == -1 ) {
441   close(fh);
442   return -1;
443  }
444
445 return fh;
446}
447
448int roar_socket_open_fork  (int mode, char * host, int port) {
449 int socks[2];
450 int r;
451 char fhstr[8];
452
453 if ( mode == MODE_LISTEN )
454  return -1;
455
456 if ( socketpair(AF_UNIX, SOCK_STREAM, 0, socks) == -1 ) {
457  return -1;
458 }
459
460 r = fork();
461
462 if ( r == -1 ) { // error!
463  ROAR_ERR("roar_socket_open_fork(*): Can not fork: %s", strerror(errno));
464  close(socks[0]);
465  close(socks[1]);
466  return -1;
467 } else if ( r == 0 ) { // we are the child
468  close(socks[0]);
469
470  close(ROAR_STDIN ); // we do not want roard to have any standard input
471  close(ROAR_STDOUT); // STDOUT is also not needed, so we close it,
472                      // but STDERR we keep open for error messages.
473
474  snprintf(fhstr, 7, "%i", socks[1]);
475
476  execlp("roard", "roard", "--terminate", "--no-listen", "--client-fh", fhstr, NULL);
477
478  // we are still alive?
479  ROAR_ERR("roar_socket_open_fork(*): alive after exec(), that's bad!");
480  _exit(1);
481 } else { // we are the parent
482  close(socks[1]);
483  return socks[0];
484 }
485
486 return -1;
487}
488
489int roar_socket_open_file  (int mode, char * host, int port) {
490 int fh;
491
492 if ( mode == MODE_LISTEN )
493  return -1;
494
495 if ( (fh = open(host, O_RDONLY, 0644)) == -1 ) {
496  ROAR_ERR("roar_socket_open_file(*): Can not open file %s: %s", host, strerror(errno));
497 }
498
499 return fh;
500}
501
502// --- [ PROXY CODE ] ---
503
504// generic proxy code:
505
506int roar_socket_open_proxy (int mode, int type, char * host, int port, char * proxy_type) {
507 int    proxy_port;
508 char   proxy_host[ROAR_SOCKET_MAX_HOSTNAMELEN];
509 char * proxy_addr;
510 int    i;
511 int    fh;
512
513 // TODO: change this so we support listen() proxys (ssh -R)
514 if ( mode != MODE_CONNECT )
515  return -1;
516
517 if ( !strcmp(proxy_type, "socks4a") ) { // for TOR, the only supported type at the moment
518  proxy_addr = getenv("socks_proxy");
519
520  proxy_port = 9050; // TOR's default port
521
522  if ( proxy_addr == NULL )
523   return -1;
524
525  for (i = 0; proxy_addr[i] != 0 && proxy_addr[i] != ':' && i < ROAR_SOCKET_MAX_HOSTNAMELEN; i++)
526   proxy_host[i] = proxy_addr[i];
527  proxy_host[i] = 0;
528
529  if ( i == 0 ) // no hostname found
530   return -1;
531
532  if ( proxy_addr[i] == ':' )
533   proxy_port = atoi(&proxy_addr[i+1]);
534
535  if ( (fh = roar_socket_open(mode, type, proxy_host, proxy_port)) == -1) {
536   return -1;
537  }
538
539  if ( roar_socket_open_socks4a(mode, fh, host, port) == -1 ) {
540   close(fh);
541   return -1;
542  }
543
544  return fh;
545 } else {
546  return -1; // unknown type
547 }
548}
549
550// protocoll dependet proxy code:
551
552int roar_socket_open_socks4a(int mode, int fh, char * host, int port) {
553 char buf[9];
554 int  len;
555
556 buf[0] = 0x04;
557 buf[1] = mode == MODE_CONNECT ? 0x01 : 0x02;
558 *((uint16_t*)&buf[2]) = htons(port);
559 buf[4] = 0x00;
560 buf[5] = 0x00;
561 buf[6] = 0x00;
562 buf[7] = 0x01;
563 buf[8] = 0x00;
564
565 if ( write(fh, buf, 9) != 9 )
566  return -1;
567
568 len = strlen(host);
569
570 if ( write(fh, host, len) != len )
571  return -1;
572
573 if ( write(fh, "\0", 1) != 1 )
574  return -1;
575
576 if ( read(fh, buf, 8) != 8 )
577  return -1;
578
579 if ( buf[1] != 0x5a )
580  return -1;
581
582 return 0;
583}
584
585//ll
Note: See TracBrowser for help on using the repository browser.