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

📄 snmp.xs

📁 ucd-snmp源代码
💻 XS
📖 第 1 页 / 共 5 页
字号:
   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,( "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,( "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", 	      sprint_objid(_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,		  struct snmp_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,( "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,             ("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 RECEIVED_MESSAGE:      {	 DBPRT(1,( "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;	       else		  done = _bulkwalk_done(context); /* Also set req ignore flags */	       break;	    }	    default:	    {	       DBPRT(1,( "unexpected pdu->command %d\n", pdu->command));	       done = 1;   /* "This can't happen!", so bail out when it does. */	       break;	    }	 }	 break;      }      case TIMED_OUT:      {	 DBPRT(1,( "\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,( "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,( "bulkwalk not complete -- send next pdu from callback\n"));      if (_bulkwalk_send_pdu(context) != NULL)	 return 1;      DBPRT(1,( "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 struct snmp_pdu *_bulkwalk_send_pdu(walk_context *context){   struct snmp_pdu *pdu = NULL;   struct snmp_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);   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);   /* 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" : "",	         sprint_objid(_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,( "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 (struct snmp_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,( "__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, struct snmp_pdu *pdu){   struct variable_list *vars;   struct tree	*tp;   char		type_str[MAX_TYPE_NAME_LEN];   char		str_buf[STR_BUF_SIZE];

⌨️ 快捷键说明

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