libpurple/protocols/jabber/jabber.c

changeset 40106
52dc2d315d73
parent 40105
54f0cc747958
child 40107
6320c272e8b2
equal deleted inserted replaced
40105:54f0cc747958 40106:52dc2d315d73
821 _("Unable to connect")); 821 _("Unable to connect"));
822 return; 822 return;
823 } 823 }
824 } 824 }
825 825
826 static void
827 jabber_login_callback(gpointer data, gint source, const gchar *error)
828 {
829 PurpleConnection *gc = data;
830 JabberStream *js = purple_connection_get_protocol_data(gc);
831
832 if (source < 0) {
833 GResolver *resolver = g_resolver_get_default();
834 gchar *name = g_strdup_printf("_xmppconnect.%s", js->user->domain);
835
836 purple_debug_info("jabber", "Couldn't connect directly to %s. Trying to find alternative connection methods, like BOSH.\n", js->user->domain);
837
838 g_resolver_lookup_records_async(resolver,
839 name,
840 G_RESOLVER_RECORD_TXT,
841 js->cancellable,
842 txt_resolved_cb,
843 js);
844 g_free(name);
845 g_object_unref(resolver);
846
847 return;
848 }
849
850 js->fd = source;
851
852 if(js->state == JABBER_STREAM_CONNECTING)
853 jabber_send_raw(js, "<?xml version='1.0' ?>", -1);
854
855 jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING);
856 js->inpa = purple_input_add(js->fd, PURPLE_INPUT_READ, jabber_recv_cb, gc);
857 }
858
859 /* Grabbed duplicate_fd() from GLib's testcases (gio/tests/socket.c). 826 /* Grabbed duplicate_fd() from GLib's testcases (gio/tests/socket.c).
860 * Can be dropped once this prpl has been fully converted to Gio. 827 * Can be dropped once this prpl has been fully converted to Gio.
861 */ 828 */
862 static int 829 static int
863 duplicate_fd(int fd) 830 duplicate_fd(int fd)
876 #endif 843 #endif
877 } 844 }
878 /* End function grabbed from GLib */ 845 /* End function grabbed from GLib */
879 846
880 static void 847 static void
881 jabber_login_callback_async(GObject *source_object, GAsyncResult *res, 848 jabber_login_callback(GObject *source_object, GAsyncResult *res, gpointer data)
882 gpointer data)
883 { 849 {
884 GSocketClient *client = G_SOCKET_CLIENT(source_object); 850 GSocketClient *client = G_SOCKET_CLIENT(source_object);
885 JabberStream *js = data; 851 JabberStream *js = data;
886 GSocketConnection *conn; 852 GSocketConnection *conn;
887 GSocket *socket; 853 GSocket *socket;
958 jabber_login_callback_ssl, jabber_ssl_connect_failure, js->certificate_CN, js->gc); 924 jabber_login_callback_ssl, jabber_ssl_connect_failure, js->certificate_CN, js->gc);
959 /* The fd is no longer our concern */ 925 /* The fd is no longer our concern */
960 js->fd = -1; 926 js->fd = -1;
961 } 927 }
962 928
963 static gboolean
964 jabber_login_connect(JabberStream *js, const char *host, int port,
965 gboolean fatal_failure)
966 {
967 if (purple_proxy_connect(js->gc, purple_connection_get_account(js->gc),
968 host, port, jabber_login_callback, js->gc) == NULL) {
969 if (fatal_failure) {
970 purple_connection_error(js->gc,
971 PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
972 _("Unable to connect"));
973 }
974
975 return FALSE;
976 }
977
978 return TRUE;
979 }
980
981 static void 929 static void
982 srv_resolved_cb(GObject *sender, GAsyncResult *result, gpointer data) 930 srv_resolved_cb(GObject *source_object, GAsyncResult *result, gpointer data)
983 { 931 {
932 GSocketClient *client = G_SOCKET_CLIENT(source_object);
984 GError *error = NULL; 933 GError *error = NULL;
985 GList *targets = NULL, *l = NULL; 934 GSocketConnection *conn;
935 GSocket *socket;
986 JabberStream *js = data; 936 JabberStream *js = data;
987 937
988 targets = g_resolver_lookup_service_finish(G_RESOLVER(sender), 938 conn = g_socket_client_connect_to_service_finish(client, result, &error);
989 result, &error); 939 if (error) {
990 if(error) { 940 if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
991 purple_debug_warning("jabber", 941 /* Do nothing; cancelled. */
992 "SRV lookup failed, proceeding with normal connection : %s", 942
993 error->message); 943 } else if (g_error_matches(error, G_RESOLVER_ERROR,
944 G_RESOLVER_ERROR_NOT_FOUND)) {
945 /* If there was no response, then attempt fallback behaviour of XMPP
946 * Core 3.2.2. */
947 purple_debug_warning(
948 "jabber",
949 "SRV lookup failed, proceeding with normal connection : %s",
950 error->message);
951
952 g_socket_client_connect_to_host_async(
953 js->client, js->user->domain,
954 purple_account_get_int(
955 purple_connection_get_account(js->gc), "port",
956 5222),
957 js->cancellable, jabber_login_callback, js);
958
959 } else {
960 /* If resolving failed or connecting failed, then just error out, as
961 * in XMPP Core 3.2.1 step 8. */
962 purple_connection_g_error(js->gc, error);
963 }
994 964
995 g_error_free(error); 965 g_error_free(error);
996 966 return;
997 jabber_login_connect( 967 }
998 js, js->user->domain, 968
999 purple_account_get_int(purple_connection_get_account(js->gc), 969 socket = g_socket_connection_get_socket(conn);
1000 "port", 5222), 970 g_assert(socket != NULL);
1001 TRUE); 971
1002 972 /* Duplicate the file descriptor, and then free the connection.
1003 } else { 973 * libpurple's proxy code doesn't keep an object around for the
1004 for(l = targets; l; l = l->next) { 974 * lifetime of the connection. Therefore, in order to not leak
1005 GSrvTarget *target = (GSrvTarget *)l->data; 975 * memory, the GSocketConnection must be freed here. In order
1006 const gchar *hostname = g_srv_target_get_hostname(target); 976 * to avoid the double close/free of the file descriptor, the
1007 guint port = g_srv_target_get_port(target); 977 * file descriptor is duplicated.
1008 978 */
1009 if (jabber_login_connect(js, hostname, port, FALSE)) { 979 js->fd = duplicate_fd(g_socket_get_fd(socket));
1010 g_resolver_free_targets(targets); 980 g_object_unref(conn);
1011 981
1012 return; 982 if (js->state == JABBER_STREAM_CONNECTING) {
1013 } 983 jabber_send_raw(js, "<?xml version='1.0' ?>", -1);
1014 } 984 }
1015 985
1016 g_resolver_free_targets(targets); 986 jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING);
1017 987 js->inpa =
1018 jabber_login_connect( 988 purple_input_add(js->fd, PURPLE_INPUT_READ, jabber_recv_cb, js->gc);
1019 js, js->user->domain,
1020 purple_account_get_int(purple_connection_get_account(js->gc),
1021 "port", 5222),
1022 TRUE);
1023 }
1024 } 989 }
1025 990
1026 static JabberStream * 991 static JabberStream *
1027 jabber_stream_new(PurpleAccount *account) 992 jabber_stream_new(PurpleAccount *account)
1028 { 993 {
1189 * invoke the magic of SRV lookups, to figure out host and port */ 1154 * invoke the magic of SRV lookups, to figure out host and port */
1190 if(connect_server[0]) { 1155 if(connect_server[0]) {
1191 g_socket_client_connect_to_host_async( 1156 g_socket_client_connect_to_host_async(
1192 js->client, connect_server, 1157 js->client, connect_server,
1193 purple_account_get_int(account, "port", 5222), js->cancellable, 1158 purple_account_get_int(account, "port", 5222), js->cancellable,
1194 jabber_login_callback_async, js); 1159 jabber_login_callback, js);
1195 } else { 1160 } else {
1196 GResolver *resolver = g_resolver_get_default(); 1161 g_socket_client_connect_to_service_async(js->client, js->user->domain,
1197 g_resolver_lookup_service_async(resolver, 1162 "xmpp-client", js->cancellable,
1198 "xmpp-client", 1163 srv_resolved_cb, js);
1199 "tcp",
1200 js->user->domain,
1201 js->cancellable,
1202 srv_resolved_cb,
1203 js);
1204 g_object_unref(resolver);
1205 } 1164 }
1206 } 1165 }
1207 1166
1208 void 1167 void
1209 jabber_login(PurpleAccount *account) 1168 jabber_login(PurpleAccount *account)

mercurial