We shall now discuss how inet allocates memory to store the data which is sent and received.
This is handled in buf.c.


1 /*
2 This file contains routines for buffer management.
3
4 Copyright 1995 Philip Homburg
5 */
6
7 #define BUF_IMPLEMENTATION      1       /* Avoid some macros */
8
9 #include "inet.h"
10
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include "generic/assert.h"
15 #include "generic/buf.h"
16 #include "generic/type.h"
17
18 THIS_FILE
19

BUF_USEMALLOC determines whether storage is allocated using malloc or by using arrays.
If BUF_USEMALLOC is defined, storage is allocated using malloc.
If BUF_USEMALLOC is not defined, storage is allocated using arrays.
Henceforth we shall assume storage using arrays.
We shall only handle the case when storage is allocated without malloc - by using arrays.

20 #ifndef BUF_USEMALLOC
21 #define BUF_USEMALLOC   0
22 #endif
23

Storage is allocated in chunks of 512 bytes of data since CRAMPED is not defined.

24 #ifndef BUF512_NR
25 #if CRAMPED
26 #define BUF512_NR       32
27 #else
28 #define BUF512_NR       128
29 #endif
30 #endif
31 #ifndef BUF2K_NR
32 #define BUF2K_NR        0
33 #endif
34 #ifndef BUF32K_NR
35 #define BUF32K_NR       0
36 #endif
37

ACC_NR defines the number of accessors in the accessors array which is an array of acc_t structures.

38 #define ACC_NR          ((BUF512_NR+BUF2K_NR+BUF32K_NR)*3/2)
39 #define CLIENT_NR       6
40

DECLARE_TYPE declares a structure which holds the data.
DECLARE_STORAGE declares an array of the structure.

41 #define DECLARE_TYPE(Tag, Type, Size)                                   \
42         typedef struct Tag                                              \
43         {                                                               \
44                 buf_t buf_header;                                       \
45                 char buf_data[Size];                                    \
46         } Type
47
48 #if BUF_USEMALLOC
49 #define DECLARE_STORAGE(Type, Ident, Nitems)                            \
50         PRIVATE Type *Ident
51
52 #define ALLOC_STORAGE(Ident, Nitems, Label)                             \
53         do                                                              \
54         {                                                               \
55                 printf("buf.c: malloc %d %s\n", Nitems, Label);         \
56                 Ident= malloc(sizeof(*Ident) * Nitems);                 \
57                 if (!Ident)                                             \
58                         ip_panic(( "unable to alloc %s", Label ));      \
59         } while(0)
60 #else
61 #define DECLARE_STORAGE(Type, Ident, Nitems)                            \
62         PRIVATE Type Ident[Nitems]
63
64 #define ALLOC_STORAGE(Ident, Nitems, Label)                             \
65         (void)0
66 #endif
67

The buffer structure is declared below.
buffers512 is the array which stores the data. buffers512 is an array of Buf512_t structures.
Buf512_t is the structure that holds buffer data.
A Buf512_t structure has 2 parts: the buf_header header field which stores information about the
buffer data and a buf_data field which stores the data.
buffers512 is an array of Buf512_t structures.
In the code below, buffers512 has BUF512_NR elements of Buf512_t structures.
Each element in buffers512 can store 512 bytes of data.
buf512_freelist points to a freelist of accessors (acc_t structures) which are free and can be used and which has buf_t structure allocated to it ie the acc_buffer is not null.
It is used by bf_memreq to return a acc_t structure which has a buffer allocated to it
but the buffer is not being used by another acc_t structure.
The buf512_freelist freelist is made up of accessors (acc_t structures).
An acc_t structure holds a pointer to a buf_t structure and holds pointers to other acc_t structures
which allows several buffers to link together in a singly linked list
so that inet can hold data of arbitrary size.

We shall now go over the buf_t structure. buf_t is defined in buf.h. Ignoring certain defines buf_t is defined as follows:

typedef struct buf
{
int buf_linkC;
buffree_t buf_free;
size_t buf_size;
char *buf_data_p;
} buf_t;

buf_linkC: holds the number of accessors which holds pointers to this structure. If buf_linkC = 0 the buffer goes back to one of the free lists.
buf_free: pointer to the function which is called to free the acc_t structures which holds the buffer.
buf_size: amount (in byes) of data held in buf_data.
buf_data_p: pointer to the buf_data array which holds the data.

We shall now go over the acc_t structure. acc_t is defined in buf.h. In general the specific implementations of the protocols (as in udp.c) access the buf_t structure indirectly throught the acc_t structure. Ignoring certain defines acc_t is defined as follows:

typedef struct acc
{
int acc_linkC;
int acc_offset, acc_length;
buf_t *acc_buffer;
struct acc *acc_next, *acc_ext_link;
} acc_t;

acc_linkC: holds the number of variables which points to this structure. If acc_linkC = 0 the buffer goes back to one of the free lists.

acc_offset: holds an offset in to the buffer data.

acc_length: length of buffer data which acc_t structure is storing.

acc_buffer: points to buf_t structure which stores the data.

acc_next: points to next acc_t structure in linked list. When the acc_t structure is not being used it points to the next free item in a linked list. When it's not free, the linked list is used in the following way for example: one acc_t structure points to the ip header, acc_next points to the udp header., the acc_next of that acc_t structure points to the data, etc. In the case the acc_t structure is not free, the different buffers which belong to the different acc_t structures in the linked list are considered to store the same chunk of data. Therefore if the size of the array pointed to by buf_data_p is not large enough to hold the chunk of data desired, new acc_t structures (with their own buf_data_p arrays) are used until there are enough buf_data_p buffers to hold all of data. The acc_t structures are linked together by the acc_next pointer.

acc_ext_link: points to next acc_t structure in linked list. It's used by the implementation of a protocol.

One define which is used quite often is the following from buf.h


#define ptr2acc_data(/* acc_t * */ a) (bf_temporary_acc=(a), \
(&bf_temporary_acc->acc_buffer->buf_data_p[bf_temporary_acc-> \
acc_offset]))


