Giter Site home page Giter Site logo

ustadmobile / meshrabiya Goto Github PK

View Code? Open in Web Editor NEW
54.0 5.0 6.0 887 KB

Virtual mesh network for Android that operates over WiFi

License: GNU Lesser General Public License v3.0

Kotlin 93.59% HTML 6.41%
android android-library mesh mesh-networking wifidirect

meshrabiya's Introduction

Meshrabiya

Meshrabiya is a mesh network for Android that operates over WiFi. It allows applications to seamlessly communicate over multiple hops and multiple WiFi direct and/or Local Only Hotspots. Each device is given a "virtual" IP address (typically a random auto-generated address e.g. 169.254.x.y). Applications can then use the provided SocketFactory and/or DatagramSocket class to communicate with other nodes over multiple hops as if they were directly connected. This works with various higher level networking libraries such as OkHttp.

It is intended for use in situations where multiple Android devices need to communicate with each other and a WiFi access point is not available e.g. schools and health clinics without WiFi infrastructure, when hiking, etc. WiFi enables high-speed connections with tests obtaining 300Mbps+. Using multiple hops over multiple WiFi direct groups enables more devices to connect than is possible using a single device hotspot.

Meshrabiya is entirely open-source and does not have any proprietary dependencies (e.g. it works with Android Open Source Project devices and does not use/require Google Play Services, Nearby Connections API, etc).

Meshrabiya provides socket factories (for both TCP and UDP) that can create sockets to route data between nodes over multiple hops as if they were directly connected. The socket factory can also be used with other networking libraries (e.g. OkHttp) to make it easy to send/receive data over the virtual mesh.

How it works:

  • Node A creates a hotspot using a Wifi Direct Group. or Local Only Hotspot. It generates a "connect link" that includes the hotspot SSID, passphrase, ipv6 link local address (if a WiFi direct group), BSSID (where possible), and the service port number.
  • Node B obtains the connect link by scanning a QR code (this could also potentially be discovered via Bluetooth Low Energy Advertising). Node B connects to the hotspot of Node A using the Wifi Bootstrap API. If Node A created a WiFi direct group, then Node B will use the ipv6 link local address to reach Node A. If Node A created a Local Only Hotspot, then Node B will use the DHCP server address to reach Node A. Node B sends a UDP packet to the known address / service port of Node A to enable Node A to discover Node B. Node A and Node B can now communicate. The connection is done using WifiNetworkSpecifier on Android 10+ and using WifiManager on prior versions. On Android 10+ the user will normally only see
    a confirmation dialog the first time a connection is established between two nodes (except when it is not possible for a single node to maintain the same SSID and/or when the BSSID is unknown).
  • Node B creates its own hotspot. Node C (and so forth) can connect. All nodes periodically broadcast originator messages that include their virtual IP address and connect link. The propogation of originator messages is subject to limits on the maximum number of hops. When a node receives an originator message it knows the other node, and it knows the next hop if it wants to send traffic to that node. This is based on the BATMAN Originator Message concept.
  • Each node can simultaneously operate both a hotspot for incoming connections and make one outgoing connection via its WiFi station (client). There are two possible ways to do this, each of which has some advantages and disadvantages:
  • WiFi Direct Group Almost all Android devices (except it seems Android 11+ devices that support WiFi station - Access Point concurrency) can create a WiFi direct group and simultaneously remain connected to a WiFi access point (as a station). Creating a WiFi direct group creates a hotspot for "legacy devices" that operates a normal hotspot (and does not share Internet). IPv6 link local must be used to avoid an IP conflict due to the fact that Android assigns the IP address 192.168.49.1 to all nodes that operate as a WiFi direct group owner. We also use the link local IPv6 address to attempt to calculate the MAC Address, which needs to be specified to avoid a user prompt each time a user reconnects. Using the link local address to calculate the MAC address avoids the need to use CompanionDeviceManager to discover the Mac address (which requires using an intent result and results in users seeing two dialog boxes on Android 10). It is possible to specify the hotspot SSID, passphrase and band (2.4Ghz or 5Ghz) on any Android 10+ device.
  • Local Only Hotspot This is supported on all Android 8 devices, however it can only operate concurrently with being connected to another hotspot if WiFi station - Access Point concurrency is supported. This is only available on Android 11+ devices and requires hardware support. Generally lower-end devices are less likely to have this feature. Android generates a random subnet range so there is no IP address conflict when one device is both operating as a Local Only Hotspot provider and connected to another Local Only Hotspot at the same time. It is only possible to specify the hotspot SSID, passphrase, and band on Android 13+ using a hidden API.

Want to try it yourself? Download the test app APK from releases.

Want to collaborate on development? Join us on #meshrabiya:matrix.org.

Diagram

Getting started

