[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: C on ns




   Sender: [email protected]
   Date: Mon, 01 Dec 1997 15:58:52 +0100
   From: Arioli Carlo <[email protected]>
   Reply-To: [email protected]
   Organization: CEFRIEL

   I'm a new users who should  start a project for my own degree thesys
   using
   ns as a simulator. The problem I need to solve is whether it is
   possible to include a code  written in C for an agenet on a node of ns
   simulator.
   Where can I find some information on this procedure ?? I'm new and I
   wanto to know
   whether it is possible to use ns for my purpose . Thank you very much to
   anybody who could help me


I've actually just done this.  I have reliable multicast code based on
IMM that I rewrote in C.  In order to intergrate it into NS, I created
a base class derived from Agent that had all of the NS stuff in it.
That code then just calls the C code.  The only little annoyance was
calling C++ from C.  I couldn't get it to work the way I wanted it to
due to the name mangling, so I had to hack around it with #defines.
You probably just need the Sudafed class.  The MiniSched is used to
interface with some event driven stuff I have in my live code.

In my C code, I had to add the following define for example:

    #ifdef SIMULATOR
    #undef event_post
    #define event_post(args...) event_post__FPvPFv_ide(src->agent, ## args)
    #endif

in order to call the event_post() function defined below.

The nice part of all of this is that my code now works in NS or live
with the same core source files.

I've included the C++ code below.
----------------------------------------------------------------------------
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdarg.h>

#include <stdio.h>
#include "tclcl.h"
#include "agent.h"
#include "packet.h"
#include "ip.h"
#include "rtp.h"
#include "trace.h"
#include "random.h"

extern "C" 
{
#include "cqueue.h"
#include "list.h"
#include "log.h"
#include "congestion.h"
#include "imm-protocol.h"
#include "imm.h"
#include "action.h"

int ns_send_buffer (void *agent, char *buffer, int length);

void event_cancel (void *agent, Action *action);

void *event_post (void *agent, int (*action) (), TIME how_soon, ...);
double unit_variate ();

}

#define CURRENT_TIME       Scheduler::instance().clock()

double current_time;

class SudafedAgent;

class MiniSched : public TimerHandler 
{
public: 
  //  MiniSched(SudafedAgent *a) : queue (NULL), TimerHandler() { a_ = a; }
  MiniSched(SudafedAgent *a) : queue (NULL), TimerHandler() { a_ = a; }
  Action *va_post (int func(), double time, va_list ap);
  void reschedule ();
  void cancel (Action *a);
  void print ();
protected:
  void expire(Event *e);
  Action *queue;
  SudafedAgent *a_;
};

class SudafedAgent : public Agent 
{
protected:
  RMSource *rm_source;
  RMReceiver *rm_receiver;
  void sendpkt();
  int off_cmn_;
  int off_rtp;
  int i_am_a_server;

public:
  MiniSched mini_sched;
  SudafedAgent();
  int command(int argc, const char*const* argv);
  void recv(Packet* p, Handler* h);
  void send_packet (unsigned char *buffer, int length);

};


static class SudafedAgentClass : public TclClass {
public:
        SudafedAgentClass() : TclClass("Agent/Sudafed") {}
        TclObject* create(int, const char*const*) {
		return (new SudafedAgent());
	}
} class_Sudafed_agent;


SudafedAgent::SudafedAgent() 
        : Agent(PT_RTP),
	  mini_sched(this),
	  rm_source(NULL)
{
	bind("off_cmn_", &off_cmn_);
	/*	bind("packetSize_", &packetSize_);*/
	rm_receiver = rm_receiver_new ();
	rm_receiver->addr = addr_;
	rm_receiver->agent = this;
}

void
SudafedAgent::send_packet (unsigned char *buffer, int length)
{
  Packet* p = Agent::allocpkt(length);
  unsigned char *data = p->accessdata();
  hdr_cmn* ch = (hdr_cmn*) p->access(off_cmn_);

  memcpy (data, buffer, length);

  ch->size() = length;

  send (p, 0);
}

void 
SudafedAgent::recv(Packet* p, Handler* h)
{
  hdr_ip*  ih = (hdr_ip*) p->access(off_ip_);
  hdr_cmn* ch = (hdr_cmn*) p->access(off_cmn_);
  unsigned char *data = p->accessdata();
  int length = ch->size();

  current_time = CURRENT_TIME;

  if (ih->src () == addr_)
    return;
  
  if (rm_source)
    {
      rm_receiver->addr = addr_;
      imm_server_receive (rm_source, &ih->src(), data, length);
    }
  else
    {
      rm_receiver->addr = addr_;
      imm_client_receive (rm_receiver, &ih->src(), data, length);
    }
  Packet::free (p);
}


int 
SudafedAgent::command(int argc, const char*const* argv)
{
  Tcl& tcl = Tcl::instance();
  
  /*  current_time = CURRENT_TIME;*/

  if (argc == 2) 
    {
      if (strcmp(argv[1], "start") == 0) 
	{
	  // deliver ("foo", "bar", 1024*32, 0, 20);
	  return (TCL_OK);
	}
      if (strcmp(argv[1], "stop") == 0) 
	{
	  //		stop();
	  return (TCL_OK);
	}
    } if (argc == 3) 
      {
	int size;
	if (strcmp (argv[1], "send-file") == 0)
	  {
	    if (rm_source == NULL)
	      {
		rm_source = rm_source_new ();
		rm_source->addr = addr_;
		rm_source->dest = dst_;
		rm_source->agent = this;
	      }
	    imm_send_file_or_directory (rm_source, argv[2]);
	    return (TCL_OK);
	  }
      }
    return Agent::command(argc, argv);
}

void
MiniSched::print ()
{
  Action **p;

  printf ("MiniSched 0x%x", this);

  for (p = &queue; *p != 0; p = &(*p)->next)
    {
      printf ("\n ");
      action_print (*p);
    }
  printf ("\n");
}

Action * 
MiniSched::va_post (int func(), double time, va_list ap)
{
  Action** p;
  Action *action;
  double t;

  //  printf ("MiniSched:va_post start\n");
  //  print();

  action = va_action_new (time, func, ap);


  /* insert action into list */

  t = action->time;
  for (p = &queue; *p != 0; p = &(*p)->next)
    if (t < (*p)->time)
      break;
  action->next = *p;
  *p = action;
  
  if (queue == action)
    reschedule ();

  //  printf ("MiniSched:va_post finish\n");
  //  print();

  return (action);
}

void
MiniSched::cancel(Action *a)
{
  Action** p;
  //  printf ("MiniSched::cancel\n");
  //  print();
  for (p = &queue; *p != a; p = &(*p)->next)
    if (*p == 0)
      abort();

  *p = (*p)->next;
  action_free (a);
  reschedule ();
  //  printf ("MiniSched::cancel(after)\n");
  //  print();
}

// schedule the first thing in the list 
void
MiniSched::reschedule ()
{
  double delay;

  if (queue)
    {
      delay = queue->time - current_time;
      resched (delay);
    }
  else
    {
      TimerHandler::cancel();
    }
}

void
MiniSched::expire (Event *e)
{
  Action *action;
  /* since we expired, there must be something on the queue.  Take
   * the first thing and do it.
   */

  current_time = CURRENT_TIME;

  action = queue;
  queue = action->next;
  action->next = NULL;
  action_execute (action);
  action_free (action);
  if (queue)
    reschedule ();
}

/* some glue functions for C.  Requires bizzare #defines in localdefs.h 
 * to handle name mangeling.
 */

void *
event_post (void *agent, int (*action) (), TIME how_soon, ...)
{
  SudafedAgent *a = (SudafedAgent *)agent;
  void *result;
  va_list ap;

  va_start (ap, how_soon);
  result = a->mini_sched.va_post(action, how_soon, ap);
  va_end (ap);

  return (result);
}

void
event_cancel (void *agent, Action *action)
{
  SudafedAgent *a = (SudafedAgent *)agent;
  a->mini_sched.cancel (action);
}
int
ns_send_buffer (void *agent, unsigned char *buffer, int length)
{
  SudafedAgent *a = (SudafedAgent *)agent;

  a->send_packet (buffer, length);

  return (length);
}

double
unit_variate ()
{
  return Random::uniform();
}