68 #if BUF512_NR
69 DECLARE_TYPE(buf512, buf512_t, 512);
70 PRIVATE acc_t *buf512_freelist;
71 DECLARE_STORAGE(buf512_t, buffers512, BUF512_NR);
72 FORWARD void bf_512free ARGS(( acc_t *acc ));
73 #endif
74 #if BUF2K_NR
75 DECLARE_TYPE(buf2K, buf2K_t, (2*1024));
76 PRIVATE acc_t *buf2K_freelist;
77 DECLARE_STORAGE(buf2K_t, buffers2K, BUF2K_NR);
78 FORWARD void bf_2Kfree ARGS(( acc_t *acc ));
79 #endif
80 #if BUF32K_NR
81 DECLARE_TYPE(buf32K, buf32K_t, (32*1024));
82 PRIVATE acc_t *buf32K_freelist;
83 DECLARE_STORAGE(buf32K_t, buffers32K, BUF32K_NR);
84 FORWARD void bf_32Kfree ARGS(( acc_t *acc ));
85 #endif
86

acc_freelist points to a freelist of acc_t structures which are free and can
be used and which does not have a buf_t structure allocated to it ie the acc_buffer is null. It is used
by bf_dupacc to return a copy of the original acc_t structure. Since the
acc_t structure stores a pointer to the buf_t structure, bf_dupacc merely
sets the pointer to the buf_t structure in the original buffer and no new
buf_t structure need be allocated to it.

87 PRIVATE acc_t *acc_freelist;

accessors is an array of acc_t structures. An acc_t structure holds a pointer
to a buf_t structure. A buf_t structure holds a pointer to a buf_data field
and holds information about the data stored in the buf_data field.

88 DECLARE_STORAGE(acc_t, accessors, ACC_NR);
89

The freereq array which is called when a freelist runs out of free acc_t structures.

90 PRIVATE bf_freereq_t freereq[CLIENT_NR];
91 PRIVATE size_t bf_buf_gran;
92
93 PUBLIC size_t bf_free_bufsize;
94 PUBLIC acc_t *bf_temporary_acc;
95
96 #ifdef BUF_CONSISTENCY_CHECK
97 int inet_buf_debug;
98 unsigned buf_generation;
99 PRIVATE bf_checkreq_t checkreq[CLIENT_NR];
100 #endif
101
102 #ifndef BUF_TRACK_ALLOC_FREE
103 FORWARD acc_t *bf_small_memreq ARGS(( size_t size ));
104 #else
105 FORWARD acc_t *_bf_small_memreq ARGS(( char *clnt_file, int clnt_line,
106                                                                 size_t size ));
107 #define bf_small_memreq(a) _bf_small_memreq(clnt_file, clnt_line, a)
108 #endif
109 FORWARD void free_accs ARGS(( void ));
110 #ifdef BUF_CONSISTENCY_CHECK
111 FORWARD void count_free_bufs ARGS(( acc_t *list ));
112 FORWARD int report_buffer ARGS(( buf_t *buf, char *label, int i ));
113 #endif
114

bf_init initializes the buffer used to store data. We shall only handle
the case when storage is allocated without malloc - by using arrays (this
is done by not defining BUF_USEMALLOC) - and where each buffer stores 512
bytes of data (this is done by defining BUF512_NR).

115 PUBLIC void bf_init()
116 {
117         int i;
118         size_t size;
119         size_t buf_s;
120         acc_t *acc;
121
122         bf_buf_gran= BUF_S;
123         buf_s= 0;
124

The freereq array is called when a freelist runs out of free acc_t structures.
The elements of the freereq array are set to null at initialization time.

125         for (i=0;i<CLIENT_NR;i++)
126                 freereq[i]=0;
127 #ifdef BUF_CONSISTENCY_CHECK
128         for (i=0;i<CLIENT_NR;i++)
129                 checkreq[i]=0;
130 #endif
131
132 #if BUF512_NR
133         ALLOC_STORAGE(buffers512, BUF512_NR, "512B-buffers");
134 #endif
135 #if BUF2K_NR
136         ALLOC_STORAGE(buffers2K, BUF2K_NR, "2K-buffers");
137 #endif
138 #if BUF32K_NR
139         ALLOC_STORAGE(buffers32K, BUF32K_NR, "32K-buffers");
140 #endif
141         ALLOC_STORAGE(accessors, ACC_NR, "accs");
142

The two freelists pointed to by acc_freelist and buf512_freelist are set up in the following.

143         acc_freelist= NULL;
144         for (i=0;i<ACC_NR;i++)
145         {
146                 memset(&accessors[i], '\0', sizeof(accessors[i]));
147
148                 accessors[i].acc_linkC= 0;
149                 accessors[i].acc_next= acc_freelist;
150                 acc_freelist= &accessors[i];
151         }
152
153 #define INIT_BUFFERS(Ident, Nitems, Freelist, Freefunc)                 \
154         do                                                              \
155         {                                                               \
156                 Freelist= NULL;                                         \
157                 for (i=0;i<Nitems;i++)                                  \
158                 {                                                       \
159                         acc= acc_freelist;                              \
160                         if (!acc)                                       \
161                                 ip_panic(( "fewer accessors than buffers")); \
162                         acc_freelist= acc->acc_next;                    \
163                         acc->acc_linkC= 0;                              \
164                                                                         \
165                         memset(&Ident[i], '\0', sizeof(Ident[i]));      \
166                         Ident[i].buf_header.buf_linkC= 0;               \
167                         Ident[i].buf_header.buf_free= Freefunc;         \
168                         Ident[i].buf_header.buf_size=                   \
169                                 sizeof(Ident[i].buf_data);              \
170                         Ident[i].buf_header.buf_data_p=                 \
171                                 Ident[i].buf_data;                      \
172                                                                         \
173                         acc->acc_buffer= &Ident[i].buf_header;          \
174                         acc->acc_next= Freelist;                        \
175                         Freelist= acc;                                  \
176                 }                                                       \
177                 if (sizeof(Ident[0].buf_data) < bf_buf_gran)            \
178                         bf_buf_gran= sizeof(Ident[0].buf_data);         \
179                 if (sizeof(Ident[0].buf_data) > buf_s)                  \
180                         buf_s= sizeof(Ident[0].buf_data);               \
181         } while(0)
182
183 #if BUF512_NR
184         INIT_BUFFERS(buffers512, BUF512_NR, buf512_freelist, bf_512free);
185 #endif
186 #if BUF2K_NR
187         INIT_BUFFERS(buffers2K, BUF2K_NR, buf2K_freelist, bf_2Kfree);
188 #endif
189 #if BUF32K_NR
190         INIT_BUFFERS(buffers32K, BUF32K_NR, buf32K_freelist, bf_32Kfree);
191 #endif
192
193 #undef INIT_BUFFERS
194
195         assert (buf_s == BUF_S);
196 }
197
198 #ifndef BUF_CONSISTENCY_CHECK

