[PATCH] Receive multiple packets at a time

Samuel Thibault
Thu, 10 Dec 2015 00:35:41 -0000

Hello,

Guus Sliepen, on Wed 02 Dec 2015 13:53:37 +0100, wrote:
> That's great! It would be good though to split
> handle_incoming_vpn_data() into a function that does the actual
> recvfrom/mmsg() and one that processes each individual packet, to reduce
> the level of indentation and make the functions a bit more readable.
> Then I'll merge it :)

Here it is.

Samuel
-------------- next part --------------
diff --git a/configure.ac b/configure.ac
index 5cdd642..fcac9d2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -187,7 +187,7 @@ AC_CHECK_TYPES([socklen_t, struct ether_header, struct
arphdr, struct ether_arp,

 dnl Checks for library functions.
 AC_TYPE_SIGNAL
-AC_CHECK_FUNCS([asprintf daemon fchmod flock ftime fork get_current_dir_name
gettimeofday mlockall pselect putenv random select strdup strerror strsignal
strtol system unsetenv usleep vsyslog writev],
+AC_CHECK_FUNCS([asprintf daemon fchmod flock ftime fork get_current_dir_name
gettimeofday mlockall pselect putenv random recvmmsg select strdup strerror
strsignal strtol system unsetenv usleep vsyslog writev],
   [], [], [#include "src/have.h"]
 )

diff --git a/src/net_packet.c b/src/net_packet.c
index e67857c..174db34 100644
--- a/src/net_packet.c
+++ b/src/net_packet.c
@@ -695,31 +695,26 @@ static node_t *try_harder(const sockaddr_t *from, const
vpn_packet_t *pkt) {
 	return n;
 }

-void handle_incoming_vpn_data(int sock) {
-	vpn_packet_t pkt;
+#ifdef HAVE_RECVMMSG
+#define MAX_MSG  256
+#else
+#define MAX_MSG  1
+#endif
+
+static void handle_incoming_vpn_packet(int sock, vpn_packet_t *pkt, sockaddr_t
*from) {
 	char *hostname;
-	sockaddr_t from;
-	socklen_t fromlen = sizeof(from);
 	node_t *n;

-	pkt.len = recvfrom(listen_socket[sock].udp, (char *) &pkt.seqno, MAXSIZE,
0, &from.sa, &fromlen);
-
-	if(pkt.len < 0) {
-		if(!sockwouldblock(sockerrno))
-			logger(LOG_ERR, "Receiving packet failed: %s",
sockstrerror(sockerrno));
-		return;
-	}
-
-	sockaddrunmap(&from);		/* Some braindead IPv6 implementations do stupid
things. */
+	sockaddrunmap(from);		/* Some braindead IPv6 implementations do stupid things.
*/

-	n = lookup_node_udp(&from);
+	n = lookup_node_udp(from);

 	if(!n) {
-		n = try_harder(&from, &pkt);
+		n = try_harder(from, pkt);
 		if(n)
-			update_node_udp(n, &from);
+			update_node_udp(n, from);
 		else ifdebug(PROTOCOL) {
-			hostname = sockaddr2hostname(&from);
+			hostname = sockaddr2hostname(from);
 			logger(LOG_WARNING, "Received UDP packet from unknown source %s",
hostname);
 			free(hostname);
 			return;
@@ -730,5 +725,55 @@ void handle_incoming_vpn_data(int sock) {

 	n->sock = sock;

-	receive_udppacket(n, &pkt);
+	receive_udppacket(n, pkt);
+}
+
+void handle_incoming_vpn_data(int sock) {
+	vpn_packet_t pkt[MAX_MSG];
+	sockaddr_t from[MAX_MSG];
+#ifdef HAVE_RECVMMSG
+	struct mmsghdr msg[MAX_MSG];
+	struct iovec iov[MAX_MSG];
+#else
+	socklen_t fromlen = sizeof(from[0]);
+#endif
+	int num = 1, i;
+
+#ifdef HAVE_RECVMMSG
+	for(i = 0; i < MAX_MSG; i++)
+	{
+		msg[i].msg_hdr.msg_name = &from[i].sa;
+		msg[i].msg_hdr.msg_namelen = sizeof(from[i]);
+		iov[i].iov_base = &pkt[i].seqno;
+		iov[i].iov_len = MAXSIZE;
+		msg[i].msg_hdr.msg_iov = &iov[i];
+		msg[i].msg_hdr.msg_iovlen = 1;
+		msg[i].msg_hdr.msg_control = NULL;
+		msg[i].msg_hdr.msg_controllen = 0;
+	}
+	num = recvmmsg(listen_socket[sock].udp, msg, MAX_MSG, MSG_DONTWAIT, NULL);
+#else
+	pkt[0].len = recvfrom(listen_socket[sock].udp, (char *) &pkt[0].seqno,
MAXSIZE, 0, &from[0].sa, &fromlen);
+#endif
+
+#ifdef HAVE_RECVMMSG
+	if(num < 0)
+#else
+	if(pkt[0].len < 0)
+#endif
+	{
+		if(!sockwouldblock(sockerrno))
+			logger(LOG_ERR, "Receiving packet failed: %s",
sockstrerror(sockerrno));
+		return;
+	}
+
+	for(i = 0; i < num; i++)
+	{
+#ifdef HAVE_RECVMMSG
+		pkt[i].len = msg[i].msg_len;
+		if(pkt[i].len <= 0 || pkt[i].len > MAXSIZE)
+			continue;
+#endif
+		handle_incoming_vpn_packet(sock, &pkt[i], &from[i]);
+	}
 }