--- a/src/snmp.c +++ b/src/snmp.c @@ -33,6 +33,8 @@ #include #include +#include +#include #include @@ -97,7 +99,8 @@ char *context; void *sess_handle; - c_complain_t complaint; +// c_complain_t complaint; + bool complained; data_definition_t **data_list; int data_list_len; int bulk_size; @@ -185,7 +188,10 @@ if (host->sess_handle == NULL) return; - snmp_sess_close(host->sess_handle); + if( !snmp_sess_close(host->sess_handle)) + { + ERROR("snmp plugin: closing session handle failed"); + } host->sess_handle = NULL; } /* }}} void csnmp_host_close_session */ @@ -758,8 +764,8 @@ if (hd == NULL) return -1; hd->version = 2; - C_COMPLAIN_INIT(&hd->complaint); - + hd->complained = true; + status = cf_util_get_string(ci, &hd->name); if (status != 0) { sfree(hd); @@ -1608,6 +1614,156 @@ return 0; } /* int csnmp_dispatch_table */ + +#include +static int +snmp_synch_input(int op, + netsnmp_session * session, + int reqid, netsnmp_pdu *pdu, void *magic) +{ + struct synch_state *state = (struct synch_state *) magic; + int rpt_type; + + if (reqid != state->reqid && pdu && pdu->command != SNMP_MSG_REPORT) { + DEBUGMSGTL(("snmp_synch", "Unexpected response (ReqID: %d,%d - Cmd %d)\n", + reqid, state->reqid, pdu->command )); + return 0; + } + + state->waiting = 0; + DEBUGMSGTL(("snmp_synch", "Response (ReqID: %d - Cmd %d)\n", + reqid, (pdu ? pdu->command : -1))); + + if (op == NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE && pdu) { + if (pdu->command == SNMP_MSG_REPORT) { + rpt_type = snmpv3_get_report_type(pdu); + if (SNMPV3_IGNORE_UNAUTH_REPORTS || + rpt_type == SNMPERR_NOT_IN_TIME_WINDOW) { + state->waiting = 1; + } + state->pdu = NULL; + state->status = STAT_ERROR; + session->s_snmp_errno = rpt_type; + SET_SNMP_ERROR(rpt_type); + } else if (pdu->command == SNMP_MSG_RESPONSE) { + /* + * clone the pdu to return to snmp_synch_response + */ + state->pdu = snmp_clone_pdu(pdu); + state->status = STAT_SUCCESS; + session->s_snmp_errno = SNMPERR_SUCCESS; + } + else { + char msg_buf[50]; + state->status = STAT_ERROR; + session->s_snmp_errno = SNMPERR_PROTOCOL; + SET_SNMP_ERROR(SNMPERR_PROTOCOL); + snprintf(msg_buf, sizeof(msg_buf), "Expected RESPONSE-PDU but got %s-PDU", + snmp_pdu_type(pdu->command)); + snmp_set_detail(msg_buf); + return 0; + } + } else if (op == NETSNMP_CALLBACK_OP_TIMED_OUT) { + state->pdu = NULL; + state->status = STAT_TIMEOUT; + session->s_snmp_errno = SNMPERR_TIMEOUT; + SET_SNMP_ERROR(SNMPERR_TIMEOUT); + } else if (op == NETSNMP_CALLBACK_OP_DISCONNECT) { + state->pdu = NULL; + state->status = STAT_ERROR; + session->s_snmp_errno = SNMPERR_ABORT; + SET_SNMP_ERROR(SNMPERR_ABORT); + } + DEBUGMSGTL(("snmp_synch", "status = %d errno = %d\n", + state->status, session->s_snmp_errno)); + + return 1; +} + +int +snmp_sess_synch_response2(void *sessp, + netsnmp_pdu *pdu, netsnmp_pdu **response) +{ + netsnmp_session *ss; + struct synch_state lstate, *state; + snmp_callback cbsav; + void *cbmagsav; + int numfds, count; + netsnmp_large_fd_set fdset; + struct timeval timeout, *tvp; + int block; + + ss = snmp_sess_session(sessp); + if (ss == NULL) { + return STAT_ERROR; + } + + memset((void *) &lstate, 0, sizeof(lstate)); + state = &lstate; + cbsav = ss->callback; + cbmagsav = ss->callback_magic; + ss->callback = snmp_synch_input; + ss->callback_magic = (void *) state; + + if (snmp_sess_send(sessp, pdu) == 0) { + snmp_free_pdu(pdu); + state->status = STAT_ERROR; + } else { + state->waiting = 1; + state->reqid = pdu->reqid; + } + + netsnmp_large_fd_set_init(&fdset, FD_SETSIZE); + + while (state->waiting) { + numfds = 0; + NETSNMP_LARGE_FD_ZERO(&fdset); + block = NETSNMP_SNMPBLOCK; + tvp = &timeout; + timerclear(tvp); + snmp_sess_select_info2_flags(sessp, &numfds, &fdset, tvp, &block, + NETSNMP_SELECT_NOALARMS); + if (block == 1) + tvp = NULL; /* block without timeout */ +/// count = select(numfds, &fdset, NULL, NULL, tvp); + count = netsnmp_large_fd_set_select(numfds, &fdset, NULL, NULL, tvp); + if (count > 0) { + snmp_sess_read2(sessp, &fdset); + } else + switch (count) { + case 0: + snmp_sess_timeout(sessp); + break; + case -1: + if (errno == EINTR) { + continue; + } else { + snmp_errno = SNMPERR_GENERR; /*MTCRITICAL_RESOURCE */ + /* + * CAUTION! if another thread closed the socket(s) + * waited on here, the session structure was freed. + * It would be nice, but we can't rely on the pointer. + * ss->s_snmp_errno = SNMPERR_GENERR; + * ss->s_errno = errno; + */ + snmp_set_detail(strerror(errno)); + } + /* FALLTHRU */ + default: + state->status = STAT_ERROR; + state->waiting = 0; + } + } + *response = state->pdu; + ss->callback = cbsav; + ss->callback_magic = cbmagsav; + netsnmp_large_fd_set_cleanup(&fdset); + + return state->status; +} + + + static int csnmp_read_table(host_definition_t *host, data_definition_t *data) { struct snmp_pdu *req; struct snmp_pdu *res = NULL; @@ -1772,7 +1928,7 @@ } res = NULL; - status = snmp_sess_synch_response(host->sess_handle, req, &res); + status = snmp_sess_synch_response2(host->sess_handle, req, &res); /* snmp_sess_synch_response always frees our req PDU */ req = NULL; @@ -1782,9 +1938,9 @@ snmp_sess_error(host->sess_handle, NULL, NULL, &errstr); - c_complain(LOG_ERR, &host->complaint, - "snmp plugin: host %s: snmp_sess_synch_response failed: %s", - host->name, (errstr == NULL) ? "Unknown problem" : errstr); + host->complained = true; + ERROR("snmp plugin: host %s: snmp_sess_synch_response failed: %s", + host->name, (errstr == NULL) ? "Unknown problem" : errstr ); if (res != NULL) snmp_free_pdu(res); @@ -1799,9 +1955,13 @@ status = 0; assert(res != NULL); - c_release(LOG_INFO, &host->complaint, - "snmp plugin: host %s: snmp_sess_synch_response successful.", + + if(host->complained) + { + INFO("snmp plugin: host %s: snmp_sess_synch_response successful.", host->name); + host->complained = false; + } vb = res->variables; if (vb == NULL) { @@ -2151,7 +2311,7 @@ for (i = 0; i < data->values_len; i++) snmp_add_null_var(req, data->values[i].oid, data->values[i].oid_len); - status = snmp_sess_synch_response(host->sess_handle, req, &res); + status = snmp_sess_synch_response2(host->sess_handle, req, &res); if ((status != STAT_SUCCESS) || (res == NULL)) { char *errstr = NULL;