dpipe and wirefilter: dynamic alternate stdin/stdout (not fixed fd anymore)
[vde.git] / vde-2 / wirefilter / wirefilter.c
blob44d8d27e86f53f689257bd377c6c1485fd0a7fd2
1 /* WIREFILTER (C) 2005 Renzo Davoli
2 * Licensed under the GPLv2
3 * Modified by Ludovico Gardenghi 2005
5 * This filter can be used for testing network protcols.
6 * It is possible to loose, delay or reorder packets.
7 * Options can be set on command line or interactively with a remote interface
8 * on a unix socket (see unixterm).
9 */
11 #include <stdio.h>
12 #include <unistd.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <getopt.h>
16 #include <errno.h>
17 #include <libgen.h>
18 #include <fcntl.h>
19 #include <time.h>
20 #include <signal.h>
21 #include <stdarg.h>
22 #include <sys/time.h>
23 #include <sys/poll.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <sys/socket.h>
27 #include <sys/un.h>
28 #include <config.h>
30 #include <vde.h>
32 #define NPIPES 2
33 #define MAXCONN 3
34 static int alternate_stdin;
35 static int alternate_stdout;
36 //#define STDIN_ALTFILENO 3
37 //#define STDOUT_ALTFILENO 4
38 #define NPFD NPIPES+MAXCONN+1
39 struct pollfd pfd[NPFD];
40 int outfd[NPIPES];
41 char *progname;
42 char *mgmt;
43 int mgmtmode=0700;
44 #define LR 0
45 #define RL 1
46 double loss[2],lossplus[2];
47 double delay[2],delayplus[2];
48 double ddup[2],ddupplus[2];
49 double band[2],bandplus[2];
50 double speed[2],speedplus[2];
51 double capacity[2],capacityplus[2];
52 double noise[2],noiseplus[2];
53 double mtu[2],mtuplus[2];
54 struct timeval nextband[2];
55 struct timeval nextspeed[2];
56 int nofifo;
57 int ndirs;
58 int bufsize[2];
60 #define BUFSIZE 2048
61 #define MAXCMD 128
62 #define MGMTMODEARG 129
63 #define KILO (1<<10)
64 #define MEGA (1<<20)
65 #define GIGA (1<<30)
67 static void readdualvalue(char *s,double *val,double *valplus)
69 double v=0.0;
70 double vplus=0.0;
71 int n;
72 int mult;
73 n=strlen(s)-1;
74 while ((s[n] == ' ' || s[n] == '\n' || s[n] == '\t') && n>0)
76 s[n]=0;
77 n--;
79 switch (s[n]) {
80 case 'k':
81 case 'K':
82 mult=KILO;
83 break;
84 case 'm':
85 case 'M':
86 mult=MEGA;
87 break;
88 case 'g':
89 case 'G':
90 mult=GIGA;
91 break;
92 default:
93 mult=1;
94 break;
96 if ((n=sscanf(s,"%lf+%lf",&v,&vplus)) > 0) {
97 val[LR]=val[RL]=v*mult;
98 valplus[LR]=valplus[RL]=vplus*mult;
99 } else if ((n=sscanf(s,"LR%lf+%lf",&v,&vplus)) > 0) {
100 val[LR]=v*mult;
101 valplus[LR]=vplus*mult;
102 } else if ((n=sscanf(s,"RL%lf+%lf",&v,&vplus)) > 0) {
103 val[RL]=v*mult;
104 valplus[RL]=vplus*mult;
108 struct packpq {
109 unsigned long long when;
110 int dir;
111 unsigned char *buf;
112 int size;
115 struct packpq **pqh;
116 struct packpq sentinel={0,0,NULL,0};
117 int npq,maxpq;
118 unsigned long long maxwhen;
120 #define PQCHUNK 100
122 static int nextms()
124 if (npq>0) {
125 long long deltat;
126 struct timeval v;
127 gettimeofday(&v,NULL);
128 deltat=pqh[1]->when-(v.tv_sec*1000000+v.tv_usec);
129 return (deltat>0)?(int)(deltat/1000):0;
131 return -1;
134 int writepacket(int dir,const unsigned char *buf,int size)
136 /* NOISE */
137 if (noise[dir]+noiseplus[dir] > 0) {
138 double noiseval=noise[dir];
139 int nobit=0;
140 if (noiseplus) noiseval+=((drand48()*2.0)-1.0)*noiseplus[dir];
141 while ((drand48()*8*MEGA) < (size-2)*8*noiseval)
142 nobit++;
143 if (nobit>0) {
144 unsigned char noisedpacket[BUFSIZE];
145 memcpy(noisedpacket,buf,size);
146 while(nobit>0) {
147 int flippedbit=(drand48()*size*8);
148 noisedpacket[(flippedbit >> 3) + 2] ^= 1<<(flippedbit & 0x7);
149 nobit--;
151 return write(outfd[dir],noisedpacket,size);
152 } else
153 return write(outfd[dir],buf,size);
154 } else
155 return write(outfd[dir],buf,size);
158 /* packet queues are priority queues implemented on a heap.
159 * enqueue time = dequeue time = O(log n) max&mean
162 static void packet_dequeue()
164 struct timeval v;
165 gettimeofday(&v,NULL);
166 unsigned long long now=v.tv_sec*1000000+v.tv_usec;
167 while (npq>0 && pqh[1]->when <= now) {
168 struct packpq *old=pqh[npq--];
169 int k=1;
170 bufsize[pqh[1]->dir] -= pqh[1]->size;
171 writepacket(pqh[1]->dir,pqh[1]->buf,pqh[1]->size);
172 free(pqh[1]->buf);
173 free(pqh[1]);
174 while (k<= npq>>1)
176 int j= k<<1;
177 if (j<npq && pqh[j]->when > pqh[j+1]->when) j++;
178 if (old->when <= pqh[j]->when) {
179 break;
180 } else {
181 pqh[k]=pqh[j];k=j;
184 pqh[k]=old;
188 static void packet_enqueue(int dir,const unsigned char *buf,int size,int delms)
190 struct timeval v;
192 /* CAPACITY */
193 if (capacity[dir]+capacityplus[dir] > 0) {
194 double capval=capacity[dir];
195 if (capacityplus[dir])
196 capval+=((drand48()*2.0)-1.0)*capacityplus[dir];
197 if ((bufsize[dir]+size) > capval)
198 return;
200 /* */
202 struct packpq *new=malloc(sizeof(struct packpq));
203 if (new==NULL) {
204 fprintf(stderr,"%s: malloc elem %s\n",progname,strerror(errno));
205 exit (1);
207 gettimeofday(&v,NULL);
208 new->when=v.tv_sec * 1000000 + v.tv_usec + delms * 1000;
209 if (new->when > maxwhen) maxwhen=new->when;
210 if (!nofifo && new->when < maxwhen) new->when=maxwhen;
211 new->dir=dir;
212 new->buf=malloc(size);
213 if (new->buf==NULL) {
214 fprintf(stderr,"%s: malloc elem buf %s\n",progname,strerror(errno));
215 exit (1);
217 memcpy(new->buf,buf,size);
218 new->size=size;
219 bufsize[dir]+=size;
220 if (pqh==NULL) {
221 pqh=malloc(PQCHUNK*sizeof(struct packpq *));
222 if (pqh==NULL) {
223 fprintf(stderr,"%s: malloc %s\n",progname,strerror(errno));
224 exit (1);
226 pqh[0]=&sentinel; maxpq=PQCHUNK;
228 if (npq >= maxpq) {
229 pqh=realloc(pqh,(maxpq=maxpq+PQCHUNK) * sizeof(struct packpq *));
230 if (pqh==NULL) {
231 fprintf(stderr,"%s: malloc %s\n",progname,strerror(errno));
232 exit (1);
235 {int k=++npq;
236 while (new->when < pqh[k>>1]->when) {
237 pqh[k]=pqh[k>>1];
238 k >>= 1;
240 pqh[k]=new;
244 void handle_packet(int dir,const unsigned char *buf,int size)
246 /* MTU */
247 if (mtu[dir] > 0 && size > mtu[dir])
248 return;
250 /* LOSS */
251 if (loss[dir]-lossplus[dir] >= 100.0)
252 return;
253 if (loss[dir]+lossplus[dir] > 0) {
254 double losval=(loss[dir]+((drand48()*2.0)-1.0)*lossplus[dir])/100;
255 if (drand48() < losval)
256 return;
259 /* DUP */
260 int times=1;
261 if (ddup[dir]+ddupplus[dir] > 0) {
262 double dupval=(ddup[dir]+((drand48()*2.0)-1.0)*ddupplus[dir])/100;
263 while (drand48() < dupval)
264 times++;
266 while (times>0) {
267 int banddelay=0;
269 /* SPEED */
270 if (speed[dir]+speedplus[dir] > 0) {
271 double speedval=speed[dir];
272 if (speedplus[dir]) {
273 speedval+=((drand48()*2.0)-1.0)*speedplus[dir];
274 if (speedval<=0) return;
276 if (speed>0) {
277 unsigned int commtime=((unsigned)size)*1000000/((unsigned int)speedval);
278 struct timeval tv;
279 gettimeofday(&tv,NULL);
280 banddelay=commtime/1000;
281 if (timercmp(&tv,&nextspeed[dir], > ))
282 nextspeed[dir]=tv;
283 nextspeed[dir].tv_usec += commtime;
284 nextspeed[dir].tv_sec += nextspeed[dir].tv_usec / 1000000;
285 nextspeed[dir].tv_usec %= 1000000;
289 /* BANDWIDTH */
290 if (band[dir]+bandplus[dir] > 0) {
291 double bandval=band[dir];
292 if (bandplus[dir]) {
293 bandval+=((drand48()*2.0)-1.0)*bandplus[dir];
294 if (bandval<=0) return;
296 if (band>0) {
297 unsigned int commtime=((unsigned)size)*1000000/((unsigned int)bandval);
298 struct timeval tv;
299 gettimeofday(&tv,NULL);
300 if (timercmp(&tv,&nextband[dir], > )) {
301 nextband[dir]=tv;
302 banddelay=commtime/1000;
303 } else {
304 timersub(&nextband[dir],&tv,&tv);
305 banddelay=tv.tv_sec*1000 + (tv.tv_usec + commtime)/1000;
307 nextband[dir].tv_usec += commtime;
308 nextband[dir].tv_sec += nextband[dir].tv_usec / 1000000;
309 nextband[dir].tv_usec %= 1000000;
310 } else
311 banddelay=-1;
314 /* DELAY */
315 if (banddelay >= 0) {
316 if (banddelay > 0 || delay[dir]+delayplus[dir] > 0) {
317 double delval=(delay[dir]+((drand48()*2.0)-1.0)*delayplus[dir]);
318 delval=(delval >= 0)?delval+banddelay:banddelay;
319 if (delval > 0) {
320 packet_enqueue(dir,buf,size,(int) delval);
321 } else
322 writepacket(dir,buf,size);
323 } else
324 writepacket(dir,buf,size);
326 times--;
330 #define MIN(X,Y) (((X)<(Y))?(X):(Y))
332 static void splitpacket(const unsigned char *buf,int size,int dir)
334 static unsigned char fragment[BUFSIZE][2];
335 static unsigned char *fragp[2];
336 static unsigned int rnx[2],remaining[2];
338 //fprintf(stderr,"%s: splitpacket rnx=%d remaining=%d size=%d\n",progname,rnx[dir],remaining[dir],size);
339 if (size==0) return;
340 if (rnx[dir]>0) {
341 register int amount=MIN(remaining[dir],size);
342 //fprintf(stderr,"%s: fragment amount %d\n",progname,amount);
343 memcpy(fragp[dir],buf,amount);
344 remaining[dir]-=amount;
345 fragp[dir]+=amount;
346 buf+=amount;
347 size-=amount;
348 if (remaining[dir]==0) {
349 //fprintf(stderr,"%s: delivered defrag %d\n",progname,rnx[dir]);
350 handle_packet(dir,fragment[dir],rnx[dir]+2);
351 rnx[dir]=0;
354 while (size > 0) {
355 rnx[dir]=(buf[0]<<8)+buf[1];
356 //fprintf(stderr,"%s: packet %d size %d %x %x dir %d\n",progname,rnx[dir],size-2,buf[0],buf[1],dir);
357 if (rnx[dir]>1521) {
358 fprintf(stderr,"%s: Packet length error size %d rnx %d\n",progname,size,rnx[dir]);
359 rnx[dir]=0;
360 return;
362 if (rnx[dir]+2 > size) {
363 //fprintf(stderr,"%s: begin defrag %d\n",progname,rnx[dir]);
364 fragp[dir]=fragment[dir];
365 memcpy(fragp[dir],buf,size);
366 remaining[dir]=rnx[dir]+2-size;
367 fragp[dir]+=size;
368 size=0;
369 } else {
370 handle_packet(dir,buf,rnx[dir]+2);
371 buf+=rnx[dir]+2;
372 size-=rnx[dir]+2;
373 rnx[dir]=0;
378 static void packet_in(int dir)
380 unsigned char buf[BUFSIZE];
381 int n;
382 n=read(pfd[dir].fd,buf,BUFSIZE);
383 if (n == 0)
384 exit (0);
385 splitpacket(buf,n,dir);
388 static void initrand()
390 struct timeval v;
391 gettimeofday(&v,NULL);
392 srand48(v.tv_sec ^ v.tv_usec ^ getpid());
395 static int check_open_fifos(struct pollfd *pfd,int *outfd)
397 int ndirs;
398 struct stat stfd[NPIPES];
399 char *env_in;
400 char *env_out;
401 env_in=getenv("ALTERNATE_STDIN");
402 env_out=getenv("ALTERNATE_STDOUT");
403 if (env_in != NULL)
404 alternate_stdin=atoi(env_in);
405 if (env_out != NULL)
406 alternate_stdout=atoi(env_out);
407 if (fstat(STDIN_FILENO,&stfd[STDIN_FILENO]) < 0) {
408 fprintf(stderr,"%s: Error on stdin: %s\n",progname,strerror(errno));
409 return -1;
411 if (fstat(STDOUT_FILENO,&stfd[STDOUT_FILENO]) < 0) {
412 fprintf(stderr,"%s: Error on stdout: %s\n",progname,strerror(errno));
413 return -1;
415 if (!S_ISFIFO(stfd[STDIN_FILENO].st_mode)) {
416 fprintf(stderr,"%s: Error on stdin: %s\n",progname,"it is not a pipe");
417 return -1;
419 if (!S_ISFIFO(stfd[STDOUT_FILENO].st_mode)) {
420 fprintf(stderr,"%s: Error on stdin: %s\n",progname,"it is not a pipe");
421 return -1;
423 if (env_in == NULL || fstat(alternate_stdin,&stfd[0]) < 0) {
424 ndirs=1;
425 pfd[0].fd=STDIN_FILENO;
426 pfd[0].events=POLLIN | POLLHUP;
427 pfd[0].revents=0;
428 outfd[0]=STDOUT_FILENO;
429 } else {
430 if (fstat(outfd[1],&stfd[1]) < 0) {
431 fprintf(stderr,"%s: Error on secondary out: %s\n",progname,strerror(errno));
432 return -1;
434 if (!S_ISFIFO(stfd[0].st_mode)) {
435 fprintf(stderr,"%s: Error on secondary in: %s\n",progname,"it is not a pipe");
436 return -1;
438 if (!S_ISFIFO(stfd[1].st_mode)) {
439 fprintf(stderr,"%s: Error on secondary out: %s\n",progname,"it is not a pipe");
440 return -1;
442 ndirs=2;
443 pfd[LR].fd=STDIN_FILENO;
444 pfd[LR].events=POLLIN | POLLHUP;
445 pfd[LR].revents=0;
446 outfd[LR]=alternate_stdout;
447 pfd[RL].fd=alternate_stdin;
448 pfd[RL].events=POLLIN | POLLHUP;
449 pfd[RL].revents=0;
450 outfd[RL]=STDOUT_FILENO;
452 return ndirs;
455 static void cleanup(void)
457 if (mgmt)
458 unlink(mgmt);
461 static void sig_handler(int sig)
463 /*fprintf(stderr,"Caught signal %d, cleaning up and exiting", sig);*/
464 cleanup();
465 signal(sig, SIG_DFL);
466 kill(getpid(), sig);
469 static void setsighandlers()
471 /* setting signal handlers.
472 * * * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
473 * * * ignores all the others signals which could cause termination. */
474 struct { int sig; const char *name; int ignore; } signals[] = {
475 { SIGHUP, "SIGHUP", 0 },
476 { SIGINT, "SIGINT", 0 },
477 { SIGPIPE, "SIGPIPE", 1 },
478 { SIGALRM, "SIGALRM", 1 },
479 { SIGTERM, "SIGTERM", 0 },
480 { SIGUSR1, "SIGUSR1", 1 },
481 { SIGUSR2, "SIGUSR2", 1 },
482 { SIGPROF, "SIGPROF", 1 },
483 { SIGVTALRM, "SIGVTALRM", 1 },
484 #ifdef VDE_LINUX
485 { SIGPOLL, "SIGPOLL", 1 },
486 { SIGSTKFLT, "SIGSTKFLT", 1 },
487 { SIGIO, "SIGIO", 1 },
488 { SIGPWR, "SIGPWR", 1 },
489 { SIGUNUSED, "SIGUNUSED", 1 },
490 #endif
491 #ifdef VDE_DARWIN
492 { SIGXCPU, "SIGXCPU", 1 },
493 { SIGXFSZ, "SIGXFSZ", 1 },
494 #endif
495 { 0, NULL, 0 }
498 int i;
499 for(i = 0; signals[i].sig != 0; i++)
500 if(signal(signals[i].sig,
501 signals[i].ignore ? SIG_IGN : sig_handler) < 0)
502 fprintf(stderr,"%s: Setting handler for %s: %s", progname, signals[i].name,
503 strerror(errno));
506 static int openmgmt(char *mgmt)
508 int mgmtconnfd;
509 struct sockaddr_un sun;
510 int one = 1;
512 if((mgmtconnfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0){
513 fprintf(stderr,"%s: mgmt socket: %s",progname,strerror(errno));
514 exit(1);
516 if(setsockopt(mgmtconnfd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
517 sizeof(one)) < 0){
518 fprintf(stderr,"%s: mgmt setsockopt: %s",progname,strerror(errno));
519 exit(1);
521 if(fcntl(mgmtconnfd, F_SETFL, O_NONBLOCK) < 0){
522 fprintf(stderr,"%s: Setting O_NONBLOCK on mgmt fd: %s",progname,strerror(errno));
523 exit(1);
525 sun.sun_family = PF_UNIX;
526 snprintf(sun.sun_path,sizeof(sun.sun_path),"%s",mgmt);
527 if(bind(mgmtconnfd, (struct sockaddr *) &sun, sizeof(sun)) < 0){
528 fprintf(stderr,"%s: mgmt bind %s",progname,strerror(errno));
529 exit(1);
531 chmod(sun.sun_path,mgmtmode);
532 if(listen(mgmtconnfd, 15) < 0){
533 fprintf(stderr,"%s: mgmt listen: %s",progname,strerror(errno));
534 exit(1);
536 return mgmtconnfd;
539 static char header[]="\nVDE wirefilter V.%s\n(C) R.Davoli 2005 - GPLv2\n";
540 static char prompt[]="\nVDEwf:";
541 static int newmgmtconn(int fd,struct pollfd *pfd,int nfds)
543 int new;
544 unsigned int len;
545 char buf[MAXCMD];
546 struct sockaddr addr;
547 new = accept(fd, &addr, &len);
548 if(new < 0){
549 fprintf(stderr,"%s: mgmt accept %s",progname,strerror(errno));
550 return nfds;
552 if (nfds < NPFD) {
553 snprintf(buf,MAXCMD,header,PACKAGE_VERSION);
554 write(new,buf,strlen(buf));
555 write(new,prompt,strlen(prompt));
556 pfd[nfds].fd=new;
557 pfd[nfds].events=POLLIN | POLLHUP;
558 pfd[nfds].revents=0;
559 return ++nfds;
560 } else {
561 fprintf(stderr,"%s: too many mgmt connections",progname);
562 close (new);
563 return nfds;
567 static void printoutc(int fd, const char *format, ...)
569 va_list arg;
570 char outbuf[MAXCMD+1];
572 va_start (arg, format);
573 vsnprintf(outbuf,MAXCMD,format,arg);
574 strcat(outbuf,"\n");
575 write(fd,outbuf,strlen(outbuf));
578 static int setdelay(int fd,char *s)
580 readdualvalue(s,delay,delayplus);
581 return 0;
584 static int setloss(int fd,char *s)
586 readdualvalue(s,loss,lossplus);
587 return 0;
590 static int setddup(int fd,char *s)
592 readdualvalue(s,ddup,ddupplus);
593 return 0;
596 static int setband(int fd,char *s)
598 readdualvalue(s,band,bandplus);
599 return 0;
602 static int setnoise(int fd,char *s)
604 readdualvalue(s,noise,noiseplus);
605 return 0;
608 static int setmtu(int fd,char *s)
610 readdualvalue(s,mtu,mtuplus);
611 return 0;
614 static int setspeed(int fd,char *s)
616 readdualvalue(s,speed,speedplus);
617 return 0;
620 static int setcapacity(int fd,char *s)
622 readdualvalue(s,capacity,capacityplus);
623 return 0;
626 static int setfifo(int fd,char *s)
628 int n=atoi(s);
629 if (n==0)
630 nofifo=1;
631 else
632 nofifo=0;
633 return 0;
636 static int logout(int fd,char *s)
638 return -1;
641 static int doshutdown(int fd,char *s)
643 exit(0);
647 static int help(int fd,char *s)
649 printoutc(fd, "help: print a summary of mgmt commands");
650 printoutc(fd, "showinfo: show status and parameter values");
651 printoutc(fd, "loss: set loss percentage");
652 printoutc(fd, "delay: set delay ms");
653 printoutc(fd, "dup: set dup packet percentage");
654 printoutc(fd, "bandwidth: set channel bandwidth bytes/sec");
655 printoutc(fd, "speed: set interface speed bytes/sec");
656 printoutc(fd, "noise: set noise factor bits/Mbyte");
657 printoutc(fd, "mtu: set channel MTU (bytes)");
658 printoutc(fd, "capacity: set channel capacity (bytes)");
659 printoutc(fd, "fifo: set channel fifoness");
660 printoutc(fd, "shutdown: shut the channel down");
661 printoutc(fd, "logout: log out from this mgmt session");
662 return 0;
665 static int showinfo(int fd,char *s)
667 printoutc(fd, "WireFilter: %sdirectional",(ndirs==2)?"bi":"mono");
668 if (ndirs==2) {
669 printoutc(fd, "Loss L->R %g+%g R->L %g+%g",loss[LR],lossplus[LR],loss[RL],lossplus[RL]);
670 printoutc(fd, "Delay L->R %g+%g R->L %g+%g",delay[LR],delayplus[LR],delay[RL],delayplus[RL]);
671 printoutc(fd, "Dup L->R %g+%g R->L %g+%g",ddup[LR],ddupplus[LR],ddup[RL],ddupplus[RL]);
672 printoutc(fd, "Bandw L->R %g+%g R->L %g+%g",band[LR],bandplus[LR],band[RL],bandplus[RL]);
673 printoutc(fd, "Speed L->R %g+%g R->L %g+%g",speed[LR],speedplus[LR],speed[RL],speedplus[RL]);
674 printoutc(fd, "Noise L->R %g+%g R->L %g+%g",noise[LR],noiseplus[LR],noise[RL],noiseplus[RL]);
675 printoutc(fd, "MTU L->R %g R->L %g ",mtu[LR],mtu[RL]);
676 printoutc(fd, "Cap. L->R %g+%g R->L %g+%g",capacity[LR],capacityplus[LR],capacity[RL],capacityplus[RL]);
677 printoutc(fd, "Current Delay Queue size: L->R %d R->L %d ",bufsize[LR],bufsize[RL]);
678 } else {
679 printoutc(fd, "Loss %g+%g",loss[0],lossplus[0]);
680 printoutc(fd, "Delay %g+%g",delay[0],delayplus[0]);
681 printoutc(fd, "Dup %g+%g",ddup[0],ddupplus[0]);
682 printoutc(fd, "Bandw %g+%g",band[0],bandplus[0]);
683 printoutc(fd, "Speed %g+%g",speed[0],speedplus[0]);
684 printoutc(fd, "Noise %g+%g",noise[0],noiseplus[0]);
685 printoutc(fd, "MTU %g",mtu[0]);
686 printoutc(fd, "Cap. %g+%g",capacity[0],capacityplus[0]);
687 printoutc(fd, "Current Delay Queue size: %d",bufsize[0]);
689 printoutc(fd,"Fifoness %s",(nofifo == 0)?"TRUE":"FALSE");
690 printoutc(fd,"Waiting packets in delay queues %d",npq);
691 return 0;
694 static struct comlist {
695 char *tag;
696 int (*fun)(int fd,char *arg);
697 } commandlist [] = {
698 {"help", help},
699 {"showinfo",showinfo},
700 {"delay",setdelay},
701 {"loss",setloss},
702 {"dup",setddup},
703 {"bandwidth",setband},
704 {"band",setband},
705 {"speed",setspeed},
706 {"capacity",setcapacity},
707 {"noise",setnoise},
708 {"mtu",setmtu},
709 {"fifo",setfifo},
710 {"logout",logout},
711 {"shutdown",doshutdown}
714 #define NCL sizeof(commandlist)/sizeof(struct comlist)
716 static int handle_cmd(int fd,char *inbuf)
718 int rv=ENOSYS;
719 int i;
720 while (*inbuf == ' ' || *inbuf == '\t') inbuf++;
721 if (*inbuf != '\0' && *inbuf != '#') {
722 for (i=0; i<NCL
723 && strncmp(commandlist[i].tag,inbuf,strlen(commandlist[i].tag))!=0;
724 i++)
726 if (i<NCL)
728 inbuf += strlen(commandlist[i].tag);
729 while (*inbuf == ' ' || *inbuf == '\t') inbuf++;
730 rv=commandlist[i].fun(fd,inbuf);
732 printoutc(fd,"1%03d %s",rv,strerror(rv));
733 return rv;
735 return rv;
738 static int mgmtcommand(int fd)
740 char buf[MAXCMD+1];
741 int n,rv;
742 n = read(fd, buf, MAXCMD);
743 if (n<0) {
744 fprintf(stderr,"%s: read from mgmt %s",progname,strerror(errno));
745 return 0;
747 else if (n==0)
748 return -1;
749 else {
750 buf[n]=0;
751 rv=handle_cmd(fd,buf);
752 if (rv>=0)
753 write(fd,prompt,strlen(prompt));
754 return rv;
758 static int delmgmtconn(int i,struct pollfd *pfd,int nfds)
760 if (i<nfds) {
761 close(pfd[i].fd);
762 memmove(pfd+i,pfd+i+1,sizeof (struct pollfd) * (nfds-i-1));
763 nfds--;
765 return nfds;
768 void usage(void)
770 fprintf(stderr,"Usage: %s OPTIONS\n"
771 "\t--help|-h\n"
772 "\t--loss|-l loss_percentage\n"
773 "\t--delay|-d delay_ms\n"
774 "\t--dup|-D dup_percentage\n"
775 "\t--band|-b bandwidth(bytes/s)\n"
776 "\t--speed|-s interface_speed(bytes/s)\n"
777 "\t--capacity|-c delay_channel_capacity\n"
778 "\t--noise|-n noise_bits/megabye\n"
779 "\t--mtu|-m mtu_size\n"
780 "\t--nofifo|-N\n"
781 "\t--mgmt|-M management_socket\n"
782 "\t--mgmtmode management_permission(octal)\n"
783 ,progname);
784 exit (1);
787 int main(int argc,char *argv[])
789 int n;
790 int npfd;
791 int option_index;
792 int mgmtindex=-1;
793 static struct option long_options[] = {
794 {"help",0 , 0, 'h'},
795 {"loss", 1, 0, 'l'},
796 {"delay",1 , 0, 'd'},
797 {"dup",1 , 0, 'D'},
798 {"band",1 , 0, 'b'},
799 {"speed",1 , 0, 's'},
800 {"capacity",1 , 0, 'c'},
801 {"noise",1 , 0, 'n'},
802 {"mtu",1 , 0, 'm'},
803 {"nofifo",0 , 0, 'N'},
804 {"mgmt", 1, 0, 'M'},
805 {"mgmtmode", 1, 0, MGMTMODEARG}
807 progname=basename(argv[0]);
809 setsighandlers();
810 atexit(cleanup);
812 ndirs=check_open_fifos(pfd,outfd);
813 if (ndirs < 0)
814 usage();
816 while(1) {
817 int c;
818 c = GETOPT_LONG (argc, argv, "hnl:d:M:D:m:b:s:c:",
819 long_options, &option_index);
820 if (c<0)
821 break;
822 switch (c) {
823 case 'h':
824 usage();
825 break;
826 case 'd':
827 readdualvalue(optarg,delay,delayplus);
828 break;
829 case 'l':
830 readdualvalue(optarg,loss,lossplus);
831 break;
832 case 'D':
833 readdualvalue(optarg,ddup,ddupplus);
834 break;
835 case 'b':
836 readdualvalue(optarg,band,bandplus);
837 break;
838 case 'm':
839 readdualvalue(optarg,mtu,mtuplus);
840 break;
841 case 'n':
842 readdualvalue(optarg,noise,noiseplus);
843 break;
844 case 's':
845 readdualvalue(optarg,speed,speedplus);
846 break;
847 case 'c':
848 readdualvalue(optarg,capacity,capacityplus);
849 break;
850 case 'M':
851 mgmt=strdup(optarg);
852 break;
853 case 'N':
854 nofifo=1;
855 break;
856 case MGMTMODEARG:
857 sscanf(optarg,"%o",&mgmtmode);
858 break;
859 default:
860 usage();
861 break;
864 if (optind < argc)
865 usage();
867 if (ndirs==2)
868 fprintf(stderr,"%s: bidirectional filter starting...\n",progname);
869 else
870 fprintf(stderr,"%s: monodirectional filter starting...\n",progname);
872 npfd=ndirs;
874 if(mgmt != NULL) {
875 int mgmtfd=openmgmt(mgmt);
876 mgmtindex=npfd;
877 pfd[mgmtindex].fd=mgmtfd;
878 pfd[mgmtindex].events=POLLIN | POLLHUP;
879 pfd[mgmtindex].revents=0;
880 npfd++;
883 initrand();
884 while(1) {
885 int delay=nextms();
886 pfd[0].events |= POLLIN;
887 if (speed[LR] > 0) {
888 struct timeval tv;
889 int speeddelay;
890 gettimeofday(&tv,NULL);
891 if (timercmp(&tv, &nextspeed[LR], <)) {
892 timersub(&nextspeed[LR],&tv,&tv);
893 speeddelay=tv.tv_sec*1000 + tv.tv_usec/1000;
894 if (speeddelay > 0) {
895 pfd[0].events &= ~POLLIN;
896 if (speeddelay < delay || delay < 0) delay=speeddelay;
900 if (ndirs > 1) {
901 pfd[1].events |= POLLIN;
902 if (speed[RL] > 0) {
903 struct timeval tv;
904 int speeddelay;
905 if (timercmp(&tv, &nextspeed[RL], <)) {
906 gettimeofday(&tv,NULL);
907 timersub(&nextspeed[RL],&tv,&tv);
908 speeddelay=tv.tv_sec*1000 + tv.tv_usec/1000;
909 if (speeddelay > 0) {
910 pfd[1].events &= ~POLLIN;
911 if (speeddelay < delay || delay < 0) delay=speeddelay;
916 n=poll(pfd,npfd,delay);
917 if (pfd[0].revents & POLLHUP || (ndirs>1 && pfd[1].revents & POLLHUP))
918 exit(0);
919 if (pfd[0].revents & POLLIN) {
920 packet_in(LR);
922 if (ndirs>1 && pfd[1].revents & POLLIN) {
923 packet_in(RL);
925 if (mgmtindex >= 0 && pfd[mgmtindex].revents != 0)
926 npfd=newmgmtconn(pfd[mgmtindex].fd,pfd,npfd);
927 if (npfd > mgmtindex+1) {
928 register int i;
929 for (i=mgmtindex+1;i<npfd;i++) {
930 if (pfd[i].revents & POLLHUP ||
931 (pfd[i].revents & POLLIN && mgmtcommand(pfd[i].fd) < 0))
932 npfd=delmgmtconn(i,pfd,npfd);
935 packet_dequeue();