Closed xstherrera1987 closed 7 years ago
The min SDK version has been set to 21 due to the call to setBlocking(true).
The VPN interface is non-blocking par default, which would be great if there was a possibility to select/poll it, but it is not possible since FileChannel is not selectable. So we have a non-blocking interface without asynchronous I/O API, which is stupid. This means that when no data is available, every read would return immediately with 0 bytes…
Therefore, to avoid a busy loop with arbitrary sleep(), I had no choice but to use blocking mode and read from a different thread.
However, you could set the non-blocking mode from native code in order to avoid calling this method from API 21. I didn't do it because then, the NDK would be required for building gnirehtet (and 1 apk per architecture), which IMO would be a bit overkill for this.
so the simplest pre-21 solution (without NDK) would probably be to create a long-running thread that just polls then sleeps (maybe every 150ms) if no data is available, ie created in RelayTunnel.open and polls RelayTunnel.receive. I also noticed that pre 22 VpnService.setUnderlyingNetworks
is unavailable but have to assume its not critical. Is my understanding correct and is my workaround more or less sound?
There doesn't seem to be any related android-support libraries for VPN. If this is infeasible, I can attempt the NDK solution. I learned C/C++ in college a few years ago but haven't used either since. But seeing as it should amount to setup/config and a single syscall it may be simpler.
Is my understanding correct and is my workaround more or less sound?
In principle, yes, using polling as a fallback when API < 21 is a good compromise I guess.
However, what is set blocking by the API 22 is the VPN interface (used for the communication between Android and gnirehtet), not the relay tunnel (used between the gnirehtet client and the relay server).
NOTE: the relay tunnel is also used in blocking mode in the client, but this design follows the fact that reading and writing are executed from separate threads, caused itself by the VPN interface beeing blocking.
Therefore, you need to replace both this blocking read and this blocking write (which calls this real blocking write) by some polling.
Tip: sleep only when the previous read/write returned 0 (e.g. don't wait if you just received data, maybe there are more available), otherwise performance would suffer too much.
@xstherrera1987 u can try my tool. it works with API >= 14.
as @rom1v mentioned, the main problem is non-blocking tunnel descriptor. but i use native code to put in into blocking mode. and u dont need one apk per arch, its suitable for arm, mips and x86:
lib/x86/libsimplertjni.so
lib/armeabi-v7a/libsimplertjni.so
lib/armeabi/libsimplertjni.so
lib/mips/libsimplertjni.so
Another solution to enable blocking mode without depending on the NDK is to call IoUtils.setBlocking(…)
by reflection.
I'll probably investigate this solution.
A quick test shows that if I replace the call to setBlocking(true)
by this call on the vpnInterface
, it still works… To be tested on lower APIs.
I just implemented it (branch api14
, commit https://github.com/Genymobile/gnirehtet/commit/6ececf78e0035717d0f2651d015bb4e8727c1b0c, not merged yet). It should support Android >= 4.0 (API 14).
Please test it on Android 4 devices (I have no such devices available).
I am waiting for your feedbacks ;-)
I just tried on several Android 4.x devices, unfortunately adb reverse
is not implemented on Android 4:
$ adb reverse tcp:31416 tcp:31416
error: closed
So even if I may set the VPN interface in blocking mode, it still does not work… :-(
adb forward
works, though, so it may be possible to "revert" the connection. But reverting the role of the relay and client in the connection initialization would add a lot a complexity: the relay server would have to monitor available devices, pick an unused local port to forward, etc.
However, it should be possible to "revert" the connection with 2 socat
s (one on the computer, one on the device), as I explained recently on my blog (in French, but code blocks and schema may be sufficient): http://blog.rom1v.com/2017/03/serveur-client/
Or we need another way to open a TCP connection between the client and the relay server…
adb reverse
is not implemented on Android 4
So I'm closing this issue as WONTFIX.
@rom1v thanks so much for the api14
branch. do we need to build the package ourselves? do you know if the api14
app works with the latest (v2.3) relay?
I have an API 19 tablet that for whatever reason has defective/inconsistent wifi capabilities. I'd like to fork this project to provide support for API 19 at least. My question then is why is min API set at 21, is it just for UI compatability/simplicity issue or is there some network API's on 21? Im not very familiar with low-level Android network API's so any help is appreciated, thanks.