bf_logon is called by the user process when it initializes.
bf_logon() defines the freereq array which is called when a freelist runs out of free acc_t structures.
For example, free_accs calls the freereq array functions to free acc_t structures.

199 PUBLIC void bf_logon(func)
200 bf_freereq_t func;
201 #else
202 PUBLIC void bf_logon(func, checkfunc)
203 bf_freereq_t func;
204 bf_checkreq_t checkfunc;
205 #endif
206 {
207         int i;
208
209         for (i=0;i<CLIENT_NR;i++)
210                 if (!freereq[i])
211                 {
212                         freereq[i]=func;
213 #ifdef BUF_CONSISTENCY_CHECK
214                         checkreq[i]= checkfunc;
215 #endif
216                         return;
217                 }
218
219         ip_panic(( "buf.c: to many clients" ));
220 }
221
222 /*
223 bf_memreq
224 */
225

bf_memreq(size) returns a acc_t structure whose bf_bufsize() is size. It calls freereq if
there are not any free acc_t structures in the buf512_freelist free list.

226 #ifndef BUF_TRACK_ALLOC_FREE
227 PUBLIC acc_t *bf_memreq(size)
228 #else
229 PUBLIC acc_t *_bf_memreq(clnt_file, clnt_line, size)
230 char *clnt_file;
231 int clnt_line;
232 #endif
233 size_t size;
234 {
235         acc_t *head, *tail, *new_acc;
236         buf_t *buf;
237         int i,j;
238         size_t count;
239
240         assert (size>0);
241
242         head= NULL;

Loop allocates an accessor which is the head of a linked list of accessors.
Each accessor holds a pointer to a buffer.
The sum of the size of the buffers is equal to size.
The sum of the size of the buffers is returned by bf_bufsize().
If size of the data > 512 bytes, the data is stored in multiple accessors such that
the sum of the size of accessors is equal to the sum of the size of the accessors.

243         while (size)
244         {
245                 new_acc= NULL;
246
247                 /* Note the tricky dangling else... */
248 #define ALLOC_BUF(Freelist, Bufsize)                                    \
249         if (Freelist && (Bufsize == BUF_S || size <= Bufsize))          \
250         {                                                               \
251                 new_acc= Freelist;                                      \
252                 Freelist= new_acc->acc_next;                            \
253                                                                         \

Accessor should not be used. Therefore acc_linkC = 0.

254                 assert(new_acc->acc_linkC == 0);                        \

Mark accessor being used for first time.

255                 new_acc->acc_linkC= 1;                                  \
256                 buf= new_acc->acc_buffer;                               \

Buffer should not be used. Therefore buf_linkC = 0.

257                 assert(buf->buf_linkC == 0);                            \

Mark buffer being used for first time.

258                 buf->buf_linkC= 1;                                      \
259         }                                                               \
260         else
261
262                 /* Sort attempts by buffer size */

BUF_S is defined as 512 in inet/const.h. Therefore so long as buf512_freelist still has elements in the list, it will allocate accessors from the buf512_freelist list.

263 #if BUF512_NR
264                 ALLOC_BUF(buf512_freelist, 512)
265 #endif
266 #if BUF2K_NR
267                 ALLOC_BUF(buf2K_freelist, 2*1024)
268 #endif
269 #if BUF32K_NR
270                 ALLOC_BUF(buf32K_freelist, 32*1024)
271 #endif
272 #undef ALLOC_BUF

Free some accessors if there are currently no free accessors.

273                 {
274                         DBLOCK(1, printf("freeing buffers\n"));
275
276                         bf_free_bufsize= 0;
277                         for (i=0; bf_free_bufsize<size && i<MAX_BUFREQ_PRI;
278                                 i++)
279                         {
280                                 for (j=0; j<CLIENT_NR; j++)
281                                 {
282                                         if (freereq[j])
283                                                 (*freereq[j])(i);
284                                 }
285 #if DEBUG
286  { acc_t *acc;
287    j= 0; for(acc= buf512_freelist; acc; acc= acc->acc_next) j++;
288    printf("# of free 512-bytes buffer is now %d\n", j); }
289 #endif
290                         }
291 #if DEBUG
292  { printf("last level was level %d\n", i-1); }
293 #endif
294                         if (bf_free_bufsize<size)
295                                 ip_panic(( "not enough buffers freed" ));
296
297                         continue;
298                 }
299
300 #ifdef BUF_TRACK_ALLOC_FREE
301                 new_acc->acc_alloc_file= clnt_file;
302                 new_acc->acc_alloc_line= clnt_line;
303                 buf->buf_alloc_file= clnt_file;
304                 buf->buf_alloc_line= clnt_line;
305 #endif
306
307                 if (!head)
308                         head= new_acc;
309                 else
310                         tail->acc_next= new_acc;
311                 tail= new_acc;
312
313                 count= tail->acc_buffer->buf_size;
314                 if (count > size)
315                         count= size;
316
317                 tail->acc_offset= 0;
318                 tail->acc_length=  count;
319                 size -= count;
320         }

Mark tail as end of linked list by setting the next pointer to null.

321         tail->acc_next= 0;
322
323 #if DEBUG
324         bf_chkbuf(head);
325 #endif
326
327         return head;
328 }
329
330 /*
331 bf_small_memreq
332 */
333
334 #ifndef BUF_TRACK_ALLOC_FREE
335 PRIVATE acc_t *bf_small_memreq(size)
336 #else
337 PRIVATE acc_t *_bf_small_memreq(clnt_file, clnt_line, size)
338 char *clnt_file;
339 int clnt_line;
340 #endif
341 size_t size;
342 {
343         return bf_memreq(size);
344 }
345

