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