In 2014, I think we can stop trying to outsmart the compiler. Remove
[vde.git] / vde-2 / src / wirefilter.c
blobc6ff9ef4e89b7cbb95110875d4700e8af0e2919d
1 /* WIREFILTER (C) 2005 Renzo Davoli
2 * Licensed under the GPLv2
3 * Modified by Ludovico Gardenghi 2005
4 * Modified by Renzo Davoli, Luca Bigliardi 2007
5 * Modified by Renzo Davoli, Luca Raggi 2009 (Markov chain support)
6 * Gauss normal distribution/blinking support, requested and parlty implemented
7 * by Luca Saiu and Jean-Vincent Loddo (Marionnet project)
8 * Gilbert model for packet loss requested by Leandro Galvao.
10 * This filter can be used for testing network protcols.
11 * It is possible to loose, delay or reorder packets.
12 * Options can be set on command line or interactively with a remote interface
13 * on a unix socket (see unixterm).
16 #define _GNU_SOURCE
17 #include <stdio.h>
18 #include <unistd.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <getopt.h>
22 #include <errno.h>
23 #include <libgen.h>
24 #include <syslog.h>
25 #include <fcntl.h>
26 #include <time.h>
27 #include <signal.h>
28 #include <math.h>
29 #include <stdarg.h>
30 #include <limits.h>
31 #include <sys/time.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <sys/socket.h>
35 #include <sys/un.h>
37 #include <config.h>
38 #include <vde.h>
39 #include <vdecommon.h>
40 #include <libvdeplug.h>
42 #if defined(VDE_DARWIN) || defined(VDE_FREEBSD)
43 # if defined HAVE_SYSLIMITS_H
44 # include <syslimits.h>
45 # elif defined HAVE_SYS_SYSLIMITS_H
46 # include <sys/syslimits.h>
47 # else
48 # error "No syslimits.h found"
49 # endif
50 #endif
52 #define NPIPES 2
53 #define MAXCONN 3
54 static int alternate_stdin;
55 static int alternate_stdout;
56 #define NPFD NPIPES+NPIPES+MAXCONN+1
57 struct pollfd pfd[NPFD]={[0 ... NPFD-1 ]={.fd=-1}};
58 int outfd[NPIPES];
59 char debuglevel[NPFD];
60 char *progname;
61 char *mgmt;
62 int mgmtmode=0700;
63 #define LR 0
64 #define RL 1
65 #define ALGO_UNIFORM 0
66 #define ALGO_GAUSS_NORMAL 1
67 static char charalgo[]="UN";
68 struct wirevalue {
69 double value;
70 double plus;
71 char alg;
74 #define LOSS 0
75 #define LOSTBURST 1
76 #define DELAY 2
77 #define DDUP 3
78 #define BAND 4
79 #define SPEED 5
80 #define CHANBUFSIZE 6
81 #define NOISE 7
82 #define MTU 8
83 #define NUMVALUES 9
85 /* general Markov chain approach */
86 int markov_numnodes=0;
87 int markov_current=0;
88 struct markov_node {
89 char *name;
90 struct wirevalue val[NUMVALUES][2];
92 double *adjmap;
93 #define ADJMAPN(M,I,J,N) (M)[(I)*(N)+(J)]
94 #define ADJMAP(I,J) ADJMAPN(adjmap,(I),(J),markov_numnodes)
95 #define ROT(I,J) (((I)+(J))%markov_numnodes)
96 struct markov_node **markov_nodes;
97 #define WFVAL(N,T,D) (markov_nodes[N]->val[T][D])
98 #define WFADDR(N,T) (markov_nodes[N]->val[T])
99 #define WFNAME(N) (markov_nodes[N]->name)
100 double markov_time=100.0;
101 long long markov_next;
103 /*for the Gilbert model */
104 #define OK_BURST 0
105 #define FAULTY_BURST 1
106 char loss_status[2]; /* Gilbert model Markov chain status */
107 struct timeval nextband[2];
108 struct timeval nextspeed[2];
109 int nofifo;
110 int ndirs; //1 mono directional, 2 bi directional filter (always 2 with -v)
111 int delay_bufsize[2]; //total size of delayed packets
112 char *vdepath[2]; //path of the directly connected switched (via vde_plug)
113 VDECONN *vdeplug[2]; //vde_plug connections (if NULL stdin/stdout)
114 int daemonize; // daemon mode
115 static int logok=0;
116 static char *rcfile;
117 static char *pidfile = NULL;
118 static char pidfile_path[PATH_MAX];
119 static int blinksock;
120 static struct sockaddr_un blinksun;
121 static char *blinkmsg;
122 static char blinkidlen;
124 static void printoutc(int fd, const char *format, ...);
125 /* markov node mgmt */
126 static inline struct markov_node *markov_node_new(void)
128 return calloc(1,sizeof(struct markov_node));
131 static inline void markov_node_free(struct markov_node *old)
133 free(old);
136 static void markov_compute(i)
138 int j;
139 ADJMAP(i,i)=100.0;
140 for (j=1;j<markov_numnodes;j++)
141 ADJMAP(i,i)-=ADJMAP(i,ROT(i,j));
144 static void copyadjmap(int newsize, double *newmap)
146 int i,j;
147 for (i=0;i<newsize;i++) {
148 ADJMAPN(newmap,i,i,newsize)=100.0;
149 for (j=1;j<newsize;j++) {
150 int newj=(i+j)%newsize;
151 if (i<markov_numnodes && newj<markov_numnodes)
152 ADJMAPN(newmap,i,i,newsize)-=
153 (ADJMAPN(newmap,i,newj,newsize) = ADJMAP(i,newj));
158 static void markov_resize(int numnodes)
160 if (numnodes != markov_numnodes) {
161 int i;
162 double *newadjmap=calloc(numnodes*numnodes,sizeof(double));
163 if (numnodes>markov_numnodes) {
164 markov_nodes=realloc(markov_nodes,numnodes*(sizeof(struct markov_node *)));
165 for (i=markov_numnodes;i<numnodes;i++)
166 markov_nodes[i]=markov_node_new();
167 } else {
168 for (i=numnodes;i<markov_numnodes;i++)
169 markov_node_free(markov_nodes[i]);
170 markov_nodes=realloc(markov_nodes,numnodes*(sizeof(struct markov_node *)));
171 if (markov_current >= numnodes)
172 markov_current = 0;
174 copyadjmap(numnodes,newadjmap);
175 if (adjmap)
176 free(adjmap);
177 adjmap=newadjmap;
178 markov_numnodes=numnodes;
182 static int markov_step(int i) {
183 double num=drand48() * 100;
184 int j,k=0;
185 markov_next+=markov_time;
186 for (j=0;j<markov_numnodes;j++) {
187 k=ROT(i,j);
188 double val=ADJMAP(i,ROT(i,j));
189 if (num <= val)
190 break;
191 else
192 num -= val;
194 if (i != k) {
195 for (j=0;j<NPFD;j++) {
196 if (debuglevel[j] > 0) {
197 int fd=pfd[j].fd;
198 if (fd == 0) fd=1;
199 printoutc(fd,"%04d Node %d \"%s\" -> %d \"%s\"",
200 3800+k,
201 i, WFNAME(i)?WFNAME(i):"",
202 k, WFNAME(k)?WFNAME(k):"");
206 return k;
209 static int markovms(void) {
210 if (markov_numnodes > 1) {
211 struct timeval v;
212 gettimeofday(&v,NULL);
213 unsigned long long next=markov_next-(v.tv_sec*1000+v.tv_usec/1000);
214 if (next < 0) next=0;
215 return next;
216 } else
217 return -1;
220 static inline void markov_try(void) {
221 if (markov_numnodes > 1) {
222 struct timeval v;
223 gettimeofday(&v,NULL);
224 if ((markov_next-(v.tv_sec*1000+v.tv_usec/1000)) <= 0)
225 markov_current=markov_step(markov_current);
229 static void markov_start(void) {
230 if (markov_numnodes > 1) {
231 struct timeval v;
232 gettimeofday(&v,NULL);
233 markov_next=v.tv_sec*1000+v.tv_usec/1000;
234 markov_current=markov_step(markov_current);
238 #define BUFSIZE 2048
239 #define MAXCMD 128
240 #define MGMTMODEARG 129
241 #define DAEMONIZEARG 130
242 #define PIDFILEARG 131
243 #define LOGSOCKETARG 132
244 #define LOGIDARG 133
245 #define KILO (1<<10)
246 #define MEGA (1<<20)
247 #define GIGA (1<<30)
249 static inline double max_wirevalue(int node,int tag, int dir)
251 return (WFVAL(node,tag,dir).value + WFVAL(node,tag,dir).plus);
254 static inline double min_wirevalue(int node,int tag, int dir)
256 return (WFVAL(node,tag,dir).value - WFVAL(node,tag,dir).plus);
259 static void initrand()
261 struct timeval v;
262 gettimeofday(&v,NULL);
263 srand48(v.tv_sec ^ v.tv_usec ^ getpid());
266 /*more than 98% inside the bell */
267 #define SIGMA (1.0/3.0)
268 static double compute_wirevalue(int tag, int dir)
270 struct wirevalue *wv=&WFVAL(markov_current,tag,dir);
271 if (wv->plus == 0)
272 return wv->value;
273 switch (wv->alg) {
274 case ALGO_UNIFORM:
275 return wv->value+wv->plus*((drand48()*2.0)-1.0);
276 case ALGO_GAUSS_NORMAL:
278 double x,y,r2;
279 do {
280 x = (2*drand48())-1;
281 y = (2*drand48())-1;
282 r2=x*x+y*y;
283 } while (r2 >= 1.0);
284 return wv->value+wv->plus* SIGMA * x * sqrt ( (-2 * log(r2)) /r2);
286 default:
287 return 0.0;
291 void printlog(int priority, const char *format, ...)
293 va_list arg;
295 va_start (arg, format);
297 if (logok)
298 vsyslog(priority,format,arg);
299 else {
300 fprintf(stderr,"%s: ",progname);
301 vfprintf(stderr,format,arg);
302 fprintf(stderr,"\n");
304 va_end (arg);
307 static int read_wirevalue(char *s, int tag)
309 struct wirevalue *wv;
310 int markov_node=0;
311 double v=0.0;
312 double vplus=0.0;
313 int n;
314 int mult;
315 char algo=ALGO_UNIFORM;
316 n=strlen(s)-1;
317 while ((s[n] == ' ' || s[n] == '\n' || s[n] == '\t') && n>0)
318 s[n--]=0;
319 if (s[n]==']')
321 char *idstr=&s[n];
322 s[n--] = 0;
323 while(s[n]!='[' && n>1)
324 idstr = &s[n--];
325 s[n--] = 0;
326 sscanf(idstr,"%d",&markov_node);
327 if (markov_node < 0 || markov_node >= markov_numnodes)
328 return EINVAL;
330 wv=WFADDR(markov_node,tag);
331 switch (s[n]) {
332 case 'u':
333 case 'U':
334 algo=ALGO_UNIFORM;
335 n--;
336 break;
337 case 'n':
338 case 'N':
339 algo=ALGO_GAUSS_NORMAL;
340 n--;
341 break;
343 switch (s[n]) {
344 case 'k':
345 case 'K':
346 mult=KILO;
347 break;
348 case 'm':
349 case 'M':
350 mult=MEGA;
351 break;
352 case 'g':
353 case 'G':
354 mult=GIGA;
355 break;
356 default:
357 mult=1;
358 break;
360 if ((n=sscanf(s,"%lf+%lf",&v,&vplus)) > 0) {
361 wv[LR].value=wv[RL].value=v*mult;
362 wv[LR].plus=wv[RL].plus=vplus*mult;
363 wv[LR].alg=wv[RL].alg=algo;
364 } else if ((n=sscanf(s,"LR%lf+%lf",&v,&vplus)) > 0) {
365 wv[LR].value=v*mult;
366 wv[LR].plus=vplus*mult;
367 wv[LR].alg=algo;
368 } else if ((n=sscanf(s,"RL%lf+%lf",&v,&vplus)) > 0) {
369 wv[RL].value=v*mult;
370 wv[RL].plus=vplus*mult;
371 wv[RL].alg=algo;
373 return 0;
376 struct packpq {
377 unsigned long long when;
378 unsigned int counter;
379 int dir;
380 unsigned char *buf;
381 int size;
384 struct packpq **pqh;
385 struct packpq sentinel={0,0,0,NULL,0};
386 int npq,maxpq;
387 unsigned long long maxwhen;
388 unsigned int counter;
390 #define PQCHUNK 100
392 static unsigned long long nextms()
394 if (npq>0) {
395 unsigned long long now=0;
396 struct timeval v;
397 gettimeofday(&v,NULL);
398 now = (unsigned long long) v.tv_sec*1000+v.tv_usec/1000;
399 if (pqh[1]->when > now)
400 return pqh[1]->when - now;
401 else
402 return 0;
404 return -1;
407 static inline int outpacket(int dir,const unsigned char *buf,int size)
409 if (blinksock) {
410 snprintf(blinkmsg+blinkidlen,20,"%s %d\n",
411 (ndirs==2)?((dir==0)?"LR":"RL"):"--",
412 size);
413 sendto(blinksock,blinkmsg,strlen(blinkmsg+blinkidlen)+blinkidlen,0,
414 (struct sockaddr *)&blinksun, sizeof(blinksun));
416 if (vdeplug[1-dir])
417 return vde_send(vdeplug[1-dir],buf+2,size-2,0);
418 else
419 return write(outfd[dir],buf,size);
422 int writepacket(int dir,const unsigned char *buf,int size)
424 /* NOISE */
425 if (max_wirevalue(markov_current,NOISE,dir) > 0) {
426 double noiseval=compute_wirevalue(NOISE,dir);
427 int nobit=0;
428 while ((drand48()*8*MEGA) < (size-2)*8*noiseval)
429 nobit++;
430 if (nobit>0) {
431 unsigned char noisedpacket[BUFSIZE];
432 memcpy(noisedpacket,buf,size);
433 while(nobit>0) {
434 int flippedbit=(drand48()*size*8);
435 noisedpacket[(flippedbit >> 3) + 2] ^= 1<<(flippedbit & 0x7);
436 nobit--;
438 return outpacket(dir,noisedpacket,size);
439 } else
440 return outpacket(dir,buf,size);
441 } else
442 return outpacket(dir,buf,size);
445 /* packet queues are priority queues implemented on a heap.
446 * enqueue time = dequeue time = O(log n) max&mean
448 /* the delay is evaluated in milliseconds, several packets can be
449 scheduled at the same "when" time. Counter preserve the fifoness. */
451 static void packet_dequeue()
453 struct timeval v;
454 gettimeofday(&v,NULL);
455 unsigned long long now=(unsigned long long)v.tv_sec*1000+v.tv_usec/1000;
456 /* the next packet (min time, min counter) is in the root of
457 the packetqueue heap */
458 while (npq>0 && pqh[1]->when <= now) {
459 struct packpq *old=pqh[npq--];
460 int k=1;
461 delay_bufsize[pqh[1]->dir] -= pqh[1]->size;
462 writepacket(pqh[1]->dir,pqh[1]->buf,pqh[1]->size);
463 free(pqh[1]->buf);
464 free(pqh[1]);
465 /* rebuild the heap */
466 while (k<= npq>>1)
468 int j= k<<1;
469 /* choose the min between pqh[2k] and pqh[2k+1] */
470 if (j<npq &&
471 (pqh[j]->when > pqh[j+1]->when ||
472 (pqh[j]->when == pqh[j+1]->when &&
473 pqh[j]->counter > pqh[j+1]->counter)
475 ) j++;
476 /* if old must be put here, okay else move the min up and
477 continue the rebuilding phase */
478 if (old->when < pqh[j]->when ||
479 (old->when == pqh[j]->when &&
480 old->counter < pqh[j]->counter)
482 break;
483 else {
484 pqh[k]=pqh[j];k=j;
487 pqh[k]=old;
491 static void packet_enqueue(int dir,const unsigned char *buf,int size,int delms)
493 struct timeval v;
495 struct packpq *new=malloc(sizeof(struct packpq));
496 if (new==NULL) {
497 printlog(LOG_WARNING,"malloc elem %s",strerror(errno));
498 exit (1);
500 gettimeofday(&v,NULL);
501 new->when= ((unsigned long long)v.tv_sec * 1000 + v.tv_usec/1000) + delms;
502 if (new->when > maxwhen) {
503 maxwhen=new->when;
504 counter=0;
506 if (!nofifo && new->when <= maxwhen) {
507 new->when=maxwhen;
508 counter++;
510 new->counter=counter;
511 new->dir=dir;
512 new->buf=malloc(size);
513 if (new->buf==NULL) {
514 printlog(LOG_WARNING,"malloc elem buf %s",strerror(errno));
515 exit (1);
517 memcpy(new->buf,buf,size);
518 new->size=size;
519 delay_bufsize[dir]+=size;
520 if (pqh==NULL) {
521 pqh=malloc(PQCHUNK*sizeof(struct packpq *));
522 if (pqh==NULL) {
523 printlog(LOG_WARNING,"malloc %s",strerror(errno));
524 exit (1);
526 pqh[0]=&sentinel; maxpq=PQCHUNK;
528 if (npq >= maxpq) {
529 pqh=realloc(pqh,(maxpq=maxpq+PQCHUNK) * sizeof(struct packpq *));
530 if (pqh==NULL) {
531 printlog(LOG_WARNING,"malloc %s",strerror(errno));
532 exit (1);
536 int k=++npq;
537 /* add the new element to the heap */
538 while (new->when < pqh[k>>1]->when ||
539 (new->when == pqh[k>>1]->when && new->counter < pqh[k>>1]->counter)) {
540 pqh[k]=pqh[k>>1];
541 k >>= 1;
543 pqh[k]=new;
547 void handle_packet(int dir,const unsigned char *buf,int size)
549 /* MTU */
550 /* if the packet is incosistent with the MTU of the line just drop it */
551 if (min_wirevalue(markov_current,MTU,dir) > 0 && size > min_wirevalue(markov_current,MTU,dir))
552 return;
554 /* LOSS */
555 /* Total packet loss */
556 if (min_wirevalue(markov_current,LOSS,dir) >= 100.0)
557 return;
558 /* probabilistic loss */
559 if (max_wirevalue(markov_current,LOSTBURST,dir) > 0) {
560 /* Gilbert model */
561 double losval=compute_wirevalue(LOSS,dir)/100;
562 double burstlen=compute_wirevalue(LOSTBURST,dir);
563 double alpha=losval / (burstlen*(1-losval));
564 double beta=1.0 / burstlen;
565 switch (loss_status[dir]) {
566 case OK_BURST:
567 if (drand48() < alpha) loss_status[dir]=FAULTY_BURST;
568 break;
569 case FAULTY_BURST:
570 if (drand48() < beta) loss_status[dir]=OK_BURST;
571 break;
573 if (loss_status[dir] != OK_BURST)
574 return;
575 } else {
576 loss_status[dir] = OK_BURST;
577 if (max_wirevalue(markov_current,LOSS,dir) > 0) {
578 /* standard non bursty model */
579 double losval=compute_wirevalue(LOSS,dir)/100;
580 if (drand48() < losval)
581 return;
585 /* DUP */
586 /* times is the number of dup packets */
587 int times=1;
588 if (max_wirevalue(markov_current,DDUP,dir) > 0) {
589 double dupval=compute_wirevalue(DDUP,dir)/100;
590 while (drand48() < dupval)
591 times++;
593 while (times>0) {
594 int banddelay=0;
596 /* CHANBUFSIZE */
597 /* when bandwidth is limited, packets exceeding channel bufsize are discarded */
598 if (max_wirevalue(markov_current,CHANBUFSIZE,dir) > 0) {
599 double capval=compute_wirevalue(CHANBUFSIZE,dir);
600 if ((delay_bufsize[dir]+size) > capval)
601 return;
604 /* SPEED */
605 /* speed limit, if packets arrive too fast, delay the sender */
606 if (max_wirevalue(markov_current,SPEED,dir) > 0) {
607 double speedval=compute_wirevalue(SPEED,dir);
608 if (speedval<=0) return;
609 if (speedval>0) {
610 unsigned int commtime=((unsigned)size)*1000000/((unsigned int)speedval);
611 struct timeval tv;
612 gettimeofday(&tv,NULL);
613 banddelay=commtime/1000;
614 if (timercmp(&tv,&nextspeed[dir], > ))
615 nextspeed[dir]=tv;
616 nextspeed[dir].tv_usec += commtime;
617 nextspeed[dir].tv_sec += nextspeed[dir].tv_usec / 1000000;
618 nextspeed[dir].tv_usec %= 1000000;
622 /* BANDWIDTH */
623 /* band, when band overflows, delay just the delivery */
624 if (max_wirevalue(markov_current,BAND,dir) > 0) {
625 double bandval=compute_wirevalue(BAND,dir);
626 if (bandval<=0) return;
627 if (bandval >0) {
628 unsigned int commtime=((unsigned)size)*1000000/((unsigned int)bandval);
629 struct timeval tv;
630 gettimeofday(&tv,NULL);
631 if (timercmp(&tv,&nextband[dir], > )) {
632 nextband[dir]=tv;
633 banddelay=commtime/1000;
634 } else {
635 timersub(&nextband[dir],&tv,&tv);
636 banddelay=tv.tv_sec*1000 + (tv.tv_usec + commtime)/1000;
638 nextband[dir].tv_usec += commtime;
639 nextband[dir].tv_sec += nextband[dir].tv_usec / 1000000;
640 nextband[dir].tv_usec %= 1000000;
641 } else
642 banddelay=-1;
645 /* DELAY */
646 /* line delay */
647 if (banddelay >= 0) {
648 if (banddelay > 0 || max_wirevalue(markov_current,DELAY,dir) > 0) {
649 double delval=compute_wirevalue(DELAY,dir);
650 delval=(delval >= 0)?delval+banddelay:banddelay;
651 if (delval > 0) {
652 packet_enqueue(dir,buf,size,(int) delval);
653 } else
654 writepacket(dir,buf,size);
655 } else
656 writepacket(dir,buf,size);
658 times--;
662 #define MIN(X,Y) (((X)<(Y))?(X):(Y))
664 static void splitpacket(const unsigned char *buf,int size,int dir)
666 static unsigned char fragment[BUFSIZE][2];
667 static unsigned char *fragp[2];
668 static unsigned int rnx[2],remaining[2];
670 //fprintf(stderr,"%s: splitpacket rnx=%d remaining=%d size=%d\n",progname,rnx[dir],remaining[dir],size);
671 if (size==0) return;
672 if (rnx[dir]>0) {
673 int amount=MIN(remaining[dir],size);
674 //fprintf(stderr,"%s: fragment amount %d\n",progname,amount);
675 memcpy(fragp[dir],buf,amount);
676 remaining[dir]-=amount;
677 fragp[dir]+=amount;
678 buf+=amount;
679 size-=amount;
680 if (remaining[dir]==0) {
681 //fprintf(stderr,"%s: delivered defrag %d\n",progname,rnx[dir]);
682 handle_packet(dir,fragment[dir],rnx[dir]+2);
683 rnx[dir]=0;
686 while (size > 0) {
687 rnx[dir]=(buf[0]<<8)+buf[1];
688 //fprintf(stderr,"%s: packet %d size %d %x %x dir %d\n",progname,rnx[dir],size-2,buf[0],buf[1],dir);
689 if (rnx[dir]>1521) {
690 printlog(LOG_WARNING,"Packet length error size %d rnx %d",size,rnx[dir]);
691 rnx[dir]=0;
692 return;
694 if (rnx[dir]+2 > size) {
695 //fprintf(stderr,"%s: begin defrag %d\n",progname,rnx[dir]);
696 fragp[dir]=fragment[dir];
697 memcpy(fragp[dir],buf,size);
698 remaining[dir]=rnx[dir]+2-size;
699 fragp[dir]+=size;
700 size=0;
701 } else {
702 handle_packet(dir,buf,rnx[dir]+2);
703 buf+=rnx[dir]+2;
704 size-=rnx[dir]+2;
705 rnx[dir]=0;
710 static void packet_in(int dir)
712 unsigned char buf[BUFSIZE];
713 int n;
714 if(vdeplug[dir]) {
715 n=vde_recv(vdeplug[dir],buf+2,BUFSIZE-2,0);
716 buf[0]=n>>8;
717 buf[1]=n&0xFF;
718 handle_packet(dir,buf,n+2);
719 } else {
720 n=read(pfd[dir].fd,buf,BUFSIZE);
721 if (n == 0)
722 exit (0);
723 splitpacket(buf,n,dir);
727 static int check_open_fifos_n_plugs(struct pollfd *pfd,int *outfd,char *vdepath[],VDECONN *vdeplug[])
729 int ndirs=0;
730 struct stat stfd[NPIPES];
731 char *env_in;
732 char *env_out;
733 env_in=getenv("ALTERNATE_STDIN");
734 env_out=getenv("ALTERNATE_STDOUT");
735 if (env_in != NULL)
736 alternate_stdin=atoi(env_in);
737 if (env_out != NULL)
738 alternate_stdout=atoi(env_out);
739 if (vdepath[0]) { // -v selected
740 if (strcmp(vdepath[0],"-") != 0) {
741 if((vdeplug[LR]=vde_open(vdepath[0],"vde_crosscable",NULL))==NULL){
742 fprintf(stderr,"vdeplug %s: %s\n",vdepath[0],strerror(errno));
743 return -1;
745 pfd[0].fd=vde_datafd(vdeplug[LR]);
746 pfd[0].events=POLLIN | POLLHUP;
748 if (strcmp(vdepath[1],"-") != 0) {
749 if((vdeplug[RL]=vde_open(vdepath[1],"vde_crosscable",NULL))==NULL){
750 fprintf(stderr,"vdeplug %s: %s\n",vdepath[1],strerror(errno));
751 return -1;
753 pfd[1].fd=vde_datafd(vdeplug[RL]);
754 pfd[1].events=POLLIN | POLLHUP;
756 ndirs=2;
758 if (vdeplug[LR] == NULL || vdeplug[RL] == NULL) {
759 if (fstat(STDIN_FILENO,&stfd[STDIN_FILENO]) < 0) {
760 fprintf(stderr,"%s: Error on stdin: %s\n",progname,strerror(errno));
761 return -1;
763 if (fstat(STDOUT_FILENO,&stfd[STDOUT_FILENO]) < 0) {
764 fprintf(stderr,"%s: Error on stdout: %s\n",progname,strerror(errno));
765 return -1;
767 if (!S_ISFIFO(stfd[STDIN_FILENO].st_mode)) {
768 fprintf(stderr,"%s: Error on stdin: %s\n",progname,"it is not a pipe");
769 return -1;
771 if (!S_ISFIFO(stfd[STDOUT_FILENO].st_mode)) {
772 fprintf(stderr,"%s: Error on stdin: %s\n",progname,"it is not a pipe");
773 return -1;
775 if (vdeplug[RL] != NULL) { /* -v -:xxx */
776 pfd[0].fd=STDIN_FILENO;
777 pfd[0].events=POLLIN | POLLHUP;
778 outfd[1]=STDOUT_FILENO;
779 } else if (vdeplug[LR] != NULL) { /* -v xxx:- */
780 pfd[1].fd=STDIN_FILENO;
781 pfd[1].events=POLLIN | POLLHUP;
782 outfd[0]=STDOUT_FILENO;
783 } else if (env_in == NULL || fstat(alternate_stdin,&stfd[0]) < 0) {
784 ndirs=1;
785 pfd[0].fd=STDIN_FILENO;
786 pfd[0].events=POLLIN | POLLHUP;
787 outfd[0]=STDOUT_FILENO;
788 } else {
789 if (fstat(outfd[1],&stfd[1]) < 0) {
790 fprintf(stderr,"%s: Error on secondary out: %s\n",progname,strerror(errno));
791 return -1;
793 if (!S_ISFIFO(stfd[0].st_mode)) {
794 fprintf(stderr,"%s: Error on secondary in: %s\n",progname,"it is not a pipe");
795 return -1;
797 if (!S_ISFIFO(stfd[1].st_mode)) {
798 fprintf(stderr,"%s: Error on secondary out: %s\n",progname,"it is not a pipe");
799 return -1;
801 ndirs=2;
802 pfd[LR].fd=STDIN_FILENO;
803 pfd[LR].events=POLLIN | POLLHUP;
804 outfd[LR]=alternate_stdout;
805 pfd[RL].fd=alternate_stdin;
806 pfd[RL].events=POLLIN | POLLHUP;
807 outfd[RL]=STDOUT_FILENO;
810 return ndirs;
813 static void save_pidfile()
815 if(pidfile[0] != '/')
816 strncat(pidfile_path, pidfile, PATH_MAX - strlen(pidfile_path) - 1);
817 else
818 strncpy(pidfile_path, pidfile, PATH_MAX - 1);
820 int fd = open(pidfile_path,
821 O_WRONLY | O_CREAT | O_EXCL,
822 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
823 FILE *f;
825 if(fd == -1) {
826 printlog(LOG_ERR, "Error in pidfile creation: %s", strerror(errno));
827 exit(1);
830 if((f = fdopen(fd, "w")) == NULL) {
831 printlog(LOG_ERR, "Error in FILE* construction: %s", strerror(errno));
832 exit(1);
835 if(fprintf(f, "%ld\n", (long int)getpid()) <= 0) {
836 printlog(LOG_ERR, "Error in writing pidfile");
837 exit(1);
840 fclose(f);
843 static void cleanup(void)
845 if((pidfile != NULL) && unlink(pidfile_path) < 0) {
846 printlog(LOG_WARNING,"Couldn't remove pidfile '%s': %s", pidfile, strerror(errno));
848 if (vdeplug[LR])
849 vde_close(vdeplug[LR]);
850 if (vdeplug[RL])
851 vde_close(vdeplug[RL]);
852 if (mgmt)
853 unlink(mgmt);
856 static void sig_handler(int sig)
858 /*fprintf(stderr,"Caught signal %d, cleaning up and exiting", sig);*/
859 cleanup();
860 signal(sig, SIG_DFL);
861 if (sig == SIGTERM)
862 _exit(0);
863 else
864 kill(getpid(), sig);
867 static void setsighandlers()
869 /* setting signal handlers.
870 * * * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
871 * * * ignores all the others signals which could cause termination. */
872 struct { int sig; const char *name; int ignore; } signals[] = {
873 { SIGHUP, "SIGHUP", 0 },
874 { SIGINT, "SIGINT", 0 },
875 { SIGPIPE, "SIGPIPE", 1 },
876 { SIGALRM, "SIGALRM", 1 },
877 { SIGTERM, "SIGTERM", 0 },
878 { SIGUSR1, "SIGUSR1", 1 },
879 { SIGUSR2, "SIGUSR2", 1 },
880 { SIGPROF, "SIGPROF", 1 },
881 { SIGVTALRM, "SIGVTALRM", 1 },
882 #ifdef VDE_LINUX
883 { SIGPOLL, "SIGPOLL", 1 },
884 #ifdef SIGSTKFLT
885 { SIGSTKFLT, "SIGSTKFLT", 1 },
886 #endif
887 { SIGIO, "SIGIO", 1 },
888 { SIGPWR, "SIGPWR", 1 },
889 #ifdef SIGUNUSED
890 { SIGUNUSED, "SIGUNUSED", 1 },
891 #endif
892 #endif
893 #ifdef VDE_DARWIN
894 { SIGXCPU, "SIGXCPU", 1 },
895 { SIGXFSZ, "SIGXFSZ", 1 },
896 #endif
897 { 0, NULL, 0 }
900 int i;
901 for(i = 0; signals[i].sig != 0; i++)
902 if(signal(signals[i].sig,
903 signals[i].ignore ? SIG_IGN : sig_handler) < 0)
904 fprintf(stderr,"%s: Setting handler for %s: %s", progname, signals[i].name,
905 strerror(errno));
908 static int openmgmt(char *mgmt)
910 int mgmtconnfd;
911 struct sockaddr_un sun;
912 int one = 1;
914 if((mgmtconnfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0){
915 fprintf(stderr,"%s: mgmt socket: %s",progname,strerror(errno));
916 exit(1);
918 if(setsockopt(mgmtconnfd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
919 sizeof(one)) < 0){
920 fprintf(stderr,"%s: mgmt setsockopt: %s",progname,strerror(errno));
921 exit(1);
923 if(fcntl(mgmtconnfd, F_SETFL, O_NONBLOCK) < 0){
924 fprintf(stderr,"%s: Setting O_NONBLOCK on mgmt fd: %s",progname,strerror(errno));
925 exit(1);
927 sun.sun_family = PF_UNIX;
928 snprintf(sun.sun_path,sizeof(sun.sun_path),"%s",mgmt);
929 if(bind(mgmtconnfd, (struct sockaddr *) &sun, sizeof(sun)) < 0){
930 fprintf(stderr,"%s: mgmt bind %s",progname,strerror(errno));
931 exit(1);
933 chmod(sun.sun_path,mgmtmode);
934 if(listen(mgmtconnfd, 15) < 0){
935 fprintf(stderr,"%s: mgmt listen: %s",progname,strerror(errno));
936 exit(1);
938 return mgmtconnfd;
941 static char header[]="\nVDE wirefilter V.%s\n(C) R.Davoli 2005,2006 - GPLv2\n";
942 static char prompt[]="\nVDEwf$ ";
943 static int newmgmtconn(int fd,struct pollfd *pfd,int nfds)
945 int new;
946 unsigned int len;
947 char buf[MAXCMD];
948 struct sockaddr addr;
949 new = accept(fd, &addr, &len);
950 if(new < 0){
951 printlog(LOG_WARNING,"mgmt accept %s",strerror(errno));
952 return nfds;
954 if (nfds < NPFD) {
955 snprintf(buf,MAXCMD,header,PACKAGE_VERSION);
956 write(new,buf,strlen(buf));
957 write(new,prompt,strlen(prompt));
958 pfd[nfds].fd=new;
959 pfd[nfds].events=POLLIN | POLLHUP;
960 debuglevel[nfds]=0;
961 return ++nfds;
962 } else {
963 printlog(LOG_WARNING,"too many mgmt connections");
964 close (new);
965 return nfds;
969 static void printoutc(int fd, const char *format, ...)
971 va_list arg;
972 char outbuf[MAXCMD+1];
974 va_start (arg, format);
975 vsnprintf(outbuf,MAXCMD,format,arg);
976 strcat(outbuf,"\n");
977 write(fd,outbuf,strlen(outbuf));
980 static int setdelay(int fd,char *s)
982 return read_wirevalue(s,DELAY);
985 static int setloss(int fd,char *s)
987 return read_wirevalue(s,LOSS);
990 static int setlostburst(int fd,char *s)
992 return read_wirevalue(s,LOSTBURST);
995 static int setddup(int fd,char *s)
997 return read_wirevalue(s,DDUP);
1000 static int setband(int fd,char *s)
1002 return read_wirevalue(s,BAND);
1005 static int setnoise(int fd,char *s)
1007 return read_wirevalue(s,NOISE);
1010 static int setmtu(int fd,char *s)
1012 return read_wirevalue(s,MTU);
1015 static int setspeed(int fd,char *s)
1017 return read_wirevalue(s,SPEED);
1020 static int setchanbufsize(int fd,char *s)
1022 return read_wirevalue(s,CHANBUFSIZE);
1025 static int setfifo(int fd,char *s)
1027 int n=atoi(s);
1028 if (n==0)
1029 nofifo=1;
1030 else
1031 nofifo=0;
1032 return 0;
1035 static int setmarkov_resize(int fd,char *s)
1037 int n=atoi(s);
1038 if (n>0) {
1039 markov_resize(n);
1040 markov_start();
1041 return 0;
1042 } else
1043 return EINVAL;
1046 static int setedge(int fd,char *s)
1048 int x,y;
1049 double weight;
1050 sscanf(s,"%d,%d,%lg",&x,&y,&weight);
1051 if (x>=0 && x<markov_numnodes && y>=0 && y<markov_numnodes) {
1052 ADJMAP(x,y)=weight;
1053 markov_compute(x);
1054 return 0;
1055 } else
1056 return EINVAL;
1059 static int setmarkov_time(int fd,char *s)
1061 double newvalue;
1062 sscanf(s,"%lg",&newvalue);
1063 if (newvalue > 0) {
1064 markov_time=newvalue;
1065 markov_start();
1066 return 0;
1067 } else
1068 return EINVAL;
1071 static int setmarkov_node(int fd,char *s)
1073 int n=atoi(s);
1074 if (n>=0 && n<markov_numnodes) {
1075 markov_current=n;
1076 return 0;
1077 } else
1078 return EINVAL;
1081 static int setmarkov_debug(int fd,char *s)
1083 int n=atoi(s);
1084 if (fd >= 0 && n>=0) {
1085 int i;
1086 if (fd==1) fd=0;
1087 for (i=0;i<NPFD;i++) {
1088 if (pfd[i].fd == fd)
1089 break;
1091 if (i<NPFD) {
1092 debuglevel[i]=n;
1093 return 0;
1094 } else
1095 return EINVAL;
1096 } else
1097 return EINVAL;
1100 static int showcurrent(int fd,char *s)
1102 printoutc(fd, "Current Markov Node %d \"%s\" (0,..,%d)",markov_current,
1103 WFNAME(markov_current)?WFNAME(markov_current):"",
1104 markov_numnodes-1);
1105 return 0;
1108 static int setmarkov_name(int fd,char *s)
1110 int n;
1111 while (strchr(" \t",*s)) s++;
1112 n=atoi(s);
1113 if (n>=0 && n<markov_numnodes) {
1114 while (strchr("0123456789",*s)) s++;
1115 while (strchr(" \t",*s)) s++;
1116 if (*s == ',') s++;
1117 if (s[strlen(s)-1]=='\n')
1118 s[strlen(s)-1]=0;
1119 if (WFNAME(n)) free(WFNAME(n));
1120 if (*s)
1121 WFNAME(n)=strdup(s);
1122 else
1123 WFNAME(n)=0;
1124 return 0;
1125 } else
1126 return EINVAL;
1129 static int logout(int fd,char *s)
1131 return -1;
1134 static int doshutdown(int fd,char *s)
1136 exit(0);
1140 static int help(int fd,char *s)
1142 printoutc(fd, "COMMAND HELP");
1143 printoutc(fd, "------------ ------------");
1144 printoutc(fd, "help print a summary of mgmt commands");
1145 printoutc(fd, "load load a configuration file");
1146 printoutc(fd, "showinfo show status and parameter values");
1147 printoutc(fd, "loss set loss percentage");
1148 printoutc(fd, "lostburst mean length of lost packet bursts");
1149 printoutc(fd, "delay set delay ms");
1150 printoutc(fd, "dup set dup packet percentage");
1151 printoutc(fd, "bandwidth set channel bandwidth bytes/sec");
1152 printoutc(fd, "speed set interface speed bytes/sec");
1153 printoutc(fd, "noise set noise factor bits/Mbyte");
1154 printoutc(fd, "mtu set channel MTU (bytes)");
1155 printoutc(fd, "chanbufsize set channel buffer size (bytes)");
1156 printoutc(fd, "fifo set channel fifoness");
1157 printoutc(fd, "shutdown shut the channel down");
1158 printoutc(fd, "logout log out from this mgmt session");
1159 printoutc(fd, "markov-numnodes n markov mode: set number of states");
1160 printoutc(fd, "markov-setnode n markov mode: set current state");
1161 printoutc(fd, "markov-name n,name markov mode: set state's name");
1162 printoutc(fd, "markov-time ms markov mode: transition period");
1163 printoutc(fd, "setedge n1,n2,w markov mode: set edge weight");
1164 printoutc(fd, "showinfo n markov mode: show parameter values");
1165 printoutc(fd, "showedges n markov mode: show edge weights");
1166 printoutc(fd, "showcurrent markov mode: show current state");
1167 printoutc(fd, "markov-debug n markov mode: set debug level");
1168 return 0;
1171 #define CHARALGO(X) (charalgo[(int)(X)])
1172 #define WIREVALUE_X_FIELDS(X) (X)->value,(X)->plus,(charalgo[(int)((X)->alg)])
1173 #define WIREVALUE_FIELDS(N,T,D) WIREVALUE_X_FIELDS(WFADDR(N,T)+D)
1174 static int showinfo(int fd,char *s)
1176 int node=0;
1177 if (*s != 0)
1178 node=atoi(s);
1179 else
1180 node=markov_current;
1181 if (node >= markov_numnodes || node < 0)
1182 return EINVAL;
1183 printoutc(fd, "WireFilter: %sdirectional",(ndirs==2)?"bi":"mono");
1184 if (markov_numnodes > 1) {
1185 printoutc(fd, "Node %d \"%s\" (0,..,%d) Markov-time %lg",node,
1186 WFNAME(node)?WFNAME(node):"",markov_numnodes-1,markov_time);
1188 if (ndirs==2) {
1189 printoutc(fd, "Loss L->R %g+%g%c R->L %g+%g%c",
1190 WIREVALUE_FIELDS(node,LOSS,LR),
1191 WIREVALUE_FIELDS(node,LOSS,RL));
1192 printoutc(fd, "Lburst L->R %g+%g%c R->L %g+%g%c",
1193 WIREVALUE_FIELDS(node,LOSTBURST,LR),
1194 WIREVALUE_FIELDS(node,LOSTBURST,RL));
1195 printoutc(fd, "Delay L->R %g+%g%c R->L %g+%g%c",
1196 WIREVALUE_FIELDS(node,DELAY,LR),
1197 WIREVALUE_FIELDS(node,DELAY,RL));
1198 printoutc(fd, "Dup L->R %g+%g%c R->L %g+%g%c",
1199 WIREVALUE_FIELDS(node,DDUP,LR),
1200 WIREVALUE_FIELDS(node,DDUP,RL));
1201 printoutc(fd, "Bandw L->R %g+%g%c R->L %g+%g%c",
1202 WIREVALUE_FIELDS(node,BAND,LR),
1203 WIREVALUE_FIELDS(node,BAND,RL));
1204 printoutc(fd, "Speed L->R %g+%g%c R->L %g+%g%c",
1205 WIREVALUE_FIELDS(node,SPEED,LR),
1206 WIREVALUE_FIELDS(node,SPEED,RL));
1207 printoutc(fd, "Noise L->R %g+%g%c R->L %g+%g%c",
1208 WIREVALUE_FIELDS(node,NOISE,LR),
1209 WIREVALUE_FIELDS(node,NOISE,RL));
1210 printoutc(fd, "MTU L->R %g R->L %g ",
1211 min_wirevalue(node,MTU,LR),
1212 min_wirevalue(node,MTU,RL));
1213 printoutc(fd, "Cap. L->R %g+%g%c R->L %g+%g%c",
1214 WIREVALUE_FIELDS(node,CHANBUFSIZE,LR),
1215 WIREVALUE_FIELDS(node,CHANBUFSIZE,RL));
1216 printoutc(fd, "Current Delay Queue size: L->R %d R->L %d ",delay_bufsize[LR],delay_bufsize[RL]);
1217 } else {
1218 printoutc(fd, "Loss %g+%g%c",
1219 WIREVALUE_FIELDS(node,LOSS,0));
1220 printoutc(fd, "Lburst %g+%g%c",
1221 WIREVALUE_FIELDS(node,LOSTBURST,0));
1222 printoutc(fd, "Delay %g+%g%c",
1223 WIREVALUE_FIELDS(node,DELAY,0));
1224 printoutc(fd, "Dup %g+%g%c",
1225 WIREVALUE_FIELDS(node,DDUP,0));
1226 printoutc(fd, "Bandw %g+%g%c",
1227 WIREVALUE_FIELDS(node,BAND,0));
1228 printoutc(fd, "Speed %g+%g%c",
1229 WIREVALUE_FIELDS(node,SPEED,0));
1230 printoutc(fd, "Noise %g+%g%c",
1231 WIREVALUE_FIELDS(node,NOISE,0));
1232 printoutc(fd, "MTU %g", min_wirevalue(node,MTU,0));
1233 printoutc(fd, "Cap. %g+%g%c",
1234 WIREVALUE_FIELDS(node,CHANBUFSIZE,0));
1235 printoutc(fd, "Current Delay Queue size: %d",delay_bufsize[0]);
1237 printoutc(fd,"Fifoness %s",(nofifo == 0)?"TRUE":"FALSE");
1238 printoutc(fd,"Waiting packets in delay queues %d",npq);
1239 if (blinksock) {
1240 blinkmsg[(int)blinkidlen]=0;
1241 printoutc(fd,"Blink socket: %s",blinksun.sun_path);
1242 printoutc(fd,"Blink id: %s",blinkmsg);
1244 return 0;
1247 static int showedges(int fd,char *s)
1249 int node=0;
1250 int j;
1251 if (*s != 0)
1252 node=atoi(s);
1253 else
1254 node=markov_current;
1255 if (node >= markov_numnodes || node < 0)
1256 return EINVAL;
1257 for (j=0;j<markov_numnodes;j++)
1258 if (ADJMAP(node,j) != 0)
1259 printoutc(fd, "Edge %-2d->%-2d \"%s\"->\"%s\" weigth %lg",node,j,
1260 WFNAME(node)?WFNAME(node):"",
1261 WFNAME(j)?WFNAME(j):"",
1262 ADJMAP(node,j));
1263 return 0;
1266 static int runscript(int fd,char *path);
1268 #define WITHFILE 0x80
1269 static struct comlist {
1270 char *tag;
1271 int (*fun)(int fd,char *arg);
1272 unsigned char type;
1273 } commandlist [] = {
1274 {"help", help, WITHFILE},
1275 {"showinfo",showinfo, WITHFILE},
1276 {"load",runscript,WITHFILE},
1277 {"delay",setdelay, 0},
1278 {"loss",setloss, 0},
1279 {"lostburst",setlostburst, 0},
1280 {"dup",setddup, 0},
1281 {"bandwidth",setband, 0},
1282 {"band",setband, 0},
1283 {"speed",setspeed, 0},
1284 {"chanbufsize",setchanbufsize, 0},
1285 {"capacity",setchanbufsize, 0},
1286 {"noise",setnoise, 0},
1287 {"mtu",setmtu, 0},
1288 {"fifo",setfifo, 0},
1289 {"markov-numnodes",setmarkov_resize, 0},
1290 {"markov-setnode",setmarkov_node, 0},
1291 {"markov-name",setmarkov_name, 0},
1292 {"markov-time",setmarkov_time, 0},
1293 {"setedge",setedge, 0},
1294 {"showedges",showedges, WITHFILE},
1295 {"showcurrent",showcurrent, WITHFILE},
1296 {"markov-debug",setmarkov_debug, 0},
1297 {"logout",logout, 0},
1298 {"shutdown",doshutdown, 0}
1301 #define NCL sizeof(commandlist)/sizeof(struct comlist)
1303 static inline void delnl(char *buf)
1305 int len=strlen(buf)-1;
1306 while (len>0 &&
1307 (buf[len]=='\n' || buf[len]==' ' || buf[len]=='\t')) {
1308 buf[len]=0;
1309 len--;
1313 static int handle_cmd(int fd,char *inbuf)
1315 int rv=ENOSYS;
1316 int i;
1317 char *cmd=inbuf;
1318 while (*inbuf == ' ' || *inbuf == '\t' || *inbuf == '\n') inbuf++;
1319 delnl(inbuf);
1320 if (*inbuf != '\0' && *inbuf != '#') {
1321 for (i=0; i<NCL
1322 && strncmp(commandlist[i].tag,inbuf,strlen(commandlist[i].tag))!=0;
1323 i++)
1325 if (i<NCL)
1327 inbuf += strlen(commandlist[i].tag);
1328 while (*inbuf == ' ' || *inbuf == '\t') inbuf++;
1329 if (fd>=0 && commandlist[i].type & WITHFILE)
1330 printoutc(fd,"0000 DATA END WITH '.'");
1331 rv=commandlist[i].fun(fd,inbuf);
1332 if (fd>=0 && commandlist[i].type & WITHFILE)
1333 printoutc(fd,".");
1335 if (fd >= 0) {
1336 if (rv == 0) {
1337 printoutc(fd,"1000 Success");
1338 } else {
1339 printoutc(fd,"1%03d %s",rv,strerror(rv));
1341 } else if (rv != 0) {
1342 printlog(LOG_ERR,"rc command error: %s %s",cmd,strerror(rv));
1344 return rv;
1346 return rv;
1349 static int runscript(int fd,char *path)
1351 FILE *f=fopen(path,"r");
1352 char buf[MAXCMD];
1353 if (f==NULL)
1354 return errno;
1355 else {
1356 while (fgets(buf,MAXCMD,f) != NULL) {
1357 delnl(buf);
1358 if (fd >= 0) {
1359 printoutc(fd,"%s (%s) %s",prompt,path,buf);
1361 handle_cmd(fd, buf);
1363 fclose(f);
1364 return 0;
1368 static int mgmtcommand(int fd)
1370 char buf[MAXCMD+1];
1371 int n,rv;
1372 int outfd=fd;
1373 n = read(fd, buf, MAXCMD);
1374 if (n<0) {
1375 printlog(LOG_WARNING,"read from mgmt %s",strerror(errno));
1376 return 0;
1378 else if (n==0)
1379 return -1;
1380 else {
1381 if (fd==STDIN_FILENO)
1382 outfd=STDOUT_FILENO;
1383 buf[n]=0;
1384 rv=handle_cmd(outfd,buf);
1385 if (rv>=0)
1386 write(outfd,prompt,strlen(prompt));
1387 return rv;
1391 static int delmgmtconn(int i,struct pollfd *pfd,int nfds)
1393 if (i<nfds) {
1394 close(pfd[i].fd);
1395 if (pfd[i].fd == 0) /* close stdin implies exit */
1396 exit(0);
1397 memmove(pfd+i,pfd+i+1,sizeof (struct pollfd) * (nfds-i-1));
1398 memmove(debuglevel+i,debuglevel+i+1,sizeof(char) * (nfds-i-1));
1399 pfd[nfds].fd = -1;
1400 debuglevel[nfds] = 0;
1401 nfds--;
1403 return nfds;
1406 void usage(void)
1408 fprintf(stderr,"Usage: %s OPTIONS\n"
1409 "\t--help|-h\n"
1410 "\t--rcfile|-f Configuration file\n"
1411 "\t--loss|-l loss_percentage\n"
1412 "\t--lostburst|-L lost_packet_burst_len\n"
1413 "\t--delay|-d delay_ms\n"
1414 "\t--dup|-D dup_percentage\n"
1415 "\t--band|-b bandwidth(bytes/s)\n"
1416 "\t--speed|-s interface_speed(bytes/s)\n"
1417 "\t--chanbufsize|-c channel_bufsize\n"
1418 "\t--noise|-n noise_bits/megabye\n"
1419 "\t--mtu|-m mtu_size\n"
1420 "\t--nofifo|-N\n"
1421 "\t--mgmt|-M management_socket\n"
1422 "\t--mgmtmode management_permission(octal)\n"
1423 "\t--vde-plug plug1:plug2 | -v plug1:plug2\n"
1424 "\t--daemon\n"
1425 "\t--pidfile pidfile\n"
1426 "\t--blink blinksocket\n"
1427 "\t--blinkid blink_id_string\n"
1428 ,progname);
1429 exit (1);
1432 int main(int argc,char *argv[])
1434 int n;
1435 int npfd;
1436 int option_index;
1437 int mgmtindex=-1;
1438 int consoleindex=-1;
1439 static struct option long_options[] = {
1440 {"help",0 , 0, 'h'},
1441 {"rcfile", 1, 0, 'f'},
1442 {"loss", 1, 0, 'l'},
1443 {"lostburst", 1, 0, 'L'},
1444 {"delay",1 , 0, 'd'},
1445 {"dup",1 , 0, 'D'},
1446 {"band",1 , 0, 'b'},
1447 {"speed",1 , 0, 's'},
1448 {"chanbufsize",1 , 0, 'c'},
1449 {"capacity",1 , 0, 'c'},
1450 {"noise",1 , 0, 'n'},
1451 {"mtu",1 , 0, 'm'},
1452 {"nofifo",0 , 0, 'N'},
1453 {"mgmt", 1, 0, 'M'},
1454 {"mgmtmode", 1, 0, MGMTMODEARG},
1455 {"vde-plug",1,0,'v'},
1456 {"daemon",0 , 0, DAEMONIZEARG},
1457 {"pidfile", 1, 0, PIDFILEARG},
1458 {"blink",1,0,LOGSOCKETARG},
1459 {"blinkid",1,0,LOGIDARG},
1460 {0,0,0,0}
1462 progname=basename(argv[0]);
1463 markov_resize(1);
1465 setsighandlers();
1466 atexit(cleanup);
1468 while(1) {
1469 int c;
1470 c = GETOPT_LONG (argc, argv, "hNl:n:d:M:D:m:b:s:c:v:L:f:",
1471 long_options, &option_index);
1472 if (c<0)
1473 break;
1474 switch (c) {
1475 case 'h':
1476 usage();
1477 break;
1478 case 'f':
1479 rcfile=strdup(optarg);
1480 break;
1481 case 'd':
1482 read_wirevalue(optarg,DELAY);
1483 break;
1484 case 'l':
1485 read_wirevalue(optarg,LOSS);
1486 break;
1487 case 'L':
1488 read_wirevalue(optarg,LOSTBURST);
1489 break;
1490 case 'D':
1491 read_wirevalue(optarg,DDUP);
1492 break;
1493 case 'b':
1494 read_wirevalue(optarg,BAND);
1495 break;
1496 case 'm':
1497 read_wirevalue(optarg,MTU);
1498 break;
1499 case 'n':
1500 read_wirevalue(optarg,NOISE);
1501 break;
1502 case 's':
1503 read_wirevalue(optarg,SPEED);
1504 break;
1505 case 'c':
1506 read_wirevalue(optarg,CHANBUFSIZE);
1507 break;
1508 case 'M':
1509 mgmt=strdup(optarg);
1510 break;
1511 case 'N':
1512 nofifo=1;
1513 break;
1514 case 'v':
1516 char *colon;
1517 vdepath[LR]=strdup(optarg);
1518 colon=index(vdepath[LR],':');
1519 if (colon) {
1520 *colon=0;
1521 vdepath[RL]=colon+1;
1522 } else {
1523 fprintf(stderr,"Bad vde_plugs specification.\n");
1524 usage();
1527 case MGMTMODEARG:
1528 sscanf(optarg,"%o",&mgmtmode);
1529 break;
1530 case DAEMONIZEARG:
1531 daemonize=1;
1532 break;
1533 case PIDFILEARG:
1534 pidfile=strdup(optarg);
1535 break;
1536 case LOGSOCKETARG:
1537 blinksun.sun_family = PF_UNIX;
1538 snprintf(blinksun.sun_path,sizeof(blinksun.sun_path),"%s",optarg);
1539 break;
1540 case LOGIDARG:
1541 if (blinkmsg) free(blinkmsg);
1542 blinkidlen=strlen(optarg)+1;
1543 asprintf(&blinkmsg,"%s 12345678901234567890",optarg);
1544 break;
1545 default:
1546 usage();
1547 break;
1550 if (optind < argc)
1551 usage();
1553 if (blinksun.sun_path[0] != 0) {
1554 blinksock=socket(AF_UNIX, SOCK_DGRAM, 0);
1555 if (blinkmsg==NULL) {
1556 blinkidlen=7;
1557 asprintf(&blinkmsg,"%06d 12345678901234567890",getpid());
1561 /* pfd structure:
1562 * monodir: 0 input LR, 1 mgmtctl, >1 mgmt open conn (mgmtindex==ndirs==1)
1563 * bidir on streams: 0 input LR, 1 input RL, 2 mgmtctl, >2 mgmt open conn (mgmtindex==ndirs==2)
1564 * vdeplug xx:xx : 0 input LR, 1 input RL, 2&3 ctlfd, 4 mgmtctl, > 4 mgmt open conn (mgmtindex>ndirs==2) 5 is console
1565 * vdeplug xx:xx : 0 input LR, 1 input RL, 2&3 ctlfd, 4 console (if not -M)
1566 * vdeplug -:xx : 0 input LR(stdin), 1 input RL, 2 ctlfd, 3 mgmtctl, > 3 mgmt open conn (mgmtindex>ndirs==2)
1567 * vdeplug xx:- : 0 input LR, 1 input RL(stdin), 2 ctlfd, 3 mgmtctl, > 3 mgmt open conn (mgmtindex>ndirs==2)
1570 ndirs=check_open_fifos_n_plugs(pfd,outfd,vdepath,vdeplug);
1572 if (ndirs < 0)
1573 usage();
1575 npfd=ndirs;
1577 if (rcfile)
1578 runscript(-1,rcfile);
1579 if (vdeplug[LR]) {
1580 pfd[npfd].fd=vde_ctlfd(vdeplug[LR]);
1581 pfd[npfd].events=POLLIN | POLLHUP;
1582 npfd++;
1584 if (vdeplug[RL]) {
1585 pfd[npfd].fd=vde_ctlfd(vdeplug[RL]);
1586 pfd[npfd].events=POLLIN | POLLHUP;
1587 npfd++;
1590 if(mgmt != NULL) {
1591 int mgmtfd=openmgmt(mgmt);
1592 mgmtindex=npfd;
1593 pfd[mgmtindex].fd=mgmtfd;
1594 pfd[mgmtindex].events=POLLIN | POLLHUP;
1595 npfd++;
1598 if (daemonize) {
1599 openlog(progname, LOG_PID, 0);
1600 logok=1;
1601 } else if (vdeplug[LR] && vdeplug[RL]) { // console mode
1602 consoleindex=npfd;
1603 pfd[npfd].fd=STDIN_FILENO;
1604 pfd[npfd].events=POLLIN | POLLHUP;
1605 npfd++;
1608 /* saves current path in pidfile_path, because otherwise with daemonize() we
1609 * forget it */
1610 if(getcwd(pidfile_path, PATH_MAX-2) == NULL) {
1611 printlog(LOG_ERR, "getcwd: %s", strerror(errno));
1612 exit(1);
1614 strcat(pidfile_path, "/");
1615 if (daemonize && daemon(0, 0)) {
1616 printlog(LOG_ERR,"daemon: %s",strerror(errno));
1617 exit(1);
1620 /* once here, we're sure we're the true process which will continue as a
1621 * server: save PID file if needed */
1622 if(pidfile) save_pidfile();
1624 if (vdepath[LR])
1625 printlog(LOG_INFO,"bidirectional vdeplug filter L=%s R=%s starting...",
1626 (*vdepath[LR])?vdepath[LR]:"DEFAULT_SWITCH",
1627 (*vdepath[RL])?vdepath[RL]:"DEFAULT_SWITCH");
1628 else if (ndirs==2)
1629 printlog(LOG_INFO,"bidirectional filter starting...");
1630 else
1631 printlog(LOG_INFO,"monodirectional filter starting...");
1633 initrand();
1634 while(1) {
1635 unsigned long long delay=nextms();
1636 int markovdelay=markovms();
1637 if (markovdelay >= 0 &&
1638 (markovdelay < delay || delay < 0)) delay=markovdelay;
1639 pfd[0].events |= POLLIN;
1640 if (WFVAL(markov_current,SPEED,LR).value > 0) {
1641 struct timeval tv;
1642 int speeddelay;
1643 gettimeofday(&tv,NULL);
1644 if (timercmp(&tv, &nextspeed[LR], <)) {
1645 timersub(&nextspeed[LR],&tv,&tv);
1646 speeddelay=tv.tv_sec*1000 + tv.tv_usec/1000;
1647 if (speeddelay > 0) {
1648 pfd[0].events &= ~POLLIN;
1649 if (speeddelay < delay || delay < 0) delay=speeddelay;
1653 if (ndirs > 1) {
1654 pfd[1].events |= POLLIN;
1655 if (WFVAL(markov_current,SPEED,RL).value > 0) {
1656 struct timeval tv;
1657 int speeddelay;
1658 if (timercmp(&tv, &nextspeed[RL], <)) {
1659 gettimeofday(&tv,NULL);
1660 timersub(&nextspeed[RL],&tv,&tv);
1661 speeddelay=tv.tv_sec*1000 + tv.tv_usec/1000;
1662 if (speeddelay > 0) {
1663 pfd[1].events &= ~POLLIN;
1664 if (speeddelay < delay || delay < 0) delay=speeddelay;
1669 n=poll(pfd,npfd,delay);
1670 if (pfd[0].revents & POLLHUP || (ndirs>1 && pfd[1].revents & POLLHUP))
1671 exit(0);
1672 if (pfd[0].revents & POLLIN) {
1673 packet_in(LR); n--;
1675 if (ndirs>1 && pfd[1].revents & POLLIN) {
1676 packet_in(RL); n--;
1678 if (n>0) { // if there are already events to handle (performance: packet switching first)
1679 int mgmtfdstart=consoleindex;
1680 if (mgmtindex >= 0) mgmtfdstart=mgmtindex+1;
1681 if (mgmtfdstart >= 0 && npfd > mgmtfdstart) {
1682 int i;
1683 for (i=mgmtfdstart;i<npfd;i++) {
1684 if (pfd[i].revents & POLLIN && mgmtcommand(pfd[i].fd) < 0)
1685 pfd[i].revents |= POLLHUP;
1686 if (pfd[i].revents) n--;
1688 for (i=mgmtfdstart;i<npfd;i++) {
1689 if (pfd[i].revents & POLLHUP)
1690 npfd=delmgmtconn(i,pfd,npfd);
1693 if (mgmtindex >= 0) {
1694 if (pfd[mgmtindex].revents != 0) {
1695 npfd=newmgmtconn(pfd[mgmtindex].fd,pfd,npfd);
1696 n--;
1699 /* if (n>0) // if there are already pending events, it means that a ctlfd has hunged up
1700 exit(0);*/
1702 markov_try();
1703 packet_dequeue();