4 * DEBUG: section 46 Access Log
5 * AUTHOR: Duane Wessels
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
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.
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.
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.
37 #include "AccessLogEntry.h"
39 // Store.h Required by configuration directives parsing/dumping only
42 #include "acl/Checklist.h"
44 #include "hier_code.h"
45 #include "HttpReply.h"
46 #include "HttpRequest.h"
48 #include "SquidTime.h"
49 #include "CacheManager.h"
51 static void accessLogSquid(AccessLogEntry
* al
, Logfile
* logfile
);
52 static void accessLogCommon(AccessLogEntry
* al
, Logfile
* logfile
);
53 static void accessLogCustom(AccessLogEntry
* al
, customlog
* log
);
55 static Logfile
*headerslog
= NULL
;
58 #if MULTICAST_MISS_STREAM
59 static int mcast_miss_fd
= -1;
61 static struct sockaddr_in mcast_miss_to
;
62 static void mcast_encode(unsigned int *, size_t, const unsigned int *);
65 const char *log_tags
[] = {
69 "TCP_REFRESH_UNMODIFIED",
71 "TCP_REFRESH_MODIFIED",
72 "TCP_CLIENT_REFRESH_MISS",
98 static hash_table
*via_table
= NULL
;
99 static hash_table
*forw_table
= NULL
;
100 static void fvdbInit();
101 static void fvdbDumpTable(StoreEntry
* e
, hash_table
* hash
);
102 static void fvdbCount(hash_table
* hash
, const char *key
);
103 static OBJH fvdbDumpVia
;
104 static OBJH fvdbDumpForw
;
105 static FREE fvdbFreeEntry
;
106 static void fvdbClear(void);
107 static void fvdbRegisterWithCacheManager();
110 int LogfileStatus
= LOG_DISABLE
;
113 bool alLogformatHasAdaptToken
= false;
117 bool alLogformatHasIcapToken
= false;
120 #define LOG_BUF_SZ (MAX_URL<<2)
122 static const char c2x
[] =
123 "000102030405060708090a0b0c0d0e0f"
124 "101112131415161718191a1b1c1d1e1f"
125 "202122232425262728292a2b2c2d2e2f"
126 "303132333435363738393a3b3c3d3e3f"
127 "404142434445464748494a4b4c4d4e4f"
128 "505152535455565758595a5b5c5d5e5f"
129 "606162636465666768696a6b6c6d6e6f"
130 "707172737475767778797a7b7c7d7e7f"
131 "808182838485868788898a8b8c8d8e8f"
132 "909192939495969798999a9b9c9d9e9f"
133 "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
134 "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
135 "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
136 "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
137 "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
138 "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
140 /* log_quote -- URL-style encoding on MIME headers. */
143 log_quote(const char *header
)
150 if (header
== NULL
) {
151 buf
= static_cast<char *>(xcalloc(1, 1));
156 buf
= static_cast<char *>(xcalloc(1, (strlen(header
) * 3) + 1));
159 * We escape: \x00-\x1F"#%;<>?{}|\\\\^~`\[\]\x7F-\xFF
160 * which is the default escape list for the CPAN Perl5 URI module
161 * modulo the inclusion of space (x40) to make the raw logs a bit
165 while ((c
= *(const unsigned char *) header
++) != '\0') {
169 *buf_cursor
++ = '\\';
171 } else if (c
== '\n') {
172 *buf_cursor
++ = '\\';
198 *buf_cursor
++ = c2x
[i
];
199 *buf_cursor
++ = c2x
[i
+ 1];
202 } else if (c
== '\\') {
203 *buf_cursor
++ = '\\';
204 *buf_cursor
++ = '\\';
208 *buf_cursor
++ = (char) c
;
217 username_quote(const char *header
)
218 /* copy of log_quote. Bugs there will be found here */
225 if (header
== NULL
) {
226 buf
= static_cast<char *>(xcalloc(1, 1));
231 buf
= static_cast<char *>(xcalloc(1, (strlen(header
) * 3) + 1));
234 * We escape: space \x00-\x1F and space (0x40) and \x7F-\xFF
235 * to prevent garbage in the logs. CR and LF are also there just in case.
238 while ((c
= *(const unsigned char *) header
++) != '\0') {
240 *buf_cursor
++ = '\\';
242 } else if (c
== '\n') {
243 *buf_cursor
++ = '\\';
251 *buf_cursor
++ = c2x
[i
];
252 *buf_cursor
++ = c2x
[i
+ 1];
254 *buf_cursor
++ = (char) c
;
263 accessLogFormatName(const char *name
)
271 return username_quote(name
);
275 log_quoted_string(const char *str
)
277 char *out
= (char *)xmalloc(strlen(str
) * 2 + 1);
281 int l
= strcspn(str
, "\"\\\r\n\t");
322 * Bytecodes for the configureable logformat stuff
325 LFT_NONE
, /* dummy */
328 LFT_CLIENT_IP_ADDRESS
,
332 /*LFT_SERVER_IP_ADDRESS, */
333 LFT_SERVER_IP_OR_PEER_NAME
,
334 /*LFT_SERVER_PORT, */
340 LFT_TIME_SECONDS_SINCE_EPOCH
,
344 LFT_TIME_TO_HANDLE_REQUEST
,
346 LFT_PEER_RESPONSE_TIME
,
347 LFT_TOTAL_SERVER_SIDE_RESPONSE_TIME
,
351 LFT_REQUEST_HEADER_ELEM
,
352 LFT_REQUEST_ALL_HEADERS
,
355 LFT_REPLY_HEADER_ELEM
,
356 LFT_REPLY_ALL_HEADERS
,
362 /*LFT_USER_SCHEME, */
365 LFT_HTTP_SENT_STATUS_CODE_OLD_30
,
366 LFT_HTTP_SENT_STATUS_CODE
,
367 LFT_HTTP_RECEIVED_STATUS_CODE
,
368 /*LFT_HTTP_STATUS, */
371 /*LFT_SQUID_ERROR, */
379 /*LFT_REQUEST_QUERY, * // * this is not needed. see strip_query_terms */
382 LFT_REQUEST_SIZE_TOTAL
,
383 /*LFT_REQUEST_SIZE_LINE, */
384 LFT_REQUEST_SIZE_HEADERS
,
385 /*LFT_REQUEST_SIZE_BODY, */
386 /*LFT_REQUEST_SIZE_BODY_NO_TE, */
388 LFT_REPLY_SIZE_TOTAL
,
389 LFT_REPLY_HIGHOFFSET
,
390 LFT_REPLY_OBJECTSIZE
,
391 /*LFT_REPLY_SIZE_LINE, */
392 LFT_REPLY_SIZE_HEADERS
,
393 /*LFT_REPLY_SIZE_BODY, */
394 /*LFT_REPLY_SIZE_BODY_NO_TE, */
401 LTF_ADAPTATION_SUM_XACT_TIMES
,
402 LTF_ADAPTATION_ALL_XACT_TIMES
,
408 LFT_ICAP_LAST_MATCHED_HEADER
,
409 LFT_ICAP_LAST_MATCHED_HEADER_ELEM
,
410 LFT_ICAP_LAST_MATCHED_ALL_HEADERS
,
414 LFT_ICAP_REQUEST_URI
,
415 LFT_ICAP_REQUEST_METHOD
,
420 LFT_ICAP_REQ_HEADER_ELEM
,
421 LFT_ICAP_REQ_ALL_HEADERS
,
424 LFT_ICAP_REP_HEADER_ELEM
,
425 LFT_ICAP_REP_ALL_HEADERS
,
427 LFT_ICAP_TR_RESPONSE_TIME
,
430 LFT_ICAP_STATUS_CODE
,
433 LFT_PERCENT
/* special string cases for escaped chars */
444 /* FIXME: public class so we can pre-define its type. */
445 class logformat_token
448 logformat_bcode_t type
;
460 unsigned char precision
;
461 enum log_quote quote
;
463 unsigned int space
:1;
466 logformat_token
*next
; /* todo: move from linked list to array */
469 struct logformat_token_table_entry
{
471 logformat_bcode_t token_type
;
475 struct logformat_token_table_entry logformat_token_table
[] = {
477 {">a", LFT_CLIENT_IP_ADDRESS
},
479 { ">p", LFT_CLIENT_PORT
},
480 {">A", LFT_CLIENT_FQDN
},
482 /*{ "<a", LFT_SERVER_IP_ADDRESS }, */
483 /*{ "<p", LFT_SERVER_PORT }, */
484 {"<A", LFT_SERVER_IP_OR_PEER_NAME
},
486 /* {"oa", LFT_OUTGOING_IP}, */
487 /* {"ot", LFT_OUTGOING_TOS}, */
489 {"la", LFT_LOCAL_IP
},
490 {"lp", LFT_LOCAL_PORT
},
491 /*{ "lA", LFT_LOCAL_NAME }, */
493 {"ts", LFT_TIME_SECONDS_SINCE_EPOCH
},
494 {"tu", LFT_TIME_SUBSECOND
},
495 {"tl", LFT_TIME_LOCALTIME
},
496 {"tg", LFT_TIME_GMT
},
497 {"tr", LFT_TIME_TO_HANDLE_REQUEST
},
499 {"<pt", LFT_PEER_RESPONSE_TIME
},
500 {"<tt", LFT_TOTAL_SERVER_SIDE_RESPONSE_TIME
},
501 {"dt", LFT_DNS_WAIT_TIME
},
503 {">h", LFT_REQUEST_HEADER
},
504 {">h", LFT_REQUEST_ALL_HEADERS
},
505 {"<h", LFT_REPLY_HEADER
},
506 {"<h", LFT_REPLY_ALL_HEADERS
},
508 {"un", LFT_USER_NAME
},
509 {"ul", LFT_USER_LOGIN
},
510 /*{ "ur", LFT_USER_REALM }, */
511 /*{ "us", LFT_USER_SCHEME }, */
512 {"ui", LFT_USER_IDENT
},
513 {"ue", LFT_USER_EXTERNAL
},
515 {"Hs", LFT_HTTP_SENT_STATUS_CODE_OLD_30
},
516 {">Hs", LFT_HTTP_SENT_STATUS_CODE
},
517 {"<Hs", LFT_HTTP_RECEIVED_STATUS_CODE
},
518 /*{ "Ht", LFT_HTTP_STATUS }, */
520 {"Ss", LFT_SQUID_STATUS
},
521 /*{ "Se", LFT_SQUID_ERROR }, */
522 {"Sh", LFT_SQUID_HIERARCHY
},
524 {"mt", LFT_MIME_TYPE
},
526 {"rm", LFT_REQUEST_METHOD
},
527 {"ru", LFT_REQUEST_URI
}, /* doesn't include the query-string */
528 {"rp", LFT_REQUEST_URLPATH
}, /* doesn't include the host */
529 /* { "rq", LFT_REQUEST_QUERY }, * / / * the query-string, INCLUDING the leading ? */
530 {">v", LFT_REQUEST_VERSION
},
531 {"rv", LFT_REQUEST_VERSION
},
533 { ">st", LFT_REQUEST_SIZE_TOTAL
},
534 /*{ ">sl", LFT_REQUEST_SIZE_LINE }, * / / * the request line "GET ... " */
535 { ">sh", LFT_REQUEST_SIZE_HEADERS
},
536 /*{ ">sb", LFT_REQUEST_SIZE_BODY }, */
537 /*{ ">sB", LFT_REQUEST_SIZE_BODY_NO_TE }, */
539 {"<st", LFT_REPLY_SIZE_TOTAL
},
540 {"<sH", LFT_REPLY_HIGHOFFSET
},
541 {"<sS", LFT_REPLY_OBJECTSIZE
},
542 /*{ "<sl", LFT_REPLY_SIZE_LINE }, * / / * the reply line (protocol, code, text) */
543 { "<sh", LFT_REPLY_SIZE_HEADERS
},
544 /*{ "<sb", LFT_REPLY_SIZE_BODY }, */
545 /*{ "<sB", LFT_REPLY_SIZE_BODY_NO_TE }, */
548 {"st", LFT_IO_SIZE_TOTAL
},
554 {"adapt::all_trs", LTF_ADAPTATION_ALL_XACT_TIMES
},
555 {"adapt::sum_trs", LTF_ADAPTATION_SUM_XACT_TIMES
},
559 {"icap::tt", LFT_ICAP_TOTAL_TIME
},
560 {"icap::<last_h", LFT_ICAP_LAST_MATCHED_HEADER
},
562 {"icap::<A", LFT_ICAP_ADDR
},
563 {"icap::<service_name", LFT_ICAP_SERV_NAME
},
564 {"icap::ru", LFT_ICAP_REQUEST_URI
},
565 {"icap::rm", LFT_ICAP_REQUEST_METHOD
},
566 {"icap::>st", LFT_ICAP_BYTES_SENT
},
567 {"icap::<st", LFT_ICAP_BYTES_READ
},
569 {"icap::>h", LFT_ICAP_REQ_HEADER
},
570 {"icap::<h", LFT_ICAP_REP_HEADER
},
572 {"icap::tr", LFT_ICAP_TR_RESPONSE_TIME
},
573 {"icap::tio", LFT_ICAP_IO_TIME
},
574 {"icap::to", LFT_ICAP_OUTCOME
},
575 {"icap::Hs", LFT_ICAP_STATUS_CODE
},
578 {NULL
, LFT_NONE
} /* this must be last */
582 accessLogCustom(AccessLogEntry
* al
, customlog
* log
)
586 logformat_token
*fmt
;
594 logfile
= log
->logfile
;
596 for (fmt
= lf
->format
; fmt
!= NULL
; fmt
= fmt
->next
) { /* for each token */
597 const char *out
= NULL
;
612 out
= fmt
->data
.string
;
615 case LFT_CLIENT_IP_ADDRESS
:
616 if (al
->cache
.caddr
.IsNoAddr()) // e.g., ICAP OPTIONS lack client
619 out
= al
->cache
.caddr
.NtoA(tmp
,1024);
622 case LFT_CLIENT_FQDN
:
623 if (al
->cache
.caddr
.IsAnyAddr()) // e.g., ICAP OPTIONS lack client
626 out
= fqdncache_gethostbyaddr(al
->cache
.caddr
, FQDN_LOOKUP_IF_MISS
);
628 out
= al
->cache
.caddr
.NtoA(tmp
,1024);
633 case LFT_CLIENT_PORT
:
635 outint
= al
->request
->client_addr
.GetPort();
640 /* case LFT_SERVER_IP_ADDRESS: */
642 case LFT_SERVER_IP_OR_PEER_NAME
:
647 /* case LFT_SERVER_PORT: */
651 out
= al
->request
->my_addr
.NtoA(tmp
,1024);
658 outint
= al
->request
->my_addr
.GetPort();
664 case LFT_TIME_SECONDS_SINCE_EPOCH
:
665 // some platforms store time in 32-bit, some 64-bit...
666 outoff
= static_cast<int64_t>(current_time
.tv_sec
);
670 case LFT_TIME_SUBSECOND
:
671 outint
= current_time
.tv_usec
/ fmt
->divisor
;
676 case LFT_TIME_LOCALTIME
:
682 spec
= fmt
->data
.timespec
;
684 if (fmt
->type
== LFT_TIME_LOCALTIME
) {
686 spec
= "%d/%b/%Y:%H:%M:%S %z";
687 t
= localtime(&squid_curtime
);
690 spec
= "%d/%b/%Y:%H:%M:%S";
692 t
= gmtime(&squid_curtime
);
695 strftime(tmp
, sizeof(tmp
), spec
, t
);
702 case LFT_TIME_TO_HANDLE_REQUEST
:
703 outint
= al
->cache
.msec
;
707 case LFT_PEER_RESPONSE_TIME
:
708 if (al
->hier
.peer_response_time
< 0) {
711 outoff
= al
->hier
.peer_response_time
;
716 case LFT_TOTAL_SERVER_SIDE_RESPONSE_TIME
:
717 if (al
->hier
.total_response_time
< 0) {
720 outoff
= al
->hier
.total_response_time
;
725 case LFT_DNS_WAIT_TIME
:
726 if (al
->request
&& al
->request
->dnsWait
>= 0) {
727 outint
= al
->request
->dnsWait
;
732 case LFT_REQUEST_HEADER
:
735 sb
= al
->request
->header
.getByName(fmt
->data
.header
.header
);
737 out
= sb
.termedBuf();
743 case LFT_REPLY_HEADER
:
745 sb
= al
->reply
->header
.getByName(fmt
->data
.header
.header
);
747 out
= sb
.termedBuf();
754 case LTF_ADAPTATION_SUM_XACT_TIMES
:
756 Adaptation::History::Pointer ah
= al
->request
->adaptHistory();
758 ah
->sumLogString(fmt
->data
.string
, sb
);
759 out
= sb
.termedBuf();
763 case LTF_ADAPTATION_ALL_XACT_TIMES
:
765 Adaptation::History::Pointer ah
= al
->request
->adaptHistory();
767 ah
->allLogString(fmt
->data
.string
, sb
);
768 out
= sb
.termedBuf();
774 case LFT_ICAP_LAST_MATCHED_HEADER
:
776 Adaptation::Icap::History::Pointer ih
= al
->request
->icapHistory();
778 sb
= ih
->mergeOfIcapHeaders
.getByName(fmt
->data
.header
.header
);
781 out
= sb
.termedBuf();
787 case LFT_ICAP_LAST_MATCHED_HEADER_ELEM
:
789 Adaptation::Icap::History::Pointer ih
= al
->request
->icapHistory();
791 sb
= ih
->mergeOfIcapHeaders
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
794 out
= sb
.termedBuf();
800 case LFT_ICAP_LAST_MATCHED_ALL_HEADERS
:
801 out
= al
->headers
.icap
;
809 out
= al
->icap
.hostAddr
.NtoA(tmp
,1024);
812 case LFT_ICAP_SERV_NAME
:
813 out
= al
->icap
.serviceName
.termedBuf();
816 case LFT_ICAP_REQUEST_URI
:
817 out
= al
->icap
.reqUri
.termedBuf();
820 case LFT_ICAP_REQUEST_METHOD
:
821 out
= Adaptation::Icap::ICAP::methodStr(al
->icap
.reqMethod
);
824 case LFT_ICAP_BYTES_SENT
:
825 outint
= al
->icap
.bytesSent
;
829 case LFT_ICAP_BYTES_READ
:
830 outint
= al
->icap
.bytesRead
;
834 case LFT_ICAP_REQ_HEADER
:
835 if (NULL
!= al
->icap
.request
) {
836 sb
= al
->icap
.request
->header
.getByName(fmt
->data
.header
.header
);
837 out
= sb
.termedBuf();
842 case LFT_ICAP_REQ_HEADER_ELEM
:
844 sb
= al
->icap
.request
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
846 out
= sb
.termedBuf();
852 case LFT_ICAP_REQ_ALL_HEADERS
:
853 if (al
->icap
.request
) {
854 HttpHeaderPos pos
= HttpHeaderInitPos
;
855 while (const HttpHeaderEntry
*e
= al
->icap
.request
->header
.getEntry(&pos
)) {
861 out
= sb
.termedBuf();
866 case LFT_ICAP_REP_HEADER
:
867 if (NULL
!= al
->icap
.reply
) {
868 sb
= al
->icap
.reply
->header
.getByName(fmt
->data
.header
.header
);
869 out
= sb
.termedBuf();
874 case LFT_ICAP_REP_HEADER_ELEM
:
875 if (NULL
!= al
->icap
.reply
)
876 sb
= al
->icap
.reply
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
878 out
= sb
.termedBuf();
884 case LFT_ICAP_REP_ALL_HEADERS
:
885 if (al
->icap
.reply
) {
886 HttpHeaderPos pos
= HttpHeaderInitPos
;
887 while (const HttpHeaderEntry
*e
= al
->icap
.reply
->header
.getEntry(&pos
)) {
893 out
= sb
.termedBuf();
898 case LFT_ICAP_TR_RESPONSE_TIME
:
899 outint
= al
->icap
.trTime
;
903 case LFT_ICAP_IO_TIME
:
904 outint
= al
->icap
.ioTime
;
908 case LFT_ICAP_STATUS_CODE
:
909 outint
= al
->icap
.resStatus
;
913 case LFT_ICAP_OUTCOME
:
914 out
= al
->icap
.outcome
;
917 case LFT_ICAP_TOTAL_TIME
:
918 outint
= al
->icap
.processingTime
;
922 case LFT_REQUEST_HEADER_ELEM
:
924 sb
= al
->request
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
926 out
= sb
.termedBuf();
932 case LFT_REPLY_HEADER_ELEM
:
934 sb
= al
->reply
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
936 out
= sb
.termedBuf();
942 case LFT_REQUEST_ALL_HEADERS
:
943 out
= al
->headers
.request
;
949 case LFT_REPLY_ALL_HEADERS
:
950 out
= al
->headers
.reply
;
957 out
= accessLogFormatName(al
->cache
.authuser
);
960 out
= accessLogFormatName(al
->cache
.extuser
);
965 out
= accessLogFormatName(al
->cache
.ssluser
);
970 out
= accessLogFormatName(al
->cache
.rfc931
);
977 out
= accessLogFormatName(al
->cache
.authuser
);
984 out
= accessLogFormatName(al
->cache
.rfc931
);
990 case LFT_USER_EXTERNAL
:
991 out
= accessLogFormatName(al
->cache
.extuser
);
997 /* case LFT_USER_REALM: */
998 /* case LFT_USER_SCHEME: */
1000 // the fmt->type can not be LFT_HTTP_SENT_STATUS_CODE_OLD_30
1001 // but compiler complains if ommited
1002 case LFT_HTTP_SENT_STATUS_CODE_OLD_30
:
1003 case LFT_HTTP_SENT_STATUS_CODE
:
1004 outint
= al
->http
.code
;
1010 case LFT_HTTP_RECEIVED_STATUS_CODE
:
1011 if(al
->hier
.peer_reply_status
== HTTP_STATUS_NONE
) {
1015 outint
= al
->hier
.peer_reply_status
;
1019 /* case LFT_HTTP_STATUS:
1020 * out = statusline->text;
1025 case LFT_SQUID_STATUS
:
1026 out
= log_tags
[al
->cache
.code
];
1030 /* case LFT_SQUID_ERROR: */
1032 case LFT_SQUID_HIERARCHY
:
1033 if (al
->hier
.ping
.timedout
)
1034 mb
.append("TIMEOUT_", 8);
1036 out
= hier_code_str
[al
->hier
.code
];
1041 out
= al
->http
.content_type
;
1045 case LFT_REQUEST_METHOD
:
1046 out
= al
->_private
.method_str
;
1050 case LFT_REQUEST_URI
:
1055 case LFT_REQUEST_URLPATH
:
1057 out
= al
->request
->urlpath
.termedBuf();
1062 case LFT_REQUEST_VERSION
:
1063 snprintf(tmp
, sizeof(tmp
), "%d.%d", (int) al
->http
.version
.major
, (int) al
->http
.version
.minor
);
1067 case LFT_REQUEST_SIZE_TOTAL
:
1068 outoff
= al
->cache
.requestSize
;
1072 /*case LFT_REQUEST_SIZE_LINE: */
1073 case LFT_REQUEST_SIZE_HEADERS
:
1074 outoff
= al
->cache
.requestHeadersSize
;
1077 /*case LFT_REQUEST_SIZE_BODY: */
1078 /*case LFT_REQUEST_SIZE_BODY_NO_TE: */
1080 case LFT_REPLY_SIZE_TOTAL
:
1081 outoff
= al
->cache
.replySize
;
1085 case LFT_REPLY_HIGHOFFSET
:
1086 outoff
= al
->cache
.highOffset
;
1092 case LFT_REPLY_OBJECTSIZE
:
1093 outoff
= al
->cache
.objectSize
;
1099 /*case LFT_REPLY_SIZE_LINE: */
1100 case LFT_REPLY_SIZE_HEADERS
:
1101 outint
= al
->cache
.replyHeadersSize
;
1103 /*case LFT_REPLY_SIZE_BODY: */
1104 /*case LFT_REPLY_SIZE_BODY_NO_TE: */
1108 out
= al
->request
->tag
.termedBuf();
1114 case LFT_IO_SIZE_TOTAL
:
1115 outint
= al
->cache
.requestSize
+ al
->cache
.replySize
;
1121 out
= al
->request
->extacl_log
.termedBuf();
1134 snprintf(tmp
, sizeof(tmp
), "%0*" PRId64
, fmt
->zero
? (int) fmt
->width
: 0, outoff
);
1138 snprintf(tmp
, sizeof(tmp
), "%0*ld", fmt
->zero
? (int) fmt
->width
: 0, outint
);
1143 if (quote
|| fmt
->quote
!= LOG_QUOTE_NONE
) {
1144 char *newout
= NULL
;
1147 switch (fmt
->quote
) {
1149 case LOG_QUOTE_NONE
:
1150 newout
= rfc1738_escape_unescaped(out
);
1153 case LOG_QUOTE_QUOTES
:
1154 newout
= log_quoted_string(out
);
1158 case LOG_QUOTE_BRAKETS
:
1159 newout
= log_quote(out
);
1164 newout
= rfc1738_escape(out
);
1183 mb
.Printf("%-*s", (int) fmt
->width
, out
);
1185 mb
.Printf("%*s", (int) fmt
->width
, out
);
1187 mb
.append(out
, strlen(out
));
1201 logfilePrintf(logfile
, "%s\n", mb
.buf
);
1204 /* parses a single token. Returns the token length in characters,
1205 * and fills in the lt item with the token information.
1206 * def is for sure null-terminated
1209 accessLogGetNewLogFormatToken(logformat_token
* lt
, char *def
, enum log_quote
*quote
)
1213 struct logformat_token_table_entry
*lte
;
1216 memset(lt
, 0, sizeof(*lt
));
1217 l
= strcspn(cur
, "%");
1221 /* it's a string for sure, until \0 or the next % */
1222 cp
= (char *)xmalloc(l
+ 1);
1223 xstrncpy(cp
, cur
, l
+ 1);
1224 lt
->type
= LFT_STRING
;
1225 lt
->data
.string
= cp
;
1232 if (*quote
== LOG_QUOTE_NONE
)
1233 *quote
= LOG_QUOTE_QUOTES
;
1234 else if (*quote
== LOG_QUOTE_QUOTES
)
1235 *quote
= LOG_QUOTE_NONE
;
1240 if (*quote
== LOG_QUOTE_NONE
)
1241 *quote
= LOG_QUOTE_BRAKETS
;
1246 if (*quote
== LOG_QUOTE_BRAKETS
)
1247 *quote
= LOG_QUOTE_NONE
;
1267 lt
->quote
= LOG_QUOTE_QUOTES
;
1272 lt
->quote
= LOG_QUOTE_RAW
;
1277 lt
->quote
= LOG_QUOTE_BRAKETS
;
1282 lt
->quote
= LOG_QUOTE_URL
;
1302 lt
->width
= strtol(cur
, &cur
, 10);
1305 lt
->precision
= strtol(cur
+ 1, &cur
, 10);
1310 l
= strcspn(cur
, "}");
1311 cp
= (char *)xmalloc(l
+ 1);
1312 xstrncpy(cp
, cur
, l
+ 1);
1313 lt
->data
.string
= cp
;
1320 // For upward compatibility, assume "http::" prefix as default prefix
1321 // for all log access formating codes, except those starting
1322 // from "icap::", "adapt::" and "%"
1323 if (strncmp(cur
,"http::", 6) == 0 &&
1324 strncmp(cur
+6, "icap::", 6) != 0 &&
1325 strncmp(cur
+6, "adapt::", 12) != 0 && *(cur
+6) != '%' ) {
1329 lt
->type
= LFT_NONE
;
1331 for (lte
= logformat_token_table
; lte
->config
!= NULL
; lte
++) {
1332 if (strncmp(lte
->config
, cur
, strlen(lte
->config
)) == 0) {
1333 lt
->type
= lte
->token_type
;
1334 cur
+= strlen(lte
->config
);
1339 if (lt
->type
== LFT_NONE
) {
1340 fatalf("Can't parse configuration token: '%s'\n",
1354 case LFT_ICAP_LAST_MATCHED_HEADER
:
1356 case LFT_ICAP_REQ_HEADER
:
1358 case LFT_ICAP_REP_HEADER
:
1361 case LFT_REQUEST_HEADER
:
1363 case LFT_REPLY_HEADER
:
1365 if (lt
->data
.string
) {
1366 char *header
= lt
->data
.string
;
1367 char *cp
= strchr(header
, ':');
1372 if (*cp
== ',' || *cp
== ';' || *cp
== ':')
1373 lt
->data
.header
.separator
= *cp
++;
1375 lt
->data
.header
.separator
= ',';
1377 lt
->data
.header
.element
= cp
;
1380 case LFT_REQUEST_HEADER
: lt
->type
= LFT_REQUEST_HEADER_ELEM
; break;
1381 case LFT_REPLY_HEADER
: lt
->type
= LFT_REPLY_HEADER_ELEM
; break;
1383 case LFT_ICAP_LAST_MATCHED_HEADER
: lt
->type
= LFT_ICAP_LAST_MATCHED_HEADER_ELEM
; break;
1384 case LFT_ICAP_REQ_HEADER
: lt
->type
= LFT_ICAP_REQ_HEADER_ELEM
; break;
1385 case LFT_ICAP_REP_HEADER
: lt
->type
= LFT_ICAP_REP_HEADER_ELEM
; break;
1391 lt
->data
.header
.header
= header
;
1394 case LFT_REQUEST_HEADER
: lt
->type
= LFT_REQUEST_ALL_HEADERS
; break;
1395 case LFT_REPLY_HEADER
: lt
->type
= LFT_REPLY_ALL_HEADERS
; break;
1397 case LFT_ICAP_LAST_MATCHED_HEADER
: lt
->type
= LFT_ICAP_LAST_MATCHED_ALL_HEADERS
; break;
1398 case LFT_ICAP_REQ_HEADER
: lt
->type
= LFT_ICAP_REQ_ALL_HEADERS
; break;
1399 case LFT_ICAP_REP_HEADER
: lt
->type
= LFT_ICAP_REP_ALL_HEADERS
; break;
1403 Config
.onoff
.log_mime_hdrs
= 1;
1408 case LFT_CLIENT_FQDN
:
1409 Config
.onoff
.log_fqdn
= 1;
1412 case LFT_TIME_SUBSECOND
:
1415 if (lt
->precision
) {
1417 lt
->divisor
= 1000000;
1419 for (i
= lt
->precision
; i
> 1; i
--)
1428 case LFT_HTTP_SENT_STATUS_CODE_OLD_30
:
1429 debugs(46, 0, "WARNING: the \"Hs\" formating code is deprecated use the \">Hs\" instead");
1430 lt
->type
= LFT_HTTP_SENT_STATUS_CODE
;
1440 accessLogParseLogFormat(logformat_token
** fmt
, char *def
)
1443 logformat_token
*new_lt
, *last_lt
;
1444 enum log_quote quote
= LOG_QUOTE_NONE
;
1446 debugs(46, 2, "accessLogParseLogFormat: got definition '" << def
<< "'");
1448 /* very inefficent parser, but who cares, this needs to be simple */
1449 /* First off, let's tokenize, we'll optimize in a second pass.
1450 * A token can either be a %-prefixed sequence (usually a dynamic
1451 * token but it can be an escaped sequence), or a string. */
1453 eos
= def
+ strlen(def
);
1454 *fmt
= new_lt
= last_lt
= (logformat_token
*)xmalloc(sizeof(logformat_token
));
1455 cur
+= accessLogGetNewLogFormatToken(new_lt
, cur
, "e
);
1458 new_lt
= (logformat_token
*)xmalloc(sizeof(logformat_token
));
1459 last_lt
->next
= new_lt
;
1461 cur
+= accessLogGetNewLogFormatToken(new_lt
, cur
, "e
);
1468 accessLogDumpLogFormat(StoreEntry
* entry
, const char *name
, logformat
* definitions
)
1473 struct logformat_token_table_entry
*te
;
1474 debugs(46, 0, "accessLogDumpLogFormat called");
1476 for (format
= definitions
; format
; format
= format
->next
) {
1477 debugs(46, 0, "Dumping logformat definition for " << format
->name
);
1478 storeAppendPrintf(entry
, "logformat %s ", format
->name
);
1480 for (t
= format
->format
; t
; t
= t
->next
) {
1481 if (t
->type
== LFT_STRING
)
1482 storeAppendPrintf(entry
, "%s", t
->data
.string
);
1486 logformat_bcode_t type
= t
->type
;
1494 case LFT_ICAP_LAST_MATCHED_HEADER_ELEM
:
1495 case LFT_ICAP_REQ_HEADER_ELEM
:
1496 case LFT_ICAP_REP_HEADER_ELEM
:
1498 case LFT_REQUEST_HEADER_ELEM
:
1500 case LFT_REPLY_HEADER_ELEM
:
1502 if (t
->data
.header
.separator
!= ',')
1503 snprintf(argbuf
, sizeof(argbuf
), "%s:%c%s", t
->data
.header
.header
, t
->data
.header
.separator
, t
->data
.header
.element
);
1505 snprintf(argbuf
, sizeof(argbuf
), "%s:%s", t
->data
.header
.header
, t
->data
.header
.element
);
1510 case LFT_REQUEST_HEADER_ELEM
: type
= LFT_REQUEST_HEADER_ELEM
; break;
1511 case LFT_REPLY_HEADER_ELEM
: type
= LFT_REPLY_HEADER_ELEM
; break;
1513 case LFT_ICAP_LAST_MATCHED_HEADER_ELEM
: type
= LFT_ICAP_LAST_MATCHED_HEADER
; break;
1514 case LFT_ICAP_REQ_HEADER_ELEM
: type
= LFT_ICAP_REQ_HEADER
; break;
1515 case LFT_ICAP_REP_HEADER_ELEM
: type
= LFT_ICAP_REP_HEADER
; break;
1522 case LFT_REQUEST_ALL_HEADERS
:
1524 case LFT_REPLY_ALL_HEADERS
:
1527 case LFT_ICAP_LAST_MATCHED_ALL_HEADERS
:
1528 case LFT_ICAP_REQ_ALL_HEADERS
:
1529 case LFT_ICAP_REP_ALL_HEADERS
:
1533 case LFT_REQUEST_ALL_HEADERS
: type
= LFT_REQUEST_HEADER
; break;
1534 case LFT_REPLY_ALL_HEADERS
: type
= LFT_REPLY_HEADER
; break;
1536 case LFT_ICAP_LAST_MATCHED_ALL_HEADERS
: type
= LFT_ICAP_LAST_MATCHED_HEADER
; break;
1537 case LFT_ICAP_REQ_ALL_HEADERS
: type
= LFT_ICAP_REQ_HEADER
; break;
1538 case LFT_ICAP_REP_ALL_HEADERS
: type
= LFT_ICAP_REP_HEADER
; break;
1547 arg
= t
->data
.string
;
1552 entry
->append("%", 1);
1556 case LOG_QUOTE_QUOTES
:
1557 entry
->append("\"", 1);
1560 case LOG_QUOTE_BRAKETS
:
1561 entry
->append("[", 1);
1565 entry
->append("#", 1);
1569 entry
->append("'", 1);
1572 case LOG_QUOTE_NONE
:
1577 entry
->append("-", 1);
1580 entry
->append("0", 1);
1583 storeAppendPrintf(entry
, "%d", (int) t
->width
);
1586 storeAppendPrintf(entry
, ".%d", (int) t
->precision
);
1589 storeAppendPrintf(entry
, "{%s}", arg
);
1591 for (te
= logformat_token_table
; te
->config
!= NULL
; te
++) {
1592 if (te
->token_type
== type
) {
1593 storeAppendPrintf(entry
, "%s", te
->config
);
1599 entry
->append(" ", 1);
1601 assert(te
->config
!= NULL
);
1605 entry
->append("\n", 1);
1611 accessLogFreeLogFormat(logformat_token
** tokens
)
1614 logformat_token
*token
= *tokens
;
1615 *tokens
= token
->next
;
1616 safe_free(token
->data
.string
);
1622 accessLogSquid(AccessLogEntry
* al
, Logfile
* logfile
)
1624 const char *client
= NULL
;
1625 const char *user
= NULL
;
1626 char buf
[MAX_IPSTRLEN
];
1628 if (Config
.onoff
.log_fqdn
) {
1629 client
= fqdncache_gethostbyaddr(al
->cache
.caddr
, FQDN_LOOKUP_IF_MISS
);
1632 if (client
== NULL
) {
1633 client
= al
->cache
.caddr
.NtoA(buf
,MAX_IPSTRLEN
);
1636 user
= accessLogFormatName(al
->cache
.authuser
);
1639 user
= accessLogFormatName(al
->cache
.extuser
);
1644 user
= accessLogFormatName(al
->cache
.ssluser
);
1649 user
= accessLogFormatName(al
->cache
.rfc931
);
1654 if (!Config
.onoff
.log_mime_hdrs
) {
1655 logfilePrintf(logfile
, "%9ld.%03d %6d %s %s/%03d %"PRId64
" %s %s %s %s%s/%s %s\n",
1656 (long int) current_time
.tv_sec
,
1657 (int) current_time
.tv_usec
/ 1000,
1660 log_tags
[al
->cache
.code
],
1662 al
->cache
.replySize
,
1663 al
->_private
.method_str
,
1665 user
? user
: dash_str
,
1666 al
->hier
.ping
.timedout
? "TIMEOUT_" : "",
1667 hier_code_str
[al
->hier
.code
],
1669 al
->http
.content_type
);
1671 char *ereq
= log_quote(al
->headers
.request
);
1672 char *erep
= log_quote(al
->headers
.reply
);
1673 logfilePrintf(logfile
, "%9ld.%03d %6d %s %s/%03d %"PRId64
" %s %s %s %s%s/%s %s [%s] [%s]\n",
1674 (long int) current_time
.tv_sec
,
1675 (int) current_time
.tv_usec
/ 1000,
1678 log_tags
[al
->cache
.code
],
1680 al
->cache
.replySize
,
1681 al
->_private
.method_str
,
1683 user
? user
: dash_str
,
1684 al
->hier
.ping
.timedout
? "TIMEOUT_" : "",
1685 hier_code_str
[al
->hier
.code
],
1687 al
->http
.content_type
,
1697 accessLogCommon(AccessLogEntry
* al
, Logfile
* logfile
)
1699 const char *client
= NULL
;
1700 char *user1
= NULL
, *user2
= NULL
;
1701 char buf
[MAX_IPSTRLEN
];
1703 if (Config
.onoff
.log_fqdn
) {
1704 client
= fqdncache_gethostbyaddr(al
->cache
.caddr
, 0);
1707 if (client
== NULL
) {
1708 client
= al
->cache
.caddr
.NtoA(buf
,MAX_IPSTRLEN
);
1711 user1
= accessLogFormatName(al
->cache
.authuser
);
1713 user2
= accessLogFormatName(al
->cache
.rfc931
);
1715 logfilePrintf(logfile
, "%s %s %s [%s] \"%s %s HTTP/%d.%d\" %d %"PRId64
" %s:%s",
1717 user2
? user2
: dash_str
,
1718 user1
? user1
: dash_str
,
1719 mkhttpdlogtime(&squid_curtime
),
1720 al
->_private
.method_str
,
1722 al
->http
.version
.major
, al
->http
.version
.minor
,
1724 al
->cache
.replySize
,
1725 log_tags
[al
->cache
.code
],
1726 hier_code_str
[al
->hier
.code
]);
1732 if (Config
.onoff
.log_mime_hdrs
) {
1733 char *ereq
= log_quote(al
->headers
.request
);
1734 char *erep
= log_quote(al
->headers
.reply
);
1735 logfilePrintf(logfile
, " [%s] [%s]\n", ereq
, erep
);
1739 logfilePrintf(logfile
, "\n");
1746 accessLogICAPSquid(AccessLogEntry
* al
, Logfile
* logfile
)
1748 const char *client
= NULL
;
1749 const char *user
= NULL
;
1750 char tmp
[MAX_IPSTRLEN
], clientbuf
[MAX_IPSTRLEN
];
1752 if (al
->cache
.caddr
.IsAnyAddr()) { // ICAP OPTIONS xactions lack client
1755 if (Config
.onoff
.log_fqdn
)
1756 client
= fqdncache_gethostbyaddr(al
->cache
.caddr
, FQDN_LOOKUP_IF_MISS
);
1758 client
= al
->cache
.caddr
.NtoA(clientbuf
, MAX_IPSTRLEN
);
1761 user
= accessLogFormatName(al
->cache
.authuser
);
1764 user
= accessLogFormatName(al
->cache
.extuser
);
1769 user
= accessLogFormatName(al
->cache
.ssluser
);
1774 user
= accessLogFormatName(al
->cache
.rfc931
);
1779 logfilePrintf(logfile
, "%9ld.%03d %6d %s -/%03d %"PRId64
" %s %s %s -/%s -\n",
1780 (long int) current_time
.tv_sec
,
1781 (int) current_time
.tv_usec
/ 1000,
1788 Adaptation::Icap::ICAP::methodStr(al
->icap
.reqMethod
),
1789 al
->icap
.reqUri
.termedBuf(),
1790 user
? user
: dash_str
,
1791 al
->icap
.hostAddr
.NtoA(tmp
, MAX_IPSTRLEN
));
1797 accessLogLogTo(customlog
* log
, AccessLogEntry
* al
, ACLChecklist
* checklist
)
1800 if (al
->url
== NULL
)
1803 if (!al
->http
.content_type
|| *al
->http
.content_type
== '\0')
1804 al
->http
.content_type
= dash_str
;
1807 al
->_private
.method_str
= icp_opcode_str
[al
->icp
.opcode
];
1808 else if (al
->htcp
.opcode
)
1809 al
->_private
.method_str
= al
->htcp
.opcode
;
1811 al
->_private
.method_str
= RequestMethodStr(al
->http
.method
);
1813 if (al
->hier
.host
[0] == '\0')
1814 xstrncpy(al
->hier
.host
, dash_str
, SQUIDHOSTNAMELEN
);
1816 for (; log
; log
= log
->next
) {
1817 if (checklist
&& log
->aclList
&& !checklist
->matchAclListFast(log
->aclList
))
1820 switch (log
->type
) {
1824 if (Config
.onoff
.common_log
)
1825 accessLogCommon(al
, log
->logfile
);
1827 accessLogSquid(al
, log
->logfile
);
1832 accessLogSquid(al
, log
->logfile
);
1837 accessLogCommon(al
, log
->logfile
);
1842 accessLogCustom(al
, log
);
1847 case CLF_ICAP_SQUID
:
1848 accessLogICAPSquid(al
, log
->logfile
);
1857 fatalf("Unknown log format %d\n", log
->type
);
1862 logfileFlush(log
->logfile
);
1869 (void)0; /* NULL statement for label */
1873 accessLogLog(AccessLogEntry
* al
, ACLChecklist
* checklist
)
1875 if (LogfileStatus
!= LOG_ENABLE
)
1878 accessLogLogTo(Config
.Log
.accesslogs
, al
, checklist
);
1879 #if MULTICAST_MISS_STREAM
1881 if (al
->cache
.code
!= LOG_TCP_MISS
)
1883 else if (al
->http
.method
!= METHOD_GET
)
1885 else if (mcast_miss_fd
< 0)
1888 unsigned int ibuf
[365];
1890 xstrncpy((char *) ibuf
, al
->url
, 364 * sizeof(int));
1891 isize
= ((strlen(al
->url
) + 8) / 8) * 2;
1896 mcast_encode((unsigned int *) ibuf
, isize
,
1897 (const unsigned int *) Config
.mcast_miss
.encode_key
);
1899 comm_udp_sendto(mcast_miss_fd
,
1900 &mcast_miss_to
, sizeof(mcast_miss_to
),
1901 ibuf
, isize
* sizeof(int));
1908 accessLogRotate(void)
1916 for (log
= Config
.Log
.accesslogs
; log
; log
= log
->next
) {
1918 logfileRotate(log
->logfile
);
1924 logfileRotate(headerslog
);
1930 accessLogClose(void)
1934 for (log
= Config
.Log
.accesslogs
; log
; log
= log
->next
) {
1936 logfileClose(log
->logfile
);
1937 log
->logfile
= NULL
;
1943 logfileClose(headerslog
);
1950 HierarchyLogEntry::HierarchyLogEntry() :
1952 cd_lookup(LOOKUP_NONE
),
1955 peer_reply_status(HTTP_STATUS_NONE
),
1956 peer_response_time(-1),
1957 total_response_time(-1)
1959 memset(host
, '\0', SQUIDHOSTNAMELEN
);
1960 memset(cd_host
, '\0', SQUIDHOSTNAMELEN
);
1962 peer_select_start
.tv_sec
=0;
1963 peer_select_start
.tv_usec
=0;
1965 store_complete_stop
.tv_sec
=0;
1966 store_complete_stop
.tv_usec
=0;
1968 peer_http_request_sent
.tv_sec
= 0;
1969 peer_http_request_sent
.tv_usec
= 0;
1971 first_conn_start
.tv_sec
= 0;
1972 first_conn_start
.tv_usec
= 0;
1976 hierarchyNote(HierarchyLogEntry
* hl
,
1978 const char *cache_peer
)
1982 xstrncpy(hl
->host
, cache_peer
, SQUIDHOSTNAMELEN
);
1986 accessLogRegisterWithCacheManager(void)
1989 fvdbRegisterWithCacheManager();
1998 accessLogRegisterWithCacheManager();
2000 assert(sizeof(log_tags
) == (LOG_TYPE_MAX
+ 1) * sizeof(char *));
2002 for (log
= Config
.Log
.accesslogs
; log
; log
= log
->next
) {
2003 if (log
->type
== CLF_NONE
)
2006 log
->logfile
= logfileOpen(log
->filename
, MAX_URL
<< 1, 1);
2008 LogfileStatus
= LOG_ENABLE
;
2010 #if USE_ADAPTATION || ICAP_CLIENT
2011 alLogformatHasAdaptToken
= false;
2012 alLogformatHasIcapToken
= false;
2013 for (logformat_token
* curr_token
= (log
->logFormat
?log
->logFormat
->format
:NULL
); curr_token
; curr_token
= curr_token
->next
)
2016 if (curr_token
->type
== LTF_ADAPTATION_SUM_XACT_TIMES
||
2017 curr_token
->type
== LTF_ADAPTATION_ALL_XACT_TIMES
) {
2018 alLogformatHasAdaptToken
= true;
2022 if (curr_token
->type
== LFT_ICAP_LAST_MATCHED_HEADER
||
2023 curr_token
->type
== LFT_ICAP_LAST_MATCHED_HEADER_ELEM
||
2024 curr_token
->type
== LFT_ICAP_LAST_MATCHED_ALL_HEADERS
)
2026 alLogformatHasIcapToken
= true;
2035 headerslog
= logfileOpen("/usr/local/squid/logs/headers.log", 512);
2037 assert(NULL
!= headerslog
);
2040 #if MULTICAST_MISS_STREAM
2042 if (Config
.mcast_miss
.addr
.s_addr
!= no_addr
.s_addr
) {
2043 memset(&mcast_miss_to
, '\0', sizeof(mcast_miss_to
));
2044 mcast_miss_to
.sin_family
= AF_INET
;
2045 mcast_miss_to
.sin_port
= htons(Config
.mcast_miss
.port
);
2046 mcast_miss_to
.sin_addr
.s_addr
= Config
.mcast_miss
.addr
.s_addr
;
2047 mcast_miss_fd
= comm_open(SOCK_DGRAM
,
2049 Config
.Addrs
.udp_incoming
,
2050 Config
.mcast_miss
.port
,
2052 "Multicast Miss Stream");
2054 if (mcast_miss_fd
< 0)
2055 fatal("Cannot open Multicast Miss Stream Socket");
2057 debugs(46, 1, "Multicast Miss Stream Socket opened on FD " << mcast_miss_fd
);
2059 mcastSetTtl(mcast_miss_fd
, Config
.mcast_miss
.ttl
);
2061 if (strlen(Config
.mcast_miss
.encode_key
) < 16)
2062 fatal("mcast_encode_key is too short, must be 16 characters");
2074 accessLogTime(time_t t
)
2078 static char buf
[128];
2079 static time_t last_t
= 0;
2083 strftime(buf
, 127, "%Y/%m/%d %H:%M:%S", tm
);
2096 via_table
= hash_create((HASHCMP
*) strcmp
, 977, hash4
);
2097 forw_table
= hash_create((HASHCMP
*) strcmp
, 977, hash4
);
2101 fvdbRegisterWithCacheManager(void)
2103 CacheManager
*manager
=CacheManager::GetInstance();
2104 manager
->registerAction("via_headers", "Via Request Headers", fvdbDumpVia
, 0, 1);
2105 manager
->registerAction("forw_headers", "X-Forwarded-For Request Headers",
2106 fvdbDumpForw
, 0, 1);
2110 fvdbCount(hash_table
* hash
, const char *key
)
2117 fv
= (fvdb_entry
*)hash_lookup(hash
, key
);
2120 fv
= static_cast <fvdb_entry
*>(xcalloc(1, sizeof(fvdb_entry
)));
2121 fv
->hash
.key
= xstrdup(key
);
2122 hash_join(hash
, &fv
->hash
);
2129 fvdbCountVia(const char *key
)
2131 fvdbCount(via_table
, key
);
2135 fvdbCountForw(const char *key
)
2137 fvdbCount(forw_table
, key
);
2141 fvdbDumpTable(StoreEntry
* e
, hash_table
* hash
)
2151 while ((h
= hash_next(hash
))) {
2152 fv
= (fvdb_entry
*) h
;
2153 storeAppendPrintf(e
, "%9d %s\n", fv
->n
, hashKeyStr(&fv
->hash
));
2158 fvdbDumpVia(StoreEntry
* e
)
2160 fvdbDumpTable(e
, via_table
);
2164 fvdbDumpForw(StoreEntry
* e
)
2166 fvdbDumpTable(e
, forw_table
);
2171 fvdbFreeEntry(void *data
)
2173 fvdb_entry
*fv
= static_cast <fvdb_entry
*>(data
);
2174 xfree(fv
->hash
.key
);
2181 hashFreeItems(via_table
, fvdbFreeEntry
);
2182 hashFreeMemory(via_table
);
2183 via_table
= hash_create((HASHCMP
*) strcmp
, 977, hash4
);
2184 hashFreeItems(forw_table
, fvdbFreeEntry
);
2185 hashFreeMemory(forw_table
);
2186 forw_table
= hash_create((HASHCMP
*) strcmp
, 977, hash4
);
2191 #if MULTICAST_MISS_STREAM
2193 * From http://www.io.com/~paulhart/game/algorithms/tea.html
2195 * size of 'ibuf' must be a multiple of 2.
2196 * size of 'key' must be 4.
2197 * 'ibuf' is modified in place, encrypted data is written in
2198 * network byte order.
2201 mcast_encode(unsigned int *ibuf
, size_t isize
, const unsigned int *key
)
2206 const unsigned int delta
= 0x9e3779b9;
2207 unsigned int n
= 32;
2208 const unsigned int k0
= htonl(key
[0]);
2209 const unsigned int k1
= htonl(key
[1]);
2210 const unsigned int k2
= htonl(key
[2]);
2211 const unsigned int k3
= htonl(key
[3]);
2214 for (i
= 0; i
< isize
; i
+= 2) {
2216 z
= htonl(ibuf
[i
+ 1]);
2219 for (n
= 32; n
; n
--) {
2221 y
+= (z
<< 4) + (k0
^ z
) + (sum
^ (z
>> 5)) + k1
;
2222 z
+= (y
<< 4) + (k2
^ y
) + (sum
^ (y
>> 5)) + k3
;
2226 ibuf
[i
+ 1] = htonl(z
);
2234 headersLog(int cs
, int pq
, const HttpRequestMethod
& method
, void *data
)
2238 unsigned short magic
= 0;
2239 unsigned char M
= (unsigned char) m
;
2249 hmask
= rep
->header
.mask
;
2251 if (rep
->cache_control
)
2252 ccmask
= rep
->cache_control
->mask
;
2258 hmask
= req
->header
.mask
;
2260 if (req
->cache_control
)
2261 ccmask
= req
->cache_control
->mask
;
2272 magic
= htons(magic
);
2273 ccmask
= htonl(ccmask
);
2276 S
= (unsigned short) rep
->sline
.status
;
2278 S
= (unsigned short) HTTP_STATUS_NONE
;
2280 logfileWrite(headerslog
, &magic
, sizeof(magic
));
2282 logfileWrite(headerslog
, &M
, sizeof(M
));
2284 logfileWrite(headerslog
, &S
, sizeof(S
));
2286 logfileWrite(headerslog
, hmask
, sizeof(HttpHeaderMask
));
2288 logfileWrite(headerslog
, &ccmask
, sizeof(int));
2290 logfileFlush(headerslog
);
2296 accessLogFreeMemory(AccessLogEntry
* aLogEntry
)
2298 safe_free(aLogEntry
->headers
.request
);
2301 safe_free(aLogEntry
->headers
.icap
);
2304 safe_free(aLogEntry
->headers
.reply
);
2305 safe_free(aLogEntry
->cache
.authuser
);
2307 HTTPMSGUNLOCK(aLogEntry
->reply
);
2308 HTTPMSGUNLOCK(aLogEntry
->request
);
2310 HTTPMSGUNLOCK(aLogEntry
->icap
.reply
);
2311 HTTPMSGUNLOCK(aLogEntry
->icap
.request
);
2316 logTypeIsATcpHit(log_type code
)
2318 /* this should be a bitmap for better optimization */
2320 if (code
== LOG_TCP_HIT
)
2323 if (code
== LOG_TCP_IMS_HIT
)
2326 if (code
== LOG_TCP_REFRESH_FAIL
)
2329 if (code
== LOG_TCP_REFRESH_UNMODIFIED
)
2332 if (code
== LOG_TCP_NEGATIVE_HIT
)
2335 if (code
== LOG_TCP_MEM_HIT
)
2338 if (code
== LOG_TCP_OFFLINE_HIT
)