gvfs/0005-FTP-add-EPRT-support.p...

102 lines
4.0 KiB
Diff

From 19a6bf345fdb8d445e4c3683e4ca0af0a0031f0b Mon Sep 17 00:00:00 2001
From: Benjamin Otte <otte@gnome.org>
Date: Tue, 16 Jun 2009 11:16:27 +0200
Subject: [PATCH 05/13] [FTP] add EPRT support
The code does not support some corner cases that are listed in the RFC
(see inline comments), but I suspect those will never be hit. We can add
those when they are hit.
---
daemon/gvfsftptask.c | 60 ++++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 53 insertions(+), 7 deletions(-)
diff --git a/daemon/gvfsftptask.c b/daemon/gvfsftptask.c
index 318dde4..9cab5a8 100644
--- a/daemon/gvfsftptask.c
+++ b/daemon/gvfsftptask.c
@@ -876,7 +876,52 @@ g_vfs_ftp_task_setup_data_connection_pasv (GVfsFtpTask *task, GVfsFtpMethod meth
}
static GVfsFtpMethod
-g_vfs_ftp_task_open_data_connection_port (GVfsFtpTask *task, GVfsFtpMethod unused)
+g_vfs_ftp_task_setup_data_connection_eprt (GVfsFtpTask *task, GVfsFtpMethod unused)
+{
+ GSocketAddress *addr;
+ guint status, port, family;
+ char *ip_string;
+
+ /* workaround for the task not having a connection yet */
+ if (task->conn == NULL &&
+ g_vfs_ftp_task_send (task, 0, "NOOP") == 0)
+ return G_VFS_FTP_METHOD_ANY;
+
+ addr = g_vfs_ftp_connection_listen_data_connection (task->conn, &task->error);
+ if (addr == NULL)
+ return G_VFS_FTP_METHOD_ANY;
+ switch (g_socket_address_get_family (addr))
+ {
+ case G_SOCKET_FAMILY_IPV4:
+ family = 1;
+ break;
+ case G_SOCKET_FAMILY_IPV6:
+ family = 2;
+ break;
+ default:
+ g_object_unref (addr);
+ return G_VFS_FTP_METHOD_ANY;
+ }
+
+ ip_string = g_inet_address_to_string (g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (addr)));
+ /* if this ever happens (and it must not for IP4 and IP6 addresses),
+ * we need to add support for using a different separator */
+ g_assert (strchr (ip_string, '|') == NULL);
+ port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
+
+ /* we could handle the 522 response here, (unsupported network family),
+ * but I don't think that will buy us anything */
+ status = g_vfs_ftp_task_send (task, 0, "EPRT |%u|%s|%u|", family, ip_string, port);
+ g_free (ip_string);
+ g_object_unref (addr);
+ if (status == 0)
+ return G_VFS_FTP_METHOD_ANY;
+
+ return G_VFS_FTP_METHOD_EPRT;
+}
+
+static GVfsFtpMethod
+g_vfs_ftp_task_setup_data_connection_port (GVfsFtpTask *task, GVfsFtpMethod unused)
{
GSocketAddress *addr;
guint status, i, port;
@@ -925,7 +970,8 @@ g_vfs_ftp_task_setup_data_connection_any (GVfsFtpTask *task, GVfsFtpMethod unuse
} funcs_ordered[] = {
{ G_VFS_FTP_FEATURE_EPSV, g_vfs_ftp_task_setup_data_connection_epsv },
{ 0, g_vfs_ftp_task_setup_data_connection_pasv },
- { 0, g_vfs_ftp_task_open_data_connection_port }
+ { G_VFS_FTP_FEATURE_EPSV, g_vfs_ftp_task_setup_data_connection_eprt },
+ { 0, g_vfs_ftp_task_setup_data_connection_port }
};
GVfsFtpMethod method;
guint i;
@@ -974,12 +1020,12 @@ void
g_vfs_ftp_task_setup_data_connection (GVfsFtpTask *task)
{
static const GVfsFtpOpenDataConnectionFunc connect_funcs[] = {
- [G_VFS_FTP_METHOD_ANY] = g_vfs_ftp_task_setup_data_connection_any,
- [G_VFS_FTP_METHOD_EPSV] = g_vfs_ftp_task_setup_data_connection_epsv,
- [G_VFS_FTP_METHOD_PASV] = g_vfs_ftp_task_setup_data_connection_pasv,
+ [G_VFS_FTP_METHOD_ANY] = g_vfs_ftp_task_setup_data_connection_any,
+ [G_VFS_FTP_METHOD_EPSV] = g_vfs_ftp_task_setup_data_connection_epsv,
+ [G_VFS_FTP_METHOD_PASV] = g_vfs_ftp_task_setup_data_connection_pasv,
[G_VFS_FTP_METHOD_PASV_ADDR] = g_vfs_ftp_task_setup_data_connection_pasv,
- [G_VFS_FTP_METHOD_EPRT] = NULL,
- [G_VFS_FTP_METHOD_PORT] = g_vfs_ftp_task_open_data_connection_port
+ [G_VFS_FTP_METHOD_EPRT] = g_vfs_ftp_task_setup_data_connection_eprt,
+ [G_VFS_FTP_METHOD_PORT] = g_vfs_ftp_task_setup_data_connection_port
};
GVfsFtpMethod method, result;
--
1.6.3.2