From f9aadb90f2d82aa1942127ce7f1822404319a859 Mon Sep 17 00:00:00 2001 From: Callum Beardsmore Date: Wed, 4 Dec 2024 12:04:13 +0000 Subject: [PATCH 1/5] Added addtional check for if bsd or not --- examples/adstool.rs | 17 ++++++--- src/test/test_udp.rs | 2 +- src/udp.rs | 83 +++++++++++++++++++++++++++++++------------- 3 files changed, 72 insertions(+), 30 deletions(-) diff --git a/examples/adstool.rs b/examples/adstool.rs index ce0521b..3701294 100644 --- a/examples/adstool.rs +++ b/examples/adstool.rs @@ -427,10 +427,19 @@ fn main_inner(args: Args) -> Result<(), Error> { "TwinCAT version: {}.{}.{}", info.twincat_version.0, info.twincat_version.1, info.twincat_version.2 ); - println!( - "OS version: {} {}.{}.{} {}", - info.os_version.0, info.os_version.1, info.os_version.2, info.os_version.3, info.os_version.4 - ); + match info.os_version.1 { + Some(ver) => { + println!( + "OS version: {} {:?} {}", + info.os_version.0, ver, info.os_version.2); + }, + None => { + println!( + "OS version: {} {}", + info.os_version.0, info.os_version.2); + }, + } + if !info.fingerprint.is_empty() { println!("Fingerprint: {}", info.fingerprint); } diff --git a/src/test/test_udp.rs b/src/test/test_udp.rs index 2bd37f7..f2e24af 100644 --- a/src/test/test_udp.rs +++ b/src/test/test_udp.rs @@ -45,7 +45,7 @@ fn test_udp() { assert_eq!(info.hostname, "box"); assert_eq!(info.netid, tgt_netid); assert_eq!(info.twincat_version, (4, 1, 7)); - assert_eq!(info.os_version, ("Windows NT", 5, 8, 9, "Test".into())); + assert_eq!(info.os_version, ("Windows NT", Some((5, 8, 9).into()), "Test".into())); udp::add_route(("127.0.0.1", port), tgt_netid, "a", Some("route"), None, None, false).unwrap(); assert!(udp::add_route(("127.0.0.1", port), tgt_netid, "a", None, None, None, false).is_err()); diff --git a/src/udp.rs b/src/udp.rs index d676c34..9305fd0 100644 --- a/src/udp.rs +++ b/src/udp.rs @@ -11,6 +11,7 @@ use zerocopy::{FromBytes, Immutable, IntoBytes}; use crate::errors::ErrContext; use crate::{AmsAddr, AmsNetId, Error, Result}; +use std::fmt::Debug; /// Magic number for the first four bytes of each UDP packet. pub const BECKHOFF_UDP_MAGIC: u32 = 0x_71_14_66_03; @@ -232,6 +233,31 @@ pub fn get_netid(target: (&str, u16)) -> Result { Ok(reply.get_source().netid()) } +#[derive(PartialEq)] +/// Type to display major.minor.build +pub struct Semver { + major : u32, + minor : u32, + // Also known as patch + build : u32 +} + +impl Debug for Semver { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}.{}.{}", self.major, self.minor, self.build) + } +} + +impl From<(u32, u32, u32)> for Semver{ + fn from((major, minor, build): (u32, u32, u32)) -> Self { + Self { + major, + minor, + build + } + } +} + /// Information about the system running TwinCAT. pub struct SysInfo { /// AMS NetID of the system. @@ -241,7 +267,7 @@ pub struct SysInfo { /// The TwinCAT (major, minor, build) version. pub twincat_version: (u8, u8, u16), /// The OS (name, major, minor, build, service_pack) version. - pub os_version: (&'static str, u32, u32, u32, String), + pub os_version: (&'static str, Option, String), /// The system's fingerprint. pub fingerprint: String, } @@ -260,37 +286,44 @@ pub fn get_info(target: (&str, u16)) -> Result { (0, 0, 0) }; - // Parse OS version. This is a Windows OSVERSIONINFO structure, which + // Parse OS version. If Windows OSVERSIONINFO structure, it will // consists of major/minor/build versions, the platform, and a "service - // pack" string, coded as UTF-16. It is not known how the data looks on - // non-Windows devices, but hopefully the format is kept the same. + // pack" string, coded as UTF-16. + // If TwinCAT/BSD currently no information is given other than TwinCAT/BSD let os_version = if let Some(mut bytes) = reply.get_bytes(Tag::OSVersion) { if bytes.len() >= 22 { - // Size of the structure (redundant). - let _ = bytes.read_u32::().expect("size"); - let major = bytes.read_u32::().expect("size"); - let minor = bytes.read_u32::().expect("size"); - let build = bytes.read_u32::().expect("size"); - let platform = match bytes.read_u32::().expect("size") { - 1 => "TC/RTOS", - 2 => "Windows NT", - 3 => "Windows CE", - _ => "Unknown platform", - }; - let string = if platform == "TC/RTOS" { - bytes.iter().take_while(|&&b| b != 0).map(|&b| b as char).collect() + //check if the os version is TwinCAT/BDS all the rest is not included for TC BSD. Simply just TwinCAT/BSD. + let version_info = String::from_utf8_lossy(bytes); + let is_bsd = version_info.contains("TwinCAT/BSD"); + if is_bsd { + ("TwinCAT/BSD", None, "".into()) } else { - iter::from_fn(|| bytes.read_u16::().ok()) - .take_while(|&ch| ch != 0) - .filter_map(|ch| char::from_u32(ch as u32)) - .collect() - }; - (platform, major, minor, build, string) + // Size of the structure (redundant). + let _ = bytes.read_u32::().expect("size"); + let major = bytes.read_u32::().expect("size"); + let minor = bytes.read_u32::().expect("size"); + let build = bytes.read_u32::().expect("size"); + let platform = match bytes.read_u32::().expect("size") { + 1 => "TC/RTOS", + 2 => "Windows NT", + 3 => "Windows CE", + _ => "Unknown platform", + }; + let string = if platform == "TC/RTOS" { + bytes.iter().take_while(|&&b| b != 0).map(|&b| b as char).collect() + } else { + iter::from_fn(|| bytes.read_u16::().ok()) + .take_while(|&ch| ch != 0) + .filter_map(|ch| char::from_u32(ch as u32)) + .collect() + }; + (platform, Some((major, minor, build).into()), string) + } } else { - ("Unknown OS info format", 0, 0, 0, "".into()) + ("Unknown OS info format", None, "".into()) } } else { - ("No OS info", 0, 0, 0, "".into()) + ("No OS info", None, "".into()) }; Ok(SysInfo { netid: reply.get_source().netid(), From 83d13baf715552492c25064d96d8be4a9d9a58a1 Mon Sep 17 00:00:00 2001 From: Callum Beardsmore Date: Wed, 4 Dec 2024 13:28:42 +0000 Subject: [PATCH 2/5] Realised the sem ver from twincat for bsd is actually correct, so removed the SemVer stuff to keep the upstream as simple as possible --- examples/adstool.rs | 15 ++------ src/test/test_udp.rs | 2 +- src/udp.rs | 84 +++++++++++++++----------------------------- 3 files changed, 33 insertions(+), 68 deletions(-) diff --git a/examples/adstool.rs b/examples/adstool.rs index 3701294..a545521 100644 --- a/examples/adstool.rs +++ b/examples/adstool.rs @@ -427,18 +427,9 @@ fn main_inner(args: Args) -> Result<(), Error> { "TwinCAT version: {}.{}.{}", info.twincat_version.0, info.twincat_version.1, info.twincat_version.2 ); - match info.os_version.1 { - Some(ver) => { - println!( - "OS version: {} {:?} {}", - info.os_version.0, ver, info.os_version.2); - }, - None => { - println!( - "OS version: {} {}", - info.os_version.0, info.os_version.2); - }, - } + println!("OS version: {} {}.{}.{} {}", + info.os_version.0, info.os_version.1, info.os_version.2, + info.os_version.3, info.os_version.4); if !info.fingerprint.is_empty() { println!("Fingerprint: {}", info.fingerprint); diff --git a/src/test/test_udp.rs b/src/test/test_udp.rs index f2e24af..2bd37f7 100644 --- a/src/test/test_udp.rs +++ b/src/test/test_udp.rs @@ -45,7 +45,7 @@ fn test_udp() { assert_eq!(info.hostname, "box"); assert_eq!(info.netid, tgt_netid); assert_eq!(info.twincat_version, (4, 1, 7)); - assert_eq!(info.os_version, ("Windows NT", Some((5, 8, 9).into()), "Test".into())); + assert_eq!(info.os_version, ("Windows NT", 5, 8, 9, "Test".into())); udp::add_route(("127.0.0.1", port), tgt_netid, "a", Some("route"), None, None, false).unwrap(); assert!(udp::add_route(("127.0.0.1", port), tgt_netid, "a", None, None, None, false).is_err()); diff --git a/src/udp.rs b/src/udp.rs index 9305fd0..ce24b8f 100644 --- a/src/udp.rs +++ b/src/udp.rs @@ -233,31 +233,6 @@ pub fn get_netid(target: (&str, u16)) -> Result { Ok(reply.get_source().netid()) } -#[derive(PartialEq)] -/// Type to display major.minor.build -pub struct Semver { - major : u32, - minor : u32, - // Also known as patch - build : u32 -} - -impl Debug for Semver { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}.{}.{}", self.major, self.minor, self.build) - } -} - -impl From<(u32, u32, u32)> for Semver{ - fn from((major, minor, build): (u32, u32, u32)) -> Self { - Self { - major, - minor, - build - } - } -} - /// Information about the system running TwinCAT. pub struct SysInfo { /// AMS NetID of the system. @@ -267,7 +242,7 @@ pub struct SysInfo { /// The TwinCAT (major, minor, build) version. pub twincat_version: (u8, u8, u16), /// The OS (name, major, minor, build, service_pack) version. - pub os_version: (&'static str, Option, String), + pub os_version: (&'static str, u32, u32, u32, String), /// The system's fingerprint. pub fingerprint: String, } @@ -289,41 +264,40 @@ pub fn get_info(target: (&str, u16)) -> Result { // Parse OS version. If Windows OSVERSIONINFO structure, it will // consists of major/minor/build versions, the platform, and a "service // pack" string, coded as UTF-16. - // If TwinCAT/BSD currently no information is given other than TwinCAT/BSD + // If TwinCAT/BSD currently it will give major minor and build that is displayed let os_version = if let Some(mut bytes) = reply.get_bytes(Tag::OSVersion) { if bytes.len() >= 22 { - //check if the os version is TwinCAT/BDS all the rest is not included for TC BSD. Simply just TwinCAT/BSD. - let version_info = String::from_utf8_lossy(bytes); - let is_bsd = version_info.contains("TwinCAT/BSD"); - if is_bsd { - ("TwinCAT/BSD", None, "".into()) - } else { - // Size of the structure (redundant). - let _ = bytes.read_u32::().expect("size"); - let major = bytes.read_u32::().expect("size"); - let minor = bytes.read_u32::().expect("size"); - let build = bytes.read_u32::().expect("size"); - let platform = match bytes.read_u32::().expect("size") { - 1 => "TC/RTOS", - 2 => "Windows NT", - 3 => "Windows CE", - _ => "Unknown platform", - }; - let string = if platform == "TC/RTOS" { - bytes.iter().take_while(|&&b| b != 0).map(|&b| b as char).collect() - } else { - iter::from_fn(|| bytes.read_u16::().ok()) - .take_while(|&ch| ch != 0) - .filter_map(|ch| char::from_u32(ch as u32)) - .collect() - }; - (platform, Some((major, minor, build).into()), string) + // Size of the structure (redundant). + let _ = bytes.read_u32::().expect("size"); + let major = bytes.read_u32::().expect("size"); + let minor = bytes.read_u32::().expect("size"); + let build = bytes.read_u32::().expect("size"); + let platform = match bytes.read_u32::().expect("size") { + 0 => "TwinCAT/BSD", + 1 => "TC/RTOS", + 2 => "Windows NT", + 3 => "Windows CE", + _ => "Unknown platform", + }; + let string = if platform == "TC/RTOS" { + bytes.iter().take_while(|&&b| b != 0).map(|&b| b as char).collect() } + else if platform == "TwinCAT/BSD" { + //the data after is always garbage + "".into() + } else { + iter::from_fn(|| bytes.read_u16::().ok()) + .take_while(|&ch| ch != 0) + .filter_map(|ch| char::from_u32(ch as u32)) + .collect() + }; + (platform, major, minor, build, string) + } else { - ("Unknown OS info format", None, "".into()) + ("Unknown OS info format", 0, 0, 0 , "".into()) } } else { - ("No OS info", None, "".into()) + ("No OS info", 0, 0, 0, "".into()) }; Ok(SysInfo { netid: reply.get_source().netid(), From f0cbd992f18c49a4276403ea681a1fb3f87cb97a Mon Sep 17 00:00:00 2001 From: Callum Beardsmore Date: Wed, 4 Dec 2024 13:29:53 +0000 Subject: [PATCH 3/5] Removed not needed code changes --- examples/adstool.rs | 8 ++++---- src/udp.rs | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/examples/adstool.rs b/examples/adstool.rs index a545521..ce0521b 100644 --- a/examples/adstool.rs +++ b/examples/adstool.rs @@ -427,10 +427,10 @@ fn main_inner(args: Args) -> Result<(), Error> { "TwinCAT version: {}.{}.{}", info.twincat_version.0, info.twincat_version.1, info.twincat_version.2 ); - println!("OS version: {} {}.{}.{} {}", - info.os_version.0, info.os_version.1, info.os_version.2, - info.os_version.3, info.os_version.4); - + println!( + "OS version: {} {}.{}.{} {}", + info.os_version.0, info.os_version.1, info.os_version.2, info.os_version.3, info.os_version.4 + ); if !info.fingerprint.is_empty() { println!("Fingerprint: {}", info.fingerprint); } diff --git a/src/udp.rs b/src/udp.rs index ce24b8f..9b71013 100644 --- a/src/udp.rs +++ b/src/udp.rs @@ -11,7 +11,6 @@ use zerocopy::{FromBytes, Immutable, IntoBytes}; use crate::errors::ErrContext; use crate::{AmsAddr, AmsNetId, Error, Result}; -use std::fmt::Debug; /// Magic number for the first four bytes of each UDP packet. pub const BECKHOFF_UDP_MAGIC: u32 = 0x_71_14_66_03; From 09974c8e1347985d0cbe52f734cc6fd2f69a828c Mon Sep 17 00:00:00 2001 From: Callum Beardsmore Date: Wed, 4 Dec 2024 13:30:46 +0000 Subject: [PATCH 4/5] Removed white space --- src/udp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/udp.rs b/src/udp.rs index 9b71013..bc40f4d 100644 --- a/src/udp.rs +++ b/src/udp.rs @@ -293,7 +293,7 @@ pub fn get_info(target: (&str, u16)) -> Result { (platform, major, minor, build, string) } else { - ("Unknown OS info format", 0, 0, 0 , "".into()) + ("Unknown OS info format", 0, 0, 0, "".into()) } } else { ("No OS info", 0, 0, 0, "".into()) From b254cf87a87aca8a448496a418d6c702b0ba2e77 Mon Sep 17 00:00:00 2001 From: Callum Beardsmore Date: Wed, 4 Dec 2024 13:33:40 +0000 Subject: [PATCH 5/5] clearer comment --- src/udp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/udp.rs b/src/udp.rs index bc40f4d..797b5e7 100644 --- a/src/udp.rs +++ b/src/udp.rs @@ -282,7 +282,7 @@ pub fn get_info(target: (&str, u16)) -> Result { bytes.iter().take_while(|&&b| b != 0).map(|&b| b as char).collect() } else if platform == "TwinCAT/BSD" { - //the data after is always garbage + // The following data is TwinCAT/BSD in bytes. But we know the platform from 0. "".into() } else { iter::from_fn(|| bytes.read_u16::().ok())