Merge pull request #56 from pidarped/bug/WEAV-3155

Bind connection to interface/src address only if destination address is not link-local
diff --git a/src/lib/core/WeaveFabricState.cpp b/src/lib/core/WeaveFabricState.cpp
index ee9ccfb..e4c1fe8 100644
--- a/src/lib/core/WeaveFabricState.cpp
+++ b/src/lib/core/WeaveFabricState.cpp
@@ -65,11 +65,23 @@
 using namespace nl::Weave::Profiles::Security::AppKeys;
 
 #if WEAVE_CONFIG_SECURITY_TEST_MODE
+#pragma message "\n \
+                 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n \
+                 !!!!    WARNING - SECURITY_TEST_MODE IS ENABLED    !!!!\n \
+                 !!!! BASIC WEAVE SECURITY / ENCRYPTION IS CRIPPLED !!!!\n \
+                 !!!!        DEVELOPMENT ONLY -- DO NOT SHIP        !!!!\n \
+                 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n \
+                 "
+#endif
 
-#define EXCLS "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
-#pragma message (EXCLS "\n!!!! WARNING - WEAVE SECURITY TEST MODE ENABLED !!!!" EXCLS)
-#undef EXCLS
-
+#if !WEAVE_CONFIG_REQUIRE_AUTH
+#pragma message "\n \
+                 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n \
+                 !!!!  WARNING - REQUIRE_AUTH IS DISABLED   !!!!\n \
+                 !!!! CLIENT AUTHENTICATION IS NOT REQUIRED !!!!\n \
+                 !!!!    DEVELOPMENT ONLY -- DO NOT SHIP    !!!!\n \
+                 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n \
+                 "
 #endif
 
 #ifndef nlDEFINE_ALIGNED_VAR
diff --git a/src/system/SystemTimer.cpp b/src/system/SystemTimer.cpp
index 6443f38..cb4b61a 100644
--- a/src/system/SystemTimer.cpp
+++ b/src/system/SystemTimer.cpp
@@ -296,39 +296,77 @@
 Error Timer::HandleExpiredTimers(Layer& aLayer)
 {
     // expire each timer in turn until an unexpired timer is reached or the timerlist is emptied.
-    while (aLayer.mTimerList)
+
+    // The platform timer API has MSEC resolution so expire any timer with less than 1 msec remaining.
+    Epoch currentEpoch = Timer::GetCurrentEpoch() + 1;
+
+    VerifyOrExit(aLayer.mTimerList != NULL, );
+
+    // Verify that there are any timers to be processed
+    if (Timer::IsEarlierEpoch(aLayer.mTimerList->mAwakenEpoch, currentEpoch))
     {
-        const Epoch kCurrentEpoch = Timer::GetCurrentEpoch();
+        // Bound the number of timers processed to those that are already on the
+        // expired queue. We copy the expired timers onto the queue pointed to
+        // by headTimer, and then reset the timer queue in the system layer to
+        // point to the first unexpired timer.
+        Timer * headTimer = aLayer.mTimerList;
+        Timer * cursorTimer = aLayer.mTimerList;
 
-        // The platform timer API has MSEC resolution so expire any timer with less than 1 msec remaining.
-        if (Timer::IsEarlierEpoch(aLayer.mTimerList->mAwakenEpoch, kCurrentEpoch + 1))
+        while (cursorTimer->mNextTimer != NULL &&
+               Timer::IsEarlierEpoch(cursorTimer->mNextTimer->mAwakenEpoch, currentEpoch))
         {
-            Timer& lTimer = *aLayer.mTimerList;
-            aLayer.mTimerList = lTimer.mNextTimer;
-            lTimer.mNextTimer = NULL;
+            cursorTimer = cursorTimer->mNextTimer;
+        }
 
-            aLayer.mTimerComplete = true;
-            lTimer.HandleComplete();
-            aLayer.mTimerComplete = false;
+        // unexpired timer list points to the next unexpired timer
+        aLayer.mTimerList = cursorTimer->mNextTimer;
+
+        // list pointed to by the headTimer terminates
+        cursorTimer->mNextTimer = NULL;
+
+        aLayer.mTimerComplete = true;
+
+        while (headTimer != NULL)
+        {
+            cursorTimer = headTimer;
+            headTimer = headTimer->mNextTimer;
+            cursorTimer->mNextTimer = NULL;
+
+            cursorTimer->HandleComplete();
+        }
+        aLayer.mTimerComplete = false;
+    }
+
+    if (aLayer.mTimerList)
+    {
+        // timers still exist so restart the platform timer.
+        uint64_t delayMilliseconds;
+
+        // re-read the timer to account for the time that has elapsed while we
+        // were processing the expired timers
+
+        currentEpoch = Timer::GetCurrentEpoch();
+
+        if (aLayer.mTimerList->mAwakenEpoch < currentEpoch)
+        {
+            delayMilliseconds = 0;
         }
         else
         {
-            // timers still exist so restart the platform timer.
-            const uint64_t kDelayMilliseconds = aLayer.mTimerList->mAwakenEpoch - kCurrentEpoch;
-
-            /*
-             * Original kDelayMilliseconds was a 32 bit value.  The only way in which this could overflow is if time went backwards
-             * (e.g. as a result of a time adjustment from time synchronization).  Verify that the timer can still be executed
-             * (even if it is very late) and exit if that is the case.  Note: if the time sync ever ends up adjusting the clock, we
-             * should implement a method that deals with all the timers in the system.
-             */
-            VerifyOrDie(kDelayMilliseconds <= UINT32_MAX);
-
-            aLayer.StartPlatformTimer(static_cast<uint32_t>(kDelayMilliseconds));
-            break; // all remaining timers are still ticking.
+            delayMilliseconds = aLayer.mTimerList->mAwakenEpoch - currentEpoch;
         }
+        /*
+         * StartPlatformTimer() accepts a 32bit value in milliseconds.  Epochs are 64bit numbers.  The only way in which this could
+         * overflow is if time went backwards (e.g. as a result of a time adjustment from time synchronization).  Verify that the
+         * timer can still be executed (even if it is very late) and exit if that is the case.  Note: if the time sync ever ends up
+         * adjusting the clock, we should implement a method that deals with all the timers in the system.
+         */
+        VerifyOrDie(delayMilliseconds <= UINT32_MAX);
+
+        aLayer.StartPlatformTimer(static_cast<uint32_t>(delayMilliseconds));
     }
 
+exit:
     return WEAVE_SYSTEM_NO_ERROR;
 }
 #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
