access_log.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:13k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: access_log.c,v 1.49 1999/01/29 18:31:17 wessels Exp $
  3.  *
  4.  * DEBUG: section 46    Access Log
  5.  * AUTHOR: Duane Wessels
  6.  *
  7.  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
  8.  * ----------------------------------------------------------
  9.  *
  10.  *  Squid is the result of efforts by numerous individuals from the
  11.  *  Internet community.  Development is led by Duane Wessels of the
  12.  *  National Laboratory for Applied Network Research and funded by the
  13.  *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
  14.  *  Duane Wessels and the University of California San Diego.  Please
  15.  *  see the COPYRIGHT file for full details.  Squid incorporates
  16.  *  software developed and/or copyrighted by other sources.  Please see
  17.  *  the CREDITS file for full details.
  18.  *
  19.  *  This program is free software; you can redistribute it and/or modify
  20.  *  it under the terms of the GNU General Public License as published by
  21.  *  the Free Software Foundation; either version 2 of the License, or
  22.  *  (at your option) any later version.
  23.  *  
  24.  *  This program is distributed in the hope that it will be useful,
  25.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  26.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27.  *  GNU General Public License for more details.
  28.  *  
  29.  *  You should have received a copy of the GNU General Public License
  30.  *  along with this program; if not, write to the Free Software
  31.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  32.  *
  33.  */
  34. #include "squid.h"
  35. static void accessLogOpen(const char *fname);
  36. static char *log_quote(const char *header);
  37. static void accessLogSquid(AccessLogEntry * al, MemBuf * mb);
  38. static void accessLogCommon(AccessLogEntry * al, MemBuf * mb);
  39. #if MULTICAST_MISS_STREAM
  40. static int mcast_miss_fd = -1;
  41. static struct sockaddr_in mcast_miss_to;
  42. static void mcast_encode(unsigned int *, size_t, const unsigned int *);
  43. #endif
  44. const char *log_tags[] =
  45. {
  46.     "NONE",
  47.     "TCP_HIT",
  48.     "TCP_MISS",
  49.     "TCP_REFRESH_HIT",
  50.     "TCP_REF_FAIL_HIT",
  51.     "TCP_REFRESH_MISS",
  52.     "TCP_CLIENT_REFRESH_MISS",
  53.     "TCP_IMS_HIT",
  54.     "TCP_SWAPFAIL_MISS",
  55.     "TCP_NEGATIVE_HIT",
  56.     "TCP_MEM_HIT",
  57.     "TCP_DENIED",
  58.     "TCP_OFFLINE_HIT",
  59.     "UDP_HIT",
  60.     "UDP_MISS",
  61.     "UDP_DENIED",
  62.     "UDP_INVALID",
  63.     "UDP_MISS_NOFETCH",
  64.     "ICP_QUERY",
  65.     "LOG_TYPE_MAX"
  66. };
  67. #if FORW_VIA_DB
  68. typedef struct {
  69.     char *key;
  70.     void *next;
  71.     int n;
  72. } fvdb_entry;
  73. static hash_table *via_table = NULL;
  74. static hash_table *forw_table = NULL;
  75. static void fvdbInit(void);
  76. static void fvdbDumpTable(StoreEntry * e, hash_table * hash);
  77. static void fvdbCount(hash_table * hash, const char *key);
  78. static OBJH fvdbDumpVia;
  79. static OBJH fvdbDumpForw;
  80. static FREE fvdbFreeEntry;
  81. static void fvdbClear(void);
  82. #endif
  83. static int LogfileStatus = LOG_DISABLE;
  84. static int LogfileFD = -1;
  85. static char LogfileName[SQUID_MAXPATHLEN];
  86. #define LOG_BUF_SZ (MAX_URL<<2)
  87. static const char c2x[] =
  88. "000102030405060708090a0b0c0d0e0f"
  89. "101112131415161718191a1b1c1d1e1f"
  90. "202122232425262728292a2b2c2d2e2f"
  91. "303132333435363738393a3b3c3d3e3f"
  92. "404142434445464748494a4b4c4d4e4f"
  93. "505152535455565758595a5b5c5d5e5f"
  94. "606162636465666768696a6b6c6d6e6f"
  95. "707172737475767778797a7b7c7d7e7f"
  96. "808182838485868788898a8b8c8d8e8f"
  97. "909192939495969798999a9b9c9d9e9f"
  98. "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
  99. "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
  100. "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
  101. "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
  102. "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
  103. "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
  104. /* log_quote -- URL-style encoding on MIME headers. */
  105. static char *
  106. log_quote(const char *header)
  107. {
  108.     int c;
  109.     int i;
  110.     char *buf;
  111.     char *buf_cursor;
  112.     if (header == NULL) {
  113. buf = xcalloc(1, 1);
  114. *buf = '';
  115. return buf;
  116.     }
  117.     buf = xcalloc((strlen(header) * 3) + 1, 1);
  118.     buf_cursor = buf;
  119.     /*
  120.      * We escape: x00-x1F"#%;<>?{}|\\^~`[]x7F-xFF 
  121.      * which is the default escape list for the CPAN Perl5 URI module
  122.      * modulo the inclusion of space (x40) to make the raw logs a bit
  123.      * more readable.
  124.      */
  125.     while ((c = *(const unsigned char *) header++) != '') {
  126. if (c <= 0x1F
  127.     || c >= 0x7F
  128.     || c == '"'
  129.     || c == '#'
  130.     || c == '%'
  131.     || c == ';'
  132.     || c == '<'
  133.     || c == '>'
  134.     || c == '?'
  135.     || c == '{'
  136.     || c == '}'
  137.     || c == '|'
  138.     || c == '\'
  139.     || c == '^'
  140.     || c == '~'
  141.     || c == '`'
  142.     || c == '['
  143.     || c == ']') {
  144.     *buf_cursor++ = '%';
  145.     i = c * 2;
  146.     *buf_cursor++ = c2x[i];
  147.     *buf_cursor++ = c2x[i + 1];
  148. } else {
  149.     *buf_cursor++ = (char) c;
  150. }
  151.     }
  152.     *buf_cursor = '';
  153.     return buf;
  154. }
  155. static void
  156. accessLogSquid(AccessLogEntry * al, MemBuf * mb)
  157. {
  158.     const char *client = NULL;
  159.     if (Config.onoff.log_fqdn)
  160. client = fqdncache_gethostbyaddr(al->cache.caddr, FQDN_LOOKUP_IF_MISS);
  161.     if (client == NULL)
  162. client = inet_ntoa(al->cache.caddr);
  163.     memBufPrintf(mb, "%9d.%03d %6d %s %s/%03d %d %s %s %s %s%s/%s %s",
  164. (int) current_time.tv_sec,
  165. (int) current_time.tv_usec / 1000,
  166. al->cache.msec,
  167. client,
  168. log_tags[al->cache.code],
  169. al->http.code,
  170. al->cache.size,
  171. al->private.method_str,
  172. al->url,
  173. al->cache.ident,
  174. al->hier.ping.timedout ? "TIMEOUT_" : "",
  175. hier_strings[al->hier.code],
  176. al->hier.host,
  177. al->http.content_type);
  178. }
  179. static void
  180. accessLogCommon(AccessLogEntry * al, MemBuf * mb)
  181. {
  182.     const char *client = NULL;
  183.     if (Config.onoff.log_fqdn)
  184. client = fqdncache_gethostbyaddr(al->cache.caddr, 0);
  185.     if (client == NULL)
  186. client = inet_ntoa(al->cache.caddr);
  187.     memBufPrintf(mb, "%s %s - [%s] "%s %s HTTP/%.1f" %d %d %s:%s",
  188. client,
  189. al->cache.ident,
  190. mkhttpdlogtime(&squid_curtime),
  191. al->private.method_str,
  192. al->url,
  193. al->http.version,
  194. al->http.code,
  195. al->cache.size,
  196. log_tags[al->cache.code],
  197. hier_strings[al->hier.code]);
  198. }
  199. static void
  200. accessLogOpen(const char *fname)
  201. {
  202.     assert(fname);
  203.     xstrncpy(LogfileName, fname, SQUID_MAXPATHLEN);
  204.     LogfileFD = file_open(LogfileName, O_WRONLY | O_CREAT, NULL, NULL, NULL);
  205.     if (LogfileFD == DISK_ERROR) {
  206. debug(50, 0) ("%s: %sn", LogfileName, xstrerror());
  207. fatal("Cannot open logfile.");
  208.     }
  209.     LogfileStatus = LOG_ENABLE;
  210. }
  211. void
  212. accessLogLog(AccessLogEntry * al)
  213. {
  214.     MemBuf mb;
  215.     char *xbuf = NULL;
  216.     LOCAL_ARRAY(char, ident_buf, USER_IDENT_SZ);
  217.     if (LogfileStatus != LOG_ENABLE)
  218. return;
  219.     if (al->url == NULL)
  220. al->url = dash_str;
  221.     if (!al->http.content_type || *al->http.content_type == '')
  222. al->http.content_type = dash_str;
  223.     if (!al->cache.ident || *al->cache.ident == '') {
  224. al->cache.ident = dash_str;
  225.     } else {
  226. xstrncpy(ident_buf, rfc1738_escape(al->cache.ident), USER_IDENT_SZ);
  227. al->cache.ident = ident_buf;
  228.     }
  229.     if (al->icp.opcode)
  230. al->private.method_str = icp_opcode_str[al->icp.opcode];
  231.     else
  232. al->private.method_str = RequestMethodStr[al->http.method];
  233.     if (al->hier.host[0] == '')
  234. xstrncpy(al->hier.host, dash_str, SQUIDHOSTNAMELEN);
  235.     memBufDefInit(&mb);
  236.     if (Config.onoff.common_log)
  237. accessLogCommon(al, &mb);
  238.     else
  239. accessLogSquid(al, &mb);
  240.     if (Config.onoff.log_mime_hdrs) {
  241. char *ereq = log_quote(al->headers.request);
  242. char *erep = log_quote(al->headers.reply);
  243. memBufPrintf(&mb, " [%s] [%s]n", ereq, erep);
  244. safe_free(ereq);
  245. safe_free(erep);
  246.     } else {
  247. memBufPrintf(&mb, "n");
  248.     }
  249.     file_write_mbuf(LogfileFD, -1, mb, NULL, NULL);
  250.     safe_free(xbuf);
  251. #if MULTICAST_MISS_STREAM
  252.     if (al->cache.code != LOG_TCP_MISS)
  253. (void) 0;
  254.     else if (al->http.method != METHOD_GET)
  255. (void) 0;
  256.     else if (mcast_miss_fd < 0)
  257. (void) 0;
  258.     else {
  259. unsigned int ibuf[365];
  260. size_t isize;
  261. xstrncpy((char *) ibuf, al->url, 364 * sizeof(int));
  262. isize = ((strlen(al->url) + 8) / 8) * 2;
  263. if (isize > 364)
  264.     isize = 364;
  265. mcast_encode((unsigned int *) ibuf, isize,
  266.     (const unsigned int *) Config.mcast_miss.encode_key);
  267. comm_udp_sendto(mcast_miss_fd,
  268.     &mcast_miss_to, sizeof(mcast_miss_to),
  269.     ibuf, isize * sizeof(int));
  270.     }
  271. #endif
  272. }
  273. void
  274. accessLogRotate(void)
  275. {
  276.     int i;
  277.     LOCAL_ARRAY(char, from, MAXPATHLEN);
  278.     LOCAL_ARRAY(char, to, MAXPATHLEN);
  279.     char *fname = NULL;
  280.     struct stat sb;
  281. #if FORW_VIA_DB
  282.     fvdbClear();
  283. #endif
  284.     if ((fname = LogfileName) == NULL)
  285. return;
  286. #ifdef S_ISREG
  287.     if (stat(fname, &sb) == 0)
  288. if (S_ISREG(sb.st_mode) == 0)
  289.     return;
  290. #endif
  291.     debug(46, 1) ("accessLogRotate: Rotatingn");
  292.     /* Rotate numbers 0 through N up one */
  293.     for (i = Config.Log.rotateNumber; i > 1;) {
  294. i--;
  295. snprintf(from, MAXPATHLEN, "%s.%d", fname, i - 1);
  296. snprintf(to, MAXPATHLEN, "%s.%d", fname, i);
  297. rename(from, to);
  298.     }
  299.     /* Rotate the current log to .0 */
  300.     file_close(LogfileFD); /* always close */
  301.     if (Config.Log.rotateNumber > 0) {
  302. snprintf(to, MAXPATHLEN, "%s.%d", fname, 0);
  303. rename(fname, to);
  304.     }
  305.     /* Reopen the log.  It may have been renamed "manually" */
  306.     LogfileFD = file_open(fname, O_WRONLY | O_CREAT, NULL, NULL, NULL);
  307.     if (LogfileFD == DISK_ERROR) {
  308. debug(46, 0) ("accessLogRotate: Cannot open logfile: %sn", fname);
  309. LogfileStatus = LOG_DISABLE;
  310. fatal("Cannot open logfile.");
  311.     }
  312. }
  313. void
  314. accessLogClose(void)
  315. {
  316.     file_close(LogfileFD);
  317. }
  318. void
  319. hierarchyNote(HierarchyLogEntry * hl,
  320.     hier_code code,
  321.     const char *cache_peer)
  322. {
  323.     assert(hl != NULL);
  324.     hl->code = code;
  325.     xstrncpy(hl->host, cache_peer, SQUIDHOSTNAMELEN);
  326. }
  327. void
  328. accessLogInit(void)
  329. {
  330.     assert(sizeof(log_tags) == (LOG_TYPE_MAX + 1) * sizeof(char *));
  331.     accessLogOpen(Config.Log.access);
  332. #if FORW_VIA_DB
  333.     fvdbInit();
  334. #endif
  335. #if MULTICAST_MISS_STREAM
  336.     if (Config.mcast_miss.addr.s_addr != no_addr.s_addr) {
  337. memset(&mcast_miss_to, '', sizeof(mcast_miss_to));
  338. mcast_miss_to.sin_family = AF_INET;
  339. mcast_miss_to.sin_port = htons(Config.mcast_miss.port);
  340. mcast_miss_to.sin_addr.s_addr = Config.mcast_miss.addr.s_addr;
  341. mcast_miss_fd = comm_open(SOCK_DGRAM,
  342.     0,
  343.     Config.Addrs.udp_incoming,
  344.     Config.mcast_miss.port,
  345.     COMM_NONBLOCKING,
  346.     "Multicast Miss Stream");
  347. if (mcast_miss_fd < 0)
  348.     fatal("Cannot open Multicast Miss Stream Socket");
  349. debug(46, 1) ("Multicast Miss Stream Socket opened on FD %dn",
  350.     mcast_miss_fd);
  351. mcastSetTtl(mcast_miss_fd, 128);
  352. if (strlen(Config.mcast_miss.encode_key) < 16)
  353.     fatal("mcast_encode_key is too short, must be 16 characters");
  354.     }
  355. #endif
  356. }
  357. const char *
  358. accessLogTime(time_t t)
  359. {
  360.     struct tm *tm;
  361.     static char buf[128];
  362.     static time_t last_t = 0;
  363.     if (t != last_t) {
  364. tm = localtime(&t);
  365. strftime(buf, 127, "%Y/%m/%d %H:%M:%S", tm);
  366. last_t = t;
  367.     }
  368.     return buf;
  369. }
  370. #if FORW_VIA_DB
  371. static void
  372. fvdbInit(void)
  373. {
  374.     via_table = hash_create((HASHCMP *) strcmp, 977, hash4);
  375.     forw_table = hash_create((HASHCMP *) strcmp, 977, hash4);
  376.     cachemgrRegister("via_headers", "Via Request Headers", fvdbDumpVia, 0, 1);
  377.     cachemgrRegister("forw_headers", "X-Forwarded-For Request Headers",
  378. fvdbDumpForw, 0, 1);
  379. }
  380. static void
  381. fvdbCount(hash_table * hash, const char *key)
  382. {
  383.     fvdb_entry *fv;
  384.     if (NULL == hash)
  385. return;
  386.     fv = hash_lookup(hash, key);
  387.     if (NULL == fv) {
  388. fv = xcalloc(1, sizeof(fvdb_entry));
  389. fv->key = xstrdup(key);
  390. hash_join(hash, (hash_link *) fv);
  391.     }
  392.     fv->n++;
  393. }
  394. void
  395. fvdbCountVia(const char *key)
  396. {
  397.     fvdbCount(via_table, key);
  398. }
  399. void
  400. fvdbCountForw(const char *key)
  401. {
  402.     fvdbCount(forw_table, key);
  403. }
  404. static void
  405. fvdbDumpTable(StoreEntry * e, hash_table * hash)
  406. {
  407.     hash_link *h;
  408.     fvdb_entry *fv;
  409.     if (hash == NULL)
  410. return;
  411.     hash_first(hash);
  412.     while ((h = hash_next(hash))) {
  413. fv = (fvdb_entry *) h;
  414. storeAppendPrintf(e, "%9d %sn", fv->n, fv->key);
  415.     }
  416. }
  417. static void
  418. fvdbDumpVia(StoreEntry * e)
  419. {
  420.     fvdbDumpTable(e, via_table);
  421. }
  422. static void
  423. fvdbDumpForw(StoreEntry * e)
  424. {
  425.     fvdbDumpTable(e, forw_table);
  426. }
  427. static
  428. void
  429. fvdbFreeEntry(void *data)
  430. {
  431.     fvdb_entry *fv = data;
  432.     xfree(fv->key);
  433.     xfree(fv);
  434. }
  435. static void
  436. fvdbClear(void)
  437. {
  438.     hashFreeItems(via_table, fvdbFreeEntry);
  439.     hashFreeMemory(via_table);
  440.     via_table = hash_create((HASHCMP *) strcmp, 977, hash4);
  441.     hashFreeItems(forw_table, fvdbFreeEntry);
  442.     hashFreeMemory(forw_table);
  443.     forw_table = hash_create((HASHCMP *) strcmp, 977, hash4);
  444. }
  445. #endif
  446. #if MULTICAST_MISS_STREAM
  447. /*
  448.  * From http://www.io.com/~paulhart/game/algorithms/tea.html
  449.  *
  450.  * size of 'ibuf' must be a multiple of 2.
  451.  * size of 'key' must be 4.
  452.  * 'ibuf' is modified in place, encrypted data is written in
  453.  * network byte order.
  454.  */
  455. static void
  456. mcast_encode(unsigned int *ibuf, size_t isize, const unsigned int *key)
  457. {
  458.     unsigned int y;
  459.     unsigned int z;
  460.     unsigned int sum;
  461.     const unsigned int delta = 0x9e3779b9;
  462.     unsigned int n = 32;
  463.     const unsigned int k0 = htonl(key[0]);
  464.     const unsigned int k1 = htonl(key[1]);
  465.     const unsigned int k2 = htonl(key[2]);
  466.     const unsigned int k3 = htonl(key[3]);
  467.     int i;
  468.     for (i = 0; i < isize; i += 2) {
  469. y = htonl(ibuf[i]);
  470. z = htonl(ibuf[i + 1]);
  471. sum = 0;
  472. for (n = 32; n; n--) {
  473.     sum += delta;
  474.     y += (z << 4) + (k0 ^ z) + (sum ^ (z >> 5)) + k1;
  475.     z += (y << 4) + (k2 ^ y) + (sum ^ (y >> 5)) + k3;
  476. }
  477. ibuf[i] = htonl(y);
  478. ibuf[i + 1] = htonl(z);
  479.     }
  480. }
  481. #endif