3.3.11 IPAddressWatcher

 On the latest Motif++ 1.0.6, we have introduced a very primitve Model-View update model on View class. By using the model, we can easily write a mixed program of an OZ++ Thread class and Motif++ GUI classes.
 Please note that the libraries of Open Motif 2.1 (and later) are thread-safe(See: Open Motif Overview).
 The following IPAddressWatcher program is an example to display some IPAddress information retrieved by IPAddressWatcher thread on TableView.
This sample program is built on two classes IPAddressWatcher(Thread), and MainView(ApplicationView).

The IPAddressWatcher will do the following:
1. Connect to the Linux kernel by a socketNetlink
2. Receive IPAddress information through the sokcet,
3. Get a propertyList corresponding to the IPAddress information.
4, Call updateModel method of the MainView with the propertyList.
5. Return 2 procedure to receive more information.

When the updatedModel method of MainView called, MainView will do the following:
1. Update the model variable of MainView by the propertyList passed from IPAddressWatcher.
2. Call updateView method of MainView after the model update operation.
3. Update all items of the first column of the table by the updated model variable.




//
//IPAddressWatcher.cpp
//Copyright (c) 2015 Antillia.com TOSHIYUKI ARAI. ALL RIGHTS RESERVED.

#include <oz++/CommonObject.h>
#include <oz++/LocalDateTime.h>
#include <oz++/Exception.h>
#include <oz++/SmartArray.h>
#include <oz++/Thread.h>
#include <oz++/CharString.h>
#include <oz++/LinkedList.h>
#include <oz++/Property.h>

#include <oz++/netlink/SocketNetlink.h>
#include <oz++/netlink/SockAddrNetlink.h>
#include <oz++/netlink/NetlinkReply.h>
#include <oz++/netlink/NetlinkMsgHeader.h>
#include <oz++/netlink/InterfaceAddrAttribute.h>
#include <oz++/netlink/InterfaceAddrMsg.h>


#include <oz++/motif/ApplicationView.h>
#include <oz++/motif/TableView.h>


namespace OZ {

class IPAddressWatcher: public Thread {

private:
  View*                    view; //Shallow copy
  int                      rtmGroups;
  SocketNetlink            socketNetlink;
  NetlinkReply<ifaddrmsg>  reply;
  bool                     looping;
    
public:
  IPAddressWatcher(View* v, int group = RTMGRP_IPV4_IFADDR) 
                           //|RTMGRP_IPV6_IFADDR)
  :view(v),
  rtmGroups(group)
  {
    looping = true;
  }
    
  int bind()
  {
    SockAddrNetlink  addrNetlink;
    addrNetlink.setFamily(AF_NETLINK);
    addrNetlink.setGroups(rtmGroups);
    return socketNetlink.bind(addrNetlink);
  }
    
  void recv()
  {
    while (looping) {
      bzero(&reply, sizeof(reply));

      int n = socketNetlink.recv((char*)&reply, sizeof(reply), 0);
      if ( n < 0 ){
        perror("recv");
        break;
      }
      try {         

        NetlinkMsgHeader netlinkMsgHeader(&reply.head);
        if (netlinkMsgHeader.isDone() || netlinkMsgHeader.isError()) {
          break;
        }

        do {
          LocalDateTime dateTime;
          CharString now = dateTime.nowToSeconds();
          InterfaceAddrMsg addrMsg(&reply.body);
      
          InterfaceAddrAttribute attribute(netlinkMsgHeader, addrMsg);
        
          do {
            attribute.parse();
          } while (attribute.next() );
            
          LinkedListT<Property> list;
          list.add(new Property("DateTime", (const char*)now) );
          addrMsg.getPropertyList(list);
            
          //Call updateModel                
          view -> updateModel(&list);
            
        } while (netlinkMsgHeader.next());
        
      } catch (Exception& ex) {
        ex.display();   
      }
      fflush(stdout);       
    }
  }

