cpw.malu.xmpp.jingle_ft: 107e704a: Refactor out socks5-listening code to it...
malu at pidgin.im
malu at pidgin.im
Wed May 5 16:20:49 EDT 2010
-----------------------------------------------------------------
Revision: 107e704a6ea54af028832ea8a416128b4fcf206e
Ancestor: 2075a801884dd95a558f1d8cacc9231dec200833
Author: malu at pidgin.im
Date: 2010-05-05T20:15:50
Branch: im.pidgin.cpw.malu.xmpp.jingle_ft
URL: http://d.pidgin.im/viewmtn/revision/info/107e704a6ea54af028832ea8a416128b4fcf206e
Added files:
libpurple/protocols/jabber/socks5.c
libpurple/protocols/jabber/socks5.h
Modified files:
libpurple/protocols/jabber/Makefile.am
libpurple/protocols/jabber/Makefile.mingw
libpurple/protocols/jabber/jingle/s5b.c
ChangeLog:
Refactor out socks5-listening code to its own module.
TODO: update si.c to use this too
-------------- next part --------------
============================================================
--- libpurple/protocols/jabber/socks5.c 66f50e5ae1872036c7c6f695ddad418a5f20aa14
+++ libpurple/protocols/jabber/socks5.c 66f50e5ae1872036c7c6f695ddad418a5f20aa14
@@ -0,0 +1,429 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA
+ */
+
+#include "socks5.h"
+#include "debug.h"
+#include "jutil.h"
+#include "network.h"
+
+typedef struct {
+ JabberSocks5ConnectCallback *connect_cb;
+ JabberSocks5ErrorCallback *error_cb;
+ gchar *dstaddr;
+ int watcher;
+ gint local_fd;
+ gsize rxlen;
+ gsize rxmaxlen;
+ char *rxqueue;
+ gpointer user_data;
+} JabberSocks5ListenDataPriv;
+
+
+static void
+jabber_socks5_send_read_again_resp_cb(gpointer data, gint source,
+ PurpleInputCondition cond)
+{
+ JabberSocks5ListenDataPriv *priv = (JabberSocks5ListenDataPriv *) data;
+ int len;
+
+ purple_debug_info("jabber-socks5", "in jabber_socks5_send_read_again_cb\n");
+ len = write(source, priv->rxqueue + priv->rxlen, priv->rxmaxlen - priv->rxlen);
+
+ if (len < 0 && errno == EAGAIN)
+ return;
+ else if (len < 0) {
+ purple_input_remove(priv->watcher);
+ priv->watcher = 0;
+ g_free(priv->rxqueue);
+ priv->rxqueue = NULL;
+ close(source);
+ if (priv->error_cb)
+ priv->error_cb(priv->user_data);
+ return;
+ }
+ priv->rxlen += len;
+
+ if (priv->rxlen < priv->rxmaxlen)
+ return;
+
+ purple_input_remove(priv->watcher);
+ priv->watcher = 0;
+ g_free(priv->rxqueue);
+ priv->rxqueue = NULL;
+
+ /* Before actually starting sending the file, we need to wait until the
+ * recipient sends the IQ result with <candidate-used/>
+ */
+ purple_debug_info("jabber-socks5", "SOCKS5 connection negotiation completed. "
+ "Waiting for IQ result to start transfer.\n");
+
+ if (priv->connect_cb)
+ priv->connect_cb(source, priv->user_data);
+}
+
+
+static void
+jabber_socks5_send_read_again_cb(gpointer data, gint source,
+ PurpleInputCondition cond)
+{
+ JabberSocks5ListenDataPriv *priv = (JabberSocks5ListenDataPriv *) data;
+ gchar *dstaddr = priv->dstaddr;
+ const gchar *host = purple_network_get_my_ip(-1);
+ char buffer[42]; /* 40 for DST.ADDR + 2 bytes for port number*/
+ int len;
+ char *hash;
+
+ purple_debug_info("jabber-socks5",
+ "in jabber_socks5_send_read_again_cb\n");
+
+ if(priv->rxlen < 5) {
+ purple_debug_info("jabber-socks5", "reading the first 5 bytes\n");
+ len = read(source, buffer, 5 - priv->rxlen);
+ if(len < 0 && errno == EAGAIN)
+ return;
+ else if(len <= 0) {
+ purple_input_remove(priv->watcher);
+ priv->watcher = 0;
+ close(source);
+ if (priv->error_cb)
+ priv->error_cb(priv->user_data);
+ return;
+ }
+ priv->rxqueue = g_realloc(priv->rxqueue, len + priv->rxlen);
+ memcpy(priv->rxqueue + priv->rxlen, buffer, len);
+ priv->rxlen += len;
+ return;
+ } else if (priv->rxqueue[0] != 0x05 || priv->rxqueue[1] != 0x01 ||
+ priv->rxqueue[3] != 0x03 || priv->rxqueue[4] != 40) {
+ purple_debug_info("jabber-socks5",
+ "Invalid socks5 conn req. header[0x%x,0x%x,0x%x,0x%x,0x%x]\n",
+ priv->rxqueue[0], priv->rxqueue[1], priv->rxqueue[2],
+ priv->rxqueue[3], priv->rxqueue[4]);
+ purple_input_remove(priv->watcher);
+ priv->watcher = 0;
+ close(source);
+ if (priv->error_cb)
+ priv->error_cb(priv->user_data);
+ return;
+ } else if (priv->rxlen - 5 < priv->rxqueue[4] + 2) {
+ purple_debug_info("jabber-socks5",
+ "reading %d "
+ " bytes for DST.ADDR + port num (trying to read %" G_GSIZE_FORMAT " now)\n",
+ priv->rxqueue[4] + 2,
+ priv->rxqueue[4] + 2 - (priv->rxlen - 5));
+ len = read(source, buffer, priv->rxqueue[4] + 2 - (priv->rxlen - 5));
+
+ if (len < 0 && errno == EAGAIN)
+ return;
+ else if (len <= 0) {
+ purple_input_remove(priv->watcher);
+ priv->watcher = 0;
+ close(source);
+ if (priv->error_cb)
+ priv->error_cb(priv->user_data);
+ return;
+ }
+ priv->rxqueue = g_realloc(priv->rxqueue, len + priv->rxlen);
+ memcpy(priv->rxqueue + priv->rxlen, buffer, len);
+ priv->rxlen += len;
+ }
+
+ /* Have we not read all of DST.ADDR and the following 2-byte port number? */
+ if (priv->rxlen - 5 < priv->rxqueue[4] + 2)
+ return;
+
+ purple_input_remove(priv->watcher);
+ priv->watcher = 0;
+
+ /* Per XEP-0065, the 'host' must be SHA1(SID + from JID + to JID) */
+ hash = jabber_calculate_data_hash(dstaddr, strlen(dstaddr), "sha1");
+ purple_debug_info("jabber-socks5", "dstaddr: %s\n", dstaddr);
+ purple_debug_info("jabber-socks5", "expecting to receive hash %s\n", hash);
+
+ if (strncmp(hash, priv->rxqueue + 5, 40) ||
+ priv->rxqueue[45] != 0x00 || priv->rxqueue[46] != 0x00) {
+ if (priv->rxqueue[45] != 0x00 || priv->rxqueue[46] != 0x00)
+ purple_debug_error("jabber-socks5",
+ "Got SOCKS5 BS conn with the wrong DST.PORT "
+ " (must be 0 - got[0x%x,0x%x]).\n",
+ priv->rxqueue[45], priv->rxqueue[46]);
+ else
+ purple_debug_error("jabber-socks5",
+ "Got SOCKS5 BS conn with the wrong DST.ADDR"
+ " (expected '%s' - got '%.40s').\n",
+ hash, priv->rxqueue + 5);
+
+ close(source);
+ if (priv->error_cb)
+ priv->error_cb(priv->user_data);
+ g_free(hash);
+ return;
+ }
+
+ g_free(hash);
+ g_free(priv->rxqueue);
+ priv->rxqueue = NULL;
+
+ priv->rxmaxlen = 5 + strlen(host) + 2;
+ priv->rxqueue = g_malloc(priv->rxmaxlen);
+ priv->rxlen = 0;
+
+ priv->rxqueue[0] = 0x05;
+ priv->rxqueue[1] = 0x00;
+ priv->rxqueue[2] = 0x00;
+ priv->rxqueue[3] = 0x03;
+ priv->rxqueue[4] = strlen(host);
+ memcpy(priv->rxqueue + 5, host, strlen(host));
+ priv->rxqueue[5 + strlen(host)] = 0x00;
+ priv->rxqueue[6 + strlen(host)] = 0x00;
+
+ priv->watcher = purple_input_add(source, PURPLE_INPUT_WRITE,
+ jabber_socks5_send_read_again_resp_cb, data);
+ jabber_socks5_send_read_again_resp_cb(data, source,
+ PURPLE_INPUT_WRITE);
+}
+
+
+static void
+jabber_socks5_send_read_response_cb(gpointer data, gint source,
+ PurpleInputCondition cond)
+{
+ JabberSocks5ListenDataPriv *priv = (JabberSocks5ListenDataPriv *) data;
+ int len;
+
+ purple_debug_info("jabber-socks5", "in jabber_socks5_send_read_response_cb\n");
+
+ len = write(source, priv->rxqueue + priv->rxlen, priv->rxmaxlen - priv->rxlen);
+
+ if (len < 0 && errno == EAGAIN)
+ return;
+ else if (len < 0) {
+ purple_input_remove(priv->watcher);
+ priv->watcher = 0;
+ g_free(priv->rxqueue);
+ priv->rxqueue = NULL;
+ close(source);
+ if (priv->error_cb)
+ priv->error_cb(priv->user_data);
+ return;
+ }
+ priv->rxlen += len;
+
+ if (priv->rxlen < priv->rxmaxlen) {
+ if (priv->error_cb)
+ priv->error_cb(priv->user_data);
+ return;
+ }
+
+ purple_input_remove(priv->watcher);
+ priv->watcher = 0;
+
+ /* If we sent a "Success", wait for a response, otherwise give up and cancel */
+ if (priv->rxqueue[1] == 0x00) {
+ priv->watcher = purple_input_add(source, PURPLE_INPUT_READ,
+ jabber_socks5_send_read_again_cb, data);
+ g_free(priv->rxqueue);
+ priv->rxqueue = NULL;
+ priv->rxlen = 0;
+ } else {
+ close(source);
+ if (priv->error_cb)
+ priv->error_cb(priv->user_data);
+ }
+}
+
+static void
+jabber_socks5_send_read_cb(gpointer data, gint source, PurpleInputCondition cond)
+{
+ JabberSocks5ListenDataPriv *priv = (JabberSocks5ListenDataPriv *) data;
+ int i;
+ int len;
+ char buffer[256];
+
+ purple_debug_info("jabber-socks5", "in jabber_socks5_send_read_cb\n");
+
+ priv->local_fd = source;
+
+ /* Try to read the SOCKS5 header */
+ if (priv->rxlen < 2) {
+ purple_debug_info("jabber-socks5", "reading those first two bytes\n");
+ len = read(source, buffer, 2 - priv->rxlen);
+ if(len < 0 && errno == EAGAIN)
+ return;
+ else if(len <= 0) {
+ purple_input_remove(priv->watcher);
+ priv->watcher = 0;
+ close(source);
+ if (priv->error_cb)
+ priv->error_cb(priv->user_data);
+ return;
+ }
+ priv->rxqueue =
+ g_realloc(priv->rxqueue, len + priv->rxlen);
+ memcpy(priv->rxqueue + priv->rxlen, buffer, len);
+ priv->rxlen += len;
+ return;
+ } else if (priv->rxlen - 2 < priv->rxqueue[1]) {
+ purple_debug_info("jabber-socks5",
+ "reading %d "
+ " bytes for auth methods (trying to read %" G_GSIZE_FORMAT " now)\n",
+ priv->rxqueue[1], priv->rxqueue[1] - (priv->rxlen - 2));
+ len = read(source, buffer, priv->rxqueue[1] - (priv->rxlen - 2));
+
+ if(len < 0 && errno == EAGAIN)
+ return;
+ else if(len <= 0) {
+ purple_input_remove(priv->watcher);
+ priv->watcher = 0;
+ close(source);
+ if (priv->error_cb)
+ priv->error_cb(priv->user_data);
+ return;
+ }
+ priv->rxqueue =
+ g_realloc(priv->rxqueue, len + priv->rxlen);
+ memcpy(priv->rxqueue + priv->rxlen, buffer, len);
+ priv->rxlen += len;
+ }
+
+ /* Have we not read all the auth. method bytes? */
+ if(priv->rxlen - 2 < priv->rxqueue[1])
+ return;
+
+ purple_input_remove(priv->watcher);
+ priv->watcher = 0;
+
+ purple_debug_info("jabber-socks5", "checking to make sure we're socks FIVE\n");
+
+ if(priv->rxqueue[0] != 0x05) {
+ purple_debug_error("jabber-socks5", "it's not socks FIVE, giving up\n");
+ close(source);
+ if (priv->error_cb)
+ priv->error_cb(priv->user_data);
+ return;
+ }
+
+ purple_debug_info("jabber-socks5", "going to test %hhu different methods\n",
+ priv->rxqueue[1]);
+
+ for (i = 0; i < priv->rxqueue[1]; i++) {
+ purple_debug_info("jabber-socks5", "testing %hhu\n",
+ priv->rxqueue[i+2]);
+ if (priv->rxqueue[i+2] == 0x00) {
+ g_free(priv->rxqueue);
+ priv->rxlen = 0;
+ priv->rxmaxlen = 2;
+ priv->rxqueue = g_malloc(priv->rxmaxlen);
+ priv->rxqueue[0] = 0x05;
+ priv->rxqueue[1] = 0x00;
+ priv->watcher = purple_input_add(source, PURPLE_INPUT_WRITE,
+ jabber_socks5_send_read_response_cb, priv);
+ jabber_socks5_send_read_response_cb(priv, source, PURPLE_INPUT_WRITE);
+ priv->rxqueue = NULL;
+ priv->rxlen = 0;
+ return;
+ }
+ }
+
+ /* question to self: is this called if there was no methods given? */
+ g_free(priv->rxqueue);
+ priv->rxlen = 0;
+ priv->rxmaxlen = 2;
+ priv->rxqueue = g_malloc(priv->rxmaxlen);
+ priv->rxqueue[0] = 0x05;
+ priv->rxqueue[1] = 0xFF;
+ priv->watcher = purple_input_add(source, PURPLE_INPUT_WRITE,
+ jabber_socks5_send_read_response_cb, priv);
+ jabber_socks5_send_read_response_cb(priv,
+ source, PURPLE_INPUT_WRITE);
+}
+
+
+static void
+jabber_socks5_send_connected_cb(gpointer data, gint source,
+ PurpleInputCondition cond)
+{
+ JabberSocks5ListenDataPriv *priv = (JabberSocks5ListenDataPriv *) data;
+ int acceptfd = accept(source, NULL, 0);
+ int flags;
+
+ purple_debug_info("jabber-socks5", "in jabber_socks5_send_connected_cb\n");
+
+ if(acceptfd == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
+ return;
+ else if(acceptfd == -1) {
+ purple_debug_warning("jabber-socks5", "accept: %s\n", g_strerror(errno));
+ /* Don't cancel the ft - allow it to fall to the next streamhost.*/
+ return;
+ }
+
+ purple_input_remove(priv->watcher);
+ close(source);
+
+ flags = fcntl(acceptfd, F_GETFL);
+ fcntl(acceptfd, F_SETFL, flags | O_NONBLOCK);
+#ifndef _WIN32
+ fcntl(acceptfd, F_SETFD, FD_CLOEXEC);
+#endif
+
+ priv->watcher = purple_input_add(acceptfd, PURPLE_INPUT_READ,
+ jabber_socks5_send_read_cb, priv);
+}
+
+
+JabberSocks5ListenData *
+jabber_socks5_listen(int socket, const gchar *dstaddr,
+ JabberSocks5ConnectCallback *connect_cb,
+ JabberSocks5ErrorCallback *error_cb, gpointer user_data)
+{
+ JabberSocks5ListenDataPriv *priv = g_new0(JabberSocks5ListenDataPriv, 1);
+ JabberSocks5ListenData *listen_data = g_new0(JabberSocks5ListenData, 1);
+
+ priv->connect_cb = connect_cb;
+ priv->error_cb = error_cb;
+ priv->user_data = user_data;
+ priv->dstaddr = g_strdup(dstaddr);
+ priv->watcher = purple_input_add(socket, PURPLE_INPUT_READ,
+ jabber_socks5_send_connected_cb, priv);
+
+ listen_data->priv = priv;
+
+ return listen_data;
+}
+
+void
+jabber_socks5_listen_cancel(JabberSocks5ListenData *listen_data)
+{
+ JabberSocks5ListenDataPriv *priv =
+ (JabberSocks5ListenDataPriv *) listen_data->priv;
+
+ if (priv->watcher)
+ purple_input_remove(priv->watcher);
+}
+
+void
+jabber_socks5_listen_data_free(JabberSocks5ListenData *listen_data)
+{
+ JabberSocks5ListenDataPriv *priv =
+ (JabberSocks5ListenDataPriv *) listen_data->priv;
+
+ if (priv->rxqueue)
+ g_free(priv->rxqueue);
+ if (priv->dstaddr)
+ g_free(priv->dstaddr);
+ g_free(priv);
+ g_free(listen_data);
+}
============================================================
--- libpurple/protocols/jabber/socks5.h ced2ee3d959300aa9e95a3f07989628b01fea2f6
+++ libpurple/protocols/jabber/socks5.h ced2ee3d959300aa9e95a3f07989628b01fea2f6
@@ -0,0 +1,36 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA
+ */
+
+#ifndef PURPLE_JABBER_SOCKS5_H_
+#define PURPLE_JABBER_SOCKS5_H_
+
+#include "internal.h"
+
+typedef struct {
+ gpointer priv;
+} JabberSocks5ListenData;
+
+typedef void (JabberSocks5ConnectCallback)(int fd, gpointer user_data);
+typedef void (JabberSocks5ErrorCallback)(gpointer user_data);
+
+JabberSocks5ListenData *jabber_socks5_listen(int socket, const gchar *dstadr,
+ JabberSocks5ConnectCallback *connect_cb,
+ JabberSocks5ErrorCallback *error_cb, gpointer user_data);
+
+void jabber_socks5_listen_cancel(JabberSocks5ListenData *listen_data);
+void jabber_socks5_listen_data_free(JabberSocks5ListenData *listen_data);
+
+#endif /* PURPLE_JABBER_SOCKS5_H_ */
============================================================
--- libpurple/protocols/jabber/Makefile.am 3cc9e1d13797ed32ccd79e1c9ea6be2724a75316
+++ libpurple/protocols/jabber/Makefile.am 8aa6d3dea8dabe33ba733b83f679d45bfda039d0
@@ -73,6 +73,8 @@ JABBERSOURCES = \
roster.h \
si.c \
si.h \
+ socks5.c \
+ socks5.h \
useravatar.c \
useravatar.h \
usermood.c \
============================================================
--- libpurple/protocols/jabber/Makefile.mingw ee64a101fee7fb8c7a54976867dcbef43dc7f326
+++ libpurple/protocols/jabber/Makefile.mingw c64e117ee26658f06c15fa4d0b3816a7688f3c39
@@ -78,6 +78,7 @@ C_SRC = \
presence.c \
roster.c \
si.c \
+ socks5.c \
useravatar.c \
usermood.c \
usernick.c \
============================================================
--- libpurple/protocols/jabber/jingle/s5b.c c21466dbb6474dcbbcf221257cd7e2c006c5b642
+++ libpurple/protocols/jabber/jingle/s5b.c c94b63fbddfe41b254a4241a2aadd0f355cbc65e
@@ -20,6 +20,7 @@
#include "session.h"
#include "content.h"
#include "s5b.h"
+#include "socks5.h"
#include "debug.h"
#include "network.h"
#include "xmlnode.h"
@@ -202,10 +203,7 @@ struct _JingleS5BPrivate {
PurpleNetworkListenData *listen_data;
PurpleProxyInfo *ppi;
guint connect_timeout;
- int watcher;
- char *rxqueue;
- gsize rxlen;
- gsize rxmaxlen;
+ JabberSocks5ListenData *socks5_listen_data;
GList *remote_candidates;
GList *local_candidates;
GList *remaining_candidates; /* pointer to untested remote SHs */
@@ -537,10 +535,11 @@ jingle_s5b_surrender(JingleS5B *s5b)
close(s5b->priv->local_fd);
s5b->priv->local_fd = -1;
}
-
- if (s5b->priv->watcher) {
- purple_input_remove(s5b->priv->watcher);
- s5b->priv->watcher = 0;
+
+ if (s5b->priv->socks5_listen_data) {
+ jabber_socks5_listen_cancel(s5b->priv->socks5_listen_data);
+ jabber_socks5_listen_data_free(s5b->priv->socks5_listen_data);
+ s5b->priv->socks5_listen_data = NULL;
}
if (s5b->priv->connect_timeout) {
@@ -560,10 +559,10 @@ jingle_s5b_take_command(JingleS5B *s5b)
close(s5b->priv->remote_fd);
s5b->priv->remote_fd = -1;
}
-
- if (s5b->priv->watcher) {
- purple_input_remove(s5b->priv->watcher);
- s5b->priv->watcher = 0;
+
+ if (s5b->priv->socks5_listen_data) {
+ jabber_socks5_listen_data_free(s5b->priv->socks5_listen_data);
+ s5b->priv->socks5_listen_data = NULL;
}
if (s5b->priv->connect_timeout) {
@@ -588,396 +587,52 @@ jingle_s5b_stop_connection_attempts(Jing
purple_timeout_remove(s5b->priv->connect_timeout);
s5b->priv->connect_timeout = 0;
}
-
- if (s5b->priv->watcher != 0) {
- purple_input_remove(s5b->priv->watcher);
- s5b->priv->watcher = 0;
- }
}
-
+/* holds information regarding listening socks5 connection */
typedef struct {
JingleSession *session;
JingleS5B *s5b;
} JingleS5BConnectData;
+
+/* callbacks for socks5 listner */
static void
-jingle_s5b_send_read_again_resp_cb(gpointer data, gint source,
- PurpleInputCondition cond)
+jingle_s5b_listen_connect_cb(int fd, gpointer data)
{
JingleS5B *s5b = ((JingleS5BConnectData *) data)->s5b;
- int len;
g_free(data);
+ jabber_socks5_listen_data_free(s5b->priv->socks5_listen_data);
+ s5b->priv->socks5_listen_data = NULL;
- purple_debug_info("jingle-s5b", "in jingle_s5b_send_read_again_cb\n");
- len = write(source, s5b->priv->rxqueue + s5b->priv->rxlen,
- s5b->priv->rxmaxlen - s5b->priv->rxlen);
- if (len < 0 && errno == EAGAIN)
- return;
- else if (len < 0) {
- purple_input_remove(s5b->priv->watcher);
- s5b->priv->watcher = 0;
- g_free(s5b->priv->rxqueue);
- s5b->priv->rxqueue = NULL;
- close(source);
- if (s5b->priv->error_cb && s5b->priv->error_content)
- s5b->priv->error_cb(s5b->priv->error_content);
- return;
- }
- s5b->priv->rxlen += len;
-
- if (s5b->priv->rxlen < s5b->priv->rxmaxlen)
- return;
-
- purple_input_remove(s5b->priv->watcher);
- s5b->priv->watcher = 0;
- g_free(s5b->priv->rxqueue);
- s5b->priv->rxqueue = NULL;
-
/* Before actually starting sending the file, we need to wait until the
* recipient sends the IQ result with <candidate-used/>
*/
purple_debug_info("jingle-s5b", "SOCKS5 connection negotiation completed. "
"Waiting for IQ result to start file transfer.\n");
/* set the local fd as connected */
- s5b->priv->local_fd = source;
+ s5b->priv->local_fd = fd;
s5b->priv->is_remote_connected = TRUE;
}
static void
-jingle_s5b_send_read_again_cb(gpointer data, gint source,
- PurpleInputCondition cond)
+jingle_s5b_listen_error_cb(gpointer data)
{
JingleS5B *s5b = ((JingleS5BConnectData *) data)->s5b;
- JingleSession *session = ((JingleS5BConnectData *) data)->session;
- const gchar *who = jingle_session_get_remote_jid(session);
- JabberID *dstjid = jabber_id_new(who);
- JabberStream *js = jingle_session_get_js(session);
- char buffer[42]; /* 40 for DST.ADDR + 2 bytes for port number*/
- int len;
- char *dstaddr, *hash;
- const char *host;
- purple_debug_info("jingle-s5b",
- "in jingle_s5b_send_read_again_cb\n");
-
- if(s5b->priv->rxlen < 5) {
- purple_debug_info("jingle-s5b", "reading the first 5 bytes\n");
- len = read(source, buffer, 5 - s5b->priv->rxlen);
- if(len < 0 && errno == EAGAIN)
- return;
- else if(len <= 0) {
- purple_input_remove(s5b->priv->watcher);
- s5b->priv->watcher = 0;
- close(source);
- if (s5b->priv->error_cb && s5b->priv->error_content)
- s5b->priv->error_cb(s5b->priv->error_content);
- g_free(data);
- return;
- }
- s5b->priv->rxqueue =
- g_realloc(s5b->priv->rxqueue, len + s5b->priv->rxlen);
- memcpy(s5b->priv->rxqueue + s5b->priv->rxlen, buffer, len);
- s5b->priv->rxlen += len;
- return;
- } else if(s5b->priv->rxqueue[0] != 0x05 || s5b->priv->rxqueue[1] != 0x01 ||
- s5b->priv->rxqueue[3] != 0x03 || s5b->priv->rxqueue[4] != 40) {
- purple_debug_info("jingle-s5b",
- "Invalid socks5 conn req. header[0x%x,0x%x,0x%x,0x%x,0x%x]\n",
- s5b->priv->rxqueue[0], s5b->priv->rxqueue[1], s5b->priv->rxqueue[2],
- s5b->priv->rxqueue[3], s5b->priv->rxqueue[4]);
- purple_input_remove(s5b->priv->watcher);
- s5b->priv->watcher = 0;
- close(source);
- if (s5b->priv->error_cb && s5b->priv->error_content)
- s5b->priv->error_cb(s5b->priv->error_content);
- g_free(data);
- return;
- } else if(s5b->priv->rxlen - 5 < s5b->priv->rxqueue[4] + 2) {
- purple_debug_info("jingle-s5b",
- "reading %d "
- " bytes for DST.ADDR + port num (trying to read %" G_GSIZE_FORMAT " now)\n",
- s5b->priv->rxqueue[4] + 2,
- s5b->priv->rxqueue[4] + 2 - (s5b->priv->rxlen - 5));
- len = read(source, buffer,
- s5b->priv->rxqueue[4] + 2 - (s5b->priv->rxlen - 5));
-
- if(len < 0 && errno == EAGAIN)
- return;
- else if(len <= 0) {
- purple_input_remove(s5b->priv->watcher);
- s5b->priv->watcher = 0;
- close(source);
- if (s5b->priv->error_cb && s5b->priv->error_content)
- s5b->priv->error_cb(s5b->priv->error_content);
- g_free(data);
- return;
- }
- s5b->priv->rxqueue =
- g_realloc(s5b->priv->rxqueue, len + s5b->priv->rxlen);
- memcpy(s5b->priv->rxqueue + s5b->priv->rxlen, buffer, len);
- s5b->priv->rxlen += len;
- }
-
- /* Have we not read all of DST.ADDR and the following 2-byte port number? */
- if(s5b->priv->rxlen - 5 < s5b->priv->rxqueue[4] + 2)
- return;
-
- purple_input_remove(s5b->priv->watcher);
- s5b->priv->watcher = 0;
-
- dstaddr = g_strdup_printf("%s%s@%s/%s%s@%s/%s", s5b->priv->sid,
- js->user->node, js->user->domain, js->user->resource,
- dstjid->node, dstjid->domain, dstjid->resource);
-
- g_free(dstjid);
-
- /* Per XEP-0065, the 'host' must be SHA1(SID + from JID + to JID) */
- hash = jabber_calculate_data_hash(dstaddr, strlen(dstaddr), "sha1");
- purple_debug_info("jingle-s5b", "dstaddr: %s\n", dstaddr);
- purple_debug_info("jingle-s5b", "expecting to receive hash %s\n", hash);
+ g_free(data);
+ jabber_socks5_listen_data_free(s5b->priv->socks5_listen_data);
+ s5b->priv->socks5_listen_data = NULL;
- if (strncmp(hash, s5b->priv->rxqueue + 5, 40) ||
- s5b->priv->rxqueue[45] != 0x00 || s5b->priv->rxqueue[46] != 0x00) {
- if (s5b->priv->rxqueue[45] != 0x00 || s5b->priv->rxqueue[46] != 0x00)
- purple_debug_error("jingle-s5b",
- "Got SOCKS5 BS conn with the wrong DST.PORT "
- " (must be 0 - got[0x%x,0x%x]).\n",
- s5b->priv->rxqueue[45], s5b->priv->rxqueue[46]);
- else
- purple_debug_error("jingle-s5b",
- "Got SOCKS5 BS conn with the wrong DST.ADDR"
- " (expected '%s' - got '%.40s').\n",
- hash, s5b->priv->rxqueue + 5);
+ purple_debug_info("jingle-s5b", "SOCKS5 connection negotiation failed. "
+ "Calling content handler's s5b error (fallback) handler.\n");
- close(source);
- if (s5b->priv->error_cb && s5b->priv->error_content)
+ if (s5b->priv->error_cb && s5b->priv->error_content)
s5b->priv->error_cb(s5b->priv->error_content);
- g_free(data);
- g_free(hash);
- g_free(dstaddr);
- return;
- }
-
- g_free(hash);
- g_free(dstaddr);
-
- g_free(s5b->priv->rxqueue);
- host = purple_network_get_my_ip(js->fd);
-
- s5b->priv->rxmaxlen = 5 + strlen(host) + 2;
- s5b->priv->rxqueue = g_malloc(s5b->priv->rxmaxlen);
- s5b->priv->rxlen = 0;
-
- s5b->priv->rxqueue[0] = 0x05;
- s5b->priv->rxqueue[1] = 0x00;
- s5b->priv->rxqueue[2] = 0x00;
- s5b->priv->rxqueue[3] = 0x03;
- s5b->priv->rxqueue[4] = strlen(host);
- memcpy(s5b->priv->rxqueue + 5, host, strlen(host));
- s5b->priv->rxqueue[5+strlen(host)] = 0x00;
- s5b->priv->rxqueue[6+strlen(host)] = 0x00;
-
- s5b->priv->watcher = purple_input_add(source, PURPLE_INPUT_WRITE,
- jingle_s5b_send_read_again_resp_cb, data);
- jingle_s5b_send_read_again_resp_cb(data, source,
- PURPLE_INPUT_WRITE);
}
static void
-jingle_s5b_send_read_response_cb(gpointer data, gint source,
- PurpleInputCondition cond)
-{
- JingleS5B *s5b = ((JingleS5BConnectData *) data)->s5b;
- int len;
-
- purple_debug_info("jingle-s5b", "in jingle_s5b_send_read_response_cb\n");
-
- len = write(source, s5b->priv->rxqueue + s5b->priv->rxlen,
- s5b->priv->rxmaxlen - s5b->priv->rxlen);
- if (len < 0 && errno == EAGAIN)
- return;
- else if (len < 0) {
- purple_input_remove(s5b->priv->watcher);
- s5b->priv->watcher = 0;
- g_free(s5b->priv->rxqueue);
- s5b->priv->rxqueue = NULL;
- close(source);
- if (s5b->priv->error_cb && s5b->priv->error_content)
- s5b->priv->error_cb(s5b->priv->error_content);
- g_free(data);
- return;
- }
- s5b->priv->rxlen += len;
-
- if (s5b->priv->rxlen < s5b->priv->rxmaxlen) {
- if (s5b->priv->error_cb && s5b->priv->error_content)
- s5b->priv->error_cb(s5b->priv->error_content);
- g_free(data);
- return;
- }
-
- purple_input_remove(s5b->priv->watcher);
- s5b->priv->watcher = 0;
-
- /* If we sent a "Success", wait for a response, otherwise give up and cancel */
- if (s5b->priv->rxqueue[1] == 0x00) {
- s5b->priv->watcher = purple_input_add(source, PURPLE_INPUT_READ,
- jingle_s5b_send_read_again_cb, data);
- g_free(s5b->priv->rxqueue);
- s5b->priv->rxqueue = NULL;
- s5b->priv->rxlen = 0;
- } else {
- close(source);
- if (s5b->priv->error_cb && s5b->priv->error_content)
- s5b->priv->error_cb(s5b->priv->error_content);
- g_free(data);
- }
-}
-
-static void
-jingle_s5b_send_read_cb(gpointer data, gint source, PurpleInputCondition cond)
-{
- JingleS5B *s5b = ((JingleS5BConnectData *) data)->s5b;
- int i;
- int len;
- char buffer[256];
-
- purple_debug_info("jingle-s5b", "in jingle_s5b_send_read_cb\n");
-
- s5b->priv->local_fd = source;
-
- /* Try to read the SOCKS5 header */
- if(s5b->priv->rxlen < 2) {
- purple_debug_info("jingle-s5b", "reading those first two bytes\n");
- len = read(source, buffer, 2 - s5b->priv->rxlen);
- if(len < 0 && errno == EAGAIN)
- return;
- else if(len <= 0) {
- purple_input_remove(s5b->priv->watcher);
- s5b->priv->watcher = 0;
- close(source);
- if (s5b->priv->error_cb && s5b->priv->error_content)
- s5b->priv->error_cb(s5b->priv->error_content);
- g_free(data);
- return;
- }
- s5b->priv->rxqueue =
- g_realloc(s5b->priv->rxqueue, len + s5b->priv->rxlen);
- memcpy(s5b->priv->rxqueue + s5b->priv->rxlen, buffer, len);
- s5b->priv->rxlen += len;
- return;
- } else if(s5b->priv->rxlen - 2 < s5b->priv->rxqueue[1]) {
- purple_debug_info("jingle-s5b",
- "reading %d "
- " bytes for auth methods (trying to read %" G_GSIZE_FORMAT " now)\n",
- s5b->priv->rxqueue[1], s5b->priv->rxqueue[1] - (s5b->priv->rxlen - 2));
- len = read(source, buffer, s5b->priv->rxqueue[1] - (s5b->priv->rxlen - 2));
-
- if(len < 0 && errno == EAGAIN)
- return;
- else if(len <= 0) {
- purple_input_remove(s5b->priv->watcher);
- s5b->priv->watcher = 0;
- close(source);
- if (s5b->priv->error_cb && s5b->priv->error_content)
- s5b->priv->error_cb(s5b->priv->error_content);
- g_free(data);
- return;
- }
- s5b->priv->rxqueue =
- g_realloc(s5b->priv->rxqueue, len + s5b->priv->rxlen);
- memcpy(s5b->priv->rxqueue + s5b->priv->rxlen, buffer, len);
- s5b->priv->rxlen += len;
- }
-
- /* Have we not read all the auth. method bytes? */
- if(s5b->priv->rxlen - 2 < s5b->priv->rxqueue[1])
- return;
-
- purple_input_remove(s5b->priv->watcher);
- s5b->priv->watcher = 0;
-
- purple_debug_info("jingle-s5b", "checking to make sure we're socks FIVE\n");
-
- if(s5b->priv->rxqueue[0] != 0x05) {
- purple_debug_error("jingle-s5b", "it's not socks FIVE, giving up\n");
- close(source);
- if (s5b->priv->error_cb && s5b->priv->error_content)
- s5b->priv->error_cb(s5b->priv->error_content);
- g_free(data);
- return;
- }
-
- purple_debug_info("jingle-s5b", "going to test %hhu different methods\n",
- s5b->priv->rxqueue[1]);
-
- for(i = 0; i < s5b->priv->rxqueue[1]; i++) {
- purple_debug_info("jingle-s5b", "testing %hhu\n",
- s5b->priv->rxqueue[i+2]);
- if(s5b->priv->rxqueue[i+2] == 0x00) {
- g_free(s5b->priv->rxqueue);
- s5b->priv->rxlen = 0;
- s5b->priv->rxmaxlen = 2;
- s5b->priv->rxqueue = g_malloc(s5b->priv->rxmaxlen);
- s5b->priv->rxqueue[0] = 0x05;
- s5b->priv->rxqueue[1] = 0x00;
- s5b->priv->watcher = purple_input_add(source, PURPLE_INPUT_WRITE,
- jingle_s5b_send_read_response_cb, data);
- jingle_s5b_send_read_response_cb(data, source, PURPLE_INPUT_WRITE);
- s5b->priv->rxqueue = NULL;
- s5b->priv->rxlen = 0;
- return;
- }
- }
-
- /* question to self: is this called if there was no methods given? */
- g_free(s5b->priv->rxqueue);
- s5b->priv->rxlen = 0;
- s5b->priv->rxmaxlen = 2;
- s5b->priv->rxqueue = g_malloc(s5b->priv->rxmaxlen);
- s5b->priv->rxqueue[0] = 0x05;
- s5b->priv->rxqueue[1] = 0xFF;
- s5b->priv->watcher = purple_input_add(source, PURPLE_INPUT_WRITE,
- jingle_s5b_send_read_response_cb, data);
- jingle_s5b_send_read_response_cb(data,
- source, PURPLE_INPUT_WRITE);
-}
-
-static void
-jingle_s5b_send_connected_cb(gpointer data, gint source,
- PurpleInputCondition cond)
-{
- JingleS5B *s5b = ((JingleS5BConnectData *) data)->s5b;
- int acceptfd = accept(source, NULL, 0);
- int flags;
-
- purple_debug_info("jingle-s5b", "in jingle_s5b_send_connected_cb\n");
-
- if(acceptfd == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
- return;
- else if(acceptfd == -1) {
- purple_debug_warning("jingle-s5b", "accept: %s\n", g_strerror(errno));
- /* Don't cancel the ft - allow it to fall to the next streamhost.*/
- return;
- }
-
- purple_input_remove(s5b->priv->watcher);
- close(source);
- s5b->priv->local_fd = -1;
-
- flags = fcntl(acceptfd, F_GETFL);
- fcntl(acceptfd, F_SETFL, flags | O_NONBLOCK);
-#ifndef _WIN32
- fcntl(acceptfd, F_SETFD, FD_CLOEXEC);
-#endif
-
- s5b->priv->watcher = purple_input_add(acceptfd, PURPLE_INPUT_READ,
- jingle_s5b_send_read_cb, data);
-}
-
-static void
jingle_s5b_listen_cb(int sock, gpointer data)
{
JingleS5B *s5b = ((JingleS5BConnectData *) data)->s5b;
@@ -994,7 +649,13 @@ jingle_s5b_listen_cb(int sock, gpointer
gchar *jid = g_strdup_printf("%s@%s/%s", js->user->node,
js->user->domain, js->user->resource);
gboolean has_public_ip = FALSE;
-
+ const gchar *who = jingle_session_get_remote_jid(session);
+ JabberID *dstjid = jabber_id_new(who);
+ gchar *dstaddr = g_strdup_printf("%s%s%s@%s/%s", s5b->priv->sid,
+ jid, dstjid->node, dstjid->domain, dstjid->resource);
+
+ jabber_id_free(dstjid);
+
purple_debug_info("jingle-s5b", "successfully open port %d locally\n",
local_port);
@@ -1025,9 +686,10 @@ jingle_s5b_listen_cb(int sock, gpointer
s5b->priv->local_fd = sock;
/* The listener for the local proxy */
- s5b->priv->watcher = purple_input_add(sock, PURPLE_INPUT_READ,
- jingle_s5b_send_connected_cb, data);
-
+ s5b->priv->socks5_listen_data = jabber_socks5_listen(sock, dstaddr,
+ jingle_s5b_listen_connect_cb, jingle_s5b_listen_error_cb, data);
+
+ g_free(dstaddr);
g_free(jid);
}
More information about the Commits
mailing list