cpw.malu.xmpp.jingle_ft: 949dfbf7: Add transport fallback to IBB.

malu at pidgin.im malu at pidgin.im
Wed May 6 17:15:44 EDT 2009


-----------------------------------------------------------------
Revision: 949dfbf7d6f0a81ff018be4f61c5034962e26ff7
Ancestor: 6f07196b09d67e610cc854e133cf8191429863b4
Author: malu at pidgin.im
Date: 2009-05-06T21:06:50
Branch: im.pidgin.cpw.malu.xmpp.jingle_ft
URL: http://d.pidgin.im/viewmtn/revision/info/949dfbf7d6f0a81ff018be4f61c5034962e26ff7

Modified files:
        libpurple/protocols/jabber/jingle/file-transfer.c
        libpurple/protocols/jabber/jingle/s5b.c
        libpurple/protocols/jabber/jingle/s5b.h

ChangeLog: 

Add transport fallback to IBB.
This is yet to be tested, so be aware... :)

-------------- next part --------------
============================================================
--- libpurple/protocols/jabber/jingle/file-transfer.c	964981162598f0a4decdad0282e1f98829ea9baf
+++ libpurple/protocols/jabber/jingle/file-transfer.c	ddeb31a1be6c59a5129731948e358bd760cfe590
@@ -275,40 +275,6 @@ jingle_file_transfer_ibb_send_data(Jingl
 	g_object_unref(transport);
 }
 
-/* callback functions for S5B */
-static void
-jingle_file_transfer_s5b_connect_callback(JingleContent *content)
-{
-	PurpleXfer *xfer = JINGLE_FT_GET_PRIVATE(JINGLE_FT(content))->xfer;
-	JingleTransport *transport = jingle_content_get_transport(content);
-	JingleS5B *s5b = JINGLE_S5B(transport);
-	
-	purple_debug_info("jingle-ft", 
-		"in jingle_file_transfer_s5b_connect_callback\n");
-	purple_debug_info("jingle-ft", "xfer->data: %p\n", xfer->data);
-	purple_xfer_start(xfer, jingle_s5b_get_fd(s5b), NULL, 0);
-}
-
-static void
-jingle_file_transfer_s5b_error_callback(JingleContent *content)
-{
-	PurpleXfer *xfer = JINGLE_FT_GET_PRIVATE(JINGLE_FT(content))->xfer;
-	JingleSession *session = jingle_content_get_session(content);
-	JabberStream *js = 
-		jingle_session_get_js(session);
-	PurpleConnection *gc = js->gc;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	gchar *who = jingle_session_get_remote_jid(session);
-	
-	purple_debug_error("jingle-ft", 
-		"an error occured during SOCKS5 file transfer\n");
-	purple_xfer_error(purple_xfer_get_type(xfer), account, who,
-		_("An error occured on the SOCKS5 transfer\n"));
-	purple_xfer_cancel_remote(xfer);
-	g_free(who);
-	g_object_unref(session);
-}
-
 /* callback functions for IBB */
 static void
 jingle_file_transfer_ibb_data_sent_callback(JingleContent *content)
@@ -393,11 +359,100 @@ jingle_file_transfer_add_ibb_session_to_
 		purple_debug_error("jingle-ft",
 			"trying to setup an IBB session of a non-IBB transport\n");
 	}
-		
+
 	g_free(sid);
 }
 
+/* callback functions for S5B */
 static void
