Snmp recoverable error handling

Hi,
I stuck at rust learning. I try to make simple snmp get code, but I don't know how to do recoverable error handling.I don't know how to work with SnmpMessageType. Please help with example.

Andrej

There's a guide for recoverable error handling in the book: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html

I've already tried but I get alarm > wrong type, need to be SnmpMessageType. From there I am lost because I don't know how to define SnmpMessageType.

Anyway, thanks for your moral support. It was easier did the same in Python.

If you want more help, you have to provide the actual error messages and a piece of code.

1 Like

My code is actually copy of example on github snmp - Rust (docs.rs):
use std::time::Duration;
use snmp::{SyncSession, Value};

fn main() {
let _sys_descr_oid = &[1,3,6,1,2,1,1,5,0];
let community = b"public";
let timeout = Duration::from_secs(2);
//ip of local PC
let ip = "127.0.0.1".to_string();
let port: &str = ":161";

let c = String::from(ip + port);  
let oid : [u32; 9] = _sys_descr_oid.clone();
	
let mut snmp_get = String::new();

let mut sess = SyncSession::new(c, community, Some(timeout), 0).unwrap();

//response do error if ip is wrong or connection is lost	
let mut response = sess.get(&oid).expect("no connection");		

if let Some((_oid, Value::OctetString(sys_descr))) = response.varbinds.next(){

	let vredno_get = String::from_utf8_lossy(sys_descr);
	snmp_get.push_str(&vredno_get);		
	println!("{:?}", snmp_get);

}	

}

I tried with ?:
let mut response = sess.get(&oid).expect("no connection")?; //ERROR DOESN'T WORK FOR SnmpMessageType
I tried with "match" but don't know how to handle type
struct:
pub struct SnmpPdu<'a> {
pub message_type: SnmpMessageType,
pub req_id: i32,
pub error_status: u32,
pub error_index: u32,
pub varbinds: Varbinds<'a>,
// some fields omitted
}

