Mercurial > pidgin.yaz
comparison libpurple/protocols/gg/lib/resolver.c @ 32763:326591e64aaa
Gadu-Gadu: move our win32 resolver out of libgadu sources. Refs #343
author | tomkiewicz@cpw.pidgin.im |
---|---|
date | Mon, 17 Oct 2011 21:25:53 +0000 |
parents | b8646c6ae19a |
children | ef01f180114b |
comparison
equal
deleted
inserted
replaced
32762:9c9143e32b6c | 32763:326591e64aaa |
---|---|
317 */ | 317 */ |
318 struct gg_resolver_fork_data { | 318 struct gg_resolver_fork_data { |
319 int pid; /*< Identyfikator procesu */ | 319 int pid; /*< Identyfikator procesu */ |
320 }; | 320 }; |
321 | 321 |
322 #ifdef _WIN32 | |
323 /** | |
324 * Deal with the fact that you can't select() on a win32 file fd. | |
325 * This makes it practically impossible to tie into purple's event loop. | |
326 * | |
327 * -This is thanks to Tor Lillqvist. | |
328 * XXX - Move this to where the rest of the the win32 compatiblity stuff goes when we push the changes back to libgadu. | |
329 */ | |
330 static int | |
331 socket_pipe (int *fds) | |
332 { | |
333 SOCKET temp, socket1 = -1, socket2 = -1; | |
334 struct sockaddr_in saddr; | |
335 int len; | |
336 u_long arg; | |
337 fd_set read_set, write_set; | |
338 struct timeval tv; | |
339 | |
340 temp = socket(AF_INET, SOCK_STREAM, 0); | |
341 | |
342 if (temp == INVALID_SOCKET) { | |
343 goto out0; | |
344 } | |
345 | |
346 arg = 1; | |
347 if (ioctlsocket(temp, FIONBIO, &arg) == SOCKET_ERROR) { | |
348 goto out0; | |
349 } | |
350 | |
351 memset(&saddr, 0, sizeof(saddr)); | |
352 saddr.sin_family = AF_INET; | |
353 saddr.sin_port = 0; | |
354 saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); | |
355 | |
356 if (bind(temp, (struct sockaddr *)&saddr, sizeof (saddr))) { | |
357 goto out0; | |
358 } | |
359 | |
360 if (listen(temp, 1) == SOCKET_ERROR) { | |
361 goto out0; | |
362 } | |
363 | |
364 len = sizeof(saddr); | |
365 if (getsockname(temp, (struct sockaddr *)&saddr, &len)) { | |
366 goto out0; | |
367 } | |
368 | |
369 socket1 = socket(AF_INET, SOCK_STREAM, 0); | |
370 | |
371 if (socket1 == INVALID_SOCKET) { | |
372 goto out0; | |
373 } | |
374 | |
375 arg = 1; | |
376 if (ioctlsocket(socket1, FIONBIO, &arg) == SOCKET_ERROR) { | |
377 goto out1; | |
378 } | |
379 | |
380 if (connect(socket1, (struct sockaddr *)&saddr, len) != SOCKET_ERROR || | |
381 WSAGetLastError() != WSAEWOULDBLOCK) { | |
382 goto out1; | |
383 } | |
384 | |
385 FD_ZERO(&read_set); | |
386 FD_SET(temp, &read_set); | |
387 | |
388 tv.tv_sec = 0; | |
389 tv.tv_usec = 0; | |
390 | |
391 if (select(0, &read_set, NULL, NULL, NULL) == SOCKET_ERROR) { | |
392 goto out1; | |
393 } | |
394 | |
395 if (!FD_ISSET(temp, &read_set)) { | |
396 goto out1; | |
397 } | |
398 | |
399 socket2 = accept(temp, (struct sockaddr *) &saddr, &len); | |
400 if (socket2 == INVALID_SOCKET) { | |
401 goto out1; | |
402 } | |
403 | |
404 FD_ZERO(&write_set); | |
405 FD_SET(socket1, &write_set); | |
406 | |
407 tv.tv_sec = 0; | |
408 tv.tv_usec = 0; | |
409 | |
410 if (select(0, NULL, &write_set, NULL, NULL) == SOCKET_ERROR) { | |
411 goto out2; | |
412 } | |
413 | |
414 if (!FD_ISSET(socket1, &write_set)) { | |
415 goto out2; | |
416 } | |
417 | |
418 arg = 0; | |
419 if (ioctlsocket(socket1, FIONBIO, &arg) == SOCKET_ERROR) { | |
420 goto out2; | |
421 } | |
422 | |
423 arg = 0; | |
424 if (ioctlsocket(socket2, FIONBIO, &arg) == SOCKET_ERROR) { | |
425 goto out2; | |
426 } | |
427 | |
428 fds[0] = socket1; | |
429 fds[1] = socket2; | |
430 | |
431 closesocket (temp); | |
432 | |
433 return 0; | |
434 | |
435 out2: | |
436 closesocket (socket2); | |
437 out1: | |
438 closesocket (socket1); | |
439 out0: | |
440 closesocket (temp); | |
441 errno = EIO; /* XXX */ | |
442 | |
443 return -1; | |
444 } | |
445 #endif | |
446 | |
447 | |
448 | |
449 #ifdef _WIN32 | |
450 struct gg_resolve_win32thread_data { | |
451 char *hostname; | |
452 int fd; | |
453 }; | |
454 | |
455 static DWORD WINAPI gg_resolve_win32thread_thread(LPVOID arg) | |
456 { | |
457 struct gg_resolve_win32thread_data *d = arg; | |
458 struct in_addr addr_ip[2], *addr_list; | |
459 int addr_count; | |
460 | |
461 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread_thread() host: %s, fd: %i called\n", d->hostname, d->fd); | |
462 | |
463 if ((addr_ip[0].s_addr = inet_addr(d->hostname)) == INADDR_NONE) { | |
464 /* W przypadku błędu gg_gethostbyname_real() zwróci -1 | |
465 * i nie zmieni &addr. Tam jest już INADDR_NONE, | |
466 * więc nie musimy robić nic więcej. */ | |
467 if (gg_gethostbyname_real(d->hostname, &addr_list, &addr_count, 0) == -1) | |
468 { | |
469 addr_list = addr_ip; | |
470 } | |
471 } else { | |
472 addr_list = addr_ip; | |
473 addr_ip[1].s_addr = INADDR_NONE; | |
474 addr_count = 1; | |
475 } | |
476 | |
477 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread_thread() count = %d\n", addr_count); | |
478 | |
479 write(d->fd, addr_list, (addr_count+1) * sizeof(struct in_addr)); | |
480 close(d->fd); | |
481 | |
482 free(d->hostname); | |
483 d->hostname = NULL; | |
484 | |
485 free(d); | |
486 | |
487 if (addr_list != addr_ip) | |
488 free(addr_list); | |
489 | |
490 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread_thread() done\n"); | |
491 | |
492 return 0; | |
493 } | |
494 | |
495 | |
496 static int gg_resolve_win32thread(int *fd, void **resolver, const char *hostname) | |
497 { | |
498 struct gg_resolve_win32thread_data *d = NULL; | |
499 HANDLE h; | |
500 DWORD dwTId; | |
501 int pipes[2], new_errno; | |
502 | |
503 gg_debug(GG_DEBUG_FUNCTION, "** gg_resolve_win32thread(%p, %p, \"%s\");\n", fd, resolver, hostname); | |
504 | |
505 if (!resolver || !fd || !hostname) { | |
506 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() invalid arguments\n"); | |
507 errno = EFAULT; | |
508 return -1; | |
509 } | |
510 | |
511 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() creating pipes...\n"); | |
512 | |
513 if (socket_pipe(pipes) == -1) { | |
514 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() unable to create pipes (errno=%d, %s)\n", errno, strerror(errno)); | |
515 return -1; | |
516 } | |
517 | |
518 if (!(d = malloc(sizeof(*d)))) { | |
519 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() out of memory\n"); | |
520 new_errno = errno; | |
521 goto cleanup; | |
522 } | |
523 | |
524 d->hostname = NULL; | |
525 | |
526 if (!(d->hostname = strdup(hostname))) { | |
527 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() out of memory\n"); | |
528 new_errno = errno; | |
529 goto cleanup; | |
530 } | |
531 | |
532 d->fd = pipes[1]; | |
533 | |
534 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() creating thread...\n"); | |
535 | |
536 h = CreateThread(NULL, 0, gg_resolve_win32thread_thread, | |
537 d, 0, &dwTId); | |
538 | |
539 if (h == NULL) { | |
540 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() unable to create thread\n"); | |
541 new_errno = errno; | |
542 goto cleanup; | |
543 } | |
544 | |
545 *resolver = h; | |
546 *fd = pipes[0]; | |
547 | |
548 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() done\n"); | |
549 | |
550 return 0; | |
551 | |
552 cleanup: | |
553 if (d) { | |
554 free(d->hostname); | |
555 free(d); | |
556 } | |
557 | |
558 close(pipes[0]); | |
559 close(pipes[1]); | |
560 | |
561 errno = new_errno; | |
562 | |
563 return -1; | |
564 | |
565 } | |
566 | |
567 static void gg_resolve_win32thread_cleanup(void **priv_data, int force) | |
568 { | |
569 struct gg_resolve_win32thread_data *data; | |
570 | |
571 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread_cleanup() force: %i called\n", force); | |
572 | |
573 if (priv_data == NULL || *priv_data == NULL) | |
574 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread_cleanup() priv_data: NULL\n"); | |
575 return; | |
576 | |
577 data = (struct gg_resolve_win32thread_data*) *priv_data; | |
578 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread_cleanup() data: %s called\n", data->hostname); | |
579 *priv_data = NULL; | |
580 | |
581 if (force) { | |
582 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread_cleanup() force called\n", force); | |
583 //pthread_cancel(data->thread); | |
584 //pthread_join(data->thread, NULL); | |
585 } | |
586 | |
587 free(data->hostname); | |
588 data->hostname = NULL; | |
589 | |
590 if (data->fd != -1) { | |
591 close(data->fd); | |
592 data->fd = -1; | |
593 } | |
594 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread_cleanup() done\n"); | |
595 free(data); | |
596 } | |
597 #endif | |
598 | |
599 #ifndef _WIN32 | 322 #ifndef _WIN32 |
600 /** | 323 /** |
601 * \internal Rozwiązuje nazwę serwera w osobnym procesie. | 324 * \internal Rozwiązuje nazwę serwera w osobnym procesie. |
602 * | 325 * |
603 * Połączenia asynchroniczne nie mogą blokować procesu w trakcie rozwiązywania | 326 * Połączenia asynchroniczne nie mogą blokować procesu w trakcie rozwiązywania |
871 gs->resolver_cleanup = gg_global_resolver_cleanup; | 594 gs->resolver_cleanup = gg_global_resolver_cleanup; |
872 return 0; | 595 return 0; |
873 } | 596 } |
874 | 597 |
875 #if !defined(GG_CONFIG_HAVE_PTHREAD) || !defined(GG_CONFIG_PTHREAD_DEFAULT) | 598 #if !defined(GG_CONFIG_HAVE_PTHREAD) || !defined(GG_CONFIG_PTHREAD_DEFAULT) |
876 # ifdef _WIN32 | |
877 type = GG_RESOLVER_WIN32; | |
878 # else | |
879 type = GG_RESOLVER_FORK; | 599 type = GG_RESOLVER_FORK; |
880 # endif | |
881 #else | 600 #else |
882 type = GG_RESOLVER_PTHREAD; | 601 type = GG_RESOLVER_PTHREAD; |
883 #endif | 602 #endif |
884 } | 603 } |
885 | 604 |
886 switch (type) { | 605 switch (type) { |
887 #ifdef _WIN32 | 606 #ifdef GG_CONFIG_HAVE_FORK |
888 case GG_RESOLVER_WIN32: | |
889 gs->resolver_type = type; | |
890 gs->resolver_start = gg_resolve_win32thread; | |
891 gs->resolver_cleanup = gg_resolve_win32thread_cleanup; | |
892 return 0; | |
893 #else | |
894 case GG_RESOLVER_FORK: | 607 case GG_RESOLVER_FORK: |
895 gs->resolver_type = type; | 608 gs->resolver_type = type; |
896 gs->resolver_start = gg_resolver_fork_start; | 609 gs->resolver_start = gg_resolver_fork_start; |
897 gs->resolver_cleanup = gg_resolver_fork_cleanup; | 610 gs->resolver_cleanup = gg_resolver_fork_cleanup; |
898 return 0; | 611 return 0; |
992 gh->resolver_cleanup = gg_global_resolver_cleanup; | 705 gh->resolver_cleanup = gg_global_resolver_cleanup; |
993 return 0; | 706 return 0; |
994 } | 707 } |
995 | 708 |
996 #if !defined(GG_CONFIG_HAVE_PTHREAD) || !defined(GG_CONFIG_PTHREAD_DEFAULT) | 709 #if !defined(GG_CONFIG_HAVE_PTHREAD) || !defined(GG_CONFIG_PTHREAD_DEFAULT) |
997 # ifdef _WIN32 | |
998 type = GG_RESOLVER_WIN32; | |
999 # else | |
1000 type = GG_RESOLVER_FORK; | 710 type = GG_RESOLVER_FORK; |
1001 # endif | |
1002 #else | 711 #else |
1003 type = GG_RESOLVER_PTHREAD; | 712 type = GG_RESOLVER_PTHREAD; |
1004 #endif | 713 #endif |
1005 } | 714 } |
1006 | 715 |
1007 switch (type) { | 716 switch (type) { |
1008 #ifdef _WIN32 | 717 #ifdef GG_CONFIG_HAVE_FORK |
1009 case GG_RESOLVER_WIN32: | |
1010 gh->resolver_type = type; | |
1011 gh->resolver_start = gg_resolve_win32thread; | |
1012 gh->resolver_cleanup = gg_resolve_win32thread_cleanup; | |
1013 return 0; | |
1014 #else | |
1015 case GG_RESOLVER_FORK: | 718 case GG_RESOLVER_FORK: |
1016 gh->resolver_type = type; | 719 gh->resolver_type = type; |
1017 gh->resolver_start = gg_resolver_fork_start; | 720 gh->resolver_start = gg_resolver_fork_start; |
1018 gh->resolver_cleanup = gg_resolver_fork_cleanup; | 721 gh->resolver_cleanup = gg_resolver_fork_cleanup; |
1019 return 0; | 722 return 0; |
1087 gg_global_resolver_type = type; | 790 gg_global_resolver_type = type; |
1088 gg_global_resolver_start = NULL; | 791 gg_global_resolver_start = NULL; |
1089 gg_global_resolver_cleanup = NULL; | 792 gg_global_resolver_cleanup = NULL; |
1090 return 0; | 793 return 0; |
1091 | 794 |
1092 #ifdef _WIN32 | 795 #ifdef GG_CONFIG_HAVE_FORK |
1093 case GG_RESOLVER_WIN32: | |
1094 gg_global_resolver_type = type; | |
1095 gg_global_resolver_start = gg_resolve_win32thread; | |
1096 gg_global_resolver_cleanup = gg_resolve_win32thread_cleanup; | |
1097 return 0; | |
1098 #else | |
1099 case GG_RESOLVER_FORK: | 796 case GG_RESOLVER_FORK: |
1100 gg_global_resolver_type = type; | 797 gg_global_resolver_type = type; |
1101 gg_global_resolver_start = gg_resolver_fork_start; | 798 gg_global_resolver_start = gg_resolver_fork_start; |
1102 gg_global_resolver_cleanup = gg_resolver_fork_cleanup; | 799 gg_global_resolver_cleanup = gg_resolver_fork_cleanup; |
1103 return 0; | 800 return 0; |