source: roaraudio/libroar/socket.c @ 521:f7ca1f94e9e5

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

added roar_socket_get_local_nodename() and use it as default hostname

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