source: roaraudio/libroar/socket.c @ 507:5c9574ef2183

Last change on this file since 507:5c9574ef2183 was 503:36e7185c2678, checked in by phi, 16 years ago

cleanup

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