AgentXcpp  Revision:0.1
Internals Documentation
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends
/home/tanjeff/projekte/agentxcpp/src/master_proxy.hpp
Go to the documentation of this file.
00001 /*
00002  * Copyright 2011-2012 Tanjeff-Nicolai Moos <tanjeff@cccmz.de>
00003  *
00004  * This file is part of the agentXcpp library.
00005  *
00006  * AgentXcpp is free software: you can redistribute it and/or modify
00007  * it under the terms of the AgentXcpp library license, version 1, which 
00008  * consists of the GNU General Public License and some additional 
00009  * permissions.
00010  *
00011  * AgentXcpp is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * See the AgentXcpp library license in the LICENSE file of this package 
00017  * for more details.
00018  */
00019 #ifndef _MASTER_PROXY_H_
00020 #define _MASTER_PROXY_H_
00021 
00022 #include <boost/asio.hpp>
00023 
00024 #include <fstream>
00025 #include <string>
00026 #include <map>
00027 #include <list>
00028 #include <boost/shared_ptr.hpp>
00029 #include "types.hpp"
00030 #include "oid.hpp"
00031 #include "variable.hpp"
00032 #include "ClosePDU.hpp"
00033 #include "ResponsePDU.hpp"
00034 #include "RegisterPDU.hpp"
00035 #include "UnregisterPDU.hpp"
00036 #include "connector.hpp"
00037 
00038 namespace agentxcpp
00039 {
00040     /**
00041      * \brief This class represents the master agent in a subagent program.
00042      *
00043      * \par Introduction
00044      *
00045      * This class is used on the subagent's side of a connection between 
00046      * subagent and master agent. It serves as a proxy which represents the 
00047      * master agent. It is possible for a subagent to hold connections to more 
00048      * than one master agents. For each connection one master_proxy object is 
00049      * created. Multiple connections to the same master agent are possible, 
00050      * too, in which case one master_proxy per connection is needed.
00051      */
00052     /**
00053      * \par Connection State
00054      *
00055      * The master_proxy is always in one of the following states:
00056      * -# connected
00057      * -# disconnected
00058      * .
00059      * The session to the master agent is established when creating a 
00060      * master_proxy object, thus the object usually starts in connected state.  
00061      * If that fails, the object starts in disconnected state. A connected 
00062      * master_proxy object may also loose the connection to the master agent 
00063      * and consequently become disconnected, without informing the user. It is 
00064      * possible to re-connect with the reconnect() function at any time (even 
00065      * if the session is currently established - it will be shut down and 
00066      * re-established in this case).  When the object is destroyed, the session 
00067      * will be cleanly shut down. The connection state can be inspected with 
00068      * the is_connected() function.  Some functions throw a disconnected 
00069      * exception if the session is not currently established.
00070      *
00071      */
00072     /**
00073      * \par The io_service object
00074      *
00075      * The master_proxy class uses the boost::asio library for networking and 
00076      * therefore needs a boost::asio::io_service object. This object can either 
00077      * be provided by the user or created automatically. There are two 
00078      * constructors available therefore. The used object (whether auto-created 
00079      * or not) can be obtained using the get_io_service() function. If the 
00080      * io_service object was autocreated by a constructor, it will be destroyed 
00081      * by the destructor. If the user provided the io_service, it will NOT be 
00082      * destroyed by the destructor. It is possible to create multiple 
00083      * master_proxy objects using the same io_service object, or using 
00084      * different io_service objects.
00085      *
00086      * Receiving data from the master agent is done asynchronously and only 
00087      * works if io_service::run() or io_service::run_one() is invoked.  
00088      * However, some operations (such as registering stuff) invoke 
00089      * io_service::run_one() several times while waiting for a response from 
00090      * the master agent. If the io_service object is not used exclusively by 
00091      * the master_proxy object (which is entirely  possible), this may complete 
00092      * asynchronous events before the library operation (e.g.  registering) is 
00093      * completed. Even the internal asynchronous reception calls 
00094      * io_service::run_one() while waiting for more data. If this behaviour is 
00095      * not desired, a separate io_service object should be used for other 
00096      * asynchronous I/O operations.
00097      *
00098      */
00099     /**
00100      * \par Registrations
00101      *
00102      * Before the master agent sends requests to a subagent, the subagent must 
00103      * register a subtree. Doing so informs the master agent that the subagent 
00104      * wishes to handle requests for these OIDs. A subtree is an OID which 
00105      * denotes the root of a subtree in which some of the offered objects 
00106      * resides. For example, when two objects shall be offered with the OIDs 
00107      * 1.3.6.1.4.1.42<b>.1.1</b> and 1.3.6.1.4.1.42<b>.1.2</b>, then a subtree 
00108      * with OID 1.3.6.1.4.1.42<b>.1</b> should be registered, which includes 
00109      * both objects.  The master agent will then forward all requests 
00110      * conecerning objects in this subtree to this subagent. Requests to 
00111      * non-existing objects (e.g.  1.3.6.1.4.1.42<b>.1.3</b>) are also 
00112      * forwarded, and the agentXcpp library will take care of them and return 
00113      * an appropriate error to the master agent.
00114      * 
00115      * The function register_subtree() is used to register a subtree. It is 
00116      * typically called for the highest-level OID of the MIB which is 
00117      * implemented by the subagent. However, it is entirely possible to 
00118      * register multiple subtrees.
00119      *
00120      * Identical subtrees are subtrees with the exact same root OID. Each 
00121      * registration is done with a priority value.  The higher the value, the 
00122      * lower the priority.  When identical subtrees are registered (by the same 
00123      * subagent or by different subagents), the priority value is used to 
00124      * decide which subagent gets the requests.  The master refuses identical 
00125      * registrations with the same priority values.  Note however, that in case 
00126      * of overlapping subtrees which are \e not identical (e.g.  
00127      * 1.3.6.1.4.1.42<b>.1</b> and 1.3.6.1.4.1.42<b>.1.33.1</b>), the most 
00128      * specific subtree (i.e. the one with the longest OID) wins regardless of 
00129      * the priority values.
00130      *
00131      * It is also possible to unregister subtrees using the 
00132      * unregister_subtree() function. This informs the master agent that the 
00133      * MIB region is no longer available from this subagent.
00134      *
00135      * \internal
00136      *
00137      * The master_proxy object generates a RegisterPDU object each time a 
00138      * registration is performed. These RegisterPDU objects are stored in the 
00139      * registrations member.
00140      *
00141      * When unregistering, the matching RegisterPDU is removed from the 
00142      * registration member.
00143      *
00144      * The registration member becomes invalid on connection loss. Since a 
00145      * connection loss is not signalled, the member cannot be cleared in such 
00146      * situations. Therefore, it is cleared in the connect() method if the 
00147      * object is currently disconnected. If connect() is called on a connected 
00148      * master_proxy object, the registrations member is not cleared.
00149      *
00150      * \endinternal
00151      *
00152      */
00153     /**
00154      * \par Adding and Removing Variables
00155      *
00156      * Registering a subtree does not make any SNMP variables accessible yet.  
00157      * To provide SNMP variables, they must be added to the master_proxy 
00158      * object, e.g. using add_variable(). The master_proxy object will then 
00159      * dispatch incoming requests to the variables it knows about. If a request 
00160      * is received for an OID for which no variable has been added, an 
00161      * appropriate error is returned to the master agent.
00162      *
00163      * Added variables can be removed again using remove_variable(). This makes 
00164      * a variable inaccessible for the master agent.
00165      *
00166      * \internal
00167      *
00168      * The variables are stored in the member variables, which is a 
00169      * std::map<oid, shared_ptr<variable> >. The key is the OID for which the 
00170      * variable was added. This allows easy lookup for the request 
00171      * dispatcher.
00172      *
00173      * When removing a variable, it is removed from the variables member.
00174      *
00175      * The variables member becomes invalid on connection loss. Since a 
00176      * connection loss is not signalled, the member cannot be cleared in such 
00177      * situations.  Therefore, it is cleared in the connect() method if the 
00178      * object is currently disconnected. If connect() is called on a connected 
00179      * master_proxy object, the variables member is not cleared.
00180      *
00181      * \endinternal
00182      *
00183      */
00184     /**
00185      * \internal
00186      *
00187      * \par Internals
00188      * 
00189      * The io_service_by_user variable is used to store whether the io_service 
00190      * object was generated automatically. It is set to true or false by the 
00191      * respective constructors and evaluated by the destructor.
00192      *
00193      * Receiving and processing PDU's coming from the master is done using the 
00194      * connector class. The master_proxy class implements the 
00195      * connectro::pdu_handler interface to recieve PDU's from the connector. A 
00196      * master_proxy object registers itself with the connector object, which 
00197      * then invokes master_proxy::handle_pdu() for incoming PDU's. Registering 
00198      * is done by the constructors, while the destructor unregisters the 
00199      * object.
00200      */
00201     // TODO: describe timeout handling
00202     // TODO: byte ordering is constant for a session. See rfc 2741, 7.1.1
00203     class master_proxy : public connector::pdu_handler
00204     {
00205         private:
00206 
00207             /**
00208              * \brief The mandatory io_service object.
00209              *
00210              * This object is needed for boost::asio operation. Depending on 
00211              * the constructor used, the object is either provided by the user 
00212              * or generated automatically.
00213              */
00214             // TODO: use shared_ptr<>
00215             boost::asio::io_service* io_service;
00216 
00217             /**
00218              * \brief Was the io_service object provided by the user?
00219              */
00220             bool io_service_by_user;
00221             
00222             /**
00223              * \brief The path to the unix domain socket.
00224              */
00225             std::string socket_file;
00226             
00227             /**
00228              * \brief The connector object used for networking.
00229              *
00230              * Created by constructors, destroyed by destructor.
00231              */
00232             connector* connection;
00233 
00234             /**
00235              * \brief The session ID of the current session.
00236              *
00237              * If disconnected, the value is undefined.
00238              */
00239             uint32_t sessionID;
00240 
00241             /**
00242              * \brief A string describing the subagent.
00243              *
00244              * Set upon object creation. It is allowed to be emtpy.
00245              */
00246             std::string description;
00247 
00248             /**
00249              * \brief Default timeout of the session (in seconds).
00250              *
00251              * A value of 0 indicates that there is no session-wide default.
00252              */
00253             byte_t default_timeout;
00254 
00255             /**
00256              * \brief An Object Identifier that identifies the subagent. May be
00257              *        the null OID.
00258              */
00259             oid id;
00260 
00261             /**
00262              * \brief The registrations.
00263              *
00264              * Every time an registration is performed, the RegisterPDUs is 
00265              * stored in this list. This allows to automatically re-register 
00266              * these subtrees on reconnect (e.g.  after a connection loss).
00267              */
00268             std::list< boost::shared_ptr<RegisterPDU> > registrations;
00269 
00270             /**
00271              * \brief Storage for all SNMP variables known to the agentXcpp
00272              *        library.
00273              */
00274             std::map< oid, shared_ptr<variable> > variables;
00275 
00276             /**
00277              * \brief Send a RegisterPDU to the master agent.
00278              *
00279              * This function sends a RegisterPDU to the master agent, waites 
00280              * for the response and evaluates it. This means that run_one() is 
00281              * called one or more times on the io_service object.
00282              *
00283              * \param pdu The RegisterPDU to send.
00284              *
00285              * \exception disconnected If the master_proxy is currently in
00286              *                         state 'disconnected'.
00287              *
00288              * \exception timeout_error If the master agent does not
00289              *                          respond within the timeout interval.
00290              *
00291              * \exception internal_error If the master received a malformed
00292              *                           PDU. This is probably a programming 
00293              *                           error within the agentXcpp library.
00294              *
00295              * \exception master_is_unable The master agent was unable to
00296              *                             perform the desired register 
00297              *                             request.  The reason for that is 
00298              *                             unknown.
00299              *
00300              * \exception duplicate_registration If the exact same subtree was
00301              *                                   alread registered, either by 
00302              *                                   another subagent or by this 
00303              *                                   subagent.
00304              *
00305              * \exception master_is_unwilling If the master was unwilling for
00306              *                                some reason to make the desired 
00307              *                                registration.
00308              *
00309              * \exception parse_error If an unexpected response was received
00310              *                        from the master. This is probably a 
00311              *                        programming error within the master 
00312              *                        agent.  It is possible that the master 
00313              *                        actually performed the desired 
00314              *                        registration and that a retry will result 
00315              *                        in a duplicate_registration error.
00316              */
00317             void do_registration(boost::shared_ptr<RegisterPDU> pdu);
00318 
00319             /**
00320              * \brief Send a UnregisterPDU to the master agent.
00321              *
00322              * This function sends an UnregisterPDU to the master agent which 
00323              * revokes the registration done by a RegisterPDU.  Then it waites 
00324              * for the response and evaluates it.  This means that run_one() is 
00325              * called one or more times on the io_service object.
00326              *
00327              * \param pdu The RegisterPDU whose registration is to be revoked.
00328              *
00329              * \exception disconnected If the master_proxy is currently in
00330              *                         state 'disconnected'.
00331              *
00332              * \exception timeout_error If the master agent does not
00333              *                          respond within the timeout interval.
00334              *
00335              * \exception internal_error If the master received a malformed
00336              *                           PDU. This is probably a programming 
00337              *                           error within the agentXcpp library.
00338              *
00339              * \exception master_is_unable The master agent was unable to
00340              *                             perform the desired register 
00341              *                             request.  The reason for that is 
00342              *                             unknown.
00343              *
00344              * \exception unknown_registration The MIB region is not currently
00345              *                                 registered with this parameters.
00346              *
00347              * \exception parse_error If an unexpected response was received
00348              *                        from the master. This is probably a 
00349              *                        programming error within the master 
00350              *                        agent.  It is possible that the master 
00351              *                        actually performed the desired 
00352              *                        registration and that a retry will result 
00353              *                        in a duplicate_registration error.
00354              */
00355             void undo_registration(boost::shared_ptr<UnregisterPDU> pdu);
00356 
00357            /**
00358             * \brief Create UnregisterPDU for undoing a registration.
00359             *
00360             * This function creates an UnregisterPDU which unregisters the MIB 
00361             * region which is registered by a given RegisterPDU.
00362             *
00363             * \param pdu The RegisterPDU which creates a registration.
00364             *
00365             * \return The created UnregisterPDU.
00366             *
00367             * \exception None.
00368             */
00369             boost::shared_ptr<UnregisterPDU> create_unregister_pdu(
00370                                     boost::shared_ptr<RegisterPDU> pdu);
00371 
00372 
00373         public:
00374             /**
00375              * \internal
00376              *
00377              * \brief The dispatcher for incoming %PDU's.
00378              *
00379              * This method implements pdu_handler::handle_pdu() and is invoked 
00380              * by the connector object when PDU's are received.
00381              */
00382             virtual void handle_pdu(shared_ptr<PDU>, int error);
00383 
00384             /**
00385              * \brief Create a session object connected via unix domain
00386              *        socket
00387              *
00388              * This constructor tries to connect to the master agent. If that 
00389              * fails, the object is created nevertheless and will be in state 
00390              * disconnected.
00391              *
00392              * This constructor takes an io_service object as parameter. The 
00393              * io_service is not destroyed by the constructor.
00394              *
00395              * \param io_service The io_service object.
00396              *
00397              * \param description A string describing the subagent. This
00398              *                    description cannot be changed later.
00399              *
00400              * \param default_timeout The length of time, in seconds, that
00401              *                        the master agent should allow to elapse 
00402              *                        before it regards the subagent as not 
00403              *                        responding.  The value is also used when 
00404              *                        waiting synchronously for data from the 
00405              *                        master agent (e.g. when registering 
00406              *                        stuff).  Allowed values are 0-255, with 0 
00407              *                        meaning "no default for this session".
00408              *
00409              * \param ID An Object Identifier that identifies the subagent.
00410              *           Default is the null OID (no ID).
00411              *
00412              * \param unix_domain_socket The socket file to connect to.
00413              *                           Defaults to /var/agentx/master, as 
00414              *                           desribed in RFC 2741, section 8.2.1 
00415              *                           "Well-known Values".
00416              */
00417             master_proxy(boost::asio::io_service* io_service,
00418                    std::string description="",
00419                    byte_t default_timeout=0,
00420                    oid ID=oid(),
00421                    std::string unix_domain_socket="/var/agentx/master");
00422 
00423             /**
00424              * \brief Create a session object connected via unix domain
00425              *        socket.
00426              *
00427              * This constructor tries to connect to the master agent. If that 
00428              * fails, the object is created nevertheless and will be in state 
00429              * disconnected.
00430              *
00431              * This constructor creates an io_service object which is destroyed 
00432              * by the desctructor.
00433              *
00434              * \param description A string describing the subagent. This
00435              *                    description cannot be changed later.
00436              *
00437              * \param default_timeout The length of time, in seconds, that
00438              *                        the master agent should allow to elapse 
00439              *                        before it regards the subagent as not 
00440              *                        responding.  The value is also used when 
00441              *                        waiting synchronously for data from the 
00442              *                        master agent (e.g. when registering 
00443              *                        stuff).  Allowed values are 0-255, with 0 
00444              *                        meaning "no default for this session".
00445              *
00446              * \param ID An Object Identifier that identifies the subagent.
00447              *           Default is the null OID (no ID).
00448              *
00449              * \param unix_domain_socket The socket file to connect to.
00450              *                           Defaults to /var/agentx/master, as 
00451              *                           desribed in RFC 2741, section 8.2.1 
00452              *                           "Well-known Values".
00453              */
00454             master_proxy(std::string description="",
00455                    byte_t default_timeout=0,
00456                    oid ID=oid(),
00457                    std::string unix_domain_socket="/var/agentx/master");
00458 
00459             /**
00460              * \brief Register a subtree with the master agent
00461              *
00462              * This function registers a subtree (or MIB region).
00463              * 
00464              * \internal
00465              *
00466              * This method adds the registered subtree to registrations on 
00467              * success.
00468              *
00469              * \endinternal
00470              *
00471              * \param subtree The (root of the) subtree to register.
00472              *
00473              * \param priority The priority with which to register the subtree.
00474              *                 Default is 127 according to RFC 2741, 6.2.3.  
00475              *                 "The agentx-Register-PDU".
00476              *
00477              * \param timeout The timeout value for the registered subtree, in
00478              *                seconds. This value overrides the timeout of the 
00479              *                session.  Default value is 0 (no override) 
00480              *                according to RFC 2741, 6.2.3.  "The 
00481              *                agentx-Register-PDU".
00482              *
00483              * \exception disconnected If the master_proxy is currently in
00484              *                         state 'disconnected'.
00485              *
00486              * \exception timeout_exception If the master agent does not
00487              *                              respond within the timeout 
00488              *                              interval.
00489              *
00490              * \exception master_is_unable The master agent was unable to
00491              *                             perform the desired register 
00492              *                             request.  The reason for that is 
00493              *                             unknown.
00494              *
00495              * \exception duplicate_registration If the exact same subtree was
00496              *                                   alread registered, either by 
00497              *                                   another subagent or by this 
00498              *                                   subagent.
00499              *
00500              * \exception master_is_unwilling If the master was unwilling for
00501              *                                some reason to make the desired 
00502              *                                registration.
00503              *
00504              * \exception parse_error A malformed network message was found
00505              *                        during communcation with the master. This 
00506              *                        may be a programming error in the master 
00507              *                        or in the agentXcpp library. It is 
00508              *                        possible that the master actually 
00509              *                        performed the desired registration and 
00510              *                        that a retry will result in a 
00511              *                        duplicate_registration error.
00512              *
00513              * \note This function invokes run_one() one or more times on the
00514              *       io_service object.
00515              */
00516             void register_subtree(oid subtree,
00517                                   byte_t priority=127,
00518                                   byte_t timeout=0);
00519 
00520             /**
00521              * \brief Unregister a subtree with the master agent
00522              *
00523              * This function unregisters a subtree (or MIB region) which has 
00524              * previously been registered.
00525              * 
00526              * \internal
00527              *
00528              * This method removes the registered subtree from
00529              * registrations.
00530              * 
00531              * \endinternal
00532              *
00533              * \param subtree The (root of the) subtree to unregister.
00534              *
00535              * \param priority The priority with which the registration was
00536              *                 done.
00537              *
00538              * \exception disconnected If the master_proxy is currently in
00539              *                         state 'disconnected'.
00540              *
00541              * \exception timeout_error If the master agent does not
00542              *                          respond within the timeout interval.
00543              *
00544              * \exception master_is_unable The master agent was unable to
00545              *                             perform the desired unregister 
00546              *                             request.  The reason for that is 
00547              *                             unknown.
00548              *
00549              * \exception unknown_registration The MIB region is not currently
00550              *                                 registered with this parameters.
00551              *
00552              * \exception parse_error A malformed network message was found
00553              *                        during communcation with the master. This 
00554              *                        may be a programming error in the master 
00555              *                        or in the agentXcpp library. It is 
00556              *                        possible that the master actually 
00557              *                        unregistered the MIB region.
00558              *
00559              * \note This function invokes run_one() one or more times on the
00560              *       io_service object.
00561              */
00562             // TODO: the 'priority' parameter can possibly be omitted: the 
00563             // value can be stored by master_agent upon subtree registration.
00564             void unregister_subtree(oid subtree,
00565                                     byte_t priority=127);
00566 
00567             /**
00568              * \brief Get the io_service object used by this master_proxy.
00569              */
00570             boost::asio::io_service* get_io_service() const
00571             {
00572                 return this->io_service;
00573             }
00574 
00575             /**
00576              * \brief Check whether the session is in state connected
00577              *
00578              * \returns true if the session is connected, false otherwise.
00579              */
00580             bool is_connected()
00581             {
00582                 return this->connection->is_connected();
00583             }
00584 
00585             /**
00586              * \brief Connect to the master agent.
00587              *
00588              * \note Upon creation of a session object, the connection is
00589              *       automatically established. If the current state is 
00590              *       "connected", the function does nothing.
00591              *
00592              * \exception disconnected If connecting fails.
00593              */
00594             void connect();
00595 
00596             /**
00597              * \brief Shutdown the session.
00598              *
00599              * Disconnect from the master agent.
00600              * 
00601              * \note Upon destruction of a session object the session is
00602              *       automatically shutdown. If the session is in state 
00603              *       "disconnected", this function does nothing.
00604              *
00605              * \param reason The shutdown reason is reported to the master
00606              *               agent during shutdown.
00607              *
00608              * \exception None.
00609              */
00610             void disconnect(ClosePDU::reason_t reason=ClosePDU::reasonShutdown);
00611 
00612             /**
00613              * \brief Reconnect to the master agent.
00614              *
00615              * Disconnects from the master (only if currently connected), then 
00616              * connects again.
00617              *
00618              * \exception disconnected If connecting fails.
00619              */
00620             void reconnect()
00621             {
00622                 this->connection->disconnect();
00623                 // throws disconnected, which is forwarded:
00624                 this->connection->connect();
00625             }
00626 
00627             /**
00628              * \brief Get the sessionID of the session
00629              *
00630              * Get the session ID of the last established session, even if the 
00631              * current state is "disconnected".
00632              *
00633              * \return The session ID of the last established session. If
00634              *         object was never connected to the master, 0 is 
00635              *         returned.
00636              */
00637             uint32_t get_sessionID()
00638             {
00639                 return this->sessionID;
00640             }
00641     
00642             /**
00643              * \brief Destructor.
00644              *
00645              * The destructor cleanly shuts down the session with the reason 
00646              * 'Shutdown' (if it is currently established) and destroys the 
00647              * master_proxy object. It also destroys the io_service object if 
00648              * it was created automatically (i.e. not provided by the user).
00649              */
00650             ~master_proxy();
00651 
00652             /**
00653              * \brief Add an SNMP variable for serving.
00654              *
00655              * This adds an SNMP variable which can then be read and/or 
00656              * written.
00657              *
00658              * Variables can only be added to MIB regions which were registered 
00659              * in advance.
00660              *
00661              * If adding a variable with an id for which another variable is 
00662              * already registered, it replaces the odl one.
00663              *
00664              * \param id The OID of the variable.
00665              *
00666              * \param v The variable.
00667              *
00668              * \exception unknown_registration If trying to add a variable
00669              *                                 with an id which does not reside 
00670              *                                 within a registered MIB 
00671              *                                 region.
00672              */
00673             void add_variable(const oid& id, shared_ptr<variable> v);
00674 
00675             /**
00676              * \brief Remove an SNMP variable so that is not longer accessible.
00677              *
00678              * This removes a variable previously added using add_variable().  
00679              * The variable will no longer receive SNMP requests.
00680              *
00681              * If no variable is known for the given id, nothing happens.
00682              *
00683              * \param id The OID of the variable to remove. This is the OID
00684              *           which was given to add_variable().
00685              *
00686              * \exception None.
00687              */
00688             void remove_variable(const oid& id);
00689     };
00690 }
00691 
00692 #endif