libpurple/protocols/jabber/jabber.c

branch
use-gresolver
changeset 37457
0b957b80c46a
parent 37384
3c5c8c63a686
child 37466
ef015fb22744
equal deleted inserted replaced
37456:697c2cfa4123 37457:0b957b80c46a
28 #include "core.h" 28 #include "core.h"
29 #include "cmds.h" 29 #include "cmds.h"
30 #include "connection.h" 30 #include "connection.h"
31 #include "conversation.h" 31 #include "conversation.h"
32 #include "debug.h" 32 #include "debug.h"
33 #include "dnssrv.h"
34 #include "http.h" 33 #include "http.h"
35 #include "message.h" 34 #include "message.h"
36 #include "notify.h" 35 #include "notify.h"
37 #include "pluginpref.h" 36 #include "pluginpref.h"
38 #include "proxy.h" 37 #include "proxy.h"
93 static GHashTable *jabber_cmds = NULL; /* PurpleProtocol * => GSList of ids */ 92 static GHashTable *jabber_cmds = NULL; /* PurpleProtocol * => GSList of ids */
94 93
95 static gint plugin_ref = 0; 94 static gint plugin_ref = 0;
96 95
97 static void jabber_unregister_account_cb(JabberStream *js); 96 static void jabber_unregister_account_cb(JabberStream *js);
98 static void try_srv_connect(JabberStream *js);
99 97
100 static void jabber_stream_init(JabberStream *js) 98 static void jabber_stream_init(JabberStream *js)
101 { 99 {
102 char *open_stream; 100 char *open_stream;
103 101
763 /* Tell the app that we're doing encryption */ 761 /* Tell the app that we're doing encryption */
764 jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING_ENCRYPTION); 762 jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING_ENCRYPTION);
765 } 763 }
766 764
767 static void 765 static void
768 txt_resolved_cb(GList *responses, gpointer data) 766 txt_resolved_cb(GObject *sender, GAsyncResult *result, gpointer data)
769 { 767 {
768 GError *error = NULL;
769 GList *records = NULL, *l = NULL;
770 JabberStream *js = data; 770 JabberStream *js = data;
771 gboolean found = FALSE; 771 gboolean found = FALSE;
772 772
773 js->srv_query_data = NULL; 773 records = g_resolver_lookup_service_finish(g_resolver_get_default(), result, &error);
774 774 if(error) {
775 while (responses) { 775 purple_debug_warning("jabber", "Unable to find alternative XMPP connection "
776 PurpleTxtResponse *resp = responses->data; 776 "methods after failing to connect directly. : %s\n",
777 gchar **token; 777 error->message);
778 token = g_strsplit(purple_txt_response_get_content(resp), "=", 2); 778
779 if (!strcmp(token[0], "_xmpp-client-xbosh")) { 779 purple_connection_error(js->gc,
780 purple_debug_info("jabber","Found alternative connection method using %s at %s.\n", token[0], token[1]); 780 PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
781 js->bosh = jabber_bosh_connection_new(js, token[1]); 781 _("Unable to connect"));
782
783 g_error_free(error);
784
785 return;
786 }
787
788 for(l = records; l; l = l->next) {
789 GVariantIter *iter = NULL;
790 gchar *str = NULL;
791
792 g_variant_get((GVariant *)l->data, "(as)", &iter);
793 while(g_variant_iter_loop(iter, "s", &str)) {
794 gchar **token = g_strsplit(str, "=", 2);
795
796 if(!g_ascii_strcasecmp(token[0], "_xmpp-client-xbosh")) {
797 purple_debug_info("jabber","Found alternative connection method using %s at %s.\n", token[0], token[1]);
798
799 js->bosh = jabber_bosh_connection_new(js, token[1]);
800
801 g_strfreev(token);
802
803 break;
804 }
805
782 g_strfreev(token); 806 g_strfreev(token);
783 break; 807 }
784 } 808
785 g_strfreev(token); 809 g_variant_iter_free(iter);
786 purple_txt_response_destroy(resp); 810 }
787 responses = g_list_delete_link(responses, responses); 811
788 } 812 g_list_free_full(records, (GDestroyNotify)g_variant_unref);
789 813
790 if (js->bosh) 814 if (js->bosh)
791 found = TRUE; 815 found = TRUE;
792 816
793 if (!found) { 817 if (!found) {
796 purple_connection_error(js->gc, 820 purple_connection_error(js->gc,
797 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, 821 PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
798 _("Unable to connect")); 822 _("Unable to connect"));
799 return; 823 return;
800 } 824 }
801
802 if (responses) {
803 g_list_foreach(responses, (GFunc)purple_txt_response_destroy, NULL);
804 g_list_free(responses);
805 }
806 } 825 }
807 826
808 static void 827 static void
809 jabber_login_callback(gpointer data, gint source, const gchar *error) 828 jabber_login_callback(gpointer data, gint source, const gchar *error)
810 { 829 {
811 PurpleConnection *gc = data; 830 PurpleConnection *gc = data;
812 JabberStream *js = purple_connection_get_protocol_data(gc); 831 JabberStream *js = purple_connection_get_protocol_data(gc);
813 832
814 if (source < 0) { 833 if (source < 0) {
815 if (js->srv_rec != NULL) { 834 gchar *name = g_strdup_printf("_xmppconnect.%s", js->user->domain);
816 purple_debug_error("jabber", "Unable to connect to server: %s. Trying next SRV record or connecting directly.\n", error); 835
817 try_srv_connect(js); 836 purple_debug_info("jabber", "Couldn't connect directly to %s. Trying to find alternative connection methods, like BOSH.\n", js->user->domain);
818 } else { 837
819 purple_debug_info("jabber","Couldn't connect directly to %s. Trying to find alternative connection methods, like BOSH.\n", js->user->domain); 838 g_resolver_lookup_records_async(g_resolver_get_default(),
820 js->srv_query_data = purple_txt_resolve( 839 name,
821 purple_connection_get_account(gc), "_xmppconnect", 840 G_RESOLVER_RECORD_TXT,
822 js->user->domain, txt_resolved_cb, js); 841 js->cancellable,
823 } 842 txt_resolved_cb,
843 js);
844 g_free(name);
845
824 return; 846 return;
825 } 847 }
826
827 g_free(js->srv_rec);
828 js->srv_rec = NULL;
829 848
830 js->fd = source; 849 js->fd = source;
831 850
832 if(js->state == JABBER_STREAM_CONNECTING) 851 if(js->state == JABBER_STREAM_CONNECTING)
833 jabber_send_raw(js, "<?xml version='1.0' ?>", -1); 852 jabber_send_raw(js, "<?xml version='1.0' ?>", -1);
886 } 905 }
887 906
888 return TRUE; 907 return TRUE;
889 } 908 }
890 909
891 static void try_srv_connect(JabberStream *js) 910 static void
892 { 911 srv_resolved_cb(GObject *sender, GAsyncResult *result, gpointer data)
893 while (js->srv_rec != NULL && js->srv_rec_idx < js->max_srv_rec_idx) { 912 {
894 PurpleSrvResponse *tmp_resp = js->srv_rec + (js->srv_rec_idx++); 913 GError *error = NULL;
895 if (jabber_login_connect(js, tmp_resp->hostname, tmp_resp->hostname, tmp_resp->port, FALSE)) 914 GList *targets = NULL, *l = NULL;
896 return;
897 }
898
899 g_free(js->srv_rec);
900 js->srv_rec = NULL;
901
902 /* Fall back to the defaults (I'm not sure if we should actually do this) */
903 jabber_login_connect(js, js->user->domain, js->user->domain,
904 purple_account_get_int(purple_connection_get_account(js->gc), "port", 5222),
905 TRUE);
906 }
907
908 static void srv_resolved_cb(PurpleSrvResponse *resp, int results, gpointer data)
909 {
910 JabberStream *js = data; 915 JabberStream *js = data;
911 js->srv_query_data = NULL; 916
912 917 targets = g_resolver_lookup_service_finish(g_resolver_get_default(), result, &error);
913 if(results) { 918 if(error) {
914 js->srv_rec = resp; 919 purple_debug_warning("jabber",
915 js->srv_rec_idx = 0; 920 "SRV lookup failed, proceeding with normal connection : %s",
916 js->max_srv_rec_idx = results; 921 error->message);
917 try_srv_connect(js); 922
918 } else { 923 g_error_free(error);
924
919 jabber_login_connect(js, js->user->domain, js->user->domain, 925 jabber_login_connect(js, js->user->domain, js->user->domain,
920 purple_account_get_int(purple_connection_get_account(js->gc), "port", 5222), 926 purple_account_get_int(purple_connection_get_account(js->gc), "port", 5222),
921 TRUE); 927 TRUE);
928
929 } else {
930 for(l = targets; l; l = l->next) {
931 GSrvTarget *target = (GSrvTarget *)l->data;
932 const gchar *hostname = g_srv_target_get_hostname(target);
933 guint port = g_srv_target_get_port(target);
934
935 if(jabber_login_connect(js, hostname, hostname, port, FALSE)) {
936 g_resolver_free_targets(targets);
937
938 return;
939 }
940 }
941
942 g_resolver_free_targets(targets);
943
944 jabber_login_connect(js, js->user->domain, js->user->domain,
945 purple_account_get_int(purple_connection_get_account(js->gc), "port", 5222),
946 TRUE);
922 } 947 }
923 } 948 }
924 949
925 static JabberStream * 950 static JabberStream *
926 jabber_stream_new(PurpleAccount *account) 951 jabber_stream_new(PurpleAccount *account)
934 js = g_new0(JabberStream, 1); 959 js = g_new0(JabberStream, 1);
935 purple_connection_set_protocol_data(gc, js); 960 purple_connection_set_protocol_data(gc, js);
936 js->gc = gc; 961 js->gc = gc;
937 js->fd = -1; 962 js->fd = -1;
938 js->http_conns = purple_http_connection_set_new(); 963 js->http_conns = purple_http_connection_set_new();
964
965 /* we might want to expose this at some point */
966 js->cancellable = g_cancellable_new();
939 967
940 user = g_strdup(purple_account_get_username(account)); 968 user = g_strdup(purple_account_get_username(account));
941 /* jabber_id_new doesn't accept "user@domain/" as valid */ 969 /* jabber_id_new doesn't accept "user@domain/" as valid */
942 slash = strchr(user, '/'); 970 slash = strchr(user, '/');
943 if (slash && *(slash + 1) == '\0') 971 if (slash && *(slash + 1) == '\0')
1005 js->protocol_version.major = 1; 1033 js->protocol_version.major = 1;
1006 js->protocol_version.minor = 0; 1034 js->protocol_version.minor = 0;
1007 js->sessions = NULL; 1035 js->sessions = NULL;
1008 js->stun_ip = NULL; 1036 js->stun_ip = NULL;
1009 js->stun_port = 0; 1037 js->stun_port = 0;
1010 js->stun_query = NULL;
1011 js->google_relay_token = NULL; 1038 js->google_relay_token = NULL;
1012 js->google_relay_host = NULL; 1039 js->google_relay_host = NULL;
1013 1040
1014 /* if we are idle, set idle-ness on the stream (this could happen if we get 1041 /* if we are idle, set idle-ness on the stream (this could happen if we get
1015 disconnected and the reconnects while being idle. I don't think it makes 1042 disconnected and the reconnects while being idle. I don't think it makes
1073 * invoke the magic of SRV lookups, to figure out host and port */ 1100 * invoke the magic of SRV lookups, to figure out host and port */
1074 if(connect_server[0]) { 1101 if(connect_server[0]) {
1075 jabber_login_connect(js, js->user->domain, connect_server, 1102 jabber_login_connect(js, js->user->domain, connect_server,
1076 purple_account_get_int(account, "port", 5222), TRUE); 1103 purple_account_get_int(account, "port", 5222), TRUE);
1077 } else { 1104 } else {
1078 js->srv_query_data = purple_srv_resolve(account, "xmpp-client", 1105 g_resolver_lookup_service_async(g_resolver_get_default(),
1079 "tcp", js->user->domain, srv_resolved_cb, js); 1106 "xmpp-client",
1107 "tcp",
1108 js->user->domain,
1109 js->cancellable,
1110 srv_resolved_cb,
1111 js);
1080 } 1112 }
1081 } 1113 }
1082 1114
1083 void 1115 void
1084 jabber_login(PurpleAccount *account) 1116 jabber_login(PurpleAccount *account)
1605 if (js->bosh) { 1637 if (js->bosh) {
1606 jabber_bosh_connection_destroy(js->bosh); 1638 jabber_bosh_connection_destroy(js->bosh);
1607 js->bosh = NULL; 1639 js->bosh = NULL;
1608 } else if ((js->gsc && js->gsc->fd > 0) || js->fd > 0) 1640 } else if ((js->gsc && js->gsc->fd > 0) || js->fd > 0)
1609 jabber_send_raw(js, "</stream:stream>", -1); 1641 jabber_send_raw(js, "</stream:stream>", -1);
1610
1611 if (js->srv_query_data)
1612 purple_srv_txt_query_destroy(js->srv_query_data);
1613 1642
1614 if(js->gsc) { 1643 if(js->gsc) {
1615 purple_ssl_close(js->gsc); 1644 purple_ssl_close(js->gsc);
1616 } else if (js->fd > 0) { 1645 } else if (js->fd > 0) {
1617 if(js->inpa) { 1646 if(js->inpa) {
1704 if (js->inactivity_timer != 0) 1733 if (js->inactivity_timer != 0)
1705 purple_timeout_remove(js->inactivity_timer); 1734 purple_timeout_remove(js->inactivity_timer);
1706 if (js->conn_close_timeout != 0) 1735 if (js->conn_close_timeout != 0)
1707 purple_timeout_remove(js->conn_close_timeout); 1736 purple_timeout_remove(js->conn_close_timeout);
1708 1737
1709 g_free(js->srv_rec); 1738 g_cancellable_cancel(js->cancellable);
1710 js->srv_rec = NULL; 1739 g_object_unref(G_OBJECT(js->cancellable));
1711 1740
1712 g_free(js->stun_ip); 1741 g_free(js->stun_ip);
1713 js->stun_ip = NULL;
1714
1715 /* cancel DNS query for STUN, if one is ongoing */
1716 if (js->stun_query) {
1717 purple_dnsquery_destroy(js->stun_query);
1718 js->stun_query = NULL;
1719 }
1720 1742
1721 /* remove Google relay-related stuff */ 1743 /* remove Google relay-related stuff */
1722 g_free(js->google_relay_token); 1744 g_free(js->google_relay_token);
1723 g_free(js->google_relay_host); 1745 g_free(js->google_relay_host);
1724 1746

mercurial