source: subversion/applications/utils/mod_tile/mod_tile.c @ 27690

Last change on this file since 27690 was 27690, checked in by apmon, 8 years ago

[mod_tile] Fix /dirty and /status

The sscanf expression to parse the URL was too greedy, lumping the /dirty and /status into the file extension,
causing the tile layers being rejected due to a wrong file extension.

File size: 67.0 KB
Line 
1#include "apr.h"
2#include "apr_strings.h"
3#include "apr_thread_proc.h"    /* for RLIMIT stuff */
4#include "apr_optional.h"
5#include "apr_buckets.h"
6#include "apr_lib.h"
7#include "apr_poll.h"
8
9#define APR_WANT_STRFUNC
10#define APR_WANT_MEMFUNC
11#include "apr_want.h"
12
13#include "util_filter.h"
14#include "ap_config.h"
15#include "httpd.h"
16#include "http_config.h"
17#include "http_request.h"
18#include "http_core.h"
19#include "http_protocol.h"
20#include "http_main.h"
21#include "http_log.h"
22#include "util_script.h"
23#include "ap_mpm.h"
24#include "mod_core.h"
25#include "mod_cgi.h"
26#include "util_md5.h"
27
28module AP_MODULE_DECLARE_DATA tile_module;
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <stdarg.h>
34#include <sys/types.h>
35#include <sys/socket.h>
36#include <sys/un.h>
37#include <unistd.h>
38#include <fcntl.h>
39#include <errno.h>
40#include <limits.h>
41#include <time.h>
42#include <netinet/in.h>
43#include <arpa/inet.h>
44
45
46#include "gen_tile.h"
47#include "protocol.h"
48#include "render_config.h"
49#include "store.h"
50#include "dir_utils.h"
51#include "mod_tile.h"
52
53
54
55#if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
56#include "unixd.h"
57#define MOD_TILE_SET_MUTEX_PERMS /* XXX Apache should define something */
58#endif
59
60
61
62apr_shm_t *stats_shm;
63apr_shm_t *delaypool_shm;
64char *shmfilename;
65char *shmfilename_delaypool;
66apr_global_mutex_t *stats_mutex;
67apr_global_mutex_t *delay_mutex;
68char *mutexfilename;
69
70static int error_message(request_rec *r, const char *format, ...)
71                 __attribute__ ((format (printf, 2, 3)));
72
73static int error_message(request_rec *r, const char *format, ...)
74{
75    va_list ap;
76    va_start(ap, format);
77    int len;
78    char *msg;
79
80    len = vasprintf(&msg, format, ap);
81
82    if (msg) {
83        //ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "%s", msg);
84        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "%s", msg);
85        r->content_type = "text/plain";
86        if (!r->header_only)
87            ap_rputs(msg, r);
88        free(msg);
89    }
90
91    return OK;
92}
93
94int socket_init(request_rec *r)
95{
96    ap_conf_vector_t *sconf = r->server->module_config;
97    tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
98
99    int fd;
100    struct sockaddr_un addr;
101
102    fd = socket(PF_UNIX, SOCK_STREAM, 0);
103    if (fd < 0) {
104        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "failed to create unix socket");
105        return FD_INVALID;
106    }
107
108    bzero(&addr, sizeof(addr));
109    addr.sun_family = AF_UNIX;
110    strncpy(addr.sun_path, scfg->renderd_socket_name, sizeof(addr.sun_path));
111
112    if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
113        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "socket connect failed for: %s", scfg->renderd_socket_name);
114        close(fd);
115        return FD_INVALID;
116    }
117    return fd;
118}
119
120int request_tile(request_rec *r, struct protocol *cmd, int renderImmediately)
121{
122    int fd;
123    int ret = 0;
124    int retry = 1;
125    struct protocol resp;
126
127    ap_conf_vector_t *sconf = r->server->module_config;
128    tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
129
130    fd = socket_init(r);
131
132    if (fd == FD_INVALID) {
133        ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, "Failed to connect to renderer");
134        return 0;
135    }
136
137    // cmd has already been partial filled, fill in the rest
138    cmd->ver = PROTO_VER;
139    switch (renderImmediately) {
140    case 0: { cmd->cmd = cmdDirty; break;}
141    case 1: { cmd->cmd = cmdRender; break;}
142    case 2: { cmd->cmd = cmdRenderPrio; break;}
143    }
144
145    if (scfg->bulkMode) cmd->cmd = cmdRenderBulk; 
146
147    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Requesting style(%s) z(%d) x(%d) y(%d) from renderer with priority %d", cmd->xmlname, cmd->z, cmd->x, cmd->y, cmd->cmd);
148    do {
149        ret = send(fd, cmd, sizeof(struct protocol), 0);
150
151        if (ret == sizeof(struct protocol))
152            break;
153
154        close(fd);
155        if (errno != EPIPE)
156            return 0;
157
158        fd = socket_init(r);
159        if (fd == FD_INVALID)
160            return 0;
161    } while (retry--);
162
163    if (renderImmediately) {
164        struct timeval tv = {(renderImmediately > 1?scfg->request_timeout_priority:scfg->request_timeout), 0 };
165        fd_set rx;
166        int s;
167
168        while (1) {
169            FD_ZERO(&rx);
170            FD_SET(fd, &rx);
171            s = select(fd+1, &rx, NULL, NULL, &tv);
172            if (s == 1) {
173                bzero(&resp, sizeof(struct protocol));
174                ret = recv(fd, &resp, sizeof(struct protocol), 0);
175                if (ret != sizeof(struct protocol)) {
176                    //perror("recv error");
177                    break;
178                }
179
180                if (cmd->x == resp.x && cmd->y == resp.y && cmd->z == resp.z && !strcmp(cmd->xmlname, resp.xmlname)) {
181                    close(fd);
182                    if (resp.cmd == cmdDone)
183                        return 1;
184                    else
185                        return 0;
186                } else {
187                    ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
188                       "Response does not match request: xml(%s,%s) z(%d,%d) x(%d,%d) y(%d,%d)", cmd->xmlname,
189                       resp.xmlname, cmd->z, resp.z, cmd->x, resp.x, cmd->y, resp.y);
190                }
191            } else {
192                break;
193            }
194        }
195    }
196
197    close(fd);
198    return 0;
199}
200
201static apr_time_t getPlanetTime(request_rec *r)
202{
203    static apr_time_t last_check[XMLCONFIGS_MAX];
204    static apr_time_t planet_timestamp[XMLCONFIGS_MAX];
205    static pthread_mutex_t planet_lock = PTHREAD_MUTEX_INITIALIZER;
206    apr_time_t now = r->request_time;
207    struct apr_finfo_t s;
208
209    struct tile_request_data * rdata = (struct tile_request_data *)ap_get_module_config(r->request_config, &tile_module);
210    if (rdata == NULL) {
211        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "No per request configuration data");
212                return planet_timestamp[0];
213    }
214    struct protocol * cmd = rdata->cmd;
215
216
217    pthread_mutex_lock(&planet_lock);
218    // Only check for updates periodically
219    if (now < last_check[rdata->layerNumber] + apr_time_from_sec(300)) {
220        pthread_mutex_unlock(&planet_lock);
221        return planet_timestamp[rdata->layerNumber];
222    }
223
224    ap_conf_vector_t *sconf = r->server->module_config;
225    tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
226
227    char filename[PATH_MAX];
228    snprintf(filename, PATH_MAX-1, "%s/%s%s", scfg->tile_dir, cmd->xmlname, PLANET_TIMESTAMP);
229
230    last_check[rdata->layerNumber] = now;
231    if (apr_stat(&s, filename, APR_FINFO_MIN, r->pool) != APR_SUCCESS) {
232        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "per tile style planet time stamp (%s) missing, trying global one", filename);
233        snprintf(filename, PATH_MAX-1, "%s/%s", scfg->tile_dir, PLANET_TIMESTAMP);
234        if (apr_stat(&s, filename, APR_FINFO_MIN, r->pool) != APR_SUCCESS) {
235                ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "Global planet time stamp file (%s) is missing. Assuming 3 days old.", filename);
236                // Make something up
237                planet_timestamp[rdata->layerNumber] = now - apr_time_from_sec(3 * 24 * 60 * 60);
238        } else {
239                if (s.mtime != planet_timestamp[rdata->layerNumber]) {
240                        planet_timestamp[rdata->layerNumber] = s.mtime;
241                        char * timestr = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
242                            apr_rfc822_date(timestr, (planet_timestamp[rdata->layerNumber]));
243                        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Global planet file time stamp (%s) updated to %s", filename, timestr);
244                }
245        }
246    } else {
247        if (s.mtime != planet_timestamp[rdata->layerNumber]) {
248                planet_timestamp[rdata->layerNumber] = s.mtime;
249                        char * timestr = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
250                apr_rfc822_date(timestr, (planet_timestamp[rdata->layerNumber]));
251                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Per style planet file time stamp (%s) updated to %s", filename, timestr);
252        }
253    }
254    pthread_mutex_unlock(&planet_lock);
255    return planet_timestamp[rdata->layerNumber];
256}
257
258static enum tileState tile_state_once(request_rec *r)
259{
260    apr_status_t rv;
261    apr_finfo_t *finfo = &r->finfo;
262
263    if (!(finfo->valid & APR_FINFO_MTIME)) {
264        rv = apr_stat(finfo, r->filename, APR_FINFO_MIN, r->pool);
265        if (rv != APR_SUCCESS)
266            return tileMissing;
267    }
268
269    if (finfo->mtime < getPlanetTime(r))
270        return tileOld;
271
272    return tileCurrent;
273}
274
275static enum tileState tile_state(request_rec *r, struct protocol *cmd)
276{
277    enum tileState state = tile_state_once(r);
278#ifdef METATILEFALLBACK
279    if (state == tileMissing) {
280        ap_conf_vector_t *sconf = r->server->module_config;
281        tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
282
283        // Try fallback to plain PNG
284        char path[PATH_MAX];
285        xyz_to_path(path, sizeof(path), scfg->tile_dir, cmd->xmlname, cmd->x, cmd->y, cmd->z);
286        r->filename = apr_pstrdup(r->pool, path);
287        state = tile_state_once(r);
288        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "png fallback %d/%d/%d",x,y,z);
289
290        if (state == tileMissing) {
291            // PNG not available either, if it gets rendered, it'll now be a .meta
292            xyz_to_meta(path, sizeof(path), scfg->tile_dir, cmd->xmlname, cmd->x, cmd->y, cmd->z);
293            r->filename = apr_pstrdup(r->pool, path);
294        }
295    }
296#endif
297    return state;
298}
299
300static void add_expiry(request_rec *r, struct protocol * cmd)
301{
302    apr_time_t holdoff;
303    apr_table_t *t = r->headers_out;
304    enum tileState state = tile_state(r, cmd);
305    apr_finfo_t *finfo = &r->finfo;
306    char *timestr;
307    long int planetTimestamp, maxAge, minCache, lastModified;
308
309    ap_conf_vector_t *sconf = r->server->module_config;
310    tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
311
312    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "expires(%s), uri(%s), filename(%s), path_info(%s)\n",
313                  r->handler, r->uri, r->filename, r->path_info);
314
315    /* If the hostname matches the "extended caching hostname" then set the cache age accordingly */
316    if ((scfg->cache_extended_hostname[0] != 0) && (strstr(r->hostname,
317            scfg->cache_extended_hostname) != NULL)) {
318        maxAge = scfg->cache_extended_duration;
319    } else {
320
321        /* Test if the tile we are serving is out of date, then set a low maxAge*/
322        if (state == tileOld) {
323            holdoff = (scfg->cache_duration_dirty / 2) * (rand() / (RAND_MAX
324                    + 1.0));
325            maxAge = scfg->cache_duration_dirty + holdoff;
326        } else {
327            // cache heuristic based on zoom level
328            if (cmd->z > MAX_ZOOM) {
329                minCache = 0;
330                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
331                        "z (%i) is larger than MAXZOOM %i\n", cmd->z, MAX_ZOOM);
332            } else {
333                minCache = scfg->mincachetime[cmd->z];
334            }
335            // Time to the next known complete rerender
336            planetTimestamp = apr_time_sec(getPlanetTime(r)
337                    + apr_time_from_sec(PLANET_INTERVAL) - r->request_time);
338            // Time since the last render of this tile
339            lastModified = (int) (((double) apr_time_sec(r->request_time
340                    - finfo->mtime))
341                    * scfg->cache_duration_last_modified_factor);
342            // Add a random jitter of 3 hours to space out cache expiry
343            holdoff = (3 * 60 * 60) * (rand() / (RAND_MAX + 1.0));
344
345            maxAge = MAX(minCache, planetTimestamp);
346            maxAge = MAX(maxAge, lastModified);
347            maxAge += holdoff;
348
349            ap_log_rerror(
350                    APLOG_MARK,
351                    APLOG_DEBUG,
352                    0,
353                    r,
354                    "caching heuristics: next planet render %ld; zoom level based %ld; last modified %ld\n",
355                    planetTimestamp, minCache, lastModified);
356        }
357
358        maxAge = MIN(maxAge, scfg->cache_duration_max);
359    }
360
361    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Setting tiles maxAge to %ld\n", maxAge);
362
363    apr_table_mergen(t, "Cache-Control",
364                     apr_psprintf(r->pool, "max-age=%" APR_TIME_T_FMT,
365                     maxAge));
366    timestr = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
367    apr_rfc822_date(timestr, (apr_time_from_sec(maxAge) + r->request_time));
368    apr_table_setn(t, "Expires", timestr);
369}
370
371double get_load_avg(request_rec *r)
372{
373    double loadavg[1];
374    int n = getloadavg(loadavg, 1);
375
376    if (n < 1)
377        return 1000;
378    else
379        return loadavg[0];
380}
381
382static int get_global_lock(request_rec *r, apr_global_mutex_t * mutex) {
383    apr_status_t rs;
384    int camped;
385
386    for (camped = 0; camped < MAXCAMP; camped++) {
387        rs = apr_global_mutex_trylock(mutex);
388        if (APR_STATUS_IS_EBUSY(rs)) {
389            apr_sleep(CAMPOUT);
390        } else if (rs == APR_SUCCESS) {
391            return 1;
392        } else if (APR_STATUS_IS_ENOTIMPL(rs)) {
393            /* If it's not implemented, just hang in the mutex. */
394            rs = apr_global_mutex_lock(mutex);
395            if (rs == APR_SUCCESS) {
396                return 1;
397            } else {
398                ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "Could not get hardlock");
399                return 0;
400            }
401        } else {
402            ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, "Unknown return status from trylock");
403            return 0;
404        }
405    }
406    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Timedout trylock");
407    return 0;
408}
409
410static int incRespCounter(int resp, request_rec *r, struct protocol * cmd, int layerNumber) {
411    stats_data *stats;
412
413    ap_conf_vector_t *sconf = r->server->module_config;
414    tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
415
416    if (!scfg->enableGlobalStats) {
417        /* If tile stats reporting is not enable
418         * pretend we correctly updated the counter to
419         * not fill the logs with warnings about failed
420         * stats
421         */
422        return 1;
423    }
424
425    if (get_global_lock(r, stats_mutex) != 0) {
426        stats = (stats_data *)apr_shm_baseaddr_get(stats_shm);
427        switch (resp) {
428        case OK: {
429            stats->noResp200++;
430                        if (cmd != NULL) {
431                                stats->noRespZoom[cmd->z]++;
432                                stats->noResp200Layer[layerNumber]++;
433                        }
434            break;
435        }
436        case HTTP_NOT_MODIFIED: {
437            stats->noResp304++;
438                        if (cmd != NULL) {
439                                stats->noRespZoom[cmd->z]++;
440                                stats->noResp200Layer[layerNumber]++;
441                        }
442            break;
443        }
444        case HTTP_NOT_FOUND: {
445            stats->noResp404++;
446            stats->noResp404Layer[layerNumber]++;
447            break;
448        }
449                case HTTP_SERVICE_UNAVAILABLE: {
450            stats->noResp503++;
451            break;
452        }
453        case HTTP_INTERNAL_SERVER_ERROR: {
454            stats->noResp5XX++;
455            break;
456        }
457        default: {
458            stats->noRespOther++;
459        }
460
461        }
462        apr_global_mutex_unlock(stats_mutex);
463        /* Swallowing the result because what are we going to do with it at
464         * this stage?
465         */
466        return 1;
467    } else {
468        return 0;
469    }
470}
471
472static int incFreshCounter(int status, request_rec *r) {
473    stats_data *stats;
474
475    ap_conf_vector_t *sconf = r->server->module_config;
476    tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
477
478    if (!scfg->enableGlobalStats) {
479        /* If tile stats reporting is not enable
480         * pretend we correctly updated the counter to
481         * not fill the logs with warnings about failed
482         * stats
483         */
484        return 1;
485    }
486
487    if (get_global_lock(r, stats_mutex) != 0) {
488        stats = (stats_data *)apr_shm_baseaddr_get(stats_shm);
489        switch (status) {
490        case FRESH: {
491            stats->noFreshCache++;
492            break;
493        }
494        case FRESH_RENDER: {
495            stats->noFreshRender++;
496            break;
497        }
498        case OLD: {
499            stats->noOldCache++;
500            break;
501        }
502        case OLD_RENDER: {
503            stats->noOldRender++;
504            break;
505        }
506        }
507        apr_global_mutex_unlock(stats_mutex);
508        /* Swallowing the result because what are we going to do with it at
509         * this stage?
510         */
511        return 1;
512    } else {
513        return 0;
514    }
515}
516
517static int delay_allowed(request_rec *r, enum tileState state) {
518        delaypool * delayp;
519        int delay = 0;
520        int i,j;
521
522    ap_conf_vector_t *sconf = r->server->module_config;
523        tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
524        delayp = (delaypool *)apr_shm_baseaddr_get(delaypool_shm);
525
526        /* TODO: fix IPv6 compatibility */
527        in_addr_t ip = inet_addr(r->connection->remote_ip);
528       
529        int hashkey = ip % DELAY_HASHTABLE_WHITELIST_SIZE;
530        if (delayp->whitelist[hashkey] == ip) {
531                return 1;
532        }
533
534        /* If a delaypool fillup is ongoing, just skip accounting to not block on a lock */
535        if (delayp->locked) {
536                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "skipping delay pool accounting, during fillup procedure\n");
537                return 1;
538        }
539
540       
541        hashkey = ip % DELAY_HASHTABLE_SIZE;
542       
543        if (get_global_lock(r,delay_mutex) == 0) {
544                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Could not acquire lock, skipping delay pool accounting\n");
545                return 1;
546        };
547        if (delayp->users[hashkey].ip_addr == ip) {
548                /* Repeat the process to determin if we have tockens in the bucket, as the fillup only runs once a client hits an empty bucket,
549                   so in the mean time, the bucket might have been filled */
550                for (j = 0; j < 3; j++) {
551                        //ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Checking delays: Current poolsize: %i tiles and %i renders\n", delayp->users[hashkey].available_tiles, delayp->users[hashkey].available_render_req);
552                        delay = 0;
553                        if (delayp->users[hashkey].available_tiles > 0) {
554                                delayp->users[hashkey].available_tiles--;
555                        } else {
556                                delay = 1;
557                        }
558                        if (state == tileMissing) {
559                                if (delayp->users[hashkey].available_render_req > 0) {
560                                        delayp->users[hashkey].available_render_req--;
561                                } else {
562                                        delay = 2;
563                                }
564                        }
565
566                        if (delay > 0) {
567                                /* If we are on the second round, we really  hit an empty delaypool, timeout for a while to slow down clients */
568                                if (j > 0) {
569                                        apr_global_mutex_unlock(delay_mutex);
570                                        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Delaypool: Client %s has hit its limits, throttling (%i)\n", r->connection->remote_ip, delay);
571                                        sleep(CLIENT_PENALTY);
572                                        if (get_global_lock(r,delay_mutex) == 0) {
573                                                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Could not acquire lock, but had to delay\n");
574                                                return 0;
575                                        };
576                                }
577                                /* We hit an empty bucket, so run the bucket fillup procedure to check if new tokens should have arrived in the mean time. */
578                                apr_time_t now = apr_time_now();
579                                int tiles_topup = (now - delayp->last_tile_fillup) / scfg->delaypoolTileRate;
580                                int render_topup = (now - delayp->last_render_fillup) / scfg->delaypoolRenderRate;
581                                //ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Filling up pools with %i tiles and %i renders\n", tiles_topup, render_topup);
582                                if ((tiles_topup > 0) || (render_topup > 0)) {
583                                        delayp->locked = 1;
584                                        for (i = 0; i < DELAY_HASHTABLE_SIZE; i++) {
585                                                delayp->users[i].available_tiles += tiles_topup;
586                                                delayp->users[i].available_render_req += render_topup;
587                                                if (delayp->users[i].available_tiles > scfg->delaypoolTileSize) {
588                                                        delayp->users[i].available_tiles = scfg->delaypoolTileSize;
589                                                }
590                                                if (delayp->users[i].available_render_req > scfg->delaypoolRenderSize) {
591                                                        delayp->users[i].available_render_req = scfg->delaypoolRenderSize;
592                                                }
593                                        }
594                                        delayp->locked = 0;
595                                }
596                                delayp->last_tile_fillup += scfg->delaypoolTileRate*tiles_topup;
597                                delayp->last_render_fillup += scfg->delaypoolRenderRate*render_topup;                           
598                               
599                        } else {
600                                break;
601                        }
602                }
603        } else {
604                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Creating a new delaypool for ip %s, overwriting %s\n", r->connection->remote_ip, inet_ntoa(inet_makeaddr(delayp->users[hashkey].ip_addr,delayp->users[hashkey].ip_addr)));
605                delayp->users[hashkey].ip_addr = ip;
606                delayp->users[hashkey].available_tiles = scfg->delaypoolTileSize;
607            delayp->users[hashkey].available_render_req = scfg->delaypoolRenderSize;
608                delay = 0;
609        }
610        apr_global_mutex_unlock(delay_mutex);
611
612        if (delay > 0) {
613                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Delaypool: Client %s has hit its limits, rejecting (%i)\n", r->connection->remote_ip, delay);
614                return 0;
615        } else {
616                return 1;
617        }
618}
619
620static int tile_handler_dirty(request_rec *r)
621{
622    if(strcmp(r->handler, "tile_dirty"))
623        return DECLINED;
624
625        struct tile_request_data * rdata = (struct tile_request_data *)ap_get_module_config(r->request_config, &tile_module);
626    struct protocol * cmd = rdata->cmd;
627    if (cmd == NULL)
628        return DECLINED;
629
630    ap_conf_vector_t *sconf = r->server->module_config;
631    tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
632        if (scfg->bulkMode) return OK;
633
634    request_tile(r, cmd, 0);
635    return error_message(r, "Tile submitted for rendering\n");
636}
637
638static int tile_storage_hook(request_rec *r)
639{
640//    char abs_path[PATH_MAX];
641    int avg;
642    int renderPrio = 0;
643    enum tileState state;
644
645    if (!r->handler)
646        return DECLINED;
647
648        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "tile_storage_hook: handler(%s), uri(%s), filename(%s), path_info(%s)",
649                  r->handler, r->uri, r->filename, r->path_info);
650
651    // Any status request is OK. tile_dirty also doesn't need to be handled, as tile_handler_dirty will take care of it
652    if (!strcmp(r->handler, "tile_status") || !strcmp(r->handler, "tile_dirty") || !strcmp(r->handler, "tile_mod_stats"))
653        return OK;
654
655    if (strcmp(r->handler, "tile_serve"))
656        return DECLINED;
657
658    struct tile_request_data * rdata = (struct tile_request_data *)ap_get_module_config(r->request_config, &tile_module);
659    struct protocol * cmd = rdata->cmd;
660    if (cmd == NULL)
661        return DECLINED;
662
663/*
664should already be done
665    // Generate the tile filename
666#ifdef METATILE
667    ap_conf_vector_t *sconf = r->server->module_config;
668    tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
669    xyz_to_meta(abs_path, sizeof(abs_path), scfg->tile_dir, cmd->xmlname, cmd->x, cmd->y, cmd->z);
670#else
671    xyz_to_path(abs_path, sizeof(abs_path), scfg->tile_dir, cmd->xmlname, cmd->x, cmd->y, cmd->z);
672#endif
673    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "abs_path(%s)", abs_path);
674    r->filename = apr_pstrdup(r->pool, abs_path);
675*/
676    avg = get_load_avg(r);
677    state = tile_state(r, cmd);
678
679    ap_conf_vector_t *sconf = r->server->module_config;
680    tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
681
682        if (scfg->enableTileThrottling && !delay_allowed(r, state)) {
683                if (!incRespCounter(HTTP_SERVICE_UNAVAILABLE, r, cmd, rdata->layerNumber)) {
684                   ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
685                        "Failed to increase response stats counter");
686        }
687        return HTTP_SERVICE_UNAVAILABLE;               
688        }
689
690    switch (state) {
691        case tileCurrent:
692            if (!incFreshCounter(FRESH, r)) {
693                ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
694                    "Failed to increase fresh stats counter");
695            }
696            return OK;
697            break;
698        case tileOld:
699            if (scfg->bulkMode) {
700                return OK;
701            } else if (avg > scfg->max_load_old) {
702               // Too much load to render it now, mark dirty but return old tile
703               request_tile(r, cmd, 0);
704               ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Load larger max_load_old (%d). Mark dirty and deliver from cache.", scfg->max_load_old);
705               if (!incFreshCounter(OLD, r)) {
706                   ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
707                        "Failed to increase fresh stats counter");
708               }
709               return OK;
710            }
711            renderPrio = 1;
712            break;
713        case tileMissing:
714            if (avg > scfg->max_load_missing) {
715               request_tile(r, cmd, 0);
716               ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Load larger max_load_missing (%d). Return HTTP_NOT_FOUND.", scfg->max_load_missing);
717               if (!incRespCounter(HTTP_NOT_FOUND, r, cmd, rdata->layerNumber)) {
718                   ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
719                        "Failed to increase response stats counter");
720               }
721               return HTTP_NOT_FOUND;
722            }
723            renderPrio = 2;
724            break;
725    }
726
727    if (request_tile(r, cmd, renderPrio)) {
728        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Update file info abs_path(%s)", r->filename);
729        // Need to update fileinfo for new rendered tile
730        apr_stat(&r->finfo, r->filename, APR_FINFO_MIN, r->pool);
731        if (!incFreshCounter(FRESH_RENDER, r)) {
732            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
733                    "Failed to increase fresh stats counter");
734        }
735        return OK;
736    }
737
738    if (state == tileOld) {
739        if (!incFreshCounter(OLD_RENDER, r)) {
740            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
741                    "Failed to increase fresh stats counter");
742        }
743        return OK;
744    }
745    if (!incRespCounter(HTTP_NOT_FOUND, r, cmd, rdata->layerNumber)) {
746        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
747                "Failed to increase response stats counter");
748    }
749
750    return HTTP_NOT_FOUND;
751}
752
753static int tile_handler_status(request_rec *r)
754{
755    enum tileState state;
756    char time_str[APR_CTIME_LEN];
757
758    if(strcmp(r->handler, "tile_status"))
759        return DECLINED;
760
761    struct tile_request_data * rdata = (struct tile_request_data *)ap_get_module_config(r->request_config, &tile_module);
762    struct protocol * cmd = rdata->cmd;
763    if (cmd == NULL){
764        sleep(CLIENT_PENALTY);
765        return HTTP_NOT_FOUND;
766    }
767
768    state = tile_state(r, cmd);
769    if (state == tileMissing)
770        return error_message(r, "Unable to find a tile at %s\n", r->filename);
771    apr_ctime(time_str, r->finfo.mtime);
772
773    return error_message(r, "Tile is %s. Last rendered at %s\n", (state == tileOld) ? "due to be rendered" : "clean", time_str);
774}
775
776static int tile_handler_mod_stats(request_rec *r)
777{
778    stats_data * stats;
779    stats_data local_stats;
780        int i;
781
782    if (strcmp(r->handler, "tile_mod_stats"))
783        return DECLINED;
784
785    ap_conf_vector_t *sconf = r->server->module_config;
786    tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
787    tile_config_rec *tile_configs = (tile_config_rec *) scfg->configs->elts;
788
789    if (!scfg->enableGlobalStats) {
790        return error_message(r, "Stats are not enabled for this server");
791    }
792
793    if (get_global_lock(r,stats_mutex) != 0) {
794        //Copy over the global counter variable into
795        //local variables, that we can immediately
796        //release the lock again
797        stats = (stats_data *) apr_shm_baseaddr_get(stats_shm);
798        memcpy(&local_stats, stats, sizeof(stats_data));
799        apr_global_mutex_unlock(stats_mutex);
800    } else {
801        return error_message(r, "Failed to acquire lock, can't display stats");
802    }
803
804    ap_rprintf(r, "NoResp200: %li\n", local_stats.noResp200);
805    ap_rprintf(r, "NoResp304: %li\n", local_stats.noResp304);
806    ap_rprintf(r, "NoResp404: %li\n", local_stats.noResp404);
807        ap_rprintf(r, "NoResp503: %li\n", local_stats.noResp503);
808    ap_rprintf(r, "NoResp5XX: %li\n", local_stats.noResp5XX);
809    ap_rprintf(r, "NoRespOther: %li\n", local_stats.noRespOther);
810    ap_rprintf(r, "NoFreshCache: %li\n", local_stats.noFreshCache);
811    ap_rprintf(r, "NoOldCache: %li\n", local_stats.noOldCache);
812    ap_rprintf(r, "NoFreshRender: %li\n", local_stats.noFreshRender);
813    ap_rprintf(r, "NoOldRender: %li\n", local_stats.noOldRender);
814        for (i = 0; i <= MAX_ZOOM; i++) {
815                ap_rprintf(r, "NoRespZoom%02i: %li\n", i, local_stats.noRespZoom[i]);
816        }
817        for (i = 0; i < scfg->configs->nelts; ++i) {
818                tile_config_rec *tile_config = &tile_configs[i];
819                        ap_rprintf(r,"NoRes200Layer%s: %li\n", tile_config->xmlname, local_stats.noResp200Layer[i]);
820                        ap_rprintf(r,"NoRes404Layer%s: %li\n", tile_config->xmlname, local_stats.noResp404Layer[i]);
821        }
822
823
824
825    return OK;
826}
827
828static int tile_handler_serve(request_rec *r)
829{
830    const int tile_max = MAX_SIZE;
831    unsigned char *buf;
832    int len;
833    apr_status_t errstatus;
834
835    if(strcmp(r->handler, "tile_serve"))
836        return DECLINED;
837
838    struct tile_request_data * rdata = (struct tile_request_data *)ap_get_module_config(r->request_config, &tile_module);
839    struct protocol * cmd = rdata->cmd;
840    if (cmd == NULL){
841        sleep(CLIENT_PENALTY);
842        if (!incRespCounter(HTTP_NOT_FOUND, r, cmd, rdata->layerNumber)) {
843            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
844                    "Failed to increase response stats counter");
845        }
846        return HTTP_NOT_FOUND;
847    }
848
849    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "tile_handler_serve: xml(%s) z(%d) x(%d) y(%d)", cmd->xmlname, cmd->z, cmd->x, cmd->y);
850
851    // FIXME: It is a waste to do the malloc + read if we are fulfilling a HEAD or returning a 304.
852    buf = malloc(tile_max);
853    if (!buf) {
854        if (!incRespCounter(HTTP_INTERNAL_SERVER_ERROR, r, cmd, rdata->layerNumber)) {
855            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
856                    "Failed to increase response stats counter");
857        }
858        return HTTP_INTERNAL_SERVER_ERROR;
859    }
860
861    len = tile_read(cmd->xmlname, cmd->x, cmd->y, cmd->z, buf, tile_max);
862    if (len > 0) {
863#if 0
864        // Set default Last-Modified and Etag headers
865        ap_update_mtime(r, r->finfo.mtime);
866        ap_set_last_modified(r);
867        ap_set_etag(r);
868#else
869        // Use MD5 hash as only cache attribute.
870        // If a tile is re-rendered and produces the same output
871        // then we can continue to use the previous cached copy
872        char *md5 = ap_md5_binary(r->pool, buf, len);
873        apr_table_setn(r->headers_out, "ETag",
874                        apr_psprintf(r->pool, "\"%s\"", md5));
875#endif
876                tile_server_conf *scfg = ap_get_module_config(r->server->module_config, &tile_module);
877        tile_config_rec *tile_configs = (tile_config_rec *) scfg->configs->elts;
878        ap_set_content_type(r, tile_configs[rdata->layerNumber].mimeType);
879        ap_set_content_length(r, len);
880        add_expiry(r, cmd);
881        if ((errstatus = ap_meets_conditions(r)) != OK) {
882            free(buf);
883            if (!incRespCounter(errstatus, r, cmd, rdata->layerNumber)) {
884                ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
885                        "Failed to increase response stats counter");
886            }
887            return errstatus;
888        } else {
889            ap_rwrite(buf, len, r);
890            free(buf);
891            if (!incRespCounter(errstatus, r, cmd, rdata->layerNumber)) {
892                ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
893                        "Failed to increase response stats counter");
894            }
895            return OK;
896        }
897    }
898    free(buf);
899    //ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "len = %d", len);
900    if (!incRespCounter(HTTP_NOT_FOUND, r, cmd, rdata->layerNumber)) {
901        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
902                "Failed to increase response stats counter");
903    }
904    return DECLINED;
905}
906
907static int tile_translate(request_rec *r)
908{
909    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "tile_translate: uri(%s)", r->uri);
910
911    int i,n,limit,oob;
912    char option[11];
913
914    ap_conf_vector_t *sconf = r->server->module_config;
915    tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
916
917    tile_config_rec *tile_configs = (tile_config_rec *) scfg->configs->elts;
918
919    /*
920     * The page /mod_tile returns global stats about the number of tiles
921     * handled and in what state those tiles were.
922     * This should probably not be hard coded
923     */
924    if (!strncmp("/mod_tile", r->uri, strlen("/mod_tile"))) {
925        r->handler = "tile_mod_stats";
926        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
927                "tile_translate: retrieving global mod_tile stats");
928        return OK;
929    }
930
931    for (i = 0; i < scfg->configs->nelts; ++i) {
932        tile_config_rec *tile_config = &tile_configs[i];
933
934        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "tile_translate: testing baseuri(%s) name(%s) extension(%s)",
935                        tile_config->baseuri, tile_config->xmlname, tile_config->fileExtension );
936
937        if (!strncmp(tile_config->baseuri, r->uri, strlen(tile_config->baseuri))) {
938
939                struct tile_request_data * rdata = (struct tile_request_data *) apr_pcalloc(r->pool, sizeof(struct tile_request_data));
940            struct protocol * cmd = (struct protocol *) apr_pcalloc(r->pool, sizeof(struct protocol));
941            bzero(cmd, sizeof(struct protocol));
942            bzero(rdata, sizeof(struct tile_request_data));
943            char extension[256];
944            n = sscanf(r->uri+strlen(tile_config->baseuri),"%d/%d/%d.%[a-z]/%10s", &(cmd->z), &(cmd->x), &(cmd->y), extension, option);
945            if (n < 4) {
946                                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "tile_translate: Invalid URL for tilelayer %s", tile_config->xmlname);
947                                return DECLINED;
948                        }
949                        if (strcmp(extension, tile_config->fileExtension) != 0) {
950                                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "tile_translate: Invalid file extension (%s) for tilelayer %s, required %s",
951                                                extension, tile_config->xmlname, tile_config->fileExtension);
952                                return DECLINED;
953                        }
954
955            oob = (cmd->z < 0 || cmd->z > MAX_ZOOM);
956            if (!oob) {
957                 // valid x/y for tiles are 0 ... 2^zoom-1
958                 limit = (1 << cmd->z) - 1;
959                 oob =  (cmd->x < 0 || cmd->x > limit || cmd->y < 0 || cmd->y > limit);
960            }
961
962            if (oob) {
963                                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "tile_translate: request for %s was outside of allowed bounds", tile_config->xmlname);
964                sleep(CLIENT_PENALTY);
965                //Don't increase stats counter here,
966                //As we are interested in valid tiles only
967                return HTTP_NOT_FOUND;
968            }
969
970            strcpy(cmd->xmlname, tile_config->xmlname);
971
972            // Store a copy for later
973                        rdata->cmd = cmd;
974                        rdata->layerNumber = i;
975            ap_set_module_config(r->request_config, &tile_module, rdata);
976
977            // Generate the tile filename?
978            char abs_path[PATH_MAX];
979#ifdef METATILE
980            xyz_to_meta(abs_path, sizeof(abs_path), scfg->tile_dir, cmd->xmlname, cmd->x, cmd->y, cmd->z);
981#else
982            xyz_to_path(abs_path, sizeof(abs_path), scfg->tile_dir, cmd->xmlname, cmd->x, cmd->y, cmd->z);
983#endif
984            r->filename = apr_pstrdup(r->pool, abs_path);
985
986            if (n == 5) {
987                if (!strcmp(option, "status")) r->handler = "tile_status";
988                else if (!strcmp(option, "dirty")) r->handler = "tile_dirty";
989                else return DECLINED;
990            } else {
991                r->handler = "tile_serve";
992            }
993
994            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "tile_translate: op(%s) xml(%s) mime(%s) z(%d) x(%d) y(%d)",
995                        r->handler , cmd->xmlname, tile_config->mimeType, cmd->z, cmd->x, cmd->y);
996
997            return OK;
998        }
999    }
1000        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "tile_translate: No suitable tile layer found");
1001    return DECLINED;
1002}
1003
1004/*
1005 * This routine is called in the parent, so we'll set up the shared
1006 * memory segment and mutex here.
1007 */
1008
1009static int mod_tile_post_config(apr_pool_t *pconf, apr_pool_t *plog,
1010                             apr_pool_t *ptemp, server_rec *s)
1011{
1012    void *data; /* These two help ensure that we only init once. */
1013    const char *userdata_key = "mod_tile_init_module";
1014    apr_status_t rs;
1015    stats_data *stats;
1016        delaypool *delayp;
1017        int i;
1018
1019
1020    /*
1021     * The following checks if this routine has been called before.
1022     * This is necessary because the parent process gets initialized
1023     * a couple of times as the server starts up, and we don't want
1024     * to create any more mutexes and shared memory segments than
1025     * we're actually going to use.
1026     */
1027    apr_pool_userdata_get(&data, userdata_key, s->process->pool);
1028    if (!data) {
1029        apr_pool_userdata_set((const void *) 1, userdata_key,
1030                              apr_pool_cleanup_null, s->process->pool);
1031        return OK;
1032    } /* Kilroy was here */
1033
1034    /* Create the shared memory segment */
1035
1036    /*
1037     * Create a unique filename using our pid. This information is
1038     * stashed in the global variable so the children inherit it.
1039     * TODO get the location from the environment $TMPDIR or somesuch.
1040     */
1041    shmfilename = apr_psprintf(pconf, "/tmp/httpd_shm.%ld", (long int)getpid());
1042        shmfilename_delaypool = apr_psprintf(pconf, "/tmp/httpd_shm_delay.%ld", (long int)getpid());
1043
1044    /* Now create that segment */
1045    rs = apr_shm_create(&stats_shm, sizeof(stats_data),
1046                        (const char *) shmfilename, pconf);
1047    if (rs != APR_SUCCESS) {
1048        ap_log_error(APLOG_MARK, APLOG_ERR, rs, s,
1049                     "Failed to create shared memory segment on file %s",
1050                     shmfilename);
1051        return HTTP_INTERNAL_SERVER_ERROR;
1052    }
1053
1054        rs = apr_shm_create(&delaypool_shm, sizeof(delaypool),
1055                        (const char *) shmfilename_delaypool, pconf);
1056    if (rs != APR_SUCCESS) {
1057        ap_log_error(APLOG_MARK, APLOG_ERR, rs, s,
1058                     "Failed to create shared memory segment on file %s",
1059                     shmfilename_delaypool);
1060        return HTTP_INTERNAL_SERVER_ERROR;
1061    }
1062
1063    /* Created it, now let's zero it out */
1064    stats = (stats_data *)apr_shm_baseaddr_get(stats_shm);
1065    stats->noResp200 = 0;
1066    stats->noResp304 = 0;
1067    stats->noResp404 = 0;
1068        stats->noResp503 = 0;
1069    stats->noResp5XX = 0;
1070        for (i = 0; i <= MAX_ZOOM; i++) {
1071                stats->noRespZoom[i] = 0;
1072        }
1073    stats->noRespOther = 0;
1074    stats->noFreshCache = 0;
1075    stats->noFreshRender = 0;
1076    stats->noOldCache = 0;
1077    stats->noOldRender = 0;
1078
1079        delayp = (delaypool *)apr_shm_baseaddr_get(delaypool_shm);
1080       
1081        delayp->last_tile_fillup = apr_time_now();
1082        delayp->last_render_fillup = apr_time_now();
1083
1084        for (i = 0; i < DELAY_HASHTABLE_SIZE; i++) {
1085                delayp->users[i].ip_addr = (in_addr_t)0;
1086                delayp->users[i].available_tiles = 0;
1087                delayp->users[i].available_render_req = 0;
1088        }
1089        for (i = 0; i < DELAY_HASHTABLE_WHITELIST_SIZE; i++) {
1090                delayp->whitelist[i] = (in_addr_t)0;
1091        }
1092        /* TODO: need a way to initialise the delaypool whitelist */
1093
1094
1095    /* Create global mutex */
1096
1097    /*
1098     * Create another unique filename to lock upon. Note that
1099     * depending on OS and locking mechanism of choice, the file
1100     * may or may not be actually created.
1101     */
1102    mutexfilename = apr_psprintf(pconf, "/tmp/httpd_mutex.%ld",
1103                                 (long int) getpid());
1104
1105    rs = apr_global_mutex_create(&stats_mutex, (const char *) mutexfilename,
1106                                 APR_LOCK_DEFAULT, pconf);
1107    if (rs != APR_SUCCESS) {
1108        ap_log_error(APLOG_MARK, APLOG_ERR, rs, s,
1109                     "Failed to create mutex on file %s",
1110                     mutexfilename);
1111        return HTTP_INTERNAL_SERVER_ERROR;
1112    }
1113
1114#ifdef MOD_TILE_SET_MUTEX_PERMS
1115    rs = unixd_set_global_mutex_perms(stats_mutex);
1116    if (rs != APR_SUCCESS) {
1117        ap_log_error(APLOG_MARK, APLOG_CRIT, rs, s,
1118                     "Parent could not set permissions on mod_tile "
1119                     "mutex: check User and Group directives");
1120        return HTTP_INTERNAL_SERVER_ERROR;
1121    }
1122#endif /* MOD_TILE_SET_MUTEX_PERMS */
1123
1124    /*
1125     * Create another unique filename to lock upon. Note that
1126     * depending on OS and locking mechanism of choice, the file
1127     * may or may not be actually created.
1128     */
1129    mutexfilename = apr_psprintf(pconf, "/tmp/httpd_mutex_delay.%ld",
1130                                 (long int) getpid());
1131
1132    rs = apr_global_mutex_create(&delay_mutex, (const char *) mutexfilename,
1133                                 APR_LOCK_DEFAULT, pconf);
1134    if (rs != APR_SUCCESS) {
1135        ap_log_error(APLOG_MARK, APLOG_ERR, rs, s,
1136                     "Failed to create mutex on file %s",
1137                     mutexfilename);
1138        return HTTP_INTERNAL_SERVER_ERROR;
1139    }
1140
1141#ifdef MOD_TILE_SET_MUTEX_PERMS
1142    rs = unixd_set_global_mutex_perms(delay_mutex);
1143    if (rs != APR_SUCCESS) {
1144        ap_log_error(APLOG_MARK, APLOG_CRIT, rs, s,
1145                     "Parent could not set permissions on mod_tile "
1146                     "mutex: check User and Group directives");
1147        return HTTP_INTERNAL_SERVER_ERROR;
1148    }
1149#endif /* MOD_TILE_SET_MUTEX_PERMS */
1150
1151    return OK;
1152}
1153
1154
1155/*
1156 * This routine gets called when a child inits. We use it to attach
1157 * to the shared memory segment, and reinitialize the mutex.
1158 */
1159
1160static void mod_tile_child_init(apr_pool_t *p, server_rec *s)
1161{
1162    apr_status_t rs;
1163
1164     /*
1165      * Re-open the mutex for the child. Note we're reusing
1166      * the mutex pointer global here.
1167      */
1168     rs = apr_global_mutex_child_init(&stats_mutex,
1169                                      (const char *) mutexfilename,
1170                                      p);
1171     if (rs != APR_SUCCESS) {
1172         ap_log_error(APLOG_MARK, APLOG_CRIT, rs, s,
1173                     "Failed to reopen mutex on file %s",
1174                     shmfilename);
1175         /* There's really nothing else we can do here, since
1176          * This routine doesn't return a status. */
1177         exit(1); /* Ugly, but what else? */
1178     }
1179}
1180
1181static void register_hooks(__attribute__((unused)) apr_pool_t *p)
1182{
1183    ap_hook_post_config(mod_tile_post_config, NULL, NULL, APR_HOOK_MIDDLE);
1184    ap_hook_child_init(mod_tile_child_init, NULL, NULL, APR_HOOK_MIDDLE);
1185    ap_hook_handler(tile_handler_serve, NULL, NULL, APR_HOOK_MIDDLE);
1186    ap_hook_handler(tile_handler_dirty, NULL, NULL, APR_HOOK_MIDDLE);
1187    ap_hook_handler(tile_handler_status, NULL, NULL, APR_HOOK_MIDDLE);
1188    ap_hook_handler(tile_handler_mod_stats, NULL, NULL, APR_HOOK_MIDDLE);
1189    ap_hook_translate_name(tile_translate, NULL, NULL, APR_HOOK_MIDDLE);
1190    ap_hook_map_to_storage(tile_storage_hook, NULL, NULL, APR_HOOK_FIRST);
1191}
1192
1193static const char *_add_tile_config(cmd_parms *cmd, void *mconfig, const char *baseuri, const char *name, int minzoom, int maxzoom, const char * fileExtension, const char *mimeType)
1194{
1195    if (strlen(name) == 0) {
1196        return "ConfigName value must not be null";
1197    }
1198
1199
1200    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
1201    tile_config_rec *tilecfg = apr_array_push(scfg->configs);
1202
1203    // Ensure URI string ends with a trailing slash
1204    int urilen = strlen(baseuri);
1205
1206    if (urilen==0)
1207      snprintf(tilecfg->baseuri, PATH_MAX, "/");
1208    else if (baseuri[urilen-1] != '/')
1209      snprintf(tilecfg->baseuri, PATH_MAX, "%s/", baseuri);
1210    else
1211      snprintf(tilecfg->baseuri, PATH_MAX, "%s", baseuri);
1212
1213    strncpy(tilecfg->xmlname, name, XMLCONFIG_MAX-1);
1214    strncpy(tilecfg->fileExtension, fileExtension, XMLCONFIG_MAX-1);
1215    strncpy(tilecfg->mimeType, mimeType, XMLCONFIG_MAX-1);
1216    tilecfg->xmlname[XMLCONFIG_MAX-1] = 0;
1217    tilecfg->minzoom = minzoom;
1218    tilecfg->maxzoom = maxzoom;
1219
1220        ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, cmd->server,
1221                    "Loading tile config %s at %s for zooms %i - %i from tile directory %s with extension .%s and mime type %s",
1222                                 name, baseuri, minzoom, maxzoom, scfg->tile_dir, fileExtension, mimeType);
1223
1224
1225    return NULL;
1226}
1227
1228static const char *add_tile_mime_config(cmd_parms *cmd, void *mconfig, const char *baseuri, const char *name, const char * fileExtension)
1229{
1230        if (strcmp(fileExtension,"png") == 0) {
1231                return _add_tile_config(cmd, mconfig, baseuri, name, 0, MAX_ZOOM, fileExtension, "image/png");
1232        }
1233        if (strcmp(fileExtension,"js") == 0) {
1234                return _add_tile_config(cmd, mconfig, baseuri, name, 0, MAX_ZOOM, fileExtension, "text/javascript");
1235        }
1236        return _add_tile_config(cmd, mconfig, baseuri, name, 0, MAX_ZOOM, fileExtension, "image/png");
1237}
1238
1239static const char *add_tile_config(cmd_parms *cmd, void *mconfig, const char *baseuri, const char *name)
1240{
1241    return _add_tile_config(cmd, mconfig, baseuri, name, 0, MAX_ZOOM, "png", "image/png");
1242}
1243
1244static const char *load_tile_config(cmd_parms *cmd, void *mconfig, const char *conffile)
1245{
1246    FILE * hini ;
1247    char filename[PATH_MAX];
1248    char xmlname[XMLCONFIG_MAX];
1249    char line[INILINE_MAX];
1250    char key[INILINE_MAX];
1251    char value[INILINE_MAX];
1252    const char * result;
1253    char fileExtension[INILINE_MAX];
1254    char mimeType[INILINE_MAX];
1255
1256    if (strlen(conffile) == 0) {
1257        strcpy(filename, RENDERD_CONFIG);
1258    } else {
1259        strcpy(filename, conffile);
1260    }
1261
1262    // Load the config
1263    if ((hini=fopen(filename, "r"))==NULL) {
1264        return "Unable to open config file";
1265    }
1266
1267    while (fgets(line, INILINE_MAX, hini)!=NULL) {
1268        if (line[0] == '#') continue;
1269        if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = 0;
1270        if (line[0] == '[') {
1271            if (strlen(line) >= XMLCONFIG_MAX){
1272                return "XML name too long";
1273            }
1274            sscanf(line, "[%[^]]", xmlname);
1275            strcpy(fileExtension,"png");
1276            strcpy(mimeType,"image/png");
1277        } else if (sscanf(line, "%[^=]=%[^;#]", key, value) == 2
1278               ||  sscanf(line, "%[^=]=\"%[^\"]\"", key, value) == 2) {
1279
1280            if (!strcmp(key, "URI")){
1281                if (strlen(value) >= PATH_MAX){
1282                    return "URI too long";
1283                }
1284                result = _add_tile_config(cmd, mconfig, value, xmlname, 0, MAX_ZOOM, fileExtension, mimeType);
1285                if (result != NULL) return result;
1286            }
1287            if (!strcmp(key, "TYPE")){
1288                if (strlen(value) >= PATH_MAX){
1289                        return "TYPE too long";
1290                }
1291                if (sscanf(value, "%[^ ] %[^;#]", fileExtension, mimeType) != 2) {
1292                        return "TYPE is not correctly parsable";
1293                }
1294            }
1295        }
1296    }
1297    fclose(hini);
1298    return NULL;
1299}
1300
1301static const char *mod_tile_request_timeout_config(cmd_parms *cmd, void *mconfig, const char *request_timeout_string)
1302{
1303    int request_timeout;
1304
1305    if (sscanf(request_timeout_string, "%d", &request_timeout) != 1) {
1306        return "ModTileRequestTimeout needs integer argument";
1307    }
1308
1309    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
1310    scfg->request_timeout = request_timeout;
1311    return NULL;
1312}
1313
1314static const char *mod_tile_request_timeout_missing_config(cmd_parms *cmd, void *mconfig, const char *request_timeout_string)
1315{
1316    int request_timeout;
1317
1318    if (sscanf(request_timeout_string, "%d", &request_timeout) != 1) {
1319        return "ModTileMissingRequestTimeout needs integer argument";
1320    }
1321
1322    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
1323    scfg->request_timeout_priority = request_timeout;
1324    return NULL;
1325}
1326
1327static const char *mod_tile_max_load_old_config(cmd_parms *cmd, void *mconfig, const char *max_load_old_string)
1328{
1329    int max_load_old;
1330
1331    if (sscanf(max_load_old_string, "%d", &max_load_old) != 1) {
1332        return "ModTileMaxLoadOld needs integer argument";
1333    }
1334
1335    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
1336    scfg->max_load_old = max_load_old;
1337    return NULL;
1338}
1339
1340static const char *mod_tile_max_load_missing_config(cmd_parms *cmd, void *mconfig, const char *max_load_missing_string)
1341{
1342    int max_load_missing;
1343
1344    if (sscanf(max_load_missing_string, "%d", &max_load_missing) != 1) {
1345        return "ModTileMaxLoadMissing needs integer argument";
1346    }
1347
1348    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
1349    scfg->max_load_missing = max_load_missing;
1350    return NULL;
1351}
1352
1353static const char *mod_tile_renderd_socket_name_config(cmd_parms *cmd, void *mconfig, const char *renderd_socket_name_string)
1354{
1355    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
1356    strncpy(scfg->renderd_socket_name, renderd_socket_name_string, PATH_MAX-1);
1357    scfg->renderd_socket_name[PATH_MAX-1] = 0;
1358    return NULL;
1359}
1360
1361static const char *mod_tile_tile_dir_config(cmd_parms *cmd, void *mconfig, const char *tile_dir_string)
1362{
1363    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
1364    strncpy(scfg->tile_dir, tile_dir_string, PATH_MAX-1);
1365    scfg->tile_dir[PATH_MAX-1] = 0;
1366    return NULL;
1367}
1368
1369static const char *mod_tile_cache_extended_host_name_config(cmd_parms *cmd, void *mconfig, const char *cache_extended_hostname)
1370{
1371    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
1372    strncpy(scfg->cache_extended_hostname, cache_extended_hostname, PATH_MAX-1);
1373    scfg->cache_extended_hostname[PATH_MAX-1] = 0;
1374
1375    return NULL;
1376}
1377
1378static const char *mod_tile_cache_extended_duration_config(cmd_parms *cmd, void *mconfig, const char *cache_duration_string)
1379{
1380    int cache_duration;
1381    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
1382    if (sscanf(cache_duration_string, "%d", &cache_duration) != 1) {
1383            return "ModTileCacheExtendedDuration needs integer argument";
1384    }
1385    scfg->cache_extended_duration = cache_duration;
1386
1387    return NULL;
1388}
1389
1390static const char *mod_tile_cache_lastmod_factor_config(cmd_parms *cmd, void *mconfig, const char *modified_factor_string)
1391{
1392    float modified_factor;
1393    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config,
1394            &tile_module);
1395    if (sscanf(modified_factor_string, "%f", &modified_factor) != 1) {
1396        return "ModTileCacheLastModifiedFactor needs float argument";
1397    }
1398    scfg->cache_duration_last_modified_factor = modified_factor;
1399    return NULL;
1400}
1401
1402static const char *mod_tile_cache_duration_max_config(cmd_parms *cmd, void *mconfig, const char *cache_duration_string)
1403{
1404    int cache_duration;
1405    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config,
1406            &tile_module);
1407    if (sscanf(cache_duration_string, "%d", &cache_duration) != 1) {
1408        return "ModTileCacheDurationMax needs integer argument";
1409    }
1410    scfg->cache_duration_max = cache_duration;
1411    return NULL;
1412}
1413
1414static const char *mod_tile_cache_duration_dirty_config(cmd_parms *cmd, void *mconfig, const char *cache_duration_string)
1415{
1416    int cache_duration;
1417    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config,
1418            &tile_module);
1419    if (sscanf(cache_duration_string, "%d", &cache_duration) != 1) {
1420        return "ModTileCacheDurationDirty needs integer argument";
1421    }
1422    scfg->cache_duration_dirty = cache_duration;
1423    return NULL;
1424}
1425
1426static const char *mod_tile_cache_duration_minimum_config(cmd_parms *cmd, void *mconfig, const char *cache_duration_string)
1427{
1428    int cache_duration;
1429    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config,
1430            &tile_module);
1431    if (sscanf(cache_duration_string, "%d", &cache_duration) != 1) {
1432        return "ModTileCacheDurationMinimum needs integer argument";
1433    }
1434    scfg->cache_duration_minimum = cache_duration;
1435    return NULL;
1436}
1437
1438static const char *mod_tile_cache_duration_low_config(cmd_parms *cmd, void *mconfig, const char *zoom_level_string, const char *cache_duration_string)
1439{
1440    int zoom_level;
1441    int cache_duration;
1442    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
1443    if (sscanf(zoom_level_string, "%d", &zoom_level) != 1) {
1444            return "ModTileCacheDurationLowZoom needs integer argument";
1445    }
1446    if (sscanf(cache_duration_string, "%d", &cache_duration) != 1) {
1447            return "ModTileCacheDurationLowZoom needs integer argument";
1448    }
1449    scfg->cache_level_low_zoom = zoom_level;
1450    scfg->cache_duration_low_zoom = cache_duration;
1451
1452    return NULL;
1453}
1454static const char *mod_tile_cache_duration_medium_config(cmd_parms *cmd, void *mconfig, const char *zoom_level_string, const char *cache_duration_string)
1455{
1456    int zoom_level;
1457    int cache_duration;
1458    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
1459    if (sscanf(zoom_level_string, "%d", &zoom_level) != 1) {
1460            return "ModTileCacheDurationMediumZoom needs integer argument";
1461    }
1462    if (sscanf(cache_duration_string, "%d", &cache_duration) != 1) {
1463            return "ModTileCacheDurationMediumZoom needs integer argument";
1464    }
1465    scfg->cache_level_medium_zoom = zoom_level;
1466    scfg->cache_duration_medium_zoom = cache_duration;
1467
1468    return NULL;
1469}
1470
1471static const char *mod_tile_enable_stats(cmd_parms *cmd, void *mconfig, int enableStats)
1472{
1473    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
1474    scfg->enableGlobalStats = enableStats;
1475    return NULL;
1476}
1477
1478static const char *mod_tile_enable_throttling(cmd_parms *cmd, void *mconfig, int enableThrottling)
1479{
1480    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
1481    scfg->enableTileThrottling = enableThrottling;
1482    return NULL;
1483}
1484
1485static const char *mod_tile_bulk_mode(cmd_parms *cmd, void *mconfig, int bulkMode)
1486{
1487    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
1488    scfg->bulkMode = bulkMode;
1489    return NULL;
1490}
1491
1492static const char *mod_tile_delaypool_tiles_config(cmd_parms *cmd, void *mconfig, const char *bucketsize_string, const char *topuprate_string)
1493{
1494    int bucketsize;
1495    float topuprate;
1496
1497    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
1498    if (sscanf(bucketsize_string, "%d", &bucketsize) != 1) {
1499            return "ModTileThrottlingTiles needs two numerical arguments, the first one must be integer";
1500    }
1501    if (sscanf(topuprate_string, "%f", &topuprate) != 1) {
1502            return "ModTileThrottlingTiles needs two numerical arguments, the first one must be integer";
1503    }
1504    scfg->delaypoolTileSize = bucketsize;
1505
1506        /*Convert topup rate into microseconds per tile */
1507    scfg->delaypoolTileRate = (long)(1000000.0/topuprate);
1508
1509    return NULL;
1510}
1511
1512static const char *mod_tile_delaypool_render_config(cmd_parms *cmd, void *mconfig, const char *bucketsize_string, const char *topuprate_string)
1513{
1514    int bucketsize;
1515    float topuprate;
1516
1517    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
1518    if (sscanf(bucketsize_string, "%d", &bucketsize) != 1) {
1519            return "ModTileThrottlingRenders needs two numerical arguments, the first one must be integer";
1520    }
1521    if (sscanf(topuprate_string, "%f", &topuprate) != 1) {
1522            return "ModTileThrottlingRenders needs two numerical arguments, the first one must be integer";
1523    }
1524    scfg->delaypoolRenderSize = bucketsize;
1525
1526        /*Convert topup rate into microseconds per tile */
1527    scfg->delaypoolRenderRate = (long)(1000000.0/topuprate);
1528
1529    return NULL;
1530}
1531
1532static void *create_tile_config(apr_pool_t *p, server_rec *s)
1533{
1534    tile_server_conf * scfg = (tile_server_conf *) apr_pcalloc(p, sizeof(tile_server_conf));
1535
1536    scfg->configs = apr_array_make(p, 4, sizeof(tile_config_rec));
1537    scfg->request_timeout = REQUEST_TIMEOUT;
1538    scfg->request_timeout_priority = REQUEST_TIMEOUT;
1539    scfg->max_load_old = MAX_LOAD_OLD;
1540    scfg->max_load_missing = MAX_LOAD_MISSING;
1541    strncpy(scfg->renderd_socket_name, RENDER_SOCKET, PATH_MAX-1);
1542    scfg->renderd_socket_name[PATH_MAX-1] = 0;
1543    strncpy(scfg->tile_dir, HASH_PATH, PATH_MAX-1);
1544    scfg->tile_dir[PATH_MAX-1] = 0;
1545        memset(&(scfg->cache_extended_hostname),0,PATH_MAX);
1546        scfg->cache_extended_duration = 0;
1547    scfg->cache_duration_dirty = 15*60;
1548    scfg->cache_duration_last_modified_factor = 0.0;
1549    scfg->cache_duration_max = 7*24*60*60;
1550    scfg->cache_duration_minimum = 3*60*60;
1551    scfg->cache_duration_low_zoom = 6*24*60*60;
1552    scfg->cache_duration_medium_zoom = 1*24*60*60;
1553    scfg->cache_level_low_zoom = 0;
1554    scfg->cache_level_medium_zoom = 0;
1555    scfg->enableGlobalStats = 1;
1556        scfg->enableTileThrottling = 0;
1557        scfg->delaypoolTileSize = AVAILABLE_TILE_BUCKET_SIZE;
1558        scfg->delaypoolTileRate = RENDER_TOPUP_RATE;
1559        scfg->delaypoolRenderSize = AVAILABLE_RENDER_BUCKET_SIZE;
1560        scfg->delaypoolRenderRate = RENDER_TOPUP_RATE;
1561        scfg->bulkMode = 0;
1562
1563
1564    return scfg;
1565}
1566
1567static void *merge_tile_config(apr_pool_t *p, void *basev, void *overridesv)
1568{
1569    int i;
1570    tile_server_conf * scfg = (tile_server_conf *) apr_pcalloc(p, sizeof(tile_server_conf));
1571    tile_server_conf * scfg_base = (tile_server_conf *) basev;
1572    tile_server_conf * scfg_over = (tile_server_conf *) overridesv;
1573
1574    scfg->configs = apr_array_append(p, scfg_base->configs, scfg_over->configs);
1575    scfg->request_timeout = scfg_over->request_timeout;
1576        scfg->request_timeout_priority = scfg_over->request_timeout_priority;
1577    scfg->max_load_old = scfg_over->max_load_old;
1578    scfg->max_load_missing = scfg_over->max_load_missing;
1579    strncpy(scfg->renderd_socket_name, scfg_over->renderd_socket_name, PATH_MAX-1);
1580    scfg->renderd_socket_name[PATH_MAX-1] = 0;
1581    strncpy(scfg->tile_dir, scfg_over->tile_dir, PATH_MAX-1);
1582    scfg->tile_dir[PATH_MAX-1] = 0;
1583    strncpy(scfg->cache_extended_hostname, scfg_over->cache_extended_hostname, PATH_MAX-1);
1584    scfg->cache_extended_hostname[PATH_MAX-1] = 0;
1585    scfg->cache_extended_duration = scfg_over->cache_extended_duration;
1586    scfg->cache_duration_dirty = scfg_over->cache_duration_dirty;
1587    scfg->cache_duration_last_modified_factor = scfg_over->cache_duration_last_modified_factor;
1588    scfg->cache_duration_max = scfg_over->cache_duration_max;
1589    scfg->cache_duration_minimum = scfg_over->cache_duration_minimum;
1590    scfg->cache_duration_low_zoom = scfg_over->cache_duration_low_zoom;
1591    scfg->cache_duration_medium_zoom = scfg_over->cache_duration_medium_zoom;
1592    scfg->cache_level_low_zoom = scfg_over->cache_level_low_zoom;
1593    scfg->cache_level_medium_zoom = scfg_over->cache_level_medium_zoom;
1594    scfg->enableGlobalStats = scfg_over->enableGlobalStats;
1595        scfg->enableTileThrottling = scfg_over->enableTileThrottling;
1596        scfg->delaypoolTileSize = scfg_over->delaypoolTileSize;
1597        scfg->delaypoolTileRate = scfg_over->delaypoolTileRate;
1598        scfg->delaypoolRenderSize = scfg_over->delaypoolRenderSize;
1599        scfg->delaypoolRenderRate = scfg_over->delaypoolRenderRate;
1600        scfg->bulkMode = scfg_over->bulkMode;
1601
1602    //Construct a table of minimum cache times per zoom level
1603    for (i = 0; i <= MAX_ZOOM; i++) {
1604        if (i <= scfg->cache_level_low_zoom) {
1605            scfg->mincachetime[i] = scfg->cache_duration_low_zoom;
1606        } else if (i <= scfg->cache_level_medium_zoom) {
1607            scfg->mincachetime[i] = scfg->cache_duration_medium_zoom;
1608        } else {
1609            scfg->mincachetime[i] = scfg->cache_duration_minimum;
1610        }
1611    }
1612
1613    return scfg;
1614}
1615
1616static const command_rec tile_cmds[] =
1617{
1618    AP_INIT_TAKE1(
1619        "LoadTileConfigFile",            /* directive name */
1620        load_tile_config,                /* config action routine */
1621        NULL,                            /* argument to include in call */
1622        OR_OPTIONS,                      /* where available */
1623        "load an entire renderd config file"  /* directive description */
1624    ),
1625    AP_INIT_TAKE2(
1626        "AddTileConfig",                 /* directive name */
1627        add_tile_config,                 /* config action routine */
1628        NULL,                            /* argument to include in call */
1629        OR_OPTIONS,                      /* where available */
1630        "path and name of renderd config to use"  /* directive description */
1631    ),
1632    AP_INIT_TAKE3(
1633            "AddTileMimeConfig",                 /* directive name */
1634            add_tile_mime_config,                 /* config action routine */
1635            NULL,                            /* argument to include in call */
1636            OR_OPTIONS,                      /* where available */
1637            "path, name and file extension of renderd config to use"  /* directive description */
1638        ),
1639    AP_INIT_TAKE1(
1640        "ModTileRequestTimeout",         /* directive name */
1641        mod_tile_request_timeout_config, /* config action routine */
1642        NULL,                            /* argument to include in call */
1643        OR_OPTIONS,                      /* where available */
1644        "Set timeout in seconds on mod_tile requests"  /* directive description */
1645    ),
1646    AP_INIT_TAKE1(
1647        "ModTileMissingRequestTimeout",         /* directive name */
1648        mod_tile_request_timeout_missing_config, /* config action routine */
1649        NULL,                            /* argument to include in call */
1650        OR_OPTIONS,                      /* where available */
1651        "Set timeout in seconds on missing mod_tile requests"  /* directive description */
1652    ),
1653    AP_INIT_TAKE1(
1654        "ModTileMaxLoadOld",             /* directive name */
1655        mod_tile_max_load_old_config,    /* config action routine */
1656        NULL,                            /* argument to include in call */
1657        OR_OPTIONS,                      /* where available */
1658        "Set max load for rendering old tiles"  /* directive description */
1659    ),
1660    AP_INIT_TAKE1(
1661        "ModTileMaxLoadMissing",         /* directive name */
1662        mod_tile_max_load_missing_config, /* config action routine */
1663        NULL,                            /* argument to include in call */
1664        OR_OPTIONS,                      /* where available */
1665        "Set max load for rendering missing tiles"  /* directive description */
1666    ),
1667    AP_INIT_TAKE1(
1668        "ModTileRenderdSocketName",      /* directive name */
1669        mod_tile_renderd_socket_name_config, /* config action routine */
1670        NULL,                            /* argument to include in call */
1671        OR_OPTIONS,                      /* where available */
1672        "Set name of unix domain socket for connecting to rendering daemon"  /* directive description */
1673    ),
1674    AP_INIT_TAKE1(
1675        "ModTileTileDir",                /* directive name */
1676        mod_tile_tile_dir_config,        /* config action routine */
1677        NULL,                            /* argument to include in call */
1678        OR_OPTIONS,                      /* where available */
1679        "Set name of tile cache directory"  /* directive description */
1680    ),
1681        AP_INIT_TAKE1(
1682        "ModTileCacheExtendedHostName",                /* directive name */
1683        mod_tile_cache_extended_host_name_config,        /* config action routine */
1684        NULL,                            /* argument to include in call */
1685        OR_OPTIONS,                      /* where available */
1686        "set hostname for extended period caching"  /* directive description */
1687    ),
1688        AP_INIT_TAKE1(
1689        "ModTileCacheExtendedDuration",                /* directive name */
1690        mod_tile_cache_extended_duration_config,        /* config action routine */
1691        NULL,                            /* argument to include in call */
1692        OR_OPTIONS,                      /* where available */
1693        "set length of extended period caching"  /* directive description */
1694    ),
1695    AP_INIT_TAKE1(
1696        "ModTileCacheDurationMax",                /* directive name */
1697        mod_tile_cache_duration_max_config,        /* config action routine */
1698        NULL,                            /* argument to include in call */
1699        OR_OPTIONS,                      /* where available */
1700        "Set the maximum cache expiry in seconds"  /* directive description */
1701    ),
1702    AP_INIT_TAKE1(
1703        "ModTileCacheDurationDirty",                    /* directive name */
1704        mod_tile_cache_duration_dirty_config,           /* config action routine */
1705        NULL,                                           /* argument to include in call */
1706        OR_OPTIONS,                                     /* where available */
1707        "Set the cache expiry for serving dirty tiles"  /* directive description */
1708    ),
1709    AP_INIT_TAKE1(
1710        "ModTileCacheDurationMinimum",          /* directive name */
1711        mod_tile_cache_duration_minimum_config, /* config action routine */
1712        NULL,                                   /* argument to include in call */
1713        OR_OPTIONS,                             /* where available */
1714        "Set the minimum cache expiry"          /* directive description */
1715    ),
1716    AP_INIT_TAKE1(
1717        "ModTileCacheLastModifiedFactor",       /* directive name */
1718        mod_tile_cache_lastmod_factor_config,   /* config action routine */
1719        NULL,                                   /* argument to include in call */
1720        OR_OPTIONS,                             /* where available */
1721        "Set the factor by which the last modified determins cache expiry" /* directive description */
1722    ),
1723    AP_INIT_TAKE2(
1724        "ModTileCacheDurationLowZoom",       /* directive name */
1725        mod_tile_cache_duration_low_config,                 /* config action routine */
1726        NULL,                            /* argument to include in call */
1727        OR_OPTIONS,                      /* where available */
1728        "Set the minimum cache duration and zoom level for low zoom tiles"  /* directive description */
1729    ),
1730    AP_INIT_TAKE2(
1731        "ModTileCacheDurationMediumZoom",       /* directive name */
1732        mod_tile_cache_duration_medium_config,                 /* config action routine */
1733        NULL,                            /* argument to include in call */
1734        OR_OPTIONS,                      /* where available */
1735        "Set the minimum cache duration and zoom level for medium zoom tiles"  /* directive description */
1736    ),
1737    AP_INIT_FLAG(
1738        "ModTileEnableStats",       /* directive name */
1739        mod_tile_enable_stats,                 /* config action routine */
1740        NULL,                            /* argument to include in call */
1741        OR_OPTIONS,                      /* where available */
1742        "On Off - enable of keeping stats about what mod_tile is serving"  /* directive description */
1743    ),
1744        AP_INIT_FLAG(
1745        "ModTileEnableTileThrottling",       /* directive name */
1746        mod_tile_enable_throttling,                 /* config action routine */
1747        NULL,                            /* argument to include in call */
1748        OR_OPTIONS,                      /* where available */
1749        "On Off - enable of throttling of IPs that excessively download tiles such as scrapers"  /* directive description */
1750    ),
1751        AP_INIT_TAKE2(
1752        "ModTileThrottlingTiles",       /* directive name */
1753        mod_tile_delaypool_tiles_config,                 /* config action routine */
1754        NULL,                            /* argument to include in call */
1755        OR_OPTIONS,                      /* where available */
1756        "Set the initial bucket size (number of tiles) and top up rate (tiles per second) for throttling tile request per IP"  /* directive description */
1757    ),
1758        AP_INIT_TAKE2(
1759        "ModTileThrottlingRenders",       /* directive name */
1760        mod_tile_delaypool_render_config,                 /* config action routine */
1761        NULL,                            /* argument to include in call */
1762        OR_OPTIONS,                      /* where available */
1763        "Set the initial bucket size (number of tiles) and top up rate (tiles per second) for throttling tile request per IP"  /* directive description */
1764    ),
1765        AP_INIT_FLAG(
1766        "ModTileBulkMode",       /* directive name */
1767        mod_tile_bulk_mode,                 /* config action routine */
1768        NULL,                            /* argument to include in call */
1769        OR_OPTIONS,                      /* where available */
1770        "On Off - make all requests to renderd with bulk render priority, never mark tiles dirty"  /* directive description */
1771    ),
1772    {NULL}
1773};
1774
1775module AP_MODULE_DECLARE_DATA tile_module =
1776{
1777    STANDARD20_MODULE_STUFF,
1778    NULL,                                /* dir config creater */
1779    NULL,                                /* dir merger --- default is to override */
1780    create_tile_config,                  /* server config */
1781    merge_tile_config,                   /* merge server config */
1782    tile_cmds,                           /* command apr_table_t */
1783    register_hooks                       /* register hooks */
1784};
1785
Note: See TracBrowser for help on using the repository browser.