1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /* Memory handler for a plain memory divided in slot.
18  * This one uses plain memory.
19  */
20 
21 #include  "ap_slotmem.h"
22 
23 #define AP_SLOTMEM_IS_PREGRAB(t) (t->type & AP_SLOTMEM_TYPE_PREGRAB)
24 
25 struct ap_slotmem_instance_t {
26     char                 *name;       /* per segment name */
27     void                 *base;       /* data set start */
28     apr_size_t           size;        /* size of each memory slot */
29     unsigned int         num;         /* number of mem slots */
30     apr_pool_t           *gpool;      /* per segment global pool */
31     char                 *inuse;      /* in-use flag table*/
32     ap_slotmem_type_t    type;        /* type-specific flags */
33     struct ap_slotmem_instance_t  *next;       /* location of next allocated segment */
34 };
35 
36 
37 /* global pool and list of slotmem we are handling */
38 static struct ap_slotmem_instance_t *globallistmem = NULL;
39 static apr_pool_t *gpool = NULL;
40 
slotmem_do(ap_slotmem_instance_t * mem,ap_slotmem_callback_fn_t * func,void * data,apr_pool_t * pool)41 static apr_status_t slotmem_do(ap_slotmem_instance_t *mem, ap_slotmem_callback_fn_t *func, void *data, apr_pool_t *pool)
42 {
43     unsigned int i;
44     char *ptr;
45     char *inuse;
46     apr_status_t retval = APR_SUCCESS;
47 
48 
49     if (!mem)
50         return APR_ENOSHMAVAIL;
51 
52     ptr = (char *)mem->base;
53     inuse = mem->inuse;
54     for (i = 0; i < mem->num; i++, inuse++) {
55         if (!AP_SLOTMEM_IS_PREGRAB(mem) ||
56            (AP_SLOTMEM_IS_PREGRAB(mem) && *inuse)) {
57             retval = func((void *) ptr, data, pool);
58             if (retval != APR_SUCCESS)
59                 break;
60         }
61         ptr += mem->size;
62     }
63     return retval;
64 }
65 
slotmem_create(ap_slotmem_instance_t ** new,const char * name,apr_size_t item_size,unsigned int item_num,ap_slotmem_type_t type,apr_pool_t * pool)66 static apr_status_t slotmem_create(ap_slotmem_instance_t **new, const char *name, apr_size_t item_size, unsigned int item_num, ap_slotmem_type_t type, apr_pool_t *pool)
67 {
68     ap_slotmem_instance_t *res;
69     ap_slotmem_instance_t *next = globallistmem;
70     apr_size_t basesize = (item_size * item_num);
71 
72     const char *fname;
73 
74     if (name) {
75         if (name[0] == ':')
76             fname = name;
77         else
78             fname = ap_runtime_dir_relative(pool, name);
79 
80         /* first try to attach to existing slotmem */
81         if (next) {
82             for (;;) {
83                 if (strcmp(next->name, fname) == 0) {
84                     /* we already have it */
85                     *new = next;
86                     return APR_SUCCESS;
87                 }
88                 if (!next->next) {
89                      break;
90                 }
91                 next = next->next;
92             }
93         }
94     }
95     else
96         fname = "anonymous";
97 
98     /* create the memory using the gpool */
99     res = (ap_slotmem_instance_t *) apr_pcalloc(gpool, sizeof(ap_slotmem_instance_t));
100     res->base = apr_pcalloc(gpool, basesize + (item_num * sizeof(char)));
101     if (!res->base)
102         return APR_ENOSHMAVAIL;
103 
104     /* For the chained slotmem stuff */
105     res->name = apr_pstrdup(gpool, fname);
106     res->size = item_size;
107     res->num = item_num;
108     res->next = NULL;
109     res->type = type;
110     res->inuse = (char *)res->base + basesize;
111     if (globallistmem == NULL)
112         globallistmem = res;
113     else
114         next->next = res;
115 
116     *new = res;
117     return APR_SUCCESS;
118 }
119 
slotmem_attach(ap_slotmem_instance_t ** new,const char * name,apr_size_t * item_size,unsigned int * item_num,apr_pool_t * pool)120 static apr_status_t slotmem_attach(ap_slotmem_instance_t **new, const char *name, apr_size_t *item_size, unsigned int *item_num, apr_pool_t *pool)
121 {
122     ap_slotmem_instance_t *next = globallistmem;
123     const char *fname;
124 
125     if (name) {
126         if (name[0] == ':')
127             fname = name;
128         else
129             fname = ap_runtime_dir_relative(pool, name);
130     }
131     else
132         return APR_ENOSHMAVAIL;
133 
134     /* first try to attach to existing slotmem */
135     while (next) {
136         if (strcmp(next->name, fname) == 0) {
137             /* we already have it */
138             *new = next;
139             *item_size = next->size;
140             *item_num = next->num;
141             return APR_SUCCESS;
142         }
143         next = next->next;
144     }
145 
146     return APR_ENOSHMAVAIL;
147 }
148 
slotmem_dptr(ap_slotmem_instance_t * score,unsigned int id,void ** mem)149 static apr_status_t slotmem_dptr(ap_slotmem_instance_t *score, unsigned int id, void **mem)
150 {
151 
152     char *ptr;
153 
154     if (!score)
155         return APR_ENOSHMAVAIL;
156     if (id >= score->num)
157         return APR_EINVAL;
158 
159     ptr = (char *)score->base + score->size * id;
160     if (!ptr)
161         return APR_ENOSHMAVAIL;
162     *mem = ptr;
163     return APR_SUCCESS;
164 }
165 
slotmem_get(ap_slotmem_instance_t * slot,unsigned int id,unsigned char * dest,apr_size_t dest_len)166 static apr_status_t slotmem_get(ap_slotmem_instance_t *slot, unsigned int id, unsigned char *dest, apr_size_t dest_len)
167 {
168     void *ptr;
169     char *inuse;
170     apr_status_t ret;
171 
172     if (!slot) {
173         return APR_ENOSHMAVAIL;
174     }
175 
176     inuse = slot->inuse + id;
177     if (id >= slot->num) {
178         return APR_EINVAL;
179     }
180     if (AP_SLOTMEM_IS_PREGRAB(slot) && !*inuse) {
181         return APR_NOTFOUND;
182     }
183     ret = slotmem_dptr(slot, id, &ptr);
184     if (ret != APR_SUCCESS) {
185         return ret;
186     }
187     *inuse=1;
188     memcpy(dest, ptr, dest_len); /* bounds check? */
189     return APR_SUCCESS;
190 }
191 
slotmem_put(ap_slotmem_instance_t * slot,unsigned int id,unsigned char * src,apr_size_t src_len)192 static apr_status_t slotmem_put(ap_slotmem_instance_t *slot, unsigned int id, unsigned char *src, apr_size_t src_len)
193 {
194     void *ptr;
195     char *inuse;
196     apr_status_t ret;
197 
198     if (!slot) {
199         return APR_ENOSHMAVAIL;
200     }
201 
202     inuse = slot->inuse + id;
203     if (id >= slot->num) {
204         return APR_EINVAL;
205     }
206     if (AP_SLOTMEM_IS_PREGRAB(slot) && !*inuse) {
207         return APR_NOTFOUND;
208     }
209     ret = slotmem_dptr(slot, id, &ptr);
210     if (ret != APR_SUCCESS) {
211         return ret;
212     }
213     *inuse=1;
214     memcpy(ptr, src, src_len); /* bounds check? */
215     return APR_SUCCESS;
216 }
217 
slotmem_num_slots(ap_slotmem_instance_t * slot)218 static unsigned int slotmem_num_slots(ap_slotmem_instance_t *slot)
219 {
220     return slot->num;
221 }
222 
slotmem_num_free_slots(ap_slotmem_instance_t * slot)223 static unsigned int slotmem_num_free_slots(ap_slotmem_instance_t *slot)
224 {
225     unsigned int i, counter=0;
226     char *inuse = slot->inuse;
227     for (i = 0; i < slot->num; i++, inuse++) {
228         if (!*inuse)
229             counter++;
230     }
231     return counter;
232 }
233 
slotmem_slot_size(ap_slotmem_instance_t * slot)234 static apr_size_t slotmem_slot_size(ap_slotmem_instance_t *slot)
235 {
236     return slot->size;
237 }
238 
239 /*
240  * XXXX: if !AP_SLOTMEM_IS_PREGRAB, then still worry about
241  *       inuse for grab and return?
242  */
slotmem_grab(ap_slotmem_instance_t * slot,unsigned int * id)243 static apr_status_t slotmem_grab(ap_slotmem_instance_t *slot, unsigned int *id)
244 {
245     unsigned int i;
246     char *inuse;
247 
248     if (!slot) {
249         return APR_ENOSHMAVAIL;
250     }
251 
252     inuse = slot->inuse;
253 
254     for (i = 0; i < slot->num; i++, inuse++) {
255         if (!*inuse) {
256             break;
257         }
258     }
259     if (i >= slot->num) {
260         return APR_EINVAL;
261     }
262     *inuse = 1;
263     *id = i;
264     return APR_SUCCESS;
265 }
266 
slotmem_fgrab(ap_slotmem_instance_t * slot,unsigned int id)267 static apr_status_t slotmem_fgrab(ap_slotmem_instance_t *slot, unsigned int id)
268 {
269     char *inuse;
270 
271     if (!slot) {
272         return APR_ENOSHMAVAIL;
273     }
274 
275     if (id >= slot->num) {
276         return APR_EINVAL;
277     }
278     inuse = slot->inuse + id;
279     *inuse = 1;
280     return APR_SUCCESS;
281 }
282 
slotmem_release(ap_slotmem_instance_t * slot,unsigned int id)283 static apr_status_t slotmem_release(ap_slotmem_instance_t *slot, unsigned int id)
284 {
285     char *inuse;
286 
287     if (!slot) {
288         return APR_ENOSHMAVAIL;
289     }
290 
291     inuse = slot->inuse;
292 
293     if (id >= slot->num) {
294         return APR_EINVAL;
295     }
296     if (!inuse[id] ) {
297         return APR_NOTFOUND;
298     }
299     inuse[id] = 0;
300     return APR_SUCCESS;
301 }
302 
303 static const ap_slotmem_provider_t storage = {
304     "plainmem",
305     &slotmem_do,
306     &slotmem_create,
307     &slotmem_attach,
308     &slotmem_dptr,
309     &slotmem_get,
310     &slotmem_put,
311     &slotmem_num_slots,
312     &slotmem_num_free_slots,
313     &slotmem_slot_size,
314     &slotmem_grab,
315     &slotmem_release,
316     &slotmem_fgrab
317 };
318 
pre_config(apr_pool_t * p,apr_pool_t * plog,apr_pool_t * ptemp)319 static int pre_config(apr_pool_t *p, apr_pool_t *plog,
320                       apr_pool_t *ptemp)
321 {
322     gpool = p;
323     return OK;
324 }
325 
ap_slotmem_plain_register_hook(apr_pool_t * p)326 static void ap_slotmem_plain_register_hook(apr_pool_t *p)
327 {
328     /* XXX: static const char * const prePos[] = { "mod_slotmem.c", NULL }; */
329     ap_register_provider(p, AP_SLOTMEM_PROVIDER_GROUP, "plain",
330                          AP_SLOTMEM_PROVIDER_VERSION, &storage);
331     ap_hook_pre_config(pre_config, NULL, NULL, APR_HOOK_MIDDLE);
332 }
333 
334 AP_DECLARE_MODULE(slotmem_plain) = {
335     STANDARD20_MODULE_STUFF,
336     NULL,                        /* create per-directory config structure */
337     NULL,                        /* merge per-directory config structures */
338     NULL,                        /* create per-server config structure */
339     NULL,                        /* merge per-server config structures */
340     NULL,                        /* command apr_table_t */
341     ap_slotmem_plain_register_hook    /* register hooks */
342 };
343 
344