source: roaraudio/libroar/socket.c @ 75:bca1641a0cd8

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

added support to open files like sockets

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