bf_afree(acc) attempts to free all of the acc_t structures in the linked list whose head is pointed
to by acc. If the buf_t structure acc_buffer is still being used by
another acc_t structure, acc is put on the acc_freelist; else acc is put on the buf512_freelist.
346 #ifndef BUF_TRACK_ALLOC_FREE
347 PUBLIC void bf_afree(acc)
348 #else
349 PUBLIC void _bf_afree(clnt_file, clnt_line, acc)
350 char *clnt_file;
351 int clnt_line;
352 #endif
353 acc_t *acc;
354 {
355         acc_t *next_acc;
356         buf_t *buf;
357
358         while (acc)
359         {
360 #if defined(bf_afree)
361                 DIFBLOCK(1, (acc->acc_linkC <= 0),
362                         printf("clnt_file= %s, clnt_line= %d\n",
363                         clnt_file, clnt_line));
364 #endif
365                 assert (acc->acc_linkC>0);

Checks if the accessor is still being used. If it is then no more accessors are freed.

366                 if (--acc->acc_linkC > 0)
367                         break;
368
369 #ifdef BUF_TRACK_ALLOC_FREE
370                 acc->acc_free_file= clnt_file;
371                 acc->acc_free_line= clnt_line;
372 #endif
373                 buf= acc->acc_buffer;
374                 assert (buf);
375
376 #if defined(bf_afree)
377                 DIFBLOCK(1, (buf->buf_linkC == 0),
378                         printf("clnt_file= %s, clnt_line= %d\n",
379                         clnt_file, clnt_line));
380 #endif
381                 assert (buf->buf_linkC>0);
Checks if the buf_t structure acc_buffer of the accessor is still being used.
If it is then acc is put on the acc_freelist.

Checks if the buffer is still being used by another accessor. If it is then the accessor is
placed in the acc_freelist list and acc_buffer is set to null.

382                 if (--buf->buf_linkC > 0)
383                 {
384                         acc->acc_buffer= NULL;
385                         next_acc= acc->acc_next;
386                         acc->acc_next= acc_freelist;
387                         acc_freelist= acc;
388 #ifdef BUF_CONSISTENCY_CHECK
389                         if (inet_buf_debug)
390                         {
391                                 acc->acc_offset= 0xdeadbeaf;
392                                 acc->acc_length= 0xdeadbeaf;
393                                 acc->acc_buffer= (buf_t *)0xdeadbeaf;
394                                 acc->acc_ext_link= (acc_t *)0xdeadbeaf;
395                         }
396 #endif
397                         acc= next_acc;
398                         continue;
399                 }
400

If the buffer is not being used by another accessor, the accessor is
placed in the buf512_freelist list by calling buf->buf_free(acc).

401                 bf_free_bufsize += buf->buf_size;
402 #ifdef BUF_TRACK_ALLOC_FREE
403                 buf->buf_free_file= clnt_file;
404                 buf->buf_free_line= clnt_line;
405 #endif
406                 next_acc= acc->acc_next;
407                 buf->buf_free(acc);
408                 acc= next_acc;
409                 continue;
410         }
411 }

bf_dupacc(acc_ptr) returns a copy of the original accessor pointed to by acc_ptr.
bf_dupacc does the copy by copying the contents of the original accessor to the new accessor.

412
413 #ifndef BUF_TRACK_ALLOC_FREE
414 PUBLIC acc_t *bf_dupacc(acc_ptr)
415 #else
416 PUBLIC acc_t *_bf_dupacc(clnt_file, clnt_line, acc_ptr)
417 char *clnt_file;
418 int clnt_line;
419 #endif
420 register acc_t *acc_ptr;
421 {
422         register acc_t *new_acc;
423         int i, j;
424

Checks if there are any more accessors in the acc_freelist free list.

425         if (!acc_freelist)
426         {

If there are no more accessors in the acc_freelist free list, call free_accs() to get more.

427                 free_accs();
428                 if (!acc_freelist)
429                         ip_panic(( "buf.c: out of accessors" ));
430         }
431         new_acc= acc_freelist;
432         acc_freelist= new_acc->acc_next;
433

Copy old accessor to new accessor.

434         *new_acc= *acc_ptr;

Increment acc_linkC because another accessor is pointing to it.

435         if (acc_ptr->acc_next)
436                 acc_ptr->acc_next->acc_linkC++;
437         if (acc_ptr->acc_buffer)

Increment buf_linkC because another accessor is pointing to it.

438                 acc_ptr->acc_buffer->buf_linkC++;
439         new_acc->acc_linkC= 1;
440 #ifdef BUF_TRACK_ALLOC_FREE
441         new_acc->acc_alloc_file= clnt_file;
442         new_acc->acc_alloc_line= clnt_line;
443 #endif
444         return new_acc;
445 }
446

acc_ptr is the head of a linked list of accesssors.
Each accessor holds a pointer to a buffer.
The sum of the size of the buffers is returned by bf_bufsize().

447 PUBLIC size_t bf_bufsize(acc_ptr)
448 register acc_t *acc_ptr;
449 {
450         register size_t size;
451
452 assert(acc_ptr);
453
454         size=0;
455
456         while (acc_ptr)
457         {
458 assert(acc_ptr >= accessors && acc_ptr <= &accessors[ACC_NR-1]);
459                 size += acc_ptr->acc_length;
460                 acc_ptr= acc_ptr->acc_next;
461         }
462         return size;
463 }
464

I have no idea what bf_packIffLess() does.

465 #ifndef BUF_TRACK_ALLOC_FREE
466 PUBLIC acc_t *bf_packIffLess(pack, min_len)
467 #else
468 PUBLIC acc_t *_bf_packIffLess(clnt_file, clnt_line, pack, min_len)
469 char *clnt_file;
470 int clnt_line;
471 #endif
472 acc_t *pack;
473 int min_len;
474 {
475         if (!pack || pack->acc_length >= min_len)
476                 return pack;
477
478 #if DEBUG
479 #ifdef bf_packIffLess
480  { where(); printf("calling bf_pack because of %s %d: %d\n", bf_pack_file,
481         bf_pack_line, min_len); }
482 #endif
483 #endif
484         return bf_pack(pack);
485 }
486

I have no idea what bf_pack() does.

