New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API < 21 support #2

Closed
xstherrera1987 opened this Issue Apr 2, 2017 · 8 comments

Comments

Projects
None yet
3 participants
@xstherrera1987

xstherrera1987 commented Apr 2, 2017

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.

@rom1v

This comment has been minimized.

Collaborator

rom1v commented Apr 2, 2017

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.

@xstherrera1987

This comment has been minimized.

xstherrera1987 commented Apr 3, 2017

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.

@rom1v

This comment has been minimized.

Collaborator

rom1v commented Apr 3, 2017

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.

@vvviperrr

This comment has been minimized.

vvviperrr commented Apr 6, 2017

@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
@rom1v

This comment has been minimized.

Collaborator

rom1v commented Apr 11, 2017

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.

rom1v added a commit that referenced this issue Apr 11, 2017

Support API >= 14
The minSdkVersion was set to 21 due to the call to
VpnService.Builder.setBlocking(true).

On API < 21, we can call the internal method
libcore.io.IoUtils.setBlocking() using reflection:
<https://android.googlesource.com/platform/libcore/+/30c669166d86d0bd133edfb67909665fb41d29b6/luni/src/main/java/libcore/io/IoUtils.java#89>

Therefore, use it as a fallback and set the minSdkVersion to 14, in
order to support devices from Android 4.0.

Related to <#2>.
@rom1v

This comment has been minimized.

Collaborator

rom1v commented Apr 11, 2017

I just implemented it (branch api14, commit 6ececf7, 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 ;-)

rom1v added a commit that referenced this issue Apr 11, 2017

Support API >= 14
The minSdkVersion was set to 21 due to the call to
VpnService.Builder.setBlocking(true).

On API < 21, we can call the internal method
libcore.io.IoUtils.setBlocking() using reflection:
<https://android.googlesource.com/platform/libcore/+/30c669166d86d0bd133edfb67909665fb41d29b6/luni/src/main/java/libcore/io/IoUtils.java#89>

Therefore, use it as a fallback and set the minSdkVersion to 14, in
order to support devices from Android 4.0.

Related to <#2>.

@rom1v rom1v self-assigned this Apr 11, 2017

@rom1v rom1v added the enhancement label Apr 11, 2017

@rom1v

This comment has been minimized.

Collaborator

rom1v commented Apr 13, 2017

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 socats (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…

@rom1v

This comment has been minimized.

Collaborator

rom1v commented Aug 9, 2017

adb reverse is not implemented on Android 4

So I'm closing this issue as WONTFIX.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment