hostcache.c
上传用户:zm130024
上传日期:2007-01-04
资源大小:432k
文件大小:10k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (c) 1997, 1998, 1999
  3.  *      Inferno Nettverk A/S, Norway.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. The above copyright notice, this list of conditions and the following
  9.  *    disclaimer must appear in all copies of the software, derivative works
  10.  *    or modified versions, and any portions thereof, aswell as in all
  11.  *    supporting documentation.
  12.  * 2. All advertising materials mentioning features or use of this software
  13.  *    must display the following acknowledgement:
  14.  *      This product includes software developed by
  15.  *      Inferno Nettverk A/S, Norway.
  16.  * 3. The name of the author may not be used to endorse or promote products
  17.  *    derived from this software without specific prior written permission.
  18.  *
  19.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  20.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  21.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  22.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  23.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  24.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  28.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29.  *
  30.  * Inferno Nettverk A/S requests users of this software to return to
  31.  *
  32.  *  Software Distribution Coordinator  or  sdc@inet.no
  33.  *  Inferno Nettverk A/S
  34.  *  Oslo Research Park
  35.  *  Gaustadal閑n 21
  36.  *  N-0349 Oslo
  37.  *  Norway
  38.  *
  39.  * any improvements or extensions that they make and grant Inferno Nettverk A/S
  40.  * the rights to redistribute these changes.
  41.  *
  42.  */
  43. #include "common.h"
  44. static const char rcsid[] =
  45. "$Id: hostcache.c,v 1.15 1999/12/22 09:29:24 karls Exp $";
  46. __BEGIN_DECLS
  47. #if SOCKS_SERVER
  48. /* we want the real thing. */
  49. #undef gethostbyname
  50. #undef gethostbyaddr
  51. static struct hostent *
  52. hostentupdate __P((struct hostent *old, const struct hostent *new));
  53. /*
  54.  * Updates "old" with the contents of "new", freeing any
  55.  * resources currently used by "old".
  56.  * Returns:
  57.  * On success: "old", updated.
  58.  * On failure: NULL.
  59. */
  60. static int
  61. hosthash __P((const char *name, size_t size));
  62. /*
  63.  * Calculates a hashvalue for "name" and returns it's value.
  64.  * Size of hashtable is given by "size".
  65. */
  66. static int
  67. addrhash __P((in_addr_t addr, size_t size));
  68. /*
  69.  * Calculates a hashvalue for "addr" and returns it's value.
  70.  * Size of hashtable is given by "size".
  71. */
  72. #endif /* SOCKS_SERVER */
  73. static char **
  74. listrealloc __P((char ***old, const char ***new, int length));
  75. /*
  76.  * Reallocates "old" and copies in the contents of "new".
  77.  * The last element of both "old" and "new" must be NULL.
  78.  * If "length" is less than 0, each element is assumed to
  79.  * be NUL terminated, otherwise "length" gives the total length
  80.  * of every string.
  81.  * Returns:
  82.  * On success: "**old", with the contents of "new".
  83.  * On failure: NULL.
  84. */
  85. __END_DECLS
  86. struct hostent *
  87. hostentdup(hostent)
  88. const struct hostent *hostent;
  89. {
  90. static struct hostent dupedinit;
  91. struct hostent *duped;
  92. if ((duped = (struct hostent *)malloc(sizeof(*duped))) == NULL)
  93. return NULL;
  94. *duped = dupedinit;
  95. if ((duped->h_name = strdup(hostent->h_name)) == NULL) {
  96. hostentfree(duped);
  97. return NULL;
  98. }
  99. if (listrealloc(&duped->h_aliases, (const char ***)&hostent->h_aliases, -1)
  100. == NULL) {
  101. hostentfree(duped);
  102. return NULL;
  103. }
  104. duped->h_addrtype = hostent->h_addrtype;
  105. duped->h_length = hostent->h_length;
  106. if (listrealloc(&duped->h_addr_list, (const char ***)&hostent->h_addr_list,
  107. hostent->h_length) == NULL) {
  108. hostentfree(duped);
  109. return NULL;
  110. }
  111. return duped;
  112. }
  113. void
  114. hostentfree(hostent)
  115. struct hostent *hostent;
  116. {
  117. char **p;
  118. if (hostent == NULL)
  119. return;
  120. free(hostent->h_name);
  121. hostent->h_name = NULL;
  122. if (hostent->h_aliases != NULL)
  123. for (p = hostent->h_aliases; *p != NULL; ++p)
  124. free(*p);
  125. free(hostent->h_aliases);
  126. hostent->h_aliases = NULL;
  127. if (hostent->h_addr_list != NULL)
  128. for (p = hostent->h_addr_list; *p != NULL; ++p)
  129. free(*p);
  130. free(hostent->h_addr_list);
  131. hostent->h_addr_list = NULL;
  132. free(hostent);
  133. }
  134. static char **
  135. listrealloc(old, new, length)
  136. char ***old;
  137. const char ***new;
  138. int length;
  139. {
  140. int i, oldi, newi;
  141. /* entries we can reallocate, starting at 0. */
  142. oldi = 0;
  143. if (*old != NULL)
  144. while ((*old)[oldi] != NULL)
  145. ++oldi;
  146. newi = 0;
  147. while ((*new)[newi] != NULL)
  148. ++newi;
  149. for (i = newi; i < oldi; ++i)
  150. free((*old)[i]);
  151. if ((*old = (char **)realloc(*old, sizeof(**new) * (newi + 1))) == NULL)
  152. return NULL;
  153. for (newi = 0; (*new)[newi] != NULL; ++newi, --oldi) {
  154. if (((*old)[newi] = (char *)realloc(oldi > 0 ? (*old)[newi] : NULL,
  155. length < 0 ? (strlen((*new)[newi]) + 1) : length)) == NULL)
  156. return NULL;
  157. if (length < 0)
  158. strcpy((*old)[newi], (*new)[newi]);
  159. else
  160. memcpy((*old)[newi], (*new)[newi], (size_t)length);
  161. }
  162. (*old)[newi] = NULL;
  163. return *old;
  164. }
  165. #if SOCKS_SERVER
  166. struct hostent *
  167. cgethostbyname(name)
  168. const char *name;
  169. {
  170. const char *function = "cgethostbyname()";
  171. static struct {
  172. unsigned allocated:1;
  173. char host[MAXHOSTNAMELEN];
  174. time_t written;
  175. struct hostent hostent;
  176. } table[SOCKD_HOSTCACHE], *freehost;
  177. static unsigned int hit, miss, count;
  178. const time_t timenow = time(NULL);
  179. const int hashi = hosthash(name, ELEMENTS(table));
  180. size_t i;
  181. struct hostent *hostent;
  182. #if SOCKD_CACHESTAT
  183. if (++count % SOCKD_CACHESTAT == 0)
  184. slog(LOG_INFO, "%s: hit: %d, miss: %d", function, hit, miss);
  185. #endif /* SOCKD_CACHESTAT */
  186. for (i = hashi, freehost = NULL; i < ELEMENTS(table); ++i) {
  187. if (!table[i].allocated) {
  188. if (freehost == NULL)
  189. freehost = &table[i];
  190. continue;
  191. }
  192. if (strcasecmp(table[i].host, name) == 0) {
  193. if (difftime(timenow, table[i].written) >= SOCKD_CACHETIMEOUT) {
  194. freehost = &table[i];
  195. break;
  196. }
  197. ++hit;
  198. return &table[i].hostent;
  199. }
  200. }
  201. ++miss;
  202. if ((hostent = gethostbyname(name)) == NULL)
  203. return NULL;
  204. if (freehost == NULL)
  205. for (i = hashi, freehost = &table[i]; i < ELEMENTS(table); ++i) {
  206. if (difftime(timenow, table[i].written) >= SOCKD_CACHETIMEOUT) {
  207. freehost = &table[i];
  208. break;
  209. }
  210. if (freehost->written < table[i].written) {
  211. freehost = &table[i]; /* oldest. */
  212. break;
  213. }
  214. }
  215. if (hostentupdate(&freehost->hostent, hostent) == NULL) {
  216. freehost->allocated = 0;
  217. slog(LOG_WARNING, "%s: %s", NOMEM, function);
  218. return NULL;
  219. }
  220. SASSERTX(strlen(name) < sizeof(freehost->host));
  221. strcpy(freehost->host, name);
  222. time(&freehost->written);
  223. freehost->allocated = 1;
  224. return &freehost->hostent;
  225. }
  226. struct hostent *
  227. cgethostbyaddr(addr, len, type)
  228. const char *addr;
  229. int len;
  230. int type;
  231. {
  232. const char *function = "cgethostbyaddr()";
  233. static struct {
  234. unsigned allocated:1;
  235. in_addr_t addr;
  236. time_t written;
  237. struct hostent hostent;
  238. } table[SOCKD_ADDRESSCACHE], *freehost;
  239. static unsigned long int hit, miss, count;
  240. const time_t timenow = time(NULL);
  241. /* LINTED pointer casts may be troublesome */
  242. const int hashi
  243. = addrhash(((const struct in_addr *)addr)->s_addr, ELEMENTS(table));
  244. size_t i;
  245. struct hostent *hostent;
  246. #if SOCKD_CACHESTAT
  247. if (++count % SOCKD_CACHESTAT == 0)
  248. slog(LOG_INFO, "%s: hit: %d, miss: %d", function, hit, miss);
  249. #endif /* SOCKD_CACHESTAT */
  250. for (i = hashi, freehost = NULL; i < ELEMENTS(table); ++i) {
  251. if (!table[i].allocated) {
  252. if (freehost == NULL)
  253. freehost = &table[i];
  254. continue;
  255. }
  256. /* LINTED pointer casts may be troublesome */
  257. if (table[i].addr == ((const struct in_addr *)addr)->s_addr) {
  258. if (difftime(timenow, table[i].written) >= SOCKD_CACHETIMEOUT) {
  259. freehost = &table[i];
  260. break;
  261. }
  262. ++hit;
  263. return &table[i].hostent;
  264. }
  265. }
  266. ++miss;
  267. if ((hostent = gethostbyaddr(addr, len, type)) == NULL)
  268. return NULL;
  269. if (freehost == NULL)
  270. for (i = hashi, freehost = &table[i]; i < ELEMENTS(table); ++i) {
  271. if (difftime(timenow, table[i].written) >= SOCKD_CACHETIMEOUT) {
  272. freehost = &table[i];
  273. break;
  274. }
  275. if (freehost->written < table[i].written) {
  276. freehost = &table[i]; /* oldest. */
  277. break;
  278. }
  279. }
  280. if (hostentupdate(&freehost->hostent, hostent) == NULL) {
  281. freehost->allocated = 0;
  282. slog(LOG_WARNING, "%s: %s", NOMEM, function);
  283. return NULL;
  284. }
  285. /* LINTED pointer casts may be troublesome */
  286. freehost->addr = ((const struct in_addr *)addr)->s_addr;
  287. time(&freehost->written);
  288. freehost->allocated = 1;
  289. return &freehost->hostent;
  290. }
  291. static int
  292. hosthash(name, size)
  293. const char *name;
  294. size_t size;
  295. {
  296. char *end;
  297. unsigned int value;
  298. /* end at second dot. */
  299. if ((end = strchr(name, '.')) != NULL)
  300. end = strchr(end, '.');
  301. if (end == NULL)
  302. end = strchr(name, NUL);
  303. SASSERTX(name <= end);
  304. value = 0;
  305. while (name != end)
  306. value = (value << 5) + *name++; /* MAW - DS&A: Horner's rule. */
  307. return value % size;
  308. }
  309. static int
  310. addrhash(addr, size)
  311. in_addr_t addr;
  312. size_t size;
  313. {
  314. return addr % size;
  315. }
  316. static struct hostent *
  317. hostentupdate(old, new)
  318. struct hostent *old;
  319. const struct hostent *new;
  320. {
  321. if ((old->h_name = (char *)realloc(old->h_name, strlen(new->h_name) + 1))
  322. == NULL)
  323. return NULL;
  324. strcpy(old->h_name, new->h_name);
  325. if (listrealloc(&old->h_aliases, (const char ***)&new->h_aliases, -1)
  326. == NULL)
  327. return NULL;
  328. old->h_addrtype = new->h_addrtype;
  329. old->h_length = new->h_length;
  330. if (listrealloc(&old->h_addr_list, (const char ***)&new->h_addr_list,
  331. new->h_length) == NULL)
  332. return NULL;
  333. return old;
  334. }
  335. #endif /* SOCKS_SERVER */