Mercurial > pidgin
comparison libgaim/proxy.c @ 14451:8bc97389bdb2
[gaim-migrate @ 17165]
Some proxy love. This is much less crash-happy. I'm having
problems getting HTTP proxies to work for me, but my squid
might be misconfigured. And I haven't tested socks4 or 5 yet.
committer: Tailor Script <tailor@pidgin.im>
| author | Mark Doliner <mark@kingant.net> |
|---|---|
| date | Tue, 05 Sep 2006 06:10:38 +0000 |
| parents | 92eb7a040663 |
| children | adcdf5e04128 |
comparison
equal
deleted
inserted
replaced
| 14450:1a01b1dae517 | 14451:8bc97389bdb2 |
|---|---|
| 40 #include "util.h" | 40 #include "util.h" |
| 41 | 41 |
| 42 struct _GaimProxyConnectData { | 42 struct _GaimProxyConnectData { |
| 43 GaimProxyConnectFunction connect_cb; | 43 GaimProxyConnectFunction connect_cb; |
| 44 gpointer data; | 44 gpointer data; |
| 45 char *host; | 45 gchar *host; |
| 46 int port; | 46 int port; |
| 47 int fd; | 47 int fd; |
| 48 guint inpa; | 48 guint inpa; |
| 49 GaimProxyInfo *gpi; | 49 GaimProxyInfo *gpi; |
| 50 GaimDnsQueryData *query_data; | 50 GaimDnsQueryData *query_data; |
| 272 } | 272 } |
| 273 /************************************************************************** | 273 /************************************************************************** |
| 274 * Proxy API | 274 * Proxy API |
| 275 **************************************************************************/ | 275 **************************************************************************/ |
| 276 | 276 |
| 277 /* | 277 /** |
| 278 * This is used when the connection attempt to one particular IP | 278 * Whoever calls this needs to have called |
| 279 * address fails. We close the socket, remove the watcher and get | 279 * gaim_proxy_connect_data_disconnect() beforehand. |
| 280 * rid of input and output buffers. Normally try_connect() will | |
| 281 * be called immediately after this. | |
| 282 */ | 280 */ |
| 283 static void | 281 static void |
| 284 gaim_proxy_connect_data_disconnect(GaimProxyConnectData *connect_data) | |
| 285 { | |
| 286 if (connect_data->inpa > 0) | |
| 287 { | |
| 288 gaim_input_remove(connect_data->inpa); | |
| 289 connect_data->inpa = 0; | |
| 290 } | |
| 291 | |
| 292 if (connect_data->fd >= 0) | |
| 293 { | |
| 294 close(connect_data->fd); | |
| 295 connect_data->fd = -1; | |
| 296 } | |
| 297 | |
| 298 g_free(connect_data->write_buffer); | |
| 299 connect_data->write_buffer = NULL; | |
| 300 | |
| 301 g_free(connect_data->read_buffer); | |
| 302 connect_data->read_buffer = NULL; | |
| 303 } | |
| 304 | |
| 305 static void | |
| 306 gaim_proxy_connect_data_destroy(GaimProxyConnectData *connect_data) | 282 gaim_proxy_connect_data_destroy(GaimProxyConnectData *connect_data) |
| 307 { | 283 { |
| 308 gaim_proxy_connect_data_disconnect(connect_data); | |
| 309 | |
| 310 connect_datas = g_slist_remove(connect_datas, connect_data); | 284 connect_datas = g_slist_remove(connect_datas, connect_data); |
| 311 | 285 |
| 312 if (connect_data->query_data != NULL) | 286 if (connect_data->query_data != NULL) |
| 313 gaim_dnsquery_destroy(connect_data->query_data); | 287 gaim_dnsquery_destroy(connect_data->query_data); |
| 314 | 288 |
| 321 connect_data->hosts = g_slist_remove(connect_data->hosts, connect_data->hosts->data); | 295 connect_data->hosts = g_slist_remove(connect_data->hosts, connect_data->hosts->data); |
| 322 } | 296 } |
| 323 | 297 |
| 324 g_free(connect_data->host); | 298 g_free(connect_data->host); |
| 325 g_free(connect_data); | 299 g_free(connect_data); |
| 300 } | |
| 301 | |
| 302 /** | |
| 303 * Free all information dealing with a connection attempt and | |
| 304 * reset the connect_data to prepare for it to try to connect | |
| 305 * to another IP address. | |
| 306 * | |
| 307 * If an error message is passed in, then we know the connection | |
| 308 * attempt failed. If the connection attempt failed and | |
| 309 * connect_data->hosts is not empty then we try the next IP address. | |
| 310 * If the connection attempt failed and we have no more hosts | |
| 311 * try try then we call the callback with the given error message, | |
| 312 * then destroy the connect_data. | |
| 313 * | |
| 314 * @param error_message An error message explaining why the connection | |
| 315 * failed. This will be passed to the callback function | |
| 316 * specified in the call to gaim_proxy_connect(). If the | |
| 317 * connection was successful then pass in null. | |
| 318 */ | |
| 319 static void | |
| 320 gaim_proxy_connect_data_disconnect(GaimProxyConnectData *connect_data, const gchar *error_message) | |
| 321 { | |
| 322 if (connect_data->inpa > 0) | |
| 323 { | |
| 324 gaim_input_remove(connect_data->inpa); | |
| 325 connect_data->inpa = 0; | |
| 326 } | |
| 327 | |
| 328 if (connect_data->fd >= 0) | |
| 329 { | |
| 330 close(connect_data->fd); | |
| 331 connect_data->fd = -1; | |
| 332 } | |
| 333 | |
| 334 g_free(connect_data->write_buffer); | |
| 335 connect_data->write_buffer = NULL; | |
| 336 | |
| 337 g_free(connect_data->read_buffer); | |
| 338 connect_data->read_buffer = NULL; | |
| 339 | |
| 340 if (error_message != NULL) | |
| 341 { | |
| 342 gaim_debug_info("proxy", "Connection attempt failed: %s\n", | |
| 343 error_message); | |
| 344 if (connect_data->hosts != NULL) | |
| 345 try_connect(connect_data); | |
| 346 else | |
| 347 { | |
| 348 /* Everything failed! Tell the originator of the request. */ | |
| 349 connect_data->connect_cb(connect_data->data, -1, error_message); | |
| 350 gaim_proxy_connect_data_destroy(connect_data); | |
| 351 } | |
| 352 } | |
| 353 } | |
| 354 | |
| 355 /** | |
| 356 * This calls gaim_proxy_connect_data_disconnect(), but it lets you | |
| 357 * specify the error_message using a printf()-like syntax. | |
| 358 */ | |
| 359 static void | |
| 360 gaim_proxy_connect_data_disconnect_formatted(GaimProxyConnectData *connect_data, const char *format, ...) | |
| 361 { | |
| 362 va_list args; | |
| 363 gchar *tmp; | |
| 364 | |
| 365 va_start(args, format); | |
| 366 tmp = g_strdup_vprintf(format, args); | |
| 367 va_end(args); | |
| 368 | |
| 369 gaim_proxy_connect_data_disconnect(connect_data, tmp); | |
| 370 g_free(tmp); | |
| 326 } | 371 } |
| 327 | 372 |
| 328 static void | 373 static void |
| 329 gaim_proxy_connect_data_connected(GaimProxyConnectData *connect_data) | 374 gaim_proxy_connect_data_connected(GaimProxyConnectData *connect_data) |
| 330 { | 375 { |
| 335 * our responsibility, and we should be careful not to free it when | 380 * our responsibility, and we should be careful not to free it when |
| 336 * we destroy the connect_data. | 381 * we destroy the connect_data. |
| 337 */ | 382 */ |
| 338 connect_data->fd = -1; | 383 connect_data->fd = -1; |
| 339 | 384 |
| 385 gaim_proxy_connect_data_disconnect(connect_data, NULL); | |
| 340 gaim_proxy_connect_data_destroy(connect_data); | 386 gaim_proxy_connect_data_destroy(connect_data); |
| 341 } | 387 } |
| 342 | 388 |
| 343 /** | 389 static void |
| 344 * @param error An error message explaining why the connection | 390 socket_ready_cb(gpointer data, gint source, GaimInputCondition cond) |
| 345 * failed. This will be passed to the callback function | |
| 346 * specified in the call to gaim_proxy_connect(). | |
| 347 */ | |
| 348 /* | |
| 349 * TODO: Make sure all callers of this function pass a really really | |
| 350 * good error_message. | |
| 351 */ | |
| 352 static void | |
| 353 gaim_proxy_connect_data_error(GaimProxyConnectData *connect_data, const char *format, ...) | |
| 354 { | |
| 355 gchar *error_message; | |
| 356 va_list args; | |
| 357 | |
| 358 va_start(args, format); | |
| 359 error_message = g_strdup_vprintf(format, args); | |
| 360 va_end(args); | |
| 361 | |
| 362 connect_data->connect_cb(connect_data->data, -1, error_message); | |
| 363 g_free(error_message); | |
| 364 | |
| 365 gaim_proxy_connect_data_destroy(connect_data); | |
| 366 } | |
| 367 | |
| 368 static void | |
| 369 no_one_calls(gpointer data, gint source, GaimInputCondition cond) | |
| 370 { | 391 { |
| 371 GaimProxyConnectData *connect_data = data; | 392 GaimProxyConnectData *connect_data = data; |
| 372 socklen_t len; | 393 socklen_t len; |
| 373 int error=0, ret; | 394 int error = 0; |
| 395 int ret; | |
| 374 | 396 |
| 375 gaim_debug_info("proxy", "Connected.\n"); | 397 gaim_debug_info("proxy", "Connected.\n"); |
| 376 | |
| 377 len = sizeof(error); | |
| 378 | 398 |
| 379 /* | 399 /* |
| 380 * getsockopt after a non-blocking connect returns -1 if something is | 400 * getsockopt after a non-blocking connect returns -1 if something is |
| 381 * really messed up (bad descriptor, usually). Otherwise, it returns 0 and | 401 * really messed up (bad descriptor, usually). Otherwise, it returns 0 and |
| 382 * error holds what connect would have returned if it blocked until now. | 402 * error holds what connect would have returned if it blocked until now. |
| 385 * | 405 * |
| 386 * (error == EINPROGRESS can happen after a select because the kernel can | 406 * (error == EINPROGRESS can happen after a select because the kernel can |
| 387 * be overly optimistic sometimes. select is just a hint that you might be | 407 * be overly optimistic sometimes. select is just a hint that you might be |
| 388 * able to do something.) | 408 * able to do something.) |
| 389 */ | 409 */ |
| 410 len = sizeof(error); | |
| 390 ret = getsockopt(connect_data->fd, SOL_SOCKET, SO_ERROR, &error, &len); | 411 ret = getsockopt(connect_data->fd, SOL_SOCKET, SO_ERROR, &error, &len); |
| 412 | |
| 391 if (ret == 0 && error == EINPROGRESS) | 413 if (ret == 0 && error == EINPROGRESS) |
| 392 return; /* we'll be called again later */ | 414 /* No worries - we'll be called again later */ |
| 393 if (ret < 0 || error != 0) { | 415 /* TODO: Does this ever happen? */ |
| 394 if (ret!=0) | 416 return; |
| 417 | |
| 418 if (ret != 0 || error != 0) { | |
| 419 if (ret != 0) | |
| 395 error = errno; | 420 error = errno; |
| 396 | 421 gaim_proxy_connect_data_disconnect(connect_data, strerror(error)); |
| 397 gaim_debug_error("proxy", | 422 return; |
| 398 "getsockopt SO_ERROR check: %s\n", strerror(error)); | 423 } |
| 399 | |
| 400 gaim_proxy_connect_data_disconnect(connect_data); | |
| 401 try_connect(connect_data); | |
| 402 return; | |
| 403 } | |
| 404 | |
| 405 gaim_input_remove(connect_data->inpa); | |
| 406 connect_data->inpa = 0; | |
| 407 | 424 |
| 408 gaim_proxy_connect_data_connected(connect_data); | 425 gaim_proxy_connect_data_connected(connect_data); |
| 409 } | 426 } |
| 410 | 427 |
| 411 static gboolean | 428 static gboolean |
| 412 clean_connect(gpointer data) | 429 clean_connect(gpointer data) |
| 413 { | 430 { |
| 414 GaimProxyConnectData *connect_data; | 431 gaim_proxy_connect_data_connected(data); |
| 415 | |
| 416 connect_data = data; | |
| 417 gaim_proxy_connect_data_connected(connect_data); | |
| 418 | 432 |
| 419 return FALSE; | 433 return FALSE; |
| 420 } | 434 } |
| 421 | 435 |
| 422 static int | 436 static void |
| 423 proxy_connect_none(GaimProxyConnectData *connect_data, struct sockaddr *addr, socklen_t addrlen) | 437 proxy_connect_none(GaimProxyConnectData *connect_data, struct sockaddr *addr, socklen_t addrlen) |
| 424 { | 438 { |
| 425 gaim_debug_info("proxy", "Connecting to %s:%d with no proxy\n", | 439 gaim_debug_info("proxy", "Connecting to %s:%d with no proxy\n", |
| 426 connect_data->host, connect_data->port); | 440 connect_data->host, connect_data->port); |
| 427 | 441 |
| 428 connect_data->fd = socket(addr->sa_family, SOCK_STREAM, 0); | 442 connect_data->fd = socket(addr->sa_family, SOCK_STREAM, 0); |
| 429 if (connect_data->fd < 0) | 443 if (connect_data->fd < 0) |
| 430 { | 444 { |
| 431 gaim_debug_error("proxy", | 445 gaim_proxy_connect_data_disconnect_formatted(connect_data, |
| 432 "Unable to create socket: %s\n", strerror(errno)); | 446 _("Unable to create socket:\n%s"), strerror(errno)); |
| 433 return -1; | 447 return; |
| 434 } | 448 } |
| 449 | |
| 435 fcntl(connect_data->fd, F_SETFL, O_NONBLOCK); | 450 fcntl(connect_data->fd, F_SETFL, O_NONBLOCK); |
| 436 #ifndef _WIN32 | 451 #ifndef _WIN32 |
| 437 fcntl(connect_data->fd, F_SETFD, FD_CLOEXEC); | 452 fcntl(connect_data->fd, F_SETFD, FD_CLOEXEC); |
| 438 #endif | 453 #endif |
| 439 | 454 |
| 440 if (connect(connect_data->fd, (struct sockaddr *)addr, addrlen) != 0) | 455 if (connect(connect_data->fd, addr, addrlen) != 0) |
| 441 { | 456 { |
| 442 if ((errno == EINPROGRESS) || (errno == EINTR)) { | 457 if ((errno == EINPROGRESS) || (errno == EINTR)) |
| 458 { | |
| 443 gaim_debug_info("proxy", "Connection in progress\n"); | 459 gaim_debug_info("proxy", "Connection in progress\n"); |
| 444 connect_data->inpa = gaim_input_add(connect_data->fd, GAIM_INPUT_WRITE, no_one_calls, connect_data); | 460 connect_data->inpa = gaim_input_add(connect_data->fd, |
| 445 } | 461 GAIM_INPUT_WRITE, socket_ready_cb, connect_data); |
| 446 else { | 462 } |
| 447 gaim_debug_error("proxy", | 463 else |
| 448 "Connect failed: %s\n", strerror(errno)); | 464 { |
| 449 close(connect_data->fd); | 465 gaim_proxy_connect_data_disconnect(connect_data, strerror(errno)); |
| 450 connect_data->fd = -1; | |
| 451 return -1; | |
| 452 } | 466 } |
| 453 } | 467 } |
| 454 else | 468 else |
| 455 { | 469 { |
| 456 /* | 470 /* |
| 457 * The connection happened IMMEDIATELY... strange, but whatever. | 471 * The connection happened IMMEDIATELY... strange, but whatever. |
| 458 */ | 472 */ |
| 459 socklen_t len; | 473 socklen_t len; |
| 460 int error = ETIMEDOUT; | 474 int error = ETIMEDOUT; |
| 475 int ret; | |
| 476 | |
| 461 gaim_debug_info("proxy", "Connected immediately.\n"); | 477 gaim_debug_info("proxy", "Connected immediately.\n"); |
| 478 | |
| 462 len = sizeof(error); | 479 len = sizeof(error); |
| 463 if (getsockopt(connect_data->fd, SOL_SOCKET, SO_ERROR, &error, &len) != 0) | 480 ret = getsockopt(connect_data->fd, SOL_SOCKET, SO_ERROR, &error, &len); |
| 481 if ((ret != 0) || (error != 0)) | |
| 464 { | 482 { |
| 465 gaim_debug_error("proxy", "getsockopt failed.\n"); | 483 if (ret != 0) |
| 466 close(connect_data->fd); | 484 error = errno; |
| 467 connect_data->fd = -1; | 485 gaim_proxy_connect_data_disconnect(connect_data, strerror(error)); |
| 468 return -1; | 486 return; |
| 469 } | 487 } |
| 470 | 488 |
| 471 /* | 489 /* |
| 472 * We want to call the "connected" callback eventually, but we | 490 * We want to call the "connected" callback eventually, but we |
| 473 * don't want to call it before we return, just in case. | 491 * don't want to call it before we return, just in case. |
| 474 */ | 492 */ |
| 475 gaim_timeout_add(10, clean_connect, connect_data); | 493 gaim_timeout_add(10, clean_connect, connect_data); |
| 476 } | 494 } |
| 477 | 495 } |
| 478 return connect_data->fd; | 496 |
| 479 } | 497 /** |
| 480 | 498 * This is a utility function used by the HTTP, SOCKS4 and SOCKS5 |
| 499 * connect functions. It writes data from a buffer to a socket. | |
| 500 * When all the data is written it sets up a watcher to read a | |
| 501 * response and call a specified function. | |
| 502 */ | |
| 481 static void | 503 static void |
| 482 proxy_do_write(gpointer data, gint source, GaimInputCondition cond) | 504 proxy_do_write(gpointer data, gint source, GaimInputCondition cond) |
| 483 { | 505 { |
| 484 GaimProxyConnectData *connect_data = data; | 506 GaimProxyConnectData *connect_data; |
| 485 const guchar *request = connect_data->write_buffer + connect_data->written_len; | 507 const guchar *request; |
| 486 gsize request_len = connect_data->write_buf_len - connect_data->written_len; | 508 gsize request_len; |
| 487 | 509 int ret; |
| 488 int ret = write(connect_data->fd, request, request_len); | 510 |
| 489 | 511 connect_data = data; |
| 490 if(ret < 0 && errno == EAGAIN) | 512 request = connect_data->write_buffer + connect_data->written_len; |
| 491 return; | 513 request_len = connect_data->write_buf_len - connect_data->written_len; |
| 492 else if(ret < 0) { | 514 |
| 493 gaim_proxy_connect_data_disconnect(connect_data); | 515 ret = write(connect_data->fd, request, request_len); |
| 494 try_connect(connect_data); | 516 if (ret <= 0) |
| 495 return; | 517 { |
| 496 } else if (ret < request_len) { | 518 if (errno == EAGAIN) |
| 519 /* No worries */ | |
| 520 return; | |
| 521 | |
| 522 /* Error! */ | |
| 523 gaim_proxy_connect_data_disconnect(connect_data, strerror(errno)); | |
| 524 return; | |
| 525 } | |
| 526 if (ret < request_len) { | |
| 497 connect_data->written_len += ret; | 527 connect_data->written_len += ret; |
| 498 return; | 528 return; |
| 499 } | 529 } |
| 500 | 530 |
| 501 gaim_input_remove(connect_data->inpa); | 531 /* We're done writing data! Wait for a response. */ |
| 502 g_free(connect_data->write_buffer); | 532 g_free(connect_data->write_buffer); |
| 503 connect_data->write_buffer = NULL; | 533 connect_data->write_buffer = NULL; |
| 504 | 534 gaim_input_remove(connect_data->inpa); |
| 505 /* register the response handler for the response */ | 535 connect_data->inpa = gaim_input_add(connect_data->fd, |
| 506 connect_data->inpa = gaim_input_add(connect_data->fd, GAIM_INPUT_READ, connect_data->read_cb, connect_data); | 536 GAIM_INPUT_READ, connect_data->read_cb, connect_data); |
| 507 } | 537 } |
| 508 | 538 |
| 509 #define HTTP_GOODSTRING "HTTP/1.0 200" | 539 #define HTTP_GOODSTRING "HTTP/1.0 200" |
| 510 #define HTTP_GOODSTRING2 "HTTP/1.1 200" | 540 #define HTTP_GOODSTRING2 "HTTP/1.1 200" |
| 511 | 541 |
| 512 /* read the response to the CONNECT request, if we are requesting a non-port-80 tunnel */ | 542 /** |
| 543 * We're using an HTTP proxy for a non-port 80 tunnel. Read the | |
| 544 * response to the CONNECT request. | |
| 545 */ | |
| 513 static void | 546 static void |
| 514 http_canread(gpointer data, gint source, GaimInputCondition cond) | 547 http_canread(gpointer data, gint source, GaimInputCondition cond) |
| 515 { | 548 { |
| 516 int len, headers_len, status = 0; | 549 int len, headers_len, status = 0; |
| 517 gboolean error; | 550 gboolean error; |
| 518 GaimProxyConnectData *connect_data = data; | 551 GaimProxyConnectData *connect_data = data; |
| 519 guchar *p; | 552 guchar *p; |
| 520 gsize max_read; | 553 gsize max_read; |
| 521 | 554 |
| 522 if(connect_data->read_buffer == NULL) { | 555 if (connect_data->read_buffer == NULL) |
| 556 { | |
| 523 connect_data->read_buf_len = 8192; | 557 connect_data->read_buf_len = 8192; |
| 524 connect_data->read_buffer = g_malloc(connect_data->read_buf_len); | 558 connect_data->read_buffer = g_malloc(connect_data->read_buf_len); |
| 525 connect_data->read_len = 0; | 559 connect_data->read_len = 0; |
| 526 } | 560 } |
| 527 | 561 |
| 528 p = connect_data->read_buffer + connect_data->read_len; | 562 p = connect_data->read_buffer + connect_data->read_len; |
| 529 max_read = connect_data->read_buf_len - connect_data->read_len - 1; | 563 max_read = connect_data->read_buf_len - connect_data->read_len - 1; |
| 530 | 564 |
| 531 len = read(connect_data->fd, p, max_read); | 565 len = read(connect_data->fd, p, max_read); |
| 532 if(len < 0 && errno == EAGAIN) | 566 |
| 533 return; | 567 if (len == 0) |
| 534 else if(len <= 0) { | 568 { |
| 535 gaim_proxy_connect_data_error(connect_data, _("Lost connection with server for an unknown reason.")); | 569 gaim_proxy_connect_data_disconnect(connect_data, |
| 536 return; | 570 _("Server closed the connection.")); |
| 537 } else { | 571 return; |
| 538 connect_data->read_len += len; | 572 } |
| 539 } | 573 |
| 574 if (len < 0) | |
| 575 { | |
| 576 if (errno == EAGAIN) | |
| 577 /* No worries */ | |
| 578 return; | |
| 579 | |
| 580 /* Error! */ | |
| 581 gaim_proxy_connect_data_disconnect_formatted(connect_data, | |
| 582 _("Lost connection with server:\n%s"), strerror(errno)); | |
| 583 return; | |
| 584 } | |
| 585 | |
| 586 connect_data->read_len += len; | |
| 540 p[len] = '\0'; | 587 p[len] = '\0'; |
| 541 | 588 |
| 542 if((p = (guchar *)g_strstr_len((const gchar *)connect_data->read_buffer, connect_data->read_len, "\r\n\r\n"))) { | 589 p = (guchar *)g_strstr_len((const gchar *)connect_data->read_buffer, |
| 590 connect_data->read_len, "\r\n\r\n"); | |
| 591 if (p != NULL) { | |
| 543 *p = '\0'; | 592 *p = '\0'; |
| 544 headers_len = (p - connect_data->read_buffer) + 4; | 593 headers_len = (p - connect_data->read_buffer) + 4; |
| 545 } else if(len == max_read) | 594 } else if(len == max_read) |
| 546 headers_len = len; | 595 headers_len = len; |
| 547 else | 596 else |
| 584 | 633 |
| 585 /* Compensate for what has already been read */ | 634 /* Compensate for what has already been read */ |
| 586 len -= connect_data->read_len - headers_len; | 635 len -= connect_data->read_len - headers_len; |
| 587 /* I'm assuming that we're doing this to prevent the server from | 636 /* I'm assuming that we're doing this to prevent the server from |
| 588 complaining / breaking since we don't read the whole page */ | 637 complaining / breaking since we don't read the whole page */ |
| 589 while(len--) { | 638 while (len--) { |
| 590 /* TODO: deal with EAGAIN (and other errors) better */ | 639 /* TODO: deal with EAGAIN (and other errors) better */ |
| 591 if (read(connect_data->fd, &tmpc, 1) < 0 && errno != EAGAIN) | 640 if (read(connect_data->fd, &tmpc, 1) < 0 && errno != EAGAIN) |
| 592 break; | 641 break; |
| 593 } | 642 } |
| 594 } | 643 } |
| 595 | 644 |
| 596 if (error) | 645 if (error) |
| 597 { | 646 { |
| 598 gaim_proxy_connect_data_error(connect_data, | 647 gaim_proxy_connect_data_disconnect_formatted(connect_data, |
| 599 _("Unable to parse response from HTTP proxy: %s\n"), | 648 _("Unable to parse response from HTTP proxy: %s\n"), |
| 600 connect_data->read_buffer); | 649 connect_data->read_buffer); |
| 601 return; | 650 return; |
| 602 } | 651 } |
| 603 else if (status != 200) | 652 else if (status != 200) |
| 604 { | 653 { |
| 605 gaim_debug_error("proxy", | 654 gaim_debug_error("proxy", |
| 606 "Proxy server replied with:\n%s\n", | 655 "Proxy server replied with:\n%s\n", |
| 607 connect_data->read_buffer); | 656 connect_data->read_buffer); |
| 608 | 657 |
| 609 | 658 if (status == 407 /* Proxy Auth */) |
| 610 if(status == 407 /* Proxy Auth */) { | 659 { |
| 611 gchar *ntlm; | 660 gchar *ntlm; |
| 612 if((ntlm = g_strrstr((const gchar *)connect_data->read_buffer, "Proxy-Authenticate: NTLM "))) { /* Check for Type-2 */ | 661 ntlm = g_strrstr((const gchar *)connect_data->read_buffer, |
| 662 "Proxy-Authenticate: NTLM "); | |
| 663 if (ntlm != NULL) | |
| 664 { | |
| 665 /* Check for Type-2 */ | |
| 613 gchar *tmp = ntlm; | 666 gchar *tmp = ntlm; |
| 614 guint8 *nonce; | 667 guint8 *nonce; |
| 615 gchar *domain = (gchar*)gaim_proxy_info_get_username(connect_data->gpi); | 668 gchar *domain = (gchar*)gaim_proxy_info_get_username(connect_data->gpi); |
| 616 gchar *username; | 669 gchar *username; |
| 617 gchar *request; | 670 gchar *request; |
| 618 gchar *response; | 671 gchar *response; |
| 619 username = strchr(domain, '\\'); | 672 username = strchr(domain, '\\'); |
| 620 if (username == NULL) | 673 if (username == NULL) |
| 621 { | 674 { |
| 622 gaim_proxy_connect_data_error(connect_data, | 675 gaim_proxy_connect_data_disconnect_formatted(connect_data, |
| 623 _("HTTP proxy connection error %d"), status); | 676 _("HTTP proxy connection error %d"), status); |
| 624 return; | 677 return; |
| 625 } | 678 } |
| 626 *username = '\0'; | 679 *username = '\0'; |
| 627 username++; | 680 username++; |
| 642 "Proxy-Connection: Keep-Alive\r\n\r\n", | 695 "Proxy-Connection: Keep-Alive\r\n\r\n", |
| 643 connect_data->host, connect_data->port, connect_data->host, | 696 connect_data->host, connect_data->port, connect_data->host, |
| 644 connect_data->port, response); | 697 connect_data->port, response); |
| 645 g_free(response); | 698 g_free(response); |
| 646 | 699 |
| 647 gaim_input_remove(connect_data->inpa); | |
| 648 g_free(connect_data->read_buffer); | 700 g_free(connect_data->read_buffer); |
| 649 connect_data->read_buffer = NULL; | 701 connect_data->read_buffer = NULL; |
| 650 | 702 |
| 651 connect_data->write_buffer = (guchar *)request; | 703 connect_data->write_buffer = (guchar *)request; |
| 652 connect_data->write_buf_len = strlen(request); | 704 connect_data->write_buf_len = strlen(request); |
| 653 connect_data->written_len = 0; | 705 connect_data->written_len = 0; |
| 654 | |
| 655 connect_data->read_cb = http_canread; | 706 connect_data->read_cb = http_canread; |
| 656 | 707 |
| 708 gaim_input_remove(connect_data->inpa); | |
| 657 connect_data->inpa = gaim_input_add(connect_data->fd, | 709 connect_data->inpa = gaim_input_add(connect_data->fd, |
| 658 GAIM_INPUT_WRITE, proxy_do_write, connect_data); | 710 GAIM_INPUT_WRITE, proxy_do_write, connect_data); |
| 659 | |
| 660 proxy_do_write(connect_data, connect_data->fd, cond); | 711 proxy_do_write(connect_data, connect_data->fd, cond); |
| 661 return; | 712 return; |
| 662 } else if((ntlm = g_strrstr((const char *)connect_data->read_buffer, "Proxy-Authenticate: NTLM"))) { /* Empty message */ | 713 } else if((ntlm = g_strrstr((const char *)connect_data->read_buffer, "Proxy-Authenticate: NTLM"))) { /* Empty message */ |
| 663 gchar request[2048]; | 714 gchar request[2048]; |
| 664 gchar *domain = (gchar*) gaim_proxy_info_get_username(connect_data->gpi); | 715 gchar *domain = (gchar*) gaim_proxy_info_get_username(connect_data->gpi); |
| 665 gchar *username; | 716 gchar *username; |
| 666 int request_len; | 717 int request_len; |
| 667 username = strchr(domain, '\\'); | 718 username = strchr(domain, '\\'); |
| 668 if (username == NULL) | 719 if (username == NULL) |
| 669 { | 720 { |
| 670 gaim_proxy_connect_data_error(connect_data, | 721 gaim_proxy_connect_data_disconnect_formatted(connect_data, |
| 671 _("HTTP proxy connection error %d"), status); | 722 _("HTTP proxy connection error %d"), status); |
| 672 return; | 723 return; |
| 673 } | 724 } |
| 674 *username = '\0'; | 725 *username = '\0'; |
| 675 | 726 |
| 703 GAIM_INPUT_WRITE, proxy_do_write, connect_data); | 754 GAIM_INPUT_WRITE, proxy_do_write, connect_data); |
| 704 | 755 |
| 705 proxy_do_write(connect_data, connect_data->fd, cond); | 756 proxy_do_write(connect_data, connect_data->fd, cond); |
| 706 return; | 757 return; |
| 707 } else { | 758 } else { |
| 708 gaim_proxy_connect_data_error(connect_data, | 759 gaim_proxy_connect_data_disconnect_formatted(connect_data, |
| 709 _("HTTP proxy connection error %d"), status); | 760 _("HTTP proxy connection error %d"), status); |
| 710 return; | 761 return; |
| 711 } | 762 } |
| 712 } | 763 } |
| 713 if(status == 403 /* Forbidden */ ) { | 764 if (status == 403) |
| 714 gaim_proxy_connect_data_error(connect_data, | 765 { |
| 715 _("Access denied: HTTP proxy server forbids port %d tunnelling."), | 766 /* Forbidden */ |
| 767 gaim_proxy_connect_data_disconnect_formatted(connect_data, | |
| 768 _("Access denied: HTTP proxy server forbids port %d tunneling."), | |
| 716 connect_data->port); | 769 connect_data->port); |
| 717 } else { | 770 } else { |
| 718 gaim_proxy_connect_data_error(connect_data, | 771 gaim_proxy_connect_data_disconnect_formatted(connect_data, |
| 719 _("HTTP proxy connection error %d"), status); | 772 _("HTTP proxy connection error %d"), status); |
| 720 } | 773 } |
| 721 } else { | 774 } else { |
| 722 gaim_input_remove(connect_data->inpa); | 775 gaim_input_remove(connect_data->inpa); |
| 723 connect_data->inpa = 0; | 776 connect_data->inpa = 0; |
| 727 gaim_proxy_connect_data_connected(connect_data); | 780 gaim_proxy_connect_data_connected(connect_data); |
| 728 return; | 781 return; |
| 729 } | 782 } |
| 730 } | 783 } |
| 731 | 784 |
| 732 | |
| 733 | |
| 734 static void | 785 static void |
| 735 http_canwrite(gpointer data, gint source, GaimInputCondition cond) | 786 http_canwrite(gpointer data, gint source, GaimInputCondition cond) |
| 736 { | 787 { |
| 737 char request[8192]; | 788 GString *request; |
| 738 int request_len = 0; | 789 GaimProxyConnectData *connect_data; |
| 739 GaimProxyConnectData *connect_data = data; | |
| 740 socklen_t len; | 790 socklen_t len; |
| 741 int error = ETIMEDOUT; | 791 int error = ETIMEDOUT; |
| 742 | 792 int ret; |
| 743 gaim_debug_info("http proxy", "Connected.\n"); | 793 |
| 794 gaim_debug_info("proxy", "Connected.\n"); | |
| 795 | |
| 796 connect_data = data; | |
| 744 | 797 |
| 745 if (connect_data->inpa > 0) | 798 if (connect_data->inpa > 0) |
| 746 { | 799 { |
| 747 gaim_input_remove(connect_data->inpa); | 800 gaim_input_remove(connect_data->inpa); |
| 748 connect_data->inpa = 0; | 801 connect_data->inpa = 0; |
| 749 } | 802 } |
| 750 | 803 |
| 751 len = sizeof(error); | 804 len = sizeof(error); |
| 752 | 805 ret = getsockopt(connect_data->fd, SOL_SOCKET, SO_ERROR, &error, &len); |
| 753 if (getsockopt(connect_data->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { | 806 if ((ret != 0) || (error != 0)) |
| 754 gaim_proxy_connect_data_disconnect(connect_data); | 807 { |
| 755 try_connect(connect_data); | 808 if (ret != 0) |
| 756 return; | 809 error = errno; |
| 757 } | 810 gaim_proxy_connect_data_disconnect(connect_data, strerror(error)); |
| 758 | 811 return; |
| 759 gaim_debug_info("proxy", "using CONNECT tunnelling for %s:%d\n", | 812 } |
| 813 | |
| 814 gaim_debug_info("proxy", "Using CONNECT tunneling for %s:%d\n", | |
| 760 connect_data->host, connect_data->port); | 815 connect_data->host, connect_data->port); |
| 761 request_len = g_snprintf(request, sizeof(request), | 816 |
| 762 "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n", | 817 request = g_string_sized_new(4096); |
| 763 connect_data->host, connect_data->port, connect_data->host, connect_data->port); | 818 g_string_append_printf(request, |
| 764 | 819 "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n", |
| 765 if (gaim_proxy_info_get_username(connect_data->gpi) != NULL) { | 820 connect_data->host, connect_data->port, |
| 821 connect_data->host, connect_data->port); | |
| 822 | |
| 823 if (gaim_proxy_info_get_username(connect_data->gpi) != NULL) | |
| 824 { | |
| 766 char *t1, *t2; | 825 char *t1, *t2; |
| 826 | |
| 767 t1 = g_strdup_printf("%s:%s", | 827 t1 = g_strdup_printf("%s:%s", |
| 768 gaim_proxy_info_get_username(connect_data->gpi), | 828 gaim_proxy_info_get_username(connect_data->gpi), |
| 769 gaim_proxy_info_get_password(connect_data->gpi) ? | 829 gaim_proxy_info_get_password(connect_data->gpi) ? |
| 770 gaim_proxy_info_get_password(connect_data->gpi) : ""); | 830 gaim_proxy_info_get_password(connect_data->gpi) : ""); |
| 771 t2 = gaim_base64_encode((const guchar *)t1, strlen(t1)); | 831 t2 = gaim_base64_encode((const guchar *)t1, strlen(t1)); |
| 772 g_free(t1); | 832 g_free(t1); |
| 773 g_return_if_fail(request_len < sizeof(request)); | 833 |
| 774 | 834 g_string_append_printf(request, |
| 775 request_len += g_snprintf(request + request_len, | |
| 776 sizeof(request) - request_len, | |
| 777 "Proxy-Authorization: Basic %s\r\n" | 835 "Proxy-Authorization: Basic %s\r\n" |
| 778 "Proxy-Authorization: NTLM %s\r\n" | 836 "Proxy-Authorization: NTLM %s\r\n" |
| 779 "Proxy-Connection: Keep-Alive\r\n", t2, | 837 "Proxy-Connection: Keep-Alive\r\n", |
| 780 gaim_ntlm_gen_type1( | 838 t2, gaim_ntlm_gen_type1( |
| 781 (gchar*)gaim_proxy_info_get_host(connect_data->gpi),"")); | 839 gaim_proxy_info_get_host(connect_data->gpi), "")); |
| 782 g_free(t2); | 840 g_free(t2); |
| 783 } | 841 } |
| 784 | 842 |
| 785 g_return_if_fail(request_len < sizeof(request)); | 843 g_string_append(request, "\r\n"); |
| 786 strcpy(request + request_len, "\r\n"); | 844 |
| 787 request_len += 2; | 845 connect_data->write_buf_len = request->len; |
| 788 connect_data->write_buffer = g_memdup(request, request_len); | 846 connect_data->write_buffer = (guchar *)g_string_free(request, FALSE); |
| 789 connect_data->write_buf_len = request_len; | |
| 790 connect_data->written_len = 0; | 847 connect_data->written_len = 0; |
| 791 | |
| 792 connect_data->read_cb = http_canread; | 848 connect_data->read_cb = http_canread; |
| 793 | 849 |
| 794 connect_data->inpa = gaim_input_add(connect_data->fd, GAIM_INPUT_WRITE, proxy_do_write, | 850 connect_data->inpa = gaim_input_add(connect_data->fd, |
| 795 connect_data); | 851 GAIM_INPUT_WRITE, proxy_do_write, connect_data); |
| 796 | |
| 797 proxy_do_write(connect_data, connect_data->fd, cond); | 852 proxy_do_write(connect_data, connect_data->fd, cond); |
| 798 } | 853 } |
| 799 | 854 |
| 800 static int | 855 static void |
| 801 proxy_connect_http(GaimProxyConnectData *connect_data, struct sockaddr *addr, socklen_t addrlen) | 856 proxy_connect_http(GaimProxyConnectData *connect_data, struct sockaddr *addr, socklen_t addrlen) |
| 802 { | 857 { |
| 803 gaim_debug_info("http proxy", | 858 gaim_debug_info("proxy", |
| 804 "Connecting to %s:%d via %s:%d using HTTP\n", | 859 "Connecting to %s:%d via %s:%d using HTTP\n", |
| 805 (connect_data->host ? connect_data->host : "(null)"), connect_data->port, | 860 connect_data->host, connect_data->port, |
| 806 (gaim_proxy_info_get_host(connect_data->gpi) ? gaim_proxy_info_get_host(connect_data->gpi) : "(null)"), | 861 (gaim_proxy_info_get_host(connect_data->gpi) ? gaim_proxy_info_get_host(connect_data->gpi) : "(null)"), |
| 807 gaim_proxy_info_get_port(connect_data->gpi)); | 862 gaim_proxy_info_get_port(connect_data->gpi)); |
| 808 | 863 |
| 809 connect_data->fd = socket(addr->sa_family, SOCK_STREAM, 0); | 864 connect_data->fd = socket(addr->sa_family, SOCK_STREAM, 0); |
| 810 if (connect_data->fd < 0) | 865 if (connect_data->fd < 0) |
| 811 return -1; | 866 { |
| 867 gaim_proxy_connect_data_disconnect_formatted(connect_data, | |
| 868 _("Unable to create socket:\n%s"), strerror(errno)); | |
| 869 return; | |
| 870 } | |
| 812 | 871 |
| 813 fcntl(connect_data->fd, F_SETFL, O_NONBLOCK); | 872 fcntl(connect_data->fd, F_SETFL, O_NONBLOCK); |
| 814 #ifndef _WIN32 | 873 #ifndef _WIN32 |
| 815 fcntl(connect_data->fd, F_SETFD, FD_CLOEXEC); | 874 fcntl(connect_data->fd, F_SETFD, FD_CLOEXEC); |
| 816 #endif | 875 #endif |
| 817 | 876 |
| 818 if (connect(connect_data->fd, addr, addrlen) != 0) | 877 if (connect(connect_data->fd, addr, addrlen) != 0) |
| 819 { | 878 { |
| 820 if ((errno == EINPROGRESS) || (errno == EINTR)) { | 879 if ((errno == EINPROGRESS) || (errno == EINTR)) { |
| 821 gaim_debug_info("http proxy", "Connection in progress\n"); | 880 gaim_debug_info("proxy", "Connection in progress\n"); |
| 822 | 881 |
| 823 if (connect_data->port != 80) { | 882 if (connect_data->port != 80) |
| 883 { | |
| 824 /* we need to do CONNECT first */ | 884 /* we need to do CONNECT first */ |
| 825 connect_data->inpa = gaim_input_add(connect_data->fd, GAIM_INPUT_WRITE, | 885 connect_data->inpa = gaim_input_add(connect_data->fd, |
| 826 http_canwrite, connect_data); | 886 GAIM_INPUT_WRITE, http_canwrite, connect_data); |
| 827 } else { | 887 } |
| 888 else | |
| 889 { | |
| 890 /* | |
| 891 * TODO: Uh, is this a good idea? For something like | |
| 892 * oscar, for example, we end up sending binary | |
| 893 * oscar protocol data to the proxy server, which | |
| 894 * has no idea what we're talking about, since | |
| 895 * the proxy server is expecting an HTTP request. | |
| 896 */ | |
| 828 gaim_debug_info("proxy", "HTTP proxy connection established\n"); | 897 gaim_debug_info("proxy", "HTTP proxy connection established\n"); |
| 829 gaim_proxy_connect_data_connected(connect_data); | 898 gaim_proxy_connect_data_connected(connect_data); |
| 830 } | 899 } |
| 831 } else { | 900 } |
| 832 close(connect_data->fd); | 901 else |
| 833 connect_data->fd = -1; | |
| 834 return -1; | |
| 835 } | |
| 836 } | |
| 837 else { | |
| 838 socklen_t len; | |
| 839 int error = ETIMEDOUT; | |
| 840 | |
| 841 gaim_debug_info("http proxy", "Connected immediately.\n"); | |
| 842 | |
| 843 len = sizeof(error); | |
| 844 if (getsockopt(connect_data->fd, SOL_SOCKET, SO_ERROR, &error, &len) != 0) | |
| 845 { | 902 { |
| 846 close(connect_data->fd); | 903 gaim_proxy_connect_data_disconnect(connect_data, strerror(errno)); |
| 847 connect_data->fd = -1; | 904 } |
| 848 return -1; | 905 } |
| 849 } | 906 else |
| 907 { | |
| 908 gaim_debug_info("proxy", "Connected immediately.\n"); | |
| 909 | |
| 850 http_canwrite(connect_data, connect_data->fd, GAIM_INPUT_WRITE); | 910 http_canwrite(connect_data, connect_data->fd, GAIM_INPUT_WRITE); |
| 851 } | 911 } |
| 852 | 912 } |
| 853 return connect_data->fd; | |
| 854 } | |
| 855 | |
| 856 | 913 |
| 857 static void | 914 static void |
| 858 s4_canread(gpointer data, gint source, GaimInputCondition cond) | 915 s4_canread(gpointer data, gint source, GaimInputCondition cond) |
| 859 { | 916 { |
| 860 GaimProxyConnectData *connect_data = data; | 917 GaimProxyConnectData *connect_data = data; |
| 882 gaim_proxy_connect_data_connected(connect_data); | 939 gaim_proxy_connect_data_connected(connect_data); |
| 883 return; | 940 return; |
| 884 } | 941 } |
| 885 } | 942 } |
| 886 | 943 |
| 887 gaim_proxy_connect_data_disconnect(connect_data); | 944 gaim_proxy_connect_data_disconnect(connect_data, strerror(errno)); |
| 888 try_connect(connect_data); | |
| 889 } | 945 } |
| 890 | 946 |
| 891 static void | 947 static void |
| 892 s4_canwrite(gpointer data, gint source, GaimInputCondition cond) | 948 s4_canwrite(gpointer data, gint source, GaimInputCondition cond) |
| 893 { | 949 { |
| 894 unsigned char packet[9]; | 950 unsigned char packet[9]; |
| 895 struct hostent *hp; | 951 struct hostent *hp; |
| 896 GaimProxyConnectData *connect_data = data; | 952 GaimProxyConnectData *connect_data = data; |
| 897 socklen_t len; | 953 socklen_t len; |
| 898 int error = ETIMEDOUT; | 954 int error = ETIMEDOUT; |
| 955 int ret; | |
| 899 | 956 |
| 900 gaim_debug_info("socks4 proxy", "Connected.\n"); | 957 gaim_debug_info("socks4 proxy", "Connected.\n"); |
| 901 | 958 |
| 902 if (connect_data->inpa > 0) | 959 if (connect_data->inpa > 0) |
| 903 { | 960 { |
| 904 gaim_input_remove(connect_data->inpa); | 961 gaim_input_remove(connect_data->inpa); |
| 905 connect_data->inpa = 0; | 962 connect_data->inpa = 0; |
| 906 } | 963 } |
| 907 | 964 |
| 908 len = sizeof(error); | 965 len = sizeof(error); |
| 909 | 966 ret = getsockopt(connect_data->fd, SOL_SOCKET, SO_ERROR, &error, &len); |
| 910 if (getsockopt(connect_data->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { | 967 if ((ret != 0) || (error != 0)) |
| 911 gaim_proxy_connect_data_disconnect(connect_data); | 968 { |
| 912 try_connect(connect_data); | 969 if (ret != 0) |
| 970 error = errno; | |
| 971 gaim_proxy_connect_data_disconnect(connect_data, strerror(error)); | |
| 913 return; | 972 return; |
| 914 } | 973 } |
| 915 | 974 |
| 916 /* | 975 /* |
| 917 * The socks4 spec doesn't include support for doing host name | 976 * The socks4 spec doesn't include support for doing host name |
| 919 * extensions to the protocol. Since we don't know if a | 978 * extensions to the protocol. Since we don't know if a |
| 920 * server supports this, it would need to be implemented | 979 * server supports this, it would need to be implemented |
| 921 * with an option, or some detection mechanism - in the | 980 * with an option, or some detection mechanism - in the |
| 922 * meantime, stick with plain old SOCKS4. | 981 * meantime, stick with plain old SOCKS4. |
| 923 */ | 982 */ |
| 924 /* TODO: This needs to be non-blocking! */ | 983 /* TODO: Use gaim_dnsquery_a() */ |
| 925 hp = gethostbyname(connect_data->host); | 984 hp = gethostbyname(connect_data->host); |
| 926 if (hp == NULL) { | 985 if (hp == NULL) { |
| 927 gaim_proxy_connect_data_disconnect(connect_data); | 986 gaim_proxy_connect_data_disconnect_formatted(connect_data, |
| 928 try_connect(connect_data); | 987 _("Error resolving %s"), connect_data->host); |
| 929 return; | 988 return; |
| 930 } | 989 } |
| 931 | 990 |
| 932 packet[0] = 4; | 991 packet[0] = 4; |
| 933 packet[1] = 1; | 992 packet[1] = 1; |
| 947 connect_data->inpa = gaim_input_add(connect_data->fd, GAIM_INPUT_WRITE, proxy_do_write, connect_data); | 1006 connect_data->inpa = gaim_input_add(connect_data->fd, GAIM_INPUT_WRITE, proxy_do_write, connect_data); |
| 948 | 1007 |
| 949 proxy_do_write(connect_data, connect_data->fd, cond); | 1008 proxy_do_write(connect_data, connect_data->fd, cond); |
| 950 } | 1009 } |
| 951 | 1010 |
| 952 static int | 1011 static void |
| 953 proxy_connect_socks4(GaimProxyConnectData *connect_data, struct sockaddr *addr, socklen_t addrlen) | 1012 proxy_connect_socks4(GaimProxyConnectData *connect_data, struct sockaddr *addr, socklen_t addrlen) |
| 954 { | 1013 { |
| 955 gaim_debug_info("socks4 proxy", | 1014 gaim_debug_info("proxy", |
| 956 "Connecting to %s:%d via %s:%d using SOCKS4\n", | 1015 "Connecting to %s:%d via %s:%d using SOCKS4\n", |
| 957 connect_data->host, connect_data->port, | 1016 connect_data->host, connect_data->port, |
| 958 gaim_proxy_info_get_host(connect_data->gpi), | 1017 gaim_proxy_info_get_host(connect_data->gpi), |
| 959 gaim_proxy_info_get_port(connect_data->gpi)); | 1018 gaim_proxy_info_get_port(connect_data->gpi)); |
| 960 | 1019 |
| 961 connect_data->fd = socket(addr->sa_family, SOCK_STREAM, 0); | 1020 connect_data->fd = socket(addr->sa_family, SOCK_STREAM, 0); |
| 962 if (connect_data->fd < 0) | 1021 if (connect_data->fd < 0) |
| 963 return -1; | 1022 { |
| 1023 gaim_proxy_connect_data_disconnect_formatted(connect_data, | |
| 1024 _("Unable to create socket:\n%s"), strerror(errno)); | |
| 1025 return; | |
| 1026 } | |
| 964 | 1027 |
| 965 fcntl(connect_data->fd, F_SETFL, O_NONBLOCK); | 1028 fcntl(connect_data->fd, F_SETFL, O_NONBLOCK); |
| 966 #ifndef _WIN32 | 1029 #ifndef _WIN32 |
| 967 fcntl(connect_data->fd, F_SETFD, FD_CLOEXEC); | 1030 fcntl(connect_data->fd, F_SETFD, FD_CLOEXEC); |
| 968 #endif | 1031 #endif |
| 969 | 1032 |
| 970 if (connect(connect_data->fd, addr, addrlen) != 0) | 1033 if (connect(connect_data->fd, addr, addrlen) != 0) |
| 971 { | 1034 { |
| 972 if ((errno == EINPROGRESS) || (errno == EINTR)) { | 1035 if ((errno == EINPROGRESS) || (errno == EINTR)) |
| 973 gaim_debug_info("socks4 proxy", "Connection in progress.\n"); | |
| 974 connect_data->inpa = gaim_input_add(connect_data->fd, GAIM_INPUT_WRITE, s4_canwrite, connect_data); | |
| 975 } | |
| 976 else { | |
| 977 close(connect_data->fd); | |
| 978 connect_data->fd = -1; | |
| 979 return -1; | |
| 980 } | |
| 981 } else { | |
| 982 socklen_t len; | |
| 983 int error = ETIMEDOUT; | |
| 984 | |
| 985 gaim_debug_info("socks4 proxy", "Connected immediately.\n"); | |
| 986 | |
| 987 len = sizeof(error); | |
| 988 | |
| 989 if (getsockopt(connect_data->fd, SOL_SOCKET, SO_ERROR, &error, &len) != 0) | |
| 990 { | 1036 { |
| 991 close(connect_data->fd); | 1037 gaim_debug_info("proxy", "Connection in progress.\n"); |
| 992 connect_data->fd = -1; | 1038 connect_data->inpa = gaim_input_add(connect_data->fd, |
| 993 return -1; | 1039 GAIM_INPUT_WRITE, s4_canwrite, connect_data); |
| 994 } | 1040 } |
| 1041 else | |
| 1042 { | |
| 1043 gaim_proxy_connect_data_disconnect(connect_data, strerror(errno)); | |
| 1044 } | |
| 1045 } | |
| 1046 else | |
| 1047 { | |
| 1048 gaim_debug_info("proxy", "Connected immediately.\n"); | |
| 995 | 1049 |
| 996 s4_canwrite(connect_data, connect_data->fd, GAIM_INPUT_WRITE); | 1050 s4_canwrite(connect_data, connect_data->fd, GAIM_INPUT_WRITE); |
| 997 } | 1051 } |
| 998 | |
| 999 return connect_data->fd; | |
| 1000 } | 1052 } |
| 1001 | 1053 |
| 1002 static void | 1054 static void |
| 1003 s5_canread_again(gpointer data, gint source, GaimInputCondition cond) | 1055 s5_canread_again(gpointer data, gint source, GaimInputCondition cond) |
| 1004 { | 1056 { |
| 1016 buf = connect_data->read_buffer; | 1068 buf = connect_data->read_buffer; |
| 1017 | 1069 |
| 1018 gaim_debug_info("socks5 proxy", "Able to read again.\n"); | 1070 gaim_debug_info("socks5 proxy", "Able to read again.\n"); |
| 1019 | 1071 |
| 1020 len = read(connect_data->fd, dest, (connect_data->read_buf_len - connect_data->read_len)); | 1072 len = read(connect_data->fd, dest, (connect_data->read_buf_len - connect_data->read_len)); |
| 1021 if(len < 0 && errno == EAGAIN) | 1073 |
| 1022 return; | 1074 if (len == 0) |
| 1023 else if(len <= 0) { | 1075 { |
| 1024 gaim_debug_warning("socks5 proxy", "or not...\n"); | 1076 gaim_proxy_connect_data_disconnect(connect_data, |
| 1025 gaim_proxy_connect_data_disconnect(connect_data); | 1077 _("Server closed the connection.")); |
| 1026 try_connect(connect_data); | 1078 return; |
| 1027 return; | 1079 } |
| 1028 } | 1080 |
| 1081 if (len < 0) | |
| 1082 { | |
| 1083 if (errno == EAGAIN) | |
| 1084 /* No worries */ | |
| 1085 return; | |
| 1086 | |
| 1087 /* Error! */ | |
| 1088 gaim_proxy_connect_data_disconnect_formatted(connect_data, | |
| 1089 _("Lost connection with server:\n%s"), strerror(errno)); | |
| 1090 return; | |
| 1091 } | |
| 1092 | |
| 1029 connect_data->read_len += len; | 1093 connect_data->read_len += len; |
| 1030 | 1094 |
| 1031 if(connect_data->read_len < 4) | 1095 if(connect_data->read_len < 4) |
| 1032 return; | 1096 return; |
| 1033 | 1097 |
| 1034 if ((buf[0] != 0x05) || (buf[1] != 0x00)) { | 1098 if ((buf[0] != 0x05) || (buf[1] != 0x00)) { |
| 1035 if ((buf[0] == 0x05) && (buf[1] < 0x09)) | 1099 if ((buf[0] == 0x05) && (buf[1] < 0x09)) { |
| 1036 gaim_debug_error("socks5 proxy", socks5errors[buf[1]]); | 1100 gaim_debug_error("socks5 proxy", socks5errors[buf[1]]); |
| 1037 else | 1101 gaim_proxy_connect_data_disconnect(connect_data, |
| 1102 socks5errors[buf[1]]); | |
| 1103 } else { | |
| 1038 gaim_debug_error("socks5 proxy", "Bad data.\n"); | 1104 gaim_debug_error("socks5 proxy", "Bad data.\n"); |
| 1039 gaim_proxy_connect_data_disconnect(connect_data); | 1105 gaim_proxy_connect_data_disconnect(connect_data, |
| 1040 try_connect(connect_data); | 1106 _("Received invalid data on connection with server.")); |
| 1107 } | |
| 1041 return; | 1108 return; |
| 1042 } | 1109 } |
| 1043 | 1110 |
| 1044 /* Skip past BND.ADDR */ | 1111 /* Skip past BND.ADDR */ |
| 1045 switch(buf[3]) { | 1112 switch(buf[3]) { |
| 1112 | 1179 |
| 1113 gaim_debug_info("socks5 proxy", "Got auth response.\n"); | 1180 gaim_debug_info("socks5 proxy", "Got auth response.\n"); |
| 1114 | 1181 |
| 1115 len = read(connect_data->fd, connect_data->read_buffer + connect_data->read_len, | 1182 len = read(connect_data->fd, connect_data->read_buffer + connect_data->read_len, |
| 1116 connect_data->read_buf_len - connect_data->read_len); | 1183 connect_data->read_buf_len - connect_data->read_len); |
| 1117 if(len < 0 && errno == EAGAIN) | 1184 |
| 1118 return; | 1185 if (len == 0) |
| 1119 else if(len <= 0) { | 1186 { |
| 1120 gaim_proxy_connect_data_disconnect(connect_data); | 1187 gaim_proxy_connect_data_disconnect(connect_data, |
| 1121 try_connect(connect_data); | 1188 _("Server closed the connection.")); |
| 1122 return; | 1189 return; |
| 1123 } | 1190 } |
| 1191 | |
| 1192 if (len < 0) | |
| 1193 { | |
| 1194 if (errno == EAGAIN) | |
| 1195 /* No worries */ | |
| 1196 return; | |
| 1197 | |
| 1198 /* Error! */ | |
| 1199 gaim_proxy_connect_data_disconnect_formatted(connect_data, | |
| 1200 _("Lost connection with server:\n%s"), strerror(errno)); | |
| 1201 return; | |
| 1202 } | |
| 1203 | |
| 1124 connect_data->read_len += len; | 1204 connect_data->read_len += len; |
| 1125 | |
| 1126 if (connect_data->read_len < 2) | 1205 if (connect_data->read_len < 2) |
| 1127 return; | 1206 return; |
| 1128 | 1207 |
| 1129 gaim_input_remove(connect_data->inpa); | 1208 gaim_input_remove(connect_data->inpa); |
| 1130 connect_data->inpa = 0; | 1209 connect_data->inpa = 0; |
| 1131 | 1210 |
| 1132 if ((connect_data->read_buffer[0] != 0x01) || (connect_data->read_buffer[1] != 0x00)) { | 1211 if ((connect_data->read_buffer[0] != 0x01) || (connect_data->read_buffer[1] != 0x00)) { |
| 1133 gaim_proxy_connect_data_disconnect(connect_data); | 1212 gaim_proxy_connect_data_disconnect(connect_data, |
| 1134 try_connect(connect_data); | 1213 _("Received invalid data on connection with server.")); |
| 1135 return; | 1214 return; |
| 1136 } | 1215 } |
| 1137 | 1216 |
| 1138 g_free(connect_data->read_buffer); | 1217 g_free(connect_data->read_buffer); |
| 1139 connect_data->read_buffer = NULL; | 1218 connect_data->read_buffer = NULL; |
| 1201 } | 1280 } |
| 1202 | 1281 |
| 1203 len = read(connect_data->fd, connect_data->read_buffer + connect_data->read_len, | 1282 len = read(connect_data->fd, connect_data->read_buffer + connect_data->read_len, |
| 1204 connect_data->read_buf_len - connect_data->read_len); | 1283 connect_data->read_buf_len - connect_data->read_len); |
| 1205 | 1284 |
| 1206 if(len < 0 && errno == EAGAIN) | 1285 if (len == 0) |
| 1207 return; | 1286 { |
| 1208 else if(len <= 0) { | 1287 gaim_proxy_connect_data_disconnect(connect_data, |
| 1209 gaim_proxy_connect_data_disconnect(connect_data); | 1288 _("Server closed the connection.")); |
| 1210 try_connect(connect_data); | 1289 return; |
| 1211 return; | 1290 } |
| 1212 } | 1291 |
| 1292 if (len < 0) | |
| 1293 { | |
| 1294 if (errno == EAGAIN) | |
| 1295 /* No worries */ | |
| 1296 return; | |
| 1297 | |
| 1298 /* Error! */ | |
| 1299 gaim_proxy_connect_data_disconnect_formatted(connect_data, | |
| 1300 _("Lost connection with server:\n%s"), strerror(errno)); | |
| 1301 return; | |
| 1302 } | |
| 1303 | |
| 1213 connect_data->read_len += len; | 1304 connect_data->read_len += len; |
| 1214 | |
| 1215 if (connect_data->read_len < 2) | 1305 if (connect_data->read_len < 2) |
| 1216 return; | 1306 return; |
| 1217 | 1307 |
| 1218 cmdbuf = connect_data->read_buffer; | 1308 cmdbuf = connect_data->read_buffer; |
| 1219 | 1309 |
| 1220 if (*cmdbuf != 0x01) { | 1310 if (*cmdbuf != 0x01) { |
| 1221 gaim_proxy_connect_data_disconnect(connect_data); | 1311 gaim_proxy_connect_data_disconnect(connect_data, |
| 1222 try_connect(connect_data); | 1312 _("Received invalid data on connection with server.")); |
| 1223 return; | 1313 return; |
| 1224 } | 1314 } |
| 1225 cmdbuf++; | 1315 cmdbuf++; |
| 1226 | 1316 |
| 1227 navas = *cmdbuf; | 1317 navas = *cmdbuf; |
| 1247 } else { | 1337 } else { |
| 1248 /* Failure */ | 1338 /* Failure */ |
| 1249 gaim_debug_warning("proxy", | 1339 gaim_debug_warning("proxy", |
| 1250 "socks5 CHAP authentication " | 1340 "socks5 CHAP authentication " |
| 1251 "failed. Disconnecting..."); | 1341 "failed. Disconnecting..."); |
| 1252 gaim_proxy_connect_data_disconnect(connect_data); | 1342 gaim_proxy_connect_data_disconnect(connect_data, |
| 1253 try_connect(connect_data); | 1343 _("Authentication failed")); |
| 1254 return; | 1344 return; |
| 1255 } | 1345 } |
| 1256 break; | 1346 break; |
| 1257 case 0x03: | 1347 case 0x03: |
| 1258 /* Server wants our credentials */ | 1348 /* Server wants our credentials */ |
| 1288 "Server tried to select an " | 1378 "Server tried to select an " |
| 1289 "algorithm that we did not advertise " | 1379 "algorithm that we did not advertise " |
| 1290 "as supporting. This is a violation " | 1380 "as supporting. This is a violation " |
| 1291 "of the socks5 CHAP specification. " | 1381 "of the socks5 CHAP specification. " |
| 1292 "Disconnecting..."); | 1382 "Disconnecting..."); |
| 1293 gaim_proxy_connect_data_disconnect(connect_data); | 1383 gaim_proxy_connect_data_disconnect(connect_data, |
| 1294 try_connect(connect_data); | 1384 _("Received invalid data on connection with server.")); |
| 1295 return; | 1385 return; |
| 1296 } | 1386 } |
| 1297 break; | 1387 break; |
| 1298 } | 1388 } |
| 1299 cmdbuf = buf + cmdbuf[1]; | 1389 cmdbuf = buf + cmdbuf[1]; |
| 1317 | 1407 |
| 1318 gaim_debug_info("socks5 proxy", "Able to read.\n"); | 1408 gaim_debug_info("socks5 proxy", "Able to read.\n"); |
| 1319 | 1409 |
| 1320 len = read(connect_data->fd, connect_data->read_buffer + connect_data->read_len, | 1410 len = read(connect_data->fd, connect_data->read_buffer + connect_data->read_len, |
| 1321 connect_data->read_buf_len - connect_data->read_len); | 1411 connect_data->read_buf_len - connect_data->read_len); |
| 1322 if(len < 0 && errno == EAGAIN) | 1412 |
| 1323 return; | 1413 if (len == 0) |
| 1324 else if(len <= 0) { | 1414 { |
| 1325 gaim_proxy_connect_data_disconnect(connect_data); | 1415 gaim_proxy_connect_data_disconnect(connect_data, |
| 1326 try_connect(connect_data); | 1416 _("Server closed the connection.")); |
| 1327 return; | 1417 return; |
| 1328 } | 1418 } |
| 1419 | |
| 1420 if (len < 0) | |
| 1421 { | |
| 1422 if (errno == EAGAIN) | |
| 1423 /* No worries */ | |
| 1424 return; | |
| 1425 | |
| 1426 /* Error! */ | |
| 1427 gaim_proxy_connect_data_disconnect_formatted(connect_data, | |
| 1428 _("Lost connection with server:\n%s"), strerror(errno)); | |
| 1429 return; | |
| 1430 } | |
| 1431 | |
| 1329 connect_data->read_len += len; | 1432 connect_data->read_len += len; |
| 1330 | |
| 1331 if (connect_data->read_len < 2) | 1433 if (connect_data->read_len < 2) |
| 1332 return; | 1434 return; |
| 1333 | 1435 |
| 1334 gaim_input_remove(connect_data->inpa); | 1436 gaim_input_remove(connect_data->inpa); |
| 1335 connect_data->inpa = 0; | 1437 connect_data->inpa = 0; |
| 1336 | 1438 |
| 1337 if ((connect_data->read_buffer[0] != 0x05) || (connect_data->read_buffer[1] == 0xff)) { | 1439 if ((connect_data->read_buffer[0] != 0x05) || (connect_data->read_buffer[1] == 0xff)) { |
| 1338 gaim_proxy_connect_data_disconnect(connect_data); | 1440 gaim_proxy_connect_data_disconnect(connect_data, |
| 1339 try_connect(connect_data); | 1441 _("Received invalid data on connection with server.")); |
| 1340 return; | 1442 return; |
| 1341 } | 1443 } |
| 1342 | 1444 |
| 1343 if (connect_data->read_buffer[1] == 0x02) { | 1445 if (connect_data->read_buffer[1] == 0x02) { |
| 1344 gsize i, j; | 1446 gsize i, j; |
| 1416 unsigned char buf[5]; | 1518 unsigned char buf[5]; |
| 1417 int i; | 1519 int i; |
| 1418 GaimProxyConnectData *connect_data = data; | 1520 GaimProxyConnectData *connect_data = data; |
| 1419 socklen_t len; | 1521 socklen_t len; |
| 1420 int error = ETIMEDOUT; | 1522 int error = ETIMEDOUT; |
| 1523 int ret; | |
| 1421 | 1524 |
| 1422 gaim_debug_info("socks5 proxy", "Connected.\n"); | 1525 gaim_debug_info("socks5 proxy", "Connected.\n"); |
| 1423 | 1526 |
| 1424 if (connect_data->inpa > 0) | 1527 if (connect_data->inpa > 0) |
| 1425 { | 1528 { |
| 1426 gaim_input_remove(connect_data->inpa); | 1529 gaim_input_remove(connect_data->inpa); |
| 1427 connect_data->inpa = 0; | 1530 connect_data->inpa = 0; |
| 1428 } | 1531 } |
| 1429 | 1532 |
| 1430 len = sizeof(error); | 1533 len = sizeof(error); |
| 1431 if (getsockopt(connect_data->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { | 1534 ret = getsockopt(connect_data->fd, SOL_SOCKET, SO_ERROR, &error, &len); |
| 1432 gaim_proxy_connect_data_disconnect(connect_data); | 1535 if ((ret != 0) || (error != 0)) |
| 1433 try_connect(connect_data); | 1536 { |
| 1537 if (ret != 0) | |
| 1538 error = errno; | |
| 1539 gaim_proxy_connect_data_disconnect(connect_data, strerror(error)); | |
| 1434 return; | 1540 return; |
| 1435 } | 1541 } |
| 1436 | 1542 |
| 1437 i = 0; | 1543 i = 0; |
| 1438 buf[0] = 0x05; /* SOCKS version 5 */ | 1544 buf[0] = 0x05; /* SOCKS version 5 */ |
| 1458 | 1564 |
| 1459 connect_data->inpa = gaim_input_add(connect_data->fd, GAIM_INPUT_WRITE, proxy_do_write, connect_data); | 1565 connect_data->inpa = gaim_input_add(connect_data->fd, GAIM_INPUT_WRITE, proxy_do_write, connect_data); |
| 1460 proxy_do_write(connect_data, connect_data->fd, GAIM_INPUT_WRITE); | 1566 proxy_do_write(connect_data, connect_data->fd, GAIM_INPUT_WRITE); |
| 1461 } | 1567 } |
| 1462 | 1568 |
| 1463 static int | 1569 static void |
| 1464 proxy_connect_socks5(GaimProxyConnectData *connect_data, struct sockaddr *addr, socklen_t addrlen) | 1570 proxy_connect_socks5(GaimProxyConnectData *connect_data, struct sockaddr *addr, socklen_t addrlen) |
| 1465 { | 1571 { |
| 1466 gaim_debug_info("socks5 proxy", | 1572 gaim_debug_info("proxy", |
| 1467 "Connecting to %s:%d via %s:%d using SOCKS5\n", | 1573 "Connecting to %s:%d via %s:%d using SOCKS5\n", |
| 1468 connect_data->host, connect_data->port, | 1574 connect_data->host, connect_data->port, |
| 1469 gaim_proxy_info_get_host(connect_data->gpi), | 1575 gaim_proxy_info_get_host(connect_data->gpi), |
| 1470 gaim_proxy_info_get_port(connect_data->gpi)); | 1576 gaim_proxy_info_get_port(connect_data->gpi)); |
| 1471 | 1577 |
| 1472 connect_data->fd = socket(addr->sa_family, SOCK_STREAM, 0); | 1578 connect_data->fd = socket(addr->sa_family, SOCK_STREAM, 0); |
| 1473 if (connect_data->fd < 0) | 1579 if (connect_data->fd < 0) |
| 1474 return -1; | 1580 { |
| 1581 gaim_proxy_connect_data_disconnect_formatted(connect_data, | |
| 1582 _("Unable to create socket:\n%s"), strerror(errno)); | |
| 1583 return; | |
| 1584 } | |
| 1475 | 1585 |
| 1476 fcntl(connect_data->fd, F_SETFL, O_NONBLOCK); | 1586 fcntl(connect_data->fd, F_SETFL, O_NONBLOCK); |
| 1477 #ifndef _WIN32 | 1587 #ifndef _WIN32 |
| 1478 fcntl(connect_data->fd, F_SETFD, FD_CLOEXEC); | 1588 fcntl(connect_data->fd, F_SETFD, FD_CLOEXEC); |
| 1479 #endif | 1589 #endif |
| 1480 | 1590 |
| 1481 if (connect(connect_data->fd, addr, addrlen) != 0) | 1591 if (connect(connect_data->fd, addr, addrlen) != 0) |
| 1482 { | 1592 { |
| 1483 if ((errno == EINPROGRESS) || (errno == EINTR)) { | 1593 if ((errno == EINPROGRESS) || (errno == EINTR)) |
| 1594 { | |
| 1484 gaim_debug_info("socks5 proxy", "Connection in progress\n"); | 1595 gaim_debug_info("socks5 proxy", "Connection in progress\n"); |
| 1485 connect_data->inpa = gaim_input_add(connect_data->fd, GAIM_INPUT_WRITE, s5_canwrite, connect_data); | 1596 connect_data->inpa = gaim_input_add(connect_data->fd, |
| 1486 } | 1597 GAIM_INPUT_WRITE, s5_canwrite, connect_data); |
| 1487 else { | 1598 } |
| 1488 close(connect_data->fd); | 1599 else |
| 1489 connect_data->fd = -1; | |
| 1490 return -1; | |
| 1491 } | |
| 1492 } | |
| 1493 else { | |
| 1494 socklen_t len; | |
| 1495 int error = ETIMEDOUT; | |
| 1496 | |
| 1497 gaim_debug_info("socks5 proxy", "Connected immediately.\n"); | |
| 1498 | |
| 1499 len = sizeof(error); | |
| 1500 | |
| 1501 if (getsockopt(connect_data->fd, SOL_SOCKET, SO_ERROR, &error, &len) != 0) | |
| 1502 { | 1600 { |
| 1503 close(connect_data->fd); | 1601 gaim_proxy_connect_data_disconnect(connect_data, strerror(errno)); |
| 1504 connect_data->fd = -1; | 1602 } |
| 1505 return -1; | 1603 } |
| 1506 } | 1604 else |
| 1605 { | |
| 1606 gaim_debug_info("proxy", "Connected immediately.\n"); | |
| 1507 | 1607 |
| 1508 s5_canwrite(connect_data, connect_data->fd, GAIM_INPUT_WRITE); | 1608 s5_canwrite(connect_data, connect_data->fd, GAIM_INPUT_WRITE); |
| 1509 } | 1609 } |
| 1510 | |
| 1511 return connect_data->fd; | |
| 1512 } | 1610 } |
| 1513 | 1611 |
| 1514 /** | 1612 /** |
| 1515 * This function iterates through a list of IP addresses and attempts | 1613 * This function attempts to connect to the next IP address in the list |
| 1614 * of IP addresses returned to us by gaim_dnsquery_a() and attemps | |
| 1516 * to connect to each one. This is called after the hostname is | 1615 * to connect to each one. This is called after the hostname is |
| 1517 * resolved, and if a connection attempt fails. | 1616 * resolved, and each time a connection attempt fails (assuming there |
| 1617 * is another IP address to try). | |
| 1518 */ | 1618 */ |
| 1519 static void try_connect(GaimProxyConnectData *connect_data) | 1619 static void try_connect(GaimProxyConnectData *connect_data) |
| 1520 { | 1620 { |
| 1521 size_t addrlen; | 1621 size_t addrlen; |
| 1522 struct sockaddr *addr; | 1622 struct sockaddr *addr; |
| 1523 int ret = -1; | 1623 |
| 1524 | 1624 addrlen = GPOINTER_TO_INT(connect_data->hosts->data); |
| 1525 if (connect_data->hosts == NULL) | 1625 connect_data->hosts = g_slist_remove(connect_data->hosts, connect_data->hosts->data); |
| 1526 { | 1626 addr = connect_data->hosts->data; |
| 1527 gaim_proxy_connect_data_error(connect_data, _("Could not resolve host name")); | 1627 connect_data->hosts = g_slist_remove(connect_data->hosts, connect_data->hosts->data); |
| 1528 return; | 1628 |
| 1529 } | 1629 gaim_debug_info("proxy", "Attempting connection to %s\n", "TODO"); |
| 1530 | 1630 |
| 1531 while (connect_data->hosts) | 1631 switch (gaim_proxy_info_get_type(connect_data->gpi)) { |
| 1532 { | 1632 case GAIM_PROXY_NONE: |
| 1533 addrlen = GPOINTER_TO_INT(connect_data->hosts->data); | 1633 proxy_connect_none(connect_data, addr, addrlen); |
| 1534 connect_data->hosts = g_slist_remove(connect_data->hosts, connect_data->hosts->data); | |
| 1535 addr = connect_data->hosts->data; | |
| 1536 connect_data->hosts = g_slist_remove(connect_data->hosts, connect_data->hosts->data); | |
| 1537 | |
| 1538 switch (gaim_proxy_info_get_type(connect_data->gpi)) { | |
| 1539 case GAIM_PROXY_NONE: | |
| 1540 ret = proxy_connect_none(connect_data, addr, addrlen); | |
| 1541 break; | |
| 1542 | |
| 1543 case GAIM_PROXY_HTTP: | |
| 1544 ret = proxy_connect_http(connect_data, addr, addrlen); | |
| 1545 break; | |
| 1546 | |
| 1547 case GAIM_PROXY_SOCKS4: | |
| 1548 ret = proxy_connect_socks4(connect_data, addr, addrlen); | |
| 1549 break; | |
| 1550 | |
| 1551 case GAIM_PROXY_SOCKS5: | |
| 1552 ret = proxy_connect_socks5(connect_data, addr, addrlen); | |
| 1553 break; | |
| 1554 | |
| 1555 case GAIM_PROXY_USE_ENVVAR: | |
| 1556 ret = proxy_connect_http(connect_data, addr, addrlen); | |
| 1557 break; | |
| 1558 | |
| 1559 default: | |
| 1560 break; | |
| 1561 } | |
| 1562 | |
| 1563 g_free(addr); | |
| 1564 | |
| 1565 if (ret >= 0) | |
| 1566 break; | 1634 break; |
| 1567 } | 1635 |
| 1568 | 1636 case GAIM_PROXY_HTTP: |
| 1569 if (ret < 0) { | 1637 proxy_connect_http(connect_data, addr, addrlen); |
| 1570 gaim_proxy_connect_data_error(connect_data, _("Unable to establish a connection")); | 1638 break; |
| 1571 } | 1639 |
| 1640 case GAIM_PROXY_SOCKS4: | |
| 1641 proxy_connect_socks4(connect_data, addr, addrlen); | |
| 1642 break; | |
| 1643 | |
| 1644 case GAIM_PROXY_SOCKS5: | |
| 1645 proxy_connect_socks5(connect_data, addr, addrlen); | |
| 1646 break; | |
| 1647 | |
| 1648 case GAIM_PROXY_USE_ENVVAR: | |
| 1649 proxy_connect_http(connect_data, addr, addrlen); | |
| 1650 break; | |
| 1651 | |
| 1652 default: | |
| 1653 break; | |
| 1654 } | |
| 1655 | |
| 1656 g_free(addr); | |
| 1572 } | 1657 } |
| 1573 | 1658 |
| 1574 static void | 1659 static void |
| 1575 connection_host_resolved(GSList *hosts, gpointer data, | 1660 connection_host_resolved(GSList *hosts, gpointer data, |
| 1576 const char *error_message) | 1661 const char *error_message) |
| 1580 connect_data = data; | 1665 connect_data = data; |
| 1581 connect_data->query_data = NULL; | 1666 connect_data->query_data = NULL; |
| 1582 | 1667 |
| 1583 if (error_message != NULL) | 1668 if (error_message != NULL) |
| 1584 { | 1669 { |
| 1585 gaim_proxy_connect_data_error(connect_data, error_message); | 1670 gaim_proxy_connect_data_disconnect(connect_data, error_message); |
| 1671 return; | |
| 1672 } | |
| 1673 | |
| 1674 if (hosts == NULL) | |
| 1675 { | |
| 1676 gaim_proxy_connect_data_disconnect(connect_data, _("Could not resolve host name")); | |
| 1586 return; | 1677 return; |
| 1587 } | 1678 } |
| 1588 | 1679 |
| 1589 connect_data->hosts = hosts; | 1680 connect_data->hosts = hosts; |
| 1590 | 1681 |
| 1754 } | 1845 } |
| 1755 | 1846 |
| 1756 void | 1847 void |
| 1757 gaim_proxy_connect_cancel(GaimProxyConnectData *connect_data) | 1848 gaim_proxy_connect_cancel(GaimProxyConnectData *connect_data) |
| 1758 { | 1849 { |
| 1850 gaim_proxy_connect_data_disconnect(connect_data, NULL); | |
| 1759 gaim_proxy_connect_data_destroy(connect_data); | 1851 gaim_proxy_connect_data_destroy(connect_data); |
| 1760 } | 1852 } |
| 1761 | 1853 |
| 1762 static void | 1854 static void |
| 1763 proxy_pref_cb(const char *name, GaimPrefType type, | 1855 proxy_pref_cb(const char *name, GaimPrefType type, |
| 1833 | 1925 |
| 1834 void | 1926 void |
| 1835 gaim_proxy_uninit(void) | 1927 gaim_proxy_uninit(void) |
| 1836 { | 1928 { |
| 1837 while (connect_datas != NULL) | 1929 while (connect_datas != NULL) |
| 1930 { | |
| 1931 gaim_proxy_connect_data_disconnect(connect_datas->data, NULL); | |
| 1838 gaim_proxy_connect_data_destroy(connect_datas->data); | 1932 gaim_proxy_connect_data_destroy(connect_datas->data); |
| 1839 } | 1933 } |
| 1934 } |
