diff options
Diffstat (limited to 'agent/mibgroup/Rmon/rows.c')
-rw-r--r-- | agent/mibgroup/Rmon/rows.c | 878 |
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) +{ +} |