diff --git a/src/test-apps/TestSystemTimer.cpp b/src/test-apps/TestSystemTimer.cpp
index 531842d..7e51ffb 100644
--- a/src/test-apps/TestSystemTimer.cpp
+++ b/src/test-apps/TestSystemTimer.cpp
@@ -156,6 +156,38 @@
     lSys.CancelTimer(HandleTimer10Success, aContext);
 }
 
+static uint32_t sNumTimersHandled = 0;
+static const uint32_t MAX_NUM_TIMERS = 1000;
+
+
+void HandleGreedyTimer(Layer *aLayer, void * aState, Error aError)
+{
+    TestContext& lContext = *static_cast<TestContext*>(aState);
+    NL_TEST_ASSERT(lContext.mTestSuite, sNumTimersHandled < MAX_NUM_TIMERS);
+
+    if (sNumTimersHandled >= MAX_NUM_TIMERS)
+    {
+        return;
+    }
+
+    aLayer->StartTimer(0, HandleGreedyTimer, aState);
+    sNumTimersHandled ++;
+
+}
+
+static void CheckStarvation(nlTestSuite* inSuite, void* aContext)
+{
+    TestContext& lContext = *static_cast<TestContext*>(aContext);
+    Layer& lSys = *lContext.mLayer;
+    struct timeval sleepTime;
+
+    lSys.StartTimer(0, HandleGreedyTimer, aContext);
+
+    sleepTime.tv_sec = 0;
+    sleepTime.tv_usec = 1000; // 1 ms tick
+    ServiceEvents(lSys, sleepTime);
+}
+
 
 // Test Suite
 
@@ -165,6 +197,7 @@
  */
 static const nlTest sTests[] = {
     NL_TEST_DEF("Timer::TestOverflow",             CheckOverflow),
+    NL_TEST_DEF("Timer::TestTimerStarvation",      CheckStarvation),
     NL_TEST_SENTINEL()
 };