Skip to content

Commit 3f6451d

Browse files
authored
Merge pull request #3 from jgallag88/ipv4AddrBackport
[Backport to 6.0] Print IPv4 address correctly on little-endian systems
2 parents 09b81ed + 9e22813 commit 3f6451d

File tree

1 file changed

+46
-14
lines changed

1 file changed

+46
-14
lines changed

src/ptools.rs

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,12 @@ struct ParseError {
133133
}
134134

135135
impl ParseError {
136-
fn new(file: &str, reason: &str) -> Self {
136+
fn new(item: &str, reason: &str) -> Self {
137+
ParseError {
138+
reason: format!("Error parsing {}: {}", item, reason),
139+
}
140+
}
141+
fn in_file(file: &str, reason: &str) -> Self {
137142
ParseError {
138143
reason: format!("Error parsing /proc/[pid]/{}: {}", file, reason),
139144
}
@@ -182,7 +187,7 @@ impl ProcStat {
182187
let s: String = s?;
183188
let substrs = s.splitn(2, ":").collect::<Vec<&str>>();
184189
if substrs.len() < 2 {
185-
Err(ParseError::new(
190+
Err(ParseError::in_file(
186191
"status",
187192
&format!(
188193
"Fewer fields than expected in line '{}' of file {}",
@@ -208,7 +213,7 @@ impl ProcStat {
208213
fn get_field(&self, field: &str) -> Result<&str, Box<Error>> {
209214
match self.fields.get(field) {
210215
Some(val) => Ok(val),
211-
None => Err(From::from(ParseError::new(
216+
None => Err(From::from(ParseError::in_file(
212217
"status",
213218
&format!(
214219
"Missing expected field '{}' file {}",
@@ -646,17 +651,27 @@ fn parse_sock_type(type_code: &str) -> SockType {
646651
}
647652
}
648653

649-
// Parse a socket address of the form "0100007F:1538" (i.e. 127.0.0.1:1538)
650-
fn parse_ipv4_sock_addr(s: &str) -> Result<SocketAddr, Box<Error>> {
651-
let port = u16::from_str_radix(s.split(':').collect::<Vec<&str>>()[1], 16).unwrap();
652-
let addr = u32::from_str_radix(s.split(':').collect::<Vec<&str>>()[0], 16).unwrap();
653-
// TODO do we need to change 'addr' to network order?
654-
let addr = Ipv4Addr::new(
655-
((addr >> 24) & 0xFF) as u8,
656-
((addr >> 16) & 0xFF) as u8,
657-
((addr >> 8) & 0xFF) as u8,
658-
(addr & 0xFF) as u8,
659-
);
654+
// Parse a socket address of the form "0100007F:1538" (i.e. 127.0.0.1:5432)
655+
fn parse_ipv4_sock_addr(s: &str) -> Result<SocketAddr, ParseError> {
656+
let mk_err = || {
657+
ParseError::new(
658+
"IPv4 address",
659+
&format!("expected address in form '0100007F:1538', got {}", s),
660+
)
661+
};
662+
663+
let fields = s.split(':').collect::<Vec<_>>();
664+
if fields.len() != 2 {
665+
return Err(mk_err());
666+
}
667+
668+
// Port is always printed with most-significant byte first.
669+
let port = u16::from_str_radix(fields[1], 16).map_err(|_| mk_err())?;
670+
671+
// Address is printed with most-significant byte first on big-endian systems and vice-versa on
672+
// little-endian systems.
673+
let addr_native_endian = u32::from_str_radix(fields[0], 16).map_err(|_| mk_err())?;
674+
let addr = Ipv4Addr::from(addr_native_endian.to_be());
660675

661676
Ok(SocketAddr::new(IpAddr::V4(addr), port))
662677
}
@@ -916,3 +931,20 @@ pub fn ptree_main() {
916931
}
917932
}
918933
}
934+
935+
mod test {
936+
use super::*;
937+
use std::net::SocketAddr;
938+
939+
#[test]
940+
fn test_parse_ipv4_sock_addr() {
941+
assert_eq!(
942+
parse_ipv4_sock_addr("0100007F:1538").unwrap(),
943+
"127.0.0.1:5432".parse::<SocketAddr>().unwrap()
944+
);
945+
946+
assert!(parse_ipv4_sock_addr("0100007F 1538").is_err());
947+
assert!(parse_ipv4_sock_addr("010000YY:1538").is_err());
948+
assert!(parse_ipv4_sock_addr("0100007F:15YY").is_err());
949+
}
950+
}

0 commit comments

Comments
 (0)