487 #ifndef BUF_TRACK_ALLOC_FREE
488 PUBLIC acc_t *bf_pack(old_acc)
489 #else
490 PUBLIC acc_t *_bf_pack(clnt_file, clnt_line, old_acc)
491 char *clnt_file;
492 int clnt_line;
493 #endif
494 acc_t *old_acc;
495 {
496         acc_t *new_acc, *acc_ptr_old, *acc_ptr_new;
497         size_t size, offset_old, offset_new, block_size, block_size_old;
498
499         /* Check if old acc is good enough. */
500         if (!old_acc || !old_acc->acc_next && old_acc->acc_linkC == 1 &&
501                 old_acc->acc_buffer->buf_linkC == 1)
502         {
503                 return old_acc;
504         }
505
506         size= bf_bufsize(old_acc);
507         assert(size > 0);
508         new_acc= bf_memreq(size);
509         acc_ptr_old= old_acc;
510         acc_ptr_new= new_acc;
511         offset_old= 0;
512         offset_new= 0;
513         while (size)
514         {
515                 assert (acc_ptr_old);
516                 if (offset_old == acc_ptr_old->acc_length)
517                 {
518                         offset_old= 0;
519                         acc_ptr_old= acc_ptr_old->acc_next;
520                         continue;
521                 }
522                 assert (offset_old < acc_ptr_old->acc_length);
523                 block_size_old= acc_ptr_old->acc_length - offset_old;
524                 assert (acc_ptr_new);
525                 if (offset_new == acc_ptr_new->acc_length)
526                 {
527                         offset_new= 0;
528                         acc_ptr_new= acc_ptr_new->acc_next;
529                         continue;
530                 }
531                 assert (offset_new < acc_ptr_new->acc_length);
532                 block_size= acc_ptr_new->acc_length - offset_new;
533                 if (block_size > block_size_old)
534                         block_size= block_size_old;
535                 memcpy(ptr2acc_data(acc_ptr_new)+offset_new,
536                         ptr2acc_data(acc_ptr_old)+offset_old, block_size);
537                 offset_new += block_size;
538                 offset_old += block_size;
539                 size -= block_size;
540         }
541         bf_afree(old_acc);
542         return new_acc;
543 }
544

bf_cut(data, offset, length) returns a copy of the chunk of data starting with
offset and ending at offset + length - 1. It does not free the original data.

545 #ifndef BUF_TRACK_ALLOC_FREE
546 PUBLIC acc_t *bf_cut (data, offset, length)
547 #else
548 PUBLIC acc_t *_bf_cut (clnt_file, clnt_line, data, offset, length)
549 char *clnt_file;
550 int clnt_line;
551 #endif
552 register acc_t *data;
553 register unsigned offset;
554 register unsigned length;
555 {
556         register acc_t *head, *tail;
557
558         if (!data && !offset && !length)
559                 return 0;
560 #ifdef BUF_TRACK_ALLOC_FREE
561         assert(data ||
562                 (printf("from %s, %d: %u, %u\n",
563                 clnt_file, clnt_line, offset, length), 0));
564 #else
565         assert(data);
566 #endif
567
568         assert(data);
569 #if DEBUG
570         bf_chkbuf(data);
571 #endif
572

If length = 0 return an accessor with no data.

573         if (!length)
574         {
575                 head= bf_dupacc(data);
576                 bf_afree(head->acc_next);
577                 head->acc_next= 0;
578                 head->acc_length= 0;
579 #if DEBUG
580                 bf_chkbuf(data);
581 #endif
582                 return head;
583         }

Search for accessor which has the data beginning at offset.

584         while (data && offset>=data->acc_length)
585         {
586                 offset -= data->acc_length;
587                 data= data->acc_next;
588         }
589
590         assert (data);
591

Free the accessors which are holding data > offset.

592         head= bf_dupacc(data);
593         bf_afree(head->acc_next);
594         head->acc_next= 0;

Variable offset = bytes of excess data in accessor pointed to by head.

595         head->acc_offset += offset;
596         head->acc_length -= offset;

Set the variable length equal to the size of data still needed.
If length (size requested) < head->acc_length (size of head accessor), set size of head accessor to length.

597         if (length >= head->acc_length)
598                 length -= head->acc_length;
599         else
600         {
601                 head->acc_length= length;
602                 length= 0;
603         }
604         tail= head;
605         data= data->acc_next;

Copy the data to new accessors by calling bf_dupacc(data) for the size(length) given.
Make a "deep copy" of the data (rather than a "shallow copy") by copying the contents the accessors
and not simply make a new pointer to the accessors.

606         while (data && length && length>=data->acc_length)
607         {
608                 tail->acc_next= bf_dupacc(data);
609                 tail= tail->acc_next;
610                 bf_afree(tail->acc_next);
611                 tail->acc_next= 0;
612                 data= data->acc_next;
613                 length -= tail->acc_length;
614         }
615         if (length)
616         {

If there is still data to be copied there the variable data should not be null.

617 #ifdef bf_cut
618                 assert (data ||
619                         (printf("bf_cut called from %s:%d\n",
620                         clnt_file, clnt_line), 0));
621 #else
622                 assert (data);
623 #endif

Copy data.

624                 tail->acc_next= bf_dupacc(data);
625                 tail= tail->acc_next;

Free extra data.

626                 bf_afree(tail->acc_next);

Set acc_length to the remaining data requested.

627                 tail->acc_next= 0;
628                 tail->acc_length= length;
629         }
630 #if DEBUG
631         bf_chkbuf(data);
632 #endif
633         return head;
634 }
635

bf_delhead (data, offset) returns a copy of the chunk of data starting with offset. It frees the original accessors.

636 #ifndef BUF_TRACK_ALLOC_FREE
637 PUBLIC acc_t *bf_delhead (data, offset)
638 #else
639 PUBLIC acc_t *_bf_delhead (clnt_file, clnt_line, data, offset)
640 char *clnt_file;
641 int clnt_line;
642 #endif
643 register acc_t *data;
644 register unsigned offset;
645 {
646         acc_t *new_acc;
647
648         assert(data);
649
650         /* Find the acc we need to modify. */
651         new_acc= data;
652         while(offset >= new_acc->acc_length)
653         {
654                 offset -= new_acc->acc_length;
655                 new_acc= new_acc->acc_next;
656 #ifdef BUF_TRACK_ALLOC_FREE
657                 assert(new_acc || (printf("called from %s, %d\n",
658                         clnt_file, clnt_line),0));
659 #else
660                 assert(new_acc);
661 #endif
662         }
663
664         /* Discard the old acc(s) */
665         if (new_acc != data)
666         {

Increment acc_linkC so that bf_afree does not free any accessors after new_acc.

667                 new_acc->acc_linkC++;
668                 bf_afree(data);
669                 data= new_acc;
670         }
671
672         /* Make sure that acc_linkC == 1 */

No one else is using the accessor.

673         if (data->acc_linkC != 1)
674         {
675                 new_acc= bf_dupacc(data);
676                 bf_afree(data);
677                 data= new_acc;
678         }
679
680         /* Delete the last bit by modifying acc_offset and acc_length */
681         data->acc_offset += offset;
682         data->acc_length -= offset;
683         return data;
684 }
685

