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

Last change on this file since 15609 was 15609, checked in by jochen, 10 years ago
  • Added Apache config options for MAX_LOAD_OLD, MAX_LOAD_MISSING and REQUEST_TIMEOUT, defined in C code are only default values now
  • Preparation for adding minzoom and maxzoom to config
File size: 24.1 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
43#include "gen_tile.h"
44#include "protocol.h"
45#include "render_config.h"
46#include "store.h"
47#include "dir_utils.h"
48
49#define INILINE_MAX 256
50typedef struct {
51    char xmlname[XMLCONFIG_MAX];
52    char baseuri[PATH_MAX];
53    int minzoom;
54    int maxzoom;
55} tile_config_rec;
56
57typedef struct {
58    apr_array_header_t *configs;
59    int request_timeout;
60    int max_load_old;
61    int max_load_missing;
62} tile_server_conf;
63
64enum tileState { tileMissing, tileOld, tileCurrent };
65
66static int error_message(request_rec *r, const char *format, ...)
67                 __attribute__ ((format (printf, 2, 3)));
68
69static int error_message(request_rec *r, const char *format, ...)
70{
71    va_list ap;
72    va_start(ap, format);
73    int len;
74    char *msg;
75
76    len = vasprintf(&msg, format, ap);
77
78    if (msg) {
79        //ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "%s", msg);
80        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "%s", msg);
81        r->content_type = "text/plain";
82        if (!r->header_only)
83            ap_rputs(msg, r);
84        free(msg);
85    }
86
87    return OK;
88}
89
90
91int socket_init(request_rec *r)
92{
93    const char *spath = RENDER_SOCKET;
94    int fd;
95    struct sockaddr_un addr;
96
97    //fprintf(stderr, "Starting rendering client\n");
98
99    fd = socket(PF_UNIX, SOCK_STREAM, 0);
100    if (fd < 0) {
101        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "failed to create unix socket");
102        return FD_INVALID;
103    }
104
105    bzero(&addr, sizeof(addr));
106    addr.sun_family = AF_UNIX;
107    strncpy(addr.sun_path, spath, sizeof(addr.sun_path));
108
109    if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
110        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "socket connect failed for: %s", spath);
111        close(fd);
112        return FD_INVALID;
113    }
114    return fd;
115}
116
117static pthread_key_t key;
118static pthread_once_t key_once = PTHREAD_ONCE_INIT;
119
120static void pfd_free(void *ptr)
121{
122    int *pfd = ptr;
123
124    if (*pfd != FD_INVALID)
125        close(*pfd);
126    free(pfd);
127}
128
129static void make_key(void)
130{
131    (void) pthread_key_create(&key, pfd_free);
132}
133
134int request_tile(request_rec *r, struct protocol *cmd, int dirtyOnly)
135{
136    int *pfd;
137    int ret = 0;
138    int retry = 1;
139    struct protocol resp;
140
141    ap_conf_vector_t *sconf = r->server->module_config;
142    tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
143
144    (void) pthread_once(&key_once, make_key);
145    if ((pfd = pthread_getspecific(key)) == NULL) {
146        pfd = malloc(sizeof(*pfd));
147        if (!pfd)
148            return 0;
149        *pfd = FD_INVALID;
150        (void) pthread_setspecific(key, pfd);
151    }
152
153    if (*pfd == FD_INVALID) {
154        *pfd = socket_init(r);
155
156        if (*pfd == FD_INVALID) {
157            //fprintf(stderr, "Failed to connect to renderer\n");
158            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Failed to connected to renderer");
159            return 0;
160        } else {
161            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Connected to renderer");
162        }
163    }
164
165    // cmd has already been partial filled, fill in the rest
166    cmd->ver = PROTO_VER;
167    cmd->cmd = dirtyOnly ? cmdDirty : cmdRender;
168
169    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Requesting xml(%s) z(%d) x(%d) y(%d)", cmd->xmlname, cmd->z, cmd->x, cmd->y);
170    do {
171        ret = send(*pfd, cmd, sizeof(struct protocol), 0);
172
173        if (ret == sizeof(struct protocol))
174            break;
175
176        if (errno != EPIPE)
177            return 0;
178
179         close(*pfd);
180         *pfd = socket_init(r);
181         if (*pfd == FD_INVALID)
182             return 0;
183         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Reconnected to renderer");
184    } while (retry--);
185
186    if (!dirtyOnly) {
187        struct timeval tv = {scfg->request_timeout, 0 };
188        fd_set rx;
189        int s;
190
191        while (1) {
192            FD_ZERO(&rx);
193            FD_SET(*pfd, &rx);
194            s = select((*pfd)+1, &rx, NULL, NULL, &tv);
195            if (s == 1) {
196                bzero(&resp, sizeof(struct protocol));
197                ret = recv(*pfd, &resp, sizeof(struct protocol), 0);
198                if (ret != sizeof(struct protocol)) {
199                    if (errno == EPIPE) {
200                        close(*pfd);
201                        *pfd = FD_INVALID;
202                    }
203                    //perror("recv error");
204                    break;
205                }
206 
207                if (cmd->x == resp.x && cmd->y == resp.y && cmd->z == resp.z && !strcmp(cmd->xmlname, resp.xmlname)) {
208                    if (resp.cmd == cmdDone)
209                        return 1;
210                    else
211                        return 0;
212                } else {
213                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 
214                       "Response does not match request: xml(%s,%s) z(%d,%d) x(%d,%d) y(%d,%d)", cmd->xmlname, 
215                       resp.xmlname, cmd->z, resp.z, cmd->x, resp.x, cmd->y, resp.y);                   
216                }
217            } else if (s == 0) {
218                break;
219            } else {
220                if (errno == EPIPE) {
221                    close(*pfd);
222                    *pfd = FD_INVALID;
223                    break;
224                }
225            }
226        }
227    }
228    return 0;
229}
230
231static apr_time_t getPlanetTime(request_rec *r)
232{
233    static apr_time_t last_check;
234    static apr_time_t planet_timestamp;
235    static pthread_mutex_t planet_lock = PTHREAD_MUTEX_INITIALIZER;
236    apr_time_t now = r->request_time;
237    struct apr_finfo_t s;
238
239    pthread_mutex_lock(&planet_lock);
240    // Only check for updates periodically
241    if (now < last_check + apr_time_from_sec(300)) {
242        pthread_mutex_unlock(&planet_lock);
243        return planet_timestamp;
244    }
245
246    last_check = now;
247    if (apr_stat(&s, PLANET_TIMESTAMP, APR_FINFO_MIN, r->pool) != APR_SUCCESS) {
248        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Planet timestamp file " PLANET_TIMESTAMP " is missing");
249        // Make something up
250        planet_timestamp = now - apr_time_from_sec(3 * 24 * 60 * 60);
251    } else {
252        if (s.mtime != planet_timestamp) {
253            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Planet file updated");
254            planet_timestamp = s.mtime;
255        }
256    }
257    pthread_mutex_unlock(&planet_lock);
258    return planet_timestamp;
259}
260
261static enum tileState tile_state_once(request_rec *r)
262{
263    apr_status_t rv;
264    apr_finfo_t *finfo = &r->finfo;
265
266    if (!(finfo->valid & APR_FINFO_MTIME)) {
267        rv = apr_stat(finfo, r->filename, APR_FINFO_MIN, r->pool);
268        if (rv != APR_SUCCESS)
269            return tileMissing;
270    }
271
272    if (finfo->mtime < getPlanetTime(r))
273        return tileOld;
274
275    return tileCurrent;
276}
277
278static enum tileState tile_state(request_rec *r, struct protocol *cmd)
279{
280    enum tileState state = tile_state_once(r);
281#ifdef METATILEFALLBACK
282    if (state == tileMissing) {
283
284        // Try fallback to plain PNG
285        char path[PATH_MAX];
286        xyz_to_path(path, sizeof(path), cmd->xmlname, cmd->x, cmd->y, cmd->z);
287        r->filename = apr_pstrdup(r->pool, path);
288        state = tile_state_once(r);
289        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "png fallback %d/%d/%d",x,y,z);
290
291        if (state == tileMissing) {
292            // PNG not available either, if it gets rendered, it'll now be a .meta
293            xyz_to_meta(path, sizeof(path), cmd->xmlname, cmd->x, cmd->y, cmd->z);
294            r->filename = apr_pstrdup(r->pool, path);
295        }
296    }
297#endif
298    return state;
299}
300
301static void add_expiry(request_rec *r, struct protocol * cmd)
302{
303    apr_time_t expires, holdoff, planetTimestamp;
304    apr_table_t *t = r->headers_out;
305    enum tileState state = tile_state(r, cmd);
306    char *timestr;
307
308    /* Append expiry headers ... */
309
310    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "expires(%s), uri(%s), filename(%s), path_info(%s)\n",
311                  r->handler, r->uri, r->filename, r->path_info);
312
313    // We estimate an expiry based on when the next planet dump is (or was) due
314    // If we are past this time already then round up to request time
315    // Then add a randomisation of up to 3 hours
316    planetTimestamp = (state == tileCurrent) ? (getPlanetTime(r) + apr_time_from_sec(PLANET_INTERVAL)) : getPlanetTime(r);
317    holdoff = apr_time_from_sec(3 * 60 * 60) * (rand() / (RAND_MAX + 1.0));
318    expires = MAX(r->request_time, planetTimestamp) + holdoff;
319
320    apr_table_mergen(t, "Cache-Control",
321                     apr_psprintf(r->pool, "max-age=%" APR_TIME_T_FMT,
322                     apr_time_sec(expires - r->request_time)));
323    timestr = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
324    apr_rfc822_date(timestr, expires);
325    apr_table_setn(t, "Expires", timestr);
326}
327
328
329double get_load_avg(request_rec *r)
330{
331    double loadavg[1];
332    int n = getloadavg(loadavg, 1);
333
334    if (n < 1)
335        return 1000;
336    else
337        return loadavg[0];
338}
339
340static int tile_handler_dirty(request_rec *r)
341{
342    if(strcmp(r->handler, "tile_dirty"))
343        return DECLINED;
344
345    struct protocol * cmd = (struct protocol *)ap_get_module_config(r->request_config, &tile_module);
346    if (cmd == NULL)
347        return DECLINED;
348
349    request_tile(r, cmd, 1);
350    return error_message(r, "Tile submitted for rendering\n");
351}
352
353static int tile_storage_hook(request_rec *r)
354{
355//    char abs_path[PATH_MAX];
356    int avg;
357    enum tileState state;
358
359    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "tile_storage_hook: handler(%s), uri(%s), filename(%s), path_info(%s)",
360                  r->handler, r->uri, r->filename, r->path_info);
361
362    if (!r->handler)
363        return DECLINED;
364
365    // Any status request is OK
366    if (!strcmp(r->handler, "tile_status"))
367        return OK;
368
369    if (strcmp(r->handler, "tile_serve") && strcmp(r->handler, "tile_dirty"))
370        return DECLINED;
371
372    struct protocol * cmd = (struct protocol *)ap_get_module_config(r->request_config, &tile_module);
373    if (cmd == NULL)
374        return DECLINED;
375/*
376should already be done
377    // Generate the tile filename
378#ifdef METATILE
379    xyz_to_meta(abs_path, sizeof(abs_path), cmd->xmlname, cmd->x, cmd->y, cmd->z);
380#else
381    xyz_to_path(abs_path, sizeof(abs_path), cmd->xmlname, cmd->x, cmd->y, cmd->z);
382#endif
383    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "abs_path(%s)", abs_path);
384    r->filename = apr_pstrdup(r->pool, abs_path);
385*/
386    avg = get_load_avg(r);
387    state = tile_state(r, cmd);
388
389    ap_conf_vector_t *sconf = r->server->module_config;
390    tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
391
392    switch (state) {
393        case tileCurrent:
394            return OK;
395            break;
396        case tileOld:
397            if (avg > scfg->max_load_old) {
398               // Too much load to render it now, mark dirty but return old tile
399               request_tile(r, cmd, 1);
400               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);
401               return OK;
402            }
403            break;
404        case tileMissing:
405            if (avg > scfg->max_load_missing) {
406               request_tile(r, cmd, 1);
407               ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Load larger max_load_missing (%d). Return HTTP_NOT_FOUND.", scfg->max_load_missing);
408               return HTTP_NOT_FOUND;
409            }
410            break;
411    }
412
413    if (request_tile(r, cmd, 0)) {
414        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Update file info abs_path(%s)", r->filename);
415        // Need to update fileinfo for new rendered tile
416        apr_stat(&r->finfo, r->filename, APR_FINFO_MIN, r->pool);
417        return OK;
418    }
419
420    if (state == tileOld)
421        return OK;
422
423    return HTTP_NOT_FOUND;
424}
425
426static int tile_handler_status(request_rec *r)
427{
428    enum tileState state;
429    char time_str[APR_CTIME_LEN];
430
431    if(strcmp(r->handler, "tile_status"))
432        return DECLINED;
433
434    struct protocol * cmd = (struct protocol *)ap_get_module_config(r->request_config, &tile_module);
435    if (cmd == NULL){
436        sleep(CLIENT_PENALTY);
437        return HTTP_NOT_FOUND;
438    }
439
440    state = tile_state(r, cmd);
441    if (state == tileMissing)
442        return error_message(r, "Unable to find a tile at %s\n", r->filename);
443    apr_ctime(time_str, r->finfo.mtime);
444
445    return error_message(r, "Tile is %s. Last rendered at %s\n", (state == tileOld) ? "due to be rendered" : "clean", time_str);
446}
447
448static int tile_handler_serve(request_rec *r)
449{
450    const int tile_max = MAX_SIZE;
451    unsigned char *buf;
452    int len;
453    apr_status_t errstatus;
454
455    if(strcmp(r->handler, "tile_serve"))
456        return DECLINED;
457
458    struct protocol * cmd = (struct protocol *)ap_get_module_config(r->request_config, &tile_module);
459    if (cmd == NULL){
460        sleep(CLIENT_PENALTY);
461        return HTTP_NOT_FOUND;
462    }
463
464    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "tile_handler_serve: xml(%s) z(%d) x(%d) y(%d)", cmd->xmlname, cmd->z, cmd->x, cmd->y);
465
466    // FIXME: It is a waste to do the malloc + read if we are fulfilling a HEAD or returning a 304.
467    buf = malloc(tile_max);
468    if (!buf)
469        return HTTP_INTERNAL_SERVER_ERROR;
470
471    len = tile_read(cmd->xmlname, cmd->x, cmd->y, cmd->z, buf, tile_max);
472    if (len > 0) {
473#if 0
474        // Set default Last-Modified and Etag headers
475        ap_update_mtime(r, r->finfo.mtime);
476        ap_set_last_modified(r);
477        ap_set_etag(r);
478#else
479        // Use MD5 hash as only cache attribute.
480        // If a tile is re-rendered and produces the same output
481        // then we can continue to use the previous cached copy
482        char *md5 = ap_md5_binary(r->pool, buf, len);
483        apr_table_setn(r->headers_out, "ETag",
484                        apr_psprintf(r->pool, "\"%s\"", md5));
485#endif
486        ap_set_content_type(r, "image/png");
487        ap_set_content_length(r, len);
488        add_expiry(r, cmd);
489        if ((errstatus = ap_meets_conditions(r)) != OK) {
490            free(buf);
491            return errstatus;
492        } else {
493            ap_rwrite(buf, len, r);
494            free(buf);
495            return OK;
496        }
497    }
498    free(buf);
499    //ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "len = %d", len);
500
501    return DECLINED;
502}
503
504static int tile_translate(request_rec *r)
505{
506    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "tile_translate: uri(%s)", r->uri);
507
508    int i,n,limit,oob;
509    char option[11];
510
511    ap_conf_vector_t *sconf = r->server->module_config;
512    tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
513
514    tile_config_rec *tile_configs = (tile_config_rec *) scfg->configs->elts;
515    for (i = 0; i < scfg->configs->nelts; ++i) {
516        tile_config_rec *tile_config = &tile_configs[i];
517   
518        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "tile_translate: baseuri(%s) name(%s)", tile_config->baseuri, tile_config->xmlname);
519
520        if (!strncmp(tile_config->baseuri, r->uri, strlen(tile_config->baseuri))) {
521
522            struct protocol * cmd = (struct protocol *) apr_pcalloc(r->pool, sizeof(struct protocol));
523            bzero(cmd, sizeof(struct protocol));
524
525            n = sscanf(r->uri+strlen(tile_config->baseuri), "%d/%d/%d.png/%10s", &(cmd->z), &(cmd->x), &(cmd->y), option);
526            if (n < 3) return DECLINED;
527
528            oob = (cmd->z < 0 || cmd->z > MAX_ZOOM);
529            if (!oob) {
530                 // valid x/y for tiles are 0 ... 2^zoom-1
531                 limit = (1 << cmd->z) - 1;
532                 oob =  (cmd->x < 0 || cmd->x > limit || cmd->y < 0 || cmd->y > limit);
533            }
534
535            if (oob) {
536                sleep(CLIENT_PENALTY);
537                return HTTP_NOT_FOUND;
538            }
539
540            strcpy(cmd->xmlname, tile_config->xmlname);
541
542            // Store a copy for later
543            ap_set_module_config(r->request_config, &tile_module, cmd);
544
545            // Generate the tile filename?
546            char abs_path[PATH_MAX];
547#ifdef METATILE
548            xyz_to_meta(abs_path, sizeof(abs_path), cmd->xmlname, cmd->x, cmd->y, cmd->z);
549#else
550            xyz_to_path(abs_path, sizeof(abs_path), cmd->xmlname, cmd->x, cmd->y, cmd->z);
551#endif
552            r->filename = apr_pstrdup(r->pool, abs_path);
553
554            if (n == 4) {
555                if (!strcmp(option, "status")) r->handler = "tile_status";
556                else if (!strcmp(option, "dirty")) r->handler = "tile_dirty";
557                else return DECLINED;
558            } else {
559                r->handler = "tile_serve";
560            }
561
562            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "tile_translate: op(%s) xml(%s) z(%d) x(%d) y(%d)", r->handler , cmd->xmlname, cmd->z, cmd->x, cmd->y);
563
564            return OK;
565        }
566    }   
567    return DECLINED;
568}
569
570static void register_hooks(__attribute__((unused)) apr_pool_t *p)
571{
572    ap_hook_handler(tile_handler_serve, NULL, NULL, APR_HOOK_MIDDLE);
573    ap_hook_handler(tile_handler_dirty, NULL, NULL, APR_HOOK_MIDDLE);
574    ap_hook_handler(tile_handler_status, NULL, NULL, APR_HOOK_MIDDLE);
575    ap_hook_translate_name(tile_translate, NULL, NULL, APR_HOOK_MIDDLE);
576    ap_hook_map_to_storage(tile_storage_hook, NULL, NULL, APR_HOOK_FIRST);
577}
578
579static const char *_add_tile_config(cmd_parms *cmd, void *mconfig, const char *baseuri, const char *name, int minzoom, int maxzoom)
580{
581    if (strlen(name) == 0) {
582        return "ConfigName value must not be null";
583    }
584
585    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
586    tile_config_rec *tilecfg = apr_array_push(scfg->configs);   
587
588    strncpy(tilecfg->baseuri, baseuri, PATH_MAX-1);
589    tilecfg->baseuri[PATH_MAX-1] = 0;
590    strncpy(tilecfg->xmlname, name, XMLCONFIG_MAX-1);
591    tilecfg->xmlname[XMLCONFIG_MAX-1] = 0;
592    tilecfg->minzoom = minzoom;
593    tilecfg->maxzoom = maxzoom;
594   
595    return NULL;
596}
597
598static const char *add_tile_config(cmd_parms *cmd, void *mconfig, const char *baseuri, const char *name)
599{
600    return _add_tile_config(cmd, mconfig, baseuri, name, 0, MAX_ZOOM);
601}
602
603static const char *load_tile_config(cmd_parms *cmd, void *mconfig, const char *conffile)
604{
605    FILE * hini ;
606    char filename[PATH_MAX];
607    char xmlname[XMLCONFIG_MAX];
608    char line[INILINE_MAX];
609    char key[INILINE_MAX];
610    char value[INILINE_MAX];
611    const char * result;
612
613    if (strlen(conffile) == 0) {
614        strcpy(filename, RENDERD_CONFIG);
615    } else {
616        strcpy(filename, conffile);
617    }
618
619    // Load the config
620    if ((hini=fopen(filename, "r"))==NULL) {
621        return "Unable to open config file";
622    }
623
624    while (fgets(line, INILINE_MAX, hini)!=NULL) {
625        if (line[0] == '#') continue;
626        if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = 0;
627        if (line[0] == '[') {
628            if (strlen(line) >= XMLCONFIG_MAX){
629                return "XML name too long";
630            }
631            sscanf(line, "[%[^]]", xmlname);
632        } else if (sscanf(line, "%[^=]=%[^;#]", key, value) == 2
633               ||  sscanf(line, "%[^=]=\"%[^\"]\"", key, value) == 2) {
634
635            if (!strcmp(key, "URI")){
636                if (strlen(value) >= PATH_MAX){
637                    return "URI too long";
638                }
639                result = add_tile_config(cmd, mconfig, value, xmlname);
640                if (result != NULL) return result;
641            }
642        }
643    }
644    fclose(hini);
645    return NULL;
646}
647
648static const char *mod_tile_request_timeout_config(cmd_parms *cmd, void *mconfig, const char *request_timeout_string)
649{
650    int request_timeout;
651
652    if (sscanf(request_timeout_string, "%d", &request_timeout) != 1) {
653        return "ModTileRequestTimeout needs integer argument";
654    }
655
656    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
657    scfg->request_timeout = request_timeout;
658    return NULL;
659}
660
661static const char *mod_tile_max_load_old_config(cmd_parms *cmd, void *mconfig, const char *max_load_old_string)
662{
663    int max_load_old;
664
665    if (sscanf(max_load_old_string, "%d", &max_load_old) != 1) {
666        return "ModTileMaxLoadOld needs integer argument";
667    }
668
669    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
670    scfg->max_load_old = max_load_old;
671    return NULL;
672}
673
674static const char *mod_tile_max_load_missing_config(cmd_parms *cmd, void *mconfig, const char *max_load_missing_string)
675{
676    int max_load_missing;
677
678    if (sscanf(max_load_missing_string, "%d", &max_load_missing) != 1) {
679        return "ModTileMaxLoadMissing needs integer argument";
680    }
681
682    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
683    scfg->max_load_missing = max_load_missing;
684    return NULL;
685}
686
687static void *create_tile_config(apr_pool_t *p, server_rec *s)
688{
689    tile_server_conf * scfg = (tile_server_conf *) apr_pcalloc(p, sizeof(tile_server_conf));
690
691    scfg->configs = apr_array_make(p, 4, sizeof(tile_config_rec));
692    scfg->request_timeout = REQUEST_TIMEOUT;
693    scfg->max_load_old = MAX_LOAD_OLD;
694    scfg->max_load_missing = MAX_LOAD_MISSING;
695
696    return scfg;
697}
698
699static void *merge_tile_config(apr_pool_t *p, void *basev, void *overridesv)
700{
701    tile_server_conf * scfg = (tile_server_conf *) apr_pcalloc(p, sizeof(tile_server_conf));
702    tile_server_conf * scfg_base = (tile_server_conf *) basev;
703    tile_server_conf * scfg_over = (tile_server_conf *) overridesv;
704
705    scfg->configs = apr_array_append(p, scfg_base->configs, scfg_over->configs);
706    scfg->request_timeout = scfg_over->request_timeout;
707    scfg->max_load_old = scfg_over->max_load_old;
708    scfg->max_load_missing = scfg_over->max_load_missing;
709
710    return scfg;
711}
712
713static const command_rec tile_cmds[] =
714{
715    AP_INIT_TAKE1(
716        "LoadTileConfigFile",            /* directive name */
717        load_tile_config,                /* config action routine */
718        NULL,                            /* argument to include in call */
719        OR_OPTIONS,                      /* where available */
720        "load an entire renderd config file"  /* directive description */
721    ),
722    AP_INIT_TAKE2(
723        "AddTileConfig",                 /* directive name */
724        add_tile_config,                 /* config action routine */
725        NULL,                            /* argument to include in call */
726        OR_OPTIONS,                      /* where available */
727        "path and name of renderd config to use"  /* directive description */
728    ),
729    AP_INIT_TAKE1(
730        "ModTileRequestTimeout",         /* directive name */
731        mod_tile_request_timeout_config, /* config action routine */
732        NULL,                            /* argument to include in call */
733        OR_OPTIONS,                      /* where available */
734        "Set timeout in seconds on mod_tile requests"  /* directive description */
735    ),
736    AP_INIT_TAKE1(
737        "ModTileMaxLoadOld",             /* directive name */
738        mod_tile_max_load_old_config,    /* config action routine */
739        NULL,                            /* argument to include in call */
740        OR_OPTIONS,                      /* where available */
741        "Set max load for rendering old tiles"  /* directive description */
742    ),
743    AP_INIT_TAKE1(
744        "ModTileMaxLoadMissing",         /* directive name */
745        mod_tile_max_load_missing_config, /* config action routine */
746        NULL,                            /* argument to include in call */
747        OR_OPTIONS,                      /* where available */
748        "Set max load for rendering missing tiles"  /* directive description */
749    ),
750    {NULL}
751};
752
753module AP_MODULE_DECLARE_DATA tile_module =
754{
755    STANDARD20_MODULE_STUFF,
756    NULL,                                /* dir config creater */
757    NULL,                                /* dir merger --- default is to override */
758    create_tile_config,                  /* server config */
759    merge_tile_config,                   /* merge server config */
760    tile_cmds,                           /* command apr_table_t */
761    register_hooks                       /* register hooks */
762};
763
Note: See TracBrowser for help on using the repository browser.