[GH-ISSUE #828] Redesign (S)FTP asynchronous processing #2591

Closed
opened 2026-03-01 17:21:44 +03:00 by kerem · 9 comments
Owner

Originally created by @itagagaki on GitHub (Jan 6, 2025).
Original GitHub issue: https://github.com/1Remote/1Remote/issues/828

Originally assigned to: @itagagaki on GitHub.

I installed File Manager on my Google Pixel 8 (Android 15) and started the FTP server function and tried to connect from 1Remote, but it doesn't work.

The device folder in the root directory is visible. However, an error message appears at the bottom of the window. It may be one of the following, although it varies from time to time.

ls /: Arithmetic operation resulted in an overflow.
ls : One or more errors occurred. (Timed out trying to connect!)
ls : One or more errors occurred. (The operation is not allowed on non-connected sockets.)
ls : One or more errors occurred. (Safe handle has been closed.
Object name: 'SafeHandle')

*The last one is on multiple lines, but the display area is for one line, so it protrudes a bit.

Error messages may not be displayed. When this happens, it is displayed as

ls /

However, in any case, when I double-click on device, I get the same error and cannot access the directory.

Note that WinSCP can access the same protocol/address/port without any problems.

Originally created by @itagagaki on GitHub (Jan 6, 2025). Original GitHub issue: https://github.com/1Remote/1Remote/issues/828 Originally assigned to: @itagagaki on GitHub. I installed [File Manager](https://play.google.com/store/apps/details?id=com.alphainventor.filemanager) on my Google Pixel 8 (Android 15) and started the FTP server function and tried to connect from 1Remote, but it doesn't work. The `device` folder in the root directory is visible. However, an error message appears at the bottom of the window. It may be one of the following, although it varies from time to time. ``` ls /: Arithmetic operation resulted in an overflow. ``` ``` ls : One or more errors occurred. (Timed out trying to connect!) ``` ``` ls : One or more errors occurred. (The operation is not allowed on non-connected sockets.) ``` ``` ls : One or more errors occurred. (Safe handle has been closed. Object name: 'SafeHandle') ``` *The last one is on multiple lines, but the display area is for one line, so it protrudes a bit. Error messages may not be displayed. When this happens, it is displayed as `ls /` However, in any case, when I double-click on `device`, I get the same error and cannot access the directory. Note that WinSCP can access the same protocol/address/port without any problems.
kerem 2026-03-01 17:21:44 +03:00
  • closed this issue
  • added the
    bug
    label
Author
Owner

@VShawn commented on GitHub (Jan 7, 2025):

I am not able to proceed this ticket as I do not have an Android device.

<!-- gh-comment-id:2574191585 --> @VShawn commented on GitHub (Jan 7, 2025): I am not able to proceed this ticket as I do not have an Android device.
Author
Owner

@itagagaki commented on GitHub (Jan 7, 2025):

I will analyze this.

<!-- gh-comment-id:2574325256 --> @itagagaki commented on GitHub (Jan 7, 2025): I will analyze this.
Author
Owner

@itagagaki commented on GitHub (Jan 7, 2025):

First, I monitored the network traffic.
For 1Remote, it was as follows.

Response           220 File Manager ready
Command    TYPE I
Response           530 Login incorrect
Command    USER xxx
Response           331 Password required
Command    TYPE I
Response           530 Login incorrect
Command    PASS xxx
Response           230 Access granted
Command    TYPE I
Response           200 Binary type set
Command    FEAT
Response           211- Extensions supported:<CR><LF> UTF8<CR><LF> MLST<CR><LF> MLSD<CR><LF> MFMT<CR><LF> REST STREAM<CR><LF>211 End
Command    EPSV
Response           550 Unsupported command
Command    OPTS UTF8 ON
Response           220 UTF8 OK
Command    PASV
Response           227 Entering Passive Mode
Command    SYST
Response           215 UNIX Type: L8
Command    LIST /
Response           150 Opening BINARY mode data connection for LIST
Command    PWD
Response           226 Data transmission succeeded
Response           257 "/"

It sends the TYPE command many times before logging in (presumably it appears to be done before each command is executed), and each time it is rejected. I'm not sure, but "One or more errors occurred.” might mean these responses. And this could be the reason why 1Remote does not work afterwards.

Or it may simply be that this FTP server does not support the EPSV command, which is why it is not available on 1Remote.

For the same FTP server, WinSCP worked as follows.

Response           220 File Manager ready
Command    USER xxx
Response           331 Password required
Command    PASS xxx
Response           230 Access granted
Command    SYST
Response           215 UNIX Type: L8
Command    FEAT
Response           211- Extensions supported:<CR><LF> UTF8<CR><LF> MLST<CR><LF> MLSD<CR><LF> MFMT<CR><LF> REST STREAM<CR><LF>211 End
Command    OPTS UTF8 ON
Response           220 UTF8 OK
Command    PWD
Repsonse           257 "/"
Command    TYPE A
Response           200 ASCII type set
Command    PASV
Response           227 Entering Passive Mode
Command    MLSD
Response           150 Opening ASCII mode data connection for MLSD
Response           226 Data transmission succeeded

Next, to resolve this issue, we also need to investigate 1Remote's built-in FTP runner and related codes.
Any advice on where to look?

<!-- gh-comment-id:2575072309 --> @itagagaki commented on GitHub (Jan 7, 2025): First, I monitored the network traffic. For 1Remote, it was as follows. ``` Response 220 File Manager ready Command TYPE I Response 530 Login incorrect Command USER xxx Response 331 Password required Command TYPE I Response 530 Login incorrect Command PASS xxx Response 230 Access granted Command TYPE I Response 200 Binary type set Command FEAT Response 211- Extensions supported:<CR><LF> UTF8<CR><LF> MLST<CR><LF> MLSD<CR><LF> MFMT<CR><LF> REST STREAM<CR><LF>211 End Command EPSV Response 550 Unsupported command Command OPTS UTF8 ON Response 220 UTF8 OK Command PASV Response 227 Entering Passive Mode Command SYST Response 215 UNIX Type: L8 Command LIST / Response 150 Opening BINARY mode data connection for LIST Command PWD Response 226 Data transmission succeeded Response 257 "/" ``` It sends the `TYPE` command many times before logging in (presumably it appears to be done before each command is executed), and each time it is rejected. I'm not sure, but "One or more errors occurred.” might mean these responses. And this could be the reason why 1Remote does not work afterwards. Or it may simply be that this FTP server does not support the `EPSV` command, which is why it is not available on 1Remote. For the same FTP server, WinSCP worked as follows. ``` Response 220 File Manager ready Command USER xxx Response 331 Password required Command PASS xxx Response 230 Access granted Command SYST Response 215 UNIX Type: L8 Command FEAT Response 211- Extensions supported:<CR><LF> UTF8<CR><LF> MLST<CR><LF> MLSD<CR><LF> MFMT<CR><LF> REST STREAM<CR><LF>211 End Command OPTS UTF8 ON Response 220 UTF8 OK Command PWD Repsonse 257 "/" Command TYPE A Response 200 ASCII type set Command PASV Response 227 Entering Passive Mode Command MLSD Response 150 Opening ASCII mode data connection for MLSD Response 226 Data transmission succeeded ``` Next, to resolve this issue, we also need to investigate 1Remote's built-in FTP runner and related codes. Any advice on where to look?
Author
Owner

@itagagaki commented on GitHub (Jan 8, 2025):

It may send a PASV before logging in. In this case, the server will still respond with 530 Login incorrect, but 1Remote will continue to send PASV for many time after that.

<!-- gh-comment-id:2577364561 --> @itagagaki commented on GitHub (Jan 8, 2025): It may send a `PASV` before logging in. In this case, the server will still respond with `530 Login incorrect`, but 1Remote will continue to send `PASV` for many time after that.
Author
Owner

@itagagaki commented on GitHub (Jan 8, 2025):

Okay, the following patch may be a workaround to avoid errors immediately after connection.

--- a/Ui/Model/Protocol/FileTransmit/Transmitters/TransmitterFtp.cs
+++ b/Ui/Model/Protocol/FileTransmit/Transmitters/TransmitterFtp.cs
@@ -1,14 +1,15 @@
 using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using System.Threading;
+using System.Threading.Tasks;
 using FluentFTP;
 using Shawn.Utils;

 namespace _1RM.Model.Protocol.FileTransmit.Transmitters
 {
     public class TransmitterFtp : ITransmitter
     {
         public readonly string Hostname;
         public readonly int Port;
@@ -248,18 +249,21 @@ namespace _1RM.Model.Protocol.FileTransmit.Transmitters
         private void InitClient()
         {
             lock (this)
             {
                 if (_ftp?.IsConnected != true)
                 {
                     _ftp?.Dispose();
                     _ftp = new AsyncFtpClient(Hostname, new System.Net.NetworkCredential(Username, Password), Port);
                     _ftp.Connect();
+                    while (_ftp.IsAuthenticated != true) {
+                        Task.Delay(1);
+                    }
                 }
             }
         }

However, it still cannot access the subdirectory. The message "ls /: Arithmetic operation resulted in an overflow." is shown.

I will continue the analysis.

<!-- gh-comment-id:2577668756 --> @itagagaki commented on GitHub (Jan 8, 2025): Okay, the following patch may be a workaround to avoid errors immediately after connection. ``` --- a/Ui/Model/Protocol/FileTransmit/Transmitters/TransmitterFtp.cs +++ b/Ui/Model/Protocol/FileTransmit/Transmitters/TransmitterFtp.cs @@ -1,14 +1,15 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; +using System.Threading.Tasks; using FluentFTP; using Shawn.Utils; namespace _1RM.Model.Protocol.FileTransmit.Transmitters { public class TransmitterFtp : ITransmitter { public readonly string Hostname; public readonly int Port; @@ -248,18 +249,21 @@ namespace _1RM.Model.Protocol.FileTransmit.Transmitters private void InitClient() { lock (this) { if (_ftp?.IsConnected != true) { _ftp?.Dispose(); _ftp = new AsyncFtpClient(Hostname, new System.Net.NetworkCredential(Username, Password), Port); _ftp.Connect(); + while (_ftp.IsAuthenticated != true) { + Task.Delay(1); + } } } } ``` However, it still cannot access the subdirectory. The message "ls /: Arithmetic operation resulted in an overflow." is shown. I will continue the analysis.
Author
Owner

@itagagaki commented on GitHub (Jan 9, 2025):

Okay, I found the cause of the "Arithmetic operation resulted in an overflow" error and fixed it.
Now I can connect to the FTP server and browse any remote directory.

But there is still a problem. It cannot download a file. The download starts, but the progress stays at zero and eventually times out. Strangely, if the file already exists at the download destination, the download proceeds normally and the file is overwritten.
I think it's a problem with _ftp.DownloadFile() or the way it's used, but I don't know how to resolve it yet.

<!-- gh-comment-id:2580557329 --> @itagagaki commented on GitHub (Jan 9, 2025): Okay, I found the cause of the "Arithmetic operation resulted in an overflow" error and fixed it. Now I can connect to the FTP server and browse any remote directory. But there is still a problem. It cannot download a file. The download starts, but the progress stays at zero and eventually times out. Strangely, if the file already exists at the download destination, the download proceeds normally and the file is overwritten. I think it's a problem with `_ftp.DownloadFile()` or the way it's used, but I don't know how to resolve it yet.
Author
Owner

@itagagaki commented on GitHub (Jan 11, 2025):

When downloading a file, if a file with the same name exists in the destination folder, it can be downloaded, otherwise it fails.

This seems to be a permissions issue.

In the case of failure, after loading C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App\6.0.36\Accessibility.dll, a System.AggregateException is thrown in System.Private.CoreLib.dll.

I don't know how to get around it.

<!-- gh-comment-id:2585240128 --> @itagagaki commented on GitHub (Jan 11, 2025): When downloading a file, if a file with the same name exists in the destination folder, it can be downloaded, otherwise it fails. This seems to be a permissions issue. In the case of failure, after loading `C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App\6.0.36\Accessibility.dll`, a `System.AggregateException` is thrown in `System.Private.CoreLib.dll`. I don't know how to get around it.
Author
Owner

@itagagaki commented on GitHub (Jan 11, 2025):

More analysis is needed, but one thing has emerged.
_ftp.Connect() in TransmitterFtp.InitClient() must be changed to await _ftp.Connect().
If not, the main thread goes charging on.
(The delay I wrote earlier helps a bit, but is not the right solution).

To do this, InitClient must be changed to async and the lock must be removed.
@VShawn can you tell me what the intent of this lock is?

<!-- gh-comment-id:2585401497 --> @itagagaki commented on GitHub (Jan 11, 2025): More analysis is needed, but one thing has emerged. `_ftp.Connect()` in `TransmitterFtp.InitClient()` must be changed to `await _ftp.Connect()`. If not, the main thread goes charging on. (The delay I wrote earlier helps a bit, but is not the right solution). To do this, `InitClient` must be changed to `async` and the `lock` must be removed. @VShawn can you tell me what the intent of this `lock` is?
Author
Owner

@VShawn commented on GitHub (Jan 12, 2025):

Any advice on where to look?

I think https://github.com/sshnet/SSH.NET

When downloading a file, if a file with the same name exists in the destination folder, it can be downloaded, otherwise it fails.

Is this exception thrown by Renci.SshNet? If so, we can seek help at https://github.com/sshnet/SSH.NET.

can you tell me what the intent of this lock is?

I don't have any recollection of this lock; it's from very early code. And from the context, it seems that this lock is intended to prevent duplicate init of connection and to address issues related to concurrent calls.

github.com/1Remote/1Remote@785042a37b (diff-ac81bd4867)

<!-- gh-comment-id:2585534015 --> @VShawn commented on GitHub (Jan 12, 2025): > Any advice on where to look? I think https://github.com/sshnet/SSH.NET > When downloading a file, if a file with the same name exists in the destination folder, it can be downloaded, otherwise it fails. Is this exception thrown by `Renci.SshNet`? If so, we can seek help at https://github.com/sshnet/SSH.NET. > can you tell me what the intent of this lock is? I don't have any recollection of this lock; it's from very early code. And from the context, it seems that this lock is intended to prevent duplicate init of connection and to address issues related to concurrent calls. https://github.com/1Remote/1Remote/commit/785042a37b0c2f151b780dd726c1ad6d0d61150f#diff-ac81bd48676bd3564921c5ebfc973199d44081f7faf2320d6c5e55680b76e388R259
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/1Remote#2591
No description provided.