Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

optimize snmp library to search a device ip address in iphone

I'm using Mobile snmp++ library (https://github.com/Zchander/mobile-snmp-plusplus/tree/master/Mobile%20SNMP%2B%2B) in iPhone app to scan devices using swift language.

The Mobile Snmp++ library is written in Objective-C and with Bridging header I'm able to use the this library in my swift project and it works perfectly.

I need to scan devices from particular range of ip address suppose 170.23.45.0 to 170.23.45.255. For this i'm using getoid function from XISMobile_SNMP_PP.mm (https://github.com/Zchander/mobile-snmp-plusplus/blob/master/Mobile%20SNMP%2B%2B/XISMobile_SNMP_PP.mm)

To get response from single ip address, it approximately takes 1-2 seconds per response.So to reduce the time, me using multithreading as suggested in the below link ( with maximum 20 of threads only at time since we are going to use the app in iphone) and it takes 20 seconds for complete scan from 0 to 255. I need to reduce this time to around 5 seconds. optimized way to search a device ip address within a range in iphone

Issue : Every time when search begins, getoid funtion opens socket and sends data and then gets response and closes socket. So can't we keep the socket open, scan all ip address and get it's respone and close the socket at last ? I need to reduce the search time from 20 seconds to 5 seconds so how can we do it in getoid function.