  void stop()
  {
    looping = false;
    socketNetlink.close();
  }

  //Thread main procedure method
  void run()
  {
    try {
      this -> bind();
      this -> recv();
    } catch (Exception& ex) {
      ex.display();   
    }
  }
};
    

class MainView :public ApplicationView {
private:
  SmartPtr<TableView>        table;
  SmartArray<CharString*>    model;
  SmartPtr<IPAddressWatcher> watcher;
  
private:
  virtual void updateModel(CommonObject* object)
  {
    if (object) {
      //Update model
      LinkedListT<Property>* list = (LinkedListT<Property>*)object;
      model.removeAllItems();
      size_t size = list->getLength();
      for (size_t i = 0; i < size; i++) {
        Property* prop = list->getNth(i);
        model[i] = new CharString(prop -> value());
      }
      //Call updateView
      updateView();
    }
  }

  virtual void updateView()
  {
    table -> removeAllItems();

    int size = model.getSize();
    for (int i = 0; i<size; i++) {
      CharString* value = model[i];
      if (value) {
        printf("%d %s\n", i, (const char*)(*value));
        table -> setItem(i, 0, (const char*)(*value));
      }
    }
    // Call flush to update items of the table immediately. 
    flush();
  }

public:
  MainView(Application& applet, const char* name, Args& args)
  :ApplicationView(applet, name, args),
  table(NULL)
  {
    ColumnData columnData[]  = {
      {"Value", 500, XmALIGNMENT_BEGINNING}, 
    };

    RowData rowData[]  = {
    {"DateTime",          160, XmALIGNMENT_BEGINNING},
    {"IFADDR family",     0, XmALIGNMENT_BEGINNING},
    {"IFADDR prefixlen",  0, XmALIGNMENT_BEGINNING},
    {"IFADDR flags",      0, XmALIGNMENT_BEGINNING},
    {"IFADDR scope",      0, XmALIGNMENT_BEGINNING},
    {"IFADDR index",      0, XmALIGNMENT_BEGINNING},
    {"IFA_ADDRESS",       0, XmALIGNMENT_BEGINNING},
    {"IFA_LOCAL",         0, XmALIGNMENT_BEGINNING},
    {"IFA_LABEL",         0, XmALIGNMENT_BEGINNING},
    {"IFA_BROADCAST",     0, XmALIGNMENT_BEGINNING},
    {"IFA_ANYCAST",       0, XmALIGNMENT_BEGINNING},
    {"IFA_CACHEINFO",     0, XmALIGNMENT_BEGINNING},
    {"IFA_MULTICAST",     0, XmALIGNMENT_BEGINNING},
    };

    int numColumns = XtNumber(columnData);
    int numRows    = XtNumber(rowData);

    Args ar;
    ar.set(XmNtableNumColumns, numColumns);
    ar.set(XmNtableColumnData, (XtArgVal)columnData);
    ar.set(XmNtableNumRows, numRows);
    ar.set(XmNtableRowData, (XtArgVal)rowData);
    table = new TableView(this, "", ar);
    table -> removeAllItems();

    watcher = new IPAddressWatcher(this);
    watcher -> start();
  }
  
  ~MainView() 
  {
    watcher -> cancel();
    watcher -> wait();

    model.clear();
  }
};
}

//
int main(int argc, char** argv)
{
  XInitThreads(); //2015/06/10

  try {
    const char*  appclass = argv[0];
    Application applet(appclass, argc, argv);
    Args args;
    args.set(XmNgeometry, "700x300");
    MainView view(applet, argv[0], args);
    
    view.realize();
    applet.run();
    
  } catch (Exception& ex) {
    ex.display(); 
  }
  return 0;
}


Last modified: 1 Jan 2017

 Last modified: 1 Jan 2017

Copyright (c) 2000-2017 Antillia.com ALL RIGHTS RESERVED.