Exemplo n.º 1
0
/* report the value interfaces.ifNumber.0, actually the number of interfaces */
static int snmp_get_ifcount(struct snmp_session *ss) {
  int nifaces = -1;
  oid ifcount[] = { 1, 3, 6, 1, 2, 1, 2, 1, 0 };
  struct snmp_pdu *pdu;
  struct snmp_pdu *response = NULL;
  int status;

  if ((pdu = snmp_pdu_create(SNMP_MSG_GET)) == NULL) {
    ifstat_error("snmp_pdu_create: %s", snmp_api_errstring(snmp_errno));
    return -1;
  }

  snmp_add_null_var(pdu, ifcount, sizeof(ifcount) / sizeof(oid));

  if ((status = snmp_synch_response(ss, pdu, &response)) != STAT_SUCCESS ||
      response->errstat != SNMP_ERR_NOERROR ||
      response->variables == NULL ||
      response->variables->type != ASN_INTEGER) {
    if (status == STAT_SUCCESS)
      ifstat_error("snmp: Error: %s", snmp_errstring(response->errstat));
    else
      ifstat_error("snmpget(interfaces.ifNumber.0): %s", snmp_sess_errstring(ss));
    if (response)
      snmp_free_pdu(response);
    return -1;
  }
  nifaces = *(response->variables->val.integer);
  snmp_free_pdu(response);  
  
  if (nifaces < 0)
    return -1;
  return nifaces;
}
Exemplo n.º 2
0
v8::Handle<v8::Value> Session::sendNativePdu(const v8::Arguments& args) {
    UNWRAP(Session, wrap, args.This());
    SwapScope scope(wrap, args);
    if(0 == wrap->session_) {
        return ThrowError("Session hasn't opened.");
    }

    if(2 != args.Length()) {
        return ThrowError("Must pass pdu and cb arguments to sendNativePdu.");
    }

    v8::Handle<v8::Object> cb = args[1]->ToObject();
    if (!cb->IsCallable()) {
        return ThrowError("Must pass pdu and cb arguments to sendNativePdu.");
    }

    UNWRAP(Pdu, pdu, args[0]->ToObject());

	std::auto_ptr<netsnmp_pdu> copy(pdu->is_owner()? pdu->release() : snmp_clone_pdu(pdu->native()));
    std::auto_ptr<Callable> callable(new Callable(cb, args[0], copy.get()));
    if(0 == snmp_sess_async_send(wrap->session_, copy.get(),
                                 Callable::OnEvent, callable.get())) {
        return ThrowError(snmp_api_errstring(wrap->arguments_.s_snmp_errno));
    }
    callable.release();
    copy.release();

    if(scope.hasException()) {
        return scope.getException();
    }
    return v8::Undefined();
}
Exemplo n.º 3
0
v8::Handle<v8::Value> Session::Open(const v8::Arguments& args) {
    UNWRAP(Session, wrap, args.This());
    SwapScope scope(wrap, args);
    if(0 != wrap->session_) {
        return ThrowError("Session already opened.");
    }
    wrap->session_ = snmp_sess_open(&wrap->arguments_);
    if(0 == wrap->session_) {
        return ThrowError(snmp_api_errstring(wrap->arguments_.s_snmp_errno));
    }
    if(scope.hasException()) {
        return scope.getException();
    }
    return v8::Undefined();
}
Exemplo n.º 4
0
void get_netsnmp_error( netsnmp_session *session, CString *errstr )
{
    int sys_errno, snmp_errno;
    int winsockerr;
    
    winsockerr = WSAGetLastError();

    /* Don't bother with error string to snmp_error() since it doesn't
     * return snmp_detail[]. errno is mostly useless with WinSock but get
     * it anyway.
     */
    snmp_error( session, &sys_errno, &snmp_errno, NULL );

    /* FIXME - snmp_api_errstring() is not threadsafe */
    *errstr = snmp_api_errstring( snmp_errno );
}
Exemplo n.º 5
0
v8::Handle<v8::Value> Session::onData(const v8::Arguments& args) {

    fd_set fdset;
    struct timeval timeout;
    int block = 1;
    int numfds = 0;

    UNWRAP(Session, wrap, args.This());
    SwapScope scope(wrap, args);
    if(0 == wrap->session_) {
        return ThrowError("Session hasn't opened.");
    }

    if(2 != args.Length()) {
        return ThrowError("Must pass the msg and rinfo arguments to onData.");
    }

    FD_ZERO(&fdset);

    /**
    * block input:  set to 1 if input timeout value is undefined
    * set to 0 if input timeout value is defined
    * block output: set to 1 if output timeout value is undefined
    * set to 0 if output rimeout vlaue id defined
    */
    if(1 != snmp_sess_select_info(wrap->session_, &numfds, &fdset,
                                  &timeout, &block)) {
        return v8::Undefined();
    }


    if(-1 == snmp_sess_read(wrap->session_, &fdset)) {
        return ThrowError(snmp_api_errstring(wrap->arguments_.s_snmp_errno));
    }

    if(0 == block) {
        v8::Handle<v8::Object> ret = v8::Object::New();
        v8::Handle<v8::Object> timeout_v8 = v8::Object::New();
        timeout_v8->Set(tv_sec_symbol,  from_long(timeout.tv_sec));
        timeout_v8->Set(tv_usec_symbol, from_long(timeout.tv_usec));
        ret->Set(timeout_symbol, timeout_v8);
        return scope.Close(ret);
    } else {
        return v8::Undefined();
    }
}
Exemplo n.º 6
0
static int snmp_get_nextif(struct snmp_session *ss, int index) {
  oid ifindex[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 1, 0 };
  int len = sizeof(ifindex) / sizeof(oid);
  struct snmp_pdu *pdu;
  struct snmp_pdu *response = NULL;
  struct variable_list *vars;
  int status;

  if (index >= 0)
    ifindex[len - 1] = index;

  if ((pdu = snmp_pdu_create(SNMP_MSG_GETNEXT)) == NULL) {
    ifstat_error("snmp_pdu_create: %s", snmp_api_errstring(snmp_errno));
    return -1;
  }

  snmp_add_null_var(pdu, ifindex, (index < 0) ? len - 1 : len);

  if ((status = snmp_synch_response(ss, pdu, &response)) != STAT_SUCCESS ||
      response->errstat != SNMP_ERR_NOERROR ||
      response->variables == NULL) {
    if (status == STAT_SUCCESS) 
      ifstat_error("snmp: Error: %s", snmp_errstring(response->errstat));
    else
      ifstat_error("snmpgetnext(interfaces.ifTable.ifEntry.ifIndex...): %s",
		   snmp_sess_errstring(ss));
    if (response != NULL)
      snmp_free_pdu(response);
    return -1;
  }

  for(vars = response->variables; vars; vars = vars->next_variable) {
    /* check that the variable is under the base oid */
    if (vars->name_length != len)
      continue;
    if (memcmp(ifindex, vars->name, sizeof(ifindex) - sizeof(oid)) != 0)
      continue;

    index = vars->name[vars->name_length - 1];
    snmp_free_pdu(response);
    return index;
  }
  snmp_free_pdu(response);
  return -1;
}
Exemplo n.º 7
0
v8::Handle<v8::Value> Session::readData(const v8::Arguments& args) {

    fd_set fdset;
    struct timeval timeout;
    int block = 1;
    int numfds = 0;

    v8::HandleScope scope;
    UNWRAP(Session, wrap, args.This());
    if(0 == wrap->session_) {
        return ThrowError("Session hasn't opened.");
    }

    if(0 != args.Length()) {
        return ThrowError("Must not pass any arguments to readData.");
    }

    FD_ZERO(&fdset);

    /**
    * block input:  set to 1 if input timeout value is undefined
    * set to 0 if input timeout value is defined
    * block output: set to 1 if output timeout value is undefined
    * set to 0 if output rimeout vlaue id defined
    */
    if(0 == snmp_sess_select_info(wrap->session_, &numfds, &fdset,
		&timeout, &block)) {
		snmp_sess_timeout(wrap->session_);
		goto error;
	}

	if(0 == block) {
		int ret = select(numfds, &fdset, 0, 0, &timeout);
		if(SOCKET_ERROR == ret || 0 == ret) {
			snmp_sess_timeout(wrap->session_);
			goto error;
		}
	}

    if(-1 == snmp_sess_read(wrap->session_, &fdset)) {
        return ThrowError(snmp_api_errstring(wrap->arguments_.s_snmp_errno));
    }
error:
    return v8::Undefined();
}
Exemplo n.º 8
0
v8::Handle<v8::Value> Session::sendPdu(const v8::Arguments& args) {
    UNWRAP(Session, wrap, args.This());
    SwapScope scope(wrap, args);
    if(0 == wrap->session_) {
        return ThrowError("Session hasn't opened.");
    }

    if(2 != args.Length()) {
        return ThrowError("Must pass pdu and cb arguments to sendPdu.");
    }

    v8::Handle<v8::Object> cb = args[1]->ToObject();
    if (!cb->IsCallable()) {
        return ThrowError("Must pass pdu and cb arguments to sendPdu.");
    }

    std::auto_ptr<netsnmp_pdu> pdu(snmp_pdu_create(SNMP_MSG_GET));
    v8::Handle<v8::Value> ret = Pdu::toPdu(args[0], pdu.get());
    if(!ret->IsUndefined()) {
        return ret;
    }


    std::auto_ptr<Callable> callable(new Callable(cb, args[0], pdu.get()));

    if(0 != snmp_sess_async_send(wrap->session_, pdu.get(),
                                 Callable::OnEvent, callable.get())) {
        return ThrowError(snmp_api_errstring(wrap->arguments_.s_snmp_errno));
    }
    callable.release();
    pdu.release();

    if(scope.hasException()) {
        return scope.getException();
    }
    return v8::Undefined();
}
// Pack oids into the PDU
void snmpDeliverTrap_netsnmp::_packOidsIntoPdu(
    const Array<String>& vbOids,
    const Array<String>& vbTypes,
    const Array<String>& vbValues,
    snmp_pdu* snmpPdu)
{

    PEG_METHOD_ENTER(TRC_IND_HANDLER,
        "snmpDeliverTrap_netsnmp::_packOidsIntoPdu");

    char dataType;
    oid vbOid[MAX_OID_LEN];
    size_t vbOidLength = MAX_OID_LEN;

    for (Uint32 i=0; i < vbOids.size(); i++)
    {
        if (vbTypes[i] == "OctetString")
        {
            dataType = 's';
        }
        else if (vbTypes[i] == "Integer")
        {
            dataType = 'i';
        }
        else if (vbTypes[i] == "OID")
        {
            dataType = 'o';
        }
        else
        {
            // Integer, OctetString, and OID are supported SNMP Data Types
            // for the CIM Property

            PEG_METHOD_EXIT();

            throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED,
                MessageLoaderParms(_MSG_UNSUPPORTED_SNMP_DATA_TYPE_KEY,
                                   _MSG_UNSUPPORTED_SNMP_DATA_TYPE,
                                   vbTypes[i]));

        }

        // Convert oid of a CIM property from numeric form to a list of
        // subidentifiers
        if (read_objid((const char*)vbOids[i].getCString(), vbOid,
            &vbOidLength) == 0)
        {
            // Failed to parse vbOids

            PEG_METHOD_EXIT();

            throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED,
                MessageLoaderParms(_MSG_PARSE_CIM_PROPERTY_OID_FAILED_KEY,
                                   _MSG_PARSE_CIM_PROPERTY_OID_FAILED,
                                   vbOids[i]));
        }

        Sint32 retCode;
        retCode = snmp_add_var(snmpPdu, vbOid, vbOidLength, dataType,
                               vbValues[i].getCString());

        // Failed to add vbOid to the pdu
        if (retCode != 0)
        {
            PEG_METHOD_EXIT();

            throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED,
                MessageLoaderParms(_MSG_ADD_VAR_TO_PDU_FAILED_KEY,
                                   _MSG_ADD_VAR_TO_PDU_FAILED,
                                   vbOids[i],
                                   String(snmp_api_errstring(retCode))));

        }
    }

    PEG_METHOD_EXIT();
}
Exemplo n.º 10
0
static int send_snmp_inform_or_trap(const GpErrorData * errorData, const char * subject, const char * severity)
{

	netsnmp_session session, *ss = NULL;
	netsnmp_pdu    *pdu, *response;
	int				status;
	char            csysuptime[20];
	static bool 	snmp_initialized = false;
	static char myhostname[255];	/* gethostname usually is limited to 65 chars out, but make this big to be safe */
	char	   *rawstring = NULL;
	List	   *elemlist = NIL;
	ListCell   *l = NULL;

	/*
	 * "inform" messages get a positive acknowledgement response from the SNMP manager.
	 * If it doesn't come, the message might be resent.
	 *
	 * "trap" messages are one-way, and we have no idea if the manager received it.
	 * But, it's faster and cheaper, and no need to retry.  So some people might prefer it.
	 */
	bool inform = strcmp(gp_snmp_use_inform_or_trap,"inform") == 0;


	if (gp_snmp_monitor_address == NULL || gp_snmp_monitor_address[0] == '\0')
	{
		static bool firsttime = 1;

		ereport(firsttime ? LOG : DEBUG1,(errmsg("SNMP inform/trap alerts are disabled")));
		firsttime = false;

		return -1;
	}


	/*
	 * SNMP managers are required to handle messages up to at least 484 bytes long, but I believe most existing
	 * managers support messages up to one packet (ethernet frame) in size, 1472 bytes.
	 *
	 * But, should we take that chance?  Or play it safe and limit the message to 484 bytes?
	 */

	elog(DEBUG2,"send_snmp_inform_or_trap");

	if (!snmp_initialized)
	{
		snmp_enable_stderrlog();

		if (gp_snmp_debug_log != NULL && gp_snmp_debug_log[0] != '\0')
		{
			snmp_enable_filelog(gp_snmp_debug_log, 1);

			//debug_register_tokens("ALL");
			snmp_set_do_debugging(1);
		}

		/*
		 * Initialize the SNMP library.  This also reads the MIB database.
		 */
		/* Add GPDB-MIB to the list to be loaded */
		putenv("MIBS=+GPDB-MIB:SNMP-FRAMEWORK-MIB:SNMPv2-CONF:SNMPv2-TC:SNMPv2-TC");

		init_snmp("sendalert");

		snmp_initialized = true;

		{
			char portnum[16];
			myhostname[0] = '\0';

			if (gethostname(myhostname, sizeof(myhostname)) == 0)
			{
				strcat(myhostname,":");
				pg_ltoa(PostPortNumber,portnum);
				strcat(myhostname,portnum);
			}
		}
	}

	/*
	 * Trap/Inform messages always start with the system up time. (SysUpTime.0)
	 *
	 * This presumably would be the uptime of GPDB, not the machine it is running on, I think.
	 *
	 * Use Postmaster's "MyStartTime" as a way to get that.
	 */

	sprintf(csysuptime, "%ld", (long)(time(NULL) - MyStartTime));


	/*
	// ERRCODE_DISK_FULL could be reported vi rbmsMIB rdbmsTraps rdbmsOutOfSpace trap.
	// But it appears we never generate that error?

	// ERRCODE_ADMIN_SHUTDOWN means SysAdmin aborted somebody's request.  Not interesting?

	// ERRCODE_CRASH_SHUTDOWN sounds interesting, but I don't see that we ever generate it.

	// ERRCODE_CANNOT_CONNECT_NOW means we are starting up, shutting down, in recovery, or Too many users are logged on.

	// abnormal database system shutdown
	*/



	/*
	 * The gpdbAlertSeverity is a crude attempt to classify some of these messages based on severity,
	 * where OK means everything is running normal, Down means everything is shut down, degraded would be
	 * for times when some segments are down, but the system is up, The others are maybe useful in the future
	 *
	 *  gpdbSevUnknown(0),
	 *	gpdbSevOk(1),
	 *	gpdbSevWarning(2),
	 *	gpdbSevError(3),
	 *	gpdbSevFatal(4),
	 *	gpdbSevPanic(5),
	 *	gpdbSevSystemDegraded(6),
	 *	gpdbSevSystemDown(7)
	 */


	char detail[MAX_ALERT_STRING+1];
	snprintf(detail, MAX_ALERT_STRING, "%s", errorData->error_detail);
	detail[127] = '\0';

	char sqlstmt[MAX_ALERT_STRING+1];
	char * sqlstmtp = errorData->debug_query_string;
	if (sqlstmtp == NULL || sqlstmtp[0] == '\0')
		sqlstmtp = errorData->internal_query;
	if (sqlstmtp == NULL)
		sqlstmtp = "";


	snprintf(sqlstmt, MAX_ALERT_STRING, "%s", sqlstmtp);
	sqlstmt[MAX_ALERT_STRING] = '\0';


	/* Need a modifiable copy of To list */
	rawstring = pstrdup(gp_snmp_monitor_address);

	/* Parse string into list of identifiers */
	if (!SplitMailString(rawstring, ',', &elemlist))
	{
		/* syntax error in list */
		ereport(LOG,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("invalid list syntax for \"gp_snmp_monitor_address\"")));
		return -1;
	}


	/*
	 * This session is just a template, and doesn't need to be connected.
	 * It is used by snmp_add(), which copies this info, opens the new session, and assigns the transport.
	 */
	snmp_sess_init( &session );	/* Initialize session to default values */
	session.version = SNMP_VERSION_2c;
	session.timeout = SNMP_DEFAULT_TIMEOUT;
	session.retries = SNMP_DEFAULT_RETRIES;
	session.remote_port = 162; 							// I think this isn't used by net-snmp any more.

	/*if (strchr(session.peername,':')==NULL)
		strcat(session.peername,":162");*/
	session.community = (u_char *)gp_snmp_community;
	session.community_len = strlen((const char *)session.community);  // SNMP_DEFAULT_COMMUNITY_LEN means "public"
	session.callback_magic = NULL;

	foreach(l, elemlist)
	{
		char	   *cur_gp_snmp_monitor_address = (char *) lfirst(l);

		if (cur_gp_snmp_monitor_address == NULL || cur_gp_snmp_monitor_address[0] == '\0')
			continue;

		session.peername = cur_gp_snmp_monitor_address;
		/*
		 * If we try to "snmp_open( &session )", net-snmp will set up a connection to that
		 * endpoint on port 161, assuming we are the network monitor, and the other side is an agent.
		 *
		 * But we are pretending to be an agent, sending traps to the NM, so we don't need this.
		 */

		/*if (!snmp_open( &session ))   	// Don't open the session here!
		{
			const char     *str;
			int             xerr;
			xerr = snmp_errno;
			str = snmp_api_errstring(xerr);
			elog(LOG, "snmp_open: %s", str);
			return -1;
		}*/

		/*
		 * This call copies the info from "session" to "ss", assigns the transport, and opens the session.
		 * We must specify "snmptrap" so the transport will know we want port 162 by default.
		 */
		ss = snmp_add(&session,
					  netsnmp_transport_open_client("snmptrap", cur_gp_snmp_monitor_address),
					  NULL, NULL);
		if (ss == NULL) {
			/*
			 * diagnose netsnmp_transport_open_client and snmp_add errors with
			 * the input netsnmp_session pointer
			 */
			{
				char           *err;
				snmp_error(&session, NULL, NULL, &err);
				elog(LOG, "send_alert snmp_add of %s failed: %s", cur_gp_snmp_monitor_address, err);
				free(err);
			}
			return -1;
		}

		/*
		 * We need to create the pdu each time, as it gets freed when we send a trap.
		 */
		pdu = snmp_pdu_create(inform ? SNMP_MSG_INFORM : SNMP_MSG_TRAP2);
		if (!pdu)
		{
			const char     *str;
			int             xerr;
			xerr = snmp_errno;
			str = snmp_api_errstring(xerr);
			elog(LOG, "Failed to create notification PDU: %s", str);
			return -1;
		}

		/*
		 * Trap/Inform messages always start with the system up time. (SysUpTime.0)
		 * We use Postmaster's "MyStartTime" as a way to get that.
		 */

		snmp_add_var(pdu, objid_sysuptime,
							sizeof(objid_sysuptime) / sizeof(oid),
							't', (const char *)csysuptime);

	#if 0
		/*
		 * In the future, we might want to send RDBMS-MIB::rdbmsStateChange when the system becomes unavailable or
		 * partially unavailable.  This code, which is not currently used, shows how to build the pdu for
		 * that trap.
		 */
		/* {iso(1) identified-organization(3) dod(6) internet(1) mgmt(2) mib-2(1) rdbmsMIB(39) rdbmsTraps(2) rdbmsStateChange(1)} */
		snmp_add_var(pdu, objid_snmptrap,
							sizeof(objid_snmptrap) / sizeof(oid),
							'o', "1.3.6.1.2.1.39.2.1");  // rdbmsStateChange


		snmp_add_var(pdu, objid_rdbmsrelstate,
							sizeof(objid_rdbmsrelstate) / sizeof(oid),
							'i', "5");  // 4 = restricted, 5 = unavailable
	#endif

		/* {iso(1) identified-organization(3) dod(6) internet(1) private(4) enterprises(1) gpdbMIB(31327) gpdbTraps(5) gpdbTrapsList(0) gpdbAlert(1)} */

		/*
		 * We could specify this trap oid by name, rather than numeric oid, but then if the GPDB-MIB wasn't
		 * found, we'd get an error.  Using the numeric oid means we can still work without the MIB loaded.
		 */
		snmp_add_var(pdu, objid_snmptrap,
							sizeof(objid_snmptrap) / sizeof(oid),
							'o', "1.3.6.1.4.1.31327.5.0.1");  // gpdbAlert


		snmp_add_var(pdu, objid_gpdbAlertMsg,
							sizeof(objid_gpdbAlertMsg) / sizeof(oid),
							's', subject);  // SnmpAdminString = UTF-8 text
		snmp_add_var(pdu, objid_gpdbAlertSeverity,
							sizeof(objid_gpdbAlertSeverity) / sizeof(oid),
							'i', (char *)severity);

		snmp_add_var(pdu, objid_gpdbAlertSqlstate,
							sizeof(objid_gpdbAlertSqlstate) / sizeof(oid),
							's', errorData->sql_state);

		snmp_add_var(pdu, objid_gpdbAlertDetail,
							sizeof(objid_gpdbAlertDetail) / sizeof(oid),
							's', detail); // SnmpAdminString = UTF-8 text

		snmp_add_var(pdu, objid_gpdbAlertSqlStmt,
							sizeof(objid_gpdbAlertSqlStmt) / sizeof(oid),
							's', sqlstmt); // SnmpAdminString = UTF-8 text

		snmp_add_var(pdu, objid_gpdbAlertSystemName,
							sizeof(objid_gpdbAlertSystemName) / sizeof(oid),
							's', myhostname); // SnmpAdminString = UTF-8 text



		elog(DEBUG2,"ready to send to %s",cur_gp_snmp_monitor_address);
		if (inform)
			status = snmp_synch_response(ss, pdu, &response);
		else
			status = snmp_send(ss, pdu) == 0;

		elog(DEBUG2,"send, status %d",status);
		if (status != STAT_SUCCESS)
		{
			/* Something went wrong */
			if (ss)
			{
				char           *err;
				snmp_error(ss, NULL, NULL, &err);
				elog(LOG, "sendalert failed to send %s: %s", inform ? "inform" : "trap", err);
				free(err);
			}
			else
			{
				elog(LOG, "sendalert failed to send %s: %s", inform ? "inform" : "trap", "Something went wrong");
			}
			if (!inform)
				snmp_free_pdu(pdu);
		}
		else if (inform)
			snmp_free_pdu(response);

		snmp_close(ss);
		ss = NULL;

	}
