int sprint_record(void *db, wg_int *rec, char **buf, int *bufsize, char **bptr, int format, int showid, int depth, int maxdepth, int strenc) { int i,limit; wg_int enc, len; #ifdef USE_CHILD_DB void *parent; #endif limit=MIN_STRLEN; str_guarantee_space(buf, bufsize, bptr, MIN_STRLEN); if (rec==NULL) { snprintf(*bptr, limit, JS_NULL); (*bptr)+=strlen(JS_NULL); return 1; } if (format!=0) { // json **bptr= '['; (*bptr)++; } #ifdef USE_CHILD_DB parent = wg_get_rec_owner(db, rec); #endif if (1) { len = wg_get_record_len(db, rec); if (showid) { // add record id (offset) as the first extra elem of record snprintf(*bptr, limit-1, "%d",wg_encode_record(db,rec)); *bptr=*bptr+strlen(*bptr); } for(i=0; i<len; i++) { enc = wg_get_field(db, rec, i); #ifdef USE_CHILD_DB if(parent != db) enc = wg_translate_hdroffset(db, parent, enc); #endif str_guarantee_space(buf, bufsize, bptr, MIN_STRLEN); if (i || showid) { if (format!=0) **bptr = ','; else **bptr = CSV_SEPARATOR; (*bptr)++; } *bptr=sprint_value(db, enc, buf, bufsize, bptr, format, showid, depth, maxdepth, strenc); } } if (format!=0) { // json str_guarantee_space(buf, bufsize, bptr, MIN_STRLEN); **bptr = ']'; (*bptr)++; } return 1; }
/* * Generic SNMP object fetcher * * st=1 snmpget() - query an agent and return a single value. * st=2 snmpwalk() - walk the mib and return a single dimensional array * containing the values. * st=3 snmprealwalk() and snmpwalkoid() - walk the mib and return an * array of oid,value pairs. * st=5-8 ** Reserved ** * st=11 snmpset() - query an agent and set a single value * */ void php_snmp(INTERNAL_FUNCTION_PARAMETERS, int st) { zval **a1, **a2, **a3, **a4, **a5, **a6, **a7; struct snmp_session session, *ss; struct snmp_pdu *pdu=NULL, *response; struct variable_list *vars; char *objid; oid name[MAX_NAME_LEN]; int name_length; int status, count,rootlen=0,gotroot=0; oid root[MAX_NAME_LEN]; char buf[2048]; char buf2[2048]; int keepwalking=1; long timeout=SNMP_DEFAULT_TIMEOUT; long retries=SNMP_DEFAULT_RETRIES; int myargc = ZEND_NUM_ARGS(); char type = (char) 0; char *value = (char *) 0; if (myargc < 3 || myargc > 7 || zend_get_parameters_ex(myargc, &a1, &a2, &a3, &a4, &a5, &a6, &a7) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string_ex(a1); convert_to_string_ex(a2); convert_to_string_ex(a3); if (st == 11) { if (myargc < 5) { WRONG_PARAM_COUNT; } convert_to_string_ex(a4); convert_to_string_ex(a5); if(myargc > 5) { convert_to_long_ex(a6); timeout = (*a6)->value.lval; } if(myargc > 6) { convert_to_long_ex(a7); retries = (*a7)->value.lval; } type = (*a4)->value.str.val[0]; value = (*a5)->value.str.val; } else { if(myargc > 3) { convert_to_long_ex(a4); timeout = (*a4)->value.lval; } if(myargc > 4) { convert_to_long_ex(a5); retries = (*a5)->value.lval; } } objid = (*a3)->value.str.val; if (st >= 2) { /* walk */ rootlen = MAX_NAME_LEN; if ( strlen(objid) ) { /* on a walk, an empty string means top of tree - no error */ if ( read_objid(objid, root, &rootlen) ) { gotroot = 1; } else { php_error(E_WARNING,"Invalid object identifier: %s\n", objid); } } if (gotroot == 0) { memmove((char *)root, (char *)objid_mib, sizeof(objid_mib)); rootlen = sizeof(objid_mib) / sizeof(oid); gotroot = 1; } } memset(&session, 0, sizeof(struct snmp_session)); session.peername = (*a1)->value.str.val; session.version = SNMP_VERSION_1; /* * FIXME: potential memory leak * This is a workaround for an "artifact" (Mike Slifcak) * in (at least) ucd-snmp 3.6.1 which frees * memory it did not allocate */ #ifdef UCD_SNMP_HACK session.community = (u_char *)strdup((*a2)->value.str.val); /* memory freed by SNMP library, strdup NOT estrdup */ #else session.community = (u_char *)(*a2)->value.str.val; #endif session.community_len = (*a2)->value.str.len; session.retries = retries; session.timeout = timeout; session.authenticator = NULL; snmp_synch_setup(&session); if ((ss = snmp_open(&session)) == NULL) { php_error(E_WARNING,"Could not open snmp\n"); RETURN_FALSE; } if (st >= 2) { memmove((char *)name, (char *)root, rootlen * sizeof(oid)); name_length = rootlen; if (array_init(return_value) == FAILURE) { php_error(E_WARNING, "Cannot prepare result array"); RETURN_FALSE; } } while(keepwalking) { keepwalking=0; if (st == 1) { pdu = snmp_pdu_create(SNMP_MSG_GET); name_length = MAX_NAME_LEN; if ( !read_objid(objid, name, &name_length) ) { php_error(E_WARNING,"Invalid object identifier: %s\n", objid); RETURN_FALSE; } snmp_add_null_var(pdu, name, name_length); } else if (st == 11) { pdu = snmp_pdu_create(SNMP_MSG_SET); if (snmp_add_var(pdu, name, name_length, type, value)) { php_error(E_WARNING,"Could not add variable: %s\n", name); RETURN_FALSE; } } else if (st >= 2) { pdu = snmp_pdu_create(SNMP_MSG_GETNEXT); snmp_add_null_var(pdu, name, name_length); } retry: status = snmp_synch_response(ss, pdu, &response); if (status == STAT_SUCCESS) { if (response->errstat == SNMP_ERR_NOERROR) { for (vars = response->variables; vars; vars = vars->next_variable) { if (st >= 2 && st != 11 && (vars->name_length < rootlen || memcmp(root, vars->name, rootlen * sizeof(oid)))) { continue; /* not part of this subtree */ } if (st != 11) { sprint_value(buf,vars->name, vars->name_length, vars); } #if 0 Debug("snmp response is: %s\n",buf); #endif if (st == 1) { RETVAL_STRING(buf,1); } else if (st == 2) { add_next_index_string(return_value,buf,1); /* Add to returned array */ } else if (st == 3) { sprint_objid(buf2, vars->name, vars->name_length); add_assoc_string(return_value,buf2,buf,1); } if (st >= 2 && st != 11) { if (vars->type != SNMP_ENDOFMIBVIEW && vars->type != SNMP_NOSUCHOBJECT && vars->type != SNMP_NOSUCHINSTANCE) { memmove((char *)name, (char *)vars->name,vars->name_length * sizeof(oid)); name_length = vars->name_length; keepwalking = 1; } } } } else { if (st != 2 || response->errstat != SNMP_ERR_NOSUCHNAME) { php_error(E_WARNING,"Error in packet.\nReason: %s\n", snmp_errstring(response->errstat)); if (response->errstat == SNMP_ERR_NOSUCHNAME) { for (count=1, vars = response->variables; vars && count != response->errindex; vars = vars->next_variable, count++); if (vars) { sprint_objid(buf,vars->name, vars->name_length); } php_error(E_WARNING,"This name does not exist: %s\n",buf); } if (st == 1) { if ((pdu = snmp_fix_pdu(response, SNMP_MSG_GET)) != NULL) { goto retry; } } else if (st == 11) { if ((pdu = snmp_fix_pdu(response, SNMP_MSG_SET)) != NULL) { goto retry; } } else if (st >= 2) { if ((pdu = snmp_fix_pdu(response, SNMP_MSG_GETNEXT)) != NULL) { goto retry; } } RETURN_FALSE; } } } else if (status == STAT_TIMEOUT) { php_error(E_WARNING,"No Response from %s\n", (*a1)->value.str.val); RETURN_FALSE; } else { /* status == STAT_ERROR */ php_error(E_WARNING,"An error occurred, Quitting...\n"); RETURN_FALSE; } if (response) { snmp_free_pdu(response); } } /* keepwalking */ snmp_close(ss); }
void *poller(void *thread_args) { worker_t *worker = (worker_t *) thread_args; crew_t *crew = worker->crew; target_t *entry = NULL; void *sessp = NULL; struct snmp_session session; struct snmp_pdu *pdu = NULL; struct snmp_pdu *response = NULL; oid anOID[MAX_OID_LEN]; size_t anOID_len = MAX_OID_LEN; struct variable_list *vars = NULL; unsigned long long result = 0; unsigned long long last_value = 0; unsigned long long insert_val = 0; int status = 0, bits = 0, init = 0; char query[BUFSIZE]; char storedoid[BUFSIZE]; char result_string[BUFSIZE]; if (set.verbose >= HIGH) printf("Thread [%d] starting.\n", worker->index); if (MYSQL_VERSION_ID > 40000) mysql_thread_init(); else my_thread_init(); while (1) { if (set.verbose >= DEVELOP) printf("Thread [%d] locking (wait on work)\n", worker->index); PT_MUTEX_LOCK(&crew->mutex); while (current == NULL) { PT_COND_WAIT(&crew->go, &crew->mutex); } if (set.verbose >= DEVELOP) printf("Thread [%d] done waiting, received go (work cnt: %d)\n", worker->index, crew->work_count); if (current != NULL) { if (set.verbose >= HIGH) printf("Thread [%d] processing %s %s (%d work units remain in queue)\n", worker->index, current->host, current->objoid, crew->work_count); snmp_sess_init(&session); if (set.snmp_ver == 2) session.version = SNMP_VERSION_2c; else session.version = SNMP_VERSION_1; session.peername = current->host; session.remote_port = set.snmp_port; session.community = current->community; session.community_len = strlen(session.community); sessp = snmp_sess_open(&session); anOID_len = MAX_OID_LEN; pdu = snmp_pdu_create(SNMP_MSG_GET); read_objid(current->objoid, anOID, &anOID_len); entry = current; last_value = current->last_value; init = current->init; insert_val = 0; bits = current->bits; strncpy(storedoid, current->objoid, sizeof(storedoid)); current = getNext(); } if (set.verbose >= DEVELOP) printf("Thread [%d] unlocking (done grabbing current)\n", worker->index); PT_MUTEX_UNLOCK(&crew->mutex); snmp_add_null_var(pdu, anOID, anOID_len); if (sessp != NULL) status = snmp_sess_synch_response(sessp, pdu, &response); else status = STAT_DESCRIP_ERROR; /* Collect response and process stats */ PT_MUTEX_LOCK(&stats.mutex); if (status == STAT_DESCRIP_ERROR) { stats.errors++; printf("*** SNMP Error: (%s) Bad descriptor.\n", session.peername); } else if (status == STAT_TIMEOUT) { stats.no_resp++; printf("*** SNMP No response: (%s@%s).\n", session.peername, storedoid); } else if (status != STAT_SUCCESS) { stats.errors++; printf("*** SNMP Error: (%s@%s) Unsuccessuful (%d).\n", session.peername, storedoid, status); } else if (status == STAT_SUCCESS && response->errstat != SNMP_ERR_NOERROR) { stats.errors++; printf("*** SNMP Error: (%s@%s) %s\n", session.peername, storedoid, snmp_errstring(response->errstat)); } else if (status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR) { stats.polls++; } PT_MUTEX_UNLOCK(&stats.mutex); /* Liftoff, successful poll, process it */ if (status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR) { vars = response->variables; #ifdef OLD_UCD_SNMP sprint_value(result_string, anOID, anOID_len, vars); #else snprint_value(result_string, BUFSIZE, anOID, anOID_len, vars); #endif switch (vars->type) { /* * Switch over vars->type and modify/assign result accordingly. */ case ASN_COUNTER64: if (set.verbose >= DEBUG) printf("64-bit result: (%s@%s) %s\n", session.peername, storedoid, result_string); result = vars->val.counter64->high; result = result << 32; result = result + vars->val.counter64->low; break; case ASN_COUNTER: if (set.verbose >= DEBUG) printf("32-bit result: (%s@%s) %s\n", session.peername, storedoid, result_string); result = (unsigned long) *(vars->val.integer); break; case ASN_INTEGER: if (set.verbose >= DEBUG) printf("Integer result: (%s@%s) %s\n", session.peername, storedoid, result_string); result = (unsigned long) *(vars->val.integer); break; case ASN_GAUGE: if (set.verbose >= DEBUG) printf("32-bit gauge: (%s@%s) %s\n", session.peername, storedoid, result_string); result = (unsigned long) *(vars->val.integer); break; case ASN_TIMETICKS: if (set.verbose >= DEBUG) printf("Timeticks result: (%s@%s) %s\n", session.peername, storedoid, result_string); result = (unsigned long) *(vars->val.integer); break; case ASN_OPAQUE: if (set.verbose >= DEBUG) printf("Opaque result: (%s@%s) %s\n", session.peername, storedoid, result_string); result = (unsigned long) *(vars->val.integer); break; default: if (set.verbose >= DEBUG) printf("Unknown result type: (%s@%s) %s\n", session.peername, storedoid, result_string); } /* Gauge Type */ if (bits == 0) { if (result != last_value) { insert_val = result; if (set.verbose >= HIGH) printf("Thread [%d]: Gauge change from %lld to %lld\n", worker->index, last_value, insert_val); } else { if (set.withzeros) insert_val = result; if (set.verbose >= HIGH) printf("Thread [%d]: Gauge steady at %lld\n", worker->index, insert_val); } /* Counter Wrap Condition */ } else if (result < last_value) { PT_MUTEX_LOCK(&stats.mutex); stats.wraps++; PT_MUTEX_UNLOCK(&stats.mutex); if (bits == 32) insert_val = (THIRTYTWO - last_value) + result; else if (bits == 64) insert_val = (SIXTYFOUR - last_value) + result; if (set.verbose >= LOW) { printf("*** Counter Wrap (%s@%s) [poll: %llu][last: %llu][insert: %llu]\n", session.peername, storedoid, result, last_value, insert_val); } /* Not a counter wrap and this is not the first poll */ } else if ((last_value >= 0) && (init != NEW)) { insert_val = result - last_value; /* Print out SNMP result if verbose */ if (set.verbose == DEBUG) printf("Thread [%d]: (%lld-%lld) = %llu\n", worker->index, result, last_value, insert_val); if (set.verbose == HIGH) printf("Thread [%d]: %llu\n", worker->index, insert_val); /* last_value < 0, so this must be the first poll */ } else { if (set.verbose >= HIGH) printf("Thread [%d]: First Poll, Normalizing\n", worker->index); } /* Check for bogus data, either negative or unrealistic */ if (insert_val > entry->maxspeed || result < 0) { if (set.verbose >= LOW) printf("*** Out of Range (%s@%s) [insert_val: %llu] [oor: %lld]\n", session.peername, storedoid, insert_val, entry->maxspeed); insert_val = 0; PT_MUTEX_LOCK(&stats.mutex); stats.out_of_range++; PT_MUTEX_UNLOCK(&stats.mutex); } if (!(set.dboff)) { if ( (insert_val > 0) || (set.withzeros) ) { PT_MUTEX_LOCK(&crew->mutex); snprintf(query, sizeof(query), "INSERT INTO %s VALUES (%d, NOW(), %llu)", entry->table, entry->iid, insert_val); if (set.verbose >= DEBUG) printf("SQL: %s\n", query); status = mysql_query(&mysql, query); if (status) printf("*** MySQL Error: %s\n", mysql_error(&mysql)); PT_MUTEX_UNLOCK(&crew->mutex); if (!status) { PT_MUTEX_LOCK(&stats.mutex); stats.db_inserts++; PT_MUTEX_UNLOCK(&stats.mutex); } } /* insert_val > 0 or withzeros */ } /* !dboff */ } /* STAT_SUCCESS */ if (sessp != NULL) { snmp_sess_close(sessp); if (response != NULL) snmp_free_pdu(response); } if (set.verbose >= DEVELOP) printf("Thread [%d] locking (update work_count)\n", worker->index); PT_MUTEX_LOCK(&crew->mutex); crew->work_count--; /* Only if we received a positive result back do we update the last_value object */ if (status == STAT_SUCCESS) entry->last_value = result; if (init == NEW) entry->init = LIVE; if (crew->work_count <= 0) { if (set.verbose >= HIGH) printf("Queue processed. Broadcasting thread done condition.\n"); PT_COND_BROAD(&crew->done); } if (set.verbose >= DEVELOP) printf("Thread [%d] unlocking (update work_count)\n", worker->index); PT_MUTEX_UNLOCK(&crew->mutex); } /* while(1) */ }
/*! \fn char *snmp_get_multi(host_t *current_host, snmp_oids_t *snmp_oids, int num_oids) * \brief performs multiple OID snmp_get's in a single network call * * This function will a group of snmp OID's for a host. The host snmp * session must already be established. The function will modify elements of * the snmp_oids array with the results from the snmp api call. * */ void snmp_get_multi(host_t *current_host, snmp_oids_t *snmp_oids, int num_oids) { struct snmp_pdu *pdu = NULL; struct snmp_pdu *response = NULL; struct variable_list *vars = NULL; int status; int i; int max_repetitions = 1; int non_repeaters = 0; int array_count; int index_count; /* get rid of some compiler warnings */ errstat = 0; errindex = 0; struct nameStruct { oid name[MAX_OID_LEN]; size_t name_len; } *name, *namep; /* load up oids */ namep = name = (struct nameStruct *) calloc(num_oids, sizeof(*name)); pdu = snmp_pdu_create(SNMP_MSG_GET); for (i = 0; i < num_oids; i++) { namep->name_len = MAX_OID_LEN; if (!snmp_parse_oid(snmp_oids[i].oid, namep->name, &namep->name_len)) { SPINE_LOG(("Host[%i] ERROR: Problems parsing Multi SNMP OID! (oid: %s)\n", current_host->id, snmp_oids[i].oid)); /* Mark this OID as "bad" */ SET_UNDEFINED(snmp_oids[i].result); }else{ snmp_add_null_var(pdu, namep->name, namep->name_len); } namep++; } status = STAT_DESCRIP_ERROR; /* execute the multi-get request */ retry: status = snmp_sess_synch_response(current_host->snmp_session, pdu, &response); /* liftoff, successful poll, process it!! */ if (status == STAT_SUCCESS) { if (response == NULL) { SPINE_LOG(("ERROR: An internal Net-Snmp error condition detected in Cacti snmp_get_multi\n")); status = STAT_ERROR; }else{ if (response->errstat == SNMP_ERR_NOERROR) { vars = response->variables; for(i = 0; i < num_oids && vars; i++) { if (!IS_UNDEFINED(snmp_oids[i].result)) { #ifdef USE_NET_SNMP snmp_snprint_value(snmp_oids[i].result, RESULTS_BUFFER, vars->name, vars->name_length, vars); #else sprint_value(snmp_oids[i].result, vars->name, vars->name_length, vars); #endif vars = vars->next_variable; } } }else{ if (response->errindex != 0) { index_count = 1; array_count = 0; /* Find our index against errindex */ while (array_count < num_oids) { if (IS_UNDEFINED(snmp_oids[array_count].result) ) { array_count++; }else{ /* if we have found our error, exit */ if (index_count == response->errindex) { SET_UNDEFINED(snmp_oids[array_count].result); break; } array_count++; index_count++; } } /* remote the invalid OID from the PDU */ pdu = snmp_fix_pdu(response, SNMP_MSG_GET); /* free the previous response */ snmp_free_pdu(response); response = NULL; if (pdu != NULL) { /* retry the request */ goto retry; }else{ /* all OID's errored out so exit cleanly */ status = STAT_SUCCESS; } }else{ status = STAT_DESCRIP_ERROR; } } } } if (status != STAT_SUCCESS) { current_host->ignore_host = 1; for (i = 0; i < num_oids; i++) { SET_UNDEFINED(snmp_oids[i].result); } } if (response != NULL) { snmp_free_pdu(response); } }
/*! \fn char *snmp_getnext(host_t *current_host, char *snmp_oid) * \brief performs a single snmp_getnext for a specific snmp OID * * This function will poll a specific snmp OID for a host. The host snmp * session must already be established. * * \return returns the character representaton of the snmp OID, or "U" if * unsuccessful. * */ char *snmp_getnext(host_t *current_host, char *snmp_oid) { struct snmp_pdu *pdu = NULL; struct snmp_pdu *response = NULL; struct variable_list *vars = NULL; size_t anOID_len = MAX_OID_LEN; oid anOID[MAX_OID_LEN]; int status; char *result_string; if (!(result_string = (char *) malloc(RESULTS_BUFFER))) { die("ERROR: Fatal malloc error: snmp.c snmp_get!"); } result_string[0] = '\0'; status = STAT_DESCRIP_ERROR; if (current_host->snmp_session != NULL) { anOID_len = MAX_OID_LEN; pdu = snmp_pdu_create(SNMP_MSG_GETNEXT); if (!snmp_parse_oid(snmp_oid, anOID, &anOID_len)) { SPINE_LOG(("ERROR: Problems parsing SNMP OID\n")); SET_UNDEFINED(result_string); return result_string; }else{ snmp_add_null_var(pdu, anOID, anOID_len); } /* poll host */ status = snmp_sess_synch_response(current_host->snmp_session, pdu, &response); /* liftoff, successful poll, process it!! */ if (status == STAT_SUCCESS) { if (response == NULL) { SPINE_LOG(("ERROR: An internal Net-Snmp error condition detected in Cacti snmp_get\n")); SET_UNDEFINED(result_string); status = STAT_ERROR; }else{ if (response->errstat == SNMP_ERR_NOERROR) { vars = response->variables; #ifdef USE_NET_SNMP snprint_value(result_string, RESULTS_BUFFER, anOID, anOID_len, vars); #else sprint_value(result_string, anOID, anOID_len, vars); #endif } } } if (response) { snmp_free_pdu(response); response = NULL; } }else{ status = STAT_DESCRIP_ERROR; } if (status != STAT_SUCCESS) { current_host->ignore_host = TRUE; SET_UNDEFINED(result_string); } return result_string; }
/* * Generic SNMP object fetcher * * st=1 GET * st=2 WALK */ void _php3_snmp(INTERNAL_FUNCTION_PARAMETERS, int st) { pval *a1, *a2, *a3; struct snmp_session session, *ss; struct snmp_pdu *pdu=NULL, *response; struct variable_list *vars; char *community, *hostname; char *objid; oid name[MAX_NAME_LEN]; int name_length; int status, count,rootlen=0,gotroot=0; oid root[MAX_NAME_LEN]; char buf[2048]; int keepwalking=1; static int mib_init=0; if (getParameters(ht, 3, &a1, &a2, &a3) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(a1); convert_to_string(a2); convert_to_string(a3); hostname=a1->value.str.val; community=a2->value.str.val; objid=a3->value.str.val; if (!mib_init) { init_mib(); mib_init=1; } if (st==2) { /* walk */ rootlen = MAX_NAME_LEN; if (strlen(objid)) { /* on a walk, an empty string means top of tree - no error */ if (read_objid(objid, root, &rootlen)) { gotroot = 1; } else { php3_error(E_WARNING,"Invalid object identifier: %s\n", objid); } } if (gotroot == 0) { memmove((char *)root, (char *)objid_mib, sizeof(objid_mib)); rootlen = sizeof(objid_mib) / sizeof(oid); gotroot = 1; } } memset(&session, 0, sizeof(struct snmp_session)); session.peername = hostname; session.version = SNMP_VERSION_1; session.community = (u_char *)community; session.community_len = strlen((char *)community); session.retries = SNMP_DEFAULT_RETRIES; session.timeout = SNMP_DEFAULT_TIMEOUT; session.authenticator = NULL; snmp_synch_setup(&session); ss = snmp_open(&session); if (ss == NULL){ php3_error(E_WARNING,"Couldn't open snmp\n"); RETURN_FALSE; } if (st==2) { memmove((char *)name, (char *)root, rootlen * sizeof(oid)); name_length = rootlen; /* prepare result array */ array_init(return_value); } while(keepwalking) { keepwalking=0; if (st==1) pdu = snmp_pdu_create(GET_REQ_MSG); else if (st==2) pdu = snmp_pdu_create(GETNEXT_REQ_MSG); if (st==1) { name_length = MAX_NAME_LEN; if (!read_objid(objid, name, &name_length)) { php3_error(E_WARNING,"Invalid object identifier: %s\n", objid); RETURN_FALSE; } } snmp_add_null_var(pdu, name, name_length); retry: status = snmp_synch_response(ss, pdu, &response); if (status == STAT_SUCCESS) { if (response->errstat == SNMP_ERR_NOERROR) { for(vars = response->variables; vars; vars = vars->next_variable) { if (st==2 && (vars->name_length < rootlen || memcmp(root, vars->name, rootlen * sizeof(oid)))) continue; /* not part of this subtree */ sprint_value(buf,vars->name, vars->name_length, vars); #if 0 Debug("snmp response is: %s\n",buf); #endif if (st==1) { RETVAL_STRING(buf,1); } else if (st==2) { /* Add to returned array */ add_next_index_string(return_value,buf,1); if (vars->type != SNMP_ENDOFMIBVIEW && vars->type != SNMP_NOSUCHOBJECT && vars->type != SNMP_NOSUCHINSTANCE) { memmove((char *)name, (char *)vars->name,vars->name_length * sizeof(oid)); name_length = vars->name_length; keepwalking = 1; } } } } else { if (st!=2 || response->errstat != SNMP_ERR_NOSUCHNAME) { php3_error(E_WARNING,"Error in packet.\nReason: %s\n", snmp_errstring(response->errstat)); if (response->errstat == SNMP_ERR_NOSUCHNAME) { for(count=1, vars = response->variables; vars && count != response->errindex; vars = vars->next_variable, count++); if (vars) sprint_objid(buf,vars->name, vars->name_length); php3_error(E_WARNING,"This name does not exist: %s\n",buf); } if (st==1) { if ((pdu = snmp_fix_pdu(response, GET_REQ_MSG)) != NULL) goto retry; } else if (st==2) { if ((pdu = snmp_fix_pdu(response, GETNEXT_REQ_MSG)) != NULL) goto retry; } RETURN_FALSE; } } } else if (status == STAT_TIMEOUT) { php3_error(E_WARNING,"No Response from %s\n", hostname); RETURN_FALSE; } else { /* status == STAT_ERROR */ php3_error(E_WARNING,"An error occurred, Quitting\n"); RETURN_FALSE; } if (response) snmp_free_pdu(response); } /* keepwalking */ snmp_close(ss); }
void *poller(void *thread_args) { worker_t *worker = (worker_t *) thread_args; crew_t *crew = worker->crew; target_t *entry = NULL; void *sessp = NULL; struct snmp_session session; struct snmp_pdu *pdu = NULL; struct snmp_pdu *response = NULL; oid anOID[MAX_OID_LEN]; size_t anOID_len = MAX_OID_LEN; struct variable_list *vars = NULL; unsigned long long result = 0; unsigned long long last_value = 0; unsigned long long insert_val = 0; int poll_status = 0, db_status = 0, bits = 0, init = 0; char query[BUFSIZE]; char storedoid[BUFSIZE]; char result_string[BUFSIZE]; int cur_work = 0; int prev_work = 99999999; int loop_count = 0; #ifdef FEATURES /* Per thread SQL connection testing */ #if HAVE_MYSQL MYSQL mysql; #elif HAVE_PGSQL PGconn *pgsql; #endif double rate = 0; struct timezone tzp; struct timeval current_time; struct timeval last_time; /* for thread settings */ int oldstate, oldtype; #endif debug(HIGH, "Thread [%d] starting.\n", worker->index); pthread_cleanup_push(cleanup_db, NULL); /* Attempt to connect to the MySQL Database */ #ifdef FEATURES /* Per thread MySQL connection testing */ if (!(set->dboff)) { /* load the database driver */ if (!(db_init(set))) { fatal("** Database error - check configuration.\n"); } /* connect to the database */ if (!(db_connect(set))) { fatal("server not responding.\n"); } /* set up cancel function for exit */ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); } #endif /* FEATURES */ while (1) { /* if(loop_count >= POLLS_PER_TRANSACTION) { debug(HIGH, "Thread [%d] doing commit on %d\n", worker->index, POLLS_PER_TRANSACTION); db_status = db_commit(); loop_count = 0; } */ #ifdef FEATURES /* see if we've been cancelled before we start another loop */ pthread_testcancel(); #endif debug(DEVELOP, "Thread [%d] locking (wait on work)\n", worker->index); PT_MUTEX_LOCK(&crew->mutex); #ifdef FEATURES /* add an unlock to the cancel stack */ pthread_cleanup_push(cancel_lock, &crew->mutex); #endif while (current == NULL) { PT_COND_WAIT(&crew->go, &crew->mutex); } debug(DEVELOP, "Thread [%d] done waiting, received go (work cnt: %d)\n", worker->index, crew->work_count); cur_work = crew->work_count; /* if(cur_work > prev_work) { debug(HIGH, "Thread [%d] doing commit at %d\n", worker->index,time(NULL)); db_status = db_commit(); loop_count = 0; } */ prev_work = cur_work; if (current != NULL) { debug(DEVELOP, "Thread [%d] processing %s %s (%d work units remain in queue)\n", worker->index, current->host->host, current->objoid, crew->work_count); snmp_enable_stderrlog(); snmp_sess_init(&session); if (current->host->snmp_ver == 2) session.version = SNMP_VERSION_2c; else session.version = SNMP_VERSION_1; session.peername = current->host->host; session.community = current->host->community; session.remote_port = set->snmp_port; session.community_len = strlen(session.community); sessp = snmp_sess_open(&session); anOID_len = MAX_OID_LEN; pdu = snmp_pdu_create(SNMP_MSG_GET); read_objid(current->objoid, anOID, &anOID_len); entry = current; last_value = current->last_value; #ifdef FEATURES /* save the time so we can calculate rate */ last_time = current->last_time; #endif init = current->init; insert_val = 0; bits = current->bits; strncpy(storedoid, current->objoid, sizeof(storedoid)); current = getNext(); } debug(DEVELOP, "Thread [%d] unlocking (done grabbing current)\n", worker->index); PT_MUTEX_UNLOCK(&crew->mutex); #ifdef FEATURES /* take the unlock off the cancel stack */ pthread_cleanup_pop(FALSE); #endif snmp_add_null_var(pdu, anOID, anOID_len); if (sessp != NULL) poll_status = snmp_sess_synch_response(sessp, pdu, &response); else poll_status = STAT_DESCRIP_ERROR; /* Collect response and process stats */ PT_MUTEX_LOCK(&stats.mutex); if (poll_status == STAT_DESCRIP_ERROR) { stats.errors++; printf("*** SNMP Error: (%s) Bad descriptor.\n", session.peername); } else if (poll_status == STAT_TIMEOUT) { stats.no_resp++; printf("*** SNMP No response: (%s@%s).\n", session.peername, storedoid); } else if (poll_status != STAT_SUCCESS) { stats.errors++; printf("*** SNMP Error: (%s@%s) Unsuccessuful (%d).\n", session.peername, storedoid, poll_status); } else if (poll_status == STAT_SUCCESS && response->errstat != SNMP_ERR_NOERROR) { stats.errors++; printf("*** SNMP Error: (%s@%s) %s\n", session.peername, storedoid, snmp_errstring(response->errstat)); } else if (poll_status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR && response->variables->type == SNMP_NOSUCHINSTANCE) { stats.errors++; printf("*** SNMP Error: No Such Instance Exists (%s@%s)\n", session.peername, storedoid); } else if (poll_status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR) { stats.polls++; } PT_MUTEX_UNLOCK(&stats.mutex); /* Liftoff, successful poll, process it */ #ifdef FEATURES /* Get the current time */ gettimeofday(¤t_time, &tzp); #endif if (poll_status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR && response->variables->type != SNMP_NOSUCHINSTANCE) { vars = response->variables; #ifdef OLD_UCD_SNMP sprint_value(result_string, anOID, anOID_len, vars); #else snprint_value(result_string, BUFSIZE, anOID, anOID_len, vars); #endif switch (vars->type) { /* * Switch over vars->type and modify/assign result accordingly. */ case ASN_COUNTER64: debug(DEBUG, "64-bit result: (%s@%s) %s\n", session.peername, storedoid, result_string); result = vars->val.counter64->high; result = result << 32; result = result + vars->val.counter64->low; break; case ASN_COUNTER: debug(DEBUG, "32-bit result: (%s@%s) %s\n", session.peername, storedoid, result_string); result = (unsigned long) *(vars->val.integer); break; case ASN_INTEGER: debug(DEBUG, "Integer result: (%s@%s) %s\n", session.peername, storedoid, result_string); result = (unsigned long) *(vars->val.integer); break; case ASN_GAUGE: debug(DEBUG, "32-bit gauge: (%s@%s) %s\n", session.peername, storedoid, result_string); result = (unsigned long) *(vars->val.integer); break; case ASN_TIMETICKS: debug(DEBUG, "Timeticks result: (%s@%s) %s\n", session.peername, storedoid, result_string); result = (unsigned long) *(vars->val.integer); break; case ASN_OPAQUE: debug(DEBUG, "Opaque result: (%s@%s) %s\n", session.peername, storedoid, result_string); result = (unsigned long) *(vars->val.integer); break; case ASN_OCTET_STR: debug(DEBUG, "String Result: (%s@%s) %s\n", session.peername, storedoid, result_string); #ifdef HAVE_STRTOLL result = strtoll(vars->val.string, NULL, 0); #else result = strtol(vars->val.string, NULL, 0); #endif break; default: debug(LOW, "Unknown result type: (%s@%s) %s\n", session.peername, storedoid, result_string); } /* Gauge Type */ if (bits == 0) { if (result != last_value) { insert_val = result; debug(DEVELOP, "Thread [%d]: Gauge change from %lld to %lld\n", worker->index, last_value, insert_val); } else { if (set->withzeros) insert_val = result; debug(DEVELOP, "Thread [%d]: Gauge steady at %lld\n", worker->index, insert_val); } /* Counter Wrap Condition */ } else if (result < last_value) { PT_MUTEX_LOCK(&stats.mutex); stats.wraps++; PT_MUTEX_UNLOCK(&stats.mutex); if (bits == 32) insert_val = (THIRTYTWO - last_value) + result; else if (bits == 64) insert_val = (SIXTYFOUR - last_value) + result; #ifdef FEATURES rate = insert_val / timediff(current_time, last_time); #endif debug(LOW, "*** Counter Wrap (%s@%s) [poll: %llu][last: %llu][insert: %llu]\n", session.peername, storedoid, result, last_value, insert_val); /* Not a counter wrap and this is not the first poll */ } else if ((last_value >= 0) && (init != NEW)) { insert_val = result - last_value; #ifdef FEATURES rate = insert_val / timediff(current_time, last_time); #endif /* Print out SNMP result if verbose */ if (set->verbose == DEBUG) printf("Thread [%d]: (%lld-%lld -- %llu) = %llu\n", worker->index, result, last_value, insert_val,rate); if (set->verbose == HIGH) printf("Thread [%d]: %llu\n", worker->index, insert_val); /* last_value < 0, so this must be the first poll */ } else { #ifdef FEATURES /* set up this result for the next poll */ entry->last_value = result; #endif debug(HIGH, "Thread [%d]: First Poll, Normalizing\n", worker->index); } /* Check for bogus data, either negative or unrealistic */ if (insert_val > entry->maxspeed || result < 0) { debug(LOW, "*** Out of Range (%s@%s) [insert_val: %llu] [oor: %lld]\n", session.peername, storedoid, insert_val, entry->maxspeed); insert_val = 0; #ifdef FEATURES rate = 0; #endif PT_MUTEX_LOCK(&stats.mutex); stats.out_of_range++; PT_MUTEX_UNLOCK(&stats.mutex); } if (!(set->dboff)) { if ( (insert_val > 0) || (set->withzeros) ) { #ifndef FEATURES /* MP - since we have our own database connection we don't need to lock it anymore */ PT_MUTEX_LOCK(&crew->mutex); #endif debug(DEVELOP, "db_insert sent: %s %d %d %e\n",entry->table,entry->iid,insert_val,rate); /* insert into the database */ db_status = db_insert(entry->table, entry->iid, insert_val, rate); #ifndef FEATURES /* MP - since we have our own database connection we don't need to lock it anymore */ PT_MUTEX_UNLOCK(&crew->mutex); #endif if (db_status) { PT_MUTEX_LOCK(&stats.mutex); stats.db_inserts++; PT_MUTEX_UNLOCK(&stats.mutex); } else { fatal("Fatal database error.\n"); } } /* insert_val > 0 or withzeros */ } /* !dboff */ } /* STAT_SUCCESS */ /* debug(HIGH, "Thread [%d] doing commit\n", worker->index); db_status = db_commit(); */ if (sessp != NULL) { snmp_sess_close(sessp); if (response != NULL) snmp_free_pdu(response); } debug(DEVELOP, "Thread [%d] locking (update work_count)\n", worker->index); PT_MUTEX_LOCK(&crew->mutex); crew->work_count--; /* Only if we received a positive result back do we update the last_value object */ if (poll_status == STAT_SUCCESS) { entry->last_value = result; if (init == NEW) entry->init = LIVE; } #ifdef FEATURES /* always update the time */ entry->last_time = current_time; #endif if (crew->work_count <= 0) { debug(HIGH, "Queue processed. Broadcasting thread done condition.\n"); PT_COND_BROAD(&crew->done); } debug(DEVELOP, "Thread [%d] unlocking (update work_count)\n", worker->index); PT_MUTEX_UNLOCK(&crew->mutex); loop_count++; } /* while(1) */ pthread_cleanup_pop(FALSE); /* Not reached */ }
/*! \fn char *snmp_get_multi(host_t *current_host, snmp_oids_t *snmp_oids, int num_oids) * \brief performs multiple OID snmp_get's in a single network call * * This function will a group of snmp OID's for a host. The host snmp * session must already be established. The function will modify elements of * the snmp_oids array with the results from the snmp api call. * */ void snmp_get_multi(host_t *current_host, snmp_oids_t *snmp_oids, int num_oids) { struct snmp_pdu *pdu = NULL; struct snmp_pdu *response = NULL; struct variable_list *vars = NULL; int status; int i; int max_repetitions = 1; int non_repeaters = 0; struct nameStruct { oid name[MAX_OID_LEN]; size_t name_len; } *name, *namep; /* load up oids */ namep = name = (struct nameStruct *) calloc(num_oids, sizeof(*name)); pdu = snmp_pdu_create(SNMP_MSG_GET); for (i = 0; i < num_oids; i++) { namep->name_len = MAX_OID_LEN; if (!snmp_parse_oid(snmp_oids[i].oid, namep->name, &namep->name_len)) { CACTID_LOG(("Host[%i] ERROR: Problems parsing Multi SNMP OID! (oid: %s)\n", current_host->id, snmp_oids[i].oid)); /* Mark this OID as "bad" */ SET_UNDEFINED(snmp_oids[i].result); }else{ snmp_add_null_var(pdu, namep->name, namep->name_len); } namep++; } status = STAT_DESCRIP_ERROR; /* execute the multi-get request */ retry: status = snmp_sess_synch_response(current_host->snmp_session, pdu, &response); /* liftoff, successful poll, process it!! */ if (status == STAT_SUCCESS) { if (response == NULL) { CACTID_LOG(("ERROR: An internal Net-Snmp error condition detected in Cacti snmp_get_multi\n")); status = STAT_ERROR; }else{ if (response->errstat == SNMP_ERR_NOERROR) { vars = response->variables; for(i = 0; i < num_oids && vars; i++) { if (!IS_UNDEFINED(snmp_oids[i].result)) { #ifdef USE_NET_SNMP snmp_snprint_value(snmp_oids[i].result, sizeof(snmp_oids[i].result), vars->name, vars->name_length, vars); #else sprint_value(snmp_oids[i].result, vars->name, vars->name_length, vars); #endif vars = vars->next_variable; } } }else{ if (response->errindex != 0) { /* removed errored OID and then retry */ int count; /* Find our index against errindex */ count = 0; for(i = 0; i < num_oids && count < response->errindex; i++) { if ( ! IS_UNDEFINED(snmp_oids[i].result) ) { count++; } } i--; SET_UNDEFINED(snmp_oids[i].result); for (count = 1, vars = response->variables; vars && count != response->errindex; vars = vars->next_variable, count++) { } pdu = snmp_fix_pdu(response, SNMP_MSG_GET); snmp_free_pdu(response); response = NULL; if (pdu != NULL) { goto retry; }else{ status = STAT_DESCRIP_ERROR; } }else{ status = STAT_DESCRIP_ERROR; } } } } if (status != STAT_SUCCESS) { current_host->ignore_host = 1; for (i = 0; i < num_oids; i++) { SET_UNDEFINED(snmp_oids[i].result); } } if (response != NULL) { snmp_free_pdu(response); } }