------------------------------------------------------------ revno: 10155 revision-id: squid3@treenet.co.nz-20091122203727-25btbtui2sypm24z parent: henrik@henriknordstrom.net-20091121221631-2wvw10p81njsz989 committer: Amos Jeffries branch nick: trunk timestamp: Mon 2009-11-23 09:37:27 +1300 message: Author: Adrian Chadd Author: Tim Starling Port from 2.7: Logging infrastructure updates. * Basic port of the Squid-2.7 modular logging code * Adds support for async daemon helpers. * One daemon helper for file IO is included. * Adds UDP stream logging facility. (Tim Starling) Ported by Amos Jeffries. ------------------------------------------------------------ # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: squid3@treenet.co.nz-20091122203727-25btbtui2sypm24z # target_branch: http://www.squid-cache.org/bzr/squid3/trunk/ # testament_sha1: f2e67d435462bc53c86aae308dcc6ce20838442a # timestamp: 2009-11-22 20:50:52 +0000 # source_branch: http://www.squid-cache.org/bzr/squid3/trunk/ # base_revision_id: henrik@henriknordstrom.net-20091121221631-\ # 2wvw10p81njsz989 # # Begin patch === modified file 'configure.in' --- configure.in 2009-11-20 20:00:06 +0000 +++ configure.in 2009-11-22 20:37:27 +0000 @@ -1894,6 +1894,47 @@ fi AC_SUBST(DIGEST_AUTH_HELPERS) +dnl Select logging daemon helpers to build +LOG_DAEMON_HELPERS="all" +AC_ARG_ENABLE(log-daemon-helpers, + AS_HELP_STRING([--enable-log-daemon-auth-helpers="list of helpers"],[This option selects which logging daemon + helpers to build and install as part of the normal build process. For a list of available + helpers see the helpers/log_daemon directory.]), +[ case "$enableval" in + yes) + LOG_DAEMON_HELPERS="all" + ;; + no) + LOG_DAEMON_HELPERS="" + ;; + *) + LOG_DAEMON_HELPERS="`echo $enableval| sed -e 's/,/ /g;s/ */ /g'`" + ;; + esac +]) +if test "$LOG_DAEMON_HELPERS" = "all" ; then + LOG_DAEMON_HELPERS="" + for dir in $srcdir/helpers/log_daemon/*; do + helper="`basename $dir`" + if test -f $dir/config.test && sh $dir/config.test "$@"; then + LOG_DAEMON_HELPERS="$LOG_DAEMON_HELPERS $helper" + elif test -d $srcdir/helpers/log_daemon/$helper ; then + AC_MSG_NOTICE([Log daemon auth helper $helper ... found but cannot be built]) + fi + done +fi +if test -n "$LOG_DAEMON_HELPERS"; then + for helper in $LOG_DAEMON_HELPERS; do + if test -d $srcdir/helpers/log_daemon/$helper; then + : + else + AC_MSG_ERROR(Log daemon helper $helper does not exist) + fi + done + AC_MSG_NOTICE([Log daemon helpers built: $LOG_DAEMON_HELPERS]) +fi +AC_SUBST(LOG_DAEMON_HELPERS) + dnl dnl Check Kerberos/GSSAPI/SPNEGO dnl @@ -4240,6 +4281,7 @@ src/icmp/Makefile \ src/ident/Makefile \ src/ip/Makefile \ + src/log/Makefile \ contrib/Makefile \ snmplib/Makefile \ icons/Makefile \ @@ -4283,6 +4325,8 @@ helpers/external_acl/wbinfo_group/Makefile \ helpers/external_acl/mswin_ad_group/Makefile \ helpers/external_acl/mswin_lm_group/Makefile \ + helpers/log_daemon/Makefile \ + helpers/log_daemon/file/Makefile \ helpers/url_rewrite/Makefile \ helpers/url_rewrite/fake/Makefile \ tools/Makefile === modified file 'doc/release-notes/release-3.2.sgml' --- doc/release-notes/release-3.2.sgml 2009-11-05 09:49:21 +0000 +++ doc/release-notes/release-3.2.sgml 2009-11-22 20:37:27 +0000 @@ -309,6 +309,9 @@ network Only objects fetched from network is kept in memory + logfile_daemon +

Ported from 2.7 + Changes to existing tags

Replaced by url_rewrite_bypass + upgrade_http0.9 +

Obsolete. + zph_local

Replaced by qos_flows local-hit= @@ -583,9 +589,6 @@ location_rewrite_program

Not yet ported from 2.6 - logfile_daemon -

Not yet ported from 2.7 - logformat

%oa tag not yet ported from 2.7 @@ -622,9 +625,6 @@ update_headers

Not yet ported from 2.7 - upgrade_http0.9 -

Not yet ported from 2.7 - zero_buffers

