1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ |
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ |
2 /* |
2 /* |
3 * Copyright (C) 2006 Imendio AB |
3 * Copyright (C) 2006 Imendio AB |
|
4 * Copyright (C) 2006 Nokia Corporation. All rights reserved. |
|
5 * Copyright (C) 2007 Collabora Ltd. |
4 * |
6 * |
5 * This program is free software; you can redistribute it and/or |
7 * This program is free software; you can redistribute it and/or |
6 * modify it under the terms of the GNU Lesser General Public License as |
8 * modify it under the terms of the GNU Lesser General Public License as |
7 * published by the Free Software Foundation; either version 2 of the |
9 * published by the Free Software Foundation; either version 2 of the |
8 * License, or (at your option) any later version. |
10 * License, or (at your option) any later version. |
610 } |
614 } |
611 |
615 |
612 return TRUE; |
616 return TRUE; |
613 } |
617 } |
614 |
618 |
|
619 static gboolean |
|
620 _parse_srv_response (unsigned char *srv, int srv_len, gchar **out_server, guint *out_port) |
|
621 { |
|
622 int qdcount; |
|
623 int ancount; |
|
624 int len; |
|
625 const unsigned char *pos = srv + sizeof(HEADER); |
|
626 unsigned char *end = srv + srv_len; |
|
627 HEADER *head = (HEADER *)srv; |
|
628 char name[256]; |
|
629 char pref_name[256]; |
|
630 guint pref_port = 0; |
|
631 guint pref_prio = 9999; |
|
632 |
|
633 pref_name[0] = 0; |
|
634 |
|
635 qdcount = ntohs (head->qdcount); |
|
636 ancount = ntohs (head->ancount); |
|
637 |
|
638 /* Ignore the questions */ |
|
639 while (qdcount-- > 0 && (len = dn_expand (srv, end, pos, name, 255)) >= 0) { |
|
640 g_assert (len >= 0); |
|
641 pos += len + QFIXEDSZ; |
|
642 } |
|
643 |
|
644 /* Parse the answers */ |
|
645 while (ancount-- > 0 && (len = dn_expand (srv, end, pos, name, 255)) >= 0) { |
|
646 /* Ignore the initial string */ |
|
647 uint16_t pref, weight, port; |
|
648 g_assert (len >= 0); |
|
649 pos += len; |
|
650 /* Ignore type, ttl, class and dlen */ |
|
651 pos += 10; |
|
652 GETSHORT (pref, pos); |
|
653 GETSHORT (weight, pos); |
|
654 GETSHORT (port, pos); |
|
655 len = dn_expand (srv, end, pos, name, 255); |
|
656 if (pref < pref_prio) { |
|
657 pref_prio = pref; |
|
658 strcpy (pref_name, name); |
|
659 pref_port = port; |
|
660 } |
|
661 pos += len; |
|
662 } |
|
663 |
|
664 if (pref_name[0]) { |
|
665 *out_server = g_strdup (pref_name); |
|
666 *out_port = pref_port; |
|
667 return TRUE; |
|
668 } |
|
669 return FALSE; |
|
670 } |
|
671 |
615 LmSocket * |
672 LmSocket * |
616 lm_socket_create (GMainContext *context, |
673 lm_socket_create (GMainContext *context, |
617 IncomingDataFunc func, |
674 IncomingDataFunc func, |
618 gpointer user_data, |
675 gpointer user_data, |
619 LmConnection *connection, |
676 LmConnection *connection, |
625 GError **error) |
682 GError **error) |
626 { |
683 { |
627 LmSocket *socket; |
684 LmSocket *socket; |
628 struct addrinfo req; |
685 struct addrinfo req; |
629 struct addrinfo *ans; |
686 struct addrinfo *ans; |
|
687 const char *remote_addr; |
630 LmConnectData *data; |
688 LmConnectData *data; |
|
689 int err; |
|
690 char *srv; |
|
691 #define SRV_LEN 8192 |
|
692 unsigned char srv_ans[SRV_LEN]; |
631 |
693 |
632 g_return_val_if_fail (server != NULL, NULL); |
694 g_return_val_if_fail (server != NULL, NULL); |
633 g_return_val_if_fail ((port >= MIN_PORT && port <= MAX_PORT), NULL); |
695 g_return_val_if_fail ((port >= MIN_PORT && port <= MAX_PORT), NULL); |
634 g_return_val_if_fail (func != NULL, NULL); |
696 g_return_val_if_fail (func != NULL, NULL); |
635 |
697 |
651 socket->proxy = NULL; |
713 socket->proxy = NULL; |
652 socket->blocking = blocking; |
714 socket->blocking = blocking; |
653 socket->func = func; |
715 socket->func = func; |
654 socket->user_data = user_data; |
716 socket->user_data = user_data; |
655 |
717 |
|
718 res_init (); |
|
719 srv = g_strdup_printf ("_xmpp-client._tcp.%s", socket->server); |
|
720 err = res_query (srv, C_IN, T_SRV, srv_ans, SRV_LEN); |
|
721 if (err > 0) { |
|
722 _parse_srv_response (srv_ans, err, &(socket->server), &(socket->port)); |
|
723 } |
|
724 g_free (srv); |
|
725 |
656 if (context) { |
726 if (context) { |
657 socket->context = g_main_context_ref (context); |
727 socket->context = g_main_context_ref (context); |
658 } |
728 } |
659 |
729 |
660 if (proxy) { |
730 if (proxy) { |
661 int err; |
|
662 const gchar *proxy_server; |
|
663 |
|
664 socket->proxy = lm_proxy_ref (proxy); |
731 socket->proxy = lm_proxy_ref (proxy); |
665 |
732 remote_addr = lm_proxy_get_server (socket->proxy); |
666 proxy_server = lm_proxy_get_server (socket->proxy); |
733 } else { |
667 |
734 remote_addr = socket->server; |
668 /* Connect through proxy */ |
735 } |
669 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, |
736 |
670 "Going to connect to proxy %s\n", proxy_server); |
737 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, |
671 |
738 "Going to connect to %s%s:%u\n", (proxy) ? "proxy " : "", |
672 err = getaddrinfo (proxy_server, NULL, &req, &ans); |
739 remote_addr, socket->port); |
673 if (err != 0) { |
740 |
674 const char *str; |
741 err = getaddrinfo (remote_addr, NULL, &req, &ans); |
675 |
742 if (err != 0) { |
676 str = _lm_sock_addrinfo_get_error_str (err); |
743 const char *str; |
677 g_set_error (error, |
744 |
678 LM_ERROR, |
745 str = _lm_sock_addrinfo_get_error_str (err); |
679 LM_ERROR_CONNECTION_FAILED, |
746 g_set_error (error, |
680 str); |
747 LM_ERROR, |
681 return NULL; |
748 LM_ERROR_CONNECTION_FAILED, |
682 } |
749 str); |
683 } else { |
750 return NULL; |
684 int err; |
|
685 |
|
686 /* Connect directly */ |
|
687 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, |
|
688 "Going to connect to %s\n", |
|
689 socket->server); |
|
690 |
|
691 err = getaddrinfo (socket->server, |
|
692 NULL, &req, &ans); |
|
693 if (err != 0) { |
|
694 const char *str; |
|
695 |
|
696 str = _lm_sock_addrinfo_get_error_str (err); |
|
697 g_set_error (error, |
|
698 LM_ERROR, |
|
699 LM_ERROR_CONNECTION_FAILED, |
|
700 str); |
|
701 return NULL; |
|
702 } |
|
703 } |
751 } |
704 |
752 |
705 if (ssl) { |
753 if (ssl) { |
706 socket->ssl = lm_ssl_ref (ssl); |
754 socket->ssl = lm_ssl_ref (ssl); |
707 _lm_ssl_initialize (socket->ssl); |
755 _lm_ssl_initialize (socket->ssl); |