AgentXcpp  Revision:4ac4848
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 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 "ClosePDU.hpp"
00032 #include "ResponsePDU.hpp"
00033 #include "RegisterPDU.hpp"
00034 #include "UnregisterPDU.hpp"
00035 #include "connector.hpp"
00036 
00037 namespace agentxcpp
00038 {
00039     /**
00040      * \brief This class represents the master agent in a subagent program.
00041      *
00042      * \par Introduction
00043      *
00044      * This class is used on the subagent's side of a connection between 
00045      * subagent and master agent. It serves as a proxy which represents the 
00046      * master agent. It is possible for a subagent to hold connections to more 
00047      * than one master agents. For each connection one master_proxy object is 
00048      * created. Multiple connections to the same master agent are possible, 
00049      * too, in which case one master_proxy per connection is needed.
00050      */
00051     /**
00052      * \par Connection State
00053      *
00054      * The master_proxy is always in one of the following states:
00055      *
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      * This class uses the boost::asio library for networking and therefore 
00076      * needs a boost::asio::io_service object. This object can either be 
00077      * 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 (requests or responses to requests) 
00087      * is done asynchronously and only works if io_service::run() or 
00088      * io_service::run_one() is invoked. However, some operations (such as 
00089      * registering stuff) invoke io_service::run_one() several times while 
00090      * waiting for a response from the master agent. If the io_service object 
00091      * is not used exclusively by the master_proxy object (which is entirely  
00092      * possible), this may complete asynchronous events before the library 
00093      * operation (e.g.  registering) is completed. Even the internal 
00094      * asynchronous reception calls io_service::run_one() while waiting for 
00095      * more data. If this behaviour is not desired, a separate io_service 
00096      * object should be used for other 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. The function 
00114      * register_subtree() is used to register a subtree. It is typically called 
00115      * for the highest-level OID of the MIB which is implemented by the 
00116      * subagent. However, it is entirely possible to register multiple 
00117      * subtrees.
00118      *
00119      * Identical subtrees are subtrees with the exact same root OID. Each 
00120      * registration is done with a priority value.  The higher the value, the 
00121      * lower the priority.  When identical subtrees are registered (by the same 
00122      * subagent or by different subagents), the priority value is used to 
00123      * decide which subagent gets the requests.  The master refuses identical 
00124      * registrations with the same priority values.  Note however, that in case 
00125      * of overlapping subtrees which are \e not identical (e.g.  
00126      * 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 
00127      * specific subtree (i.e. the one with the longest OID) wins regardless of 
00128      * the priority values.
00129      *
00130      * It is also possible to unregister subtrees using the 
00131      * unregister_subtree() function. This informs the master agent that the 
00132      * MIB region is no longer available from this subagent.
00133      *
00134      * \internal
00135      *
00136      * The master_proxy object generates a RegisterPDU object each time a 
00137      * registration is performed. These RegisterPDU objects are stored in the 
00138      * registrations member.
00139      *
00140      * When unregistering, the matching RegisterPDU is removed from the 
00141      * registration member.
00142      *
00143      * The registration member becomes invalid on connection loss. Since a 
00144      * connection loss is not signalled, the member cannot be cleared in such 
00145      * situations. Therefore, it is cleared in the connect() method if the 
00146      * object is currently disconnected. If connect() is called on a connected 
00147      * master_proxy object, the registrations member is not cleared.
00148      *
00149      * \endinternal
00150      *
00151      */
00152     /**
00153      * \internal
00154      *
00155      * \par Internals
00156      * 
00157      * The io_service_by_user variable is used to store whether the io_service 
00158      * object was generated automatically. It is set to true or false by the 
00159      * respective constructors and evaluated by the destructor.
00160      *
00161      * Receiving and processing PDU's coming from the master is done using the 
00162      * connector class. The master_proxy class implements the 
00163      * connectro::pdu_handler interface to recieve PDU's from the connector. A 
00164      * master_proxy object registers itself with the connector object, which 
00165      * then invokes master_proxy::handle_pdu() for incoming PDU's. Registering 
00166      * is done by the constructors, while the destructor unregisters the 
00167      * object.
00168      */
00169     // TODO: describe timeout handling
00170     // TODO: byte ordering is constant for a session. See rfc 2741, 7.1.1
00171     class master_proxy : public connector::pdu_handler
00172     {
00173         private:
00174 
00175             /**
00176              * \brief The mandatory io_service object.
00177              *
00178              * This object is needed for boost::asio operation. Depending on 
00179              * the constructor used, the object is either provided by the user 
00180              * or generated automatically.
00181              */
00182             // TODO: use shared_ptr<>
00183             boost::asio::io_service* io_service;
00184 
00185             /**
00186              * \brief Was the io_service object provided by the user?
00187              */
00188             bool io_service_by_user;
00189             
00190             /**
00191              * \brief The path to the unix domain socket.
00192              */
00193             std::string socket_file;
00194             
00195             /**
00196              * \brief The connector object used for networking.
00197              *
00198              * Created by constructors, destroyed by destructor.
00199              */
00200             connector* connection;
00201 
00202             /**
00203              * \brief The session ID of the current session.
00204              *
00205              * If disconnected, the value is undefined.
00206              */
00207             uint32_t sessionID;
00208 
00209             /**
00210              * \brief A string describing the subagent.
00211              *
00212              * Set upon object creation. It is allowed to be emtpy.
00213              */
00214             std::string description;
00215 
00216             /**
00217              * \brief Default timeout of the session (in seconds).
00218              *
00219              * A value of 0 indicates that there is no session-wide default.
00220              */
00221             byte_t default_timeout;
00222 
00223             /**
00224              * \brief An Object Identifier that identifies the subagent. May be
00225              *        the null OID.
00226              */
00227             oid id;
00228 
00229             /**
00230              * \brief The registrations.
00231              *
00232              * Every time an registration is performed, the RegisterPDUs is 
00233              * stored in this list. This allows to automatically re-register 
00234              * these subtrees on reconnect (e.g.  after a connection loss).
00235              */
00236             std::list< boost::shared_ptr<RegisterPDU> > registrations;
00237 
00238             /**
00239              * \brief Send a RegisterPDU to the master agent.
00240              *
00241              * This function sends a RegisterPDU to the master agent, waites 
00242              * for the response and evaluates it. This means that run_one() is 
00243              * called one or more times on the io_service object.
00244              *
00245              * \param pdu The RegisterPDU to send.
00246              *
00247              * \exception disconnected If the master_proxy is currently in
00248              *                         state 'disconnected'.
00249              *
00250              * \exception timeout_error If the master agent does not
00251              *                          respond within the timeout interval.
00252              *
00253              * \exception internal_error If the master received a malformed
00254              *                           PDU. This is probably a programming 
00255              *                           error within the agentXcpp library.
00256              *
00257              * \exception master_is_unable The master agent was unable to
00258              *                             perform the desired register 
00259              *                             request.  The reason for that is 
00260              *                             unknown.
00261              *
00262              * \exception duplicate_registration If the exact same subtree was
00263              *                                   alread registered, either by 
00264              *                                   another subagent or by this 
00265              *                                   subagent.
00266              *
00267              * \exception master_is_unwilling If the master was unwilling for
00268              *                                some reason to make the desired 
00269              *                                registration.
00270              *
00271              * \exception parse_error If an unexpected response was received
00272              *                        from the master. This is probably a 
00273              *                        programming error within the master 
00274              *                        agent.  It is possible that the master 
00275              *                        actually performed the desired 
00276              *                        registration and that a retry will result 
00277              *                        in a duplicate_registration error.
00278              */
00279             void do_registration(boost::shared_ptr<RegisterPDU> pdu);
00280 
00281             /**
00282              * \brief Send a UnregisterPDU to the master agent.
00283              *
00284              * This function sends an UnregisterPDU to the master agent which 
00285              * revokes the registration done by a RegisterPDU.  Then it waites 
00286              * for the response and evaluates it.  This means that run_one() is 
00287              * called one or more times on the io_service object.
00288              *
00289              * \param pdu The RegisterPDU whose registration is to be revoked.
00290              *
00291              * \exception disconnected If the master_proxy is currently in
00292              *                         state 'disconnected'.
00293              *
00294              * \exception timeout_error If the master agent does not
00295              *                          respond within the timeout interval.
00296              *
00297              * \exception internal_error If the master received a malformed
00298              *                           PDU. This is probably a programming 
00299              *                           error within the agentXcpp library.
00300              *
00301              * \exception master_is_unable The master agent was unable to
00302              *                             perform the desired register 
00303              *                             request.  The reason for that is 
00304              *                             unknown.
00305              *
00306              * \exception unknown_registration The MIB region is not currently
00307              *                                 registered with this parameters.
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 undo_registration(boost::shared_ptr<UnregisterPDU> pdu);
00318 
00319            /**
00320             * \brief Create UnregisterPDU for undoing a registration.
00321             *
00322             * This function creates an UnregisterPDU which unregisters the MIB 
00323             * region which is registered by a given RegisterPDU.
00324             *
00325             * \param pdu The RegisterPDU which creates a registration.
00326             *
00327             * \return The created UnregisterPDU.
00328             *
00329             * \exception None.
00330             */
00331             boost::shared_ptr<UnregisterPDU> create_unregister_pdu(
00332                                     boost::shared_ptr<RegisterPDU> pdu);
00333 
00334 
00335         public:
00336             /**
00337              * \brief The dispatcher for incoming %PDU's.
00338              *
00339              * This method implements pdu_handler::handle_pdu() and is invoked 
00340              * by the connector object when PDU's are received.
00341              */
00342             virtual void handle_pdu(shared_ptr<PDU>);
00343 
00344             /**
00345              * \brief Create a session object connected via unix domain
00346              *        socket
00347              *
00348              * This constructor tries to connect to the master agent. If that 
00349              * fails, the object is created nevertheless and will be in state 
00350              * disconnected.
00351              *
00352              * This constructor takes an io_service object as parameter. This 
00353              * io_service is not destroyed by the consntructor.
00354              *
00355              * \param io_service The io_service object.
00356              *
00357              * \param description A string describing the subagent. This
00358              *                    description cannot be changed later.
00359              *
00360              * \param default_timeout The length of time, in seconds, that
00361              *                        the master agent should allow to elapse 
00362              *                        after receiving a message before it 
00363              *                        regards the subagent as not responding.  
00364              *                        The value is also used when waiting 
00365              *                        synchronously for data from the master 
00366              *                        agent (e.g. when registering stuff).  
00367              *                        Allowed values are 0-255, with 0 meaning 
00368              *                        "no default for this session".
00369              *
00370              * \param ID An Object Identifier that identifies the subagent.
00371              *           Default is the null OID (no ID).
00372              *
00373              * \param unix_domain_socket The socket file to connect to.
00374              *                           Defaults to /var/agentx/master, as 
00375              *                           desribed in RFC 2741, section 8.2.1 
00376              *                           "Well-known Values".
00377              */
00378             master_proxy(boost::asio::io_service* io_service,
00379                    std::string description="",
00380                    byte_t default_timeout=0,
00381                    oid ID=oid(),
00382                    std::string unix_domain_socket="/var/agentx/master");
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 creates an io_service object which is destroyed 
00393              * by the desctructor.
00394              *
00395              * \param description A string describing the subagent. This
00396              *                    description cannot be changed later.
00397              *
00398              * \param default_timeout The length of time, in seconds, that
00399              *                        the master agent should allow to elapse 
00400              *                        after receiving a message before it 
00401              *                        regards the subagent as not responding.  
00402              *                        The value is also used when waiting 
00403              *                        synchronously for data from the master 
00404              *                        agent (e.g. when registering stuff).  
00405              *                        Allowed values are 0-255, with 0 meaning 
00406              *                        "no default for this session".
00407              *
00408              * \param ID An Object Identifier that identifies the subagent.
00409              *           Default is the null OID (no ID).
00410              *
00411              * \param unix_domain_socket The socket file to connect to.
00412              *                           Defaults to /var/agentx/master, as 
00413              *                           desribed in RFC 2741, section 8.2.1 
00414              *                           "Well-known Values".
00415              */
00416             master_proxy(std::string description="",
00417                    byte_t default_timeout=0,
00418                    oid ID=oid(),
00419                    std::string unix_domain_socket="/var/agentx/master");
00420 
00421             /**
00422              * \brief Register a subtree with the master agent
00423              *
00424              * This function registers a subtree (or MIB region). This function 
00425              * invokes run_one() one or more times on the io_service object.
00426              *
00427              * \internal
00428              *
00429              * This method adds the registered subtree to registrations on 
00430              * success.
00431              *
00432              * \endinternal
00433              *
00434              * \param subtree The (root of the) subtree to register.
00435              *
00436              * \param priority The priority with which to register the subtree.
00437              *                 Default is 127 according to RFC 2741, 6.2.3.  
00438              *                 "The agentx-Register-PDU".
00439              *
00440              * \param timeout The timeout value for the registered subtree, in
00441              *                seconds. This value overrides the timeout of the 
00442              *                session.  Default value is 0 (no override) 
00443              *                according to RFC 2741, 6.2.3.  "The 
00444              *                agentx-Register-PDU".
00445              *
00446              * \exception disconnected If the master_proxy is currently in
00447              *                         state 'disconnected'.
00448              *
00449              * \exception timeout_exception If the master agent does not
00450              *                              respond within the timeout 
00451              *                              interval.
00452              *
00453              * \exception master_is_unable The master agent was unable to
00454              *                             perform the desired register 
00455              *                             request.  The reason for that is 
00456              *                             unknown.
00457              *
00458              * \exception duplicate_registration If the exact same subtree was
00459              *                                   alread registered, either by 
00460              *                                   another subagent or by this 
00461              *                                   subagent.
00462              *
00463              * \exception master_is_unwilling If the master was unwilling for
00464              *                                some reason to make the desired 
00465              *                                registration.
00466              *
00467              * \exception parse_error A malformed network message was found
00468              *                        during communcation with the master. This 
00469              *                        may be a programming error in the master 
00470              *                        or in the agentXcpp library. It is 
00471              *                        possible that the master actually 
00472              *                        performed the desired registration and 
00473              *                        that a retry will result in a 
00474              *                        duplicate_registration error.
00475              */
00476             void register_subtree(oid subtree,
00477                                   byte_t priority=127,
00478                                   byte_t timeout=0);
00479 
00480             /**
00481              * \brief Unregister a subtree with the master agent
00482              *
00483              * This function unregisters a subtree (or MIB region) which has 
00484              * previously been registered. This function invokes run_one() one 
00485              * or more times on the io_service object.
00486              *
00487              * \internal
00488              *
00489              * This method removes the registered subtree from
00490              * registrations.
00491              * 
00492              * \endinternal
00493              *
00494              * \param subtree The (root of the) subtree to unregister.
00495              *
00496              * \param priority The priority with which the registration was
00497              *                 done. the subtree.  Because register_subtree() 
00498              *                 uses 127 as default, this value is also the 
00499              *                 default for this function.
00500              *
00501              * \exception disconnected If the master_proxy is currently in
00502              *                         state 'disconnected'.
00503              *
00504              * \exception timeout_error If the master agent does not
00505              *                          respond within the timeout interval.
00506              *
00507              * \exception master_is_unable The master agent was unable to
00508              *                             perform the desired unregister 
00509              *                             request.  The reason for that is 
00510              *                             unknown.
00511              *
00512              * \exception unknown_registration The MIB region is not currently
00513              *                                 registered with this parameters.
00514              *
00515              * \exception parse_error A malformed network message was found
00516              *                        during communcation with the master. This 
00517              *                        may be a programming error in the master 
00518              *                        or in the agentXcpp library. It is 
00519              *                        possible that the master actually 
00520              *                        unregistered the MIB region.
00521              */
00522             void unregister_subtree(oid subtree,
00523                                     byte_t priority=127);
00524 
00525             /**
00526              * \brief Get the io_service object used by this master_proxy.
00527              */
00528             boost::asio::io_service* get_io_service() const
00529             {
00530                 return this->io_service;
00531             }
00532 
00533             /**
00534              * \brief Check whether the session is in state connected
00535              *
00536              * \returns true if the session is connected, false otherwise.
00537              */
00538             bool is_connected()
00539             {
00540                 return this->connection->is_connected();
00541             }
00542 
00543             /**
00544              * \brief Connect to the master agent.
00545              *
00546              * \note Upon creation of a session object, the connection is
00547              *       automatically established. If the current state is 
00548              *       "connected", the function does nothing.
00549              *
00550              * \exception disconnected If connecting fails.
00551              */
00552             void connect();
00553 
00554             /**
00555              * \brief Shutdown the session.
00556              *
00557              * Disconnect from the master agent.
00558              * 
00559              * \note Upon destruction of a session object the session is
00560              *       automatically shutdown. If the session is in state 
00561              *       "disconnected", the function does nothing.
00562              *
00563              * \param reason The shutdown reason is reported to the master
00564              *               agent during shutdown.
00565              *
00566              * \exception None.
00567              */
00568             void disconnect(ClosePDU::reason_t reason=ClosePDU::reasonShutdown);
00569 
00570             /**
00571              * \brief Reconnect to the master agent.
00572              *
00573              * Disconnects from the master (only if currently connected), then 
00574              * connects again.
00575              *
00576              * \exception disconnected If connecting fails.
00577              */
00578             void reconnect()
00579             {
00580                 this->connection->disconnect();
00581                 // throws disconnected, which is forwarded:
00582                 this->connection->connect();
00583             }
00584 
00585             /**
00586              * \brief Get the sessionID of the session
00587              *
00588              * Get the session ID of the last established session, even if the 
00589              * current state is "disconnected".
00590              *
00591              * \return The session ID of the last established session. If
00592              *         object was never connected to the master, 0 is 
00593              *         returned.
00594              */
00595             uint32_t get_sessionID()
00596             {
00597                 return this->sessionID;
00598             }
00599     
00600             /**
00601              * \brief Default destructor
00602              *
00603              * The default destructor cleanly shuts down the session with the 
00604              * reason 'Shutdown' (if it is currently established) and destroys 
00605              * the session object. It also destroys the io_service object if it 
00606              * was created automatically (i.e. not provided by the user).
00607              */
00608             ~master_proxy();
00609     };
00610 }
00611 
00612 #endif