source: roaraudio/libroar/socket.c @ 234:6c85d324d304

Last change on this file since 234:6c85d324d304 was 234:6c85d324d304, checked in by phi, 16 years ago

set IPTOS_LOWDELAY on TCP sockets

File size: 6.9 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_unix (void) {
30 int fh;
31
32 fh = socket(AF_UNIX, SOCK_STREAM, 0);
33
34 return fh;
35}
36
37int roar_socket_nonblock(int fh, int state) {
38 int flags;
39
40 if ( (flags = fcntl(fh, F_GETFL, 0)) == -1 ) {
41  ROAR_ERR("roar_socket_nonblock(fh=%i, state=%i): Can not read flags: %s", fh, state, strerror(errno));
42  ROAR_DBG("roar_socket_nonblock(fh=%i, state=%i) = -1", fh, state);
43  return -1;
44 }
45
46 flags |= O_NONBLOCK;
47
48 if ( state == ROAR_SOCKET_BLOCK )
49  flags -= O_NONBLOCK;
50
51 if ( fcntl(fh, F_SETFL, flags) == -1 ) {
52  ROAR_ERR("roar_socket_nonblock(fh=%i, state=%i): Can not set flags: %s", fh, state, strerror(errno));
53  ROAR_DBG("roar_socket_nonblock(fh=%i, state=%i) = -1", fh, state);
54  return -1;
55 }
56
57 ROAR_DBG("roar_socket_nonblock(fh=%i, state=%i) = 0", fh, state);
58 return 0;
59}
60
61int roar_socket_listen  (int type, char * host, int port) {
62 return roar_socket_open(MODE_LISTEN, type, host, port);
63}
64
65int roar_socket_connect (char * host, int port) {
66 char * proxy_type = getenv("ROAR_PROXY");
67
68 if ( proxy_type == NULL || strcmp(proxy_type, "") == 0 ) {
69  return roar_socket_open(MODE_CONNECT, ROAR_SOCKET_TYPE_UNKNOWN, host, port);
70 } else {
71  return roar_socket_open_proxy(MODE_CONNECT, ROAR_SOCKET_TYPE_UNKNOWN, host, port, proxy_type);
72 }
73}
74
75int roar_socket_open (int mode, int type, char * host, int port) {
76// int type = ROAR_SOCKET_TYPE_INET;
77 int fh;
78 struct sockaddr_in   socket_addr;
79 struct sockaddr_un   socket_addr_un;
80 struct hostent     * he;
81 //unsigned int host_div = 0;
82 int (*mode_func)(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen) = connect; // default is to connect
83
84 if ( mode == MODE_LISTEN )
85  mode_func = bind;
86
87 if ( type == ROAR_SOCKET_TYPE_UNKNOWN ) {
88  type = ROAR_SOCKET_TYPE_INET;
89  if ( *host == '/' ) {
90   type = ROAR_SOCKET_TYPE_UNIX;
91  } else if ( strcmp(host, "+fork") == 0 ) {
92   type = ROAR_SOCKET_TYPE_FORK;
93  }
94 }
95
96
97 ROAR_DBG("roar_socket_open(*): type=%s, host='%s', port=%i",
98             type == ROAR_SOCKET_TYPE_UNIX ? "UNIX" : "INET", host, port);
99
100 memset(&socket_addr   , 0, sizeof(socket_addr));
101 memset(&socket_addr_un, 0, sizeof(socket_addr_un));
102 memset(&he,             0, sizeof(he));               // FIXME: we have a valid pointer in here????
103
104
105 if ( type == ROAR_SOCKET_TYPE_INET ) {
106
107  if ( (he = gethostbyname(host)) == NULL ) {
108   ROAR_ERR("roar_socket_open(*): Can\'t resolve host name '%s'",
109                     host);
110   return -1;
111  }
112
113  memcpy((struct in_addr *)&socket_addr.sin_addr, he->h_addr, sizeof(struct in_addr));
114
115  /* set the connect information */
116  socket_addr.sin_family = AF_INET;
117  socket_addr.sin_port = htons( port );
118
119  fh = roar_socket_new_tcp();
120
121  if ( mode_func(fh, (struct sockaddr *)&socket_addr, sizeof(struct sockaddr_in)) == -1 ) {
122   ROAR_DBG("roar_socket_open(*): Can not connect/bind: %s", strerror(errno));
123   close(fh);
124   return -1;
125  }
126  // hey! we have a socket...
127 } else if ( type == ROAR_SOCKET_TYPE_UNIX ) {
128  socket_addr_un.sun_family = AF_UNIX;
129  strncpy(socket_addr_un.sun_path, host, sizeof(socket_addr_un.sun_path) - 1);
130
131  fh = roar_socket_new_unix();
132
133  if ( mode_func(fh, (struct sockaddr *)&socket_addr_un, sizeof(struct sockaddr_un)) == -1 ) {
134   ROAR_DBG("roar_socket_open(*): Can not connect/bind: %s", strerror(errno));
135   close(fh);
136   return -1;
137  }
138 } else if ( type == ROAR_SOCKET_TYPE_FORK ) {
139  return roar_socket_open_fork(mode, host, port);
140 } else if ( type == ROAR_SOCKET_TYPE_FILE ) {
141  return roar_socket_open_file(mode, host, port);
142 } else {
143  return -1;
144 }
145
146 if ( mode == MODE_LISTEN )
147  if ( listen(fh, ROAR_SOCKET_QUEUE_LEN) == -1 ) {
148   close(fh);
149   return -1;
150  }
151
152 return fh;
153}
154
155int roar_socket_open_fork  (int mode, char * host, int port) {
156 int socks[2];
157 int r;
158 char fhstr[8];
159
160 if ( mode == MODE_LISTEN )
161  return -1;
162
163 if ( socketpair(AF_UNIX, SOCK_STREAM, 0, socks) == -1 ) {
164  return -1;
165 }
166
167 r = fork();
168
169 if ( r == -1 ) { // error!
170  ROAR_ERR("roar_socket_open_fork(*): Can not fork: %s", strerror(errno));
171  close(socks[0]);
172  close(socks[1]);
173  return -1;
174 } else if ( r == 0 ) { // we are the child
175  close(socks[0]);
176
177  close(ROAR_STDIN ); // we do not want roard to have any standard input
178  close(ROAR_STDOUT); // STDOUT is also not needed, so we close it,
179                      // but STDERR we keep open for error messages.
180
181  snprintf(fhstr, 7, "%i", socks[1]);
182
183  execlp("roard", "roard", "--terminate", "--no-listen", "--client-fh", fhstr, NULL);
184
185  // we are still alive?
186  ROAR_ERR("roar_socket_open_fork(*): alive after exec(), that's bad!");
187  _exit(1);
188 } else { // we are the parent
189  close(socks[1]);
190  return socks[0];
191 }
192
193 return -1;
194}
195
196int roar_socket_open_file  (int mode, char * host, int port) {
197 int fh;
198
199 if ( mode == MODE_LISTEN )
200  return -1;
201
202 if ( (fh = open(host, O_RDONLY, 0644)) == -1 ) {
203  ROAR_ERR("roar_socket_open_file(*): Can not open file %s: %s", host, strerror(errno));
204 }
205
206 return fh;
207}
208
209// --- [ PROXY CODE ] ---
210
211// generic proxy code:
212
213int roar_socket_open_proxy (int mode, int type, char * host, int port, char * proxy_type) {
214 int    proxy_port;
215 char   proxy_host[ROAR_SOCKET_MAX_HOSTNAMELEN];
216 char * proxy_addr;
217 int    i;
218 int    fh;
219
220 // TODO: change this so we support listen() proxys (ssh -R)
221 if ( mode != MODE_CONNECT )
222  return -1;
223
224 if ( !strcmp(proxy_type, "socks4a") ) { // for TOR, the only supported type at the moment
225  proxy_addr = getenv("socks_proxy");
226
227  proxy_port = 9050; // TOR's default port
228
229  if ( proxy_addr == NULL )
230   return -1;
231
232  for (i = 0; proxy_addr[i] != 0 && proxy_addr[i] != ':' && i < ROAR_SOCKET_MAX_HOSTNAMELEN; i++)
233   proxy_host[i] = proxy_addr[i];
234  proxy_host[i] = 0;
235
236  if ( i == 0 ) // no hostname found
237   return -1;
238
239  if ( proxy_addr[i] == ':' )
240   proxy_port = atoi(&proxy_addr[i+1]);
241
242  if ( (fh = roar_socket_open(mode, type, proxy_host, proxy_port)) == -1) {
243   return -1;
244  }
245
246  if ( roar_socket_open_socks4a(mode, fh, host, port) == -1 ) {
247   close(fh);
248   return -1;
249  }
250
251  return fh;
252 } else {
253  return -1; // unknown type
254 }
255}
256
257// protocoll dependet proxy code:
258
259int roar_socket_open_socks4a(int mode, int fh, char * host, int port) {
260 char buf[9];
261 int  len;
262
263 buf[0] = 0x04;
264 buf[1] = mode == MODE_CONNECT ? 0x01 : 0x02;
265 *((uint16_t*)&buf[2]) = htons(port);
266 buf[4] = 0x00;
267 buf[5] = 0x00;
268 buf[6] = 0x00;
269 buf[7] = 0x01;
270 buf[8] = 0x00;
271
272 if ( write(fh, buf, 9) != 9 )
273  return -1;
274
275 len = strlen(host);
276
277 if ( write(fh, host, len) != len )
278  return -1;
279
280 if ( write(fh, "\0", 1) != 1 )
281  return -1;
282
283 if ( read(fh, buf, 8) != 8 )
284  return -1;
285
286 if ( buf[1] != 0x5a )
287  return -1;
288
289 return 0;
290}
291
292//ll
Note: See TracBrowser for help on using the repository browser.