Android Question IP address confusing when upload file with FTP

Sergio83

Member
Licensed User
Hello everybody,

A few days ago I opened a thread about file transfering with the NET library FTP client and the Erel writen FTP server class. Erel gave me the solution to my issue at once (even à Sunday !!!), but now I'm facing a new issue regarding the FTP server IP address ...

Let me explain my network configuration:

1- FTP server is hosted by an Android TVBox wich is connected to my Internet access router via a wired connection (IP address is 192.168.1.6)

2- FTP client is hosted by an android smartphone which is wirelessly connected to the TVBox (via its wifi hotspot, the IP address is 192.168.43.1)

When I use the ethernet IP address of the TVBox (192.168.1.6) to initialize the FTP client and upload a file everyting works OK.

When I use the wifi hotspot IP address of the TVBox (192.168.43.1) to initialize the FTP client and upload a file I get this exception:

B4X:
java.IOException: Host attempting data connection 192.168.1.6 is not the same as server 192.168.43.1
Here after some pieces of code I use:

FTP client initialization

B4X:
FTP.Initialize("FTP", "192.168.43.1",51041, "admin", "admin")
FTP.PassiveMode = True
Upload command:

B4X:
Sub FTP_transfer_start(FilePath As String, FileName As String)
   
   FTP.UploadFile(FilePath, FileName, True, "/USB_DISK1/udisk0/domus/backup/"&FileName)

End Sub
Does anybody has an idea where I'm mistaken ?

Thanks by advance for your help

Regards
 

Sergio83

Member
Licensed User
Hi Erel,

Of course it works .... but I really need to have a link to internet via my router ...
 

OliverA

