⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 snmp.xs

📁 snmp的源代码,已经在我的ubuntu下编译通过
💻 XS
📖 第 1 页 / 共 5 页
字号:
	       else		  done = _bulkwalk_done(context); /* Also set req ignore flags */	       break;	    }	    default:	    {	       DBPRT(1,(DBOUT "unexpected pdu->command %d\n", pdu->command));	       done = 1;   /* "This can't happen!", so bail out when it does. */	       break;	    }	 }	 break;      }      case NETSNMP_CALLBACK_OP_TIMED_OUT:      {	 DBPRT(1,(DBOUT "\n*** Timeout for reqid 0x%08X\n\n", reqid));         sv_setpv(*err_str_svp, (char*)snmp_api_errstring(SNMPERR_TIMEOUT));         sv_setiv(*err_num_svp, SNMPERR_TIMEOUT);	 /* Timeout means something bad has happened.  Return a not-okay	 ** result to the async callback.	 */	 npushed = _bulkwalk_finish(context, 0 /* NOT OKAY */);	 return 1;      }      default:      {	 DBPRT(1,(DBOUT "unexpected callback op %d\n", op));         sv_setpv(*err_str_svp, (char*)snmp_api_errstring(SNMPERR_GENERR));         sv_setiv(*err_num_svp, SNMPERR_GENERR);	 npushed = _bulkwalk_finish(context, 0 /* NOT OKAY */);	 return 1;      }   }   /* We have either timed out, or received and parsed in a response.  Now,   ** if we have more variables to test, call bulkwalk_send_pdu() to enqueue   ** another async packet, and return.   **   ** If, however, the bulkwalk has completed (or an error has occurred that   ** cuts the walk short), call bulkwalk_finish() to push the results onto   ** the Perl call stack.  Then explicitly call the Perl callback that was   ** passed in by the user oh-so-long-ago.   */   if (!done) {      DBPRT(1,(DBOUT "bulkwalk not complete -- send next pdu from callback\n"));      if (_bulkwalk_send_pdu(context) != NULL)	 return 1;      DBPRT(1,(DBOUT "send_pdu() failed!\n"));      /* Fall through and return what we have so far. */   }   /* Call the perl callback with the return values and we're done. */   npushed = _bulkwalk_finish(context, 1 /* OKAY */);   return 1;}static netsnmp_pdu *_bulkwalk_send_pdu(walk_context *context){   netsnmp_pdu *pdu = NULL;   netsnmp_pdu *response = NULL;   struct bulktbl  *bt_entry;   int	nvars = 0;   int	reqid;   int	status;   int	i;   /* Send a pdu requesting any remaining variables in the context.   **   ** In synchronous mode, returns a pointer to the response packet.   **   ** In asynchronous mode, it returns the request ID, cast to a struct snmp *,   **   not a valid SNMP response packet.  The async code should not be trying   **   to get variables out of this "response".   **   ** In either case, return a NULL pointer on error or failure.   */   SV **sess_ptr_sv = hv_fetch((HV*)SvRV(context->sess_ref), "SessPtr", 7, 1);   netsnmp_session *ss = (SnmpSession *)SvIV((SV*)SvRV(*sess_ptr_sv));   SV **err_str_svp = hv_fetch((HV*)SvRV(context->sess_ref), "ErrorStr", 8, 1);   SV **err_num_svp = hv_fetch((HV*)SvRV(context->sess_ref), "ErrorNum", 8, 1);   SV **err_ind_svp = hv_fetch((HV*)SvRV(context->sess_ref), "ErrorInd", 8, 1);   /* Create a new PDU and send the remaining set of requests to the agent. */   pdu = snmp_pdu_create(SNMP_MSG_GETBULK);   if (pdu == NULL) {      sv_setpv(*err_str_svp, "snmp_pdu_create(GETBULK) failed: ");      sv_catpv(*err_str_svp, strerror(errno));      sv_setiv(*err_num_svp, SNMPERR_MALLOC);      goto err;   }   /* Request non-repeater variables only in the first packet exchange. */   pdu->errstat  = (context->pkts_exch == 0) ? context->non_reps : 0;   pdu->errindex = context->max_reps;   for (i = 0; i < context->nreq_oids; i++) {      bt_entry = &context->req_oids[i];      if (bt_entry->ignore)	 continue;      assert(bt_entry->complete == 0);      if (!snmp_add_null_var(pdu, bt_entry->last_oid, bt_entry->last_len)) {	 sv_setpv(*err_str_svp, "snmp_add_null_var() failed");	 sv_setiv(*err_num_svp, SNMPERR_GENERR);	 sv_setiv(*err_ind_svp, i);	 goto err;      }      nvars ++;      DBPRT(1, (DBOUT "   Add %srepeater %s\n", bt_entry->norepeat ? "non" : "",	         snprint_objid(_debugx, sizeof(_debugx), bt_entry->last_oid, bt_entry->last_len)));   }   /* Make sure variables are actually being requested in the packet. */   assert (nvars != 0);   context->pkts_exch ++;   DBPRT(1, (DBOUT "Sending %ssynchronous request %d...\n",		     SvTRUE(context->perl_cb) ? "a" : "", context->pkts_exch));   /* We handle the asynchronous and synchronous requests differently here.   ** For async, we simply enqueue the packet with a callback to handle the   ** returned response, then return.  Note that this we call the bulkwalk   ** callback, and hand it the walk_context, not the Perl callback.  The   ** snmp_async_send() function returns the reqid on success, 0 on failure.   */   if (SvTRUE(context->perl_cb)) {      reqid = snmp_async_send(ss, pdu, _bulkwalk_async_cb, (void *)context);      DBPRT(2,(DBOUT "bulkwalk_send_pdu(): snmp_async_send => 0x%08X\n", reqid));      if (reqid == 0) {	 sv_setpv(*err_str_svp, (char*)snmp_api_errstring(ss->s_snmp_errno));	 sv_setiv(*err_num_svp, ss->s_snmp_errno);	 goto err;      }      /* Make a note of the request we expect to be answered. */      context->exp_reqid = reqid;      /* Callbacks take care of the rest.  Let the caller know how many vars      ** we sent in this request.  Note that this is not a valid SNMP PDU,      ** but that's because a response has not yet been received.      */      return (netsnmp_pdu *)reqid;   }   /* This code is for synchronous mode support.   **   ** Send the PDU and block awaiting the response.  Return the response   ** packet back to the caller.  Note that snmp_sess_read() frees the pdu.   */   status = __send_sync_pdu(ss, pdu, &response, NO_RETRY_NOSUCH,				    *err_str_svp, *err_num_svp, *err_ind_svp);   pdu = NULL;   /* Check for a failed request.  __send_sync_pdu() will set the appropriate   ** values in the error string and number SV's.   */   if (status != STAT_SUCCESS) {      DBPRT(1,(DBOUT "__send_sync_pdu() -> %d\n",(int)status));      goto err;   }   DBPRT(1, (DBOUT "%d packets exchanged, response 0x%p\n", context->pkts_exch,								    response));   return response;   err:   if (pdu)      snmp_free_pdu(pdu);   return NULL;}/* Handle an incoming GETBULK response PDU.  This function just pulls the** variables off of the PDU and builds up the arrays of returned values** that are stored in the context.**** Returns the number of variables found in this packet, or -1 on error.** Note that the caller is expected to free the pdu.*/static int_bulkwalk_recv_pdu(walk_context *context, netsnmp_pdu *pdu){   netsnmp_variable_list *vars;   struct tree	*tp;   char		type_str[MAX_TYPE_NAME_LEN];   u_char	str_buf[STR_BUF_SIZE], *str_bufp = str_buf;   size_t str_buf_len = sizeof(str_buf);   size_t out_len = 0;   int buf_over = 0;   char		*label;   char		*iid;   bulktbl	*expect = NULL;   int		old_numeric;   int		old_printfull;   int		old_format;   int		getlabel_flag;   int		type;   int		pix;   int		len;   int		i;   AV		*varbind;   SV		*rv;   SV **sess_ptr_sv = hv_fetch((HV*)SvRV(context->sess_ref), "SessPtr", 7, 1);   SV **err_str_svp = hv_fetch((HV*)SvRV(context->sess_ref), "ErrorStr", 8, 1);   SV **err_num_svp = hv_fetch((HV*)SvRV(context->sess_ref), "ErrorNum", 8, 1);   SV **err_ind_svp = hv_fetch((HV*)SvRV(context->sess_ref), "ErrorInd", 8, 1);   DBPRT(3, (DBOUT "bulkwalk: sess_ref = 0x%p, sess_ptr_sv = 0x%p\n",             context->sess_ref, sess_ptr_sv));   /* 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);   old_format = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT);   if (context->getlabel_f & USE_NUMERIC_OIDS) {      DBPRT(2,(DBOUT "Using numeric oid's\n"));      netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS, 1);      netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_FULL_OID, 1);      netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, NETSNMP_OID_OUTPUT_NUMERIC);   }   /* Parse through the list of variables returned, adding each return to   ** the appropriate array (as a VarBind).  Also keep track of which   ** repeated OID we're expecting to see, and check if that tree walk has   ** been completed (i.e. we've walked past the root of our request).  If   ** so, mark the request complete so that we don't send it again in any   ** subsequent request packets.   */   if (context->pkts_exch == 1)      context->reqbase = context->req_oids;	/* Request with non-repeaters */   else      context->reqbase = context->repbase;	/* Request only repeater vars */   /* Note the first variable we expect to see.  Should be reqbase. */   expect = context->reqbase;   for (vars = pdu->variables, pix = 0;	vars != NULL;	vars = vars->next_variable, pix ++)   {      /* If no outstanding requests remain, we're done.  This works, but it      ** causes the reported total variable count to be wrong (since the      ** remaining vars on the last packet are not counted).  In practice      ** this is probably worth the win, but for debugging it's not.      */      if (context->req_remain == 0) {	 DBPRT(2,(DBOUT "No outstanding requests remain.  Terminating processing.\n"));	 while (vars) {	    pix ++;	    vars = vars->next_variable;	 }	 break;      }      /* Determine which OID we expect to see next.  We assert that the OID's      ** must be returned in the expected order.  The first nreq_oids returns      ** should match the req_oids array, after that, we must cycle through      ** the repeaters in order.  Non-repeaters are not included in later      ** packets, so cannot have the "ignore" flag set.      */      if (context->oid_saved < context->non_reps) {	 assert(context->pkts_exch == 1);	 expect = context->reqbase ++;	 assert(expect->norepeat);      } else {	 /* Must be a repeater.  Look for the first one that is not being	 ** ignored.  Make sure we don't loop around to where we started.	 ** If we get here but everything is being ignored, there's a problem.	 **	 ** Note that we *do* accept completed but not ignored OID's -- these	 ** are OID's for trees that have been completed sometime in this	 ** response, but must be looked at to maintain ordering.	 */	 if (pix == 0) {	    /* Special case code for no non-repeater case.  This	    ** is necessary because expect normally points to the	    ** last non-repeater upon entry to this code (so the	    ** '++expect' below increments it into the repeaters	    ** section of the req_oids[] array).	    ** If there are no non-repeaters, the expect pointer	    ** is never initialized.  This addresses this problem.	    */	    expect = context->reqbase;	 } else {	    /* Find the repeater OID we expect to see.  Ignore any	    ** OID's marked 'ignore' -- these have been completed	    ** and were not requested in this iteration.	    */	    for (i = 0; i < context->repeaters; i++) {	       /* Loop around to first repeater if we hit the end. */	       if (++ expect == &context->req_oids[context->nreq_oids])		  expect = context->reqbase = context->repbase;	       /* Stop if this OID is not being ignored. */	       if (!expect->ignore)		  break;	    }	    /* Make sure we did find an expected OID. */	    assert(i <= context->repeaters);	 }      }      DBPRT(2, (DBOUT "Var %03d request %s\n", pix, snprint_objid(_debugx, sizeof(_debugx), 					     expect->req_oid, expect->req_len)));      /* Did we receive an error condition for this variable?      ** If it's a repeated variable, mark it as complete and      ** fall through to the block below.      */      if ((vars->type == SNMP_ENDOFMIBVIEW) ||	  (vars->type == SNMP_NOSUCHOBJECT) ||	  (vars->type == SNMP_NOSUCHINSTANCE))      {	 DBPRT(2,(DBOUT "error type %d\n", (int)vars->type));	 /* ENDOFMIBVIEW should be okay for a repeater - just walked off the	 ** end of the tree.  Mark the request as complete, and go on to the	 ** next one.	 */	 if ((context->oid_saved >= context->non_reps) &&	     (vars->type == SNMP_ENDOFMIBVIEW))	 {	    expect->complete = 1;	    DBPRT(2, (DBOUT "Ran out of tree for oid %s\n",			   snprint_objid(_debugx, sizeof(_debugx), vars->name,vars->name_length)));	    context->req_remain --;	    /* Go on to the next variable. */	    continue;	 }	 sv_setpv(*err_str_svp,			      (char*)snmp_api_errstring(SNMPERR_UNKNOWN_OBJID));	 sv_setiv(*err_num_svp, SNMPERR_UNKNOWN_OBJID);	 sv_setiv(*err_ind_svp, pix);	 goto err;      }      /* If this is not the first packet, skip any duplicated OID values, if      ** present.  These should be the seed values copied from the last OID's      ** of the previous packet.  In practice we don't see this, but it is      ** easy enough to do, and will avoid confusion for the caller from mis-      ** behaving agents (badly misbehaving... ;^).      */      if ((context->pkts_exch > 1) && (pix < context->repeaters)) {	 if (__oid_cmp(vars->name, vars->name_length,				   context->reqbase[pix].last_oid,				   context->reqbase[pix].last_len) == 0)	 {	    DBPRT(2, (DBOUT "Ignoring repeat oid: %s\n",			snprint_objid(_debugx, sizeof(_debugx), vars->name,vars->name_length)));	    continue;	 }      }      context->oid_total ++;	/* Count each variable received. */      /* If this is a non-repeater, handle it.  Otherwise, if it is a      ** repeater, has the walk wandered off of the requested tree?  If so,      ** this request is complete, so mark it as such.  Ignore any other      ** variables in a completed request.  In order to maintain the correct      ** ordering of which variables we expect to see in this packet, we must      ** not set the ignore flags immediately.  It is done in bulkwalk_done().      ** XXX Can we use 'expect' instead of 'context->req_oids[pix]'?      */      if (context->oid_saved < context->non_reps) {	 DBPRT(2, (DBOUT "   expected var %s (nonrepeater %d/%d)\n",		     snprint_objid(_debugx, sizeof(_debugx), context->req_oids[pix].req_oid,					   context->req_oids[pix].req_len),		     pix, context->non_reps));	 DBPRT(2, (DBOUT "   received var %s\n",		     snprint_objid(_debugx, sizeof(_debugx), vars->name, vars->name_length)));	 /* This non-repeater has now been seen, so mark the sub-tree as	 ** completed.  Note that this may not be the same oid as requested,	 ** since non-repeaters act like GETNEXT requests, not GET's. <sigh>	 */	 context->req_oids[pix].complete = 1;	 context->req_remain --;      } else {		/* Must be a repeater variable. */	 DBPRT(2, (DBOUT "   received oid %s\n",	       snprint_objid(_debugx, sizeof(_debugx), vars->name, vars->name_length)));	 /* Are we already done with this tree?  If so, just ignore this	 ** variable and move on to the next expected variable.	 */	 if (expect->complete) {	    DBPRT(2,(DBOUT "      this branch is complete - ignoring.\n"));	    continue;	 }	 /* If the base oid of this variable doesn't match the expected oid,	 ** assume that we've walked past the end of the subtree.  Set this	 ** subtree to be completed, and go on to the next variable.	 */	 if (((int)vars->name_length < expect->req_len) ||	     (memcmp(vars->name, expect

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -