src/protocols/gg/lib/events.c

changeset 14253
b63ebf84c42b
parent 14252
d10dda2777a9
child 14254
77edc7a6191a
equal deleted inserted replaced
14252:d10dda2777a9 14253:b63ebf84c42b
1 /* $Id: events.c 14520 2005-11-25 00:32:45Z rlaager $ */
2
3 /*
4 * (C) Copyright 2001-2003 Wojtek Kaniewski <wojtekka@irc.pl>
5 * Robert J. Woźny <speedy@ziew.org>
6 * Arkadiusz Miśkiewicz <arekm@pld-linux.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License Version
10 * 2.1 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
20 * USA.
21 */
22
23 #include <sys/types.h>
24 #ifndef _WIN32
25 #include <sys/wait.h>
26 #include <sys/ioctl.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
30 #endif
31
32 #include "libgadu-config.h"
33
34 #include <errno.h>
35 #ifdef __GG_LIBGADU_HAVE_PTHREAD
36 # include <pthread.h>
37 #endif
38 #include <stdio.h>
39 #include <string.h>
40 #include <stdlib.h>
41 #include <time.h>
42 #include <unistd.h>
43 #ifdef __GG_LIBGADU_HAVE_OPENSSL
44 # include <openssl/err.h>
45 # include <openssl/x509.h>
46 #endif
47
48 #include "compat.h"
49 #include "libgadu.h"
50
51 /*
52 * gg_event_free()
53 *
54 * zwalnia pamięć zajmowaną przez informację o zdarzeniu.
55 *
56 * - e - wskaźnik do informacji o zdarzeniu
57 */
58 void gg_event_free(struct gg_event *e)
59 {
60 gg_debug(GG_DEBUG_FUNCTION, "** gg_event_free(%p);\n", e);
61
62 if (!e)
63 return;
64
65 switch (e->type) {
66 case GG_EVENT_MSG:
67 free(e->event.msg.message);
68 free(e->event.msg.formats);
69 free(e->event.msg.recipients);
70 break;
71
72 case GG_EVENT_NOTIFY:
73 free(e->event.notify);
74 break;
75
76 case GG_EVENT_NOTIFY60:
77 {
78 int i;
79
80 for (i = 0; e->event.notify60[i].uin; i++)
81 free(e->event.notify60[i].descr);
82
83 free(e->event.notify60);
84
85 break;
86 }
87
88 case GG_EVENT_STATUS60:
89 free(e->event.status60.descr);
90 break;
91
92 case GG_EVENT_STATUS:
93 free(e->event.status.descr);
94 break;
95
96 case GG_EVENT_NOTIFY_DESCR:
97 free(e->event.notify_descr.notify);
98 free(e->event.notify_descr.descr);
99 break;
100
101 case GG_EVENT_DCC_VOICE_DATA:
102 free(e->event.dcc_voice_data.data);
103 break;
104
105 case GG_EVENT_PUBDIR50_SEARCH_REPLY:
106 case GG_EVENT_PUBDIR50_READ:
107 case GG_EVENT_PUBDIR50_WRITE:
108 gg_pubdir50_free(e->event.pubdir50);
109 break;
110
111 case GG_EVENT_USERLIST:
112 free(e->event.userlist.reply);
113 break;
114
115 case GG_EVENT_IMAGE_REPLY:
116 free(e->event.image_reply.filename);
117 free(e->event.image_reply.image);
118 break;
119 }
120
121 free(e);
122 }
123
124 /*
125 * gg_image_queue_remove()
126 *
127 * usuwa z kolejki dany wpis.
128 *
129 * - s - sesja
130 * - q - kolejka
131 * - freeq - czy zwolnić kolejkę
132 *
133 * 0/-1
134 */
135 int gg_image_queue_remove(struct gg_session *s, struct gg_image_queue *q, int freeq)
136 {
137 if (!s || !q) {
138 errno = EFAULT;
139 return -1;
140 }
141
142 if (s->images == q)
143 s->images = q->next;
144 else {
145 struct gg_image_queue *qq;
146
147 for (qq = s->images; qq; qq = qq->next) {
148 if (qq->next == q) {
149 qq->next = q->next;
150 break;
151 }
152 }
153 }
154
155 if (freeq) {
156 free(q->image);
157 free(q->filename);
158 free(q);
159 }
160
161 return 0;
162 }
163
164 /*
165 * gg_image_queue_parse() // funkcja wewnętrzna
166 *
167 * parsuje przychodzący pakiet z obrazkiem.
168 *
169 * - e - opis zdarzenia
170 * -
171 */
172 static void gg_image_queue_parse(struct gg_event *e, char *p, unsigned int len, struct gg_session *sess, uin_t sender)
173 {
174 struct gg_msg_image_reply *i = (void*) p;
175 struct gg_image_queue *q, *qq;
176
177 if (!p || !sess || !e) {
178 errno = EFAULT;
179 return;
180 }
181
182 /* znajdź dany obrazek w kolejce danej sesji */
183
184 for (qq = sess->images, q = NULL; qq; qq = qq->next) {
185 if (sender == qq->sender && i->size == qq->size && i->crc32 == qq->crc32) {
186 q = qq;
187 break;
188 }
189 }
190
191 if (!q) {
192 gg_debug(GG_DEBUG_MISC, "// gg_image_queue_parse() unknown image from %d, size=%d, crc32=%.8x\n", sender, i->size, i->crc32);
193 return;
194 }
195
196 if (p[0] == 0x05) {
197 unsigned int i, ok = 0;
198
199 q->done = 0;
200
201 len -= sizeof(struct gg_msg_image_reply);
202 p += sizeof(struct gg_msg_image_reply);
203
204 /* sprawdź, czy mamy tekst zakończony \0 */
205
206 for (i = 0; i < len; i++) {
207 if (!p[i]) {
208 ok = 1;
209 break;
210 }
211 }
212
213 if (!ok) {
214 gg_debug(GG_DEBUG_MISC, "// gg_image_queue_parse() malformed packet from %d, unlimited filename\n", sender);
215 return;
216 }
217
218 if (!(q->filename = strdup(p))) {
219 gg_debug(GG_DEBUG_MISC, "// gg_image_queue_parse() not enough memory for filename\n");
220 return;
221 }
222
223 len -= strlen(p) + 1;
224 p += strlen(p) + 1;
225 } else {
226 len -= sizeof(struct gg_msg_image_reply);
227 p += sizeof(struct gg_msg_image_reply);
228 }
229
230 if (q->done + len > q->size)
231 len = q->size - q->done;
232
233 memcpy(q->image + q->done, p, len);
234 q->done += len;
235
236 /* jeśli skończono odbierać obrazek, wygeneruj zdarzenie */
237
238 if (q->done >= q->size) {
239 e->type = GG_EVENT_IMAGE_REPLY;
240 e->event.image_reply.sender = sender;
241 e->event.image_reply.size = q->size;
242 e->event.image_reply.crc32 = q->crc32;
243 e->event.image_reply.filename = q->filename;
244 e->event.image_reply.image = q->image;
245
246 gg_image_queue_remove(sess, q, 0);
247
248 free(q);
249 }
250 }
251
252 /*
253 * gg_handle_recv_msg() // funkcja wewnętrzna
254 *
255 * obsługuje pakiet z przychodzącą wiadomością, rozbijając go na dodatkowe
256 * struktury (konferencje, kolorki) w razie potrzeby.
257 *
258 * - h - nagłówek pakietu
259 * - e - opis zdarzenia
260 *
261 * 0, -1.
262 */
263 static int gg_handle_recv_msg(struct gg_header *h, struct gg_event *e, struct gg_session *sess)
264 {
265 struct gg_recv_msg *r = (struct gg_recv_msg*) ((char*) h + sizeof(struct gg_header));
266 char *p, *packet_end = (char*) r + h->length;
267
268 gg_debug(GG_DEBUG_FUNCTION, "** gg_handle_recv_msg(%p, %p);\n", h, e);
269
270 if (!r->seq && !r->msgclass) {
271 gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() oops, silently ignoring the bait\n");
272 e->type = GG_EVENT_NONE;
273 return 0;
274 }
275
276 for (p = (char*) r + sizeof(*r); *p; p++) {
277 if (*p == 0x02 && p == packet_end - 1) {
278 gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() received ctcp packet\n");
279 break;
280 }
281 if (p >= packet_end) {
282 gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() malformed packet, message out of bounds (0)\n");
283 goto malformed;
284 }
285 }
286
287 p++;
288
289 /* przeanalizuj dodatkowe opcje */
290 while (p < packet_end) {
291 switch (*p) {
292 case 0x01: /* konferencja */
293 {
294 struct gg_msg_recipients *m = (void*) p;
295 uint32_t i, count;
296
297 p += sizeof(*m);
298
299 if (p > packet_end) {
300 gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (1)\n");
301 goto malformed;
302 }
303
304 count = gg_fix32(m->count);
305
306 if (p + count * sizeof(uin_t) > packet_end || p + count * sizeof(uin_t) < p || count > 0xffff) {
307 gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (1.5)\n");
308 goto malformed;
309 }
310
311 if (!(e->event.msg.recipients = (void*) malloc(count * sizeof(uin_t)))) {
312 gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() not enough memory for recipients data\n");
313 goto fail;
314 }
315
316 for (i = 0; i < count; i++, p += sizeof(uint32_t)) {
317 uint32_t u;
318 memcpy(&u, p, sizeof(uint32_t));
319 e->event.msg.recipients[i] = gg_fix32(u);
320 }
321
322 e->event.msg.recipients_count = count;
323
324 break;
325 }
326
327 case 0x02: /* richtext */
328 {
329 uint16_t len;
330 char *buf;
331
332 if (p + 3 > packet_end) {
333 gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (2)\n");
334 goto malformed;
335 }
336
337 memcpy(&len, p + 1, sizeof(uint16_t));
338 len = gg_fix16(len);
339
340 if (!(buf = malloc(len))) {
341 gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() not enough memory for richtext data\n");
342 goto fail;
343 }
344
345 p += 3;
346
347 if (p + len > packet_end) {
348 gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (3)\n");
349 free(buf);
350 goto malformed;
351 }
352
353 memcpy(buf, p, len);
354
355 e->event.msg.formats = buf;
356 e->event.msg.formats_length = len;
357
358 p += len;
359
360 break;
361 }
362
363 case 0x04: /* image_request */
364 {
365 struct gg_msg_image_request *i = (void*) p;
366
367 if (p + sizeof(*i) > packet_end) {
368 gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (3)\n");
369 goto malformed;
370 }
371
372 e->event.image_request.sender = gg_fix32(r->sender);
373 e->event.image_request.size = gg_fix32(i->size);
374 e->event.image_request.crc32 = gg_fix32(i->crc32);
375
376 e->type = GG_EVENT_IMAGE_REQUEST;
377
378 return 0;
379 }
380
381 case 0x05: /* image_reply */
382 case 0x06:
383 {
384 struct gg_msg_image_reply *rep = (void*) p;
385
386 if (p + sizeof(struct gg_msg_image_reply) == packet_end) {
387
388 /* pusta odpowiedź - klient po drugiej stronie nie ma żądanego obrazka */
389
390 e->type = GG_EVENT_IMAGE_REPLY;
391 e->event.image_reply.sender = gg_fix32(r->sender);
392 e->event.image_reply.size = 0;
393 e->event.image_reply.crc32 = gg_fix32(rep->crc32);
394 e->event.image_reply.filename = NULL;
395 e->event.image_reply.image = NULL;
396 return 0;
397
398 } else if (p + sizeof(struct gg_msg_image_reply) + 1 > packet_end) {
399
400 gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (4)\n");
401 goto malformed;
402 }
403
404 rep->size = gg_fix32(rep->size);
405 rep->crc32 = gg_fix32(rep->crc32);
406 gg_image_queue_parse(e, p, (unsigned int)(packet_end - p), sess, gg_fix32(r->sender));
407
408 return 0;
409 }
410
411 default:
412 {
413 gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() unknown payload 0x%.2x\n", *p);
414 p = packet_end;
415 }
416 }
417 }
418
419 e->type = GG_EVENT_MSG;
420 e->event.msg.msgclass = gg_fix32(r->msgclass);
421 e->event.msg.sender = gg_fix32(r->sender);
422 e->event.msg.time = gg_fix32(r->time);
423 e->event.msg.message = (unsigned char *)strdup((char*) r + sizeof(*r));
424
425 return 0;
426
427 malformed:
428 e->type = GG_EVENT_NONE;
429
430 free(e->event.msg.recipients);
431 free(e->event.msg.formats);
432
433 return 0;
434
435 fail:
436 free(e->event.msg.recipients);
437 free(e->event.msg.formats);
438 return -1;
439 }
440
441 /*
442 * gg_watch_fd_connected() // funkcja wewnętrzna
443 *
444 * patrzy na gniazdo, odbiera pakiet i wypełnia strukturę zdarzenia.
445 *
446 * - sess - struktura opisująca sesję
447 * - e - opis zdarzenia
448 *
449 * 0, -1.
450 */
451 static int gg_watch_fd_connected(struct gg_session *sess, struct gg_event *e)
452 {
453 struct gg_header *h = NULL;
454 char *p;
455
456 gg_debug(GG_DEBUG_FUNCTION, "** gg_watch_fd_connected(%p, %p);\n", sess, e);
457
458 if (!sess) {
459 errno = EFAULT;
460 return -1;
461 }
462
463 if (!(h = gg_recv_packet(sess))) {
464 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() gg_recv_packet failed (errno=%d, %s)\n", errno, strerror(errno));
465 goto fail;
466 }
467
468 p = (char*) h + sizeof(struct gg_header);
469
470 switch (h->type) {
471 case GG_RECV_MSG:
472 {
473 if (h->length >= sizeof(struct gg_recv_msg))
474 if (gg_handle_recv_msg(h, e, sess))
475 goto fail;
476
477 break;
478 }
479
480 case GG_NOTIFY_REPLY:
481 {
482 struct gg_notify_reply *n = (void*) p;
483 unsigned int count, i;
484 char *tmp;
485
486 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received a notify reply\n");
487
488 if (h->length < sizeof(*n)) {
489 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() incomplete packet\n");
490 errno = EINVAL;
491 goto fail;
492 }
493
494 if (gg_fix32(n->status) == GG_STATUS_BUSY_DESCR || gg_fix32(n->status) == GG_STATUS_NOT_AVAIL_DESCR || gg_fix32(n->status) == GG_STATUS_AVAIL_DESCR) {
495 e->type = GG_EVENT_NOTIFY_DESCR;
496
497 if (!(e->event.notify_descr.notify = (void*) malloc(sizeof(*n) * 2))) {
498 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n");
499 goto fail;
500 }
501 e->event.notify_descr.notify[1].uin = 0;
502 memcpy(e->event.notify_descr.notify, p, sizeof(*n));
503 e->event.notify_descr.notify[0].uin = gg_fix32(e->event.notify_descr.notify[0].uin);
504 e->event.notify_descr.notify[0].status = gg_fix32(e->event.notify_descr.notify[0].status);
505 e->event.notify_descr.notify[0].remote_ip = e->event.notify_descr.notify[0].remote_ip;
506 e->event.notify_descr.notify[0].remote_port = gg_fix16(e->event.notify_descr.notify[0].remote_port);
507
508 count = h->length - sizeof(*n);
509 if (!(tmp = malloc(count + 1))) {
510 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n");
511 goto fail;
512 }
513 memcpy(tmp, p + sizeof(*n), count);
514 tmp[count] = 0;
515 e->event.notify_descr.descr = tmp;
516
517 } else {
518 e->type = GG_EVENT_NOTIFY;
519
520 if (!(e->event.notify = (void*) malloc(h->length + 2 * sizeof(*n)))) {
521 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n");
522 goto fail;
523 }
524
525 memcpy(e->event.notify, p, h->length);
526 count = h->length / sizeof(*n);
527 e->event.notify[count].uin = 0;
528
529 for (i = 0; i < count; i++) {
530 e->event.notify[i].uin = gg_fix32(e->event.notify[i].uin);
531 e->event.notify[i].status = gg_fix32(e->event.notify[i].status);
532 e->event.notify[i].remote_ip = e->event.notify[i].remote_ip;
533 e->event.notify[i].remote_port = gg_fix16(e->event.notify[i].remote_port);
534 }
535 }
536
537 break;
538 }
539
540 case GG_STATUS:
541 {
542 struct gg_status *s = (void*) p;
543
544 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received a status change\n");
545
546 if (h->length >= sizeof(*s)) {
547 e->type = GG_EVENT_STATUS;
548 memcpy(&e->event.status, p, sizeof(*s));
549 e->event.status.uin = gg_fix32(e->event.status.uin);
550 e->event.status.status = gg_fix32(e->event.status.status);
551 if (h->length > sizeof(*s)) {
552 int len = h->length - sizeof(*s);
553 char *buf = malloc(len + 1);
554 if (buf) {
555 memcpy(buf, p + sizeof(*s), len);
556 buf[len] = 0;
557 }
558 e->event.status.descr = buf;
559 } else
560 e->event.status.descr = NULL;
561 }
562
563 break;
564 }
565
566 case GG_NOTIFY_REPLY60:
567 {
568 struct gg_notify_reply60 *n = (void*) p;
569 unsigned int length = h->length, i = 0;
570
571 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received a notify reply\n");
572
573 e->type = GG_EVENT_NOTIFY60;
574 e->event.notify60 = malloc(sizeof(*e->event.notify60));
575
576 if (!e->event.notify60) {
577 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n");
578 goto fail;
579 }
580
581 e->event.notify60[0].uin = 0;
582
583 while (length >= sizeof(struct gg_notify_reply60)) {
584 uin_t uin = gg_fix32(n->uin);
585 char *tmp;
586
587 e->event.notify60[i].uin = uin & 0x00ffffff;
588 e->event.notify60[i].status = n->status;
589 e->event.notify60[i].remote_ip = n->remote_ip;
590 e->event.notify60[i].remote_port = gg_fix16(n->remote_port);
591 e->event.notify60[i].version = n->version;
592 e->event.notify60[i].image_size = n->image_size;
593 e->event.notify60[i].descr = NULL;
594 e->event.notify60[i].time = 0;
595
596 if (uin & 0x40000000)
597 e->event.notify60[i].version |= GG_HAS_AUDIO_MASK;
598 if (uin & 0x08000000)
599 e->event.notify60[i].version |= GG_ERA_OMNIX_MASK;
600
601 if (GG_S_D(n->status)) {
602 unsigned char descr_len = *((char*) n + sizeof(struct gg_notify_reply60));
603
604 if (descr_len < length) {
605 if (!(e->event.notify60[i].descr = malloc(descr_len + 1))) {
606 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n");
607 goto fail;
608 }
609
610 memcpy(e->event.notify60[i].descr, (char*) n + sizeof(struct gg_notify_reply60) + 1, descr_len);
611 e->event.notify60[i].descr[descr_len] = 0;
612
613 /* XXX czas */
614 }
615
616 length -= sizeof(struct gg_notify_reply60) + descr_len + 1;
617 n = (void*) ((char*) n + sizeof(struct gg_notify_reply60) + descr_len + 1);
618 } else {
619 length -= sizeof(struct gg_notify_reply60);
620 n = (void*) ((char*) n + sizeof(struct gg_notify_reply60));
621 }
622
623 if (!(tmp = realloc(e->event.notify60, (i + 2) * sizeof(*e->event.notify60)))) {
624 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n");
625 free(e->event.notify60);
626 goto fail;
627 }
628
629 e->event.notify60 = (void*) tmp;
630 e->event.notify60[++i].uin = 0;
631 }
632
633 break;
634 }
635
636 case GG_STATUS60:
637 {
638 struct gg_status60 *s = (void*) p;
639 uint32_t uin;
640
641 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received a status change\n");
642
643 if (h->length < sizeof(*s))
644 break;
645
646 uin = gg_fix32(s->uin);
647
648 e->type = GG_EVENT_STATUS60;
649 e->event.status60.uin = uin & 0x00ffffff;
650 e->event.status60.status = s->status;
651 e->event.status60.remote_ip = s->remote_ip;
652 e->event.status60.remote_port = gg_fix16(s->remote_port);
653 e->event.status60.version = s->version;
654 e->event.status60.image_size = s->image_size;
655 e->event.status60.descr = NULL;
656 e->event.status60.time = 0;
657
658 if (uin & 0x40000000)
659 e->event.status60.version |= GG_HAS_AUDIO_MASK;
660 if (uin & 0x08000000)
661 e->event.status60.version |= GG_ERA_OMNIX_MASK;
662
663 if (h->length > sizeof(*s)) {
664 int len = h->length - sizeof(*s);
665 char *buf = malloc(len + 1);
666
667 if (buf) {
668 memcpy(buf, (char*) p + sizeof(*s), len);
669 buf[len] = 0;
670 }
671
672 e->event.status60.descr = buf;
673
674 if (len > 4 && p[h->length - 5] == 0) {
675 uint32_t t;
676 memcpy(&t, p + h->length - 4, sizeof(uint32_t));
677 e->event.status60.time = gg_fix32(t);
678 }
679 }
680
681 break;
682 }
683
684 case GG_SEND_MSG_ACK:
685 {
686 struct gg_send_msg_ack *s = (void*) p;
687
688 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received a message ack\n");
689
690 if (h->length < sizeof(*s))
691 break;
692
693 e->type = GG_EVENT_ACK;
694 e->event.ack.status = gg_fix32(s->status);
695 e->event.ack.recipient = gg_fix32(s->recipient);
696 e->event.ack.seq = gg_fix32(s->seq);
697
698 break;
699 }
700
701 case GG_PONG:
702 {
703 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received a pong\n");
704
705 e->type = GG_EVENT_PONG;
706 sess->last_pong = time(NULL);
707
708 break;
709 }
710
711 case GG_DISCONNECTING:
712 {
713 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received disconnection warning\n");
714 e->type = GG_EVENT_DISCONNECT;
715 break;
716 }
717
718 case GG_PUBDIR50_REPLY:
719 {
720 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received pubdir/search reply\n");
721 if (gg_pubdir50_handle_reply(e, p, h->length) == -1)
722 goto fail;
723 break;
724 }
725
726 case GG_USERLIST_REPLY:
727 {
728 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received userlist reply\n");
729
730 if (h->length < 1)
731 break;
732
733 /* jeśli odpowiedź na eksport, wywołaj zdarzenie tylko
734 * gdy otrzymano wszystkie odpowiedzi */
735 if (p[0] == GG_USERLIST_PUT_REPLY || p[0] == GG_USERLIST_PUT_MORE_REPLY) {
736 if (--sess->userlist_blocks)
737 break;
738
739 p[0] = GG_USERLIST_PUT_REPLY;
740 }
741
742 if (h->length > 1) {
743 char *tmp;
744 unsigned int len = (sess->userlist_reply) ? strlen(sess->userlist_reply) : 0;
745
746 gg_debug(GG_DEBUG_MISC, "userlist_reply=%p, len=%d\n", sess->userlist_reply, len);
747
748 if (!(tmp = realloc(sess->userlist_reply, len + h->length))) {
749 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for userlist reply\n");
750 free(sess->userlist_reply);
751 sess->userlist_reply = NULL;
752 goto fail;
753 }
754
755 sess->userlist_reply = tmp;
756 sess->userlist_reply[len + h->length - 1] = 0;
757 memcpy(sess->userlist_reply + len, p + 1, h->length - 1);
758 }
759
760 if (p[0] == GG_USERLIST_GET_MORE_REPLY)
761 break;
762
763 e->type = GG_EVENT_USERLIST;
764 e->event.userlist.type = p[0];
765 e->event.userlist.reply = sess->userlist_reply;
766 sess->userlist_reply = NULL;
767
768 break;
769 }
770
771 default:
772 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received unknown packet 0x%.2x\n", h->type);
773 }
774
775 free(h);
776 return 0;
777
778 fail:
779 free(h);
780 return -1;
781 }
782
783 /*
784 * gg_watch_fd()
785 *
786 * funkcja, którą należy wywołać, gdy coś się stanie z obserwowanym
787 * deskryptorem. zwraca klientowi informację o tym, co się dzieje.
788 *
789 * - sess - opis sesji
790 *
791 * wskaźnik do struktury gg_event, którą trzeba zwolnić później
792 * za pomocą gg_event_free(). jesli rodzaj zdarzenia jest równy
793 * GG_EVENT_NONE, należy je zignorować. jeśli zwróciło NULL,
794 * stało się coś niedobrego -- albo zabrakło pamięci albo zerwało
795 * połączenie.
796 */
797 struct gg_event *gg_watch_fd(struct gg_session *sess)
798 {
799 struct gg_event *e;
800 int res = 0;
801 int port = 0;
802 int errno2 = 0;
803
804 gg_debug(GG_DEBUG_FUNCTION, "** gg_watch_fd(%p);\n", sess);
805
806 if (!sess) {
807 errno = EFAULT;
808 return NULL;
809 }
810
811 if (!(e = (void*) calloc(1, sizeof(*e)))) {
812 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() not enough memory for event data\n");
813 return NULL;
814 }
815
816 e->type = GG_EVENT_NONE;
817
818 switch (sess->state) {
819 case GG_STATE_RESOLVING:
820 {
821 struct in_addr addr;
822 int failed = 0;
823
824 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_RESOLVING\n");
825
826 if (read(sess->fd, &addr, sizeof(addr)) < (signed)sizeof(addr) || addr.s_addr == INADDR_NONE) {
827 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() resolving failed\n");
828 failed = 1;
829 errno2 = errno;
830 }
831
832 close(sess->fd);
833 sess->fd = -1;
834
835 #ifdef __GG_LIBGADU_HAVE_PTHREAD
836 if (sess->resolver) {
837 pthread_cancel(*((pthread_t*) sess->resolver));
838 free(sess->resolver);
839 sess->resolver = NULL;
840 }
841 #elif defined _WIN32
842 if (sess->resolver) {
843 HANDLE h = sess->resolver;
844 TerminateThread(h, 0);
845 CloseHandle(h);
846 sess->resolver = NULL;
847 }
848 #else
849 waitpid(sess->pid, NULL, 0);
850 sess->pid = -1;
851 #endif
852
853 if (failed) {
854 errno = errno2;
855 goto fail_resolving;
856 }
857
858 /* jeśli jesteśmy w resolverze i mamy ustawiony port
859 * proxy, znaczy, że resolvowaliśmy proxy. zatem
860 * wpiszmy jego adres. */
861 if (sess->proxy_port)
862 sess->proxy_addr = addr.s_addr;
863
864 /* zapiszmy sobie adres huba i adres serwera (do
865 * bezpośredniego połączenia, jeśli hub leży)
866 * z resolvera. */
867 if (sess->proxy_addr && sess->proxy_port)
868 port = sess->proxy_port;
869 else {
870 sess->server_addr = sess->hub_addr = addr.s_addr;
871 port = GG_APPMSG_PORT;
872 }
873
874 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() resolved, connecting to %s:%d\n", inet_ntoa(addr), port);
875
876 /* łączymy się albo z hubem, albo z proxy, zależnie
877 * od tego, co resolvowaliśmy. */
878 if ((sess->fd = gg_connect(&addr, port, sess->async)) == -1) {
879 /* jeśli w trybie asynchronicznym gg_connect()
880 * zwróci błąd, nie ma sensu próbować dalej. */
881 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s), critical\n", errno, strerror(errno));
882 goto fail_connecting;
883 }
884
885 /* jeśli podano serwer i łączmy się przez proxy,
886 * jest to bezpośrednie połączenie, inaczej jest
887 * do huba. */
888 sess->state = (sess->proxy_addr && sess->proxy_port && sess->server_addr) ? GG_STATE_CONNECTING_GG : GG_STATE_CONNECTING_HUB;
889 sess->check = GG_CHECK_WRITE;
890 sess->timeout = GG_DEFAULT_TIMEOUT;
891
892 break;
893 }
894
895 case GG_STATE_CONNECTING_HUB:
896 {
897 char buf[1024], *client, *auth;
898 int res = 0;
899 socklen_t res_size = sizeof(res);
900 const char *host, *appmsg;
901
902 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_CONNECTING_HUB\n");
903
904 /* jeśli asynchroniczne, sprawdzamy, czy nie wystąpił
905 * przypadkiem jakiś błąd. */
906 if (sess->async && (getsockopt(sess->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) || res)) {
907 /* no tak, nie udało się połączyć z proxy. nawet
908 * nie próbujemy dalej. */
909 if (sess->proxy_addr && sess->proxy_port) {
910 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", res, strerror(res));
911 goto fail_connecting;
912 }
913
914 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection to hub failed (errno=%d, %s), trying direct connection\n", res, strerror(res));
915 close(sess->fd);
916
917 if ((sess->fd = gg_connect(&sess->hub_addr, GG_DEFAULT_PORT, sess->async)) == -1) {
918 /* przy asynchronicznych, gg_connect()
919 * zwraca -1 przy błędach socket(),
920 * ioctl(), braku routingu itd. dlatego
921 * nawet nie próbujemy dalej. */
922 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() direct connection failed (errno=%d, %s), critical\n", errno, strerror(errno));
923 goto fail_connecting;
924 }
925
926 sess->state = GG_STATE_CONNECTING_GG;
927 sess->check = GG_CHECK_WRITE;
928 sess->timeout = GG_DEFAULT_TIMEOUT;
929 break;
930 }
931
932 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connected to hub, sending query\n");
933
934 if (!(client = gg_urlencode((sess->client_version) ? sess->client_version : GG_DEFAULT_CLIENT_VERSION))) {
935 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() out of memory for client version\n");
936 goto fail_connecting;
937 }
938
939 if (!gg_proxy_http_only && sess->proxy_addr && sess->proxy_port)
940 host = "http://" GG_APPMSG_HOST;
941 else
942 host = "";
943
944 #ifdef __GG_LIBGADU_HAVE_OPENSSL
945 if (sess->ssl)
946 appmsg = "appmsg3.asp";
947 else
948 #endif
949 appmsg = "appmsg2.asp";
950
951 auth = gg_proxy_auth();
952
953 snprintf(buf, sizeof(buf) - 1,
954 "GET %s/appsvc/%s?fmnumber=%u&version=%s&lastmsg=%d HTTP/1.0\r\n"
955 "Host: " GG_APPMSG_HOST "\r\n"
956 "User-Agent: " GG_HTTP_USERAGENT "\r\n"
957 "Pragma: no-cache\r\n"
958 "%s"
959 "\r\n", host, appmsg, sess->uin, client, sess->last_sysmsg, (auth) ? auth : "");
960
961 if (auth)
962 free(auth);
963
964 free(client);
965
966 /* zwolnij pamięć po wersji klienta. */
967 if (sess->client_version) {
968 free(sess->client_version);
969 sess->client_version = NULL;
970 }
971
972 gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-QUERY-----\n%s\n=> -----END-HTTP-QUERY-----\n", buf);
973
974 /* zapytanie jest krótkie, więc zawsze zmieści się
975 * do bufora gniazda. jeśli write() zwróci mniej,
976 * stało się coś złego. */
977 if (write(sess->fd, buf, strlen(buf)) < (signed)strlen(buf)) {
978 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() sending query failed\n");
979
980 e->type = GG_EVENT_CONN_FAILED;
981 e->event.failure = GG_FAILURE_WRITING;
982 sess->state = GG_STATE_IDLE;
983 close(sess->fd);
984 sess->fd = -1;
985 break;
986 }
987
988 sess->state = GG_STATE_READING_DATA;
989 sess->check = GG_CHECK_READ;
990 sess->timeout = GG_DEFAULT_TIMEOUT;
991
992 break;
993 }
994
995 case GG_STATE_READING_DATA:
996 {
997 char buf[1024], *tmp, *host;
998 int port = GG_DEFAULT_PORT;
999 struct in_addr addr;
1000
1001 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_READING_DATA\n");
1002
1003 /* czytamy linię z gniazda i obcinamy \r\n. */
1004 gg_read_line(sess->fd, buf, sizeof(buf) - 1);
1005 gg_chomp(buf);
1006 gg_debug(GG_DEBUG_TRAFFIC, "// gg_watch_fd() received http header (%s)\n", buf);
1007
1008 /* sprawdzamy, czy wszystko w porządku. */
1009 if (strncmp(buf, "HTTP/1.", 7) || strncmp(buf + 9, "200", 3)) {
1010 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() that's not what we've expected, trying direct connection\n");
1011
1012 close(sess->fd);
1013
1014 /* jeśli otrzymaliśmy jakieś dziwne informacje,
1015 * próbujemy się łączyć z pominięciem huba. */
1016 if (sess->proxy_addr && sess->proxy_port) {
1017 if ((sess->fd = gg_connect(&sess->proxy_addr, sess->proxy_port, sess->async)) == -1) {
1018 /* trudno. nie wyszło. */
1019 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", errno, strerror(errno));
1020 goto fail_connecting;
1021 }
1022
1023 sess->state = GG_STATE_CONNECTING_GG;
1024 sess->check = GG_CHECK_WRITE;
1025 sess->timeout = GG_DEFAULT_TIMEOUT;
1026 break;
1027 }
1028
1029 sess->port = GG_DEFAULT_PORT;
1030
1031 /* łączymy się na port 8074 huba. */
1032 if ((sess->fd = gg_connect(&sess->hub_addr, sess->port, sess->async)) == -1) {
1033 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s), trying https\n", errno, strerror(errno));
1034
1035 sess->port = GG_HTTPS_PORT;
1036
1037 /* łączymy się na port 443. */
1038 if ((sess->fd = gg_connect(&sess->hub_addr, sess->port, sess->async)) == -1) {
1039 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", errno, strerror(errno));
1040 goto fail_connecting;
1041 }
1042 }
1043
1044 sess->state = GG_STATE_CONNECTING_GG;
1045 sess->check = GG_CHECK_WRITE;
1046 sess->timeout = GG_DEFAULT_TIMEOUT;
1047 break;
1048 }
1049
1050 /* ignorujemy resztę nagłówka. */
1051 while (strcmp(buf, "\r\n") && strcmp(buf, ""))
1052 gg_read_line(sess->fd, buf, sizeof(buf) - 1);
1053
1054 /* czytamy pierwszą linię danych. */
1055 gg_read_line(sess->fd, buf, sizeof(buf) - 1);
1056 gg_chomp(buf);
1057
1058 /* jeśli pierwsza liczba w linii nie jest równa zeru,
1059 * oznacza to, że mamy wiadomość systemową. */
1060 if (atoi(buf)) {
1061 char tmp[1024], *foo, *sysmsg_buf = NULL;
1062 int len = 0;
1063
1064 while (gg_read_line(sess->fd, tmp, sizeof(tmp) - 1)) {
1065 if (!(foo = realloc(sysmsg_buf, len + strlen(tmp) + 2))) {
1066 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() out of memory for system message, ignoring\n");
1067 break;
1068 }
1069
1070 sysmsg_buf = foo;
1071
1072 if (!len)
1073 strcpy(sysmsg_buf, tmp);
1074 else
1075 strcat(sysmsg_buf, tmp);
1076
1077 len += strlen(tmp);
1078 }
1079
1080 e->type = GG_EVENT_MSG;
1081 e->event.msg.msgclass = atoi(buf);
1082 e->event.msg.sender = 0;
1083 e->event.msg.message = (unsigned char *)sysmsg_buf;
1084 }
1085
1086 close(sess->fd);
1087
1088 gg_debug(GG_DEBUG_TRAFFIC, "// gg_watch_fd() received http data (%s)\n", buf);
1089
1090 /* analizujemy otrzymane dane. */
1091 tmp = buf;
1092
1093 while (*tmp && *tmp != ' ')
1094 tmp++;
1095 while (*tmp && *tmp == ' ')
1096 tmp++;
1097 host = tmp;
1098 while (*tmp && *tmp != ' ')
1099 tmp++;
1100 *tmp = 0;
1101
1102 if ((tmp = strchr(host, ':'))) {
1103 *tmp = 0;
1104 port = atoi(tmp + 1);
1105 }
1106
1107 addr.s_addr = inet_addr(host);
1108 sess->server_addr = addr.s_addr;
1109
1110 if (!gg_proxy_http_only && sess->proxy_addr && sess->proxy_port) {
1111 /* jeśli mamy proxy, łączymy się z nim. */
1112 if ((sess->fd = gg_connect(&sess->proxy_addr, sess->proxy_port, sess->async)) == -1) {
1113 /* nie wyszło? trudno. */
1114 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", errno, strerror(errno));
1115 goto fail_connecting;
1116 }
1117
1118 sess->state = GG_STATE_CONNECTING_GG;
1119 sess->check = GG_CHECK_WRITE;
1120 sess->timeout = GG_DEFAULT_TIMEOUT;
1121 break;
1122 }
1123
1124 sess->port = port;
1125
1126 /* łączymy się z właściwym serwerem. */
1127 if ((sess->fd = gg_connect(&addr, sess->port, sess->async)) == -1) {
1128 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s), trying https\n", errno, strerror(errno));
1129
1130 sess->port = GG_HTTPS_PORT;
1131
1132 /* nie wyszło? próbujemy portu 443. */
1133 if ((sess->fd = gg_connect(&addr, GG_HTTPS_PORT, sess->async)) == -1) {
1134 /* ostatnia deska ratunku zawiodła?
1135 * w takim razie zwijamy manatki. */
1136 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", errno, strerror(errno));
1137 goto fail_connecting;
1138 }
1139 }
1140
1141 sess->state = GG_STATE_CONNECTING_GG;
1142 sess->check = GG_CHECK_WRITE;
1143 sess->timeout = GG_DEFAULT_TIMEOUT;
1144
1145 break;
1146 }
1147
1148 case GG_STATE_CONNECTING_GG:
1149 {
1150 int res = 0;
1151 socklen_t res_size = sizeof(res);
1152
1153 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_CONNECTING_GG\n");
1154
1155 /* jeśli wystąpił błąd podczas łączenia się... */
1156 if (sess->async && (sess->timeout == 0 || getsockopt(sess->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) || res)) {
1157 /* jeśli nie udało się połączenie z proxy,
1158 * nie mamy czego próbować więcej. */
1159 if (sess->proxy_addr && sess->proxy_port) {
1160 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", res, strerror(res));
1161 goto fail_connecting;
1162 }
1163
1164 close(sess->fd);
1165 sess->fd = -1;
1166
1167 #ifdef ETIMEDOUT
1168 if (sess->timeout == 0)
1169 errno = ETIMEDOUT;
1170 #endif
1171
1172 #ifdef __GG_LIBGADU_HAVE_OPENSSL
1173 /* jeśli logujemy się po TLS, nie próbujemy
1174 * się łączyć już z niczym innym w przypadku
1175 * błędu. nie dość, że nie ma sensu, to i
1176 * trzeba by się bawić w tworzenie na nowo
1177 * SSL i SSL_CTX. */
1178
1179 if (sess->ssl) {
1180 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", res, strerror(res));
1181 goto fail_connecting;
1182 }
1183 #endif
1184
1185 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s), trying https\n", res, strerror(res));
1186
1187 sess->port = GG_HTTPS_PORT;
1188
1189 /* próbujemy na port 443. */
1190 if ((sess->fd = gg_connect(&sess->server_addr, sess->port, sess->async)) == -1) {
1191 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", errno, strerror(errno));
1192 goto fail_connecting;
1193 }
1194 }
1195
1196 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connected\n");
1197
1198 if (gg_proxy_http_only)
1199 sess->proxy_port = 0;
1200
1201 /* jeśli mamy proxy, wyślijmy zapytanie. */
1202 if (sess->proxy_addr && sess->proxy_port) {
1203 char buf[100], *auth = gg_proxy_auth();
1204 struct in_addr addr;
1205
1206 if (sess->server_addr)
1207 addr.s_addr = sess->server_addr;
1208 else
1209 addr.s_addr = sess->hub_addr;
1210
1211 snprintf(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.0\r\n", inet_ntoa(addr), sess->port);
1212
1213 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() proxy request:\n// %s", buf);
1214
1215 /* wysyłamy zapytanie. jest ono na tyle krótkie,
1216 * że musi się zmieścić w buforze gniazda. jeśli
1217 * write() zawiedzie, stało się coś złego. */
1218 if (write(sess->fd, buf, strlen(buf)) < (signed)strlen(buf)) {
1219 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() can't send proxy request\n");
1220 goto fail_connecting;
1221 }
1222
1223 if (auth) {
1224 gg_debug(GG_DEBUG_MISC, "// %s", auth);
1225 if (write(sess->fd, auth, strlen(auth)) < (signed)strlen(auth)) {
1226 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() can't send proxy request\n");
1227 goto fail_connecting;
1228 }
1229
1230 free(auth);
1231 }
1232
1233 if (write(sess->fd, "\r\n", 2) < 2) {
1234 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() can't send proxy request\n");
1235 goto fail_connecting;
1236 }
1237 }
1238
1239 #ifdef __GG_LIBGADU_HAVE_OPENSSL
1240 if (sess->ssl) {
1241 SSL_set_fd(sess->ssl, sess->fd);
1242
1243 sess->state = GG_STATE_TLS_NEGOTIATION;
1244 sess->check = GG_CHECK_WRITE;
1245 sess->timeout = GG_DEFAULT_TIMEOUT;
1246
1247 break;
1248 }
1249 #endif
1250
1251 sess->state = GG_STATE_READING_KEY;
1252 sess->check = GG_CHECK_READ;
1253 sess->timeout = GG_DEFAULT_TIMEOUT;
1254
1255 break;
1256 }
1257
1258 #ifdef __GG_LIBGADU_HAVE_OPENSSL
1259 case GG_STATE_TLS_NEGOTIATION:
1260 {
1261 int res;
1262 X509 *peer;
1263
1264 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_TLS_NEGOTIATION\n");
1265
1266 if ((res = SSL_connect(sess->ssl)) <= 0) {
1267 int err = SSL_get_error(sess->ssl, res);
1268
1269 if (res == 0) {
1270 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() disconnected during TLS negotiation\n");
1271
1272 e->type = GG_EVENT_CONN_FAILED;
1273 e->event.failure = GG_FAILURE_TLS;
1274 sess->state = GG_STATE_IDLE;
1275 close(sess->fd);
1276 sess->fd = -1;
1277 break;
1278 }
1279
1280 if (err == SSL_ERROR_WANT_READ) {
1281 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() SSL_connect() wants to read\n");
1282
1283 sess->state = GG_STATE_TLS_NEGOTIATION;
1284 sess->check = GG_CHECK_READ;
1285 sess->timeout = GG_DEFAULT_TIMEOUT;
1286
1287 break;
1288 } else if (err == SSL_ERROR_WANT_WRITE) {
1289 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() SSL_connect() wants to write\n");
1290
1291 sess->state = GG_STATE_TLS_NEGOTIATION;
1292 sess->check = GG_CHECK_WRITE;
1293 sess->timeout = GG_DEFAULT_TIMEOUT;
1294
1295 break;
1296 } else {
1297 char buf[1024];
1298
1299 ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
1300
1301 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() SSL_connect() bailed out: %s\n", buf);
1302
1303 e->type = GG_EVENT_CONN_FAILED;
1304 e->event.failure = GG_FAILURE_TLS;
1305 sess->state = GG_STATE_IDLE;
1306 close(sess->fd);
1307 sess->fd = -1;
1308 break;
1309 }
1310 }
1311
1312 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() TLS negotiation succeded:\n// cipher: %s\n", SSL_get_cipher_name(sess->ssl));
1313
1314 peer = SSL_get_peer_certificate(sess->ssl);
1315
1316 if (!peer)
1317 gg_debug(GG_DEBUG_MISC, "// WARNING! unable to get peer certificate!\n");
1318 else {
1319 char buf[1024];
1320
1321 X509_NAME_oneline(X509_get_subject_name(peer), buf, sizeof(buf));
1322 gg_debug(GG_DEBUG_MISC, "// cert subject: %s\n", buf);
1323
1324 X509_NAME_oneline(X509_get_issuer_name(peer), buf, sizeof(buf));
1325 gg_debug(GG_DEBUG_MISC, "// cert issuer: %s\n", buf);
1326 }
1327
1328 sess->state = GG_STATE_READING_KEY;
1329 sess->check = GG_CHECK_READ;
1330 sess->timeout = GG_DEFAULT_TIMEOUT;
1331
1332 break;
1333 }
1334 #endif
1335
1336 case GG_STATE_READING_KEY:
1337 {
1338 struct gg_header *h;
1339 struct gg_welcome *w;
1340 struct gg_login60 l;
1341 unsigned int hash;
1342 char *password = sess->password;
1343 int ret;
1344
1345 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_READING_KEY\n");
1346
1347 memset(&l, 0, sizeof(l));
1348 l.dunno2 = 0xbe;
1349
1350 /* XXX bardzo, bardzo, bardzo głupi pomysł na pozbycie
1351 * się tekstu wrzucanego przez proxy. */
1352 if (sess->proxy_addr && sess->proxy_port) {
1353 char buf[100];
1354
1355 strcpy(buf, "");
1356 gg_read_line(sess->fd, buf, sizeof(buf) - 1);
1357 gg_chomp(buf);
1358 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() proxy response:\n// %s\n", buf);
1359
1360 while (strcmp(buf, "")) {
1361 gg_read_line(sess->fd, buf, sizeof(buf) - 1);
1362 gg_chomp(buf);
1363 if (strcmp(buf, ""))
1364 gg_debug(GG_DEBUG_MISC, "// %s\n", buf);
1365 }
1366
1367 /* XXX niech czeka jeszcze raz w tej samej
1368 * fazie. głupio, ale działa. */
1369 sess->proxy_port = 0;
1370
1371 break;
1372 }
1373
1374 /* czytaj pierwszy pakiet. */
1375 if (!(h = gg_recv_packet(sess))) {
1376 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() didn't receive packet (errno=%d, %s)\n", errno, strerror(errno));
1377
1378 e->type = GG_EVENT_CONN_FAILED;
1379 e->event.failure = GG_FAILURE_READING;
1380 sess->state = GG_STATE_IDLE;
1381 errno2 = errno;
1382 close(sess->fd);
1383 errno = errno2;
1384 sess->fd = -1;
1385 break;
1386 }
1387
1388 if (h->type != GG_WELCOME) {
1389 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() invalid packet received\n");
1390 free(h);
1391 close(sess->fd);
1392 sess->fd = -1;
1393 errno = EINVAL;
1394 e->type = GG_EVENT_CONN_FAILED;
1395 e->event.failure = GG_FAILURE_INVALID;
1396 sess->state = GG_STATE_IDLE;
1397 break;
1398 }
1399
1400 w = (struct gg_welcome*) ((char*) h + sizeof(struct gg_header));
1401 w->key = gg_fix32(w->key);
1402
1403 hash = gg_login_hash((unsigned char *)password, w->key);
1404
1405 gg_debug(GG_DEBUG_DUMP, "// gg_watch_fd() challenge %.4x --> hash %.8x\n", w->key, hash);
1406
1407 free(h);
1408
1409 free(sess->password);
1410 sess->password = NULL;
1411
1412 {
1413 struct in_addr dcc_ip;
1414 dcc_ip.s_addr = gg_dcc_ip;
1415 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() gg_dcc_ip = %s\n", inet_ntoa(dcc_ip));
1416 }
1417
1418 if (gg_dcc_ip == (unsigned long) inet_addr("255.255.255.255")) {
1419 struct sockaddr_in sin;
1420 socklen_t sin_len = sizeof(sin);
1421
1422 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() detecting address\n");
1423
1424 if (!getsockname(sess->fd, (struct sockaddr*) &sin, &sin_len)) {
1425 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() detected address to %s\n", inet_ntoa(sin.sin_addr));
1426 l.local_ip = sin.sin_addr.s_addr;
1427 } else {
1428 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() unable to detect address\n");
1429 l.local_ip = 0;
1430 }
1431 } else
1432 l.local_ip = gg_dcc_ip;
1433
1434 l.uin = gg_fix32(sess->uin);
1435 l.hash = gg_fix32(hash);
1436 l.status = gg_fix32(sess->initial_status ? sess->initial_status : GG_STATUS_AVAIL);
1437 l.version = gg_fix32(sess->protocol_version);
1438 l.local_port = gg_fix16(gg_dcc_port);
1439 l.image_size = sess->image_size;
1440
1441 if (sess->external_addr && sess->external_port > 1023) {
1442 l.external_ip = sess->external_addr;
1443 l.external_port = gg_fix16(sess->external_port);
1444 }
1445
1446 gg_debug(GG_DEBUG_TRAFFIC, "// gg_watch_fd() sending GG_LOGIN60 packet\n");
1447 ret = gg_send_packet(sess, GG_LOGIN60, &l, sizeof(l), sess->initial_descr, (sess->initial_descr) ? strlen(sess->initial_descr) : 0, NULL);
1448
1449 free(sess->initial_descr);
1450 sess->initial_descr = NULL;
1451
1452 if (ret == -1) {
1453 gg_debug(GG_DEBUG_TRAFFIC, "// gg_watch_fd() sending packet failed. (errno=%d, %s)\n", errno, strerror(errno));
1454 errno2 = errno;
1455 close(sess->fd);
1456 errno = errno2;
1457 sess->fd = -1;
1458 e->type = GG_EVENT_CONN_FAILED;
1459 e->event.failure = GG_FAILURE_WRITING;
1460 sess->state = GG_STATE_IDLE;
1461 break;
1462 }
1463
1464 sess->state = GG_STATE_READING_REPLY;
1465
1466 break;
1467 }
1468
1469 case GG_STATE_READING_REPLY:
1470 {
1471 struct gg_header *h;
1472
1473 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_READING_REPLY\n");
1474
1475 if (!(h = gg_recv_packet(sess))) {
1476 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() didn't receive packet (errno=%d, %s)\n", errno, strerror(errno));
1477 e->type = GG_EVENT_CONN_FAILED;
1478 e->event.failure = GG_FAILURE_READING;
1479 sess->state = GG_STATE_IDLE;
1480 errno2 = errno;
1481 close(sess->fd);
1482 errno = errno2;
1483 sess->fd = -1;
1484 break;
1485 }
1486
1487 if (h->type == GG_LOGIN_OK) {
1488 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() login succeded\n");
1489 e->type = GG_EVENT_CONN_SUCCESS;
1490 sess->state = GG_STATE_CONNECTED;
1491 sess->timeout = -1;
1492 sess->status = (sess->initial_status) ? sess->initial_status : GG_STATUS_AVAIL;
1493 free(h);
1494 break;
1495 }
1496
1497 if (h->type == GG_LOGIN_FAILED) {
1498 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() login failed\n");
1499 e->event.failure = GG_FAILURE_PASSWORD;
1500 errno = EACCES;
1501 } else if (h->type == GG_NEED_EMAIL) {
1502 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() email change needed\n");
1503 e->event.failure = GG_FAILURE_NEED_EMAIL;
1504 errno = EACCES;
1505 } else {
1506 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() invalid packet\n");
1507 e->event.failure = GG_FAILURE_INVALID;
1508 errno = EINVAL;
1509 }
1510
1511 e->type = GG_EVENT_CONN_FAILED;
1512 sess->state = GG_STATE_IDLE;
1513 errno2 = errno;
1514 close(sess->fd);
1515 errno = errno2;
1516 sess->fd = -1;
1517 free(h);
1518
1519 break;
1520 }
1521
1522 case GG_STATE_CONNECTED:
1523 {
1524 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_CONNECTED\n");
1525
1526 sess->last_event = time(NULL);
1527
1528 if ((res = gg_watch_fd_connected(sess, e)) == -1) {
1529
1530 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() watch_fd_connected failed (errno=%d, %s)\n", errno, strerror(errno));
1531
1532 if (errno == EAGAIN) {
1533 e->type = GG_EVENT_NONE;
1534 res = 0;
1535 } else
1536 res = -1;
1537 }
1538 break;
1539 }
1540 }
1541
1542 done:
1543 if (res == -1) {
1544 free(e);
1545 e = NULL;
1546 }
1547
1548 return e;
1549
1550 fail_connecting:
1551 if (sess->fd != -1) {
1552 errno2 = errno;
1553 close(sess->fd);
1554 errno = errno2;
1555 sess->fd = -1;
1556 }
1557 e->type = GG_EVENT_CONN_FAILED;
1558 e->event.failure = GG_FAILURE_CONNECTING;
1559 sess->state = GG_STATE_IDLE;
1560 goto done;
1561
1562 fail_resolving:
1563 e->type = GG_EVENT_CONN_FAILED;
1564 e->event.failure = GG_FAILURE_RESOLVING;
1565 sess->state = GG_STATE_IDLE;
1566 goto done;
1567 }
1568
1569 /*
1570 * Local variables:
1571 * c-indentation-style: k&r
1572 * c-basic-offset: 8
1573 * indent-tabs-mode: notnil
1574 * End:
1575 *
1576 * vim: shiftwidth=8:
1577 */

mercurial