Difference between revisions of "TUT:Simple Async Application"
m (A few pedantic grammar touch-ups) |
m |
||
(One intermediate revision by one other user not shown) | |||
Line 1: | Line 1: | ||
− | Here we discuss how to write an asynchronous application. It's only purpose is to retrieve the value of a set of variables from a set of remote hosts. | + | Here we discuss how to write an asynchronous application. It's only purpose is to retrieve the value of a set of variables from a set of remote hosts. (This is for the C library, see [[TUT:Simple_Perl_Async_Application]] for Perl.) |
{{TUT:File-Table-Top-and-basics}} | {{TUT:File-Table-Top-and-basics}} | ||
Line 5: | Line 5: | ||
|} | |} | ||
− | This discussion assumes that you | + | This discussion assumes that you already have read the snmpdemoapp tutorial section. |
The program assumes that you have a set of hosts that you want to interrogate for a set of variables. For simplicity's sake each query just asks for one variable. | The program assumes that you have a set of hosts that you want to interrogate for a set of variables. For simplicity's sake each query just asks for one variable. |
Latest revision as of 14:33, 11 November 2014
Here we discuss how to write an asynchronous application. It's only purpose is to retrieve the value of a set of variables from a set of remote hosts. (This is for the C library, see TUT:Simple_Perl_Async_Application for Perl.)
Here are the files discussed in this example so you can download them:
File | Description |
---|---|
Makefile | A simple makefile used to build the projects |
NET-SNMP-TUTORIAL-MIB.txt | The MIB we'll be writing code for in the various pieces of the agent extension tutorial |
asyncapp.c | The Asynchronous C source code |
This discussion assumes that you already have read the snmpdemoapp tutorial section.
The program assumes that you have a set of hosts that you want to interrogate for a set of variables. For simplicity's sake each query just asks for one variable.
The program defines two structures, struct host which holds the host specific data, hostname and community to be used, and struct oid which holds the object to be queried for.
/* * a list of hosts to query */ struct host { char *name; char *community; } hosts[] = { { "test1", "public" }, { "test2", "public" }, { "test3", "public" }, { "test4", "public" }, { NULL } }; /* * a list of variables to query for */ struct oid { char *Name; oid Oid[MAX_OID_LEN]; int OidLen; } oids[] = { { "system.sysDescr.0" }, { "interfaces.ifNumber.1" }, { "interfaces.ifNumber.0" }, { NULL } };
As a brush up, we then define the function synchronous that scans the hosts using synchronous calls:
void synchronous (void) { struct host *hp; for (hp = hosts; hp->name; hp++) { struct snmp_session ss, *sp; struct oid *op; snmp_sess_init(&ss); /* initialize session */ ss.version = SNMP_VERSION_2c; ss.peername = hp->name; ss.community = hp->community; ss.community_len = strlen(ss.community); snmp_synch_setup(&ss); if (!(sp = snmp_open(&ss))) { snmp_perror("snmp_open"); continue; } for (op = oids; op->Name; op++) { struct snmp_pdu *req, *resp; int status; req = snmp_pdu_create(SNMP_MSG_GET); snmp_add_null_var(req, op->Oid, op->OidLen); status = snmp_synch_response(sp, req, &resp); if (!print_result(status, sp, resp)) break; snmp_free_pdu(resp); } snmp_close(sp); } }
This should contain no surprises, as you already mastered the snmpdemoapp chapter.
Now onto the new material. We define a struct session to hold our per-host state:
struct session { struct snmp_session *sess; /* SNMP session data */ struct oid *current_oid; /* How far in our poll are we */ } sessions[sizeof(hosts)/sizeof(hosts[0])]; int active_hosts; /* hosts that we have not completed */
We then need a callback function, to be called whenever a response is received:
int asynch_response(int operation, struct snmp_session *sp, int reqid, struct snmp_pdu *pdu, void *magic) { struct session *host = (struct session *)magic; struct snmp_pdu *req;
whenever a response is received, we will print it out, and send the next request out:
if (operation == RECEIVED_MESSAGE) { if (print_result(STAT_SUCCESS, host->sess, pdu)) { host->current_oid++; /* send next GET (if any) */ if (host->current_oid->Name) {
there is still more to do ... build the next request
req = snmp_pdu_create(SNMP_MSG_GET); snmp_add_null_var(req, host->current_oid->Oid, host->current_oid->OidLen); if (snmp_send(host->sess, req))
we are still in business
return 1; else {
something went wrong. Print out error message, and fall through to decrement active_hosts
snmp_perror("snmp_send"); snmp_free_pdu(req); } } } } else print_result(STAT_TIMEOUT, host->sess, pdu);
/* something went wrong (or end of variables) * this host not active any more */ active_hosts--; return 1; }
Now the code to fire this up, and keep it running until we are done
void asynchronous(void) { struct session *hs; struct host *hp;
First we loop through all the hosts, opening a session for each and sending out the first request:
/* startup all hosts */ for (hs = sessions, hp = hosts; hp->name; hs++, hp++) { struct snmp_pdu *req; struct snmp_session sess; snmp_sess_init(&sess); /* initialize session */ sess.version = SNMP_VERSION_2c; sess.peername = hp->name; sess.community = hp->community; sess.community_len = strlen(sess.community);
The next two lines is where we deviate from the good old sync setup
sess.callback = asynch_response; /* default callback */ sess.callback_magic = hs; if (!(hs->sess = snmp_open(&sess))) { snmp_perror("snmp_open"); continue; } hs->current_oid = oids; req = snmp_pdu_create(SNMP_MSG_GET); /* send the first GET */ snmp_add_null_var(req, hs->current_oid->Oid, hs->current_oid->OidLen); if (snmp_send(hs->sess, req)) active_hosts++; else { snmp_perror("snmp_send"); snmp_free_pdu(req); } }
That was the startup code. Now we just wait for things to settle down again. All the real work is handled inside the callback function.
/* loop while any active hosts */ while (active_hosts) { int fds = 0, block = 1; fd_set fdset; struct timeval timeout;
snmp_select_info is the function that gets us all we need to be able to call select
FD_ZERO(&fdset); snmp_select_info(&fds, &fdset, &timeout, &block); fds = select(fds, &fdset, NULL, NULL, block ? NULL : &timeout);
snmp_read will read all sockets with pending data, and process them
if (fds) snmp_read(&fdset); else snmp_timeout(); }
Now active_hosts == 0, and all data have been returned. Close all sessions and finish up.
/* cleanup */ for (hp = hosts, hs = sessions; hp->name; hs++, hp++) { if (hs->sess) snmp_close(hs->sess); } }
The main program just demonstrates the two ways to do the job:
int main (int argc, char **argv) { initialize(); printf("---------- synchronous -----------\n"); synchronous(); printf("---------- asynchronous -----------\n"); asynchronous(); return 0; }
Thats it. Lets now see it in action:
% ./asyncapp ---------- synchronous ----------- 23:08:49.429595 test1: Timeout 23:08:49.609789 test2: system.sysDescr.0 = SunOS test2 5.6 Generic_105181-16 sun4u 23:08:49.759717 test2: interfaces.ifNumber.1 = No Such Instance currently exists 23:08:49.899715 test2: interfaces.ifNumber.0 = No Such Object available on this agent 23:08:50.059725 test3: system.sysDescr.0 = Linux test3 2.2.5-22 #1 Wed Jun 2 09:17:03 EDT 1999 i686 23:08:50.199715 test3: interfaces.ifNumber.1 = No Such Object available on this agent 23:08:50.339712 test3: interfaces.ifNumber.0 = No Such Object available on this agent 23:08:56.429595 test4: Timeout ---------- asynchronous ----------- 23:08:50.519702 test2: system.sysDescr.0 = SunOS test2 5.6 Generic_105181-16 sun4u 23:08:50.569680 test3: system.sysDescr.0 = Linux test3 2.2.5-22 #1 Wed Jun 2 09:17:03 EDT 1999 i686 23:08:50.669682 test2: interfaces.ifNumber.1 = No Such Instance currently exists 23:08:50.699669 test3: interfaces.ifNumber.1 = No Such Object available on this agent 23:08:50.809714 test2: interfaces.ifNumber.0 = No Such Object available on this agent 23:08:50.879675 test3: interfaces.ifNumber.0 = No Such Object available on this agent 23:08:56.429590 test1: Timeout 23:08:56.430095 test4: Timeout %
Contents
Tutorial Sections
About the SNMP Protocol
These tutorial links talk about SNMP generically and how the protocol itself works. They are good introductory reading material and the concepts are important to understand before diving into the later tutorials about Net-SNMP itself.
- How SNMP Works: About the protocol itself (GETs, GETNEXTs, etc)
- What data is in SNMP: All about SNMP Management Information Bases (MIBs)
- Securing SNMP: How to use the SNMP protocol securely
Net-SNMP Command Line Applications
These tutorial pages discuss the command line tools provided in the Net-SNMP suite of tools. Nearly all the example commands in these tutorials works if you try it yourself, as they're all examples that talk to our online Net-SNMP test agent. Given them a shot!
- snmptranslate: learning about the MIB tree.
- snmpget: retrieving data from a host.
- snmpgetnext: retrieving unknown indexed data.
- snmpwalk: retrieving lots of data at once!
- snmptable: displaying a table.
- snmpset: peforming write operations.
- snmpbulkget: communicates with a network entity using SNMP GETBULK request
- snmpbulkwalk: retrieve a sub-tree of management values using SNMP GETBULK requests.
- snmptrap: Sending and receiving traps, and acting upon them.
- Traps/informs with SNMPv3/USM: Sending and receiving SNMPv3/USM TRAPs and INFORMs
- Sending Traps/Informs via AgentX: Sending notifications from the command line through snmpd
- Common command line options:
- Writing mib2c config files
Application Configuration
All of our applications support configuration to allow you to customize how they behave.
Net-SNMP Daemons
Net-SNMP comes with two long-running daemons: a SNMP agent (snmpd) for responding to management requests and a notification receiver (snmptrapd) for receiving SNMP notifications.
- SNMP Agent (snmpd) Configuration
- SNMP Notification Receiver (snmptrapd)
- Agent Monitoring
Coding Tutorials
Net-SNMP comes with a highly flexible and extensible API. The API allows you to create your own commands, add extensions to the agent to support your own MIBs and perform specialized processing of notifications.
- Client / Manager Coding Tutorials
- Writing a simple application
- Writing a simple asynchronous application
- Agent Coding Tutorials
- The Agent Architecture page might be worth reading before or after the agent coding tutorials, and describes how the Agent Helpers work under the hood.
- Writing a mib module to serve information described by an SNMP MIB, and how to compile it into the net-snmp snmpd agent.
- Writing a Dynamically Loadable Object that can be loaded into the SNMP agent.
- Writing a Subagent that can be run to attach to the snmpd master agent.
- Writing a perl plugin to extend the agent using the NetSNMP::agent module.
- Writing shell scripts to extend the agent
- Using mib2c to help write an agent code template for you
- Header files and autoconf
Debugging SNMP Applications and Agents
All our tools and applications have extensive debugging output. These tutorials talk about how the debugging system works and how you can add your own debugging statements to you code:
- Debugging output printed using the -D command line option
- Using -Ddump to display packet breakdowns
- Debugging using GDB
Operating System Specific Tutorials
- Building With Visual Studio 2005 Express
- Building Net-SNMP 64-bit with Visual C++ 2010 Express
- Net-Snmp on Ubuntu
- Net-SNMP and lm-sensors on Ubuntu 10.04
- Net-SNMP for windows: