Using snmpgetnext on a table - snmp

I am writing my own MIB Module containing a table with 2 columns. Using snmptable works just fine and retrieves all values of the table with all the rows.
But with snmpgetnext I can only retrieve the first row of the table.
snmpgetnext -v2c -c public localhost sensorTable
MY-PERSONAL-MIB::sensorVoltage."1" = STRING: "2.3V"
To retrieve the next value I must run:
snmpgetnext -v2c -c public localhost sensorVoltage."2"
MY-PERSONAL-MIB::sensorTemperature."1" = "3.2C"
Running snmpgetnext -v2c -c public localhost sensorVoltage."1" would result in sensorVoltage."1" again, the same for sensorTemperature."1".
snmpgetnext -v2c -c public localhost sensorTemperature."2"
SNMPv2-MIB::snmpSetSerialNo.0 = INTEGER: 1664041205
Also, I ran snmptable -CB so the manager only uses GETNEXT to retrieve the table values. This works fine as well.
So why can't I retrieve the single values with a simple snmpgetnext request?
As last, snmpget doesn't work at all. I get the following error:
snmpget -v2c -c publicl localhost sensorTemperature."1"
MY-PERSONAL-MIB::sensorTemperature.1 = No such Instance currently exists at this OID
At last, my code I use for my MIB-Module. I use the handler to read data from a file and create a table struct through it. I tried using snmpgetnext with a table created through the initialization routine resulting in the same problem, so the handler routine shouldn't be the issue here but I still appended it just for completion and well, who knows!
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "sensorTable.h"
#define firstEntryRow 2
netsnmp_table_data_set *table_set;
void
initialize_table_sensorTable(void)
{
netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_X_SOCKET, "tcp:localhost:705");
const oid sensorTable_oid[] = { 1 ,3 ,6 ,1 ,4 ,1 ,8072 ,1259 ,1 ,1 };
table_set = netsnmp_create_table_data_set("sensorTable");
netsnmp_table_row *row;
table_set->allow_creation = 1;
DEBUGMSGTL(("initialize_table_sensorTable",
"adding indexes to table sensorTable\n"));
netsnmp_table_dataset_add_index(table_set,
ASN_OCTET_STR);
DEBUGMSGTL(("initialize_table_sensorTable",
"adding column types to table sensorTable\n"));
netsnmp_table_set_multi_add_default_row(table_set,
COLUMN_SENSORVOLTAGE, ASN_OCTET_STR, 1,
NULL, 0,
COLUMN_SENSORTEMPERATURE, ASN_OCTET_STR, 1,
NULL, 0,
0);
netsnmp_register_table_data_set(netsnmp_create_handler_registration("sensorTable", sensorTable_handler,
sensorTable_oid,
OID_LENGTH(sensorTable_oid),
HANDLER_CAN_RWRITE),
table_set, NULL);
row = netsnmp_create_table_data_row();
netsnmp_table_row_add_index(row, ASN_OCTET_STR, "1",
strlen("1"));
netsnmp_set_row_column(row, 2, ASN_OCTET_STR,
"5.9V", strlen("5.9V"));
netsnmp_set_row_column(row, 3, ASN_OCTET_STR,
"21.5C", strlen("21.5C"));
netsnmp_table_dataset_add_row(table_set, row);
}
void
init_sensorTable(void)
{
initialize_table_sensorTable();
}
int
sensorTable_handler(
netsnmp_mib_handler *handler,
netsnmp_handler_registration *reginfo,
netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests) {
netsnmp_table_row *row, *tempRow;
if( table_set != NULL )
{
for ( tempRow = table_set->table->first_row;
tempRow; tempRow = tempRow->next )
{
row = netsnmp_table_data_set_get_first_row(table_set);
netsnmp_table_dataset_remove_row(table_set, row);
}
}
/* Start reading "input.txt */
char sensorValues[32];
char *singleValue;
FILE *f = fopen("/home/supra/Desktop/input.txt", "r");
/* check if the file was found */
if( f == NULL ) {
printf("Error opening file!\n");
exit(EXIT_FAILURE);
}
/* check if the file is empty */
if ( fgets( sensorValues, sizeof(sensorValues), f) == NULL )
{
printf("Warning: File is empty!\n");
exit(EXIT_FAILURE);
}
/* if the file is not empty, create a row and start
* breaking the string into words. Fill the row with the words
* and add it to the table. */
do
{
int rowEntries = firstEntryRow;
singleValue = strtok( sensorValues, " ");
row = netsnmp_create_table_data_row();
netsnmp_table_row_add_index(row, ASN_OCTET_STR, singleValue, strlen(singleValue) );
singleValue = strtok( NULL, " ");
/* Fill the row with values */
while(singleValue != NULL)
{
netsnmp_set_row_column(row, rowEntries, ASN_OCTET_STR, singleValue, strlen(singleValue) );
rowEntries++;
singleValue = strtok(NULL, " ");
}
netsnmp_table_dataset_add_row(table_set, row);
} while( fgets( sensorValues, sizeof(sensorValues), f) != NULL);
fclose(f);
return SNMP_ERR_NOERROR;
}

