How to Get/Set a variable at the run-time?

 

[Background]

  Refer to the section 2.1.3 in the DeveloperManual.pdf for advanced information. But in that document, it teaches you to use “EXPORT” function to register the variables that you are interested in. And then modify the module description file in order to get/set a variable at the run-time. Take the following scenario as an example. Node 2 is using stg program to send packets to Node 3. If we are interested in the current queue length in the Node 2, we have to do the following procedures: “Simulation/Run”->Node 2->Node editor->FIFO->GET (Current Queue Length) in the Run Time Query group. It takes time and many procedures to achieve what we want. Therefore, I will introduce another method. With this method, you can get/set the information at the time exactly at any time you want during simulation.

 

 

 

  In this example, I will show how to write a simple TCP-based socket program that can directly talk to simulation engine (S.E). When the program is connected to S.E, we can ask .SE to get/set a variable registered in a module.

 

[Preparation]

 In this example, I still use the FIFO module as the example. But take a look at the fifo.cc first. In the init() function, “cur-queue-length” and “max-queue-length” are both exported and can be accessed at the run-time. In the command() function, the Get for “cur-queue-length” and “max-queue-length” and Set for “max-queue-length” are implemented.

 

 

 

 

Refer to section 4.4 Dispatcher and Figure 4.2.5 in the DeveloperManual.pdf, we can see that the coordinator (C.O) opens a port for listening to tcsh command. The C.O can forward to the SE. But the Developer Manual does not explain it clearly. Therefore, I fail to use tcsh directly to talk to C.O and S.E. Luckily, I check the source code and find that the C.O open 9880 port for tcsh. Then I try to write my own TCP-based socket program to directly talk to C.O in order to get/set a variable status at the run-time. It works.

 

(dyn_get.c: a prototype for Get)

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <sys/time.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <time.h>

#include <netdb.h>

#include "nctuns_syscall.h"

 

int main(int argc, char *argv[])

{

  double mytime;

  struct timeval now;

  int sockfd;

  struct sockaddr_in server;

  int PORT=9880;

  char buf[100];

  struct hostent  *phe;

 

  memset(&server, '\0', sizeof(server));

  server.sin_family=AF_INET;

  server.sin_port=htons(PORT);

  phe=gethostbyname("127.0.0.1");

  memcpy(&server.sin_addr, phe->h_addr, phe->h_length);

 

  gettimeofday(&now, 0);

  mytime=(double)now.tv_sec+(double)now.tv_usec/1000000.0;

  printf("now: %lf\n", mytime);  

   

  if((sockfd=socket(AF_INET, SOCK_STREAM, 0))<0)

  {

     perror("socket");

     exit(1);

  } else {

     //printf("socket ok, sockfd=%d\n", sockfd);

  }

 

 /*This function internally calls a NCTUns system call to tell the kernel

        that the created socket should be treated differently from

        other sockets created for communication with other agent programs. */

 

  if(syscall_NCTUNS_cancel_socknodeID(sockfd)<0){

     printf("syscall_NCTUNS_cancel_socknodeID() fails\n");

     exit(1);

  }

 

  if(connect(sockfd, (struct sockaddr *) &server, sizeof(server))<0)

  {

      perror("connect");

      exit(1);

  } else {

      //printf("connect to server ok\n");

  }

 

  memset(buf, 0, sizeof(buf));

 

/* 2 means Node 2, 1 means port ID=1, of module FIFO. */

  sprintf(buf, "%s", "Get 2 1 FIFO cur-queue-length\n");

 

write(sockfd, buf, strlen(buf));

  close(sockfd);

  return 0;

}

 

(dyn_set.c: a prototype for Set)

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <sys/time.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <time.h>

#include "nctuns_syscall.h"

 

int main(int argc, char *argv[])

{

  double mytime;

  struct timeval now;

  int sockfd;

  struct sockaddr_in server;

  int PORT=9880;

  char buf[100];

 

  memset(&server, '\0', sizeof(server));

  server.sin_family=AF_INET;

  server.sin_port=htons(PORT);

  inet_aton("127.0.0.1", &server.sin_addr);

 

  gettimeofday(&now, 0);

  mytime=(double)now.tv_sec+(double)now.tv_usec/1000000.0;

  printf("now: %lf\n", mytime); 

  

  if((sockfd=socket(AF_INET, SOCK_STREAM, 0))<0)

  {

     perror("socket");

     exit(1);

  }

 

  if(syscall_NCTUNS_cancel_socknodeID(sockfd)<0){

     printf("syscall_NCTUNS_cancel_socknodeID() fails\n");

     exit(1);

  }

 

  if(connect(sockfd, (struct sockaddr *) &server, sizeof(server))<0)

  {

      perror("connect");

      exit(1);

  } else {

      //printf("connect to server ok\n");

  }

 

  memset(buf, 0, sizeof(buf));

 

 /* Set the max-queue-length to 10 packets in the port id 1 of Node 2 in the FIFO module */

  sprintf(buf, "%s", "Set 2 1 FIFO max-queue-length 10\n");

  printf("buf=%s\n", buf);

  write(sockfd, buf, strlen(buf));

 

  close(sockfd);

  return 0;

}

 

Before compiling these two programs, we have to copy nctuns_syscall.h from NCTUns-6.0/src/nctuns to the place you put these two programs.

 

Now refer to http://csie.nqu.edu.tw/smallko/nctuns/realap.htm to know how to insert dyn_get and dyn_set into NCTUNS.

 

[Simulation]

1.      Create a topology.

 

2.      Click “E” to edit property. (At 5.0, we use dyn_get to get the current queue length. At 10.0, we use dyn_set to set the max queue length to 10 packets at Node 2. At 11.0, we again use dyn_get to get the current queue length.)

 

3.      Click “R” and Simulation/Run to start simulation.

 

4.      When the simulation is execution, click the terminal that runs “coordinator” and you will see the messages like the following figures.

 

(At 5.0, we can see that “Get 2 1 FIFO cur-queue-length” is sent to S.E and then cur-queue-length=46 shown on the screen. The default value for max-queue-length is 50.)

 

(At 10, the dyn_set is executed and “Set 2 1 FIFO max-queu-length 10” is sent to S.E. At 11, the cur-queue-length=5 which is smaller than the max-queue-length 10.)

 

Dr. Chih-Heng Ke (http://csie.nqu.edu.tw/smallko), smallko@gmail.com

Department of Computer Science and Information Engineering, National Quemoy University, Taiwan