[CONPRO-1272] Disable the Multicast Action in Mobile Network Case. 98/183398/1
authorsenthil.gs@samsung.com <senthil.gs@samsung.com>
Tue, 3 Jul 2018 15:44:48 +0000 (21:14 +0530)
committerAmit KS <amit.s12@samsung.com>
Thu, 5 Jul 2018 06:40:59 +0000 (12:10 +0530)
Starting multicast server on all identified interfaces results in resource loss as many of identified interfaces may not have Multicast capability. It make sense to start multicast server on only active wifi connected interface for android platform.

This patch handles -
1. Create UDP sockets(Unicast and Multicast) and join multicast group only when there on active WiFi connection.
2. Whenever the WiFi connection comes up, UDP sockets will be closed, created, and joined to multicast group.

https://github.sec.samsung.net/RS7-IOTIVITY/IoTivity/pull/296
(cherry picked from commit ce73d5846ecb99fb04e87860b94afbaeff0ddcb4)

Change-Id: Ib3586d77d3c0e96c990e3fb5a398e78b29a20be8
Signed-off-by: Amit KS <amit.s12@samsung.com>
android/android_api/base/src/main/java/org/iotivity/ca/CaIpInterface.java
resource/csdk/connectivity/inc/caipnwmonitor.h
resource/csdk/connectivity/src/ip_adapter/android/caipnwmonitor.c
resource/csdk/connectivity/src/ip_adapter/android/org_iotivity_ca_CaIpInterface.h
resource/csdk/connectivity/src/ip_adapter/caipserver.c

index e2da3ec419e77c60842c27b51606b0256313370a..e285f4e0eca7451fd6963bcd1b3d5a4ec6320b58 100644 (file)
@@ -28,11 +28,17 @@ import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.net.wifi.WifiManager;
 import android.util.Log;
