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