Home | History | Annotate | Download | only in proxy
      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
     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
     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
     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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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