1 /* For terms of usage/redistribution/modification see the LICENSE file */
2 /* For authors and contributors see the AUTHORS file */
4 #include "iptraf-ng-compat.h"
10 #include "capt-recvmsg.h"
11 #include "capt-recvmmsg.h"
12 #include "capt-mmap-v2.h"
13 #include "capt-mmap-v3.h"
15 static int capt_set_recv_timeout(int fd
, unsigned int msec
)
17 struct timeval timeout
;
18 socklen_t len
= sizeof(timeout
);
20 timeout
.tv_sec
= msec
/ 1000;
21 timeout
.tv_usec
= (msec
% 1000) * 1000;
22 if(setsockopt(fd
, SOL_SOCKET
, SO_RCVTIMEO
, &timeout
, len
) != 0)
28 static int capt_setup_receive_function(struct capt
*capt
)
30 /* try packet mmap() TPACKET_V3 */
31 if (capt_setup_mmap_v3(capt
) == 0)
34 /* try packet mmap() TPACKET_V2 */
35 if (capt_setup_mmap_v2(capt
) == 0)
38 /* try packet recvmmsg() */
39 if (capt_setup_recvmmsg(capt
) == 0)
42 /* try packet recvmsg() */
43 if (capt_setup_recvmsg(capt
) == 0)
49 int capt_init(struct capt
*capt
, char *ifname
)
51 capt
->have_packet
= NULL
;
52 capt
->get_packet
= NULL
;
53 capt
->put_packet
= NULL
;
58 /* initialize socket first with some default protocol;
59 * the right protocol is then set with bind();
60 * this overcomes the problem with getting packets
61 * from other interfaces, because the socket was not
62 * properly initialized yet */
63 int fd
= socket(PF_PACKET
, SOCK_RAW
, 0);
68 /* set socket receive timeout */
69 if (capt_set_recv_timeout(capt
->fd
, 250) == -1)
72 /* try all available receive functions */
73 if (capt_setup_receive_function(capt
) == -1)
76 /* bind interface (and protocol) to socket
77 * (interface can be NULL -> any interface) */
78 if (dev_bind_ifname(capt
->fd
, ifname
) == -1)
81 return 0; /* all O.K. */
90 void capt_destroy(struct capt
*capt
)
99 unsigned long capt_get_dropped(struct capt
*capt
)
101 struct tpacket_stats stats
;
102 socklen_t len
= sizeof(stats
);
104 memset(&stats
, 0, len
);
105 int err
= getsockopt(capt
->fd
, SOL_PACKET
, PACKET_STATISTICS
, &stats
, &len
);
107 die_errno("%s(): getsockopt(PACKET_STATISTICS)", __func__
);
109 capt
->dropped
+= stats
.tp_drops
;
111 return capt
->dropped
;
114 static bool time_after(struct timeval
const *a
, struct timeval
const *b
)
116 if (a
->tv_sec
> b
->tv_sec
)
118 if (a
->tv_sec
< b
->tv_sec
)
120 if(a
->tv_usec
> b
->tv_usec
)
126 static void time_add_msecs(struct timeval
*time
, unsigned int msecs
)
129 while (msecs
>= 1000) {
133 time
->tv_usec
+= msecs
* 1000;
134 while (time
->tv_usec
>= 1000000) {
136 time
->tv_usec
-= 1000000;
141 int capt_get_packet(struct capt
*capt
, struct pkt_hdr
*pkt
, int *ch
, WINDOW
*win
)
143 struct pollfd pfds
[2];
148 int have_packet
= capt
->have_packet(capt
);
149 int timeout
= DEFAULT_UPDATE_DELAY
;
150 static struct timeval next_kbd_check
= { 0 };
152 /* no packet ready, so poll() for it */
154 pfds
[nfds
].fd
= capt
->fd
;
155 pfds
[nfds
].events
= POLLIN
;
160 /* check for key press */
161 /* Monitor stdin only if in interactive, not daemon mode. */
162 if (ch
&& !daemonized
) {
165 gettimeofday(&now
, NULL
);
166 if (time_after(&now
, &next_kbd_check
)) {
168 pfds
[nfds
].events
= POLLIN
;
174 next_kbd_check
= now
;
175 time_add_msecs(&next_kbd_check
, 20);
181 ss
= poll(pfds
, nfds
, timeout
);
182 } while ((ss
== -1) && (errno
== EINTR
));
184 /* no packet ready yet */
187 if ((pfd_packet
!= -1) && (ss
> 0)) {
188 if (pfds
[pfd_packet
].revents
& POLLERR
) {
189 /* some error occured, don't try to get packet */
191 /* ... and return error */
193 } else if (pfds
[pfd_packet
].revents
& POLLIN
) {
199 int ret
= capt
->get_packet(capt
, pkt
);
205 *ch
= ERR
; /* signalize we have no key ready */
206 if (!daemonized
&& (((pfd_key
!= -1) && ((ss
> 0) && ((pfds
[pfd_key
].revents
& POLLIN
) != 0)))))
213 int capt_put_packet(struct capt
*capt
, struct pkt_hdr
*pkt
)
215 if (capt
->put_packet
)
216 capt
->put_packet(capt
, pkt
);