main.c 27.9 KB
Newer Older
Sampo Saaristo's avatar
Sampo Saaristo committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*****************************************************************************
 *   main.c - the body for CRUDE
 *
 *   Copyright (C) 1999 Juha Laine and Sampo Saaristo
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 *   Authors:      Juha Laine     <james@cs.tut.fi>
 *                 Sampo Saaristo <sambo@cc.tut.fi>
 *
 *****************************************************************************/
#include <config.h>
#include <rude.h>
Arne Øslebø's avatar
Arne Øslebø committed
26
#include <mcast.h>
Sampo Saaristo's avatar
Sampo Saaristo committed
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48

#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sched.h>
#include <sys/mman.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <limits.h>


/*
 * Private struct for each flow of runtime statistics
 */
Arne Øslebø's avatar
Arne Øslebø committed
49 50
struct flow_stat
{
Sampo Saaristo's avatar
Sampo Saaristo committed
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
  unsigned long flowid;
  unsigned long seqmin, seq;  /* Seq number of the first and current packets */
  unsigned long rec;          /* Number of received packets */
  unsigned long oos;          /* Number of packets out of sequence */
  long long js_sec;           /* Jitter sum of seconds */
  long long js_usec;          /* Jitter sum of microsseconds */
  long long ds_sec;           /* Delay sum of seconds */
  long long ds_usec;          /* Delay sum of microsseconds */
  long last_tx_sec;
  long last_tx_usec;
  long last_rx_sec;
  long last_rx_usec;
  long last_delay_sec;
  long last_delay_usec;
  long first_rx_sec;
  long first_rx_usec;
  long max_jitter_sec;
  long max_jitter_usec;
  unsigned long long s_size;  /* Sum of all packet sizes */
};


/*
 * Function prototypes
 */
static void usage(char *);
Arne Øslebø's avatar
Arne Øslebø committed
77
static int  make_conn(unsigned short, char *,int,unsigned int);
Sampo Saaristo's avatar
Sampo Saaristo committed
78 79 80 81 82 83
static int  decode_file(void);
static int  runtime_stats(unsigned short, unsigned long);
void        print_stats(void);
static int  rec_to_file(unsigned short,unsigned long);
static int  rec_n_print(unsigned short,unsigned long);
void        crude_handler(int);
Arne Øslebø's avatar
Arne Øslebø committed
84
static void get_str_addr(struct sockaddr_storage,char[]);
Sampo Saaristo's avatar
Sampo Saaristo committed
85 86 87 88 89 90 91 92 93

/*
 * Global variables
 */
int main_socket         = 0;     /* The socket to listen to                  */
int main_file           = 0;     /* File to read from/to write to            */
unsigned long pkt_count = 0;     /* Counter for received/processed packets   */
struct flow_stat *flows = NULL;  /* List of flows for runtime statistics  */
int nflows              = 0;
Arne Øslebø's avatar
Arne Øslebø committed
94
char preffix[] = "::ffff:";
Sampo Saaristo's avatar
Sampo Saaristo committed
95 96

