• 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 "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