Hi Akbar,

Thanks for the patch. Its merged now.

https://sourceforge.net/p/tipc/tipcutils/ci/88ffe493ae72d1c16fa5bdb36ed92d39a05f9fd2/

/Partha

On 06/15/2017 12:22 PM, Akbar Rezvan wrote:
Hi Ying,

Sorry for the delay.


Here it is (Pls see below):

Ciao//Anthony


 From 11155e72babf481b526e3aaf1d9427c41d718dd5 Mon Sep 17 00:00:00 2001
From: Akbar Rezvanpour <akbrez...@gmail.com>
Date: Thu, 1 Jun 2017 17:58:57 +0200
Subject: [PATCH] Introducing tipc-link-watcher

In this commit we add tipc-link-watcher which monitors the tipc link
status and reports in foreground mode as shown below.

Sample output of the program when invoked by following options:
./tipc-link-watcher -d -p 2 -s 2

1.1.2:data1-1.1.1:data1: link reset:0          rx_packets:0
  tx_packets:0          rx_loss:0          tx_loss:0          Working :)
1.1.2:data1-1.1.3:data1: link reset:0          rx_packets:0
  tx_packets:0          rx_loss:0          tx_loss:0          Working :)
1.1.2:data1-1.1.4:data1: link reset:0          rx_packets:0
  tx_packets:0          rx_loss:0          tx_loss:0          Working :)
1.1.2:data0-1.1.1:data0: link reset:4          rx_packets:0
  tx_packets:0          rx_loss:0          tx_loss:0          Working :)
1.1.2:data0-1.1.4:data0: link reset:5          rx_packets:0
  tx_packets:0          rx_loss:0          tx_loss:0          Working :)
1.1.2:data0-1.1.3:data0: link reset:5          rx_packets:0
  tx_packets:0          rx_loss:0          tx_loss:0          Working :)
1.1.2:data0-1.1.1:data1: link reset:0          rx_packets:0
  tx_packets:0          rx_loss:0          tx_loss:0          Working :)
1.1.2:data0-1.1.3:data1: link reset:0          rx_packets:0
  tx_packets:0          rx_loss:0          tx_loss:0          Working :)

The user is always able to dump the tipc link statistics.
Further information is available in the README.

Signed-off-by: Akbar Rezvanpour <akbrez...@gmail.com>
---
  .gitignore                            |    1 +
  Makefile.am                           |    2 +-
  configure.ac                          |    1 +
  tipc-link-watcher/Makefile.am         |    4 +
  tipc-link-watcher/README              |  233 ++++
  tipc-link-watcher/tipc-link-watcher.c | 2143
+++++++++++++++++++++++++++++++++
  6 files changed, 2383 insertions(+), 1 deletion(-)
  create mode 100644 tipc-link-watcher/Makefile.am
  create mode 100644 tipc-link-watcher/README
  create mode 100644 tipc-link-watcher/tipc-link-watcher.c

diff --git a/.gitignore b/.gitignore
index f544ddfceff9..0ff143dea8ec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -48,3 +48,4 @@ tipc-pipe/tipc-pipe
  tipclog/tipclog
  multicast_blast/mcast_tipc
  multicast_blast/group_cast
+tipc-link-watcher/tipc-link-watcher
diff --git a/Makefile.am b/Makefile.am
index 0643d78e03b5..5f0d5e979b15 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,4 +1,4 @@
  SUBDIRS=tipc-pipe ptts demos man scripts
  if TIPC_LINK_STATE_SUBSCRITION
-SUBDIRS+=tipclog multicast_blast
+SUBDIRS+=tipclog multicast_blast tipc-link-watcher
  endif
diff --git a/configure.ac b/configure.ac
index 0602878bada7..b466d56cc522 100644
--- a/configure.ac
+++ b/configure.ac
@@ -40,6 +40,7 @@ AC_CONFIG_FILES([
          man/Makefile
   scripts/Makefile
   tipclog/Makefile
+ tipc-link-watcher/Makefile
   ])
  AM_CONDITIONAL(WITH_SCRIPTS, false)
  AC_ARG_ENABLE(scripts,
diff --git a/tipc-link-watcher/Makefile.am b/tipc-link-watcher/Makefile.am
new file mode 100644
index 000000000000..f8484d07ff45
--- /dev/null
+++ b/tipc-link-watcher/Makefile.am
@@ -0,0 +1,4 @@
+sbin_PROGRAMS=tipc-link-watcher
+tipc_link_watcher_SOURCES=tipc-link-watcher.c
+tipc_link_watcher_CFLAGS=-Werror $(shell $(PKG_CONFIG) libmnl --cflags)
+tipc_link_watcher_LDFLAGS=$(shell $(PKG_CONFIG) libmnl --libs)
diff --git a/tipc-link-watcher/README b/tipc-link-watcher/README
new file mode 100644
index 000000000000..5c8a7b901b80
--- /dev/null
+++ b/tipc-link-watcher/README
@@ -0,0 +1,233 @@
+#The following commits are pre-requisite for this feature.
+1.
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=78acb1f9b898e85fa2c1e28e700b54b66b288e8d
+2. https://lwn.net/Articles/611994/
+#The former commit is implemented in kernel v3.16 and the later in v3.19.
So this tool will work only from v3.19.
+
+#Install the shared library libmnl-dev on your build environment.
+
+=== To Build tipc-link-watcher ===
+
+#To build the daemon (SuSE environment):
+
+#First install libmnl on your build host: (libmnl-1.0.4)
+
+"zypper install libmnl-devel"
+
+#and run:
+
+"gcc -o tipc-link-watcher  $(pkg-config --libs --cflags libmnl) *.c"
+
+=== 2Do ===
+- Possible bug in current code or TIPC regarding values of rx_packets and
tx_packets.
+  When a link is reset, rx_packets and tx_packets contain rubbish values
until the link is reestablished.
+
+=== Couple of notes ===
+
+-Option "-x" and "-a" should not be used at the same time.
+
+-One shot (-x):
+You will get one single "layer 1" sample when you run with option "-x".
+Setting "-a" option will not change this behaviour.
+
+-Run forever:
+When all layer 0 samples (s) are taken every p second, the window
+layer 0 start to slide. Afterwards, every p seconds "mean of samples of
layer 0"
+ are calculated.  The calculated mean value will be the sample that is
inserted into layer 1 window.
+The procedure above will continue to fill the layer 1 window until the
layer 1 window begin to slide.
+When layer 1 window begin to slide the oldest value will be deleted from
that window.
+The size of layer 1 window is set by option "-a"
+
+=== So what is "layer 0 and layer 1"? ===
+Note:
+    -layer 0 samples are statistic values obtained from TIPC.
+    -layer 1 samples are "mean of samples of full layer 0 window".
+
+When Layer 0 is complete, it starts to "slide" and the first sample (mean
of layer 0 samples) of layer 1 is
+calculated and inserted in layer 1 samples.
+
+-P 4 : Sample period (how often) in secounds (Default:60 secounds)
+-s 5 : Number of samples in the window(layer 0) which must be gt 1
+       Default:60 samples
+-a 4 : Number of samples in the window layer 1 which must be gt 1
+      These samples are mean of layer zero samples over full window
+      size defined by -s option
+      Default value is 3600 samples.
+      __________ _______________
+      | 3  | 2  |2   |1   |2   |
+      |____|____|____|____|____|
+      <-p->
+      <----------- s ---------->
+
+3+2+2+1+2=10
+The mean value = 10 / 5(-s) = 2
+"2" is mean of layer 0 samples, which is sample number one in layer 1.
+
+     layer 1
+     _____________________
+     | 2  |    |    |    |
+     |____|____|____|____|
+      <-p->
+     <------------ a ---->
+
+Layer 0 received a new sample (8) and the second
+sample (mean of layer 0 samples) of layer 1 is calculated and inserted in
layer 1 samples.!
+
+      layer 0
+      __________ _______________
+      | 8  | 3  |2   |2   |1   |
+      |____|____|____|____|____|
+      <-p->
+      <----------- s ---------->
+
+8+3+2+2+1=15
+The mean value = 15 / 5(-s) = 3
+"3" is mean of layer 0 samples, which is sample number two in layer 1.
+
+     layer 1
+     _____________________
+     | 2  | 3  |    |    |
+     |____|____|____|____|
+      <-p->
+      <----------- a ---->
+
+Layer 1 windown mean samples are generated at the same rate as the -p
value.
+=== Examples how to run the Deamon ===
+
+#3.1: Run forever(absence of -x option); do not run as Daemon(-d);
+      every second(-p); 60 samples (-s: window size layer 0) and
+      3600 mean samples (-a:Default, window size layer 1).
+
+"tipc-link-watcher -d -p 1 -s 60"
+
+To make the process generate samples into a file run:
+"kill -HUP $(pidof tipc-link-watcher)"
+
+#3.2: Run forever as a daemon, every second(-p),
+      60 samples (-s) and 3600 mean samples (-a:Default).
+
+"tipc-link-watcher -p 1 -s 60"
+
+To request samples run:
+"kill -HUP $(pidof tipc-link-watcher)"
+
+#3.3: One shot(-x), do not run as daemon(-d), every 1 second (-p), 60
samples (-s) and dump the samples in "/my/print/path" when the daemon exits.
+
+"tipc-link-watcher -dx -p 1 -s 60 -f /my/print/path"
+
+To request additional samples before the daemon exist:
+"kill -HUP $(pidof tipc-link-watcher)"
+
+#3.4: Run forever (last 24 hour) and do not run as daemon(-d),
+     every 60 seconds (-p:Default), 60 samples (-s:Default). 3600 mean
samples (-a:Default).
+
+     "-tipc-link-watcher -d"
+
+     To request samples run:
+     "kill -HUP $(pidof tipc-link-watcher)"
+
+Be aware that after 24 hours window layer 1 begins to slide and oldest
mean value are removed from the window.
+
+#3.5:Run forever (latest 24 hour) as a daemon,
+     every 60 seconds (-p:Default), 60 samples (-s:Default). 3600 mean
samples (-a:Default).
+
+     "-tipc-link-watcher"
+
+     To request samples run:
+     "kill -HUP $(pidof tipc-link-watcher)"
+
+Be aware that after 24 hours window layer 1 begins to slide and oldest
mean value are removed from the window.
+
+
+#3.5:Run for one hour (-x), as daemon, every 60 seconds (-p:Default), 60
samples (-s:Default)
+     dump the samples in "tmp" directory at exit.
+     "-tipc-link-watcher -x"
+
+     To request samples run:
+     "kill -HUP $(pidof tipc-link-watcher)"
+
+#3.6: Run forever; do not run as Daemon(-d), every second(-p), 2 samlpes
(-s) and set thresholds (-o).
+
+"tipc-link-watcher -d -p 1 -s 2 -o t1_rx_loss_rate=10 -o rx_packets=666"
+
+The thresholds warnings will be written in syslog.
+
+#3.7: Run forever, do not run as daemon(-d), every second(-p) and 60
samples (-s), 3600 mean samples (-a:Default), with selected links to watch
(-l)
+
+"tipc-link-watcher -d -p 1 -s 60 -l 1.1.1:bond0-1.1.3:bond0 -l
1.1.1:bond0-1.1.4:bond0"
+
+The program will print the quality levels of selected links: (looks like
this for a link   )
+"1.1.1:bond0-1.1.2:bond0: link reset:0   rx_packets:11  tx_packets:71
  rx_loss:0  tx_loss:0  Working :)"
