|
14192
|
1 /* $Id: common.c 16856 2006-08-19 01:13:25Z evands $ */
|
|
|
2
|
|
|
3 /*
|
|
|
4 * (C) Copyright 2001-2002 Wojtek Kaniewski <wojtekka@irc.pl>
|
|
|
5 * Robert J. Woźny <speedy@ziew.org>
|
|
|
6 *
|
|
|
7 * This program is free software; you can redistribute it and/or modify
|
|
|
8 * it under the terms of the GNU Lesser General Public License Version
|
|
|
9 * 2.1 as published by the Free Software Foundation.
|
|
|
10 *
|
|
|
11 * This program is distributed in the hope that it will be useful,
|
|
|
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
14 * GNU Lesser General Public License for more details.
|
|
|
15 *
|
|
|
16 * You should have received a copy of the GNU Lesser General Public
|
|
|
17 * License along with this program; if not, write to the Free Software
|
|
|
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
|
|
|
19 * USA.
|
|
|
20 */
|
|
|
21
|
|
|
22 #ifndef _WIN32
|
|
|
23 #include <sys/types.h>
|
|
|
24 #include <sys/ioctl.h>
|
|
|
25 #include <sys/socket.h>
|
|
|
26 #include <netinet/in.h>
|
|
|
27 #include <arpa/inet.h>
|
|
|
28 #ifdef sun
|
|
|
29 # include <sys/filio.h>
|
|
|
30 #endif
|
|
|
31 #endif
|
|
|
32
|
|
|
33 #include <errno.h>
|
|
|
34 #include <fcntl.h>
|
|
|
35 #ifndef _WIN32
|
|
|
36 #include <netdb.h>
|
|
|
37 #endif
|
|
|
38 #include <stdarg.h>
|
|
|
39 #include <stdio.h>
|
|
|
40 #include <stdlib.h>
|
|
|
41 #include <string.h>
|
|
|
42 #include <unistd.h>
|
|
|
43
|
|
|
44 #include "libgadu.h"
|
|
|
45
|
|
|
46 FILE *gg_debug_file = NULL;
|
|
|
47
|
|
|
48 #ifndef GG_DEBUG_DISABLE
|
|
|
49
|
|
|
50 /*
|
|
|
51 * gg_debug() // funkcja wewnętrzna
|
|
|
52 *
|
|
|
53 * wyświetla komunikat o danym poziomie, o ile użytkownik sobie tego życzy.
|
|
|
54 *
|
|
|
55 * - level - poziom wiadomości
|
|
|
56 * - format... - treść wiadomości (kompatybilna z printf())
|
|
|
57 */
|
|
|
58 void gg_debug(int level, const char *format, ...)
|
|
|
59 {
|
|
|
60 va_list ap;
|
|
|
61 int old_errno = errno;
|
|
|
62
|
|
|
63 if (gg_debug_handler) {
|
|
|
64 va_start(ap, format);
|
|
|
65 (*gg_debug_handler)(level, format, ap);
|
|
|
66 va_end(ap);
|
|
|
67
|
|
|
68 goto cleanup;
|
|
|
69 }
|
|
|
70
|
|
|
71 if ((gg_debug_level & level)) {
|
|
|
72 va_start(ap, format);
|
|
|
73 vfprintf((gg_debug_file) ? gg_debug_file : stderr, format, ap);
|
|
|
74 va_end(ap);
|
|
|
75 }
|
|
|
76
|
|
|
77 cleanup:
|
|
|
78 errno = old_errno;
|
|
|
79 }
|
|
|
80
|
|
|
81 #endif
|
|
|
82
|
|
|
83 /*
|
|
|
84 * gg_vsaprintf() // funkcja pomocnicza
|
|
|
85 *
|
|
|
86 * robi dokładnie to samo, co vsprintf(), tyle że alokuje sobie wcześniej
|
|
|
87 * miejsce na dane. powinno działać na tych maszynach, które mają funkcję
|
|
|
88 * vsnprintf() zgodną z C99, jak i na wcześniejszych.
|
|
|
89 *
|
|
|
90 * - format - opis wyświetlanego tekstu jak dla printf()
|
|
|
91 * - ap - lista argumentów dla printf()
|
|
|
92 *
|
|
|
93 * zaalokowany bufor, który należy później zwolnić, lub NULL
|
|
|
94 * jeśli nie udało się wykonać zadania.
|
|
|
95 */
|
|
|
96 char *gg_vsaprintf(const char *format, va_list ap)
|
|
|
97 {
|
|
|
98 int size = 0;
|
|
|
99 const char *start;
|
|
|
100 char *buf = NULL;
|
|
|
101
|
|
|
102 #ifdef __GG_LIBGADU_HAVE_VA_COPY
|
|
|
103 va_list aq;
|
|
|
104
|
|
|
105 va_copy(aq, ap);
|
|
|
106 #else
|
|
|
107 # ifdef __GG_LIBGADU_HAVE___VA_COPY
|
|
|
108 va_list aq;
|
|
|
109
|
|
|
110 __va_copy(aq, ap);
|
|
|
111 # endif
|
|
|
112 #endif
|
|
|
113
|
|
|
114 start = format;
|
|
|
115
|
|
|
116 #ifndef __GG_LIBGADU_HAVE_C99_VSNPRINTF
|
|
|
117 {
|
|
|
118 int res;
|
|
|
119 char *tmp;
|
|
|
120
|
|
|
121 size = 128;
|
|
|
122 do {
|
|
|
123 size *= 2;
|
|
|
124 if (!(tmp = realloc(buf, size))) {
|
|
|
125 free(buf);
|
|
|
126 return NULL;
|
|
|
127 }
|
|
|
128 buf = tmp;
|
|
|
129 res = vsnprintf(buf, size, format, ap);
|
|
|
130 } while (res == size - 1 || res == -1);
|
|
|
131 }
|
|
|
132 #else
|
|
|
133 {
|
|
|
134 char tmp[2];
|
|
|
135
|
|
|
136 /* libce Solarisa przy buforze NULL zawsze zwracają -1, więc
|
|
|
137 * musimy podać coś istniejącego jako cel printf()owania. */
|
|
|
138 size = vsnprintf(tmp, sizeof(tmp), format, ap);
|
|
|
139 if (!(buf = malloc(size + 1)))
|
|
|
140 return NULL;
|
|
|
141 }
|
|
|
142 #endif
|
|
|
143
|
|
|
144 format = start;
|
|
|
145
|
|
|
146 #ifdef __GG_LIBGADU_HAVE_VA_COPY
|
|
|
147 vsnprintf(buf, size + 1, format, aq);
|
|
|
148 va_end(aq);
|
|
|
149 #else
|
|
|
150 # ifdef __GG_LIBGADU_HAVE___VA_COPY
|
|
|
151 vsnprintf(buf, size + 1, format, aq);
|
|
|
152 va_end(aq);
|
|
|
153 # else
|
|
|
154 vsnprintf(buf, size + 1, format, ap);
|
|
|
155 # endif
|
|
|
156 #endif
|
|
|
157
|
|
|
158 return buf;
|
|
|
159 }
|
|
|
160
|
|
|
161 /*
|
|
|
162 * gg_saprintf() // funkcja pomocnicza
|
|
|
163 *
|
|
|
164 * robi dokładnie to samo, co sprintf(), tyle że alokuje sobie wcześniej
|
|
|
165 * miejsce na dane. powinno działać na tych maszynach, które mają funkcję
|
|
|
166 * vsnprintf() zgodną z C99, jak i na wcześniejszych.
|
|
|
167 *
|
|
|
168 * - format... - treść taka sama jak w funkcji printf()
|
|
|
169 *
|
|
|
170 * zaalokowany bufor, który należy później zwolnić, lub NULL
|
|
|
171 * jeśli nie udało się wykonać zadania.
|
|
|
172 */
|
|
|
173 char *gg_saprintf(const char *format, ...)
|
|
|
174 {
|
|
|
175 va_list ap;
|
|
|
176 char *res;
|
|
|
177
|
|
|
178 va_start(ap, format);
|
|
|
179 res = gg_vsaprintf(format, ap);
|
|
|
180 va_end(ap);
|
|
|
181
|
|
|
182 return res;
|
|
|
183 }
|
|
|
184
|
|
|
185 /*
|
|
|
186 * gg_get_line() // funkcja pomocnicza
|
|
|
187 *
|
|
|
188 * podaje kolejną linię z bufora tekstowego. niszczy go bezpowrotnie, dzieląc
|
|
|
189 * na kolejne stringi. zdarza się, nie ma potrzeby pisania funkcji dublującej
|
|
|
190 * bufor żeby tylko mieć nieruszone dane wejściowe, skoro i tak nie będą nam
|
|
|
191 * poźniej potrzebne. obcina `\r\n'.
|
|
|
192 *
|
|
|
193 * - ptr - wskaźnik do zmiennej, która przechowuje aktualną pozycję
|
|
|
194 * w przemiatanym buforze
|
|
|
195 *
|
|
|
196 * wskaźnik do kolejnej linii tekstu lub NULL, jeśli to już koniec bufora.
|
|
|
197 */
|
|
|
198 char *gg_get_line(char **ptr)
|
|
|
199 {
|
|
|
200 char *foo, *res;
|
|
|
201
|
|
|
202 if (!ptr || !*ptr || !strcmp(*ptr, ""))
|
|
|
203 return NULL;
|
|
|
204
|
|
|
205 res = *ptr;
|
|
|
206
|
|
|
207 if (!(foo = strchr(*ptr, '\n')))
|
|
|
208 *ptr += strlen(*ptr);
|
|
|
209 else {
|
|
|
210 *ptr = foo + 1;
|
|
|
211 *foo = 0;
|
|
|
212 if (strlen(res) > 1 && res[strlen(res) - 1] == '\r')
|
|
|
213 res[strlen(res) - 1] = 0;
|
|
|
214 }
|
|
|
215
|
|
|
216 return res;
|
|
|
217 }
|
|
|
218
|
|
|
219 /*
|
|
|
220 * gg_connect() // funkcja pomocnicza
|
|
|
221 *
|
|
|
222 * łączy się z serwerem. pierwszy argument jest typu (void *), żeby nie
|
|
|
223 * musieć niczego inkludować w libgadu.h i nie psuć jakiś głupich zależności
|
|
|
224 * na dziwnych systemach.
|
|
|
225 *
|
|
|
226 * - addr - adres serwera (struct in_addr *)
|
|
|
227 * - port - port serwera
|
|
|
228 * - async - asynchroniczne połączenie
|
|
|
229 *
|
|
|
230 * deskryptor gniazda lub -1 w przypadku błędu (kod błędu w zmiennej errno).
|
|
|
231 */
|
|
|
232 int gg_connect(void *addr, int port, int async)
|
|
|
233 {
|
|
|
234 int sock, one = 1, errno2;
|
|
|
235 struct sockaddr_in sin;
|
|
|
236 struct in_addr *a = addr;
|
|
|
237 struct sockaddr_in myaddr;
|
|
|
238
|
|
|
239 gg_debug(GG_DEBUG_FUNCTION, "** gg_connect(%s, %d, %d);\n", inet_ntoa(*a), port, async);
|
|
|
240
|
|
|
241 if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
|
|
|
242 gg_debug(GG_DEBUG_MISC, "// gg_connect() socket() failed (errno=%d, %s)\n", errno, strerror(errno));
|
|
|
243 return -1;
|
|
|
244 }
|
|
|
245
|
|
|
246 memset(&myaddr, 0, sizeof(myaddr));
|
|
|
247 myaddr.sin_family = AF_INET;
|
|
|
248
|
|
|
249 myaddr.sin_addr.s_addr = gg_local_ip;
|
|
|
250
|
|
|
251 if (bind(sock, (struct sockaddr *) &myaddr, sizeof(myaddr)) == -1) {
|
|
|
252 gg_debug(GG_DEBUG_MISC, "// gg_connect() bind() failed (errno=%d, %s)\n", errno, strerror(errno));
|
|
|
253 return -1;
|
|
|
254 }
|
|
|
255
|
|
|
256 #ifdef ASSIGN_SOCKETS_TO_THREADS
|
|
|
257 gg_win32_thread_socket(0, sock);
|
|
|
258 #endif
|
|
|
259
|
|
|
260 if (async) {
|
|
|
261 #ifdef FIONBIO
|
|
|
262 if (ioctl(sock, FIONBIO, &one) == -1) {
|
|
|
263 #else
|
|
|
264 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
|
|
|
265 #endif
|
|
|
266 gg_debug(GG_DEBUG_MISC, "// gg_connect() ioctl() failed (errno=%d, %s)\n", errno, strerror(errno));
|
|
|
267 errno2 = errno;
|
|
|
268 close(sock);
|
|
|
269 errno = errno2;
|
|
|
270 return -1;
|
|
|
271 }
|
|
|
272 }
|
|
|
273
|
|
|
274 sin.sin_port = htons(port);
|
|
|
275 sin.sin_family = AF_INET;
|
|
|
276 sin.sin_addr.s_addr = a->s_addr;
|
|
|
277
|
|
|
278 if (connect(sock, (struct sockaddr*) &sin, sizeof(sin)) == -1) {
|
|
|
279 if (errno && (!async || errno != EINPROGRESS)) {
|
|
|
280 gg_debug(GG_DEBUG_MISC, "// gg_connect() connect() failed (errno=%d, %s)\n", errno, strerror(errno));
|
|
|
281 errno2 = errno;
|
|
|
282 close(sock);
|
|
|
283 errno = errno2;
|
|
|
284 return -1;
|
|
|
285 }
|
|
|
286 gg_debug(GG_DEBUG_MISC, "// gg_connect() connect() in progress\n");
|
|
|
287 }
|
|
|
288
|
|
|
289 return sock;
|
|
|
290 }
|
|
|
291
|
|
|
292 /*
|
|
|
293 * gg_read_line() // funkcja pomocnicza
|
|
|
294 *
|
|
|
295 * czyta jedną linię tekstu z gniazda.
|
|
|
296 *
|
|
|
297 * - sock - deskryptor gniazda
|
|
|
298 * - buf - wskaźnik do bufora
|
|
|
299 * - length - długość bufora
|
|
|
300 *
|
|
|
301 * jeśli trafi na błąd odczytu lub podano nieprawidłowe parametry, zwraca NULL.
|
|
|
302 * inaczej zwraca buf.
|
|
|
303 */
|
|
|
304 char *gg_read_line(int sock, char *buf, int length)
|
|
|
305 {
|
|
|
306 int ret;
|
|
|
307
|
|
|
308 if (!buf || length < 0)
|
|
|
309 return NULL;
|
|
|
310
|
|
|
311 for (; length > 1; buf++, length--) {
|
|
|
312 do {
|
|
|
313 if ((ret = read(sock, buf, 1)) == -1 && errno != EINTR) {
|
|
|
314 gg_debug(GG_DEBUG_MISC, "// gg_read_line() error on read (errno=%d, %s)\n", errno, strerror(errno));
|
|
|
315 *buf = 0;
|
|
|
316 return NULL;
|
|
|
317 } else if (ret == 0) {
|
|
|
318 gg_debug(GG_DEBUG_MISC, "// gg_read_line() eof reached\n");
|
|
|
319 *buf = 0;
|
|
|
320 return NULL;
|
|
|
321 }
|
|
|
322 } while (ret == -1 && errno == EINTR);
|
|
|
323
|
|
|
324 if (*buf == '\n') {
|
|
|
325 buf++;
|
|
|
326 break;
|
|
|
327 }
|
|
|
328 }
|
|
|
329
|
|
|
330 *buf = 0;
|
|
|
331 return buf;
|
|
|
332 }
|
|
|
333
|
|
|
334 /*
|
|
|
335 * gg_chomp() // funkcja pomocnicza
|
|
|
336 *
|
|
|
337 * ucina "\r\n" lub "\n" z końca linii.
|
|
|
338 *
|
|
|
339 * - line - linia do przycięcia
|
|
|
340 */
|
|
|
341 void gg_chomp(char *line)
|
|
|
342 {
|
|
|
343 int len;
|
|
|
344
|
|
|
345 if (!line)
|
|
|
346 return;
|
|
|
347
|
|
|
348 len = strlen(line);
|
|
|
349
|
|
|
350 if (len > 0 && line[len - 1] == '\n')
|
|
|
351 line[--len] = 0;
|
|
|
352 if (len > 0 && line[len - 1] == '\r')
|
|
|
353 line[--len] = 0;
|
|
|
354 }
|
|
|
355
|
|
|
356 /*
|
|
|
357 * gg_urlencode() // funkcja wewnętrzna
|
|
|
358 *
|
|
|
359 * zamienia podany tekst na ciąg znaków do formularza http. przydaje się
|
|
|
360 * przy różnych usługach katalogu publicznego.
|
|
|
361 *
|
|
|
362 * - str - ciąg znaków do zakodowania
|
|
|
363 *
|
|
|
364 * zaalokowany bufor, który należy później zwolnić albo NULL
|
|
|
365 * w przypadku błędu.
|
|
|
366 */
|
|
|
367 char *gg_urlencode(const char *str)
|
|
|
368 {
|
|
|
369 char *q, *buf, hex[] = "0123456789abcdef";
|
|
|
370 const char *p;
|
|
|
371 unsigned int size = 0;
|
|
|
372
|
|
|
373 if (!str)
|
|
|
374 str = "";
|
|
|
375
|
|
|
376 for (p = str; *p; p++, size++) {
|
|
|
377 if (!((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9') || *p == ' ') || (*p == '@') || (*p == '.') || (*p == '-'))
|
|
|
378 size += 2;
|
|
|
379 }
|
|
|
380
|
|
|
381 if (!(buf = malloc(size + 1)))
|
|
|
382 return NULL;
|
|
|
383
|
|
|
384 for (p = str, q = buf; *p; p++, q++) {
|
|
|
385 if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9') || (*p == '@') || (*p == '.') || (*p == '-'))
|
|
|
386 *q = *p;
|
|
|
387 else {
|
|
|
388 if (*p == ' ')
|
|
|
389 *q = '+';
|
|
|
390 else {
|
|
|
391 *q++ = '%';
|
|
|
392 *q++ = hex[*p >> 4 & 15];
|
|
|
393 *q = hex[*p & 15];
|
|
|
394 }
|
|
|
395 }
|
|
|
396 }
|
|
|
397
|
|
|
398 *q = 0;
|
|
|
399
|
|
|
400 return buf;
|
|
|
401 }
|
|
|
402
|
|
|
403 /*
|
|
|
404 * gg_http_hash() // funkcja wewnętrzna
|
|
|
405 *
|
|
|
406 * funkcja licząca hash dla adresu e-mail, hasła i paru innych.
|
|
|
407 *
|
|
|
408 * - format... - format kolejnych parametrów ('s' jeśli dany parametr jest
|
|
|
409 * ciągiem znaków lub 'u' jeśli numerem GG)
|
|
|
410 *
|
|
|
411 * hash wykorzystywany przy rejestracji i wszelkich manipulacjach własnego
|
|
|
412 * wpisu w katalogu publicznym.
|
|
|
413 */
|
|
|
414 int gg_http_hash(const char *format, ...)
|
|
|
415 {
|
|
|
416 unsigned int a, c, i, j;
|
|
|
417 va_list ap;
|
|
|
418 int b = -1;
|
|
|
419
|
|
|
420 va_start(ap, format);
|
|
|
421
|
|
|
422 for (j = 0; j < strlen(format); j++) {
|
|
|
423 char *arg, buf[16];
|
|
|
424
|
|
|
425 if (format[j] == 'u') {
|
|
|
426 snprintf(buf, sizeof(buf), "%d", va_arg(ap, uin_t));
|
|
|
427 arg = buf;
|
|
|
428 } else {
|
|
|
429 if (!(arg = va_arg(ap, char*)))
|
|
|
430 arg = "";
|
|
|
431 }
|
|
|
432
|
|
|
433 i = 0;
|
|
|
434 while ((c = (unsigned char) arg[i++]) != 0) {
|
|
|
435 a = (c ^ b) + (c << 8);
|
|
|
436 b = (a >> 24) | (a << 8);
|
|
|
437 }
|
|
|
438 }
|
|
|
439
|
|
|
440 va_end(ap);
|
|
|
441
|
|
|
442 return (b < 0 ? -b : b);
|
|
|
443 }
|
|
|
444
|
|
|
445 /*
|
|
|
446 * gg_gethostbyname() // funkcja pomocnicza
|
|
|
447 *
|
|
|
448 * odpowiednik gethostbyname() troszczący się o współbieżność, gdy mamy do
|
|
|
449 * dyspozycji funkcję gethostbyname_r().
|
|
|
450 *
|
|
|
451 * - hostname - nazwa serwera
|
|
|
452 *
|
|
|
453 * zwraca wskaźnik na strukturę in_addr, którą należy zwolnić.
|
|
|
454 */
|
|
|
455 struct in_addr *gg_gethostbyname(const char *hostname)
|
|
|
456 {
|
|
|
457 struct in_addr *addr = NULL;
|
|
|
458
|
|
|
459 #ifdef HAVE_GETHOSTBYNAME_R
|
|
|
460 char *tmpbuf = NULL, *buf = NULL;
|
|
|
461 struct hostent *hp = NULL, *hp2 = NULL;
|
|
|
462 int h_errnop, ret;
|
|
|
463 size_t buflen = 1024;
|
|
|
464 int new_errno;
|
|
|
465
|
|
|
466 new_errno = ENOMEM;
|
|
|
467
|
|
|
468 if (!(addr = malloc(sizeof(struct in_addr))))
|
|
|
469 goto cleanup;
|
|
|
470
|
|
|
471 if (!(hp = calloc(1, sizeof(*hp))))
|
|
|
472 goto cleanup;
|
|
|
473
|
|
|
474 if (!(buf = malloc(buflen)))
|
|
|
475 goto cleanup;
|
|
|
476
|
|
|
477 tmpbuf = buf;
|
|
|
478
|
|
|
479 while ((ret = gethostbyname_r(hostname, hp, buf, buflen, &hp2, &h_errnop)) == ERANGE) {
|
|
|
480 buflen *= 2;
|
|
|
481
|
|
|
482 if (!(tmpbuf = realloc(buf, buflen)))
|
|
|
483 break;
|
|
|
484
|
|
|
485 buf = tmpbuf;
|
|
|
486 }
|
|
|
487
|
|
|
488 if (ret)
|
|
|
489 new_errno = h_errnop;
|
|
|
490
|
|
|
491 if (ret || !hp2 || !tmpbuf)
|
|
|
492 goto cleanup;
|
|
|
493
|
|
|
494 memcpy(addr, hp->h_addr, sizeof(struct in_addr));
|
|
|
495
|
|
|
496 free(buf);
|
|
|
497 free(hp);
|
|
|
498
|
|
|
499 return addr;
|
|
|
500
|
|
|
501 cleanup:
|
|
|
502 errno = new_errno;
|
|
|
503
|
|
|
504 if (addr)
|
|
|
505 free(addr);
|
|
|
506 if (hp)
|
|
|
507 free(hp);
|
|
|
508 if (buf)
|
|
|
509 free(buf);
|
|
|
510
|
|
|
511 return NULL;
|
|
|
512 #else
|
|
|
513 struct hostent *hp;
|
|
|
514
|
|
|
515 if (!(addr = malloc(sizeof(struct in_addr)))) {
|
|
|
516 goto cleanup;
|
|
|
517 }
|
|
|
518
|
|
|
519 if (!(hp = gethostbyname(hostname)))
|
|
|
520 goto cleanup;
|
|
|
521
|
|
|
522 memcpy(addr, hp->h_addr, sizeof(struct in_addr));
|
|
|
523
|
|
|
524 return addr;
|
|
|
525
|
|
|
526 cleanup:
|
|
|
527 if (addr)
|
|
|
528 free(addr);
|
|
|
529
|
|
|
530 return NULL;
|
|
|
531 #endif
|
|
|
532 }
|
|
|
533
|
|
|
534 #ifdef ASSIGN_SOCKETS_TO_THREADS
|
|
|
535
|
|
|
536 typedef struct gg_win32_thread {
|
|
|
537 int id;
|
|
|
538 int socket;
|
|
|
539 struct gg_win32_thread *next;
|
|
|
540 } gg_win32_thread;
|
|
|
541
|
|
|
542 struct gg_win32_thread *gg_win32_threads = 0;
|
|
|
543
|
|
|
544 /*
|
|
|
545 * gg_win32_thread_socket() // funkcja pomocnicza, tylko dla win32
|
|
|
546 *
|
|
|
547 * zwraca deskryptor gniazda, które było ostatnio tworzone dla wątku
|
|
|
548 * o podanym identyfikatorze.
|
|
|
549 *
|
|
|
550 * jeśli na win32 przy połączeniach synchronicznych zapamiętamy w jakim
|
|
|
551 * wątku uruchomiliśmy funkcję, która się z czymkolwiek łączy, to z osobnego
|
|
|
552 * wątku możemy anulować połączenie poprzez gg_win32_thread_socket(watek, -1);
|
|
|
553 *
|
|
|
554 * - thread_id - id wątku. jeśli jest równe 0, brany jest aktualny wątek,
|
|
|
555 * jeśli równe -1, usuwa wpis o podanym sockecie.
|
|
|
556 * - socket - deskryptor gniazda. jeśli równe 0, zwraca deskryptor gniazda
|
|
|
557 * dla podanego wątku, jeśli równe -1, usuwa wpis, jeśli coś
|
|
|
558 * innego, ustawia dla podanego wątku dany numer deskryptora.
|
|
|
559 *
|
|
|
560 * jeśli socket jest równe 0, zwraca deskryptor gniazda dla podanego wątku.
|
|
|
561 */
|
|
|
562 int gg_win32_thread_socket(int thread_id, int socket)
|
|
|
563 {
|
|
|
564 char close = (thread_id == -1) || socket == -1;
|
|
|
565 gg_win32_thread *wsk = gg_win32_threads;
|
|
|
566 gg_win32_thread **p_wsk = &gg_win32_threads;
|
|
|
567
|
|
|
568 if (!thread_id)
|
|
|
569 thread_id = GetCurrentThreadId();
|
|
|
570
|
|
|
571 while (wsk) {
|
|
|
572 if ((thread_id == -1 && wsk->socket == socket) || wsk->id == thread_id) {
|
|
|
573 if (close) {
|
|
|
574 /* socket zostaje usuniety */
|
|
|
575 closesocket(wsk->socket);
|
|
|
576 *p_wsk = wsk->next;
|
|
|
577 free(wsk);
|
|
|
578 return 1;
|
|
|
579 } else if (!socket) {
|
|
|
580 /* socket zostaje zwrocony */
|
|
|
581 return wsk->socket;
|
|
|
582 } else {
|
|
|
583 /* socket zostaje ustawiony */
|
|
|
584 wsk->socket = socket;
|
|
|
585 return socket;
|
|
|
586 }
|
|
|
587 }
|
|
|
588 p_wsk = &(wsk->next);
|
|
|
589 wsk = wsk->next;
|
|
|
590 }
|
|
|
591
|
|
|
592 if (close && socket != -1)
|
|
|
593 closesocket(socket);
|
|
|
594 if (close || !socket)
|
|
|
595 return 0;
|
|
|
596
|
|
|
597 /* Dodaje nowy element */
|
|
|
598 wsk = malloc(sizeof(gg_win32_thread));
|
|
|
599 wsk->id = thread_id;
|
|
|
600 wsk->socket = socket;
|
|
|
601 wsk->next = 0;
|
|
|
602 *p_wsk = wsk;
|
|
|
603
|
|
|
604 return socket;
|
|
|
605 }
|
|
|
606
|
|
|
607 #endif /* ASSIGN_SOCKETS_TO_THREADS */
|
|
|
608
|
|
|
609 static char gg_base64_charset[] =
|
|
|
610 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
|
611
|
|
|
612 /*
|
|
|
613 * gg_base64_encode()
|
|
|
614 *
|
|
|
615 * zapisuje ciąg znaków w base64.
|
|
|
616 *
|
|
|
617 * - buf - ciąg znaków.
|
|
|
618 *
|
|
|
619 * zaalokowany bufor.
|
|
|
620 */
|
|
|
621 char *gg_base64_encode(const char *buf)
|
|
|
622 {
|
|
|
623 char *out, *res;
|
|
|
624 unsigned int i = 0, j = 0, k = 0, len = strlen(buf);
|
|
|
625
|
|
|
626 res = out = malloc((len / 3 + 1) * 4 + 2);
|
|
|
627
|
|
|
628 if (!res)
|
|
|
629 return NULL;
|
|
|
630
|
|
|
631 while (j <= len) {
|
|
|
632 switch (i % 4) {
|
|
|
633 case 0:
|
|
|
634 k = (buf[j] & 252) >> 2;
|
|
|
635 break;
|
|
|
636 case 1:
|
|
|
637 if (j < len)
|
|
|
638 k = ((buf[j] & 3) << 4) | ((buf[j + 1] & 240) >> 4);
|
|
|
639 else
|
|
|
640 k = (buf[j] & 3) << 4;
|
|
|
641
|
|
|
642 j++;
|
|
|
643 break;
|
|
|
644 case 2:
|
|
|
645 if (j < len)
|
|
|
646 k = ((buf[j] & 15) << 2) | ((buf[j + 1] & 192) >> 6);
|
|
|
647 else
|
|
|
648 k = (buf[j] & 15) << 2;
|
|
|
649
|
|
|
650 j++;
|
|
|
651 break;
|
|
|
652 case 3:
|
|
|
653 k = buf[j++] & 63;
|
|
|
654 break;
|
|
|
655 }
|
|
|
656 *out++ = gg_base64_charset[k];
|
|
|
657 i++;
|
|
|
658 }
|
|
|
659
|
|
|
660 if (i % 4)
|
|
|
661 for (j = 0; j < 4 - (i % 4); j++, out++)
|
|
|
662 *out = '=';
|
|
|
663
|
|
|
664 *out = 0;
|
|
|
665
|
|
|
666 return res;
|
|
|
667 }
|
|
|
668
|
|
|
669 /*
|
|
|
670 * gg_base64_decode()
|
|
|
671 *
|
|
|
672 * dekoduje ciąg znaków z base64.
|
|
|
673 *
|
|
|
674 * - buf - ciąg znaków.
|
|
|
675 *
|
|
|
676 * zaalokowany bufor.
|
|
|
677 */
|
|
|
678 char *gg_base64_decode(const char *buf)
|
|
|
679 {
|
|
|
680 char *res, *save, *foo, val;
|
|
|
681 const char *end;
|
|
|
682 unsigned int index = 0;
|
|
|
683
|
|
|
684 if (!buf)
|
|
|
685 return NULL;
|
|
|
686
|
|
|
687 save = res = calloc(1, (strlen(buf) / 4 + 1) * 3 + 2);
|
|
|
688
|
|
|
689 if (!save)
|
|
|
690 return NULL;
|
|
|
691
|
|
|
692 end = buf + strlen(buf);
|
|
|
693
|
|
|
694 while (*buf && buf < end) {
|
|
|
695 if (*buf == '\r' || *buf == '\n') {
|
|
|
696 buf++;
|
|
|
697 continue;
|
|
|
698 }
|
|
|
699 if (!(foo = strchr(gg_base64_charset, *buf)))
|
|
|
700 foo = gg_base64_charset;
|
|
|
701 val = (int)(foo - gg_base64_charset);
|
|
|
702 buf++;
|
|
|
703 switch (index) {
|
|
|
704 case 0:
|
|
|
705 *res |= val << 2;
|
|
|
706 break;
|
|
|
707 case 1:
|
|
|
708 *res++ |= val >> 4;
|
|
|
709 *res |= val << 4;
|
|
|
710 break;
|
|
|
711 case 2:
|
|
|
712 *res++ |= val >> 2;
|
|
|
713 *res |= val << 6;
|
|
|
714 break;
|
|
|
715 case 3:
|
|
|
716 *res++ |= val;
|
|
|
717 break;
|
|
|
718 }
|
|
|
719 index++;
|
|
|
720 index %= 4;
|
|
|
721 }
|
|
|
722 *res = 0;
|
|
|
723
|
|
|
724 return save;
|
|
|
725 }
|
|
|
726
|
|
|
727 /*
|
|
|
728 * gg_proxy_auth() // funkcja wewnętrzna
|
|
|
729 *
|
|
|
730 * tworzy nagłówek autoryzacji dla proxy.
|
|
|
731 *
|
|
|
732 * zaalokowany tekst lub NULL, jeśli proxy nie jest włączone lub nie wymaga
|
|
|
733 * autoryzacji.
|
|
|
734 */
|
|
|
735 char *gg_proxy_auth()
|
|
|
736 {
|
|
|
737 char *tmp, *enc, *out;
|
|
|
738 unsigned int tmp_size;
|
|
|
739
|
|
|
740 if (!gg_proxy_enabled || !gg_proxy_username || !gg_proxy_password)
|
|
|
741 return NULL;
|
|
|
742
|
|
|
743 if (!(tmp = malloc((tmp_size = strlen(gg_proxy_username) + strlen(gg_proxy_password) + 2))))
|
|
|
744 return NULL;
|
|
|
745
|
|
|
746 snprintf(tmp, tmp_size, "%s:%s", gg_proxy_username, gg_proxy_password);
|
|
|
747
|
|
|
748 if (!(enc = gg_base64_encode(tmp))) {
|
|
|
749 free(tmp);
|
|
|
750 return NULL;
|
|
|
751 }
|
|
|
752
|
|
|
753 free(tmp);
|
|
|
754
|
|
|
755 if (!(out = malloc(strlen(enc) + 40))) {
|
|
|
756 free(enc);
|
|
|
757 return NULL;
|
|
|
758 }
|
|
|
759
|
|
|
760 snprintf(out, strlen(enc) + 40, "Proxy-Authorization: Basic %s\r\n", enc);
|
|
|
761
|
|
|
762 free(enc);
|
|
|
763
|
|
|
764 return out;
|
|
|
765 }
|
|
|
766
|
|
|
767 static uint32_t gg_crc32_table[256];
|
|
|
768 static int gg_crc32_initialized = 0;
|
|
|
769
|
|
|
770 /*
|
|
|
771 * gg_crc32_make_table() // funkcja wewnętrzna
|
|
|
772 */
|
|
|
773 static void gg_crc32_make_table()
|
|
|
774 {
|
|
|
775 uint32_t h = 1;
|
|
|
776 unsigned int i, j;
|
|
|
777
|
|
|
778 memset(gg_crc32_table, 0, sizeof(gg_crc32_table));
|
|
|
779
|
|
|
780 for (i = 128; i; i >>= 1) {
|
|
|
781 h = (h >> 1) ^ ((h & 1) ? 0xedb88320L : 0);
|
|
|
782
|
|
|
783 for (j = 0; j < 256; j += 2 * i)
|
|
|
784 gg_crc32_table[i + j] = gg_crc32_table[j] ^ h;
|
|
|
785 }
|
|
|
786
|
|
|
787 gg_crc32_initialized = 1;
|
|
|
788 }
|
|
|
789
|
|
|
790 /*
|
|
|
791 * gg_crc32()
|
|
|
792 *
|
|
|
793 * wyznacza sumę kontrolną CRC32 danego bloku danych.
|
|
|
794 *
|
|
|
795 * - crc - suma kontrola poprzedniego bloku danych lub 0 jeśli pierwszy
|
|
|
796 * - buf - bufor danych
|
|
|
797 * - size - ilość danych
|
|
|
798 *
|
|
|
799 * suma kontrolna CRC32.
|
|
|
800 */
|
|
|
801 uint32_t gg_crc32(uint32_t crc, const unsigned char *buf, int len)
|
|
|
802 {
|
|
|
803 if (!gg_crc32_initialized)
|
|
|
804 gg_crc32_make_table();
|
|
|
805
|
|
|
806 if (!buf || len < 0)
|
|
|
807 return crc;
|
|
|
808
|
|
|
809 crc ^= 0xffffffffL;
|
|
|
810
|
|
|
811 while (len--)
|
|
|
812 crc = (crc >> 8) ^ gg_crc32_table[(crc ^ *buf++) & 0xff];
|
|
|
813
|
|
|
814 return crc ^ 0xffffffffL;
|
|
|
815 }
|
|
|
816
|
|
|
817
|
|
|
818 /*
|
|
|
819 * Local variables:
|
|
|
820 * c-indentation-style: k&r
|
|
|
821 * c-basic-offset: 8
|
|
|
822 * indent-tabs-mode: notnil
|
|
|
823 * End:
|
|
|
824 *
|
|
|
825 * vim: shiftwidth=8:
|
|
|
826 */
|