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

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