Please read Forum Code Formatting and Syntax Highlighting and edit your prior post by using the pencil-shaped edit button under that post. Note that you can specify the language syntax to be used in highlighting by specifying the language at the end of the first row of three backticks. (Rust is the default language if you don't specify toml or c++ or something else.)

Many readers of this forum will ignore code snippets, compiler error reports, etc that do not follow the posting guidelines for new contributors that are pinned to the top of this forum. Even those who do respond may feel that the lack of following the forum posting guidelines is disrespectful of their time. Thanks. :clap:

excuse my ignorance, I am new member on any forum. I will correct if there is still any issue.

Code:

use std::time::Duration;
use snmp::{SyncSession, Value};

fn main() {	
	let _sys_descr_oid = &[1,3,6,1,2,1,1,5,0];
	let community       = b"public";
	let timeout         = Duration::from_secs(2);
  	//ip of local PC       	
	let ip = "127.0.0.1".to_string();
	let port: &str = ":161";

	let c = String::from(ip + port);  
	let oid : [u32; 9] = _sys_descr_oid.clone();
		
	let mut snmp_get = String::new();
	
	let mut sess = SyncSession::new(c, community, Some(timeout), 0).unwrap();
	
	//response do error if ip is wrong or connection is lost	
	let mut response = sess.get(&oid).expect("no connection");		

	if let Some((_oid, Value::OctetString(sys_descr))) = response.varbinds.next(){

		let vredno_get = String::from_utf8_lossy(sys_descr);
		snmp_get.push_str(&vredno_get);		
		println!("{:?}", snmp_get);

	}	
}

cargo file:

[package]
name = "get_try_catch"
version = "0.1.0"
authors = ["Uporabnik"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
snmp = { git = "https://github.com/hroi/rust-snmp" }

If you want to use the ? operator then the function needs a return type that works with what ? operator does.
I added a return type to main, that is a Result of either nothing ( the () in the Result, because you previously didn't return anything from main) or an ErrorType that is the same as the ErrorTypes appearing in the function or is convertible from it.

use snmp::{SyncSession, Value};
use std::time::Duration;

fn main() -> std::result::Result<(), snmp::SnmpError> {
    let _sys_descr_oid = &[1, 3, 6, 1, 2, 1, 1, 5, 0];
    let community = b"public";
    let timeout = Duration::from_secs(2);
    //ip of local PC
    let ip = "127.0.0.1".to_string();
    let port: &str = ":161";

    let c = String::from(ip + port);
    let oid: [u32; 9] = _sys_descr_oid.clone();

    let mut snmp_get = String::new();

    let mut sess = SyncSession::new(c, community, Some(timeout), 0).unwrap();

    //response do error if ip is wrong or connection is lost
// after adding an appropriate return type we can now use ? 
    let mut _response = sess.get(&oid)?;
// I am not up to date what the exact implementation of the ? operator is but in my mind 
// it does something similar to this
    let mut response = match sess.get(&oid) {
        Ok(inner) => inner,
        Err(err) => return Err(err),
    };

    if let Some((_oid, Value::OctetString(sys_descr))) = response.varbinds.next() {
        let vredno_get = String::from_utf8_lossy(sys_descr);
        snmp_get.push_str(&vredno_get);
        println!("{:?}", snmp_get);
    }
    Ok(())
}

I wanted to recommend https://crates.io/crates/anyhow as a nice way of handling errors but I got an error that the trait std::error::Error isn't implemented for SnmpError. So the automatic conversions that anyhow::Result<SomeType> would give you aren't possible, I think.
But you should look at anyhow or something similar anyway.
This way you can return anyhow::Result<YourType> from functions and the errors (as long as they implement the error trait) can be handled more ergonomically.

1 Like

Looking at the snmp documentation, sess.get(&oid) returns a Result<SnmpPdu, SnmpError>. Calling expect() on that causes it to panic if an error value is returned.

If you want to use ? to pass the error up to the caller of the function, that should be instead of calling expect(). You would also need to change the type of main() to Result<(), SnmpError>. However, using ? in main has much the same effect as using expect(), but without the ability to set an error message. [EDIT: and this won't work anyway, because SnmpError doesn't implement Error for some reason]

You seem to be asking instead about recoverable error handling, which is different from the above two approaches. For that, you will want to match on the Result:

let mut response = match sess.get(&oid) {
    Ok(response) => response,
    Err(error) => {
        // error handling goes here
    }
};

The struct SnmpPdu doesn't need special handling since it is the type of the response value that you already have. The error variable has type SnmpError, which is an enumeration you can further match on to determine the cause of the error. You can also do something else in the error handling branch, such as retrying the get() call. Note that the error handling branch has to either end with returning an instance of SnmpPdu for the rest of the code to use, or do something that means it won't return (for example, by calling panic!()), though.

1 Like

I need to get over again.

thank you

here soon

I will try as you've suggested.

Thanks, Andrej

Hi,
I am not proud on my progress. I stacked on the second match sentence. Please,can you help. I tried with another match sentence and also with new function. Compiler tells the type is wrong:

use snmp::{SyncSession, Value};
use std::time::Duration;

fn main() -> std::result::Result<(), snmp::SnmpError> {
    let _sys_descr_oid = &[1, 3, 6, 1, 2, 1, 1, 5, 0];
    let community = b"public";
    let timeout = Duration::from_secs(2);

    let ip = "127.0.0.1".to_string();
    let port: &str = ":161";

    let c = String::from(ip + port);
    let oid: [u32; 9] = _sys_descr_oid.clone();

    let mut snmp_get = String::new();

    //I need todo match also with this one in case of wrong community 
    let mut sess = SyncSession::new(c, community, Some(timeout), 0).unwrap();

    /*
    //try n#1
    let mut sess = match SyncSession::new(c, community, Some(timeout), 0){
        Ok(krneki) => krneki,
        Err(err) => Err(err), 
    };
    Ok(());
    //Ok(krneki) => krneki, >>> error: this is found to be of type 'snmp::SyncSession' 
    //Err(err) => Err(err), >>> expected struct `snmp::SyncSession`, found enum `std::result::Result`
    //found type `std::result::Result<_, std::io::Error>`
    */

    /*
    //try n#2
    fn seja() -> std::result::Result<(), snmp::SnmpError> {
        let _community = b"public";
        let _timeout = Duration::from_secs(2);
        let _ip = "127.0.0.1".to_string();
        let _port: &str = ":161";
        let _c = String::from(_ip + _port);
        let mut sess = match SyncSession::new(_c, _community, Some(_timeout), 0){
            Ok(krneki) => krneki,
            Err(err) => Err(err), 
        };
        Ok(sess)
    }    
    //note: expected type `snmp::SyncSession`
    //      found type `std::result::Result<_, std::io::Error>`
    let mut sess = seja();
    */


    let mut response = match sess.get(&oid) {
        Ok(inner) => inner,
        Err(err) => return Err(err),
    };

    if let Some((_oid, Value::OctetString(sys_descr))) = response.varbinds.next() {
        let vredno_get = String::from_utf8_lossy(sys_descr);
        snmp_get.push_str(&vredno_get);
        println!("{:?}", snmp_get);
    }
    Ok(());
}

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.