+Possible quality levels are: Working, Degraded, Faulty and Down
+
+Watching(-l) links quality is only possible in "non" daemon mode.
+
+The sample files are NOT effected by "-l" option. That means that you will
still get statistic for all published links.
+
+Note: "rx_packets and tx_packets" are mean values of window layer 0!
+      "rx_loss and tx_loss" are presented in precent.
+      "link reset" is number of reset of the link!
+
+
+Attention: There is some bug in TIPC or this code regarding values of
+ rx_packets and tx_packets.
+ When any link is reset, rx_packets and tx_packets are rabish values until
+ the link is restablished.
+=== Tipc link quality ===
+
+t1: Threshold one! 10%
+t2: Threshold two! 30%
+
+This is how the link quality is calculated:
+Down      == (Tipc link is not up)
+
+Working   == (Tipc link is up) &&
+       (Tipc link not reset during a size of window layer 0, which is -s)
&&
+       ((rx loss rate < t1)  && (tx loss rate < t1))
+
+Degraded  == (Tipc link is up) &&
+    ((link rested: up->Down->up) ||
+      !((rx loss rate < 10 %)  && (tx loss rate < 10 %))) &&
+      ((rx loss rate < t2)  && (tx loss rate < t2))
+
+Faulty    == (Tipc link is up) &&
+  ((link rested: up->Down->up) ||
+    !((rx loss rate < 10 %)  && (tx loss rate < 10 %))) &&
+      !((rx loss rate < t2)  && (tx loss rate < t2))
+
+
+=== Couple of notes ===
+
+-Option "-x" and "-a" should not be used at the same time.
+
+-One shot (-x):
+  1-One full set of samples which are represented by values in layer 0
window of samples. The first sample in
+    the file represents the accumulated staticstic since last time the
link statistics were reset by TIPC.
+  2-And One single "layer 1" sample which is mean of samples in layer 0
window.
+    Setting "-a" option will not change this behaviour.
+
+-Run forever(absence of -x):
+ When all layer 0 samples (s) are taken every p second, the window
+ layer 0 start to slide. Afterwards, every p seconds "mean of samples of
+ layer 0" are calculated.  The calculated mean value will be the sample
+ that is inserted into layer 1 window. The procedure above will continue
+ to fill the layer 1 window until the layer 1 window begin to slide.
+ When layer 1 window begin to slide the oldest value will be deleted
+ from that window.
+ The size of layer 1 window is set by option "-a"
+
+-The dumped sample files name look like this: (in csv format)
+ 2017-05-30.14.26.28_tipc (layer 0 samples)
+ 2017-05-30.14.26.28_tipc_l1 (layer 1 samples; which are mean values of
+ layer 0 samples for every "-p" over every "-s" samples)
+
+-The link "up" and "active" statistics in *_tipc_l1 are the sum
+ of (not mean of) the link "up" and "active" statistics in window layer 0.
+
+-"Mean of" some of properties; such as, "dest" and "mtu" in "*_tipc_l1"
file; it does
+ not make sence.
+ The advantage of mean calculation for these properties is, to reveal any
changes of
+ these values during sampling time.
+ For example: if "mtu" is configured to the value "1500" the mean value of
"mtu"
+ in window layer 0 should of course be equal to "1500".
+
+=== That's all folks ===
diff --git a/tipc-link-watcher/tipc-link-watcher.c
b/tipc-link-watcher/tipc-link-watcher.c
new file mode 100644
index 000000000000..c7c36fce7397
--- /dev/null
+++ b/tipc-link-watcher/tipc-link-watcher.c
@@ -0,0 +1,2143 @@
+/*
+ * tipc-link-watcher.c: TIPC link Fault detection tool
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <sys/timerfd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <linux/kernel.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/resource.h>
+#include <linux/tipc.h>
+#include <linux/tipc_netlink.h>
+
+#include <pthread.h>
+
+#include <linux/genetlink.h>
+#include <libmnl/libmnl.h>
+
+#define RUN "/run"
+#define LOCKMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
+static char LOCKFILE[512] = {};
+
+#define RESET   "\x1b[0m"
+#define RED     "\x1b[31m"
+#define GREEN   "\x1b[32m"
+#define YELLOW  "\x1b[33m"
+
+#define MAX_MY_TIPC_RESOURCE 0x400
+#define SLIDING_WINDOW_L1_SIZE 3600
+
+#define DEFUALT_THRESHOLD_ONE_STATS_RESET_RATE 0
+#define DEFUALT_THRESHOLD_ONE_STATS_RX_LOSS_RATE 10
+#define DEFUALT_THRESHOLD_ONE_STATS_TX_LOSS_RATE 10
+#define DEFUALT_THRESHOLD_TWO_STATS_RESET_RATE 0
+#define DEFUALT_THRESHOLD_TWO_STATS_RX_LOSS_RATE 10
+#define DEFUALT_THRESHOLD_TWO_STATS_TX_LOSS_RATE 10
+
+static int first_sample[MAX_MY_TIPC_RESOURCE];
+static int stat_index, l1_stat_index;
+static int topsrv_sd, timer_fd;
+static unsigned int this_node;
+static char start_time[64];
+static bool take_sample = false;
+
+#define IF_WATCH(W, IN_LIST, FUNC) \
+  do { \
+    if (W)  { if (IN_LIST) FUNC; } else {FUNC; } \
+  } \
+  while (0)
+
+#define TIPC_ALARM(EXP, S, T, V, N) \
+  do { if (EXP) \
+      syslog (LOG_WARNING, " %s"" %s" ":%d" " crossed the threshold value
" "%d", N, S, V, T); } \
+     while (0)
+
+#define SET_OFFSET_AND_STEP(OFFSETPOINTER, STEP, OFFSET, STRUCT) \
+  do { \
+    OFFSETPOINTER = (uintptr_t *)((char *)OFFSET +
offsetof(tipceLinkStatistics, STRUCT)); \
+    int i = STEP; \
+    while (i > 0 ) { \
+      OFFSETPOINTER++; \
+      i--; \
+    } \
+  } \
+  while (0)
+
+#define SET_MEM_AND_STEP(OFFSETPOINTER, STEP_SIZE, MEM) \
+  do { \
+    *OFFSETPOINTER = (uintptr_t)MEM; \
+    OFFSETPOINTER++; \
+    MEM += STEP_SIZE; \
+  } \
+  while (0)
+
+enum {
+  THRESHOLD_UNSPEC,
+  THRESHOLD_ONE_STATS_RESET_RATE,
+  THRESHOLD_ONE_STATS_RX_LOSS_RATE,
+  THRESHOLD_ONE_STATS_TX_LOSS_RATE,
+  THRESHOLD_TWO_STATS_RESET_RATE,
+  THRESHOLD_TWO_STATS_RX_LOSS_RATE,
+  THRESHOLD_TWO_STATS_TX_LOSS_RATE,
+  THRESHOLD_MAX
+};
+
+char * const thresholds[] = {
+  [THRESHOLD_UNSPEC]                 =  "thresholed_unspec",
+  [THRESHOLD_ONE_STATS_RESET_RATE]   =  "t1_reset_rate",
+  [THRESHOLD_ONE_STATS_RX_LOSS_RATE] =  "t1_rx_loss_rate",
+  [THRESHOLD_ONE_STATS_TX_LOSS_RATE] =  "t1_rx_loss_rate",
+  [THRESHOLD_TWO_STATS_RESET_RATE]   =  "t2_reset_rate",
+  [THRESHOLD_TWO_STATS_RX_LOSS_RATE] =  "t2_rx_loss_rate",
+  [THRESHOLD_TWO_STATS_TX_LOSS_RATE] =  "t2_tx_loss_rate",
+  [THRESHOLD_MAX] = NULL,
+};
+
+enum {
+  PRIV_TIPC_NLA_STATS_LINK_STATE,
+  PRIV_TIPC_NLA_STATS_RX_PACKETS,
+  PRIV_TIPC_NLA_STATS_TX_PACKETS,
+  PRIV_TIPC_NLA_STATS_RX_LOSS_RATE,
+  PRIV_TIPC_NLA_STATS_TX_LOSS_RATE,
+  __PRIV_TIPC_NLA_STATS_MAX
+};
+
+char * const stat_opts[] = {
+  [TIPC_NLA_STATS_UNSPEC]     = "unspec",
+  [TIPC_NLA_STATS_RX_INFO]     = "rx_info",
+  [TIPC_NLA_STATS_RX_FRAGMENTS]     = "rx_fragments",
+  [TIPC_NLA_STATS_RX_FRAGMENTED]     = "rx_fragmented",
+  [TIPC_NLA_STATS_RX_BUNDLES]     = "rx_bundles",
+  [TIPC_NLA_STATS_RX_BUNDLED]     = "rx_bundled",
+  [TIPC_NLA_STATS_TX_INFO]     = "tx_info",
+  [TIPC_NLA_STATS_TX_FRAGMENTS]     = "tx_fragments",
+  [TIPC_NLA_STATS_TX_FRAGMENTED]     = "tx_fragmented",
+  [TIPC_NLA_STATS_TX_BUNDLES]     = "tx_bundles",
+  [TIPC_NLA_STATS_TX_BUNDLED]     = "tx_bundled",
+  [TIPC_NLA_STATS_MSG_PROF_TOT]     = "msg_prof_tot",
+  [TIPC_NLA_STATS_MSG_LEN_CNT]     = "msg_len_cnt",
+  [TIPC_NLA_STATS_MSG_LEN_TOT]     = "msg_len_tot",
+  [TIPC_NLA_STATS_MSG_LEN_P0]     = "msg_len_0",
+  [TIPC_NLA_STATS_MSG_LEN_P1]     = "msg_len_1",
+  [TIPC_NLA_STATS_MSG_LEN_P2]     = "msg_len_2",
+  [TIPC_NLA_STATS_MSG_LEN_P3]     = "msg_len_3",
+  [TIPC_NLA_STATS_MSG_LEN_P4]     = "msg_len_4",
+  [TIPC_NLA_STATS_MSG_LEN_P5]     = "msg_len_5",
+  [TIPC_NLA_STATS_MSG_LEN_P6]     = "msg_len_6",
+  [TIPC_NLA_STATS_RX_STATES]     = "rx_states",
+  [TIPC_NLA_STATS_RX_PROBES]     = "rx_probes",
+  [TIPC_NLA_STATS_RX_NACKS]     = "rx_nacks",
+  [TIPC_NLA_STATS_RX_DEFERRED]     = "rx_defs",
+  [TIPC_NLA_STATS_TX_STATES]     = "tx_states",
+  [TIPC_NLA_STATS_TX_PROBES]     = "tx_probes",
+  [TIPC_NLA_STATS_TX_NACKS]     = "tx_nacks",
+  [TIPC_NLA_STATS_TX_ACKS]     = "tx_acks",
+  [TIPC_NLA_STATS_RETRANSMITTED]     = "retrans",
+  [TIPC_NLA_STATS_DUPLICATES]     = "dups",
+  [TIPC_NLA_STATS_LINK_CONGS]     = "link_congestion",
+  [TIPC_NLA_STATS_MAX_QUEUE]     = "send_queue_max",
+  [TIPC_NLA_STATS_AVG_QUEUE]     = "send_queue_avg",
+  [__TIPC_NLA_STATS_MAX]             = NULL
+};
+
+char * const stat_opts_priv[] = {
+  /* EXTENDED PART*/
+  [PRIV_TIPC_NLA_STATS_LINK_STATE]   = "link_state",
+  [PRIV_TIPC_NLA_STATS_RX_PACKETS]   = "rx_packets",
+  [PRIV_TIPC_NLA_STATS_TX_PACKETS]   = "tx_packets",
+  [PRIV_TIPC_NLA_STATS_RX_LOSS_RATE] = "rx_loss",
+  [PRIV_TIPC_NLA_STATS_TX_LOSS_RATE] = "tx_loss",
+  [__PRIV_TIPC_NLA_STATS_MAX]        = NULL
+};
+
+char * const stat_opts_link[] = {
+  [TIPC_NLA_LINK_UNSPEC]    =  "unspec",
+  [TIPC_NLA_LINK_NAME]      =  "link",
+  [TIPC_NLA_LINK_DEST]      =  "dest",
+  [TIPC_NLA_LINK_MTU]       =  "mtu",
+  [TIPC_NLA_LINK_BROADCAST] =  "broadcast",
+  [TIPC_NLA_LINK_UP]        =  "up",
+  [TIPC_NLA_LINK_ACTIVE]    =  "active",
+  [TIPC_NLA_LINK_PROP]      =  "prop",
+  [TIPC_NLA_LINK_STATS]     =  "stats",
+  [TIPC_NLA_LINK_RX]        =  "link_rx",
+  [TIPC_NLA_LINK_TX]        =  "link_tx",
+  [__TIPC_NLA_LINK_MAX]     =  NULL
+};
+
+uint32_t link_stat_threshold[__TIPC_NLA_STATS_MAX];
+uint32_t link_stat_threshold_priv[__PRIV_TIPC_NLA_STATS_MAX];
+uint32_t link_info_threshold[__TIPC_NLA_LINK_MAX];
+
+uint32_t thresholds_link[THRESHOLD_MAX+1] =
+  {0,
+   DEFUALT_THRESHOLD_ONE_STATS_RESET_RATE,
+   DEFUALT_THRESHOLD_ONE_STATS_RX_LOSS_RATE,
+   DEFUALT_THRESHOLD_ONE_STATS_TX_LOSS_RATE,
+   DEFUALT_THRESHOLD_TWO_STATS_RESET_RATE,
+   DEFUALT_THRESHOLD_TWO_STATS_RX_LOSS_RATE,
+   DEFUALT_THRESHOLD_TWO_STATS_TX_LOSS_RATE
+  };
+
+typedef struct link_miscellaneous {
+  char   *link_state;    /* TIPC_NLA_LINK_ACTIVE, TIPC_NLA_LINK_UP */
+  uint32_t *rx_packets;    /* TIPC_NLA_LINK_RX - TIPC_NLA_STATS_RX_INFO */
+  uint32_t *tx_packets;    /* TIPC_NLA_LINK_TX - TIPC_NLA_STATS_TX_INFO */
+  uint32_t *rx_loss;        /* perc(TIPC_NLA_STATS_RX_NACKS,
+       PRIV_TIPC_NLA_STATS_TX_PACKETS) */
+  uint32_t *tx_loss;    /* prec(TIPC_NLA_STATS_TX_NACKS,
+       PRIV_TIPC_NLA_STATS_RX_PACKETS) */
+}link_miscellaneous;
+
+/* Link info */
+typedef struct link_information {
+  uint32_t *unspec;
+  char     *link;   /* TIPC_NLA_LINK_NAME */
+  uint32_t *dest;   /* TIPC_NLA_LINK_DEST */
+  uint32_t *mtu;   /* TIPC_NLA_LINK_MTU */
+  uint32_t *broadcast;   /* TIPC_NLA_LINK_BROADCAST */
+  uint32_t *up;            /* TIPC_NLA_LINK_UP */
+  uint32_t *active;        /* TIPC_NLA_LINK_ACTIVE */
+  uint32_t *prop;   /* TIPC_NLA_LINK_PROP */
+  uint32_t *stats;   /* TIPC_NLA_LINK_STATS */
+  uint32_t *link_rx;   /* TIPC_NLA_LINK_RX */
+  uint32_t *link_tx;   /* TIPC_NLA_LINK_TX */
+}link_information;
+
+/* Nest, link propreties. Valid for link, media and bearer */
+typedef struct nest_link_propreties {
+  uint32_t *unspec;
+  uint32_t *priority;   /* TIPC_NLA_PROP_PRIO */
+  uint32_t *tolerance;   /* TIPC_NLA_PROP_TOL */
+  uint32_t *window;   /* TIPC_NLA_PROP_WIN */
+}link_propreties;
+
+/* Nest, statistics info */
+typedef struct nest_stat_information {
+  uint32_t *unspec;
+  uint32_t *rx_info;    /* TIPC_NLA_STATS_RX_INFO */
+  uint32_t *rx_fragments;   /* TIPC_NLA_STATS_RX_FRAGMENTS */
+  uint32_t *rx_fragmented;  /* TIPC_NLA_STATS_RX_FRAGMENTED */
+  uint32_t *rx_bundles;     /* TIPC_NLA_STATS_RX_BUNDLED */
+  uint32_t *rx_bundled;     /* TIPC_NLA_STATS_RX_BUNDLED */
+  uint32_t *tx_info;    /* TIPC_NLA_STATS_TX_INFO */
+  uint32_t *tx_fragments;   /* TIPC_NLA_STATS_TX_FRAGMENTS */
+  uint32_t *tx_fragmented;  /* TIPC_NLA_STATS_TX_FRAGMENTED */
+  uint32_t *tx_bundles;     /* TIPC_NLA_STATS_TX_BUNDLES */
+  uint32_t *tx_bundled;     /* TIPC_NLA_STATS_TX_BUNDLED */
+  uint32_t *msg_prof_tot;   /* TIPC_NLA_STATS_MSG_PROF_TOT */
+  uint32_t *len_cnt;    /* TIPC_NLA_STATS_MSG_LEN_CNT */
+  uint32_t *len_tot;    /* TIPC_NLA_STATS_MSG_LEN_TOT */
+  uint32_t *len_0;    /* TIPC_NLA_STATS_MSG_LEN_P0 */
+  uint32_t *len_1;    /* TIPC_NLA_STATS_MSG_LEN_P1 */
+  uint32_t *len_2;    /* TIPC_NLA_STATS_MSG_LEN_P2 */
+  uint32_t *len_3;    /* TIPC_NLA_STATS_MSG_LEN_P3 */
+  uint32_t *len_4;    /* TIPC_NLA_STATS_MSG_LEN_P4 */
+  uint32_t *len_5;    /* TIPC_NLA_STATS_MSG_LEN_P5 */
+  uint32_t *len_6;    /* TIPC_NLA_STATS_MSG_LEN_P6 */
+  uint32_t *rx_states;    /* TIPC_NLA_STATS_RX_STATES */
+  uint32_t *rx_probes;    /* TIPC_NLA_STATS_RX_PROBES */
+  uint32_t *rx_nacks;    /* TIPC_NLA_STATS_RX_NACKS */
+  uint32_t *rx_defs;    /* TIPC_NLA_STATS_RX_DEFERRED */
+  uint32_t *tx_states;    /* TIPC_NLA_STATS_TX_STATES */
+  uint32_t *tx_probes;    /* TIPC_NLA_STATS_TX_PROBES */
+  uint32_t *tx_nacks;    /* TIPC_NLA_STATS_TX_NACKS */
+  uint32_t *tx_acks ;    /* TIPC_NLA_STATS_TX_ACKS */
+  uint32_t *retrans;    /* TIPC_NLA_STATS_RETRANSMITTED */
+  uint32_t *dups;    /* TIPC_NLA_STATS_DUPLICATES */
+  uint32_t *link_congestion;/* TIPC_NLA_STATS_LINK_CONGS */
+  uint32_t *send_queue_max; /* TIPC_NLA_STATS_MAX_QUEUE */
+  uint32_t *send_queue_avg; /* TIPC_NLA_STATS_AVG_QUEUE */
+}stat_information;
+
+typedef struct link_status {
+  uint64_t up;
+  uint64_t down;
+  uint64_t count_down;
+}link_status;
+
+typedef struct linkStatistics {
+  /* link misc */
+  link_miscellaneous link_misc;
+
+  /* Link info */
+  link_information link_info;
+
+  /* Nest, link propreties. Valid for link, media and bearer */
+  link_propreties  link_props;
+
+  /* Nest, statistics info */
+  stat_information stat_info;
+
+ /* Current link status */
+  link_status link_state;
+}tipceLinkStatistics;
+
+
+/* FIXME: This is a copy from struct from socket.c libmnl*/
+struct mnl_socket {
+  int fd;
+  struct sockaddr_nl addr;
+};
+
+struct tipc_link_name_map {
+ struct tipc_sioc_ln_req req;
+ SLIST_ENTRY(tipc_link_name_map) entries;
+};
+
+SLIST_HEAD(listhead, tipc_link_name_map) head =
SLIST_HEAD_INITIALIZER(head);
+
+typedef struct event_status {
+  char *resource;
+  uint32_t event;
+}event_status;
+
+event_status tipc_events[2] =
+  {{.resource = "l_event", .event = TIPC_LINK_STATE},
+   {.resource = "n_event", .event = TIPC_CFG_SRV}};
+
+typedef struct resource_status {
+  char     *name;
+  uint64_t up;
+  uint64_t down;
+}resource_status;
+
+resource_status *node_status = NULL;
+
+typedef struct data {
+  int links;
+  int sample_limit;
+  char *mem;
+  tipceLinkStatistics *samples;
+  int counter[1000];
+}data;
+
+data uc_d = {
+  .links = 0,
+  .sample_limit = 0,
+  .mem = NULL,
+  .samples = NULL
+};
+data *uc_dp = &uc_d;
+
+data l1_d = {
+  .links = 0,
+  .sample_limit = 0,
+  .mem = NULL,
+  .samples = NULL
+};
+data *l1_dp = &l1_d;
+
+#define uc_links uc_dp->links
+#define uc_samples uc_dp->samples
+#define uc_tot_mem uc_dp->mem
+
+typedef struct action_resource {
+  int action;
+  char *action_list[MAX_MY_TIPC_RESOURCE];
+}action_resource;
+
+action_resource w_link, w_node, r_link;
+
+action_resource *w_linkp = &w_link;
+action_resource *w_nodep = &w_node;
+action_resource *r_linkp = &r_link;
+
+char *user_dir = NULL;
+typedef struct l0_default_conf {
+  int period;
+  int nos;
+  bool window_passed;
+  int nod;
+  int one_shot;
+}l0_default_conf;
+
+/* default config */
+/* Run as Daemon every minute in one hour and quit without dumping any
file*/
+l0_default_conf l0_w_conf = {
+  .period = 60,    /* Number of secounds between samples*/
+  .nos = 60,       /* Number of samples*/
+  .window_passed = false,
+  .nod = 0,        /* Daemonize, 1 => Not Daemonize*/
+  .one_shot = 0,   /* Just run one layer zero window */
+};
+
+typedef struct l1_default_conf {
+  int counter; /* Counter to discover when the window start to slid*/
+  int nos;     /* The size of the sliding window*/
+  bool window_passed;
+
+}l1_default_conf;
+
+/* default l1 config */
+l1_default_conf l1_w_conf = {
+  .counter = 0,
+  .nos = SLIDING_WINDOW_L1_SIZE,   /* Maximum Number of collected means */
+  .window_passed = false
+};
+
+typedef void (*add_link) (const char *,
+  const char *,
+  int,
+  data **);
+typedef void(*print_sample_to_file) (char *, int, char *,
+     char *, int, int,
+     tipceLinkStatistics **);
+
+static void usage(char *pName)
+{
+  int i;
+  fprintf(stdout,
+  "usage: %s [options]\n"
+  "options:\n"
+  " -h         Print this message\n"
+  " -a [value] Number of samples in the window layer 1 which must be gt 0
\n"
+  "            These samples are mean of layer 0 full window samples
(Default: 3600 samples)\n"
+  " -d         Do not daemonize; i.e. non daemon mode\n"
+  " -f [value] The directory to save the sample files in csv format with
following postfixes:\n"
+  "            \"_tipc\" and  \"_tipc_l1\" (Default: \"%s\" directory)\n"
+  " -l [value] Link(s) to watch, only in non daemon mode\n"
+  " -n [value] Node(s) to watch, only in non daemon mode\n"
+  " -p [value] Sample period (how often) in secounds (Default: 60
secounds)\n"
+  " -o [option=value] Threshold options: Threshold option value must be gt
0\n"
+  " -s [value] Number of samples in the window layer 0 which must be gt 1
(Default: 60 samples)\n"
+  " -x         Run only one window of samples and exit the program; i.e.
\"-s\" samples that are \n"
+  "            written to \"_tipc\" file; and one single \"mean of layer 0
window\" sample;\n"
+  "            which is written to \"_tipc_l1\" file\n"
+  "\n"
+  " Only tipc \"unicast\" messages are sampled!\n"
+  " Threshold options are only valid for following statistics:\n",
+  pName, P_tmpdir);
+  for (i = THRESHOLD_ONE_STATS_RESET_RATE; i < THRESHOLD_MAX; i ++)
+    fprintf(stdout, " %s \n", thresholds[i]);
+
+  for (i = TIPC_NLA_STATS_RX_INFO; i < (TIPC_NLA_STATS_MAX + 1); i ++)
+    fprintf(stdout, " %s \n", stat_opts[i]);
+
+  for (i = PRIV_TIPC_NLA_STATS_RX_PACKETS; i < __PRIV_TIPC_NLA_STATS_MAX;
i ++)
+    fprintf(stdout, " %s \n", stat_opts_priv[i]);
+  fprintf(stdout, " link_rx\n link_tx \n\n");
+  fprintf(stdout,"-o option example: %s -d -o t1_rx_loss_rate=10 -o
rx_packets=666 -o tx_packets=123117\n",  pName);
+  fprintf(stdout,"**************************\n");
+}
+
+static void sigs_term_int(int signo)
+{
+  syslog(LOG_INFO, "The TIPC Network Daemon has terminated by %s signal",
+ strsignal(signo));
+  exit(0);
+}
+
+static void sig_hup(int signo)
+{
+  syslog(LOG_INFO, "Create the csv sample file(s)");
+  take_sample = true;
+}
+
+static void handle_signals (void)
+{
+  struct sigaction sa;
+
+  sa.sa_handler = sigs_term_int;
+  sigemptyset(&sa.sa_mask);
+  sigaddset(&sa.sa_mask, SIGHUP);
+  sa.sa_flags = 0;
+
+  if (sigaction(SIGINT, &sa, NULL) < 0)
+    {
+      syslog(LOG_ERR, "sigaction: Failed to catch SIGINT, %s",
strerror(errno));
+      exit(-1);
+    }
+  if (sigaction(SIGTERM, &sa, NULL) < 0)
+    {
+      syslog(LOG_ERR, "sigaction: Failed to catch SIGTERM, %s",
+     strerror(errno));
+      exit(-1);
+    }
+
+  sa.sa_handler = sig_hup;
+  sigemptyset(&sa.sa_mask);
+
+  sigaddset(&sa.sa_mask, SIGINT);
+  sa.sa_flags = SA_RESTART;
+  if (sigaction(SIGHUP, &sa, NULL) < 0)
+    {
+      syslog(LOG_ERR, "sigaction: Failed to catch SIGHUP, %s",
strerror(errno));
+      exit(-1);
+    }
+}
+
+static uint32_t calc_sum(int samples, uint32_t *array)
+{
+  int sample;
+  uint32_t sum = 0;
+
+  for (sample = 0; sample < samples; sample++)
+    sum = sum + array[sample];
+
+  return sum;
+}
+
+static uint32_t calc_mean(int index, int samples, uint32_t **array, int
first)
+{
+  int sample, skip = 0;
+  uint32_t sum = 0, *data = *array;
+
+  if (samples == 0 )
+    return 0;
+
+  for (sample = 0; sample < samples; sample++) {
+    index = (index + 1) % samples;
+    if (first == 0 && index == 0)
+      {
+ skip = 1;
+      } else {
+      sum = sum + data[index];
+    }
+  }
+  if (skip)
+    {
+      if ((samples - 1) == 0 )
+ return 0;
+      return (sum/(samples - 1));
+    } else {
+    return(sum/samples);
+  }
+}
+
+static uint32_t perc(uint32_t count, uint32_t total)
+{
+  if(total > 0)
+    return (count * 100 + (total / 2)) / total;
+  return 0;
+}
+
+static void print_samples(FILE *csv_fp,
+  const char *opt,
+  uint32_t *stat,
+  int nos,
+  int s_index)
+{
+  int sample=0;
+  char *buf = malloc(strlen(opt) + 2);
+  if (!buf)
+    {
+      syslog(LOG_ERR, "malloc: Failed to alloc buffer , %s",
+     strerror(errno));
+      exit(-1);
+    }
+  sprintf(buf, "%s,", opt);
+  fprintf(csv_fp,"%s %u", buf, stat[0]);
+  for (sample = 1 ; sample < nos; sample++) {
+    s_index = (s_index + 1 ) % nos;
+    fprintf(csv_fp,"%s %u", ",", stat[s_index]);
+  }
+  fprintf(csv_fp,"\n");
+  free(buf);
+};
+
+static void print_uc_samples_to_file(char *filename,
+      int link,
+      char *start_time, char *end_time,
+      int s_index,
+      int nos,
+      tipceLinkStatistics **samples)
+{
+  FILE *csv_fp;
+  uintptr_t *offset_p;
+  int i;
+  uint32_t *stat_p;
+
+  csv_fp=fopen(filename,"a+");
+  fprintf(csv_fp,"stime: %s , etime: %s,", start_time, end_time);
+  fprintf(csv_fp,"\n");
+  fprintf(csv_fp,"%s, ", (*samples)[link].link_info.link);
+  fprintf(csv_fp,"mtu(%u), ", (*samples)[link].link_info.mtu[link]);
+  fprintf(csv_fp,"priority(%u), ",
(*samples)[link].link_props.priority[link]);
+  fprintf(csv_fp,"tolerance(%u ms), ",
(*samples)[link].link_props.tolerance[link]);
+  fprintf(csv_fp,"window(%u packets), ",
(*samples)[link].link_props.window[link]);
+  fprintf(csv_fp,"link_up(%lu), link_down(%lu)",
+  (*samples)[link].link_state.up, (*samples)[link].link_state.down);
+  fprintf(csv_fp,"\n");
+  /* skip link_state*/
+  SET_OFFSET_AND_STEP(offset_p, 1, &(*samples)[link], link_misc);
+  for (i = PRIV_TIPC_NLA_STATS_RX_PACKETS; i < __PRIV_TIPC_NLA_STATS_MAX;
i++) {
+    stat_p = (uint32_t *)((uintptr_t)*offset_p);
+    print_samples(csv_fp, stat_opts_priv[i], stat_p, nos, s_index);
+    offset_p++;
+  }
+  SET_OFFSET_AND_STEP(offset_p, 2, &(*samples)[link], link_info);
+  for (i = TIPC_NLA_LINK_DEST; i < __TIPC_NLA_LINK_MAX; i++) {
+    stat_p = (uint32_t *)((uintptr_t)*offset_p);
+    if( i == TIPC_NLA_LINK_UP || i == TIPC_NLA_LINK_ACTIVE ||
+ i == TIPC_NLA_LINK_RX || i == TIPC_NLA_LINK_TX)
+      print_samples(csv_fp, stat_opts_link[i], stat_p, nos, s_index);
+    offset_p++;
+  }
+  SET_OFFSET_AND_STEP(offset_p, 1, &(*samples)[link], stat_info);
+  for (i = TIPC_NLA_STATS_RX_INFO; i < __TIPC_NLA_STATS_MAX; i++) {
+    stat_p = (uint32_t *)((uintptr_t)*offset_p);
+    print_samples(csv_fp, stat_opts[i], stat_p, nos, s_index);
+    offset_p++;
+  }
+  fclose(csv_fp);
+};
+
+static char * get_full_path_file_name(const char * post_str)
+{
+   time_t the_time = time(NULL);
+   /* If threadsafe is wished, use localtime_r*/
+   struct tm *tm = localtime(&the_time);
+   char tmp[300], *fullpath, *csv_file;
+
+  strftime(tmp, sizeof(tmp),"%Y-%m-%d.%H.%M.%S",tm);
+  fullpath = malloc(300*strlen(tmp) + 2);
+  if (!fullpath) {
+    syslog(LOG_ERR, "malloc: Failed to alloc buffer , %s",
+   strerror(errno));
+    exit(-1);
+  }
+  sprintf(fullpath, "%s/%s", user_dir ? user_dir : P_tmpdir, tmp);
+  strcat(fullpath, post_str);
+  csv_file = malloc(150*strlen(tmp) + 2);
+  if (!csv_file)
+    {
+      syslog(LOG_ERR, "malloc: Failed to alloc buffer , %s",
+     strerror(errno));
+      exit(-1);
+    }
+  strcpy (csv_file, fullpath);
+  free(fullpath);
+  return csv_file;
+}
+
+static void print_to_file(char* csv_file_post_str,
+  int s_index,
+  int nos,
+  print_sample_to_file print2file,
+  data **dp)
+{
+  int j;
+  char end_time[64];
+  time_t the_time = time(NULL);
+  /* If threadsafe is wished, use localtime_r*/
+  struct tm *tm = localtime(&the_time);
+  strftime(end_time, sizeof(end_time),"%Y-%B-%d:%H:%M:%S",tm);
+  char *csv_file = get_full_path_file_name(csv_file_post_str);
+
+  for (j = 0; j < (*dp)->links; j++) {
+    (*print2file)(csv_file, j, start_time, end_time, s_index, nos,
&((*dp)->samples));
+  }
+  free(csv_file);
+}
+
+static void handle_print_to_file(void)
+{
+    print_to_file("_tipc",
+  stat_index,
+  l0_w_conf.window_passed ? l0_w_conf.nos : stat_index,
+  print_uc_samples_to_file,
+  &uc_dp);
+
+    if(l0_w_conf.window_passed)
+      print_to_file("_tipc_l1",
+    l1_stat_index,
+    l1_w_conf.window_passed ? l1_w_conf.nos : l1_stat_index,
+    print_uc_samples_to_file,
+    &l1_dp);
+}
+
+static bool check_link_reset(int link,
+     data *dp)
+{
+  return ((dp->samples)[link].link_state.count_down == 0 );
+}
+
+static bool check_link_up(int link, data *dp, int s_index)
+{
+  return ((dp->samples)[link].link_info.up[s_index] == 0 );
+}
+
+static bool check_threshold_one(int link, data *dp, int s_index)
+{
+  return (((dp->samples)[link].link_misc.rx_loss[s_index] <
+   thresholds_link[THRESHOLD_ONE_STATS_RX_LOSS_RATE]) &&
+  ((dp->samples)[link].link_misc.tx_loss[s_index] <
+   thresholds_link[THRESHOLD_ONE_STATS_TX_LOSS_RATE]));
+}
+
+static bool check_threshold_two_lt(int link, data *dp, int s_index)
+{
+  return (((dp->samples)[link].link_misc.rx_loss[s_index] <
+   thresholds_link[THRESHOLD_TWO_STATS_RX_LOSS_RATE]) &&
+  ((dp->samples)[link].link_misc.tx_loss[s_index] <
+   thresholds_link[THRESHOLD_TWO_STATS_TX_LOSS_RATE]));
+}
+
+static bool check_threshold_two_gt(int link, data *dp, int s_index)
+{
+  return (((dp->samples)[link].link_misc.rx_loss[s_index] >
+   thresholds_link[THRESHOLD_TWO_STATS_RX_LOSS_RATE]) ||
+  ((dp->samples)[link].link_misc.tx_loss[s_index] >
+   thresholds_link[THRESHOLD_TWO_STATS_TX_LOSS_RATE]));
+}
+
+static void link_quality(int link, data *l1_dp, data *uc_dp)
+{
+  if (!check_link_up(link, uc_dp, stat_index))
+    {
+      printf("Down!\n");
+    } else if (check_link_up(link, uc_dp, stat_index) &&
+       check_link_reset(link, uc_dp) &&
+       check_threshold_one(link, l1_dp, l1_stat_index))
+    {
+      printf(GREEN "Working :)" RESET "\n");
+    } else if (check_link_up(link, uc_dp, stat_index) &&
+       (!check_link_reset(link, uc_dp) ||
+ !check_threshold_one(link, l1_dp, l1_stat_index)) &&
+       check_threshold_two_lt(link, l1_dp, l1_stat_index))
+    {
+      printf(YELLOW "Degraded :(" RESET "\n");
+    } else if (check_link_up(link, uc_dp, stat_index) &&
+       (!check_link_reset(link, uc_dp) ||
+ !check_threshold_one(link, l1_dp, l1_stat_index)) &&
+       !check_threshold_two_gt(link, l1_dp, l1_stat_index))
+    {
+      printf(RED "Faulty!!!" RESET  "\n");
+    } else {
+    printf(RED "Faulty .... going down!!!" RESET "\n");
+  }
+}
+
+static int already_pid_running(char *cmd)
+{
+  int  fd;
+  char buf[16];
+  struct flock fl;
+  memset(&fl, 0, sizeof fl);
+
+  snprintf(LOCKFILE, sizeof(LOCKFILE), "%s/%s.pid", RUN, cmd);
+  fd = open(LOCKFILE, O_RDWR|O_CREAT, LOCKMODE);
+  if (fd < 0)
+    {
+      syslog(LOG_ERR, "open: Failed to open %s -> %s",
+     LOCKFILE, strerror(errno));
+      exit(-1);
+    }
+
+  fl.l_type = F_WRLCK;
+  fl.l_whence = SEEK_SET;
+
+  if (fcntl(fd, F_SETLK, &fl) < 0)
+    {
+      if (errno == EACCES || errno == EAGAIN) {
+ close(fd);
+ return(1);
+      }
+      syslog(LOG_ERR, "fcntl: Failed to lock %s -> %s",
+     LOCKFILE, strerror(errno));
+      exit(-1);
+    }
+
+
+  if (ftruncate(fd, 0) < 0 )
+  {
+    syslog(LOG_ERR, "ftruncate: Failed to truncate %d, %s", fd,
strerror(errno));
+    exit(-1);
+  }
+
+  sprintf(buf, "%ld", (long)getpid());
+
+  if (write(fd, buf, strlen(buf)+1) < 0 )
+    {
+      syslog(LOG_ERR, "write: Failed to write to %d, %s",
+     fd, strerror(errno));
+      exit(-1);
+    }
+  return(0);
+}
+
+static void daemonise(const char *cmd)
+{
+  int i, fd0, fd1, fd2;
+  pid_t pid;
+  struct rlimit rl;
+
+  /*
+   * Clear file creation mask.
+   */
+  umask(0);
+
+  /*
+   * Get maximum number of file descriptors.
+   */
+  if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
+    {
+      syslog(LOG_ERR, "getrlimit: Failed to get file limit: %s",
+     strerror(errno));
+      exit(-1);
+    }
+
+  /*
+   * Become a session leader to lose controlling TTY.
+   */
+  if ((pid = fork()) < 0)
+    {
+      syslog(LOG_ERR, "fork: Failed to fork: %s", strerror(errno));
+      exit(-1);
+    }
+  else if (pid != 0) /* parent */
+    exit(0);
+  setsid();
+
+  /*
+   * Ensure future opens won't allocate controlling TTYs.
+   */
+
+  /* Second fork */
+  if ((pid = fork()) < 0)
+    {
+      syslog(LOG_ERR, "fork: Failed to fork: %s", strerror(errno));
+      exit(-1);
+    }
+  else if (pid != 0) /* parent */
+    exit(0);
+
+  /*
+   * Second child:
+   * 1-The second child is a child of init now.
+   * 2-That the child  will never acquire a controlling TTY.
+   */
+
+  /*
+   * Change the current working directory to the root so
+   * we won't prevent file systems from being unmounted.
+   */
+  if (chdir("/") < 0)
+    {
+      syslog(LOG_ERR, "chdir: Failed to change directory to /: %s",
+     strerror(errno));
+      exit(-1);
+    }
+  /*
+   * Close all open file descriptors.
+   */
+  if (rl.rlim_max == RLIM_INFINITY)
+    rl.rlim_max = 1024;
+  for (i = 0; i < rl.rlim_max; i++)
+    close(i);
+
+  /*
+   * Attach file descriptors 0, 1, and 2 to /dev/null.
+   */
+  fd0 = open("/dev/null", O_RDWR);
+  fd1 = dup(0);
+  fd2 = dup(0);
+
+  /*
+   * Initialize the log file.
+   */
+  openlog(cmd, LOG_CONS, LOG_DAEMON);
+  if (fd0 != 0 || fd1 != 1 || fd2 != 2)
+    {
+      syslog(LOG_ERR, "openlog: unexpected file descriptors %d %d %d: %s",
+     fd0, fd1, fd2, strerror(errno));
+      exit(-1);
+    }
+}
+
+static void daemonize_me(char *cmd)
+{
+
+  if(!l0_w_conf.nod)
+    {
+      daemonise(cmd);
+      if (already_pid_running(cmd))
+ {
+  syslog(LOG_ERR, "daemonize_me: daemon already running");
+  exit(-1);
+ }
+    }
+};
+
+static void add_resource(const char *name,
+ resource_status **resource,
+ int *limit,
+ int *count)
+{
+  (*limit)++;
+  resource_status new_resource;
+  memset(&new_resource, 0, sizeof(new_resource));
+  resource_status *resource_p = &new_resource;
+
+  resource_status *newArray = realloc(*resource,
+      (*limit)*sizeof(resource_status));
+  if(!newArray)
+    {
+      free(*resource);
+      syslog(LOG_ERR, "realloc: Failed to realloc buffer , %s",
+     strerror(errno));
+      exit(-1);
+    } else {
+    resource_p->name = (char*)malloc(strlen(name) + 1);
+    if (!resource_p->name)
+      {
+ syslog(LOG_ERR, "malloc: Failed to alloc buffer , %s",
+       strerror(errno));
+ exit(-1);
+      }
+    strncpy(resource_p->name, name, strlen(name));
+    *(resource) = newArray;
+    (*(resource))[(*count)++] = *resource_p;
+  }
+  return;
+}
+
+static int look_up_node_index(char * name,
+       resource_status *node,
+       int len)
+{
+  int i;
+  for (i = 0; i < len ; i++) {
+      if (!strncmp(name, (node)[i].name, strlen(name)))
+ return i;
+  }
+  return -1;
+}
+
+static int look_up_link_index(char *name, char **links, int len)
+{
+  int link;
+  for (link = 0; link < len; link++) {
+    if (!strncmp(name, links[link], strlen(name)))
+ return link;
+  }
+  return -1;
+}
+
+static int insert_link(const char *name,
+       const char *link_state,
+       add_link link2add,
+       int nos,
+       data *dp)
+{
+  int link;
+  for (link = 0; link < dp->links ; link++) {
+      if (!strncmp(name, dp->samples[link].link_info.link, strlen(name)))
+ return link;
+  }
+  (*link2add)(name, link_state, nos, &dp);
+  return (dp->links - 1);
+}
+
+static void uc_add_link(const char *name,
+ const char * link_state,
+ int nos,
+ data **uc_dp)
+{
+  /* "nos + 1"  in the function allocates memory for last sampled value!
+   *  2bused in the delta calculation!
+   */
+  ((*uc_dp)->sample_limit)++;
+  int i;
+  uint16_t size_tot_chars, size_tot_chars_2b_alligend;
+  uint16_t size_tot_u32s;
+
+  uint16_t step_size = (nos + 1)*sizeof(uint32_t);
+  tipceLinkStatistics new_l;
+  tipceLinkStatistics *new_link = &new_l;
+  tipceLinkStatistics *new_samples = realloc((*uc_dp)->samples,
((*uc_dp)->sample_limit)*sizeof(tipceLinkStatistics));
+  char *tot_mem;
+
+  if(!new_samples)
+    {
+      free((*uc_dp)->samples);
+      syslog(LOG_ERR, "uc realloc: Failed to realloc buffer, %s",
+     strerror(errno));
+      exit(-1);
+    } else {
+    uintptr_t *offset_p;
+
+    /* Memory to 2b allocted for nos*linkstate and link name */
+    size_tot_chars_2b_alligend = strlen(link_state)*(nos + 1 ) + (nos + 1
) + strlen(name) + 1 ; /*  null characters*/
+    size_tot_chars = (size_tot_chars_2b_alligend + (4 - 1)) & - 4; /*
Round up to 4-byte boundary */
+    size_tot_u32s  = (sizeof(tipceLinkStatistics) / sizeof(uintptr_t)) -
(2); /*  const strings*/
+    (*uc_dp)->mem  = calloc((nos + 1), sizeof(uint32_t)*size_tot_u32s +
size_tot_chars);
+    tot_mem = (*uc_dp)->mem;
+    /* linkstate miscellaneous */
+    new_link->link_misc.link_state = tot_mem;
+    strncpy(new_link->link_misc.link_state, link_state,
strlen(link_state));
+    *(new_link->link_misc.link_state + strlen(link_state)) = '\0';
+
+    /* Make space for nos of linkstate string and null character!*/
+    tot_mem   = tot_mem + (((strlen(link_state)*nos + nos) + (4 - 1)) & -
4);
+    SET_OFFSET_AND_STEP(offset_p, 1, new_link, link_misc);
+
+    for ( i = PRIV_TIPC_NLA_STATS_RX_PACKETS; i <
__PRIV_TIPC_NLA_STATS_MAX; i++ )
+      SET_MEM_AND_STEP(offset_p, step_size, tot_mem);
+
+    new_link->link_info.link = tot_mem;
+    strncpy(new_link->link_info.link, name, strlen(name));
+    *(new_link->link_info.link + strlen(name)) =  '\0';
+    tot_mem  = tot_mem + (((strlen(name) + 1) + (4 - 1)) & - 4);
+    SET_OFFSET_AND_STEP(offset_p, 0, new_link, link_info);
+    /* skip unspec*/
+    SET_MEM_AND_STEP(offset_p, step_size, tot_mem);
+    /* skip link pointer */
+    offset_p++;
+    for ( i = TIPC_NLA_LINK_DEST; i < __TIPC_NLA_LINK_MAX; i++ )
+      SET_MEM_AND_STEP(offset_p, step_size, tot_mem);
+
+    /* nest link propreties */
+    SET_OFFSET_AND_STEP(offset_p, 0, new_link, link_props);
+    /* skip unspec */
+    SET_MEM_AND_STEP(offset_p, step_size, tot_mem);
+    for ( i = TIPC_NLA_PROP_PRIO; i < __TIPC_NLA_PROP_MAX; i++ )
+      SET_MEM_AND_STEP(offset_p, step_size, tot_mem);
+
+    /* nest stat information */
+    SET_OFFSET_AND_STEP(offset_p, 0, new_link, stat_info);
+    SET_MEM_AND_STEP(offset_p, step_size, tot_mem);
+    for ( i = TIPC_NLA_STATS_RX_INFO; i < __TIPC_NLA_STATS_MAX; i++ )
+      SET_MEM_AND_STEP(offset_p, step_size, tot_mem);
+
+    /* link status  FIXME: dubble check" if tot_mem includes this part
too*/
+    SET_OFFSET_AND_STEP(offset_p ,0 ,new_link , link_state);
+    *offset_p = (uintptr_t)tot_mem;
+    memset((link_status *)offset_p, 0, sizeof(link_status));
+
+    (*uc_dp)->samples = new_samples;
+    ((*uc_dp)->samples)[((*uc_dp)->links)++] = *new_link;
+  }
+ return;
+}
+
+static void log_event(int topsrv_sd,
+      struct tipc_event *evt)
+{
+
+  static int count = 0;
+  static int limit = 0;
+  int node;
+
+  char r_name[TIPC_MAX_LINK_NAME];
+  char full_name[TIPC_MAX_LINK_NAME + 100];
+  struct tipc_link_name_map *link;
+  struct tipc_sioc_ln_req lnr = {
+    .peer = ntohl(evt->found_lower),
+    .bearer_id = ntohl(evt->port.ref)
+  };
+
+  if (ntohl(evt->event) == TIPC_PUBLISHED)
+    {
+      /* UP*/
+      if ((ntohl((*evt).s.seq.type)) == TIPC_LINK_STATE)
+ {
+  if (ioctl(topsrv_sd, SIOCGETLINKNAME, &lnr) < 0)
+    {
+      syslog(LOG_ERR, "ioctl: Failed, %s", strerror(errno));
+      exit(-1);
+    } else {
+    strcpy(r_name, lnr.linkname);
+    sprintf(full_name, "<%s> on network plane %c",
+    r_name, lnr.bearer_id + 'A');
+  }
+  link = malloc(sizeof(struct tipc_link_name_map));
+  if (!link)
+    {
+      syslog(LOG_ERR, "malloc: Failed to alloc buffer , %s",
+     strerror(errno));
+      exit(-1);
+    }
+  link->req.peer = lnr.peer;
+  link->req.bearer_id = lnr.bearer_id;
+  strcpy(link->req.linkname, lnr.linkname);
+
+  SLIST_INSERT_HEAD(&head, link, entries);
+
+  int uc_index = insert_link(r_name, "UP", uc_add_link,
+     l0_w_conf.nos, uc_dp);
+  (uc_dp->samples)[uc_index].link_state.up++;
+  IF_WATCH(w_linkp->action,
+   ((look_up_link_index(r_name, w_linkp->action_list, w_linkp->action)) >=
0),
+   syslog(LOG_INFO, "Published link: %s\n", full_name));
+
+  if (l0_w_conf.window_passed)
+    if((uc_dp->samples)[uc_index].link_state.down)
+      IF_WATCH(w_linkp->action,
+       ((look_up_link_index((uc_dp->samples)[uc_index].link_info.link,
+    w_linkp->action_list,  w_linkp->action)) >= 0),
+       link_quality(uc_index, l1_dp, uc_dp));
+ } else { /* TIPC_CFG_SRV */
+ node = ntohl(evt->port.node);
+ sprintf(r_name, "%u.%u.%u",
+ tipc_zone(node), tipc_cluster(node), tipc_node(node));
+ IF_WATCH(w_nodep->action,
+ ((look_up_link_index(r_name, w_nodep->action_list, w_nodep->action)) >=
0),
+ syslog(LOG_INFO, "Published node: %s\n", r_name));
+
+ node = look_up_node_index(r_name, node_status, count);
+ if(node < 0)
+  {
+    add_resource(r_name,
+ &node_status,
+ &limit,
+ &count);
+    node = count - 1;
+  }
+ (node_status)[node].up++;
+      }
+
+  } else if (evt->event == htonl(TIPC_WITHDRAWN))
+    {
+      int found = 0;
+      SLIST_FOREACH(link, &head, entries) {
+ if ((link->req.peer == lnr.peer) &&
+    (link->req.bearer_id == lnr.bearer_id)) {
+  strcpy(r_name, link->req.linkname);
+  SLIST_REMOVE(&head, link, tipc_link_name_map, entries);
+  free(link);
+  found = 1;
+  break;
+ }
+      }
+      if (!found)
+ {
+  syslog(LOG_ERR, "Unknown link with peer:%x bearer_id:%x withdrawn!",
+ lnr.peer, lnr.bearer_id);
+  return;
+ }
+      /* Down*/
+      if ((ntohl((*evt).s.seq.type)) == TIPC_LINK_STATE)
+ {
+  int link = -1;
+  for ( link = 0; link < uc_dp->links ; link++ ) {
+    if (!strncmp(r_name, uc_dp->samples[link].link_info.link,
strlen(r_name)))
+      break;
+  }
+
+  if (link < 0 )
+    {
+      syslog(LOG_ERR, "Did I? missed to insert the link!");
+      exit(-1);
+    }
+  (uc_dp->samples)[link].link_state.down++;
+  (uc_dp->samples)[link].link_state.count_down = l0_w_conf.nos;
+
+  if (l0_w_conf.window_passed)
+    IF_WATCH(w_linkp->action,
+     ((look_up_link_index(((uc_dp)->samples)[link].link_info.link,
+  w_linkp->action_list,  w_linkp->action)) >= 0),
+     link_quality(link, l1_dp, uc_dp));
+  IF_WATCH(w_linkp->action,
+   ((look_up_link_index(r_name, w_linkp->action_list,  w_linkp->action))
= 0),
+   syslog(LOG_INFO, "Withdrawn link: %s\n", full_name));
+ } else {
+ if(look_up_node_index(r_name, node_status, count) < 0)
+  {
+    syslog(LOG_ERR, "Did I? missed to insert the node!");
+    exit(-1);
+  }
+ printf("Withdrawn node: %s\n", r_name);
+      }
+    }
+  else if (evt->event == htonl(TIPC_SUBSCR_TIMEOUT))
+    syslog(LOG_WARNING, "TIPC_SUBSCR_TIMEOUT event");
+  else
+    syslog(LOG_WARNING, "unknown event type (%u)\n", ntohl(evt->event));
+  return;
+}
+
+static int unicast_sample(struct nlattr *attrs[],
+  struct nlattr *prop[],
+  struct nlattr *stats[],
+  int index,
+  data *dp,
+  const char *name)
+{
+ int i;
+ uint32_t *last_p;
+ uint32_t *stat_p;
+ uintptr_t *offset_p;
+
+ uint32_t threshold = 0;
+ stat_information *offset_stat_info_p;
+ link_information *offset_link_info_p;
+ link_miscellaneous *offset_link_misc_p;
+ /*skip unspec and link*/
+ SET_OFFSET_AND_STEP(offset_p, 2, &(dp->samples)[index], link_info);
+ for ( i = TIPC_NLA_LINK_DEST; i <  __TIPC_NLA_LINK_MAX; i++) {
+   stat_p = (uint32_t *)(uintptr_t)*offset_p;
+   last_p = &stat_p[l0_w_conf.nos];
+   stat_p +=  stat_index;
+   if ((i < TIPC_NLA_LINK_BROADCAST) || (i > TIPC_NLA_LINK_STATS))
+     {
+       if( i > TIPC_NLA_LINK_STATS)
+ {
+   if(dp->counter[index] < (l0_w_conf.nos) )
+     {
+ /* link_rx, link_tx */
+       if(stat_index)
+ {
+   *stat_p = mnl_attr_get_u32(attrs[i]) - *last_p;
+ } else {
+ *stat_p = mnl_attr_get_u32(attrs[i]);
+       }
+     } else {
+     *stat_p = mnl_attr_get_u32(attrs[i]) - *last_p;
+   }
+   *last_p = mnl_attr_get_u32(attrs[i]);
+   threshold = link_info_threshold[i];
+   TIPC_ALARM(((threshold > 0) && (*stat_p > threshold)),
stat_opts_link[i], threshold, *stat_p, name);
+ } else {
+ /*dest mtu*/
+ *stat_p = mnl_attr_get_u32(attrs[i]);
+       }
+     } else {
+     /*bc, up and active*/
+     if(i < TIPC_NLA_LINK_PROP)
+       {
+ *stat_p = attrs[i] ? 0: 1;
+       }
+   }
+   offset_p++;
+ }
+ /*skip unspec*/
+ SET_OFFSET_AND_STEP(offset_p, 1, &(dp->samples)[index], link_props);
+ for ( i = TIPC_NLA_PROP_PRIO; i < __TIPC_NLA_PROP_MAX; i++) {
+   stat_p = (uint32_t *)(uintptr_t)*offset_p;
+   stat_p +=  stat_index;
+   *stat_p = mnl_attr_get_u32(prop[i]);
+   offset_p++;
+ }
+ /*skip unspec*/
+ SET_OFFSET_AND_STEP(offset_p, 1, &(dp->samples)[index], stat_info);
+ for ( i = TIPC_NLA_STATS_RX_INFO; i < __TIPC_NLA_STATS_MAX; i++) {
+   stat_p = (uint32_t *)(uintptr_t)*offset_p;
+   last_p = &stat_p[l0_w_conf.nos];
+   stat_p += stat_index;
+
+   if(dp->counter[index] < (l0_w_conf.nos))
+     {
+       if(stat_index)
+ {
+   *stat_p = mnl_attr_get_u32(stats[i]) - *last_p;
+ } else {
+ *stat_p = mnl_attr_get_u32(stats[i]);
+       }
+     } else {
+     *stat_p = mnl_attr_get_u32(stats[i]) - *last_p;
+   }
+   *last_p = mnl_attr_get_u32(stats[i]);
+   offset_p++;
+   threshold = link_stat_threshold[i];
+   TIPC_ALARM(((threshold > 0) && (*stat_p > threshold)), stat_opts[i],
threshold, *stat_p, name);
+ }
+
+ offset_stat_info_p = (stat_information *)(uintptr_t *)((char
*)&(dp->samples)[index] + offsetof(tipceLinkStatistics, stat_info));
+ offset_link_info_p = (link_information *)(uintptr_t *)((char
*)&(dp->samples)[index] + offsetof(tipceLinkStatistics, link_info));
+ offset_link_misc_p = (link_miscellaneous *)(uintptr_t *)((char
*)&(dp->samples)[index] + offsetof(tipceLinkStatistics, link_misc));
+
+ offset_link_misc_p->rx_packets[stat_index] =
+   offset_link_info_p->link_rx[stat_index] -
offset_stat_info_p->rx_info[stat_index];
+ threshold = link_stat_threshold_priv[PRIV_TIPC_NLA_STATS_RX_PACKETS];
+ TIPC_ALARM(((threshold > 0) &&
(offset_link_misc_p->rx_packets[stat_index] > threshold)),
+    "rx_packets", threshold, offset_link_misc_p->rx_packets[stat_index],
name);
+
+ offset_link_misc_p->tx_packets[stat_index] =
+   offset_link_info_p->link_tx[stat_index] -
offset_stat_info_p->tx_info[stat_index];
+ threshold = link_stat_threshold_priv[PRIV_TIPC_NLA_STATS_TX_PACKETS];
+ TIPC_ALARM(((threshold > 0) &&
+     ( offset_link_misc_p->tx_packets[stat_index] > threshold)),
+    "tx_packets", threshold, offset_link_misc_p->tx_packets[stat_index],
name);
+
+ offset_link_misc_p->rx_loss[stat_index] = perc(
offset_stat_info_p->rx_nacks[stat_index],
+ offset_link_misc_p->tx_packets[stat_index]);
+ threshold = link_stat_threshold_priv[PRIV_TIPC_NLA_STATS_RX_LOSS_RATE];
+ TIPC_ALARM(((threshold > 0) &&
+     (offset_link_misc_p->rx_loss[stat_index] > threshold)),
+    "rx_loss", threshold , offset_link_misc_p->rx_loss[stat_index], name);
+
+ offset_link_misc_p->tx_loss[stat_index] =
perc(offset_stat_info_p->tx_nacks[stat_index],
+ offset_link_misc_p->rx_packets[stat_index]);
+ threshold = link_stat_threshold_priv[PRIV_TIPC_NLA_STATS_TX_LOSS_RATE];
+ TIPC_ALARM(((threshold > 0) &&
+     (offset_link_misc_p->tx_loss[stat_index] > threshold)),
+    "tx_loss", threshold, offset_link_misc_p->tx_loss[stat_index], name);
+
+ dp->counter[index]++;
+ return MNL_CB_OK;
+}
+
+static int l1_unicast_sample(int index,
+     int uc_index,
+     data *uc_dp,
+     data *dp)
+{
+ int i;
+ uint32_t *uc_stat_p;
+ uint32_t *stat_p;
+ uintptr_t *offset_p;
+ uintptr_t *uc_offset_p;
+
+ SET_OFFSET_AND_STEP(offset_p, 2, &(dp->samples)[index], link_info);
+ SET_OFFSET_AND_STEP(uc_offset_p, 2, &(uc_dp->samples)[uc_index],
link_info);
+
+ /* FIXME: fix the print to csv file b4 rewrite this part!
+    it does not make sence to calculate some of following propreties*/
+ for ( i = TIPC_NLA_LINK_DEST; i <  __TIPC_NLA_LINK_MAX; i++)
+   {
+     stat_p = (uint32_t *)(uintptr_t)*offset_p;
+     stat_p += l1_stat_index;
+     uc_stat_p = (uint32_t *)(uintptr_t)*uc_offset_p;
+
+     if ((i < TIPC_NLA_LINK_BROADCAST) || (i > TIPC_NLA_LINK_STATS))
+       {
+ /* link_rx, link_tx
+ *  dest, mtu: should be the same value as dest and mtu values
+ *  in layer 0 window.
+ */
+ *stat_p = calc_mean(stat_index, l0_w_conf.nos, &uc_stat_p,
first_sample[uc_index]);
+       } else {
+       /* up and active*/
+       if((i < TIPC_NLA_LINK_PROP) && (i > TIPC_NLA_LINK_BROADCAST))
+ /* *stat_p = calc_mean(stat_index, l0_w_conf.nos, &uc_stat_p,
  first_sample[uc_index]); */
+ *stat_p = calc_sum(l0_w_conf.nos, uc_stat_p);
+     }
+   offset_p++;
+   uc_offset_p++;
+ }
+
+ SET_OFFSET_AND_STEP(offset_p, 1, &(dp->samples)[index], link_props);
+ SET_OFFSET_AND_STEP(uc_offset_p, 1, &(uc_dp->samples)[index], link_props);
+ for (i = TIPC_NLA_PROP_PRIO; i < __TIPC_NLA_PROP_MAX; i++) {
+     stat_p = (uint32_t *)(uintptr_t)*offset_p;
+     stat_p += l1_stat_index;
+     uc_stat_p = (uint32_t *)(uintptr_t)*uc_offset_p;
+     *stat_p = calc_mean(stat_index, l0_w_conf.nos, &uc_stat_p,
first_sample[uc_index]);
+     offset_p++;
+     uc_offset_p++;
+   }
+ SET_OFFSET_AND_STEP(offset_p, 1, &(dp->samples)[index],  stat_info);
+ SET_OFFSET_AND_STEP(uc_offset_p, 1, &(uc_dp->samples)[index], stat_info);
+ for (i = TIPC_NLA_STATS_RX_INFO; i < __TIPC_NLA_STATS_MAX; i++) {
+   stat_p = (uint32_t *)(uintptr_t)*offset_p;
+   stat_p +=  l1_stat_index;
+   uc_stat_p = (uint32_t *)(uintptr_t)*uc_offset_p;
+   *stat_p = calc_mean(stat_index, l0_w_conf.nos, &uc_stat_p,
  first_sample[uc_index]);
+   offset_p++;
+   uc_offset_p++;
+ }
+ SET_OFFSET_AND_STEP(offset_p, 1, &(dp->samples)[index], link_misc);
+ SET_OFFSET_AND_STEP( uc_offset_p, 1, &(uc_dp->samples)[index], link_misc);
+
+ IF_WATCH(w_linkp->action,
+  (look_up_link_index(uc_dp->samples[index].link_info.link,
+      w_linkp->action_list,  w_linkp->action) >= 0),
+  printf("\n%s: link reset:%-10lu ",
(uc_dp)->samples[index].link_info.link,
(uc_dp)->samples[index].link_state.down));
+
+ for (i = PRIV_TIPC_NLA_STATS_RX_PACKETS; i < __PRIV_TIPC_NLA_STATS_MAX;
i++) {
+   stat_p = (uint32_t *)(uintptr_t)*offset_p;
+   stat_p += l1_stat_index;
+   uc_stat_p = (uint32_t *)(uintptr_t)*uc_offset_p;
+   *stat_p = calc_mean(stat_index, l0_w_conf.nos, &uc_stat_p,
first_sample[uc_index]);
+   /*
+    * Attention: There is some bug in TIPC or this code regarding values of
+    * rx_packets and tx_packets.
+    * When any link is reset, rx_packets and tx_packets are rabish values
until the link
+    * is restablished.
+    */
+   IF_WATCH(w_linkp->action,
+    (look_up_link_index(uc_dp->samples[index].link_info.link,
w_linkp->action_list, w_linkp->action) >= 0),
+    printf("%s:%-10u ", stat_opts_priv[i], *stat_p));
+   offset_p++;
+   uc_offset_p++;
+ }
+ dp->counter[index]++;
+ return MNL_CB_OK;
+}
+
+static int parse_attrs(const struct nlattr *attr, void *data)
+{
+ const struct nlattr **tb = data;
+
+ tb[ mnl_attr_get_type(attr)] = attr;
+ return MNL_CB_OK;
+}
+
+static int family_id_cb(const struct nlmsghdr *nlh, void *data)
+{
+  struct nlattr *tb[CTRL_ATTR_MAX + 1] = {};
+  struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+  int *id = data;
+
+  mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, tb);
+  if (!tb[CTRL_ATTR_FAMILY_ID])
+    return MNL_CB_ERROR;
+
+  *id = mnl_attr_get_u16(tb[CTRL_ATTR_FAMILY_ID]);
+  return MNL_CB_OK;
+}
+
+
+static void nl_prep_msg(struct nlmsghdr **nlhp,
+ void *buf,
+ uint16_t nlmsg_type,
+ uint16_t nlmsg_flags,
+ uint16_t cmd,  /* uint16_t? */
+ time_t *nlSeq)
+{
+  /*
+    Allocate a buffer of MNL_SOCKET_BUFFER_SIZE
+    (which is 8KB, see linux/netlink.h for more information).
+    Using this buffer size ensures that the buffer is big enough
+    to store the netlink message without truncating it.
+  */
+
+  /* Pointer to Generic Netlink message header */
+  struct genlmsghdr *genlh;
+  struct nlmsghdr *nlh;
+  nlh = mnl_nlmsg_put_header(buf);
+  nlh->nlmsg_type  = nlmsg_type;
+  nlh->nlmsg_flags = nlmsg_flags;
+
+  (void)time(nlSeq);
+  nlh->nlmsg_seq = *nlSeq;
+
+  genlh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr));
+  genlh->cmd = cmd;
+  genlh->version = 1;
+  *nlhp = nlh;
+  return;
+}
+
+static void nl_send_msg(struct mnl_socket **nls,
+ struct nlmsghdr *nlh,
+ int nlSocket,
+ pid_t portId)
+{
+  /* R we getting the right errno when mnl_*_* funcs returns?!*/
+  if ((*nls = mnl_socket_open(nlSocket) ) == NULL)
+    {
+      syslog(LOG_ERR, "mnl_socket_open: Failed, %s", strerror(errno));
+      exit(-1);
+    }
+
+  if (mnl_socket_bind(*nls, 0, portId) < 0)
+    {
+      mnl_socket_close(*nls);
+      syslog(LOG_ERR, "mnl_socket_bind: Failed, %s", strerror(errno));
+      exit(-1);
+    }
+
+  /* Maybe check return value equal to nlh->nlmsg_len? */
+  if (mnl_socket_sendto(*nls, nlh, nlh->nlmsg_len) < 0)
+    {
+      mnl_socket_close(*nls);
+      syslog(LOG_ERR, "mnl_socket_sendto: Failed, %s", strerror(errno));
+      exit(-1);
+    }
+  return;
+}
+
+static void nl_rcv_msg(struct mnl_socket *nls,
+      mnl_cb_t cb,
+      void *cb_data,
+      time_t *nlSeq)
+{
+  int ret;
+  char buf[MNL_SOCKET_BUFFER_SIZE];
+  uint32_t portId = mnl_socket_get_portid(nls);
+
+  if ((ret = mnl_socket_recvfrom(nls, buf, sizeof(buf))) < 0)
+    {
+      mnl_socket_close(nls);
+      syslog(LOG_ERR, "mnl_socket_recvfrom: Failed, %s", strerror(errno));
+      exit(-1);
+    }
+
+  while (ret > 0) {
+    ret = mnl_cb_run(buf,
+     ret,
+     (uint32_t)*nlSeq,
+     portId,
+     cb,
+     cb_data);
+    if (ret <= 0) {
+      if (ret == MNL_CB_ERROR)
+ {
+  mnl_socket_close(nls);
+  syslog(LOG_ERR, "mnl_cb_run: Failed, (MNL_CB_ERROR) %s",
strerror(errno));
+  exit(-1);
+ }
+      break;
+    }
+
+    if ((ret = mnl_socket_recvfrom(nls, buf, sizeof(buf))) < 0)
+      {
+ mnl_socket_close(nls);
+ syslog(LOG_ERR, "mnl_socket_recvfrom: Failed, %s", strerror(errno));
+ exit(-1);
+      }
+  }
+  return;
+}
+
+static int get_tipc_family(void)
+{
+  int nlFamily;
+  time_t nlSeq;
+  struct mnl_socket *nls;
+  struct nlmsghdr *nlh;
+  char buf[MNL_SOCKET_BUFFER_SIZE];
+
+  nl_prep_msg(&nlh,
+      buf,
+      GENL_ID_CTRL,
+      NLM_F_REQUEST | NLM_F_ACK,
+      CTRL_CMD_GETFAMILY,
+      &nlSeq);
+
+  mnl_attr_put_u32(nlh, CTRL_ATTR_FAMILY_ID, GENL_ID_CTRL);
+  mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, TIPC_GENL_V2_NAME);
+
+  nl_send_msg(&nls,
+      nlh,
+      NETLINK_GENERIC,
+      MNL_SOCKET_AUTOPID);
+
+  nl_rcv_msg(nls,
+     family_id_cb,
+     &nlFamily,
+     &nlSeq);
+  mnl_socket_close(nls);
+
+  return nlFamily;
+}
+
+static int validate_opt(const char* str)
+{
+  size_t i, len = strlen(str);
+
+  for (i = 0; i < len; i++) {
+    if(!isdigit(str[i]))
+      return 0;
+  }
+  return 1;
+}
+
+static bool handle_getsubopt(char **optionp, char *const *tokens,
+      uint32_t *t_link, int t_low, int t_high)
+{
+  int sub_opt;
+  int tmp;
+  char *valuep;
+  while (*optionp != '\0') {
+    sub_opt = getsubopt (optionp, tokens, &valuep);
+    if ((t_low < sub_opt) && (sub_opt < t_high) )
+      {
+ if ( *valuep )
+  {
+    tmp = atoi (valuep);
+    if (tmp > 0)
+      {
+ t_link[sub_opt] = atoi (valuep);
+ return true;
+      }
+  }
+ fprintf(stderr, "The suboption `%s is not given any valid value!\n",
+ tokens[sub_opt]);
+ fflush(stderr);
+ abort ();
+      }
+    else
+      return false;
+  }
+  return false;
+}
+
+static int handle_opts(int argc, char *const argv[])
+{
+
+  int opt;
+  bool found =false;
+  char *pName = strrchr(argv[0], '/');
+  pName = pName ? 1+pName : argv[0];
+
+  while (EOF != (opt = getopt(argc, argv, "hdxs:a:p:f:l:n:r:o:"))) {
+
+    switch (opt) {
+    case 'r':
+      /* Reset following link(s) */
+      r_linkp->action_list[r_linkp->action] = malloc(strlen(optarg) + 1);
+      if (!r_linkp->action_list[r_linkp->action])
+ {
+  syslog(LOG_ERR, "malloc: Failed to alloc buffer , %s",
+ strerror(errno));
+  exit(-1);
+ }
+      strncpy(r_linkp->action_list[r_linkp->action], optarg,
strlen(optarg));
+      r_linkp->action++;
+      break;
+    case 'l':
+      /* Watch only following link(s) */
+      w_linkp->action_list[w_linkp->action] = malloc(strlen(optarg) + 1);
+      if (!w_linkp->action_list[w_linkp->action])
+ {
+  syslog(LOG_ERR, "malloc: Failed to alloc buffer , %s",
+ strerror(errno));
+  exit(-1);
+ }
+      strncpy(w_linkp->action_list[w_linkp->action], optarg,
strlen(optarg));
+      w_linkp->action++;
+      break;
+    case 'n':
+      /* Watch only following nodes(s) */
+      w_nodep->action_list[w_nodep->action] = malloc(strlen(optarg) + 1);
+      if (!w_nodep->action_list[w_nodep->action])
+ {
+  syslog(LOG_ERR, "malloc: Failed to alloc buffer , %s",
+ strerror(errno));
+  exit(-1);
+ }
+      strncpy(w_nodep->action_list[w_nodep->action], optarg,
strlen(optarg));
+      w_nodep->action++;
+      break;
+    case 'f':
+      printf(" %d %s \n", __LINE__, optarg);
+      fflush(stdout);
+      user_dir = malloc(strlen(optarg) + 1);
+      if (!user_dir)
+ {
+  syslog(LOG_ERR, "malloc: Failed to alloc buffer , %s",
+ strerror(errno));
+  exit(-1);
+ }
+      strncpy(user_dir, optarg, strlen(optarg));
+      printf(" %d \n", __LINE__);
+      fflush(stdout);
+      break;
+    case 'x':
+      /* Only one sample */
+      l0_w_conf.one_shot = 1;
+      break;
+    case 'd':
+      /* Do not daemonize */
+      l0_w_conf.nod = 1;
+      break;
+    case 's':
+      /* Number of samples, The size of sliding window level zero*/
+      if(validate_opt(optarg))
+ {
+ l0_w_conf.nos = atoi(optarg);
+ if(l0_w_conf.nos < 2)
+   {
+     printf("The size of the window must be gt one!\n");
+     abort();
+   }
+ } else {
+ printf("option requires an argument\n");
+ abort();
+      }
+      break;
+    case 'a':
+      /* The size of sliding window level one; mean of samples of window
level zero*/
+      if(validate_opt(optarg))
+ {
+ l1_w_conf.nos = atoi(optarg);
+ if(l1_w_conf.nos < 1)
+   {
+     printf("The size of the window must be gt zero!\n");
+     abort();
+   }
+ }
+      else {
+ printf("option requires an argument\n");
+ abort();
+      }
+      break;
+    case 'p':
+      /* How often*/
+      if(validate_opt(optarg))
+ l0_w_conf.period = atoi(optarg);
+      else {
+ printf("option requires an argument\n");
+ abort();
+      }
+      break;
+    case 'o':
+      {
+ char *sub_opts;
+ sub_opts = optarg;
+ found = handle_getsubopt(&sub_opts, thresholds,
+ thresholds_link,
+ THRESHOLD_UNSPEC,
+ THRESHOLD_MAX);
+ if(!found)
+  {
+    sub_opts = optarg;
+    found = handle_getsubopt(&sub_opts, stat_opts_link,
+     link_info_threshold,
+     TIPC_NLA_LINK_STATS,
+     __TIPC_NLA_LINK_MAX);
+  }
+ if(!found)
+  {
+    sub_opts = optarg;
+    found = handle_getsubopt(&sub_opts, stat_opts,
+     link_stat_threshold,
+     TIPC_NLA_STATS_UNSPEC,
+     __TIPC_NLA_STATS_MAX);
+  }
+ if(!found)
+  {
+    sub_opts = optarg;
+    found = handle_getsubopt(&sub_opts, stat_opts_priv,
+     link_stat_threshold_priv,
+     PRIV_TIPC_NLA_STATS_LINK_STATE,
+     __PRIV_TIPC_NLA_STATS_MAX);
+  }
+ if(found)
+  found=false;
+ else {
+  fprintf(stderr,"Unknown suboption\n");
+  abort();
+ }
+      }
+      break;
+    case 'h':
+      usage(pName);
+      exit(0);
+    case ':':
+    case '?':
+    default:
+      usage(pName);
+       exit(-1);
+    }
+  }
+  return 0;
+}
+
+static void topsrv_subscibe(event_status *events, int len)
+{
+  int i;
+  struct sockaddr_tipc sa = {
+    .family = AF_TIPC,
+    .addrtype = TIPC_ADDR_NAME,
+    .addr.name.name.type = TIPC_TOP_SRV,
+    .addr.name.name.instance = TIPC_TOP_SRV,
+    .addr.name.domain = 0
+  };
+  socklen_t sa_len = sizeof(sa);
+
+  if (!(topsrv_sd = socket(AF_TIPC, SOCK_SEQPACKET, 0)))
+    {
+      syslog(LOG_ERR, "socket: Failed to open TIPC socket: %s",
+     strerror(errno));
+      exit(-1);
+    }
+
+  if ( 0 > connect(topsrv_sd, (struct sockaddr*)&sa, sizeof(sa)))
+    {
+      syslog(LOG_ERR, "connect: Failed to connect to TIPC topology server:
%s",
+     strerror(errno));
+      exit(-1);
+    }
+
+  memset(&sa, 0, sizeof(sa));
+  sa_len = sizeof(sa);
+
+  if (0 > getsockname(topsrv_sd, (struct sockaddr*)&sa, &sa_len))
+    {
+      syslog(LOG_ERR, "getsockname: Failed to get this node TIPC address:
%s",
+     strerror(errno));
+      exit(-1);
+  }
+
+  this_node = sa.addr.id.node;
+
+  for (i = 0; i < len; i++) {
+
+      struct tipc_subscr link_sub = {
+ .seq.type   = htonl(events[i].event), /* topology service name type */
+ .seq.lower  = htonl(0),
+ .seq.upper  = htonl(~0),
+ /* subscription duration set 24ever*/
+ .timeout    = htonl(TIPC_WAIT_FOREVER),
+ .filter     = htonl(TIPC_SUB_PORTS),
+      };
+      strcpy(link_sub.usr_handle,  events[i].resource);
+      if (send(topsrv_sd, &link_sub, sizeof(link_sub), 0) !=
sizeof(link_sub))
+ {
+  syslog(LOG_ERR,
+ "Failed to subscribe to \"TIPC Link\" Or \"Node State\" event(s): %s",
+ strerror(errno));
+  exit(-1);
+ }
+  }
+  return;
+}
+
+static void setup_sample_timer(void)
+{
+  int err = 0;
+  timer_fd = timerfd_create (CLOCK_REALTIME, 0);
+  struct itimerspec new_value = {
+    /* new_value.it_value specifies the initial expiration of the timer, in
+       seconds and nanoseconds.  Setting either field of new_value.it_value
+       to a nonzero value arms the timer.  Setting both fields of
+       new_value.it_value to zero disarms the timer.
+    */
+
+    .it_value.tv_sec = 1,
+    .it_value.tv_nsec = 0,
+
+    /* Setting one or both fields of new_value.it_interval to nonzero
values
+       specifies the period, in seconds and nanoseconds, for repeated timer
+       expirations after the initial expiration.  If both fields of
+       new_value.it_interval are zero, the timer expires just once, at the
+       time specified by new_value.it_value.
+    */
+
+    .it_interval.tv_sec = l0_w_conf.period,
+    .it_interval.tv_nsec = 0
+  };
+
+  if ((err = timerfd_settime(timer_fd, 0, &new_value, 0))  < 0)
+    {
+      syslog(LOG_ERR, "timerfd_settime: Failed with error: %d", err);
+      exit(-1);
+    }
+  return;
+}
+
+static void reset_tipc_stat(char *link)
+{
+  struct mnl_socket *nls;
+  struct nlmsghdr *nlh;
+  time_t nlSeq;
+  char  mnl_s_buffer[MNL_SOCKET_BUFFER_SIZE];
+  struct nlattr *nest;
+  syslog(LOG_INFO, "start to reset the link %s \n", link);
+  nl_prep_msg(&nlh,
+ mnl_s_buffer,
+ get_tipc_family(),
+ NLM_F_REQUEST | NLM_F_ACK,
+ TIPC_NL_LINK_RESET_STATS,
+ &nlSeq);
+  nest = mnl_attr_nest_start(nlh, TIPC_NLA_LINK);
+  mnl_attr_put_strz(nlh, TIPC_NLA_LINK_NAME, link);
+  mnl_attr_nest_end(nlh, nest);
+  nl_send_msg(&nls,
+      nlh,
+      NETLINK_GENERIC,
+      MNL_SOCKET_AUTOPID);
+  nl_rcv_msg(nls,
+     NULL,
+     NULL,
+     &nlSeq);
+  mnl_socket_close(nls);
+  syslog(LOG_INFO, "reset link %s is done \n", link);
+}
+
+static void reset_link_statistic(void)
+{
+  if (r_linkp->action)
+    {
+      int r;
+      for (r = 0; r < r_linkp->action ; r++) {
+ reset_tipc_stat(r_linkp->action_list[r]);
+      }
+  }
+}
+
+static void request_link_statistic(char *mnl_s_buffer,
+   struct mnl_socket **nls,
+   struct nlmsghdr **nlh,
+   time_t *nlSeq)
+{
+
+  nl_prep_msg(nlh,
+      mnl_s_buffer,
+      get_tipc_family(),
+      NLM_F_REQUEST | NLM_F_DUMP,
+      TIPC_NL_LINK_GET,
+      nlSeq);
+  nl_send_msg(nls,
+      *nlh,
+      NETLINK_GENERIC,
+      MNL_SOCKET_AUTOPID);
+ }
+
+static void handle_l1_uc(void)
+{
+
+  int i;
+  l1_w_conf.counter++;
+
+  for (i = 0; i < uc_links; i++) {
+    int j = insert_link(uc_samples[i].link_info.link,
+ "L1_W", /*Not used*/
+ uc_add_link,
+ l1_w_conf.nos,
+ l1_dp);
+
+    l1_unicast_sample(j, i, uc_dp, l1_dp);
+
+    if ( (first_sample[i] == 0) && ( (stat_index + 1) % l0_w_conf.nos ) ==
0 )
+      first_sample[i] = 1;
+
+    if (l0_w_conf.window_passed)
+      IF_WATCH(w_linkp->action,
+       ((look_up_link_index(uc_dp->samples[i].link_info.link,
+    w_linkp->action_list,  w_linkp->action)) >= 0),
+       link_quality(i, l1_dp, uc_dp));
+  }
+
+  if (l0_w_conf.one_shot)
+    l1_stat_index++;
+  else
+    l1_stat_index = ( l1_stat_index + 1 ) % l1_w_conf.nos;
+
+  if (l1_w_conf.counter > l1_w_conf.nos)
+    l1_w_conf.window_passed = true;
+}
+
+static int link_get_stat_cb(const struct nlmsghdr *nlh, void *data)
+{
+  const char *name;
+  const char *link_state;
+  struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+  struct nlattr *attrs[TIPC_NLA_MAX + 1] = {};
+  struct nlattr *info[TIPC_NLA_LINK_MAX + 1] = {};
+  struct nlattr *prop[TIPC_NLA_PROP_MAX + 1] = {};
+  struct nlattr *stats[TIPC_NLA_STATS_MAX + 1] = {};
+  int link = 0;
+
+  mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
+  if (!info[TIPC_NLA_LINK])
+    return MNL_CB_ERROR;
+
+  mnl_attr_parse_nested(info[TIPC_NLA_LINK], parse_attrs, attrs);
+
+  if (!attrs[TIPC_NLA_LINK_NAME] ||
+      !attrs[TIPC_NLA_LINK_PROP] ||
+      !attrs[TIPC_NLA_LINK_STATS])
+    return MNL_CB_ERROR;
+
+  mnl_attr_parse_nested(attrs[TIPC_NLA_LINK_PROP], parse_attrs, prop);
+  mnl_attr_parse_nested(attrs[TIPC_NLA_LINK_STATS], parse_attrs, stats);
+
+  name = mnl_attr_get_str(attrs[TIPC_NLA_LINK_NAME]);
+
+  if (attrs[TIPC_NLA_LINK_BROADCAST])
+    return 1;
+
+  if (attrs[TIPC_NLA_LINK_ACTIVE])
+    link_state = "ACTIVE";
+  else if (attrs[TIPC_NLA_LINK_UP])
+    link_state = "STANDBY";
+  else
+    link_state = "DEFUNCT";
+
+  link = insert_link(name, link_state, uc_add_link, l0_w_conf.nos, uc_dp);
+
+  return unicast_sample(attrs, prop,
+ stats, link,
+ uc_dp, name);
+}
+
+static void handle_statistic_fd(struct mnl_socket **nls,
+ time_t **nlSeq)
+{
+  static int  counter=0;
+
+  nl_rcv_msg(*nls, link_get_stat_cb, NULL, *nlSeq);
+  counter++;
+  printf("Total # of samples: %d \n", counter);
+  if( counter > ( l0_w_conf.nos - 1 ))
+    {
+      l0_w_conf.window_passed = true;
+      handle_l1_uc();
+    }
+  else
+    {
+      /*skip so far*/
+      ;
+    }
+}
+
+static void handle_topsrv_sd(struct tipc_event *tipc_evt)
+{
+
+  if (recv(topsrv_sd, tipc_evt, sizeof(*tipc_evt), 0) == sizeof(*tipc_evt))
+    {
+    switch (ntohl((*tipc_evt).s.seq.type))
+      {
+      case TIPC_CFG_SRV:
+ if (ntohl(tipc_evt->port.node) == this_node)
+  return;
+ /* fall through*/
+      case TIPC_LINK_STATE:
+ log_event(topsrv_sd, tipc_evt);
+ break;
+      default:
+ syslog(LOG_WARNING, "Unknown event received: %d", (*tipc_evt).s.seq.type);
+ break;
+      }
+  }
+}
+
+static void handle_select(time_t *nlSeq,
+  struct nlmsghdr **nlh,
+  struct mnl_socket *nls)
+{
+  int link, err = 0;
+  fd_set fds;
+  struct tipc_event tipc_evt = {0};
+  time_t the_time = time(NULL);
+  /* If threadsafe is wished, use localtime_r*/
+  struct tm *tm = localtime(&the_time);
+  strftime(start_time, sizeof(start_time),"%Y-%B-%d:%H:%M:%S",tm);
+  stat_index = 0;
+  l1_stat_index = 0;
+
+  while (stat_index < l0_w_conf.nos ) {
+    FD_ZERO(&fds);
+    FD_SET((nls)->fd, &fds);
+    FD_SET(timer_fd, &fds);
+    FD_SET(topsrv_sd, &fds);
+    if ((err = select(FD_SETSIZE, &fds, NULL, NULL, NULL)) < 0)
+      {
+ if ( err == -1 && errno == EINTR)
+  continue;
+ syslog(LOG_ERR, "select: Failed, %s", strerror(errno));
+ exit(-1);
+      }
+    /* Accept only one print at a time, dirty?*/
+    if(take_sample)
+      {
+ handle_print_to_file();
+ take_sample = false;
+      }
+    if (FD_ISSET((nls)->fd, &fds))
+      {
+      printf("\033[2J\033[;H");
+
+      handle_statistic_fd(&nls,
+  &nlSeq);
+
+      if (l0_w_conf.one_shot)
+ {
+  stat_index++;
+ }
+      else
+ stat_index = (stat_index + 1) % l0_w_conf.nos;
+    }
+
+    if (FD_ISSET(topsrv_sd, &fds))
+      {
+ handle_topsrv_sd(&tipc_evt);
+      }
+
+    if (FD_ISSET(timer_fd, &fds))
+      {
+ /*
+  If the timer has expired one or more times since its
+  settings were last modified using timerfd_settime(), or since
+  the last successful read(2), then the buffer given to read(2)
+  returns an unsigned 8-byte integer (uint64_t) containing the
+  number of expirations that have occurred.
+  Do this dummy read to get select happy!!!
+ */
+ uint64_t dummy;
+ if (read(timer_fd, &dummy, sizeof(dummy)) < 0) {
+  syslog(LOG_ERR, "read: Failed to read %d, %s",
+ timer_fd, strerror(errno));
+  exit(-1);
+ }
+
+ if (mnl_socket_sendto(nls, *nlh, (*nlh)->nlmsg_len) < 0)
+  {
+    syslog(LOG_ERR, "mnl_socket_sendto: Failed, %s", strerror(errno));
+    exit(-1);
+  }
+
+ for (link = 0; link < uc_links; link++) {
+  if ((uc_dp->samples)[link].link_state.count_down)
+    {
+      (uc_dp->samples)[link].link_state.count_down--;
+      break;
+    }
+ }
+      }
+  }
+}
+
+/*FIXME: call the function when process terminats with non zero exit()*/
+static void free_resources(struct mnl_socket *nls)
+{
+  if (nls)
+    mnl_socket_close(nls);
+  if (topsrv_sd)
+    shutdown(topsrv_sd, SHUT_RDWR);
+  if (uc_samples)
+    free(uc_samples);
+  if (uc_tot_mem)
+    free(uc_tot_mem);
+  //if(LOCKFILE) /*FIXME the check of lockfile*/
+  unlink(LOCKFILE);
+}
+
+/* Thank you a lots W. Richie S.! */
+int main(int argc, char *argv[])
+{
+  struct mnl_socket *nls;
+  struct nlmsghdr *nlh;
+  char mnl_s_buffer[MNL_SOCKET_BUFFER_SIZE];
+  time_t nlSeq;
+  char *cmd = strrchr(argv[0], '/');
+  cmd = cmd ? 1+cmd : argv[0];
+
+  handle_opts(argc, argv);
+
+  daemonize_me(cmd);
+
+  syslog(LOG_INFO, "The TIPC Network Daemon has started");
+
+  printf("\033[2J\033[;H");
+
+  handle_signals();
+  /* Subsrcibe for all link and node events! No Zero div problem?!*/
+  topsrv_subscibe(tipc_events, sizeof(tipc_events)/sizeof(tipc_events[0]));
+
+  setup_sample_timer();
+
+  reset_link_statistic();
+
+  request_link_statistic(mnl_s_buffer, &nls, &nlh, &nlSeq);
+
+  handle_select(&nlSeq, &nlh, nls);
+
+  handle_print_to_file();
+
+  free_resources(nls);
+  syslog(LOG_INFO, "The TIPC Network Daemon has terminated");
+  exit(0);
+}


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
tipc-discussion mailing list
tipc-discussion@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tipc-discussion

Reply via email to