diff options
author | Benjamin Otte <otte@gnome.org> | 2009-06-16 11:16:27 +0200 |
---|---|---|
committer | Benjamin Otte <otte@gnome.org> | 2009-06-16 12:14:24 +0200 |
commit | 19a6bf345fdb8d445e4c3683e4ca0af0a0031f0b (patch) | |
tree | 3669b3cffd34df008b130d6ef8f5e35565db1299 /daemon/gvfsftptask.c | |
parent | 81fb75b2dc11a969d890f58bc3255ceae3f7bfde (diff) | |
download | gvfs-19a6bf345fdb8d445e4c3683e4ca0af0a0031f0b.tar.gz |
[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.
Diffstat (limited to 'daemon/gvfsftptask.c')
-rw-r--r-- | daemon/gvfsftptask.c | 60 |
1 files changed, 53 insertions, 7 deletions
diff --git a/daemon/gvfsftptask.c b/daemon/gvfsftptask.c index 318dde41..9cab5a8d 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; |