💾 Archived View for gmi.noulin.net › gitRepositories › tuyau › file › rateLimiter › rateLimiter.c.gm… captured on 2023-01-29 at 13:27:42. Gemini links have been rewritten to link to archived content
-=-=-=-=-=-=-
rateLimiter.c (6618B)
1 2 3 /* Add class methods and modify the base functions (free, duplicate, ...) where there are the TODOs (TODO)*/ 4 5 #include "libsheepyObject.h" 6 #include "rateLimiter.h" 7 #include "rateLimiterInternal.h" 8 9 #include <stdlib.h> 10 #include <string.h> 11 #include <stdio.h> 12 13 void initiateRateLimiter(rateLimitert *self); 14 void registerMethodsRateLimiter(rateLimiterFunctionst *f); 15 void initiateAllocateRateLimiter(rateLimitert **self); 16 void finalizeRateLimiter(void); 17 rateLimitert* allocRateLimiter(void); 18 internal void freeRateLimiter(rateLimitert *self); 19 internal void terminateRateLimiter(rateLimitert **self); 20 internal char* toStringRateLimiter(rateLimitert *self); 21 internal rateLimitert* duplicateRateLimiter(rateLimitert *self); 22 internal void smashRateLimiter(rateLimitert **self); 23 internal void finishRateLimiter(rateLimitert **self); 24 internal bool setupRateLimiter(rateLimitert *self, u32 maxClients, u64 window, u32 maxAccessCount); 25 internal size_t countRateLimiter(rateLimitert *self); 26 internal bool incomingRateLimiter(rateLimitert *self, u32 ip); 27 internal bool hasRateLimiter(rateLimitert *self, u32 ip); 28 internal time_t getTime(void); 29 internal void prune(rateLimitert *self); 30 internal int cmprateL(u32 k1, u32 k2); 31 internal void freerateLKV(u32* k, u32* v); 32 /* TODO add prototypes */ 33 34 /* enable/disable logging */ 35 #undef pLog 36 #define pLog(...) 37 38 #define RATELIMA self->rateLimiterA 39 #define RATELIMIX self->rateLimiterIx 40 #define RATELIMH self->rateLimiterH 41 42 #define RATELIM(index) RATELIMA[indexerRef(RATELIMIX, index)] 43 #define RATELIMFirst RATELIMA[indexerFirst(RATELIMIX)] 44 #define RATELIMLast RATELIMA[indexerLast(RATELIMIX)] 45 46 internal int cmprateL(u32 k1, u32 k2) { 47 return k1 == k2 ? 0 : 1; 48 } 49 50 internal void freerateLKV(u32* k, u32* v) { 51 // nothing to free, the data is stored in rateLimiterA 52 } 53 54 #define HASHFUNC u32Hash // hash function from the hashfunctions spm package 55 #define CMPFUNC cmprateL 56 #define FREEFUNC freerateLKV 57 58 hashTbFunctions(, rateL, rateL, u32, u32); 59 60 #undef HASHFUNC 61 #undef CMPFUNC 62 #undef FREEFUNC 63 64 void initiateRateLimiter(rateLimitert *self) { 65 66 self->type = "rateLimiter"; 67 if (!rateLimiterF) { 68 rateLimiterF = malloc(sizeof(rateLimiterFunctionst)); 69 registerMethodsRateLimiter(rateLimiterF); 70 pErrorNot0(atexit(finalizeRateLimiter)); 71 } 72 self->f = rateLimiterF; 73 74 RATELIMA = NULL; 75 initrateL(&RATELIMH); 76 /* TODO Initialize object data */ 77 } 78 79 void registerMethodsRateLimiter(rateLimiterFunctionst *f) { 80 81 f->free = freeRateLimiter; 82 f->terminate = terminateRateLimiter; 83 f->toString = toStringRateLimiter; 84 f->duplicate = duplicateRateLimiter; 85 f->smash = smashRateLimiter; 86 f->finish = finishRateLimiter; 87 f->setup = setupRateLimiter; 88 f->count = countRateLimiter; 89 f->incoming = incomingRateLimiter; 90 f->has = hasRateLimiter; 91 /* TODO add class functions */ 92 } 93 94 void initiateAllocateRateLimiter(rateLimitert **self) { 95 96 if (self) { 97 (*self) = malloc(sizeof(rateLimitert)); 98 if (*self) { 99 initiateRateLimiter(*self); 100 } 101 } 102 } 103 104 void finalizeRateLimiter(void) { 105 106 if (rateLimiterF) { 107 free(rateLimiterF); 108 rateLimiterF = NULL; 109 } 110 } 111 112 rateLimitert* allocRateLimiter(void) { 113 rateLimitert *r = NULL; 114 115 initiateAllocateRateLimiter(&r); 116 /* TODO copy data given in parameter to the object */ 117 return(r); 118 } 119 120 121 internal void freeRateLimiter(rateLimitert *self) { 122 123 free(RATELIMA); 124 freerateL(&RATELIMH); 125 /* TODO free internal data (not the structure holding the function pointers) */ 126 return; 127 } 128 129 internal void terminateRateLimiter(rateLimitert **self) { 130 131 freeRateLimiter(*self); 132 free(*self); 133 *self = NULL; 134 } 135 136 137 internal char* toStringRateLimiter(rateLimitert *self) { 138 139 /* TODO convert object data to string */ 140 return(strdup("TODO - rateLimiter")); 141 } 142 143 internal rateLimitert* duplicateRateLimiter(rateLimitert *self) { 144 145 createAllocateRateLimiter(dup); 146 /* TODO COPY data */ 147 return(dup); 148 } 149 150 internal void smashRateLimiter(rateLimitert **self) { 151 152 finishRateLimiter(self); 153 } 154 155 internal void finishRateLimiter(rateLimitert **self) { 156 157 free(*self); 158 *self = NULL; 159 } 160 161 162 internal bool setupRateLimiter(rateLimitert *self, u32 maxClients, u64 window, u32 maxAccessCount) { 163 164 if (RATELIMA) free(RATELIMA); 165 emptyrateL(&RATELIMH); 166 167 RATELIMA = malloc(sizeof(rateLimterE) * maxClients); 168 if (!RATELIMA) return false; 169 170 indexerInit(RATELIMIX, maxClients); 171 172 self->window = window; 173 self->maxAccessCount = maxAccessCount; 174 return true; 175 } 176 177 internal time_t getTime(void) { 178 return getCurrentUnixTime(); 179 /* static time_t tim = 0; */ 180 /* return tim++; */ 181 } 182 183 internal void prune(rateLimitert *self) { 184 time_t now = getTime(); 185 186 range (p, indexerCount(RATELIMIX)) { 187 if ((u64)(now - RATELIMFirst.time) < self->window) 188 break; 189 delrateL(&RATELIMH, RATELIMFirst.ip); 190 logI("removed %x", RATELIMFirst.ip); 191 indexerDequeue(RATELIMIX); 192 } 193 } 194 195 internal size_t countRateLimiter(rateLimitert *self) { 196 prune(self); 197 return indexerCount(RATELIMIX); 198 } 199 200 internal bool incomingRateLimiter(rateLimitert *self, u32 ip) { 201 time_t now = getTime(); 202 logVarG(now); 203 204 u32 *value; 205 if ((value = findrateL(&RATELIMH, ip))) { // assign value and test NULL 206 u32 i = *value; 207 RATELIM(i).count++; 208 logI("found ip in rateLimiterA %x i %d, count %d time %d", ip, i, RATELIM(i).count, RATELIM(i).time); 209 210 if ((u64)(now - RATELIM(i).time) < self->window) { 211 //if ((now - RATELIM(i).time) < self->window) { 212 if (RATELIM(i).count < self->maxAccessCount) { 213 // limit not yet reached 214 return true; 215 } 216 else { 217 logI("too many connections from ip %x", ip); 218 return false; 219 } 220 } 221 else { 222 // remove connections older than self->window 223 prune(self); 224 size_t cnt = indexerCount(RATELIMIX); 225 logVarG(cnt); 226 return true; 227 } 228 } 229 else { 230 if (indexerIsFull(RATELIMIX)) { 231 if ((u64)(now - RATELIMFirst.time) >= self->window) { 232 // free first slot since it is older than self->window 233 delrateL(&RATELIMH, RATELIMFirst.ip); 234 indexerDequeue(RATELIMIX); 235 } 236 else { 237 logI("too many connections"); 238 return false; 239 } 240 } 241 242 indexerPush(RATELIMIX); 243 /* u32 i = indexerLast(RATELIMIX); */ 244 /* logI("new ip %x, i %d", ip, i); */ 245 addrateL(&RATELIMH, ip, indexerLast(RATELIMIX)); 246 RATELIMLast.ip = ip; 247 RATELIMLast.count = 1; 248 RATELIMLast.time = now; 249 return true; 250 } 251 } 252 253 internal bool hasRateLimiter(rateLimitert *self, u32 ip) { 254 prune(self); 255 ret findrateL(&RATELIMH, ip) ? true : false; 256 } 257 /* TODO add method implementations */