int main(int argc, char **argv)
Arne Øslebø's avatar
Arne Øslebø committed
97
{
Sampo Saaristo's avatar
Sampo Saaristo committed
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
  extern char *optarg;
  extern int  optind, opterr, optopt, errno;

  char *ifipadd       = NULL;    /* pointer to interface IP address */
  unsigned short port = 10001;   /* default UDP port number         */
  long w_num          = 0;       /* # pkts to capture. 0=unlimited  */
  int priority        = 0;
  uid_t user_id       = getuid();
  int  cmd_char       = 0;
  int  retval         = 0;
  long temp1          = 0;
  int ps_flag         = 0;
  struct sigaction action;
  struct sched_param p;
  char *sptr, *eptr;
  struct flow_stat *newflows;
Arne Øslebø's avatar
Arne Øslebø committed
114 115
  int use_ip6=0;
  int ifindex = -1;
Sampo Saaristo's avatar
Sampo Saaristo committed
116 117

  printf("crude version %s, Copyright (C) 1999 Juha Laine and Sampo Saaristo\n"
Arne Øslebø's avatar
Arne Øslebø committed
118 119 120 121 122 123 124
         "crude comes with ABSOLUTELY NO WARRANTY!\n"
         "This is free software, and you are welcome to redistribute it\n"
         "under GNU GENERAL PUBLIC LICENSE Version 2.\n",VERSION);
  
  struct sockaddr_storage test;
  printf("Size of sockaddr_storage: %d ss_len:%d \n",sizeof(test),sizeof(test.ss_family));		
		 
Sampo Saaristo's avatar
Sampo Saaristo committed
125
  while((retval >= 0) &&
Arne Øslebø's avatar
Arne Øslebø committed
126 127 128 129
        ((cmd_char = getopt(argc,argv,"hvd:p:i:l:P:n:s:6D:")) != EOF))
  {
    switch(cmd_char)
    {
Sampo Saaristo's avatar
Sampo Saaristo committed
130
    case 'v':
Arne Øslebø's avatar
Arne Øslebø committed
131 132 133 134 135 136 137 138 139
      if((optind == 2) && (argc == 2))
      {
        printf("crude version is %s\n",VERSION);
        retval = -1;
      }
      else
      {
        RUDEBUG1("crude: invalid commandline arguments!\n");
        retval = -2;
Sampo Saaristo's avatar
Sampo Saaristo committed
140 141 142 143
      }
      break;

    case 'h':
Arne Øslebø's avatar
Arne Øslebø committed
144 145 146 147 148 149 150 151 152
      if((optind == 2) && (argc == 2))
      {
        usage(argv[0]);
        retval = -1;
      }
      else
      {
        RUDEBUG1("crude: invalid commandline arguments!\n");
        retval = -2;
Sampo Saaristo's avatar
Sampo Saaristo committed
153 154 155 156
      }
      break;

    case 'd':
Arne Øslebø's avatar
Arne Øslebø committed
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
      if((optind == 3) && (argc == 3) && (optarg != NULL))
      {
        if((main_file = open(optarg, O_RDONLY, 0)) < 0)
        {
          RUDEBUG1("crude: couldn't open file %s: %s\n",optarg,strerror(errno));
          retval = -3;
        }
        else
        {
          retval = 1;
        }
      }
      else
      {
        RUDEBUG1("crude: invalid commandline arguments!\n");
        retval = -2;
Sampo Saaristo's avatar
Sampo Saaristo committed
173 174 175 176
      }
      break;

    case 'p':
Arne Øslebø's avatar
Arne Øslebø committed
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
      if(optarg != NULL)
      {
        errno = 0;
        temp1 = strtol((const char *)optarg,NULL,0);
        if(errno != 0)
        {
          RUDEBUG1("crude: '-p' number format error: %s\n",strerror(errno));
          retval = -4;
        }
        else if((temp1 < 1025) || (temp1 > 65535))
        {
          RUDEBUG1("crude: port must be  between 1025-65535!\n");
          retval = -4;
        }
        else
        {
          port = temp1;
          retval += 2;
        }
      }
      else
      {
        RUDEBUG1("crude: invalid commandline arguments!\n");
        retval = -2;
Sampo Saaristo's avatar
Sampo Saaristo committed
201 202 203 204
      }
      break;

    case 'i':
Arne Øslebø's avatar
Arne Øslebø committed
205 206 207 208 209 210 211 212 213
      if(optarg != NULL)
      {
        ifipadd = argv[(optind-1)];
        retval += 4;
      }
      else
      {
        RUDEBUG1("crude: invalid commandline arguments!\n");
        retval = -2;
Sampo Saaristo's avatar
Sampo Saaristo committed
214 215 216 217
      }
      break;

    case 'l':
Arne Øslebø's avatar
Arne Øslebø committed
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
      if(optarg != NULL)
      {
        if((main_file = open(optarg, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0)
        {
          RUDEBUG1("crude: couldn't open file %s: %s\n",optarg,strerror(errno));
          retval = -5;
        }
        else
        {
          retval += 8;
        }
      }
      else
      {
        RUDEBUG1("crude: invalid commandline arguments!\n");
        retval = -2;
Sampo Saaristo's avatar
Sampo Saaristo committed
234 235 236 237
      }
      break;

    case 'P':
Arne Øslebø's avatar
Arne Øslebø committed
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
      if(optarg != NULL)
      {
        priority = atoi(optarg);
        if((priority < 1) || (priority > 90))
        {
          fprintf(stderr,"crude: priority must be between 1 to 90\n");
          retval = -2;
        }
        if(user_id != 0)
        {
          fprintf(stderr,"crude: must be root to set the priority level\n");
          retval = -2;
        }
      }
      else
      {
        RUDEBUG1("crude: invalid commandline arguments!\n");
        retval = -2;
      }
      break;
Sampo Saaristo's avatar
Sampo Saaristo committed
258 259

    case 'n':
Arne Øslebø's avatar
Arne Øslebø committed
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
      if(optarg != NULL)
      {
        errno = 0;
        w_num = strtol((const char *)optarg,NULL,0);
        if(errno != 0)
        {
          RUDEBUG1("crude: '-w' number format error: %s\n",strerror(errno));
          retval = -6;
        }
        else if(w_num <= 0)
        {
          RUDEBUG1("crude: # of logged packets must be > 0!\n");
          retval = -6;
        }
        else
        {
          retval += 16;
        }
      }
      else
      {
        RUDEBUG1("crude: invalid commandline arguments!\n");
        retval = -2;
Sampo Saaristo's avatar
Sampo Saaristo committed
283 284 285 286
      }
      break;

    case 's':
Arne Øslebø's avatar
Arne Øslebø committed
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
      if(optarg != NULL)
      {
        sptr = optarg;
        do
        {
          newflows = realloc(flows, (nflows + 1) * sizeof(struct flow_stat));
          if (newflows == NULL)
          {
            RUDEBUG1("crude: failed to allocate memory for statistics!\n");
            retval = -6;
            break;
          }
          flows = newflows;
          flows[nflows].flowid = strtoul(sptr, &eptr, 10);
          if (eptr == sptr || flows[nflows].flowid == ULONG_MAX)
          {
            RUDEBUG1("crude: error reading flow IDs!\n");
            retval = -6;
            break;
          }
          if (*eptr && *eptr != ',')
          {
            RUDEBUG1("crude: flow IDs must be separated by a comma!\n");
            retval = -6;
            break;
          }
          sptr = eptr + 1;
          flows[nflows].rec = 0;
          flows[nflows].oos = 0;
          flows[nflows].seq = ULONG_MAX;
          flows[nflows].seqmin = ULONG_MAX;
          flows[nflows].js_sec = 0;
          flows[nflows].js_usec = 0;
          flows[nflows].ds_sec = 0;
          flows[nflows].ds_usec = 0;
          flows[nflows].s_size = 0;
          flows[nflows].last_delay_sec = 0;
          flows[nflows].last_delay_usec = 0;
          flows[nflows].max_jitter_sec = 0;
          flows[nflows].max_jitter_usec = 0;
          /* The other fields are initialized when the first packet arrives */
          nflows++;
        }
        while (*eptr);
      }
      else
      {
        RUDEBUG1("crude: invalid commandline arguments!\n");
        retval = -2;
      }
      break;

	  case '6':
		use_ip6 = 1; 
	  break;
	  
	  case 'D':
Sampo Saaristo's avatar
Sampo Saaristo committed
344
      if(optarg != NULL){
Arne Øslebø's avatar
Arne Øslebø committed
345 346 347 348 349 350 351 352 353 354
		  RUDEBUG7("crude: using specified interface for multicast, name: %s\n",optarg);
		  if(0==(ifindex = if_nametoindex(optarg))){
			RUDEBUG1("crude: specified interface does not exist\n");
			retval = -10;
		  }
      }
      else
      {
        RUDEBUG1("crude: invalid commandline arguments!\n");
        retval = -2;
Sampo Saaristo's avatar
Sampo Saaristo committed
355 356 357
      }
      break;

Arne Øslebø's avatar
Arne Øslebø committed
358
	    
Sampo Saaristo's avatar
Sampo Saaristo committed
359 360 361 362 363 364 365 366 367
    default:
      usage(argv[0]);
      retval = -1;
      break;
    }
  }

  /* (if retval < 0 -> ERROR or/and EXIT IMMEDIATELY) */
  if(retval < 0){ goto crude_exit; }
Arne Øslebø's avatar
Arne Øslebø committed
368

Sampo Saaristo's avatar
Sampo Saaristo committed
369 370 371 372
  /*
   * If this process is owned by root we can do some tricks to
   * improve the performance... (the -P option)
   */
Arne Øslebø's avatar
Arne Øslebø committed
373 374
  if((user_id == 0) && (priority > 0))
  {
Sampo Saaristo's avatar
Sampo Saaristo committed
375
    /* Try to lock the memory to avoid paging delays */
Arne Øslebø's avatar
Arne Øslebø committed
376 377
    if(mlockall(MCL_CURRENT | MCL_FUTURE) < 0)
    {
Sampo Saaristo's avatar
Sampo Saaristo committed
378 379 380 381 382
      RUDEBUG1("crude: memory lock failed: %s\n", strerror(errno));
    }

    /* Switch to Round-Robin-Real-Time Scheduling */
    p.sched_priority = priority;
Arne Øslebø's avatar
Arne Øslebø committed
383 384
    if(sched_setscheduler(0, SCHED_RR, &p) < 0)
    {
Sampo Saaristo's avatar
Sampo Saaristo committed
385 386 387 388 389
      RUDEBUG1("crude: sched_setscheduler() failed: %s\n",strerror(errno));
      retval = -1;
      goto crude_exit;
    }
    RUDEBUG7("crude: program priority set to %d\n", p.sched_priority);
Arne Øslebø's avatar
Arne Øslebø committed
390 391
  }

Sampo Saaristo's avatar
Sampo Saaristo committed
392 393 394
  /* Activate the signal handler(s) */
  memset(&action, 0, sizeof(struct sigaction));
  action.sa_handler = crude_handler;
Arne Øslebø's avatar
Arne Øslebø committed
395 396
  if(sigaction(SIGINT,&action,NULL))
  {
Sampo Saaristo's avatar
Sampo Saaristo committed
397 398 399 400 401
    RUDEBUG1("crude: signal SIGINT handler failure!\n");
    retval = -7;
    goto crude_exit;
  }

Arne Øslebø's avatar
Arne Øslebø committed
402 403
  if(retval == 1)
  {
Sampo Saaristo's avatar
Sampo Saaristo committed
404
    retval = decode_file();
Arne Øslebø's avatar
Arne Øslebø committed
405 406 407 408 409
  }
  else
  {
    if((main_socket=make_conn(port,ifipadd,use_ip6,ifindex)) < 0)
    {
Sampo Saaristo's avatar
Sampo Saaristo committed
410 411
      RUDEBUG1("crude: couldn't create socket!\n");
      retval = -8;
Arne Øslebø's avatar
Arne Øslebø committed
412 413 414
    }
    else
    {
Sampo Saaristo's avatar
Sampo Saaristo committed
415 416 417 418 419 420
      if (nflows > 0){ retval = runtime_stats(port,w_num); }
      else if(main_file > 0){ retval = rec_to_file(port,w_num); }
      else { retval = rec_n_print(port,w_num); }
    }
  }

Arne Øslebø's avatar
Arne Øslebø committed
421
crude_exit:
Sampo Saaristo's avatar
Sampo Saaristo committed
422 423 424 425
  if (retval >= 0 && nflows > 0) { ps_flag = 1; }
  /*
   * Restore the tweaked settings...
   */
Arne Øslebø's avatar
Arne Øslebø committed
426 427
  if((user_id == 0) && (priority > 0))
  {
Sampo Saaristo's avatar
Sampo Saaristo committed
428 429
    /* Restore the program priority */
    p.sched_priority = 0;
Arne Øslebø's avatar
Arne Øslebø committed
430 431
    if(sched_setscheduler(0, SCHED_OTHER, &p) < 0)
    {
Sampo Saaristo's avatar
Sampo Saaristo committed
432 433 434
      RUDEBUG1("crude: program priority restoring failed: %s\n",
               strerror(errno));
      retval = -1;
Arne Øslebø's avatar
Arne Øslebø committed
435 436 437
    }
    else
    {
Sampo Saaristo's avatar
Sampo Saaristo committed
438 439 440 441 442
      RUDEBUG7("crude: program priority restored\n");
    }

    /* Release the locked memory */
    munlockall();
Arne Øslebø's avatar
Arne Øslebø committed
443
  }
Sampo Saaristo's avatar
Sampo Saaristo committed
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458

  if(ps_flag){ print_stats(); }
  if(main_file > 0){ close(main_file); }
  if(main_socket > 0){ close(main_socket); }
  if(flows){free(flows); }
  exit(retval);
}


/*
 * usage() - print help and usage information
 */
static void usage(char *name)
{
  printf("\nusage: %s -h | -v | -d file | "
Arne Øslebø's avatar
Arne Øslebø committed
459 460 461 462 463 464 465 466 467 468 469 470 471 472
         "[-p port] [-i addr] [-l file] [-n #]\n\n"
         "\t-h           = print (this) short help and usage information\n"
         "\t-v           = print the version number and exit\n"
         "\t-d file      = decode the file to stdout\n"
         "\t-p port      = port to listen to\n"
         "\t-i addr      = numeric IP addres for the interface to listen to\n"
		 "\t-6           = use ipv6\n"
		 "\t-D if_name   = interface name(e.g. eth0) to be used-use only with multicast and -i option\n"
	     "\t-l file      = direct undecoded output to file (fastest method!)\n"
         "\t               default is to decode the output to stdout\n"
         "\t-P priority  = process realtime priority {1-90}\n\n"
         "\t-s #[,# ...] = don't record: get runtime stats for specified flows\n"
         "\t-n #         = exit automatically after # packets has been logged.\n"
         "\t               use CTRL+C to exit the program otherwise\n\n", name);
Sampo Saaristo's avatar
Sampo Saaristo committed
473 474 475 476 477 478 479 480 481 482
}


/*
 * crude_handler() - simple signal handler function
 */
void crude_handler(int value)
{
  struct sched_param pri;
  RUDEBUG7("\ncrude: SIGNAL caught - exiting...\n");
Arne Øslebø's avatar
Arne Øslebø committed
483

Sampo Saaristo's avatar
Sampo Saaristo committed
484
  /* Check & restore process priority */
Arne Øslebø's avatar
Arne Øslebø committed
485 486
  if((getuid() == 0) && (sched_getscheduler(0) != SCHED_OTHER))
  {
Sampo Saaristo's avatar
Sampo Saaristo committed
487
    pri.sched_priority = 0;
Arne Øslebø's avatar
Arne Øslebø committed
488 489
    if(sched_setscheduler(0, SCHED_OTHER, &pri) < 0)
    {
Sampo Saaristo's avatar
Sampo Saaristo committed
490
      RUDEBUG1("crude_handler: crude priority failure: %s\n",strerror(errno));
Arne Øslebø's avatar
Arne Øslebø committed
491 492 493
    }
    else
    {
Sampo Saaristo's avatar
Sampo Saaristo committed
494 495
      RUDEBUG7("crude_handler: crude priority restored\n");
    }
Arne Øslebø's avatar
Arne Øslebø committed
496
  }
Sampo Saaristo's avatar
Sampo Saaristo committed
497 498 499 500 501 502 503 504 505 506 507 508

  if(nflows > 0){ print_stats(); }
  if(main_file > 0){ close(main_file); }
  if(main_socket > 0){ close(main_socket); }
  RUDEBUG1("\ncrude: captured/processed %lu packets\n", pkt_count);
  exit(0);
}


/*
 * make_conn()   - make the required connection(s)
 */
Arne Øslebø's avatar
Arne Øslebø committed
509
static int make_conn(unsigned short port, char *ifaddr,int use_ip6,unsigned int ifindex)
Sampo Saaristo's avatar
Sampo Saaristo committed
510
{
Arne Øslebø's avatar
Arne Øslebø committed
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547
  struct sockaddr_storage our_addr;
  struct in6_addr our_ip6;
  struct in_addr our_ip4;
  int our_sock;

  memset(&our_addr, 0, sizeof(struct sockaddr_storage));
  ((struct sockaddr_in6*)&our_addr)->sin6_port = htons(port);


  if((ifaddr == NULL) || (strlen(ifaddr) == 0))
  {
 	if(use_ip6){
 	   	((struct sockaddr_in6*)&our_addr)->sin6_addr = in6addr_any;
    	((struct sockaddr_in6*)&our_addr)->sin6_family = AF_INET6;
    	RUDEBUG7("crude: using an ipv6 wildcard interface \n");
	}
	else
	{
		((struct sockaddr_in*)&our_addr)->sin_addr.s_addr = INADDR_ANY;
    	((struct sockaddr_in*)&our_addr)->sin_family = AF_INET;
    	RUDEBUG7("crude: using an ipv4 wildcard interface \n");
	}
   }
  else if((inet_pton(AF_INET6, ifaddr, &our_ip6)) > 0)
  {
    ((struct sockaddr_in6*)&our_addr)->sin6_addr = our_ip6;
    ((struct sockaddr_in6*)&our_addr)->sin6_family = AF_INET6;
    RUDEBUG7("crude: using an ipv6 interface \n");
  }
  else if((inet_pton(AF_INET, ifaddr, &our_ip4)) > 0)
  {
    ((struct sockaddr_in*)&our_addr)->sin_addr = our_ip4;
    ((struct sockaddr_in*)&our_addr)->sin_family = AF_INET;
    RUDEBUG7("crude: using an ipv4 interface \n");
  }
  else
  {
Sampo Saaristo's avatar
Sampo Saaristo committed
548 549 550 551
    RUDEBUG1("crude: invalid interface address %s !\n",ifaddr);
    return -1;
  }

Arne Øslebø's avatar
Arne Øslebø committed
552 553 554 555 556 557 558 559
   if((our_sock=socket(our_addr.ss_family ,SOCK_DGRAM,0)) < 0)
   {
       RUDEBUG1("crude: socket() failed: %s\n", strerror(errno));
       return -2;
   }
   
  if(bind(our_sock, (struct sockaddr *)&our_addr, sizeof(struct sockaddr_storage)) < 0)
  {
Sampo Saaristo's avatar
Sampo Saaristo committed
560 561 562 563
    RUDEBUG1("crude: bind() failed: %s\n", strerror(errno));
    close(our_sock);
    return -3;
  }
Arne Øslebø's avatar
Arne Øslebø committed
564 565 566 567 568 569 570 571 572 573 574 575 576
   
  if(isMulticastAddr(&our_addr)>0)
  {
    RUDEBUG7("crude: make_conn(): address is a multicast one\n",port,ifaddr);
  	if(joinGroup(our_sock, 0, 200, &our_addr,ifindex) < 0){
      RUDEBUG1("crude: make_conn() failed to join group\n");
	  close(our_sock);
	  return -4;
	}
    else
      RUDEBUG7("crude: make_conn() group joined\n");

  }
Sampo Saaristo's avatar
Sampo Saaristo committed
577 578 579 580 581 582 583 584 585 586 587 588 589 590 591

  return our_sock;
}


/*
 * decode_file() - read the file and print the statistics to stdout in
 *                 human readable form
 */
static int decode_file(void)
{
  struct udp_data *ptr1   = NULL;
  struct crude_struct *ptr2 = NULL;
  char *buffer            = NULL;
  int buf_len             = 0;
Arne Øslebø's avatar
Arne Øslebø committed
592 593
  struct sockaddr_storage s_add,d_add;
  char str1[INET6_ADDRSTRLEN],str2[INET6_ADDRSTRLEN];
Sampo Saaristo's avatar
Sampo Saaristo committed
594 595 596

  /* Allocate memory for the small buffer */
  buf_len = (sizeof(struct udp_data) + sizeof(struct crude_struct));
Arne Øslebø's avatar
Arne Øslebø committed
597 598
  if((buffer=(char *)malloc(buf_len)) == NULL)
  {
Sampo Saaristo's avatar
Sampo Saaristo committed
599 600 601 602
    RUDEBUG1("crude: couldn't allocate memory: %s\n", strerror(errno));
    return -10;
  }

Arne Øslebø's avatar
Arne Øslebø committed
603 604
  memset(str1,0,INET6_ADDRSTRLEN);
  memset(str2,0,INET6_ADDRSTRLEN);
Sampo Saaristo's avatar
Sampo Saaristo committed
605

Arne Øslebø's avatar
Arne Øslebø committed
606 607
  while(read(main_file,buffer,buf_len) > 0)
  {
Sampo Saaristo's avatar
Sampo Saaristo committed
608 609 610
    pkt_count++;
    ptr1 = (struct udp_data*)buffer;
    ptr2 = (struct crude_struct*)(buffer + sizeof(struct udp_data));
Arne Øslebø's avatar
Arne Øslebø committed
611 612 613 614 615 616 617 618
    s_add = ptr2->src; 
    d_add = ptr1->dest_addr;
    char srcport[10];

    get_str_addr(s_add,str1);
	get_str_addr(d_add,str2);		
			
	printf("ID=%lu SEQ=%lu SRC=%s:%hu DST=%s:%hu "
Sampo Saaristo's avatar
Sampo Saaristo committed
619 620 621
	   "Tx=%ld.%06ld Rx=%ld.%06ld SIZE=%ld\n",
	   (unsigned long)ntohl(ptr1->flow_id),
	   (unsigned long)ntohl(ptr1->sequence_number),
Arne Øslebø's avatar
Arne Øslebø committed
622
	   str1, ntohs(((struct sockaddr_in *)&s_add)->sin_port),
Sampo Saaristo's avatar
Sampo Saaristo committed
623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
	   str2, ntohs(ptr2->dest_port),
	   (unsigned long)ntohl(ptr1->tx_time_seconds),
	   (unsigned long)ntohl(ptr1->tx_time_useconds),
	   (unsigned long)ntohl(ptr2->rx_time_seconds),
	   (unsigned long)ntohl(ptr2->rx_time_useconds),
	   (long)ntohl(ptr2->pkt_size));
  }

  if(errno){ RUDEBUG1("crude: read failed: %s\n", strerror(errno)); }
  free(buffer);
  RUDEBUG1("crude: captured/processed %lu packets\n", pkt_count);
  return 0;
}


/*
 * runtime_stats() - don't record: gather statistics at runtime...
 * This routine 
 */
static int runtime_stats(unsigned short port, unsigned long limit)
{
  long               rec_bytes = 0;     /* Bytes read            */
  int                wri_bytes = 0;     /* Bytes written         */
Arne Øslebø's avatar
Arne Øslebø committed
646 647
  int                src_len = sizeof(struct sockaddr_in6);
  struct sockaddr_in6 src_addr;
Sampo Saaristo's avatar
Sampo Saaristo committed
648 649 650 651 652 653 654 655
  struct timeval     time1;
  char buffer[PMAXSIZE];
  struct udp_data *data = (struct udp_data *) buffer;
  int i;
  struct flow_stat *fsp;
  unsigned long seq;
  long tx_s;
  long tx_us;
Arne Øslebø's avatar
Arne Øslebø committed
656
  unsigned long flowid;
Sampo Saaristo's avatar
Sampo Saaristo committed
657 658 659 660 661 662 663
  long delay_s;
  long delay_us;
  long jitter_s;
  long jitter_us;

  /* Initialize some variables */
  memset(buffer,0,PMAXSIZE);
Arne Øslebø's avatar
Arne Øslebø committed
664 665 666
//TODO: mozna misto sockaddr_in6 by se melo pouzit sockaddr_storage
  while(1)
  {
Sampo Saaristo's avatar
Sampo Saaristo committed
667
    rec_bytes = recvfrom(main_socket, buffer, PMAXSIZE, 0,
Arne Øslebø's avatar
Arne Øslebø committed
668 669 670
                         (struct sockaddr *)&src_addr, (socklen_t *)&src_len);
    if(rec_bytes <= 0)
    {
Sampo Saaristo's avatar
Sampo Saaristo committed
671
      RUDEBUG1("crude: error when receiving packet: %s\n",strerror(errno));
Arne Øslebø's avatar
Arne Øslebø committed
672 673 674
    }
    else
    {
Sampo Saaristo's avatar
Sampo Saaristo committed
675 676
      gettimeofday(&time1, NULL);
      flowid = ntohl(data->flow_id);
Arne Øslebø's avatar
Arne Øslebø committed
677 678
      for (i = 0; i < nflows; i++)
      {
Sampo Saaristo's avatar
Sampo Saaristo committed
679 680 681
        if (flows[i].flowid == flowid)
          break;
      }
Arne Øslebø's avatar
Arne Øslebø committed
682 683
      if (i == nflows)
      {
Sampo Saaristo's avatar
Sampo Saaristo committed
684 685 686 687 688 689 690 691 692 693 694 695 696
        continue;
      }
      fsp = &(flows[i]);
      /* BUG: the remaining code in the loop should really be atomic, but
       * how do we guaratee that?
       * Anyway, if you stop your sources before hitting CTRL-C this should
       * be OK. */
      seq = ntohl(data->sequence_number);
      fsp->rec++;
      tx_s = ntohl(data->tx_time_seconds);
      tx_us = ntohl(data->tx_time_useconds);
      delay_s = time1.tv_sec - tx_s;
      delay_us = time1.tv_usec - tx_us;
Arne Øslebø's avatar
Arne Øslebø committed
697 698
      if (seq <= fsp->seq)
      {
Sampo Saaristo's avatar
Sampo Saaristo committed
699
        fsp->oos++;
Arne Øslebø's avatar
Arne Øslebø committed
700 701
        if (seq < fsp->seqmin)
        {
Sampo Saaristo's avatar
Sampo Saaristo committed
702 703
          /* Should only occur in case of reordering of the first packets */
          fsp->seqmin = seq;
Arne Øslebø's avatar
Arne Øslebø committed
704 705 706 707 708 709 710 711 712 713 714 715
          if (fsp->rec == 1)
          {
            /* First packet: do the initialization.
             * Here we use a trick to move the initialization conditional out
             * of the normal execution path: we initialized seqmin with
             * ULONG_MAX so that when we receive the first packet it's sequence
             * number is always less than that.  :-)  */
            fsp->oos--; /* The first packet obviously isn't out of sequence */
            fsp->first_rx_sec = time1.tv_sec;
            fsp->first_rx_usec = time1.tv_usec;
            fsp->seq = seq;
            goto update_last;
Sampo Saaristo's avatar
Sampo Saaristo committed
716 717
          }
        }
Arne Øslebø's avatar
Arne Øslebø committed
718 719 720 721
      }
      else
      {
        fsp->seq = seq;
Sampo Saaristo's avatar
Sampo Saaristo committed
722 723 724 725 726 727
      }
      fsp->ds_sec += delay_s;
      fsp->ds_usec += delay_us;
      jitter_s = delay_s - fsp->last_delay_sec;
      jitter_us = delay_us - fsp->last_delay_usec;
      /* We need the absolute value, so: */
Arne Øslebø's avatar
Arne Øslebø committed
728 729
      if (jitter_s < 0)
      {
Sampo Saaristo's avatar
Sampo Saaristo committed
730 731 732
        jitter_s = -jitter_s;
        jitter_us = -jitter_us;
      }  /* At this point, jitter_s >= 0 */
Arne Øslebø's avatar
Arne Øslebø committed
733 734 735 736 737 738 739 740 741 742 743
      if (jitter_us < 0)
      {
        if (jitter_s == 0)
        {
          jitter_us = -jitter_us;
        }
        else
        {
          jitter_us += 1000000;
          jitter_s--;
        }
Sampo Saaristo's avatar
Sampo Saaristo committed
744 745 746 747
      }  /* Now both jitter components are positive */
      fsp->js_sec += jitter_s;
      fsp->js_usec += jitter_us;
      if (jitter_s > fsp->max_jitter_sec ||
Arne Øslebø's avatar
Arne Øslebø committed
748 749
          jitter_s == fsp->max_jitter_sec && jitter_us > fsp->max_jitter_usec)
      {
Sampo Saaristo's avatar
Sampo Saaristo committed
750 751 752
        fsp->max_jitter_sec = jitter_s;
        fsp->max_jitter_usec = jitter_us;
      }
Arne Øslebø's avatar
Arne Øslebø committed
753
    update_last:
Sampo Saaristo's avatar
Sampo Saaristo committed
754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787
      fsp->last_tx_sec = tx_s;
      fsp->last_tx_usec = tx_us;
      fsp->last_rx_sec = time1.tv_sec;
      fsp->last_rx_usec = time1.tv_usec;
      fsp->last_delay_sec = delay_s;
      fsp->last_delay_usec = delay_us;
      fsp->s_size += rec_bytes;
    }

    pkt_count++;
    /* Note that we only count packets from the flows we are gathering
     * statistics for: the others don't matter in this case. */
    if((limit != 0) && (pkt_count >= limit)){ break; }
  } /* end of while */

  RUDEBUG1("\ncrude: captured/processed %lu packets\n", pkt_count);
  return 0;
}


/*
 * print_stats() - print the statistics at the end of a runtime statistics
 *                 gathering session
 */
void print_stats(void)
{
  int i;
  struct flow_stat *fsp;
  long long sec, usec;
  double interval;

  printf("\n"
         "Runtime statistics results: \n"
         "--------------------------- \n");
Arne Øslebø's avatar
Arne Øslebø committed
788 789
  for (i = 0; i < nflows; i++)
  {
Sampo Saaristo's avatar
Sampo Saaristo committed
790 791 792 793 794 795
    fsp = &flows[i];
    printf("\nFlow_ID=%lu \n", fsp->flowid);
    printf("Packets: received=%lu   out-of-seq=%lu   "
           "lost(est)=%lu \n", fsp->rec, fsp->oos,
           fsp->rec > 0 ? (fsp->seq - fsp->seqmin + 1 - fsp->rec) : 0);
    printf("Total bytes received=%llu \n", fsp->s_size);
Arne Øslebø's avatar
Arne Øslebø committed
796 797 798 799
    if (fsp->rec > 0)
    {
      printf("Sequence numbers: first=%lu   last=%lu \n",
             fsp->seqmin, fsp->seq);
Sampo Saaristo's avatar
Sampo Saaristo committed
800
    }
Arne Øslebø's avatar
Arne Øslebø committed
801 802
    if (fsp->rec < 2)
    {
Sampo Saaristo's avatar
Sampo Saaristo committed
803 804 805 806 807 808 809 810 811 812 813 814
      printf("Can't calculate statistics: not enough packets received. \n");
      continue;
    }
    sec = fsp->ds_sec / fsp->rec;
    usec = (fsp->ds_usec + 1000000 * (fsp->ds_sec % fsp->rec)) / fsp->rec;
    sec += usec / 1000000;
    usec %= 1000000;

    // printf( "Raw data:       sec = %lld    usec = %lld\n", sec, usec );

    /* Possible with dessynchronized clocks */
    /* sec and usec must have same sign for output */
Arne Øslebø's avatar
Arne Øslebø committed
815 816
    if  ( (sec > 0 ) && (usec < 0) )
    {
Sampo Saaristo's avatar
Sampo Saaristo committed
817 818 819
      sec--;
      usec = 1000000 + usec;
    }
Arne Øslebø's avatar
Arne Øslebø committed
820 821
    else if ( (sec < 0 ) && (usec > 0) )
    {
Sampo Saaristo's avatar
Sampo Saaristo committed
822 823 824 825
      sec++;
      usec = -1000000 + usec;
    }

Arne Øslebø's avatar
Arne Øslebø committed
826
    // printf( "Corrected data: sec = %lld    usec = %lld\n", sec, usec );
Sampo Saaristo's avatar
Sampo Saaristo committed
827 828

    /* print average delay as sign and absolute value */
Arne Øslebø's avatar
Arne Øslebø committed
829 830
    if ( (sec < 0) || (usec < 0) )
    {
Sampo Saaristo's avatar
Sampo Saaristo committed
831 832 833
      sec  = llabs( sec );
      usec = llabs( usec );
      printf("Delay: average = -%lld.%06llu   ", sec, usec);
Arne Øslebø's avatar
Arne Øslebø committed
834 835 836
    }
    else
    {
Sampo Saaristo's avatar
Sampo Saaristo committed
837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866
      printf("Delay: average = %lld.%06llu   ", sec, usec);
    }

    /* Both components of all jitter values are positive, thus the sum of
     * them is also positive */
    sec = fsp->js_sec / (fsp->rec - 1);
    usec = (fsp->js_usec + 1000000 * (fsp->js_sec % (fsp->rec - 1))) /
           (fsp->rec - 1);
    sec += usec / 1000000;
    usec %= 1000000;
    printf("jitter=%llu.%06llu   seconds \n", sec, usec);
    printf("Absolute maximum jitter=%ld.%06ld   seconds \n",
           fsp->max_jitter_sec, fsp->max_jitter_usec);
    sec = (long) fsp->last_rx_sec - (long) fsp->first_rx_sec;
    usec = (long) fsp->last_rx_usec - (long) fsp->first_rx_usec;
    interval = (double) sec + (double) usec / 1000000.0;
    printf("Throughput=%g   Bps  (from first to last packet received) \n",
           (double) fsp->s_size / interval);
  }
  printf("\n");
}


/*
 * rec_to_file() - record packets to file in binary format...
 */
static int rec_to_file(unsigned short port, unsigned long limit)
{
  long               rec_bytes = 0;     /* Bytes read            */
  int                wri_bytes = 0;     /* Bytes written         */
Arne Øslebø's avatar
Arne Øslebø committed
867 868
  int                src_len = sizeof(struct sockaddr_storage);
  struct sockaddr_storage src_addr;
Sampo Saaristo's avatar
Sampo Saaristo committed
869 870 871 872 873 874 875 876
  struct timeval     time1;
  struct crude_struct  other_info;
  char buffer[PMAXSIZE];

  /* Initialize some variables */
  memset(buffer,0,PMAXSIZE);
  other_info.dest_port = htons(port);

Arne Øslebø's avatar
Arne Øslebø committed
877 878
  while(1)
  {
Sampo Saaristo's avatar
Sampo Saaristo committed
879
    rec_bytes = recvfrom(main_socket, buffer, PMAXSIZE, 0,
Arne Øslebø's avatar
Arne Øslebø committed
880 881 882
                         (struct sockaddr *)&src_addr, (socklen_t *)&src_len);
    if(rec_bytes <= 0)
    {
Sampo Saaristo's avatar
Sampo Saaristo committed
883
      RUDEBUG1("crude: error when receiving packet: %s\n",strerror(errno));
Arne Øslebø's avatar
Arne Øslebø committed
884 885 886
    }
    else
    {
Sampo Saaristo's avatar
Sampo Saaristo committed
887 888 889 890 891
      gettimeofday(&time1, NULL);
      pkt_count++;
      other_info.rx_time_seconds  = htonl(time1.tv_sec);
      other_info.rx_time_useconds = htonl(time1.tv_usec);
      other_info.pkt_size         = htonl(rec_bytes);
Arne Øslebø's avatar
Arne Øslebø committed
892 893 894 895 896 897
    	//other_info.src_port         = ((struct sockaddr_in6 *)&src_addr)->sin6_port;
      //other_info.src_addr         = ((struct sockaddr_in6 *)&src_addr)->sin6_addr;
			other_info.src 							=src_addr;
      
			
			wri_bytes = write(main_file,buffer,(sizeof(struct udp_data)));
Sampo Saaristo's avatar
Sampo Saaristo committed
898 899
      wri_bytes += write(main_file,&other_info,sizeof(struct crude_struct));
      RUDEBUG7("crude: pkt %lu (%ldbytes) status: %s\n",
Arne Øslebø's avatar
Arne Øslebø committed
900
               pkt_count, rec_bytes, strerror(errno));
Sampo Saaristo's avatar
Sampo Saaristo committed
901 902 903 904 905
    }

    if((limit != 0) && (pkt_count >= limit)){ break; }
  } /* end of while */

Arne Øslebø's avatar
Arne Øslebø committed
906
  RUDEBUG1("\ncrude: captured/processed %lu packets \n", pkt_count);
Sampo Saaristo's avatar
Sampo Saaristo committed
907 908 909 910
  return 0;
}


Arne Øslebø's avatar
Arne Øslebø committed
911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934
/*
* get_str_addr - prints address in readable format into buffer
*/
static void get_str_addr(struct sockaddr_storage src_addr,char buffer[]){
	char straddr[INET6_ADDRSTRLEN];
	switch (src_addr.ss_family) {
		case AF_INET:{
			struct sockaddr_in* dstin = (struct sockaddr_in *)&(src_addr);
			strncpy(buffer,inet_ntop(AF_INET, &(dstin->sin_addr), straddr, sizeof(straddr)),INET6_ADDRSTRLEN-1);

			}
			return;
		case AF_INET6:{
			struct sockaddr_in6* dstin = (struct sockaddr_in6 *)&(src_addr);
			strncpy(buffer,inet_ntop(AF_INET6, &(dstin->sin6_addr), straddr, sizeof(straddr)),INET6_ADDRSTRLEN-1);
			//if address starts with ::ffff: cut this part from string
			if(strncmp(buffer,preffix,strlen(preffix)) == 0){
				strncpy(buffer,straddr+strlen(preffix),INET6_ADDRSTRLEN-1);
				}
			return;
			}
		}
}

Sampo Saaristo's avatar
Sampo Saaristo committed
935 936 937 938 939 940
/*
 * rec_n_print() - print information of received packets to stdout
 */
static int rec_n_print(unsigned short port, unsigned long limit)
{
  long               rec_bytes = 0;     /* Bytes read            */
Arne Øslebø's avatar
Arne Øslebø committed
941 942
  int                src_len   = sizeof(struct sockaddr_storage);
  struct sockaddr_storage src_addr;
Sampo Saaristo's avatar
Sampo Saaristo committed
943 944
  struct timeval     time1;
  struct udp_data    *udp_ptr;
Arne Øslebø's avatar
Arne Øslebø committed
945 946
  struct sockaddr_storage  d_add;
  char buffer[PMAXSIZE], str1[INET6_ADDRSTRLEN], str2[INET6_ADDRSTRLEN];
Sampo Saaristo's avatar
Sampo Saaristo committed
947 948 949

  /* Initialize some variables */
  memset(buffer,0,PMAXSIZE);
Arne Øslebø's avatar
Arne Øslebø committed
950 951 952
  memset(str1,0,INET6_ADDRSTRLEN);
  memset(str2,0,INET6_ADDRSTRLEN);
  char srcport[10];
Sampo Saaristo's avatar
Sampo Saaristo committed
953

Arne Øslebø's avatar
Arne Øslebø committed
954 955
  while(1)
  {
Sampo Saaristo's avatar
Sampo Saaristo committed
956
    rec_bytes = recvfrom(main_socket, buffer, PMAXSIZE, 0,
Arne Øslebø's avatar
Arne Øslebø committed
957 958 959
                         (struct sockaddr *)&src_addr, (socklen_t *)&src_len);
    if(rec_bytes <= 0)
    {
Sampo Saaristo's avatar
Sampo Saaristo committed
960
      RUDEBUG1("crude: error when receiving packet: %s\n",strerror(errno));
Arne Øslebø's avatar
Arne Øslebø committed
961 962 963
    }
    else
    {
Sampo Saaristo's avatar
Sampo Saaristo committed
964 965 966
      gettimeofday(&time1, NULL);
      pkt_count++;
      udp_ptr = (struct udp_data*)buffer;
Arne Øslebø's avatar
Arne Øslebø committed
967 968 969 970 971 972 973 974 975 976 977 978 979 980
     	d_add = udp_ptr->dest_addr;   

	  get_str_addr(src_addr,str1);
	  get_str_addr(d_add,str2);		

		printf("ID=%lu SEQ=%lu SRC=%s:%hu DST=%s:%hu "
		 "Tx=%lu.%06lu Rx=%ld.%06ld SIZE=%ld\n",
		 (unsigned long)ntohl(udp_ptr->flow_id),
		 (unsigned long)ntohl(udp_ptr->sequence_number),
		 str1, ntohs(((struct sockaddr_in *)&src_addr)->sin_port), str2, port,
		 (unsigned long)ntohl(udp_ptr->tx_time_seconds),
		 (unsigned long)ntohl(udp_ptr->tx_time_useconds),
		 time1.tv_sec, time1.tv_usec, rec_bytes);
		fflush(stdout);
Sampo Saaristo's avatar
Sampo Saaristo committed
981 982 983 984 985 986 987 988
    }

    if((limit != 0) && (pkt_count >= limit)){ break; }
  } /* end of while */

  RUDEBUG1("\ncrude: captured/processed %lu packets\n", pkt_count);
  return 0;
}