You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
184 lines
6.0 KiB
184 lines
6.0 KiB
/* libanode: the Anode C reference implementation |
|
* Copyright (C) 2009-2010 Adam Ierymenko <adam.ierymenko@gmail.com> |
|
* |
|
* This program is free software: you can redistribute it and/or modify |
|
* it under the terms of the GNU General Public License as published by |
|
* the Free Software Foundation, either version 3 of the License, or |
|
* (at your option) any later version. |
|
* |
|
* This program is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
* GNU General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU General Public License |
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
|
|
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <time.h> |
|
#include <sys/time.h> |
|
#include <sys/types.h> |
|
#include <sys/stat.h> |
|
#include "impl/types.h" |
|
#include "impl/misc.h" |
|
#include "impl/dictionary.h" |
|
#include "impl/environment.h" |
|
#include "impl/http_client.h" |
|
#include "anode.h" |
|
|
|
static const char *_MONTHS[12] = { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" }; |
|
static const char *_DAYS_OF_WEEK[7] = { "Sun","Mon","Tue","Wed","Thu","Fri","Sat" }; |
|
static inline unsigned long get_file_time_for_http(const char *path,char *buf,unsigned int len) |
|
{ |
|
struct stat st; |
|
struct tm *gmt; |
|
|
|
if (!stat(path,(struct stat *)&st)) { |
|
gmt = gmtime(&st.st_mtime); |
|
if (gmt) { |
|
snprintf(buf,len,"%s, %d %s %d %d:%d:%d GMT", |
|
_DAYS_OF_WEEK[gmt->tm_wday], |
|
gmt->tm_mday, |
|
_MONTHS[gmt->tm_mon], |
|
(1900 + gmt->tm_year), |
|
gmt->tm_hour, |
|
gmt->tm_min, |
|
gmt->tm_sec); |
|
buf[len - 1] = (char)0; |
|
return (unsigned long)st.st_size; |
|
} |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
struct AnodeZoneLookupJob |
|
{ |
|
char cached_zone_file[2048]; |
|
struct AnodeDictionary *zone_dict; |
|
AnodeZone zone; |
|
void *ptr; |
|
void (*zone_lookup_handler)(void *,const AnodeZone *,AnodeZoneFile *); |
|
int had_cached_zone; |
|
}; |
|
|
|
static void AnodeZone_lookup_http_handler(struct AnodeHttpClient *client) |
|
{ |
|
char *data_tmp; |
|
struct AnodeZoneLookupJob *job = (struct AnodeZoneLookupJob *)client->ptr[0]; |
|
FILE *zf; |
|
|
|
if ((client->response.code == 200)&&(client->response.data_length > 0)) { |
|
zf = fopen(job->cached_zone_file,"w"); |
|
if (zf) { |
|
fwrite(client->response.data,1,client->response.data_length,zf); |
|
fclose(zf); |
|
} |
|
|
|
data_tmp = (char *)malloc(client->response.data_length + 1); |
|
Anode_memcpy((void *)data_tmp,client->response.data,client->response.data_length); |
|
data_tmp[client->response.data_length] = (char)0; |
|
|
|
AnodeDictionary_clear(job->zone_dict); |
|
AnodeDictionary_read( |
|
job->zone_dict, |
|
data_tmp, |
|
"\r\n", |
|
"=", |
|
";", |
|
'\\', |
|
1,1); |
|
|
|
free((void *)data_tmp); |
|
|
|
job->zone_lookup_handler(job->ptr,&job->zone,(AnodeZoneFile *)job->zone_dict); |
|
} else if (job->had_cached_zone) |
|
job->zone_lookup_handler(job->ptr,&job->zone,(AnodeZoneFile *)job->zone_dict); |
|
else { |
|
AnodeDictionary_destroy(job->zone_dict); |
|
free((void *)job->zone_dict); |
|
job->zone_lookup_handler(job->ptr,&job->zone,(AnodeZoneFile *)0); |
|
} |
|
|
|
free((void *)job); |
|
AnodeHttpClient_free(client); |
|
} |
|
|
|
void AnodeZone_lookup( |
|
AnodeTransportEngine *transport, |
|
const AnodeZone *zone, |
|
void *ptr, |
|
void (*zone_lookup_handler)(void *,const AnodeZone *,AnodeZone *)) |
|
{ |
|
char cached_zones_folder[2048]; |
|
char cached_zone_file[2048]; |
|
char if_modified_since[256]; |
|
unsigned long file_size; |
|
struct AnodeZoneLookupJob *job; |
|
struct AnodeHttpClient *client; |
|
char *file_data; |
|
FILE *zf; |
|
|
|
if (Anode_get_cache_sub("zones",cached_zones_folder,sizeof(cached_zones_folder))) { |
|
snprintf(cached_zone_file,sizeof(cached_zone_file),"%s%c%.2x%.2x%.2x%.2x.z",cached_zones_folder,ANODE_PATH_SEPARATOR,(unsigned int)zone->bits[0],(unsigned int)zone->bits[1],(unsigned int)zone->bits[2],(unsigned int)zone->bits[3]); |
|
cached_zone_file[sizeof(cached_zone_file)-1] = (char)0; |
|
|
|
job = (struct AnodeZoneLookupJob *)malloc(sizeof(struct AnodeZoneLookupJob)); |
|
Anode_str_copy(job->cached_zone_file,cached_zone_file,sizeof(job->cached_zone_file)); |
|
job->zone_dict = (struct AnodeDictionary *)malloc(sizeof(struct AnodeDictionary)); |
|
AnodeDictionary_init(job->zone_dict,0); |
|
job->zone.bits[0] = zone->bits[0]; |
|
job->zone.bits[1] = zone->bits[1]; |
|
job->zone.bits[2] = zone->bits[2]; |
|
job->zone.bits[3] = zone->bits[3]; |
|
job->ptr = ptr; |
|
job->zone_lookup_handler = zone_lookup_handler; |
|
job->had_cached_zone = 0; |
|
|
|
client = AnodeHttpClient_new(transport); |
|
|
|
Anode_str_copy(client->uri.scheme,"http",sizeof(client->uri.scheme)); |
|
snprintf(client->uri.host,sizeof(client->uri.host),"a--%.2x%.2x%.2x%.2x.net",(unsigned int)zone->bits[0],(unsigned int)zone->bits[1],(unsigned int)zone->bits[2],(unsigned int)zone->bits[3]); |
|
client->uri.host[sizeof(client->uri.host)-1] = (char)0; |
|
Anode_str_copy(client->uri.path,"/z",sizeof(client->uri.path)); |
|
|
|
client->handler = &AnodeZone_lookup_http_handler; |
|
client->ptr[0] = job; |
|
|
|
if ((file_size = get_file_time_for_http(cached_zone_file,if_modified_since,sizeof(if_modified_since)))) { |
|
zf = fopen(cached_zone_file,"r"); |
|
if (zf) { |
|
AnodeDictionary_put(&client->headers,"If-Modified-Since",if_modified_since); |
|
file_data = (char *)malloc(file_size + 1); |
|
if (fread((void *)file_data,1,file_size,zf)) { |
|
file_data[file_size] = (char)0; |
|
AnodeDictionary_read( |
|
job->zone_dict, |
|
file_data, |
|
"\r\n", |
|
"=", |
|
";", |
|
'\\', |
|
1,1); |
|
job->had_cached_zone = 1; |
|
} |
|
free((void *)file_data); |
|
fclose(zf); |
|
} |
|
} |
|
|
|
AnodeHttpClient_send(client); |
|
} else zone_lookup_handler(ptr,zone,(AnodeZone *)0); |
|
} |
|
|
|
const char *AnodeZoneFile_get(AnodeZoneFile *zone,const char *key) |
|
{ |
|
return AnodeDictionary_get((struct AnodeDictionary *)zone,key); |
|
} |
|
|
|
void AnodeZoneFile_free(AnodeZoneFile *zone) |
|
{ |
|
AnodeDictionary_destroy((struct AnodeDictionary *)zone); |
|
free((void *)zone); |
|
}
|
|
|