1 /* $Id$ */
2 
3 /*
4  *  (C) Copyright 2001-2006 Wojtek Kaniewski <wojtekka@irc.pl>
5  *                          Robert J. Woźny <speedy@ziew.org>
6  *                          Arkadiusz Miśkiewicz <arekm@pld-linux.org>
7  *                          Adam Wysocki <gophi@ekg.chmurka.net>
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU Lesser General Public License Version
11  *  2.1 as published by the Free Software Foundation.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU Lesser General Public License for more details.
17  *
18  *  You should have received a copy of the GNU Lesser General Public
19  *  License along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
21  *  USA.
22  */
23 
24 /**
25  * \file events.c
26  *
27  * \brief Obsługa zdarzeń
28  *
29  * \todo Poprawna obsługa gg_proxy_http_only
30  */
31 
32 #include "strman.h"
33 #include "network.h"
34 
35 #include "libgadu.h"
36 #include "protocol.h"
37 #include "internal.h"
38 #include "encoding.h"
39 #include "debug.h"
40 #include "session.h"
41 #include "resolver.h"
42 #include "config.h"
43 
44 #include <errno.h>
45 #include <string.h>
46 #include <stdlib.h>
47 #include <time.h>
48 #include <ctype.h>
49 #ifdef GG_CONFIG_HAVE_GNUTLS
50 #  include <gnutls/gnutls.h>
51 #  include <gnutls/x509.h>
52 #endif
53 #ifdef GG_CONFIG_HAVE_OPENSSL
54 #  include <openssl/err.h>
55 #  include <openssl/x509.h>
56 #  include <openssl/rand.h>
57 #endif
58 
59 /**
60  * Zwalnia pamięć zajmowaną przez informację o zdarzeniu.
61  *
62  * Funkcję należy wywoływać za każdym razem gdy funkcja biblioteki zwróci
63  * strukturę \c gg_event.
64  *
65  * \param e Struktura zdarzenia
66  *
67  * \ingroup events
68  */
gg_event_free(struct gg_event * e)69 void gg_event_free(struct gg_event *e)
70 {
71 	gg_debug(GG_DEBUG_FUNCTION, "** gg_event_free(%p);\n", e);
72 
73 	if (!e)
74 		return;
75 
76 	switch (e->type) {
77 		case GG_EVENT_MSG:
78 		case GG_EVENT_MULTILOGON_MSG:
79 			free(e->event.msg.message);
80 			free(e->event.msg.formats);
81 			free(e->event.msg.recipients);
82 			free(e->event.msg.xhtml_message);
83 			break;
84 
85 		case GG_EVENT_NOTIFY:
86 			free(e->event.notify);
87 			break;
88 
89 		case GG_EVENT_NOTIFY60:
90 		{
91 			int i;
92 
93 			for (i = 0; e->event.notify60[i].uin; i++)
94 				free(e->event.notify60[i].descr);
95 
96 			free(e->event.notify60);
97 
98 			break;
99 		}
100 
101 		case GG_EVENT_STATUS60:
102 			free(e->event.status60.descr);
103 			break;
104 
105 		case GG_EVENT_STATUS:
106 			free(e->event.status.descr);
107 			break;
108 
109 		case GG_EVENT_NOTIFY_DESCR:
110 			free(e->event.notify_descr.notify);
111 			free(e->event.notify_descr.descr);
112 			break;
113 
114 		case GG_EVENT_DCC_VOICE_DATA:
115 			free(e->event.dcc_voice_data.data);
116 			break;
117 
118 		case GG_EVENT_PUBDIR50_SEARCH_REPLY:
119 		case GG_EVENT_PUBDIR50_READ:
120 		case GG_EVENT_PUBDIR50_WRITE:
121 			gg_pubdir50_free(e->event.pubdir50);
122 			break;
123 
124 		case GG_EVENT_USERLIST:
125 			free(e->event.userlist.reply);
126 			break;
127 
128 		case GG_EVENT_IMAGE_REPLY:
129 			free(e->event.image_reply.filename);
130 			free(e->event.image_reply.image);
131 			break;
132 
133 		case GG_EVENT_XML_EVENT:
134 			free(e->event.xml_event.data);
135 			break;
136 
137 		case GG_EVENT_JSON_EVENT:
138 			free(e->event.json_event.data);
139 			free(e->event.json_event.type);
140 			break;
141 
142 		case GG_EVENT_USER_DATA:
143 		{
144 			unsigned int i, j;
145 
146 			for (i = 0; i < e->event.user_data.user_count; i++) {
147 				for (j = 0; j < e->event.user_data.users[i].attr_count; j++) {
148 					free(e->event.user_data.users[i].attrs[j].key);
149 					free(e->event.user_data.users[i].attrs[j].value);
150 				}
151 
152 				free(e->event.user_data.users[i].attrs);
153 			}
154 
155 			free(e->event.user_data.users);
156 
157 			break;
158 		}
159 
160 		case GG_EVENT_MULTILOGON_INFO:
161 		{
162 			int i;
163 
164 			for (i = 0; i < e->event.multilogon_info.count; i++)
165 				free(e->event.multilogon_info.sessions[i].name);
166 
167 			free(e->event.multilogon_info.sessions);
168 
169 			break;
170 		}
171 
172 		case GG_EVENT_USERLIST100_REPLY:
173 			free(e->event.userlist100_reply.reply);
174 			break;
175 
176 		case GG_EVENT_IMTOKEN:
177 			free(e->event.imtoken.imtoken);
178 			break;
179 
180 		case GG_EVENT_CHAT_INFO:
181 			free(e->event.chat_info.participants);
182 			break;
183 	}
184 
185 	free(e);
186 }
187 
188 /** \cond internal */
189 
190 /**
191  * \internal Usuwa obrazek z kolejki do wysłania.
192  *
193  * \param s Struktura sesji
194  * \param q Struktura obrazka
195  * \param freeq Flaga zwolnienia elementu kolejki
196  *
197  * \return 0 jeśli się powiodło, -1 jeśli wystąpił błąd
198  */
gg_image_queue_remove(struct gg_session * s,struct gg_image_queue * q,int freeq)199 int gg_image_queue_remove(struct gg_session *s, struct gg_image_queue *q, int freeq)
200 {
201 	if (!s || !q) {
202 		errno = EFAULT;
203 		return -1;
204 	}
205 
206 	if (s->images == q)
207 		s->images = q->next;
208 	else {
209 		struct gg_image_queue *qq;
210 
211 		for (qq = s->images; qq; qq = qq->next) {
212 			if (qq->next == q) {
213 				qq->next = q->next;
214 				break;
215 			}
216 		}
217 	}
218 
219 	if (freeq) {
220 		free(q->image);
221 		free(q->filename);
222 		free(q);
223 	}
224 
225 	return 0;
226 }
227 
228 /** \endcond */
229 
230 /**
231  * \internal Inicjalizuje struktury SSL.
232  *
233  * \param gs Struktura sesji
234  *
235  * \return 0 jeśli się powiodło, -1 jeśli wystąpił błąd
236  */
gg_session_init_ssl(struct gg_session * gs)237 int gg_session_init_ssl(struct gg_session *gs)
238 {
239 #ifdef GG_CONFIG_HAVE_GNUTLS
240 	gg_session_gnutls_t *tmp;
241 
242 	tmp = (gg_session_gnutls_t*) gs->ssl;
243 
244 	if (tmp == NULL) {
245 		tmp = malloc(sizeof(gg_session_gnutls_t));
246 
247 		if (tmp == NULL) {
248 			gg_debug(GG_DEBUG_MISC, "// gg_session_connect() out of memory for GnuTLS session\n");
249 			return -1;
250 		}
251 
252 		memset(tmp, 0, sizeof(gg_session_gnutls_t));
253 
254 		gs->ssl = tmp;
255 
256 		gnutls_global_init();
257 		gnutls_certificate_allocate_credentials(&tmp->xcred);
258 #ifdef GG_CONFIG_SSL_SYSTEM_TRUST
259 #ifdef HAVE_GNUTLS_CERTIFICATE_SET_X509_SYSTEM_TRUST
260 		gnutls_certificate_set_x509_system_trust(tmp->xcred);
261 #else
262 		gnutls_certificate_set_x509_trust_file(tmp->xcred,
263 			GG_CONFIG_GNUTLS_SYSTEM_TRUST_STORE,
264 			GNUTLS_X509_FMT_PEM);
265 #endif
266 #endif
267 	} else {
268 		gnutls_deinit(tmp->session);
269 	}
270 
271 	gnutls_init(&tmp->session, GNUTLS_CLIENT);
272 	gnutls_set_default_priority(tmp->session);
273 	gnutls_credentials_set(tmp->session, GNUTLS_CRD_CERTIFICATE, tmp->xcred);
274 	gnutls_transport_set_ptr(tmp->session, (gnutls_transport_ptr_t) (intptr_t) gs->fd);
275 #endif
276 
277 #ifdef GG_CONFIG_HAVE_OPENSSL
278 	char buf[1024];
279 
280 	OpenSSL_add_ssl_algorithms();
281 
282 	if (!RAND_status()) {
283 		char rdata[1024];
284 		struct {
285 			time_t time;
286 			void *ptr;
287 		} rstruct;
288 
289 		time(&rstruct.time);
290 		rstruct.ptr = (void *) &rstruct;
291 
292 		RAND_seed((void *) rdata, sizeof(rdata));
293 		RAND_seed((void *) &rstruct, sizeof(rstruct));
294 	}
295 
296 	if (gs->ssl_ctx == NULL) {
297 		gs->ssl_ctx = SSL_CTX_new(SSLv3_client_method());
298 
299 		if (gs->ssl_ctx == NULL) {
300 			ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
301 			gg_debug(GG_DEBUG_MISC, "// gg_session_connect() SSL_CTX_new() failed: %s\n", buf);
302 			return -1;
303 		}
304 
305 		SSL_CTX_set_verify(gs->ssl_ctx, SSL_VERIFY_NONE, NULL);
306 #ifdef GG_CONFIG_SSL_SYSTEM_TRUST
307 		SSL_CTX_set_default_verify_paths(gs->ssl_ctx);
308 #endif
309 	}
310 
311 	if (gs->ssl != NULL)
312 		SSL_free(gs->ssl);
313 
314 	gs->ssl = SSL_new(gs->ssl_ctx);
315 
316 	if (gs->ssl == NULL) {
317 		ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
318 		gg_debug(GG_DEBUG_MISC, "// gg_session_connect() SSL_new() failed: %s\n", buf);
319 		return -1;
320 	}
321 
322 	SSL_set_fd(gs->ssl, gs->fd);
323 #endif
324 
325 	return 0;
326 }
327 
328 /**
329  * \internal Funkcja próbuje wysłać dane zakolejkowane do wysyłki.
330  *
331  * \param sess Struktura sesji
332  *
333  * \return 0 jeśli się powiodło, -1 jeśli wystąpił błąd
334  */
gg_send_queued_data(struct gg_session * sess)335 static int gg_send_queued_data(struct gg_session *sess)
336 {
337 	int res;
338 
339 	if (sess->send_buf == NULL || sess->send_left == 0)
340 		return 0;
341 
342 	gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() sending %d bytes of queued data\n", sess->send_left);
343 
344 	res = send(sess->fd, sess->send_buf, sess->send_left, 0);
345 
346 	if (res == -1) {
347 		if (errno == EAGAIN || errno == EINTR) {
348 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd()"
349 				" non-critical send error (errno=%d, %s)\n",
350 				errno, strerror(errno));
351 
352 			return 0;
353 		}
354 
355 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() send() "
356 			"failed (errno=%d, %s)\n", errno, strerror(errno));
357 
358 		return -1;
359 	}
360 
361 	if (res == sess->send_left) {
362 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() sent all queued data\n");
363 		free(sess->send_buf);
364 		sess->send_buf = NULL;
365 		sess->send_left = 0;
366 	} else if (res > 0) {
367 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() sent %d"
368 			" bytes of queued data, %d bytes left\n",
369 			res, sess->send_left - res);
370 
371 		memmove(sess->send_buf, sess->send_buf + res, sess->send_left - res);
372 		sess->send_left -= res;
373 	}
374 
375 	return 0;
376 }
377 
378 /**
379  * \internal Sprawdza wynik połączenia asynchronicznego.
380  * \param gs Struktura sesji
381  * \param res_ptr Wskaźnik na kod błędu
382  * \return 0 jeśli się powiodło, -1 jeśli wystąpił błąd
383  */
gg_async_connect_failed(struct gg_session * gs,int * res_ptr)384 static int gg_async_connect_failed(struct gg_session *gs, int *res_ptr)
385 {
386 	int res = 0;
387 	socklen_t res_size = sizeof(res);
388 
389 	if (!gs->async)
390 		return 0;
391 
392 	if (gs->timeout == 0) {
393 		*res_ptr = ETIMEDOUT;
394 		return 1;
395 	}
396 
397 	if (getsockopt(gs->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) == -1) {
398 		*res_ptr = errno;
399 		return 1;
400 	}
401 
402 	if (res != 0) {
403 		*res_ptr = res;
404 		return 1;
405 	}
406 
407 	*res_ptr = 0;
408 
409 	return 0;
410 }
411 
412 typedef enum
413 {
414 	GG_ACTION_WAIT,
415 	GG_ACTION_NEXT,
416 	GG_ACTION_FAIL
417 } gg_action_t;
418 
419 typedef gg_action_t (*gg_state_handler_t)(struct gg_session *gs,
420 	struct gg_event *ge, enum gg_state_t next_state,
421 	enum gg_state_t alt_state, enum gg_state_t alt2_state);
422 
423 typedef struct
424 {
425 	enum gg_state_t state;
426 	gg_state_handler_t handler;
427 	enum gg_state_t next_state;
428 	enum gg_state_t alt_state;
429 	enum gg_state_t alt2_state;
430 } gg_state_transition_t;
431 
432 /* zwraca:
433  * -1 w przypadku błędu
434  * 0 jeżeli nie ma ustawionego specjalnego managera gniazdek
435  * 1 w przypadku powodzenia
436  */
gg_handle_resolve_custom(struct gg_session * sess,enum gg_state_t next_state)437 static int gg_handle_resolve_custom(struct gg_session *sess, enum gg_state_t next_state)
438 {
439 	struct gg_session_private *p = sess->private_data;
440 	int is_tls = 0;
441 	int port;
442 
443 	if (p->socket_manager_type == GG_SOCKET_MANAGER_TYPE_INTERNAL)
444 		return 0;
445 
446 	if (p->socket_manager.connect_cb == NULL) {
447 		gg_debug_session(sess, GG_DEBUG_MISC | GG_DEBUG_ERROR,
448 			"// gg_handle_resolve_custom() socket_manager.connect "
449 			"callback is empty\n");
450 		return -1;
451 	}
452 
453 	if (p->socket_handle != NULL) {
454 		gg_debug_session(sess, GG_DEBUG_MISC | GG_DEBUG_ERROR,
455 			"// gg_handle_resolve_custom() socket_handle is not "
456 			"NULL\n");
457 		return -1;
458 	}
459 
460 	port = sess->connect_port[sess->connect_index];
461 	if (next_state == GG_STATE_SEND_HUB)
462 		port = GG_APPMSG_PORT;
463 
464 	if (sess->ssl_flag != GG_SSL_DISABLED &&
465 		next_state == GG_STATE_READING_KEY)
466 	{
467 		/* XXX: w tej chwili nie ma możliwości łączenia się do HUBa po
468 		 * SSL, ale może będzie w przyszłości */
469 		is_tls = 1;
470 	}
471 
472 	if (is_tls && p->socket_manager_type == GG_SOCKET_MANAGER_TYPE_TCP) {
473 		is_tls = 0;
474 		next_state = GG_STATE_TLS_NEGOTIATION;
475 	}
476 
477 	if (port <= 0) {
478 		gg_debug_session(sess, GG_DEBUG_MISC | GG_DEBUG_ERROR,
479 			"// gg_handle_resolve_custom() port <= 0\n");
480 		return -1;
481 	}
482 
483 	p->socket_failure = 0;
484 	p->socket_next_state = next_state;
485 	p->socket_handle = p->socket_manager.connect_cb(
486 		p->socket_manager.cb_data, sess->resolver_host, port, is_tls,
487 		sess->async, sess);
488 
489 	if (p->socket_failure != 0) {
490 		if (p->socket_handle != NULL) {
491 			gg_debug_session(sess, GG_DEBUG_MISC | GG_DEBUG_WARNING,
492 				"// gg_handle_resolve_custom() handle should be"
493 				" empty on error\n");
494 		}
495 		return -1;
496 	}
497 
498 	if (p->socket_handle == NULL) {
499 		gg_debug_session(sess, GG_DEBUG_MISC | GG_DEBUG_ERROR,
500 			"// gg_handle_resolve_custom() returned empty "
501 			"handle\n");
502 		return -1;
503 	}
504 
505 	return 1;
506 }
507 
gg_handle_resolve_sync(struct gg_session * sess,struct gg_event * e,enum gg_state_t next_state,enum gg_state_t alt_state,enum gg_state_t alt2_state)508 static gg_action_t gg_handle_resolve_sync(struct gg_session *sess,
509 	struct gg_event *e, enum gg_state_t next_state,
510 	enum gg_state_t alt_state, enum gg_state_t alt2_state)
511 {
512 	struct in_addr addr;
513 	int res;
514 
515 	res = gg_handle_resolve_custom(sess, alt_state);
516 	if (res == 1)
517 		return GG_ACTION_NEXT;
518 	else if (res == -1)
519 		return GG_ACTION_FAIL;
520 
521 	addr.s_addr = inet_addr(sess->resolver_host);
522 
523 	if (addr.s_addr == INADDR_NONE) {
524 		struct in_addr *addr_list = NULL;
525 		unsigned int addr_count;
526 
527 		if (gg_gethostbyname_real(sess->resolver_host, &addr_list, &addr_count, 0) == -1) {
528 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd()"
529 				" host %s not found\n", sess->resolver_host);
530 			e->event.failure = GG_FAILURE_RESOLVING;
531 			free(addr_list);
532 			return GG_ACTION_FAIL;
533 		}
534 
535 		sess->resolver_result = addr_list;
536 		sess->resolver_count = addr_count;
537 		sess->resolver_index = 0;
538 	} else {
539 		sess->resolver_result = malloc(sizeof(struct in_addr));
540 
541 		if (sess->resolver_result == NULL) {
542 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() out of memory\n");
543 			return GG_ACTION_FAIL;
544 		}
545 
546 		sess->resolver_result[0].s_addr = addr.s_addr;
547 		sess->resolver_count = 1;
548 		sess->resolver_index = 0;
549 	}
550 
551 	sess->state = next_state;
552 
553 	return GG_ACTION_NEXT;
554 }
555 
gg_handle_resolve_async(struct gg_session * sess,struct gg_event * e,enum gg_state_t next_state,enum gg_state_t alt_state,enum gg_state_t alt2_state)556 static gg_action_t gg_handle_resolve_async(struct gg_session *sess,
557 	struct gg_event *e, enum gg_state_t next_state,
558 	enum gg_state_t alt_state, enum gg_state_t alt2_state)
559 {
560 	int res;
561 
562 	res = gg_handle_resolve_custom(sess, alt_state);
563 	if (res == 1)
564 		return GG_ACTION_WAIT;
565 	else if (res == -1)
566 		return GG_ACTION_FAIL;
567 
568 	if (sess->resolver_start(&sess->fd, &sess->resolver, sess->resolver_host) == -1) {
569 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() "
570 			"resolving failed (errno=%d, %s)\n",
571 			errno, strerror(errno));
572 		e->event.failure = GG_FAILURE_RESOLVING;
573 		return GG_ACTION_FAIL;
574 	}
575 
576 	sess->state = next_state;
577 	sess->check = GG_CHECK_READ;
578 	sess->timeout = GG_DEFAULT_TIMEOUT;
579 
580 	return GG_ACTION_WAIT;
581 }
582 
gg_handle_resolving(struct gg_session * sess,struct gg_event * e,enum gg_state_t next_state,enum gg_state_t alt_state,enum gg_state_t alt2_state)583 static gg_action_t gg_handle_resolving(struct gg_session *sess,
584 	struct gg_event *e, enum gg_state_t next_state,
585 	enum gg_state_t alt_state, enum gg_state_t alt2_state)
586 {
587 	char buf[256];
588 	int count = -1;
589 	int res;
590 	unsigned int i;
591 	struct in_addr *addrs;
592 
593 	res = gg_resolver_recv(sess->fd, buf, sizeof(buf));
594 
595 	if (res == -1 && (errno == EAGAIN || errno == EINTR)) {
596 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() "
597 			"non-critical error (errno=%d, %s)\n",
598 			errno, strerror(errno));
599 		return GG_ACTION_WAIT;
600 	}
601 
602 	sess->resolver_cleanup(&sess->resolver, 0);
603 
604 	if (res == -1) {
605 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() read "
606 			"error (errno=%d, %s)\n", errno, strerror(errno));
607 		e->event.failure = GG_FAILURE_RESOLVING;
608 		return GG_ACTION_FAIL;
609 	}
610 
611 	if (res > 0) {
612 		char *tmp;
613 
614 		tmp = realloc(sess->recv_buf, sess->recv_done + res);
615 
616 		if (tmp == NULL)
617 			return GG_ACTION_FAIL;
618 
619 		sess->recv_buf = tmp;
620 		memcpy(sess->recv_buf + sess->recv_done, buf, res);
621 		sess->recv_done += res;
622 	}
623 
624 	/* Sprawdź, czy mamy listę zakończoną INADDR_NONE */
625 
626 	addrs = (struct in_addr *)(void *)sess->recv_buf;
627 
628 	for (i = 0; i < sess->recv_done / sizeof(struct in_addr); i++) {
629 		if (addrs[i].s_addr == INADDR_NONE) {
630 			count = i;
631 			break;
632 		}
633 	}
634 
635 	/* Nie znaleziono hosta */
636 
637 	if (count == 0) {
638 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() host not found\n");
639 		e->event.failure = GG_FAILURE_RESOLVING;
640 		return GG_ACTION_FAIL;
641 	}
642 
643 	/* Nie mamy pełnej listy, ale połączenie zerwane */
644 
645 	if (res == 0 && count == -1) {
646 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection broken\n");
647 		e->event.failure = GG_FAILURE_RESOLVING;
648 		return GG_ACTION_FAIL;
649 	}
650 
651 	/* Nie mamy pełnej listy, normalna sytuacja */
652 
653 	if (count == -1)
654 		return GG_ACTION_WAIT;
655 
656 #ifndef GG_DEBUG_DISABLE
657 	if ((gg_debug_level & GG_DEBUG_DUMP) && (count > 0)) {
658 		char *list;
659 		size_t len;
660 
661 		len = 0;
662 
663 		for (i = 0; i < (unsigned int) count; i++) {
664 			if (i > 0)
665 				len += 2;
666 
667 			len += strlen(inet_ntoa(addrs[i]));
668 		}
669 
670 		list = malloc(len + 1);
671 
672 		if (list == NULL)
673 			return GG_ACTION_FAIL;
674 
675 		list[0] = 0;
676 
677 		for (i = 0; i < (unsigned int) count; i++) {
678 			if (i > 0)
679 				strcat(list, ", ");
680 
681 			strcat(list, inet_ntoa(addrs[i]));
682 		}
683 
684 		gg_debug_session(sess, GG_DEBUG_DUMP, "// gg_watch_fd() resolved: %s\n", list);
685 
686 		free(list);
687 	}
688 #endif
689 
690 	gg_close(sess);
691 
692 	sess->state = next_state;
693 	sess->resolver_result = addrs;
694 	sess->resolver_count = count;
695 	sess->resolver_index = 0;
696 	sess->recv_buf = NULL;
697 	sess->recv_done = 0;
698 
699 	return GG_ACTION_NEXT;
700 }
701 
gg_handle_connect(struct gg_session * sess,struct gg_event * e,enum gg_state_t next_state,enum gg_state_t alt_state,enum gg_state_t alt2_state)702 static gg_action_t gg_handle_connect(struct gg_session *sess,
703 	struct gg_event *e, enum gg_state_t next_state,
704 	enum gg_state_t alt_state, enum gg_state_t alt2_state)
705 {
706 	struct in_addr addr;
707 	int port;
708 
709 	if (sess->resolver_index >= sess->resolver_count) {
710 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() out of addresses to connect to\n");
711 		e->event.failure = GG_FAILURE_CONNECTING;
712 		return GG_ACTION_FAIL;
713 	}
714 
715 	addr = sess->resolver_result[sess->resolver_index];
716 
717 	if (sess->state == GG_STATE_CONNECT_HUB) {
718 		sess->hub_addr = addr.s_addr;
719 		port = GG_APPMSG_PORT;
720 	} else {
721 		sess->proxy_addr = addr.s_addr;
722 		port = sess->proxy_port;
723 	}
724 
725 	gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connecting to %s:%d\n", inet_ntoa(addr), port);
726 
727 	sess->fd = gg_connect(&addr, port, sess->async);
728 
729 	if (sess->fd == -1) {
730 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() "
731 			"connection failed (errno=%d, %s)\n",
732 			errno, strerror(errno));
733 		sess->resolver_index++;
734 		return GG_ACTION_NEXT;
735 	}
736 
737 	sess->state = next_state;
738 	sess->check = GG_CHECK_WRITE;
739 	sess->timeout = GG_DEFAULT_TIMEOUT;
740 	sess->soft_timeout = 1;
741 
742 	return GG_ACTION_WAIT;
743 }
744 
gg_handle_connecting(struct gg_session * sess,struct gg_event * e,enum gg_state_t next_state,enum gg_state_t alt_state,enum gg_state_t alt2_state)745 static gg_action_t gg_handle_connecting(struct gg_session *sess,
746 	struct gg_event *e, enum gg_state_t next_state,
747 	enum gg_state_t alt_state, enum gg_state_t alt2_state)
748 {
749 	int res;
750 
751 	sess->soft_timeout = 0;
752 
753 	if (gg_async_connect_failed(sess, &res)) {
754 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() "
755 			"connection failed (errno=%d, %s)\n",
756 			res, strerror(res));
757 		gg_close(sess);
758 		sess->resolver_index++;
759 		sess->state = alt_state;
760 	} else {
761 		/* Z proxy zwykle łączymy się dwa razy, więc nie zwalniamy
762 		 * adresów IP po pierwszym połączeniu. */
763 		if (sess->state != GG_STATE_CONNECTING_PROXY_HUB) {
764 			free(sess->resolver_result);
765 			sess->resolver_result = NULL;
766 		}
767 
768 		sess->state = next_state;
769 	}
770 
771 	return GG_ACTION_NEXT;
772 }
773 
gg_handle_connect_gg(struct gg_session * sess,struct gg_event * e,enum gg_state_t next_state,enum gg_state_t alt_state,enum gg_state_t alt2_state)774 static gg_action_t gg_handle_connect_gg(struct gg_session *sess,
775 	struct gg_event *e, enum gg_state_t next_state,
776 	enum gg_state_t alt_state, enum gg_state_t alt2_state)
777 {
778 	struct in_addr addr;
779 	uint16_t port;
780 
781 	gg_debug_session(sess, GG_DEBUG_MISC, "resolver_index=%d, "
782 		"connect_index=%d, connect_port={%d,%d}\n",
783 		sess->resolver_index, sess->connect_index,
784 		sess->connect_port[0], sess->connect_port[1]);
785 
786 	if ((unsigned int) sess->connect_index >=
787 		sizeof(sess->connect_port) / sizeof(sess->connect_port[0]) ||
788 		sess->connect_port[sess->connect_index] == 0)
789 	{
790 		sess->connect_index = 0;
791 		sess->resolver_index++;
792 		if (sess->resolver_index >= sess->resolver_count) {
793 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() out of addresses to connect to\n");
794 			e->event.failure = GG_FAILURE_CONNECTING;
795 			return GG_ACTION_FAIL;
796 		}
797 	}
798 
799 	addr = sess->resolver_result[sess->resolver_index];
800 	port = sess->connect_port[sess->connect_index];
801 
802 	gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connecting to %s:%d\n", inet_ntoa(addr), port);
803 
804 	sess->server_addr = addr.s_addr;
805 	sess->fd = gg_connect(&addr, port, sess->async);
806 
807 	if (sess->fd == -1) {
808 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() "
809 			"connection failed (errno=%d, %s)\n",
810 			errno, strerror(errno));
811 		sess->connect_index++;
812 		return GG_ACTION_NEXT;
813 	}
814 
815 	sess->state = next_state;
816 	sess->check = GG_CHECK_WRITE;
817 	sess->timeout = GG_DEFAULT_TIMEOUT;
818 	sess->soft_timeout = 1;
819 
820 	return GG_ACTION_WAIT;
821 }
822 
gg_handle_connecting_gg(struct gg_session * sess,struct gg_event * e,enum gg_state_t next_state,enum gg_state_t alt_state,enum gg_state_t alt2_state)823 static gg_action_t gg_handle_connecting_gg(struct gg_session *sess,
824 	struct gg_event *e, enum gg_state_t next_state,
825 	enum gg_state_t alt_state, enum gg_state_t alt2_state)
826 {
827 	int res;
828 
829 	sess->soft_timeout = 0;
830 
831 	/* jeśli wystąpił błąd podczas łączenia się... */
832 	if (gg_async_connect_failed(sess, &res)) {
833 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() "
834 			"connection failed (errno=%d, %s)\n",
835 			res, strerror(res));
836 		gg_close(sess);
837 		sess->connect_index++;
838 		sess->state = alt_state;
839 		return GG_ACTION_NEXT;
840 	}
841 
842 	free(sess->resolver_result);
843 	sess->resolver_result = NULL;
844 
845 	gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connected\n");
846 
847 	if (sess->ssl_flag != GG_SSL_DISABLED) {
848 		if (gg_session_init_ssl(sess) == -1) {
849 			e->event.failure = GG_FAILURE_TLS;
850 			return GG_ACTION_FAIL;
851 		}
852 
853 		sess->state = alt2_state;
854 		sess->check = GG_CHECK_WRITE;
855 		sess->timeout = GG_DEFAULT_TIMEOUT;
856 
857 		return GG_ACTION_NEXT;
858 	} else {
859 		sess->state = next_state;
860 		sess->check = GG_CHECK_READ;
861 		sess->timeout = GG_DEFAULT_TIMEOUT;
862 
863 		return GG_ACTION_WAIT;
864 	}
865 }
866 
gg_handle_send_hub(struct gg_session * sess,struct gg_event * e,enum gg_state_t next_state,enum gg_state_t alt_state,enum gg_state_t alt2_state)867 static gg_action_t gg_handle_send_hub(struct gg_session *sess,
868 	struct gg_event *e, enum gg_state_t next_state,
869 	enum gg_state_t alt_state, enum gg_state_t alt2_state)
870 {
871 	char *req, *client, *auth;
872 	const char *host;
873 	int res;
874 	int proxy;
875 	size_t req_len;
876 
877 	if (sess->client_version != NULL && isdigit(sess->client_version[0]))
878 		client = gg_urlencode(sess->client_version);
879 	else if (sess->protocol_version <= GG_PROTOCOL_VERSION_100)
880 		client = gg_urlencode(GG_DEFAULT_CLIENT_VERSION_100);
881 	else /* sess->protocol_version >= GG_PROTOCOL_VERSION_110 */
882 		client = gg_urlencode(GG_DEFAULT_CLIENT_VERSION_110);
883 
884 	if (client == NULL) {
885 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() out of memory for client version\n");
886 		return GG_ACTION_FAIL;
887 	}
888 
889 	if (sess->proxy_addr && sess->proxy_port) {
890 		host = "http://" GG_APPMSG_HOST;
891 		proxy = 1;
892 	} else {
893 		host = "";
894 		proxy = 0;
895 	}
896 
897 	auth = gg_proxy_auth();
898 
899 	if (sess->ssl_flag != GG_SSL_DISABLED) {
900 		req = gg_saprintf
901 			("GET %s/appsvc/appmsg_ver10.asp?fmnumber=%u&fmt=2&"
902 			"lastmsg=%d&version=%s&age=2&gender=1 HTTP/1.0\r\n"
903 			"Connection: close\r\n"
904 			"Host: " GG_APPMSG_HOST "\r\n"
905 			"%s"
906 			"\r\n", host, sess->uin, sess->last_sysmsg, client, (auth) ? auth : "");
907 	} else {
908 		req = gg_saprintf
909 			("GET %s/appsvc/appmsg_ver8.asp?fmnumber=%u&fmt=2&lastmsg=%d&version=%s HTTP/1.0\r\n"
910 			"Host: " GG_APPMSG_HOST "\r\n"
911 			"%s"
912 			"\r\n", host, sess->uin, sess->last_sysmsg, client, (auth) ? auth : "");
913 	}
914 
915 	free(auth);
916 	free(client);
917 
918 	if (req == NULL) {
919 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() out of memory\n");
920 		e->event.failure = GG_FAILURE_PROXY;
921 		return GG_ACTION_FAIL;
922 	}
923 
924 	req_len = strlen(req);
925 
926 	gg_debug_session(sess, GG_DEBUG_TRAFFIC, "// sending http query:\n%s", req);
927 
928 	res = send(sess->fd, req, req_len, 0);
929 
930 	free(req);
931 
932 	if (res == -1 && errno != EINTR && errno != EAGAIN) {
933 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() sending query failed\n");
934 		e->event.failure = (!proxy) ? GG_FAILURE_HUB : GG_FAILURE_PROXY;
935 		return GG_ACTION_FAIL;
936 	}
937 
938 	if ((size_t) res < req_len) {
939 		sess->state = alt_state;
940 		sess->check = GG_CHECK_WRITE;
941 		sess->timeout = GG_DEFAULT_TIMEOUT;
942 	} else {
943 		sess->state = next_state;
944 		sess->check = GG_CHECK_READ;
945 		sess->timeout = GG_DEFAULT_TIMEOUT;
946 	}
947 
948 	return GG_ACTION_WAIT;
949 }
950 
gg_handle_sending_hub_proxy(struct gg_session * sess,struct gg_event * e,enum gg_state_t next_state,enum gg_state_t alt_state,enum gg_state_t alt2_state)951 static gg_action_t gg_handle_sending_hub_proxy(struct gg_session *sess,
952 	struct gg_event *e, enum gg_state_t next_state,
953 	enum gg_state_t alt_state, enum gg_state_t alt2_state)
954 {
955 	if (gg_send_queued_data(sess) == -1) {
956 		e->event.failure = GG_FAILURE_WRITING;
957 		return GG_ACTION_FAIL;
958 	}
959 
960 	if (sess->send_left > 0)
961 		return GG_ACTION_WAIT;
962 
963 	sess->state = next_state;
964 	sess->check = GG_CHECK_READ;
965 	sess->timeout = GG_DEFAULT_TIMEOUT;
966 
967 	return GG_ACTION_WAIT;
968 }
969 
gg_handle_reading_hub_proxy(struct gg_session * sess,struct gg_event * e,enum gg_state_t next_state,enum gg_state_t alt_state,enum gg_state_t alt2_state)970 static gg_action_t gg_handle_reading_hub_proxy(struct gg_session *sess,
971 	struct gg_event *e, enum gg_state_t next_state,
972 	enum gg_state_t alt_state, enum gg_state_t alt2_state)
973 {
974 	char buf[1024], *tmp, host[129];
975 	int port = GG_DEFAULT_PORT;
976 	int reply;
977 	const char *body;
978 	struct in_addr addr;
979 	int res;
980 	char **host_white;
981 	char *host_white_default[] = GG_DEFAULT_HOST_WHITE_LIST;
982 
983 	res = recv(sess->fd, buf, sizeof(buf), 0);
984 
985 	if (res == -1 && (errno == EAGAIN || errno == EINTR)) {
986 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() "
987 			"non-critical recv error (errno=%d, %s)\n",
988 			errno, strerror(errno));
989 		return GG_ACTION_WAIT;
990 	}
991 
992 	if (res == -1) {
993 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() recv "
994 			"error (errno=%d, %s)\n", errno, strerror(errno));
995 		e->event.failure = GG_FAILURE_CONNECTING;
996 		return GG_ACTION_FAIL;
997 	}
998 
999 	if (res != 0) {
1000 		tmp = realloc(sess->recv_buf, sess->recv_done + res + 1);
1001 
1002 		if (tmp == NULL) {
1003 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() not enough memory for http reply\n");
1004 			return GG_ACTION_FAIL;
1005 		}
1006 
1007 		sess->recv_buf = tmp;
1008 		memcpy(sess->recv_buf + sess->recv_done, buf, res);
1009 		sess->recv_done += res;
1010 		sess->recv_buf[sess->recv_done] = 0;
1011 	}
1012 
1013 	if (res == 0 && sess->recv_buf == NULL) {
1014 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection closed\n");
1015 		e->event.failure = GG_FAILURE_CONNECTING;
1016 		return GG_ACTION_FAIL;
1017 	}
1018 
1019 	if (res != 0)
1020 		return GG_ACTION_WAIT;
1021 
1022 	gg_debug_session(sess, GG_DEBUG_TRAFFIC, "// received http reply:\n%s", sess->recv_buf);
1023 
1024 	res = sscanf(sess->recv_buf, "HTTP/1.%*d %3d ", &reply);
1025 
1026 	/* sprawdzamy, czy wszystko w porządku. */
1027 	if (res != 1 || reply != 200) {
1028 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() invalid http reply, connection failed\n");
1029 		e->event.failure = GG_FAILURE_CONNECTING;
1030 		return GG_ACTION_FAIL;
1031 	}
1032 
1033 	/* szukamy początku treści */
1034 	body = strstr(sess->recv_buf, "\r\n\r\n");
1035 
1036 	if (body == NULL) {
1037 		body = strstr(sess->recv_buf, "\n\n");
1038 
1039 		if (body == NULL) {
1040 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() can't find body\n");
1041 			e->event.failure = GG_FAILURE_CONNECTING;
1042 			return GG_ACTION_FAIL;
1043 		} else {
1044 			body += 2;
1045 		}
1046 	} else {
1047 		body += 4;
1048 	}
1049 
1050 	/* 17591 0 91.197.13.71:8074 91.197.13.71 */
1051 	res = sscanf(body, "%d %*d %128s", &reply, host);
1052 
1053 	if (res != 2) {
1054 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() invalid hub reply, connection failed\n");
1055 		e->event.failure = GG_FAILURE_CONNECTING;
1056 		return GG_ACTION_FAIL;
1057 	}
1058 
1059 	gg_debug_session(sess, GG_DEBUG_MISC, "reply=%d, host=\"%s\"\n", reply, host);
1060 
1061 	/* jeśli pierwsza liczba w linii nie jest równa zeru,
1062 	 * oznacza to, że mamy wiadomość systemową. */
1063 	if (reply != 0) {
1064 		tmp = strchr(body, '\n');
1065 
1066 		if (tmp != NULL) {
1067 			e->type = GG_EVENT_MSG;
1068 			e->event.msg.msgclass = reply;
1069 			e->event.msg.sender = 0;
1070 			e->event.msg.message = (unsigned char*) strdup(tmp + 1);
1071 
1072 			if (e->event.msg.message == NULL) {
1073 				gg_debug_session(sess, GG_DEBUG_MISC,
1074 					"// gg_watch_fd() not enough memory "
1075 					"for system message\n");
1076 				return GG_ACTION_FAIL;
1077 			}
1078 		}
1079 	}
1080 
1081 	gg_close(sess);
1082 
1083 	tmp = strchr(host, ':');
1084 
1085 	if (tmp != NULL) {
1086 		*tmp = 0;
1087 		port = atoi(tmp + 1);
1088 	}
1089 
1090 	if (strcmp(host, "notoperating") == 0) {
1091 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() service unavailable\n");
1092 		e->event.failure = GG_FAILURE_UNAVAILABLE;
1093 		return GG_ACTION_FAIL;
1094 	}
1095 
1096 	addr.s_addr = inet_addr(host);
1097 	if (addr.s_addr == INADDR_NONE)
1098 		addr.s_addr = 0;
1099 	sess->server_addr = addr.s_addr;
1100 
1101 	free(sess->recv_buf);
1102 	sess->recv_buf = NULL;
1103 	sess->recv_done = 0;
1104 
1105 	if (sess->state != GG_STATE_READING_PROXY_HUB) {
1106 		if (sess->port == 0) {
1107 			sess->connect_port[0] = port;
1108 			sess->connect_port[1] = (port != GG_HTTPS_PORT) ? GG_HTTPS_PORT : 0;
1109 		} else {
1110 			sess->connect_port[0] = sess->port;
1111 			sess->connect_port[1] = 0;
1112 		}
1113 	} else {
1114 		sess->connect_port[0] = (sess->port == 0) ? GG_HTTPS_PORT : sess->port;
1115 		sess->connect_port[1] = 0;
1116 	}
1117 
1118 	free(sess->connect_host);
1119 	sess->connect_host = strdup(host);
1120 
1121 	if (sess->connect_host == NULL) {
1122 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() not enough memory\n");
1123 		return GG_ACTION_FAIL;
1124 	}
1125 
1126 	host_white = sess->private_data->host_white_list;
1127 	if (!host_white)
1128 		host_white = host_white_default;
1129 
1130 	if (sess->ssl_flag == GG_SSL_REQUIRED && host_white[0] != NULL) {
1131 		int host_ok = 0;
1132 		char **it;
1133 		int host_len;
1134 
1135 		host_len = strlen(sess->connect_host);
1136 
1137 		for (it = host_white; *it != NULL; it++) {
1138 			const char *white = *it;
1139 			int white_len, dom_offset;
1140 
1141 			white_len = strlen(white);
1142 			if (white_len > host_len)
1143 				continue;
1144 
1145 			dom_offset = host_len - white_len;
1146 			if (strncasecmp(sess->connect_host + dom_offset, white,
1147 				white_len) != 0)
1148 			{
1149 				continue;
1150 			}
1151 
1152 			if (white_len < host_len) {
1153 				if (sess->connect_host[dom_offset - 1] != '.')
1154 					continue;
1155 			}
1156 
1157 			host_ok = 1;
1158 			break;
1159 		}
1160 
1161 		if (!host_ok) {
1162 			gg_debug_session(sess, GG_DEBUG_MISC | GG_DEBUG_ERROR,
1163 				"// gg_watch_fd() the HUB server returned "
1164 				"a host that is not trusted (%s)\n",
1165 				sess->connect_host);
1166 			e->event.failure = GG_FAILURE_TLS;
1167 			return GG_ACTION_FAIL;
1168 		}
1169 	}
1170 
1171 	if (sess->state == GG_STATE_READING_HUB)
1172 		sess->resolver_host = sess->connect_host;
1173 
1174 	/* Jeśli łączymy się przez proxy, zacznijmy od początku listy */
1175 	sess->resolver_index = 0;
1176 
1177 	sess->state = (sess->async) ? next_state : alt_state;
1178 
1179 	return GG_ACTION_NEXT;
1180 }
1181 
gg_handle_send_proxy_gg(struct gg_session * sess,struct gg_event * e,enum gg_state_t next_state,enum gg_state_t alt_state,enum gg_state_t alt2_state)1182 static gg_action_t gg_handle_send_proxy_gg(struct gg_session *sess,
1183 	struct gg_event *e, enum gg_state_t next_state,
1184 	enum gg_state_t alt_state, enum gg_state_t alt2_state)
1185 {
1186 	char *req, *auth;
1187 	size_t req_len;
1188 	int res;
1189 
1190 	gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() %s\n", gg_debug_state(sess->state));
1191 
1192 	if (sess->connect_index > 1 || sess->connect_port[sess->connect_index] == 0) {
1193 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() out of connection candidates\n");
1194 		e->event.failure = GG_FAILURE_CONNECTING;
1195 		return GG_ACTION_FAIL;
1196 	}
1197 
1198 	auth = gg_proxy_auth();
1199 
1200 	req = gg_saprintf("CONNECT %s:%d HTTP/1.0\r\n%s\r\n",
1201 		sess->connect_host, sess->connect_port[sess->connect_index],
1202 		(auth) ? auth : "");
1203 
1204 	free(auth);
1205 
1206 	sess->connect_index++;
1207 
1208 	if (req == NULL) {
1209 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() out of memory\n");
1210 		e->event.failure = GG_FAILURE_PROXY;
1211 		return GG_ACTION_FAIL;
1212 	}
1213 
1214 	req_len = strlen(req);
1215 
1216 	gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() proxy request:\n%s", req);
1217 
1218 	res = send(sess->fd, req, req_len, 0);
1219 
1220 	free(req);
1221 
1222 	if (res == -1 && errno != EINTR && errno != EAGAIN) {
1223 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() sending query failed\n");
1224 		e->event.failure = GG_FAILURE_PROXY;
1225 		return GG_ACTION_FAIL;
1226 	}
1227 
1228 	if ((size_t) res < req_len) {
1229 		sess->state = alt_state;
1230 		sess->check = GG_CHECK_WRITE;
1231 		sess->timeout = GG_DEFAULT_TIMEOUT;
1232 	} else {
1233 		sess->state = next_state;
1234 		sess->check = GG_CHECK_READ;
1235 		sess->timeout = GG_DEFAULT_TIMEOUT;
1236 	}
1237 
1238 	return GG_ACTION_WAIT;
1239 }
1240 
gg_handle_tls_negotiation(struct gg_session * sess,struct gg_event * e,enum gg_state_t next_state,enum gg_state_t alt_state,enum gg_state_t alt2_state)1241 static gg_action_t gg_handle_tls_negotiation(struct gg_session *sess,
1242 	struct gg_event *e, enum gg_state_t next_state,
1243 	enum gg_state_t alt_state, enum gg_state_t alt2_state)
1244 {
1245 #if defined(GG_CONFIG_HAVE_GNUTLS) || defined(GG_CONFIG_HAVE_OPENSSL)
1246 	int valid_hostname = 0;
1247 #endif
1248 
1249 #ifdef GG_CONFIG_HAVE_GNUTLS
1250 	unsigned int status;
1251 	int res;
1252 
1253 	gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_TLS_NEGOTIATION\n");
1254 
1255 	for (;;) {
1256 		res = gnutls_handshake(GG_SESSION_GNUTLS(sess));
1257 
1258 		if (res == GNUTLS_E_AGAIN) {
1259 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() TLS handshake GNUTLS_E_AGAIN\n");
1260 
1261 			if (gnutls_record_get_direction(GG_SESSION_GNUTLS(sess)) == 0)
1262 				sess->check = GG_CHECK_READ;
1263 			else
1264 				sess->check = GG_CHECK_WRITE;
1265 			sess->timeout = GG_DEFAULT_TIMEOUT;
1266 			return GG_ACTION_WAIT;
1267 		}
1268 
1269 		if (res == GNUTLS_E_INTERRUPTED) {
1270 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() TLS handshake GNUTLS_E_INTERRUPTED\n");
1271 			continue;
1272 		}
1273 
1274 		if (res != GNUTLS_E_SUCCESS) {
1275 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd()"
1276 				" TLS handshake error: %d, %s\n",
1277 				res, gnutls_strerror(res));
1278 			e->event.failure = GG_FAILURE_TLS;
1279 			return GG_ACTION_FAIL;
1280 		}
1281 
1282 		break;
1283 	}
1284 
1285 	gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() TLS negotiation succeded:\n");
1286 	gg_debug_session(sess, GG_DEBUG_MISC, "//   cipher: VERS-%s:%s:%s:%s:COMP-%s\n",
1287 		gnutls_protocol_get_name(gnutls_protocol_get_version(GG_SESSION_GNUTLS(sess))),
1288 		gnutls_cipher_get_name(gnutls_cipher_get(GG_SESSION_GNUTLS(sess))),
1289 		gnutls_kx_get_name(gnutls_kx_get(GG_SESSION_GNUTLS(sess))),
1290 		gnutls_mac_get_name(gnutls_mac_get(GG_SESSION_GNUTLS(sess))),
1291 		gnutls_compression_get_name(gnutls_compression_get(GG_SESSION_GNUTLS(sess))));
1292 
1293 	if (gnutls_certificate_type_get(GG_SESSION_GNUTLS(sess)) == GNUTLS_CRT_X509) {
1294 		unsigned int peer_count;
1295 		const gnutls_datum_t *peers;
1296 		gnutls_x509_crt_t cert;
1297 
1298 		if (gnutls_x509_crt_init(&cert) == 0) {
1299 			peers = gnutls_certificate_get_peers(GG_SESSION_GNUTLS(sess), &peer_count);
1300 
1301 			if (peers != NULL) {
1302 				char buf[256];
1303 				size_t size;
1304 
1305 				if (gnutls_x509_crt_import(cert, &peers[0], GNUTLS_X509_FMT_DER) == 0) {
1306 					size = sizeof(buf);
1307 					gnutls_x509_crt_get_dn(cert, buf, &size);
1308 					gg_debug_session(sess, GG_DEBUG_MISC, "//   cert subject: %s\n", buf);
1309 					size = sizeof(buf);
1310 					gnutls_x509_crt_get_issuer_dn(cert, buf, &size);
1311 					gg_debug_session(sess, GG_DEBUG_MISC, "//   cert issuer: %s\n", buf);
1312 
1313 					if (gnutls_x509_crt_check_hostname(cert, sess->connect_host) != 0)
1314 						valid_hostname = 1;
1315 				}
1316 			}
1317 
1318 			gnutls_x509_crt_deinit(cert);
1319 		}
1320 	}
1321 
1322 	res = gnutls_certificate_verify_peers2(GG_SESSION_GNUTLS(sess), &status);
1323 
1324 	if (res != 0 || status != 0) {
1325 		gg_debug_session(sess, GG_DEBUG_MISC, "//   WARNING!  unable to"
1326 			" verify peer certificate: 0x%x, %d, %s\n", status, res,
1327 			gnutls_strerror(res));
1328 
1329 		if (sess->ssl_flag == GG_SSL_REQUIRED) {
1330 			e->event.failure = GG_FAILURE_TLS;
1331 			return GG_ACTION_FAIL;
1332 		}
1333 	} else {
1334 		gg_debug_session(sess, GG_DEBUG_MISC, "//   verified peer certificate\n");
1335 	}
1336 
1337 
1338 #elif defined GG_CONFIG_HAVE_OPENSSL
1339 
1340 	X509 *peer;
1341 	int res;
1342 
1343 	gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() %s\n", gg_debug_state(sess->state));
1344 
1345 	res = SSL_connect(GG_SESSION_OPENSSL(sess));
1346 
1347 	if (res <= 0) {
1348 		int err;
1349 
1350 		err = SSL_get_error(GG_SESSION_OPENSSL(sess), res);
1351 
1352 		if (res == 0) {
1353 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() disconnected during TLS negotiation\n");
1354 			e->event.failure = GG_FAILURE_TLS;
1355 			return GG_ACTION_FAIL;
1356 		}
1357 
1358 		if (err == SSL_ERROR_WANT_READ) {
1359 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() SSL_connect() wants to read\n");
1360 
1361 			sess->check = GG_CHECK_READ;
1362 			sess->timeout = GG_DEFAULT_TIMEOUT;
1363 			return GG_ACTION_WAIT;
1364 		} else if (err == SSL_ERROR_WANT_WRITE) {
1365 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() SSL_connect() wants to write\n");
1366 
1367 			sess->check = GG_CHECK_WRITE;
1368 			sess->timeout = GG_DEFAULT_TIMEOUT;
1369 			return GG_ACTION_WAIT;
1370 		} else {
1371 			char buf[256];
1372 
1373 			ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
1374 
1375 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() SSL_connect() bailed out: %s\n", buf);
1376 
1377 			e->event.failure = GG_FAILURE_TLS;
1378 			return GG_ACTION_FAIL;
1379 		}
1380 	}
1381 
1382 	gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() TLS negotiation"
1383 		" succeded:\n//   cipher: %s\n",
1384 		SSL_get_cipher_name(GG_SESSION_OPENSSL(sess)));
1385 
1386 	peer = SSL_get_peer_certificate(GG_SESSION_OPENSSL(sess));
1387 
1388 	if (peer == NULL) {
1389 		gg_debug_session(sess, GG_DEBUG_MISC, "//   WARNING! unable to get peer certificate!\n");
1390 
1391 		if (sess->ssl_flag == GG_SSL_REQUIRED) {
1392 			e->event.failure = GG_FAILURE_TLS;
1393 			return GG_ACTION_FAIL;
1394 		}
1395 	} else {
1396 		char buf[256];
1397 		long res;
1398 
1399 		X509_NAME_oneline(X509_get_subject_name(peer), buf, sizeof(buf));
1400 		gg_debug_session(sess, GG_DEBUG_MISC, "//   cert subject: %s\n", buf);
1401 
1402 		X509_NAME_oneline(X509_get_issuer_name(peer), buf, sizeof(buf));
1403 		gg_debug_session(sess, GG_DEBUG_MISC, "//   cert issuer: %s\n", buf);
1404 
1405 		res = SSL_get_verify_result(GG_SESSION_OPENSSL(sess));
1406 
1407 		if (res != X509_V_OK) {
1408 			gg_debug_session(sess, GG_DEBUG_MISC, "//   WARNING!  "
1409 				"unable to verify peer certificate! "
1410 				"res=%ld\n", res);
1411 
1412 			if (sess->ssl_flag == GG_SSL_REQUIRED) {
1413 				e->event.failure = GG_FAILURE_TLS;
1414 				return GG_ACTION_FAIL;
1415 			}
1416 		} else {
1417 			gg_debug_session(sess, GG_DEBUG_MISC, "//   verified peer certificate\n");
1418 		}
1419 
1420 		if (X509_NAME_get_text_by_NID(X509_get_subject_name(peer), NID_commonName, buf, sizeof(buf)) == -1)
1421 			buf[0] = 0;
1422 
1423 		/* Obsługa certyfikatów z wieloznacznikiem */
1424 		if (strchr(buf, '*') == buf && strchr(buf + 1, '*') == NULL) {
1425 			char *tmp;
1426 
1427 			tmp = strchr(sess->connect_host, '.');
1428 
1429 			if (tmp != NULL)
1430 				valid_hostname = (strcasecmp(tmp, buf + 1) == 0);
1431 		} else {
1432 			valid_hostname = (strcasecmp(sess->connect_host, buf) == 0);
1433 		}
1434 	}
1435 
1436 #else
1437 
1438 	gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() no SSL support\n");
1439 	e->event.failure = GG_FAILURE_TLS;
1440 	return GG_ACTION_FAIL;
1441 
1442 #endif
1443 
1444 #if defined(GG_CONFIG_HAVE_GNUTLS) || defined(GG_CONFIG_HAVE_OPENSSL)
1445 	if (!valid_hostname) {
1446 		gg_debug_session(sess, GG_DEBUG_MISC, "//   WARNING!  unable to verify hostname\n");
1447 
1448 		if (sess->ssl_flag == GG_SSL_REQUIRED) {
1449 			e->event.failure = GG_FAILURE_TLS;
1450 			return GG_ACTION_FAIL;
1451 		}
1452 	}
1453 
1454 	sess->state = next_state;
1455 	sess->check = GG_CHECK_READ;
1456 	sess->timeout = GG_DEFAULT_TIMEOUT;
1457 
1458 	return GG_ACTION_WAIT;
1459 #endif
1460 }
1461 
gg_handle_reading_proxy_gg(struct gg_session * sess,struct gg_event * e,enum gg_state_t next_state,enum gg_state_t alt_state,enum gg_state_t alt2_state)1462 static gg_action_t gg_handle_reading_proxy_gg(struct gg_session *sess,
1463 	struct gg_event *e, enum gg_state_t next_state,
1464 	enum gg_state_t alt_state, enum gg_state_t alt2_state)
1465 {
1466 	char buf[256];
1467 	int res;
1468 	int reply;
1469 	char *body;
1470 
1471 	res = recv(sess->fd, buf, sizeof(buf), 0);
1472 
1473 	gg_debug_session(sess, GG_DEBUG_MISC, "recv() = %d\n", res);
1474 
1475 	if (res == -1 && (errno == EAGAIN || errno == EINTR)) {
1476 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() "
1477 			"non-critical recv error (errno=%d, %s)\n",
1478 			errno, strerror(errno));
1479 		return GG_ACTION_WAIT;
1480 	}
1481 
1482 	if (res == -1) {
1483 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() recv "
1484 			"error (errno=%d, %s)\n", errno, strerror(errno));
1485 		e->event.failure = GG_FAILURE_CONNECTING;
1486 		return GG_ACTION_FAIL;
1487 	}
1488 
1489 	if (res != 0) {
1490 		char *tmp;
1491 
1492 		tmp = realloc(sess->recv_buf, sess->recv_done + res + 1);
1493 
1494 		if (tmp == NULL) {
1495 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() not enough memory for http reply\n");
1496 			return GG_ACTION_FAIL;
1497 		}
1498 
1499 		sess->recv_buf = tmp;
1500 		memcpy(sess->recv_buf + sess->recv_done, buf, res);
1501 		sess->recv_done += res;
1502 		sess->recv_buf[sess->recv_done] = 0;
1503 	}
1504 
1505 	if (res == 0 && sess->recv_buf == NULL) {
1506 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection closed\n");
1507 		e->event.failure = GG_FAILURE_CONNECTING;
1508 		return GG_ACTION_FAIL;
1509 	}
1510 
1511 	/* szukamy początku treści */
1512 	body = strstr(sess->recv_buf, "\r\n\r\n");
1513 
1514 	if (body == NULL) {
1515 		body = strstr(sess->recv_buf, "\n\n");
1516 
1517 		if (body == NULL) {
1518 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() can't find body\n");
1519 			e->event.failure = GG_FAILURE_CONNECTING;
1520 			return GG_ACTION_FAIL;
1521 		} else {
1522 			body += 2;
1523 		}
1524 	} else {
1525 		body += 4;
1526 	}
1527 
1528 	gg_debug_session(sess, GG_DEBUG_MISC, "// found body!\n");
1529 
1530 	gg_debug_session(sess, GG_DEBUG_TRAFFIC, "// received proxy reply:\n%s\n", sess->recv_buf);
1531 
1532 	res = sscanf(sess->recv_buf, "HTTP/1.%*d %3d ", &reply);
1533 
1534 	gg_debug_session(sess, GG_DEBUG_MISC, "res = %d, reply = %d\n", res, reply);
1535 
1536 	/* sprawdzamy, czy wszystko w porządku. */
1537 	if (res != 1 || reply != 200) {
1538 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() invalid http reply, connection failed\n");
1539 		e->event.failure = GG_FAILURE_CONNECTING;
1540 		return GG_ACTION_FAIL;
1541 	}
1542 
1543 	if (sess->ssl_flag != GG_SSL_DISABLED) {
1544 		if (gg_session_init_ssl(sess) == -1) {
1545 			e->event.failure = GG_FAILURE_TLS;
1546 			return GG_ACTION_FAIL;
1547 		}
1548 
1549 		/* Teoretycznie SSL jest inicjowany przez klienta, więc serwer
1550 		 * nie powinien niczego wysłać. */
1551 		if (sess->recv_buf + sess->recv_done > body) {
1552 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() unexpected SSL data\n");
1553 			e->event.failure = GG_FAILURE_TLS;
1554 			return GG_ACTION_FAIL;
1555 		}
1556 
1557 		free(sess->recv_buf);
1558 		sess->recv_buf = NULL;
1559 		sess->recv_done = 0;
1560 
1561 		sess->state = alt_state;
1562 		sess->check = GG_CHECK_WRITE;
1563 		sess->timeout = GG_DEFAULT_TIMEOUT;
1564 
1565 		return GG_ACTION_WAIT;
1566 	}
1567 
1568 	sess->state = next_state;
1569 	sess->check = GG_CHECK_READ;
1570 	sess->timeout = GG_DEFAULT_TIMEOUT;	/* Pierwszy pakiet musi przyjść */
1571 
1572 	/* Jeśli zbuforowaliśmy za dużo, przeanalizuj */
1573 
1574 	if (sess->recv_buf + sess->recv_done > body) {
1575 		sess->recv_done = sess->recv_done - (body - sess->recv_buf);
1576 		memmove(sess->recv_buf, body, sess->recv_done);
1577 		sess->state = alt2_state;
1578 		return GG_ACTION_NEXT;
1579 	} else {
1580 		free(sess->recv_buf);
1581 		sess->recv_buf = NULL;
1582 		sess->recv_done = 0;
1583 	}
1584 
1585 	return GG_ACTION_WAIT;
1586 }
1587 
gg_handle_connected(struct gg_session * sess,struct gg_event * e,enum gg_state_t next_state,enum gg_state_t alt_state,enum gg_state_t alt2_state)1588 static gg_action_t gg_handle_connected(struct gg_session *sess,
1589 	struct gg_event *e, enum gg_state_t next_state,
1590 	enum gg_state_t alt_state, enum gg_state_t alt2_state)
1591 {
1592 #if 0
1593 	char buf[1024];
1594 	int res;
1595 
1596 	if (gg_send_queued_data(sess) == -1)
1597 		return GG_ACTION_FAIL;
1598 
1599 	res = gg_read(sess, buf, sizeof(buf));
1600 
1601 	if (res == -1 && (errno == EAGAIN || errno == EINTR)) {
1602 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() "
1603 			"non-critical read error (errno=%d, %s)\n",
1604 			errno, strerror(errno));
1605 		return GG_ACTION_WAIT;
1606 	}
1607 
1608 	if (res == -1 || res == 0) {
1609 		if (res == -1) {
1610 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd()"
1611 				" read error (errno=%d, %s)\n",
1612 				errno, strerror(errno));
1613 		} else {
1614 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd()"
1615 				" connection closed\n");
1616 		}
1617 
1618 		if (sess->state == GG_STATE_DISCONNECTING && res == 0) {
1619 			e->type = GG_EVENT_DISCONNECT_ACK;
1620 		} else if (sess->state == GG_STATE_READING_KEY) {
1621 			e->event.failure = GG_FAILURE_INVALID;
1622 			return GG_ACTION_FAIL;
1623 		}
1624 
1625 		return GG_ACTION_FAIL;
1626 	}
1627 
1628 	gg_debug_dump(sess, GG_DEBUG_DUMP, buf, res);
1629 
1630 	if (gg_session_handle_data(sess, buf, res, e) == -1)
1631 		return GG_ACTION_FAIL;
1632 
1633 	if (sess->send_buf != NULL)
1634 		sess->check |= GG_CHECK_WRITE;
1635 
1636 	return GG_ACTION_WAIT;
1637 #else
1638 	struct gg_header *gh;
1639 
1640 	if (gg_send_queued_data(sess) == -1)
1641 		return GG_ACTION_FAIL;
1642 
1643 	gh = gg_recv_packet(sess);
1644 
1645 	if (gh == NULL) {
1646 		if (sess->state == GG_STATE_DISCONNECTING) {
1647 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection broken expectedly\n");
1648 			e->type = GG_EVENT_DISCONNECT_ACK;
1649 			return GG_ACTION_WAIT;
1650 		}
1651 
1652 		if (errno != EAGAIN) {
1653 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd()"
1654 				" gg_recv_packet failed (errno=%d, %s)\n",
1655 				errno, strerror(errno));
1656 			return GG_ACTION_FAIL;
1657 		}
1658 	} else {
1659 		if (gg_session_handle_packet(sess, gh->type,
1660 			(const char *) gh + sizeof(struct gg_header),
1661 			gh->length, e) == -1)
1662 		{
1663 			free(gh);
1664 			return GG_ACTION_FAIL;
1665 		}
1666 
1667 		free(gh);
1668 	}
1669 
1670 	sess->check = GG_CHECK_READ;
1671 
1672 	if (sess->send_buf != NULL)
1673 		sess->check |= GG_CHECK_WRITE;
1674 
1675 	return GG_ACTION_WAIT;
1676 #endif
1677 }
1678 
gg_handle_error(struct gg_session * sess,struct gg_event * e,enum gg_state_t next_state,enum gg_state_t alt_state,enum gg_state_t alt2_state)1679 static gg_action_t gg_handle_error(struct gg_session *sess, struct gg_event *e,
1680 	enum gg_state_t next_state, enum gg_state_t alt_state,
1681 	enum gg_state_t alt2_state)
1682 {
1683 	struct gg_session_private *p = sess->private_data;
1684 
1685 	gg_debug_session(sess, GG_DEBUG_MISC | GG_DEBUG_ERROR, "// gg_handle_error() failure=%d\n", p->socket_failure);
1686 
1687 	e->event.failure = p->socket_failure;
1688 
1689 	return GG_ACTION_FAIL;
1690 }
1691 
1692 static const gg_state_transition_t handlers[] =
1693 {
1694 	/* style:maxlinelength:start-ignore */
1695 	{ GG_STATE_RESOLVE_HUB_SYNC, gg_handle_resolve_sync, GG_STATE_CONNECT_HUB, GG_STATE_SEND_HUB, 0 },
1696 	{ GG_STATE_RESOLVE_GG_SYNC, gg_handle_resolve_sync, GG_STATE_CONNECT_GG, GG_STATE_READING_KEY, 0 },
1697 	{ GG_STATE_RESOLVE_PROXY_HUB_SYNC, gg_handle_resolve_sync, GG_STATE_CONNECT_PROXY_HUB, GG_STATE_SEND_PROXY_HUB, 0 },
1698 	{ GG_STATE_RESOLVE_PROXY_GG_SYNC, gg_handle_resolve_sync, GG_STATE_CONNECT_PROXY_GG, GG_STATE_SEND_PROXY_GG, 0 },
1699 
1700 	{ GG_STATE_RESOLVE_HUB_ASYNC, gg_handle_resolve_async, GG_STATE_RESOLVING_HUB, GG_STATE_SEND_HUB, 0 },
1701 	{ GG_STATE_RESOLVE_GG_ASYNC, gg_handle_resolve_async, GG_STATE_RESOLVING_GG, GG_STATE_READING_KEY, 0 },
1702 	{ GG_STATE_RESOLVE_PROXY_HUB_ASYNC, gg_handle_resolve_async, GG_STATE_RESOLVING_PROXY_HUB, GG_STATE_SEND_PROXY_HUB, 0 },
1703 	{ GG_STATE_RESOLVE_PROXY_GG_ASYNC, gg_handle_resolve_async, GG_STATE_RESOLVING_PROXY_GG, GG_STATE_SEND_PROXY_GG, 0 },
1704 
1705 	{ GG_STATE_RESOLVING_HUB, gg_handle_resolving, GG_STATE_CONNECT_HUB, 0, 0 },
1706 	{ GG_STATE_RESOLVING_GG, gg_handle_resolving, GG_STATE_CONNECT_GG, 0, 0 },
1707 	{ GG_STATE_RESOLVING_PROXY_HUB, gg_handle_resolving, GG_STATE_CONNECT_PROXY_HUB, 0, 0 },
1708 	{ GG_STATE_RESOLVING_PROXY_GG, gg_handle_resolving, GG_STATE_CONNECT_PROXY_GG, 0, 0 },
1709 
1710 	{ GG_STATE_CONNECT_HUB, gg_handle_connect, GG_STATE_CONNECTING_HUB, 0, 0 },
1711 	{ GG_STATE_CONNECT_PROXY_HUB, gg_handle_connect, GG_STATE_CONNECTING_PROXY_HUB, 0, 0 },
1712 	{ GG_STATE_CONNECT_PROXY_GG, gg_handle_connect, GG_STATE_CONNECTING_PROXY_GG, 0, 0 },
1713 
1714 	{ GG_STATE_CONNECT_GG, gg_handle_connect_gg, GG_STATE_CONNECTING_GG, 0, 0 },
1715 
1716 	{ GG_STATE_CONNECTING_HUB, gg_handle_connecting, GG_STATE_SEND_HUB, GG_STATE_CONNECT_HUB, 0 },
1717 	{ GG_STATE_CONNECTING_PROXY_HUB, gg_handle_connecting, GG_STATE_SEND_PROXY_HUB, GG_STATE_CONNECT_PROXY_HUB, 0 },
1718 	{ GG_STATE_CONNECTING_PROXY_GG, gg_handle_connecting, GG_STATE_SEND_PROXY_GG, GG_STATE_CONNECT_PROXY_GG, 0 },
1719 
1720 	{ GG_STATE_CONNECTING_GG, gg_handle_connecting_gg, GG_STATE_READING_KEY, GG_STATE_CONNECT_GG, GG_STATE_TLS_NEGOTIATION },
1721 
1722 	{ GG_STATE_SEND_HUB, gg_handle_send_hub, GG_STATE_READING_HUB, GG_STATE_SENDING_HUB, 0 },
1723 	{ GG_STATE_SEND_PROXY_HUB, gg_handle_send_hub, GG_STATE_READING_PROXY_HUB, GG_STATE_SENDING_PROXY_HUB, 0 },
1724 
1725 	{ GG_STATE_SEND_PROXY_GG, gg_handle_send_proxy_gg, GG_STATE_READING_PROXY_GG, GG_STATE_SENDING_PROXY_GG, 0 },
1726 
1727 	{ GG_STATE_SENDING_HUB, gg_handle_sending_hub_proxy, GG_STATE_READING_HUB, 0, 0 },
1728 	{ GG_STATE_SENDING_PROXY_HUB, gg_handle_sending_hub_proxy, GG_STATE_READING_PROXY_HUB, 0, 0 },
1729 	{ GG_STATE_SENDING_PROXY_GG, gg_handle_sending_hub_proxy, GG_STATE_READING_PROXY_GG, 0, 0 },
1730 
1731 	{ GG_STATE_READING_HUB, gg_handle_reading_hub_proxy, GG_STATE_RESOLVE_GG_ASYNC, GG_STATE_RESOLVE_GG_SYNC, 0 },
1732 	{ GG_STATE_READING_PROXY_HUB, gg_handle_reading_hub_proxy, GG_STATE_CONNECT_PROXY_GG, GG_STATE_CONNECT_PROXY_GG, 0 },
1733 
1734 	{ GG_STATE_READING_PROXY_GG, gg_handle_reading_proxy_gg, GG_STATE_READING_KEY, GG_STATE_TLS_NEGOTIATION, GG_STATE_READING_KEY },
1735 
1736 	{ GG_STATE_TLS_NEGOTIATION, gg_handle_tls_negotiation, GG_STATE_READING_KEY, 0, 0 },
1737 
1738 	{ GG_STATE_READING_KEY, gg_handle_connected, 0, 0, 0 },
1739 	{ GG_STATE_READING_REPLY, gg_handle_connected, 0, 0, 0 },
1740 	{ GG_STATE_CONNECTED, gg_handle_connected, 0, 0, 0 },
1741 	{ GG_STATE_DISCONNECTING, gg_handle_connected, 0, 0, 0 },
1742 	{ GG_STATE_ERROR, gg_handle_error, 0, 0, 0 },
1743 	/* style:maxlinelength:end-ignore */
1744 };
1745 
gg_eventqueue_add(struct gg_session * sess)1746 struct gg_event *gg_eventqueue_add(struct gg_session *sess)
1747 {
1748 	struct gg_event *ge;
1749 	gg_eventqueue_t *queue_el, *it;
1750 
1751 	queue_el = gg_new0(sizeof(gg_eventqueue_t));
1752 	ge = gg_new0(sizeof(struct gg_event));
1753 
1754 	if (queue_el == NULL || ge == NULL) {
1755 		free(queue_el);
1756 		free(ge);
1757 		return NULL;
1758 	}
1759 
1760 	ge->type = GG_EVENT_NONE;
1761 
1762 	queue_el->event = ge;
1763 	if (sess->private_data->event_queue == NULL)
1764 		sess->private_data->event_queue = queue_el;
1765 	else {
1766 		it = sess->private_data->event_queue;
1767 		while (it->next != NULL)
1768 			it = it->next;
1769 		it->next = queue_el;
1770 	}
1771 
1772 	return ge;
1773 }
1774 
1775 /**
1776  * Funkcja wywoływana po zaobserwowaniu zmian na deskryptorze sesji.
1777  *
1778  * Funkcja zwraca strukturę zdarzenia \c gg_event. Jeśli rodzaj zdarzenia
1779  * to \c GG_EVENT_NONE, nie wydarzyło się jeszcze nic wartego odnotowania.
1780  * Strukturę zdarzenia należy zwolnić funkcja \c gg_event_free().
1781  *
1782  * \param sess Struktura sesji
1783  *
1784  * \return Struktura zdarzenia lub \c NULL jeśli wystąpił błąd
1785  *
1786  * \ingroup events
1787  */
gg_watch_fd(struct gg_session * sess)1788 struct gg_event *gg_watch_fd(struct gg_session *sess)
1789 {
1790 	struct gg_event *ge;
1791 	struct gg_session_private *priv;
1792 
1793 	gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_watch_fd(%p);\n", sess);
1794 
1795 	if (sess == NULL) {
1796 		errno = EFAULT;
1797 		return NULL;
1798 	}
1799 
1800 	priv = sess->private_data;
1801 
1802 	if (priv->event_queue != NULL) {
1803 		gg_eventqueue_t *next;
1804 
1805 		ge = priv->event_queue->event;
1806 		next = priv->event_queue->next;
1807 		free(priv->event_queue);
1808 		priv->event_queue = next;
1809 
1810 		if (next == NULL) {
1811 			sess->check = priv->check_after_queue;
1812 			sess->fd = priv->fd_after_queue;
1813 		}
1814 		return ge;
1815 	}
1816 
1817 	ge = malloc(sizeof(struct gg_event));
1818 
1819 	if (ge == NULL) {
1820 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() not enough memory for event data\n");
1821 		return NULL;
1822 	}
1823 
1824 	memset(ge, 0, sizeof(struct gg_event));
1825 
1826 	ge->type = GG_EVENT_NONE;
1827 
1828 	for (;;) {
1829 		unsigned int i, found = 0;
1830 		gg_action_t res;
1831 
1832 		res = GG_ACTION_FAIL;
1833 
1834 		for (i = 0; i < sizeof(handlers) / sizeof(handlers[0]); i++) {
1835 			if (handlers[i].state == (enum gg_state_t) sess->state) {
1836 				gg_debug_session(sess, GG_DEBUG_MISC,
1837 					"// gg_watch_fd() %s\n",
1838 					gg_debug_state(sess->state));
1839 				res = (*handlers[i].handler)(sess, ge,
1840 					handlers[i].next_state,
1841 					handlers[i].alt_state,
1842 					handlers[i].alt2_state);
1843 				found = 1;
1844 				break;
1845 			}
1846 		}
1847 
1848 		if (!found) {
1849 			gg_debug_session(sess, GG_DEBUG_MISC | GG_DEBUG_ERROR,
1850 				"// gg_watch_fd() invalid state %s\n",
1851 				gg_debug_state(sess->state));
1852 			ge->event.failure = GG_FAILURE_INTERNAL;
1853 		}
1854 
1855 		if (!sess->async && ge->type == GG_EVENT_NONE && res == GG_ACTION_WAIT)
1856 			res = GG_ACTION_NEXT;
1857 
1858 		switch (res) {
1859 			case GG_ACTION_WAIT:
1860 				if (priv->event_queue != NULL) {
1861 					priv->fd_after_queue = sess->fd;
1862 					priv->check_after_queue = sess->check;
1863 					/* wymuszamy ponowne wywołanie gg_watch_fd */
1864 					sess->fd = gg_get_dummy_fd(sess);
1865 					if (sess->fd < 0)
1866 						sess->fd = priv->fd_after_queue;
1867 					sess->check = GG_CHECK_READ | GG_CHECK_WRITE;
1868 				}
1869 				return ge;
1870 
1871 			case GG_ACTION_NEXT:
1872 				continue;
1873 
1874 			case GG_ACTION_FAIL:
1875 				sess->state = GG_STATE_IDLE;
1876 
1877 				gg_close(sess);
1878 
1879 				if (ge->event.failure != 0) {
1880 					ge->type = GG_EVENT_CONN_FAILED;
1881 				} else {
1882 					free(ge);
1883 					ge = NULL;
1884 				}
1885 
1886 				return ge;
1887 
1888 			/* Celowo nie ma default */
1889 		}
1890 	}
1891 }
1892 
1893 /*
1894  * Local variables:
1895  * c-indentation-style: k&r
1896  * c-basic-offset: 8
1897  * indent-tabs-mode: notnil
1898  * End:
1899  *
1900  * vim: shiftwidth=8:
1901  */
1902