summaryrefslogtreecommitdiff
path: root/agent/mibgroup/Rmon/rows.c
diff options
context:
space:
mode:
Diffstat (limited to 'agent/mibgroup/Rmon/rows.c')
-rw-r--r--agent/mibgroup/Rmon/rows.c878
1 files changed, 878 insertions, 0 deletions
diff --git a/agent/mibgroup/Rmon/rows.c b/agent/mibgroup/Rmon/rows.c
new file mode 100644
index 0000000..ac26e30
--- /dev/null
+++ b/agent/mibgroup/Rmon/rows.c
@@ -0,0 +1,878 @@
+/**************************************************************
+ * Copyright (C) 2001 Alex Rozin, Optical Access
+ *
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * ALEX ROZIN DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ * ALEX ROZIN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ ******************************************************************/
+
+#include <net-snmp/net-snmp-config.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+
+#include "agutil_api.h"
+#include "rows.h"
+#include "row_api.h"
+
+#define MAX_CREATION_TIME 60
+
+/*
+ * ***************************
+ */
+/*
+ * static file scope functions
+ */
+/*
+ * ***************************
+ */
+
+static void
+rowapi_delete(RMON_ENTRY_T * eold)
+{
+ register RMON_ENTRY_T *eptr;
+ register RMON_ENTRY_T *prev = NULL;
+ TABLE_DEFINTION_T *table_ptr;
+
+ table_ptr = (TABLE_DEFINTION_T *) eold->table_ptr;
+
+ /*
+ * delete timout scheduling
+ */
+ snmp_alarm_unregister(eold->timer_id);
+ ag_trace("Entry %ld in %s has been deleted",
+ eold->ctrl_index, table_ptr->name);
+
+ /*
+ * It it was valid entry => deactivate it
+ */
+ if (RMON1_ENTRY_VALID == eold->status) {
+ if (table_ptr->ClbkDeactivate)
+ table_ptr->ClbkDeactivate(eold);
+ }
+
+ /*
+ * delete it in users's sence
+ */
+ if (table_ptr->ClbkDelete)
+ table_ptr->ClbkDelete((RMON_ENTRY_T *) eold->body);
+
+ if (eold->body) {
+ AGFREE(eold->body);
+ }
+
+ if (eold->owner)
+ AGFREE(eold->owner);
+
+ /*
+ * delete it from the list in table
+ */
+
+ table_ptr->current_number_of_entries--;
+
+ for (eptr = table_ptr->first; eptr; eptr = eptr->next) {
+ if (eptr == eold)
+ break;
+ prev = eptr;
+ }
+
+ if (prev)
+ prev->next = eold->next;
+ else
+ table_ptr->first = eold->next;
+
+ AGFREE(eold);
+}
+
+static void
+rowapi_too_long_creation_callback(unsigned int clientreg, void *clientarg)
+{
+ RMON_ENTRY_T *eptr;
+ TABLE_DEFINTION_T *table_ptr;
+
+ eptr = (RMON_ENTRY_T *) clientarg;
+ table_ptr = (TABLE_DEFINTION_T *) eptr->table_ptr;
+ if (RMON1_ENTRY_VALID != eptr->status) {
+ ag_trace("row #%d in %s was under creation more then %ld sec.",
+ eptr->ctrl_index, table_ptr->name,
+ (long) MAX_CREATION_TIME);
+ rowapi_delete(eptr);
+ } else {
+ snmp_alarm_unregister(eptr->timer_id);
+ }
+}
+
+static int
+rowapi_deactivate(TABLE_DEFINTION_T * table_ptr, RMON_ENTRY_T * eptr)
+{
+ if (RMON1_ENTRY_UNDER_CREATION == eptr->status) {
+ /*
+ * nothing to do
+ */
+ return SNMP_ERR_NOERROR;
+ }
+
+ if (table_ptr->ClbkDeactivate)
+ table_ptr->ClbkDeactivate(eptr);
+ eptr->status = RMON1_ENTRY_UNDER_CREATION;
+ eptr->timer_id = snmp_alarm_register(MAX_CREATION_TIME, 0,
+ rowapi_too_long_creation_callback,
+ eptr);
+ ag_trace("Entry %ld in %s has been deactivated",
+ eptr->ctrl_index, table_ptr->name);
+
+ return SNMP_ERR_NOERROR;
+}
+
+static int
+rowapi_activate(TABLE_DEFINTION_T * table_ptr, RMON_ENTRY_T * eptr)
+{
+ RMON1_ENTRY_STATUS_T prev_status = eptr->status;
+
+ eptr->status = RMON1_ENTRY_VALID;
+
+ if (table_ptr->ClbkActivate) {
+ if (0 != table_ptr->ClbkActivate(eptr)) {
+ ag_trace("Can't activate entry #%ld in %s",
+ eptr->ctrl_index, table_ptr->name);
+ eptr->status = prev_status;
+ return SNMP_ERR_BADVALUE;
+ }
+ }
+
+ snmp_alarm_unregister(eptr->timer_id);
+ eptr->timer_id = 0;
+ ag_trace("Entry %ld in %s has been activated",
+ eptr->ctrl_index, table_ptr->name);
+ return SNMP_ERR_NOERROR;
+}
+
+/*
+ * creates an entry, locats it in proper sorted order by index
+ * Row is initialized to zero,
+ * except: 'next', 'table_ptr', 'index',
+ * 'timer_id' & 'status'=(RMON1_ENTRY_UNDER_CREATION)
+ * Calls (if need) ClbkCreate.
+ * Schedules for timeout under entry creation (id of this
+ * scheduling is saved in 'timer_id').
+ * Returns 0: OK,
+ -1:max. number exedes;
+ -2:malloc failed;
+ -3:ClbkCreate failed */
+int
+ROWAPI_new(TABLE_DEFINTION_T * table_ptr, u_long ctrl_index)
+{
+ register RMON_ENTRY_T *eptr;
+ register RMON_ENTRY_T *prev = NULL;
+ register RMON_ENTRY_T *enew;
+
+ /*
+ * check on 'max.number'
+ */
+ if (table_ptr->max_number_of_entries > 0 &&
+ table_ptr->current_number_of_entries >=
+ table_ptr->max_number_of_entries)
+ return -1;
+
+ /*
+ * allocate memory for the header
+ */
+ enew = (RMON_ENTRY_T *) AGMALLOC(sizeof(RMON_ENTRY_T));
+ if (!enew)
+ return -2;
+
+ /*
+ * init the header
+ */
+ memset(enew, 0, sizeof(RMON_ENTRY_T));
+ enew->ctrl_index = ctrl_index;
+ enew->table_ptr = (void *) table_ptr;
+ enew->status = RMON1_ENTRY_UNDER_CREATION;
+ enew->only_just_created = 1;
+
+ /*
+ * create the body: alloc it and set defaults
+ */
+ if (table_ptr->ClbkCreate) {
+ if (0 != table_ptr->ClbkCreate(enew)) {
+ AGFREE(enew);
+ return -3;
+ }
+ }
+
+ table_ptr->current_number_of_entries++;
+
+ /*
+ * find the place : before 'eptr' and after 'prev'
+ */
+ for (eptr = table_ptr->first; eptr; eptr = eptr->next) {
+ if (ctrl_index < eptr->ctrl_index)
+ break;
+ prev = eptr;
+ }
+
+ /*
+ * insert it
+ */
+ enew->next = eptr;
+ if (prev)
+ prev->next = enew;
+ else
+ table_ptr->first = enew;
+
+ enew->timer_id = snmp_alarm_register(MAX_CREATION_TIME, 0,
+ rowapi_too_long_creation_callback,
+ enew);
+ ag_trace("Entry %ld in %s has been created",
+ enew->ctrl_index, table_ptr->name);
+ return 0;
+}
+
+/*
+ * ******************************
+ */
+/*
+ * external usage (API) functions
+ */
+/*
+ * ******************************
+ */
+
+void
+ROWAPI_init_table(TABLE_DEFINTION_T * table_ptr,
+ const char *name,
+ u_long max_number_of_entries,
+ ENTRY_CALLBACK_T * ClbkCreate,
+ ENTRY_CALLBACK_T * ClbkClone,
+ ENTRY_CALLBACK_T * ClbkDelete,
+ ENTRY_CALLBACK_T * ClbkValidate,
+ ENTRY_CALLBACK_T * ClbkActivate,
+ ENTRY_CALLBACK_T * ClbkDeactivate,
+ ENTRY_CALLBACK_T * ClbkCopy)
+{
+ table_ptr->name = name;
+ if (!table_ptr->name)
+ table_ptr->name = NETSNMP_REMOVE_CONST(char*,"Unknown");
+
+ table_ptr->max_number_of_entries = max_number_of_entries;
+ table_ptr->ClbkCreate = ClbkCreate;
+ table_ptr->ClbkClone = ClbkClone;
+ table_ptr->ClbkDelete = ClbkDelete;
+ table_ptr->ClbkValidate = ClbkValidate;
+ table_ptr->ClbkActivate = ClbkActivate;
+ table_ptr->ClbkDeactivate = ClbkDeactivate;
+ table_ptr->ClbkCopy = ClbkCopy;
+
+ table_ptr->first = NULL;
+ table_ptr->current_number_of_entries = 0;
+}
+
+void
+ROWAPI_delete_clone(TABLE_DEFINTION_T * table_ptr, u_long ctrl_index)
+{
+ register RMON_ENTRY_T *eptr;
+
+ eptr = ROWAPI_find(table_ptr, ctrl_index);
+ if (eptr) {
+ if (eptr->new_owner)
+ AGFREE(eptr->new_owner);
+
+ if (eptr->tmp) {
+ if (table_ptr->ClbkDelete)
+ table_ptr->ClbkDelete((RMON_ENTRY_T *) eptr->tmp);
+ AGFREE(eptr->tmp);
+ }
+
+ if (eptr->only_just_created) {
+ rowapi_delete(eptr);
+ }
+ }
+}
+
+RMON_ENTRY_T *
+ROWAPI_get_clone(TABLE_DEFINTION_T * table_ptr,
+ u_long ctrl_index, size_t body_size)
+{
+ register RMON_ENTRY_T *eptr;
+
+ if (ctrl_index < 1 || ctrl_index > 0xFFFFu) {
+ ag_trace("%s: index %ld out of range (1..65535)",
+ table_ptr->name, (long) ctrl_index);
+ return NULL;
+ }
+
+ /*
+ * get it
+ */
+ eptr = ROWAPI_find(table_ptr, ctrl_index);
+
+ if (!eptr) { /* try to create */
+ if (0 != ROWAPI_new(table_ptr, ctrl_index)) {
+ return NULL;
+ }
+
+ /*
+ * get it
+ */
+ eptr = ROWAPI_find(table_ptr, ctrl_index);
+ if (!eptr) /* it is unbelievable, but ... :( */
+ return NULL;
+ }
+
+ eptr->new_status = eptr->status;
+
+ eptr->tmp = AGMALLOC(body_size);
+ if (!eptr->tmp) {
+ if (eptr->only_just_created)
+ rowapi_delete(eptr);
+ return NULL;
+ }
+
+ memcpy(eptr->tmp, eptr->body, body_size);
+ if (table_ptr->ClbkClone)
+ table_ptr->ClbkClone(eptr);
+
+ if (eptr->new_owner)
+ AGFREE(eptr->new_owner);
+ return eptr->tmp;
+}
+
+RMON_ENTRY_T *
+ROWAPI_first(TABLE_DEFINTION_T * table_ptr)
+{
+ return table_ptr->first;
+}
+
+/*
+ * returns an entry with the smallest index
+ * which index > prev_index
+ */
+RMON_ENTRY_T *
+ROWAPI_next(TABLE_DEFINTION_T * table_ptr, u_long prev_index)
+{
+ register RMON_ENTRY_T *eptr;
+
+ for (eptr = table_ptr->first; eptr; eptr = eptr->next)
+ if (eptr->ctrl_index > prev_index)
+ return eptr;
+
+ return NULL;
+}
+
+RMON_ENTRY_T *
+ROWAPI_find(TABLE_DEFINTION_T * table_ptr, u_long ctrl_index)
+{
+ register RMON_ENTRY_T *eptr;
+
+ for (eptr = table_ptr->first; eptr; eptr = eptr->next) {
+ if (eptr->ctrl_index == ctrl_index)
+ return eptr;
+ if (eptr->ctrl_index > ctrl_index)
+ break;
+ }
+
+ return NULL;
+}
+
+int
+ROWAPI_action_check(TABLE_DEFINTION_T * table_ptr, u_long ctrl_index)
+{
+ register RMON_ENTRY_T *eptr;
+
+ eptr = ROWAPI_find(table_ptr, ctrl_index);
+ if (!eptr) {
+ ag_trace("Smth wrong ?");
+ return SNMP_ERR_GENERR;
+ }
+
+ /*
+ * test owner string
+ */
+ if (RMON1_ENTRY_UNDER_CREATION != eptr->status) {
+ /*
+ * Only the same value is allowed
+ */
+ if (eptr->new_owner &&
+ (!eptr->owner
+ || strncmp(eptr->new_owner, eptr->owner, MAX_OWNERSTRING))) {
+ ag_trace("invalid owner string in ROWAPI_action_check");
+ ag_trace("eptr->new_owner=%p eptr->owner=%p", eptr->new_owner,
+ eptr->owner);
+ return SNMP_ERR_BADVALUE;
+ }
+ }
+
+ switch (eptr->new_status) { /* this status we want to set */
+ case RMON1_ENTRY_CREATE_REQUEST:
+ if (RMON1_ENTRY_UNDER_CREATION != eptr->status)
+ return SNMP_ERR_BADVALUE;
+ break;
+ case RMON1_ENTRY_INVALID:
+ break;
+ case RMON1_ENTRY_VALID:
+ if (RMON1_ENTRY_VALID == eptr->status) {
+ break; /* nothing to do */
+ }
+ if (RMON1_ENTRY_UNDER_CREATION != eptr->status) {
+ ag_trace("Validate %s: entry %ld has wrong status %d",
+ table_ptr->name, (long) ctrl_index,
+ (int) eptr->status);
+ return SNMP_ERR_BADVALUE;
+ }
+
+ /*
+ * Our MIB understanding extension: we permit to set
+ * VALID when entry doesn't exit, in this case PDU has to have
+ * the nessessary & valid set of non-default values
+ */
+ if (table_ptr->ClbkValidate) {
+ return table_ptr->ClbkValidate(eptr);
+ }
+ break;
+ case RMON1_ENTRY_UNDER_CREATION:
+ /*
+ * Our MIB understanding extension: we permit to travel from
+ * VALID to 'UNDER_CREATION' state
+ */
+ break;
+ }
+
+ return SNMP_ERR_NOERROR;
+}
+
+int
+ROWAPI_commit(TABLE_DEFINTION_T * table_ptr, u_long ctrl_index)
+{
+ register RMON_ENTRY_T *eptr;
+
+ eptr = ROWAPI_find(table_ptr, ctrl_index);
+ if (!eptr) {
+ ag_trace("Smth wrong ?");
+ return SNMP_ERR_GENERR;
+ }
+
+ eptr->only_just_created = 0;
+
+ switch (eptr->new_status) { /* this status we want to set */
+ case RMON1_ENTRY_CREATE_REQUEST: /* copy tmp => eprt */
+ if (eptr->new_owner) {
+ if (eptr->owner)
+ AGFREE(eptr->owner);
+ eptr->owner = AGSTRDUP(eptr->new_owner);
+ }
+
+ if (table_ptr->ClbkCopy && eptr->tmp)
+ table_ptr->ClbkCopy(eptr);
+ break;
+ case RMON1_ENTRY_INVALID:
+ ROWAPI_delete_clone(table_ptr, ctrl_index);
+ rowapi_delete(eptr);
+#if 0 /* for debug */
+ dbg_f_AG_MEM_REPORT();
+#endif
+ break;
+ case RMON1_ENTRY_VALID: /* copy tmp => eprt and activate */
+ /*
+ * Our MIB understanding extension: we permit to set
+ * VALID when entry doesn't exit, in this case PDU has to have
+ * the nessessary & valid set of non-default values
+ */
+ if (eptr->new_owner) {
+ if (eptr->owner)
+ AGFREE(eptr->owner);
+ eptr->owner = AGSTRDUP(eptr->new_owner);
+ }
+ if (table_ptr->ClbkCopy && eptr->tmp)
+ table_ptr->ClbkCopy(eptr);
+ if (RMON1_ENTRY_VALID != eptr->status) {
+ rowapi_activate(table_ptr, eptr);
+ }
+ break;
+ case RMON1_ENTRY_UNDER_CREATION: /* deactivate (if need) and copy tmp => eprt */
+ /*
+ * Our MIB understanding extension: we permit to travel from
+ * VALID to 'UNDER_CREATION' state
+ */
+ rowapi_deactivate(table_ptr, eptr);
+ if (eptr->new_owner) {
+ if (eptr->owner)
+ AGFREE(eptr->owner);
+ eptr->owner = AGSTRDUP(eptr->new_owner);
+ }
+ if (table_ptr->ClbkCopy && eptr->tmp)
+ table_ptr->ClbkCopy(eptr);
+ break;
+ }
+
+ ROWAPI_delete_clone(table_ptr, ctrl_index);
+ return SNMP_ERR_NOERROR;
+}
+
+RMON_ENTRY_T *
+ROWAPI_header_ControlEntry(struct variable * vp, oid * name,
+ size_t * length, int exact,
+ size_t * var_len,
+ TABLE_DEFINTION_T * table_ptr,
+ void *entry_ptr, size_t entry_size)
+{
+ long ctrl_index;
+ RMON_ENTRY_T *hdr = NULL;
+
+ if (0 != AGUTIL_advance_index_name(vp, name, length, exact)) {
+ ag_trace("cannot advance_index_name");
+ return NULL;
+ }
+
+ ctrl_index = vp->namelen >= *length ? 0 : name[vp->namelen];
+
+ if (exact) {
+ if (ctrl_index)
+ hdr = ROWAPI_find(table_ptr, ctrl_index);
+ } else {
+ if (ctrl_index)
+ hdr = ROWAPI_next(table_ptr, ctrl_index);
+ else
+ hdr = ROWAPI_first(table_ptr);
+
+ if (hdr) { /* set new index */
+ name[vp->namelen] = hdr->ctrl_index;
+ *length = vp->namelen + 1;
+ }
+ }
+
+ if (hdr)
+ memcpy(entry_ptr, hdr->body, entry_size);
+ return hdr;
+}
+
+int
+ROWAPI_do_another_action(oid * name, int tbl_first_index_begin,
+ int action, int *prev_action,
+ TABLE_DEFINTION_T * table_ptr, size_t entry_size)
+{
+ long long_temp;
+ RMON_ENTRY_T *tmp;
+
+ if (action == *prev_action)
+ return SNMP_ERR_NOERROR; /* I want to process it only once ! */
+ *prev_action = action;
+
+ long_temp = name[tbl_first_index_begin];
+
+ switch (action) {
+ case RESERVE1:
+ tmp = ROWAPI_get_clone(table_ptr, long_temp, entry_size);
+ if (!tmp) {
+ ag_trace("RESERVE1: cannot get clone\n");
+ return SNMP_ERR_TOOBIG;
+ }
+ break;
+
+ case FREE: /* if RESERVEx failed: release any resources that have been allocated */
+ case UNDO: /* if ACTION failed: release any resources that have been allocated */
+ ROWAPI_delete_clone(table_ptr, long_temp);
+ break;
+
+ case ACTION:
+ long_temp = ROWAPI_action_check(table_ptr, long_temp);
+ if (0 != long_temp)
+ return long_temp;
+ break;
+
+ case COMMIT:
+ long_temp = ROWAPI_commit(table_ptr, long_temp);
+ if (0 != long_temp) /* it MUST NOT be */
+ return long_temp;
+ break;
+ default:
+ ag_trace("Unknown action %d", (int) action);
+ return SNMP_ERR_GENERR;
+ } /* of switch by actions */
+
+ return SNMP_ERR_NOERROR;
+}
+
+/*
+ * data tables API section
+ */
+
+int
+ROWDATAAPI_init(SCROLLER_T * scrlr,
+ u_long data_requested,
+ u_long max_number_of_entries,
+ size_t data_size,
+ int (*data_destructor) (struct data_scroller *, void *))
+{
+ scrlr->data_granted = 0;
+ scrlr->data_created = 0;
+ scrlr->data_total_number = 0;
+ scrlr->first_data_ptr =
+ scrlr->last_data_ptr = scrlr->current_data_ptr = NULL;
+
+ scrlr->max_number_of_entries = max_number_of_entries;
+ scrlr->data_size = data_size;
+
+ scrlr->data_destructor = data_destructor;
+
+ ROWDATAAPI_set_size(scrlr, data_requested, 0);
+
+ return 0;
+}
+
+static int
+delete_data_entry(SCROLLER_T * scrlr, void *delete_me)
+{
+ NEXTED_PTR_T *data_ptr = delete_me;
+ register NEXTED_PTR_T *tmp;
+
+ if (data_ptr == scrlr->first_data_ptr) {
+ scrlr->first_data_ptr = data_ptr->next;
+ if (data_ptr == scrlr->last_data_ptr)
+ scrlr->last_data_ptr = NULL;
+ } else { /* not first */
+ for (tmp = scrlr->first_data_ptr; tmp; tmp = tmp->next) {
+ if (tmp->next == data_ptr) {
+ if (data_ptr == scrlr->last_data_ptr)
+ scrlr->last_data_ptr = tmp;
+ tmp->next = data_ptr->next;
+ break;
+ }
+ } /* for */
+ } /* not first */
+
+ if (data_ptr == scrlr->current_data_ptr)
+ scrlr->current_data_ptr = data_ptr->next;
+
+ if (scrlr->data_destructor)
+ scrlr->data_destructor(scrlr, data_ptr);
+ AGFREE(data_ptr);
+ scrlr->data_created--;
+ scrlr->data_stored--;
+
+ return 0;
+}
+
+static void
+realloc_number_of_data(SCROLLER_T * scrlr, long dlong)
+{
+ void *bptr; /* DATA_ENTRY_T */
+ NEXTED_PTR_T *prev = NULL;
+ void *first = NULL;
+
+ if (dlong > 0) {
+ for (; dlong; dlong--, prev = bptr, scrlr->data_created++) {
+ bptr = AGMALLOC(scrlr->data_size);
+ if (!bptr) {
+ ag_trace("Err: no memory for data");
+ break;
+ }
+ memset(bptr, 0, scrlr->data_size);
+ if (prev)
+ prev->next = bptr;
+ else
+ first = bptr;
+ } /* of loop by malloc bucket */
+
+ if (!scrlr->current_data_ptr)
+ scrlr->current_data_ptr = first;
+ if (scrlr->last_data_ptr) {
+ scrlr->last_data_ptr->next = first;
+ } else
+ scrlr->first_data_ptr = first;
+
+ scrlr->last_data_ptr = bptr;
+
+ } else {
+ for (; dlong && scrlr->data_created > 0; dlong++) {
+ if (scrlr->current_data_ptr)
+ delete_data_entry(scrlr, scrlr->current_data_ptr);
+ else
+ delete_data_entry(scrlr, scrlr->first_data_ptr);
+ }
+ }
+}
+
+void
+ROWDATAAPI_set_size(SCROLLER_T * scrlr,
+ u_long data_requested, u_char do_allocation)
+{
+ long dlong;
+
+ scrlr->data_requested = data_requested;
+ scrlr->data_granted = (data_requested < scrlr->max_number_of_entries) ?
+ data_requested : scrlr->max_number_of_entries;
+ if (do_allocation) {
+ dlong = (long) scrlr->data_granted - (long) scrlr->data_created;
+ realloc_number_of_data(scrlr, dlong);
+ }
+}
+
+void
+ROWDATAAPI_descructor(SCROLLER_T * scrlr)
+{
+ register NEXTED_PTR_T *bptr;
+ register void *next;
+
+ for (bptr = scrlr->first_data_ptr; bptr; bptr = next) {
+ next = bptr->next;
+ if (scrlr->data_destructor)
+ scrlr->data_destructor(scrlr, bptr);
+ AGFREE(bptr);
+ }
+ scrlr->data_created = 0;
+ scrlr->data_granted = 0;
+ scrlr->first_data_ptr =
+ scrlr->last_data_ptr = scrlr->current_data_ptr = NULL;
+}
+
+void *
+ROWDATAAPI_locate_new_data(SCROLLER_T * scrlr)
+{
+ register NEXTED_PTR_T *bptr;
+
+ if (!scrlr->current_data_ptr) { /* there was wrap */
+ bptr = scrlr->first_data_ptr;
+ if (!bptr) {
+ ag_trace("Err: SCROLLER_T:locate_new_data: internal error :(");
+ return NULL;
+ }
+ scrlr->first_data_ptr = bptr->next;
+ scrlr->last_data_ptr->next = bptr;
+ scrlr->last_data_ptr = (NEXTED_PTR_T *) bptr;
+ bptr->next = NULL;
+ } else {
+ bptr = scrlr->current_data_ptr;
+ scrlr->current_data_ptr = bptr->next;
+ ++scrlr->data_stored;
+ }
+
+ scrlr->data_total_number++;
+
+ return bptr;
+}
+
+u_long
+ROWDATAAPI_get_total_number(SCROLLER_T * scrlr)
+{
+ return scrlr->data_total_number;
+}
+
+RMON_ENTRY_T *
+ROWDATAAPI_header_DataEntry(struct variable * vp, oid * name,
+ size_t * length, int exact,
+ size_t * var_len,
+ TABLE_DEFINTION_T * table_ptr,
+ SCROLLER_T * (*extract_scroller) (void *body),
+ size_t data_size, void *entry_ptr)
+{
+ long ctrl_indx, data_index;
+ RMON_ENTRY_T *hdr = NULL;
+ SCROLLER_T *scrlr;
+ NEXTED_PTR_T *bptr = NULL;
+ register u_long iii;
+
+ if (0 != AGUTIL_advance_index_name(vp, name, length, exact)) {
+ ag_trace("cannot advance_index_name");
+ return NULL;
+ }
+
+ ctrl_indx = vp->namelen >= *length ? 0 : name[vp->namelen];
+ if (ctrl_indx)
+ data_index =
+ ((int)(vp->namelen + 1) >= (int)*length) ? 0 : name[vp->namelen + 1];
+ else
+ data_index = 0;
+
+ if (exact) {
+ if (ctrl_indx && data_index) {
+ hdr = ROWAPI_find(table_ptr, ctrl_indx);
+ if (hdr) {
+ scrlr = extract_scroller(hdr->body);
+ bptr = scrlr->first_data_ptr;
+ for (iii = 0; iii < scrlr->data_stored && bptr;
+ iii++, bptr = bptr->next) {
+ if ((long)bptr->data_index == data_index)
+ break;
+ }
+ if (!bptr)
+ hdr = NULL;
+ }
+ }
+ } else {
+ if (ctrl_indx)
+ hdr = ROWAPI_find(table_ptr, ctrl_indx);
+ else
+ hdr = ROWAPI_first(table_ptr);
+
+ if (hdr) {
+ scrlr = extract_scroller(hdr->body);
+ /*
+ * ag_trace ("get next after (%d %d)", (int) ctrl_indx, (int) data_index);
+ */
+ bptr = scrlr->first_data_ptr;
+ for (iii = 0; iii < scrlr->data_stored && bptr;
+ iii++, bptr = bptr->next) {
+ if (bptr->data_index && (long)bptr->data_index > data_index)
+ break;
+ }
+
+ if (bptr && (long)bptr->data_index <= data_index)
+ bptr = NULL;
+
+ if (!bptr) { /* travel to next row */
+ /*
+ * ag_trace ("Dbg: travel to next row");
+ */
+ for (hdr = hdr->next; hdr; hdr = hdr->next) {
+ if (RMON1_ENTRY_VALID != hdr->status)
+ continue;
+
+ scrlr = extract_scroller(hdr->body);
+ if (scrlr->data_stored <= 0)
+ continue;
+ for (bptr = scrlr->first_data_ptr; bptr;
+ bptr = bptr->next) {
+ if (bptr->data_index)
+ break;
+ }
+
+ if (bptr)
+ break;
+ }
+ }
+ if (bptr) { /* set new index */
+ /*
+ * ag_trace ("Dbg: So (%d %d)", (int) hdr->index, (int) bptr->data_index);
+ */
+ name[vp->namelen] = hdr->ctrl_index;
+ name[vp->namelen + 1] = bptr->data_index;
+ *length = vp->namelen + 2;
+ } else
+ hdr = NULL;
+ }
+ }
+
+ if (hdr)
+ memcpy(entry_ptr, bptr, data_size);
+ return hdr;
+}
+
+void
+init_rows(void)
+{
+}