zone.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /* libanode: the Anode C reference implementation
  2. * Copyright (C) 2009-2010 Adam Ierymenko <[email protected]>
  3. *
  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 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>. */
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <time.h>
  19. #include <sys/time.h>
  20. #include <sys/types.h>
  21. #include <sys/stat.h>
  22. #include "impl/types.h"
  23. #include "impl/misc.h"
  24. #include "impl/dictionary.h"
  25. #include "impl/environment.h"
  26. #include "impl/http_client.h"
  27. #include "anode.h"
  28. static const char *_MONTHS[12] = { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" };
  29. static const char *_DAYS_OF_WEEK[7] = { "Sun","Mon","Tue","Wed","Thu","Fri","Sat" };
  30. static inline unsigned long get_file_time_for_http(const char *path,char *buf,unsigned int len)
  31. {
  32. struct stat st;
  33. struct tm *gmt;
  34. if (!stat(path,(struct stat *)&st)) {
  35. gmt = gmtime(&st.st_mtime);
  36. if (gmt) {
  37. snprintf(buf,len,"%s, %d %s %d %d:%d:%d GMT",
  38. _DAYS_OF_WEEK[gmt->tm_wday],
  39. gmt->tm_mday,
  40. _MONTHS[gmt->tm_mon],
  41. (1900 + gmt->tm_year),
  42. gmt->tm_hour,
  43. gmt->tm_min,
  44. gmt->tm_sec);
  45. buf[len - 1] = (char)0;
  46. return (unsigned long)st.st_size;
  47. }
  48. }
  49. return 0;
  50. }
  51. struct AnodeZoneLookupJob
  52. {
  53. char cached_zone_file[2048];
  54. struct AnodeDictionary *zone_dict;
  55. AnodeZone zone;
  56. void *ptr;
  57. void (*zone_lookup_handler)(void *,const AnodeZone *,AnodeZoneFile *);
  58. int had_cached_zone;
  59. };
  60. static void AnodeZone_lookup_http_handler(struct AnodeHttpClient *client)
  61. {
  62. char *data_tmp;
  63. struct AnodeZoneLookupJob *job = (struct AnodeZoneLookupJob *)client->ptr[0];
  64. FILE *zf;
  65. if ((client->response.code == 200)&&(client->response.data_length > 0)) {
  66. zf = fopen(job->cached_zone_file,"w");
  67. if (zf) {
  68. fwrite(client->response.data,1,client->response.data_length,zf);
  69. fclose(zf);
  70. }
  71. data_tmp = (char *)malloc(client->response.data_length + 1);
  72. Anode_memcpy((void *)data_tmp,client->response.data,client->response.data_length);
  73. data_tmp[client->response.data_length] = (char)0;
  74. AnodeDictionary_clear(job->zone_dict);
  75. AnodeDictionary_read(
  76. job->zone_dict,
  77. data_tmp,
  78. "\r\n",
  79. "=",
  80. ";",
  81. '\\',
  82. 1,1);
  83. free((void *)data_tmp);
  84. job->zone_lookup_handler(job->ptr,&job->zone,(AnodeZoneFile *)job->zone_dict);
  85. } else if (job->had_cached_zone)
  86. job->zone_lookup_handler(job->ptr,&job->zone,(AnodeZoneFile *)job->zone_dict);
  87. else {
  88. AnodeDictionary_destroy(job->zone_dict);
  89. free((void *)job->zone_dict);
  90. job->zone_lookup_handler(job->ptr,&job->zone,(AnodeZoneFile *)0);
  91. }
  92. free((void *)job);
  93. AnodeHttpClient_free(client);
  94. }
  95. void AnodeZone_lookup(
  96. AnodeTransportEngine *transport,
  97. const AnodeZone *zone,
  98. void *ptr,
  99. void (*zone_lookup_handler)(void *,const AnodeZone *,AnodeZone *))
  100. {
  101. char cached_zones_folder[2048];
  102. char cached_zone_file[2048];
  103. char if_modified_since[256];
  104. unsigned long file_size;
  105. struct AnodeZoneLookupJob *job;
  106. struct AnodeHttpClient *client;
  107. char *file_data;
  108. FILE *zf;
  109. if (Anode_get_cache_sub("zones",cached_zones_folder,sizeof(cached_zones_folder))) {
  110. 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]);
  111. cached_zone_file[sizeof(cached_zone_file)-1] = (char)0;
  112. job = (struct AnodeZoneLookupJob *)malloc(sizeof(struct AnodeZoneLookupJob));
  113. Anode_str_copy(job->cached_zone_file,cached_zone_file,sizeof(job->cached_zone_file));
  114. job->zone_dict = (struct AnodeDictionary *)malloc(sizeof(struct AnodeDictionary));
  115. AnodeDictionary_init(job->zone_dict,0);
  116. job->zone.bits[0] = zone->bits[0];
  117. job->zone.bits[1] = zone->bits[1];
  118. job->zone.bits[2] = zone->bits[2];
  119. job->zone.bits[3] = zone->bits[3];
  120. job->ptr = ptr;
  121. job->zone_lookup_handler = zone_lookup_handler;
  122. job->had_cached_zone = 0;
  123. client = AnodeHttpClient_new(transport);
  124. Anode_str_copy(client->uri.scheme,"http",sizeof(client->uri.scheme));
  125. 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]);
  126. client->uri.host[sizeof(client->uri.host)-1] = (char)0;
  127. Anode_str_copy(client->uri.path,"/z",sizeof(client->uri.path));
  128. client->handler = &AnodeZone_lookup_http_handler;
  129. client->ptr[0] = job;
  130. if ((file_size = get_file_time_for_http(cached_zone_file,if_modified_since,sizeof(if_modified_since)))) {
  131. zf = fopen(cached_zone_file,"r");
  132. if (zf) {
  133. AnodeDictionary_put(&client->headers,"If-Modified-Since",if_modified_since);
  134. file_data = (char *)malloc(file_size + 1);
  135. if (fread((void *)file_data,1,file_size,zf)) {
  136. file_data[file_size] = (char)0;
  137. AnodeDictionary_read(
  138. job->zone_dict,
  139. file_data,
  140. "\r\n",
  141. "=",
  142. ";",
  143. '\\',
  144. 1,1);
  145. job->had_cached_zone = 1;
  146. }
  147. free((void *)file_data);
  148. fclose(zf);
  149. }
  150. }
  151. AnodeHttpClient_send(client);
  152. } else zone_lookup_handler(ptr,zone,(AnodeZone *)0);
  153. }
  154. const char *AnodeZoneFile_get(AnodeZoneFile *zone,const char *key)
  155. {
  156. return AnodeDictionary_get((struct AnodeDictionary *)zone,key);
  157. }
  158. void AnodeZoneFile_free(AnodeZoneFile *zone)
  159. {
  160. AnodeDictionary_destroy((struct AnodeDictionary *)zone);
  161. free((void *)zone);
  162. }