Merge branch 'master' of git://git.ucc.asn.au/tpg/acess2
[tpg/acess2.git] / KernelLand / Modules / IPStack / buffer.c
1 /*
2  * Acess2 Networking Stack
3  * - By John Hodge (thePowersGang)
4  *
5  * buffer.c
6  * - Scatter-gather handling
7  */
8 #include "ipstack.h"
9 #include "include/buffer.h"
10
11 // === STRUCTURES ===
12 struct sIPStackBuffer
13 {
14          int    MaxSubBufffers;
15          int    nSubBuffers;
16         size_t  TotalLength;
17         struct _subbuffer
18         {
19                 const void      *Data;
20                 size_t  PreLength;
21                 size_t  PostLength;
22                 tIPStackBufferCb        Cb;
23                 void    *CbArg;
24                 // TODO: Callbacks?
25         } SubBuffers[];
26 };
27
28 // === CODE ===
29 tIPStackBuffer *IPStack_Buffer_CreateBuffer(int MaxBuffers)
30 {
31         tIPStackBuffer *ret;
32         
33         ret = malloc( sizeof(*ret) + MaxBuffers * sizeof(ret->SubBuffers[0]) );
34         ret->MaxSubBufffers = MaxBuffers;
35         ret->nSubBuffers = 0;
36         ret->TotalLength = 0;
37         memset(ret->SubBuffers, 0, MaxBuffers * sizeof(ret->SubBuffers[0]));
38         return ret;
39 }
40
41 void IPStack_Buffer_ClearBuffer(tIPStackBuffer *Buffer)
42 {
43         for( int i = 0; i < Buffer->nSubBuffers; i ++ )
44         {
45                 if( Buffer->SubBuffers[i].Cb == NULL )
46                         continue ;
47                 Buffer->SubBuffers[i].Cb(
48                         Buffer->SubBuffers[i].CbArg,
49                         Buffer->SubBuffers[i].PreLength,
50                         Buffer->SubBuffers[i].PostLength,
51                         Buffer->SubBuffers[i].Data
52                         );
53         }
54         // TODO: Fire callbacks?
55         Buffer->nSubBuffers = 0;
56 }
57
58 void IPStack_Buffer_DestroyBuffer(tIPStackBuffer *Buffer)
59 {
60         IPStack_Buffer_ClearBuffer(Buffer);
61         Buffer->MaxSubBufffers = 0;
62         free(Buffer);
63 }
64
65 void IPStack_Buffer_AppendSubBuffer(tIPStackBuffer *Buffer,
66         size_t HeaderLen, size_t FooterLen, const void *Data,
67         tIPStackBufferCb Cb, void *Arg
68         )
69 {
70         if( Buffer->nSubBuffers == Buffer->MaxSubBufffers ) {
71                 // Ah, oops?
72                 Log_Error("IPStack", "Buffer %p only had %i sub-buffers allocated, which was not enough",
73                         Buffer, Buffer->MaxSubBufffers);
74                 return ;
75         }
76         
77         int index = Buffer->nSubBuffers++;
78         Buffer->TotalLength += HeaderLen + FooterLen;
79         
80         Buffer->SubBuffers[index].Data = Data;
81         Buffer->SubBuffers[index].PreLength = HeaderLen;
82         Buffer->SubBuffers[index].PostLength = FooterLen;
83         Buffer->SubBuffers[index].Cb = Cb;
84         Buffer->SubBuffers[index].CbArg = Arg;
85 }
86
87 size_t IPStack_Buffer_GetLength(tIPStackBuffer *Buffer)
88 {
89         return Buffer->TotalLength;
90 }
91
92 size_t IPStack_Buffer_GetData(tIPStackBuffer *Buffer, void *Dest, size_t MaxBytes)
93 {
94         Uint8   *dest = Dest;
95         size_t  rem_space = MaxBytes;
96         size_t  len;
97         
98         for( int i = Buffer->nSubBuffers; i -- && rem_space != 0; )
99         {
100                 len = MIN(Buffer->SubBuffers[i].PreLength, rem_space);
101                 memcpy(dest,
102                         Buffer->SubBuffers[i].Data,
103                         len
104                         );
105                 dest += len;
106                 rem_space -= len;
107         }
108         for( int i = 0; i < Buffer->nSubBuffers && rem_space; i ++ )
109         {
110                 if( Buffer->SubBuffers[i].PostLength == 0  )
111                         continue ;
112                 
113                 len = MIN(Buffer->SubBuffers[i].PostLength, rem_space);
114                 memcpy(dest,
115                         (Uint8*)Buffer->SubBuffers[i].Data + Buffer->SubBuffers[i].PreLength,
116                         len
117                         );
118                 dest += len;
119                 rem_space -= len;
120         }
121         
122         return MaxBytes - rem_space;
123 }
124
125 void *IPStack_Buffer_CompactBuffer(tIPStackBuffer *Buffer, size_t *Length)
126 {
127         void    *ret;
128         
129         ret = malloc(Buffer->TotalLength);
130         if(!ret) {
131                 *Length = 0;
132                 return NULL;
133         }
134         
135         *Length = Buffer->TotalLength;
136
137         IPStack_Buffer_GetData(Buffer, ret, Buffer->TotalLength);
138
139         return ret;
140 }
141
142 int IPStack_Buffer_GetBuffer(tIPStackBuffer *Buffer, int Index, size_t *Length, const void **DataPtr)
143 {
144         if( Index == -1 )       Index = 0;
145
146         if( Index >= Buffer->nSubBuffers*2 ) {
147                 return -1;
148         }
149
150         if( Index > Buffer->nSubBuffers )
151         {
152                 // Appended buffers
153                 Index -= Buffer->nSubBuffers;
154         
155                 // Bit of a hack to avoid multiple calls which return a zero length
156                 while( !Buffer->SubBuffers[Index].PostLength )
157                 {
158                         if( Index++ == Buffer->nSubBuffers )
159                                 return -1;
160                 }
161
162                 *DataPtr = (Uint8*)Buffer->SubBuffers[Index].Data + Buffer->SubBuffers[Index].PreLength;
163                 *Length = Buffer->SubBuffers[Index].PostLength;
164
165                 return (Index + 1) + Buffer->nSubBuffers;
166         }
167         else
168         {
169                 Index = Buffer->nSubBuffers - Index;
170                 // Prepended buffers
171                 *DataPtr = Buffer->SubBuffers[Index].Data;
172                 *Length = Buffer->SubBuffers[Index].PreLength;
173                 return Buffer->nSubBuffers - (Index - 1);
174         }
175 }
176

UCC git Repository :: git.ucc.asn.au