-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsocket.rs
More file actions
76 lines (63 loc) · 2.21 KB
/
socket.rs
File metadata and controls
76 lines (63 loc) · 2.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
use core::fmt;
use std::{
error,
ffi::{CStr, CString},
io, mem, ptr,
};
#[derive(Debug)]
pub enum Error {
Getaddrinfo(String),
Socket(io::Error),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::Getaddrinfo(err) => write!(f, "getaddrinfo error: {}", err),
Error::Socket(err) => write!(f, "socket error: {}", err),
}
}
}
impl error::Error for Error {}
// EXAMPLE: Showcases how `socket()` can be used.
// Section 5.2 - `socket()` - Get the File Descriptor!
// MANPAGE: man 3 socket
pub fn socket() -> Result<(), Error> {
// Preparing the getaddrinfo call.
let node = CString::new("www.example.com").unwrap();
let node_ptr = node.as_ptr();
let service = CString::new("http").unwrap();
let service_ptr = service.as_ptr();
// SAFETY: hints is initialized as empty, but the required fields are set later on.
let mut hints: libc::addrinfo = unsafe { mem::zeroed() };
hints.ai_family = libc::AF_INET;
hints.ai_socktype = libc::SOCK_STREAM;
let mut res_ptr = ptr::null_mut();
// SAFETY: all the required vars are initialized for getaddrinfo().
// gai_stderror() is used for error cases only.
unsafe {
let s = libc::getaddrinfo(node_ptr, service_ptr, &hints, &mut res_ptr);
if s != 0 {
let err = CStr::from_ptr(libc::gai_strerror(s)).to_string_lossy();
Err(Error::Getaddrinfo(err.into_owned()))
} else {
Ok(())
}
}?;
// SAFETY: `res_ptr` is initialized upon a successful getaddrinfo() call.
// Therefore we can guarantee that there is atleast one addrinfo that `res_ptr` points to, making deref safe.
let sock_fd = unsafe {
let res = *res_ptr;
let sock_fd = libc::socket(res.ai_family, res.ai_socktype, 0);
if sock_fd == -1 {
let err = io::Error::last_os_error();
return Err(Error::Socket(err));
}
sock_fd
};
println!("created sock fd: {}", sock_fd);
// SAFETY: `res_ptr` will not be used after this call, therefore it is safe to free it.
unsafe {
libc::freeaddrinfo(res_ptr);
}
Ok(())
}