Expert
Licensed User
The problem is that the FTP server attaches/listens to all interfaces of the router. So even though you can get to the FTP server via the 43.1 address, it also listens on the 1.6 address and it looks like the server's ServerSocket is using that address (the 1.6) as a return for the GetMyIP method. So, you create a connection to the server via the 43.1 address and then the server creates a Socket that's bound to 1.6 for the passive data connection which then leads to the error message posted. Solutions to the issue may include:
  1. Figure out how to have the router bind the FTP software to only one interface.
  2. Modify the FTP source to listen to only one interface (with code gleaned from this thread (https://www.b4x.com/android/forum/threads/serversocket-listening-on-a-single-ip.56832/#post-357698).
  3. Use a different FTP server that allows you to configure what interface it listens too.
  4. Some other solution from a more experienced/knowledgeable forum member.
 

Sergio83

Member
Licensed User
Hello OliverA,

I tryed your second solution. To be shure we're talking about the same "FTP source" for me it is Erel's classes based.

I modify the class module "FTPDataConnection" this way:

B4X:
Public Sub Initialize (Client As FTPClient, Server As FTPServer, port As Int)
   'ssocket.Initialize(port, "ssocket")
   InitializeWithIp(ssocket, "ssocket", 51041, "192.168.43.1")
   ssocket.Listen
   mClient = Client
   mServer = Server
   RETRTimer.Initialize("RETRTimer", 30)
End Sub

Sub InitializeWithIp(Server As ServerSocket, EventName As String, Port As Int, ip As String)
   Server.Initialize(0, EventName)
   Dim ia As JavaObject
   ia = ia.InitializeStatic("java.net.InetAddress").RunMethod("getByName", Array(ip))
   Dim s As JavaObject = Server
   Dim socket As JavaObject
   socket.InitializeNewInstance("java.net.ServerSocket", Array(Port, 50, ia))
   s.SetField("ssocket", socket)
End Sub
And now I get this exception:

B4X:
java.lang.RuntimeException: Error uploading file.
500 Error: libcore.io.ErrnoException: bind failed: EADDRINUSE (Address already in use)
Have you any idea of what's happening?

Regards
 

OliverA

Expert
Licensed User
I modify the class module "FTPDataConnection" this way
I think you need to modify the Start method in the FTPServer class module. This way, the client PASV request (FTPClient class module, HandleClientCommand method, Case "PASV") should return the IP address assigned in the Start method. That should also take care of the Initialize method of the FTPDataConnection class module (without modifying the FTPDataConnection class module).
 

Sergio83

Member
Licensed User
OK OliverA,

I'm a bit busy this morning, I will try your suggestion this afternoon and let you know what's going on

Regards
 

sorex

Expert
Licensed User
can't you modify the dhcp settings on your router so that both wifi and wired end up in the same ip range?

removing the wifi dhcp will make it all end up in the .1.x range as it will use the dhcp of the lan for wifi addresses leases.
 

Sergio83

Member
Licensed User
Hello Sorex,

Thanks for your help. But what you suggested me is not possible in my case.

The wired and wifi lan of my router is a multipurpose network:

- Chromecast
- DNLA server
- private home webradio with several home made receivers
- documents storage server
_ etc ....

The hotspot of my TVBox server manage many things:

- a smartphone as driving console and sms receiver/sender
- Openwrt boxes
- ESP8866 boxes
- etc

AS I can't modifify the hotspot IP address (192.168.43.x) I've to modify network parameters of all the boxes on my multipurpose network, and it will be a lot of work to to do that (most of them are IP static defined).

But I thing I have a solution only harware based ...

Thanks again for your help

Regards
 

Sergio83

Member
Licensed User
Hello OliverA,

I tryed your solution and I got the same exception: "IP allready in use" !

So I took my head in my hands and try to think in terms of network architecture.

My operationnal TVBox server is not directly connected to my internet router but through an ethernet switch because some boxes have a wired connection to my home automation network. This is not the case for my test platform.

Starting from that, I've connected my test TVBox server and the test link to my internet router to an ethernet switch and it's work perfect whether or not the internet router is up or down.

This is important because my home automation environment is power protected by an UPS not the internet router and the boxes connected to it (wire or wireless).

In any case I learnt some interesting thinks trying your suggestions

Thanks a lot for you help

Regards
 

sorex

Expert
Licensed User
also notice that a real open hotspot doesn't allow devices to connect with each other.
 

Sergio83

Member
Licensed User
Hello Sorex,

I fully agree with you on that point.

But in my (particular) case we have to consider both: logical servers (HTTP, MJPEG streamer, MJPEG recorder, MQTT Broker, FTP server, ...) and physical devices.

All these logical servers are hosted by the same device my TVBox and they share the same IP address (except the FTP server, for the reason you know ...), and each client is hosted by a specific device (OPENWRT boxes, Android devices, ESP 8266 boxes, and LINUX or WINDOWS PCs)

Clients are connecting to one or several logical servers hosted by the TVBox but never each other, they interact each other via the logical servers.

Additionnaly I think my hotspot is not very "open" don't you think so?

Thanks again for your help Sorex ...

Regards
 

OliverA

Expert
Licensed User
B4X:
java.lang.RuntimeException: Error uploading file.
500 Error: libcore.io.ErrnoException: bind failed: EADDRINUSE (Address already in use)
Have you any idea of what's happening?
Looking at this (https://stackoverflow.com/questions/24615704/socket-eaddrinuse-address-already-in-use) and this (https://stackoverflow.com/questions/23123395/what-is-the-purpose-of-setreuseaddress-in-serversocket) it looks like it may have to do with some sort of timeout issues with port assignments. The interesting part is that I cannot replicate this under B4J (seems to just work) and I don't have a project available under B4A to look into this. If it is because Android deals with port assignments differently, the InitializeWithIP method would need to be modified to work properly with Android (using the stackoverflow articles as a guide).

Regardless, I don't think this would have worked anyways, since I'm starting to believe that the culprit is the usage of the GetMyIP method of the ServerSocket class. Looking at the source (https://github.com/AnywhereSoftware...ywheresoftware/b4a/objects/SocketWrapper.java), GetMyIP just goes through the list of interfaces found on a device and returns an IP address that is not a 127.0.0.1 address. This has nothing to do with what interface the ServerSocket is actually running on. So even if the ServerSocket is restricted to a particular IP address, GetMyIP may not return that IP address. The code at issue is this in FTPClient:
B4X:
Case "PASV"
           PrepareDataConnection
           SendResponse (227, mServer.ssocket.GetMyIP.Replace(".", ",") & "," & Floor(mDataPort / 256) & "," & (mDataPort Mod 256))
Using this code (https://www.b4x.com/android/forum/bookmarks/?type=post&id=167644) and java documentation (https://docs.oracle.com/javase/7/docs/api/java/net/Socket.html#getLocalAddress()) as a guide, modify FTPClient as follows:

1) Add a new variable in Class_Globals
B4X:
Private IPAddress as String
2) Add the following lines to Initialize
B4X:
Dim jo As JavaObject = socket
jo = jo.GetField("socket")
jo = jo.RunMethod("getLocalAddress", Null) 'InetAddress
IPAddress = jo.RunMethod("getHostAddress", Null)
3) Modify the Case "PASV" in the HandleClientCommand
B4X:
Case "PASV"
   PrepareDataConnection
   'SendResponse (227, mServer.ssocket.GetMyIP.Replace(".", ",") & "," & Floor(mDataPort / 256) & "," & (mDataPort Mod 256))
   SendResponse (227, IPAddress.Replace(".", ",") & "," & Floor(mDataPort / 256) & "," & (mDataPort Mod 256))
This should take care of the issue that the command connection and data connection are bound to two different interfaces (in a multi-interface environment). If still willing please test if this resolves the issue (by re-configuring your network to the way it was when you were having you issues).
 

sorex

Expert
Licensed User
I re-read the first post again. it seems you're using tethering on the android tv stick?

that's the reason why you end up in a different subnet and probably missing correct routing routes to your other subnet exept for the gateway or it's left out for security reasons since it's a portable hotspot.

don't you have a normal access point to test with so that both the android phone and tv are in the same 1.x subnet?
 
Last edited:

Sergio83

Member
Licensed User
Hi OliverA,

Thank you for being so obstinate to help me!

In spite I found a usable turnaround, I will try your new suggestion because it's cleaner than using another IP address which should be never known by a client device of my TVBox servers.

I'll let you know the result

Regards
 

Sergio83

Member
Licensed User
Hello Sorex,

May be I'm not clear enough in my explanations, or maybe I do not have the right level of expertise to understand your suggestion, but "my normal access point" is my HotSpot TVBox (using the Android tethering feature) and regarding my home automation environment all the client devices should (have to) be connected to this HotSpot.

The reason why is that only this environment is power protected by a UPS device. Connexion of my TVBox to the main network (192.1681.x) is only for internet access and other home servers access purpose. If this connexion is down, it never minds because it is not mandatory to my home automation environment to work as expected.

Regards.
 

Sergio83

Member
Licensed User
Hello OliverA,

I tryed your last suggestion, but infortunately it doesn't work ... when the FTP client initialize a file transfer (upload) my server crashes!

I hope you will not shade but I will stay on my turn around solution

Best regards
 

OliverA

Expert
Licensed User
I hope you will not shade but I will stay on my turn around solution
No problem. Wish I had the error log on that crash though, but enough may be enough on this (may have to set up my own multi NIC environment).
 

Sergio83

Member
Licensed User
Hi OliverA,

Regarding the time you spent to help me I owe you this!

I will make this test again tomorrow, but as far as my memory is good the main reason of the crash was "socket not found" or something like that.

See you next ...
 

OliverA

Expert
Licensed User
I will make this test again tomorrow
No need. Foolish me was testing B4J, but I do now have a B4A implementation running and I see the failure. The socket implementation in Android is different and the SocketWrapper does not have a socket field. I'll have to do some research...
 
Top