+jingle_file_transfer_s5b_connect_callback(JingleContent *content)
+{
+	PurpleXfer *xfer = JINGLE_FT_GET_PRIVATE(JINGLE_FT(content))->xfer;
+	JingleTransport *transport = jingle_content_get_transport(content);
+	JingleS5B *s5b = JINGLE_S5B(transport);
+	
+	purple_debug_info("jingle-ft", 
+		"in jingle_file_transfer_s5b_connect_callback\n");
+	purple_debug_info("jingle-ft", "xfer->data: %p\n", xfer->data);
+	purple_xfer_start(xfer, jingle_s5b_get_fd(s5b), NULL, 0);
+}
+
+static void
+jingle_file_transfer_s5b_error_callback(JingleContent *content)
+{
+	PurpleXfer *xfer = JINGLE_FT_GET_PRIVATE(JINGLE_FT(content))->xfer;
+	JingleSession *session = jingle_content_get_session(content);
+	JabberStream *js = 
+		jingle_session_get_js(session);
+	PurpleConnection *gc = js->gc;
+	PurpleAccount *account = purple_connection_get_account(gc);
+	gchar *who = jingle_session_get_remote_jid(session);
+	
+	purple_debug_error("jingle-ft", 
+		"an error occured during SOCKS5 file transfer\n");
+	purple_xfer_error(purple_xfer_get_type(xfer), account, who,
+		_("An error occured on the SOCKS5 transfer\n"));
+	purple_xfer_cancel_remote(xfer);
+	g_free(who);
+	g_object_unref(session);
+}
+
+
+static void
+jingle_file_transfer_s5b_connect_failed_callback(JingleContent *content)
+{
+	/* the S5B transport has failed to connect */
+	PurpleXfer *xfer = JINGLE_FT_GET_PRIVATE(JINGLE_FT(content))->xfer;
+	JingleSession *session = jingle_content_get_session(content);
+
+	if (JINGLE_FT(content)->priv->remote_failed_s5b &&
+		jingle_session_is_initiator(session)) {
+		/* if the other end supports IBB, offer a transport replace */
+		gchar *who = jingle_session_get_remote_jid(session);
+		JabberStream *js = jingle_session_get_js(session);
+		JabberBuddy *jb = jabber_buddy_find(js, who, FALSE);
+		const gchar *resource = jabber_get_resource(who);
+		JabberBuddyResource *jbr = jabber_buddy_find_resource(jb, resource);
+
+		if (jabber_resource_has_capability(jbr, JINGLE_TRANSPORT_IBB)) {
+			/* the buddy supports IBB, offer a transport replace */
+			JabberIq *transport_replace = NULL;
+			JingleTransport *new_transport = 
+				jingle_transport_create(JINGLE_TRANSPORT_IBB);
+			/* setup IBB stuff for the transport */
+			jingle_file_transfer_add_ibb_session_to_transport(
+				js, new_transport, content, who);
+			/* let the transport be pending until we get a transport-accept */
+			jingle_content_set_pending_transport(content, new_transport);
+
+			transport_replace = 
+				jingle_session_to_packet(session, JINGLE_TRANSPORT_REPLACE);
+		} else {
+			/* the buddy doesn't support IBB, terminate it */
+			JabberStream *js = jingle_session_get_js(session);
+			PurpleConnection *gc = js->gc;
+			PurpleAccount *account = purple_connection_get_account(gc);
+			JabberIq *session_terminate =
+				jingle_session_terminate_packet(session, "connectivity-error");
+
+			purple_debug_error("jingle-ft", 
+				"could not establish s5b connection, and IBB is not "
+				"available\n");
+			purple_xfer_error(purple_xfer_get_type(xfer), account, who,
+				_("Failed to establish a SOCKS5 connection\n"));
+			purple_xfer_cancel_remote(xfer);
+			
+			jabber_iq_send(session_terminate);
+			g_object_unref(session);
+		}
+		g_free(who);
+	}
+}
+
+
+
+
+static void
 jingle_file_transfer_xfer_init(PurpleXfer *xfer)
 {
 	if (purple_xfer_get_type(xfer) == PURPLE_XFER_SEND) {
@@ -489,6 +544,8 @@ jingle_file_transfer_xfer_init(PurpleXfe
 				jingle_file_transfer_s5b_connect_callback, content);
 			jingle_s5b_set_error_callback(JINGLE_S5B(transport),
 				jingle_file_transfer_s5b_error_callback, content);
+			jingle_s5b_set_failed_connect_callback(JINGLE_S5B(transport),
+				jingle_file_transfer_s5b_connect_failed_callback, content);
 			/* start local listen on the S5B transport */
 			jingle_s5b_gather_streamhosts(session, JINGLE_S5B(transport));
 		}	
@@ -536,6 +593,8 @@ jingle_file_transfer_xfer_init(PurpleXfe
 				jingle_file_transfer_s5b_connect_callback, content);
 			jingle_s5b_set_error_callback(JINGLE_S5B(transport),
 				jingle_file_transfer_s5b_error_callback, content);
+			jingle_s5b_set_failed_connect_callback(JINGLE_S5B(transport),
+				jingle_file_transfer_s5b_connect_failed_callback, content);
 			jingle_s5b_gather_streamhosts(session, JINGLE_S5B(transport));
 		}
 		g_object_unref(session);