Not yet ported from 2.7 === modified file 'helpers/Makefile.am' --- helpers/Makefile.am 2009-08-28 04:14:35 +0000 +++ helpers/Makefile.am 2009-11-22 20:37:27 +0000 @@ -1,1 +1,8 @@ -SUBDIRS = basic_auth ntlm_auth digest_auth negotiate_auth external_acl url_rewrite +SUBDIRS = \ + basic_auth \ + digest_auth \ + external_acl \ + log_daemon \ + negotiate_auth \ + ntlm_auth \ + url_rewrite === added directory 'helpers/log_daemon' === added file 'helpers/log_daemon/Makefile.am' --- helpers/log_daemon/Makefile.am 1970-01-01 00:00:00 +0000 +++ helpers/log_daemon/Makefile.am 2009-11-22 20:37:27 +0000 @@ -0,0 +1,5 @@ +## Alphabetical list of sub-directories to distribute with Squid: +DIST_SUBDIRS = \ + file + +SUBDIRS = $(LOG_DAEMON_HELPERS) === added directory 'helpers/log_daemon/file' === added file 'helpers/log_daemon/file/Makefile.am' --- helpers/log_daemon/file/Makefile.am 1970-01-01 00:00:00 +0000 +++ helpers/log_daemon/file/Makefile.am 2009-11-22 20:37:27 +0000 @@ -0,0 +1,4 @@ +include $(top_srcdir)/src/Common.am + +libexec_PROGRAMS = log_file_daemon +log_file_daemon_SOURCES = log_file_daemon.cc === added file 'helpers/log_daemon/file/config.test' --- helpers/log_daemon/file/config.test 1970-01-01 00:00:00 +0000 +++ helpers/log_daemon/file/config.test 2009-11-22 20:37:27 +0000 @@ -0,0 +1,2 @@ +#!/bin/sh +exit 0 === added file 'helpers/log_daemon/file/log_file_daemon.cc' --- helpers/log_daemon/file/log_file_daemon.cc 1970-01-01 00:00:00 +0000 +++ helpers/log_daemon/file/log_file_daemon.cc 2009-11-22 20:37:27 +0000 @@ -0,0 +1,154 @@ +#include "config.h" + +#if HAVE_STDIO_H +#include +#endif +#if HAVE_STDLIB_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_FCNTL_H +#include +#endif +#if HAVE_ASSERT_H +#include +#endif +#if HAVE_SYS_PARAM_H +#include +#endif +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SIGNAL_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#if HAVE_STRING_H +#include +#endif +#if HAVE_PATHS_H +#include +#endif + +#include "defines.h" + +/* parse buffer - ie, length of longest expected line */ +#define LOGFILE_BUF_LEN 65536 + +static void +rotate(const char *path, int rotate_count) +{ +#ifdef S_ISREG + struct stat sb; +#endif + int i; + char from[MAXPATHLEN]; + char to[MAXPATHLEN]; + assert(path); +#ifdef S_ISREG + if (stat(path, &sb) == 0) + if (S_ISREG(sb.st_mode) == 0) + return; +#endif + /* Rotate numbers 0 through N up one */ + for (i = rotate_count; i > 1;) { + i--; + snprintf(from, MAXPATHLEN, "%s.%d", path, i - 1); + snprintf(to, MAXPATHLEN, "%s.%d", path, i); +#if defined(_SQUID_OS2_) || defined(_SQUID_WIN32_) + remove(to); +#endif + rename(from, to); + } + if (rotate_count > 0) { + snprintf(to, MAXPATHLEN, "%s.%d", path, 0); +#if defined(_SQUID_OS2_) || defined(_SQUID_WIN32_) + remove(to); +#endif + rename(path, to); + } +} + +/** + * The commands: + * + * L\n - logfile data + * R\n - rotate file + * T\n - truncate file + * O\n - repoen file + * F\n - flush file + * r\n - set rotate count to + * b\n - 1 = buffer output, 0 = don't buffer output + */ +int +main(int argc, char *argv[]) +{ + int t; + FILE *fp; + char buf[LOGFILE_BUF_LEN]; + int rotate_count = 10; + int do_buffer = 1; + + if (argc < 2) { + printf("Error: usage: %s \n", argv[0]); + exit(1); + } + fp = fopen(argv[1], "a"); + if (fp == NULL) { + perror("fopen"); + exit(1); + } + setbuf(stdout, NULL); + close(2); + t = open(_PATH_DEVNULL, O_RDWR); + assert(t > -1); + dup2(t, 2); + + while (fgets(buf, LOGFILE_BUF_LEN, stdin)) { + /* First byte indicates what we're logging! */ + switch (buf[0]) { + case 'L': + if (buf[1] != '\0') { + fprintf(fp, "%s", buf + 1); + } + if (!do_buffer) + fflush(fp); + break; + case 'R': + fclose(fp); + rotate(argv[1], rotate_count); + fp = fopen(argv[1], "a"); + if (fp == NULL) { + perror("fopen"); + exit(1); + } + break; + case 'T': + break; + case 'O': + break; + case 'r': + //fprintf(fp, "SET ROTATE: %s\n", buf + 1); + rotate_count = atoi(buf + 1); + break; + case 'b': + //fprintf(fp, "SET BUFFERED: %s\n", buf + 1); + do_buffer = (buf[1] == '1'); + break; + case 'F': + fflush(fp); + break; + default: + /* Just in case .. */ + fprintf(fp, "%s", buf); + break; + } + } + fclose(fp); + fp = NULL; + exit(0); +} === modified file 'include/config.h' --- include/config.h 2009-02-14 13:18:34 +0000 +++ include/config.h 2009-11-22 20:37:27 +0000 @@ -262,6 +262,8 @@ #define LEAK_CHECK_MODE 1 #endif +/* temp hack: needs to be pre-defined for now. */ +#define SQUID_MAXPATHLEN 256 /* * strnstr() is needed. The OS may not provide a working copy. === modified file 'src/Makefile.am' --- src/Makefile.am 2009-11-21 22:16:31 +0000 +++ src/Makefile.am 2009-11-22 20:37:27 +0000 @@ -34,7 +34,7 @@ LoadableModules.h \ LoadableModules.cc -SUBDIRS = base eui acl fs repl auth ip icmp ident +SUBDIRS = base eui acl fs repl auth ip icmp ident log if USE_ADAPTATION SUBDIRS += adaptation @@ -258,7 +258,6 @@ squid_SOURCES = \ $(ACL_REGISTRATION_SOURCES) \ - access_log.cc \ AccessLogEntry.h \ AsyncEngine.cc \ AsyncEngine.h \ @@ -371,7 +370,6 @@ ipcache.cc \ $(LEAKFINDERSOURCE) \ list.cc \ - logfile.cc \ lookup_t.h \ main.cc \ mem.cc \ @@ -534,6 +532,7 @@ $(COMMON_LIBS) \ eui/libeui.la \ icmp/libicmp.la icmp/libicmp-core.la \ + log/liblog.la \ $(XTRA_OBJS) \ $(DISK_LINKOBJS) \ $(REPL_OBJS) \ @@ -577,7 +576,7 @@ unlinkd_SOURCES = unlinkd_daemon.cc SquidNew.cc -dnsserver_SOURCES = dnsserver.cc SquidNew.cc +dnsserver_SOURCES = dnsserver.cc SquidNew.cc test_tools.cc time.cc recv_announce_SOURCES = recv-announce.cc SquidNew.cc ## What requires what.. @@ -609,6 +608,7 @@ MemBuf.cc \ MemBuf.cci \ MemBuf.h \ + Parsing.h \ store_key_md5.cc \ StoreMeta.cc \ StoreMetaMD5.cc \ @@ -635,7 +635,7 @@ $(REGEXLIB) \ $(SNMPLIB) \ $(SSLLIB) \ - -L$(top_builddir)/lib -lmiscutil \ + $(COMPAT_LIB) \ $(EPOLL_LIBS) \ $(MINGW_LIBS) \ $(XTRA_LIBS) @@ -656,7 +656,7 @@ data_DATA = \ mib.txt -LDADD = $(COMMON_LIBS)\ +LDADD = $(COMMON_LIBS) \ -L../lib \ -lmiscutil \ $(EPOLL_LIBS) \ @@ -734,6 +734,7 @@ DEFAULT_SWAP_DIR = $(localstatedir)/cache DEFAULT_PINGER = $(libexecdir)/`echo pinger | sed '$(transform);s/$$/$(EXEEXT)/'` DEFAULT_UNLINKD = $(libexecdir)/`echo unlinkd | sed '$(transform);s/$$/$(EXEEXT)/'` +DEFAULT_LOGFILED = $(libexecdir)/`echo log_file_daemon | sed '$(transform);s/$$/$(EXEEXT)/'` DEFAULT_DISKD = $(libexecdir)/`echo diskd | sed '$(transform);s/$$/$(EXEEXT)/'` DEFAULT_ICON_DIR = $(datadir)/icons DEFAULT_ERROR_DIR = $(datadir)/errors @@ -798,6 +799,7 @@ -e "s%[@]DEFAULT_UNLINKD[@]%$(DEFAULT_UNLINKD)%g" \ -e "s%[@]DEFAULT_PINGER[@]%$(DEFAULT_PINGER)%g" \ -e "s%[@]DEFAULT_DISKD[@]%$(DEFAULT_DISKD)%g" \ + -e "s%[@]DEFAULT_LOGFILED[@]%$(DEFAULT_LOGFILED)%g;" \ -e "s%[@]DEFAULT_CACHE_LOG[@]%$(DEFAULT_CACHE_LOG)%g" \ -e "s%[@]DEFAULT_ACCESS_LOG[@]%$(DEFAULT_ACCESS_LOG)%g" \ -e "s%[@]DEFAULT_STORE_LOG[@]%$(DEFAULT_STORE_LOG)%g" \ @@ -968,20 +970,20 @@ tests/stub_MemObject.cc mem_node.cc \ tests/stub_cache_manager.cc \ stmem.cc \ - tests/stub_comm.cc \ - tests/stub_http.cc \ HttpMsg.cc \ HttpRequestMethod.cc \ - tests/stub_mime.cc \ tests/stub_access_log.cc \ + tests/stub_comm.cc \ + tests/stub_http.cc \ + tests/stub_mime.cc \ time.cc \ URLScheme.cc \ $(TEST_CALL_SOURCES) \ wordlist.cc ## acl.cc cache_cf.cc tools.cc \ ## helper.cc String.cc cbdata.cc HttpHeaderTools.cc store.cc cache_manager.cc \ -## HttpHeader.cc url.cc mem.cc HttpRequest.cc Packer.cc access_log.cc \ -## MemBuf.cc StatHist.cc logfile.cc +## HttpHeader.cc url.cc mem.cc HttpRequest.cc Packer.cc \ +## MemBuf.cc StatHist.cc nodist_tests_testAuth_SOURCES = \ $(TESTSOURCES) @@ -1088,7 +1090,6 @@ tests/testCacheManager.h \ tests/testMain.cc \ time.cc \ - access_log.cc \ BodyPipe.cc \ cache_manager.cc \ cache_cf.cc \ @@ -1144,7 +1145,6 @@ int.cc \ internal.cc \ list.cc \ - logfile.cc \ multicast.cc \ mem_node.cc \ MemBuf.cc \ @@ -1208,6 +1208,7 @@ tests_testCacheManager_LDADD = \ $(COMMON_LIBS) \ icmp/libicmp.la icmp/libicmp-core.la \ + log/liblog.la \ $(REPL_OBJS) \ ${ADAPTATION_LIBS} \ $(ESI_LIBS) \ @@ -1262,7 +1263,6 @@ tests/testEvent.h \ tests/testMain.cc \ time.cc \ - access_log.cc \ BodyPipe.cc \ cache_manager.cc \ cache_cf.cc \ @@ -1318,7 +1318,6 @@ int.cc \ internal.cc \ list.cc \ - logfile.cc \ multicast.cc \ mem_node.cc \ MemBuf.cc \ @@ -1381,6 +1380,7 @@ tests_testEvent_LDADD = \ $(COMMON_LIBS) \ icmp/libicmp.la icmp/libicmp-core.la \ + log/liblog.la \ $(REPL_OBJS) \ ${ADAPTATION_LIBS} \ $(ESI_LIBS) \ @@ -1411,7 +1411,6 @@ tests/testEventLoop.h \ tests/testMain.cc \ time.cc \ - access_log.cc \ BodyPipe.cc \ cache_manager.cc \ cache_cf.cc \ @@ -1467,7 +1466,6 @@ int.cc \ internal.cc \ list.cc \ - logfile.cc \ multicast.cc \ mem_node.cc \ MemBuf.cc \ @@ -1530,6 +1528,7 @@ tests_testEventLoop_LDADD = \ $(COMMON_LIBS) \ icmp/libicmp.la icmp/libicmp-core.la \ + log/liblog.la \ $(REPL_OBJS) \ ${ADAPTATION_LIBS} \ $(ESI_LIBS) \ @@ -1548,7 +1547,6 @@ tests_test_http_range_SOURCES = \ tests/test_http_range.cc \ - access_log.cc \ BodyPipe.cc \ cache_cf.cc \ ProtoPort.cc \ @@ -1607,7 +1605,6 @@ $(IPC_SOURCE) \ ipcache.cc \ list.cc \ - logfile.cc \ mem.cc \ mem_node.cc \ MemObject.cc \ @@ -1674,6 +1671,7 @@ tests_test_http_range_LDADD = \ $(COMMON_LIBS) \ icmp/libicmp.la icmp/libicmp-core.la \ + log/liblog.la \ $(REPL_OBJS) \ ${ADAPTATION_LIBS} \ $(ESI_LIBS) \ @@ -1703,7 +1701,6 @@ tests/testHttpRequestMethod.cc \ tests/testMain.cc \ time.cc \ - access_log.cc \ BodyPipe.cc \ cache_manager.cc \ cache_cf.cc \ @@ -1759,7 +1756,6 @@ int.cc \ internal.cc \ list.cc \ - logfile.cc \ multicast.cc \ mem_node.cc \ MemBuf.cc \ @@ -1823,6 +1819,7 @@ tests_testHttpRequest_LDADD = \ $(COMMON_LIBS) \ icmp/libicmp.la icmp/libicmp-core.la \ + log/liblog.la \ $(REPL_OBJS) \ ${ADAPTATION_LIBS} \ $(ESI_LIBS) \ @@ -2061,7 +2058,6 @@ tests/testURLScheme.h \ tests/testMain.cc \ time.cc \ - access_log.cc \ BodyPipe.cc \ cache_manager.cc \ cache_cf.cc \ @@ -2117,7 +2113,6 @@ int.cc \ internal.cc \ list.cc \ - logfile.cc \ multicast.cc \ mem_node.cc \ MemBuf.cc \ @@ -2178,6 +2173,7 @@ tests_testURL_LDADD = \ $(COMMON_LIBS) \ icmp/libicmp.la icmp/libicmp-core.la \ + log/liblog.la \ $(REGEXLIB) \ $(REPL_OBJS) \ ${ADAPTATION_LIBS} \ === modified file 'src/Parsing.cc' --- src/Parsing.cc 2009-06-28 08:34:50 +0000 +++ src/Parsing.cc 2009-11-22 20:37:27 +0000 @@ -160,3 +160,55 @@ return false; } + +bool +GetHostWithPort(char *token, IpAddress *ipa) +{ + char *t; + char *host; + char *tmp; + unsigned short port; + + host = NULL; + port = 0; + +#if USE_IPV6 + if (*token == '[') { + /* [host]:port */ + host = token + 1; + t = strchr(host, ']'); + if (!t) + return false; + *t++ = '\0'; + if (*t != ':') + return false; + port = xatos(t + 1); + } else +#endif + if ((t = strchr(token, ':'))) { + /* host:port */ + host = token; + *t = '\0'; + port = xatos(t + 1); + + if (0 == port) + return false; + } else if ((port = strtol(token, &tmp, 10)), !*tmp) { + /* port */ + } else { + host = token; + port = 0; + } + + if (NULL == host) + ipa->SetAnyAddr(); + else if ( ipa->GetHostByName(host) ) /* dont use ipcache. Accept either FQDN or IPA. */ + (void) 0; + else + return false; + + /* port MUST be set after the IPA lookup/conversion is performed. */ + ipa->SetPort(port); + + return true; +} === modified file 'src/Parsing.h' --- src/Parsing.h 2009-06-28 08:34:50 +0000 +++ src/Parsing.h 2009-11-22 20:37:27 +0000 @@ -60,4 +60,12 @@ extern bool StringToInt(const char *str, int &result, const char **p, int base); extern bool StringToInt64(const char *str, int64_t &result, const char **p, int base); +/** + * Parse a socket address (host:port), fill the given IpAddress object + * \retval false Failure. + * \retval true Success. + * Destroys token during parse. + */ +extern bool GetHostWithPort(char *token, IpAddress *ipa); + #endif /* SQUID_PARSING_H */ === modified file 'src/adaptation/icap/icap_log.cc' --- src/adaptation/icap/icap_log.cc 2009-08-23 09:30:49 +0000 +++ src/adaptation/icap/icap_log.cc 2009-11-22 20:37:27 +0000 @@ -1,6 +1,7 @@ #include "squid.h" #include "icap_log.h" #include "AccessLogEntry.h" +#include "log/File.h" int IcapLogfileStatus = LOG_DISABLE; === modified file 'src/cache_cf.cc' --- src/cache_cf.cc 2009-11-09 11:25:11 +0000 +++ src/cache_cf.cc 2009-11-22 20:37:27 +0000 @@ -33,59 +33,62 @@ */ #include "squid.h" -#include "ProtoPort.h" -#include "HttpRequestMethod.h" + +#include "acl/Acl.h" +#include "acl/Gadgets.h" +#include "acl/MethodData.h" +#if USE_ADAPTATION +#include "adaptation/Config.h" +#endif +#if ICAP_CLIENT +#include "adaptation/icap/Config.h" +#endif +#if USE_ECAP +#include "adaptation/ecap/Config.h" +#endif #include "auth/Config.h" #include "auth/Scheme.h" #include "CacheManager.h" -#include "Store.h" -#include "SwapDir.h" #include "ConfigParser.h" -#include "acl/Acl.h" -#include "acl/MethodData.h" -#include "acl/Gadgets.h" -#include "StoreFileSystem.h" +#include "eui/Config.h" +#if USE_SQUID_ESI +#include "esi/Parser.h" +#endif +#include "HttpRequestMethod.h" +#include "ident/Config.h" +#include "ip/IpIntercept.h" +#include "log/Config.h" +#include "MemBuf.h" #include "Parsing.h" +#include "ProtoPort.h" #include "rfc1738.h" -#include "MemBuf.h" +#if SQUID_SNMP +#include "snmp.h" +#endif +#include "Store.h" +#include "StoreFileSystem.h" +#include "SwapDir.h" #include "wordlist.h" -#include "ident/Config.h" -#include "ip/IpIntercept.h" #if HAVE_GLOB_H #include #endif -#if SQUID_SNMP -#include "snmp.h" -#endif -#if USE_SQUID_ESI -#include "esi/Parser.h" -#endif -#include "eui/Config.h" - #if USE_ADAPTATION -#include "adaptation/Config.h" - static void parse_adaptation_service_set_type(); static void parse_adaptation_service_chain_type(); static void parse_adaptation_access_type(); - #endif #if ICAP_CLIENT -#include "adaptation/icap/Config.h" - static void parse_icap_service_type(Adaptation::Icap::Config *); static void dump_icap_service_type(StoreEntry *, const char *, const Adaptation::Icap::Config &); static void free_icap_service_type(Adaptation::Icap::Config *); static void parse_icap_class_type(); static void parse_icap_access_type(); - #endif #if USE_ECAP -#include "adaptation/ecap/Config.h" static void parse_ecap_service_type(Adaptation::Ecap::Config *); static void dump_ecap_service_type(StoreEntry *, const char *, const Adaptation::Ecap::Config &); static void free_ecap_service_type(Adaptation::Ecap::Config *); @@ -527,7 +530,7 @@ requirePathnameExists("unlinkd_program", Config.Program.unlinkd); #endif - + requirePathnameExists("logfile_daemon", Log::TheConfig.logfile_daemon); if (Config.Program.redirect) requirePathnameExists("redirect_program", Config.Program.redirect->key); @@ -2855,74 +2858,26 @@ } #if USE_WCCPv2 -void -parse_IpAddress_list_token(IpAddress_list ** head, char *token) +static void +parse_IpAddress_list(IpAddress_list ** head) { - char *t; - char *host; - char *tmp; - + char *token; + IpAddress_list *s; IpAddress ipa; - unsigned short port; - IpAddress_list *s; - - host = NULL; - port = 0; - -#if USE_IPV6 - if (*token == '[') { - /* [host]:port */ - host = token + 1; - t = strchr(host, ']'); - if (!t) - self_destruct(); - *t++ = '\0'; - if (*t != ':') - self_destruct(); - port = xatos(t + 1); - } else -#endif - if ((t = strchr(token, ':'))) { - /* host:port */ - host = token; - *t = '\0'; - port = xatos(t + 1); - - if (0 == port) - self_destruct(); - } else if ((port = strtol(token, &tmp, 10)), !*tmp) { - /* port */ - } else { - host = token; - port = 0; + + while ((token = strtok(NULL, w_space))) { + if (GetHostWithPort(token, &ipa)) { + + while (*head) + head = &(*head)->next; + + s = static_cast(xcalloc(1, sizeof(*s))); + s->s = ipa; + + *head = s; } - - if (NULL == host) - ipa.SetAnyAddr(); - else if ( ipa.GetHostByName(host) ) /* dont use ipcache. Accept either FQDN or IPA. */ - (void) 0; - else - self_destruct(); - - /* port MUST be set after the IPA lookup/conversion is perofrmed. */ - ipa.SetPort(port); - - while (*head) - head = &(*head)->next; - - s = static_cast(xcalloc(1, sizeof(*s))); - s->s = ipa; - - *head = s; -} - -static void -parse_IpAddress_list(IpAddress_list ** head) -{ - char *token; - - while ((token = strtok(NULL, w_space))) { - parse_IpAddress_list_token(head, token); + else + self_destruct(); } } === modified file 'src/cf.data.pre' --- src/cf.data.pre 2009-11-06 11:58:03 +0000 +++ src/cf.data.pre 2009-11-22 20:37:27 +0000 @@ -2546,32 +2546,49 @@ TYPE: access_log LOC: Config.Log.accesslogs DEFAULT: none -DEFAULT_IF_NONE: @DEFAULT_ACCESS_LOG@ squid +DEFAULT_IF_NONE: daemon:@DEFAULT_ACCESS_LOG@ squid DOC_START These files log client request activities. Has a line every HTTP or ICP request. The format is: - access_log [ [acl acl ...]] + access_log : [ [acl acl ...]] access_log none [acl acl ...]] - - Will log to the specified file using the specified format (which + + Will log to the specified module:place using the specified format (which must be defined in a logformat directive) those entries which match ALL the acl's specified (which must be defined in acl clauses). - If no acl is specified, all requests will be logged to this file. - - To disable logging of a request use the filepath "none", in which case - a logformat name should not be specified. - - To log the request via syslog specify a filepath of "syslog": - - access_log syslog[:facility.priority] [format [acl1 [acl2 ....]]] - where facility could be any of: - authpriv, daemon, local0 .. local7 or user. - - And priority could be any of: - err, warning, notice, info, debug. + If no acl is specified, all requests will be logged to this destination. + + ===== Modules Currently available ===== + + none Do not log any requests matchign these ACL. + Do not specify Place or logformat name. + + stdio Write each log line to disk immediately at the completion of + each request. + Place: the filename and path to be written. + + daemon Very similar to stdio. But instead of writing to disk the log + line is passed to a daemon helper for asychronous handling instead. + Place: varies depending on the daemon. + + log_file_daemon Place: the file name and path to be written. + + syslog To log each request via syslog facility. + Place: The syslog facility and priority level for these entries. + Place Format: facility.priority + + where facility could be any of: + authpriv, daemon, local0 ... local7 or user. + + And priority could be any of: + err, warning, notice, info, debug. + + udp To send each log line as text data to a UDP receiver. + Place: The destination host name or IP and port. + Place Format: \\host:port Default: - access_log @DEFAULT_ACCESS_LOG@ squid + access_log daemon:@DEFAULT_ACCESS_LOG@ squid DOC_END NAME: icap_log @@ -2656,6 +2673,15 @@ See also: logformat, log_icap, and %icap:: 'src/log/File.cc' --- src/logfile.cc 2009-09-16 09:53:46 +0000 +++ src/log/File.cc 2009-11-22 20:37:27 +0000 @@ -34,113 +34,54 @@ #include "squid.h" #include "fde.h" - -static void logfileWriteWrapper(Logfile * lf, const void *buf, size_t len); - -#if HAVE_SYSLOG - -/* Define LOG_AUTHPRIV as LOG_AUTH on systems still using the old deprecated LOG_AUTH */ -#if !defined(LOG_AUTHPRIV) && defined(LOG_AUTH) -#define LOG_AUTHPRIV LOG_AUTH -#endif - -struct syslog_symbol_t { - const char* name; - int value; -}; - -static int syslog_ntoa (const char* s) -{ -#define syslog_symbol(a) #a, a - static syslog_symbol_t _symbols[] = { - { syslog_symbol(LOG_AUTHPRIV) }, - { syslog_symbol(LOG_DAEMON) }, - { syslog_symbol(LOG_LOCAL0) }, - { syslog_symbol(LOG_LOCAL1) }, - { syslog_symbol(LOG_LOCAL2) }, - { syslog_symbol(LOG_LOCAL3) }, - { syslog_symbol(LOG_LOCAL4) }, - { syslog_symbol(LOG_LOCAL5) }, - { syslog_symbol(LOG_LOCAL6) }, - { syslog_symbol(LOG_LOCAL7) }, - { syslog_symbol(LOG_USER) }, - { syslog_symbol(LOG_ERR) }, - { syslog_symbol(LOG_WARNING) }, - { syslog_symbol(LOG_NOTICE) }, - { syslog_symbol(LOG_INFO) }, - { syslog_symbol(LOG_DEBUG) }, - { NULL, 0 } - }; - - for (syslog_symbol_t* p = _symbols; p->name != NULL; ++p) - if (!strcmp(s, p->name) || !strcasecmp(s, p->name+4)) - return p->value; - - debugs(1, 1, "Unknown syslog facility/priority '" << s << "'"); - - return 0; -} - -#define PRIORITY_MASK (LOG_ERR | LOG_WARNING | LOG_NOTICE | LOG_INFO | LOG_DEBUG) -#endif +#include "log/File.h" +#include "log/ModDaemon.h" +#include "log/ModStdio.h" +#include "log/ModSyslog.h" +#include "log/ModUdp.h" + +CBDATA_TYPE(Logfile); + Logfile * logfileOpen(const char *path, size_t bufsz, int fatal_flag) { - int fd; - Logfile *lf = static_cast(xcalloc(1, sizeof(*lf))); - + int ret; + const char *patharg; + + debugs(50, 1, "Logfile: opening log " << path); + CBDATA_INIT_TYPE(Logfile); + + Logfile *lf = cbdataAlloc(Logfile); xstrncpy(lf->path, path, MAXPATHLEN); - + patharg = path; + /* need to call the per-logfile-type code */ + if (strncmp(path, "stdio:", 6) == 0) { + patharg = path + 6; + ret = logfile_mod_stdio_open(lf, patharg, bufsz, fatal_flag); + } else if (strncmp(path, "daemon:", 7) == 0) { + patharg = path + 7; + ret = logfile_mod_daemon_open(lf, patharg, bufsz, fatal_flag); + } else if (strncmp(path, "udp:", 4) == 0) { + patharg = path + 4; + ret = logfile_mod_udp_open(lf, patharg, bufsz, fatal_flag); #if HAVE_SYSLOG - - if (strncmp(path, "syslog", 6) == 0) { - lf->flags.syslog = 1; - lf->syslog_priority = LOG_INFO; - lf->fd = -1; - - if (path[6] != '\0') { - path += 7; - char *priority = xstrdup(path); - char *facility = (char *) strchr(priority, '.'); - if (!facility) - facility = (char *) strchr(priority, '|'); - if (facility) { - *facility++ = '\0'; - lf->syslog_priority |= syslog_ntoa(facility); - } - lf->syslog_priority |= syslog_ntoa(priority); - xfree(priority); - if (0 == (lf->syslog_priority & PRIORITY_MASK)) - lf->syslog_priority |= LOG_INFO; - } - } else + } else if (strncmp(path, "syslog:", 7) == 0) { + patharg = path + 7; + ret = logfile_mod_syslog_open(lf, patharg, bufsz, fatal_flag); #endif - { - fd = file_open(path, O_WRONLY | O_CREAT | O_TEXT); - - if (DISK_ERROR == fd) { - if (ENOENT == errno && fatal_flag) { - fatalf("Cannot open '%s' because\n" - "\tthe parent directory does not exist.\n" - "\tPlease create the directory.\n", path); - } else if (EACCES == errno && fatal_flag) { - fatalf("Cannot open '%s' for writing.\n" - "\tThe parent directory must be writeable by the\n" - "\tuser '%s', which is the cache_effective_user\n" - "\tset in squid.conf.", path, Config.effectiveUser); - } else { - debugs(50, 1, "logfileOpen: " << path << ": " << xstrerror()); - return NULL; - } - } - - lf->fd = fd; - - if (bufsz > 0) { - lf->buf = (char *) xmalloc(bufsz); - lf->bufsz = bufsz; - } - } + } else { + ret = logfile_mod_stdio_open(lf, patharg, bufsz, fatal_flag); + } + if (!ret) { + if (fatal_flag) + fatalf("logfileOpen: path %s: couldn't open!\n", path); + else + debugs(50, 1, "logfileOpen: path " << path << ": couldn't open!"); + lf->f_close(lf); + cbdataFree(lf); + return NULL; + } + assert(lf->data != NULL); if (fatal_flag) lf->flags.fatal = 1; @@ -153,108 +94,23 @@ void logfileClose(Logfile * lf) { - logfileFlush(lf); - - if (lf->fd >= 0) - file_close(lf->fd); - - if (lf->buf) - xfree(lf->buf); - - xfree(lf); + debugs(50, 1, "Logfile: closing log " << lf->path); + lf->f_flush(lf); + lf->f_close(lf); + cbdataFree(lf); } void logfileRotate(Logfile * lf) { -#ifdef S_ISREG - - struct stat sb; -#endif - - int i; - char from[MAXPATHLEN]; - char to[MAXPATHLEN]; - assert(lf->path); - - if (lf->flags.syslog) - return; - -#ifdef S_ISREG - - if (stat(lf->path, &sb) == 0) - if (S_ISREG(sb.st_mode) == 0) - return; - -#endif - - debugs(0, 1, "logfileRotate: " << lf->path); - - /* Rotate numbers 0 through N up one */ - for (i = Config.Log.rotateNumber; i > 1;) { - i--; - snprintf(from, MAXPATHLEN, "%s.%d", lf->path, i - 1); - snprintf(to, MAXPATHLEN, "%s.%d", lf->path, i); - xrename(from, to); - } - - /* Rotate the current log to .0 */ - logfileFlush(lf); - - file_close(lf->fd); /* always close */ - - if (Config.Log.rotateNumber > 0) { - snprintf(to, MAXPATHLEN, "%s.%d", lf->path, 0); - xrename(lf->path, to); - } - - /* Reopen the log. It may have been renamed "manually" */ - lf->fd = file_open(lf->path, O_WRONLY | O_CREAT | O_TEXT); - - if (DISK_ERROR == lf->fd && lf->flags.fatal) { - debugs(50, 1, "logfileRotate: " << lf->path << ": " << xstrerror()); - fatalf("Cannot open %s: %s", lf->path, xstrerror()); - } + debugs(50, 1, "logfileRotate: " << lf->path); + lf->f_rotate(lf); } void -logfileWrite(Logfile * lf, void *buf, size_t len) +logfileWrite(Logfile * lf, char *buf, size_t len) { - /* AYJ: this write gets called once per line? Squid-2 did it in lineEnd which we dont have. */ - lf->sequence_number++; - -#if HAVE_SYSLOG - - if (lf->flags.syslog) { - syslog(lf->syslog_priority, "%s", (char *)buf); - return; - } - -#endif - - if (0 == lf->bufsz) { - /* buffering disabled */ - logfileWriteWrapper(lf, buf, len); - return; - } - - if (lf->offset > 0 && lf->offset + len > lf->bufsz) - logfileFlush(lf); - - if (len > lf->bufsz) { - /* too big to fit in buffer */ - logfileWriteWrapper(lf, buf, len); - return; - } - - /* buffer it */ - xmemcpy(lf->buf + lf->offset, buf, len); - - lf->offset += len; - - assert (lf->offset >= 0); - - assert((size_t)lf->offset <= lf->bufsz); + lf->f_linewrite(lf, buf, len); } void @@ -280,32 +136,20 @@ } void +logfileLineStart(Logfile * lf) +{ + lf->f_linestart(lf); +} + +void +logfileLineEnd(Logfile * lf) +{ + lf->f_lineend(lf); + lf->sequence_number++; +} + +void logfileFlush(Logfile * lf) { - if (0 == lf->offset) - return; - - logfileWriteWrapper(lf, lf->buf, (size_t) lf->offset); - - lf->offset = 0; -} - -/* - * Aborts with fatal message if write() returns something other - * than its length argument. - */ -static void -logfileWriteWrapper(Logfile * lf, const void *buf, size_t len) -{ - size_t s; - s = FD_WRITE_METHOD(lf->fd, (char const *)buf, len); - fd_bytes(lf->fd, s, FD_WRITE); - - if (s == len) - return; - - if (!lf->flags.fatal) - return; - - fatalf("logfileWrite: %s: %s\n", lf->path, xstrerror()); + lf->f_flush(lf); } === added file 'src/log/File.h' --- src/log/File.h 1970-01-01 00:00:00 +0000 +++ src/log/File.h 2009-11-22 20:37:27 +0000 @@ -0,0 +1,57 @@ +#ifndef SQUID_SRC_LOG_FILE_H +#define SQUID_SRC_LOG_FILE_H + +#include "config.h" +#include "dlink.h" + +class logfile_buffer_t { +public: + char *buf; + int size; + int len; + int written_len; + dlink_node node; +}; + +class Logfile; + +typedef void LOGLINESTART(Logfile *); +typedef void LOGWRITE(Logfile *, const char *, size_t len); +typedef void LOGLINEEND(Logfile *); +typedef void LOGFLUSH(Logfile *); +typedef void LOGROTATE(Logfile *); +typedef void LOGCLOSE(Logfile *); + +class Logfile { + +public: + char path[SQUID_MAXPATHLEN]; + + struct { + unsigned int fatal; + } flags; + + int64_t sequence_number; ///< Unique sequence number per log line. + +public: + void *data; + + LOGLINESTART *f_linestart; + LOGWRITE *f_linewrite; + LOGLINEEND *f_lineend; + LOGFLUSH *f_flush; + LOGROTATE *f_rotate; + LOGCLOSE *f_close; +}; + +/* Legacy API */ +extern Logfile *logfileOpen(const char *path, size_t bufsz, int); +extern void logfileClose(Logfile * lf); +extern void logfileRotate(Logfile * lf); +extern void logfileWrite(Logfile * lf, char *buf, size_t len); +extern void logfileFlush(Logfile * lf); +extern void logfilePrintf(Logfile * lf, const char *fmt,...) PRINTF_FORMAT_ARG2; +extern void logfileLineStart(Logfile * lf); +extern void logfileLineEnd(Logfile * lf); + +#endif /* SQUID_SRC_LOG_FILE_H */ === added file 'src/log/Makefile.am' --- src/log/Makefile.am 1970-01-01 00:00:00 +0000 +++ src/log/Makefile.am 2009-11-22 20:37:27 +0000 @@ -0,0 +1,19 @@ +include $(top_srcdir)/src/Common.am +include $(top_srcdir)/src/TestHeaders.am + +noinst_LTLIBRARIES = liblog.la + +liblog_la_SOURCES = \ + access_log.cc \ + Config.cc \ + Config.h \ + File.cc \ + File.h \ + ModDaemon.cc \ + ModDaemon.h \ + ModStdio.cc \ + ModStdio.h \ + ModSyslog.cc \ + ModSyslog.h \ + ModUdp.cc \ + ModUdp.h === added file 'src/log/ModDaemon.cc' --- src/log/ModDaemon.cc 1970-01-01 00:00:00 +0000 +++ src/log/ModDaemon.cc 2009-11-22 20:37:27 +0000 @@ -0,0 +1,363 @@ +/* + * DEBUG: section 50 Log file handling + * AUTHOR: Adrian Chadd + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" +#include "cbdata.h" +#include "fde.h" +#include "log/Config.h" +#include "log/File.h" +#include "log/ModDaemon.h" +#include "SquidTime.h" + +/* How many buffers to keep before we say we've buffered too much */ +#define LOGFILE_MAXBUFS 128 + +/* Size of the logfile buffer */ +/* + * For optimal performance this should match LOGFILE_BUFSIZ in logfile-daemon.c + */ +#define LOGFILE_BUFSZ 32768 + +/* How many seconds between warnings */ +#define LOGFILE_WARN_TIME 30 + +static LOGWRITE logfile_mod_daemon_writeline; +static LOGLINESTART logfile_mod_daemon_linestart; +static LOGLINEEND logfile_mod_daemon_lineend; +static LOGROTATE logfile_mod_daemon_rotate; +static LOGFLUSH logfile_mod_daemon_flush; +static LOGCLOSE logfile_mod_daemon_close; + +static void logfile_mod_daemon_append(Logfile * lf, const char *buf, int len); + +struct _l_daemon { + int rfd, wfd; + char eol; + pid_t pid; + int flush_pending; + dlink_list bufs; + int nbufs; + int last_warned; +}; + +typedef struct _l_daemon l_daemon_t; + +/* Internal code */ +static void +logfileNewBuffer(Logfile * lf) +{ + l_daemon_t *ll = (l_daemon_t *) lf->data; + logfile_buffer_t *b; + + debugs(50, 5, "logfileNewBuffer: " << lf->path << ": new buffer"); + + b = static_cast(xcalloc(1, sizeof(logfile_buffer_t))); + assert(b != NULL); + b->buf = static_cast(xcalloc(1, LOGFILE_BUFSZ)); + assert(b->buf != NULL); + b->size = LOGFILE_BUFSZ; + b->written_len = 0; + b->len = 0; + dlinkAddTail(b, &b->node, &ll->bufs); + ll->nbufs++; +} + +static void +logfileFreeBuffer(Logfile * lf, logfile_buffer_t * b) +{ + l_daemon_t *ll = (l_daemon_t *) lf->data; + assert(b != NULL); + dlinkDelete(&b->node, &ll->bufs); + ll->nbufs--; + xfree(b->buf); + xfree(b); +} + +static void +logfileHandleWrite(int fd, void *data) +{ + Logfile *lf = (Logfile *) data; + l_daemon_t *ll = (l_daemon_t *) lf->data; + int ret; + logfile_buffer_t *b; + + /* + * We'll try writing the first entry until its done - if we + * get a partial write then we'll re-schedule until its completed. + * Its naive but it'll do for now. + */ + b = static_cast(ll->bufs.head->data); + assert(b != NULL); + ll->flush_pending = 0; + + ret = FD_WRITE_METHOD(ll->wfd, b->buf + b->written_len, b->len - b->written_len); + debugs(50, 3, "logfileHandleWrite: " << lf->path << ": write returned " << ret); + if (ret < 0) { + if (ignoreErrno(errno)) { + /* something temporary */ + goto reschedule; + } + debugs(50, DBG_IMPORTANT,"logfileHandleWrite: " << lf->path << ": error writing (" << xstrerror() << ")"); + /* XXX should handle this better */ + fatal("I don't handle this error well!"); + } + if (ret == 0) { + /* error? */ + debugs(50, DBG_IMPORTANT, "logfileHandleWrite: " << lf->path << ": wrote 0 bytes?"); + /* XXX should handle this better */ + fatal("I don't handle this error well!"); + } + /* ret > 0, so something was written */ + b->written_len += ret; + assert(b->written_len <= b->len); + if (b->written_len == b->len) { + /* written the whole buffer! */ + logfileFreeBuffer(lf, b); + b = NULL; + } + /* Is there more to write? */ + if (ll->bufs.head == NULL) { + goto finish; + } + /* there is, so schedule more */ + + reschedule: + commSetSelect(ll->wfd, COMM_SELECT_WRITE, logfileHandleWrite, lf, 0); + ll->flush_pending = 1; + finish: + return; +} + +static void +logfileQueueWrite(Logfile * lf) +{ + l_daemon_t *ll = (l_daemon_t *) lf->data; + if (ll->flush_pending || ll->bufs.head == NULL) { + return; + } + ll->flush_pending = 1; + if (ll->bufs.head) { + logfile_buffer_t *b = static_cast(ll->bufs.head->data); + if (b->len + 2 <= b->size) + logfile_mod_daemon_append(lf, "F\n", 2); + } + /* Ok, schedule a write-event */ + commSetSelect(ll->wfd, COMM_SELECT_WRITE, logfileHandleWrite, lf, 0); +} + +static void +logfile_mod_daemon_append(Logfile * lf, const char *buf, int len) +{ + l_daemon_t *ll = (l_daemon_t *) lf->data; + logfile_buffer_t *b; + int s; + + /* Is there a buffer? If not, create one */ + if (ll->bufs.head == NULL) { + logfileNewBuffer(lf); + } + debugs(50, 3, "logfile_mod_daemon_append: " << lf->path << ": appending " << len << " bytes"); + /* Copy what can be copied */ + while (len > 0) { + b = static_cast(ll->bufs.tail->data); + debugs(50, 3, "logfile_mod_daemon_append: current buffer has " << b->len << " of " << b->size << " bytes before append"); + s = min(len, (b->size - b->len)); + xmemcpy(b->buf + b->len, buf, s); + len = len - s; + buf = buf + s; + b->len = b->len + s; + assert(b->len <= LOGFILE_BUFSZ); + assert(len >= 0); + if (len > 0) { + logfileNewBuffer(lf); + } + } +} + +/* + * only schedule a flush (write) if one isn't scheduled. + */ +static void +logfileFlushEvent(void *data) +{ + Logfile *lf = static_cast(data); + + /* + * This might work better if we keep track of when we wrote last and only + * schedule a write if we haven't done so in the last second or two. + */ + logfileQueueWrite(lf); + eventAdd("logfileFlush", logfileFlushEvent, lf, 1.0, 1); +} + + +/* External code */ + +int +logfile_mod_daemon_open(Logfile * lf, const char *path, size_t bufsz, int fatal_flag) +{ + const char *args[5]; + char *tmpbuf; + l_daemon_t *ll; + + lf->f_close = logfile_mod_daemon_close; + lf->f_linewrite = logfile_mod_daemon_writeline; + lf->f_linestart = logfile_mod_daemon_linestart; + lf->f_lineend = logfile_mod_daemon_lineend; + lf->f_flush = logfile_mod_daemon_flush; + lf->f_rotate = logfile_mod_daemon_rotate; + + cbdataInternalLock(lf); // WTF? + debugs(50, 1, "Logfile Daemon: opening log " << path); + ll = static_cast(xcalloc(1, sizeof(*ll))); + lf->data = ll; + ll->eol = 1; + { + IpAddress localhost; + args[0] = "(logfile-daemon)"; + args[1] = path; + args[2] = NULL; + localhost.SetLocalhost(); + ll->pid = ipcCreate(IPC_STREAM, Log::TheConfig.logfile_daemon, args, "logfile-daemon", localhost, &ll->rfd, &ll->wfd, NULL); + if (ll->pid < 0) + fatal("Couldn't start logfile helper"); + } + ll->nbufs = 0; + + /* Queue the initial control data */ + tmpbuf = static_cast(xmalloc(BUFSIZ)); + snprintf(tmpbuf, BUFSIZ, "r%d\nb%d\n", Config.Log.rotateNumber, Config.onoff.buffered_logs); + logfile_mod_daemon_append(lf, tmpbuf, strlen(tmpbuf)); + xfree(tmpbuf); + + /* Start the flush event */ + eventAdd("logfileFlush", logfileFlushEvent, lf, 1.0, 1); + + return 1; +} + +static void +logfile_mod_daemon_close(Logfile * lf) +{ + l_daemon_t *ll = static_cast(lf->data); + debugs(50, 1, "Logfile Daemon: closing log " << lf->path); + logfileFlush(lf); + if (ll->rfd == ll->wfd) + comm_close(ll->rfd); + else { + comm_close(ll->rfd); + comm_close(ll->wfd); + } + kill(ll->pid, SIGTERM); + eventDelete(logfileFlushEvent, lf); + xfree(ll); + lf->data = NULL; + cbdataInternalUnlock(lf); // WTF?? +} + +static void +logfile_mod_daemon_rotate(Logfile * lf) +{ + char tb[3]; + debugs(50, 1, "logfileRotate: " << lf->path); + tb[0] = 'R'; + tb[1] = '\n'; + tb[2] = '\0'; + logfile_mod_daemon_append(lf, tb, 2); +} + +/* + * This routine assumes that up to one line is written. Don't try to + * call this routine with more than one line or subsequent lines + * won't be prefixed with the command type and confuse the logging + * daemon somewhat. + */ +static void +logfile_mod_daemon_writeline(Logfile * lf, const char *buf, size_t len) +{ + l_daemon_t *ll = static_cast(lf->data); + /* Make sure the logfile buffer isn't too large */ + if (ll->nbufs > LOGFILE_MAXBUFS) { + if (ll->last_warned < squid_curtime - LOGFILE_WARN_TIME) { + ll->last_warned = squid_curtime; + debugs(50, DBG_IMPORTANT, "Logfile: " << lf->path << ": queue is too large; some log messages have been lost."); + } + return; + } + /* Append this data to the end buffer; create a new one if needed */ + /* Are we eol? If so, prefix with our logfile command byte */ + logfile_mod_daemon_append(lf, buf, len); +} + +static void +logfile_mod_daemon_linestart(Logfile * lf) +{ + l_daemon_t *ll = static_cast(lf->data); + char tb[2]; + assert(ll->eol == 1); + ll->eol = 0; + tb[0] = 'L'; + tb[1] = '\0'; + logfile_mod_daemon_append(lf, tb, 1); +} + +static void +logfile_mod_daemon_lineend(Logfile * lf) +{ + l_daemon_t *ll = static_cast(lf->data); + logfile_buffer_t *b; + assert(ll->eol == 0); + ll->eol = 1; + /* Kick a write off if the head buffer is -full- */ + if (ll->bufs.head != NULL) { + b = static_cast(ll->bufs.head->data); + if (b->node.next != NULL || !Config.onoff.buffered_logs) + logfileQueueWrite(lf); + } +} + +static void +logfile_mod_daemon_flush(Logfile * lf) +{ + l_daemon_t *ll = static_cast(lf->data); + if (commUnsetNonBlocking(ll->wfd)) { + debugs(50, DBG_IMPORTANT, "Logfile Daemon: Couldn't set the pipe blocking for flush! You're now missing some log entries."); + return; + } + while (ll->bufs.head != NULL) { + logfileHandleWrite(ll->wfd, lf); + } + if (commSetNonBlocking(ll->wfd)) { + fatalf("Logfile Daemon: %s: Couldn't set the pipe non-blocking for flush!\n", lf->path); + return; + } +} === added file 'src/log/ModDaemon.h' --- src/log/ModDaemon.h 1970-01-01 00:00:00 +0000 +++ src/log/ModDaemon.h 2009-11-22 20:37:27 +0000 @@ -0,0 +1,41 @@ +/* + * DEBUG: section 50 Log file handling + * AUTHOR: Adrian Chadd + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ +#ifndef _SQUID_SRC_LOG_MODDAEMON_H +#define _SQUID_SRC_LOG_MODDAEMON_H + +#include "config.h" + +class Logfile; + +extern int logfile_mod_daemon_open(Logfile * lf, const char *path, size_t bufsz, int fatal_flag); + +#endif /* _SQUID_SRC_LOG_MODDAEMON_H */ === added file 'src/log/ModStdio.cc' --- src/log/ModStdio.cc 1970-01-01 00:00:00 +0000 +++ src/log/ModStdio.cc 2009-11-22 20:37:27 +0000 @@ -0,0 +1,219 @@ +/* + * DEBUG: section 50 Log file handling + * AUTHOR: Duane Wessels + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" +#include "fde.h" +#include "log/File.h" +#include "log/ModStdio.h" + +typedef struct { + int fd; + char *buf; + size_t bufsz; + int offset; +} l_stdio_t; + +/* + * Aborts with fatal message if write() returns something other + * than its length argument. + */ +static void +logfileWriteWrapper(Logfile * lf, const void *buf, size_t len) +{ + l_stdio_t *ll = (l_stdio_t *) lf->data; + size_t s; + s = FD_WRITE_METHOD(ll->fd, (char const *) buf, len); + fd_bytes(ll->fd, s, FD_WRITE); + + if (s == len) + return; + + if (!lf->flags.fatal) + return; + + fatalf("logfileWrite (stdio): %s: %s\n", lf->path, xstrerror()); +} + +static void +logfile_mod_stdio_writeline(Logfile * lf, const char *buf, size_t len) +{ + l_stdio_t *ll = (l_stdio_t *) lf->data; + + if (0 == ll->bufsz) { + /* buffering disabled */ + logfileWriteWrapper(lf, buf, len); + return; + } + if (ll->offset > 0 && (ll->offset + len) > ll->bufsz) + logfileFlush(lf); + + if (len > ll->bufsz) { + /* too big to fit in buffer */ + logfileWriteWrapper(lf, buf, len); + return; + } + /* buffer it */ + xmemcpy(ll->buf + ll->offset, buf, len); + + ll->offset += len; + + assert(ll->offset >= 0); + + assert((size_t) ll->offset <= ll->bufsz); +} + +static void +logfile_mod_stdio_linestart(Logfile * lf) +{ +} + +static void +logfile_mod_stdio_lineend(Logfile * lf) +{ + lf->f_flush(lf); +} + +static void +logfile_mod_stdio_flush(Logfile * lf) +{ + l_stdio_t *ll = (l_stdio_t *) lf->data; + if (0 == ll->offset) + return; + logfileWriteWrapper(lf, ll->buf, (size_t) ll->offset); + ll->offset = 0; +} + +static void +logfile_mod_stdio_rotate(Logfile * lf) +{ +#ifdef S_ISREG + + struct stat sb; +#endif + + int i; + char from[MAXPATHLEN]; + char to[MAXPATHLEN]; + l_stdio_t *ll = (l_stdio_t *) lf->data; + assert(lf->path); + +#ifdef S_ISREG + + if (stat(lf->path, &sb) == 0) + if (S_ISREG(sb.st_mode) == 0) + return; + +#endif + + debugs(0, DBG_IMPORTANT, "logfileRotate (stdio): " << lf->path); + + /* Rotate numbers 0 through N up one */ + for (i = Config.Log.rotateNumber; i > 1;) { + i--; + snprintf(from, MAXPATHLEN, "%s.%d", lf->path, i - 1); + snprintf(to, MAXPATHLEN, "%s.%d", lf->path, i); + xrename(from, to); + } + + /* Rotate the current log to .0 */ + logfileFlush(lf); + + file_close(ll->fd); /* always close */ + + if (Config.Log.rotateNumber > 0) { + snprintf(to, MAXPATHLEN, "%s.%d", lf->path, 0); + xrename(lf->path, to); + } + /* Reopen the log. It may have been renamed "manually" */ + ll->fd = file_open(lf->path, O_WRONLY | O_CREAT | O_TEXT); + + if (DISK_ERROR == ll->fd && lf->flags.fatal) { + debugs(50, DBG_CRITICAL, "logfileRotate (stdio): " << lf->path << ": " << xstrerror()); + fatalf("Cannot open %s: %s", lf->path, xstrerror()); + } +} + +static void +logfile_mod_stdio_close(Logfile * lf) +{ + l_stdio_t *ll = (l_stdio_t *) lf->data; + lf->f_flush(lf); + + if (ll->fd >= 0) + file_close(ll->fd); + + if (ll->buf) + xfree(ll->buf); + + xfree(lf->data); + lf->data = NULL; +} + +/* + * This code expects the path to be a writable filename + */ +int +logfile_mod_stdio_open(Logfile * lf, const char *path, size_t bufsz, int fatal_flag) +{ + lf->f_close = logfile_mod_stdio_close; + lf->f_linewrite = logfile_mod_stdio_writeline; + lf->f_linestart = logfile_mod_stdio_linestart; + lf->f_lineend = logfile_mod_stdio_lineend; + lf->f_flush = logfile_mod_stdio_flush; + lf->f_rotate = logfile_mod_stdio_rotate; + + l_stdio_t *ll = static_cast(xcalloc(1, sizeof(*ll))); + lf->data = ll; + + ll->fd = file_open(path, O_WRONLY | O_CREAT | O_TEXT); + + if (DISK_ERROR == ll->fd) { + if (ENOENT == errno && fatal_flag) { + fatalf("Cannot open '%s' because\n" + "\tthe parent directory does not exist.\n" + "\tPlease create the directory.\n", path); + } else if (EACCES == errno && fatal_flag) { + fatalf("Cannot open '%s' for writing.\n" + "\tThe parent directory must be writeable by the\n" + "\tuser '%s', which is the cache_effective_user\n" + "\tset in squid.conf.", path, Config.effectiveUser); + } else { + debugs(50, DBG_IMPORTANT, "logfileOpen (stdio): " << path << ": " << xstrerror()); + return 0; + } + } + if (bufsz > 0) { + ll->buf = static_cast(xmalloc(bufsz)); + ll->bufsz = bufsz; + } + return 1; +} === added file 'src/log/ModStdio.h' --- src/log/ModStdio.h 1970-01-01 00:00:00 +0000 +++ src/log/ModStdio.h 2009-11-22 20:37:27 +0000 @@ -0,0 +1,43 @@ +/* + * $Id$ + * + * DEBUG: section 50 Log file handling + * AUTHOR: Duane Wessels + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ +#ifndef _SQUID_SRC_LOG_MODSTDIO_H +#define _SQUID_SRC_LOG_MODSTDIO_H + +#include "config.h" + +class Logfile; + +extern int logfile_mod_stdio_open(Logfile * lf, const char *path, size_t bufsz, int fatal_flag); + +#endif /* _SQUID_SRC_LOG_MODSTDIO_H */ === added file 'src/log/ModSyslog.cc' --- src/log/ModSyslog.cc 1970-01-01 00:00:00 +0000 +++ src/log/ModSyslog.cc 2009-11-22 20:37:27 +0000 @@ -0,0 +1,193 @@ +/* + * DEBUG: section 50 Log file handling + * AUTHOR: Duane Wessels + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" + +#if HAVE_SYSLOG + +#include "log/File.h" +#include "log/ModSyslog.h" + +/* Define LOG_AUTHPRIV as LOG_AUTH on systems still using the old deprecated LOG_AUTH */ +#if !defined(LOG_AUTHPRIV) && defined(LOG_AUTH) +#define LOG_AUTHPRIV LOG_AUTH +#endif + +typedef struct { + const char *name; + int value; +} syslog_symbol_t; + +static int +syslog_ntoa(const char *s) +{ +#define syslog_symbol(a) #a, a + static syslog_symbol_t symbols[] = + { +#ifdef LOG_AUTHPRIV + {syslog_symbol(LOG_AUTHPRIV)}, +#endif +#ifdef LOG_DAEMON + {syslog_symbol(LOG_DAEMON)}, +#endif +#ifdef LOG_LOCAL0 + {syslog_symbol(LOG_LOCAL0)}, +#endif +#ifdef LOG_LOCAL1 + {syslog_symbol(LOG_LOCAL1)}, +#endif +#ifdef LOG_LOCAL2 + {syslog_symbol(LOG_LOCAL2)}, +#endif +#ifdef LOG_LOCAL3 + {syslog_symbol(LOG_LOCAL3)}, +#endif +#ifdef LOG_LOCAL4 + {syslog_symbol(LOG_LOCAL4)}, +#endif +#ifdef LOG_LOCAL5 + {syslog_symbol(LOG_LOCAL5)}, +#endif +#ifdef LOG_LOCAL6 + {syslog_symbol(LOG_LOCAL6)}, +#endif +#ifdef LOG_LOCAL7 + {syslog_symbol(LOG_LOCAL7)}, +#endif +#ifdef LOG_USER + {syslog_symbol(LOG_USER)}, +#endif +#ifdef LOG_ERR + {syslog_symbol(LOG_ERR)}, +#endif +#ifdef LOG_WARNING + {syslog_symbol(LOG_WARNING)}, +#endif +#ifdef LOG_NOTICE + {syslog_symbol(LOG_NOTICE)}, +#endif +#ifdef LOG_INFO + {syslog_symbol(LOG_INFO)}, +#endif +#ifdef LOG_DEBUG + {syslog_symbol(LOG_DEBUG)}, +#endif + {NULL, 0} + }; + syslog_symbol_t *p; + + for (p = symbols; p->name != NULL; ++p) + if (!strcmp(s, p->name) || !strcasecmp(s, p->name + 4)) + return p->value; + + debugs(1, 1, "Unknown syslog facility/priority '" << s << "'"); + return 0; +} + +typedef struct { + int syslog_priority; +} l_syslog_t; + +#define PRIORITY_MASK (LOG_ERR | LOG_WARNING | LOG_NOTICE | LOG_INFO | LOG_DEBUG) + +static void +logfile_mod_syslog_writeline(Logfile * lf, const char *buf, size_t len) +{ + l_syslog_t *ll = (l_syslog_t *) lf->data; + syslog(ll->syslog_priority, "%s", (char *) buf); +} + +static void +logfile_mod_syslog_linestart(Logfile * lf) +{ +} + +static void +logfile_mod_syslog_lineend(Logfile * lf) +{ +} + +static void +logfile_mod_syslog_flush(Logfile * lf) +{ +} + +static void +logfile_mod_syslog_rotate(Logfile * lf) +{ +} + +static void +logfile_mod_syslog_close(Logfile * lf) +{ + xfree(lf->data); + lf->data = NULL; +} + + + +/* + * This code expects the path to be syslog: + */ +int +logfile_mod_syslog_open(Logfile * lf, const char *path, size_t bufsz, int fatal_flag) +{ + lf->f_close = logfile_mod_syslog_close; + lf->f_linewrite = logfile_mod_syslog_writeline; + lf->f_linestart = logfile_mod_syslog_linestart; + lf->f_lineend = logfile_mod_syslog_lineend; + lf->f_flush = logfile_mod_syslog_flush; + lf->f_rotate = logfile_mod_syslog_rotate; + + l_syslog_t *ll = static_cast(xcalloc(1, sizeof(*ll))); + lf->data = ll; + + ll->syslog_priority = LOG_INFO; + + if (path[6] != '\0') { + char *priority = xstrdup(path); + char *facility = (char *) strchr(priority, '.'); + if (!facility) + facility = (char *) strchr(priority, '|'); + if (facility) { + *facility++ = '\0'; + ll->syslog_priority |= syslog_ntoa(facility); + } + ll->syslog_priority |= syslog_ntoa(priority); + xfree(priority); + if ((ll->syslog_priority & PRIORITY_MASK) == 0) + ll->syslog_priority |= LOG_INFO; + } + + return 1; +} +#endif === added file 'src/log/ModSyslog.h' --- src/log/ModSyslog.h 1970-01-01 00:00:00 +0000 +++ src/log/ModSyslog.h 2009-11-22 20:37:27 +0000 @@ -0,0 +1,43 @@ +/* + * $Id$ + * + * DEBUG: section 50 Log file handling + * AUTHOR: Duane Wessels + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ +#ifndef _SQUID_SRC_LOG_MODSYSLOG_H +#define _SQUID_SRC_LOG_MODSYSLOG_H + +#include "config.h" + +class Logfile; + +extern int logfile_mod_syslog_open(Logfile * lf, const char *path, size_t bufsz, int fatal_flag); + +#endif /* _SQUID_SRC_LOG_MODSYSLOG_H */ === added file 'src/log/ModUdp.cc' --- src/log/ModUdp.cc 1970-01-01 00:00:00 +0000 +++ src/log/ModUdp.cc 2009-11-22 20:37:27 +0000 @@ -0,0 +1,233 @@ +/* + * DEBUG: section 50 Log file handling + * AUTHOR: Adrian Chadd + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" +#include "comm.h" +#include "log/File.h" +#include "log/ModUdp.h" +#include "Parsing.h" + +/* + * This logfile UDP module is mostly inspired by a patch by Tim Starling + * from Wikimedia. + * + * It doesn't do any UDP buffering - it'd be quite a bit of work for + * something which the kernel could be doing for you! + */ + +typedef struct { + int fd; + char *buf; + size_t bufsz; + int offset; +} l_udp_t; + +static void +logfile_mod_udp_write(Logfile * lf, const char *buf, size_t len) +{ + l_udp_t *ll = (l_udp_t *) lf->data; + ssize_t s; + s = write(ll->fd, (char const *) buf, len); + fd_bytes(ll->fd, s, FD_WRITE); +#if 0 + if (s < 0) { + debugs(1, 1, "logfile (udp): got errno (" << errno << "):" << xstrerror()); + } + if (s != len) { + debugs(1, 1, "logfile (udp): len=" << len << ", wrote=" << s); + } +#endif + + /* We don't worry about network errors for now */ +} + +static void +logfile_mod_udp_flush(Logfile * lf) +{ + l_udp_t *ll = (l_udp_t *) lf->data; + if (0 == ll->offset) + return; + logfile_mod_udp_write(lf, ll->buf, (size_t) ll->offset); + ll->offset = 0; +} + +static void +logfile_mod_udp_writeline(Logfile * lf, const char *buf, size_t len) +{ + l_udp_t *ll = (l_udp_t *) lf->data; + + if (0 == ll->bufsz) { + /* buffering disabled */ + logfile_mod_udp_write(lf, buf, len); + return; + } + if (ll->offset > 0 && (ll->offset + len + 4) > ll->bufsz) + logfile_mod_udp_flush(lf); + + if (len > ll->bufsz) { + /* too big to fit in buffer */ + logfile_mod_udp_write(lf, buf, len); + return; + } + /* buffer it */ + xmemcpy(ll->buf + ll->offset, buf, len); + + ll->offset += len; + + assert(ll->offset >= 0); + + assert((size_t) ll->offset <= ll->bufsz); +} + +static void +logfile_mod_udp_linestart(Logfile * lf) +{ +} + +static void +logfile_mod_udp_lineend(Logfile * lf) +{ +} + +static void +logfile_mod_udp_rotate(Logfile * lf) +{ + return; +} + +static void +logfile_mod_udp_close(Logfile * lf) +{ + l_udp_t *ll = (l_udp_t *) lf->data; + lf->f_flush(lf); + + if (ll->fd >= 0) + file_close(ll->fd); + + if (ll->buf) + xfree(ll->buf); + + xfree(lf->data); + lf->data = NULL; +} + + + +/* + * This code expects the path to be //host:port + */ +int +logfile_mod_udp_open(Logfile * lf, const char *path, size_t bufsz, int fatal_flag) +{ + IpAddress addr; + char *strAddr; + + lf->f_close = logfile_mod_udp_close; + lf->f_linewrite = logfile_mod_udp_writeline; + lf->f_linestart = logfile_mod_udp_linestart; + lf->f_lineend = logfile_mod_udp_lineend; + lf->f_flush = logfile_mod_udp_flush; + lf->f_rotate = logfile_mod_udp_rotate; + + l_udp_t *ll = static_cast(xcalloc(1, sizeof(*ll))); + lf->data = ll; + + if (strncmp(path, "//", 2) == 0) { + path += 2; + } + strAddr = xstrdup(path); + if (!GetHostWithPort(strAddr, &addr)) { + if (lf->flags.fatal) { + fatalf("Invalid UDP logging address '%s'\n", lf->path); + } else { + debugs(50, DBG_IMPORTANT, "Invalid UDP logging address '" << lf->path << "'"); + safe_free(strAddr); + return FALSE; + } + } + safe_free(strAddr); + + IpAddress no_addr; + no_addr.SetNoAddr(); + +#if USE_IPV6 + // require the sending UDP port to be of the right family for the destination address. + if (addr.IsIPv4()) + no_addr.SetIPv4(); +#endif + + ll->fd = comm_open(SOCK_DGRAM, IPPROTO_UDP, no_addr, COMM_NONBLOCKING, "UDP log socket"); + if (ll->fd < 0) { + if (lf->flags.fatal) { + fatalf("Unable to open UDP socket for logging\n"); + } else { + debugs(50, DBG_IMPORTANT, "Unable to open UDP socket for logging"); + return FALSE; + } + } + else if (comm_connect_addr(ll->fd, &addr)) { + if (lf->flags.fatal) { + fatalf("Unable to connect to %s for UDP log: %s\n", lf->path, xstrerror()); + } else { + debugs(50, DBG_IMPORTANT, "Unable to connect to " << lf->path << " for UDP log: " << xstrerror()); + return FALSE; + } + } + if (ll->fd == -1) { + if (ENOENT == errno && fatal_flag) { + fatalf("Cannot open '%s' because\n" + "\tthe parent directory does not exist.\n" + "\tPlease create the directory.\n", path); + } else if (EACCES == errno && fatal_flag) { + fatalf("Cannot open '%s' for writing.\n" + "\tThe parent directory must be writeable by the\n" + "\tuser '%s', which is the cache_effective_user\n" + "\tset in squid.conf.", path, Config.effectiveUser); + } else { + debugs(50, DBG_IMPORTANT, "logfileOpen (UDP): " << lf->path << ": " << xstrerror()); + return 0; + } + } + /* Force buffer size to something roughly fitting inside an MTU */ + /* + * XXX note the receive side needs to receive the whole packet at once; + * applications like netcat have a small default receive buffer and will + * truncate! + */ + bufsz = 1400; + if (bufsz > 0) { + ll->buf = static_cast(xmalloc(bufsz)); + ll->bufsz = bufsz; + } + + return 1; +} === added file 'src/log/ModUdp.h' --- src/log/ModUdp.h 1970-01-01 00:00:00 +0000 +++ src/log/ModUdp.h 2009-11-22 20:37:27 +0000 @@ -0,0 +1,43 @@ +/* + * $Id$ + * + * DEBUG: section 50 Log file handling + * AUTHOR: Adrian Chadd + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ +#ifndef _SQUID_SRC_LOG_MODUDP_H +#define _SQUID_SRC_LOG_MODSYSLOG_H + +#include "config.h" + +class Logfile; + +extern int logfile_mod_udp_open(Logfile * lf, const char *path, size_t bufsz, int fatal_flag); + +#endif /* _SQUID_SRC_LOG_MODSYSLOG_H */ === renamed file 'src/access_log.cc' => 'src/log/access_log.cc' --- src/access_log.cc 2009-11-09 11:25:11 +0000 +++ src/log/access_log.cc 2009-11-22 20:37:27 +0000 @@ -48,6 +48,7 @@ #include "hier_code.h" #include "HttpReply.h" #include "HttpRequest.h" +#include "log/File.h" #include "MemBuf.h" #include "rfc1738.h" #include "SquidTime.h" @@ -1889,56 +1890,51 @@ if (checklist && log->aclList && !checklist->matchAclListFast(log->aclList)) continue; - switch (log->type) { - - case CLF_AUTO: - - if (Config.onoff.common_log) + if (log->logfile) { + logfileLineStart(log->logfile); + + switch (log->type) { + + case CLF_AUTO: + if (Config.onoff.common_log) + accessLogCommon(al, log->logfile); + else + accessLogSquid(al, log->logfile); + break; + + case CLF_SQUID: + accessLogSquid(al, log->logfile); + break; + + case CLF_COMMON: accessLogCommon(al, log->logfile); - else - accessLogSquid(al, log->logfile); - - break; - - case CLF_SQUID: - accessLogSquid(al, log->logfile); - - break; - - case CLF_COMMON: - accessLogCommon(al, log->logfile); - - break; - - case CLF_CUSTOM: - accessLogCustom(al, log); - - break; + break; + + case CLF_CUSTOM: + accessLogCustom(al, log); + break; #if ICAP_CLIENT - case CLF_ICAP_SQUID: - accessLogICAPSquid(al, log->logfile); - - break; + case CLF_ICAP_SQUID: + accessLogICAPSquid(al, log->logfile); + break; #endif - case CLF_NONE: - goto last; - - default: - fatalf("Unknown log format %d\n", log->type); - - break; + case CLF_NONE: + return; // abort! + + default: + fatalf("Unknown log format %d\n", log->type); + break; + } + + logfileLineEnd(log->logfile); } - logfileFlush(log->logfile); - + // NP: WTF? if _any_ log line has no checklist ignore the following ones? if (!checklist) break; } - -last: - (void)0; /* NULL statement for label */ } void @@ -2075,7 +2071,7 @@ if (log->type == CLF_NONE) continue; - log->logfile = logfileOpen(log->filename, MAX_URL << 1, 1); + log->logfile = logfileOpen(log->filename, MAX_URL << 2, 1); LogfileStatus = LOG_ENABLE; @@ -2352,16 +2348,10 @@ S = (unsigned short) HTTP_STATUS_NONE; logfileWrite(headerslog, &magic, sizeof(magic)); - logfileWrite(headerslog, &M, sizeof(M)); - logfileWrite(headerslog, &S, sizeof(S)); - logfileWrite(headerslog, hmask, sizeof(HttpHeaderMask)); - logfileWrite(headerslog, &ccmask, sizeof(int)); - - logfileFlush(headerslog); } #endif === modified file 'src/protos.h' --- src/protos.h 2009-11-17 10:07:53 +0000 +++ src/protos.h 2009-11-22 20:37:27 +0000 @@ -98,6 +98,7 @@ extern void clientAccessCheck(void *); #include "Debug.h" + /* see debug.c for info on context-based debugging */ SQUIDCEXTERN Ctx ctx_enter(const char *descr); SQUIDCEXTERN void ctx_exit(Ctx ctx); @@ -704,14 +705,6 @@ SQUIDCEXTERN void *leakFreeFL(void *, const char *, int); #endif -/* logfile.c */ -SQUIDCEXTERN Logfile *logfileOpen(const char *path, size_t bufsz, int); -SQUIDCEXTERN void logfileClose(Logfile * lf); -SQUIDCEXTERN void logfileRotate(Logfile * lf); -SQUIDCEXTERN void logfileWrite(Logfile * lf, void *buf, size_t len); -SQUIDCEXTERN void logfileFlush(Logfile * lf); -SQUIDCEXTERN void logfilePrintf(Logfile * lf, const char *fmt,...) PRINTF_FORMAT_ARG2; - /* * prototypes for system functions missing from system includes */ === modified file 'src/referer.cc' --- src/referer.cc 2009-01-21 03:47:47 +0000 +++ src/referer.cc 2009-11-22 20:37:27 +0000 @@ -34,7 +34,7 @@ */ #include "squid.h" - +#include "log/File.h" #include "SquidTime.h" #if USE_REFERER_LOG === modified file 'src/squid.h' --- src/squid.h 2009-02-18 00:18:43 +0000 +++ src/squid.h 2009-11-22 20:37:27 +0000 @@ -205,11 +205,11 @@ #define SQUIDHOSTNAMELEN 256 #endif -#define SQUID_MAXPATHLEN 256 #ifndef MAXPATHLEN #define MAXPATHLEN SQUID_MAXPATHLEN #endif + #if !HAVE_STRUCT_RUSAGE /* * If we don't have getrusage() then we create a fake structure === modified file 'src/store_log.cc' --- src/store_log.cc 2009-02-12 16:06:20 +0000 +++ src/store_log.cc 2009-11-22 20:37:27 +0000 @@ -33,10 +33,11 @@ */ #include "squid.h" +#include "CacheManager.h" +#include "HttpReply.h" +#include "log/File.h" +#include "MemObject.h" #include "Store.h" -#include "MemObject.h" -#include "HttpReply.h" -#include "CacheManager.h" #include "SquidTime.h" static const char *storeLogTags[] = { @@ -83,6 +84,7 @@ String ctype=(reply->content_type.size() ? reply->content_type.termedBuf() : str_unknown); + logfileLineStart(storelog); logfilePrintf(storelog, "%9d.%03d %-7s %02d %08X %s %4d %9d %9d %9d " SQUIDSTRINGPH " %"PRId64"/%"PRId64" %s %s\n", (int) current_time.tv_sec, (int) current_time.tv_usec / 1000, @@ -99,8 +101,10 @@ e->contentLen(), RequestMethodStr(mem->method), mem->log_url); + logfileLineEnd(storelog); } else { /* no mem object. Most RELEASE cases */ + logfileLineStart(storelog); logfilePrintf(storelog, "%9d.%03d %-7s %02d %08X %s ? ? ? ? ?/? ?/? ? ?\n", (int) current_time.tv_sec, (int) current_time.tv_usec / 1000, @@ -108,6 +112,7 @@ e->swap_dirn, e->swap_filen, e->getMD5Text()); + logfileLineEnd(storelog); } } === modified file 'src/structs.h' --- src/structs.h 2009-09-25 11:09:37 +0000 +++ src/structs.h 2009-11-22 20:37:27 +0000 @@ -1292,23 +1292,6 @@ int zero_object_sz; }; -struct _Logfile { - int fd; - char path[MAXPATHLEN]; - char *buf; - size_t bufsz; - size_t offset; - - struct { - unsigned int fatal; - unsigned int syslog; - } flags; - - int syslog_priority; - - int64_t sequence_number; ///< Unique sequence number per log line. -}; - class logformat_token; struct _logformat { @@ -1317,6 +1300,8 @@ logformat *next; }; +class Logfile; + struct _customlog { char *filename; ACLList *aclList; === modified file 'src/typedefs.h' --- src/typedefs.h 2009-07-27 21:50:59 +0000 +++ src/typedefs.h 2009-11-22 20:37:27 +0000 @@ -170,8 +170,6 @@ typedef struct _link_list link_list; -typedef struct _Logfile Logfile; - typedef struct _logformat logformat; typedef struct _customlog customlog; === modified file 'src/useragent.cc' --- src/useragent.cc 2009-01-21 03:47:47 +0000 +++ src/useragent.cc 2009-11-22 20:37:27 +0000 @@ -1,4 +1,3 @@ - /* * $Id$ * @@ -34,6 +33,7 @@ */ #include "squid.h" +#include "log/File.h" #include "SquidTime.h" #if USE_USERAGENT_LOG === modified file 'tools/Makefile.am' --- tools/Makefile.am 2009-07-10 12:51:13 +0000 +++ tools/Makefile.am 2009-11-22 20:37:27 +0000 @@ -17,19 +17,28 @@ DISTCLEANFILES = LDADD = \ - ../compat/libcompat.la \ - ../src/ip/libip.la \ - -L../lib -lmiscutil \ + $(top_builddir)/src/time.o \ + $(top_builddir)/src/ip/libip.la \ + $(COMPAT_LIB) \ $(XTRA_LIBS) include $(top_srcdir)/doc/manuals/Substitute.am +test_tools.cc: $(top_srcdir)/test-suite/test_tools.cc + cp $(top_srcdir)/test-suite/test_tools.cc . + +# stock tools for unit tests - library independent versions of dlink_list +# etc. +# globals.cc is needed by test_tools.cc. +# Neither of these should be disted from here. +TESTSOURCES= test_tools.cc ## ##### squidclient ##### bin_PROGRAMS = squidclient -squidclient_SOURCES = squidclient.cc +squidclient_SOURCES = squidclient.cc \ + test_tools.cc EXTRA_DIST += squidclient.1 man_MANS += squidclient.1 @@ -42,7 +51,9 @@ libexec_PROGRAMS = cachemgr$(CGIEXT) -cachemgr__CGIEXT__SOURCES = cachemgr.cc +cachemgr__CGIEXT__SOURCES = cachemgr.cc \ + test_tools.cc + cachemgr__CGIEXT__CXXFLAGS = -DDEFAULT_CACHEMGR_CONFIG=\"$(DEFAULT_CACHEMGR_CONFIG)\" $(AM_CXXFLAGS) EXTRA_DIST += cachemgr.conf cachemgr.cgi.8 cachemgr.cgi.8.in