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 "android/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 "android/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