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).
32 #include <sys/types.h>
34 #include <sys/socket.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>
48 # error "No syslimits.h found"
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}};
59 char debuglevel
[NPFD
];
65 #define ALGO_UNIFORM 0
66 #define ALGO_GAUSS_NORMAL 1
67 static char charalgo
[]="UN";
85 /* general Markov chain approach */
86 int markov_numnodes
=0;
90 struct wirevalue val
[NUMVALUES
][2];
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 */
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];
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
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
)
136 static void markov_compute(i
)
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
)
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
) {
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();
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
)
174 copyadjmap(numnodes
,newadjmap
);
178 markov_numnodes
=numnodes
;
182 static int markov_step(int i
) {
183 double num
=drand48() * 100;
185 markov_next
+=markov_time
;
186 for (j
=0;j
<markov_numnodes
;j
++) {
188 double val
=ADJMAP(i
,ROT(i
,j
));
195 for (j
=0;j
<NPFD
;j
++) {
196 if (debuglevel
[j
] > 0) {
199 printoutc(fd
,"%04d Node %d \"%s\" -> %d \"%s\"",
201 i
, WFNAME(i
)?WFNAME(i
):"",
202 k
, WFNAME(k
)?WFNAME(k
):"");
209 static int markovms(void) {
210 if (markov_numnodes
> 1) {
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;
220 static inline void markov_try(void) {
221 if (markov_numnodes
> 1) {
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) {
232 gettimeofday(&v
,NULL
);
233 markov_next
=v
.tv_sec
*1000+v
.tv_usec
/1000;
234 markov_current
=markov_step(markov_current
);
240 #define MGMTMODEARG 129
241 #define DAEMONIZEARG 130
242 #define PIDFILEARG 131
243 #define LOGSOCKETARG 132
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()
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
);
275 return wv
->value
+wv
->plus
*((drand48()*2.0)-1.0);
276 case ALGO_GAUSS_NORMAL
:
284 return wv
->value
+wv
->plus
* SIGMA
* x
* sqrt ( (-2 * log(r2
)) /r2
);
291 void printlog(int priority
, const char *format
, ...)
295 va_start (arg
, format
);
298 vsyslog(priority
,format
,arg
);
300 fprintf(stderr
,"%s: ",progname
);
301 vfprintf(stderr
,format
,arg
);
302 fprintf(stderr
,"\n");
307 static int read_wirevalue(char *s
, int tag
)
309 struct wirevalue
*wv
;
315 char algo
=ALGO_UNIFORM
;
317 while ((s
[n
] == ' ' || s
[n
] == '\n' || s
[n
] == '\t') && n
>0)
323 while(s
[n
]!='[' && n
>1)
326 sscanf(idstr
,"%d",&markov_node
);
327 if (markov_node
< 0 || markov_node
>= markov_numnodes
)
330 wv
=WFADDR(markov_node
,tag
);
339 algo
=ALGO_GAUSS_NORMAL
;
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) {
366 wv
[LR
].plus
=vplus
*mult
;
368 } else if ((n
=sscanf(s
,"RL%lf+%lf",&v
,&vplus
)) > 0) {
370 wv
[RL
].plus
=vplus
*mult
;
377 unsigned long long when
;
378 unsigned int counter
;
385 struct packpq sentinel
={0,0,0,NULL
,0};
387 unsigned long long maxwhen
;
388 unsigned int counter
;
392 static unsigned long long nextms()
395 unsigned long long now
=0;
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
;
407 static inline int outpacket(int dir
,const unsigned char *buf
,int size
)
410 snprintf(blinkmsg
+blinkidlen
,20,"%s %d\n",
411 (ndirs
==2)?((dir
==0)?"LR":"RL"):"--",
413 sendto(blinksock
,blinkmsg
,strlen(blinkmsg
+blinkidlen
)+blinkidlen
,0,
414 (struct sockaddr
*)&blinksun
, sizeof(blinksun
));
417 return vde_send(vdeplug
[1-dir
],buf
+2,size
-2,0);
419 return write(outfd
[dir
],buf
,size
);
422 int writepacket(int dir
,const unsigned char *buf
,int size
)
425 if (max_wirevalue(markov_current
,NOISE
,dir
) > 0) {
426 double noiseval
=compute_wirevalue(NOISE
,dir
);
428 while ((drand48()*8*MEGA
) < (size
-2)*8*noiseval
)
431 unsigned char noisedpacket
[BUFSIZE
];
432 memcpy(noisedpacket
,buf
,size
);
434 int flippedbit
=(drand48()*size
*8);
435 noisedpacket
[(flippedbit
>> 3) + 2] ^= 1<<(flippedbit
& 0x7);
438 return outpacket(dir
,noisedpacket
,size
);
440 return outpacket(dir
,buf
,size
);
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()
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
--];
461 delay_bufsize
[pqh
[1]->dir
] -= pqh
[1]->size
;
462 writepacket(pqh
[1]->dir
,pqh
[1]->buf
,pqh
[1]->size
);
465 /* rebuild the heap */
469 /* choose the min between pqh[2k] and pqh[2k+1] */
471 (pqh
[j
]->when
> pqh
[j
+1]->when
||
472 (pqh
[j
]->when
== pqh
[j
+1]->when
&&
473 pqh
[j
]->counter
> pqh
[j
+1]->counter
)
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
)
491 static void packet_enqueue(int dir
,const unsigned char *buf
,int size
,int delms
)
495 struct packpq
*new=malloc(sizeof(struct packpq
));
497 printlog(LOG_WARNING
,"malloc elem %s",strerror(errno
));
500 gettimeofday(&v
,NULL
);
501 new->when
= ((unsigned long long)v
.tv_sec
* 1000 + v
.tv_usec
/1000) + delms
;
502 if (new->when
> maxwhen
) {
506 if (!nofifo
&& new->when
<= maxwhen
) {
510 new->counter
=counter
;
512 new->buf
=malloc(size
);
513 if (new->buf
==NULL
) {
514 printlog(LOG_WARNING
,"malloc elem buf %s",strerror(errno
));
517 memcpy(new->buf
,buf
,size
);
519 delay_bufsize
[dir
]+=size
;
521 pqh
=malloc(PQCHUNK
*sizeof(struct packpq
*));
523 printlog(LOG_WARNING
,"malloc %s",strerror(errno
));
526 pqh
[0]=&sentinel
; maxpq
=PQCHUNK
;
529 pqh
=realloc(pqh
,(maxpq
=maxpq
+PQCHUNK
) * sizeof(struct packpq
*));
531 printlog(LOG_WARNING
,"malloc %s",strerror(errno
));
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
)) {
547 void handle_packet(int dir
,const unsigned char *buf
,int size
)
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
))
555 /* Total packet loss */
556 if (min_wirevalue(markov_current
,LOSS
,dir
) >= 100.0)
558 /* probabilistic loss */
559 if (max_wirevalue(markov_current
,LOSTBURST
,dir
) > 0) {
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
]) {
567 if (drand48() < alpha
) loss_status
[dir
]=FAULTY_BURST
;
570 if (drand48() < beta
) loss_status
[dir
]=OK_BURST
;
573 if (loss_status
[dir
] != OK_BURST
)
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
)
586 /* times is the number of dup packets */
588 if (max_wirevalue(markov_current
,DDUP
,dir
) > 0) {
589 double dupval
=compute_wirevalue(DDUP
,dir
)/100;
590 while (drand48() < dupval
)
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
)
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;
610 unsigned int commtime
=((unsigned)size
)*1000000/((unsigned int)speedval
);
612 gettimeofday(&tv
,NULL
);
613 banddelay
=commtime
/1000;
614 if (timercmp(&tv
,&nextspeed
[dir
], > ))
616 nextspeed
[dir
].tv_usec
+= commtime
;
617 nextspeed
[dir
].tv_sec
+= nextspeed
[dir
].tv_usec
/ 1000000;
618 nextspeed
[dir
].tv_usec
%= 1000000;
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;
628 unsigned int commtime
=((unsigned)size
)*1000000/((unsigned int)bandval
);
630 gettimeofday(&tv
,NULL
);
631 if (timercmp(&tv
,&nextband
[dir
], > )) {
633 banddelay
=commtime
/1000;
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;
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
;
652 packet_enqueue(dir
,buf
,size
,(int) delval
);
654 writepacket(dir
,buf
,size
);
656 writepacket(dir
,buf
,size
);
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);
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
;
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);
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);
690 printlog(LOG_WARNING
,"Packet length error size %d rnx %d",size
,rnx
[dir
]);
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
;
702 handle_packet(dir
,buf
,rnx
[dir
]+2);
710 static void packet_in(int dir
)
712 unsigned char buf
[BUFSIZE
];
715 n
=vde_recv(vdeplug
[dir
],buf
+2,BUFSIZE
-2,0);
718 handle_packet(dir
,buf
,n
+2);
720 n
=read(pfd
[dir
].fd
,buf
,BUFSIZE
);
723 splitpacket(buf
,n
,dir
);
727 static int check_open_fifos_n_plugs(struct pollfd
*pfd
,int *outfd
,char *vdepath
[],VDECONN
*vdeplug
[])
730 struct stat stfd
[NPIPES
];
733 env_in
=getenv("ALTERNATE_STDIN");
734 env_out
=getenv("ALTERNATE_STDOUT");
736 alternate_stdin
=atoi(env_in
);
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
));
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
));
753 pfd
[1].fd
=vde_datafd(vdeplug
[RL
]);
754 pfd
[1].events
=POLLIN
| POLLHUP
;
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
));
763 if (fstat(STDOUT_FILENO
,&stfd
[STDOUT_FILENO
]) < 0) {
764 fprintf(stderr
,"%s: Error on stdout: %s\n",progname
,strerror(errno
));
767 if (!S_ISFIFO(stfd
[STDIN_FILENO
].st_mode
)) {
768 fprintf(stderr
,"%s: Error on stdin: %s\n",progname
,"it is not a pipe");
771 if (!S_ISFIFO(stfd
[STDOUT_FILENO
].st_mode
)) {
772 fprintf(stderr
,"%s: Error on stdin: %s\n",progname
,"it is not a pipe");
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) {
785 pfd
[0].fd
=STDIN_FILENO
;
786 pfd
[0].events
=POLLIN
| POLLHUP
;
787 outfd
[0]=STDOUT_FILENO
;
789 if (fstat(outfd
[1],&stfd
[1]) < 0) {
790 fprintf(stderr
,"%s: Error on secondary out: %s\n",progname
,strerror(errno
));
793 if (!S_ISFIFO(stfd
[0].st_mode
)) {
794 fprintf(stderr
,"%s: Error on secondary in: %s\n",progname
,"it is not a pipe");
797 if (!S_ISFIFO(stfd
[1].st_mode
)) {
798 fprintf(stderr
,"%s: Error on secondary out: %s\n",progname
,"it is not a pipe");
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
;
813 static void save_pidfile()
815 if(pidfile
[0] != '/')
816 strncat(pidfile_path
, pidfile
, PATH_MAX
- strlen(pidfile_path
) - 1);
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
);
826 printlog(LOG_ERR
, "Error in pidfile creation: %s", strerror(errno
));
830 if((f
= fdopen(fd
, "w")) == NULL
) {
831 printlog(LOG_ERR
, "Error in FILE* construction: %s", strerror(errno
));
835 if(fprintf(f
, "%ld\n", (long int)getpid()) <= 0) {
836 printlog(LOG_ERR
, "Error in writing pidfile");
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
));
849 vde_close(vdeplug
[LR
]);
851 vde_close(vdeplug
[RL
]);
856 static void sig_handler(int sig
)
858 /*fprintf(stderr,"Caught signal %d, cleaning up and exiting", sig);*/
860 signal(sig
, SIG_DFL
);
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 },
883 { SIGPOLL
, "SIGPOLL", 1 },
885 { SIGSTKFLT
, "SIGSTKFLT", 1 },
887 { SIGIO
, "SIGIO", 1 },
888 { SIGPWR
, "SIGPWR", 1 },
890 { SIGUNUSED
, "SIGUNUSED", 1 },
894 { SIGXCPU
, "SIGXCPU", 1 },
895 { SIGXFSZ
, "SIGXFSZ", 1 },
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
,
908 static int openmgmt(char *mgmt
)
911 struct sockaddr_un sun
;
914 if((mgmtconnfd
= socket(PF_UNIX
, SOCK_STREAM
, 0)) < 0){
915 fprintf(stderr
,"%s: mgmt socket: %s",progname
,strerror(errno
));
918 if(setsockopt(mgmtconnfd
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &one
,
920 fprintf(stderr
,"%s: mgmt setsockopt: %s",progname
,strerror(errno
));
923 if(fcntl(mgmtconnfd
, F_SETFL
, O_NONBLOCK
) < 0){
924 fprintf(stderr
,"%s: Setting O_NONBLOCK on mgmt fd: %s",progname
,strerror(errno
));
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
));
933 chmod(sun
.sun_path
,mgmtmode
);
934 if(listen(mgmtconnfd
, 15) < 0){
935 fprintf(stderr
,"%s: mgmt listen: %s",progname
,strerror(errno
));
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
)
948 struct sockaddr addr
;
949 new = accept(fd
, &addr
, &len
);
951 printlog(LOG_WARNING
,"mgmt accept %s",strerror(errno
));
955 snprintf(buf
,MAXCMD
,header
,PACKAGE_VERSION
);
956 write(new,buf
,strlen(buf
));
957 write(new,prompt
,strlen(prompt
));
959 pfd
[nfds
].events
=POLLIN
| POLLHUP
;
963 printlog(LOG_WARNING
,"too many mgmt connections");
969 static void printoutc(int fd
, const char *format
, ...)
972 char outbuf
[MAXCMD
+1];
974 va_start (arg
, format
);
975 vsnprintf(outbuf
,MAXCMD
,format
,arg
);
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
)
1035 static int setmarkov_resize(int fd
,char *s
)
1046 static int setedge(int fd
,char *s
)
1050 sscanf(s
,"%d,%d,%lg",&x
,&y
,&weight
);
1051 if (x
>=0 && x
<markov_numnodes
&& y
>=0 && y
<markov_numnodes
) {
1059 static int setmarkov_time(int fd
,char *s
)
1062 sscanf(s
,"%lg",&newvalue
);
1064 markov_time
=newvalue
;
1071 static int setmarkov_node(int fd
,char *s
)
1074 if (n
>=0 && n
<markov_numnodes
) {
1081 static int setmarkov_debug(int fd
,char *s
)
1084 if (fd
>= 0 && n
>=0) {
1087 for (i
=0;i
<NPFD
;i
++) {
1088 if (pfd
[i
].fd
== fd
)
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
):"",
1108 static int setmarkov_name(int fd
,char *s
)
1111 while (strchr(" \t",*s
)) s
++;
1113 if (n
>=0 && n
<markov_numnodes
) {
1114 while (strchr("0123456789",*s
)) s
++;
1115 while (strchr(" \t",*s
)) s
++;
1117 if (s
[strlen(s
)-1]=='\n')
1119 if (WFNAME(n
)) free(WFNAME(n
));
1121 WFNAME(n
)=strdup(s
);
1129 static int logout(int fd
,char *s
)
1134 static int doshutdown(int fd
,char *s
)
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");
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
)
1180 node
=markov_current
;
1181 if (node
>= markov_numnodes
|| node
< 0)
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
);
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
]);
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
);
1240 blinkmsg
[(int)blinkidlen
]=0;
1241 printoutc(fd
,"Blink socket: %s",blinksun
.sun_path
);
1242 printoutc(fd
,"Blink id: %s",blinkmsg
);
1247 static int showedges(int fd
,char *s
)
1254 node
=markov_current
;
1255 if (node
>= markov_numnodes
|| node
< 0)
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
):"",
1266 static int runscript(int fd
,char *path
);
1268 #define WITHFILE 0x80
1269 static struct comlist
{
1271 int (*fun
)(int fd
,char *arg
);
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},
1281 {"bandwidth",setband
, 0},
1282 {"band",setband
, 0},
1283 {"speed",setspeed
, 0},
1284 {"chanbufsize",setchanbufsize
, 0},
1285 {"capacity",setchanbufsize
, 0},
1286 {"noise",setnoise
, 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;
1307 (buf
[len
]=='\n' || buf
[len
]==' ' || buf
[len
]=='\t')) {
1313 static int handle_cmd(int fd
,char *inbuf
)
1318 while (*inbuf
== ' ' || *inbuf
== '\t' || *inbuf
== '\n') inbuf
++;
1320 if (*inbuf
!= '\0' && *inbuf
!= '#') {
1322 && strncmp(commandlist
[i
].tag
,inbuf
,strlen(commandlist
[i
].tag
))!=0;
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
)
1337 printoutc(fd
,"1000 Success");
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
));
1349 static int runscript(int fd
,char *path
)
1351 FILE *f
=fopen(path
,"r");
1356 while (fgets(buf
,MAXCMD
,f
) != NULL
) {
1359 printoutc(fd
,"%s (%s) %s",prompt
,path
,buf
);
1361 handle_cmd(fd
, buf
);
1368 static int mgmtcommand(int fd
)
1373 n
= read(fd
, buf
, MAXCMD
);
1375 printlog(LOG_WARNING
,"read from mgmt %s",strerror(errno
));
1381 if (fd
==STDIN_FILENO
)
1382 outfd
=STDOUT_FILENO
;
1384 rv
=handle_cmd(outfd
,buf
);
1386 write(outfd
,prompt
,strlen(prompt
));
1391 static int delmgmtconn(int i
,struct pollfd
*pfd
,int nfds
)
1395 if (pfd
[i
].fd
== 0) /* close stdin implies exit */
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));
1400 debuglevel
[nfds
] = 0;
1408 fprintf(stderr
,"Usage: %s OPTIONS\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"
1421 "\t--mgmt|-M management_socket\n"
1422 "\t--mgmtmode management_permission(octal)\n"
1423 "\t--vde-plug plug1:plug2 | -v plug1:plug2\n"
1425 "\t--pidfile pidfile\n"
1426 "\t--blink blinksocket\n"
1427 "\t--blinkid blink_id_string\n"
1432 int main(int argc
,char *argv
[])
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'},
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'},
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
},
1462 progname
=basename(argv
[0]);
1470 c
= GETOPT_LONG (argc
, argv
, "hNl:n:d:M:D:m:b:s:c:v:L:f:",
1471 long_options
, &option_index
);
1479 rcfile
=strdup(optarg
);
1482 read_wirevalue(optarg
,DELAY
);
1485 read_wirevalue(optarg
,LOSS
);
1488 read_wirevalue(optarg
,LOSTBURST
);
1491 read_wirevalue(optarg
,DDUP
);
1494 read_wirevalue(optarg
,BAND
);
1497 read_wirevalue(optarg
,MTU
);
1500 read_wirevalue(optarg
,NOISE
);
1503 read_wirevalue(optarg
,SPEED
);
1506 read_wirevalue(optarg
,CHANBUFSIZE
);
1509 mgmt
=strdup(optarg
);
1517 vdepath
[LR
]=strdup(optarg
);
1518 colon
=index(vdepath
[LR
],':');
1521 vdepath
[RL
]=colon
+1;
1523 fprintf(stderr
,"Bad vde_plugs specification.\n");
1528 sscanf(optarg
,"%o",&mgmtmode
);
1534 pidfile
=strdup(optarg
);
1537 blinksun
.sun_family
= PF_UNIX
;
1538 snprintf(blinksun
.sun_path
,sizeof(blinksun
.sun_path
),"%s",optarg
);
1541 if (blinkmsg
) free(blinkmsg
);
1542 blinkidlen
=strlen(optarg
)+1;
1543 asprintf(&blinkmsg
,"%s 12345678901234567890",optarg
);
1553 if (blinksun
.sun_path
[0] != 0) {
1554 blinksock
=socket(AF_UNIX
, SOCK_DGRAM
, 0);
1555 if (blinkmsg
==NULL
) {
1557 asprintf(&blinkmsg
,"%06d 12345678901234567890",getpid());
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
);
1578 runscript(-1,rcfile
);
1580 pfd
[npfd
].fd
=vde_ctlfd(vdeplug
[LR
]);
1581 pfd
[npfd
].events
=POLLIN
| POLLHUP
;
1585 pfd
[npfd
].fd
=vde_ctlfd(vdeplug
[RL
]);
1586 pfd
[npfd
].events
=POLLIN
| POLLHUP
;
1591 int mgmtfd
=openmgmt(mgmt
);
1593 pfd
[mgmtindex
].fd
=mgmtfd
;
1594 pfd
[mgmtindex
].events
=POLLIN
| POLLHUP
;
1599 openlog(progname
, LOG_PID
, 0);
1601 } else if (vdeplug
[LR
] && vdeplug
[RL
]) { // console mode
1603 pfd
[npfd
].fd
=STDIN_FILENO
;
1604 pfd
[npfd
].events
=POLLIN
| POLLHUP
;
1608 /* saves current path in pidfile_path, because otherwise with daemonize() we
1610 if(getcwd(pidfile_path
, PATH_MAX
-2) == NULL
) {
1611 printlog(LOG_ERR
, "getcwd: %s", strerror(errno
));
1614 strcat(pidfile_path
, "/");
1615 if (daemonize
&& daemon(0, 0)) {
1616 printlog(LOG_ERR
,"daemon: %s",strerror(errno
));
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();
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");
1629 printlog(LOG_INFO
,"bidirectional filter starting...");
1631 printlog(LOG_INFO
,"monodirectional filter starting...");
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) {
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
;
1654 pfd
[1].events
|= POLLIN
;
1655 if (WFVAL(markov_current
,SPEED
,RL
).value
> 0) {
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
))
1672 if (pfd
[0].revents
& POLLIN
) {
1675 if (ndirs
>1 && pfd
[1].revents
& POLLIN
) {
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
) {
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
);
1699 /* if (n>0) // if there are already pending events, it means that a ctlfd has hunged up