2 * Copyright © 2018 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
25 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <netinet/ip.h>
30 #define ALTOS_MAP_PORT 16717
32 #define MISSING 0x7fffffff
34 #define ALTOS_MAP_PROTOCOL_VERSION "1.0.0"
37 reason_string(int code)
49 return "Request Timeout";
56 write_status(int status)
58 printf("Status: %d %s\n", status, reason_string(status));
62 write_type(char * type)
64 printf("Content-Type: %s\n", type);
68 fail(int status, char *format, ...)
73 write_type("text/html");
76 printf("<head><title>Map Fetch Failure</title></head>\n");
87 getenv_copy(const char *name)
89 const char *value = getenv(name);
98 parse_double(char *string)
103 value = strtod(string, &end);
105 fail(400, "Invalid double %s", string);
110 parse_int(char *string)
115 value = strtol(string, &end, 10);
117 fail(400, "Invalid int %s", string);
118 if (value < INT_MIN || INT_MAX < value)
119 fail(400, "Int value out of range %ld", value);
125 connect_service(void)
127 struct sockaddr_in altos_map_addr = {
128 .sin_family = AF_INET,
129 .sin_port = htons(ALTOS_MAP_PORT),
131 .s_addr = htonl(INADDR_LOOPBACK),
135 int s = socket(AF_INET, SOCK_STREAM, 0);
140 if (connect (s, (const struct sockaddr *) &altos_map_addr, sizeof (altos_map_addr)) < 0) {
148 int main(int argc, char **argv)
151 char *query_string = getenv_copy("QUERY_STRING");
153 if (query_string == NULL)
154 fail(400, "%s", "Missing query string");
156 char *remote_addr = getenv_copy("REMOTE_ADDR");
158 if (remote_addr == NULL)
159 fail(400, "%s", "Missing remote address");
161 double lon = MISSING;
162 double lat = MISSING;
164 char *version = NULL;
166 char *query, *query_save = NULL;
167 char *query_start = query_string;
169 while ((query = strtok_r(query_start, "&", &query_save)) != NULL) {
172 char *token, *token_save = NULL;
173 char *token_start = query;
178 while ((token = strtok_r(token_start, "=", &token_save)) != NULL) {
182 else if (value == NULL)
189 if (!strcmp(name, "lon"))
190 lon = parse_double(value);
191 else if (!strcmp(name, "lat"))
192 lat = parse_double(value);
193 else if (!strcmp(name, "zoom"))
194 zoom = parse_int(value);
195 else if (!strcmp(name, "version"))
198 fail(400, "Extra query param \"%s\"", query);
202 if (version != NULL) {
203 printf("Content-Type: text/plain\n");
205 printf("%s\n", ALTOS_MAP_PROTOCOL_VERSION);
209 fail(400, "Missing longitude");
211 fail(400, "Missing latitude");
213 fail(400, "Missing zoom");
218 while (tries < 10 && s < 0) {
219 s = connect_service();
227 fail(408, "Cannot connect AltOS map daemon");
229 FILE *sf = fdopen(s, "r+");
232 fail(400, "allocation failure");
234 json_t *request = json_pack("{s:f s:f s:i s:s}", "lat", lat, "lon", lon, "zoom", zoom, "remote_addr", remote_addr);
237 fail(400, "Cannot create JSON request");
239 if (json_dumpf(request, sf, 0) < 0)
240 fail(400, "Cannot write JSON request");
245 json_t *reply = json_loadf(sf, 0, &error);
248 fail(400, "Cannot read JSON reply");
252 if (json_unpack(reply, "{s:i}", "status", &status) < 0)
253 fail(400, "No status returned");
256 fail(status, "Bad cache status");
258 char *filename, *content_type;
260 if (json_unpack(reply, "{s:s s:s}", "filename", &filename, "content_type", &content_type) < 0)
261 fail(400, "JSON reply parse failure");
263 int fd = open(filename, O_RDONLY);
266 fail(400, "%s: %s", filename, strerror(errno));
270 if (fstat(fd, &statb) < 0)
271 fail(400, "%s: %s", filename, strerror(errno));
273 printf("Content-Type: %s\n", content_type);
274 printf("Content-Length: %lu\n", (unsigned long) statb.st_size);
281 while ((bytes_read = read(fd, buf, sizeof (buf))) > 0) {
282 ssize_t total_write = 0;
283 while (total_write < bytes_read) {
284 ssize_t bytes_write = write(1, buf + total_write, bytes_read - total_write);
285 if (bytes_write <= 0)
287 total_write += bytes_write;