| |
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 */ |