source: roaraudio/libroar/socket.c @ 508:1129ff87dd1e

Last change on this file since 508:1129ff87dd1e was 508:1129ff87dd1e, checked in by phi, 16 years ago

added DECnet listen support, introused -n/--decnet to roard, added woraround to Linux DECnet stack bugs on streams and added some helpfull DECnet macros, puh...

File size: 10.5 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_unix (void) {
31 int fh;
32#ifdef SO_PEERCRED
33 int opt = 1;
34#endif
35
36 fh = socket(AF_UNIX, SOCK_STREAM, 0);
37
38#ifdef SO_PEERCRED
39 setsockopt(fh, SOL_SOCKET, SO_PASSCRED, &opt, sizeof(int));
40#endif
41
42 return fh;
43}
44
45int roar_socket_new_decnet_seqpacket (void) {
46#ifdef ROAR_HAVE_LIBDNET
47 int fh;
48
49 fh = socket(AF_DECnet, SOCK_SEQPACKET, DNPROTO_NSP);
50
51 return fh;
52#else
53 return -1;
54#endif
55}
56
57
58int roar_socket_new_decnet_stream (void) {
59#ifdef ROAR_HAVE_LIBDNET
60 int fh;
61
62 fh = socket(AF_DECnet, SOCK_STREAM, DNPROTO_NSP);
63
64 return fh;
65#else
66 return -1;
67#endif
68}
69
70
71int roar_socket_nonblock(int fh, int state) {
72 int flags;
73
74 if ( (flags = fcntl(fh, F_GETFL, 0)) == -1 ) {
75  ROAR_ERR("roar_socket_nonblock(fh=%i, state=%i): Can not read flags: %s", fh, state, strerror(errno));
76  ROAR_DBG("roar_socket_nonblock(fh=%i, state=%i) = -1", fh, state);
77  return -1;
78 }
79
80 flags |= O_NONBLOCK;
81
82 if ( state == ROAR_SOCKET_BLOCK )
83  flags -= O_NONBLOCK;
84
85 if ( fcntl(fh, F_SETFL, flags) == -1 ) {
86  ROAR_ERR("roar_socket_nonblock(fh=%i, state=%i): Can not set flags: %s", fh, state, strerror(errno));
87  ROAR_DBG("roar_socket_nonblock(fh=%i, state=%i) = -1", fh, state);
88  return -1;
89 }
90
91 ROAR_DBG("roar_socket_nonblock(fh=%i, state=%i) = 0", fh, state);
92 return 0;
93}
94
95int roar_socket_dup_udp_local_end (int fh) {
96 int                  n              = -1;
97 int                  flags          = -1;
98 struct sockaddr_in   socket_addr;
99 socklen_t            len            = sizeof(struct sockaddr_in);
100
101 if ( (flags = fcntl(fh, F_GETFL, 0)) == -1 ) {
102  ROAR_WARN("roar_socket_dup_udp_local_end(fh=%i): Can not read flags: %s", fh, strerror(errno));
103 }
104
105 if ( getsockname(fh, (struct sockaddr *)&socket_addr, &len) == -1 ) {
106  return -1;
107 }
108
109 if ( socket_addr.sin_family != AF_INET ) {
110  return -1;
111 }
112
113 n = roar_socket_new_udp();
114
115 if ( n == -1 )
116  return -1;
117
118//  if ( mode_func(fh, (struct sockaddr *)&socket_addr, sizeof(struct sockaddr_in)) == -1 ) {
119 if ( bind(n, (struct sockaddr *)&socket_addr, len) == -1 ) {
120  close(n);
121  return -1;
122 }
123
124 if ( flags != -1 ) {
125  if ( fcntl(fh, F_SETFL, flags) == -1 ) {
126   ROAR_WARN("roar_socket_dup_udp_local_end(fh=%i): Can not set flags: %s", fh, strerror(errno));
127   return -1;
128  }
129 }
130
131
132 return n;
133}
134
135int roar_socket_listen  (int type, char * host, int port) {
136 return roar_socket_open(MODE_LISTEN, type, host, port);
137}
138
139int roar_socket_connect (char * host, int port) {
140 char * proxy_type = getenv("ROAR_PROXY");
141
142 if ( proxy_type == NULL || strcmp(proxy_type, "") == 0 ) {
143  return roar_socket_open(MODE_CONNECT, ROAR_SOCKET_TYPE_UNKNOWN, host, port);
144 } else {
145  return roar_socket_open_proxy(MODE_CONNECT, ROAR_SOCKET_TYPE_UNKNOWN, host, port, proxy_type);
146 }
147}
148
149
150int roar_socket_listen_decnet (char * object, int num) {
151#ifdef ROAR_HAVE_LIBDNET
152 int fh = roar_socket_new_decnet_stream();
153 struct sockaddr_dn bind_sockaddr;
154
155 if ( fh == -1 )
156  return -1;
157
158 if ( !*object )
159  object = NULL;
160
161 if ( (object && num) || (!*object && !num) ) {
162  ROAR_WARN("roar_socket_listen_decnet(object='%s', num=%i): illegal address!", object, num);
163  close(fh);
164  return -1;
165 }
166
167 memset((void*)&bind_sockaddr, 0, sizeof(struct sockaddr_dn));
168
169 bind_sockaddr.sdn_family    = AF_DECnet;
170 bind_sockaddr.sdn_flags     = 0;
171 bind_sockaddr.sdn_objnum    = num;
172
173 if ( num ) {
174  bind_sockaddr.sdn_objnamel = 0;
175 } else {
176  bind_sockaddr.sdn_objnamel  = ROAR_dn_htons(strlen(object));
177  strcpy((char*)bind_sockaddr.sdn_objname, object); // FIXME: shouldn't we use strncpy()?
178 }
179
180 if ( bind(fh, (struct sockaddr *) &bind_sockaddr, sizeof(bind_sockaddr)) == -1 ) {
181  close(fh);
182  return -1;
183 }
184
185 if ( listen(fh, 8) == -1 ) {
186  close(fh);
187  return -1;
188 }
189
190 return fh;
191#else
192 return -1;
193#endif
194}
195
196int roar_socket_open (int mode, int type, char * host, int port) {
197// int type = ROAR_SOCKET_TYPE_INET;
198 int fh;
199 struct sockaddr_in   socket_addr;
200 struct sockaddr_un   socket_addr_un;
201 struct hostent     * he;
202 //unsigned int host_div = 0;
203 int (*mode_func)(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen) = connect; // default is to connect
204#ifdef ROAR_HAVE_LIBDNET
205 char obj[80];
206 char * del;
207#endif
208
209 if ( mode == MODE_LISTEN )
210  mode_func = bind;
211
212 if ( type == ROAR_SOCKET_TYPE_UNKNOWN ) {
213  type = ROAR_SOCKET_TYPE_INET;
214  if ( *host == '/' ) {
215   type = ROAR_SOCKET_TYPE_UNIX;
216  } else if ( strcmp(host, "+fork") == 0 ) {
217   type = ROAR_SOCKET_TYPE_FORK;
218  } else if ( strstr(host, "::") != NULL ) {
219   type = ROAR_SOCKET_TYPE_DECNET;
220  }
221 }
222
223
224 ROAR_DBG("roar_socket_open(*): type=%s, host='%s', port=%i",
225             type == ROAR_SOCKET_TYPE_UNIX ? "UNIX" : "INET", host, port);
226
227 if ( type == ROAR_SOCKET_TYPE_DECNET ) {
228#ifdef ROAR_HAVE_LIBDNET
229   ROAR_DBG("roar_socket_open(*): hostname for DECnet: host(%p)=%s", host, host);
230   del = strstr(host, "::");
231   ROAR_DBG("roar_socket_open(*): hostname for DECnet: del(%p)=%s", del, del);
232
233   if ( del == NULL ) {
234    ROAR_WARN("roar_socket_open(*): invalid hostname for DECnet: %s", host);
235    return -1;
236   }
237
238   *del = 0;
239
240   if ( *(del+2) == '#' ) { // assume we have node::#num
241    port = atoi(del+2);
242   }
243
244   if ( port ) {
245    sprintf(obj, "%i", port); // no need for snprintf() as dec(port) is smaller than obj[]
246   } else {
247    *obj = 0;
248    strncat(obj, del+2, 79);
249   }
250
251  if ( mode == MODE_LISTEN ) {
252   fh = roar_socket_listen_decnet(obj, port);
253   *del = ':';
254   return fh;
255//   return -1; // listen sockets on DECnet are not supportet at the moment
256  } else {
257   // There is nothing wrong in this case to use dnet_conn() so we do.
258   fh = dnet_conn(host, obj, SOCK_STREAM, 0 ,0 ,0 , 0);
259   *del = ':';
260   return fh;
261#else
262   return -1; // no decnet support
263#endif
264  }
265 }
266
267 memset(&socket_addr   , 0, sizeof(socket_addr));
268 memset(&socket_addr_un, 0, sizeof(socket_addr_un));
269 memset(&he,             0, sizeof(he));               // FIXME: we have a valid pointer in here????
270
271
272 if ( type == ROAR_SOCKET_TYPE_INET ) {
273
274  if ( (he = gethostbyname(host)) == NULL ) {
275   ROAR_ERR("roar_socket_open(*): Can\'t resolve host name '%s'",
276                     host);
277   return -1;
278  }
279
280  memcpy((struct in_addr *)&socket_addr.sin_addr, he->h_addr, sizeof(struct in_addr));
281
282  /* set the connect information */
283  socket_addr.sin_family = AF_INET;
284  socket_addr.sin_port = htons( port );
285
286  fh = roar_socket_new_tcp();
287
288  if ( mode_func(fh, (struct sockaddr *)&socket_addr, sizeof(struct sockaddr_in)) == -1 ) {
289   ROAR_DBG("roar_socket_open(*): Can not connect/bind: %s", strerror(errno));
290   close(fh);
291   return -1;
292  }
293  // hey! we have a socket...
294 } else if ( type == ROAR_SOCKET_TYPE_UNIX ) {
295  socket_addr_un.sun_family = AF_UNIX;
296  strncpy(socket_addr_un.sun_path, host, sizeof(socket_addr_un.sun_path) - 1);
297
298  fh = roar_socket_new_unix();
299
300  if ( mode_func(fh, (struct sockaddr *)&socket_addr_un, sizeof(struct sockaddr_un)) == -1 ) {
301   ROAR_DBG("roar_socket_open(*): Can not connect/bind: %s", strerror(errno));
302   close(fh);
303   return -1;
304  }
305 } else if ( type == ROAR_SOCKET_TYPE_FORK ) {
306  return roar_socket_open_fork(mode, host, port);
307 } else if ( type == ROAR_SOCKET_TYPE_FILE ) {
308  return roar_socket_open_file(mode, host, port);
309 } else {
310  return -1;
311 }
312
313 if ( mode == MODE_LISTEN )
314  if ( listen(fh, ROAR_SOCKET_QUEUE_LEN) == -1 ) {
315   close(fh);
316   return -1;
317  }
318
319 return fh;
320}
321
322int roar_socket_open_fork  (int mode, char * host, int port) {
323 int socks[2];
324 int r;
325 char fhstr[8];
326
327 if ( mode == MODE_LISTEN )
328  return -1;
329
330 if ( socketpair(AF_UNIX, SOCK_STREAM, 0, socks) == -1 ) {
331  return -1;
332 }
333
334 r = fork();
335
336 if ( r == -1 ) { // error!
337  ROAR_ERR("roar_socket_open_fork(*): Can not fork: %s", strerror(errno));
338  close(socks[0]);
339  close(socks[1]);
340  return -1;
341 } else if ( r == 0 ) { // we are the child
342  close(socks[0]);
343
344  close(ROAR_STDIN ); // we do not want roard to have any standard input
345  close(ROAR_STDOUT); // STDOUT is also not needed, so we close it,
346                      // but STDERR we keep open for error messages.
347
348  snprintf(fhstr, 7, "%i", socks[1]);
349
350  execlp("roard", "roard", "--terminate", "--no-listen", "--client-fh", fhstr, NULL);
351
352  // we are still alive?
353  ROAR_ERR("roar_socket_open_fork(*): alive after exec(), that's bad!");
354  _exit(1);
355 } else { // we are the parent
356  close(socks[1]);
357  return socks[0];
358 }
359
360 return -1;
361}
362
363int roar_socket_open_file  (int mode, char * host, int port) {
364 int fh;
365
366 if ( mode == MODE_LISTEN )
367  return -1;
368
369 if ( (fh = open(host, O_RDONLY, 0644)) == -1 ) {
370  ROAR_ERR("roar_socket_open_file(*): Can not open file %s: %s", host, strerror(errno));
371 }
372
373 return fh;
374}
375
376// --- [ PROXY CODE ] ---
377
378// generic proxy code:
379
380int roar_socket_open_proxy (int mode, int type, char * host, int port, char * proxy_type) {
381 int    proxy_port;
382 char   proxy_host[ROAR_SOCKET_MAX_HOSTNAMELEN];
383 char * proxy_addr;
384 int    i;
385 int    fh;
386
387 // TODO: change this so we support listen() proxys (ssh -R)
388 if ( mode != MODE_CONNECT )
389  return -1;
390
391 if ( !strcmp(proxy_type, "socks4a") ) { // for TOR, the only supported type at the moment
392  proxy_addr = getenv("socks_proxy");
393
394  proxy_port = 9050; // TOR's default port
395
396  if ( proxy_addr == NULL )
397   return -1;
398
399  for (i = 0; proxy_addr[i] != 0 && proxy_addr[i] != ':' && i < ROAR_SOCKET_MAX_HOSTNAMELEN; i++)
400   proxy_host[i] = proxy_addr[i];
401  proxy_host[i] = 0;
402
403  if ( i == 0 ) // no hostname found
404   return -1;
405
406  if ( proxy_addr[i] == ':' )
407   proxy_port = atoi(&proxy_addr[i+1]);
408
409  if ( (fh = roar_socket_open(mode, type, proxy_host, proxy_port)) == -1) {
410   return -1;
411  }
412
413  if ( roar_socket_open_socks4a(mode, fh, host, port) == -1 ) {
414   close(fh);
415   return -1;
416  }
417
418  return fh;
419 } else {
420  return -1; // unknown type
421 }
422}
423
424// protocoll dependet proxy code:
425
426int roar_socket_open_socks4a(int mode, int fh, char * host, int port) {
427 char buf[9];
428 int  len;
429
430 buf[0] = 0x04;
431 buf[1] = mode == MODE_CONNECT ? 0x01 : 0x02;
432 *((uint16_t*)&buf[2]) = htons(port);
433 buf[4] = 0x00;
434 buf[5] = 0x00;
435 buf[6] = 0x00;
436 buf[7] = 0x01;
437 buf[8] = 0x00;
438
439 if ( write(fh, buf, 9) != 9 )
440  return -1;
441
442 len = strlen(host);
443
444 if ( write(fh, host, len) != len )
445  return -1;
446
447 if ( write(fh, "\0", 1) != 1 )
448  return -1;
449
450 if ( read(fh, buf, 8) != 8 )
451  return -1;
452
453 if ( buf[1] != 0x5a )
454  return -1;
455
456 return 0;
457}
458
459//ll
Note: See TracBrowser for help on using the repository browser.