Implement network monitor

This commit listens for the ipaddress add event
and prints the message once it gets the NEWADDR
signal.

Change-Id: I5cdebc023dc8848fc736eca8d785c33387d401df
Signed-off-by: Ratan Gupta <ratagupt@in.ibm.com>
diff --git a/Makefile.am b/Makefile.am
index 8135e16..aacb465 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5,7 +5,6 @@
 
 sbin_PROGRAMS = netman_watch_dns phosphor-network-manager
 
-
 netman_watch_dns_SOURCES = netman_watch_dns.c
 netman_watch_dns_LDFLAGS = $(SYSTEMD_LIBS)
 netman_watch_dns_CFLAGS = $(SYSTEMD_CFLAGS)
@@ -21,7 +20,8 @@
 		config_parser.hpp \
 		system_configuration.hpp \
 		dhcp_configuration.hpp \
-        vlan_interface.hpp
+		vlan_interface.hpp \
+		rtnetlink_server.hpp
 
 phosphor_network_manager_SOURCES = \
 		ethernet_interface.cpp \
@@ -36,7 +36,8 @@
 		routing_table.cpp \
 		config_parser.cpp \
 		dhcp_configuration.cpp \
-        vlan_interface.cpp
+        vlan_interface.cpp \
+		rtnetlink_server.cpp
 
 CLEANFILES = \
 		xyz/openbmc_project/Network/VLAN/Create/server.cpp \
diff --git a/network_manager_main.cpp b/network_manager_main.cpp
index 461ddd6..993efc7 100644
--- a/network_manager_main.cpp
+++ b/network_manager_main.cpp
@@ -1,26 +1,56 @@
+#include "network_manager.hpp"
+#include "rtnetlink_server.hpp"
+
+#include <memory>
+
+#include <phosphor-logging/log.hpp>
 #include <sdbusplus/bus.hpp>
 #include <sdbusplus/server/manager.hpp>
-#include "config.h"
-#include "network_manager.hpp"
+
+namespace phosphor
+{
+namespace network
+{
+
+std::unique_ptr<phosphor::network::Manager> manager = nullptr;
+
+} //namespace network
+} //namespace phosphor
 
 int main(int argc, char *argv[])
 {
+    using namespace phosphor::logging;
+
     auto bus = sdbusplus::bus::new_default();
 
+    // Need sd_event to watch for OCC device errors
+    sd_event* event = nullptr;
+    auto r = sd_event_default(&event);
+    if (r < 0)
+    {
+        log<level::ERR>("Error creating a default sd_event handler");
+        return r;
+    }
+
+    phosphor::network::EventPtr eventPtr{event};
+    event = nullptr;
+
+    // Attach the bus to sd_event to service user requests
+    bus.attach_event(eventPtr.get(), SD_EVENT_PRIORITY_NORMAL);
+
     // Add sdbusplus Object Manager for the 'root' path of the network manager.
     sdbusplus::server::manager::manager objManager(bus, OBJ_NETWORK);
     bus.request_name(BUSNAME_NETWORK);
 
-    phosphor::network::Manager manager(bus, OBJ_NETWORK, NETWORK_CONF_DIR);
+    phosphor::network::manager =
+            std::make_unique<phosphor::network::Manager>(bus,
+                                                         OBJ_NETWORK,
+                                                         NETWORK_CONF_DIR);
 
-    manager.createChildObjects();
+    phosphor::network::rtnetlink::Server svr(eventPtr);
+
+    phosphor::network::manager->createChildObjects();
 
 
-    while(true)
-    {
-        bus.process_discard();
-        bus.wait();
-    }
-
-    return 0;
+    return svr.run();
 }