+import java.lang.reflect.Method;
 
 public class CaIpInterface {
     private static Context mContext;
     private static volatile boolean isIpInitialized = false;
-    private static String TAG          = "OIC_IP_CB_INTERFACE";
+
+    private static String WIFI_INTERFACE_PROP_KEY = "wifi.interface";
+    private static String ANDROID_SYS_PROPS_CLS = "android.os.SystemProperties";
+    private static String ANDROID_SYS_PROPS_GET_METHOD = "get";
+
+    private static String TAG = "OIC_IP_CB_INTERFACE";
 
     private CaIpInterface(Context context) {
         synchronized(CaIpInterface.class) {
@@ -47,11 +53,38 @@ public class CaIpInterface {
     private void registerIpStateReceiver() {
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
-        intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
-
         mContext.registerReceiver(mReceiver, intentFilter);
     }
 
+    private boolean hasWifiConnection() {
+        ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+        NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
+        return (activeNetwork != null && activeNetwork.getType() == ConnectivityManager.TYPE_WIFI &&
+                activeNetwork.isConnected());
+    }
+
+    private String getWiFiInterfaceName() {
+        String wifiInterfaceName= "";
+
+        try {
+            ClassLoader classLoader = mContext.getClassLoader();
+
+            Class systemPropertiesCls = classLoader.loadClass(ANDROID_SYS_PROPS_CLS);
+            Class[] paramTypes = new Class[1];
+            paramTypes[0] = String.class;
+
+            Method getMethod = systemPropertiesCls.getMethod(ANDROID_SYS_PROPS_GET_METHOD, paramTypes);
+            Object[] params = new Object[1];
+            params[0] = new String(WIFI_INTERFACE_PROP_KEY);
+
+            wifiInterfaceName = (String) getMethod.invoke(systemPropertiesCls, params);
+        } catch(Exception e) {
+            Log.d(TAG, "Error in getWiFiInterfaceName(). Details: " + e);
+        }
+
+        return wifiInterfaceName;
+    }
+
     public static void destroyIpInterface() {
         if (isIpInitialized) {
             mContext.unregisterReceiver(mReceiver);
@@ -62,36 +95,22 @@ public class CaIpInterface {
     private static BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
-                NetworkInfo activeNetwork = ((ConnectivityManager) mContext
-                        .getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();
-                if (activeNetwork != null) {
-                    Log.d(TAG, "CONNECTIVITY_ACTION - activeNetwork: "
-                        + activeNetwork.getTypeName()
-                        + " isConnected: " + activeNetwork.isConnected());
-                    caIpStateEnabled();
-                } else {
-                    Log.d(TAG, "CONNECTIVITY_ACTION - activeNetwork: NONE");
-                    caIpStateDisabled();
-                }
-            } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
-                NetworkInfo netInfo = (NetworkInfo) intent
-                        .getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
-                if (ConnectivityManager.TYPE_WIFI == netInfo.getType()) {
-                    NetworkInfo.State netState = netInfo.getState();
-                    if (NetworkInfo.State.CONNECTED == netState) {
-                        Log.d(TAG, "NETWORK_STATE_CHANGED_ACTION - CONNECTED: TYPE_WIFI");
-                        caIpStateEnabled();
-                    } else if (NetworkInfo.State.DISCONNECTED == netState) {
-                        Log.d(TAG, "NETWORK_STATE_CHANGED_ACTION - DISCONNECTED: TYPE_WIFI");
-                    }
-                }
+            NetworkInfo activeNetwork = ((ConnectivityManager) mContext
+                    .getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();
+            if (activeNetwork != null) {
+                Log.d(TAG, "CONNECTIVITY_ACTION - activeNetwork: "
+                    + activeNetwork.getTypeName()
+                    + " isConnected: " + activeNetwork.isConnected());
+                boolean wifi = (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI);
+                caIpStateEnabled(wifi);
+            } else {
+                Log.d(TAG, "CONNECTIVITY_ACTION - activeNetwork: NONE");
+                caIpStateDisabled();
             }
         }
     };
 
-    private native static void caIpStateEnabled();
+    private native static void caIpStateEnabled(boolean wifi);
 
     private native static void caIpStateDisabled();
 }
index 6b537596764a9ff940eb0afe4f73fe1ae356913f..230261803469461e8e8f1762de75626797314e44 100644 (file)
@@ -121,6 +121,11 @@ CAResult_t CAIPStopNetworkMonitor(CATransportAdapter_t adapter);
  */
 void CAProcessNewInterface(CAInterface_t *ifchanged);
 
+#ifdef __ANDROID__
+bool isWifiConnectedDuringInit();
+const char *getWifiInterfaceName();
+#endif
+
 #ifdef __cplusplus
 }
 #endif
index 8f67d474005ea5e4135d3c5ed7a1d1f41c1c1f8b..2c451f6f932b8d9b39e339d16bee4ef36774fc9b 100644 (file)
  */
 static struct CAIPCBData_t *g_adapterCallbackList = NULL;
 
+/**
+ * Used to indicate whether WiFi is enabled or not during init.
+ */
+static bool g_wifiConnectionDuringInit = false;
+
+/**
+ * WiFi Interface's Name.
+ */
+static const char *g_wifiInterfaceName = NULL;
+
 /**
  * Create new interface item to add in activated interface list.
  * @param[in]  index    Network interface index number.
@@ -242,6 +252,14 @@ static bool CAParsingNetorkInfo(int idx, u_arraylist_t *iflist)
             continue;
         }
 
+        // Ignoring all non WiFi interfaces.
+        if (g_wifiInterfaceName != NULL && (strlen(g_wifiInterfaceName) > 0) &&
+            (strcmp(ifa->ifa_name, g_wifiInterfaceName) != 0))
+        {
+            OIC_LOG_V(DEBUG, TAG, "Ignoring Non-WiFi interface: %s(%d)", ifa->ifa_name, ifindex);
+            continue;
+        }
+
         char ipaddr[MAX_ADDR_STR_SIZE_CA] = {0};
         if (family == AF_INET6)
         {
@@ -316,12 +334,6 @@ static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
         return CA_STATUS_FAILED;
     }
 
-    /* Added preventive patch for CONRO-1269
-     * Network unreachable error was coming whenever WIFI-AP connection is changed.
-     * To avoid that scenario we are creating sockets again when interfaces are identified.
-     */
-    CreateMulticastSocket();
-
     return CA_STATUS_OK;
 }
 
@@ -402,8 +414,44 @@ CAResult_t CAIPJniInit()
         return CA_STATUS_FAILED;
     }
 
-    (*env)->NewObject(env, cls_CaIpInterface, mid_CaIpInterface_ctor, jApplicationContext);
-    OIC_LOG(DEBUG, TAG, "Create CaIpInterface instance, success");
+    jobject jCaIpInterface = (*env)->NewObject(env, cls_CaIpInterface, mid_CaIpInterface_ctor, jApplicationContext);
+    if (!jCaIpInterface)
+    {
+        OIC_LOG(ERROR, TAG, "Could not create an instance of CaIpInterface");
+        return CA_STATUS_FAILED;
+    }
+
+    // Get WiFi Connection status.
+    jmethodID mid_hasWifiConnection = (*env)->GetMethodID(env, cls_CaIpInterface, "hasWifiConnection", "()Z");
+    if (!mid_hasWifiConnection)
+    {
+        OIC_LOG(ERROR, TAG, "Could not get hasWifiConnection method");
+        return CA_STATUS_FAILED;
+    }
+
+    g_wifiConnectionDuringInit = (*env)->CallBooleanMethod(env, jCaIpInterface, mid_hasWifiConnection);
+
+    // Get WiFi Interface's name.
+    jmethodID mid_getWiFiInterfaceName = (*env)->GetMethodID(env, cls_CaIpInterface,
+                                                                        "getWiFiInterfaceName", "()Ljava/lang/String;");
+    if (!mid_getWiFiInterfaceName)
+    {
+        OIC_LOG(ERROR, TAG, "Could not get getWiFiInterfaceName method");
+        return CA_STATUS_FAILED;
+    }
+
+    jstring jWifiInterfaceName = (*env)->CallObjectMethod(env, jCaIpInterface, mid_getWiFiInterfaceName);
+    const char *wifiInterfaceNameLocal = (*env)->GetStringUTFChars(env, jWifiInterfaceName, NULL);
+    g_wifiInterfaceName = OICStrdup(wifiInterfaceNameLocal);
+    if (!g_wifiInterfaceName)
+    {
+        OIC_LOG(ERROR, TAG, "Failed to duplicate the Wifi Interface name.");
+    }
+
+    (*env)->ReleaseStringUTFChars(env, jWifiInterfaceName, wifiInterfaceNameLocal);
+
+    OIC_LOG_V(DEBUG, TAG, "WiFi Interface Name: %s, WiFi Connection State: %d", g_wifiInterfaceName,
+        g_wifiConnectionDuringInit);
 
     OIC_LOG(DEBUG, TAG, "CAIPJniInit_OUT");
     return CA_STATUS_OK;
@@ -464,6 +512,12 @@ static CAResult_t CAIPDestroyJniInterface()
 
     OIC_LOG(DEBUG, TAG, "Destroy instance for CaIpInterface");
 
+    if (g_wifiInterfaceName)
+    {
+        OICFree(g_wifiInterfaceName);
+        g_wifiInterfaceName = NULL;
+    }
+
     if (isAttached)
     {
         (*jvm)->DetachCurrentThread(jvm);
@@ -481,18 +535,37 @@ error_exit:
     return CA_STATUS_FAILED;
 }
 
+bool isWifiConnectedDuringInit()
+{
+    return g_wifiConnectionDuringInit;
+}
+
+const char *getWifiInterfaceName()
+{
+    return g_wifiInterfaceName;
+}
+
 JNIEXPORT void JNICALL
-Java_org_iotivity_ca_CaIpInterface_caIpStateEnabled(JNIEnv *env, jclass class)
+Java_org_iotivity_ca_CaIpInterface_caIpStateEnabled(JNIEnv *env, jclass class,
+    jboolean wifi)
 {
     (void)env;
     (void)class;
 
-    OIC_LOG(DEBUG, TAG, "Wifi is in Activated State");
     CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
 
-    // Closing sockets so that it will be created again when interfaces are identified(CONPRO-1269).
+    if(!wifi)
+    {
+        return;
+    }
+
+    OIC_LOG(DEBUG, TAG, "Wifi is in Activated State");
+
+    // Closing sockets for safety reasons to handle missed out WiFi state disabled events.
     CloseMulticastSocket();
 
+    // Creating sockets.
+    CreateMulticastSocket();
 
     // Apply network interface changes.
     u_arraylist_t *iflist = CAIPGetInterfaceInformation(0);
@@ -512,7 +585,6 @@ Java_org_iotivity_ca_CaIpInterface_caIpStateEnabled(JNIEnv *env, jclass class)
         }
 
         CAProcessNewInterface(ifitem);
-
     }
     u_arraylist_destroy(iflist);
 }
