[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 e2da3ec..e285f4e 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 6b53759..2302618 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 8f67d47..2c451f6 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.
  * @param[in]  name     Network interface name.
@@ -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 2c5cf38..59fb37d 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 87afa90..77f4d02 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);