mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2024-12-30 17:56:57 +00:00
185 lines
6.0 KiB
C
185 lines
6.0 KiB
C
|
/* 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);
|
||
|
}
|