Regarding :
So why can't I retrieve the single values with a simple snmpgetnext request?
Quoting man snmpgetnext
DESCRIPTION
snmpget is an SNMP application that uses the SNMP GETNEXT request to query for information on a network entity. One or more
object identifiers (OIDs) may
be given as arguments on the command line. Each variable name is given in the format specified in variables(5). For each one, the
variable that is lexicographically "next" in the remote entity's MIB will be returned. For example:
snmpgetnext -c public zeus interfaces.ifTable.ifEntry.ifType.1
will retrieve the variable
interfaces.ifTable.ifEntry.ifType.2
In other words its job is to get one thing back.
If you want to use it to get a full table, you need to invoke it multiple times. Quoting man page for snmptable :
snmptable is an SNMP application that repeatedly uses the SNMP GETNEXT or GETBULK requests to query for information on a network entity.

Related

How to get mode name using XCB?

In Xlib the structure XRRModeInfo contains, aside from nameLength field, the name itself. But in XCB the corresponding structure xcb_randr_mode_info_t only contains name_len, and there seems to be no function to get actual name string.
I do see all the mode names in the string returned by xcb_randr_get_screen_resources_names(), but they are all concatenated, and I don't know how to find the offset of a particular mode in this string.
So, how can I get the mode name using XCB?
I do see all the mode names in the string returned by xcb_randr_get_screen_resources_names(), but they are all concatenated, and I don't know how to find the offset of a particular mode in this string.
You have the length of the individual names and you know the length of each name, so you just have to count bytes:
#include <stdio.h>
#include <xcb/randr.h>
int main()
{
xcb_connection_t *c = xcb_connect(NULL, NULL);
xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
// TODO: Error handling
// TODO: Checking if the RandR extension is available
xcb_randr_get_screen_resources_reply_t *reply =
xcb_randr_get_screen_resources_reply(c,
xcb_randr_get_screen_resources(c, screen->root),
NULL);
xcb_randr_mode_info_iterator_t iter = xcb_randr_get_screen_resources_modes_iterator(reply);
uint8_t *names = xcb_randr_get_screen_resources_names(reply);
while (iter.rem) {
xcb_randr_mode_info_t *mode = iter.data;
printf("Mode %d has size %dx%d and name %.*s\n",
mode->id, mode->width, mode->height, mode->name_len, names);
names += mode->name_len;
xcb_randr_mode_info_next(&iter);
}
free(reply);
xcb_disconnect(c);
return 0;
}

How to compare enum in arduino?

