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