source: roaraudio/libroar/socket.c @ 442:f150cd44ec16

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

enable SO_PASSCRED on UNIX socktes per default

File size: 8.1 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
142 if ( mode == MODE_LISTEN )
143  mode_func = bind;
144
145 if ( type == ROAR_SOCKET_TYPE_UNKNOWN ) {
146  type = ROAR_SOCKET_TYPE_INET;
147  if ( *host == '/' ) {
148   type = ROAR_SOCKET_TYPE_UNIX;
149  } else if ( strcmp(host, "+fork") == 0 ) {
150   type = ROAR_SOCKET_TYPE_FORK;
151  }
152 }
153
154
155 ROAR_DBG("roar_socket_open(*): type=%s, host='%s', port=%i",
156             type == ROAR_SOCKET_TYPE_UNIX ? "UNIX" : "INET", host, port);
157
158 memset(&socket_addr   , 0, sizeof(socket_addr));
159 memset(&socket_addr_un, 0, sizeof(socket_addr_un));
160 memset(&he,             0, sizeof(he));               // FIXME: we have a valid pointer in here????
161
162
163 if ( type == ROAR_SOCKET_TYPE_INET ) {
164
165  if ( (he = gethostbyname(host)) == NULL ) {
166   ROAR_ERR("roar_socket_open(*): Can\'t resolve host name '%s'",
167                     host);
168   return -1;
169  }
170
171  memcpy((struct in_addr *)&socket_addr.sin_addr, he->h_addr, sizeof(struct in_addr));
172
173  /* set the connect information */
174  socket_addr.sin_family = AF_INET;
175  socket_addr.sin_port = htons( port );
176
177  fh = roar_socket_new_tcp();
178
179  if ( mode_func(fh, (struct sockaddr *)&socket_addr, sizeof(struct sockaddr_in)) == -1 ) {
180   ROAR_DBG("roar_socket_open(*): Can not connect/bind: %s", strerror(errno));
181   close(fh);
182   return -1;
183  }
184  // hey! we have a socket...
185 } else if ( type == ROAR_SOCKET_TYPE_UNIX ) {
186  socket_addr_un.sun_family = AF_UNIX;
187  strncpy(socket_addr_un.sun_path, host, sizeof(socket_addr_un.sun_path) - 1);
188
189  fh = roar_socket_new_unix();
190
191  if ( mode_func(fh, (struct sockaddr *)&socket_addr_un, sizeof(struct sockaddr_un)) == -1 ) {
192   ROAR_DBG("roar_socket_open(*): Can not connect/bind: %s", strerror(errno));
193   close(fh);
194   return -1;
195  }
196 } else if ( type == ROAR_SOCKET_TYPE_FORK ) {
197  return roar_socket_open_fork(mode, host, port);
198 } else if ( type == ROAR_SOCKET_TYPE_FILE ) {
199  return roar_socket_open_file(mode, host, port);
200 } else {
201  return -1;
202 }
203
204 if ( mode == MODE_LISTEN )
205  if ( listen(fh, ROAR_SOCKET_QUEUE_LEN) == -1 ) {
206   close(fh);
207   return -1;
208  }
209
210 return fh;
211}
212
213int roar_socket_open_fork  (int mode, char * host, int port) {
214 int socks[2];
215 int r;
216 char fhstr[8];
217
218 if ( mode == MODE_LISTEN )
219  return -1;
220
221 if ( socketpair(AF_UNIX, SOCK_STREAM, 0, socks) == -1 ) {
222  return -1;
223 }
224
225 r = fork();
226
227 if ( r == -1 ) { // error!
228  ROAR_ERR("roar_socket_open_fork(*): Can not fork: %s", strerror(errno));
229  close(socks[0]);
230  close(socks[1]);
231  return -1;
232 } else if ( r == 0 ) { // we are the child
233  close(socks[0]);
234
235  close(ROAR_STDIN ); // we do not want roard to have any standard input
236  close(ROAR_STDOUT); // STDOUT is also not needed, so we close it,
237                      // but STDERR we keep open for error messages.
238
239  snprintf(fhstr, 7, "%i", socks[1]);
240
241  execlp("roard", "roard", "--terminate", "--no-listen", "--client-fh", fhstr, NULL);
242
243  // we are still alive?
244  ROAR_ERR("roar_socket_open_fork(*): alive after exec(), that's bad!");
245  _exit(1);
246 } else { // we are the parent
247  close(socks[1]);
248  return socks[0];
249 }
250
251 return -1;
252}
253
254int roar_socket_open_file  (int mode, char * host, int port) {
255 int fh;
256
257 if ( mode == MODE_LISTEN )
258  return -1;
259
260 if ( (fh = open(host, O_RDONLY, 0644)) == -1 ) {
261  ROAR_ERR("roar_socket_open_file(*): Can not open file %s: %s", host, strerror(errno));
262 }
263
264 return fh;
265}
266
267// --- [ PROXY CODE ] ---
268
269// generic proxy code:
270
271int roar_socket_open_proxy (int mode, int type, char * host, int port, char * proxy_type) {
272 int    proxy_port;
273 char   proxy_host[ROAR_SOCKET_MAX_HOSTNAMELEN];
274 char * proxy_addr;
275 int    i;
276 int    fh;
277
278 // TODO: change this so we support listen() proxys (ssh -R)
279 if ( mode != MODE_CONNECT )
280  return -1;
281
282 if ( !strcmp(proxy_type, "socks4a") ) { // for TOR, the only supported type at the moment
283  proxy_addr = getenv("socks_proxy");
284
285  proxy_port = 9050; // TOR's default port
286
287  if ( proxy_addr == NULL )
288   return -1;
289
290  for (i = 0; proxy_addr[i] != 0 && proxy_addr[i] != ':' && i < ROAR_SOCKET_MAX_HOSTNAMELEN; i++)
291   proxy_host[i] = proxy_addr[i];
292  proxy_host[i] = 0;
293
294  if ( i == 0 ) // no hostname found
295   return -1;
296
297  if ( proxy_addr[i] == ':' )
298   proxy_port = atoi(&proxy_addr[i+1]);
299
300  if ( (fh = roar_socket_open(mode, type, proxy_host, proxy_port)) == -1) {
301   return -1;
302  }
303
304  if ( roar_socket_open_socks4a(mode, fh, host, port) == -1 ) {
305   close(fh);
306   return -1;
307  }
308
309  return fh;
310 } else {
311  return -1; // unknown type
312 }
313}
314
315// protocoll dependet proxy code:
316
317int roar_socket_open_socks4a(int mode, int fh, char * host, int port) {
318 char buf[9];
319 int  len;
320
321 buf[0] = 0x04;
322 buf[1] = mode == MODE_CONNECT ? 0x01 : 0x02;
323 *((uint16_t*)&buf[2]) = htons(port);
324 buf[4] = 0x00;
325 buf[5] = 0x00;
326 buf[6] = 0x00;
327 buf[7] = 0x01;
328 buf[8] = 0x00;
329
330 if ( write(fh, buf, 9) != 9 )
331  return -1;
332
333 len = strlen(host);
334
335 if ( write(fh, host, len) != len )
336  return -1;
337
338 if ( write(fh, "\0", 1) != 1 )
339  return -1;
340
341 if ( read(fh, buf, 8) != 8 )
342  return -1;
343
344 if ( buf[1] != 0x5a )
345  return -1;
346
347 return 0;
348}
349
350//ll
Note: See TracBrowser for help on using the repository browser.