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