diff --git a/rtnetlink_server.cpp b/rtnetlink_server.cpp
new file mode 100644
index 0000000..d3cac19
--- /dev/null
+++ b/rtnetlink_server.cpp
@@ -0,0 +1,144 @@
+#include "xyz/openbmc_project/Common/error.hpp"
+#include "rtnetlink_server.hpp"
+#include "types.hpp"
+#include "util.hpp"
+
+
+#include <netinet/in.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <net/if.h>
+#include <sys/types.h>
+#include <systemd/sd-daemon.h>
+#include <unistd.h>
+
+#include <phosphor-logging/log.hpp>
+#include <phosphor-logging/elog-errors.hpp>
+
+#include <memory>
+#include <iostream>
+
+namespace phosphor
+{
+namespace network
+{
+namespace rtnetlink
+{
+
+/* Call Back for the sd event loop */
+static int eventHandler(sd_event_source* es, int fd, uint32_t revents,
+                        void* userdata)
+{
+    char buffer[phosphor::network::rtnetlink::BUFSIZE] {};
+    int len {};
+
+    auto netLinkHeader = reinterpret_cast<struct nlmsghdr*>(buffer);
+    while ((len = recv(fd, netLinkHeader,
+                        phosphor::network::rtnetlink::BUFSIZE, 0)) > 0)
+    {
+        for (; (NLMSG_OK(netLinkHeader, len)) &&
+               (netLinkHeader->nlmsg_type != NLMSG_DONE);
+                    netLinkHeader = NLMSG_NEXT(netLinkHeader, len))
+        {
+            if (netLinkHeader->nlmsg_type == RTM_NEWADDR ||
+                netLinkHeader->nlmsg_type == RTM_DELADDR)
+            {
+                // TODO delete the below trace in later commit.
+                std::cout << "Address Changed\n";
+
+            } // end if
+
+        } // end for
+
+    } // end while
+
+    return 0;
+}
+
+
+int Server::run()
+{
+    using namespace phosphor::logging;
+
+    struct sockaddr_nl addr {};
+
+    int fd = -1;
+    phosphor::Descriptor smartSock(fd);
+
+    int r {};
+
+    sigset_t ss {};
+
+
+    if (sigemptyset(&ss) < 0 || sigaddset(&ss, SIGTERM) < 0 ||
+        sigaddset(&ss, SIGINT) < 0)
+    {
+        r = -errno;
+        goto finish;
+    }
+    /* Block SIGTERM first, so that the event loop can handle it */
+    if (sigprocmask(SIG_BLOCK, &ss, NULL) < 0)
+    {
+        r = -errno;
+        goto finish;
+    }
+
+    /* Let's make use of the default handler and "floating"
+       reference features of sd_event_add_signal() */
+
+    r = sd_event_add_signal(eventPtr.get(), NULL, SIGTERM, NULL, NULL);
+    if (r < 0)
+    {
+        goto finish;
+    }
+
+    r = sd_event_add_signal(eventPtr.get(), NULL, SIGINT, NULL, NULL);
+    if (r < 0)
+    {
+        goto finish;
+    }
+
+    fd = socket(PF_NETLINK, SOCK_RAW | SOCK_NONBLOCK, NETLINK_ROUTE);
+    if (fd < 0)
+    {
+        r = -errno;
+        goto finish;
+    }
+
+    smartSock.set(fd);
+    fd = -1;
+
+    memset(&addr, 0, sizeof(addr));
+    addr.nl_family = AF_NETLINK;
+    addr.nl_groups = RTMGRP_IPV4_IFADDR;
+
+    if (bind(smartSock(), (struct sockaddr*)&addr, sizeof(addr)) < 0)
+    {
+        r = -errno;
+        goto finish;
+    }
+
+    r = sd_event_add_io(eventPtr.get(), nullptr,
+                        smartSock(), EPOLLIN, eventHandler, nullptr);
+    if (r < 0)
+    {
+        goto finish;
+    }
+
+    r = sd_event_loop(eventPtr.get());
+
+finish:
+
+    if (r < 0)
+    {
+        log<level::ERR>("Failure Occured in starting of server:",
+                        entry("errno = %d", errno));
+    }
+
+    return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
+
+} //rtnetlink
+} //network
+} //phosphor
diff --git a/rtnetlink_server.hpp b/rtnetlink_server.hpp
new file mode 100644
index 0000000..51cf7bb
--- /dev/null
+++ b/rtnetlink_server.hpp
@@ -0,0 +1,55 @@
+#pragma once
+
+#include "types.hpp"
+
+#include <systemd/sd-event.h>
+
+namespace phosphor
+{
+namespace network
+{
+namespace rtnetlink
+{
+
+constexpr auto BUFSIZE = 4096;
+
+/** General rtnetlink server which waits for the POLLIN event
+    and calls the  call back once it gets the event.
+    Usage would be create the server with the  call back
+    and call the run method.
+ */
+
+class Server
+{
+
+    public:
+
+        /** @brief Constructor
+         *
+         *  @param[in] event - Unique ptr reference to sd_event.
+         */
+
+        Server(EventPtr& event):
+            eventPtr(event) {};
+
+        Server(const Server&) = delete;
+        Server& operator=(const Server&) = delete;
+        Server(Server&&) = default;
+        Server& operator=(Server &&) = default;
+
+        /** @brief Initialise the event loop and add the handler for incoming
+         *         RTNETLINK events.
+         *
+         *  @return EXIT_SUCCESS on success and EXIT_FAILURE on failure.
+         */
+        int run();
+
+    private:
+        /** @brief reference to sd_event wrapped in unique_ptr */
+        EventPtr& eventPtr;
+
+};
+
+} //namespace rtnetlink
+} //namespce network
+} //namespace phosphor
diff --git a/types.hpp b/types.hpp
index eb1f9fe..e792a3e 100644
--- a/types.hpp
+++ b/types.hpp
@@ -8,6 +8,8 @@
 #include <map>
 #include <memory>
 
+#include <systemd/sd-event.h>
+
 namespace phosphor
 {
 namespace network
@@ -44,6 +46,18 @@
 
 using AddrPtr = std::unique_ptr<ifaddrs, AddrDeleter>;
 
+/* Need a custom deleter for freeing up sd_event */
+struct EventDeleter
+{
+    void operator()(sd_event* event) const
+    {
+        event = sd_event_unref(event);
+    }
+};
+using EventPtr = std::unique_ptr<sd_event, EventDeleter>;
+
+template<typename T>
+using UniquePtr = std::unique_ptr<T, std::function<void(T*)>>;
 
 using AddrList = std::list<AddrInfo>;
 using IntfAddrMap = std::map<IntfName, AddrList>;
diff --git a/util.hpp b/util.hpp
index 2d5c3f3..4a9d5f7 100644
--- a/util.hpp
+++ b/util.hpp
@@ -165,6 +165,27 @@
 
         Descriptor(int fd) : fd(fd) {}
 
+        /* @brief sets the internal file descriptor with the given descriptor
+         *        and closes the old descriptor.
+         * @param[in] descriptor - File/Socket descriptor.
+         */
+        void set(int descriptor)
+        {
+            // same descriptor given
+            if (fd == descriptor)
+            {
+               return;
+            }
+
+            // close the old descriptor
+            if (fd >= 0)
+            {
+                close(fd);
+            }
+
+            fd = descriptor;
+        }
+
         ~Descriptor()
         {
             if (fd >= 0)