- (NSDictionary *)getOid:(NSString *)oid
                 address:(NSString *)hostAddress
             snmpVersion:(uint)version
              remotePort:(NSNumber *)aPort
           withCommunity:(NSString *)community
                   retry:(uint)retries
                 timeout:(uint)timeout
                   error:(NSError * __autoreleasing*)error
{
    int status;

    uint l_retries;
    uint l_timeout;
    NSNumber *localPort;

    snmp_version snmpVersion = version1;
    OctetStr snmpCommunity([community UTF8String]);

    if ( aPort == nil ) {
        localPort = [NSNumber numberWithInteger:161];
    } else localPort = aPort;

    if ( retries > 100 ) {
        l_retries = 100;
    } else l_retries = retries;

    if ( timeout < 100 ) {
        l_timeout = 100;
    } else if ( timeout > 500 ) {
        l_timeout = 500;
    } else l_timeout = timeout;

    switch ( version ) {
        case 1:
            snmpVersion = version1;
            break;
        case 2:
            snmpVersion = version2c;
            break;
        default:
            snmpVersion = version1;
            break;
    }

    // Generate a SNMP++ generic address
    UdpAddress udpAddress([hostAddress UTF8String]);

    // Check if it is a valid address, if we got an invalid address
    // we return a 'nil' dictionary and an error code
    if ( !udpAddress.valid() ) {
        *error = [self constructError:ERR_INVALID_DESTINATION];
#ifdef DEBUG
        NSLog(@"ERROR SNMPController (getOid:hostAddress:oid:snmpVersion:remotePort:withCommunity:retry:timeout:error:)");
        NSLog(@"ERROR SNMP++ Invalid host address or IP: %@", hostAddress);
        NSLog(@"ERROR ====================");
#endif
        return nil;
    }

    // Check if we got a valid Oid, otherwise use sysDescr
    Oid localOid([oid UTF8String]);
    if ( !localOid.valid() ) {
#ifdef DEBUG
        NSLog(@"ERROR SNMPController (getOid:hostAddress:oid:snmpVersion:remotePort:withCommunity:retry:timeout:error:)");
        NSLog(@"ERROR SNMP++ We got an invalid Oid (%@), we are using sysDescr for now (.1.3.6.1.2.1.1.1.0)", oid);
        NSLog(@"ERROR ====================");
#endif
        Oid localOid("1.3.6.1.2.1.1.1.0");
    }

    // Create the SNMP session
    Snmp snmp(status, 0, (udpAddress.get_ip_version() == Address::version_ipv6));

    if ( status != SNMP_CLASS_SUCCESS ) {
#ifdef DEBUG
        NSLog(@"ERROR SNMPController (getOid:hostAddress:oid:snmpVersion:remotePort:withCommunity:retry:timeout:error:)");
        NSLog(@"ERROR SNMP++ Could not create session: %s", snmp.error_msg(status));
        NSLog(@"ERROR ====================");
#endif
        *error = [self constructError:ERR_NO_SNMP_SESSION];
        return nil;
    }

    // We are ready to build the SNMP++ object we need
    Pdu pdu;                                    // construct a Pdu object
    Vb vb;                                      // construct a Vb object
    vb.set_oid(localOid);                       // set the Oid portion of the Vb
    pdu += vb;                                  // add the vb to the Pdu

    // Set the port
    udpAddress.set_port([localPort integerValue]);
    CTarget ctarget(udpAddress);                // Make a target using the address

    ctarget.set_version(snmpVersion);           // Set the SNMP version
    ctarget.set_retry(l_retries);               // Set the number of retries
    ctarget.set_timeout(l_timeout);             // Set the timeout for the request
    ctarget.set_readcommunity(snmpCommunity);   // Set the read community name

    // Issue the request, in blocked mode
#ifdef DEBUG
    NSLog(@"DEBUG SNMPController (getOid:hostAddress:oid:snmpVersion:remotePort:withCommunity:retry:timeout:error:)");
    NSLog(@"DEBUG SNMP++ GET to %@ (oid: %@) with version %d on Port: %d using community %@ with retries %d and timeout %d", hostAddress, oid, version, [aPort integerValue], community, retries, timeout);
    NSLog(@"DEBUG SNMP++ What is the community we are sending.... %s", snmpCommunity.get_printable());
    NSLog(@"DEBUG ====================");
#endif

    SnmpTarget *target;
    target = &ctarget;

    status = snmp.get(pdu, *target);

    NSMutableDictionary *resultsDict = [[NSMutableDictionary alloc] init];

    if ( status == SNMP_CLASS_SUCCESS ) {
        pdu.get_vb(vb, 0);

#ifdef DEBUG
        NSLog(@"DEBUG SNMPController (getOid:hostAddress:oid:snmpVersion:remotePort:withCommunity:retry:timeout:error:)");
        NSLog(@"DEBUG SNMP++ -- Oid: %s", vb.get_printable_oid());
        NSLog(@"DEBUG SNMP++ -- Value: %s", vb.get_printable_value());
#endif

        // Add the result(s) to the resultsDict
        [resultsDict setObject:[NSString stringWithUTF8String:vb.get_printable_value()] forKey:[NSString stringWithUTF8String:vb.get_printable_oid()]];

        if ( (vb.get_syntax() == sNMP_SYNTAX_ENDOFMIBVIEW) ||
             (vb.get_syntax() == sNMP_SYNTAX_NOSUCHINSTANCE) ||
             (vb.get_syntax() == sNMP_SYNTAX_NOSUCHOBJECT)) {

            NSLog(@"ERROR SNMP++ Exception found: %lu", vb.get_syntax());

        } else {

            NSLog(@"ERROR SNMP++ GET Error: %s (%d)", snmp.error_msg(status), status);

        }
#ifdef DEBUG
        NSLog(@"DEBUG ====================");
#endif
    }

    // Make sure error is nil!

    *error = nil;

    return ( resultsDict != nil ) ? [NSDictionary dictionaryWithDictionary:resultsDict] : nil;

}
like image 207
sia Avatar asked Dec 10 '15 00:12

sia


2 Answers

The underlying C++ library you're using supports the use of callbacks when a response is recieved. If you update the Objective-C wrapper to use this approach instead of the thread-blocking getOid function, you're going to see much better performance, and you'll only have to use 1 or 2 threads.

I'd look at

int Snmp::get(Pdu &pdu, const SnmpTarget &target, const snmp_callback callback, const void * callback_data)

in uxsnmp.cpp. You may even be able to wrap it to use Obj-C blocks. That's where you're going to get your performance from.

Firing off large numbers of SNMP-over-UDP queries like this is very doable as long as you use the asyncronous library hooks, I've gotten great results using EventMachine from Ruby to do DNS queries in the same way - I got ~1500 queries done in 3-5 seconds!!

like image 65
Fiid Avatar answered Oct 05 '22 23:10

Fiid


try Concurrency Programming in iOS to increase the numbers of concurrency work.

like image 37
Allen Avatar answered Oct 06 '22 00:10

Allen