📄 snmp.xs
字号:
* Ideally, we would use the return value from the callback to * decide what response, if any, we send, and what the error status * and error index should be. */ reply_pdu = snmp_clone_pdu(pdu); if (reply_pdu) { reply_pdu->command = SNMP_MSG_RESPONSE; reply_pdu->reqid = pdu->reqid; reply_pdu->errstat = reply_pdu->errindex = 0; snmp_send(ss, reply_pdu); } else { warn("Couldn't clone PDU for inform response"); } /* FALLTHRU */ case SNMP_MSG_TRAP2: traplist = newAV(); traplist_ref = newRV_noinc((SV*)traplist);#if 0 /* of dubious utility... */ av_push(traplist, newSViv(pdu->command));#endif av_push(traplist, newSViv(pdu->reqid)); if ((transport = snmp_sess_transport(snmp_sess_pointer(ss))) != NULL) { cp = transport->f_fmtaddr(transport, pdu->transport_data, pdu->transport_data_length); av_push(traplist, newSVpv(cp, strlen(cp))); free(cp); } else { /* This shouldn't ever happen; every session has a transport. */ av_push(traplist, newSVpv("", 0)); } av_push(traplist, newSVpv((char*) pdu->community, pdu->community_len)); /* FALLTHRU */ case SNMP_MSG_RESPONSE: { varlist = newAV(); varlist_ref = newRV_noinc((SV*)varlist); /* ** Set up for numeric OID's, if necessary. Save the old values ** so that they can be restored when we finish -- these are ** library-wide globals, and have to be set/restored for each ** session. */ old_numeric = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS); old_printfull = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_FULL_OID); if (SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseLongNames", 12, 1))) { getlabel_flag |= USE_LONG_NAMES; netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_FULL_OID, 1); } /* Setting UseNumeric forces UseLongNames on so check for UseNumeric after UseLongNames (above) to make sure the final outcome of NETSNMP_DS_LIB_OID_OUTPUT_FORMAT is NETSNMP_OID_OUTPUT_NUMERIC */ if (SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseNumeric", 10, 1))) { getlabel_flag |= USE_NUMERIC_OIDS; netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS, 1); } sv_bless(varlist_ref, gv_stashpv("SNMP::VarList",0)); for(vars = (pdu?pdu->variables:NULL); vars; vars = vars->next_variable) { varbind = newAV(); varbind_ref = newRV_noinc((SV*)varbind); sv_bless(varbind_ref, gv_stashpv("SNMP::Varbind",0)); av_push(varlist, varbind_ref); *str_buf = '.'; *(str_buf+1) = '\0'; out_len = 0; tp = netsnmp_sprint_realloc_objid_tree(&str_bufp, &str_buf_len, &out_len, 0, &buf_over, vars->name,vars->name_length); str_buf[sizeof(str_buf)-1] = '\0'; if (__is_leaf(tp)) { type = tp->type; } else { getlabel_flag |= NON_LEAF_NAME; type = __translate_asn_type(vars->type); } __get_label_iid(str_buf,&label,&iid,getlabel_flag); if (label) { av_store(varbind, VARBIND_TAG_F, newSVpv(label, strlen(label))); } else { av_store(varbind, VARBIND_TAG_F, newSVpv("", 0)); } if (iid) { av_store(varbind, VARBIND_IID_F, newSVpv(iid, strlen(iid))); } else { av_store(varbind, VARBIND_IID_F, newSVpv("", 0)); } __get_type_str(type, tmp_type_str); tmp_sv = newSVpv(tmp_type_str, strlen(tmp_type_str)); av_store(varbind, VARBIND_TYPE_F, tmp_sv); len = __snprint_value(str_buf, sizeof(str_buf), vars, tp, type, sprintval_flag); tmp_sv = newSVpv((char*)str_buf, len); av_store(varbind, VARBIND_VAL_F, tmp_sv); } /* for */ /* Reset the library's behavior for numeric/symbolic OID's. */ netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS, old_numeric ); netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_FULL_OID, old_printfull); } /* case SNMP_MSG_RESPONSE */ break; default:; } /* switch pdu->command */ break; case NETSNMP_CALLBACK_OP_TIMED_OUT: varlist_ref = &sv_undef; break; default:; } /* switch op */ sv_2mortal(cb); cb = __push_cb_args2(cb, (SvTRUE(varlist_ref) ? sv_2mortal(varlist_ref):varlist_ref), (SvTRUE(traplist_ref) ? sv_2mortal(traplist_ref):traplist_ref)); __call_callback(cb, G_DISCARD); FREETMPS; LEAVE; sv_2mortal(sess_ref); return 1;}static SV *__push_cb_args2(sv,esv,tsv)SV *sv;SV *esv;SV *tsv;{ dSP; if (SvTYPE(SvRV(sv)) != SVt_PVCV) sv = SvRV(sv); PUSHMARK(sp); if (SvTYPE(sv) == SVt_PVAV) { AV *av = (AV *) sv; int n = av_len(av) + 1; SV **x = av_fetch(av, 0, 0); if (x) { int i = 1; sv = *x; for (i = 1; i < n; i++) { x = av_fetch(av, i, 0); if (x) { SV *arg = *x; XPUSHs(sv_mortalcopy(arg)); } else { XPUSHs(&sv_undef); } } } else { sv = &sv_undef; } } if (esv) XPUSHs(sv_mortalcopy(esv)); if (tsv) XPUSHs(sv_mortalcopy(tsv)); PUTBACK; return sv;}static int__call_callback(sv, flags)SV *sv;int flags;{ dSP; I32 myframe = TOPMARK; I32 count; ENTER; if (SvTYPE(sv) == SVt_PVCV) { count = perl_call_sv(sv, flags); } else if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVCV) { count = perl_call_sv(SvRV(sv), flags); } else { SV **top = stack_base + myframe + 1; SV *obj = *top; if (SvPOK(sv) && SvROK(obj) && SvOBJECT(SvRV(obj))) { count = perl_call_method(SvPV(sv, na), flags); } else if (SvPOK(obj) && SvROK(sv) && SvOBJECT(SvRV(sv))) { /* We have obj method ... Used to be used instead of LangMethodCall() */ *top = sv; count = perl_call_method(SvPV(obj, na), flags); } else { count = perl_call_sv(sv, flags); } } LEAVE; return count;}/* Bulkwalk support routines *//* Add a context pointer to the list of valid pointers. Place it in the first** NULL slot in the array.*/static int_context_add(walk_context *context){ int i, j, new_sz; if ((i = _context_okay(context)) != 0) /* Already exists? Okay. */ return i; /* Initialize the array if necessary. */ if (_valid_contexts == NULL) { /* Create the _valid_contexts structure. */ Newz(0, _valid_contexts, 1, struct valid_contexts); assert(_valid_contexts != NULL); /* Populate the original valid contexts array. */ Newz(0, _valid_contexts->valid, 4, walk_context *); assert(_valid_contexts->valid != NULL); /* Computer number of slots in the array. */ _valid_contexts->sz_valid = sizeof(*_valid_contexts->valid) / sizeof(walk_context *); for (i = 0; i < _valid_contexts->sz_valid; i++) _valid_contexts->valid[i] = NULL; DBPRT(3, (DBOUT "Created valid_context array 0x%p (%d slots)\n", _valid_contexts->valid, _valid_contexts->sz_valid)); } /* Search through the list, looking for NULL's -- unused slots. */ for (i = 0; i < _valid_contexts->sz_valid; i++) if (_valid_contexts->valid[i] == NULL) break; /* Did we walk off the end of the list? Need to grow the list. Double ** it for now. */ if (i == _valid_contexts->sz_valid) { new_sz = _valid_contexts->sz_valid * 2; Renew(_valid_contexts->valid, new_sz, walk_context *); assert(_valid_contexts->valid != NULL); DBPRT(3, (DBOUT "Resized valid_context array 0x%p from %d to %d slots\n", _valid_contexts->valid, _valid_contexts->sz_valid, new_sz)); _valid_contexts->sz_valid = new_sz; /* Initialize the new half of the resized array. */ for (j = i; j < new_sz; j++) _valid_contexts->valid[j] = NULL; } /* Store the context pointer in the array and return 0 (success). */ _valid_contexts->valid[i] = context; DBPRT(3,(DBOUT "Add context 0x%p to valid context list\n", context)); return 0;}/* Remove a context pointer from the valid list. Replace the pointer with** NULL in the valid pointer list.*/static int_context_del(walk_context *context){ int i; if (_valid_contexts == NULL) /* Make sure it was initialized. */ return 1; for (i = 0; i < _valid_contexts->sz_valid; i++) { if (_valid_contexts->valid[i] == context) { DBPRT(3,(DBOUT "Remove context 0x%p from valid context list\n", context)); _valid_contexts->valid[i] = NULL; /* Remove it from the list. */ return 0; /* Return successful status. */ } } return 1;}/* Check if a specific context pointer is in the valid list. Return true (1)** if the context is still in the valid list, or 0 if not (or context is NULL).*/static int_context_okay(walk_context *context){ int i; if (_valid_contexts == NULL) /* Make sure it was initialized. */ return 0; if (context == NULL) /* Asked about a NULL context? Fail. */ return 0; for (i = 0; i < _valid_contexts->sz_valid; i++) if (_valid_contexts->valid[i] == context) return 1; /* Found it! */ return 0; /* No match -- return failure. */}/* Check if the walk is completed, based upon the context. Also set the** ignore flag on any completed variables -- this prevents them from being** being sent in later packets.*/static int_bulkwalk_done(walk_context *context){ int is_done = 1; int i; bulktbl *bt_entry; /* bulktbl requested OID entry */ /* Don't consider walk done until at least one packet has been exchanged. */ if (context->pkts_exch == 0) return 0; /* Fix up any requests that have completed. If the complete flag is set, ** or it is a non-repeater OID, set the ignore flag so that it will not ** be considered further. Assume we are done with the walk, and note ** otherwise if we aren't. Return 1 if all requests are complete, or 0 ** if there's more to do. */ for (i = 0; i < context->nreq_oids; i ++) { bt_entry = &context->req_oids[i]; if (bt_entry->complete || bt_entry->norepeat) { /* This request is complete. Remove it from list of ** walks still in progress. */ DBPRT(1, (DBOUT "Ignoring %s request oid %s\n", bt_entry->norepeat? "nonrepeater" : "completed", snprint_objid(_debugx, sizeof(_debugx), bt_entry->req_oid, bt_entry->req_len))); /* Ignore this OID in any further packets. */ bt_entry->ignore = 1; } /* If any OID is not being ignored, the walk is not done. Must loop ** through all requests to do the fixup -- no early return possible. */ if (!bt_entry->ignore) is_done = 0; } return is_done; /* Did the walk complete? */}/* Callback registered with SNMP. Return 1 from this callback to cause the** current request to be deleted from the retransmit queue.*/static int_bulkwalk_async_cb(int op, SnmpSession *ss, int reqid, netsnmp_pdu *pdu, void *context_ptr){ walk_context *context; int done = 0; int npushed; SV **err_str_svp; SV **err_num_svp; /* Handle callback request for asynchronous bulkwalk. If the bulkwalk has ** not completed, and has not timed out, send the next request packet in ** the walk. ** ** Return 0 to indicate success (caller ignores return value). */ DBPRT(2, (DBOUT "bulkwalk_async_cb(op %d, reqid 0x%08X, context 0x%p)\n", op, reqid, context_ptr)); context = (walk_context *)context_ptr; /* Make certain this is a valid context pointer. This pdu may ** have been retransmitted after the bulkwalk was completed ** (and the context was destroyed). If so, just return. */ if (!_context_okay(context)) { DBPRT(2,(DBOUT "Ignoring PDU for dead context 0x%p...\n", context)); return 1; } /* Is this a retransmission of a request we've already seen or some ** unexpected request id? If so, just ignore it. */ if (reqid != context->exp_reqid) { DBPRT(2, (DBOUT "Got reqid 0x%08X, expected reqid 0x%08X. Ignoring...\n", reqid, context->exp_reqid)); return 1; } /* Ignore any future packets for this reqid. */ context->exp_reqid = -1; err_str_svp = hv_fetch((HV*)SvRV(context->sess_ref), "ErrorStr", 8, 1); err_num_svp = hv_fetch((HV*)SvRV(context->sess_ref), "ErrorNum", 8, 1); switch (op) { case NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE: { DBPRT(1,(DBOUT "Received message for reqid 0x%08X ...\n", reqid)); switch (pdu->command) { case SNMP_MSG_RESPONSE: { DBPRT(2, (DBOUT "Calling bulkwalk_recv_pdu(context 0x%p, pdu 0x%p)\n", context_ptr, pdu)); /* Handle the response PDU. If an error occurs or there were ** no variables in the response, consider the walk done. If ** the response was okay, check if we have any more to do after ** this response. */ if (_bulkwalk_recv_pdu(context, pdu) <= 0) done = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -