Mercurial > pidgin.yaz
diff libpurple/protocols/gg/lib/dcc7.c @ 32072:3a90a59ddea2
Update libgadu to 0.11.0 plus local changes; thanks to Tomasz Wasilczyk.
Fixes 14248
author | Ethan Blanton <elb@pidgin.im> |
---|---|
date | Sun, 05 Jun 2011 01:28:53 +0000 |
parents | 93b08d43f684 |
children | 9c9143e32b6c |
line wrap: on
line diff
--- a/libpurple/protocols/gg/lib/dcc7.c Tue May 24 01:48:26 2011 +0000 +++ b/libpurple/protocols/gg/lib/dcc7.c Sun Jun 05 01:28:53 2011 +0000 @@ -1,11 +1,11 @@ -/* $Id: dcc7.c 1037 2010-12-17 22:18:08Z wojtekka $ */ +/* $Id: dcc7.c 1087 2011-04-14 20:53:25Z wojtekka $ */ /* * (C) Copyright 2001-2010 Wojtek Kaniewski <wojtekka@irc.pl> * Tomasz Chiliński <chilek@chilan.com> * Adam Wysocki <gophi@ekg.chmurka.net> * Bartłomiej Zimoń <uzi18@o2.pl> - * + * * Thanks to Jakub Zawadzki <darkjames@darkjames.ath.cx> * * This program is free software; you can redistribute it and/or modify @@ -29,13 +29,8 @@ * \brief Obsługa połączeń bezpośrednich od wersji Gadu-Gadu 7.x */ -#include "libgadu.h" -#include "libgadu-internal.h" -#include "libgadu-debug.h" - #include <sys/types.h> #include <sys/stat.h> - #ifndef _WIN32 # include <sys/ioctl.h> # include <sys/socket.h> @@ -45,7 +40,6 @@ # include <sys/filio.h> # endif #endif - #include <time.h> #include <ctype.h> @@ -58,8 +52,11 @@ #include <unistd.h> #include "compat.h" +#include "libgadu.h" #include "protocol.h" #include "resolver.h" +#include "libgadu-internal.h" +#include "libgadu-debug.h" #define gg_debug_dcc(dcc, level, fmt...) \ gg_debug_session(((dcc) != NULL) ? (dcc)->sess : NULL, level, fmt) @@ -223,13 +220,16 @@ * \internal Tworzy gniazdo nasłuchujące dla połączenia bezpośredniego * * \param dcc Struktura połączenia - * \param port Preferowany port (jeśli równy 0 lub -1, próbuje się domyślnego) + * \param addr Preferowany adres (jeśli równy 0, nasłuchujemy na wszystkich interfejsach) + * \param port Preferowany port (jeśli równy 0, nasłuchujemy na losowym) * * \return 0 jeśli się powiodło, -1 w przypadku błędu */ -static int gg_dcc7_listen(struct gg_dcc7 *dcc, uint16_t port) +static int gg_dcc7_listen(struct gg_dcc7 *dcc, uint32_t addr, uint16_t port) { struct sockaddr_in sin; + socklen_t sin_len = sizeof(sin); + int errsv; int fd; gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_listen(%p, %d)\n", dcc, port); @@ -245,45 +245,40 @@ return -1; } - // XXX losować porty? - - if (!port) - port = GG_DEFAULT_DCC_PORT; - - while (1) { - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = INADDR_ANY; - sin.sin_port = htons(port); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = addr; + sin.sin_port = htons(port); - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() trying port %d\n", port); - - if (!bind(fd, (struct sockaddr*) &sin, sizeof(sin))) - break; + if (bind(fd, (struct sockaddr*) &sin, sizeof(sin)) == -1) { + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() unable to bind to %s:%d\n", inet_ntoa(sin.sin_addr), port); + goto fail; + } - if (port++ == 65535) { - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() no free port found\n"); - close(fd); - errno = ENOENT; - return -1; - } + if (port == 0 && getsockname(fd, (struct sockaddr*) &sin, &sin_len) == -1) { + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() unable to bind to port %d\n", port); + goto fail; } if (listen(fd, 1)) { - int errsv = errno; gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() unable to listen (%s)\n", strerror(errno)); - close(fd); - errno = errsv; - return -1; + goto fail; } dcc->fd = fd; - dcc->local_port = port; - + dcc->local_addr = sin.sin_addr.s_addr; + dcc->local_port = ntohs(sin.sin_port); + dcc->state = GG_STATE_LISTENING; dcc->check = GG_CHECK_READ; dcc->timeout = GG_DCC7_TIMEOUT_FILE_ACK; return 0; + +fail: + errsv = errno; + close(fd); + errno = errsv; + return -1; } /** @@ -297,38 +292,34 @@ { struct gg_dcc7_info pkt; uint16_t external_port; - uint16_t local_port; + uint32_t external_addr; + struct in_addr addr; gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_listen_and_send_info(%p)\n", dcc); - if (!dcc->sess->client_port) - local_port = dcc->sess->external_port; - else - local_port = dcc->sess->client_port; - - if (gg_dcc7_listen(dcc, local_port) == -1) + if (gg_dcc7_listen(dcc, dcc->sess->client_addr, dcc->sess->client_port) == -1) return -1; - if (!dcc->sess->external_port || dcc->local_port != local_port) + if (dcc->sess->external_port != 0) + external_port = dcc->sess->external_port; + else external_port = dcc->local_port; - else - external_port = dcc->sess->external_port; - if (!dcc->sess->external_addr || dcc->local_port != local_port) - dcc->local_addr = dcc->sess->client_addr; - else - dcc->local_addr = dcc->sess->external_addr; + if (dcc->sess->external_addr != 0) + external_addr = dcc->sess->external_addr; + else + external_addr = dcc->local_addr; - gg_debug_dcc(dcc, GG_DEBUG_MISC, "// dcc7_listen_and_send_info() sending IP address %s and port %d\n", inet_ntoa(*((struct in_addr*) &dcc->local_addr)), external_port); + addr.s_addr = external_addr; + + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// dcc7_listen_and_send_info() sending IP address %s and port %d\n", inet_ntoa(addr), external_port); memset(&pkt, 0, sizeof(pkt)); pkt.uin = gg_fix32(dcc->peer_uin); pkt.type = GG_DCC7_TYPE_P2P; pkt.id = dcc->cid; - snprintf((char*) pkt.info, sizeof(pkt.info), "%s %d", inet_ntoa(*((struct in_addr*) &dcc->local_addr)), external_port); - // TODO: implement hash count - // we MUST fill hash to recive from server request for server connection - snprintf((char*) pkt.hash, sizeof(pkt.hash), "0"); + snprintf((char*) pkt.info, sizeof(pkt.info), "%s %d", inet_ntoa(addr), external_port); + snprintf((char*) pkt.hash, sizeof(pkt.hash), "%u", external_addr + external_port * rand()); return gg_send_packet(dcc->sess, GG_DCC7_INFO, &pkt, sizeof(pkt), NULL); } @@ -388,7 +379,7 @@ errno = EINVAL; return -1; } - + memset(&pkt, 0, sizeof(pkt)); pkt.type = gg_fix32(type); @@ -649,7 +640,7 @@ if (tmp->state != GG_STATE_REQUESTING_ID || tmp->dcc_type != gg_fix32(p->type)) continue; - + tmp->cid = p->id; switch (tmp->dcc_type) { @@ -708,9 +699,9 @@ e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE; return 0; } - + // XXX czy dla odwrotnego połączenia powinniśmy wywołać już zdarzenie GG_DCC7_ACCEPT? - + dcc->offset = gg_fix32(p->offset); dcc->state = GG_STATE_WAITING_FOR_INFO; @@ -764,8 +755,10 @@ } if (dcc->state == GG_STATE_WAITING_FOR_INFO) { - gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() wainting for info so send one\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() waiting for info so send one\n"); gg_dcc7_listen_and_send_info(dcc); + e->type = GG_EVENT_DCC7_PENDING; + e->event.dcc7_pending.dcc7 = dcc; return 0; } @@ -809,7 +802,7 @@ gg_send_packet(dcc->sess, GG_DCC7_INFO, payload, len, NULL); - break; + return 0; default: gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() unhandled transfer type (%d)\n", p->type); @@ -877,7 +870,7 @@ gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_reject() unknown dcc session\n"); return 0; } - + if (dcc->state != GG_STATE_WAITING_FOR_ACCEPT) { gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_reject() invalid state\n"); e->type = GG_EVENT_DCC7_ERROR; @@ -917,7 +910,7 @@ gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_new() not enough memory\n"); return -1; } - + memset(dcc, 0, sizeof(struct gg_dcc7)); dcc->type = GG_SESSION_DCC7_GET; dcc->dcc_type = GG_DCC7_TYPE_FILE; @@ -949,7 +942,7 @@ gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_packet() not enough memory\n"); return -1; } - + memset(dcc, 0, sizeof(struct gg_dcc7)); dcc->type = GG_SESSION_DCC7_VOICE; @@ -984,7 +977,7 @@ /** * \internal Ustawia odpowiednie stany wewnętrzne w zależności od rodzaju * połączenia. - * + * * \param dcc Struktura połączenia * * \return 0 jeśli się powiodło, -1 w przypadku błędu. @@ -1382,6 +1375,9 @@ dcc->check = GG_CHECK_WRITE; dcc->timeout = GG_DEFAULT_TIMEOUT; + e->type = GG_EVENT_DCC7_PENDING; + e->event.dcc7_pending.dcc7 = dcc; + return e; }