Exemplo n.º 11
0
netsnmp_session *mp_snmp_init(void) {

    netsnmp_session session, *ss;
    int status;

    init_snmp(progname);

    snmp_sess_init( &session );

    if (mp_snmp_community == NULL)
        mp_snmp_community = mp_strdup("public");

    mp_asprintf(&(session.peername), "%s:%d", hostname, port);

    switch(mp_snmp_version) {
        case SNMP_VERSION_1:
            session.version = SNMP_VERSION_1;
            session.community = (u_char *)mp_snmp_community;
            session.community_len = strlen((char *)session.community);
            break;
        case SNMP_VERSION_2c:
            session.version = SNMP_VERSION_2c;
            session.community = (u_char *)mp_snmp_community;
            session.community_len = strlen((char *)session.community);
            break;
        case SNMP_VERSION_3:
            session.version = SNMP_VERSION_3;

            session.securityName = mp_strdup(mp_snmp_secname);
            session.securityNameLen = strlen(session.securityName);

            /* set the security level */
            session.securityLevel = mp_snmp_seclevel;
            session.contextName = mp_strdup(mp_snmp_context);

            session.contextNameLen = strlen(session.contextName);

            /* set the authentication method */
            session.securityAuthProto = mp_snmp_authproto;
            session.securityAuthProtoLen = 10;
            session.securityAuthKeyLen = USM_AUTH_KU_LEN;

            status = generate_Ku(session.securityAuthProto,
                    session.securityAuthProtoLen,
                    (u_char *) mp_snmp_authpass, strlen(mp_snmp_authpass),
                    session.securityAuthKey,
                    &session.securityAuthKeyLen);
            if (status != SNMPERR_SUCCESS) {
                snmp_perror(progname);
                snmp_log(LOG_ERR,
                        "Error generating Ku from authentication pass phrase. \n%s\n",snmp_api_errstring(status));
                exit(1);
            }

            break;
    }

    netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
                           NETSNMP_DS_LIB_DONT_PERSIST_STATE, 1);

    SOCK_STARTUP;
    ss = snmp_open(&session);

    if (!ss) {
      snmp_sess_perror("ack", &session);
      SOCK_CLEANUP;
      exit(1);
    }

    free(session.peername);

    if (mp_snmp_retries > 0)
        ss->retries = mp_snmp_retries;
    if (mp_snmp_timeout > 0)
        ss->timeout = (long)(mp_snmp_timeout * 1000000L);

    return ss;

}
// Creates a SNMP TRAP PDU
void snmpDeliverTrap_netsnmp::_createPdu(
    Uint16 snmpVersion,
    const String& trapOid,
    snmp_session*& sessionPtr,
    snmp_pdu*& snmpPdu)
{
    PEG_METHOD_ENTER(TRC_IND_HANDLER, "snmpDeliverTrap_netsnmp::_createPdu");

    oid _SYSTEM_UP_TIME_OID [] = {1,3,6,1,2,1,1,3,0};
    oid _SNMPTRAP_OID [] = {1,3,6,1,6,3,1,1,4,1,0};

    in_addr_t* pduInAddr;

    switch (snmpVersion)
    {
        case _SNMPv1_TRAP:
        {

            sessionPtr->version = SNMP_VERSION_1;

            // Create the PDU
            snmpPdu = snmp_pdu_create(SNMP_MSG_TRAP);

            // Failed to create pdu
            if (!snmpPdu)
            {
                PEG_METHOD_EXIT();
                throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED,
                    MessageLoaderParms(
                        _MSG_PDU_CREATE_FAILED_KEY,
                        _MSG_PDU_CREATE_FAILED));
            }

            // Make sure that the v1 trap PDU includes the local IP address
            pduInAddr = (in_addr_t*) snmpPdu->agent_addr;
            *pduInAddr = get_myaddr();

            // get system up time
            snmpPdu->time = get_uptime();

            // Pack trap information into the PDU
            try
            {
                _packTrapInfoIntoPdu(trapOid, snmpPdu);
            }
            catch (CIMException& e)
            {
                Logger::put_l(
                    Logger::STANDARD_LOG, System::CIMSERVER, Logger::WARNING,
                    MessageLoaderParms(
                        _MSG_PACK_TRAP_INFO_INTO_PDU_FAILED_KEY,
                        _MSG_PACK_TRAP_INFO_INTO_PDU_FAILED,
                        e.getMessage()));
            }

            break;
        }
        case _SNMPv2C_TRAP:
        {
            sessionPtr->version = SNMP_VERSION_2c;

            // Create the PDU
            snmpPdu = snmp_pdu_create(SNMP_MSG_TRAP2);

            // Failed to create pdu
            if (!snmpPdu)
            {
                PEG_METHOD_EXIT();

                throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED,
                    MessageLoaderParms(
                        _MSG_PDU_CREATE_FAILED_KEY,
                        _MSG_PDU_CREATE_FAILED));
            }

            // Add sysUpTime to the PDU
            char sysUpTime[32];
            sprintf(sysUpTime, "%ld", get_uptime());

            Sint32 retCode;
            retCode = snmp_add_var(
                snmpPdu,
                _SYSTEM_UP_TIME_OID,
                OID_LENGTH(_SYSTEM_UP_TIME_OID),
                't',
                sysUpTime);

            // Failed to add sysUpTime to the pdu
            if (retCode != 0)
            {
                String errMsg = snmp_api_errstring(retCode);

                Logger::put_l(
                    Logger::STANDARD_LOG, System::CIMSERVER, Logger::WARNING,
                    MessageLoaderParms(
                        _MSG_ADD_SYSUPTIME_TO_PDU_FAILED_KEY,
                        _MSG_ADD_SYSUPTIME_TO_PDU_FAILED,
                        errMsg));
            }

            // Add snmp trap to the PDU
            retCode = snmp_add_var(
                snmpPdu,
                _SNMPTRAP_OID,
                OID_LENGTH(_SNMPTRAP_OID),
                'o',
                trapOid.getCString());

            // Failed to add snmp trap to the pdu
            if (retCode != 0)
            {
                String errMsg = snmp_api_errstring(retCode);

                Logger::put_l(
                    Logger::STANDARD_LOG, System::CIMSERVER, Logger::WARNING,
                    MessageLoaderParms(
                        _MSG_ADD_SNMP_TRAP_TO_PDU_FAILED_KEY,
                        _MSG_ADD_SNMP_TRAP_TO_PDU_FAILED,
                        errMsg));
            }

            break;
        }
        default:
        {
            PEG_METHOD_EXIT();

            throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_NOT_SUPPORTED,
                MessageLoaderParms(
                    _MSG_VERSION_NOT_SUPPORTED_KEY,
                    _MSG_VERSION_NOT_SUPPORTED));
        }
    }

    PEG_METHOD_EXIT();
}
Exemplo n.º 13
0
static rsRetVal omsnmp_sendsnmp(wrkrInstanceData_t *pWrkrData, uchar *psz)
{
	DEFiRet;

	netsnmp_pdu    *pdu = NULL;
	oid             enterpriseoid[MAX_OID_LEN];
	size_t          enterpriseoidlen = MAX_OID_LEN;
	oid				oidSyslogMessage[MAX_OID_LEN];
	size_t			oLen = MAX_OID_LEN;
	int             status;
	char            *trap = NULL;
	const char		*strErr = NULL;
	instanceData *pData;

	pData = pWrkrData->pData;
	/* Init SNMP Session if necessary */
	if (pWrkrData->snmpsession == NULL) {
		CHKiRet(omsnmp_initSession(pWrkrData));
	}
	
	/* String should not be NULL */
	ASSERT(psz != NULL);
	dbgprintf( "omsnmp_sendsnmp: ENTER - Syslogmessage = '%s'\n", (char*)psz);

	/* If SNMP Version1 is configured !*/
	if(pWrkrData->snmpsession->version == SNMP_VERSION_1) {
		pdu = snmp_pdu_create(SNMP_MSG_TRAP);

		/* Set enterprise */
		if(!snmp_parse_oid(pData->szEnterpriseOID == NULL ? "1.3.6.1.4.1.3.1.1" : (char*)pData->szEnterpriseOID,
				   enterpriseoid, &enterpriseoidlen )) {
			strErr = snmp_api_errstring(snmp_errno);
			errmsg.LogError(0, RS_RET_DISABLE_ACTION, "omsnmp_sendsnmp: Parsing EnterpriseOID "
					"failed '%s' with error '%s' \n", pData->szSyslogMessageOID, strErr);
			ABORT_FINALIZE(RS_RET_DISABLE_ACTION);
		}
		pdu->enterprise = (oid *) MALLOC(enterpriseoidlen * sizeof(oid));
		memcpy(pdu->enterprise, enterpriseoid, enterpriseoidlen * sizeof(oid));
		pdu->enterprise_length = enterpriseoidlen;

		/* Set Traptype */
		pdu->trap_type = pData->iTrapType; 
		
		/* Set SpecificType */
		pdu->specific_type = pData->iSpecificType;

		/* Set Updtime */
		pdu->time = get_uptime();
	}
	/* If SNMP Version2c is configured !*/
	else if (pWrkrData->snmpsession->version == SNMP_VERSION_2c) 
	{
		long sysuptime;
		char csysuptime[20];
		
		/* Create PDU */
		pdu = snmp_pdu_create(SNMP_MSG_TRAP2);
		
		/* Set uptime */
		sysuptime = get_uptime();
		snprintf( csysuptime, sizeof(csysuptime) , "%ld", sysuptime);
		trap = csysuptime;
		snmp_add_var(pdu, objid_sysuptime, sizeof(objid_sysuptime) / sizeof(oid), 't', trap);

		/* Now set the SyslogMessage Trap OID */
		if ( snmp_add_var(pdu, objid_snmptrap, sizeof(objid_snmptrap) / sizeof(oid), 'o',
			pData->szSnmpTrapOID == NULL ?  "1.3.6.1.4.1.19406.1.2.1" : (char*) pData->szSnmpTrapOID
			) != 0) {
			strErr = snmp_api_errstring(snmp_errno);
			errmsg.LogError(0, RS_RET_DISABLE_ACTION, "omsnmp_sendsnmp: Adding trap OID failed '%s' with error '%s' \n", pData->szSnmpTrapOID, strErr);
			ABORT_FINALIZE(RS_RET_DISABLE_ACTION);
		}
	}

	/* SET TRAP PARAMETER for SyslogMessage! */
/*	dbgprintf( "omsnmp_sendsnmp: SyslogMessage '%s'\n", psz );*/

	/* First create new OID object */
	if (snmp_parse_oid(pData->szSyslogMessageOID == NULL ?
			    "1.3.6.1.4.1.19406.1.1.2.1" : (char*)pData->szSyslogMessageOID,
				oidSyslogMessage, &oLen)) {
		int iErrCode = snmp_add_var(pdu, oidSyslogMessage, oLen, 's', (char*) psz);
		if (iErrCode) {
			const char *str = snmp_api_errstring(iErrCode);
			errmsg.LogError(0, RS_RET_DISABLE_ACTION,  "omsnmp_sendsnmp: Invalid SyslogMessage OID, error code '%d' - '%s'\n", iErrCode, str );
			ABORT_FINALIZE(RS_RET_DISABLE_ACTION);
		}
	} else {
		strErr = snmp_api_errstring(snmp_errno);
		errmsg.LogError(0, RS_RET_DISABLE_ACTION, "omsnmp_sendsnmp: Parsing SyslogMessageOID failed '%s' with error '%s' \n", pData->szSyslogMessageOID, strErr);

		ABORT_FINALIZE(RS_RET_DISABLE_ACTION);
	}

	/* Send the TRAP */
	status = snmp_send(pWrkrData->snmpsession, pdu) == 0;
	if (status)
	{
		/* Debug Output! */
		int iErrorCode = pWrkrData->snmpsession->s_snmp_errno;
		errmsg.LogError(0, RS_RET_SUSPENDED,  "omsnmp_sendsnmp: snmp_send failed error '%d', Description='%s'\n", iErrorCode*(-1), api_errors[iErrorCode*(-1)]);

		/* Clear Session */
		omsnmp_exitSession(pWrkrData);

		ABORT_FINALIZE(RS_RET_SUSPENDED);
	}

finalize_it:
	if(iRet != RS_RET_OK) {
		if(pdu != NULL) {
			snmp_free_pdu(pdu);
		}
	}

	dbgprintf( "omsnmp_sendsnmp: LEAVE\n");
	RETiRet;
}
Exemplo n.º 14
0
void *sync_poller(void *thread_args) {

	// phoenix async poller;
	worker_t *worker = (worker_t *) thread_args;
	crew_t *crew = worker -> crew;
	// target_t *entry = NULL;

	target_t *_current_local = NULL;

	PT_MUTEX_LOCK(&crew -> mutex);
	PT_COND_WAIT(&crew->go, &crew->mutex);
	PT_MUTEX_UNLOCK(&crew -> mutex);

	for( ; ; ) {

		PT_MUTEX_LOCK(&crew -> mutex);

		current = _current_local = getNext();
		crew -> _sent_work_count--;

		if (_current_local == NULL && crew->_sent_work_count <= 0) {

			crew -> _send_worker_count--;
			PT_COND_BROAD(&crew -> _sending_done);
			PT_COND_WAIT(&crew -> go, &crew -> mutex);
//		} else if (_current_local == NULL) {
//			PT_COND_WAIT(&crew->go, &crew->mutex);
//			// PT_MUTEX_UNLOCK(&crew -> mutex);
//			continue;
//			// return 0;
//		} else if (crew->_sent_work_count <= 0) {
//			PT_COND_BROAD(&crew->_sending_done);
//			// PT_MUTEX_UNLOCK(&crew -> mutex);
//			continue;
//			// return 0;
			PT_MUTEX_UNLOCK(&crew -> mutex);
			continue;
		}

		PT_MUTEX_UNLOCK(&crew -> mutex);

//		PT_MUTEX_LOCK(&crew->mutex);
//		current = getNext();
//		if (status == STAT_SUCCESS) entry->last_value = result;
//		if (init == NEW) entry->init = LIVE;
//		 signal for our control thread;
//		 but should also check for number of threads completed;
//		PT_MUTEX_UNLOCK(&crew->mutex);

//		while (current == NULL) {
//			PT_COND_WAIT(&crew -> go, &crew -> mutex);
//			_current_local = NULL;
//		}
//
//		if (current != NULL) {
//			_current_local = current;
//			// printf("[ info] thread [%d] work_count index: %d\n", worker->index, crew -> _send_work_count);
//		}
		// make a copy of current and then unlock;

		// preparing snmp session;
		// we got what we need from current entry
		// moving to next entry for other wating threads;

			printf(
				"[ info] thread [%d] processing -> host: %s, oid: %s\n",
				worker -> index,
				_current_local -> host,
			    _current_local -> objoid
			);

		// making a snmp session ...

		// struct session *_host_ss = stuepd you are, this is a ptr! sohuld be initialized 1st :- ;
		struct session *_host_ss = calloc(1, sizeof(struct session));
		// stuepd you are, this is a ptr! sohuld be initialized 1st :- ;
		// struct host *hp;

		/* startup all hosts */
		// for (hs = sessions, hp = hosts; hp->name; hs++, hp++) {

		struct snmp_session _sess;

		struct snmp_pdu *pdu = NULL;
		struct snmp_pdu *response = NULL;

		snmp_sess_init(&_sess);

		/* initialize session */
		_sess.version = SNMP_VERSION_2c;
		_sess.peername = strdup(_current_local-> host);
		_sess.community = strdup(_current_local -> community);
		_sess.community_len = strlen(_sess.community);

//		/* default callback */
//		_sess.callback = asynch_response;
//		_sess.callback_magic = _host_ss;
//
		if (!(_host_ss -> _sess = snmp_sess_open(&_sess))) {

			//, snmp_api_errstring(snmp_errno)
			printf("[error] %s!\n", snmp_api_errstring(snmp_errno));
			// exit(-1);
			// snmp_perror(snmp_errno);
			continue;

		}

//		printf("[ info] thread [%d] &sess: %llu, _host_ss -> _sess: %llu\n", worker->index,
//		       &sess, _host_ss -> _sess);

//		struct snmp_session *_ss_ptr = snmp_sess_session(_host_ss -> _sess);

		_host_ss -> _oid_name = strdup(_current_local -> objoid);
		// also translate this in to snmp format;
		_host_ss -> _oid_len = sizeof(_host_ss -> _oid) / sizeof(_host_ss -> _oid[0]);

		if (!read_objid(_host_ss -> _oid_name, _host_ss -> _oid, &_host_ss -> _oid_len)) {
			snmp_perror("read_objid");
			exit(1);
		}

		pdu = snmp_pdu_create(SNMP_MSG_GET);	/* send the first GET */
		snmp_add_null_var(pdu, _host_ss -> _oid, _host_ss -> _oid_len);

		int _status = snmp_sess_synch_response(_host_ss -> _sess, pdu, &response);

		// int print_result (int status, struct snmp_session *sp, struct snmp_pdu *pdu)
		print_result(_status, &_sess, response);

		// analyzing the result;
		// and making it look like correct one (limits and correctness check);
		// if out of range for example we have the following stats update;
		// PT_MUTEX_LOCK(&stats.mutex);
		// stats.out_of_range++;
		// PT_MUTEX_UNLOCK(&stats.mutex);

		snmp_sess_close(_host_ss -> _sess);

		/* Collect response and process stats */
		PT_MUTEX_LOCK(&stats.mutex);
		// when we have a snmp result, updating a starts counters;
		PT_MUTEX_UNLOCK(&stats.mutex);

		// decreasing work counter;


	} // for (;;)

}
Exemplo n.º 15
0
/* fill a struct ifsnmp buffer of selected information (flags) for
   interface index to (index + nifaces - 1). ifsnmp must be large
   enough, and nifaces shouldb'nt too large since some devices have
   limited capability for large responses...
   In case we get a unknown name answer and we're
   polling several interfaces at once, interfaces will be polled
   again individually to try to solve the problem.
*/
static int snmp_get_ifinfos(struct snmp_session *ss, int nifaces,
			    int flags, struct ifsnmp * ifsnmp, int *toobig) {
  struct snmp_pdu *pdu, *response = NULL;
  oid ifinfo[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 0, 0 }; /* interfaces.ifTable.ifEntry.x.n */
#define ifDescr 2
#define ifType 3  
#define ifOperStatus 8  
#define ifInOctets 10
#define ifOutOctets 16
  struct variable_list *vars;
  int i, status;
 
  if (nifaces <= 0)
    return 0;
  
  if ((pdu = snmp_pdu_create(SNMP_MSG_GET)) == NULL) {
    ifstat_error("snmp_pdu_create: %s", snmp_api_errstring(snmp_errno));
    return 0;
  }

  for (i = 0; i < nifaces; i++) {
    ifsnmp[i].flags = 0;
    ifsnmp[i].name[0] = 0;

    /* set interface index */
    ifinfo[10] = ifsnmp[i].index;

    if (flags & S_NUMNAME) {
      sprintf(ifsnmp[i].name, "if%d", ifsnmp[i].index);
    } else if (flags & S_IFNAME) {
      /* require descr */
      ifinfo[9] = ifDescr;
      snmp_add_null_var(pdu, ifinfo, sizeof(ifinfo) / sizeof(oid));
    }
    
    /* then optional data */
    if (flags & S_UP) {
      ifinfo[9] = ifOperStatus;
      snmp_add_null_var(pdu, ifinfo, sizeof(ifinfo) / sizeof(oid));
    }
    if (flags & S_BOUT) {
      ifinfo[9] = ifOutOctets;
      snmp_add_null_var(pdu, ifinfo, sizeof(ifinfo) / sizeof(oid));
    }
    if (flags & S_BIN) {
      ifinfo[9] = ifInOctets;
      snmp_add_null_var(pdu, ifinfo, sizeof(ifinfo) / sizeof(oid));
    }
    if (flags & S_LOOP) {
      ifinfo[9] = ifType;
      snmp_add_null_var(pdu, ifinfo, sizeof(ifinfo) / sizeof(oid));
    }
  }
    
  if ((status = snmp_synch_response(ss, pdu, &response)) != STAT_SUCCESS ||
      response->errstat != SNMP_ERR_NOERROR ||
      response->variables == NULL) {
    if (status == STAT_SUCCESS) {
      if (response->errstat != SNMP_ERR_NOSUCHNAME &&
	  response->errstat != SNMP_ERR_TOOBIG)
	ifstat_error("snmp: Error: %s", snmp_errstring(response->errstat));
      else if (nifaces > 1) {
	/* maybe only one of the interface is broken or too many interfaces polled at once
	   -- repoll inetrface per interface */
	if (response->errstat == SNMP_ERR_TOOBIG && toobig != NULL)
	  (*toobig)++;
	if (response != NULL)
	  snmp_free_pdu(response);
	status = 0;
	for (i = 0; i < nifaces; i++) {
	  if (!snmp_get_ifinfos(ss, 1, flags, ifsnmp + i, NULL))
	    ifsnmp[i].flags |= S_INVALID;
	  else
	    status = 1;
	}
	return status;
      }
    } else
      ifstat_error("snmpget(interfaces.ifTable.ifEntry...): %s", snmp_sess_errstring(ss));
    if (response != NULL)
      snmp_free_pdu(response);
    return 0;
  }

  for(vars = response->variables; vars; vars = vars->next_variable) {
    /* check that the variable is under the base oid */
    if (memcmp(ifinfo, vars->name, sizeof(ifinfo) - 2 * sizeof(oid)) != 0)
      continue;
    for(i = 0; i < nifaces; i++) {
      if (ifsnmp[i].index == vars->name[10])
	break;
    }

    if (i == nifaces) /* not found */
      continue;

    switch (vars->name[9]) {
    case ifDescr:
      if (vars->type == ASN_OCTET_STR) {
        int count = vars->val_len;

        if (count >= sizeof(ifsnmp[i].name))
          count = sizeof(ifsnmp[i].name) - 1;
	strncpy(ifsnmp[i].name, vars->val.string, count);
        ifsnmp[i].name[count] = '\0';
      }
      break;
    case ifOperStatus:
      if (vars->type == ASN_INTEGER) {
	if (*(vars->val.integer) == 1) /* up */
	  ifsnmp[i].flags |= S_UP;
      }
      break;
    case ifType:
      if (vars->type == ASN_INTEGER) {
	if (*(vars->val.integer) == 24) /* softwareLoopback */
	  ifsnmp[i].flags |= S_LOOP;
      }
      break;
    case ifInOctets:
      if (vars->type == ASN_INTEGER || vars->type == ASN_COUNTER) {
	ifsnmp[i].flags |= S_BIN;
	ifsnmp[i].bin =	*(vars->val.integer);
      }
      break;
    case ifOutOctets:
      if (vars->type == ASN_INTEGER || vars->type == ASN_COUNTER) {
	ifsnmp[i].flags |= S_BOUT;
	ifsnmp[i].bout = *(vars->val.integer);
      }
      break;
    }
  }
  snmp_free_pdu(response);
  return 1;
}
Exemplo n.º 16
0
/* initiailise the snmp driver, strings syntax is [comm@][#]host*/
int snmp_open_driver(struct ifstat_driver *driver, char *options) {
  char *host;
  char *community;
  struct snmp_session session;
  struct snmp_driver_data *data;
  
  if ((data = malloc(sizeof(struct snmp_driver_data))) == NULL) {
    ifstat_perror("malloc");
    return 0;
  }

  if (options == NULL)
    options = "localhost";
  
  if ((host = strchr(options, '@')) != NULL) {
    *host++ = '\0';
    community = options;
  } else {
    host = options;
    community = "public";
  }

  if (*host == '#') {
    host++;
    data->num_ifnames = 1; /* numeric interface names */
  } else
    data->num_ifnames = 0;

  if ((options = strchr(host, '/')) != NULL) {
    *options++ = '\0';
    data->num_ifsreqs = atoi(options);
    if (data->num_ifsreqs < 1) {
      ifstat_error("snmp: bad number of interface requests: %s; ignored.", options);
      data->num_ifsreqs = DEFIFSREQS;
    } else if (data->num_ifsreqs > MAXIFSREQS) {
      ifstat_error("snmp: number of interface requests too large: %d; using %d instead.",
	      data->num_ifsreqs, MAXIFSREQS);
      data->num_ifsreqs = MAXIFSREQS;
    } 
  } else
    data->num_ifsreqs = DEFIFSREQS;
  
  if ((data->ifsnmp = calloc(sizeof(struct ifsnmp), data->num_ifsreqs)) == NULL) {
    ifstat_perror("malloc");
    free(data);
    return 0;
  }
  
  init_snmp(ifstat_progname);
  snmp_sess_init(&session);
  session.peername = host;
  session.version = SNMP_VERSION_1;
  session.community = community;
  session.community_len = strlen(community);

  if ((data->session = snmp_open(&session)) == NULL) {
    ifstat_error("snmp_open: %s", snmp_api_errstring(snmp_errno));
    free(data->ifsnmp);
    free(data);
    return 0;
  }
  
  driver->data = (void *) data;
  return 1;
}
Exemplo n.º 17
0
/**
 * FSAL_readdir :
 *     Read the entries of an opened directory.
 *     
 * \param dir_descriptor (input):
 *        Pointer to the directory descriptor filled by FSAL_opendir.
 * \param start_position (input):
 *        Cookie that indicates the first object to be read during
 *        this readdir operation.
 *        This should be :
 *        - FSAL_READDIR_FROM_BEGINNING for reading the content
 *          of the directory from the beginning.
 *        - The end_position parameter returned by the previous
 *          call to FSAL_readdir.
 * \param get_attr_mask (input)
 *        Specify the set of attributes to be retrieved for directory entries.
 * \param buffersize (input)
 *        The size (in bytes) of the buffer where
 *        the direntries are to be stored.
 * \param pdirent (output)
 *        Adresse of the buffer where the direntries are to be stored.
 * \param end_position (output)
 *        Cookie that indicates the current position in the directory.
 * \param nb_entries (output)
 *        Pointer to the number of entries read during the call.
 * \param end_of_dir (output)
 *        Pointer to a boolean that indicates if the end of dir
 *        has been reached during the call.
 * 
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - ERR_FSAL_FAULT        (a NULL pointer was passed as mandatory argument) 
 *        - Other error codes can be returned :
 *          ERR_FSAL_IO, ...
 */
