tolerate additional IPv4 address now available for gnunet.org
[oweals/gnunet.git] / src / util / time.c
index 46d3a2b6574b41a29a4b3899edf77ad6521dbdc3..758921718abffedb7af3fb204810cd1b18f67d52 100644 (file)
      WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      Affero General Public License for more details.
-    
+
      You should have received a copy of the GNU Affero General Public License
      along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+     SPDX-License-Identifier: AGPL3.0-or-later
 */
 
 /**
  */
 #include "platform.h"
 #include "gnunet_util_lib.h"
+#if __STDC_NO_ATOMICS__
+#define ATOMIC
+#else
+#ifdef HAVE_STDATOMIC_H
+#include <stdatomic.h>
+#define ATOMIC _Atomic
+#else
+#define __STDC_NO_ATOMICS__ 1
+#define ATOMIC
+#endif
+#endif
 
 #define LOG(kind,...) GNUNET_log_from (kind, "util-time", __VA_ARGS__)
 
@@ -756,20 +769,36 @@ GNUNET_TIME_randomized_backoff(struct GNUNET_TIME_Relative rt, struct GNUNET_TIM
 }
 
 
+/**
+ * Return a random time value between 0.5*r and 1.5*r.
+ *
+ * @param r input time for scaling
+ * @return randomized time
+ */
+struct GNUNET_TIME_Relative
+GNUNET_TIME_randomize (struct GNUNET_TIME_Relative r)
+{
+  double d = ((rand() % 1001) - 500) / 1000.0;
+
+  return relative_multiply_double (r,
+                                   d);
+}
+
+
 /**
  * Obtain the current time and make sure it is monotonically
  * increasing.  Guards against systems without an RTC or
  * clocks running backwards and other nasty surprises. Does
  * not guarantee that the returned time is near the current
- * time returned by #GNUNET_TIME_absolute_get().  Two 
+ * time returned by #GNUNET_TIME_absolute_get().  Two
  * subsequent calls (within a short time period) may return the
  * same value. Persists the last returned time on disk to
  * ensure that time never goes backwards. As a result, the
- * resulting value can be used to check if a message is the 
+ * resulting value can be used to check if a message is the
  * "most recent" value and replays of older messages (from
  * the same origin) would be discarded.
- * 
- * @param cfg configuration, used to determine where to 
+ *
+ * @param cfg configuration, used to determine where to
  *   store the time; user can also insist RTC is working
  *   nicely and disable the feature
  * @return monotonically increasing time
@@ -780,7 +809,7 @@ GNUNET_TIME_absolute_get_monotonic (const struct GNUNET_CONFIGURATION_Handle *cf
   static const struct GNUNET_CONFIGURATION_Handle *last_cfg;
   static struct GNUNET_TIME_Absolute last_time;
   static struct GNUNET_DISK_MapHandle *map_handle;
-  static struct GNUNET_TIME_AbsoluteNBO *map;
+  static ATOMIC volatile uint64_t *map;
   struct GNUNET_TIME_Absolute now;
 
   now = GNUNET_TIME_absolute_get ();
@@ -794,7 +823,7 @@ GNUNET_TIME_absolute_get_monotonic (const struct GNUNET_CONFIGURATION_Handle *cf
       map_handle = NULL;
     }
     map = NULL;
-    
+
     last_cfg = cfg;
     if ( (NULL != cfg) &&
         (GNUNET_OK ==
@@ -806,66 +835,91 @@ GNUNET_TIME_absolute_get_monotonic (const struct GNUNET_CONFIGURATION_Handle *cf
       struct GNUNET_DISK_FileHandle *fh;
 
       fh = GNUNET_DISK_file_open (filename,
-                                 GNUNET_DISK_OPEN_READWRITE | GNUNET_DISK_OPEN_CREATE,
-                                 GNUNET_DISK_PERM_USER_WRITE | GNUNET_DISK_PERM_GROUP_WRITE |
-                                 GNUNET_DISK_PERM_USER_READ  | GNUNET_DISK_PERM_GROUP_READ);
+                                  GNUNET_DISK_OPEN_READWRITE | GNUNET_DISK_OPEN_CREATE,
+                                  GNUNET_DISK_PERM_USER_WRITE | GNUNET_DISK_PERM_GROUP_WRITE |
+                                  GNUNET_DISK_PERM_USER_READ  | GNUNET_DISK_PERM_GROUP_READ);
       if (NULL == fh)
       {
-       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                   _("Failed to map `%s', cannot assure monotonic time!\n"),
-                   filename);
+        GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                    _("Failed to map `%s', cannot assure monotonic time!\n"),
+                    filename);
       }
       else
-      {        
-       off_t size;
-
-       size = 0;
-       GNUNET_break (GNUNET_OK ==
-                     GNUNET_DISK_file_handle_size (fh,
-                                                   &size));
-       if (size < sizeof (*map))
-       {
-         struct GNUNET_TIME_AbsoluteNBO o;
-
-         o = GNUNET_TIME_absolute_hton (now);
-         if (sizeof (o) !=
-             GNUNET_DISK_file_write (fh,
-                                     &o,
-                                     sizeof (o)))
-           size = 0;
-         else
-           size = sizeof (o);
-       }
-       if (size == sizeof (*map))
-       {
-         map = GNUNET_DISK_file_map (fh,
-                                     &map_handle,
-                                     GNUNET_DISK_MAP_TYPE_READWRITE,
-                                     sizeof (*map));
-         if (NULL == map)
-           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                       _("Failed to map `%s', cannot assure monotonic time!\n"),
-                       filename);
-       }
-       else
-       {
-         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                     _("Failed to setup monotonic time file `%s', cannot assure monotonic time!\n"),
-                     filename);
-       }
+      {
+        off_t size;
+
+        size = 0;
+        GNUNET_break (GNUNET_OK ==
+                      GNUNET_DISK_file_handle_size (fh,
+                                                    &size));
+        if (size < (off_t) sizeof (*map))
+        {
+          struct GNUNET_TIME_AbsoluteNBO o;
+          
+          o = GNUNET_TIME_absolute_hton (now);
+          if (sizeof (o) !=
+              GNUNET_DISK_file_write (fh,
+                                      &o,
+                                      sizeof (o)))
+            size = 0;
+          else
+            size = sizeof (o);
+        }
+        if (size == sizeof (*map))
+        {
+          map = GNUNET_DISK_file_map (fh,
+                                      &map_handle,
+                                      GNUNET_DISK_MAP_TYPE_READWRITE,
+                                      sizeof (*map));
+          if (NULL == map)
+            GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                        _("Failed to map `%s', cannot assure monotonic time!\n"),
+                        filename);
+        }
+        else
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                      _("Failed to setup monotonic time file `%s', cannot assure monotonic time!\n"),
+                      filename);
+        }
       }
       GNUNET_DISK_file_close (fh);
       GNUNET_free (filename);
     }
   }
   if (NULL != map)
-    last_time = GNUNET_TIME_absolute_max (GNUNET_TIME_absolute_ntoh (*map),
+  {
+    struct GNUNET_TIME_AbsoluteNBO mt;
+
+#if __STDC_NO_ATOMICS__
+#if __GNUC__
+    mt.abs_value_us__ = __sync_fetch_and_or (map, 0);
+#else
+    mt.abs_value_us__ = *map; /* godspeed, pray this is atomic */
+#endif
+#else
+    mt.abs_value_us__ = atomic_load (map);
+#endif
+    last_time = GNUNET_TIME_absolute_max (GNUNET_TIME_absolute_ntoh (mt),
                                          last_time);
+  }
   if (now.abs_value_us <= last_time.abs_value_us)
     now.abs_value_us = last_time.abs_value_us+1;
   last_time = now;
   if (NULL != map)
-    *map = GNUNET_TIME_absolute_hton (now);
+  {
+    uint64_t val = GNUNET_TIME_absolute_hton (now).abs_value_us__;
+#if __STDC_NO_ATOMICS__
+#if __GNUC__
+    (void) __sync_lock_test_and_set (map, val);
+#else
+    *map = val;  /* godspeed, pray this is atomic */
+#endif
+#else
+    atomic_store (map,
+                 val);
+#endif
+  }
   return now;
 }