bf_append() appends data_second to data_first. It frees the original accessors.

686 /*
687 bf_append
688 */
689
690 #ifndef BUF_TRACK_ALLOC_FREE
691 PUBLIC acc_t *bf_append(data_first, data_second)
692 #else
693 PUBLIC acc_t *_bf_append(clnt_file, clnt_line, data_first, data_second)
694 char *clnt_file;
695 int clnt_line;
696 #endif
697 acc_t *data_first;
698 acc_t  *data_second;
699 {
700         acc_t *head, *tail, *new_acc, *acc_ptr_new, tmp_acc, *curr;
701         char *src_ptr, *dst_ptr;
702         size_t size, offset_old, offset_new, block_size_old, block_size;
703
704         if (!data_first)
705                 return data_second;
706         if (!data_second)
707                 return data_first;
708
709         head= 0;
710         while (data_first)
711         {

Make sure no one else is using the accessor.

712                 if (data_first->acc_linkC == 1)
713                         curr= data_first;
714                 else

Copy the accessor and then free the original accessor.

715                 {
716                         curr= bf_dupacc(data_first);
717                         assert (curr->acc_linkC == 1);
718                         bf_afree(data_first);
719                 }
720                 data_first= curr->acc_next;

Only copy the accessor if there is data in it.

721                 if (!curr->acc_length)
722                 {
723                         curr->acc_next= 0;
724                         bf_afree(curr);
725                         continue;
726                 }

Place accessor in linked list.

727                 if (!head)
728                         head= curr;
729                 else
730                         tail->acc_next= curr;
731                 tail= curr;
732         }

If there is no data in data_first return data_second.

733         if (!head)
734                 return data_second;
735         tail->acc_next= 0;
736

Skip accessors which have no data.

737         while (data_second && !data_second->acc_length)
738         {
739                 curr= data_second;
740                 data_second= data_second->acc_next;
741                 if (data_second)
742                         data_second->acc_linkC++;
743                 bf_afree(curr);
744         }
745         if (!data_second)
746                 return head;
747
748         if (tail->acc_length + data_second->acc_length >
749                 tail->acc_buffer->buf_size)
750         {
751                 tail->acc_next= data_second;
752                 return head;
753         }
754

If data in data_second fits in tail and tail is not used by anything else, then
copy the data from data_second to tail and put the rest of chunk of data in the
data_second linked list in the linked list pointed to by head.

755         if (tail->acc_buffer->buf_size == bf_buf_gran &&
756                 tail->acc_buffer->buf_linkC == 1)
757         {
758                 if (tail->acc_offset)
759                 {
760                         memmove(tail->acc_buffer->buf_data_p,
761                                 ptr2acc_data(tail), tail->acc_length);
762                         tail->acc_offset= 0;
763                 }
764                 dst_ptr= ptr2acc_data(tail) + tail->acc_length;
765                 src_ptr= ptr2acc_data(data_second);
766                 memcpy(dst_ptr, src_ptr, data_second->acc_length);
767                 tail->acc_length += data_second->acc_length;
768                 tail->acc_next= data_second->acc_next;
769                 if (data_second->acc_next)
770                         data_second->acc_next->acc_linkC++;
771                 bf_afree(data_second);
772                 return head;
773         }
774
775         new_acc= bf_small_memreq(tail->acc_length+data_second->acc_length);
776         acc_ptr_new= new_acc;
777         offset_old= 0;
778         offset_new= 0;
779         size= tail->acc_length;

If data in data_second fits in tail and tail is used by someone else, then
get a new accessor acc_ptr_new (ie new_acc) and copy the old data from tail and data_second
to acc_ptr_new.

780         while (size)
781         {
782 assert (acc_ptr_new);
783                 if (offset_new == acc_ptr_new->acc_length)
784                 {
785                         offset_new= 0;
786                         acc_ptr_new= acc_ptr_new->acc_next;
787                         continue;
788                 }
789 assert (offset_new < acc_ptr_new->acc_length);
790 assert (offset_old < tail->acc_length);
791                 block_size_old= tail->acc_length - offset_old;
792                 block_size= acc_ptr_new->acc_length - offset_new;
793                 if (block_size > block_size_old)
794                         block_size= block_size_old;
795                 memcpy(ptr2acc_data(acc_ptr_new)+offset_new,
796                         ptr2acc_data(tail)+offset_old, block_size);
797                 offset_new += block_size;
798                 offset_old += block_size;
799                 size -= block_size;
800         }
801         offset_old= 0;
802         size= data_second->acc_length;
803         while (size)
804         {
805 assert (acc_ptr_new);
806                 if (offset_new == acc_ptr_new->acc_length)
807                 {
808                         offset_new= 0;
809                         acc_ptr_new= acc_ptr_new->acc_next;
810                         continue;
811                 }
812 assert (offset_new < acc_ptr_new->acc_length);
813 assert (offset_old < data_second->acc_length);
814                 block_size_old= data_second->acc_length - offset_old;
815                 block_size= acc_ptr_new->acc_length - offset_new;
816                 if (block_size > block_size_old)
817                         block_size= block_size_old;
818                 memcpy(ptr2acc_data(acc_ptr_new)+offset_new,
819                         ptr2acc_data(data_second)+offset_old, block_size);
820                 offset_new += block_size;
821                 offset_old += block_size;
822                 size -= block_size;
823         }

Replace tail and data_second with new_acc and put new_acc in the appropriate place in
the linked list headed by head.

824         tmp_acc= *tail;
825         *tail= *new_acc;
826         *new_acc= tmp_acc;
827
828         bf_afree(new_acc);
829         while (tail->acc_next)
830                 tail= tail->acc_next;
831
832         tail->acc_next= data_second->acc_next;
833         if (data_second->acc_next)
834                 data_second->acc_next->acc_linkC++;
835         bf_afree(data_second);
836         return head;
837 }
838

bf_512free(acc) puts the accessor acc at the head of the buf512_freelist list.

