src/protocols/gg/lib/events.c

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

mercurial