Mercurial > pidgin.yaz
diff src/protocols/gg/libgg.c @ 2792:9123abd0db92
[gaim-migrate @ 2805]
Arkadiusz Miskiewicz's updates to Gadu-Gadu
committer: Tailor Script <tailor@pidgin.im>
author | Eric Warmenhoven <eric@warmenhoven.org> |
---|---|
date | Mon, 26 Nov 2001 21:22:56 +0000 |
parents | 04a5f68f640c |
children | 4b3f17ca66bf |
line wrap: on
line diff
--- a/src/protocols/gg/libgg.c Mon Nov 26 20:39:54 2001 +0000 +++ b/src/protocols/gg/libgg.c Mon Nov 26 21:22:56 2001 +0000 @@ -1,7 +1,8 @@ -/* $Id: libgg.c 2608 2001-10-24 08:35:55Z warmenhoven $ */ +/* $Id: libgg.c 2805 2001-11-26 21:22:56Z warmenhoven $ */ /* - * (C) Copyright 2001 Wojtek Kaniewski <wojtekka@irc.pl> + * (C) Copyright 2001 Wojtek Kaniewski <wojtekka@irc.pl>, + * Robert J. Woźny <speedy@atman.pl> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as @@ -26,22 +27,39 @@ #include <arpa/inet.h> #include <sys/ioctl.h> #include <sys/wait.h> -#include <sys/types.h> -#include <fcntl.h> +#include <sys/time.h> #include <netdb.h> #include <errno.h> -#include <string.h> +#ifndef _AIX +# include <string.h> +#endif #include <stdarg.h> #include <pwd.h> +#include <time.h> +#ifdef sun +#include <sys/filio.h> +#endif #include <glib.h> +#if G_BYTE_ORDER == G_BIG_ENDIAN +# define WORDS_BIGENDIAN 1 +#endif #include "libgg.h" +#include "config.h" int gg_debug_level = 0; -#ifdef GG_DEBUG +#ifndef lint + +static char rcsid[] +#ifdef __GNUC__ + __attribute__ ((unused)) +#endif + = "$Id: libgg.c 2805 2001-11-26 21:22:56Z warmenhoven $"; + +#endif /* - * gg_debug_real() + * gg_debug() * * wyrzuca komunikat o danym poziomie, o ile użytkownik sobie tego życzy. * @@ -50,10 +68,10 @@ * * niczego nie zwraca. */ -void gg_debug_real(int level, char *format, ...) +void gg_debug(int level, char *format, ...) { va_list ap; - + if ((gg_debug_level & level)) { va_start(ap, format); vprintf(format, ap); @@ -61,8 +79,6 @@ } } -#endif /* GG_DEBUG */ - /* * fix32() // funkcja wewnętrzna * @@ -70,15 +86,14 @@ */ static inline unsigned long fix32(unsigned long x) { -#if G_BYTE_ORDER == G_LITTLE_ENDIAN +#ifndef WORDS_BIGENDIAN return x; #else return (unsigned long) - (((x & (unsigned long) 0x000000ffU) << 24) | - ((x & (unsigned long) 0x0000ff00U) << 8) | - ((x & (unsigned long) 0x00ff0000U) >> 8) | - ((x & (unsigned long) 0xff000000U) >> 24)); -#endif + (((x & (unsigned long)0x000000ffU) << 24) | + ((x & (unsigned long)0x0000ff00U) << 8) | + ((x & (unsigned long)0x00ff0000U) >> 8) | ((x & (unsigned long)0xff000000U) >> 24)); +#endif } /* @@ -88,12 +103,11 @@ */ static inline unsigned short fix16(unsigned short x) { -#if G_BYTE_ORDER == G_LITTLE_ENDIAN +#ifndef WORDS_BIGENDIAN return x; #else return (unsigned short) - (((x & (unsigned short) 0x00ffU) << 8) | - ((x & (unsigned short) 0xff00U) >> 8)); + (((x & (unsigned short)0x00ffU) << 8) | ((x & (unsigned short)0xff00U) >> 8)); #endif } @@ -101,8 +115,8 @@ * gg_alloc_sprintf() // funkcja wewnętrzna * * robi dokładnie to samo, co sprintf(), tyle że alokuje sobie wcześniej - * miejsce na dane. jak znam życie, ze względu na różnice między funkcjami - * vsnprintf() na różnych platformach, nie będzie działało ;) + * miejsce na dane. powinno działać na tych maszynach, które mają funkcję + * vsnprintf() zgodną z C99, jak i na wcześniejszych. * * - format, ... - parametry takie same jak w innych funkcjach *printf() * @@ -112,16 +126,26 @@ char *gg_alloc_sprintf(char *format, ...) { va_list ap; - char *buf = NULL; - int size; + char *buf = NULL, *tmp; + int size = 0, res; va_start(ap, format); - if ((size = vsnprintf(buf, 0, format, ap)) < 0) - return NULL; - - if (!(buf = malloc(size + 1))) - return NULL; + if ((size = vsnprintf(buf, 0, format, ap)) < 1) { + size = 128; + do { + size *= 2; + if (!(tmp = realloc(buf, size))) { + free(buf); + return NULL; + } + buf = tmp; + res = vsnprintf(buf, size, format, ap); + } while (res == size - 1); + } else { + if (!(buf = malloc(size + 1))) + return NULL; + } vsnprintf(buf, size + 1, format, ap); @@ -131,6 +155,40 @@ } /* + * gg_get_line() // funkcja wewnętrzna + * + * podaje kolejną linię z bufora tekstowego. psuje co bezpowrotnie, dzieląc + * na kolejne stringi. zdarza się, nie ma potrzeby pisania funkcji dublującej + * bufor żeby tylko mieć nieruszone dane wejściowe, skoro i tak nie będą nam + * poźniej potrzebne. obcina `\r\n'. + * + * - ptr - wskaźnik do zmiennej, która przechowuje aktualną pozycję + * w przemiatanym buforze. + * + * wskaźnik do kolejnej linii tekstu lub NULL, jeśli to już koniec bufora. + */ +char *gg_get_line(char **ptr) +{ + char *foo, *res; + + if (!ptr || !*ptr || !strcmp(*ptr, "")) + return NULL; + + res = *ptr; + + if (!(foo = strchr(*ptr, '\n'))) + *ptr += strlen(*ptr); + else { + *ptr = foo + 1; + *foo = 0; + if (res[strlen(res) - 1] == '\r') + res[strlen(res) - 1] = 0; + } + + return res; +} + +/* * gg_resolve() // funkcja wewnętrzna * * tworzy pipe'y, forkuje się i w drugim procesie zaczyna resolvować @@ -150,7 +208,7 @@ struct in_addr a; gg_debug(GG_DEBUG_FUNCTION, "** gg_resolve(..., \"%s\");\n", hostname); - + if (!fd | !pid) { errno = EFAULT; return -1; @@ -165,11 +223,11 @@ if (!res) { if ((a.s_addr = inet_addr(hostname)) == INADDR_NONE) { struct hostent *he; - + if (!(he = gethostbyname(hostname))) a.s_addr = INADDR_NONE; else - memcpy((char*) &a, he->h_addr, sizeof(a)); + memcpy((char *)&a, he->h_addr, sizeof(a)); } write(pipes[1], &a, sizeof(a)); @@ -205,21 +263,16 @@ struct in_addr *a = addr; gg_debug(GG_DEBUG_FUNCTION, "** gg_connect(%s, %d, %d);\n", inet_ntoa(*a), port, async); - + if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { gg_debug(GG_DEBUG_MISC, "-- socket() failed. errno = %d (%s)\n", errno, strerror(errno)); return -1; } if (async) { -#ifdef FIONBIO if (ioctl(sock, FIONBIO, &one) == -1) { -#else - int flags = fcntl (sock, F_GETFL); - if (flags < 0 || - fcntl (sock, F_SETFL, flags | O_NONBLOCK) < 0) { -#endif - gg_debug(GG_DEBUG_MISC, "-- ioctl() failed. errno = %d (%s)\n", errno, strerror(errno)); + gg_debug(GG_DEBUG_MISC, "-- ioctl() failed. errno = %d (%s)\n", errno, + strerror(errno)); return -1; } } @@ -227,13 +280,16 @@ sin.sin_port = htons(port); sin.sin_family = AF_INET; sin.sin_addr.s_addr = a->s_addr; - - if (connect(sock, (struct sockaddr*) &sin, sizeof(sin)) == -1) { - gg_debug(GG_DEBUG_MISC, "-- connect() failed. errno = %d (%s)\n", errno, strerror(errno)); - if (errno && (!async || errno != EINPROGRESS)) + + if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) == -1) { + if (errno && (!async || errno != EINPROGRESS)) { + gg_debug(GG_DEBUG_MISC, "-- connect() failed. errno = %d (%s)\n", errno, + strerror(errno)); return -1; + } + gg_debug(GG_DEBUG_MISC, "-- connect() in progress\n"); } - + return sock; } @@ -253,7 +309,7 @@ int ret; gg_debug(GG_DEBUG_FUNCTION, "** gg_read_line(...);\n"); - + for (; length > 1; buf++, length--) { do { if ((ret = read(sock, buf, 1)) == -1 && errno != EINTR) { @@ -289,7 +345,7 @@ int ret = 0, offset, size = 0; gg_debug(GG_DEBUG_FUNCTION, "** gg_recv_packet(...);\n"); - + if (!sess) { errno = EFAULT; return NULL; @@ -301,7 +357,8 @@ gg_debug(GG_DEBUG_MISC, "-- header recv(..., %d) = %d\n", sizeof(h), ret); if (ret < sizeof(h)) { if (errno != EINTR) { - gg_debug(GG_DEBUG_MISC, "-- errno = %d (%s)\n", errno, strerror(errno)); + gg_debug(GG_DEBUG_MISC, "-- errno = %d (%s)\n", errno, + strerror(errno)); return NULL; } } @@ -343,7 +400,7 @@ if (ret > -1 && ret <= size) { offset += ret; size -= ret; - } else if (ret == -1) { + } else if (ret == -1) { gg_debug(GG_DEBUG_MISC, "-- errno = %d (%s)\n", errno, strerror(errno)); if (errno == EAGAIN) { gg_debug(GG_DEBUG_MISC, "-- %d bytes received, %d left\n", offset, size); @@ -353,7 +410,7 @@ return NULL; } if (errno != EINTR) { - /* errno = EINVAL; */ +// errno = EINVAL; free(buf); return NULL; } @@ -362,16 +419,14 @@ sess->recv_left = 0; -#ifdef GG_DEBUG if ((gg_debug_level & GG_DEBUG_DUMP)) { int i; gg_debug(GG_DEBUG_DUMP, ">> received packet (type=%.2x):", h.type); - for (i = 0; i < sizeof(h) + h.length; i++) - gg_debug(GG_DEBUG_DUMP, " %.2x", (unsigned char) buf[i]); + for (i = 0; i < sizeof(h) + h.length; i++) + gg_debug(GG_DEBUG_DUMP, " %.2x", (unsigned char)buf[i]); gg_debug(GG_DEBUG_DUMP, "\n"); } -#endif return buf; } @@ -392,14 +447,16 @@ * zabrakło pamięci. inaczej był błąd przy wysyłaniu pakietu. dla errno=0 * nie wysłano całego pakietu. */ -static int gg_send_packet(int sock, int type, void *packet, int length, void *payload, int payload_length) +static int gg_send_packet(int sock, int type, void *packet, int length, void *payload, + int payload_length) { struct gg_header *h; int res, plen; char *tmp; - gg_debug(GG_DEBUG_FUNCTION, "** gg_send_packet(0x%.2x, %d, %d);\n", type, length, payload_length); - + gg_debug(GG_DEBUG_FUNCTION, "** gg_send_packet(0x%.2x, %d, %d);\n", type, length, + payload_length); + if (length < 0 || payload_length < 0) { gg_debug(GG_DEBUG_MISC, "-- invalid packet/payload length\n"); errno = ERANGE; @@ -411,7 +468,7 @@ return -1; } - h = (struct gg_header*) tmp; + h = (struct gg_header *)tmp; h->type = fix32(type); h->length = fix32(length + payload_length); @@ -420,26 +477,25 @@ if (payload) memcpy(tmp + sizeof(struct gg_header) + length, payload, payload_length); -#ifdef GG_DEBUG if ((gg_debug_level & GG_DEBUG_DUMP)) { int i; gg_debug(GG_DEBUG_DUMP, "%%%% sending packet (type=%.2x):", fix32(h->type)); for (i = 0; i < sizeof(struct gg_header) + fix32(h->length); i++) - gg_debug(GG_DEBUG_DUMP, " %.2x", (unsigned char) tmp[i]); + gg_debug(GG_DEBUG_DUMP, " %.2x", (unsigned char)tmp[i]); gg_debug(GG_DEBUG_DUMP, "\n"); } -#endif plen = sizeof(struct gg_header) + length + payload_length; - + if ((res = write(sock, tmp, plen)) < plen) { - gg_debug(GG_DEBUG_MISC, "-- write() failed. res = %d, errno = %d (%s)\n", res, errno, strerror(errno)); + gg_debug(GG_DEBUG_MISC, "-- write() failed. res = %d, errno = %d (%s)\n", res, errno, + strerror(errno)); free(tmp); return -1; } - free(tmp); + free(tmp); return 0; } @@ -479,6 +535,9 @@ sess->async = async; sess->seq = 0; sess->recv_left = 0; + sess->last_pong = 0; + sess->server_ip = 0; + sess->initial_status = 0; if (async) { if (gg_resolve(&sess->fd, &sess->pid, GG_APPMSG_HOST)) { @@ -491,13 +550,13 @@ if ((a.s_addr = inet_addr(GG_APPMSG_HOST)) == INADDR_NONE) { struct hostent *he; - + if (!(he = gethostbyname(GG_APPMSG_HOST))) { gg_debug(GG_DEBUG_MISC, "-- host %s not found\n", GG_APPMSG_HOST); free(sess); return NULL; } else - memcpy((char*) &a, he->h_addr, sizeof(a)); + memcpy((char *)&a, he->h_addr, sizeof(a)); } if (!(sess->fd = gg_connect(&a, GG_APPMSG_PORT, 0)) == -1) { @@ -518,6 +577,7 @@ } if (e->type == GG_EVENT_CONN_FAILED) { + errno = EACCES; gg_debug(GG_DEBUG_MISC, "-- could not login\n"); gg_free_event(e); free(sess); @@ -598,7 +658,7 @@ if (sess->state == GG_STATE_CONNECTED) gg_change_status(sess, GG_STATUS_NOT_AVAIL); - + if (sess->fd) { shutdown(sess->fd, 2); close(sess->fd); @@ -626,7 +686,7 @@ errno = EFAULT; return -1; } - + if (sess->state != GG_STATE_CONNECTED) { errno = ENOTCONN; return -1; @@ -640,7 +700,7 @@ s.seq = fix32(sess->seq); s.msgclass = fix32(msgclass); sess->seq += (rand() % 0x300) + 0x300; - + if (gg_send_packet(sess->fd, GG_SEND_MSG, &s, sizeof(s), message, strlen(message) + 1) == -1) return -1; @@ -704,7 +764,7 @@ * * jeśli udało się, zwraca 0. jeśli błąd, dostajemy -1. */ -int gg_notify(struct gg_session *sess, uin_t *userlist, int count) +int gg_notify(struct gg_session *sess, uin_t * userlist, int count) { struct gg_notify *n; uin_t *u; @@ -714,25 +774,25 @@ errno = EFAULT; return -1; } - + if (sess->state != GG_STATE_CONNECTED) { errno = ENOTCONN; return -1; } gg_debug(GG_DEBUG_FUNCTION, "** gg_notify(..., %d);\n", count); - + if (!userlist || !count) return 0; - - if (!(n = (struct gg_notify*) malloc(sizeof(*n) * count))) + + if (!(n = (struct gg_notify *)malloc(sizeof(*n) * count))) return -1; - - for (u = userlist, i = 0; i < count; u++, i++) { + + for (u = userlist, i = 0; i < count; u++, i++) { n[i].uin = fix32(*u); n[i].dunno1 = 3; } - + if (gg_send_packet(sess->fd, GG_NOTIFY, n, sizeof(*n) * count, NULL, 0) == -1) res = -1; @@ -764,12 +824,12 @@ errno = ENOTCONN; return -1; } - + gg_debug(GG_DEBUG_FUNCTION, "** gg_add_notify(..., %u);\n", uin); - + a.uin = fix32(uin); a.dunno1 = 3; - + return gg_send_packet(sess->fd, GG_ADD_NOTIFY, &a, sizeof(a), NULL, 0); } @@ -798,10 +858,10 @@ } gg_debug(GG_DEBUG_FUNCTION, "** gg_remove_notify(..., %u);\n", uin); - + a.uin = fix32(uin); a.dunno1 = 3; - + return gg_send_packet(sess->fd, GG_REMOVE_NOTIFY, &a, sizeof(a), NULL, 0); } @@ -827,12 +887,13 @@ gg_debug(GG_DEBUG_FUNCTION, "** gg_watch_fd_connected(...);\n"); if (!(h = gg_recv_packet(sess))) { - gg_debug(GG_DEBUG_MISC, "-- gg_recv_packet failed. errno = %d (%d)\n", errno, strerror(errno)); + gg_debug(GG_DEBUG_MISC, "-- gg_recv_packet failed. errno = %d (%d)\n", errno, + strerror(errno)); return -1; } - p = (void*) h + sizeof(struct gg_header); - + p = (void *)h + sizeof(struct gg_header); + if (h->type == GG_RECV_MSG) { struct gg_recv_msg *r = p; @@ -842,7 +903,8 @@ e->type = GG_EVENT_MSG; e->event.msg.msgclass = fix32(r->msgclass); e->event.msg.sender = fix32(r->sender); - e->event.msg.message = strdup((char*) r + sizeof(*r)); + e->event.msg.message = strdup((char *)r + sizeof(*r)); + e->event.msg.time = fix32(r->time); } } @@ -851,9 +913,9 @@ int count, i; gg_debug(GG_DEBUG_MISC, "-- received a notify reply\n"); - + e->type = GG_EVENT_NOTIFY; - if (!(e->event.notify = (void*) malloc(h->length + 2 * sizeof(*n)))) { + if (!(e->event.notify = (void *)malloc(h->length + 2 * sizeof(*n)))) { gg_debug(GG_DEBUG_MISC, "-- not enough memory\n"); free(h); return -1; @@ -893,6 +955,12 @@ } } + if (h->type == GG_PONG) { + gg_debug(GG_DEBUG_MISC, "-- received a pong\n"); + + sess->last_pong = time(NULL); + } + free(h); return 0; @@ -944,7 +1012,7 @@ gg_debug(GG_DEBUG_FUNCTION, "** gg_watch_fd(...);\n"); - if (!(e = (void*) malloc(sizeof(*e)))) { + if (!(e = (void *)malloc(sizeof(*e)))) { gg_debug(GG_DEBUG_MISC, "-- not enough memory\n"); return NULL; } @@ -952,15 +1020,16 @@ e->type = GG_EVENT_NONE; switch (sess->state) { - case GG_STATE_RESOLVING: + case GG_STATE_RESOLVING: { struct in_addr a; gg_debug(GG_DEBUG_MISC, "== GG_STATE_RESOLVING\n"); if (read(sess->fd, &a, sizeof(a)) < sizeof(a) || a.s_addr == INADDR_NONE) { - gg_debug(GG_DEBUG_MISC, "-- resolving failed\n"); + gg_debug(GG_DEBUG_MISC, "-- resolving failed\n"); + errno = ENOENT; e->type = GG_EVENT_CONN_FAILED; e->event.failure = GG_FAILURE_RESOLVING; sess->state = GG_STATE_IDLE; @@ -970,6 +1039,8 @@ break; } + sess->server_ip = a.s_addr; + close(sess->fd); waitpid(sess->pid, NULL, 0); @@ -977,50 +1048,83 @@ gg_debug(GG_DEBUG_MISC, "-- resolved, now connecting\n"); if ((sess->fd = gg_connect(&a, GG_APPMSG_PORT, sess->async)) == -1) { - gg_debug(GG_DEBUG_MISC, "-- connection failed\n"); + struct in_addr *addr = (struct in_addr *)&sess->server_ip; + + gg_debug(GG_DEBUG_MISC, + "-- connection failed, trying direct connection\n"); - e->type = GG_EVENT_CONN_FAILED; - e->event.failure = GG_FAILURE_CONNECTING; - sess->state = GG_STATE_IDLE; - break; + if ((sess->fd = gg_connect(addr, GG_DEFAULT_PORT, sess->async)) == -1) { + gg_debug(GG_DEBUG_MISC, + "-- connection failed, trying https connection\n"); + if ((sess->fd = + gg_connect(&a, GG_HTTPS_PORT, sess->async)) == -1) { + gg_debug(GG_DEBUG_MISC, + "-- connect() failed. errno = %d (%s)\n", errno, + strerror(errno)); + + e->type = GG_EVENT_CONN_FAILED; + e->event.failure = GG_FAILURE_CONNECTING; + sess->state = GG_STATE_IDLE; + break; + } + } + sess->state = GG_STATE_CONNECTING_GG; + sess->check = GG_CHECK_WRITE; + } else { + sess->state = GG_STATE_CONNECTING_HTTP; + sess->check = GG_CHECK_WRITE; } - sess->state = GG_STATE_CONNECTING_HTTP; - sess->check = GG_CHECK_WRITE; - break; } - case GG_STATE_CONNECTING_HTTP: + case GG_STATE_CONNECTING_HTTP: { char buf[1024]; int res, res_size = sizeof(res); gg_debug(GG_DEBUG_MISC, "== GG_STATE_CONNECTING_HTTP\n"); - if (sess->async && (getsockopt(sess->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) || res)) { - gg_debug(GG_DEBUG_MISC, "-- http connection failed, errno = %d (%s)\n", res, strerror(res)); + if (sess->async + && (getsockopt(sess->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) || res)) { + struct in_addr *addr = (struct in_addr *)&sess->server_ip; + gg_debug(GG_DEBUG_MISC, + "-- http connection failed, errno = %d (%s), trying direct connection\n", + res, strerror(res)); - errno = res; - e->type = GG_EVENT_CONN_FAILED; - e->event.failure = GG_FAILURE_CONNECTING; - sess->state = GG_STATE_IDLE; + if ((sess->fd = gg_connect(addr, GG_DEFAULT_PORT, sess->async)) == -1) { + gg_debug(GG_DEBUG_MISC, + "-- connection failed, trying https connection\n"); + if ((sess->fd = + gg_connect(addr, GG_HTTPS_PORT, sess->async)) == -1) { + gg_debug(GG_DEBUG_MISC, + "-- connect() failed. errno = %d (%s)\n", errno, + strerror(errno)); + + e->type = GG_EVENT_CONN_FAILED; + e->event.failure = GG_FAILURE_CONNECTING; + sess->state = GG_STATE_IDLE; + break; + } + } + + sess->state = GG_STATE_CONNECTING_GG; + sess->check = GG_CHECK_WRITE; break; } gg_debug(GG_DEBUG_MISC, "-- http connection succeded, sending query\n"); - snprintf(buf, sizeof(buf) - 1, - "GET /appsvc/appmsg.asp?fmnumber=%u HTTP/1.0\r\n" - "Host: " GG_APPMSG_HOST "\r\n" - "User-Agent: Mozilla/4.7 [en] (Win98; I)\r\n" - "Pragma: no-cache\r\n" - "\r\n", sess->uin); + "GET /appsvc/appmsg.asp?fmnumber=%lu HTTP/1.0\r\n" + "Host: " GG_APPMSG_HOST "\r\n" + "User-Agent: " GG_HTTP_USERAGENT "\r\n" + "Pragma: no-cache\r\n" "\r\n", sess->uin); if (write(sess->fd, buf, strlen(buf)) < strlen(buf)) { gg_debug(GG_DEBUG_MISC, "-- sending query failed\n"); + errno = EIO; e->type = GG_EVENT_CONN_FAILED; e->event.failure = GG_FAILURE_WRITING; sess->state = GG_STATE_IDLE; @@ -1033,7 +1137,7 @@ break; } - case GG_STATE_WRITING_HTTP: + case GG_STATE_WRITING_HTTP: { char buf[1024], *tmp, *host; int port = GG_DEFAULT_PORT; @@ -1043,26 +1147,27 @@ gg_read_line(sess->fd, buf, sizeof(buf) - 1); gg_chomp(buf); - + gg_debug(GG_DEBUG_TRAFFIC, "-- got http response (%s)\n", buf); - + if (strncmp(buf, "HTTP/1.", 7) || strncmp(buf + 9, "200", 3)) { gg_debug(GG_DEBUG_MISC, "-- but that's not what we've expected\n"); + errno = EINVAL; e->type = GG_EVENT_CONN_FAILED; e->event.failure = GG_FAILURE_INVALID; sess->state = GG_STATE_IDLE; break; } - + while (strcmp(buf, "\r\n") && strcmp(buf, "")) gg_read_line(sess->fd, buf, sizeof(buf) - 1); gg_read_line(sess->fd, buf, sizeof(buf) - 1); gg_chomp(buf); - + close(sess->fd); - + gg_debug(GG_DEBUG_TRAFFIC, "-- received http data (%s)\n", buf); tmp = buf; @@ -1085,53 +1190,68 @@ if ((tmp = strchr(host, ':'))) { *tmp = 0; - port = atoi(tmp+1); + port = atoi(tmp + 1); } a.s_addr = inet_addr(host); + sess->server_ip = a.s_addr; if ((sess->fd = gg_connect(&a, port, sess->async)) == -1) { - gg_debug(GG_DEBUG_MISC, "-- connect() failed. errno = %d (%s)\n", errno, strerror(errno)); + gg_debug(GG_DEBUG_MISC, + "-- connection failed, trying https connection\n"); + if ((sess->fd = gg_connect(&a, GG_HTTPS_PORT, sess->async)) == -1) { + gg_debug(GG_DEBUG_MISC, + "-- connection failed, errno = %d (%s)\n", errno, + strerror(errno)); - e->type = GG_EVENT_CONN_FAILED; - e->event.failure = GG_FAILURE_CONNECTING; - sess->state = GG_STATE_IDLE; - break; + e->type = GG_EVENT_CONN_FAILED; + e->event.failure = GG_FAILURE_CONNECTING; + sess->state = GG_STATE_IDLE; + break; + } } sess->state = GG_STATE_CONNECTING_GG; sess->check = GG_CHECK_WRITE; - + break; } - case GG_STATE_CONNECTING_GG: + case GG_STATE_CONNECTING_GG: { int res, res_size = sizeof(res); gg_debug(GG_DEBUG_MISC, "== GG_STATE_CONNECTING_GG\n"); - if (sess->async && (getsockopt(sess->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) || res)) { - gg_debug(GG_DEBUG_MISC, "-- connection failed, errno = %d (%s)\n", errno, strerror(errno)); + if (sess->async + && (getsockopt(sess->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) || res)) { + struct in_addr *addr = (struct in_addr *)&sess->server_ip; - errno = res; - e->type = GG_EVENT_CONN_FAILED; - e->event.failure = GG_FAILURE_CONNECTING; - sess->state = GG_STATE_IDLE; - break; + gg_debug(GG_DEBUG_MISC, + "-- connection failed, trying https connection\n"); + if ((sess->fd = gg_connect(addr, GG_HTTPS_PORT, sess->async)) == -1) { + gg_debug(GG_DEBUG_MISC, + "-- connection failed, errno = %d (%s)\n", errno, + strerror(errno)); + + e->type = GG_EVENT_CONN_FAILED; + e->event.failure = GG_FAILURE_CONNECTING; + sess->state = GG_STATE_IDLE; + break; + } } gg_debug(GG_DEBUG_MISC, "-- connected\n"); - + sess->state = GG_STATE_WAITING_FOR_KEY; sess->check = GG_CHECK_READ; break; } - case GG_STATE_WAITING_FOR_KEY: + case GG_STATE_WAITING_FOR_KEY: { - struct gg_header *h; + struct gg_header *h; struct gg_welcome *w; struct gg_login l; unsigned int hash; @@ -1140,7 +1260,8 @@ gg_debug(GG_DEBUG_MISC, "== GG_STATE_WAITING_FOR_KEY\n"); if (!(h = gg_recv_packet(sess))) { - gg_debug(GG_DEBUG_MISC, "-- gg_recv_packet() failed. errno = %d (%s)\n", errno, strerror(errno)); + gg_debug(GG_DEBUG_MISC, "-- gg_recv_packet() failed. errno = %d (%s)\n", + errno, strerror(errno)); e->type = GG_EVENT_CONN_FAILED; e->event.failure = GG_FAILURE_READING; @@ -1148,43 +1269,46 @@ close(sess->fd); break; } - + if (h->type != GG_WELCOME) { gg_debug(GG_DEBUG_MISC, "-- invalid packet received\n"); free(h); close(sess->fd); + errno = EINVAL; e->type = GG_EVENT_CONN_FAILED; e->event.failure = GG_FAILURE_INVALID; sess->state = GG_STATE_IDLE; break; } - - w = (void*) h + sizeof(struct gg_header); + + w = (void *)h + sizeof(struct gg_header); w->key = fix32(w->key); for (hash = 1; *password; password++) hash *= (*password) + 1; hash *= w->key; - - gg_debug(GG_DEBUG_DUMP, "%%%% klucz serwera %.4x, hash hasła %.8x\n", w->key, hash); - + + gg_debug(GG_DEBUG_DUMP, "%%%% klucz serwera %.4x, hash hasła %.8x\n", w->key, + hash); + free(h); free(sess->password); sess->password = NULL; - + l.uin = fix32(sess->uin); l.hash = fix32(hash); - l.status = fix32(GG_STATUS_AVAIL); + l.status = fix32(sess->initial_status ? sess->initial_status : GG_STATUS_AVAIL); l.dunno = fix32(0x0b); l.local_ip = 0; l.local_port = 0; - + gg_debug(GG_DEBUG_TRAFFIC, "-- sending GG_LOGIN packet\n"); if (gg_send_packet(sess->fd, GG_LOGIN, &l, sizeof(l), NULL, 0) == -1) { - gg_debug(GG_DEBUG_TRAFFIC, "-- oops, failed. errno = %d (%s)\n", errno, strerror(errno)); + gg_debug(GG_DEBUG_TRAFFIC, "-- oops, failed. errno = %d (%s)\n", errno, + strerror(errno)); close(sess->fd); e->type = GG_EVENT_CONN_FAILED; @@ -1192,13 +1316,13 @@ sess->state = GG_STATE_IDLE; break; } - + sess->state = GG_STATE_SENDING_KEY; break; } - case GG_STATE_SENDING_KEY: + case GG_STATE_SENDING_KEY: { struct gg_header *h; @@ -1212,11 +1336,12 @@ close(sess->fd); break; } - + if (h->type == GG_LOGIN_OK) { gg_debug(GG_DEBUG_MISC, "-- login succeded\n"); e->type = GG_EVENT_CONN_SUCCESS; sess->state = GG_STATE_CONNECTED; + free(h); break; } @@ -1227,24 +1352,28 @@ } else { gg_debug(GG_DEBUG_MISC, "-- invalid packet\n"); e->event.failure = GG_FAILURE_INVALID; + errno = EINVAL; } e->type = GG_EVENT_CONN_FAILED; sess->state = GG_STATE_IDLE; close(sess->fd); + free(h); break; } - case GG_STATE_CONNECTED: + case GG_STATE_CONNECTED: { gg_debug(GG_DEBUG_MISC, "== GG_STATE_CONNECTED\n"); if ((res = gg_watch_fd_connected(sess, e)) == -1) { - gg_debug(GG_DEBUG_MISC, "-- watch_fd_connected failed. errno = %d (%s)\n", errno, strerror(errno)); + gg_debug(GG_DEBUG_MISC, + "-- watch_fd_connected failed. errno = %d (%s)\n", errno, + strerror(errno)); - if (errno == EAGAIN) { + if (errno == EAGAIN) { e->type = GG_EVENT_NONE; res = 0; } else @@ -1261,5 +1390,3 @@ return e; } - -