source: roaraudio/libroar/socket.c @ 233:01c44c8eecf8

Last change on this file since 233:01c44c8eecf8 was 81:d4aa20e568c9, checked in by phi, 16 years ago

added roar_stream_connect_to() to libroar

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