Add repository to settings.gradle :

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
      ...
      maven { url "https://devserver3.ustadmobile.com/maven2/" }
    }
}       

Add the dependency

implementation "com.github.UstadMobile.Meshrabiya:lib-meshrabiya:0.1-snapshot"

Connect devices

Create a Virtual Node:

//Create a DataStore instance that Meshrabiya can use to remember networks etc.
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "meshr_settings")

val myNode = AndroidVirtualNode(
    appContext = applicationContext,
    dataStore = applicationContext.dataStore,
    //optionally - set address, network prefix length, etc.
)

Create a hotspot on one node:

myNode.setWifiHotspotEnabled(
  enabled = true,
  preferredBand = ConnectBand.BAND_5GHZ,
)

val connectLink = myNode.state.filter {
   it.connectUri != null
}.first()

Use the connect link to connect from another node:


val connectLink = ... //Get this from QR code scan etc.
val connectConfig = MeshrabiyaConnectLink.parseUri(connectLink).hotspotConfig
if(connectConfig != null) {
  myNode.connectAsStation(connectConfig)
}

Exchange data using TCP

  1. On the server side - create a normal server socket:
val serverVirtualAddr: InetAddress = myNode.address 
val serverSocket = ServerSocket(port)
  1. On the client side - use the socket factory to create a socket
val socketFactory = myNode.socketFactory
val clientSocket = socketFactory.createSocket(serverVirtualAddr, port)

The Socket Factory uses a "socket chain" under the hood. It will lookup the next hop to reach the given destination. It will then connect to the next hop and write its destination to socket stream, similar to how an http proxy uses the host header. Each node runs a chain socket forwarding server. Once the next hop is the destination (e.g. it reaches a node that has a direct connection to the destination node), then the socket is connected to the destination port. See ChainSocketServer for further details.

The Socket factory will fallback to using the system default socket factory for any destination that is not on the virtual network (e.g where the ip address does not match the netmask of the virtual node). It is therefor possible to use the socket factory anywhere, even when connections to non-virtual destinations are required - e.g. it can be used with an OKHttp Client and the client will be able to connect to both virtual and non-virtual addresses. e.g.

val okHttpClient: OkHttpClient = OkHttpClient.Builder()
            .socketFactory(myNode.socketFactory)
            .build()

Exchange data using UDP

Create a DatagramSocket with a given port (or use 0 to get a random port assignment)

val datagramSocket = myNode.createBoundDatagramSocket(port)

The socket can be used the same as a normal DatagramSocket (e.g. by using send/receive), but it will send/receive ONLY over the virtual network. Broadcast packets are supported by setting the destination address to 255.255.255.255

Known issues

Instrumented test debug: You must go to test settings, debug tab, and change to "java only" debugger type. Thank you, Google.

meshrabiya's People

Contributors

mikedawson avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

meshrabiya's Issues

Android 8: IPv6 linklocal addresses not working

As per the README, Meshrabiya uses IPv6 to workaround the IP address conflict that would otherwise happen when using WiFi direct.

Testing on a Lava Iris 60C (Android 8) results in a failure when attempting to ping using IPv6 link local addresses. The same ping command using the IPv4 address works.

Unless this can be resolved, Android 8 devices can probably only be terminal nodes.

Allow IPv6, v8

Problem:

Current implementation is hardcoded to use 32bit IPv4 addresses - does not allow use of IPv6 / IPv8 (which has P2P use cases).

Enhancement proposed:

  • Allow up to 256 bit IP addresses
  • Add API surface to allow app developers to control nodes joining and packet filtering (e.g. virtual firewall)

WifiDirect hotspot not working on Android 9 and below

Expected behavior:

Can enable hotspot on Xiaomi Redmi 6A and other devices can connect to it

Observed behavior:

Other devices can connect to Wifi hotspot; however node is not detected. IP traffic cannot be sent to/from device. Also fails when using ping

Ping on the adb command line also fails on almost all cases. Ping from Redmi to connected device on IPv4 will work. Ping from connected device to Redmi will fail on both IPv4 and IPv6.

Screenshot from 2023-08-16 19-47-20

redmi3-log.txt

[Feature Request] Option to share and combine mobile data?

Hello, I really love the concept of this app. I'm not sure if it's possible, but I think it would be nice if you could combine and share your mobile data to potentially get faster speeds. Is implementing this even possible, or dose this already exist?

Thank you for reading.

Allow manual connection (without QR code / discovery)

Issue:

The camera on a device can be broken. Users may want to manually enter the details to connect to another node

Suggested enhancement:

Allow users to manually enter the network SSID, passphrase, and port.

Add tun interface / VPN service

Use case:

Users wants to use the mesh network with other apps (e.g. meshenger, kiwix, file sharing, etc). Other apps might not want to embed Meshrabiya into their own source code. There could also be an issue if more than one app with Meshrabiya embedded is operating at the same time.