fsal_status_t SNMPFSAL_readdir(fsal_dir_t * dir_desc, /* IN */
                               fsal_cookie_t start_pos,        /* IN */
                               fsal_attrib_mask_t get_attr_mask,        /* IN */
                               fsal_mdsize_t buffersize,        /* IN */
                               fsal_dirent_t * pdirent, /* OUT */
                               fsal_cookie_t * end_pos,        /* OUT */
                               fsal_count_t * nb_entries,       /* OUT */
                               fsal_boolean_t * end_of_dir      /* OUT */
    )
{
  fsal_count_t max_dir_entries;
  fsal_count_t cur_nb_entries;
  fsal_boolean_t bool_eod;
  snmpfsal_cookie_t last_listed;

  fsal_request_desc_t req_opt;
  netsnmp_variable_list *p_curr_var;
  struct tree *cur_node;
  struct tree *nearest_node;
  int rc;
  snmpfsal_dir_t * dir_descriptor = (snmpfsal_dir_t *)dir_desc;
  snmpfsal_cookie_t start_position;
  snmpfsal_cookie_t * end_position = (snmpfsal_cookie_t *)end_pos;

  /* sanity checks */

  if(!dir_descriptor || !pdirent || !end_position || !nb_entries || !end_of_dir)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readdir);

  /* The readdir call is a sequence of GET/GETNEXT operations :
   * The first call, is a get on the hypothetic next brother
   * => if it exists, we add it to the dirents, and try to get the next child.
   * => if it doesnt exist, we make a getnext on it. 
   *    then, when a next branch is discovered, the next item to be tested 
   *    is the next hypothetic child.
   */

  /* initial cookie  */

  memcpy(&start_position.data, &start_pos.data, sizeof(snmpfsal_cookie_t));
  if(start_position.data.oid_len == 0)       /* readdir from begginning  */
    {
      FSAL_OID_DUP(&last_listed, dir_descriptor->node_handle.data.oid_tab,
                   dir_descriptor->node_handle.data.oid_len);
      /* first try to get .0 child */
      last_listed.data.oid_tab[last_listed.data.oid_len] = 0;
      last_listed.data.oid_len++;
    }
  else                          /* readdir from another entry */
    {
      FSAL_OID_DUP(&last_listed, start_position.data.oid_tab, start_position.data.oid_len);
    }

  /* calculate the requested dircount */

  max_dir_entries = (buffersize / sizeof(fsal_dirent_t));

  /* init counters and outputs */
  memset(pdirent, 0, buffersize);
  bool_eod = FALSE;
  cur_nb_entries = 0;

  if(max_dir_entries == 0)
    Return(ERR_FSAL_TOOSMALL, 0, INDEX_FSAL_readdir);

  while(!bool_eod && cur_nb_entries < max_dir_entries)
    {
      snmpfsal_handle_t *dir_entry = (snmpfsal_handle_t *) &pdirent[cur_nb_entries].handle;
      snmpfsal_cookie_t *dir_cookie = (snmpfsal_cookie_t *) &pdirent[cur_nb_entries].cookie;

      /* First, we proceed a GET request  */
      req_opt.request_type = SNMP_MSG_GET;

      TakeTokenFSCall();

      rc = IssueSNMPQuery(dir_descriptor->p_context, last_listed.data.oid_tab,
                          last_listed.data.oid_len, &req_opt);

      ReleaseTokenFSCall();

      if(rc != SNMP_ERR_NOERROR && snmp2fsal_error(rc) != ERR_FSAL_NOENT)
        {
          LogDebug(COMPONENT_FSAL,
                   "SNMP GET request failed: error=%d, snmp_errno=%d, errno=%d, msg=%s",
                   rc, snmp_errno, errno, snmp_api_errstring(rc));
          Return(snmp2fsal_error(rc), rc, INDEX_FSAL_readdir);
        }
      else if(snmp2fsal_error(rc) != ERR_FSAL_NOENT)
        {

          p_curr_var = GetNextResponse(dir_descriptor->p_context);

          /* Then test if the object exists  */
          if(p_curr_var != NULL
             && p_curr_var->type != SNMP_NOSUCHOBJECT
             && p_curr_var->type != SNMP_NOSUCHINSTANCE
             && p_curr_var->type != SNMP_ENDOFMIBVIEW)
            {
              FSAL_OID_DUP(dir_entry, p_curr_var->name,
                           p_curr_var->name_length);
              dir_entry->data.object_type_reminder = FSAL_NODETYPE_LEAF;

              /* object cookie is the hypothetic next object at the same level */
              FSAL_OID_DUP(dir_cookie, p_curr_var->name,
                           p_curr_var->name_length);
              FSAL_OID_INC(dir_cookie);

              cur_node =
                  GetMIBNode(dir_descriptor->p_context, dir_entry,
                             FALSE);

              /* build the label */
              rc = snmp_object2name(p_curr_var, cur_node, dir_entry,
                                    &pdirent[cur_nb_entries].name);

              if(rc)
                Return(rc, 0, INDEX_FSAL_readdir);

              /* when a node does not exist, we take its nearest parent's rights */
              if(cur_node == NULL)
                nearest_node =
                    GetMIBNode(dir_descriptor->p_context, dir_entry,
                               TRUE);
              else
                nearest_node = cur_node;

              if(isFullDebug(COMPONENT_FSAL))
                {
                  LogFullDebug(COMPONENT_FSAL,
                               "FOUND A DIRECT CHILD (LEAF) = %s, parent_oid_len=%zu, oid_len=%zu, index=%d",
                               pdirent[cur_nb_entries].name.name, dir_descriptor->node_handle.data.oid_len,
                               p_curr_var->name_length, p_curr_var->index);
                  if(nearest_node)
                    LogFullDebug(COMPONENT_FSAL, "type = %#X, last oid=%ld",
                                 nearest_node->type,
                                 p_curr_var->name[p_curr_var->name_length - 1]);
                }

              /* set entry attributes  */
              if(get_attr_mask)
                {
                  pdirent[cur_nb_entries].attributes.asked_attributes = get_attr_mask;
                  rc = snmp2fsal_attributes(dir_entry, p_curr_var,
                                            nearest_node,
                                            &pdirent[cur_nb_entries].attributes);

                  if(rc != ERR_FSAL_NO_ERROR)
                    {
                      FSAL_CLEAR_MASK(pdirent[cur_nb_entries].attributes.
                                      asked_attributes);
                      FSAL_SET_MASK(pdirent[cur_nb_entries].attributes.asked_attributes,
                                    FSAL_ATTR_RDATTR_ERR);
                    }
                }

              /* link entries together */
              pdirent[cur_nb_entries].nextentry = NULL;
              if(cur_nb_entries > 0)
                pdirent[cur_nb_entries - 1].nextentry = &pdirent[cur_nb_entries];

              /* copy hypothetic next entry to cookie and increment nb_entries  */
              FSAL_OID_DUP(&last_listed, dir_cookie->data.oid_tab,
                           dir_cookie->data.oid_len);
              cur_nb_entries++;

              /* restart a sequence from GET request  */
              continue;
            }
        }

      /* the entry has not been found, we can look for the next child */

      req_opt.request_type = SNMP_MSG_GETNEXT;

      TakeTokenFSCall();

      rc = IssueSNMPQuery(dir_descriptor->p_context, last_listed.data.oid_tab,
                          last_listed.data.oid_len, &req_opt);

      ReleaseTokenFSCall();

      if(rc != SNMP_ERR_NOERROR && snmp2fsal_error(rc) != ERR_FSAL_NOENT)
        {
          LogDebug(COMPONENT_FSAL,
                   "SNMP GETNEXT request failed: error=%d, snmp_errno=%d, errno=%d, msg=%s",
                   rc, snmp_errno, errno, snmp_api_errstring(rc));
          Return(snmp2fsal_error(rc), rc, INDEX_FSAL_readdir);
        }
      else if(snmp2fsal_error(rc) == ERR_FSAL_NOENT)
        {
          bool_eod = TRUE;
          break;
        }

      p_curr_var = GetNextResponse(dir_descriptor->p_context);

      if(p_curr_var == NULL
         || p_curr_var->type == SNMP_NOSUCHOBJECT
         || p_curr_var->type == SNMP_NOSUCHINSTANCE
         || p_curr_var->type == SNMP_ENDOFMIBVIEW)
        {
          bool_eod = TRUE;
          break;
        }

      /* check if the response is under the root (else, end of dir is reached)  */
      if(IsSNMPChild
         (dir_descriptor->node_handle.data.oid_tab, dir_descriptor->node_handle.data.oid_len,
          p_curr_var->name, p_curr_var->name_length))
        {
          /* if the object is exactly 1 level under the dir, we insert it in the list */
          if(p_curr_var->name_length == dir_descriptor->node_handle.data.oid_len + 1)
            {
              FSAL_OID_DUP(dir_entry, p_curr_var->name,
                           p_curr_var->name_length);
              dir_entry->data.object_type_reminder = FSAL_NODETYPE_LEAF;

              /* object cookie is the hypothetic next object */
              FSAL_OID_DUP(dir_cookie, p_curr_var->name,
                           p_curr_var->name_length);
              FSAL_OID_INC(dir_cookie);

              cur_node =
                  GetMIBNode(dir_descriptor->p_context, dir_entry,
                             FALSE);

              /* build the label */
              rc = snmp_object2name(p_curr_var, cur_node, dir_entry,
                                    &pdirent[cur_nb_entries].name);

              if(rc)
                Return(rc, 0, INDEX_FSAL_readdir);

              /* when a node does not exist, we take its nearest parent's rights */
              if(cur_node == NULL)
                nearest_node =
                    GetMIBNode(dir_descriptor->p_context, dir_entry,
                               TRUE);
              else
                nearest_node = cur_node;

              if(isFullDebug(COMPONENT_FSAL))
                {
                  LogFullDebug(COMPONENT_FSAL,
                               "FOUND A DIRECT CHILD (LEAF) = %s, parent_oid_len=%zu, oid_len=%zu, index=%d",
                               pdirent[cur_nb_entries].name.name, dir_descriptor->node_handle.data.oid_len,
                               p_curr_var->name_length, p_curr_var->index);
                  if(nearest_node)
                    LogFullDebug(COMPONENT_FSAL, "type = %#X, last oid=%ld",
                                 nearest_node->type,
                                 p_curr_var->name[p_curr_var->name_length - 1]);
                }

              /* set entry attributes  */
              if(get_attr_mask)
                {
                  pdirent[cur_nb_entries].attributes.asked_attributes = get_attr_mask;
                  rc = snmp2fsal_attributes(dir_entry, p_curr_var,
                                            nearest_node,
                                            &pdirent[cur_nb_entries].attributes);

                  if(rc != ERR_FSAL_NO_ERROR)
                    {
                      FSAL_CLEAR_MASK(pdirent[cur_nb_entries].attributes.
                                      asked_attributes);
                      FSAL_SET_MASK(pdirent[cur_nb_entries].attributes.asked_attributes,
                                    FSAL_ATTR_RDATTR_ERR);
                    }
                }

              /* link entries together */
              pdirent[cur_nb_entries].nextentry = NULL;
              if(cur_nb_entries > 0)
                pdirent[cur_nb_entries - 1].nextentry = &pdirent[cur_nb_entries];

              /* copy hypothetic next entry to cookie and increment nb_entries  */
              FSAL_OID_DUP(&last_listed, dir_cookie->data.oid_tab,
                           dir_cookie->data.oid_len);
              cur_nb_entries++;

              /* restart a sequence from GET request  */
              continue;
            }
          else                  /* directory item */
            {

              /* it the returned subdirectory is "smaller" than the cookie, we skip it
               * and incrment the cookie.
               */
              if(fsal_oid_cmp(p_curr_var->name, last_listed.data.oid_tab, last_listed.data.oid_len)
                 < 0)
                {
                  FSAL_OID_INC(&last_listed);
                  continue;
                }

              /* we found a new subsirectory */

              FSAL_OID_DUP(dir_entry, p_curr_var->name,
                           dir_descriptor->node_handle.data.oid_len + 1);
              dir_entry->data.object_type_reminder = FSAL_NODETYPE_NODE;

              /* object cookie is the next potentiel object at this level */
              FSAL_OID_DUP(dir_cookie,
                           dir_entry->data.oid_tab,
                           dir_entry->data.oid_len);
              FSAL_OID_INC(dir_cookie);

              /* try to get the associated MIB node  */
              cur_node =
                  GetMIBNode(dir_descriptor->p_context, dir_entry,
                             FALSE);

              /* build the label */
              rc = snmp_object2name(NULL, cur_node, dir_entry,
                                    &pdirent[cur_nb_entries].name);

              if(rc)
                Return(rc, 0, INDEX_FSAL_readdir);

              /* when a node does not exist, we take its nearest parent's rights */
              if(cur_node == NULL)
                nearest_node =
                    GetMIBNode(dir_descriptor->p_context, dir_entry,
                               TRUE);
              else
                nearest_node = cur_node;

              LogFullDebug(COMPONENT_FSAL, "FOUND A NEW SUBDIR = %s (%ld) (cookie->%ld)",
                           pdirent[cur_nb_entries].name.name,
                           dir_entry->data.oid_tab[dir_descriptor->node_handle.data.oid_len],
                           dir_cookie->data.oid_tab[dir_cookie->data.oid_len - 1]);

              /* set entry attributes  */
              if(get_attr_mask)
                {
                  pdirent[cur_nb_entries].attributes.asked_attributes = get_attr_mask;
                  rc = snmp2fsal_attributes(dir_entry, NULL,
                                            nearest_node,
                                            &pdirent[cur_nb_entries].attributes);

                  if(rc != ERR_FSAL_NO_ERROR)
                    {
                      FSAL_CLEAR_MASK(pdirent[cur_nb_entries].attributes.
                                      asked_attributes);
                      FSAL_SET_MASK(pdirent[cur_nb_entries].attributes.asked_attributes,
                                    FSAL_ATTR_RDATTR_ERR);
                    }
                }

              /* link entries together */
              pdirent[cur_nb_entries].nextentry = NULL;
              if(cur_nb_entries > 0)
                pdirent[cur_nb_entries - 1].nextentry = &pdirent[cur_nb_entries];

              /* copy last listed item to cookie and increment nb_entries  */
              FSAL_OID_DUP(&last_listed, dir_cookie->data.oid_tab,
                           dir_cookie->data.oid_len);
              cur_nb_entries++;

              /* end of subdir processing */

            }

        }
      else                      /* no more objects in the directory tree */
        {
          bool_eod = TRUE;
          break;
        }

      /* loop until the requested count is reached
       * or the end of dir is reached.
       */
    }

  /* setting output vars : end_position, nb_entries, end_of_dir  */
  *end_of_dir = bool_eod;

  memset(end_position, 0, sizeof(snmpfsal_cookie_t));
  FSAL_OID_DUP(end_position, last_listed.data.oid_tab, last_listed.data.oid_len);

  *nb_entries = cur_nb_entries;

  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readdir);

}