| # TODO |
| |
| |
| impl_debug macro: |
| |
| // Same as above, but the flags are bit OR-ed. |
| ( |
| $type: path, |
| ORed: |
| $( |
| $(#[$target: meta])* |
| $libc: ident :: $flag: ident |
| ),+ $(,)* |
| ) => { |
| impl std::fmt::Debug for $type { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| let mut written_one = false; |
| $( |
| $(#[$target])* |
| #[allow(clippy::bad_bit_mask)] // Apparently some flags are zero. |
| { |
| if (self.0 & $libc :: $flag) == $libc :: $flag { |
| if !written_one { |
| write!(f, "{}", stringify!($flag))?; |
| written_one = true; |
| } else { |
| write!(f, "|{}", stringify!($flag))?; |
| } |
| } |
| } |
| )+ |
| if !written_one { |
| write!(f, "{}", self.0) |
| } else { |
| Ok(()) |
| } |
| } |
| } |
| }; |
| |
| |
| |
| |
| |
| |
| getsockopt/setsockopt |
| https://docs.microsoft.com/en-us/windows/win32/winsock/socket-options |
| |
| |
| # IP_PROTO |
| IP_ADD_SOURCE_MEMBERSHIP |
| IP_BLOCK_SOURCE |
| IP_DONTFRAGMENT |
| IP_DROP_SOURCE_MEMBERSHIP |
| IP_HDRINCL |
| IP_OPTIONS |
| IP_ORIGINAL_ARRIVAL_IF |
| IP_PKTINFO |
| IP_RECEIVE_BROADCAST |
| IP_RECVIF |
| IP_RECVTTL |
| IP_TOS |
| IP_UNBLOCK_SOURCE |
| IP_UNICAST_IF |
| IP_WFP_REDIRECT_CONTEXT |
| IP_WFP_REDIRECT_RECORDS |
| |
| # IPPROTO_IPV6 |
| IP_ORIGINAL_ARRIVAL_IF |
| IPV6_HDRINCL |
| IPV6_HOPLIMIT |
| IPV6_PKTINFO |
| IPV6_PROTECTION_LEVEL |
| IPV6_RECVIF |
| IPV6_UNICAST_HOPS |
| IPV6_UNICAST_IF |
| |
| # IPPROTO_TCP |
| TCP_BSDURGENT |
| TCP_EXPEDITED_1122 |
| TCP_KEEPCNT |
| TCP_MAXRT |
| TCP_NODELAY |
| TCP_TIMESTAMPS |
| TCP_FASTOPEN |
| |
| # SOL_SOCKET |
| PVD_CONFIG |
| SO_ACCEPTCONN |
| SO_BROADCAST |
| SO_BSP_STATE |
| SO_CONDITIONAL_ACCEPT |
| SO_CONNDATA |
| SO_CONNDATALEN |
| SO_CONNECT_TIME |
| SO_CONNOPT |
| SO_CONNOPTLEN |
| SO_DISCDATA |
| SO_DISCDATALEN |
| SO_DISCOPT |
| SO_DISCOPTLEN |
| SO_DEBUG |
| SO_DONTLINGER |
| SO_DONTROUTE |
| SO_ERROR |
| SO_EXCLUSIVEADDRUSE |
| SO_GROUP_ID |
| SO_GROUP_PRIORITY |
| SO_KEEPALIVE |
| SO_LINGER |
| SO_MAX_MSG_SIZE |
| SO_MAXDG |
| SO_MAXPATHDG |
| SO_OOBINLINE |
| SO_OPENTYPE |
| SO_PORT_SCALABILITY |
| SO_PROTECT |
| SO_PROTOCOL_INFO |
| SO_PROTOCOL_INFOA |
| SO_PROTOCOL_INFOW |
| SO_RCVBUF |
| SO_RCVLOWAT |
| SO_RCVTIMEO |
| SO_RANDOMIZE_PORT |
| SO_REUSEADDR |
| SO_REUSE_UNICASTPORT |
| SO_REUSE_MULTICASTPORT |
| SO_SNDBUF |
| SO_SNDLOWAT |
| SO_SNDTIMEO |
| SO_TYPE |
| SO_UPDATE_ACCEPT_CONTEXT |
| SO_UPDATE_CONNECT_CONTEXT |
| SO_USELOOPBACK |
| |
| |
| |
| |
| |
| |
| |
| ## SockAddr |
| |
| /// Unix only API. |
| impl SockAddr { |
| /// Returns this address as a `SocketAddr` if it is in the `AF_UNIX` family. |
| #[cfg(feature = "all")] |
| pub fn as_unix(&self) -> Option<SocketAddr> { |
| if self.storage.ss_family as libc::c_int == libc::AF_UNIX { |
| todo!() |
| } else { |
| None |
| } |
| } |
| } |
| |
| /// Unix only API. |
| #[cfg(feature = "all")] |
| impl From<SocketAddr> for SockAddr { |
| fn from(addr: SocketAddr) -> SockAddr { |
| todo!() |
| } |
| } |
| |
| |
| |
| ## Other |
| |
| |
| |
| * Add to src/lib.rs: |
| |
| * Windows impl. |
| |
| * Expand tests. Anything after shutdown. |
| // TODO: test: |
| // * take_error |
| // * shutdown |
| // |
| // Raw: |
| // * setsockopt |
| // * getsockopt |
| // * fcntl |
| |
| |
| * Add Domain::for methods: |
| fn Domain::for_socket_addr(addr: &std::net::SocketAddr) -> Domain. |
| |
| |
| |
| SockAddr from UDS SocketAddr: |
| |
| /// Unix only API. |
| impl SockAddr { |
| /// Returns the contents of this address if it is a pathname address. |
| /// |
| /// Only possible if the address is of type `AF_UNIX` and the address it not |
| /// unnamed. |
| pub fn as_pathname(&self) -> Option<&Path> { |
| // AF_UNIX |
| todo!() |
| } |
| } |
| |
| // TODO: I don't like this. |
| impl From<SocketAddr> for SockAddr { |
| fn from(addr: SocketAddr) -> SockAddr { |
| // Same layout as that in the standard library. |
| struct StdSocketAddr { |
| addr: libc::sockaddr_un, |
| len: libc::socklen_t, |
| } |
| |
| unsafe { |
| let addr = mem::transmute::<SocketAddr, StdSocketAddr>(addr); |
| SockAddr::from_raw_parts(*(&addr.addr as *const _ as *const _), addr.len) |
| } |
| } |
| } |
| |
| |
| |
| |
| |
| /* TODO: OLD TESTS. |
| #[cfg(test)] |
| mod test { |
| use std::net::SocketAddr; |
| |
| use super::*; |
| |
| #[test] |
| fn connect_timeout_unrouteable() { |
| // this IP is unroutable, so connections should always time out |
| let addr = "10.255.255.1:80".parse::<SocketAddr>().unwrap().into(); |
| |
| let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); |
| match socket.connect_timeout(&addr, Duration::from_millis(250)) { |
| Ok(_) => panic!("unexpected success"), |
| Err(ref e) if e.kind() == io::ErrorKind::TimedOut => {} |
| Err(e) => panic!("unexpected error {}", e), |
| } |
| } |
| |
| #[test] |
| fn connect_timeout_unbound() { |
| // bind and drop a socket to track down a "probably unassigned" port |
| let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); |
| let addr = "127.0.0.1:0".parse::<SocketAddr>().unwrap().into(); |
| socket.bind(&addr).unwrap(); |
| let addr = socket.local_addr().unwrap(); |
| drop(socket); |
| |
| let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); |
| match socket.connect_timeout(&addr, Duration::from_millis(250)) { |
| Ok(_) => panic!("unexpected success"), |
| Err(ref e) |
| if e.kind() == io::ErrorKind::ConnectionRefused |
| || e.kind() == io::ErrorKind::TimedOut => {} |
| Err(e) => panic!("unexpected error {}", e), |
| } |
| } |
| |
| #[test] |
| fn connect_timeout_valid() { |
| let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); |
| socket |
| .bind(&"127.0.0.1:0".parse::<SocketAddr>().unwrap().into()) |
| .unwrap(); |
| socket.listen(128).unwrap(); |
| |
| let addr = socket.local_addr().unwrap(); |
| |
| let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); |
| socket |
| .connect_timeout(&addr, Duration::from_millis(250)) |
| .unwrap(); |
| } |
| |
| #[test] |
| #[cfg(all(unix, feature = "pair", feature = "unix"))] |
| fn pair() { |
| let (mut a, mut b) = Socket::pair(Domain::unix(), Type::stream(), None).unwrap(); |
| a.write_all(b"hello world").unwrap(); |
| let mut buf = [0; 11]; |
| b.read_exact(&mut buf).unwrap(); |
| assert_eq!(buf, &b"hello world"[..]); |
| } |
| |
| #[test] |
| #[cfg(all(unix, feature = "unix"))] |
| fn unix() { |
| use tempdir::TempDir; |
| |
| let dir = TempDir::new("unix").unwrap(); |
| let addr = SockAddr::unix(dir.path().join("sock")).unwrap(); |
| |
| let listener = Socket::new(Domain::unix(), Type::stream(), None).unwrap(); |
| listener.bind(&addr).unwrap(); |
| listener.listen(10).unwrap(); |
| |
| let mut a = Socket::new(Domain::unix(), Type::stream(), None).unwrap(); |
| a.connect(&addr).unwrap(); |
| |
| let mut b = listener.accept().unwrap().0; |
| |
| a.write_all(b"hello world").unwrap(); |
| let mut buf = [0; 11]; |
| b.read_exact(&mut buf).unwrap(); |
| assert_eq!(buf, &b"hello world"[..]); |
| } |
| |
| #[test] |
| fn keepalive() { |
| let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); |
| socket.set_keepalive(Some(Duration::from_secs(7))).unwrap(); |
| // socket.keepalive() doesn't work on Windows #24 |
| #[cfg(unix)] |
| assert_eq!(socket.keepalive().unwrap(), Some(Duration::from_secs(7))); |
| socket.set_keepalive(None).unwrap(); |
| #[cfg(unix)] |
| assert_eq!(socket.keepalive().unwrap(), None); |
| } |
| |
| #[test] |
| fn nodelay() { |
| let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); |
| |
| assert!(socket.set_nodelay(true).is_ok()); |
| |
| let result = socket.nodelay(); |
| |
| assert!(result.is_ok()); |
| assert!(result.unwrap()); |
| } |
| } |
| */ |