capt_get_packet(): check for key press only every 20ms
[iptraf-ng.git] / src / capt.c
blob4bb653b0804eaa2c2765c07a6756f3b7b519a338
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"
6 #include "error.h"
7 #include "ifaces.h"
8 #include "packet.h"
9 #include "capt.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)
23 return -1;
24 else
25 return 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)
32 return 0;
34 /* try packet mmap() TPACKET_V2 */
35 if (capt_setup_mmap_v2(capt) == 0)
36 return 0;
38 /* try packet recvmmsg() */
39 if (capt_setup_recvmmsg(capt) == 0)
40 return 0;
42 /* try packet recvmsg() */
43 if (capt_setup_recvmsg(capt) == 0)
44 return 0;
46 return -1;
49 int capt_init(struct capt *capt, char *ifname)
51 capt->have_packet = NULL;
52 capt->get_packet = NULL;
53 capt->put_packet = NULL;
54 capt->cleanup = NULL;
56 capt->dropped = 0UL;
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);
64 if (fd == -1)
65 return fd;
66 capt->fd = fd;
68 /* set socket receive timeout */
69 if (capt_set_recv_timeout(capt->fd, 250) == -1)
70 goto out;
72 /* try all available receive functions */
73 if (capt_setup_receive_function(capt) == -1)
74 goto out;
76 /* bind interface (and protocol) to socket
77 * (interface can be NULL -> any interface) */
78 if (dev_bind_ifname(capt->fd, ifname) == -1)
79 goto out;
81 return 0; /* all O.K. */
83 out:
84 close(capt->fd);
85 capt->fd = -1;
87 return -1;
90 void capt_destroy(struct capt *capt)
92 if (capt->cleanup)
93 capt->cleanup(capt);
95 close(capt->fd);
96 capt->fd = -1;
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);
106 if (err < 0)
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)
117 return true;
118 if (a->tv_sec < b->tv_sec)
119 return false;
120 if(a->tv_usec > b->tv_usec)
121 return true;
122 else
123 return false;
126 static void time_add_msecs(struct timeval *time, unsigned int msecs)
128 if (time != NULL) {
129 while (msecs >= 1000) {
130 time->tv_sec++;
131 msecs -= 1000;
133 time->tv_usec += msecs * 1000;
134 while (time->tv_usec >= 1000000) {
135 time->tv_sec++;
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];
144 nfds_t nfds = 0;
145 int pfd_packet = -1;
146 int pfd_key = -1;
147 int ss = 0;
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 */
153 if (!have_packet) {
154 pfds[nfds].fd = capt->fd;
155 pfds[nfds].events = POLLIN;
156 pfd_packet = nfds;
157 nfds++;
160 /* check for key press */
161 /* Monitor stdin only if in interactive, not daemon mode. */
162 if (ch && !daemonized) {
163 struct timeval now;
165 gettimeofday(&now, NULL);
166 if (time_after(&now, &next_kbd_check)) {
167 pfds[nfds].fd = 0;
168 pfds[nfds].events = POLLIN;
169 pfd_key = nfds;
170 nfds++;
171 if (have_packet)
172 timeout = 0;
174 next_kbd_check = now;
175 time_add_msecs(&next_kbd_check, 20);
179 if (nfds > 0)
180 do {
181 ss = poll(pfds, nfds, timeout);
182 } while ((ss == -1) && (errno == EINTR));
184 /* no packet ready yet */
185 pkt->pkt_len = 0;
187 if ((pfd_packet != -1) && (ss > 0)) {
188 if (pfds[pfd_packet].revents & POLLERR) {
189 /* some error occured, don't try to get packet */
190 have_packet = false;
191 /* ... and return error */
192 ss = -1;
193 } else if (pfds[pfd_packet].revents & POLLIN) {
194 /* packet ready */
195 have_packet = true;
198 if (have_packet) {
199 int ret = capt->get_packet(capt, pkt);
200 if (ret <= 0)
201 ss = ret;
204 if (ch) {
205 *ch = ERR; /* signalize we have no key ready */
206 if (!daemonized && (((pfd_key != -1) && ((ss > 0) && ((pfds[pfd_key].revents & POLLIN) != 0)))))
207 *ch = wgetch(win);
210 return ss;
213 int capt_put_packet(struct capt *capt, struct pkt_hdr *pkt)
215 if (capt->put_packet)
216 capt->put_packet(capt, pkt);
218 return 0;