quiche-server: sendmmsg() support when supported.
diff --git a/tools/apps/src/bin/quiche-server.rs b/tools/apps/src/bin/quiche-server.rs
index e7d8828..b04077f 100644
--- a/tools/apps/src/bin/quiche-server.rs
+++ b/tools/apps/src/bin/quiche-server.rs
@@ -86,8 +86,10 @@
 
     let max_datagram_size = MAX_DATAGRAM_SIZE;
     let enable_gso = detect_gso(&socket, max_datagram_size);
+    let enable_sendmmsg = detect_sendmmsg();
 
     trace!("GSO detected: {}", enable_gso);
+    trace!("sendmmsg() detected: {}", enable_sendmmsg);
 
     // Create the configuration for the QUIC connections.
     let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
@@ -522,6 +524,7 @@
                 &dst_info.unwrap().to,
                 client.max_datagram_size,
                 enable_gso,
+                enable_sendmmsg,
             ) {
                 if e.kind() == std::io::ErrorKind::WouldBlock {
                     trace!("send() would block");
diff --git a/tools/apps/src/sendto.rs b/tools/apps/src/sendto.rs
index da7a8ba..059bd09 100644
--- a/tools/apps/src/sendto.rs
+++ b/tools/apps/src/sendto.rs
@@ -92,12 +92,89 @@
     panic!("send_to_gso() should not be called on non-linux platforms");
 }
 
+/// Detecting whether sendmmsg() can be used.
+pub fn detect_sendmmsg() -> bool {
+    cfg!(target_os = "linux") ||
+        cfg!(target_os = "android") ||
+        cfg!(target_os = "freebsd") ||
+        cfg!(target_os = "netbsd")
+}
+
+/// Send packets using sendmmsg().
+#[cfg(any(
+    target_os = "linux",
+    target_os = "android",
+    target_os = "freebsd",
+    target_os = "netbsd",
+))]
+fn send_to_sendmmsg(
+    socket: &mio::net::UdpSocket, buf: &[u8], target: &net::SocketAddr,
+    segment_size: usize,
+) -> io::Result<usize> {
+    use nix::sys::socket::sendmmsg;
+    use nix::sys::socket::InetAddr;
+    use nix::sys::socket::MsgFlags;
+    use nix::sys::socket::SendMmsgData;
+    use nix::sys::socket::SockAddr;
+    use nix::sys::uio::IoVec;
+    use std::os::unix::io::AsRawFd;
+
+    let dst = SockAddr::new_inet(InetAddr::from_std(target));
+
+    let mut off = 0;
+    let mut left = buf.len();
+
+    let mut msgs = Vec::new();
+    let mut iovs = Vec::new();
+
+    while left > 0 {
+        let pkt_len = cmp::min(left, segment_size);
+
+        iovs.push([IoVec::from_slice(&buf[off..off + pkt_len])]);
+
+        off += pkt_len;
+        left -= pkt_len;
+    }
+
+    for iov in iovs.iter() {
+        msgs.push(SendMmsgData {
+            iov,
+            cmsgs: &[],
+            addr: Some(dst),
+            _lt: Default::default(),
+        });
+    }
+
+    match sendmmsg(socket.as_raw_fd(), msgs.iter(), MsgFlags::empty()) {
+        Ok(results) => Ok(results.iter().sum()),
+        Err(e) => match e.as_errno() {
+            Some(v) => Err(io::Error::from(v)),
+            None => Err(io::Error::new(io::ErrorKind::Other, e)),
+        },
+    }
+}
+
+/// Send packets using sendmmsg().
+#[cfg(not(any(
+    target_os = "linux",
+    target_os = "android",
+    target_os = "freebsd",
+    target_os = "netbsd",
+)))]
+fn send_to_sendmmsg(
+    _socket: &mio::net::UdpSocket, _buf: &[u8], _target: &net::SocketAddr,
+    _segment_size: usize,
+) -> io::Result<usize> {
+    panic!("send_to_sendmmsg() should not be called on non-supported platforms");
+}
+
 /// A wrapper function of send_to().
 /// - when GSO enabled, send a packet using send_to_gso().
+/// - when sendmmsg() enabled, send a packet using send_to_sendmmsg().
 /// Otherwise, send packet using socket.send_to().
 pub fn send_to(
     socket: &mio::net::UdpSocket, buf: &[u8], target: &net::SocketAddr,
-    segment_size: usize, enable_gso: bool,
+    segment_size: usize, enable_gso: bool, enable_sendmmsg: bool,
 ) -> io::Result<usize> {
     if enable_gso {
         match send_to_gso(socket, buf, target, segment_size) {
@@ -110,6 +187,17 @@
         }
     }
 
+    if enable_sendmmsg {
+        match send_to_sendmmsg(socket, buf, target, segment_size) {
+            Ok(v) => {
+                return Ok(v);
+            },
+            Err(e) => {
+                return Err(e);
+            },
+        }
+    }
+
     let mut off = 0;
     let mut left = buf.len();
     let mut written = 0;