source: roaraudio/libroar/socket.c @ 548:bf2791966e7b

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

--no-listen now impleys --terminate

File size: 12.4 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   memcpy((struct in_addr *)&socket_addr.in.sin_addr, he->h_addr, sizeof(struct in_addr));
361
362   /* set the connect information */
363   socket_addr.in.sin_family = AF_INET;
364   socket_addr.in.sin_port   = ROAR_HOST2NET16(port);
365
366   fh = roar_socket_new_tcp();
367
368   if ( mode_func(fh, (struct sockaddr *)&socket_addr.in, sizeof(struct sockaddr_in)) == -1 ) {
369    ROAR_DBG("roar_socket_open(*): Can not connect/bind: %s", strerror(errno));
370    close(fh);
371    return -1;
372   }
373  // hey! we have a socket...
374 } else if ( type == ROAR_SOCKET_TYPE_UNIX ) {
375  socket_addr.un.sun_family = AF_UNIX;
376  strncpy(socket_addr.un.sun_path, host, sizeof(socket_addr.un.sun_path) - 1);
377
378  fh = roar_socket_new_unix();
379
380  if ( mode_func(fh, (struct sockaddr *)&socket_addr.un, sizeof(struct sockaddr_un)) == -1 ) {
381   ROAR_DBG("roar_socket_open(*): Can not connect/bind: %s", strerror(errno));
382   close(fh);
383   return -1;
384  }
385 } else if ( type == ROAR_SOCKET_TYPE_IPX ) {
386#ifdef ROAR_HAVE_IPX
387  socket_addr.ipx.sipx_family = AF_IPX;
388
389  obj[0] = 0;
390
391  if ( (ret = sscanf(host, "%8x.%12s(%x)", &socket_addr.ipx.sipx_network, obj,
392                               (unsigned int *)&socket_addr.ipx.sipx_port)) < 2 ) {
393   return -1;
394  } else if ( ret == 2 ) {
395   socket_addr.ipx.sipx_port = port; // Network Byte Order?
396  }
397
398  memset(socket_addr.ipx.sipx_node, 0, IPX_NODE_LEN);
399  ret = strlen(obj);
400
401  if ( ret % 2 )  // needs to be even at the moment
402   return -1;
403
404  fh = roar_socket_new_ipx();
405
406  close(fh);
407  return -1;
408#else
409  return -1;
410#endif
411 } else if ( type == ROAR_SOCKET_TYPE_FORK ) {
412  return roar_socket_open_fork(mode, host, port);
413 } else if ( type == ROAR_SOCKET_TYPE_FILE ) {
414  return roar_socket_open_file(mode, host, port);
415 } else {
416  return -1;
417 }
418
419 if ( mode == MODE_LISTEN )
420  if ( listen(fh, ROAR_SOCKET_QUEUE_LEN) == -1 ) {
421   close(fh);
422   return -1;
423  }
424
425 return fh;
426}
427
428int roar_socket_open_fork  (int mode, char * host, int port) {
429 int socks[2];
430 int r;
431 char fhstr[8];
432
433 if ( mode == MODE_LISTEN )
434  return -1;
435
436 if ( socketpair(AF_UNIX, SOCK_STREAM, 0, socks) == -1 ) {
437  return -1;
438 }
439
440 r = fork();
441
442 if ( r == -1 ) { // error!
443  ROAR_ERR("roar_socket_open_fork(*): Can not fork: %s", strerror(errno));
444  close(socks[0]);
445  close(socks[1]);
446  return -1;
447 } else if ( r == 0 ) { // we are the child
448  close(socks[0]);
449
450  close(ROAR_STDIN ); // we do not want roard to have any standard input
451  close(ROAR_STDOUT); // STDOUT is also not needed, so we close it,
452                      // but STDERR we keep open for error messages.
453
454  snprintf(fhstr, 7, "%i", socks[1]);
455
456  execlp("roard", "roard", "--no-listen", "--client-fh", fhstr, NULL);
457
458  // we are still alive?
459  ROAR_ERR("roar_socket_open_fork(*): alive after exec(), that's bad!");
460  _exit(1);
461 } else { // we are the parent
462  close(socks[1]);
463  return socks[0];
464 }
465
466 return -1;
467}
468
469int roar_socket_open_file  (int mode, char * host, int port) {
470 int fh;
471
472 if ( mode == MODE_LISTEN )
473  return -1;
474
475 if ( (fh = open(host, O_RDONLY, 0644)) == -1 ) {
476  ROAR_ERR("roar_socket_open_file(*): Can not open file %s: %s", host, strerror(errno));
477 }
478
479 return fh;
480}
481
482// --- [ PROXY CODE ] ---
483
484// generic proxy code:
485
486int roar_socket_open_proxy (int mode, int type, char * host, int port, char * proxy_type) {
487 int    proxy_port;
488 char   proxy_host[ROAR_SOCKET_MAX_HOSTNAMELEN];
489 char * proxy_addr;
490 int    i;
491 int    fh;
492
493 // TODO: change this so we support listen() proxys (ssh -R)
494 if ( mode != MODE_CONNECT )
495  return -1;
496
497 if ( !strcmp(proxy_type, "socks4a") ) { // for TOR, the only supported type at the moment
498  proxy_addr = getenv("socks_proxy");
499
500  proxy_port = 9050; // TOR's default port
501
502  if ( proxy_addr == NULL )
503   return -1;
504
505  for (i = 0; proxy_addr[i] != 0 && proxy_addr[i] != ':' && i < ROAR_SOCKET_MAX_HOSTNAMELEN; i++)
506   proxy_host[i] = proxy_addr[i];
507  proxy_host[i] = 0;
508
509  if ( i == 0 ) // no hostname found
510   return -1;
511
512  if ( proxy_addr[i] == ':' )
513   proxy_port = atoi(&proxy_addr[i+1]);
514
515  if ( (fh = roar_socket_open(mode, type, proxy_host, proxy_port)) == -1) {
516   return -1;
517  }
518
519  if ( roar_socket_open_socks4a(mode, fh, host, port) == -1 ) {
520   close(fh);
521   return -1;
522  }
523
524  return fh;
525 } else {
526  return -1; // unknown type
527 }
528}
529
530// protocoll dependet proxy code:
531
532int roar_socket_open_socks4a(int mode, int fh, char * host, int port) {
533 char buf[9];
534 int  len;
535
536 buf[0] = 0x04;
537 buf[1] = mode == MODE_CONNECT ? 0x01 : 0x02;
538 *((uint16_t*)&buf[2]) = htons(port);
539 buf[4] = 0x00;
540 buf[5] = 0x00;
541 buf[6] = 0x00;
542 buf[7] = 0x01;
543 buf[8] = 0x00;
544
545 if ( write(fh, buf, 9) != 9 )
546  return -1;
547
548 len = strlen(host);
549
550 if ( write(fh, host, len) != len )
551  return -1;
552
553 if ( write(fh, "\0", 1) != 1 )
554  return -1;
555
556 if ( read(fh, buf, 8) != 8 )
557  return -1;
558
559 if ( buf[1] != 0x5a )
560  return -1;
561
562 return 0;
563}
564
565//ll
Note: See TracBrowser for help on using the repository browser.