The following example program, monitor.c, demonstrates the steps outlined in the previous section. Commentary for each step follows the example.
/*monitor.c
** Example program showing logic flow of Monitor Client Library
** application. This example assumes the use of an ANSI C
** compliant compiler. This program creates two connections
** to the Monitor Server. Data is extracted from one connection
** at the beginning and end of the monitoring session.
** Data is extracted from the other connection every
** SAMPLE_INTERVAL seconds NUM_OF_SAMPLES times.
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
/* The mcpublic.h header file contains function prototypes, etc.
** for monitor client library functions. It also includes a
** header file called mctypes.h, which defines the datatypes
** used for monitor client library applications.
*/
#include "mcpublic.h"
#define NUM_OF_SAMPLES 10
#define SAMPLE_INTERVAL 5
#define NUM_SERVER_DATA_ITEMS 3
#define NUM_DB_INFO_ITEMS 14
#define NUM_NW_INFO_ITEMS 6
#define OPTIONAL_CALLS -1
/*Error signals*/
#define VIEW_NONEXISTENT -1
#define CONNECT_NONEXISTENT -1
SMC_RETURN_CODE main (SMC_INT argc, SMC_CHARP argv[])
{
SMC_VALUE_UNION serverNameUnion;
SMC_VALUE_UNION userNameUnion;
SMC_VALUE_UNION passwordUnion;
SMC_VALUE_UNION interfacesFileUnion;
SMC_VALUE_UNION workUnion;
SMC_VALUE_UNION returnedDataUnion;
SMC_CONNECT_ID connect1_id;
SMC_CONNECT_ID connect2_id;
SMC_VIEW_ID server_view_id;
SMC_VIEW_ID db_info_view_id;
SMC_VIEW_ID nw_info_view_id;
SMC_RETURN_CODE ret;
SMC_DATAITEM_TYPE dataitem_type; /*Holds data item type
returned by get_dataitem_type
function call*/
/*Needed if alarms and filters are used */
#ifdef OPTIONAL_CALLS
SMC_ALARM_ID alarm_id;
SMC_FILTER_ID filter_id;
SMC_CHARP filter_strings[2]; /*datatype is pointer to
string. This is an array
of pointers.*/
#endif
SMC_SIZET row,num_of_rows,item; /*This is an integer data
type*/
SMC_SIZET outputLength; /*Length of output returned
by smc_connect_props
function call*/
/*
** Definition of SMC_DATAITEM_STRUCT datatype
*/
SMC_DATAITEM_STRUCT server_info_view[NUM_SERVER_DATA_ITEMS];
SMC_DATAITEM_STRUCT db_info_view[NUM_DB_INFO_ITEMS];
SMC_DATAITEM_STRUCT nw_bytes_view[NUM_NW_INFO_ITEMS];
SMC_VALUE_UNION server_data[NUM_SERVER_DATA_ITEMS];
SMC_VALUE_UNION db_data[NUM_DB_INFO_ITEMS];
SMC_VALUE_UNION nw_data[NUM_NW_INFO_ITEMS];
/*Callback function prototypes. Actual functions are defined
** below.
*/
SMC_VOID errorCallback(SMC_CONNECT_ID,SMC_COMMAND_ID,SMC_VOIDP);
SMC_VOID alarmCallback(SMC_CONNECT_ID,SMC_COMMAND_ID,SMC_VOIDP);
SMC_BOOL explicitInterfacesFile = FALSE;
int index,iterations;
/*
** These are labels used when printing out data returned by the
** database info view.
*/
SMC_CHARP db_info_labels[NUM_DB_INFO_ITEMS] = {
"Database ID: ",
"Object ID: ",
"Database name: ",
"Object name: ",
"Page hit percent: ",
"Page I/O: ",
"Page logical reads this sample: ",
"Page logical reads this session: ",
"Page logical read rate this sample: ",
"Page logical read rate this session: ",
"Page physical reads this sample: ",
"Page physical reads this session: ",
"Page physical read rate this sample: ",
"Page physical read rate this session: "
};
/*
** These are labels used when printing out data returned by
** network info view.
*/
SMC_CHARP nw_info_labels[NUM_NW_INFO_ITEMS] = {
"Network bytes received this sample: ",
"Network bytes received this session: ",
"Network bytes sent this sample: ",
"Network bytes sent this session: ",
"Network byte I/O rate this sample: ",
"Network byte I/O rate this session: "
};
if (argc <5){
printf("Usage <%s> -U <user_name> [-P <password>]\
-S <monserver name> [-I <interfaces_file>]\n",argv[0]);
exit(1);
}
/*
** Connect to a server.
*/
For commentary, see “Step 2: Connecting to a server”.
/*
** Allocate first connection
*/
ret=smc_connect_alloc(errorCallback,
&connect1_id /*Pointer to connect_id!*/
);
if (ret != SMC_RET_SUCCESS) {
printf("Attempt to allocate first connection failed \
with error %d.\n",ret);
exit(1);
}
/*
** Allocate second connection
*/
ret=smc_connect_alloc(errorCallback,
&connect2_id /*Pointer to connect_id!*/
);
if (ret != SMC_RET_SUCCESS) {
printf("Attempt to allocate second connection failed \
with error %d.\n",ret);
exit(1);
}
/*
** Set mandatory and some optional connection properties.
** Mandatory connection properties are user name, server name,
** and password if user password is not NULL. If interfaces
** file name is not set, default is "interfaces" in directory
** pointed to by $SYBASE environment variable.
For commentary, see “Required connection properties”.
*/
for (index=1;index<argc;index++) {
/*User name*/
if (strncmp(argv[index],"-U",2) == 0) {
userNameUnion.stringValue = argv[index+1];
ret=smc_connect_props(connect1_id,
SMC_PROP_ACT_SET, /*Property action*/
SMC_PROP_USERNAME,/*Property*/
&userNameUnion, /*Note that union,
not member of union,
is used for
property value*/
SMC_NULLTERM, /*Indicates null-
terminated string
for buffer length*/
NULL /*Use NULL when
setting a property*/
);
} /*End if argument is user name*/
if (ret != SMC_RET_SUCCESS) {
printf("Could not set user name.\n");
exit(SMC_RET_FAILURE);
}
/*Password. Default password is a null string*/ if (strncmp(argv[index],"-P",2) == 0) {
passwordUnion.stringValue = argv[index+1];
ret=smc_connect_props(connect1_id,
SMC_PROP_ACT_SET, /*Property action*/
SMC_PROP_PASSWORD,/*Property*/
&passwordUnion, /*Note that union,
not member of union,
is used for
property value*/
SMC_NULLTERM, /*Indicates null-
terminated string
for buffer length*/
NULL /*Use NULL when
setting a property*/
);
} /*End if argument is password*/
if (ret != SMC_RET_SUCCESS) {
printf("Could not set password.\n");
exit(SMC_RET_FAILURE);
}
/*Server name*/
if (strncmp(argv[index],"-S",2) == 0) {
serverNameUnion.stringValue = argv[index+1];
ret=smc_connect_props(connect1_id,
SMC_PROP_ACT_SET, /*Property action*/
SMC_PROP_SERVERNAME,/*Property*/
&serverNameUnion, /*Note that union,
not member of union,
is used for
property value*/
SMC_NULLTERM, /*Indicates null-
terminated string
for buffer length*/
NULL /*Use NULL when
setting a property*/
);
} /*End if argument is server name*/
if (ret != SMC_RET_SUCCESS) {
printf("Could not set server name.\n");
exit(SMC_RET_FAILURE);
}
/*Interfaces file. If unspecified, $SYBASE/interfaces is used*/
if (strncmp(argv[index],"-I",2) == 0) {
interfacesFileUnion.stringValue = argv[index+1];
ret=smc_connect_props(connect1_id,
SMC_PROP_ACT_SET, /*Property action*/
SMC_PROP_IFILE, /*Property*/
&interfacesFileUnion, /*Note that
pointer to union,
not member of
union,is used for
property value*/
SMC_NULLTERM, /*Indicates null-
terminated string
for buffer length*/
NULL /*Use NULL when
setting a property*/
);
explicitInterfacesFile = TRUE;
} /*End if argument is interfaces file pathname*/
if (ret != SMC_RET_SUCCESS) {
printf("Could not set interfaces file name.\n");
printf("Using default interfaces file.\n");
}
} /*End for loop getting connection properties
from command-line arguments*/
/*
** Optional smc_get_connect_props call that sets a pointer to be
** passed to error callback. In this case, the pointer is to a
** string that tells which connection encountered the error.
*/
workUnion.voidpValue = "first connection"; /*Call to set user
data handle looks
for value to set in
void pointer member
of union.*/
ret=smc_connect_props(connect1_id,SMC_PROP_ACT_SET,\
SMC_PROP_USERDATA,&workUnion,SMC_NULLTERM,NULL);
if (ret != SMC_RET_SUCCESS){
printf("smc_connect_props call failed to \
set userDataHandle.\n");
}
/*
** Demonstration of "get" mode for smc_get_connect_props
*/
/*Check if user name has been set*/
ret=smc_connect_props(connect1_id,
SMC_PROP_ACT_GET,/*Property action is "get"*/
SMC_PROP_USERNAME,
&workUnion,
SMC_UNUSED, /*Length parameter ignored
on "get" operations*/
&outputLength /*Note this is a pointer!*/
);
if (ret != SMC_RET_SUCCESS) {
printf ("Could not get user name. Execution continuing.\n");
}
else {
if (outputLength == 0) {
printf("User name not set. Quitting execution.\n");
exit(SMC_RET_FAILURE);
}
else {
/*
** Application is responsible for freeing
** memory allocated to string member of SMC_VALUE_UNION by
** library.
*/
free(workUnion.stringValue);
}
}
/*Check if server name has been set*/
ret=smc_connect_props(connect1_id,
SMC_PROP_ACT_GET,/*Property action is "get"*/
SMC_PROP_SERVERNAME,
&workUnion,
SMC_UNUSED, /*Length parameter ignored
on "get" operations*/
&outputLength /*Note this is a pointer!*/
);
if (ret != SMC_RET_SUCCESS) {
printf ("Could not get server name. Execution continuing.\n");
}
else {
if (outputLength == 0) {
printf("Server name not set. Quitting execution.\n");
exit(SMC_RET_FAILURE);
}
else {
free(workUnion.stringValue);
}
}
/*
** Allocate properties for second connection. No need to
** repeat error checking.
*/
ret=smc_connect_props(connect2_id,SMC_PROP_ACT_SET, \
SMC_PROP_USERNAME,&userNameUnion,SMC_NULLTERM, NULL);
if (ret != SMC_RET_SUCCESS) {
printf("Could not set user name for second connection.\n");
exit(SMC_RET_FAILURE);
}
ret=smc_connect_props(connect2_id,SMC_PROP_ACT_SET, \
SMC_PROP_PASSWORD,&passwordUnion,SMC_NULLTERM,NULL);
if (ret != SMC_RET_SUCCESS) {
printf("Could not set password for second connection.\n");
exit(SMC_RET_FAILURE);
}
ret=smc_connect_props(connect2_id,SMC_PROP_ACT_SET, \
SMC_PROP_SERVERNAME,&serverNameUnion,SMC_NULLTERM,NULL);
if (ret != SMC_RET_SUCCESS) {
printf("Could not set server name for second connection.\n");
exit(SMC_RET_FAILURE);
}
if (explicitInterfacesFile) {
ret=smc_connect_props(connect2_id,SMC_PROP_ACT_SET, \
SMC_PROP_IFILE,&interfacesFileUnion,SMC_NULLTERM,NULL);
if (ret != SMC_RET_SUCCESS) {
printf("Could not set server name for second connection.\n");
exit(SMC_RET_FAILURE);
}
}
/*
** Optional smc_connect_props call to set user-defined pointer to
** be passed to error callback. This pointer points to a
** string that tells where the error callback was triggered.
*/
workUnion.voidpValue = "second connection"; /*Call to set user
data handle looks for
value to set in void
pointer member
of union.*/
ret=smc_connect_props(connect2_id,SMC_PROP_ACT_SET, \
SMC_PROP_USERDATA,&workUnion,SMC_NULLTERM,NULL);
if (ret != SMC_RET_SUCCESS){
printf("smc_connect_props call failed to set userDataHandle.\n");
}
/*
** Connect to monitor server
For commentary, see “Connecting to a server”.
*/
/*
** First connection
*/
ret=smc_connect_ex(connect1_id);
if (ret != SMC_RET_SUCCESS) {
printf("First connection failed to connect to \
monitor server.\n");
exit(SMC_RET_FAILURE);
}
/*
** Second connection
*/
ret=smc_connect_ex(connect2_id);
if (ret != SMC_RET_SUCCESS) {
printf("Second connection failed to connect to \
monitor server.\n");
exit(SMC_RET_FAILURE);
}
/*
** Create views on connections.
*/
For commentary, see “Step 3: creating a view”.
** Define views.
/*
** Each data item must be paired with a
** statistic type . View definitions are used in create_view
** calls after connecting to monitor server.
*/
/*This is a server-wide view that returns one row of data*/ server_info_view[0].dataItemName =SMC_NAME_SQL_SERVER_NAME;
server_info_view[0].dataItemStatType = SMC_STAT_VALUE_SAMPLE;
server_info_view[1].dataItemName = SMC_NAME_SQL_SERVER_VERSION;
server_info_view[1].dataItemStatType = SMC_STAT_VALUE_SAMPLE;
server_info_view[2].dataItemName = SMC_NAME_TIMESTAMP;
server_info_view[2].dataItemStatType = SMC_STAT_VALUE_SAMPLE;
/*
** This is a view with key and result data items that returns
** multiple rows of data.
*/
db_info_view[0].dataItemName = SMC_NAME_DB_ID; /*Key data items*/
db_info_view[0].dataItemStatType = SMC_STAT_VALUE_SAMPLE;
db_info_view[1].dataItemName = SMC_NAME_OBJ_ID;
db_info_view[1].dataItemStatType = SMC_STAT_VALUE_SAMPLE;
db_info_view[2].dataItemName = SMC_NAME_DB_NAME; /*Result data
items*/
db_info_view[2].dataItemStatType = SMC_STAT_VALUE_SAMPLE;
db_info_view[3].dataItemName = SMC_NAME_OBJ_NAME;
db_info_view[3].dataItemStatType = SMC_STAT_VALUE_SAMPLE;
db_info_view[4].dataItemName = SMC_NAME_PAGE_HIT_PCT;
db_info_view[4].dataItemStatType = SMC_STAT_VALUE_SAMPLE;
db_info_view[5].dataItemName =SMC_NAME_PAGE_IO;
db_info_view[5].dataItemStatType = SMC_STAT_VALUE_SAMPLE;
db_info_view[6].dataItemName = SMC_NAME_PAGE_LOGICAL_READ;
db_info_view[6].dataItemStatType = SMC_STAT_VALUE_SAMPLE;
db_info_view[7].dataItemName = SMC_NAME_PAGE_LOGICAL_READ;
db_info_view[7].dataItemStatType = SMC_STAT_VALUE_SESSION;
db_info_view[8].dataItemName = SMC_NAME_PAGE_LOGICAL_READ;
db_info_view[8].dataItemStatType = SMC_STAT_RATE_SAMPLE;
db_info_view[9].dataItemName = SMC_NAME_PAGE_LOGICAL_READ;
db_info_view[9].dataItemStatType = SMC_STAT_RATE_SESSION;
db_info_view[10].dataItemName = SMC_NAME_PAGE_PHYSICAL_READ;
db_info_view[10].dataItemStatType = SMC_STAT_VALUE_SAMPLE;
db_info_view[11].dataItemName = SMC_NAME_PAGE_PHYSICAL_READ;
db_info_view[11].dataItemStatType = SMC_STAT_VALUE_SESSION;
db_info_view[12].dataItemName = SMC_NAME_PAGE_PHYSICAL_READ;
db_info_view[12].dataItemStatType = SMC_STAT_RATE_SAMPLE;
db_info_view[13].dataItemName = SMC_NAME_PAGE_PHYSICAL_READ;
db_info_view[13].dataItemStatType = SMC_STAT_RATE_SESSION;
/*
** Another server-wide view
*/
nw_bytes_view[0].dataItemName = SMC_NAME_NET_BYTES_RCVD;
nw_bytes_view[0].dataItemStatType = SMC_STAT_VALUE_SAMPLE;
nw_bytes_view[1].dataItemName = SMC_NAME_NET_BYTES_RCVD;
nw_bytes_view[1].dataItemStatType = SMC_STAT_VALUE_SESSION;
nw_bytes_view[2].dataItemName = SMC_NAME_NET_BYTES_SENT;
nw_bytes_view[2].dataItemStatType = SMC_STAT_VALUE_SAMPLE;
nw_bytes_view[3].dataItemName = SMC_NAME_NET_BYTES_SENT;
nw_bytes_view[3].dataItemStatType = SMC_STAT_VALUE_SESSION;
nw_bytes_view[4].dataItemName = SMC_NAME_NET_BYTE_IO;
nw_bytes_view[4].dataItemStatType = SMC_STAT_RATE_SAMPLE;
nw_bytes_view[5].dataItemName = SMC_NAME_NET_BYTE_IO;
nw_bytes_view[5].dataItemStatType = SMC_STAT_RATE_SESSION;
ret=smc_create_view (connect1_id, /*Connect ID assigned when
connect allocated*/
server_info_view, /*This is a pointer to
array of SMC_DATAITEM_STRUCTS
which defines the view*/
NUM_SERVER_DATA_ITEMS, /*No. of items in
the view*/
"server info view", /*Ignored on a live
connection*/
&server_view_id /*Value is assigned
by this call*/
);
if (ret != SMC_RET_SUCCESS) { /*Cleanup from failed
create_view call*/
ret=smc_connect_drop(connect1_id); /*Create view failed
so no further use for
this connection*/
connect1_id = CONNECT_NONEXISTENT;
}
/*
** The second connection will have two views
*/
ret=smc_create_view(connect2_id,db_info_view,NUM_DB_INFO_ITEMS,
"db info view",&db_info_view_id);
if (ret != SMC_RET_SUCCESS) {
db_info_view_id = VIEW_NONEXISTENT;
}
ret=smc_create_view(connect2_id,nw_bytes_view,NUM_NW_INFO_ITEMS,
"nw bytes view",&nw_info_view_id);
if (ret != SMC_RET_SUCCESS) {
nw_info_view_id = VIEW_NONEXISTENT;
}
/*
** Create a filter.
*/
For commentary, see “Step 4: Creating filters”.
/*
** Filters and alarms may be applied to data items within a view.
** This is optional.
** In this case, we only want to see I/O activity for a
** particular database and tempdb. If any physical reads occur,
** an alarm is triggered that posts a message to the screen.
*/
#ifdef OPTIONAL_CALLS
filter_strings[0] = "my_db"; /*Change to db of interest*/
filter_strings[1] = "tempdb";
workUnion.voidpValue = filter_strings;
ret=smc_create_filter(connect2_id, /*Connection id*/
db_info_view_id, /*View id*/
&db_info_view[2], /*Pointer to a data
item within the view
to be filtered*/
SMC_FILT_T_EQ, /*Type of filter*/
&workUnion, /*Filter value*/
2, /*Number of elements
in array of filter
values*/
SMC_DI_TYPE_CHARP, /*datatype of filter
values*/
&filter_id /*Value is assigned by
this function call*/
);
if (ret != SMC_RET_SUCCESS) {
printf("Filters were not applied. Continuing execution.\n");
}
/*
** Set alarms.
*/
For commentary, see “Step 5: Setting alarms”.
workUnion.longValue = 1; /*Value above which
alarm is triggered*/
ret=smc_create_alarm_ex(connect2_id, /*Connection id*/
db_info_view_id, /*View id*/
&db_info_view[11], /*Pointer to a data
item within the view
to which the alarm
is applied*/
&workUnion, /*Where value that
triggers the alarm
is located*/
SMC_DI_TYPE_LONG, /*datatype of item
to which alarm is
applied*/
SMC_ALARM_A_NOTIFY,/*Trigger alarm
callback function.
This is the only
action possible when
the server mode is
LIVE.*/
NULL, /*For server mode HISTORICAL,
this is where log file to be
written to or program to be
run is specified. For server
mode LIVE, this field is
ignored.*/
/*The following is a string that is passed to the alarm callback function.*/
"Physical read occurred in database.",
alarmCallback, /*Alarm callback
function*/
&alarm_id /*Variable into which
alarm id is placed.*/
);
if (ret != SMC_RET_SUCCESS) {
printf("Alarm was not applied. Execution continuing.\n");
}
#endif
/*
** Request data and process results.
*/
For commentary, see “Step 6: Requesting performance data and process results”.
/*
** Get data from first connection. As server name and version
** do not change during the connection, we only get it once.
** Post the time when the refresh was done.
*/
if (connect1_id != CONNECT_NONEXISTENT) { /*If the connect is
not successful,the
error callback is
triggered. For a
friendlier display,
we check first.*/
ret=smc_refresh_ex(connect1_id, /*ID of connect*/
0 /*STEP not used in
live connection*/
);
if (ret != SMC_RET_SUCCESS) {
printf("refresh call failed on first connect ID.\n");
}
else { /*Check row count even though only one
row is expected in this case. If no
rows are returned, get_dataitem_value
calls will return errors.*/
ret=smc_get_row_count(connect1_id,
server_view_id,
#_of_rows);
if (ret != SMC_RET_SUCCESS){
printf("Get row count call failed.\n");
}
else {
if (num_of_rows > 0){
/*
** A get_dataitem_value call is made for each item in the view.
** The retrieved data is stored in an array of SMC_VALUE_UNIONs.
*/
for (index=0;index <NUM_SERVER_DATA_ITEMS;index++){
ret=smc_get_dataitem_value(connect1_id,
server_view_id,
&server_info_view[index],/*Look at
each data
item in
the view*/
0, /*Only one row of
data is returned for
this particular view,
so the value for row
is hard-coded in this
case.*/
&server_data[index] /*Retrieved
data stored
here*/
);
} /*End for loop*/
/*
** Display the returned data.
*/
printf("Adaptive Server Enterprise name is: \
%s.\n",server_data[0].stringValue);
printf("Adaptive Server Enterprise version is: \
%s.\n",server_data[1].stringValue);
printf("Date and time is: \
%s.\n",server_data[2].stringValue);
/*
** The application is responsible for freeing memory allocated
** by the Monitor Client Library for string members of
** SMC_VALUE_UNIONs. This also illustrates the use of the
** smc_get_dataitem_type function call.
*/
for (index=0;index <NUM_SERVER_DATA_ITEMS;index++){
ret=smc_get_dataitem_type(&server_info_view[index], \
&dataitem_type);
if (ret != SMC_RET_SUCCESS) {
printf("Get dataitem type failed for item %d \
in server_info_view.\n");
}
else {
if (dataitem_type == SMC_DI_TYPE_CHARP) {
free(server_data[index].stringValue);
}
}
} /*End for loop*/
} /*End if number of rows > 0*/
} /*End case get_row_count was successful*/
} /*End case smc_refresh_ex call was successful*/
} /*End case connect still valid*/
/*
** Get the data from the views in the second connection to see
** how the data changes over time. To do this, we sample
** NUM_OF_SAMPLES times, pausing SAMPLE_INTERVAL times between
** each sample. The process of retrieving data is within a loop.
*/
for (iterations=0;iterations<NUM_OF_SAMPLES;iterations++){
sleep(SAMPLE_INTERVAL);
ret=smc_refresh_ex(connect2_id, /*Note second connection
specified for refresh*/
0 /*Step not used in live
connection*/
);
if (ret == SMC_RET_SUCCESS) {
if (db_info_view_id != VIEW_NONEXISTENT){ /*Attempting
get_row_count for
nonexistent view
will cause errors
so check if view
was actually
created*/
ret=smc_get_row_count(connect2_id,
db_info_view_id,
#_of_rows /*Multiple rows will
be returned. For
each row of data
returned, use
get_dataitem_value
loop. Function call
puts number of rows
returned into
variable.*/
);
for(row=0;row<num_of_rows;row++){
for (index=0;index <NUM_DB_INFO_ITEMS;index++){
ret=smc_get_dataitem_value(connect2_id,
db_info_view_id, /*View specified for
get_dataitem_value.*/
&db_info_view[index],
row, /*Multiple rows in
this case */
&db_data[index]
);
if (ret != SMC_RET_SUCCESS) {
printf("Get dataitem value failed for data item \
%s.\n",db_info_labels[index]);
}
else {
printf("%s",db_info_labels[index]);
ret=smc_get_dataitem_type(&db_info_view[index],\
&dataitem_type);
if (ret != SMC_RET_SUCCESS){
printf("Get data item type failed for data item \
%s.\n",db_info_view[index]);
}
else {
switch (dataitem_type) {
case SMC_DI_TYPE_CHARP:
printf("%s.\n",db_data[index].stringValue);
free(db_data[index].stringValue);
/*Application is responsible for freeing
memory allocated for strings by library*/
break;
case SMC_DI_TYPE_LONG:
printf("%d.\n",db_data[index].longValue);
break;
case SMC_DI_TYPE_DOUBLE: /*Rates are generally
floating point variables*/
printf("%f.\n",db_data[index].doubleValue);
break;
default:
printf("Unknown datatype encountered.\n");
break;
} /*End switch*/
} /*End case get_dataitem_type successful*/
} /*End case get_dataitem_value successful*/
} /*End for loop to get each data item value*/
} /*End for loop to get each row of data*/
} /*End case view exists*//*
** Retrieve data from second view in refresh.
** Processing is much the same.
*/
if (nw_info_view_id != VIEW_NONEXISTENT){ /*Attempting
get_row_count for
nonexistent view
causes errors, so
check to see if
view was actually
created*/
ret=smc_get_row_count(connect2_id,
nw_info_view_id,
#_of_rows /*This is a server-
wide view so only
one row should be
returned*/
);
if (num_of_rows > 0 ){
for (index=0;index <NUM_NW_INFO_ITEMS;index++){
ret=smc_get_dataitem_value(connect2_id,
nw_info_view_id, /*Note view
specified for
get_dataitem_value*/
&nw_bytes_view[index],
0, /*One row in this case*/
&nw_data[index]
);
if (ret != SMC_RET_SUCCESS) {
printf("Get dataitem value failed for data item \
%s.\n",nw_info_labels[index]);
}
else {
printf("%s",nw_info_labels[index]);
ret=smc_get_dataitem_type(&nw_bytes_view[index],\
&dataitem_type);
if (ret != SMC_RET_SUCCESS){
printf("Get data item type failed for data item \
%s.\n",nw_bytes_view[index]);
}
else {
switch (dataitem_type) {
case SMC_DI_TYPE_CHARP:
printf("%s.\n",nw_data[index].stringValue);
free(nw_data[index].stringValue);
/*Application is responsible for freeing
memory allocated for strings by library*/
break;
case SMC_DI_TYPE_LONG:
printf("%d.\n",nw_data[index].longValue);
break;
case SMC_DI_TYPE_DOUBLE: /*Rates are generally
floating point
variables*/
printf("%f.\n",nw_data[index].doubleValue);
break;
default:
printf("Unknown datatype encountered.\n");
break;
} /*End switch*/
} /*End case get_dataitem_type successful*/
} /*End case get_dataitem_value successful*/
} /*End for loop to get each data item value*/
} /*End if any rows of data returned*/
else {
printf("No data returned for network info view.\n");
}
} /*End case view exists*/
} /*End case refresh successful*/
else {
printf("Refresh of second connect failed. \
Return code is %d.\n",ret);
}
} /*End for loop for number of iterations*//*
** This shows how to drop filters and alarms. It is not necessary
** to do this prior to closing a connection, as it is done
** automatically when the connection is closed. Filters may be
** dropped, for example, to see the filtered results of a query
** followed by the unfiltered results.
*/
#ifdef OPTIONAL_CALLS
ret=smc_drop_filter(connect2_id,db_info_view_id,filter_id);
if (ret != SMC_RET_SUCCESS) {
printf("Attempt to drop filter failed.\n");
}
ret=smc_drop_alarm(connect2_id,db_info_view_id,alarm_id);
if (ret != SMC_RET_SUCCESS) {
printf("Attempt to drop alarm failed.\n");
}
#endif
/*
** Get another time stamp before disconnecting. To do this,
** do a refresh on the first connection again and only display
** the time stamp data returned.
*/
if (connect1_id != CONNECT_NONEXISTENT) {
ret=smc_refresh_ex(connect1_id,0 );
if (ret != SMC_RET_SUCCESS) {
printf("refresh call failed on first connect ID.\n");
}
else { /*Check row count even though
only one row is expected. If
no rows are returned,
get_dataitem_value calls
will return errors.*/
ret=smc_get_row_count(connect1_id,
server_view_id,
#_of_rows);
if (ret != SMC_RET_SUCCESS){
printf("Get row count call on first connection \
failed.\n");
}
else {
if (num_of_rows > 0){
ret=smc_get_dataitem_value(connect1_id,
server_view_id,
&server_info_view[2], /*In this case
we are only
interested in
the third data
item*/
0, /*Only one row of data
is returned for this
particular view, so the
value for row is hard-
coded in this case.*/
&server_data[2]
);
printf("Date and time on conclusion of monitoring:\
%s\n",server_data[2].stringValue);
free(server_data[2].stringValue);
/*Application must free string memory returned
by library*/
} /*End if row of data returned*/
} /*End case get_row_count successful*/
} /*End case refresh successful*/
} /*End case connection exists*/
/*
** Close and deallocate the connection.
*/
For commentary, see “Step 7: closing and deallocating connections”.
/*
** Cleanup. This consists of closing all connections, then
** de-allocating them. Alternatively, connections can be re-used.
*/
ret=smc_close(connect1_id,
SMC_CLOSE_REQUEST /*Close only if no
outstanding commands
(only close request type
currently supported)*/
);
if (ret != SMC_RET_SUCCESS) {
printf("Attempt to close first connection failed. \
Return code is %d.\n",ret);
}
ret=smc_close(connect2_id,SMC_CLOSE_REQUEST);
if (ret != SMC_RET_SUCCESS) {
printf("Attempt to close second connection failed. \
Return code is %d.\n",ret);
}
/*
** Connections can be re-used at this point, for example, to
** connect to different servers. However, we de-allocate them.
*/
ret=smc_connect_drop(connect1_id);
if (ret != SMC_RET_SUCCESS){
printf("Attempt to drop first connection failed. \
Return code is %d.\n",ret);
}
ret=smc_connect_drop(connect2_id);
if (ret != SMC_RET_SUCCESS){
printf("Attempt to drop second connection failed. \
Return code is %d.\n",ret);
}
return(SMC_RET_SUCCESS);
} /*End main*/
/*
** Callback functions
For commentary, see “Step 1: Defining error handling”.
*/
SMC_VOID errorCallback(
SMC_CONNECT_ID connectID,
SMC_COMMAND_ID commandID, /*Value internal to Monitor
Client Library*/
SMC_VOIDP userDataHandle /*User-defined pointer. Set by
smc_connect_propscall*/
)
{
SMC_SIZET ret;
SMC_VALUE_UNION errorInfo; /*Used for getting information
from smc_get_command_info
function call*/
SMC_SIZET returned_msg_length;
printf ("Inside new error callback.\n");
/*
** Use smc_get_command_info function call to get information
** from error and alarm callbacks.
*/
ret=smc_get_command_info(connectID,
commandID,
SMC_INFO_ERR_MAPSEVERITY, /*Information
requested about
command*/
&errorInfo, /*Where information
returned about
command is placed*/
NULL /*Value is numeric
so length of returned
data not needed*/
);
if (ret != SMC_RET_SUCCESS){
printf("get_command_info call requesting error map \
severity failed. Error returned is: %d\n",ret);
}
else{
printf("Monitor Client Library error severity level is: \
%d\n",errorInfo.sizetValue);
}
ret=smc_get_command_info(connectID,
commandID,
SMC_INFO_ERR_MSG,
&errorInfo,
&returned_msg_length /*Find string
length */
);
if (ret != SMC_RET_SUCCESS){
printf("get_command_info call requesting error message \
failed. Error returned is: %d\n",ret);
}
else{
printf("Error message text is: %s\n",errorInfo.stringValue);
free(errorInfo.stringValue);
/*Application is responsible for freeing string buffer
memory allocated by library*/
}
ret=smc_get_command_info(connectID,
commandID,
SMC_INFO_ERR_NUM,
&errorInfo,
NULL
);
if (ret != SMC_RET_SUCCESS){
printf("get_command_info call requesting error number \
failed. Error returned is: %d\n",ret);
}
else{
printf("Error number is: %d\n",errorInfo.sizetValue);
}
ret=smc_get_command_info(connectID,
commandID,
SMC_INFO_ERR_SEVERITY,
&errorInfo,
NULL
);
if (ret != SMC_RET_SUCCESS){
printf("get_command_info call requesting error severity \
failed. Error returned is: %d\n",ret);
}
else{
printf("Error severity level is: %d\n",errorInfo.sizetValue);
}
ret=smc_get_command_info(connectID,
commandID,
SMC_INFO_ERR_SOURCE,
&errorInfo,
NULL
);
if (ret != SMC_RET_SUCCESS){
printf("get_command_info call requesting error source \
failed. Error returned is: %d\n",ret);
}
else{
printf(" Error source is: %d\n",errorInfo.sizetValue);
}
ret=smc_get_command_info(connectID,
commandID,
SMC_INFO_ERR_STATE,
&errorInfo,
NULL
);
if (ret != SMC_RET_SUCCESS){
printf("get_command_info call requesting state failed. \
Error returned is: %d\n",ret);
}
else{
printf(" Error state is: %d\n",errorInfo.sizetValue);
}
/*
** Demonstrate use of userDataHandle. This value was set as a
** connection property for the connection in the main program and
** is passed to this function.
*/
if (userDataHandle != NULL){
printf("Connection on which error occurred is \
%s.\n",userDataHandle);
}
} /*End errorCallback */
/*Alarm callback*/
SMC_VOID alarmCallback(
SMC_CONNECT_ID connectID,
SMC_COMMAND_ID commandID, /*Value internal to Monitor
Client Library*/
SMC_VOIDP userDataHandle
)
{
#define MSG_BUFFER_LENGTH 80
SMC_SIZET ret;
SMC_VALUE_UNION alarmInfo; /*Union into which requested
data is placed*/
SMC_SIZET returned_msg_length;
printf ("Alarm callback triggered.\n");
/*
** Use smc_get_command_info function call to get information
** from error and alarm callbacks.
*/
ret=smc_get_command_info(connectID,
commandID,
SMC_INFO_ALARM_ALARMID,
&alarmInfo,
NULL
);
if (ret != SMC_RET_SUCCESS){
printf("get_command_info call failed. \
Error returned is: %d",ret);
}
else{
printf("Alarm ID is: %d\n",alarmInfo.sizetValue);
}
/*
** This demonstrates the use of the SMC_INFO_ALARM_VALUE_DATATYPE
** information that might be useful in a generic alarm callback
** function.
*/
ret=smc_get_command_info(connectID,
commandID,
SMC_INFO_ALARM_VALUE_DATATYPE,
&alarmInfo,
NULL
);
if (ret != SMC_RET_SUCCESS){
printf("get_command_info call failed. \
Error returned is: %d",ret);
}
else{
switch(alarmInfo.intValue){
case SMC_DI_TYPE_INT:
ret=smc_get_command_info(connectID,
commandID,
SMC_INFO_ALARM_CURRENT_VALUE,
&alarmInfo,
NULL
);
if (ret != SMC_RET_SUCCESS){
printf("get_command_info call failed. \
Error returned is: %d",ret);
}
else {
printf("Current value of alarmed data item is:\
%d.\n",alarmInfo.intValue);
}
break;
case SMC_DI_TYPE_LONG:
ret=smc_get_command_info(connectID,
commandID,
SMC_INFO_ALARM_CURRENT_VALUE,
&alarmInfo,
NULL
);
if (ret != SMC_RET_SUCCESS){
printf("get_command_info call failed. \
Error returned is: %d",ret);
}
else {
printf("Current value of alarmed data item is: \
%d.\n",alarmInfo.longValue);
}
break;
case SMC_DI_TYPE_DOUBLE:
ret=smc_get_command_info(connectID,
commandID,
SMC_INFO_ALARM_CURRENT_VALUE,
&alarmInfo,
NULL
);
if (ret != SMC_RET_SUCCESS){
printf("get_command_info call failed. Error returned is: %d",ret);
}
else {
printf("Current value of alarmed data item is: \
%f.\n",alarmInfo.doubleValue);
}
break;
default:
printf("Invalid value returned for datatype of \
current alarm value.\n");
break;
} /*End switch*/
}
ret=smc_get_command_info(connectID,
commandID,
SMC_INFO_ALARM_ROW,
&alarmInfo,
NULL
);
if (ret != SMC_RET_SUCCESS){
printf("get_command_info call failed. \
Error returned is: %d",ret);
}
else{
printf("Row of data which triggered alarm is: \
%d\n",alarmInfo.sizetValue);
}
ret=smc_get_command_info(connectID,
commandID,
SMC_INFO_ALARM_VALUE_DATATYPE,
&alarmInfo,
NULL
);
if (ret != SMC_RET_SUCCESS){
printf("get_command_info call failed. \
Error returned is: %d",ret);
}
else{
switch(alarmInfo.intValue){
case SMC_DI_TYPE_INT:
ret=smc_get_command_info(connectID,
commandID,
SMC_INFO_ALARM_THRESHOLD_VALUE,
&alarmInfo,
NULL
);
if (ret != SMC_RET_SUCCESS){
printf("get_command_info call failed. \
Error returned is: %d",ret);
}
else {
printf("Value of data item exceeded alarm-triggering \
value of: %d.\n",alarmInfo.intValue);
}
break;
case SMC_DI_TYPE_LONG:
ret=smc_get_command_info(connectID,
commandID,
SMC_INFO_ALARM_THRESHOLD_VALUE,
&alarmInfo,
NULL
);
if (ret != SMC_RET_SUCCESS){
printf("get_command_info call failed. \
Error returned is: %d",ret);
}
else {
printf("Value of data item exceeded alarm-triggering \
value of: %d.\n",alarmInfo.longValue);
}
break;
case SMC_DI_TYPE_DOUBLE:
ret=smc_get_command_info(connectID,
commandID,
SMC_INFO_ALARM_THRESHOLD_VALUE,
&alarmInfo,
NULL
);
if (ret != SMC_RET_SUCCESS){
printf("get_command_info call failed. \
Error returned is: %d",ret);
}
else {
printf("Value of data item exceeded alarm-triggering\
value of: %f.\n",alarmInfo.doubleValue);
}
break;
default:
printf("Invalid value returned for datatype of \
THRESHOLD alarm value.\n");
break;
} /*End switch*/
}
ret=smc_get_command_info(connectID,
commandID,
SMC_INFO_ALARM_TIMESTAMP,
&alarmInfo,
&returned_msg_length
);
if (ret != SMC_RET_SUCCESS){
printf("get_command_info call failed. \
Error returned is: %d",ret);
}
else{
printf("Time when alarm was triggered is: \
%s\n",alarmInfo.stringValue);
free(alarmInfo.stringValue); /*Application is responsible
for freeing string buffer memory
allocated by library.*/
}
ret=smc_get_command_info(connectID,
commandID,
SMC_INFO_ALARM_VIEWID,
&alarmInfo,
NULL
);
if (ret != SMC_RET_SUCCESS){
printf("get_command_info call failed. \
Error returned is: %d",ret);
}
else{
printf("ID of view which triggered alarm is: \
%d.\n",alarmInfo.sizetValue);
}
} /*End newAlarmCallback*/