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