MainWindow.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. /*_############################################################################
  2. _##
  3. _## MainWindow.cpp
  4. _##
  5. _## SNMP++v3.2.23
  6. _## -----------------------------------------------
  7. _## Copyright (c) 2001-2007 Jochen Katz, Frank Fock
  8. _##
  9. _## This software is based on SNMP++2.6 from Hewlett Packard:
  10. _##
  11. _## Copyright (c) 1996
  12. _## Hewlett-Packard Company
  13. _##
  14. _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
  15. _## Permission to use, copy, modify, distribute and/or sell this software
  16. _## and/or its documentation is hereby granted without fee. User agrees
  17. _## to display the above copyright notice and this license notice in all
  18. _## copies of the software and any documentation of the software. User
  19. _## agrees to assume all liability for the use of the software;
  20. _## Hewlett-Packard and Jochen Katz make no representations about the
  21. _## suitability of this software for any purpose. It is provided
  22. _## "AS-IS" without warranty of any kind, either express or implied. User
  23. _## hereby grants a royalty-free license to any and all derivatives based
  24. _## upon this software code base.
  25. _##
  26. _## Stuttgart, Germany, Sun Nov 11 15:10:59 CET 2007
  27. _##
  28. _##########################################################################*/
  29. #ifndef _MSC_VER
  30. #include <unistd.h>
  31. #endif
  32. #include <iostream>
  33. #include <qstring.h>
  34. #include <qlineedit.h>
  35. #include <qmessagebox.h>
  36. #include <qtimer.h>
  37. #include <qtextedit.h>
  38. #include <qpushbutton.h>
  39. #include <qcombobox.h>
  40. #include <qspinbox.h>
  41. #include <qradiobutton.h>
  42. #include <MainWindow.h>
  43. #include <Properties.h>
  44. #include "snmp_pp/snmp_pp.h"
  45. #include "snmp_pp/notifyqueue.h"
  46. #include "snmp_pp/log.h"
  47. using std::cout;
  48. using std::cerr;
  49. using std::endl;
  50. #define FILE_USERS "usm_users.bin"
  51. #define FILE_LOCALIZED_USERS "usm_localized_users.bin"
  52. /// C Callback function for snmp++
  53. void callback(int reason, Snmp *snmp, Pdu &pdu, SnmpTarget &target, void *cd)
  54. {
  55. if (cd)
  56. {
  57. // just call the real callback member function...
  58. ((MainWindow*)cd)->async_callback(reason, snmp, pdu, target);
  59. }
  60. }
  61. void MainWindow::async_callback(int reason, Snmp * /*snmp*/, Pdu &pdu,
  62. SnmpTarget &target)
  63. {
  64. Vb nextVb;
  65. int pdu_error;
  66. QString prefix_text;
  67. QString notify_text;
  68. push_button_get_next->setEnabled(true);
  69. // What is the reason for this callback?
  70. if (reason == SNMP_CLASS_NOTIFICATION)
  71. {
  72. prefix_text = "Trap: ";
  73. // get the notify id for traps
  74. Oid id;
  75. pdu.get_notify_id(id);
  76. notify_text = QString(" ID: %1 Type %2 -- ").arg(id.get_printable())
  77. .arg(pdu.get_type());
  78. }
  79. else if (reason == SNMP_CLASS_ASYNC_RESPONSE)
  80. {
  81. prefix_text = "Response ";
  82. }
  83. else if (reason == SNMP_CLASS_TIMEOUT)
  84. {
  85. prefix_text = "Timeout ";
  86. }
  87. else
  88. {
  89. QString err = QString("\nDid not receive async response/trap: (%1) %2\n")
  90. .arg(reason).arg(Snmp::error_msg(reason));
  91. text_edit_output->append(err);
  92. }
  93. // Look at the error status of the Pdu
  94. pdu_error = pdu.get_error_status();
  95. if (pdu_error)
  96. {
  97. QString err = "\nResponse contains error:\n";
  98. err += Snmp::error_msg(pdu_error);
  99. text_edit_output->append(err);
  100. return;
  101. }
  102. // The Pdu must contain at least one Vb
  103. if (pdu.get_vb_count() == 0)
  104. {
  105. QString err = "\nPdu is empty\n";
  106. text_edit_output->append(err);
  107. return;
  108. }
  109. for (int i=0; i<pdu.get_vb_count(); i++)
  110. {
  111. // Get the Vb of the Pdu
  112. pdu.get_vb(nextVb, i);
  113. // Get Oid and value from the Vb and display it
  114. line_edit_obj_id->setText(nextVb.get_printable_oid());
  115. line_edit_value->setText(nextVb.get_printable_value());
  116. text_edit_output->append(prefix_text +
  117. target.get_address().get_printable() +
  118. " -- " +
  119. notify_text +
  120. line_edit_obj_id->text() + " = " +
  121. line_edit_value->text() + "\n");
  122. }
  123. // If we received a inform pdu, we have to send a response
  124. if (pdu.get_type() == sNMP_PDU_INFORM)
  125. {
  126. text_edit_output->append("Sending response to inform.\n");
  127. // just change the value of the first vb
  128. pdu.get_vb(nextVb, 0);
  129. nextVb.set_value("This is the response.");
  130. pdu.set_vb(nextVb, 0);
  131. snmp->response(pdu, target);
  132. }
  133. }
  134. MainWindow::MainWindow(QWidget* parent, const char* name, WFlags fl)
  135. : MainWindowPrivate(parent, name, fl)
  136. {
  137. int status;
  138. #ifndef _NO_LOGGING
  139. DefaultLog::log()->set_filter(ERROR_LOG, 5);
  140. DefaultLog::log()->set_filter(WARNING_LOG, 5);
  141. DefaultLog::log()->set_filter(EVENT_LOG, 5);
  142. DefaultLog::log()->set_filter(INFO_LOG, 5);
  143. DefaultLog::log()->set_filter(DEBUG_LOG, 8);
  144. // Write debug info to a file
  145. DefaultLog::init(new AgentLogImpl("QtExample.log"));
  146. #endif
  147. Snmp::socket_startup(); // Initialize socket subsystem
  148. connect(&timer, SIGNAL(timeout()), this, SLOT(timer_expired()));
  149. // get the Boot counter (you may use any own method for this)
  150. char *engineId = "not_needed";
  151. char *filename = "snmpv3_boot_counter";
  152. unsigned int snmpEngineBoots = 0;
  153. status = getBootCounter(filename, engineId, snmpEngineBoots);
  154. if ((status != SNMPv3_OK) && (status < SNMPv3_FILEOPEN_ERROR))
  155. {
  156. QString err = QString("Error loading snmpEngineBoots counter: %1\n")
  157. .arg(status);
  158. text_edit_output->append(err);
  159. }
  160. // increase the boot counter
  161. snmpEngineBoots++;
  162. // save the boot counter
  163. status = saveBootCounter(filename, engineId, snmpEngineBoots);
  164. if (status != SNMPv3_OK)
  165. {
  166. QString err = QString("Error saving snmpEngineBoots counter: %1\n")
  167. .arg(status);
  168. text_edit_output->append(err);
  169. }
  170. // Create our SNMP session object
  171. snmp = new Snmp(status);
  172. if (status != SNMP_CLASS_SUCCESS)
  173. {
  174. QString err = "\nCould not create SNMP++ session:\n";
  175. err += Snmp::error_msg(status);
  176. text_edit_output->append(err);
  177. }
  178. // If _SNMPv3 is enabled we MUST create ONE v3MP object!
  179. v3mp = new v3MP(engineId, snmpEngineBoots, status);
  180. if (status != SNMPv3_MP_OK)
  181. {
  182. QString err = "\nCould not create v3MP object:\n";
  183. err += Snmp::error_msg(status);
  184. text_edit_output->append(err);
  185. }
  186. // The v3MP creates a USM object, get the pointer to it
  187. USM *usm = v3mp->get_usm();
  188. // Load the USM users from a file
  189. if (SNMPv3_USM_OK != usm->load_users(FILE_USERS))
  190. {
  191. QString err = "\nCould not load users from file.\n";
  192. text_edit_output->append(err);
  193. }
  194. #if 0 // Localized users will be created automatically!
  195. if (SNMPv3_USM_OK != usm->load_localized_users(FILE_LOCALIZED_USERS))
  196. {
  197. QString err = "\nCould not load localized users from file.\n";
  198. text_edit_output->append(err);
  199. }
  200. #endif
  201. update_combobox_sec_name();
  202. }
  203. void MainWindow::update_combobox_sec_name()
  204. {
  205. USM *usm = v3mp->get_usm();
  206. combo_box_sec_name->clear();
  207. // get all security names
  208. usm->lock_user_name_table(); // lock table for peek_XXX()
  209. const struct UsmUserNameTableEntry *user = usm->peek_first_user();
  210. QStringList names;
  211. QString initial("initial");
  212. QString to_add;
  213. while (user)
  214. {
  215. to_add.setAscii((const char*)(user->usmUserSecurityName.data()),
  216. user->usmUserSecurityName.len());
  217. if (!names.contains(to_add) && (to_add != initial))
  218. names += to_add;
  219. user = usm->peek_next_user(user);
  220. }
  221. usm->unlock_user_name_table(); // unlock table
  222. combo_box_sec_name->insertStringList(names);
  223. }
  224. MainWindow::~MainWindow()
  225. {
  226. if (snmp)
  227. {
  228. delete snmp;
  229. snmp = 0;
  230. }
  231. if (v3mp)
  232. {
  233. USM *usm = v3mp->get_usm();
  234. // Save USM users with their passwords into a file
  235. // The passwords are not encrypted!
  236. if (SNMPv3_USM_OK != usm->save_users(FILE_USERS))
  237. {
  238. QString err = "\nCould not save users to file file.\n";
  239. text_edit_output->append(err);
  240. }
  241. delete v3mp;
  242. v3mp = 0;
  243. }
  244. Snmp::socket_cleanup(); // Shut down socket subsystem
  245. }
  246. // issue a GET-NEXT request
  247. void MainWindow::push_button_get_next_clicked()
  248. {
  249. int status;
  250. if (!snmp)
  251. return;
  252. push_button_get_next->setEnabled(false);
  253. // Create a Oid and a address object from the entered values
  254. Oid oid(line_edit_obj_id->text());
  255. UdpAddress address(line_edit_target->text());
  256. // check if the address is valid
  257. // One problem here: if a hostname is entered, a blocking DNS lookup
  258. // is done by the address object.
  259. if (!address.valid())
  260. {
  261. QString err = QString("\nInvalid Address or DNS Name: %1\n")
  262. .arg(line_edit_target->text());
  263. text_edit_output->append(err);
  264. push_button_get_next->setEnabled(true);
  265. return;
  266. }
  267. Pdu pdu; // empty Pdu
  268. Vb vb; // empty Vb
  269. SnmpTarget *target; // will point to a CTarget(v1/v2c) or UTarget (v3)
  270. // Set the Oid part of the Vb
  271. vb.set_oid(oid);
  272. // Add the Vb to the Pdu
  273. pdu += vb;
  274. // Get retries and timeout values
  275. int retries = spin_box_retries->value();
  276. int timeout = 100 * spin_box_timeout->value();
  277. if (radio_button_v3->isChecked())
  278. {
  279. // For SNMPv3 we need a UTarget object
  280. UTarget *utarget = new UTarget(address);
  281. utarget->set_version(version3);
  282. utarget->set_security_model(SNMP_SECURITY_MODEL_USM);
  283. utarget->set_security_name(combo_box_sec_name->currentText());
  284. target = utarget;
  285. // set the security level to use
  286. if (combo_box_sec_level->currentText() == "noAuthNoPriv")
  287. pdu.set_security_level(SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV);
  288. else if (combo_box_sec_level->currentText() == "authNoPriv")
  289. pdu.set_security_level(SNMP_SECURITY_LEVEL_AUTH_NOPRIV);
  290. else
  291. pdu.set_security_level(SNMP_SECURITY_LEVEL_AUTH_PRIV);
  292. // Not needed, as snmp++ will set it, if the user does not set it
  293. pdu.set_context_name(line_edit_context_name->text());
  294. pdu.set_context_engine_id(line_edit_context_engine_id->text());
  295. }
  296. else
  297. {
  298. // For SNMPv1/v2c we need a CTarget
  299. CTarget *ctarget = new CTarget(address);
  300. if (radio_button_v2->isChecked())
  301. ctarget->set_version(version2c);
  302. else
  303. ctarget->set_version(version1);
  304. // set the community
  305. ctarget->set_readcommunity( line_edit_community->text());
  306. target = ctarget;
  307. }
  308. target->set_retry(retries); // set the number of auto retries
  309. target->set_timeout(timeout); // set timeout
  310. // Now do an async get_next
  311. status = snmp->get_next(pdu, *target, callback, this);
  312. // Could we send it?
  313. if (status == SNMP_CLASS_SUCCESS)
  314. {
  315. timer.start(100);
  316. }
  317. else
  318. {
  319. QString err = QString("\nCould not send async GETNEXT request: %1\n")
  320. .arg(Snmp::error_msg(status));
  321. text_edit_output->append(err);
  322. push_button_get_next->setEnabled(true);
  323. }
  324. // the target is no longer needed
  325. delete target;
  326. }
  327. void MainWindow::timer_expired()
  328. {
  329. // When using async requests or if we are waiting for traps or
  330. // informs, we must call this member function periodically, as
  331. // snmp++ does not use an internal thread.
  332. snmp->eventListHolder->SNMPProcessPendingEvents();
  333. }
  334. // Set the properties
  335. void MainWindow::edit_properties_action_activated()
  336. {
  337. Properties p;
  338. p.set_snmp(snmp);
  339. p.exec();
  340. update_combobox_sec_name();
  341. }
  342. // Send out a SNMP Broadcast for discovery
  343. void MainWindow::push_button_broadcast_clicked()
  344. {
  345. int status;
  346. // Create a new SNMP session object, as while waiting for
  347. // broadcast responses, all other responses are counted as
  348. // broadcast responses
  349. Snmp session(status);
  350. if (status != SNMP_CLASS_SUCCESS)
  351. {
  352. QString err = "\nCould not create SNMP++ session:\n";
  353. err += Snmp::error_msg(status);
  354. text_edit_output->append(err);
  355. }
  356. // Create a address object from the entered value
  357. UdpAddress address(line_edit_target->text());
  358. // check if the address is valid
  359. // One problem here: if a hostname is entered, a blocking DNS lookup
  360. // is done by the address object.
  361. if (!address.valid())
  362. {
  363. QString err = QString("\nInvalid Address or DNS Name: %1\n")
  364. .arg(line_edit_target->text());
  365. text_edit_output->append(err);
  366. return;
  367. }
  368. // Get retries, timeout and community
  369. int retries = spin_box_retries->value();
  370. int timeout = 100 * spin_box_timeout->value();
  371. OctetStr community(line_edit_community->text());
  372. // Get the version
  373. snmp_version version;
  374. if (radio_button_v3->isChecked())
  375. version = version3;
  376. else if (radio_button_v2->isChecked())
  377. version = version2c;
  378. else
  379. version = version1;
  380. UdpAddressCollection addresses;
  381. // Now send the broadcast
  382. // do multiple loops as requested from "retries"
  383. for (int loops=1; loops<= retries + 1; ++loops)
  384. {
  385. status = session.broadcast_discovery(addresses,
  386. (timeout + 99) / 100,
  387. address, version, &community);
  388. if (status == SNMP_CLASS_SUCCESS)
  389. {
  390. QString err = QString("\nSuccess sending broadcast %1.\n").arg(loops);
  391. text_edit_output->append(err);
  392. }
  393. else
  394. {
  395. QString err = QString("\nCould not send broadcast: %1\n")
  396. .arg(Snmp::error_msg(status));
  397. text_edit_output->append(err);
  398. }
  399. }
  400. // filter out duplicates
  401. UdpAddressCollection filtered_addrs;
  402. int dummy_pos;
  403. for (int n=0; n < addresses.size(); ++n)
  404. if (filtered_addrs.find(addresses[n], dummy_pos) == FALSE)
  405. filtered_addrs += addresses[n];
  406. // print out all addressess
  407. text_edit_output->append(QString("Found %1 agents:\n")
  408. .arg(filtered_addrs.size()));
  409. for (int m=0; m < filtered_addrs.size(); ++m)
  410. text_edit_output->append(QString("Answer received from: %1\n")
  411. .arg(filtered_addrs[m].get_printable()));
  412. }
  413. // Handle start/stop of traps
  414. void MainWindow::push_button_traps_toggled(bool isOn)
  415. {
  416. if (!snmp)
  417. return;
  418. // lock port input field while waiting for traps
  419. line_edit_trap_port->setEnabled(!isOn);
  420. if (isOn)
  421. {
  422. // Start receiving traps
  423. // get the port
  424. int port = line_edit_trap_port->text().toUInt();
  425. // Set the trap listen port for this Snmp object
  426. snmp->notify_set_listen_port(port);
  427. OidCollection oidc;
  428. TargetCollection targetc;
  429. text_edit_output->append(
  430. QString("Trying to register for traps on port %1.\n").arg(port));
  431. int status = snmp->notify_register(oidc, targetc, callback, this);
  432. if (status != SNMP_CLASS_SUCCESS)
  433. {
  434. text_edit_output->append(
  435. QString("Error register for traps (%1): %2.\n").arg(status)
  436. .arg(snmp->error_msg(status)));
  437. line_edit_trap_port->setEnabled(true);
  438. push_button_traps->setOn(false);
  439. return;
  440. }
  441. else
  442. text_edit_output->append("Registered success.\n");
  443. // Start the timer
  444. timer.start(100);
  445. }
  446. else
  447. {
  448. // stop receiving traps
  449. snmp->notify_unregister();
  450. text_edit_output->append("Stopped receiving traps.\n");
  451. }
  452. }