rows.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:24k
源码类别:

SNMP编程

开发平台:

Unix_Linux

  1. /**************************************************************
  2.  * Copyright (C) 2001 Alex Rozin, Optical Access 
  3.  *
  4.  *                     All Rights Reserved
  5.  *
  6.  * Permission to use, copy, modify and distribute this software and its
  7.  * documentation for any purpose and without fee is hereby granted,
  8.  * provided that the above copyright notice appear in all copies and that
  9.  * both that copyright notice and this permission notice appear in
  10.  * supporting documentation.
  11.  * 
  12.  * ALEX ROZIN DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  13.  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  14.  * ALEX ROZIN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  15.  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  16.  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  17.  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  18.  * SOFTWARE.
  19.  ******************************************************************/
  20. #include <net-snmp/net-snmp-config.h>
  21. #include <stddef.h>
  22. #include <string.h>
  23. #include <stdlib.h>
  24. #include <net-snmp/net-snmp-includes.h>
  25. #include <net-snmp/agent/net-snmp-agent-includes.h>
  26. #include "util_funcs.h"
  27. #include "agutil_api.h"
  28. #include "rows.h"
  29. #include "row_api.h"
  30. #define MAX_CREATION_TIME 60
  31. /*
  32.  * *************************** 
  33.  */
  34. /*
  35.  * static file scope functions 
  36.  */
  37. /*
  38.  * *************************** 
  39.  */
  40. static void
  41. rowapi_delete(RMON_ENTRY_T * eold)
  42. {
  43.     register RMON_ENTRY_T *eptr;
  44.     register RMON_ENTRY_T *prev = NULL;
  45.     TABLE_DEFINTION_T *table_ptr;
  46.     table_ptr = (TABLE_DEFINTION_T *) eold->table_ptr;
  47.     /*
  48.      * delete timout scheduling 
  49.      */
  50.     snmp_alarm_unregister(eold->timer_id);
  51.     ag_trace("Entry %ld in %s has been deleted",
  52.              eold->ctrl_index, table_ptr->name);
  53.     /*
  54.      * It it was valid entry => deactivate it 
  55.      */
  56.     if (RMON1_ENTRY_VALID == eold->status) {
  57.         if (table_ptr->ClbkDeactivate)
  58.             table_ptr->ClbkDeactivate(eold);
  59.     }
  60.     /*
  61.      * delete it in users's sence 
  62.      */
  63.     if (table_ptr->ClbkDelete)
  64.         table_ptr->ClbkDelete((RMON_ENTRY_T *) eold->body);
  65.     if (eold->body) {
  66.         AGFREE(eold->body);
  67.     }
  68.     if (eold->owner)
  69.         AGFREE(eold->owner);
  70.     /*
  71.      * delete it from the list in table 
  72.      */
  73.     table_ptr->current_number_of_entries--;
  74.     for (eptr = table_ptr->first; eptr; eptr = eptr->next) {
  75.         if (eptr == eold)
  76.             break;
  77.         prev = eptr;
  78.     }
  79.     if (prev)
  80.         prev->next = eold->next;
  81.     else
  82.         table_ptr->first = eold->next;
  83.     AGFREE(eold);
  84. }
  85. static void
  86. rowapi_too_long_creation_callback(unsigned int clientreg, void *clientarg)
  87. {
  88.     RMON_ENTRY_T   *eptr;
  89.     TABLE_DEFINTION_T *table_ptr;
  90.     eptr = (RMON_ENTRY_T *) clientarg;
  91.     table_ptr = (TABLE_DEFINTION_T *) eptr->table_ptr;
  92.     if (RMON1_ENTRY_VALID != eptr->status) {
  93.         ag_trace("row #%d in %s was under creation more then %ld sec.",
  94.                  eptr->ctrl_index, table_ptr->name,
  95.                  (long) MAX_CREATION_TIME);
  96.         rowapi_delete(eptr);
  97.     } else {
  98.         snmp_alarm_unregister(eptr->timer_id);
  99.     }
  100. }
  101. static int
  102. rowapi_deactivate(TABLE_DEFINTION_T * table_ptr, RMON_ENTRY_T * eptr)
  103. {
  104.     if (RMON1_ENTRY_UNDER_CREATION == eptr->status) {
  105.         /*
  106.          * nothing to do 
  107.          */
  108.         return SNMP_ERR_NOERROR;
  109.     }
  110.     if (table_ptr->ClbkDeactivate)
  111.         table_ptr->ClbkDeactivate(eptr);
  112.     eptr->status = RMON1_ENTRY_UNDER_CREATION;
  113.     eptr->timer_id = snmp_alarm_register(MAX_CREATION_TIME, 0,
  114.                                          rowapi_too_long_creation_callback,
  115.                                          eptr);
  116.     ag_trace("Entry %ld in %s has been deactivated",
  117.              eptr->ctrl_index, table_ptr->name);
  118.     return SNMP_ERR_NOERROR;
  119. }
  120. static int
  121. rowapi_activate(TABLE_DEFINTION_T * table_ptr, RMON_ENTRY_T * eptr)
  122. {
  123.     RMON1_ENTRY_STATUS_T prev_status = eptr->status;
  124.     eptr->status = RMON1_ENTRY_VALID;
  125.     if (table_ptr->ClbkActivate) {
  126.         if (0 != table_ptr->ClbkActivate(eptr)) {
  127.             ag_trace("Can't activate entry #%ld in %s",
  128.                      eptr->ctrl_index, table_ptr->name);
  129.             eptr->status = prev_status;
  130.             return SNMP_ERR_BADVALUE;
  131.         }
  132.     }
  133.     snmp_alarm_unregister(eptr->timer_id);
  134.     eptr->timer_id = 0;
  135.     ag_trace("Entry %ld in %s has been activated",
  136.              eptr->ctrl_index, table_ptr->name);
  137.     return SNMP_ERR_NOERROR;
  138. }
  139. /*
  140.  * creates an entry, locats it in proper sorted order by index
  141.  * Row is initialized to zero,
  142.  * except: 'next', 'table_ptr', 'index',
  143.  * 'timer_id' & 'status'=(RMON1_ENTRY_UNDER_CREATION)
  144.  * Calls (if need) ClbkCreate.
  145.  * Schedules for timeout under entry creation (id of this
  146.  * scheduling is saved in 'timer_id').
  147.  * Returns 0: OK,
  148.  -1:max. number exedes;
  149.  -2:malloc failed;
  150.  -3:ClbkCreate failed */
  151. int
  152. ROWAPI_new(TABLE_DEFINTION_T * table_ptr, u_long ctrl_index)
  153. {
  154.     register RMON_ENTRY_T *eptr;
  155.     register RMON_ENTRY_T *prev = NULL;
  156.     register RMON_ENTRY_T *enew;
  157.     /*
  158.      * check on 'max.number' 
  159.      */
  160.     if (table_ptr->max_number_of_entries > 0 &&
  161.         table_ptr->current_number_of_entries >=
  162.         table_ptr->max_number_of_entries)
  163.         return -1;
  164.     /*
  165.      * allocate memory for the header 
  166.      */
  167.     enew = (RMON_ENTRY_T *) AGMALLOC(sizeof(RMON_ENTRY_T));
  168.     if (!enew)
  169.         return -2;
  170.     /*
  171.      * init the header 
  172.      */
  173.     memset(enew, 0, sizeof(RMON_ENTRY_T));
  174.     enew->ctrl_index = ctrl_index;
  175.     enew->table_ptr = (void *) table_ptr;
  176.     enew->status = RMON1_ENTRY_UNDER_CREATION;
  177.     enew->only_just_created = 1;
  178.     /*
  179.      * create the body: alloc it and set defaults 
  180.      */
  181.     if (table_ptr->ClbkCreate) {
  182.         if (0 != table_ptr->ClbkCreate(enew)) {
  183.             AGFREE(enew);
  184.             return -3;
  185.         }
  186.     }
  187.     table_ptr->current_number_of_entries++;
  188.     /*
  189.      * find the place : before 'eptr' and after 'prev' 
  190.      */
  191.     for (eptr = table_ptr->first; eptr; eptr = eptr->next) {
  192.         if (ctrl_index < eptr->ctrl_index)
  193.             break;
  194.         prev = eptr;
  195.     }
  196.     /*
  197.      * insert it 
  198.      */
  199.     enew->next = eptr;
  200.     if (prev)
  201.         prev->next = enew;
  202.     else
  203.         table_ptr->first = enew;
  204.     enew->timer_id = snmp_alarm_register(MAX_CREATION_TIME, 0,
  205.                                          rowapi_too_long_creation_callback,
  206.                                          enew);
  207.     ag_trace("Entry %ld in %s has been created",
  208.              enew->ctrl_index, table_ptr->name);
  209.     return 0;
  210. }
  211. /*
  212.  * ****************************** 
  213.  */
  214. /*
  215.  * external usage (API) functions 
  216.  */
  217. /*
  218.  * ****************************** 
  219.  */
  220. void
  221. ROWAPI_init_table(TABLE_DEFINTION_T * table_ptr,
  222.                   char *name,
  223.                   u_long max_number_of_entries,
  224.                   ENTRY_CALLBACK_T * ClbkCreate,
  225.                   ENTRY_CALLBACK_T * ClbkClone,
  226.                   ENTRY_CALLBACK_T * ClbkDelete,
  227.                   ENTRY_CALLBACK_T * ClbkValidate,
  228.                   ENTRY_CALLBACK_T * ClbkActivate,
  229.                   ENTRY_CALLBACK_T * ClbkDeactivate,
  230.                   ENTRY_CALLBACK_T * ClbkCopy)
  231. {
  232.     table_ptr->name = name;
  233.     if (!table_ptr->name)
  234.         table_ptr->name = "Unknown";
  235.     table_ptr->max_number_of_entries = max_number_of_entries;
  236.     table_ptr->ClbkCreate = ClbkCreate;
  237.     table_ptr->ClbkClone = ClbkClone;
  238.     table_ptr->ClbkDelete = ClbkDelete;
  239.     table_ptr->ClbkValidate = ClbkValidate;
  240.     table_ptr->ClbkActivate = ClbkActivate;
  241.     table_ptr->ClbkDeactivate = ClbkDeactivate;
  242.     table_ptr->ClbkCopy = ClbkCopy;
  243.     table_ptr->first = NULL;
  244.     table_ptr->current_number_of_entries = 0;
  245. }
  246. void
  247. ROWAPI_delete_clone(TABLE_DEFINTION_T * table_ptr, u_long ctrl_index)
  248. {
  249.     register RMON_ENTRY_T *eptr;
  250.     eptr = ROWAPI_find(table_ptr, ctrl_index);
  251.     if (eptr) {
  252.         if (eptr->new_owner)
  253.             AGFREE(eptr->new_owner);
  254.         if (eptr->tmp) {
  255.             if (table_ptr->ClbkDelete)
  256.                 table_ptr->ClbkDelete((RMON_ENTRY_T *) eptr->tmp);
  257.             AGFREE(eptr->tmp);
  258.         }
  259.         if (eptr->only_just_created) {
  260.             rowapi_delete(eptr);
  261.         }
  262.     }
  263. }
  264. RMON_ENTRY_T   *
  265. ROWAPI_get_clone(TABLE_DEFINTION_T * table_ptr,
  266.                  u_long ctrl_index, size_t body_size)
  267. {
  268.     register RMON_ENTRY_T *eptr;
  269.     if (ctrl_index < 1 || ctrl_index > 0xFFFFu) {
  270.         ag_trace("%s: index %ld out of range (1..65535)",
  271.                  table_ptr->name, (long) ctrl_index);
  272.         return NULL;
  273.     }
  274.     /*
  275.      * get it 
  276.      */
  277.     eptr = ROWAPI_find(table_ptr, ctrl_index);
  278.     if (!eptr) {                /* try to create */
  279.         if (0 != ROWAPI_new(table_ptr, ctrl_index)) {
  280.             return NULL;
  281.         }
  282.         /*
  283.          * get it 
  284.          */
  285.         eptr = ROWAPI_find(table_ptr, ctrl_index);
  286.         if (!eptr)              /* it is unbelievable, but ... :( */
  287.             return NULL;
  288.     }
  289.     eptr->new_status = eptr->status;
  290.     eptr->tmp = AGMALLOC(body_size);
  291.     if (!eptr->tmp) {
  292.         if (eptr->only_just_created)
  293.             rowapi_delete(eptr);
  294.         return NULL;
  295.     }
  296.     memcpy(eptr->tmp, eptr->body, body_size);
  297.     if (table_ptr->ClbkClone)
  298.         table_ptr->ClbkClone(eptr);
  299.     if (eptr->new_owner)
  300.         AGFREE(eptr->new_owner);
  301.     return eptr->tmp;
  302. }
  303. RMON_ENTRY_T   *
  304. ROWAPI_first(TABLE_DEFINTION_T * table_ptr)
  305. {
  306.     return table_ptr->first;
  307. }
  308. /*
  309.  * returns an entry with the smallest index
  310.  * which index > prev_index
  311.  */
  312. RMON_ENTRY_T   *
  313. ROWAPI_next(TABLE_DEFINTION_T * table_ptr, u_long prev_index)
  314. {
  315.     register RMON_ENTRY_T *eptr;
  316.     for (eptr = table_ptr->first; eptr; eptr = eptr->next)
  317.         if (eptr->ctrl_index > prev_index)
  318.             return eptr;
  319.     return NULL;
  320. }
  321. RMON_ENTRY_T   *
  322. ROWAPI_find(TABLE_DEFINTION_T * table_ptr, u_long ctrl_index)
  323. {
  324.     register RMON_ENTRY_T *eptr;
  325.     for (eptr = table_ptr->first; eptr; eptr = eptr->next) {
  326.         if (eptr->ctrl_index == ctrl_index)
  327.             return eptr;
  328.         if (eptr->ctrl_index > ctrl_index)
  329.             break;
  330.     }
  331.     return NULL;
  332. }
  333. int
  334. ROWAPI_action_check(TABLE_DEFINTION_T * table_ptr, u_long ctrl_index)
  335. {
  336.     register RMON_ENTRY_T *eptr;
  337.     eptr = ROWAPI_find(table_ptr, ctrl_index);
  338.     if (!eptr) {
  339.         ag_trace("Smth wrong ?");
  340.         return SNMP_ERR_GENERR;
  341.     }
  342.     /*
  343.      * test owner string 
  344.      */
  345.     if (RMON1_ENTRY_UNDER_CREATION != eptr->status) {
  346.         /*
  347.          * Only the same value is allowed 
  348.          */
  349.         if (eptr->new_owner &&
  350.             (!eptr->owner
  351.              || strncmp(eptr->new_owner, eptr->owner, MAX_OWNERSTRING))) {
  352.             ag_trace("invalid owner string in ROWAPI_action_check");
  353.             ag_trace("eptr->new_owner=%p eptr->owner=%p", eptr->new_owner,
  354.                      eptr->owner);
  355.             return SNMP_ERR_BADVALUE;
  356.         }
  357.     }
  358.     switch (eptr->new_status) { /* this status we want to set */
  359.     case RMON1_ENTRY_CREATE_REQUEST:
  360.         if (RMON1_ENTRY_UNDER_CREATION != eptr->status)
  361.             return SNMP_ERR_BADVALUE;
  362.         break;
  363.     case RMON1_ENTRY_INVALID:
  364.         break;
  365.     case RMON1_ENTRY_VALID:
  366.         if (RMON1_ENTRY_VALID == eptr->status) {
  367.             break;              /* nothing to do */
  368.         }
  369.         if (RMON1_ENTRY_UNDER_CREATION != eptr->status) {
  370.             ag_trace("Validate %s: entry %ld has wrong status %d",
  371.                      table_ptr->name, (long) ctrl_index,
  372.                      (int) eptr->status);
  373.             return SNMP_ERR_BADVALUE;
  374.         }
  375.         /*
  376.          * Our MIB understanding extension: we permit to set
  377.          * VALID when entry doesn't exit, in this case PDU has to have
  378.          * the nessessary & valid set of non-default values 
  379.          */
  380.         if (table_ptr->ClbkValidate) {
  381.             return table_ptr->ClbkValidate(eptr);
  382.         }
  383.         break;
  384.     case RMON1_ENTRY_UNDER_CREATION:
  385.         /*
  386.          * Our MIB understanding extension: we permit to travel from 
  387.          * VALID to 'UNDER_CREATION' state 
  388.          */
  389.         break;
  390.     }
  391.     return SNMP_ERR_NOERROR;
  392. }
  393. int
  394. ROWAPI_commit(TABLE_DEFINTION_T * table_ptr, u_long ctrl_index)
  395. {
  396.     register RMON_ENTRY_T *eptr;
  397.     eptr = ROWAPI_find(table_ptr, ctrl_index);
  398.     if (!eptr) {
  399.         ag_trace("Smth wrong ?");
  400.         return SNMP_ERR_GENERR;
  401.     }
  402.     eptr->only_just_created = 0;
  403.     switch (eptr->new_status) { /* this status we want to set */
  404.     case RMON1_ENTRY_CREATE_REQUEST:   /* copy tmp => eprt */
  405.         if (eptr->new_owner) {
  406.             if (eptr->owner)
  407.                 AGFREE(eptr->owner);
  408.             eptr->owner = AGSTRDUP(eptr->new_owner);
  409.         }
  410.         if (table_ptr->ClbkCopy && eptr->tmp)
  411.             table_ptr->ClbkCopy(eptr);
  412.         break;
  413.     case RMON1_ENTRY_INVALID:
  414.         ROWAPI_delete_clone(table_ptr, ctrl_index);
  415.         rowapi_delete(eptr);
  416. #if 0                           /* for debug */
  417.         dbg_f_AG_MEM_REPORT();
  418. #endif
  419.         break;
  420.     case RMON1_ENTRY_VALID:    /* copy tmp => eprt and activate */
  421.         /*
  422.          * Our MIB understanding extension: we permit to set
  423.          * VALID when entry doesn't exit, in this case PDU has to have
  424.          * the nessessary & valid set of non-default values 
  425.          */
  426.         if (eptr->new_owner) {
  427.             if (eptr->owner)
  428.                 AGFREE(eptr->owner);
  429.             eptr->owner = AGSTRDUP(eptr->new_owner);
  430.         }
  431.         if (table_ptr->ClbkCopy && eptr->tmp)
  432.             table_ptr->ClbkCopy(eptr);
  433.         if (RMON1_ENTRY_VALID != eptr->status) {
  434.             rowapi_activate(table_ptr, eptr);
  435.         }
  436.         break;
  437.     case RMON1_ENTRY_UNDER_CREATION:   /* deactivate (if need) and copy tmp => eprt */
  438.         /*
  439.          * Our MIB understanding extension: we permit to travel from
  440.          * VALID to 'UNDER_CREATION' state 
  441.          */
  442.         rowapi_deactivate(table_ptr, eptr);
  443.         if (eptr->new_owner) {
  444.             if (eptr->owner)
  445.                 AGFREE(eptr->owner);
  446.             eptr->owner = AGSTRDUP(eptr->new_owner);
  447.         }
  448.         if (table_ptr->ClbkCopy && eptr->tmp)
  449.             table_ptr->ClbkCopy(eptr);
  450.         break;
  451.     }
  452.     ROWAPI_delete_clone(table_ptr, ctrl_index);
  453.     return SNMP_ERR_NOERROR;
  454. }
  455. RMON_ENTRY_T   *
  456. ROWAPI_header_ControlEntry(struct variable * vp, oid * name,
  457.                            size_t * length, int exact,
  458.                            size_t * var_len,
  459.                            TABLE_DEFINTION_T * table_ptr,
  460.                            void *entry_ptr, size_t entry_size)
  461. {
  462.     long            ctrl_index;
  463.     RMON_ENTRY_T   *hdr = NULL;
  464.     if (0 != AGUTIL_advance_index_name(vp, name, length, exact)) {
  465.         ag_trace("cannot advance_index_name");
  466.         return NULL;
  467.     }
  468.     ctrl_index = vp->namelen >= *length ? 0 : name[vp->namelen];
  469.     if (exact) {
  470.         if (ctrl_index)
  471.             hdr = ROWAPI_find(table_ptr, ctrl_index);
  472.     } else {
  473.         if (ctrl_index)
  474.             hdr = ROWAPI_next(table_ptr, ctrl_index);
  475.         else
  476.             hdr = ROWAPI_first(table_ptr);
  477.         if (hdr) {              /* set new index */
  478.             name[vp->namelen] = hdr->ctrl_index;
  479.             *length = vp->namelen + 1;
  480.         }
  481.     }
  482.     if (hdr)
  483.         memcpy(entry_ptr, hdr->body, entry_size);
  484.     return hdr;
  485. }
  486. int
  487. ROWAPI_do_another_action(oid * name, int tbl_first_index_begin,
  488.                          int action, int *prev_action,
  489.                          TABLE_DEFINTION_T * table_ptr, size_t entry_size)
  490. {
  491.     long            long_temp;
  492.     RMON_ENTRY_T   *tmp;
  493.     if (action == *prev_action)
  494.         return SNMP_ERR_NOERROR;        /* I want to process it only once ! */
  495.     *prev_action = action;
  496.     long_temp = name[tbl_first_index_begin];
  497.     switch (action) {
  498.     case RESERVE1:
  499.         tmp = ROWAPI_get_clone(table_ptr, long_temp, entry_size);
  500.         if (!tmp) {
  501.             ag_trace("RESERVE1: cannot get clonen");
  502.             return SNMP_ERR_TOOBIG;
  503.         }
  504.         break;
  505.     case FREE:                 /* if RESERVEx failed: release any resources that have been allocated */
  506.     case UNDO:                 /* if ACTION failed: release any resources that have been allocated */
  507.         ROWAPI_delete_clone(table_ptr, long_temp);
  508.         break;
  509.     case ACTION:
  510.         long_temp = ROWAPI_action_check(table_ptr, long_temp);
  511.         if (0 != long_temp)
  512.             return long_temp;
  513.         break;
  514.     case COMMIT:
  515.         long_temp = ROWAPI_commit(table_ptr, long_temp);
  516.         if (0 != long_temp)     /* it MUST NOT be */
  517.             return long_temp;
  518.         break;
  519.     default:
  520.         ag_trace("Unknown action %d", (int) action);
  521.         return SNMP_ERR_GENERR;
  522.     }                           /* of switch by actions */
  523.     return SNMP_ERR_NOERROR;
  524. }
  525. /*
  526.  * data tables API section 
  527.  */
  528. int
  529. ROWDATAAPI_init(SCROLLER_T * scrlr,
  530.                 u_long data_requested,
  531.                 u_long max_number_of_entries,
  532.                 size_t data_size,
  533.                 int (*data_destructor) (struct data_scroller *, void *))
  534. {
  535.     scrlr->data_granted = 0;
  536.     scrlr->data_created = 0;
  537.     scrlr->data_total_number = 0;
  538.     scrlr->first_data_ptr =
  539.         scrlr->last_data_ptr = scrlr->current_data_ptr = NULL;
  540.     scrlr->max_number_of_entries = max_number_of_entries;
  541.     scrlr->data_size = data_size;
  542.     scrlr->data_destructor = data_destructor;
  543.     ROWDATAAPI_set_size(scrlr, data_requested, 0);
  544.     return 0;
  545. }
  546. static int
  547. delete_data_entry(SCROLLER_T * scrlr, void *delete_me)
  548. {
  549.     NEXTED_PTR_T   *data_ptr = delete_me;
  550.     register NEXTED_PTR_T *tmp;
  551.     if (data_ptr == scrlr->first_data_ptr) {
  552.         scrlr->first_data_ptr = data_ptr->next;
  553.         if (data_ptr == scrlr->last_data_ptr)
  554.             scrlr->last_data_ptr = NULL;
  555.     } else {                    /* not first */
  556.         for (tmp = scrlr->first_data_ptr; tmp; tmp = tmp->next) {
  557.             if (tmp->next == data_ptr) {
  558.                 if (data_ptr == scrlr->last_data_ptr)
  559.                     scrlr->last_data_ptr = tmp;
  560.                 tmp->next = data_ptr->next;
  561.                 break;
  562.             }
  563.         }                       /* for */
  564.     }                           /* not first */
  565.     if (data_ptr == scrlr->current_data_ptr)
  566.         scrlr->current_data_ptr = data_ptr->next;
  567.     if (scrlr->data_destructor)
  568.         scrlr->data_destructor(scrlr, data_ptr);
  569.     AGFREE(data_ptr);
  570.     scrlr->data_created--;
  571.     scrlr->data_stored--;
  572.     return 0;
  573. }
  574. static void
  575. realloc_number_of_data(SCROLLER_T * scrlr, long dlong)
  576. {
  577.     void           *bptr;       /* DATA_ENTRY_T */
  578.     NEXTED_PTR_T   *prev = NULL;
  579.     void           *first = NULL;
  580.     if (dlong > 0) {
  581.         for (; dlong; dlong--, prev = bptr, scrlr->data_created++) {
  582.             bptr = AGMALLOC(scrlr->data_size);
  583.             if (!bptr) {
  584.                 ag_trace("Err: no memory for data");
  585.                 break;
  586.             }
  587.             memset(bptr, 0, scrlr->data_size);
  588.             if (prev)
  589.                 prev->next = bptr;
  590.             else
  591.                 first = bptr;
  592.         }                       /* of loop by malloc bucket */
  593.         if (!scrlr->current_data_ptr)
  594.             scrlr->current_data_ptr = first;
  595.         if (scrlr->last_data_ptr) {
  596.             scrlr->last_data_ptr->next = first;
  597.         } else
  598.             scrlr->first_data_ptr = first;
  599.         scrlr->last_data_ptr = bptr;
  600.     } else {
  601.         for (; dlong && scrlr->data_created > 0; dlong++) {
  602.             if (scrlr->current_data_ptr)
  603.                 delete_data_entry(scrlr, scrlr->current_data_ptr);
  604.             else
  605.                 delete_data_entry(scrlr, scrlr->first_data_ptr);
  606.         }
  607.     }
  608. }
  609. void
  610. ROWDATAAPI_set_size(SCROLLER_T * scrlr,
  611.                     u_long data_requested, u_char do_allocation)
  612. {
  613.     long            dlong;
  614.     scrlr->data_requested = data_requested;
  615.     scrlr->data_granted = (data_requested < scrlr->max_number_of_entries) ?
  616.         data_requested : scrlr->max_number_of_entries;
  617.     if (do_allocation) {
  618.         dlong = (long) scrlr->data_granted - (long) scrlr->data_created;
  619.         realloc_number_of_data(scrlr, dlong);
  620.     }
  621. }
  622. void
  623. ROWDATAAPI_descructor(SCROLLER_T * scrlr)
  624. {
  625.     register NEXTED_PTR_T *bptr;
  626.     register void  *next;
  627.     for (bptr = scrlr->first_data_ptr; bptr; bptr = next) {
  628.         next = bptr->next;
  629.         if (scrlr->data_destructor)
  630.             scrlr->data_destructor(scrlr, bptr);
  631.         AGFREE(bptr);
  632.     }
  633.     scrlr->data_created = 0;
  634.     scrlr->data_granted = 0;
  635.     scrlr->first_data_ptr =
  636.         scrlr->last_data_ptr = scrlr->current_data_ptr = NULL;
  637. }
  638. void           *
  639. ROWDATAAPI_locate_new_data(SCROLLER_T * scrlr)
  640. {
  641.     register NEXTED_PTR_T *bptr;
  642.     if (!scrlr->current_data_ptr) {     /* there was wrap */
  643.         bptr = scrlr->first_data_ptr;
  644.         if (!bptr) {
  645.             ag_trace("Err: SCROLLER_T:locate_new_data: internal error :(");
  646.             return NULL;
  647.         }
  648.         scrlr->first_data_ptr = bptr->next;
  649.         scrlr->last_data_ptr->next = bptr;
  650.         scrlr->last_data_ptr = (NEXTED_PTR_T *) bptr;
  651.         bptr->next = 0;
  652.     } else {
  653.         bptr = scrlr->current_data_ptr;
  654.         scrlr->current_data_ptr = bptr->next;
  655.         ++scrlr->data_stored;
  656.     }
  657.     scrlr->data_total_number++;
  658.     return bptr;
  659. }
  660. u_long
  661. ROWDATAAPI_get_total_number(SCROLLER_T * scrlr)
  662. {
  663.     return scrlr->data_total_number;
  664. }
  665. RMON_ENTRY_T   *
  666. ROWDATAAPI_header_DataEntry(struct variable * vp, oid * name,
  667.                             size_t * length, int exact,
  668.                             size_t * var_len,
  669.                             TABLE_DEFINTION_T * table_ptr,
  670.                             SCROLLER_T * (*extract_scroller) (void *body),
  671.                             size_t data_size, void *entry_ptr)
  672. {
  673.     long            ctrl_indx, data_index;
  674.     RMON_ENTRY_T   *hdr = NULL;
  675.     SCROLLER_T     *scrlr;
  676.     NEXTED_PTR_T   *bptr = NULL;
  677.     register u_long iii;
  678.     if (0 != AGUTIL_advance_index_name(vp, name, length, exact)) {
  679.         ag_trace("cannot advance_index_name");
  680.         return NULL;
  681.     }
  682.     ctrl_indx = vp->namelen >= *length ? 0 : name[vp->namelen];
  683.     if (ctrl_indx)
  684.         data_index =
  685.             ((int)(vp->namelen + 1) >= (int)*length) ? 0 : name[vp->namelen + 1];
  686.     else
  687.         data_index = 0;
  688.     if (exact) {
  689.         if (ctrl_indx && data_index) {
  690.             hdr = ROWAPI_find(table_ptr, ctrl_indx);
  691.             if (hdr) {
  692.                 scrlr = extract_scroller(hdr->body);
  693.                 bptr = scrlr->first_data_ptr;
  694.                 for (iii = 0; iii < scrlr->data_stored && bptr;
  695.                      iii++, bptr = bptr->next) {
  696.                     if ((long)bptr->data_index == data_index)
  697.                         break;
  698.                 }
  699.                 if (!bptr)
  700.                     hdr = NULL;
  701.             }
  702.         }
  703.     } else {
  704.         if (ctrl_indx)
  705.             hdr = ROWAPI_find(table_ptr, ctrl_indx);
  706.         else
  707.             hdr = ROWAPI_first(table_ptr);
  708.         if (hdr) {
  709.             scrlr = extract_scroller(hdr->body);
  710.             /*
  711.              * ag_trace ("get next after (%d %d)", (int) ctrl_indx, (int) data_index); 
  712.              */
  713.             bptr = scrlr->first_data_ptr;
  714.             for (iii = 0; iii < scrlr->data_stored && bptr;
  715.                  iii++, bptr = bptr->next) {
  716.                 if (bptr->data_index && (long)bptr->data_index > data_index)
  717.                     break;
  718.             }
  719.             if (bptr && (long)bptr->data_index <= data_index)
  720.                 bptr = NULL;
  721.             if (!bptr) {        /* travel to next row */
  722.                 /*
  723.                  * ag_trace ("Dbg: travel to next row"); 
  724.                  */
  725.                 for (hdr = hdr->next; hdr; hdr = hdr->next) {
  726.                     if (RMON1_ENTRY_VALID != hdr->status)
  727.                         continue;
  728.                     scrlr = extract_scroller(hdr->body);
  729.                     if (scrlr->data_stored <= 0)
  730.                         continue;
  731.                     for (bptr = scrlr->first_data_ptr; bptr;
  732.                          bptr = bptr->next) {
  733.                         if (bptr->data_index)
  734.                             break;
  735.                     }
  736.                     if (bptr)
  737.                         break;
  738.                 }
  739.             }
  740.             if (bptr) {         /* set new index */
  741.                 /*
  742.                  * ag_trace ("Dbg: So (%d %d)", (int) hdr->index, (int) bptr->data_index); 
  743.                  */
  744.                 name[vp->namelen] = hdr->ctrl_index;
  745.                 name[vp->namelen + 1] = bptr->data_index;
  746.                 *length = vp->namelen + 2;
  747.             } else
  748.                 hdr = NULL;
  749.         }
  750.     }
  751.     if (hdr)
  752.         memcpy(entry_ptr, bptr, data_size);
  753.     return hdr;
  754. }
  755. void
  756. init_rows(void)
  757. {
  758. }