I am facing an issue with arduino, since I want to change the state of my device using an enum, but it doesn't seeem to work, my code looks like below. I am not entirely sure where it goes wrong, I think as well that the comparison between settingTo and toP2P could be wrong?
Thanks in advance!
String toP2P = "503250"
String toABP = "414250";
String settingTo = LoRa_Tx.dataRX.substring(indx);
if( settingTo == toP2P ) {
//switching to P2P
Serial.println("current mode 1 "+(String) LoRa_Tx.current_modeRxTx);
if(LoRa_Tx.current_modeRxTx != LoRa_Tx.LoRaMod){
LoRa_Tx.current_modeRxTx = LoRa_Tx.LoRaMod;
}
} else if(settingTo == toABP){
//switching to ABP
if(LoRa_Tx.current_modeRxTx != LoRa_Tx.LoRaWan){
LoRa_Tx.current_modeRxTx = LoRa_Tx.LoRaWan;}
}
}
My class has the enum defined as
typedef enum modeRxTx{LoRaMod, LoRaWan, Idle} ;
modeRxTx current_modeRxTx = Idle;
In general, you should avoid the String class, as it will eventually cause problems. However, given that the LoRa_Tx appears to have a String member, here is one way to watch for those two modes:
if ((indx > -1) && (LoRa_Tx.dataRx.length() >= indx+5)) {
const char *settingTo = &LoRa_Tx.dataRx.c_str()[ indx ];
if ( strncmp_P( settingTo, PSTR("503250"), 6 ) == 0 ) {
//switching to P2P
Serial.print( F("current mode 1 ") ); // <-- saves RAM!
Serial.println( LoRa_Tx.current_modeRxTx );
if(LoRa_Tx.current_modeRxTx != LoRa_Tx.LoRaMod) {
LoRa_Tx.current_modeRxTx = LoRa_Tx.LoRaMod;
}
} else if ( strncmp_P( settingTo, PSTR("414250"), 6 ) == 0 ) {
//switching to ABP
if(LoRa_Tx.current_modeRxTx != LoRa_Tx.LoRaWan) {
LoRa_Tx.current_modeRxTx = LoRa_Tx.LoRaWan;
}
}
}
Instead of creating a substring, it just makes a pointer to the actual characters of data_Rx. The c_str() function returns a pointer to the first character (zero-based index) or the String, and the [ indx ] is the first of the mode number characters. Finally, the & is a pointer to the first mode number character.
Next, it uses a standard library function, strncmp_P (documented here), to compare those mode number characters with the modes you are looking for, and it only compares up to 6 characters. You don't say if there's a delimiter after "503250", so I don't know if "50325076" is possible and should be rejected.
The strncmp_P expects to get a PROGMEM string as the second argument, not just a const char *, so that's what the PSTR macro does. This saves RAM because the PSTR will be stored and compared from FLASH memory (aka PROGMEM). The Serial.print statements should use the F() macro for the same reason.

How to get a complete row data from VTS?

I am using VTS tables for passing data from 1 script to other. Now, I want to get data from all the column for particular row and print that.
I tried couple of VTC commands but unfortunately that did not work.
Command I tried:-
rc = lrvtc_query_row(vuser);
lr_output_message("Col1:- %s", lr_eval_string("{Col1}"));
can you please suggest where I got wrong or provide me a ready code to print he Row from the VTS table.
First you have to enable API access by click the "Enable" button from VTS Web Admin page, then here's the sample:
Action()
{
char* vts_ip = "127.0.0.1";
int vts_port = 8888;
char **colNames = NULL;
char **rowData = NULL;
int row_index = 1;
int i;
PVCI2 pvci = vtc_connect(vts_ip, vts_port, VTOPT_KEEP_ALIVE );
vtc_query_row(pvci, row_index, &colNames, &rowData);
for(i=0; colNames && colNames[i]; ++i){
lr_output_message("%s: %s", colNames[i], rowData[i]);
}
vtc_free_list(colNames);
vtc_free_list(rowData);
return 0;
}

Create Email address from names Compiler Design

Creating email addresses form names
You have given a file containing names of several persons. The file will have exactly one name is each line. You need to create email address ending with #bitmesra.ac.in from those names.
the rule for creating email address is defined below: A name will be expressed in the following form:
............
Let F(s) denote the first character of string s.
so, email id will be F(string 1)F(string 2)........._lastString#bitmesra.ac.in
Some names and their corresponding email id's are listed below as an example
Sachin Ramesh Tendulkar s_r_tendulkar#bitmesra.ac.in
Rahul S Dravid r_s_dravid#bitmesra.ac.in
You need to generate a grammer for this.
note: there may multiple spaces b/w names.
My Code is here
#include<cstdio>
#include<cstring>
#include<cctype>
int main()
{
char str1[100],str2[100];
char str3[] = "#bitmesra.ac.in";
while(gets(str1))
{
int index,k=0;
str2[k] = tolower(str1[0]);
for(int i=1;i<strlen(str1);i++)
{
if(str1[i]==' ')
{
index = i;
if(isalpha(str1[i+1]))
{
k++;
str2[k] = '_';
k++;
str2[k] = tolower(str1[i+1]);
}
}
}
index= index + 2;
for(int i=index;str1[i]!='\0';i++)
{
k++;
str2[k] = tolower(str1[i]);
}
str2[++k] = '\0';
strcat(str2,str3);
printf("%s\n",str2);
}
return 0;
}
How to write CFG Grammar For this.....
What about something like:
optnamelist: /* file can be empty */
| namelist /* do nothing */
namelist: nameseq NL /* process vector */
| namelist NL nameseq /* process vector */
nameseq: name /* create vector and add element 1 */
| nameseq name /* add element to vector */
The lexer should take care of white spaces (eat them). The NL token is a sequence of one or more newlines.
If you add names to the end of a vector, you'll have to process it backward.
Your code implies you're writing this in C. So you could use a fixed sized Vector, e.g.
#define MAX_NAMES 100 /* this will probably be enough :-) */
static int actpos;
static char *myVector[MAX_NAMES];
...
/* "create" vector */
memset(myVector, 0, MAX_NAMES * sizeof(char *));
actpos = 0;
...
/* add name to vector */
myVector[actpos] = strdup($1 /* or $2 */);
if (myVector[actpos) == NULL) ... /* out of memory */
actpos++;
if (actpos >= MAX_NAMES) ... /* name too long */
...
/* process vector */
for (i = actpos - 1; i > 0; --i) {
/* add myVector[i][0] to e-mail address */
free(myVector[i]);
}
/* add myVector[0] to e-mail address */
free(myVector[0]);