839 #if BUF512_NR
840 PRIVATE void bf_512free(acc)
841 acc_t *acc;
842 {
843 #ifdef BUF_CONSISTENCY_CHECK
844         if (inet_buf_debug)
845                 memset(acc->acc_buffer->buf_data_p, 0xa5, 512);
846 #endif
847         acc->acc_next= buf512_freelist;
848         buf512_freelist= acc;
849 }
850 #endif
851 #if BUF2K_NR
852 PRIVATE void bf_2Kfree(acc)
853 acc_t *acc;
854 {
855 #ifdef BUF_CONSISTENCY_CHECK
856         if (inet_buf_debug)
857                 memset(acc->acc_buffer->buf_data_p, 0xa5, 2*1024);
858 #endif
859         acc->acc_next= buf2K_freelist;
860         buf2K_freelist= acc;
861 }
862 #endif
863 #if BUF32K_NR
864 PRIVATE void bf_32Kfree(acc)
865 acc_t *acc;
866 {
867 #ifdef BUF_CONSISTENCY_CHECK
868         if (inet_buf_debug)
869                 memset(acc->acc_buffer->buf_data_p, 0xa5, 32*1024);
870 #endif
871         acc->acc_next= buf32K_freelist;
872         buf32K_freelist= acc;
873 }
874 #endif
875
876 #ifdef BUF_CONSISTENCY_CHECK
877 PUBLIC int bf_consistency_check()
878 {
879         acc_t *acc;
880         buf_t *buf;
881         int silent;
882         int error;
883         int i;
884
885         buf_generation++;
886
887         for (i=0; i<CLIENT_NR; i++)
888         {
889                 if (checkreq[i])
890                         (*checkreq[i])();
891         }
892
893         /* Add information about free accessors */
894         for(acc= acc_freelist; acc; acc= acc->acc_next)
895         {
896                 if (acc->acc_generation == buf_generation-1)
897                 {
898                         acc->acc_generation= buf_generation;
899                         acc->acc_check_linkC= 0;
900                 }
901                 else
902                 {
903                         assert(acc->acc_generation == buf_generation &&
904                                 acc->acc_check_linkC > 0);
905                         acc->acc_check_linkC= -acc->acc_check_linkC;
906                 }
907         }
908
909 #if BUF512_NR
910         count_free_bufs(buf512_freelist);
911 #endif
912 #if BUF2K_NR
913         count_free_bufs(buf2K_freelist);
914 #endif
915 #if BUF32K_NR
916         count_free_bufs(buf32K_freelist);
917 #endif
918
919         error= 0;
920
921         /* Report about accessors */
922         silent= 0;
923         for (i=0, acc= accessors; i<ACC_NR; i++, acc++)
924         {
925                 if (acc->acc_generation != buf_generation)
926                 {
927                         error++;
928                         assert(acc->acc_generation == buf_generation-1);
929                         acc->acc_generation= buf_generation;
930                         if (!silent)
931                         {
932                                 printf(
933 "acc[%d] (0x%x) has been lost with count %d, last allocated at %s, %d\n",
934         i, acc, acc->acc_linkC, acc->acc_alloc_file, acc->acc_alloc_line);
935 #if 0
936                                 silent= 1;
937 #endif
938                         }
939                         continue;
940                 }
941                 if (acc->acc_check_linkC == acc->acc_linkC)
942                         continue;
943                 error++;
944                 if (acc->acc_check_linkC < 0)
945                 {
946                         if (!silent)
947                         {
948                                 printf(
949 "acc[%d] is freed but still in use, allocated at %s, %d, freed at %s, %d\n",
950                                 i, acc->acc_alloc_file, acc->acc_alloc_line,
951                                 acc->acc_free_file, acc->acc_free_line);
952                         }
953                         acc->acc_check_linkC= -acc->acc_check_linkC;
954                         if (acc->acc_check_linkC == acc->acc_linkC)
955                         {
956                                 silent= 1;
957                                 continue;
958                         }
959                 }
960                 if (!silent)
961                 {
962                         printf(
963 "# of tracked links (%d) for acc[%d] don't match with stored link count %d\n",
964                                 acc->acc_check_linkC, i, acc->acc_linkC);
965                         printf("acc[%d] was allocated at %s, %d\n",
966                                 i, acc->acc_alloc_file, acc->acc_alloc_line);
967                         silent=1;
968                 }
969         }
970
971         /* Report about buffers */
972 #if BUF512_NR
973         {
974                 for (i= 0; i<BUF512_NR; i++)
975                 {
976                         error |= report_buffer(&buffers512[i].buf_header,
977                                 "512-buffer", i);
978                 }
979         }
980 #endif
981 #if BUF2K_NR
982         {
983                 for (i= 0; i<BUF2K_NR; i++)
984                 {
985                         error |= report_buffer(&buffers2K[i].buf_header,
986                                 "2K-buffer", i);
987                 }
988         }
989 #endif
990 #if BUF32K_NR
991         {
992                 for (i= 0; i<BUF32K_NR; i++)
993                 {
994                         error |= report_buffer(&buffers32K[i].buf_header,
995                                 "32K-buffer", i);
996                 }
997         }
998 #endif
999
1000         return !error;
1001 }
1002
1003 PRIVATE void count_free_bufs(list)
1004 acc_t *list;
1005 {
1006         acc_t *acc;
1007         buf_t *buf;
1008
1009         for(acc= list; acc; acc= acc->acc_next)
1010         {
1011                 if (acc->acc_generation != buf_generation-1)
1012                 {
1013                         assert(acc->acc_generation == buf_generation &&
1014                                 acc->acc_check_linkC > 0);
1015                         acc->acc_check_linkC= -acc->acc_check_linkC;
1016                         continue;
1017                 }
1018                 acc->acc_generation= buf_generation;
1019                 acc->acc_check_linkC= 0;
1020
1021                 buf= acc->acc_buffer;
1022                 if (buf->buf_generation == buf_generation-1)
1023                 {
1024                         buf->buf_generation= buf_generation;
1025                         buf->buf_check_linkC= 0;
1026                         continue;
1027                 }
1028                 assert(buf->buf_generation == buf_generation &&
1029                         buf->buf_check_linkC > 0);
1030                 buf->buf_check_linkC= -buf->buf_check_linkC;
1031         }
1032 }
1033
1034 PRIVATE int report_buffer(buf, label, i)
1035 buf_t *buf;
1036 char *label;
1037 int i;
1038 {
1039         if (buf->buf_generation != buf_generation)
1040         {
1041                 assert(buf->buf_generation == buf_generation-1);
1042                 buf->buf_generation= buf_generation;
1043                 printf(
1044 "%s[%d] (0x%x) has been lost with count %d, last allocated at %s, %d\n",
1045                         label, i, buf,
1046                         buf->buf_linkC, buf->buf_alloc_file,
1047                         buf->buf_alloc_line);
1048                 return 1;
1049         }
1050         if (buf->buf_check_linkC == buf->buf_linkC)
1051                 return 0;
1052         if (buf->buf_check_linkC < 0)
1053         {
1054                 printf(
1055 "%s[%d] is freed but still in use, allocated at %s, %d, freed at %s, %d\n",
1056                         label, i, buf->buf_alloc_file, buf->buf_alloc_line,
1057                         buf->buf_free_file, buf->buf_free_line);
1058                 buf->buf_check_linkC= -buf->buf_check_linkC;
1059                 if (buf->buf_check_linkC == buf->buf_linkC)
1060                         return 1;
1061         }
1062         printf(
1063 "# of tracked links (%d) for %s[%d] don't match with stored link count %d\n",
1064                         buf->buf_check_linkC, label, i, buf->buf_linkC);
1065         printf("%s[%d] was allocated at %s, %d\n",
1066                 label, i, buf->buf_alloc_file, buf->buf_alloc_line);
1067         return 1;
1068 }
1069
1070 PUBLIC void bf_check_acc(acc)
1071 acc_t *acc;
1072 {
1073         buf_t *buf;
1074
1075         while(acc != NULL)
1076         {
1077                 if (acc->acc_generation == buf_generation)
1078                 {
1079                         assert(acc->acc_check_linkC > 0);
1080                         acc->acc_check_linkC++;
1081                         return;
1082                 }
1083                 assert(acc->acc_generation == buf_generation-1);
1084                 acc->acc_generation= buf_generation;
1085                 acc->acc_check_linkC= 1;
1086
1087                 buf= acc->acc_buffer;
1088                 if (buf->buf_generation == buf_generation)
1089                 {
1090                         assert(buf->buf_check_linkC > 0);
1091                         buf->buf_check_linkC++;
1092                 }
1093                 else
1094                 {
1095                         assert(buf->buf_generation == buf_generation-1);
1096                         buf->buf_generation= buf_generation;
1097                         buf->buf_check_linkC= 1;
1098                 }
1099
1100                 acc= acc->acc_next;
1101         }
1102 }
1103
1104 PUBLIC void _bf_mark_acc(clnt_file, clnt_line, acc)
1105 char *clnt_file;
1106 int clnt_line;
1107 acc_t *acc;
1108 {
1109         buf_t *buf;
1110
1111         for (; acc; acc= acc->acc_next)
1112         {
1113                 acc->acc_alloc_file= clnt_file;
1114                 acc->acc_alloc_line= clnt_line;
1115                 buf= acc->acc_buffer;
1116                 buf->buf_alloc_file= clnt_file;
1117                 buf->buf_alloc_line= clnt_line;
1118         }
1119 }
1120 #endif
1121

