44import android .annotation .SuppressLint ;
55import android .content .Context ;
66import android .net .ConnectivityManager ;
7+ import android .net .LinkAddress ;
8+ import android .net .LinkProperties ;
79import android .net .Network ;
810import android .net .NetworkCapabilities ;
911import android .net .NetworkRequest ;
1820import com .facebook .react .bridge .ReadableMap ;
1921
2022import java .io .IOException ;
23+ import java .net .Inet4Address ;
24+ import java .util .ArrayList ;
25+ import java .util .List ;
26+ import java .util .Objects ;
2127import java .util .concurrent .ConcurrentHashMap ;
2228import java .util .concurrent .CountDownLatch ;
2329import java .util .concurrent .ExecutorService ;
@@ -76,7 +82,9 @@ public void run() {
7682 // Get the network interface
7783 final String localAddress = options .hasKey ("localAddress" ) ? options .getString ("localAddress" ) : null ;
7884 final String iface = options .hasKey ("interface" ) ? options .getString ("interface" ) : null ;
79- selectNetwork (iface , localAddress );
85+ // Get ioT device host to retreive correct network in android concurrent connections
86+ final String iotDeviceHost = options .hasKey ("host" ) ? options .getString ("host" ) : null ;
87+ selectNetwork (iface , localAddress , iotDeviceHost );
8088 TcpSocketClient client = new TcpSocketClient (tcpEvtListener , cId , null );
8189 socketMap .put (cId , client );
8290 ReadableMap tlsOptions = pendingTLS .get (cId );
@@ -213,23 +221,99 @@ public void removeListeners(Integer count) {
213221 // Keep: Required for RN built in Event Emitter Calls.
214222 }
215223
216- private void requestNetwork (final int transportType ) throws InterruptedException {
224+ private void requestNetwork (final int transportType , @ Nullable final String iotDeviceHost ) throws InterruptedException {
217225 final NetworkRequest .Builder requestBuilder = new NetworkRequest .Builder ();
218226 requestBuilder .addTransportType (transportType );
219227 final CountDownLatch awaitingNetwork = new CountDownLatch (1 ); // only needs to be counted down once to release waiting threads
220228 final ConnectivityManager cm = (ConnectivityManager ) mReactContext .getSystemService (Context .CONNECTIVITY_SERVICE );
221- cm .requestNetwork (requestBuilder .build (), new ConnectivityManager .NetworkCallback () {
222- @ Override
223- public void onAvailable (Network network ) {
224- currentNetwork .setNetwork (network );
225- awaitingNetwork .countDown (); // Stop waiting
226- }
227229
228- @ Override
229- public void onUnavailable () {
230+ if (iotDeviceHost ==null || Objects .equals (iotDeviceHost , "localhost" )) {
231+ // Use old behavior if "host" param not specified on configuration array - default value "localhost" used
232+ cm .requestNetwork (requestBuilder .build (), new ConnectivityManager .NetworkCallback () {
233+ @ Override
234+ public void onAvailable (Network network ) {
235+ currentNetwork .setNetwork (network );
236+ awaitingNetwork .countDown (); // Stop waiting
237+ }
238+
239+ @ Override
240+ public void onUnavailable () {
241+ awaitingNetwork .countDown (); // Stop waiting
242+ }
243+ });
244+ } else {
245+ // smartmedev - add support for for concurrent-connections:
246+ // Route all data to the ioT device network interface if exist more than one concurrent network
247+ // See: https://developer.android.com/about/versions/12/behavior-changes-12#concurrent-connections
248+ if (cm != null ) {
249+ // Get all connected networks
250+ Network [] allNetworks = cm .getAllNetworks ();
251+ List <Network > wifiNetworks = new ArrayList <>();
252+
253+ // Check exist at least one newtwork
254+ if (allNetworks != null && allNetworks .length > 0 ) {
255+ // Filter for retreive only networks based on selected transport type
256+ for (Network network : allNetworks ) {
257+ NetworkCapabilities nc = cm .getNetworkCapabilities (network );
258+ if (nc != null && nc .hasTransport (transportType )) {
259+ wifiNetworks .add (network );
260+ }
261+ }
262+
263+ // Check exist at least one newtwork based on selected transport type
264+ if (!wifiNetworks .isEmpty ()) {
265+ boolean networkFound = false ;
266+ for (Network network : wifiNetworks ) {
267+ LinkProperties linkProperties = cm .getLinkProperties (network );
268+ // Ensure linkProperties is not null
269+ if (linkProperties == null )
270+ continue ;
271+
272+ if (android .os .Build .VERSION .SDK_INT >= android .os .Build .VERSION_CODES .R ) {
273+ Inet4Address foundServerAddress = linkProperties .getDhcpServerAddress ();
274+ if (iotDeviceHost .equals (foundServerAddress .getHostAddress ())) {
275+ // found ioT device network
276+ currentNetwork .setNetwork (network );
277+ cm .bindProcessToNetwork (network );
278+ networkFound = true ;
279+ awaitingNetwork .countDown (); // Stop waiting
280+ break ;
281+ }
282+ } else {
283+ List <LinkAddress > linkAddressList = linkProperties .getLinkAddresses ();
284+ if (linkAddressList != null && !linkAddressList .isEmpty ()) {
285+ for (LinkAddress address : linkAddressList ) {
286+ int lastDotIndex = iotDeviceHost .lastIndexOf ('.' );
287+ String iotSubnetAddress = iotDeviceHost ;
288+ if (lastDotIndex >=0 )
289+ iotSubnetAddress = iotDeviceHost .substring (0 , lastDotIndex );
290+ if (address .getAddress ().getHostAddress ().startsWith (iotSubnetAddress )) {
291+ // found ioT device network
292+ currentNetwork .setNetwork (network );
293+ cm .bindProcessToNetwork (network );
294+ networkFound = true ;
295+ awaitingNetwork .countDown (); // Stop waiting
296+ break ;
297+ }
298+ }
299+ }
300+ }
301+ }
302+ if (!networkFound ) {
303+ awaitingNetwork .countDown (); // Stop waiting if no network was found
304+ }
305+ } else {
306+ awaitingNetwork .countDown (); // Stop waiting
307+ }
308+ } else {
309+ awaitingNetwork .countDown (); // Stop waiting
310+ }
311+ } else {
230312 awaitingNetwork .countDown (); // Stop waiting
231313 }
232- });
314+ // smartmedev - end
315+ }
316+
233317 // Timeout if there the network is unreachable
234318 ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor (1 );
235319 exec .schedule (new Runnable () {
@@ -248,7 +332,7 @@ public void run() {
248332 * "cellular" -> Cellular
249333 * etc...
250334 */
251- private void selectNetwork (@ Nullable final String iface , @ Nullable final String ipAddress ) throws InterruptedException , IOException {
335+ private void selectNetwork (@ Nullable final String iface , @ Nullable final String ipAddress , @ Nullable final String iotDeviceHost ) throws InterruptedException , IOException {
252336 currentNetwork .setNetwork (null );
253337 if (iface == null ) return ;
254338 if (ipAddress != null ) {
@@ -260,13 +344,13 @@ private void selectNetwork(@Nullable final String iface, @Nullable final String
260344 }
261345 switch (iface ) {
262346 case "wifi" :
263- requestNetwork (NetworkCapabilities .TRANSPORT_WIFI );
347+ requestNetwork (NetworkCapabilities .TRANSPORT_WIFI , iotDeviceHost );
264348 break ;
265349 case "cellular" :
266- requestNetwork (NetworkCapabilities .TRANSPORT_CELLULAR );
350+ requestNetwork (NetworkCapabilities .TRANSPORT_CELLULAR , iotDeviceHost );
267351 break ;
268352 case "ethernet" :
269- requestNetwork (NetworkCapabilities .TRANSPORT_ETHERNET );
353+ requestNetwork (NetworkCapabilities .TRANSPORT_ETHERNET , iotDeviceHost );
270354 break ;
271355 }
272356 if (currentNetwork .getNetwork () == null ) {
0 commit comments