Merge branch 'master' of git://cadel.mutabah.net/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         tMutex  lBufferLock;
18
19         struct _subbuffer
20         {
21                 const void      *Data;
22                 size_t  PreLength;
23                 size_t  PostLength;
24                 tIPStackBufferCb        Cb;
25                 void    *CbArg;
26                 // TODO: Callbacks?
27         } SubBuffers[];
28 };
29
30 // === CODE ===
31 tIPStackBuffer *IPStack_Buffer_CreateBuffer(int MaxBuffers)
32 {
33         tIPStackBuffer *ret;
34         
35         ret = malloc( sizeof(*ret) + MaxBuffers * sizeof(ret->SubBuffers[0]) );
36         ret->MaxSubBufffers = MaxBuffers;
37         ret->nSubBuffers = 0;
38         ret->TotalLength = 0;
39         memset(&ret->lBufferLock, 0, sizeof(ret->lBufferLock));
40         memset(ret->SubBuffers, 0, MaxBuffers * sizeof(ret->SubBuffers[0]));
41         return ret;
42 }
43
44 void IPStack_Buffer_ClearBuffer(tIPStackBuffer *Buffer)
45 {
46         IPStack_Buffer_LockBuffer(Buffer);
47         for( int i = 0; i < Buffer->nSubBuffers; i ++ )
48         {
49                 if( Buffer->SubBuffers[i].Cb == NULL )
50                         continue ;
51                 Buffer->SubBuffers[i].Cb(
52                         Buffer->SubBuffers[i].CbArg,
53                         Buffer->SubBuffers[i].PreLength,
54                         Buffer->SubBuffers[i].PostLength,
55                         Buffer->SubBuffers[i].Data
56                         );
57         }
58         Buffer->nSubBuffers = 0;
59         IPStack_Buffer_UnlockBuffer(Buffer);
60 }
61
62 void IPStack_Buffer_DestroyBuffer(tIPStackBuffer *Buffer)
63 {
64         IPStack_Buffer_ClearBuffer(Buffer);
65         Buffer->MaxSubBufffers = 0;
66         free(Buffer);
67 }
68
69 void IPStack_Buffer_LockBuffer(tIPStackBuffer *Buffer)
70 {
71         Mutex_Acquire(&Buffer->lBufferLock);
72 }
73 void IPStack_Buffer_UnlockBuffer(tIPStackBuffer *Buffer)
74 {
75         Mutex_Release(&Buffer->lBufferLock);
76 }
77
78 void IPStack_Buffer_AppendSubBuffer(tIPStackBuffer *Buffer,
79         size_t HeaderLen, size_t FooterLen, const void *Data,
80         tIPStackBufferCb Cb, void *Arg
81         )
82 {
83         if( Buffer->nSubBuffers == Buffer->MaxSubBufffers ) {
84                 // Ah, oops?
85                 Log_Error("IPStack", "Buffer %p only had %i sub-buffers allocated, which was not enough",
86                         Buffer, Buffer->MaxSubBufffers);
87                 return ;
88         }
89         
90         int index = Buffer->nSubBuffers++;
91         Buffer->TotalLength += HeaderLen + FooterLen;
92         
93         Buffer->SubBuffers[index].Data = Data;
94         Buffer->SubBuffers[index].PreLength = HeaderLen;
95         Buffer->SubBuffers[index].PostLength = FooterLen;
96         Buffer->SubBuffers[index].Cb = Cb;
97         Buffer->SubBuffers[index].CbArg = Arg;
98 }
99
100 size_t IPStack_Buffer_GetLength(tIPStackBuffer *Buffer)
101 {
102         return Buffer->TotalLength;
103 }
104
105 size_t IPStack_Buffer_GetData(tIPStackBuffer *Buffer, void *Dest, size_t MaxBytes)
106 {
107         Uint8   *dest = Dest;
108         size_t  rem_space = MaxBytes;
109         size_t  len;
110         
111         for( int i = Buffer->nSubBuffers; i -- && rem_space != 0; )
112         {
113                 len = MIN(Buffer->SubBuffers[i].PreLength, rem_space);
114                 memcpy(dest,
115                         Buffer->SubBuffers[i].Data,
116                         len
117                         );
118                 dest += len;
119                 rem_space -= len;
120         }
121         for( int i = 0; i < Buffer->nSubBuffers && rem_space; i ++ )
122         {
123                 if( Buffer->SubBuffers[i].PostLength == 0  )
124                         continue ;
125                 
126                 len = MIN(Buffer->SubBuffers[i].PostLength, rem_space);
127                 memcpy(dest,
128                         (Uint8*)Buffer->SubBuffers[i].Data + Buffer->SubBuffers[i].PreLength,
129                         len
130                         );
131                 dest += len;
132                 rem_space -= len;
133         }
134         
135         return MaxBytes - rem_space;
136 }
137
138 void *IPStack_Buffer_CompactBuffer(tIPStackBuffer *Buffer, size_t *Length)
139 {
140         void    *ret;
141         
142         ret = malloc(Buffer->TotalLength);
143         if(!ret) {
144                 *Length = 0;
145                 return NULL;
146         }
147         
148         *Length = Buffer->TotalLength;
149
150         IPStack_Buffer_GetData(Buffer, ret, Buffer->TotalLength);
151
152         return ret;
153 }
154
155 int IPStack_Buffer_GetBuffer(tIPStackBuffer *Buffer, int Index, size_t *Length, const void **DataPtr)
156 {
157         if( Index == -1 )       Index = 0;
158
159         if( Index >= Buffer->nSubBuffers*2 ) {
160                 return -1;
161         }
162
163         if( Index >= Buffer->nSubBuffers )
164         {
165                 // Appended buffers
166                 Index -= Buffer->nSubBuffers;
167         
168                 // Bit of a hack to avoid multiple calls which return a zero length
169                 while( !Buffer->SubBuffers[Index].PostLength )
170                 {
171                         if( Index++ == Buffer->nSubBuffers )
172                                 return -1;
173                 }
174
175                 if( DataPtr )
176                         *DataPtr = (Uint8*)Buffer->SubBuffers[Index].Data + Buffer->SubBuffers[Index].PreLength;
177                 if( Length )
178                         *Length = Buffer->SubBuffers[Index].PostLength;
179
180                 return (Index + 1) + Buffer->nSubBuffers;
181         }
182         else
183         {
184                  int    rv = Index + 1;
185                 Index = Buffer->nSubBuffers - Index - 1;
186                 // Prepended buffers
187                 if( DataPtr )
188                         *DataPtr = Buffer->SubBuffers[Index].Data;
189                 if( Length )
190                         *Length = Buffer->SubBuffers[Index].PreLength;
191                 return rv;
192         }
193 }
194

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