mariadb jdbc driver blob update not supported

After I replaced mysql jdbc driver 5.1 with mariadb jdbc driver 1.1.5 and tested the existing code base that connected with MySQL Server 5.0 and MariaDB Server 5.2, everything works fine except a JDBC call to update a blob field in a table.
The blob field contains XML configuration file. It can be read out, and convert to xml and insert some values.
Then convert it to ByteArrayInputStream object, and call the method
statement.updateBinaryStream(columnLabel, the ByteArrayInputStream object, its length)
but an exception is thrown:
Perhaps you have some incorrect SQL syntax?
java.sql.SQLFeatureNotSupportedException: Updates are not supported
at
org.mariadb.jdbc.internal.SQLExceptionMapper.getFeatureNotSupportedException(SQLExceptionMapper.java:165)
at
org.mariadb.jdbc.MySQLResultSet.updateBinaryStream(MySQLResultSet.java:1642)
at
org.apache.commons.dbcp.DelegatingResultSet.updateBinaryStream(DelegatingResultSet.java:511)
I tried updateBlob method, the same exception was thrown.
The code works well with mysql jdbc driver 5.1.
Any suggestions on how to work around with this situation?
See the ticket updating blob with updateBinaryStream, which in commnet states that it isn't supported.
A workaround would be to use two SQL statements. One which is used to select the data and other to update the data. Something like this:
final Statement select = connection.createStatement();
try {
final PreparedStatement update = connection.prepareStatement( "UPDATE table SET blobColumn=? WHERE idColumn=?" );
try {
final ResultSet selectSet = select.executeQuery( "SELECT idColumn,blobColumn FROM table" );
try {
final int id = selectSet.getInt( "idColumn" );
final InputStream stream = workWithSTreamAndRetrunANew( selectSet.getBinaryStream( "blobColumn" ) ) );
update.setBinaryStream( 1,stream );
update.setInt( 2,id );
update.execute();
}
finally {
if( selectSet != null )
selectSet.close();
}
}
finally {
if( update != null )
update.close();
}
}
finally {
if( select != null )
select.close();
}
But be aware that you need some information how to uniquely identify a table entry, in this example the column idColumn was used for that purpose. Furthermore is you stored empty stream in the
database you might get an SQLException.
A simpler work around is using binary literals (like X'2a4b54') and concatenation (UPDATE table SET blobcol = blobcol || X'2a4b54') like this:
int iBUFSIZ = 4096;
byte[] buf = new byte[iBUFSIZ];
int iLength = 0;
int iUpdated = 1;
for (int iRead = stream.read(buf, 0, iBUFSIZ);
(iUpdated == 1) && (iRead != -1) && (iLength < iTotalLength);
iRead = stream.read(buf, 0, iBUFSIZ))
{
String sValue = "X'" + toHex(buf,0,iRead) + "'";
if (iLength > 0)
sValue = sBlobColumn + " || " + sValue;
String sSql = "UPDATE "+sTable+" SET "+sBlobColumn+"= "+sValue;
Statement stmt = connection.createStatement();
iUpdated = stmt.executeUpdate(sSql);
stmt.close();
}

Resources