free_accs() is called to free accessors when more accessors are needed to store data.
free_accs() calls the functions freereq.
The freereq array functions are initialized in bf_logon.

1122 PRIVATE void free_accs()
1123 {
1124         int i, j;
1125
1126         DBLOCK(1, printf("free_accs\n"));
1127
1128         for (i=0; !acc_freelist && i<MAX_BUFREQ_PRI; i++)
1129         {
1130                 for (j=0; j<CLIENT_NR; j++)
1131                 {
1132                         bf_free_bufsize= 0;
1133                         if (freereq[j])
1134                         {
1135                                 (*freereq[j])(i);
1136                         }
1137                 }
1138         }
1139 #if DEBUG
1140         printf("last level was level %d\n", i-1);
1141 #endif
1142 }
1143

bf_align(acc, size, alignment) tests if acc's buffer is aligned with the variable alignment.
If it is not and bufsize of acc > size, then the chunk of data pointed to by acc
is split in to 2 accessors so that the data at offset < size is pointed to by the
first accessor while the data at offset >= size is in the second accessor or beyond.

1144 #ifndef BUF_TRACK_ALLOC_FREE
1145 PUBLIC acc_t *bf_align(acc, size, alignment)
1146 #else
1147 PUBLIC acc_t *_bf_align(clnt_file, clnt_line, acc, size, alignment)
1148 char *clnt_file;
1149 int clnt_line;
1150 #endif
1151 acc_t *acc;
1152 size_t size;
1153 size_t alignment;
1154 {
1155         char *ptr;
1156         size_t buf_size;
1157         acc_t *head, *tail;
1158
1159         /* Fast check if the buffer is aligned already. */
1160         if (acc->acc_length >= size)
1161         {
1162                 ptr= ptr2acc_data(acc);
1163                 if (((unsigned)ptr & (alignment-1)) == 0)
1164                         return acc;
1165         }
1166         buf_size= bf_bufsize(acc);
1167 #ifdef bf_align
1168         assert(size != 0 && buf_size != 0 ||
1169                 (printf("bf_align(..., %d, %d) from %s, %d\n",
1170                         size, alignment, clnt_file, clnt_line),0));
1171 #else
1172         assert(size != 0 && buf_size != 0);
1173 #endif
1174         if (buf_size <= size)
1175         {
1176                 acc= bf_pack(acc);
1177                 return acc;
1178         }
1179         head= bf_cut(acc, 0, size);
1180         tail= bf_cut(acc, size, buf_size-size);
1181         bf_afree(acc);
1182         head= bf_pack(head);
1183         assert(head->acc_next == NULL);
1184         head->acc_next= tail;
1185         return head;
1186 }
1187
1188 #if 0
1189 int chk_acc(acc)
1190 acc_t *acc;
1191 {
1192         int acc_nr;
1193
1194         if (!acc)
1195                 return 1;
1196         if (acc < accessors || acc >= &accessors[ACC_NR])
1197                 return 0;
1198         acc_nr= acc-accessors;
1199         return acc == &accessors[acc_nr];
1200 }
1201 #endif
1202
1203 /*
1204  * $PchId: buf.c,v 1.10 1995/11/23 11:25:25 philip Exp $
1205  */