1
/* $Id: dcc7.c 1087 2011-04-14 20:53:25Z wojtekka $ */
4
* (C) Copyright 2001-2010 Wojtek Kaniewski <wojtekka@irc.pl>
5
* Tomasz Chiliński <chilek@chilan.com>
6
* Adam Wysocki <gophi@ekg.chmurka.net>
7
* Bartłomiej Zimoń <uzi18@o2.pl>
9
* Thanks to Jakub Zawadzki <darkjames@darkjames.ath.cx>
11
* This program is free software; you can redistribute it and/or modify
12
* it under the terms of the GNU Lesser General Public License Version
13
* 2.1 as published by the Free Software Foundation.
15
* This program is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU Lesser General Public License for more details.
20
* You should have received a copy of the GNU Lesser General Public
21
* License along with this program; if not, write to the Free Software
22
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110,
29
* \brief Obsługa połączeń bezpośrednich od wersji Gadu-Gadu 7.x
32
#include <sys/types.h>
35
# include <sys/ioctl.h>
36
# include <sys/socket.h>
37
# include <netinet/in.h>
38
# include <arpa/inet.h>
40
# include <sys/filio.h>
58
#include "libgadu-internal.h"
59
#include "libgadu-debug.h"
61
#define gg_debug_dcc(dcc, level, fmt...) \
62
gg_debug_session(((dcc) != NULL) ? (dcc)->sess : NULL, level, fmt)
64
#define gg_debug_dump_dcc(dcc, level, buf, len) \
65
gg_debug_dump(((dcc) != NULL) ? (dcc)->sess : NULL, level, buf, len)
68
* \internal Dodaje połączenie bezpośrednie do sesji.
70
* \param sess Struktura sesji
71
* \param dcc Struktura połączenia
73
* \return 0 jeśli się powiodło, -1 w przypadku błędu
75
static int gg_dcc7_session_add(struct gg_session *sess, struct gg_dcc7 *dcc)
77
gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_session_add(%p, %p)\n", sess, dcc);
79
if (!sess || !dcc || dcc->next) {
80
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_session_add() invalid parameters\n");
85
dcc->next = sess->dcc7_list;
86
sess->dcc7_list = dcc;
92
* \internal Usuwa połączenie bezpośrednie z sesji.
94
* \param sess Struktura sesji
95
* \param dcc Struktura połączenia
97
* \return 0 jeśli się powiodło, -1 w przypadku błędu
99
static int gg_dcc7_session_remove(struct gg_session *sess, struct gg_dcc7 *dcc)
103
gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_session_remove(%p, %p)\n", sess, dcc);
105
if (sess == NULL || dcc == NULL) {
106
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_session_remove() invalid parameters\n");
111
if (sess->dcc7_list == dcc) {
112
sess->dcc7_list = dcc->next;
117
for (tmp = sess->dcc7_list; tmp != NULL; tmp = tmp->next) {
118
if (tmp->next == dcc) {
119
tmp->next = dcc->next;
130
* \internal Zwraca strukturę połączenia o danym identyfikatorze.
132
* \param sess Struktura sesji
133
* \param id Identyfikator połączenia
134
* \param uin Numer nadawcy lub odbiorcy
136
* \return Struktura połączenia lub \c NULL jeśli nie znaleziono
138
static struct gg_dcc7 *gg_dcc7_session_find(struct gg_session *sess, gg_dcc7_id_t id, uin_t uin)
143
gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_session_find(%p, ..., %d)\n", sess, (int) uin);
145
empty = !memcmp(&id, "\0\0\0\0\0\0\0\0", 8);
147
for (tmp = sess->dcc7_list; tmp; tmp = tmp->next) {
149
if (tmp->peer_uin == uin /*&& tmp->state != GG_STATE_WAITING_FOR_ACCEPT*/)
152
if (!memcmp(&tmp->cid, &id, sizeof(id)))
161
* \internal Rozpoczyna proces pobierania adresu
163
* \param dcc Struktura połączenia
165
* \return 0 jeśli się powiodło, -1 w przypadku błędu
167
static int gg_dcc7_get_relay_addr(struct gg_dcc7 *dcc)
169
gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_get_relay_addr(%p)\n", dcc);
171
if (dcc == NULL || dcc->sess == NULL) {
172
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_get_relay_addr() invalid parameters\n");
177
if (dcc->sess->resolver_start(&dcc->fd, &dcc->resolver, GG_RELAY_HOST) == -1) {
178
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_get_relay_addr() resolving failed (errno=%d, %s)\n", errno, strerror(errno));
182
dcc->state = GG_STATE_RESOLVING_RELAY;
183
dcc->check = GG_CHECK_READ;
184
dcc->timeout = GG_DEFAULT_TIMEOUT;
190
* \internal Nawiązuje połączenie bezpośrednie
192
* \param dcc Struktura połączenia
194
* \return 0 jeśli się powiodło, -1 w przypadku błędu
196
static int gg_dcc7_connect(struct gg_dcc7 *dcc)
198
gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_connect(%p)\n", dcc);
201
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_connect() invalid parameters\n");
206
if ((dcc->fd = gg_connect(&dcc->remote_addr, dcc->remote_port, 1)) == -1) {
207
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_connect() connection failed\n");
211
dcc->state = GG_STATE_CONNECTING;
212
dcc->check = GG_CHECK_WRITE;
213
dcc->timeout = GG_DCC7_TIMEOUT_CONNECT;
214
dcc->soft_timeout = 1;
220
* \internal Tworzy gniazdo nasłuchujące dla połączenia bezpośredniego
222
* \param dcc Struktura połączenia
223
* \param addr Preferowany adres (jeśli równy 0, nasłuchujemy na wszystkich interfejsach)
224
* \param port Preferowany port (jeśli równy 0, nasłuchujemy na losowym)
226
* \return 0 jeśli się powiodło, -1 w przypadku błędu
228
static int gg_dcc7_listen(struct gg_dcc7 *dcc, uint32_t addr, uint16_t port)
230
struct sockaddr_in sin;
231
socklen_t sin_len = sizeof(sin);
235
gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_listen(%p, %d)\n", dcc, port);
238
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() invalid parameters\n");
243
if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
244
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() can't create socket (%s)\n", strerror(errno));
248
memset(&sin, 0, sizeof(sin));
249
sin.sin_family = AF_INET;
250
sin.sin_addr.s_addr = addr;
251
sin.sin_port = htons(port);
253
if (bind(fd, (struct sockaddr*) &sin, sizeof(sin)) == -1) {
254
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() unable to bind to %s:%d\n", inet_ntoa(sin.sin_addr), port);
258
if (port == 0 && getsockname(fd, (struct sockaddr*) &sin, &sin_len) == -1) {
259
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() unable to bind to port %d\n", port);
264
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() unable to listen (%s)\n", strerror(errno));
269
dcc->local_addr = sin.sin_addr.s_addr;
270
dcc->local_port = ntohs(sin.sin_port);
272
dcc->state = GG_STATE_LISTENING;
273
dcc->check = GG_CHECK_READ;
274
dcc->timeout = GG_DCC7_TIMEOUT_FILE_ACK;
286
* \internal Tworzy gniazdo nasłuchujące i wysyła jego parametry
288
* \param dcc Struktura połączenia
290
* \return 0 jeśli się powiodło, -1 w przypadku błędu
292
static int gg_dcc7_listen_and_send_info(struct gg_dcc7 *dcc)
294
struct gg_dcc7_info pkt;
295
uint16_t external_port;
296
uint32_t external_addr;
299
gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_listen_and_send_info(%p)\n", dcc);
301
if (gg_dcc7_listen(dcc, dcc->sess->client_addr, dcc->sess->client_port) == -1)
304
if (dcc->sess->external_port != 0)
305
external_port = dcc->sess->external_port;
307
external_port = dcc->local_port;
309
if (dcc->sess->external_addr != 0)
310
external_addr = dcc->sess->external_addr;
312
external_addr = dcc->local_addr;
314
addr.s_addr = external_addr;
316
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);
318
memset(&pkt, 0, sizeof(pkt));
319
pkt.uin = gg_fix32(dcc->peer_uin);
320
pkt.type = GG_DCC7_TYPE_P2P;
322
snprintf((char*) pkt.info, sizeof(pkt.info), "%s %d", inet_ntoa(addr), external_port);
323
snprintf((char*) pkt.hash, sizeof(pkt.hash), "%u", external_addr + external_port * rand());
325
return gg_send_packet(dcc->sess, GG_DCC7_INFO, &pkt, sizeof(pkt), NULL);
329
* \internal Odwraca połączenie po nieudanym connect()
331
* \param dcc Struktura połączenia
333
* \return 0 jeśli się powiodło, -1 w przypadku błędu
335
static int gg_dcc7_reverse_connect(struct gg_dcc7 *dcc)
337
gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_reverse_connect(%p)\n", dcc);
340
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_reverse_connect() already reverse connection\n");
344
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_reverse_connect() timeout, trying reverse connection\n");
349
return gg_dcc7_listen_and_send_info(dcc);
353
* \internal Wysyła do serwera żądanie nadania identyfikatora sesji
355
* \param sess Struktura sesji
356
* \param type Rodzaj połączenia (\c GG_DCC7_TYPE_FILE lub \c GG_DCC7_TYPE_VOICE)
358
* \return 0 jeśli się powiodło, -1 w przypadku błędu
360
static int gg_dcc7_request_id(struct gg_session *sess, uint32_t type)
362
struct gg_dcc7_id_request pkt;
364
gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_request_id(%p, %d)\n", sess, type);
367
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_request_id() invalid parameters\n");
372
if (sess->state != GG_STATE_CONNECTED) {
373
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_request_id() not connected\n");
378
if (type != GG_DCC7_TYPE_VOICE && type != GG_DCC7_TYPE_FILE) {
379
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_request_id() invalid transfer type (%d)\n", type);
384
memset(&pkt, 0, sizeof(pkt));
385
pkt.type = gg_fix32(type);
387
return gg_send_packet(sess, GG_DCC7_ID_REQUEST, &pkt, sizeof(pkt), NULL);
391
* \internal Rozpoczyna wysyłanie pliku.
393
* Funkcja jest wykorzystywana przez \c gg_dcc7_send_file() oraz
394
* \c gg_dcc_send_file_fd().
396
* \param sess Struktura sesji
397
* \param rcpt Numer odbiorcy
398
* \param fd Deskryptor pliku
399
* \param size Rozmiar pliku
400
* \param filename1250 Nazwa pliku w kodowaniu CP-1250
401
* \param hash Skrót SHA-1 pliku
402
* \param seek Flaga mówiąca, czy można używać lseek()
404
* \return Struktura \c gg_dcc7 lub \c NULL w przypadku błędu
408
static struct gg_dcc7 *gg_dcc7_send_file_common(struct gg_session *sess, uin_t rcpt, int fd, size_t size, const char *filename1250, const char *hash, int seek)
410
struct gg_dcc7 *dcc = NULL;
412
if (!sess || !rcpt || !filename1250 || !hash || fd == -1) {
413
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_send_file_common() invalid parameters\n");
418
if (!(dcc = malloc(sizeof(struct gg_dcc7)))) {
419
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_send_file_common() not enough memory\n");
423
if (gg_dcc7_request_id(sess, GG_DCC7_TYPE_FILE) == -1)
426
memset(dcc, 0, sizeof(struct gg_dcc7));
427
dcc->type = GG_SESSION_DCC7_SEND;
428
dcc->dcc_type = GG_DCC7_TYPE_FILE;
429
dcc->state = GG_STATE_REQUESTING_ID;
430
dcc->timeout = GG_DEFAULT_TIMEOUT;
433
dcc->uin = sess->uin;
434
dcc->peer_uin = rcpt;
439
strncpy((char*) dcc->filename, filename1250, GG_DCC7_FILENAME_LEN - 1);
440
dcc->filename[GG_DCC7_FILENAME_LEN] = 0;
442
memcpy(dcc->hash, hash, GG_DCC7_HASH_LEN);
444
if (gg_dcc7_session_add(sess, dcc) == -1)
455
* Rozpoczyna wysyłanie pliku o danej nazwie.
457
* \param sess Struktura sesji
458
* \param rcpt Numer odbiorcy
459
* \param filename Nazwa pliku w lokalnym systemie plików
460
* \param filename1250 Nazwa pliku w kodowaniu CP-1250
461
* \param hash Skrót SHA-1 pliku (lub \c NULL jeśli ma być wyznaczony)
463
* \return Struktura \c gg_dcc7 lub \c NULL w przypadku błędu
467
struct gg_dcc7 *gg_dcc7_send_file(struct gg_session *sess, uin_t rcpt, const char *filename, const char *filename1250, const char *hash)
469
struct gg_dcc7 *dcc = NULL;
471
char hash_buf[GG_DCC7_HASH_LEN];
475
gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_send_file(%p, %d, \"%s\", %p)\n", sess, rcpt, filename, hash);
477
if (!sess || !rcpt || !filename) {
478
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_send_file() invalid parameters\n");
484
filename1250 = filename;
486
if (stat(filename, &st) == -1) {
487
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_send_file() stat() failed (%s)\n", strerror(errno));
491
if ((st.st_mode & S_IFDIR)) {
492
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_send_file() that's a directory\n");
497
if ((fd = open(filename, O_RDONLY)) == -1) {
498
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_send_file() open() failed (%s)\n", strerror(errno));
503
if (gg_file_hash_sha1(fd, (uint8_t*) hash_buf) == -1)
509
if ((tmp = strrchr(filename1250, '/')))
510
filename1250 = tmp + 1;
512
if (!(dcc = gg_dcc7_send_file_common(sess, rcpt, fd, st.st_size, filename1250, hash, 1)))
529
* \internal Rozpoczyna wysyłanie pliku o danym deskryptorze.
531
* \note Wysyłanie pliku nie będzie działać poprawnie, jeśli deskryptor
532
* źródłowy jest w trybie nieblokującym i w pewnym momencie zabraknie danych.
534
* \param sess Struktura sesji
535
* \param rcpt Numer odbiorcy
536
* \param fd Deskryptor pliku
537
* \param size Rozmiar pliku
538
* \param filename1250 Nazwa pliku w kodowaniu CP-1250
539
* \param hash Skrót SHA-1 pliku
541
* \return Struktura \c gg_dcc7 lub \c NULL w przypadku błędu
545
struct gg_dcc7 *gg_dcc7_send_file_fd(struct gg_session *sess, uin_t rcpt, int fd, size_t size, const char *filename1250, const char *hash)
547
gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_send_file_fd(%p, %d, %d, %u, \"%s\", %p)\n", sess, rcpt, fd, size, filename1250, hash);
549
return gg_dcc7_send_file_common(sess, rcpt, fd, size, filename1250, hash, 0);
554
* Potwierdza chęć odebrania pliku.
556
* \param dcc Struktura połączenia
557
* \param offset Początkowy offset przy wznawianiu przesyłania pliku
559
* \note Biblioteka nie zmienia położenia w odbieranych plikach. Jeśli offset
560
* początkowy jest różny od zera, należy ustawić go funkcją \c lseek() lub
563
* \return 0 jeśli się powiodło, -1 w przypadku błędu
567
int gg_dcc7_accept(struct gg_dcc7 *dcc, unsigned int offset)
569
struct gg_dcc7_accept pkt;
571
gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_accept(%p, %d)\n", dcc, offset);
573
if (!dcc || !dcc->sess) {
574
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_accept() invalid parameters\n");
579
memset(&pkt, 0, sizeof(pkt));
580
pkt.uin = gg_fix32(dcc->peer_uin);
582
pkt.offset = gg_fix32(offset);
584
if (gg_send_packet(dcc->sess, GG_DCC7_ACCEPT, &pkt, sizeof(pkt), NULL) == -1)
587
dcc->offset = offset;
589
return gg_dcc7_listen_and_send_info(dcc);
593
* Odrzuca próbę przesłania pliku.
595
* \param dcc Struktura połączenia
596
* \param reason Powód odrzucenia
598
* \return 0 jeśli się powiodło, -1 w przypadku błędu
602
int gg_dcc7_reject(struct gg_dcc7 *dcc, int reason)
604
struct gg_dcc7_reject pkt;
606
gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_reject(%p, %d)\n", dcc, reason);
608
if (!dcc || !dcc->sess) {
609
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_reject() invalid parameters\n");
614
memset(&pkt, 0, sizeof(pkt));
615
pkt.uin = gg_fix32(dcc->peer_uin);
617
pkt.reason = gg_fix32(reason);
619
return gg_send_packet(dcc->sess, GG_DCC7_REJECT, &pkt, sizeof(pkt), NULL);
623
* \internal Obsługuje pakiet identyfikatora połączenia bezpośredniego.
625
* \param sess Struktura sesji
626
* \param e Struktura zdarzenia
627
* \param payload Treść pakietu
628
* \param len Długość pakietu
630
* \return 0 jeśli się powiodło, -1 w przypadku błędu
632
int gg_dcc7_handle_id(struct gg_session *sess, struct gg_event *e, const void *payload, int len)
634
const struct gg_dcc7_id_reply *p = payload;
637
gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_handle_id(%p, %p, %p, %d)\n", sess, e, payload, len);
639
for (tmp = sess->dcc7_list; tmp; tmp = tmp->next) {
640
gg_debug_session(sess, GG_DEBUG_MISC, "// checking dcc %p, state %d, type %d\n", tmp, tmp->state, tmp->dcc_type);
642
if (tmp->state != GG_STATE_REQUESTING_ID || tmp->dcc_type != gg_fix32(p->type))
647
switch (tmp->dcc_type) {
648
case GG_DCC7_TYPE_FILE:
650
struct gg_dcc7_new s;
652
memset(&s, 0, sizeof(s));
654
s.type = gg_fix32(GG_DCC7_TYPE_FILE);
655
s.uin_from = gg_fix32(tmp->uin);
656
s.uin_to = gg_fix32(tmp->peer_uin);
657
s.size = gg_fix32(tmp->size);
659
memcpy((char*) s.filename, (char*) tmp->filename, GG_DCC7_FILENAME_LEN);
661
tmp->state = GG_STATE_WAITING_FOR_ACCEPT;
662
tmp->timeout = GG_DCC7_TIMEOUT_FILE_ACK;
664
return gg_send_packet(sess, GG_DCC7_NEW, &s, sizeof(s), NULL);
673
* \internal Obsługuje pakiet akceptacji połączenia bezpośredniego.
675
* \param sess Struktura sesji
676
* \param e Struktura zdarzenia
677
* \param payload Treść pakietu
678
* \param len Długość pakietu
680
* \return 0 jeśli się powiodło, -1 w przypadku błędu
682
int gg_dcc7_handle_accept(struct gg_session *sess, struct gg_event *e, const void *payload, int len)
684
const struct gg_dcc7_accept *p = payload;
687
gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_handle_accept(%p, %p, %p, %d)\n", sess, e, payload, len);
689
if (!(dcc = gg_dcc7_session_find(sess, p->id, gg_fix32(p->uin)))) {
690
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_accept() unknown dcc session\n");
691
// XXX wysłać reject?
692
e->type = GG_EVENT_DCC7_ERROR;
693
e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE;
697
if (dcc->state != GG_STATE_WAITING_FOR_ACCEPT) {
698
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_accept() invalid state\n");
699
e->type = GG_EVENT_DCC7_ERROR;
700
e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE;
704
// XXX czy dla odwrotnego połączenia powinniśmy wywołać już zdarzenie GG_DCC7_ACCEPT?
706
dcc->offset = gg_fix32(p->offset);
707
dcc->state = GG_STATE_WAITING_FOR_INFO;
713
* \internal Obsługuje pakiet informacji o połączeniu bezpośrednim.
715
* \param sess Struktura sesji
716
* \param e Struktura zdarzenia
717
* \param payload Treść pakietu
718
* \param len Długość pakietu
720
* \return 0 jeśli się powiodło, -1 w przypadku błędu
722
int gg_dcc7_handle_info(struct gg_session *sess, struct gg_event *e, const void *payload, int len)
724
const struct gg_dcc7_info *p = payload;
728
gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_handle_info(%p, %p, %p, %d)\n", sess, e, payload, len);
729
gg_debug_session(sess, GG_DEBUG_FUNCTION, "// gg_dcc7_handle_info() received address: %s, hash: %s\n", p->info, p->hash);
731
if (!(dcc = gg_dcc7_session_find(sess, p->id, gg_fix32(p->uin)))) {
732
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() unknown dcc session\n");
736
if (dcc->state == GG_STATE_CONNECTED) {
737
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() state is already connected\n");
743
case GG_DCC7_TYPE_P2P:
744
if ((dcc->remote_addr = inet_addr(p->info)) == INADDR_NONE) {
745
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() invalid IP address\n");
746
e->type = GG_EVENT_DCC7_ERROR;
747
e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE;
751
if (!(tmp = strchr(p->info, ' ')) || !(dcc->remote_port = atoi(tmp + 1))) {
752
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() invalid IP port\n");
753
e->type = GG_EVENT_DCC7_ERROR;
754
e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE;
758
if (dcc->state == GG_STATE_WAITING_FOR_INFO) {
759
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() waiting for info so send one\n");
760
gg_dcc7_listen_and_send_info(dcc);
761
e->type = GG_EVENT_DCC7_PENDING;
762
e->event.dcc7_pending.dcc7 = dcc;
768
case GG_DCC7_TYPE_SERVER:
769
if (!(tmp = strstr(p->info, "GG"))) {
770
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() unknown info packet\n");
771
e->type = GG_EVENT_DCC7_ERROR;
772
e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE;
776
#if defined(HAVE_UINT64_T) && defined(HAVE_STRTOULL)
780
cid = strtoull(tmp + 2, NULL, 0);
782
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() info.str=%s, info.id=%llu, sess.id=%llu\n", tmp + 2, cid, *((unsigned long long*) &dcc->cid));
786
if (memcmp(&dcc->cid, &cid, sizeof(cid)) != 0) {
787
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() invalid session id\n");
788
e->type = GG_EVENT_DCC7_ERROR;
789
e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE;
795
if (gg_dcc7_get_relay_addr(dcc) == -1) {
796
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_handle_info() unable to retrieve relay address\n");
797
e->type = GG_EVENT_DCC7_ERROR;
798
e->event.dcc7_error = GG_ERROR_DCC7_RELAY;
802
// XXX wysyłać dopiero jeśli uda się połączyć z serwerem?
804
gg_send_packet(dcc->sess, GG_DCC7_INFO, payload, len, NULL);
809
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() unhandled transfer type (%d)\n", p->type);
810
e->type = GG_EVENT_DCC7_ERROR;
811
e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE;
815
// jeśli nadal czekamy na połączenie przychodzące, a druga strona nie
816
// daje rady i oferuje namiary na siebie, bierzemy co dają.
818
// if (dcc->state != GG_STATE_WAITING_FOR_INFO && (dcc->state != GG_STATE_LISTENING || dcc->reverse)) {
819
// gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() invalid state\n");
820
// e->type = GG_EVENT_DCC7_ERROR;
821
// e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE;
825
if (dcc->state == GG_STATE_LISTENING) {
831
if (dcc->type == GG_SESSION_DCC7_SEND) {
832
e->type = GG_EVENT_DCC7_ACCEPT;
833
e->event.dcc7_accept.dcc7 = dcc;
834
e->event.dcc7_accept.type = gg_fix32(p->type);
835
e->event.dcc7_accept.remote_ip = dcc->remote_addr;
836
e->event.dcc7_accept.remote_port = dcc->remote_port;
838
e->type = GG_EVENT_DCC7_PENDING;
839
e->event.dcc7_pending.dcc7 = dcc;
842
if (gg_dcc7_connect(dcc) == -1) {
843
if (gg_dcc7_reverse_connect(dcc) == -1) {
844
e->type = GG_EVENT_DCC7_ERROR;
845
e->event.dcc7_error = GG_ERROR_DCC7_NET;
854
* \internal Obsługuje pakiet odrzucenia połączenia bezpośredniego.
856
* \param sess Struktura sesji
857
* \param e Struktura zdarzenia
858
* \param payload Treść pakietu
859
* \param len Długość pakietu
861
* \return 0 jeśli się powiodło, -1 w przypadku błędu
863
int gg_dcc7_handle_reject(struct gg_session *sess, struct gg_event *e, const void *payload, int len)
865
const struct gg_dcc7_reject *p = payload;
868
gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_handle_reject(%p, %p, %p, %d)\n", sess, e, payload, len);
870
if (!(dcc = gg_dcc7_session_find(sess, p->id, gg_fix32(p->uin)))) {
871
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_reject() unknown dcc session\n");
875
if (dcc->state != GG_STATE_WAITING_FOR_ACCEPT) {
876
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_reject() invalid state\n");
877
e->type = GG_EVENT_DCC7_ERROR;
878
e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE;
882
e->type = GG_EVENT_DCC7_REJECT;
883
e->event.dcc7_reject.dcc7 = dcc;
884
e->event.dcc7_reject.reason = gg_fix32(p->reason);
886
// XXX ustawić state na rejected?
892
* \internal Obsługuje pakiet nowego połączenia bezpośredniego.
894
* \param sess Struktura sesji
895
* \param e Struktura zdarzenia
896
* \param payload Treść pakietu
897
* \param len Długość pakietu
899
* \return 0 jeśli się powiodło, -1 w przypadku błędu
901
int gg_dcc7_handle_new(struct gg_session *sess, struct gg_event *e, const void *payload, int len)
903
const struct gg_dcc7_new *p = payload;
906
gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_handle_new(%p, %p, %p, %d)\n", sess, e, payload, len);
908
switch (gg_fix32(p->type)) {
909
case GG_DCC7_TYPE_FILE:
910
if (!(dcc = malloc(sizeof(struct gg_dcc7)))) {
911
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_new() not enough memory\n");
915
memset(dcc, 0, sizeof(struct gg_dcc7));
916
dcc->type = GG_SESSION_DCC7_GET;
917
dcc->dcc_type = GG_DCC7_TYPE_FILE;
920
dcc->uin = sess->uin;
921
dcc->peer_uin = gg_fix32(p->uin_from);
925
if (gg_dcc7_session_add(sess, dcc) == -1) {
926
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_new() unable to add to session\n");
931
dcc->size = gg_fix32(p->size);
932
strncpy((char*) dcc->filename, (char*) p->filename, GG_DCC7_FILENAME_LEN - 1);
933
dcc->filename[GG_DCC7_FILENAME_LEN] = 0;
934
memcpy(dcc->hash, p->hash, GG_DCC7_HASH_LEN);
936
e->type = GG_EVENT_DCC7_NEW;
937
e->event.dcc7_new = dcc;
941
case GG_DCC7_TYPE_VOICE:
942
if (!(dcc = malloc(sizeof(struct gg_dcc7)))) {
943
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_packet() not enough memory\n");
947
memset(dcc, 0, sizeof(struct gg_dcc7));
949
dcc->type = GG_SESSION_DCC7_VOICE;
950
dcc->dcc_type = GG_DCC7_TYPE_VOICE;
953
dcc->uin = sess->uin;
954
dcc->peer_uin = gg_fix32(p->uin_from);
958
if (gg_dcc7_session_add(sess, dcc) == -1) {
959
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_new() unable to add to session\n");
964
e->type = GG_EVENT_DCC7_NEW;
965
e->event.dcc7_new = dcc;
970
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_new() unknown dcc type (%d) from %ld\n", gg_fix32(p->type), gg_fix32(p->uin_from));
979
* \internal Ustawia odpowiednie stany wewnętrzne w zależności od rodzaju
982
* \param dcc Struktura połączenia
984
* \return 0 jeśli się powiodło, -1 w przypadku błędu.
986
static int gg_dcc7_postauth_fixup(struct gg_dcc7 *dcc)
988
gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_postauth_fixup(%p)\n", dcc);
991
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_postauth_fixup() invalid parameters\n");
997
case GG_SESSION_DCC7_GET:
998
dcc->state = GG_STATE_GETTING_FILE;
999
dcc->check = GG_CHECK_READ;
1002
case GG_SESSION_DCC7_SEND:
1003
dcc->state = GG_STATE_SENDING_FILE;
1004
dcc->check = GG_CHECK_WRITE;
1007
case GG_SESSION_DCC7_VOICE:
1008
dcc->state = GG_STATE_READING_VOICE_DATA;
1009
dcc->check = GG_CHECK_READ;
1019
* Funkcja wywoływana po zaobserwowaniu zmian na deskryptorze połączenia.
1021
* Funkcja zwraca strukturę zdarzenia \c gg_event. Jeśli rodzaj zdarzenia
1022
* to \c GG_EVENT_NONE, nie wydarzyło się jeszcze nic wartego odnotowania.
1023
* Strukturę zdarzenia należy zwolnić funkcja \c gg_event_free().
1025
* \param dcc Struktura połączenia
1027
* \return Struktura zdarzenia lub \c NULL jeśli wystąpił błąd
1031
struct gg_event *gg_dcc7_watch_fd(struct gg_dcc7 *dcc)
1035
gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_watch_fd(%p)\n", dcc);
1037
if (!dcc || (dcc->type != GG_SESSION_DCC7_SEND && dcc->type != GG_SESSION_DCC7_GET && dcc->type != GG_SESSION_DCC7_VOICE)) {
1038
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() invalid parameters\n");
1043
if (!(e = malloc(sizeof(struct gg_event)))) {
1044
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() not enough memory\n");
1048
memset(e, 0, sizeof(struct gg_event));
1049
e->type = GG_EVENT_NONE;
1051
switch (dcc->state) {
1052
case GG_STATE_LISTENING:
1054
struct sockaddr_in sin;
1056
socklen_t sin_len = sizeof(sin);
1058
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_LISTENING\n");
1060
if ((fd = accept(dcc->fd, (struct sockaddr*) &sin, &sin_len)) == -1) {
1061
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() accept() failed (%s)\n", strerror(errno));
1065
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() connection from %s:%d\n", inet_ntoa(sin.sin_addr), htons(sin.sin_port));
1068
if (ioctl(fd, FIONBIO, &one) == -1) {
1070
if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
1072
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() can't set nonblocking (%s)\n", strerror(errno));
1074
e->type = GG_EVENT_DCC7_ERROR;
1075
e->event.dcc_error = GG_ERROR_DCC7_HANDSHAKE;
1082
dcc->state = GG_STATE_READING_ID;
1083
dcc->check = GG_CHECK_READ;
1084
dcc->timeout = GG_DEFAULT_TIMEOUT;
1087
dcc->remote_port = ntohs(sin.sin_port);
1088
dcc->remote_addr = sin.sin_addr.s_addr;
1090
e->type = GG_EVENT_DCC7_CONNECTED;
1091
e->event.dcc7_connected.dcc7 = dcc;
1096
case GG_STATE_CONNECTING:
1098
int res = 0, error = 0;
1099
unsigned int error_size = sizeof(error);
1101
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_CONNECTING\n");
1103
dcc->soft_timeout = 0;
1105
if (dcc->timeout == 0)
1108
if (error || (res = getsockopt(dcc->fd, SOL_SOCKET, SO_ERROR, &error, &error_size)) == -1 || error != 0) {
1109
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() connection failed (%s)\n", (res == -1) ? strerror(errno) : strerror(error));
1112
for (dcc->relay_index++; dcc->relay_index < dcc->relay_count; dcc->relay_index++) {
1113
dcc->remote_addr = dcc->relay_list[dcc->relay_index].addr;
1114
dcc->remote_port = dcc->relay_list[dcc->relay_index].port;
1116
if (gg_dcc7_connect(dcc) == 0)
1120
if (dcc->relay_index >= dcc->relay_count) {
1121
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() no relay available");
1122
e->type = GG_EVENT_DCC7_ERROR;
1123
e->event.dcc_error = GG_ERROR_DCC7_RELAY;
1127
if (gg_dcc7_reverse_connect(dcc) != -1) {
1128
e->type = GG_EVENT_DCC7_PENDING;
1129
e->event.dcc7_pending.dcc7 = dcc;
1131
e->type = GG_EVENT_DCC7_ERROR;
1132
e->event.dcc_error = GG_ERROR_DCC7_NET;
1139
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() connected, sending id\n");
1141
dcc->state = GG_STATE_SENDING_ID;
1142
dcc->check = GG_CHECK_WRITE;
1143
dcc->timeout = GG_DEFAULT_TIMEOUT;
1149
case GG_STATE_READING_ID:
1153
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_READING_ID\n");
1156
struct gg_dcc7_welcome_p2p welcome, welcome_ok;
1157
welcome_ok.id = dcc->cid;
1159
if ((res = read(dcc->fd, &welcome, sizeof(welcome))) != sizeof(welcome)) {
1160
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() read() failed (%d, %s)\n", res, strerror(errno));
1161
e->type = GG_EVENT_DCC7_ERROR;
1162
e->event.dcc_error = GG_ERROR_DCC7_HANDSHAKE;
1166
if (memcmp(&welcome, &welcome_ok, sizeof(welcome))) {
1167
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() invalid id\n");
1168
e->type = GG_EVENT_DCC7_ERROR;
1169
e->event.dcc_error = GG_ERROR_DCC7_HANDSHAKE;
1173
struct gg_dcc7_welcome_server welcome, welcome_ok;
1174
welcome_ok.magic = GG_DCC7_WELCOME_SERVER;
1175
welcome_ok.id = dcc->cid;
1177
if ((res = read(dcc->fd, &welcome, sizeof(welcome))) != sizeof(welcome)) {
1178
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() read() failed (%d, %s)\n", res, strerror(errno));
1179
e->type = GG_EVENT_DCC7_ERROR;
1180
e->event.dcc_error = GG_ERROR_DCC7_HANDSHAKE;
1184
if (memcmp(&welcome, &welcome_ok, sizeof(welcome)) != 0) {
1185
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() invalid id\n");
1186
e->type = GG_EVENT_DCC7_ERROR;
1187
e->event.dcc_error = GG_ERROR_DCC7_HANDSHAKE;
1192
if (dcc->incoming) {
1193
dcc->state = GG_STATE_SENDING_ID;
1194
dcc->check = GG_CHECK_WRITE;
1195
dcc->timeout = GG_DEFAULT_TIMEOUT;
1197
gg_dcc7_postauth_fixup(dcc);
1198
dcc->timeout = GG_DEFAULT_TIMEOUT;
1204
case GG_STATE_SENDING_ID:
1208
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_SENDING_ID\n");
1211
struct gg_dcc7_welcome_p2p welcome;
1213
welcome.id = dcc->cid;
1215
if ((res = write(dcc->fd, &welcome, sizeof(welcome))) != sizeof(welcome)) {
1216
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() write() failed (%d, %s)\n", res, strerror(errno));
1217
e->type = GG_EVENT_DCC7_ERROR;
1218
e->event.dcc_error = GG_ERROR_DCC7_HANDSHAKE;
1222
struct gg_dcc7_welcome_server welcome;
1224
welcome.magic = gg_fix32(GG_DCC7_WELCOME_SERVER);
1225
welcome.id = dcc->cid;
1227
if ((res = write(dcc->fd, &welcome, sizeof(welcome))) != sizeof(welcome)) {
1228
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() write() failed (%d, %s)\n", res, strerror(errno));
1229
e->type = GG_EVENT_DCC7_ERROR;
1230
e->event.dcc_error = GG_ERROR_DCC7_HANDSHAKE;
1235
if (dcc->incoming) {
1236
gg_dcc7_postauth_fixup(dcc);
1237
dcc->timeout = GG_DEFAULT_TIMEOUT;
1239
dcc->state = GG_STATE_READING_ID;
1240
dcc->check = GG_CHECK_READ;
1241
dcc->timeout = GG_DEFAULT_TIMEOUT;
1247
case GG_STATE_SENDING_FILE:
1252
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_SENDING_FILE (offset=%d, size=%d)\n", dcc->offset, dcc->size);
1254
if (dcc->offset >= dcc->size) {
1255
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() offset >= size, finished\n");
1256
e->type = GG_EVENT_DCC7_DONE;
1257
e->event.dcc7_done.dcc7 = dcc;
1261
if (dcc->seek && lseek(dcc->file_fd, dcc->offset, SEEK_SET) == (off_t) -1) {
1262
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() lseek() failed (%s)\n", strerror(errno));
1263
e->type = GG_EVENT_DCC7_ERROR;
1264
e->event.dcc_error = GG_ERROR_DCC7_FILE;
1268
if ((chunk = dcc->size - dcc->offset) > sizeof(buf))
1269
chunk = sizeof(buf);
1271
if ((res = read(dcc->file_fd, buf, chunk)) < 1) {
1272
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() read() failed (res=%d, %s)\n", res, strerror(errno));
1273
e->type = GG_EVENT_DCC7_ERROR;
1274
e->event.dcc_error = (res == -1) ? GG_ERROR_DCC7_FILE : GG_ERROR_DCC7_EOF;
1278
if ((res = write(dcc->fd, buf, res)) == -1) {
1279
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() write() failed (%s)\n", strerror(errno));
1280
e->type = GG_EVENT_DCC7_ERROR;
1281
e->event.dcc_error = GG_ERROR_DCC7_NET;
1287
if (dcc->offset >= dcc->size) {
1288
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() finished\n");
1289
e->type = GG_EVENT_DCC7_DONE;
1290
e->event.dcc7_done.dcc7 = dcc;
1294
dcc->state = GG_STATE_SENDING_FILE;
1295
dcc->check = GG_CHECK_WRITE;
1296
dcc->timeout = GG_DCC7_TIMEOUT_SEND;
1301
case GG_STATE_GETTING_FILE:
1306
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_GETTING_FILE (offset=%d, size=%d)\n", dcc->offset, dcc->size);
1308
if (dcc->offset >= dcc->size) {
1309
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() finished\n");
1310
e->type = GG_EVENT_DCC7_DONE;
1311
e->event.dcc7_done.dcc7 = dcc;
1315
if ((res = read(dcc->fd, buf, sizeof(buf))) < 1) {
1316
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() read() failed (fd=%d, res=%d, %s)\n", dcc->fd, res, strerror(errno));
1317
e->type = GG_EVENT_DCC7_ERROR;
1318
e->event.dcc_error = (res == -1) ? GG_ERROR_DCC7_NET : GG_ERROR_DCC7_EOF;
1322
// XXX zapisywać do skutku?
1324
if ((wres = write(dcc->file_fd, buf, res)) < res) {
1325
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() write() failed (fd=%d, res=%d, %s)\n", dcc->file_fd, wres, strerror(errno));
1326
e->type = GG_EVENT_DCC7_ERROR;
1327
e->event.dcc_error = GG_ERROR_DCC7_FILE;
1333
if (dcc->offset >= dcc->size) {
1334
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() finished\n");
1335
e->type = GG_EVENT_DCC7_DONE;
1336
e->event.dcc7_done.dcc7 = dcc;
1340
dcc->state = GG_STATE_GETTING_FILE;
1341
dcc->check = GG_CHECK_READ;
1342
dcc->timeout = GG_DCC7_TIMEOUT_GET;
1347
case GG_STATE_RESOLVING_RELAY:
1349
struct in_addr addr;
1351
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_RESOLVING_RELAY\n");
1353
if (read(dcc->fd, &addr, sizeof(addr)) < sizeof(addr) || addr.s_addr == INADDR_NONE) {
1354
int errno_save = errno;
1356
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() resolving failed\n");
1359
dcc->sess->resolver_cleanup(&dcc->resolver, 0);
1361
e->type = GG_EVENT_DCC7_ERROR;
1362
e->event.dcc_error = GG_ERROR_DCC7_RELAY;
1366
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() resolved, connecting to %s:%d\n", inet_ntoa(addr), GG_RELAY_PORT);
1368
if ((dcc->fd = gg_connect(&addr, GG_RELAY_PORT, 1)) == -1) {
1369
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() connection failed (errno=%d, %s), critical\n", errno, strerror(errno));
1370
e->type = GG_EVENT_DCC7_ERROR;
1371
e->event.dcc_error = GG_ERROR_DCC7_RELAY;
1375
dcc->state = GG_STATE_CONNECTING_RELAY;
1376
dcc->check = GG_CHECK_WRITE;
1377
dcc->timeout = GG_DEFAULT_TIMEOUT;
1379
e->type = GG_EVENT_DCC7_PENDING;
1380
e->event.dcc7_pending.dcc7 = dcc;
1385
case GG_STATE_CONNECTING_RELAY:
1388
unsigned int res_size = sizeof(res);
1389
struct gg_dcc7_relay_req pkt;
1391
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_CONNECTING_RELAY\n");
1393
if (getsockopt(dcc->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) != 0 || res != 0) {
1394
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() connection failed (errno=%d, %s)\n", res, strerror(res));
1395
e->type = GG_EVENT_DCC7_ERROR;
1396
e->event.dcc_error = GG_ERROR_DCC7_RELAY;
1400
memset(&pkt, 0, sizeof(pkt));
1401
pkt.magic = gg_fix32(GG_DCC7_RELAY_REQUEST);
1402
pkt.len = gg_fix32(sizeof(pkt));
1404
pkt.type = gg_fix16(GG_DCC7_RELAY_TYPE_SERVER);
1405
pkt.dunno1 = gg_fix16(GG_DCC7_RELAY_DUNNO1);
1407
gg_debug_dcc(dcc, GG_DEBUG_DUMP, "// gg_dcc7_watch_fd() send pkt(0x%.2x)\n", gg_fix32(pkt.magic));
1408
gg_debug_dump_dcc(dcc, GG_DEBUG_DUMP, (const char*) &pkt, sizeof(pkt));
1410
if ((res = write(dcc->fd, &pkt, sizeof(pkt))) != sizeof(pkt)) {
1411
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() sending failed\n");
1412
e->type = GG_EVENT_DCC7_ERROR;
1413
e->event.dcc_error = GG_ERROR_DCC7_RELAY;
1417
dcc->state = GG_STATE_READING_RELAY;
1418
dcc->check = GG_CHECK_READ;
1419
dcc->timeout = GG_DEFAULT_TIMEOUT;
1424
case GG_STATE_READING_RELAY:
1427
struct gg_dcc7_relay_reply *pkt;
1428
struct gg_dcc7_relay_reply_server srv;
1432
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_READING_RELAY\n");
1434
if ((res = read(dcc->fd, buf, sizeof(buf))) < sizeof(*pkt)) {
1437
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() read() failed (%d, %s)\n", res, strerror(errno));
1438
e->type = GG_EVENT_DCC7_ERROR;
1439
e->event.dcc_error = GG_ERROR_DCC7_RELAY;
1443
pkt = (struct gg_dcc7_relay_reply*) buf;
1445
if (gg_fix32(pkt->magic) != GG_DCC7_RELAY_REPLY || gg_fix32(pkt->rcount) < 1 || gg_fix32(pkt->rcount > 256) || gg_fix32(pkt->len) < sizeof(*pkt) + gg_fix32(pkt->rcount) * sizeof(srv)) {
1446
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_wathc_fd() invalid reply\n");
1448
e->type = GG_EVENT_DCC7_ERROR;
1449
e->event.dcc_error = GG_ERROR_DCC7_RELAY;
1453
gg_debug_dcc(dcc, GG_DEBUG_DUMP, "// gg_dcc7_get_relay() read pkt(0x%.2x)\n", gg_fix32(pkt->magic));
1454
gg_debug_dump_dcc(dcc, GG_DEBUG_DUMP, buf, res);
1456
free(dcc->relay_list);
1458
dcc->relay_index = 0;
1459
dcc->relay_count = gg_fix32(pkt->rcount);
1460
dcc->relay_list = malloc(dcc->relay_count * sizeof(gg_dcc7_relay_t));
1462
if (dcc->relay_list == NULL) {
1463
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() not enough memory");
1464
dcc->relay_count = 0;
1469
for (i = 0; i < dcc->relay_count; i++) {
1470
struct in_addr addr;
1472
memcpy(&srv, buf + sizeof(*pkt) + i * sizeof(srv), sizeof(srv));
1473
dcc->relay_list[i].addr = srv.addr;
1474
dcc->relay_list[i].port = gg_fix16(srv.port);
1475
dcc->relay_list[i].family = srv.family;
1477
addr.s_addr = srv.addr;
1478
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// %s %d %d\n", inet_ntoa(addr), gg_fix16(srv.port), srv.family);
1483
for (; dcc->relay_index < dcc->relay_count; dcc->relay_index++) {
1484
dcc->remote_addr = dcc->relay_list[dcc->relay_index].addr;
1485
dcc->remote_port = dcc->relay_list[dcc->relay_index].port;
1487
if (gg_dcc7_connect(dcc) == 0)
1491
if (dcc->relay_index >= dcc->relay_count) {
1492
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() no relay available");
1493
e->type = GG_EVENT_DCC7_ERROR;
1494
e->event.dcc_error = GG_ERROR_DCC7_RELAY;
1503
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_???\n");
1504
e->type = GG_EVENT_DCC7_ERROR;
1505
e->event.dcc_error = GG_ERROR_DCC7_HANDSHAKE;
1515
* Zwalnia zasoby używane przez połączenie bezpośrednie.
1517
* \param dcc Struktura połączenia
1521
void gg_dcc7_free(struct gg_dcc7 *dcc)
1523
gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_free(%p)\n", dcc);
1531
if (dcc->file_fd != -1)
1532
close(dcc->file_fd);
1535
gg_dcc7_session_remove(dcc->sess, dcc);
1537
free(dcc->relay_list);