diff options
Diffstat (limited to 'local/mib2c-conf.d/mfd-access-unsorted-external-defines.m2i')
-rw-r--r-- | local/mib2c-conf.d/mfd-access-unsorted-external-defines.m2i | 1198 |
1 files changed, 1198 insertions, 0 deletions
diff --git a/local/mib2c-conf.d/mfd-access-unsorted-external-defines.m2i b/local/mib2c-conf.d/mfd-access-unsorted-external-defines.m2i new file mode 100644 index 0000000..f4f3514 --- /dev/null +++ b/local/mib2c-conf.d/mfd-access-unsorted-external-defines.m2i @@ -0,0 +1,1198 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id$ +######################################################################## +## +@eval $mfd_aue_wrap_param = "wrap_ctx"@ +@eval $mfd_aue_wrap_param_type = "${context}_interface_ctx *"@ +@eval $mfd_aue_wrap_param_decl = "$mfd_aue_wrap_param_type $mfd_aue_wrap_param"@ +## +@eval $mfd_aue_param = "${context}_reg"@ +@eval $mfd_aue_param_type = "${context}_registration *"@ +@eval $mfd_aue_param_decl = "$mfd_aue_param_type $mfd_aue_param"@ +@eval $mfd_aue_param_cmt = "$mfd_aue_param Pointer to a $mfd_aue_param_type" +## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision$ */ +@end@ +##//#################################################################### +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@if $m2c_processing_type eq 'h'@ +## +@if $m2c_include_examples == 1@ +$example_start +/* ********************************************************************* + * Since we have no idea how you really access your data, we'll go with + * a worst case example: a flat text file. + @ if $m2c_data_transient != 2@ + @ print Example code is for fully transient data. Either turn off@ + @ print m2c_include_examples or set m2c_data_transient to 2.@ + @ exit@ + @ end@ + */ +#define MAX_LINE_SIZE 256 +$example_end + +@end@ +/** + * loop context + * + * ToDo: + * define loop context structure + * + * Since the actual loop is in the MFD handler, a loop contex parameter + * is provided to help you keep track of where you are in between calls + * to functions that you wrote and the master MFD handler calls. The + * structure of this context is user defineable, and is defined in the + * file ${table}_data_access.h. + * + * E.G., if your data is stored in a linked list, the obvious thing you + * want to know from one function call to the next is your current + * position in the linked list. Thus the easiest context to use is a + * pointer within the linked list. For an array, the current index to + * that array would be easiest. + * + * The funtion calls are actually passed a reference to the loop + * context, to allow the loop context to be allocated memory. Here are + * some simple examples definitions for various data formats. These + * definitions are used in examples later on. + * + */ +typedef struct ${context}_loop_context_s { + /* + * temporary context used during iteration + */ + ${context}_rowreq_ctx *rowreq_ctx; +@if $m2c_include_examples == 1@ + + /* + * this example code is based on a data source that is a + * text file to be read and parsed. + */ + FILE *filep; + char line[MAX_LINE_SIZE]; +@end@ +} ${context}_loop_context; + +/* + * define a reference to the loop context + * + * NOTE: DO NOT ADD ITEMS TO THIS STRUCTURE! + */ +typedef struct ${context}_ref_loop_ctx_s { + ${context}_loop_context *loop_ctx; +} ${context}_ref_loop_ctx; + +int ${context}_loop_get_first( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref, + ${context}_ref_rowreq_ctx *rowreq_ctx_ref); +int ${context}_loop_get_next( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref, + ${context}_ref_rowreq_ctx *rowreq_ctx_ref); +int ${context}_loop_get_data( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref, + ${context}_ref_rowreq_ctx *rowreq_ctx_ref); +int ${context}_loop_save_position($mfd_aue_param_decl, + ${context}_ref_loop_ctx *loop_ctx_ref, + ${context}_ref_loop_ctx *save_loop_ctx_ref, int reuse); +int ${context}_loop_cleanup_context( $mfd_aue_param_decl, ${context}_ref_loop_ctx *ref); + +## +@end@ // m2c_processing_type eq 'h' +######################################################################## +##//#################################################################### +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@if $m2c_processing_type eq 'i'@ +/** + * @internal + * wrapper around clean up a loop reference + */ +static int +_${context}_loop_cleanup_context( $mfd_aue_wrap_param_decl, + ${context}_ref_loop_ctx *ref) +{ + DEBUGMSGTL(("internal:${context}:_${context}_loop_cleanup_context","called\n")); + + return ${context}_loop_cleanup_context($mfd_aue_wrap_param->user_ctx, ref); +} /* _${context}_loop_cleanup_context */ + +/** + * @internal + * wrapper around save position + */ +static int +_${context}_loop_save_position( $mfd_aue_wrap_param_decl, ${context}_ref_loop_ctx *ref, + ${context}_ref_loop_ctx *ref_copy, int reuse) +{ + DEBUGMSGTL(("internal:${context}:_${context}_loop_save_position","called\n")); + + return ${context}_loop_save_position($mfd_aue_wrap_param->user_ctx, ref, + ref_copy, reuse); +} /* _${context}_loop_save_position */ + +/** + * @internal + * wrapper around user get_first to setup the index oid + */ +static int +_${context}_loop_get_first_wrapper($mfd_aue_wrap_param_decl, + ${context}_ref_loop_ctx * loop_ctx_ref, + ${context}_ref_rowreq_ctx * rowreq_ctx_ref) +{ + int rc; + DEBUGMSGTL(("internal:${context}:_${context}_loop_get_first_wrapper","called\n")); + + rc = ${context}_loop_get_first($mfd_aue_wrap_param->user_ctx, loop_ctx_ref, + rowreq_ctx_ref); + /* + * convert index to OID + */ + if(SNMPERR_SUCCESS == rc ) { + netsnmp_assert((NULL != rowreq_ctx_ref) && + (rowreq_ctx_ref->rowreq_ctx->oid_idx.oids == rowreq_ctx_ref->rowreq_ctx->oid_tmp)); + rowreq_ctx_ref->rowreq_ctx->oid_idx.len = sizeof(rowreq_ctx_ref->rowreq_ctx->oid_tmp); + rc = ${context}_index_to_oid(&rowreq_ctx_ref->rowreq_ctx->oid_idx, + &rowreq_ctx_ref->rowreq_ctx->tbl_idx); + netsnmp_assert(rowreq_ctx_ref->rowreq_ctx->oid_idx.len != + sizeof(rowreq_ctx_ref->rowreq_ctx->oid_tmp)); + } + + return rc; +} /* _${context}_loop_get_first_wrapper */ + +/** + * @internal + * wrapper around user get_next to setup the index oid + */ +static int +_${context}_loop_get_next_wrapper($mfd_aue_wrap_param_decl, + ${context}_ref_loop_ctx * loop_ctx_ref, + ${context}_ref_rowreq_ctx * rowreq_ctx_ref) +{ + int rc; + DEBUGMSGTL(("internal:${context}:_${context}_loop_get_next_wrapper","called\n")); + + rc = ${context}_loop_get_next($mfd_aue_wrap_param->user_ctx, loop_ctx_ref, + rowreq_ctx_ref); + /* + * convert index to OID + */ + if(SNMPERR_SUCCESS == rc ) { + netsnmp_assert((NULL != rowreq_ctx_ref) && + (rowreq_ctx_ref->rowreq_ctx->oid_idx.oids == rowreq_ctx_ref->rowreq_ctx->oid_tmp)); + rowreq_ctx_ref->rowreq_ctx->oid_idx.len = sizeof(rowreq_ctx_ref->rowreq_ctx->oid_tmp); + rc = ${context}_index_to_oid(&rowreq_ctx_ref->rowreq_ctx->oid_idx, + &rowreq_ctx_ref->rowreq_ctx->tbl_idx); + netsnmp_assert(rowreq_ctx_ref->rowreq_ctx->oid_idx.len != + sizeof(rowreq_ctx_ref->rowreq_ctx->oid_tmp)); + } + + return rc; +} /* _${context}_loop_get_next_wrapper */ + +@if $m2c_data_transient != 0@ # +/** + * @internal + * get data wrapper to allocate context for the user + */ +static int +_${context}_loop_get_data_wrapper($mfd_aue_wrap_param_decl, + ${context}_ref_loop_ctx * loop_ctx_ref, + ${context}_ref_rowreq_ctx * rowreq_ctx_ref) +{ +// ${context}_rowreq_ctx *orig_ctx = rowreq_ctx_ref->rowreq_ctx; + + DEBUGMSGTL(("internal:${context}:_${context}_loop_get_data_wrapper","called\n")); + + return ${context}_loop_get_data($mfd_aue_wrap_param->user_ctx, loop_ctx_ref, rowreq_ctx_ref); +} /* _${context}_loop_get_data_wrapper */ + +@end@ // transient != 0 +/** + * @internal + * initialize the iterator container with functions or wrappers + */ +void +_${context}_container_init(${context}_interface_ctx *if_ctx) +{ + DEBUGMSGTL(("internal:${context}:_${context}_container_init","called\n")); + + if_ctx->container = netsnmp_container_iterator_get(/** registration */ + if_ctx, + /** compare */ + NULL, + /** get_first */ + (Netsnmp_Iterator_Loop_Key*)_${context}_loop_get_first_wrapper, + /** get_next */ + (Netsnmp_Iterator_Loop_Key*)_${context}_loop_get_next_wrapper, + /** get_data */ +@if $m2c_data_transient != 0@ # + (Netsnmp_Iterator_Loop_Data*)_${context}_loop_get_data_wrapper, +@else@ + NULL, +@end@ + /** save_pos */ + (Netsnmp_Iterator_Ctx_Dup*)_${context}_loop_save_position, + /** init_context */ + (Netsnmp_Iterator_Ctx*)NULL, + /** cleanup_context */ + (Netsnmp_Iterator_Ctx*)_${context}_loop_cleanup_context, + /** free_user_ctx */ + NULL, + /** sorted */ + 0); +} /* _${context}_container_init */ + +## +@end@ // m2c_processing_type eq 'i' +######################################################################## +##//#################################################################### +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@if $m2c_processing_type eq 'c'@ +/** + * unsorted-external overview + * + * The unsorted external data access code works by calling a few simple + * functions to get the index value for each row. Once the agent determines + * which row is needed to process an incoming request, another function + * is called to retrieve the data for that row. + * + * A simplified version of the pseudo-code looks like this: + * + * ${context}_loop_get_first(loop,data) + * while( no_error ) { + * if( best_match(data, key) + * ${context}_loop_save_position(loop,pos); + * ${context}_loop_get_next(loop,data) + * } + * ${context}_loop_get_data(pos,data) + * ${context}_loop_cleanup_context(loop) + */ + +/*********************************************************************** + * + * ITERATION + * + ***********************************************************************/ + +/** + * get the first data index + * + * Summary + * ------- + * This function is called to initialize the iterator loop context for a + * new iteration loop and return the index(es) for the first + * ${context}_data in the data set. + * + * Note that during the loop, the only important thing is the indexes. + * If access to your data is cheap/fast (e.g. you have a pointer to a + * structure in memory), it would make sense to update the data here. + * If, however, the accessing the data invovles more work (e.g. parsing + * some other existing data, or peforming calculations to derive the data), + * then you should limit yourself to setting the indexes. Extracting the + * can be put off until the desired row is found. See the notes on + * ${context}_loop_get_data(). + * + * Note that this function does not correspond to a SNMP GET pdu, and + * you should return data items in whatever order they are already in. + * (In fact, if your data is already ordered in the same order as the + * SNMP indexes, you shouldn't be using the unsorted-access code). + * + * This function should update the table index (rowreq_ctx_ref->rowreq_ctx->tbl_idx) + * values for the raw data (rowreq_ctx_ref->rowreq_ctx->data). + * + * More Details + * ------------ + * If there is currently no data available, return MFD_END_OF_DATA. + * Otherwise, you should set rowreq_ctx_ref->rowreq_ctx and its indexes. + * + * rowreq_ctx_ref->rowreq_ctx will be NULL. You should allocate a new context + * for this loop. [Alternatively, you could allocate one in + * ${context}_loop_init_context, save it in your + * ${context}_ref_loop_ctx, and use it here.] + * + * Once you have your context pointer, you should set the index (or indexes) + * in rowreq_ctx_ref->rowreq_ctx->tbl_idx to the appropriate value for this row. [If you + * use your loop_ctx_ref cleverly, you might be able to put this work in + * ${context}_loop_get_next, and simply call that function.] + * + * @param $mfd_aue_param_cmt + * @param loop_ctx_ref Pointer to your loop reference. + * @param rowreq_ctx_ref Pointer to a context reference. + * + * @retval MFD_SUCCESS : success. + * @retval MFD_END_OF_DATA : no data available + * @retval MFD_ERROR : error. + */ +int +${context}_loop_get_first( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref, + ${context}_ref_rowreq_ctx *rowreq_ctx_ref) +{ + DEBUGMSGTL(("verbose:${context}:${context}_loop_get_first","called\n")); + + netsnmp_assert(rowreq_ctx_ref); + netsnmp_assert(loop_ctx_ref); + + /* + * allocate memory for new structure + */ + loop_ctx_ref->loop_ctx = SNMP_MALLOC_TYPEDEF(${context}_loop_context); + if(NULL == loop_ctx_ref->loop_ctx) + return MFD_ERROR; + + /* + * allocate a temporary context to use during iteration + */ +@ eval $m2c_tmp = ""@ +@ if ($m2c_data_allocate == 1) || ($m2c_data_init == 1)@ +@ eval $m2c_tmp = "NULL"@ +@ if ($m2c_data_allocate == 1) && ($m2c_data_init == 1)@ +@ eval $m2c_tmp = "$m2c_tmp, NULL"@ +@ @end@ +@ end@ + loop_ctx_ref->loop_ctx->rowreq_ctx = ${context}_allocate_rowreq_ctx($m2c_tmp); + if(NULL == loop_ctx_ref->loop_ctx->rowreq_ctx) { + SNMP_FREE(loop_ctx_ref->loop_ctx); + return MFD_RESOURCE_UNAVAILABLE; + } + + /* + * ToDo: + * set up loop context + */ +@if $m2c_include_examples == 1@ +$example_start + /* + * open our data file. + */ + loop_ctx_ref->loop_ctx->filep = fopen("/etc/dummy.conf", "r"); + if(NULL == loop_ctx_ref->loop_ctx->filep) { + return MFD_RESOURCE_UNAVAILABLE; + } + +$example_end +@end@ + +@ifconf ${table}_update_idx.m2i@ +@ include ${table}_update_idx.m2i@ +@else@ +@ if $m2c_include_examples == 1@ +$example_start + /* + * in this example, after opening the file, get next does the same thing + * as get first, we let's just call get next... + */ + return ${context}_loop_get_next($mfd_aue_param, loop_ctx_ref, rowreq_ctx_ref); +$example_end +@ else@ + /* + * we just need the index for now. Reuse the one in the loop context's + * temporary row request context. (rowreq_ctx_ref->rowreq_ctx->tbl_idx) + */ + rowreq_ctx_ref->rowreq_ctx = loop_ctx_ref->loop_ctx->rowreq_ctx; + + /* + * ToDo: + * set local vars for index from loop_ctx_ref->loop_ctx + * this can be done in one of two ways: + */ + + /* + * 1) individually + */ +@ foreach $node index@ +@ include m2c_setup_node.m2i@ + /* + * ToDo: + * set rowreq_ctx_ref->rowreq_ctx->tbl_idx->$node +@ if $m2c_node_needlength == 1@ + * and rowreq_ctx_ref->tbl_idx->${node}_len +@ end@ + */ +@ end@ #foreach + + /* + * OR + */ + + /* + * 2) by calling ${context}_indexes_set() + * ${context}_indexes_set(rowreq_ctx_ref->tbl_idx, +@ foreach $node index@ +@ include m2c_setup_node.m2i@ +@ if $m2c_node_needlength == 1@ + * ${node}_ptr, ${node}_len +@ else@ + * $node +@ end@ +@ end@ # foreach index + * ); + */ +@ end@ # example +@end@ #ifconf + + return MFD_SUCCESS; +} /* ${context}_loop_get_first */ + +/** + * get the next data index + * + * Summary + * ------- + * This function returns the next data item in the data set. The same + * caveat applies here as did above. The indexes are the important parts + * during loop processing. + * + * Note that this function does not correspond to a SNMP GET-NEXT pdu, and + * you should return data items in whatever order they are already in. + * (In fact, if your data is already ordered in the same order as the + * SNMP indexes, you shouldn't be using the unsorted-access code). + * + * More Details + * ------------ + * rowreq_ctx_ref->rowreq_ctx will have been set in ${context}_loop_get_first. + * + * If there is currently no data available, return MFD_END_OF_DATA. + * Otherwise, you should set the indexes in rowreq_ctx_ref->rowreq_ctx->tbl_idx. + * + * You should set the index (or indexes) in rowreq_ctx_ref->rowreq_ctx->tbl_idx to the + * appropriate value for this row. + * + * @param $mfd_aue_param_cmt + * @param loop_ctx_ref Pointer to your loop reference. + * @param rowreq_ctx_ref Pointer to a context reference. + * + * @retval MFD_SUCCESS : success. + * @retval MFD_END_OF_DATA : no more data available + * @retval MFD_ERROR : error. + */ +int +${context}_loop_get_next( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref, + ${context}_ref_rowreq_ctx *rowreq_ctx_ref) +{ + DEBUGMSGTL(("verbose:${context}:${context}_loop_get_next","called\n")); + + netsnmp_assert(loop_ctx_ref && loop_ctx_ref->loop_ctx); + netsnmp_assert(rowreq_ctx_ref); + + /* + * we just need the index for now. Reuse the one in the loop context's + * temporary row request context. (rowreq_ctx_ref->rowreq_ctx->tbl_idx) + */ + rowreq_ctx_ref->rowreq_ctx = loop_ctx_ref->loop_ctx->rowreq_ctx; + +@ if $m2c_include_examples == 1@ +$example_start + /* + * get a line (skip blank lines) + */ + do { + if (!fgets(loop_ctx_ref->loop_ctx->line, sizeof(loop_ctx_ref->loop_ctx->line), + loop_ctx_ref->loop_ctx->filep)) { + /* we're done */ + fclose(loop_ctx_ref->loop_ctx->filep); + loop_ctx_ref->loop_ctx->filep = NULL; + } + } while (loop_ctx_ref->loop_ctx->filep && (loop_ctx_ref->loop_ctx->line[0] == '\n')); + + /* + * check for end of data + */ + if(NULL == loop_ctx_ref->loop_ctx->filep) + return MFD_END_OF_DATA; + + /* + * ToDo: + * set local vars for index from loop_ctx_ref->loop_ctx + * this can be done in one of two ways: + */ + + /* + * 1) individually + */ +@ foreach $node index@ +@ include m2c_setup_node.m2i@ + /* + * ToDo: + * set rowreq_ctx_ref->rowreq_ctx->tbl_idx->$node +@ if $m2c_node_needlength == 1@ + * and rowreq_ctx_ref->tbl_idx->${node}_len +@ end@ + */ +@ end@ #foreach + + /* + * OR + */ + + /* + * 2) by calling ${context}_indexes_set() + * ${context}_indexes_set(rowreq_ctx_ref->tbl_idx, +@ foreach $node index@ +@ include m2c_setup_node.m2i@ +@ if $m2c_node_needlength == 1@ + * ${node}_ptr, ${node}_len +@ else@ + * $node +@ end@ +@ end@ # foreach index + * ); + */ +$example_end +@ end@ # example + + return MFD_SUCCESS; +} /* ${context}_loop_get_next */ + +/** + * duplicate the current loop reference + * + * Summary + * ------- + * During loop iteration, the iterator keeps track of the row that + * is the current best match. This function is called when the + * current row is a better match than any previous row. + * + * You should save any information you need to be able to locate this row + * again from the current loop context to a new loop context. + * + * At the end of the loop, when the best match has been found, the saved + * loop context will be used to get the data for the row by calling + * ${context}_loop_get_data(). +@if $m2c_data_transient != 0@ # persistent + * + * Since your data is transient, you need to make a copy of it before + * the iterator moves on to the next row. +@end@ + * +@if $m2c_data_transient != 0@ # persistent + * More Details + * ------------ +@ if $m2c_data_transient == 1@ # short term + * Since your data is semi-TRANSIENT data, you could just keep a pointer + * to the data in the loop reference. The data should then be copied in + * ${context}_loop_get_data(). +@ else@ # $m2c_data_transient == 2@ # copy immediately + * One idea would be to copy it space allocated in the loop reference + * structure. Another would be to simply have a pointer in the loop + * reference structure, and allocate memory here. + * +@ end@ +@end@ + * @param $mfd_aue_param_cmt + * @param loop_ctx_ref Reference to current loop context. + * @param save_loop_ctx_ref Reference to a loop context for saving the current + * position. If reuse is not set or + * save_loop_ctx_ref->loop_ctx is NULL, allocate + * a new one. If reuse is set, you may reuse the existing + * loop_ctx. + * @param reuse Indicates if an existing save_loop_ctx_ref->loop_ctx + * may be reused. + * + * @retval MFD_SUCCESS : success. + * @retval MFD_ERROR : error. + */ +int +${context}_loop_save_position($mfd_aue_param_decl, + ${context}_ref_loop_ctx *loop_ctx_ref, + ${context}_ref_loop_ctx *save_loop_ctx_ref, + int reuse) +{ + DEBUGMSGTL(("verbose:${context}:${context}_loop_save_position","called\n")); + + netsnmp_assert(loop_ctx_ref && save_loop_ctx_ref); + + /* + * ToDo: + * 1) allocate new loop context, unless you can reuse a previous pointer. + * 2) save information for the position of loop_ctx_ref in save_loop_ctx_ref. + */ + if((0 == reuse) || (NULL == save_loop_ctx_ref->loop_ctx)) + save_loop_ctx_ref->loop_ctx = SNMP_MALLOC_TYPEDEF(${context}_loop_context); + if(NULL == save_loop_ctx_ref->loop_ctx) { + snmp_log(LOG_ERR, "could not allocate memory\n"); + return MFD_ERROR; + } + + /* + * if you can reuse a previously saved contex, just swap + * it out with the loop iterator + */ + if(reuse && save_loop_ctx_ref->loop_ctx->rowreq_ctx) { + ${context}_rowreq_ctx * tmp_rowreq_ctx = save_loop_ctx_ref->loop_ctx->rowreq_ctx; + save_loop_ctx_ref->loop_ctx->rowreq_ctx = loop_ctx_ref->loop_ctx->rowreq_ctx; + loop_ctx_ref->loop_ctx->rowreq_ctx = tmp_rowreq_ctx; + } + else { + /* + * take the current pointer + */ + save_loop_ctx_ref->loop_ctx->rowreq_ctx = loop_ctx_ref->loop_ctx->rowreq_ctx; + + /* + * allocate a new context to replace the one you just took. + */ +@ eval $m2c_tmp = ""@ +@ if ($m2c_data_allocate == 1) || ($m2c_data_init == 1)@ +@ eval $m2c_tmp = "NULL"@ +@ if ($m2c_data_allocate == 1) && ($m2c_data_init == 1)@ +@ eval $m2c_tmp = "$m2c_tmp, NULL"@ +@ @end@ +@ end@ + loop_ctx_ref->loop_ctx->rowreq_ctx = ${context}_allocate_rowreq_ctx($m2c_tmp); + if(NULL == loop_ctx_ref->loop_ctx->rowreq_ctx) { + SNMP_FREE(loop_ctx_ref->loop_ctx); + return MFD_ERROR; + } + } + +@if $m2c_data_transient == 0@ # persistent + /** non-TRANSIENT data: no need to copy */ +@elsif $m2c_data_transient == 1@ # short term + /** semi-TRANSIENT data: will copy data when index found */ + /** only need to copy pertinent data from loop context */ +@elsif $m2c_data_transient == 2@ # copy immediately + /* + * TRANSIENT data: copy all the data. + */ +@end@ +@if $m2c_include_examples == 1@ +$example_start +@ if $m2c_data_transient == 1@ # short term + /** save line to do that */ + memcpy(save_loop_ctx_ref->loop_ctx->line, loop_ctx_ref->loop_ctx->line, + sizeof(loop_ctx_ref->loop_ctx->line)); +@ elsif $m2c_data_transient == 2@ # copy immediately +@ foreach $node nonindex@ +@ include m2c_setup_node.m2i@ + /* + * ToDo: + * set rowreq_ctx_ref->${m2c_data_item}$node + * from the loop context + */ +@ end@ +@ end@ +$example_end +@end@ # example + + return MFD_SUCCESS; +} /* ${context}_loop_save_position */ + +@if $m2c_data_transient != 0@ # semi-transient +/** + * set ${context}_data from a data context + * + * Summary + * ------- + * At the end of the loop, when the best match has been found, the saved + * loop context will be used to get the data for the row by calling + * ${context}_loop_get_data(). + * + * You should return a fully populated row request context in + * rowreq_ctx_ref->rowreq_ctx. + * + * More Details + * ------------ + * @param $mfd_aue_param_cmt + * @param loop_ctx_ref pointer to your loop reference. + * @param rowreq_ctx_ref pointer to a context reference. + */ +int +${context}_loop_get_data( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref, + ${context}_ref_rowreq_ctx *rowreq_ctx_ref) +{ + DEBUGMSGTL(("verbose:${context}:${context}_loop_get_data","called\n")); + + netsnmp_assert((NULL != loop_ctx_ref) && (NULL != loop_ctx_ref->loop_ctx)); + netsnmp_assert(NULL != rowreq_ctx_ref); + netsnmp_assert(NULL != rowreq_ctx_ref->rowreq_ctx); + + /* + * take temporary row request context from loop context + */ + rowreq_ctx_ref->rowreq_ctx = loop_ctx_ref->loop_ctx->rowreq_ctx; + loop_ctx_ref->loop_ctx->rowreq_ctx = NULL; + + /* + * copy data to the data context (rowreq_ctx_ref->${m2c_data_item}) +@ if $m2c_include_examples == 1@ + * in loop_save_position, we saved line to do that +@ end@ + */ +@ foreach $node nonindex@ +@ include m2c_setup_node.m2i@ + /* + * $m2c_node_summary + */ +@ eval $m2c_ctx_lh = "rowreq_ctx_ref->$m2c_ctx_rh"@ +@ eval $m2c_ctx_lhs = "rowreq_ctx_ref->$m2c_ctx_rhs"@ +@ eval $m2c_ctx_rh = "loop_ctx_ref->loop_ctx->$node"@ +@ eval $m2c_ctx_rhs = "loop_ctx_ref->loop_ctx->${node}_len"@ +@ include generic-value-map.m2i@ + +@ end@ + + return MFD_SUCCESS; +} /* ${context}_loop_get_data */ + +@end@ // if $m2c_data_transient != 0 + +/** + * clean up a loop reference + * + * Summary + * ------- + * This function will be called once the loop iteration has completed + * to release any memory or resources allocated for the loop context. + * + * More Details + * ------------ + * @param $mfd_aue_param_cmt + * @param loop_ctx_ref Pointer to your loop reference. + * + * @retval MFD_SUCCESS : success. + * @retval MFD_ERROR : error. + */ +int +${context}_loop_cleanup_context( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref) +{ + DEBUGMSGTL(("verbose:${context}:${context}_loop_cleanup_context","called\n")); + + netsnmp_assert(loop_ctx_ref); + + if(!loop_ctx_ref->loop_ctx) + return MFD_ERROR; + + /* + * release the row request context, if it wasn't taken + */ + if(loop_ctx_ref->loop_ctx->rowreq_ctx) + ${context}_release_rowreq_ctx(loop_ctx_ref->loop_ctx->rowreq_ctx); + + /* + * ToDo: + * release resources + */ +@if $m2c_include_examples == 1@ +$example_start + /* + * close file + */ + if(loop_ctx_ref->loop_ctx->filep) + fclose(loop_ctx_ref->loop_ctx->filep); +$example_end + +@end@ + /* + * free loop context + */ + free(loop_ctx_ref->loop_ctx); + + return MFD_SUCCESS; +} /* ${context}_loop_cleanup_context */ + +@end@ // m2c_processing_type eq 'c' +######################################################################## +##//#################################################################### +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@if $m2c_processing_type eq 'r'@ +## + unsorted-external summary + ------------------------- + The unsorted-external data access code is for cases when you data is + kept UNSORTED and EXTERNAL to the agent/sub-agent. + + This code was generated based on the following assumptions or settings: + + 1) The raw data for this table is UNSORTED. + @if $mfd_readme_verbose != 0@ + + UNSORTED data is data that is not kept in the same order as the way + SNMP expects the index(es) for the table to be kept. [It could very + well be sorted in some other order, but for the purpose of SNMP, the + order is incorrect.] If you're not sure if your data is sorted + in an SNMP compliant way, its likely not. + + Because the raw data is unsorted, to satisfy a particular request, the + entire data set must be examined to find the apropriate index. This + is done via a simple loop. The MFD handler will call your get_first + function and the call the get_next function repeatedly, until it + returns SNMPERR_NO_VARS. + @end@ + + 2) The raw data for this table is EXTERNAL. + @if $mfd_readme_verbose != 0@ + + EXTERNAL data is data that is owned by some other process, + device, file or mechanism. The agent must use some interface to + read or modify the data. An external process may modify the data + without the agent's knowledge. For example, the Net-SNMP agent + implements the interface table (ifTable), which reports on + network interfaces. The host operating system owns this data, and + Net-SNMP must use system calls to report or manipulate the data. + Examples of external data include data stored in kernel space, in + files, in another non-memory shared process, and data stored in + devices. + @end@ + + 3) The raw data for this table is TRANSIENT. + @if $mfd_readme_verbose != 0@ + + TRANSIENT data is data that may be overwritten by another funtion + or process. For example, many OS functions return data in a + static buffer that will be reused the next time the function is + called. Because of this, we will assume that you will copy the + raw data retrieved from these other sources to a generated + structure for use within the Net-SNMP agent. (Don't worry, we'll + help you) + @end@ + + +## +## this should be syncronized with master version of comments in +## mfd-access-unsorted-external-body.m2i You should be able to copy +## the comments here and replace " * " with " ". +## + The unsorted external data access code works by calling a few simple + functions to get the index value for each row. Once the agent determines + which row is needed to process an incoming request, another function + is called to retrieve the data for that row. + + A simplified version of the pseudo-code looks like this: + + ${context}_loop_init_context(loop) + ${context}_loop_get_first(loop,data) + while( no_error ) { + if( best_match(data, key) + ${context}_loop_save_position(loop,pos); + ${context}_loop_get_next(loop,data) + } + ${context}_loop_get_data(pos,data) + ${context}_loop_cleanup_context(loop) +## +## end sync +## + + We will talk about each individual step below. + + +######################################################################## + Defining context for the loop + ----------------------------- + ToDo : typedef ${context}_loop_context + WHERE: ${table}_data_access.h + + @if $mfd_readme_verbose != 0@ +## +## this should be syncronized with master version of comments in +## mfd-access-unsorted-external-body.m2i You should be able to copy +## the comments here and replace " * " with " ". +## + Since the actual loop is in the MFD handler, a loop contex parameter + is provided to help you keep track of where you are in between calls + to functions that you wrote and the master MFD handler calls. The + structure of this context is user defineable, and is defined in the + file ${table}_data_access.h. + + E.G., if your data is stored in a linked list, the obvious thing you + want to know from one function call to the next is your current + position in the linked list. Thus the easiest context to use is a + pointer within the linked list. For an array, the current index to + that array would be easiest. + + The funtion calls are actually passed a reference to the loop + context, to allow the loop context to be allocated memory. Here are + some simple examples definitions for various data formats. These + definitions are used in examples later on. +## +## end sync +## + + Linked list + ----------- + typedef list_node ${context}_loop_context; + + Array + ----- + typedef integer ${context}_loop_context; + + File + ---- + typedef struct ${context}_loop_context_s { + char * file_name; + FILE * f; + char line[128]; + } ${context}_loop_context; + + @end@ + +######################################################################## + Initialization + -------------- + ToDo : Initialization + FUNC : ${context}_loop_init_data + WHERE: ${table}_data_access.c + + @if $mfd_readme_verbose != 0@ + The ${context}_loop_init_data function will be called during startup to + allow for any initialization needed for the data access routines. + + @end@ + +######################################################################## + Preparing for the loop + ---------------------- + ToDo : initialize loop context + FUNC : ${context}_loop_init_context + WHERE: ${table}_data_access.c + + @if $mfd_readme_verbose != 0@ +## +## this should be syncronized with master version of comments in +## mfd-access-unsorted-external-body.m2i You should be able to copy +## the comments here and replace " * " with " ". +## + This function will be called before the start of a new itertion over + the data. The loop context that is initialized here will be passed to + ${context}_loop_get_first and ${context}_loop_get_next. + + Set the loop context variable ref->loop_ctx so that the iteration + functions (get_first and get_next) can locate the apropriate data + context. +## +## end sync +## + + The primary purpose of the loop_init_context call is to initialize + the loop context data (ref). Here are some simple examples, based on the + earlier example loop contexts. + + Linked list + ----------- + ref->loop_ctx = my_table_head_ptr; + + Array + ----- + /* instead of actually allocating memory, just use the pointer */ + /* as an integer */ + (integer)(ref->loop_ctx) = 0; + + File + ---- + ref->loop_ctx = SNMP_MALLOC_TYPEDEF(${context}_loop_context); + /* error checking here */ + ref->loop_ctx->file_name = (char*) reg->mfd_user_ctx; + ref->loop_ctx->f = fopen( ref->loop_ctx->file_name, "r+" ); + + @end@ + +######################################################################## + The Loop + -------- + ToDo : return raw data + FUNC : ${context}_loop_get_first + WHERE: ${table}_data_access.c + + @if $mfd_readme_verbose != 0@ +## +## this should be syncronized with master version of comments in +## mfd-access-unsorted-external-body.m2i You should be able to copy +## the comments here and replace " * " with " ". +## + This function is called to return set the index(es) for the first + ${context}_data in the data set. + + Note that during the loop, the only important thing is the indexes. + If access to your data is cheap/fast (e.g. you have a pointer to a + structure in memory), it would make sense to update the data here. + If, however, the accessing the data invovles more work (e.g. parsing + some other existing data, or peforming calculations to derive the data), + then you should limit yourslef to setting the indexes. Extracting the + can be put off until the desired row is found See the notes on + ${context}_loop_get_data(). + + Note that this function does not correspond to a SNMP GET pdu, and + you should return data items in whatever order they are already in. + (In fact, if your data is already ordered in the same order as the + SNMP indexes, you shouldn't be using the unsorted-access code). + + This function should update the table index (rowreq_ctx_ref->rowreq_ctx->tbl_idx) + values for the raw data (rowreq_ctx_ref->rowreq_ctx->data). +## +## end sync +## + + Linked list + ----------- + rowreq_ctx_ref->rowreq_ctx->data = loop_ctx_ref->loop_ctx; + + Array + ----- + /* assuming registration has array of pointers */ + rowreq_ctx_ref->rowreq_ctx->data = reg->mfd_user_ctx[(integer)(ref->loop_ctx)]; + + File + ---- + fgets(loop_ctx_ref->loop_ctx->line, sizeof(loop_ctx_ref->loop_ctx->line), + loop_ctx_ref->loop_ctx->f); + rowreq_ctx_ref->rowreq_ctx->data = loop_ctx_ref->loop_ctx->line; + + @end@ + + ToDo : return raw data + FUNC : ${context}_loop_get_next + WHERE: ${table}_data_access.c + + @if $mfd_readme_verbose != 0@ +## +## this should be syncronized with master version of comments in +## mfd-access-unsorted-external-body.m2i You should be able to copy +## the comments here and replace " * " with " ". +## + This function returns the next data item in the data set. The same + caveat applies here as did above. The indexes are the important parts + during loop processing. + + Note that this function does not correspond to a SNMP GET-NEXT pdu, and + you should return data items in whatever order they are already in. + (In fact, if your data is already ordered in the same order as the + SNMP indexes, you shouldn't be using the unsorted-access code). +## +## end sync +## + + Linked list + ----------- + loop_ctx_ref->loop_ctx = loop_ctx_ref->loop_ctx->next; + rowreq_ctx_ref->rowreq_ctx->data = loop_ctx_ref->loop_ctx; + + Array + ----- + ++((integer)(ref->loop_ctx)); + /* assuming registration has array of pointers */ + rowreq_ctx_ref->rowreq_ctx->data = reg->mfd_user_ctx[(integer)(ref->loop_ctx)]; + + File + ---- + fgets(loop_ctx_ref->loop_ctx->line, sizeof(loop_ctx_ref->loop_ctx->line), + loop_ctx_ref->loop_ctx->f); + rowreq_ctx_ref->rowreq_ctx->data = loop_ctx_ref->loop_ctx->line; + + @end@ + +######################################################################## + Updating the Index + ------------------ + ToDo : update index for the raw data + FUNC : ${context}_indexes_set + WHERE: ${table}_data_access.c + + This is a convenience function for setting the index context from + the native C data. Where necessary, value mapping should be done. + + @if $mfd_readme_verbose == 1@ + This function should update the table index values (found in + tbl_idx) for the given raw data. + + @end@ + +######################################################################## + Saving a position in the loop + ----------------------------- + ToDo : Saving a position in the loop + FUNC : ${context}_loop_save_position + WHERE: ${table}_data_access.c + + @if $mfd_readme_verbose != 0@ +## +## this should be syncronized with master version of comments in +## mfd-access-unsorted-external-body.m2i You should be able to copy +## the comments here and replace " * " with " ". +## + During loop iteration, the iterator keeps track of the row that + is the current best match. This function is called when the + current row is a better match than any previous row. + + You should save any information you need to be able to locate this row + again from the current loop context to a new loop context. + + At the end of the loop, when the best match has been found, the saved + loop context will be used to get the data for the row by calling + ${context}_loop_get_data(). +@if $m2c_data_transient != 0@ # persistent + + Since your data is transient, you need to make a copy of it before + the iterator moves on to the next row. +@end@ +## +## end sync +## + + @end@ + +######################################################################## + Returning Data For an Index + --------------------------- + ToDo : copy transient raw data to generated structure + FUNC : ${context}_loop_get_data + WHERE: ${table}_data_access.c + + @if $mfd_readme_verbose != 0@ +## +## this should be syncronized with master version of comments in +## mfd-access-unsorted-external-body.m2i You should be able to copy +## the comments here and replace " * " with " ". +## + At the end of the loop, when the best match has been found, the saved + loop context will be used to get the data for the row by calling + ${context}_loop_get_data(). +## +## end sync +## + + @end@ + +######################################################################## + Cleaning up after the loop + -------------------------- + ToDo : release any allocated memory + FUNC : ${context}_loop_cleanup_context + WHERE: ${table}_data_access.c + + @if $mfd_readme_verbose != 0@ +## +## this should be syncronized with master version of comments in +## mfd-access-unsorted-external-body.m2i You should be able to copy +## the comments here and replace " * " with " ". +## + This function will be called once the loop iteration has completed + to release any memory allocated for loop reference. +## +## end sync +## + The purpose of the loop_cleanup_context call is to release any memory + allocated for the loop context data. Here are some simple examples, based + on the earlier example loop contexts. + + Linked list + ----------- + /* nothing to do */ + + Array + ----- + /* nothing to do */ + + File + ---- + free(ref->loop_ctx); + + @end@ + +## +@end@ // m2c_processing_type eq 'r +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision$ */ +@end@ |