+void handle_incoming_vpn_data(void *data, int flags) {
+ listen_socket_t *ls = data;
+
+#ifdef HAVE_RECVMMSG
+#define MAX_MSG 64
+ vpn_packet_t pkt[MAX_MSG];
+ sockaddr_t addr[MAX_MSG];
+ struct mmsghdr msg[MAX_MSG];
+ struct iovec iov[MAX_MSG];
+
+ for(int i = 0; i < MAX_MSG; i++) {
+ pkt[i].offset = 0;
+
+ iov[i] = (struct iovec){
+ .iov_base = DATA(&pkt[i]),
+ .iov_len = MAXSIZE,
+ };
+
+ msg[i].msg_hdr = (struct msghdr){
+ .msg_name = &addr[i].sa,
+ .msg_namelen = sizeof addr[i],
+ .msg_iov = &iov[i],
+ .msg_iovlen = 1,
+ };
+ }
+
+ int num = recvmmsg(ls->udp.fd, msg, MAX_MSG, MSG_DONTWAIT, NULL);
+
+ if(num < 0) {
+ if(!sockwouldblock(sockerrno))
+ logger(DEBUG_ALWAYS, LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno));
+ return;
+ }
+
+ for(int i = 0; i < num; i++) {
+ pkt[i].len = msg[i].msg_len;
+ if(pkt[i].len <= 0 || pkt[i].len > MAXSIZE)
+ continue;
+ handle_incoming_vpn_packet(ls, &pkt[i], &addr[i]);
+ }
+#else
+ vpn_packet_t pkt;
+ sockaddr_t addr = {};
+ socklen_t addrlen = sizeof addr;
+
+ pkt.offset = 0;
+ int len = recvfrom(ls->udp.fd, DATA(&pkt), MAXSIZE, 0, &addr.sa, &addrlen);
+
+ if(len <= 0 || len > MAXSIZE) {
+ if(!sockwouldblock(sockerrno))
+ logger(DEBUG_ALWAYS, LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno));
+ return;
+ }
+
+ pkt.len = len;
+
+ handle_incoming_vpn_packet(ls, &pkt, &addr);
+#endif
+}
+