@@ -740,8 +799,7 @@ jingle_file_transfer_handle_action_inter
 		}
 		case JINGLE_TRANSPORT_INFO: {
 			JingleSession *session = jingle_content_get_session(content);
-			JingleTransport *transport = jingle_transport_parse(
-					xmlnode_get_child(xmlcontent, "transport"));
+			JingleTransport *transport = jingle_content_get_transport(content);
 			xmlnode *xmltransport = xmlnode_get_child(xmlcontent, "transport");
 			
 			/* we should check for "stream-host" error (in the case of S5B) and
@@ -755,6 +813,16 @@ jingle_file_transfer_handle_action_inter
 						"got a streamhost-error, remote couldn't connect\n");
 					JINGLE_FT_GET_PRIVATE(JINGLE_FT(content))->
 						remote_failed_s5b = TRUE;
+				
+					/* if we have already tried connecting to all remote
+					 streamhost candidates, or there were none, trigger
+					 the replace callback directly */
+					if (JINGLE_IS_S5B(transport) &&
+						!jingle_s5b_has_remaining_remote_streamhosts(
+							JINGLE_S5B(transport))) {
+						jingle_file_transfer_s5b_connect_failed_callback(
+							content);
+					}
 				}
 			}
 			
@@ -764,13 +832,34 @@ jingle_file_transfer_handle_action_inter
 		case JINGLE_TRANSPORT_ACCEPT: {
 			JingleSession *session = jingle_content_get_session(content);
 			JingleTransport *transport = jingle_content_get_transport(content);
-			
+			PurpleXfer *xfer = 
+				jingle_file_transfer_get_xfer(content);
+
 			purple_debug_info("jingle-ft",
 				"content %p\n", content);
 			purple_debug_info("jingle-ft", 
 				"got transport-accept transport %p\n", transport);
 			
-			if (JINGLE_IS_S5B(transport)) {
+			/* if we got a streamhost-error before, we should switch over to
+			 IBB here */
+			if (JINGLE_FT(content)->priv->remote_failed_s5b) {
+				jingle_content_accept_transport(content);
+				/* open the file, etc... */
+				JINGLE_FT_GET_PRIVATE(JINGLE_FT(content))->ibb_fp = 
+					g_fopen(purple_xfer_get_local_filename(xfer), "rb");
+				
+				if (JINGLE_FT_GET_PRIVATE(JINGLE_FT(content))->ibb_fp) {
+					/* send first data */
+					purple_xfer_start(xfer, 0, NULL, 0);
+					purple_xfer_set_bytes_sent(xfer, 0);
+					purple_xfer_update_progress(xfer);
+					jingle_file_transfer_ibb_send_data(content);
+				} else {
+					purple_debug_error("jingle-ft", 
+						"failed to open file for reading\n");
+					jingle_file_transfer_cancel_local(content);
+				}
+			} else if (JINGLE_IS_S5B(transport)) {
 				JingleS5B *s5b = JINGLE_S5B(transport);
 				xmlnode *xmltransport = xmlnode_get_child(xmlcontent, "transport");
 				jingle_s5b_handle_transport_accept(s5b, session, xmltransport);
@@ -780,9 +869,56 @@ jingle_file_transfer_handle_action_inter
 		}
 		case JINGLE_TRANSPORT_REPLACE: {
 			JingleSession *session = jingle_content_get_session(content);
+			xmlnode *xmltransport = xmlnode_get_child(xmlcontent, "transport");
+			JingleTransport *new_transport =
+				jingle_transport_parse(xmltransport);
+			const gchar *sid = 
+				xmlnode_get_attrib(xmlnode_get_child(xmlcontent, 
+					"transport"), "sid");
+			gchar *who = jingle_session_get_remote_jid(session);
+			const PurpleXfer *xfer = JINGLE_FT(content)->priv->xfer;
+			const gchar *filename = purple_xfer_get_local_filename(xfer);
 			
 			/* fallback to IBB etc... */
+			if (JINGLE_IS_IBB(new_transport)) {
+				JingleIBB *ibb = JINGLE_IBB(new_transport);
+				
+				jingle_ibb_create_session(ibb, content, sid, who);
+				/* immediatly accept the new transport */
+				jingle_content_set_pending_transport(content, new_transport);
+				jingle_content_accept_transport(content);
+				
+				/* open the file and setup the callbacks */
+				JINGLE_FT_GET_PRIVATE(JINGLE_FT(content))->ibb_fp = 
+					g_fopen(filename, "wb");
+				if (JINGLE_FT_GET_PRIVATE(JINGLE_FT(content))->ibb_fp == NULL) {
+					purple_debug_error("jabber", 
+						"failed to open file %s for writing: %s\n", filename, 
+						g_strerror(errno));
+					purple_xfer_cancel_remote(xfer);
+					jabber_iq_send(jingle_session_to_packet(session,
+						JINGLE_SESSION_TERMINATE));
+					g_object_unref(new_transport);
+					g_object_unref(session);
+					g_object_unref(session);
+					g_free(who);
+					return;
+				}
+
+				/* setup callbacks */
+				jingle_ibb_set_data_received_callback(ibb, 
+					jingle_file_transfer_ibb_data_recv_callback);
+				jingle_ibb_set_error_callback(ibb,
+					jingle_file_transfer_ibb_error_callback);
+	
+				/* start the transfer */
+				purple_xfer_start(xfer, 0, NULL, 0);
+				
+				/* send transport-accept */
+				
+			}
 			
+			g_free(who);
 			g_object_unref(session);
 			break;
 		}
============================================================
--- libpurple/protocols/jabber/jingle/s5b.c	3f599e599cd59079cbc0425948cbe0c4df840dde
+++ libpurple/protocols/jabber/jingle/s5b.c	797456202eed8accdf2772fcb5adbc83cae955df
@@ -152,8 +152,10 @@ struct _JingleS5BPrivate {
 	JabberBytestreamsStreamhost *accepted_streamhost;
 	JingleS5BConnectCallback *connect_cb;
 	JingleS5BErrorCallback *error_cb;
+	JingleS5BFailedConnectCallback *failed_cb;
 	JingleContent *connect_content; /* used for the connect callback */
 	JingleContent *error_content;  /* used for the error callback */
+	JingleContent *failed_content; /* used for the failed callback */
 	gboolean is_connected_to_remote;
 	gboolean is_remote_connected;
 };
@@ -356,6 +358,13 @@ void jingle_s5b_set_error_callback(Jingl
 	s5b->priv->error_content = content;
 }
 
+void jingle_s5b_set_failed_connect_callback(JingleS5B *s5b,
+	JingleS5BFailedConnectCallback *cb, JingleContent *content)
+{
+	s5b->priv->failed_cb = cb;
+	s5b->priv->failed_content = content;
+}
+
 void
 jingle_s5b_add_streamhosts(JingleS5B *s5b, const xmlnode *transport)
 {
@@ -1191,6 +1200,11 @@ jingle_s5b_attempt_connect_internal(gpoi
 
 		xmlnode_insert_child(transport, xmlnode_new("streamhost-error"));
 		jabber_iq_send(streamhost_error);
+		
+		/* signal to the content that S5B failed (from our side) */
+		if (s5b->priv->failed_cb && s5b->priv->failed_content)
+			s5b->priv->failed_cb(s5b->priv->failed_content);
+
 		g_free(data);
 	}
 }
@@ -1356,3 +1370,8 @@ jingle_s5b_handle_transport_accept(Jingl
 	}
 }
 
+gboolean
+jingle_s5b_has_remaining_remote_streamhosts(const JingleS5B *s5b)
+{
+	return s5b->priv->remaining_streamhosts != NULL;
+}
============================================================
--- libpurple/protocols/jabber/jingle/s5b.h	e41dc6c96d582522526facd24fec2bc646b18418
+++ libpurple/protocols/jabber/jingle/s5b.h	4489c8d56e02f260b6308874323aa8b562cf6624
@@ -57,6 +57,7 @@ typedef void (JingleS5BErrorCallback)(Ji
 /* Callbacks used for S5B */
 typedef void (JingleS5BConnectCallback)(JingleContent *) ;
 typedef void (JingleS5BErrorCallback)(JingleContent *);
+typedef void (JingleS5BFailedConnectCallback)(JingleContent *);
 
 #ifdef __cplusplus
 extern "C" {
@@ -78,8 +79,9 @@ void jingle_s5b_set_error_callback(Jingl
 	JingleS5BConnectCallback *cb, JingleContent *content);
 void jingle_s5b_set_error_callback(JingleS5B *s5b, 
 	JingleS5BErrorCallback *cb, JingleContent *content);
+void jingle_s5b_set_failed_connect_callback(JingleS5B *s5b,
+	JingleS5BFailedConnectCallback *cb, JingleContent *content);
 
-
 void jingle_s5b_add_streamhosts(JingleS5B *s5b, const xmlnode *transport);
 
 /* start discovering streamhosts, initiator will send session-initiate when
@@ -91,6 +93,8 @@ void jingle_s5b_handle_transport_accept(
 void jingle_s5b_handle_transport_accept(JingleS5B *s5b, JingleSession *session, 
 	xmlnode *transport);
 
+gboolean jingle_s5b_has_remaining_remote_streamhosts(const JingleS5B *s5b);
+
 #ifdef __cplusplus
 }
 #endif


More information about the Commits mailing list