| /************************************************************** |
| * 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) |
| { |
| } |