1 /* Copyright (C) 2007-2008 The Android Open Source Project
2 **
3 ** This software is licensed under the terms of the GNU General Public
4 ** License version 2, as published by the Free Software Foundation, and
5 ** may be copied, distributed, and modified under those terms.
6 **
7 ** This program is distributed in the hope that it will be useful,
8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 ** GNU General Public License for more details.
11 */
12 #include "proxy_int.h"
13 #include "sockets.h"
14 #include <stdarg.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <errno.h>
18 #include "android/utils/misc.h"
19 #include "android/utils/system.h"
20 #include "iolooper.h"
21 #include <stdlib.h>
22
23 int proxy_log = 0;
24
25 void
proxy_LOG(const char * fmt,...)26 proxy_LOG(const char* fmt, ...)
27 {
28 va_list args;
29 va_start(args, fmt);
30 vfprintf(stderr, fmt, args);
31 va_end(args);
32 fprintf(stderr, "\n");
33 }
34
35 void
proxy_set_verbose(int mode)36 proxy_set_verbose(int mode)
37 {
38 proxy_log = mode;
39 }
40
41 /** Global connection list
42 **/
43
44 static ProxyConnection s_connections[1];
45
46 #define MAX_HEX_DUMP 512
47
48 static void
hex_dump(void * base,int size,const char * prefix)49 hex_dump( void* base, int size, const char* prefix )
50 {
51 STRALLOC_DEFINE(s);
52 if (size > MAX_HEX_DUMP)
53 size = MAX_HEX_DUMP;
54 stralloc_add_hexdump(s, base, size, prefix);
55 proxy_LOG( "%s", stralloc_cstr(s) );
56 stralloc_reset(s);
57 }
58
59 void
proxy_connection_init(ProxyConnection * conn,int socket,SockAddress * address,ProxyService * service,ProxyConnectionFreeFunc conn_free,ProxyConnectionSelectFunc conn_select,ProxyConnectionPollFunc conn_poll)60 proxy_connection_init( ProxyConnection* conn,
61 int socket,
62 SockAddress* address,
63 ProxyService* service,
64 ProxyConnectionFreeFunc conn_free,
65 ProxyConnectionSelectFunc conn_select,
66 ProxyConnectionPollFunc conn_poll )
67 {
68 conn->socket = socket;
69 conn->address = address[0];
70 conn->service = service;
71 conn->next = NULL;
72
73 conn->conn_free = conn_free;
74 conn->conn_select = conn_select;
75 conn->conn_poll = conn_poll;
76
77 socket_set_nonblock(socket);
78
79 {
80 SocketType type = socket_get_type(socket);
81
82 snprintf( conn->name, sizeof(conn->name),
83 "%s:%s(%d)",
84 (type == SOCKET_STREAM) ? "tcp" : "udp",
85 sock_address_to_string(address), socket );
86
87 /* just in case */
88 conn->name[sizeof(conn->name)-1] = 0;
89 }
90
91 stralloc_reset(conn->str);
92 conn->str_pos = 0;
93 }
94
95 void
proxy_connection_done(ProxyConnection * conn)96 proxy_connection_done( ProxyConnection* conn )
97 {
98 stralloc_reset( conn->str );
99 if (conn->socket >= 0) {
100 socket_close(conn->socket);
101 conn->socket = -1;
102 }
103 }
104
105
106 void
proxy_connection_rewind(ProxyConnection * conn)107 proxy_connection_rewind( ProxyConnection* conn )
108 {
109 stralloc_t* str = conn->str;
110
111 /* only keep a small buffer in the heap */
112 conn->str_pos = 0;
113 str->n = 0;
114 if (str->a > 1024)
115 stralloc_reset(str);
116 }
117
118 DataStatus
proxy_connection_send(ProxyConnection * conn,int fd)119 proxy_connection_send( ProxyConnection* conn, int fd )
120 {
121 stralloc_t* str = conn->str;
122 int avail = str->n - conn->str_pos;
123
124 conn->str_sent = 0;
125
126 if (avail <= 0)
127 return 1;
128
129 if (proxy_log) {
130 PROXY_LOG("%s: sending %d bytes:", conn->name, avail );
131 hex_dump( str->s + conn->str_pos, avail, ">> " );
132 }
133
134 while (avail > 0) {
135 int n = socket_send(fd, str->s + conn->str_pos, avail);
136 if (n == 0) {
137 PROXY_LOG("%s: connection reset by peer (send)",
138 conn->name);
139 return DATA_ERROR;
140 }
141 if (n < 0) {
142 if (errno == EWOULDBLOCK || errno == EAGAIN)
143 return DATA_NEED_MORE;
144
145 PROXY_LOG("%s: error: %s", conn->name, errno_str);
146 return DATA_ERROR;
147 }
148 conn->str_pos += n;
149 conn->str_sent += n;
150 avail -= n;
151 }
152
153 proxy_connection_rewind(conn);
154 return DATA_COMPLETED;
155 }
156
157
158 DataStatus
proxy_connection_receive(ProxyConnection * conn,int fd,int wanted)159 proxy_connection_receive( ProxyConnection* conn, int fd, int wanted )
160 {
161 stralloc_t* str = conn->str;
162
163 conn->str_recv = 0;
164
165 while (wanted > 0) {
166 int n;
167
168 stralloc_readyplus( str, wanted );
169 n = socket_recv(fd, str->s + str->n, wanted);
170 if (n == 0) {
171 PROXY_LOG("%s: connection reset by peer (receive)",
172 conn->name);
173 return DATA_ERROR;
174 }
175 if (n < 0) {
176 if (errno == EWOULDBLOCK || errno == EAGAIN)
177 return DATA_NEED_MORE;
178
179 PROXY_LOG("%s: error: %s", conn->name, errno_str);
180 return DATA_ERROR;
181 }
182
183 if (proxy_log) {
184 PROXY_LOG("%s: received %d bytes:", conn->name, n );
185 hex_dump( str->s + str->n, n, "<< " );
186 }
187
188 str->n += n;
189 wanted -= n;
190 conn->str_recv += n;
191 }
192 return DATA_COMPLETED;
193 }
194
195
196 DataStatus
proxy_connection_receive_line(ProxyConnection * conn,int fd)197 proxy_connection_receive_line( ProxyConnection* conn, int fd )
198 {
199 stralloc_t* str = conn->str;
200
201 for (;;) {
202 char c;
203 int n = socket_recv(fd, &c, 1);
204 if (n == 0) {
205 PROXY_LOG("%s: disconnected from server", conn->name );
206 return DATA_ERROR;
207 }
208 if (n < 0) {
209 if (errno == EWOULDBLOCK || errno == EAGAIN) {
210 PROXY_LOG("%s: blocked", conn->name);
211 return DATA_NEED_MORE;
212 }
213 PROXY_LOG("%s: error: %s", conn->name, errno_str);
214 return DATA_ERROR;
215 }
216
217 stralloc_add_c(str, c);
218 if (c == '\n') {
219 str->s[--str->n] = 0;
220 if (str->n > 0 && str->s[str->n-1] == '\r')
221 str->s[--str->n] = 0;
222
223 PROXY_LOG("%s: received '%s'", conn->name,
224 quote_bytes(str->s, str->n));
225 return DATA_COMPLETED;
226 }
227 }
228 }
229
230 static void
proxy_connection_insert(ProxyConnection * conn,ProxyConnection * after)231 proxy_connection_insert( ProxyConnection* conn, ProxyConnection* after )
232 {
233 conn->next = after->next;
234 after->next->prev = conn;
235 after->next = conn;
236 conn->prev = after;
237 }
238
239 static void
proxy_connection_remove(ProxyConnection * conn)240 proxy_connection_remove( ProxyConnection* conn )
241 {
242 conn->prev->next = conn->next;
243 conn->next->prev = conn->prev;
244
245 conn->next = conn->prev = conn;
246 }
247
248 /** Global service list
249 **/
250
251 #define MAX_SERVICES 4
252
253 static ProxyService* s_services[ MAX_SERVICES ];
254 static int s_num_services;
255 static int s_init;
256
257 static void proxy_manager_atexit( void );
258
259 static void
proxy_manager_init(void)260 proxy_manager_init(void)
261 {
262 s_init = 1;
263 s_connections->next = s_connections;
264 s_connections->prev = s_connections;
265 atexit( proxy_manager_atexit );
266 }
267
268
269 extern int
proxy_manager_add_service(ProxyService * service)270 proxy_manager_add_service( ProxyService* service )
271 {
272 if (!service || s_num_services >= MAX_SERVICES)
273 return -1;
274
275 if (!s_init)
276 proxy_manager_init();
277
278 s_services[s_num_services++] = service;
279 return 0;
280 }
281
282
283 extern void
proxy_manager_atexit(void)284 proxy_manager_atexit( void )
285 {
286 ProxyConnection* conn = s_connections->next;
287 int n;
288
289 /* free all proxy connections */
290 while (conn != s_connections) {
291 ProxyConnection* next = conn->next;
292 conn->conn_free( conn );
293 conn = next;
294 }
295 conn->next = conn;
296 conn->prev = conn;
297
298 /* free all proxy services */
299 for (n = s_num_services; n-- > 0;) {
300 ProxyService* service = s_services[n];
301 service->serv_free( service->opaque );
302 }
303 s_num_services = 0;
304 }
305
306
307 void
proxy_connection_free(ProxyConnection * conn,int keep_alive,ProxyEvent event)308 proxy_connection_free( ProxyConnection* conn,
309 int keep_alive,
310 ProxyEvent event )
311 {
312 if (conn) {
313 int fd = conn->socket;
314
315 proxy_connection_remove(conn);
316
317 if (event != PROXY_EVENT_NONE)
318 conn->ev_func( conn->ev_opaque, fd, event );
319
320 if (keep_alive)
321 conn->socket = -1;
322
323 conn->conn_free(conn);
324 }
325 }
326
327
328 int
proxy_manager_add(SockAddress * address,SocketType sock_type,ProxyEventFunc ev_func,void * ev_opaque)329 proxy_manager_add( SockAddress* address,
330 SocketType sock_type,
331 ProxyEventFunc ev_func,
332 void* ev_opaque )
333 {
334 int n;
335
336 if (!s_init) {
337 proxy_manager_init();
338 }
339
340 for (n = 0; n < s_num_services; n++) {
341 ProxyService* service = s_services[n];
342 ProxyConnection* conn = service->serv_connect( service->opaque,
343 sock_type,
344 address );
345 if (conn != NULL) {
346 conn->ev_func = ev_func;
347 conn->ev_opaque = ev_opaque;
348 proxy_connection_insert(conn, s_connections->prev);
349 return 0;
350 }
351 }
352 return -1;
353 }
354
355
356 /* remove an on-going proxified socket connection from the manager's list.
357 * this is only necessary when the socket connection must be canceled before
358 * the connection accept/refusal occured
359 */
360 void
proxy_manager_del(void * ev_opaque)361 proxy_manager_del( void* ev_opaque )
362 {
363 ProxyConnection* conn = s_connections->next;
364 for ( ; conn != s_connections; conn = conn->next ) {
365 if (conn->ev_opaque == ev_opaque) {
366 proxy_connection_remove(conn);
367 conn->conn_free(conn);
368 return;
369 }
370 }
371 }
372
373 void
proxy_select_set(ProxySelect * sel,int fd,unsigned flags)374 proxy_select_set( ProxySelect* sel,
375 int fd,
376 unsigned flags )
377 {
378 if (fd < 0 || !flags)
379 return;
380
381 if (*sel->pcount < fd+1)
382 *sel->pcount = fd+1;
383
384 if (flags & PROXY_SELECT_READ) {
385 FD_SET( fd, sel->reads );
386 } else {
387 FD_CLR( fd, sel->reads );
388 }
389 if (flags & PROXY_SELECT_WRITE) {
390 FD_SET( fd, sel->writes );
391 } else {
392 FD_CLR( fd, sel->writes );
393 }
394 if (flags & PROXY_SELECT_ERROR) {
395 FD_SET( fd, sel->errors );
396 } else {
397 FD_CLR( fd, sel->errors );
398 }
399 }
400
401 unsigned
proxy_select_poll(ProxySelect * sel,int fd)402 proxy_select_poll( ProxySelect* sel, int fd )
403 {
404 unsigned flags = 0;
405
406 if (fd >= 0) {
407 if ( FD_ISSET(fd, sel->reads) )
408 flags |= PROXY_SELECT_READ;
409 if ( FD_ISSET(fd, sel->writes) )
410 flags |= PROXY_SELECT_WRITE;
411 if ( FD_ISSET(fd, sel->errors) )
412 flags |= PROXY_SELECT_ERROR;
413 }
414 return flags;
415 }
416
417 /* this function is called to update the select file descriptor sets
418 * with those of the proxified connection sockets that are currently managed */
419 void
proxy_manager_select_fill(int * pcount,fd_set * read_fds,fd_set * write_fds,fd_set * err_fds)420 proxy_manager_select_fill( int *pcount, fd_set* read_fds, fd_set* write_fds, fd_set* err_fds)
421 {
422 ProxyConnection* conn;
423 ProxySelect sel[1];
424
425 if (!s_init)
426 proxy_manager_init();
427
428 sel->pcount = pcount;
429 sel->reads = read_fds;
430 sel->writes = write_fds;
431 sel->errors = err_fds;
432
433 conn = s_connections->next;
434 while (conn != s_connections) {
435 ProxyConnection* next = conn->next;
436 conn->conn_select(conn, sel);
437 conn = next;
438 }
439 }
440
441 /* this function is called to act on proxified connection sockets when network events arrive */
442 void
proxy_manager_poll(fd_set * read_fds,fd_set * write_fds,fd_set * err_fds)443 proxy_manager_poll( fd_set* read_fds, fd_set* write_fds, fd_set* err_fds )
444 {
445 ProxyConnection* conn = s_connections->next;
446 ProxySelect sel[1];
447
448 sel->pcount = NULL;
449 sel->reads = read_fds;
450 sel->writes = write_fds;
451 sel->errors = err_fds;
452
453 while (conn != s_connections) {
454 ProxyConnection* next = conn->next;
455 conn->conn_poll( conn, sel );
456 conn = next;
457 }
458 }
459
460
461 int
proxy_base64_encode(const char * src,int srclen,char * dst,int dstlen)462 proxy_base64_encode( const char* src, int srclen,
463 char* dst, int dstlen )
464 {
465 static const char cb64[64]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
466 const char* srcend = src + srclen;
467 int result = 0;
468
469 while (src+3 <= srcend && result+4 <= dstlen)
470 {
471 dst[result+0] = cb64[ src[0] >> 2 ];
472 dst[result+1] = cb64[ ((src[0] & 3) << 4) | ((src[1] & 0xf0) >> 4) ];
473 dst[result+2] = cb64[ ((src[1] & 0xf) << 2) | ((src[2] & 0xc0) >> 6) ];
474 dst[result+3] = cb64[ src[2] & 0x3f ];
475 src += 3;
476 result += 4;
477 }
478
479 if (src < srcend) {
480 unsigned char in[4];
481
482 if (result+4 > dstlen)
483 return -1;
484
485 in[0] = src[0];
486 in[1] = src+1 < srcend ? src[1] : 0;
487 in[2] = src+2 < srcend ? src[2] : 0;
488
489 dst[result+0] = cb64[ in[0] >> 2 ];
490 dst[result+1] = cb64[ ((in[0] & 3) << 4) | ((in[1] & 0xf0) >> 4) ];
491 dst[result+2] = (unsigned char) (src+1 < srcend ? cb64[ ((in[1] & 0xf) << 2) | ((in[2] & 0xc0) >> 6) ] : '=');
492 dst[result+3] = (unsigned char) (src+2 < srcend ? cb64[ in[2] & 0x3f ] : '=');
493 result += 4;
494 }
495 return result;
496 }
497
498 int
proxy_resolve_server(SockAddress * addr,const char * servername,int servernamelen,int serverport)499 proxy_resolve_server( SockAddress* addr,
500 const char* servername,
501 int servernamelen,
502 int serverport )
503 {
504 char name0[64], *name = name0;
505 int result = -1;
506
507 if (servernamelen < 0)
508 servernamelen = strlen(servername);
509
510 if (servernamelen >= sizeof(name0)) {
511 AARRAY_NEW(name, servernamelen+1);
512 }
513
514 memcpy(name, servername, servernamelen);
515 name[servernamelen] = 0;
516
517 if (sock_address_init_resolve( addr, name, serverport, 0 ) < 0) {
518 PROXY_LOG("%s: can't resolve proxy server name '%s'",
519 __FUNCTION__, name);
520 goto Exit;
521 }
522
523 PROXY_LOG("server name '%s' resolved to %s", name, sock_address_to_string(addr));
524 result = 0;
525
526 Exit:
527 if (name != name0)
528 AFREE(name);
529
530 return result;
531 }
532
533
534 int
proxy_check_connection(const char * proxyname,int proxyname_len,int proxyport,int timeout_ms)535 proxy_check_connection( const char* proxyname,
536 int proxyname_len,
537 int proxyport,
538 int timeout_ms )
539 {
540 SockAddress addr;
541 int sock;
542 IoLooper* looper;
543 int ret;
544
545 if (proxy_resolve_server(&addr, proxyname, proxyname_len, proxyport) < 0) {
546 return -1;
547 }
548
549 sock = socket_create(addr.family, SOCKET_STREAM);
550 if (sock < 0) {
551 PROXY_LOG("%s: Could not create socket !?: %s", __FUNCTION__, errno_str);
552 return -1;
553 }
554
555 socket_set_nonblock(sock);
556
557 /* An immediate connection is very unlikely, but deal with it, just in case */
558 if (socket_connect(sock, &addr) == 0) {
559 PROXY_LOG("%s: Immediate connection to %.*s:%d: %s !",
560 __FUNCTION__, proxyname_len, proxyname, proxyport);
561 socket_close(sock);
562 return 0;
563 }
564
565 /* Ok, create an IoLooper object to wait for the connection */
566 looper = iolooper_new();
567 iolooper_add_write(looper, sock);
568
569 ret = iolooper_wait(looper, timeout_ms);
570
571 iolooper_free(looper);
572 socket_close(sock);
573
574 if (ret == 0) {
575 errno = ETIMEDOUT;
576 ret = -1;
577 }
578 return ret;
579 }
580