snmp_collator.c 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #include <sys/types.h>
  44. #include <sys/stat.h>
  45. #ifndef _WIN32
  46. #include <sys/ipc.h>
  47. #include <sys/msg.h>
  48. #include <dirent.h>
  49. #include <semaphore.h>
  50. #endif
  51. #include <time.h>
  52. #include <signal.h>
  53. #include <string.h>
  54. #include <errno.h>
  55. #include "agtmmap.h"
  56. #include "slap.h"
  57. #include "prthread.h"
  58. #include "prlock.h"
  59. #include "prerror.h"
  60. #include "prcvar.h"
  61. #include "plstr.h"
  62. #ifdef HPUX
  63. /* HP-UX doesn't define SEM_FAILED like other platforms, so
  64. * we define it ourselves. */
  65. #define SEM_FAILED ((sem_t *)(-1))
  66. #endif
  67. #define SNMP_NUM_SEM_WAITS 10
  68. #include "snmp_collator.h"
  69. #include "../snmp/ntagt/nslagtcom_nt.h"
  70. /* stevross: safe to assume port should be at most 5 digits ? */
  71. #define PORT_LEN 5
  72. /* strlen of url portions ie "ldap://:/" */
  73. #define URL_CHARS_LEN 9
  74. static char *make_ds_url(char *host, int port);
  75. #ifdef DEBUG_SNMP_INTERACTION
  76. static void print_snmp_interaction_table();
  77. #endif /* DEBUG_SNMP_INTERACTION */
  78. static int search_interaction_table(char *dsURL, int *isnew);
  79. static void loadConfigStats();
  80. static Slapi_Entry *getConfigEntry( Slapi_Entry **e );
  81. static void freeConfigEntry( Slapi_Entry **e );
  82. static void snmp_update_ops_table();
  83. static void snmp_update_entries_table();
  84. static void snmp_update_interactions_table();
  85. static void snmp_update_cache_stats();
  86. static void snmp_collator_create_semaphore();
  87. static void snmp_collator_sem_wait();
  88. /* snmp stats stuff */
  89. struct agt_stats_t *stats=NULL;
  90. /* mmap stuff */
  91. static int hdl;
  92. /* collator stuff */
  93. static char *tmpstatsfile = AGT_STATS_FILE;
  94. #ifdef _WIN32
  95. static TCHAR szStatsFile[_MAX_PATH];
  96. static TCHAR szTempDir[_MAX_PATH];
  97. static HANDLE hParentProcess = NULL;
  98. static HANDLE hStatSlot = NULL;
  99. static HANDLE hLogFile = INVALID_HANDLE_VALUE;
  100. static TCHAR szSpoolRootDir[_MAX_PATH];
  101. #else
  102. static char szStatsFile[_MAX_PATH];
  103. static char stats_sem_name[_MAX_PATH];
  104. #endif /* _WIN32*/
  105. static Slapi_Eq_Context snmp_eq_ctx;
  106. static int snmp_collator_stopped = 0;
  107. /* synchronization stuff */
  108. static PRLock *interaction_table_mutex;
  109. static sem_t *stats_sem;
  110. /***********************************************************************************
  111. *
  112. * int snmp_collator_init()
  113. *
  114. * initializes the global variables used by snmp
  115. *
  116. ************************************************************************************/
  117. static int snmp_collator_init(){
  118. int i;
  119. /*
  120. * Create the global SNMP counters
  121. */
  122. g_get_global_snmp_vars()->ops_tbl.dsAnonymousBinds = slapi_counter_new();
  123. g_get_global_snmp_vars()->ops_tbl.dsUnAuthBinds = slapi_counter_new();
  124. g_get_global_snmp_vars()->ops_tbl.dsSimpleAuthBinds = slapi_counter_new();
  125. g_get_global_snmp_vars()->ops_tbl.dsStrongAuthBinds = slapi_counter_new();
  126. g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors = slapi_counter_new();
  127. g_get_global_snmp_vars()->ops_tbl.dsInOps = slapi_counter_new();
  128. g_get_global_snmp_vars()->ops_tbl.dsReadOps = slapi_counter_new();
  129. g_get_global_snmp_vars()->ops_tbl.dsCompareOps = slapi_counter_new();
  130. g_get_global_snmp_vars()->ops_tbl.dsAddEntryOps = slapi_counter_new();
  131. g_get_global_snmp_vars()->ops_tbl.dsRemoveEntryOps = slapi_counter_new();
  132. g_get_global_snmp_vars()->ops_tbl.dsModifyEntryOps = slapi_counter_new();
  133. g_get_global_snmp_vars()->ops_tbl.dsModifyRDNOps = slapi_counter_new();
  134. g_get_global_snmp_vars()->ops_tbl.dsListOps = slapi_counter_new();
  135. g_get_global_snmp_vars()->ops_tbl.dsSearchOps = slapi_counter_new();
  136. g_get_global_snmp_vars()->ops_tbl.dsOneLevelSearchOps = slapi_counter_new();
  137. g_get_global_snmp_vars()->ops_tbl.dsWholeSubtreeSearchOps = slapi_counter_new();
  138. g_get_global_snmp_vars()->ops_tbl.dsReferrals = slapi_counter_new();
  139. g_get_global_snmp_vars()->ops_tbl.dsChainings = slapi_counter_new();
  140. g_get_global_snmp_vars()->ops_tbl.dsSecurityErrors = slapi_counter_new();
  141. g_get_global_snmp_vars()->ops_tbl.dsErrors = slapi_counter_new();
  142. g_get_global_snmp_vars()->ops_tbl.dsConnections = slapi_counter_new();
  143. g_get_global_snmp_vars()->ops_tbl.dsConnectionSeq = slapi_counter_new();
  144. g_get_global_snmp_vars()->ops_tbl.dsBytesRecv = slapi_counter_new();
  145. g_get_global_snmp_vars()->ops_tbl.dsBytesSent = slapi_counter_new();
  146. g_get_global_snmp_vars()->ops_tbl.dsEntriesReturned = slapi_counter_new();
  147. g_get_global_snmp_vars()->ops_tbl.dsReferralsReturned = slapi_counter_new();
  148. g_get_global_snmp_vars()->ops_tbl.dsConnectionsInMaxThreads = slapi_counter_new();
  149. g_get_global_snmp_vars()->ops_tbl.dsMaxThreadsHit = slapi_counter_new();
  150. g_get_global_snmp_vars()->entries_tbl.dsMasterEntries = slapi_counter_new();
  151. g_get_global_snmp_vars()->entries_tbl.dsCopyEntries = slapi_counter_new();
  152. g_get_global_snmp_vars()->entries_tbl.dsCacheEntries = slapi_counter_new();
  153. g_get_global_snmp_vars()->entries_tbl.dsCacheHits = slapi_counter_new();
  154. g_get_global_snmp_vars()->entries_tbl.dsSlaveHits = slapi_counter_new();
  155. /* Initialize the global interaction table */
  156. for(i=0; i < NUM_SNMP_INT_TBL_ROWS; i++)
  157. {
  158. g_get_global_snmp_vars()->int_tbl[i].dsIntIndex = i + 1;
  159. strncpy(g_get_global_snmp_vars()->int_tbl[i].dsName, "Not Available",
  160. sizeof(g_get_global_snmp_vars()->int_tbl[i].dsName));
  161. g_get_global_snmp_vars()->int_tbl[i].dsTimeOfCreation = 0;
  162. g_get_global_snmp_vars()->int_tbl[i].dsTimeOfLastAttempt = 0;
  163. g_get_global_snmp_vars()->int_tbl[i].dsTimeOfLastSuccess = 0;
  164. g_get_global_snmp_vars()->int_tbl[i].dsFailuresSinceLastSuccess = 0;
  165. g_get_global_snmp_vars()->int_tbl[i].dsFailures = 0;
  166. g_get_global_snmp_vars()->int_tbl[i].dsSuccesses = 0;
  167. strncpy(g_get_global_snmp_vars()->int_tbl[i].dsURL, "Not Available",
  168. sizeof(g_get_global_snmp_vars()->int_tbl[i].dsURL));
  169. }
  170. /* Get the semaphore */
  171. snmp_collator_sem_wait();
  172. /* Initialize the mmap structure */
  173. memset((void *) stats, 0, sizeof(*stats));
  174. /* Load header stats table */
  175. strncpy(stats->hdr_stats.dsVersion, SLAPD_VERSION_STR,
  176. (sizeof(stats->hdr_stats.dsVersion)/sizeof(char)) - 1);
  177. stats->hdr_stats.restarted = 0;
  178. stats->hdr_stats.startTime = time(0); /* This is a bit off, hope it's ok */
  179. loadConfigStats();
  180. /* update the mmap'd tables */
  181. snmp_update_ops_table();
  182. snmp_update_entries_table();
  183. snmp_update_interactions_table();
  184. /* Release the semaphore */
  185. sem_post(stats_sem);
  186. /* create lock for interaction table */
  187. interaction_table_mutex = PR_NewLock();
  188. return 0;
  189. }
  190. /***********************************************************************************
  191. * given the name, whether or not it was successful and the URL updates snmp
  192. * interaction table appropriately
  193. *
  194. *
  195. ************************************************************************************/
  196. void set_snmp_interaction_row(char *host, int port, int error)
  197. {
  198. int index;
  199. int isnew;
  200. char *dsName;
  201. char *dsURL;
  202. /* stevross: our servers don't have a concept of dsName as a distinguished name
  203. as specified in the MIB. Make this "Not Available" for now waiting for
  204. sometime in the future when we do
  205. */
  206. dsName = "Not Available";
  207. dsURL= make_ds_url(host, port);
  208. /* lock around here to avoid race condition of two threads trying to update table at same time */
  209. PR_Lock(interaction_table_mutex);
  210. index = search_interaction_table(dsURL, &isnew);
  211. if(isnew){
  212. /* fillin the new row from scratch*/
  213. g_get_global_snmp_vars()->int_tbl[index].dsIntIndex = index;
  214. strncpy(g_get_global_snmp_vars()->int_tbl[index].dsName, dsName,
  215. sizeof(g_get_global_snmp_vars()->int_tbl[index].dsName));
  216. g_get_global_snmp_vars()->int_tbl[index].dsTimeOfCreation = time(0);
  217. g_get_global_snmp_vars()->int_tbl[index].dsTimeOfLastAttempt = time(0);
  218. if(error == 0){
  219. g_get_global_snmp_vars()->int_tbl[index].dsTimeOfLastSuccess = time(0);
  220. g_get_global_snmp_vars()->int_tbl[index].dsFailuresSinceLastSuccess = 0;
  221. g_get_global_snmp_vars()->int_tbl[index].dsFailures = 0;
  222. g_get_global_snmp_vars()->int_tbl[index].dsSuccesses = 1;
  223. }else{
  224. g_get_global_snmp_vars()->int_tbl[index].dsTimeOfLastSuccess = 0;
  225. g_get_global_snmp_vars()->int_tbl[index].dsFailuresSinceLastSuccess = 1;
  226. g_get_global_snmp_vars()->int_tbl[index].dsFailures = 1;
  227. g_get_global_snmp_vars()->int_tbl[index].dsSuccesses = 0;
  228. }
  229. strncpy(g_get_global_snmp_vars()->int_tbl[index].dsURL, dsURL,
  230. sizeof(g_get_global_snmp_vars()->int_tbl[index].dsURL));
  231. }else{
  232. /* just update the appropriate fields */
  233. g_get_global_snmp_vars()->int_tbl[index].dsTimeOfLastAttempt = time(0);
  234. if(error == 0){
  235. g_get_global_snmp_vars()->int_tbl[index].dsTimeOfLastSuccess = time(0);
  236. g_get_global_snmp_vars()->int_tbl[index].dsFailuresSinceLastSuccess = 0;
  237. g_get_global_snmp_vars()->int_tbl[index].dsSuccesses += 1;
  238. }else{
  239. g_get_global_snmp_vars()->int_tbl[index].dsFailuresSinceLastSuccess +=1;
  240. g_get_global_snmp_vars()->int_tbl[index].dsFailures +=1;
  241. }
  242. }
  243. PR_Unlock(interaction_table_mutex);
  244. /* free the memory allocated for dsURL in call to ds_make_url */
  245. if(dsURL != NULL){
  246. slapi_ch_free( (void**)&dsURL );
  247. }
  248. }
  249. /***********************************************************************************
  250. * Given: host and port
  251. * Returns: ldapUrl in form of
  252. * ldap://host.mcom.com:port/
  253. *
  254. * this should point to root DSE
  255. ************************************************************************************/
  256. static char *make_ds_url(char *host, int port){
  257. char *url;
  258. url = slapi_ch_smprintf("ldap://%s:%d/",host, port);
  259. return url;
  260. }
  261. /***********************************************************************************
  262. * searches the table for the url specified
  263. * If there, returns index to update stats
  264. * if, not there returns index of oldest interaction, and isnew flag is set
  265. * so caller can rewrite this row
  266. ************************************************************************************/
  267. static int search_interaction_table(char *dsURL, int *isnew)
  268. {
  269. int i;
  270. int index = 0;
  271. time_t oldestattempt;
  272. time_t currentattempt;
  273. oldestattempt = g_get_global_snmp_vars()->int_tbl[0].dsTimeOfLastAttempt;
  274. *isnew = 1;
  275. for(i=0; i < NUM_SNMP_INT_TBL_ROWS; i++){
  276. if(!strcmp(g_get_global_snmp_vars()->int_tbl[i].dsURL, "Not Available"))
  277. {
  278. /* found it -- this is new, first time for this row */
  279. index = i;
  280. break;
  281. }else if(!strcmp(g_get_global_snmp_vars()->int_tbl[i].dsURL, dsURL)){
  282. /* found it -- it was already there*/
  283. *isnew = 0;
  284. index = i;
  285. break;
  286. }else{
  287. /* not found so figure out oldest row */
  288. currentattempt = g_get_global_snmp_vars()->int_tbl[i].dsTimeOfLastAttempt;
  289. if(currentattempt <= oldestattempt){
  290. index=i;
  291. oldestattempt = currentattempt;
  292. }
  293. }
  294. }
  295. return index;
  296. }
  297. #ifdef DEBUG_SNMP_INTERACTION
  298. /* for debuging until subagent part working, print contents of interaction table */
  299. static void print_snmp_interaction_table()
  300. {
  301. int i;
  302. for(i=0; i < NUM_SNMP_INT_TBL_ROWS; i++)
  303. {
  304. fprintf(stderr, " dsIntIndex: %d \n", g_get_global_snmp_vars()->int_tbl[i].dsIntIndex);
  305. fprintf(stderr, " dsName: %s \n", g_get_global_snmp_vars()->int_tbl[i].dsName);
  306. fprintf(stderr, " dsTimeOfCreation: %ld \n", g_get_global_snmp_vars()->int_tbl[i].dsTimeOfCreation);
  307. fprintf(stderr, " dsTimeOfLastAttempt: %ld \n", g_get_global_snmp_vars()->int_tbl[i].dsTimeOfLastAttempt);
  308. fprintf(stderr, " dsTimeOfLastSuccess: %ld \n", g_get_global_snmp_vars()->int_tbl[i].dsTimeOfLastSuccess);
  309. fprintf(stderr, "dsFailuresSinceLastSuccess: %d \n", g_get_global_snmp_vars()->int_tbl[i].dsFailuresSinceLastSuccess);
  310. fprintf(stderr, " dsFailures: %d \n", g_get_global_snmp_vars()->int_tbl[i].dsFailures);
  311. fprintf(stderr, " dsSuccesses: %d \n", g_get_global_snmp_vars()->int_tbl[i].dsSuccesses);
  312. fprintf(stderr, " dsURL: %s \n", g_get_global_snmp_vars()->int_tbl[i].dsURL);
  313. fprintf(stderr, "\n");
  314. }
  315. }
  316. #endif /* DEBUG_SNMP_INTERACTION */
  317. /*-------------------------------------------------------------------------
  318. *
  319. * sc_setevent: Sets the specified event (NT only). The input event has
  320. * to be created by the subagent during its initialization.
  321. *
  322. * Returns: None
  323. *
  324. *-----------------------------------------------------------------------*/
  325. #ifdef _WIN32
  326. void sc_setevent(char *ev)
  327. {
  328. HANDLE hTrapEvent;
  329. DWORD err = NO_ERROR;
  330. /*
  331. * Set the event handle to force NT SNMP service to call the subagent
  332. * DLL to generate a trap. Any error will be ignored as the subagent
  333. * may not have been loaded.
  334. */
  335. if ((hTrapEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE,
  336. (LPCTSTR) ev)) != NULL)
  337. {
  338. if (SetEvent(hTrapEvent) == FALSE)
  339. err = GetLastError();
  340. }
  341. else
  342. err = GetLastError();
  343. if (err != NO_ERROR)
  344. {
  345. fprintf(stderr, "Failed to set trap (error = %d).\n", err);
  346. }
  347. }
  348. #endif
  349. /***********************************************************************************
  350. *
  351. * int snmp_collator_start()
  352. *
  353. * open the memory map and initialize the variables
  354. * initializes the global variables used by snmp
  355. *
  356. * starts the collator thread
  357. ************************************************************************************/
  358. int snmp_collator_start()
  359. {
  360. int err;
  361. char *statspath = config_get_rundir();
  362. char *instdir = config_get_configdir();
  363. char *instname = NULL;
  364. /*
  365. * Get directory for our stats file
  366. */
  367. if (NULL == statspath) {
  368. statspath = slapi_ch_strdup("/tmp");
  369. }
  370. instname = PL_strrstr(instdir, "slapd-");
  371. if (!instname) {
  372. instname = PL_strrstr(instdir, "/");
  373. if (instname) {
  374. instname++;
  375. }
  376. }
  377. PR_snprintf(szStatsFile, sizeof(szStatsFile), "%s/%s%s",
  378. statspath, instname, AGT_STATS_EXTENSION);
  379. PR_snprintf(stats_sem_name, sizeof(stats_sem_name), "/%s%s",
  380. instname, AGT_STATS_EXTENSION);
  381. tmpstatsfile = szStatsFile;
  382. slapi_ch_free_string(&statspath);
  383. slapi_ch_free_string(&instdir);
  384. /* open the memory map */
  385. if ((err = agt_mopen_stats(tmpstatsfile, O_RDWR, &hdl) != 0))
  386. {
  387. if (err != EEXIST) /* Ignore if file already exists */
  388. {
  389. slapi_log_error(SLAPI_LOG_FATAL, "snmp collator", "Failed to open stats file (%s) "
  390. "(error %d): %s.\n", szStatsFile, err, slapd_system_strerror(err));
  391. exit(1);
  392. }
  393. }
  394. /* Create semaphore for stats file access */
  395. snmp_collator_create_semaphore();
  396. /* point stats struct at mmap data */
  397. stats = (struct agt_stats_t *) mmap_tbl [hdl].fp;
  398. /* initialize stats data */
  399. snmp_collator_init();
  400. /* Arrange to be called back periodically to update the mmap'd stats file. */
  401. snmp_eq_ctx = slapi_eq_repeat(snmp_collator_update, NULL, (time_t)0,
  402. SLAPD_SNMP_UPDATE_INTERVAL);
  403. return 0;
  404. }
  405. /***********************************************************************************
  406. *
  407. * int snmp_collator_stop()
  408. *
  409. * stops the collator thread
  410. * closes the memory map
  411. * cleans up any needed memory
  412. *
  413. ************************************************************************************/
  414. int snmp_collator_stop()
  415. {
  416. int err;
  417. if (snmp_collator_stopped) {
  418. return 0;
  419. }
  420. /* Abort any pending events */
  421. slapi_eq_cancel(snmp_eq_ctx);
  422. snmp_collator_stopped = 1;
  423. /* acquire the semaphore */
  424. snmp_collator_sem_wait();
  425. /* close the memory map */
  426. if ((err = agt_mclose_stats(hdl)) != 0)
  427. {
  428. fprintf(stderr, "Failed to close stats file (%s) (error = %d).",
  429. AGT_STATS_FILE, err);
  430. }
  431. if (remove(tmpstatsfile) != 0)
  432. {
  433. fprintf(stderr, "Failed to remove (%s) (error = %d).\n",
  434. tmpstatsfile, errno);
  435. }
  436. /* close and delete semaphore */
  437. sem_close(stats_sem);
  438. sem_unlink(stats_sem_name);
  439. /* delete lock */
  440. if (interaction_table_mutex) {
  441. PR_DestroyLock(interaction_table_mutex);
  442. }
  443. #ifdef _WIN32
  444. /* send the event so server down trap gets set on NT */
  445. sc_setevent(MAGT_NSEV_SNMPTRAP);
  446. #endif
  447. /* stevross: I probably need to free stats too... make sure to add that later */
  448. return 0;
  449. }
  450. /*
  451. * snmp_collator_create_semaphore()
  452. *
  453. * Create a semaphore to synchronize access to the stats file with
  454. * the SNMP sub-agent. NSPR doesn't support a trywait function
  455. * for semaphores, so we just use POSIX semaphores directly.
  456. */
  457. static void
  458. snmp_collator_create_semaphore()
  459. {
  460. /* First just try to create the semaphore. This should usually just work. */
  461. if ((stats_sem = sem_open(stats_sem_name, O_CREAT | O_EXCL, SLAPD_DEFAULT_FILE_MODE, 1)) == SEM_FAILED) {
  462. if (errno == EEXIST) {
  463. /* It appears that we didn't exit cleanly last time and left the semaphore
  464. * around. Recreate it since we don't know what state it is in. */
  465. if (sem_unlink(stats_sem_name) != 0) {
  466. LDAPDebug( LDAP_DEBUG_ANY, "Failed to delete old semaphore for stats file (%s). "
  467. "Error %d (%s).\n", szStatsFile, errno, slapd_system_strerror(errno) );
  468. exit(1);
  469. }
  470. if ((stats_sem = sem_open(stats_sem_name, O_CREAT | O_EXCL, SLAPD_DEFAULT_FILE_MODE, 1)) == SEM_FAILED) {
  471. /* No dice */
  472. LDAPDebug( LDAP_DEBUG_ANY, "Failed to create semaphore for stats file (%s). Error %d (%s).\n",
  473. szStatsFile, errno, slapd_system_strerror(errno) );
  474. exit(1);
  475. }
  476. } else {
  477. /* Some other problem occurred creating the semaphore. */
  478. LDAPDebug( LDAP_DEBUG_ANY, "Failed to create semaphore for stats file (%s). Error %d.(%s)\n",
  479. szStatsFile, errno, slapd_system_strerror(errno) );
  480. exit(1);
  481. }
  482. }
  483. /* If we've reached this point, everything should be good. */
  484. return;
  485. }
  486. /*
  487. * snmp_collator_sem_wait()
  488. *
  489. * A wrapper used to get the semaphore. We don't want to block,
  490. * but we want to retry a specified number of times in case the
  491. * semaphore is help by the sub-agent.
  492. */
  493. static void
  494. snmp_collator_sem_wait()
  495. {
  496. int i = 0;
  497. int got_sem = 0;
  498. if (SEM_FAILED == stats_sem) {
  499. LDAPDebug1Arg(LDAP_DEBUG_ANY,
  500. "semaphore for stats file (%s) is not available.\n", szStatsFile);
  501. return;
  502. }
  503. for (i=0; i < SNMP_NUM_SEM_WAITS; i++) {
  504. if (sem_trywait(stats_sem) == 0) {
  505. got_sem = 1;
  506. break;
  507. }
  508. PR_Sleep(PR_SecondsToInterval(1));
  509. }
  510. if (!got_sem) {
  511. /* If we've been unable to get the semaphore, there's
  512. * something wrong (likely the sub-agent went out to
  513. * lunch). We remove the old semaphore and recreate
  514. * a new one to avoid hanging up the server. */
  515. sem_close(stats_sem);
  516. sem_unlink(stats_sem_name);
  517. snmp_collator_create_semaphore();
  518. }
  519. }
  520. /***********************************************************************************
  521. *
  522. * int snmp_collator_update()
  523. *
  524. * Event callback function that updates the mmap'd stats file
  525. * for the SNMP sub-agent. This will use a semaphore while
  526. * updating the stats file to prevent the SNMP sub-agent from
  527. * reading it in the middle of an update.
  528. *
  529. ************************************************************************************/
  530. void
  531. snmp_collator_update(time_t start_time, void *arg)
  532. {
  533. if (snmp_collator_stopped) {
  534. return;
  535. }
  536. /* force an update of the backend cache stats. */
  537. snmp_update_cache_stats();
  538. /* get the semaphore */
  539. snmp_collator_sem_wait();
  540. /* just update the update time in the header */
  541. if( stats != NULL){
  542. stats->hdr_stats.updateTime = time(0);
  543. }
  544. /* update the mmap'd tables */
  545. snmp_update_ops_table();
  546. snmp_update_entries_table();
  547. snmp_update_interactions_table();
  548. /* release the semaphore */
  549. sem_post(stats_sem);
  550. }
  551. /*
  552. * snmp_update_ops_table()
  553. *
  554. * Updates the mmap'd operations table. The semaphore
  555. * should be acquired before you call this.
  556. */
  557. static void
  558. snmp_update_ops_table()
  559. {
  560. stats->ops_stats.dsAnonymousBinds = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsAnonymousBinds);
  561. stats->ops_stats.dsUnAuthBinds = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsUnAuthBinds);
  562. stats->ops_stats.dsSimpleAuthBinds = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsSimpleAuthBinds);
  563. stats->ops_stats.dsStrongAuthBinds = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsStrongAuthBinds);
  564. stats->ops_stats.dsBindSecurityErrors = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors);
  565. stats->ops_stats.dsInOps = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsInOps);
  566. stats->ops_stats.dsReadOps = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsReadOps);
  567. stats->ops_stats.dsCompareOps = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsCompareOps);
  568. stats->ops_stats.dsAddEntryOps = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsAddEntryOps);
  569. stats->ops_stats.dsRemoveEntryOps = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsRemoveEntryOps);
  570. stats->ops_stats.dsModifyEntryOps = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsModifyEntryOps);
  571. stats->ops_stats.dsModifyRDNOps = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsModifyRDNOps);
  572. stats->ops_stats.dsListOps = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsListOps);
  573. stats->ops_stats.dsSearchOps = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsSearchOps);
  574. stats->ops_stats.dsOneLevelSearchOps = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsOneLevelSearchOps);
  575. stats->ops_stats.dsWholeSubtreeSearchOps = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsWholeSubtreeSearchOps);
  576. stats->ops_stats.dsReferrals = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsReferrals);
  577. stats->ops_stats.dsChainings = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsChainings);
  578. stats->ops_stats.dsSecurityErrors = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsSecurityErrors);
  579. stats->ops_stats.dsErrors = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsErrors);
  580. stats->ops_stats.dsConnections = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsConnections);
  581. stats->ops_stats.dsConnectionSeq = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsConnectionSeq);
  582. stats->ops_stats.dsConnectionsInMaxThreads = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsConnectionsInMaxThreads);
  583. stats->ops_stats.dsMaxThreadsHit = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsMaxThreadsHit);
  584. stats->ops_stats.dsBytesRecv = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsBytesRecv);
  585. stats->ops_stats.dsBytesSent = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsBytesSent);
  586. stats->ops_stats.dsEntriesReturned = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsEntriesReturned);
  587. stats->ops_stats.dsReferralsReturned = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsReferralsReturned);
  588. }
  589. /*
  590. * snmp_update_entries_table()
  591. *
  592. * Updated the mmap'd entries table. The semaphore should
  593. * be acquired before you call this.
  594. */
  595. static void
  596. snmp_update_entries_table()
  597. {
  598. stats->entries_stats.dsMasterEntries = slapi_counter_get_value(g_get_global_snmp_vars()->entries_tbl.dsMasterEntries);
  599. stats->entries_stats.dsCopyEntries = slapi_counter_get_value(g_get_global_snmp_vars()->entries_tbl.dsCopyEntries);
  600. stats->entries_stats.dsCacheEntries = slapi_counter_get_value(g_get_global_snmp_vars()->entries_tbl.dsCacheEntries);
  601. stats->entries_stats.dsCacheHits = slapi_counter_get_value(g_get_global_snmp_vars()->entries_tbl.dsCacheHits);
  602. stats->entries_stats.dsSlaveHits = slapi_counter_get_value(g_get_global_snmp_vars()->entries_tbl.dsSlaveHits);
  603. }
  604. /*
  605. * snmp_update_interactions_table()
  606. *
  607. * Updates the mmap'd interactions table. The semaphore should
  608. * be acquired before you call this.
  609. */
  610. static void
  611. snmp_update_interactions_table()
  612. {
  613. int i;
  614. for(i=0; i < NUM_SNMP_INT_TBL_ROWS; i++) {
  615. stats->int_stats[i].dsIntIndex = i;
  616. strncpy(stats->int_stats[i].dsName, g_get_global_snmp_vars()->int_tbl[i].dsName,
  617. sizeof(stats->int_stats[i].dsName));
  618. stats->int_stats[i].dsTimeOfCreation = g_get_global_snmp_vars()->int_tbl[i].dsTimeOfCreation;
  619. stats->int_stats[i].dsTimeOfLastAttempt = g_get_global_snmp_vars()->int_tbl[i].dsTimeOfLastAttempt;
  620. stats->int_stats[i].dsTimeOfLastSuccess = g_get_global_snmp_vars()->int_tbl[i].dsTimeOfLastSuccess;
  621. stats->int_stats[i].dsFailuresSinceLastSuccess = g_get_global_snmp_vars()->int_tbl[i].dsFailuresSinceLastSuccess;
  622. stats->int_stats[i].dsFailures = g_get_global_snmp_vars()->int_tbl[i].dsFailures;
  623. stats->int_stats[i].dsSuccesses = g_get_global_snmp_vars()->int_tbl[i].dsSuccesses;
  624. strncpy(stats->int_stats[i].dsURL, g_get_global_snmp_vars()->int_tbl[i].dsURL,
  625. sizeof(stats->int_stats[i].dsURL));
  626. }
  627. }
  628. /*
  629. * snmp_update_cache_stats()
  630. *
  631. * Reads the backend cache stats from the backend monitor entry and
  632. * updates the global counter used by the SNMP sub-agent as well as
  633. * the SNMP monitor entry.
  634. */
  635. static void
  636. snmp_update_cache_stats()
  637. {
  638. Slapi_Backend *be, *be_next;
  639. char *cookie = NULL;
  640. Slapi_PBlock *search_result_pb = NULL;
  641. Slapi_Entry **search_entries;
  642. int search_result;
  643. /* set the cache hits/cache entries info */
  644. be = slapi_get_first_backend(&cookie);
  645. if (!be){
  646. slapi_ch_free ((void **) &cookie);
  647. return;
  648. }
  649. be_next = slapi_get_next_backend(cookie);
  650. slapi_ch_free ((void **) &cookie);
  651. /* for now, only do it if there is only 1 backend, otherwise don't know
  652. * which backend to pick */
  653. if(be_next == NULL)
  654. {
  655. Slapi_DN monitordn;
  656. slapi_sdn_init(&monitordn);
  657. be_getmonitordn(be,&monitordn);
  658. /* do a search on the monitor dn to get info */
  659. search_result_pb = slapi_search_internal( slapi_sdn_get_dn(&monitordn),
  660. LDAP_SCOPE_BASE,
  661. "objectclass=*",
  662. NULL,
  663. NULL,
  664. 0);
  665. slapi_sdn_done(&monitordn);
  666. slapi_pblock_get( search_result_pb, SLAPI_PLUGIN_INTOP_RESULT, &search_result);
  667. if(search_result == 0)
  668. {
  669. slapi_pblock_get( search_result_pb,SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
  670. &search_entries);
  671. /* set the entrycachehits */
  672. slapi_counter_set_value(g_get_global_snmp_vars()->entries_tbl.dsCacheHits,
  673. slapi_entry_attr_get_ulonglong(search_entries[0], "entrycachehits"));
  674. /* set the currententrycachesize */
  675. slapi_counter_set_value(g_get_global_snmp_vars()->entries_tbl.dsCacheEntries,
  676. slapi_entry_attr_get_ulonglong(search_entries[0], "currententrycachesize"));
  677. }
  678. slapi_free_search_results_internal(search_result_pb);
  679. slapi_pblock_destroy(search_result_pb);
  680. }
  681. }
  682. static void
  683. add_counter_to_value(Slapi_Entry *e, const char *type, PRUint64 countervalue)
  684. {
  685. char value[40];
  686. PR_snprintf(value,sizeof(value),"%" NSPRIu64, countervalue);
  687. slapi_entry_attr_set_charptr( e, type, value);
  688. }
  689. void
  690. snmp_as_entry(Slapi_Entry *e)
  691. {
  692. add_counter_to_value(e,"AnonymousBinds", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsAnonymousBinds));
  693. add_counter_to_value(e,"UnAuthBinds", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsUnAuthBinds));
  694. add_counter_to_value(e,"SimpleAuthBinds", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsSimpleAuthBinds));
  695. add_counter_to_value(e,"StrongAuthBinds", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsStrongAuthBinds));
  696. add_counter_to_value(e,"BindSecurityErrors", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors));
  697. add_counter_to_value(e,"InOps", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsInOps));
  698. add_counter_to_value(e,"ReadOps", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsReadOps));
  699. add_counter_to_value(e,"CompareOps", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsCompareOps));
  700. add_counter_to_value(e,"AddEntryOps", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsAddEntryOps));
  701. add_counter_to_value(e,"RemoveEntryOps", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsRemoveEntryOps));
  702. add_counter_to_value(e,"ModifyEntryOps", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsModifyEntryOps));
  703. add_counter_to_value(e,"ModifyRDNOps", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsModifyRDNOps));
  704. add_counter_to_value(e,"ListOps", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsListOps));
  705. add_counter_to_value(e,"SearchOps", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsSearchOps));
  706. add_counter_to_value(e,"OneLevelSearchOps", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsOneLevelSearchOps));
  707. add_counter_to_value(e,"WholeSubtreeSearchOps", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsWholeSubtreeSearchOps));
  708. add_counter_to_value(e,"Referrals", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsReferrals));
  709. add_counter_to_value(e,"Chainings", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsChainings));
  710. add_counter_to_value(e,"SecurityErrors", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsSecurityErrors));
  711. add_counter_to_value(e,"Errors", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsErrors));
  712. add_counter_to_value(e,"Connections", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsConnections));
  713. add_counter_to_value(e,"ConnectionSeq", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsConnectionSeq));
  714. add_counter_to_value(e,"ConnectionsInMaxThreads", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsConnectionsInMaxThreads));
  715. add_counter_to_value(e,"ConnectionsMaxThreadsCount", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsMaxThreadsHit));
  716. add_counter_to_value(e,"BytesRecv", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsBytesRecv));
  717. add_counter_to_value(e,"BytesSent", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsBytesSent));
  718. add_counter_to_value(e,"EntriesReturned", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsEntriesReturned));
  719. add_counter_to_value(e,"ReferralsReturned", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsReferralsReturned));
  720. add_counter_to_value(e,"MasterEntries", slapi_counter_get_value(g_get_global_snmp_vars()->entries_tbl.dsMasterEntries));
  721. add_counter_to_value(e,"CopyEntries", slapi_counter_get_value(g_get_global_snmp_vars()->entries_tbl.dsCopyEntries));
  722. add_counter_to_value(e,"CacheEntries", slapi_counter_get_value(g_get_global_snmp_vars()->entries_tbl.dsCacheEntries));
  723. add_counter_to_value(e,"CacheHits", slapi_counter_get_value(g_get_global_snmp_vars()->entries_tbl.dsCacheHits));
  724. add_counter_to_value(e,"SlaveHits", slapi_counter_get_value(g_get_global_snmp_vars()->entries_tbl.dsSlaveHits));
  725. }
  726. /*
  727. * loadConfigStats()
  728. *
  729. * Reads the header table SNMP settings and sets them in the mmap'd stats
  730. * file. This should be done only when the semaphore is held.
  731. */
  732. static void
  733. loadConfigStats() {
  734. Slapi_Entry *entry = NULL;
  735. char *name = NULL;
  736. char *desc = NULL;
  737. char *org = NULL;
  738. char *loc = NULL;
  739. char *contact = NULL;
  740. /* Read attributes from SNMP config entry */
  741. getConfigEntry( &entry );
  742. if ( entry != NULL ) {
  743. name = slapi_entry_attr_get_charptr( entry, SNMP_NAME_ATTR );
  744. desc = slapi_entry_attr_get_charptr( entry, SNMP_DESC_ATTR );
  745. org = slapi_entry_attr_get_charptr( entry, SNMP_ORG_ATTR );
  746. loc = slapi_entry_attr_get_charptr( entry, SNMP_LOC_ATTR );
  747. contact = slapi_entry_attr_get_charptr( entry, SNMP_CONTACT_ATTR );
  748. freeConfigEntry( &entry );
  749. }
  750. /* Load stats into table */
  751. if ( name != NULL) {
  752. PL_strncpyz(stats->hdr_stats.dsName, name, SNMP_FIELD_LENGTH);
  753. }
  754. if ( desc != NULL) {
  755. PL_strncpyz(stats->hdr_stats.dsDescription, desc, SNMP_FIELD_LENGTH);
  756. }
  757. if ( org != NULL) {
  758. PL_strncpyz(stats->hdr_stats.dsOrganization, org, SNMP_FIELD_LENGTH);
  759. }
  760. if ( loc != NULL) {
  761. PL_strncpyz(stats->hdr_stats.dsLocation, loc, SNMP_FIELD_LENGTH);
  762. }
  763. if ( contact != NULL) {
  764. PL_strncpyz(stats->hdr_stats.dsContact, contact, SNMP_FIELD_LENGTH);
  765. }
  766. /* Free strings */
  767. slapi_ch_free((void **) &name);
  768. slapi_ch_free((void **) &desc);
  769. slapi_ch_free((void **) &org);
  770. slapi_ch_free((void **) &loc);
  771. slapi_ch_free((void **) &contact);
  772. }
  773. static Slapi_Entry *
  774. getConfigEntry( Slapi_Entry **e ) {
  775. Slapi_DN sdn;
  776. /* SNMP_CONFIG_DN: no need to be normalized */
  777. slapi_sdn_init_normdn_byref( &sdn, SNMP_CONFIG_DN );
  778. slapi_search_internal_get_entry( &sdn, NULL, e,
  779. plugin_get_default_component_id());
  780. slapi_sdn_done( &sdn );
  781. return *e;
  782. }
  783. static void
  784. freeConfigEntry( Slapi_Entry **e ) {
  785. if ( (e != NULL) && (*e != NULL) ) {
  786. slapi_entry_free( *e );
  787. *e = NULL;
  788. }
  789. }