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 "iolooper.h"
     21 #include <stdlib.h>
     22 
     23 int  proxy_log = 0;
     24 
     25 void
     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
     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
     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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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