root/otg/trunk/src/cpp/otg.cpp

Revision 598, 11.1 KB (checked in by zhibinwu, 5 years ago)

adding clockref

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /***************************************************************************
2 * OTG: Orbit Traffic Generator
3 * Copyright (c) 2004,2005 
4 * Copyright (c) 2004,2005
5 *                                WINLAB, Rutgers University
6 * All rights reserved.
7 *
8 * Permission to use, copy, modify and distribute this software and its
9 * documentation is hereby granted, provided only with the following
10 * conditions are satisfied:
11 *
12 * 1. Both the copyright notice and this permission notice appear in
13 *    all copies of the software, derivative works or modified versions,
14 *    and any portions thereof, and that both notices appear in
15 *    supporting documentation.
16 * 2. All advertising materials mentioning features or use of this
17 *    software must display the following acknowledgement:
18 *      This product includes software developed by Nara Institute of
19 *      Science and Technology and its contributors.
20 * 3. Neither the name of Wireless INformation LABoratory nor
21 *    the names of its contributors may be used to endorse or promote
22 *    products derived from this software without specific prior written
23 *    permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND WINLAB
26 * DISCLAIMS ANY LIABILITY OF
27 * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
28 * THIS SOFTWARE. ALSO, THERE IS NO WARRANTY IMPLIED OR OTHERWISE,
29 * NOR IS SUPPORT PROVIDED.
30 *
31 * Feedback of the results generated from any improvements or
32 * extensions made to this software would be much appreciated.
33 * Any such feedback should be sent to:
34 *
35 *  Zhibin Wu
36 *  E-mail:  <zhibinwu@winlab.rutgers.edu>
37 *  URL:     <http://www.winlab.rutgers.edu/~zhibinwu>
38 *  Address: 73 Brett Rd.,
39 *           WINLAB
40 *           Piscataway, NJ 08854, USA
41 *
42 * WINLAB has the rights to redistribute these changes.
43 ***************************************************************************/
44
45#include <popt.h>
46#include <sys/time.h>
47#include <iostream>
48using namespace std;
49#include "stream.h"
50#include "address.h"
51#include "cbr_generator.h"
52#include "expo_generator.h"
53#include "sockport.h"
54#include "udpsock_port.h"
55#include "tcpsock_port.h"
56#include "etherport.h"
57#include "orbitapp.h"
58#include "otg_application.h"
59//#include "oml_orbit_winlab_otg.h"
60
61#include <pthread.h>
62
63#define STDIN 0
64#define MAX_INPUT_SIZE 256
65
66
67struct poptOption options_phase1[] = {
68  POPT_AUTOHELP
69  { "protocol", '\0', POPT_ARG_STRING, NULL, 0, "Name of protocol", "[tcp|udp|raw_packet]"},
70  { "generator", '\0', POPT_ARG_STRING, NULL, 0, "Name of generator", "[cbr|expoo]"},
71  { "debuglog", '\0',  POPT_ARG_STRING, NULL, 0, "Filename of Measurement Log", "[filename]"},
72  { "clockref", '\0',  POPT_ARG_INT, NULL, 0, "hours since 01/01/1970", "hours"},
73  { NULL, 0, 0, NULL, 0 }
74};
75
76
77/**
78 * Function to create a Generator based on the generator_name
79 * @param generator_name: generator name
80 * @return the generator created
81 */
82
83Generator*
84createGenerator(
85  char* generator_name
86) {
87  Generator* gen = NULL;   
88
89  if (strcmp(generator_name, "cbr") == 0 ){
90    gen = new CBR_Generator();
91  }else if(strcmp(generator_name, "expoo") == 0){
92    gen = new Expo_Generator();
93  }else {
94    cerr << "Error: Unknown Generator '" << generator_name << "'." << endl;
95    exit(-1);
96  } 
97  return gen;
98}
99
100
101struct poptOption options[] = {
102  POPT_AUTOHELP
103  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, NULL, 0, "Port" },
104  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, NULL, 0, "Generator" },
105  { "protocol", '\0', POPT_ARG_STRING, NULL, 0, "Name of protocol"},
106  { "generator", '\0', POPT_ARG_STRING, NULL, 0, "Name of generator"},
107  { "debuglog", '\0', POPT_ARG_STRING, NULL, 0, "Filename of Measurements Log"},
108  { "clockref", '\0',  POPT_ARG_INT, NULL, 0, "hours since 01/01/1970"},
109  { "exit", '\0', POPT_ARG_NONE, NULL, 1, "Stop the generator and exit" },
110  { "pause", '\0', POPT_ARG_NONE, NULL, 2, "pause the generator and exit" },
111  { "resume", '\0', POPT_ARG_NONE, NULL, 3, "resume the generator" },
112  { NULL, 0, 0, NULL, 0 }
113};
114
115
116/**
117 *  Parse options for phase 1: Protocol and Generator Type
118 *  @param argc:
119 *  @param argv:
120 *  @param protocol_name: protocol type
121 *  @param gt: generator type:
122 */
123void parseOptionsPhase1(
124int argc, 
125const char * argv[], 
126char** protocol_name, 
127char** generator_name, 
128char** log_name,
129int* clockref
130){ 
131 
132  options_phase1[1].arg = protocol_name;
133  options_phase1[2].arg = generator_name;
134  options_phase1[3].arg = log_name;
135  options_phase1[4].arg = clockref; 
136  int rc;
137  poptContext optCon = poptGetContext(NULL, argc, argv, options_phase1, 0);
138  while ((rc = poptGetNextOpt(optCon)) != -1); 
139  /*
140  if (*protocol_name == NULL ){
141    cerr << "Error: Missing protocol option!" << endl;
142    poptPrintUsage(optCon, stderr, 0);
143    exit(-1);
144  }
145  if (*generator_name == NULL ){
146    cerr << "Error: Missing Generator option!" << endl;
147    poptPrintUsage(optCon, stderr, 0);
148    exit(-1);
149  }
150  */
151  //options_phase1[1].arg = NULL;
152  //options_phase1[2].arg = NULL;
153  //options_phase1[3].arg = NULL;
154  //options_phase1[4].arg = NULL;
155  poptFreeContext(optCon);
156}
157
158
159/**
160 *  Parse options in second Phase.
161 *  Check all port and generator parameters except "type" which has already been parsed.
162 *  in Phase I.
163 */
164void
165parseOptionsPhase2(
166  int argc, 
167  const char * argv[], 
168  Port* port, 
169  Generator* gen
170) {
171
172  options[1].arg = (void*)port->getOptions();
173  options[2].arg = (void*)gen->getOptions();
174  options[3].argDescrip = "FIXED";
175  options[4].argDescrip = "FIXED";
176  options[5].argDescrip = "FIXED";
177  options[6].argDescrip = "FIXED";
178
179  int rc;
180  poptContext optCon = poptGetContext(NULL, argc, argv, options,0 );
181  while ((rc = poptGetNextOpt(optCon)) >= 0);
182  if (rc < -1) {
183    cerr << "ERROR: " << poptBadOption(optCon, POPT_BADOPTION_NOALIAS)
184         << " (" << poptStrerror(rc) << ")" << endl;
185    goto err;
186  }
187  {
188    const char** leftover = poptGetArgs(optCon);
189    if (leftover != NULL) {
190      cerr << "ERROR: Additional argument '" << leftover[0] << "' found." << endl;
191      goto err;
192    }
193  }
194  poptFreeContext(optCon);
195  return;
196
197 err:
198  poptPrintUsage(optCon, stderr, 0);
199  exit(-1);
200}
201
202/**
203 * Parse Runtime Options
204 */
205
206int parseRuntimeOptions(char * msg, Stream* str)
207{
208  int argc;
209  const char** argv;
210  char strin[MAX_INPUT_SIZE];
211
212  if (*msg == '\0') return -1;
213  if (*msg != '-') {
214    // allow for commands without leading --
215    strcpy(strin + 2, msg);
216    strin[0] = strin[1] = '-';
217    msg = strin;
218  }
219  poptParseArgvString(msg, &argc, &argv);
220  poptContext optCon = poptGetContext(NULL, argc, argv, options, POPT_CONTEXT_KEEP_FIRST);
221       
222  int rc;
223  while ((rc = poptGetNextOpt(optCon)) > 0) {
224
225        if (rc == 1) {// Stop
226          str->exitStream();
227          exit(0);  //exit terminate process and all its threads
228        }
229        else if (rc == 2)
230        { 
231          str->pauseStream();         
232        }
233        else if (rc==3)
234        {
235          str->resumeStream();
236        }     
237  };
238  if (rc < -1) {
239    cerr << "ERROR: " << poptBadOption(optCon, POPT_BADOPTION_NOALIAS)
240         << " (" << poptStrerror(rc) << ")" << endl;
241  }
242  poptFreeContext(optCon);
243  return rc;   
244}
245
246/**
247 * Function to create a Port based on the protocol_name
248 * @param protocol_name: protocol name
249 * @return the port created
250 */
251
252Port*
253createPort(
254  char* protocol_name
255) {
256  Port* port = NULL;   
257
258  if (strcmp(protocol_name, "udp") == 0 ){
259    port = new UDPSockPort(); 
260  } else if(strcmp(protocol_name, "tcp" ) == 0){
261    port = new TCPSockPort();
262  } else if(strcmp(protocol_name, "raw" ) == 0){
263    port = new EthernetPort();
264  } else {
265    cerr << "Error: Unknown protocol '" << protocol_name << "'." << endl;
266    exit(-1);
267  } 
268  return port;
269}
270
271
272/**
273 * Function to creat a thread for one stream
274 */
275void *create_stream_function( void *ptr )
276{
277     Stream *para = (Stream *) ptr;
278     para->startStream();  // start the stream, it cannot paused or resume unless killed by main thread
279     return NULL;
280}
281
282
283/**
284 * Fucntion in main thread to handling stdin (User input commands)
285 * Parsing them as run-time options
286 */
287
288void work(Stream *str)
289{
290  int rc;
291  char msg[MAX_INPUT_SIZE];
292  while (1) {
293 
294        cin.getline(msg, MAX_INPUT_SIZE );
295        rc = parseRuntimeOptions(msg, str);   
296  }
297}
298
299
300/**
301 *  Main funciton of the OTG
302 *
303 * The major purpose of this function are:
304 * - handle command-line inputs, before starting the program and at run-time.
305 * - arrange wait, send, and stdin reading operations.
306 *
307 * It is designed as: First, parse all options in two phases.
308 * After parsing the second level options, check the readiness of Port and Generator (if this is sender)
309 * then initialize the port and set-up the scenario, and ready to start.
310
311 * Here. we are going to have multiple streams in one OTG. 
312 * using multiple thread. the main thread is handling commands.
313 * each stream is a seperate thread, by calling th stream_init functon, the stream is independently sending packets
314 *
315 */
316int main(int argc, const char * argv[])
317{
318
319  OrbitApp *otg1 = new OTGApp();   
320
321  try {
322   
323    pthread_t thread1;
324    char *protocol_name = "udp";
325    char *generator_name = "cbr";
326    char *debuglog_name = NULL;
327    int clockref = -1;
328    parseOptionsPhase1(argc, argv, &protocol_name, &generator_name, &debuglog_name, &clockref);
329    Port* port = createPort(protocol_name);
330    Generator *gen = createGenerator(generator_name);
331    otg1->init(&argc, argv, debuglog_name);  //Initialize OML 
332    parseOptionsPhase2(argc, argv, port, gen);               
333    port->init();
334    gen->init();
335    Stream *str = new Stream(0, gen, port, otg1, clockref);  //default stream No.0   
336    int cst1 = pthread_create( &thread1, NULL, create_stream_function, (void *)str);   
337    if (cst1!=0)throw "Create a Stream Thread Failed...";               
338    work(str); //this is the main thread
339
340  } catch (const char *reason ) {
341    cerr << "Exception:" << reason << endl;
342    exit(-1);
343  } 
344  return 0;
345}
346
347//Note: I have tested that there is no issue to start more than one streams in the OTG with multiple threads,
348//but I prefer not to use this feature now because it is of no need.
349//
350//struct poptOption options_runtime_phase1[] = {
351//  POPT_AUTOHELP
352//  { "stream", '\0', POPT_ARG_INT, NULL, 0, "ID of stream", "INTEGER"},
353//  { NULL, 0, 0, NULL, 0 }
354//};
355
356/**
357 *An struct
358 *Parameter for create a new stream thread
359 */
360
361//struct stream_thread_param
362//{
363//  Generator *gp_; /*!<pointer to the generator */
364//  Port      *pp_; /*!<pointer to port */   
365//  short streamid_;/*!stream identifier*/
366//};
367
368/** An enum.
369 * Indication of generator type
370 */
371//enum generator_type
372//{
373//  cbr,         /*!< Enum value CBR traffic. */ 
374//  exponential  /*!< Enum value Exponential Traffic. */   
375//};
376
377
378  /*
379    struct stream_thread_param sp1;
380   
381    sp1.gp_ = gen;
382    sp1.pp_ = port;
383    sp2.gp_ = gen2;
384    */
385    //sp2.pp_ = port2;
386    //sp1.streamid_= 1;
387    //sp2.streamid_= 2;   
388    // two threads, create two streams   
389
390
391    //generator_type gtype = cbr;
392    //Generator* gen = new CBR_Generator();
393    //Generator* gen2 = new CBR_Generator();  //gen2 default options, does not need parse anycommandline options 
394     //port2->setDstHostname("internal1");
395    //port2->init();
396
397    //Port* port2 = createPort(protocol_name); // port2 default options, does not need parse any commandline options
398
399 //int cst2 = pthread_create( &thread2, NULL, create_stream_function, (void *)&sp2);
Note: See TracBrowser for help on using the browser.