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

📄 snmp.xs

📁 ucd-snmp源代码
💻 XS
📖 第 1 页 / 共 5 页
字号:
   char		*label;   char		*iid;   bulktbl	*expect = NULL;   int		old_numeric;   int		old_printfull;   int		getlabel_flag;   int		type;   int		pix;   int		len;   int		i;   AV		*varbind;   SV		*rv;   SV		*sv_timestamp = NULL;   SV **sess_ptr_sv = hv_fetch((HV*)SvRV(context->sess_ref), "SessPtr", 7, 1);   struct snmp_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);   DBPRT(3, (DBOUT "bulkwalk: sess_ref = 0x%p, sess_ptr_sv = 0x%p, ss = 0x%p\n",					    context->sess_ref, sess_ptr_sv, ss));   if (SvIV(*hv_fetch((HV*)SvRV(context->sess_ref),"TimeStamp", 9, 1)))      sv_timestamp = newSViv((IV)time(NULL));   /* 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   = ds_get_boolean(DS_LIBRARY_ID, DS_LIB_PRINT_NUMERIC_OIDS);   old_printfull = ds_get_boolean(DS_LIBRARY_ID, DS_LIB_PRINT_FULL_OID);   if (context->getlabel_f & USE_NUMERIC_OIDS) {      DBPRT(2,( "Using numeric oid's\n"));      ds_set_boolean(DS_LIBRARY_ID, DS_LIB_PRINT_NUMERIC_OIDS, 1);      ds_set_boolean(DS_LIBRARY_ID, DS_LIB_PRINT_FULL_OID, 1);   }   /* 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,( "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, sprint_objid(_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,( "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",			   sprint_objid(_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",			sprint_objid(_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",		     sprint_objid(_debugx, context->req_oids[pix].req_oid,					   context->req_oids[pix].req_len),		     pix, context->non_reps));	 DBPRT(2, (DBOUT "   received var %s\n",		     sprint_objid(_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",	       sprint_objid(_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,( "      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 ((vars->name_length < expect->req_len) ||	     (memcmp(vars->name, expect->req_oid, expect->req_len*sizeof(oid))))	 {	    DBPRT(2,( "      walked off branch - marking subtree as complete.\n"));	    expect->complete = 1;	    context->req_remain --;	    continue;	 }	 /* Still interested in the tree -- we need to keep track of the	 ** last-seen value in case we need to send an additional request	 ** packet.	 */	 (void)memcpy(expect->last_oid, vars->name,					     vars->name_length * sizeof(oid));	 expect->last_len = vars->name_length;      }      /* Create a new Varbind and populate it with the parsed information      ** returned by the agent.  This Varbind is then pushed onto the arrays      ** maintained for each request OID in the context.  These varbinds are      ** collected into a return array by bulkwalk_finish().      */      varbind = (AV*) newAV();      if (varbind == NULL) {	 sv_setpv(*err_str_svp, "newAV() failed: ");	 sv_catpv(*err_str_svp, (char*)strerror(errno));	 sv_setiv(*err_num_svp, SNMPERR_MALLOC);	 goto err;      }      *str_buf = '.';      *(str_buf+1) = '\0';      tp = get_symbol(vars->name,vars->name_length, get_tree_head(), str_buf+1);      getlabel_flag = context->getlabel_f;      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);      DBPRT(2,( "       save var %s.%s = ", label, iid));      av_store(varbind, VARBIND_TAG_F, newSVpv(label, strlen(label)));      av_store(varbind, VARBIND_IID_F, newSVpv(iid, strlen(iid)));      __get_type_str(type, type_str);      av_store(varbind, VARBIND_TYPE_F, newSVpv(type_str, strlen(type_str)));      len=__sprint_value(str_buf, vars, tp, type, context->sprintval_f);      av_store(varbind, VARBIND_VAL_F, newSVpv((char*)str_buf, len));      str_buf[len] = '\0';      DBPRT(3,( "'%s' (%s)\n", str_buf, type_str));      /* If necessary, store a timestamp as the semi-documented 5th element. */      if (sv_timestamp)	  av_store(varbind, VARBIND_TIME_F, SvREFCNT_inc(sv_timestamp));      /* Push ref to the varbind onto the list of vars for OID. */      rv = newRV_noinc((SV *)varbind);      sv_bless(rv, gv_stashpv("SNMP::Varbind", 0));      av_push(expect->vars, rv);      context->oid_saved ++;	/* Count this as a saved variable. */   } /* next variable in response packet */   DBPRT(1, (DBOUT "-- pkt %d saw %d vars, total %d (%d saved)\n", context->pkts_exch,			   pix, context->oid_total, context->oid_saved));   /* We assert that all non-repeaters must be returned in   ** the initial response (they are not repeated in additional   ** packets, so would be dropped).  If nonrepeaters still   ** exist, consider it a fatal error.   */   if ((context->pkts_exch == 1) && (context->oid_saved < context->non_reps)) {      /* Re-use space from the value string for error message. */      sprintf(str_buf, "%d non-repeaters went unanswered", context->non_reps);      sv_setpv(*err_str_svp, str_buf);      sv_setiv(*err_num_svp, SNMPERR_GENERR);      sv_setiv(*err_num_svp, context->oid_saved);      goto err;   }   /* Reset the library's behavior for numeric/symbolic OID's. */   if (context->getlabel_f & USE_NUMERIC_OIDS) {      ds_set_boolean(DS_LIBRARY_ID, DS_LIB_PRINT_NUMERIC_OIDS, old_numeric);      ds_set_boolean(DS_LIBRARY_ID, DS_LIB_PRINT_FULL_OID, old_printfull);   }   return pix;   err:   if (pdu)      snmp_free_pdu(pdu);   return -1;}/* Once the bulkwalk has completed, extend the stack and push references to** each of the arrays of SNMP::Varbind's onto the stack.  Return the number** of arrays pushed on the stack.  The caller should return to Perl, or call** the Perl callback function.**** Note that this function free()'s the walk_context and request bulktbl's.*/static int_bulkwalk_finish(walk_context *context, int okay){   int		npushed = 0;   int		i;   int		async = 0;   bulktbl	*bt_entry;   AV		*ary = NULL;   SV		*rv;   SV		*perl_cb;   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);   dXSARGS;   async = SvTRUE(context->perl_cb);   /* Successfully completed the bulkwalk.  For synchronous calls, push each   ** of the request value arrays onto the stack, and return the number of   ** items pushed onto the stack.  For async, create a new array and push   ** the references onto it.  The array is then passed to the Perl callback.   */   if (!async)      SP -= items;   DBPRT(1, (DBOUT "Bulwalk %s (saved %d/%d), ", okay ? "completed" : "had error",					context->oid_saved, context->oid_total));   if (okay) {       DBPRT(1, (DBOUT "%s %d varbind refs %s\n",				async ? "pass ref to array of" : "return",				context->nreq_oids,				async ? "to callback" : "on stack to caller"));       /* Create the array to hold the responses for the asynchronous callback,       ** or pre-extend the stack enough to hold responses for synch return.       */       if (async) {	   ary = (AV *)newAV();	  if (ary == NULL) {	     sv_setpv(*err_str_svp, "newAV(): ");	     sv_catpv(*err_str_svp, (char *)strerror(errno));	     sv_setiv(*err_num_svp, errno);	  }	  /* NULL ary pointer is okay -- we'll handle it below... */       } else {	   EXTEND(sp, context->nreq_oids);       }       /* Push a reference to each array of varbinds onto the stack, in       ** the order requested.  Note that these arrays may be empty.       */       for (i = 0; i < context->nreq_oids; i++) {	  bt_entry = &context->req_oids[i];	  DBPRT(2, (DBOUT "  %sreq #%d (%s) => %d var%s\n",		 bt_entry->complete ? "" : "incomplete ", i,		 sprint_objid(_debugx, bt_entry->req_oid, bt_entry->req_len),		 (int)av_len(bt_entry->vars) + 1,		 (int)av_len(bt_entry->vars) > 0 ? "s" : ""));	  if (async && ary == NULL) {	     DBPRT(2,( "    [dropped due to newAV() failure]\n"));	     continue;	  }	  /* Get a reference to the varlist, and push it onto array or stack */	  rv = newRV_noinc((SV *)bt_entry->vars);	  sv_bless(rv, gv_stashpv("SNMP::VarList",0));	  if (async)	     av_push(ary, rv);	  else	     PUSHs(sv_2mortal((SV *)rv));	  npushed ++;       }   } else {	/* Not okay -- push a single undef on the stack if not async */      if (!async) {	 XPUSHs(&sv_undef);	 npushed = 1;      }   }   /* XXX Future enhancement -- make statistics (pkts exchanged, vars   ** saved vs. received, total time, etc) available to caller so they   ** can adjust their request parameters and/or re-order requests.   */   PUTBACK;   if (async) {       /* Asynchronous callback.  Push the caller's arglist onto the stack,       ** and follow it with the contents of the array (or undef if newAV()       ** failed 

⌨️ 快捷键说明

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