diff --git a/Cargo.lock b/Cargo.lock index a8d85ef06..c0a57bb2c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -417,6 +417,15 @@ dependencies = [ "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "gethostname" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "heck" version = "0.3.1" @@ -1041,6 +1050,7 @@ dependencies = [ "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "flame 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "flamer 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gethostname 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hexf-parse 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1924,6 +1934,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "45dc39533a6cae6da2b56da48edae506bb767ec07370f86f70fc062e9d435869" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" +"checksum gethostname 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4ab273ca2a31eb6ca40b15837ccf1aa59a43c5db69ac10c542be342fae2e01d" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum hexf-parse 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "79296f72d53a89096cbc9a88c9547ee8dfe793388674620e2207593d370550ac" diff --git a/tests/snippets/stdlib_socket.py b/tests/snippets/stdlib_socket.py index d7afe1bd3..581100c58 100644 --- a/tests/snippets/stdlib_socket.py +++ b/tests/snippets/stdlib_socket.py @@ -115,3 +115,17 @@ with assertRaises(OSError): with assertRaises(OSError): socket.socket(socket.AF_INET, 1000) + +with assertRaises(OSError): + socket.inet_aton("test") + +assert socket.inet_aton("127.0.0.1")==b"\x7f\x00\x00\x01" +assert socket.inet_aton("255.255.255.255")==b"\xff\xff\xff\xff" + + +assert socket.inet_ntoa(b"\x7f\x00\x00\x01")=="127.0.0.1" +assert socket.inet_ntoa(b"\xff\xff\xff\xff")=="255.255.255.255" + +with assertRaises(OSError): + socket.inet_ntoa(b"\xff\xff\xff\xff\xff") + diff --git a/vm/Cargo.toml b/vm/Cargo.toml index 6ffc8c378..50f5998af 100644 --- a/vm/Cargo.toml +++ b/vm/Cargo.toml @@ -70,3 +70,6 @@ flamer = { version = "0.3", optional = true } [target.'cfg(all(unix, not(any(target_os = "android", target_os = "redox"))))'.dependencies] pwd = "1" + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gethostname = "0.2.0" diff --git a/vm/src/stdlib/mod.rs b/vm/src/stdlib/mod.rs index b41342c22..82593c9aa 100644 --- a/vm/src/stdlib/mod.rs +++ b/vm/src/stdlib/mod.rs @@ -17,6 +17,7 @@ mod platform; mod pystruct; mod random; mod re; +#[cfg(not(target_arch = "wasm32"))] pub mod socket; mod string; #[cfg(feature = "rustpython-compiler")] diff --git a/vm/src/stdlib/os.rs b/vm/src/stdlib/os.rs index 3e6e9d732..bb8bdec66 100644 --- a/vm/src/stdlib/os.rs +++ b/vm/src/stdlib/os.rs @@ -183,7 +183,7 @@ fn convert_io_error(vm: &VirtualMachine, err: io::Error) -> PyObjectRef { } #[cfg(unix)] -fn convert_nix_error(vm: &VirtualMachine, err: nix::Error) -> PyObjectRef { +pub fn convert_nix_error(vm: &VirtualMachine, err: nix::Error) -> PyObjectRef { let nix_error = match err { nix::Error::InvalidPath => { let exc_type = vm.ctx.exceptions.file_not_found_error.clone(); diff --git a/vm/src/stdlib/socket.rs b/vm/src/stdlib/socket.rs index 714c3e30c..22f431a82 100644 --- a/vm/src/stdlib/socket.rs +++ b/vm/src/stdlib/socket.rs @@ -2,7 +2,14 @@ use std::cell::RefCell; use std::io; use std::io::Read; use std::io::Write; -use std::net::{SocketAddr, TcpListener, TcpStream, ToSocketAddrs, UdpSocket}; +use std::net::{Ipv4Addr, SocketAddr, TcpListener, TcpStream, ToSocketAddrs, UdpSocket}; + +#[cfg(unix)] +use nix::unistd::sethostname; + +use gethostname::gethostname; + +use byteorder::{BigEndian, ByteOrder}; use crate::obj::objbytes::PyBytesRef; use crate::obj::objint::PyIntRef; @@ -12,6 +19,8 @@ use crate::pyobject::{PyObjectRef, PyRef, PyResult, PyValue, TryFromObject}; use crate::vm::VirtualMachine; use crate::obj::objtype::PyClassRef; +#[cfg(unix)] +use crate::stdlib::os::convert_nix_error; use num_traits::ToPrimitive; #[derive(Debug, Copy, Clone)] @@ -372,6 +381,34 @@ fn get_addr_tuple(vm: &VirtualMachine, addr: SocketAddr) -> PyResult { Ok(vm.ctx.new_tuple(vec![ip, port])) } +fn socket_gethostname(vm: &VirtualMachine) -> PyResult { + gethostname() + .into_string() + .map(|hostname| vm.new_str(hostname)) + .map_err(|err| vm.new_os_error(err.into_string().unwrap())) +} + +#[cfg(unix)] +fn socket_sethostname(hostname: PyStringRef, vm: &VirtualMachine) -> PyResult<()> { + sethostname(hostname.value.as_str()).map_err(|err| convert_nix_error(vm, err)) +} + +fn socket_inet_aton(ip_string: PyStringRef, vm: &VirtualMachine) -> PyResult { + ip_string + .as_str() + .parse::() + .map(|ip_addr| vm.ctx.new_bytes(ip_addr.octets().to_vec())) + .map_err(|_| vm.new_os_error("illegal IP address string passed to inet_aton".to_string())) +} + +fn socket_inet_ntoa(packed_ip: PyBytesRef, vm: &VirtualMachine) -> PyResult { + if packed_ip.len() != 4 { + return Err(vm.new_os_error("packed IP wrong length for inet_ntoa".to_string())); + } + let ip_num = BigEndian::read_u32(packed_ip.get_value()); + Ok(vm.new_str(Ipv4Addr::from(ip_num).to_string())) +} + pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { let ctx = &vm.ctx; @@ -390,10 +427,31 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { "fileno" => ctx.new_rustfunc(SocketRef::fileno), }); - py_module!(vm, "socket", { + let module = py_module!(vm, "socket", { "AF_INET" => ctx.new_int(AddressFamily::Inet as i32), "SOCK_STREAM" => ctx.new_int(SocketKind::Stream as i32), "SOCK_DGRAM" => ctx.new_int(SocketKind::Dgram as i32), "socket" => socket, - }) + "inet_aton" => ctx.new_rustfunc(socket_inet_aton), + "inet_ntoa" => ctx.new_rustfunc(socket_inet_ntoa), + "gethostname" => ctx.new_rustfunc(socket_gethostname), + }); + + extend_module_platform_specific(vm, module) +} + +#[cfg(not(unix))] +fn extend_module_platform_specific(_vm: &VirtualMachine, module: PyObjectRef) -> PyObjectRef { + module +} + +#[cfg(unix)] +fn extend_module_platform_specific(vm: &VirtualMachine, module: PyObjectRef) -> PyObjectRef { + let ctx = &vm.ctx; + + extend_module!(vm, module, { + "sethostname" => ctx.new_rustfunc(socket_sethostname), + }); + + module }