Solution:

Add an Android VPN service that is accessible over a tunnel interface, so any app can use the network.

CompanionDeviceManager crash

Observed on Lenovo TB-7306F running Android 11

                        I  setInputWindows displayId=0 Window{a04930a u0 NavigationBar0} Window{1b88c3f u0 StatusBar} com.android.companiondevicemanager/com.android.companiondevicemanager.DeviceChooserActivity#0 Window{7efd62b u0 com.ustadmobile.test_app/com.ustadmobile.test_app.VNetTestActivity} Window{9b0a507 u0 com.android.systemui.ImageWallpaper} 
2023-06-16 16:51:45.999   889-1048  bt_btif_config          com.android.bluetooth                D  btif_get_device_type: Device [e0:51:d3:42:8e:8b] type 2
--------- beginning of crash
2023-06-16 16:51:46.001 13967-13967 AndroidRuntime          com.android.companiondevicemanager   D  Shutting down VM
2023-06-16 16:51:46.002 13967-13967 AndroidRuntime          com.android.companiondevicemanager   E  FATAL EXCEPTION: main
                                                                                                    Process: com.android.companiondevicemanager, PID: 13967
                                                                                                    java.lang.NullPointerException
                                                                                                    	at com.android.internal.util.AnnotationValidations.validate(AnnotationValidations.java:129)
                                                                                                    	at android.companion.Association.<init>(Association.java:66)
                                                                                                    	at com.android.companiondevicemanager.DeviceDiscoveryService.onDeviceSelected(DeviceDiscoveryService.java:307)
                                                                                                    	at com.android.companiondevicemanager.DeviceChooserActivity.onDeviceConfirmed(DeviceChooserActivity.java:158)
                                                                                                    	at com.android.companiondevicemanager.DeviceChooserActivity.onSelectionUpdate(DeviceChooserActivity.java:147)
                                                                                                    	at com.android.companiondevicemanager.DeviceChooserActivity.access$000(DeviceChooserActivity.java:40)
                                                                                                    	at com.android.companiondevicemanager.DeviceChooserActivity$1.onChanged(DeviceChooserActivity.java:85)
                                                                                                    	at android.database.DataSetObservable.notifyChanged(DataSetObservable.java:37)
                                                                                                    	at android.widget.BaseAdapter.notifyDataSetChanged(BaseAdapter.java:54)
                                                                                                    	at android.widget.ArrayAdapter.notifyDataSetChanged(ArrayAdapter.java:355)
                                                                                                    	at com.android.companiondevicemanager.DeviceDiscoveryService.onDeviceFoundMainThread(DeviceDiscoveryService.java:278)
                                                                                                    	at com.android.companiondevicemanager.-$$Lambda$FF3bv59uzMtgFDQgbuOHg5xdwqo.accept(Unknown Source:4)
                                                                                                    	at com.android.internal.util.function.pooled.PooledLambdaImpl.doInvoke(PooledLambdaImpl.java:278)
                                                                                                    	at com.android.internal.util.function.pooled.PooledLambdaImpl.invoke(PooledLambdaImpl.java:201)
                                                                                                    	at com.android.internal.util.function.pooled.OmniFunction.run(OmniFunction.java:97)
                                                                                                    	at android.os.Handler.handleCallback(Handler.java:938)
                                                                                                    	at android.os.Handler.dispatchMessage(Handler.java:99)
                                                                                                    	at android.os.Looper.loop(Looper.java:223)
                                                                                                    	at android.app.ActivityThread.main(ActivityThread.java:7709)
                                                                                                    	at java.lang.reflect.Method.invoke(Native Method)
                                                                                                    	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:612)
                                                                                                    	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:997)
2023-06-16 16:51:46.004   710-5971  InputDispatcher         system_server                        I  setInputWindows displayId=0 Window{a04930a u0 NavigationBar0} Window{1b88c3f u0 StatusBar} com.android.companiondevicemanager/com.android.companiondevicemanager.DeviceChooserActivity#0 Window{7efd62b u0 com.ustadmobile.test_app/com.ustadmobile.test_app.VNetTestActivity} Window{9b0a507 u0 com.android.systemui.ImageWallpaper} 
2023-06-16 16:51:46.006   387-449   libPowerHal             [email protected]  I  [perfNotifyAppState] pack:com.android.companiondevicemanager, pid:13967, STATE_DEAD
2023-06-16 16:51:46.006   387-449   RilUtility              [email protected]  D  notify_rild_crash_pid_set certPid:-1, crash:13967, scn:0x0
2023-06-16 16:51:46.007   889-1048  bt_btif_config          com.android.bluetooth                D  btif_get_device_type: Device [6b:2c:cc:41:05:f5] t

WhatsApp Image 2023-06-16 at 15 08 42

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.