| 
									
										
										
										
											2018-04-17 19:46:50 -07:00
										 |  |  | //! The `packet` module defines data structures and methods to pull data from the network.
 | 
					
						
							| 
									
										
										
										
											2020-01-02 20:50:43 -07:00
										 |  |  | use crate::recvmmsg::{recv_mmsg, NUM_RCVMMSGS};
 | 
					
						
							| 
									
										
										
										
											2019-11-06 10:52:30 -08:00
										 |  |  | pub use solana_perf::packet::{
 | 
					
						
							|  |  |  |     limited_deserialize, to_packets, to_packets_chunked, Packets, PacketsRecycler, NUM_PACKETS,
 | 
					
						
							|  |  |  |     PACKETS_BATCH_SIZE, PACKETS_PER_BATCH,
 | 
					
						
							| 
									
										
										
										
											2019-11-02 00:38:30 -07:00
										 |  |  | };
 | 
					
						
							| 
									
										
										
										
											2018-11-19 23:20:18 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-04 20:13:43 -08:00
										 |  |  | use solana_metrics::inc_new_counter_debug;
 | 
					
						
							|  |  |  | pub use solana_sdk::packet::{Meta, Packet, PACKET_DATA_SIZE};
 | 
					
						
							| 
									
										
										
										
											2020-01-02 20:50:43 -07:00
										 |  |  | use std::{io::Result, net::UdpSocket, time::Instant};
 | 
					
						
							| 
									
										
										
										
											2019-11-04 20:13:43 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-10 11:49:07 -08:00
										 |  |  | pub fn recv_from(obj: &mut Packets, socket: &UdpSocket, max_wait_ms: usize) -> Result<usize> {
 | 
					
						
							| 
									
										
										
										
											2019-11-04 20:13:43 -08:00
										 |  |  |     let mut i = 0;
 | 
					
						
							|  |  |  |     //DOCUMENTED SIDE-EFFECT
 | 
					
						
							|  |  |  |     //Performance out of the IO without poll
 | 
					
						
							|  |  |  |     //  * block on the socket until it's readable
 | 
					
						
							|  |  |  |     //  * set the socket to non blocking
 | 
					
						
							|  |  |  |     //  * read until it fails
 | 
					
						
							|  |  |  |     //  * set it back to blocking before returning
 | 
					
						
							|  |  |  |     socket.set_nonblocking(false)?;
 | 
					
						
							|  |  |  |     trace!("receiving on {}", socket.local_addr().unwrap());
 | 
					
						
							|  |  |  |     let start = Instant::now();
 | 
					
						
							|  |  |  |     loop {
 | 
					
						
							| 
									
										
										
										
											2020-02-10 11:49:07 -08:00
										 |  |  |         obj.packets.resize(
 | 
					
						
							|  |  |  |             std::cmp::min(i + NUM_RCVMMSGS, PACKETS_PER_BATCH),
 | 
					
						
							|  |  |  |             Packet::default(),
 | 
					
						
							|  |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2019-11-04 20:13:43 -08:00
										 |  |  |         match recv_mmsg(socket, &mut obj.packets[i..]) {
 | 
					
						
							|  |  |  |             Err(_) if i > 0 => {
 | 
					
						
							|  |  |  |                 if start.elapsed().as_millis() > 1 {
 | 
					
						
							|  |  |  |                     break;
 | 
					
						
							| 
									
										
										
										
											2018-04-02 19:32:58 -07:00
										 |  |  |                 }
 | 
					
						
							| 
									
										
										
										
											2019-11-04 20:13:43 -08:00
										 |  |  |             }
 | 
					
						
							|  |  |  |             Err(e) => {
 | 
					
						
							|  |  |  |                 trace!("recv_from err {:?}", e);
 | 
					
						
							| 
									
										
										
										
											2020-01-02 20:50:43 -07:00
										 |  |  |                 return Err(e);
 | 
					
						
							| 
									
										
										
										
											2019-11-04 20:13:43 -08:00
										 |  |  |             }
 | 
					
						
							| 
									
										
										
										
											2020-02-10 11:49:07 -08:00
										 |  |  |             Ok((_, npkts)) => {
 | 
					
						
							| 
									
										
										
										
											2019-11-04 20:13:43 -08:00
										 |  |  |                 if i == 0 {
 | 
					
						
							|  |  |  |                     socket.set_nonblocking(true)?;
 | 
					
						
							| 
									
										
										
										
											2018-04-02 19:32:58 -07:00
										 |  |  |                 }
 | 
					
						
							| 
									
										
										
										
											2019-11-04 20:13:43 -08:00
										 |  |  |                 trace!("got {} packets", npkts);
 | 
					
						
							|  |  |  |                 i += npkts;
 | 
					
						
							|  |  |  |                 // Try to batch into big enough buffers
 | 
					
						
							|  |  |  |                 // will cause less re-shuffling later on.
 | 
					
						
							| 
									
										
										
										
											2020-02-10 11:49:07 -08:00
										 |  |  |                 if start.elapsed().as_millis() > max_wait_ms as u128 || i >= PACKETS_PER_BATCH {
 | 
					
						
							| 
									
										
										
										
											2019-11-04 20:13:43 -08:00
										 |  |  |                     break;
 | 
					
						
							| 
									
										
										
										
											2018-04-02 19:32:58 -07:00
										 |  |  |                 }
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2019-11-04 20:13:43 -08:00
										 |  |  |     obj.packets.truncate(i);
 | 
					
						
							|  |  |  |     inc_new_counter_debug!("packets-recv_count", i);
 | 
					
						
							|  |  |  |     Ok(i)
 | 
					
						
							|  |  |  | }
 | 
					
						
							| 
									
										
										
										
											2019-04-17 14:14:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-04 20:13:43 -08:00
										 |  |  | pub fn send_to(obj: &Packets, socket: &UdpSocket) -> Result<()> {
 | 
					
						
							|  |  |  |     for p in &obj.packets {
 | 
					
						
							|  |  |  |         let a = p.meta.addr();
 | 
					
						
							|  |  |  |         socket.send_to(&p.data[..p.meta.size], &a)?;
 | 
					
						
							| 
									
										
										
										
											2018-04-02 19:32:58 -07:00
										 |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2019-11-04 20:13:43 -08:00
										 |  |  |     Ok(())
 | 
					
						
							| 
									
										
										
										
											2018-04-02 19:32:58 -07:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #[cfg(test)]
 | 
					
						
							| 
									
										
										
										
											2018-06-28 13:10:36 -06:00
										 |  |  | mod tests {
 | 
					
						
							| 
									
										
										
										
											2019-03-11 03:06:22 -07:00
										 |  |  |     use super::*;
 | 
					
						
							| 
									
										
										
										
											2018-03-26 21:07:11 -07:00
										 |  |  |     use std::io;
 | 
					
						
							|  |  |  |     use std::io::Write;
 | 
					
						
							| 
									
										
										
										
											2019-05-03 11:01:35 -07:00
										 |  |  |     use std::net::{SocketAddr, UdpSocket};
 | 
					
						
							| 
									
										
										
										
											2019-01-10 13:34:48 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     #[test]
 | 
					
						
							|  |  |  |     fn test_packets_set_addr() {
 | 
					
						
							|  |  |  |         // test that the address is actually being updated
 | 
					
						
							|  |  |  |         let send_addr = socketaddr!([127, 0, 0, 1], 123);
 | 
					
						
							|  |  |  |         let packets = vec![Packet::default()];
 | 
					
						
							| 
									
										
										
										
											2019-06-27 09:32:32 +02:00
										 |  |  |         let mut msgs = Packets::new(packets);
 | 
					
						
							| 
									
										
										
										
											2019-01-10 13:34:48 -07:00
										 |  |  |         msgs.set_addr(&send_addr);
 | 
					
						
							|  |  |  |         assert_eq!(SocketAddr::from(msgs.packets[0].meta.addr()), send_addr);
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2018-06-28 13:10:36 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-02 19:32:58 -07:00
										 |  |  |     #[test]
 | 
					
						
							|  |  |  |     pub fn packet_send_recv() {
 | 
					
						
							| 
									
										
										
										
											2019-04-17 14:14:57 -07:00
										 |  |  |         solana_logger::setup();
 | 
					
						
							|  |  |  |         let recv_socket = UdpSocket::bind("127.0.0.1:0").expect("bind");
 | 
					
						
							|  |  |  |         let addr = recv_socket.local_addr().unwrap();
 | 
					
						
							|  |  |  |         let send_socket = UdpSocket::bind("127.0.0.1:0").expect("bind");
 | 
					
						
							|  |  |  |         let saddr = send_socket.local_addr().unwrap();
 | 
					
						
							|  |  |  |         let mut p = Packets::default();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         p.packets.resize(10, Packet::default());
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for m in p.packets.iter_mut() {
 | 
					
						
							| 
									
										
										
										
											2018-04-02 19:32:58 -07:00
										 |  |  |             m.meta.set_addr(&addr);
 | 
					
						
							| 
									
										
										
										
											2018-09-07 20:18:36 -07:00
										 |  |  |             m.meta.size = PACKET_DATA_SIZE;
 | 
					
						
							| 
									
										
										
										
											2018-04-02 19:32:58 -07:00
										 |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2019-11-04 20:13:43 -08:00
										 |  |  |         send_to(&p, &send_socket).unwrap();
 | 
					
						
							| 
									
										
										
										
											2019-04-17 14:14:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-10 11:49:07 -08:00
										 |  |  |         let recvd = recv_from(&mut p, &recv_socket, 1).unwrap();
 | 
					
						
							| 
									
										
										
										
											2019-04-17 14:14:57 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         assert_eq!(recvd, p.packets.len());
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-27 09:32:32 +02:00
										 |  |  |         for m in &p.packets {
 | 
					
						
							| 
									
										
										
										
											2018-09-07 20:18:36 -07:00
										 |  |  |             assert_eq!(m.meta.size, PACKET_DATA_SIZE);
 | 
					
						
							| 
									
										
										
										
											2018-04-02 19:32:58 -07:00
										 |  |  |             assert_eq!(m.meta.addr(), saddr);
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #[test]
 | 
					
						
							|  |  |  |     pub fn debug_trait() {
 | 
					
						
							|  |  |  |         write!(io::sink(), "{:?}", Packet::default()).unwrap();
 | 
					
						
							|  |  |  |         write!(io::sink(), "{:?}", Packets::default()).unwrap();
 | 
					
						
							| 
									
										
										
										
											2019-04-14 17:30:08 -07:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #[test]
 | 
					
						
							|  |  |  |     fn test_packet_partial_eq() {
 | 
					
						
							| 
									
										
										
										
											2019-05-29 10:08:35 -07:00
										 |  |  |         let mut p1 = Packet::default();
 | 
					
						
							| 
									
										
										
										
											2019-04-14 17:30:08 -07:00
										 |  |  |         let mut p2 = Packet::default();
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-29 10:08:35 -07:00
										 |  |  |         p1.meta.size = 1;
 | 
					
						
							|  |  |  |         p1.data[0] = 0;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         p2.meta.size = 1;
 | 
					
						
							|  |  |  |         p2.data[0] = 0;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-14 17:30:08 -07:00
										 |  |  |         assert!(p1 == p2);
 | 
					
						
							| 
									
										
										
										
											2019-05-29 10:08:35 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         p2.data[0] = 4;
 | 
					
						
							| 
									
										
										
										
											2019-04-14 17:30:08 -07:00
										 |  |  |         assert!(p1 != p2);
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-02-10 11:49:07 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     #[test]
 | 
					
						
							|  |  |  |     fn test_packet_resize() {
 | 
					
						
							|  |  |  |         solana_logger::setup();
 | 
					
						
							|  |  |  |         let recv_socket = UdpSocket::bind("127.0.0.1:0").expect("bind");
 | 
					
						
							|  |  |  |         let addr = recv_socket.local_addr().unwrap();
 | 
					
						
							|  |  |  |         let send_socket = UdpSocket::bind("127.0.0.1:0").expect("bind");
 | 
					
						
							|  |  |  |         let mut p = Packets::default();
 | 
					
						
							|  |  |  |         p.packets.resize(PACKETS_PER_BATCH, Packet::default());
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Should only get PACKETS_PER_BATCH packets per iteration even
 | 
					
						
							|  |  |  |         // if a lot more were sent, and regardless of packet size
 | 
					
						
							|  |  |  |         for _ in 0..2 * PACKETS_PER_BATCH {
 | 
					
						
							|  |  |  |             let mut p = Packets::default();
 | 
					
						
							|  |  |  |             p.packets.resize(1, Packet::default());
 | 
					
						
							|  |  |  |             for m in p.packets.iter_mut() {
 | 
					
						
							|  |  |  |                 m.meta.set_addr(&addr);
 | 
					
						
							|  |  |  |                 m.meta.size = 1;
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |             send_to(&p, &send_socket).unwrap();
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let recvd = recv_from(&mut p, &recv_socket, 100).unwrap();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Check we only got PACKETS_PER_BATCH packets
 | 
					
						
							|  |  |  |         assert_eq!(recvd, PACKETS_PER_BATCH);
 | 
					
						
							|  |  |  |         assert_eq!(p.packets.capacity(), PACKETS_PER_BATCH);
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2018-04-02 19:32:58 -07:00
										 |  |  | }
 |