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

Last change on this file since 15799 was 15799, checked in by jochen, 10 years ago

Renderd uses iniparser3.0b ini file parser now which is included
Made renderd more configurable at runtime: socketname, num_threads and the mapnik settings plugins_dir, font_dir, and font_dir_recurse are now available through renderd.conf

There should be only one incompatible change: the [Default] section in the config is now in all lowercase "[default]" because the parser lib gives section and key names back in lowercase

File size: 25.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    char renderd_socket_name[PATH_MAX];
63} tile_server_conf;
64
65enum tileState { tileMissing, tileOld, tileCurrent };
66
67static int error_message(request_rec *r, const char *format, ...)
68                 __attribute__ ((format (printf, 2, 3)));
69
70static int error_message(request_rec *r, const char *format, ...)
71{
72    va_list ap;
73    va_start(ap, format);
74    int len;
75    char *msg;
76
77    len = vasprintf(&msg, format, ap);
78
79    if (msg) {
80        //ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "%s", msg);
81        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "%s", msg);
82        r->content_type = "text/plain";
83        if (!r->header_only)
84            ap_rputs(msg, r);
85        free(msg);
86    }
87
88    return OK;
89}
90
91
92int socket_init(request_rec *r)
93{
94    ap_conf_vector_t *sconf = r->server->module_config;
95    tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
96
97    int fd;
98    struct sockaddr_un addr;
99
100    fd = socket(PF_UNIX, SOCK_STREAM, 0);
101    if (fd < 0) {
102        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "failed to create unix socket");
103        return FD_INVALID;
104    }
105
106    bzero(&addr, sizeof(addr));
107    addr.sun_family = AF_UNIX;
108    strncpy(addr.sun_path, scfg->renderd_socket_name, sizeof(addr.sun_path));
109
110    if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
111        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "socket connect failed for: %s", scfg->renderd_socket_name);
112        close(fd);
113        return FD_INVALID;
114    }
115    return fd;
116}
117
118static pthread_key_t key;
119static pthread_once_t key_once = PTHREAD_ONCE_INIT;
120
121static void pfd_free(void *ptr)
122{
123    int *pfd = ptr;
124
125    if (*pfd != FD_INVALID)
126        close(*pfd);
127    free(pfd);
128}
129
130static void make_key(void)
131{
132    (void) pthread_key_create(&key, pfd_free);
133}
134
135int request_tile(request_rec *r, struct protocol *cmd, int dirtyOnly)
136{
137    int *pfd;
138    int ret = 0;
139    int retry = 1;
140    struct protocol resp;
141
142    ap_conf_vector_t *sconf = r->server->module_config;
143    tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
144
145    (void) pthread_once(&key_once, make_key);
146    if ((pfd = pthread_getspecific(key)) == NULL) {
147        pfd = malloc(sizeof(*pfd));
148        if (!pfd)
149            return 0;
150        *pfd = FD_INVALID;
151        (void) pthread_setspecific(key, pfd);
152    }
153
154    if (*pfd == FD_INVALID) {
155        *pfd = socket_init(r);
156
157        if (*pfd == FD_INVALID) {
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 const char *mod_tile_renderd_socket_name_config(cmd_parms *cmd, void *mconfig, const char *renderd_socket_name_string)
688{
689    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
690    strncpy(scfg->renderd_socket_name, renderd_socket_name_string, PATH_MAX-1);
691    scfg->renderd_socket_name[PATH_MAX-1] = 0;
692    return NULL;
693}
694
695static void *create_tile_config(apr_pool_t *p, server_rec *s)
696{
697    tile_server_conf * scfg = (tile_server_conf *) apr_pcalloc(p, sizeof(tile_server_conf));
698
699    scfg->configs = apr_array_make(p, 4, sizeof(tile_config_rec));
700    scfg->request_timeout = REQUEST_TIMEOUT;
701    scfg->max_load_old = MAX_LOAD_OLD;
702    scfg->max_load_missing = MAX_LOAD_MISSING;
703
704    return scfg;
705}
706
707static void *merge_tile_config(apr_pool_t *p, void *basev, void *overridesv)
708{
709    tile_server_conf * scfg = (tile_server_conf *) apr_pcalloc(p, sizeof(tile_server_conf));
710    tile_server_conf * scfg_base = (tile_server_conf *) basev;
711    tile_server_conf * scfg_over = (tile_server_conf *) overridesv;
712
713    scfg->configs = apr_array_append(p, scfg_base->configs, scfg_over->configs);
714    scfg->request_timeout = scfg_over->request_timeout;
715    scfg->max_load_old = scfg_over->max_load_old;
716    scfg->max_load_missing = scfg_over->max_load_missing;
717    strncpy(scfg->renderd_socket_name, scfg_over->renderd_socket_name, PATH_MAX-1);
718    scfg->renderd_socket_name[PATH_MAX-1] = 0;
719
720    return scfg;
721}
722
723static const command_rec tile_cmds[] =
724{
725    AP_INIT_TAKE1(
726        "LoadTileConfigFile",            /* directive name */
727        load_tile_config,                /* config action routine */
728        NULL,                            /* argument to include in call */
729        OR_OPTIONS,                      /* where available */
730        "load an entire renderd config file"  /* directive description */
731    ),
732    AP_INIT_TAKE2(
733        "AddTileConfig",                 /* directive name */
734        add_tile_config,                 /* config action routine */
735        NULL,                            /* argument to include in call */
736        OR_OPTIONS,                      /* where available */
737        "path and name of renderd config to use"  /* directive description */
738    ),
739    AP_INIT_TAKE1(
740        "ModTileRequestTimeout",         /* directive name */
741        mod_tile_request_timeout_config, /* config action routine */
742        NULL,                            /* argument to include in call */
743        OR_OPTIONS,                      /* where available */
744        "Set timeout in seconds on mod_tile requests"  /* directive description */
745    ),
746    AP_INIT_TAKE1(
747        "ModTileMaxLoadOld",             /* directive name */
748        mod_tile_max_load_old_config,    /* config action routine */
749        NULL,                            /* argument to include in call */
750        OR_OPTIONS,                      /* where available */
751        "Set max load for rendering old tiles"  /* directive description */
752    ),
753    AP_INIT_TAKE1(
754        "ModTileMaxLoadMissing",         /* directive name */
755        mod_tile_max_load_missing_config, /* config action routine */
756        NULL,                            /* argument to include in call */
757        OR_OPTIONS,                      /* where available */
758        "Set max load for rendering missing tiles"  /* directive description */
759    ),
760    AP_INIT_TAKE1(
761        "ModTileRenderdSocketName",      /* directive name */
762        mod_tile_renderd_socket_name_config, /* config action routine */
763        NULL,                            /* argument to include in call */
764        OR_OPTIONS,                      /* where available */
765        "Set name of unix domain socket for connecting to rendering daemon"  /* directive description */
766    ),
767    {NULL}
768};
769
770module AP_MODULE_DECLARE_DATA tile_module =
771{
772    STANDARD20_MODULE_STUFF,
773    NULL,                                /* dir config creater */
774    NULL,                                /* dir merger --- default is to override */
775    create_tile_config,                  /* server config */
776    merge_tile_config,                   /* merge server config */
777    tile_cmds,                           /* command apr_table_t */
778    register_hooks                       /* register hooks */
779};
780
Note: See TracBrowser for help on using the repository browser.