@@ -523,6 +595,8 @@ Java_org_iotivity_ca_CaIpInterface_caIpStateDisabled(JNIEnv *env, jclass class)
     (void)env;
     (void)class;
 
-    OIC_LOG(DEBUG, TAG, "Wifi is in Deactivated State");
+    OIC_LOG(DEBUG, TAG, "No network connectivity");
     CAIPPassNetworkChangesToAdapter(CA_INTERFACE_DOWN);
+
+    CloseMulticastSocket();
 }
index 2c5cf385c6a2ef128fc7042b9a31ef99065eedaf..59fb37da3b11415752fa29c29756bf5fe7bd2388 100644 (file)
@@ -30,10 +30,10 @@ extern "C"
 /*
  * Class:     org_iotivity_ca_caIpInterface
  * Method:    CaIpStateEnabled
- * Signature: ()V
+ * Signature: (Z)V
  */
 JNIEXPORT void JNICALL
-Java_org_iotivity_ca_CaIpInterface_caIpStateEnabled(JNIEnv *, jclass);
+Java_org_iotivity_ca_CaIpInterface_caIpStateEnabled(JNIEnv *, jclass, jboolean);
 
 /*
  * Class:     org_iotivity_ca_caIpInterface
index 87afa900c84974ad2a97cc8b3949bdce513bf63e..77f4d02b694d3304c689d277e7fb6d2cab90f8bd 100644 (file)
@@ -1075,7 +1075,19 @@ CAResult_t CAIPStartServer(const ca_thread_pool_t threadPool)
         caglobals.ip.ipv4enabled = true;  // only needed to run CA tests
     }
 
+#ifdef __ANDROID__
+    bool hasWifiConnection = isWifiConnectedDuringInit();
+    if (hasWifiConnection)
+    {
+        CreateMulticastSocket();
+    }
+    else
+    {
+        OIC_LOG(INFO, TAG, "No WiFi connection. So UDP sockets are not created.");
+    }
+#else
     CreateMulticastSocket();
+#endif
 
     OIC_LOG_V(INFO, TAG,
               "socket summary: u6=%d, u6s=%d, u4=%d, u4s=%d, m6=%d, m6s=%d, m4=%d, m4s=%d",
@@ -1088,6 +1100,7 @@ CAResult_t CAIPStartServer(const ca_thread_pool_t threadPool)
               caglobals.ip.u6.port, caglobals.ip.u6s.port, caglobals.ip.u4.port,
               caglobals.ip.u4s.port, caglobals.ip.m6.port, caglobals.ip.m6s.port,
               caglobals.ip.m4.port, caglobals.ip.m4s.port);
+
 #if defined (SIO_GET_EXTENSION_FUNCTION_POINTER)
     caglobals.ip.wsaRecvMsg = NULL;
     GUID GuidWSARecvMsg = WSAID_WSARECVMSG;
@@ -1107,7 +1120,19 @@ CAResult_t CAIPStartServer(const ca_thread_pool_t threadPool)
 
     caglobals.ip.selectTimeout = CAGetPollingInterval(caglobals.ip.selectTimeout);
 
+#ifdef __ANDROID__
+    if (hasWifiConnection)
+    {
+        res = CAIPStartListenServer();
+    }
+    else
+    {
+        OIC_LOG(INFO, TAG, "No WiFi connection. So IP Listen/Multicast server is not started.");
+    }
+#else
     res = CAIPStartListenServer();
+#endif
+
     if (CA_STATUS_OK != res)
     {
         OIC_LOG_V(ERROR, TAG, "Failed to start listening server![%d]", res);