source: roaraudio/libroar/socket.c @ 501:985357040570

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

ha! It's working: RoarAudio via DECnet! :), needs cleanup

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