]>
Commit | Line | Data |
---|---|---|
82b7abe3 | 1 | /* |
bde978a6 | 2 | * Copyright (C) 1996-2015 The Squid Software Foundation and contributors |
82b7abe3 | 3 | * |
bbc27441 AJ |
4 | * Squid software is distributed under GPLv2+ license and includes |
5 | * contributions from numerous individuals and organizations. | |
6 | * Please see the COPYING and CONTRIBUTORS files for details. | |
82b7abe3 AJ |
7 | */ |
8 | ||
bbc27441 AJ |
9 | /* DEBUG: section 50 Log file handling */ |
10 | ||
582c2af2 | 11 | #include "squid.h" |
82b7abe3 | 12 | #include "comm.h" |
f9b72e0c | 13 | #include "comm/Connection.h" |
438b04d4 | 14 | #include "disk.h" |
ed6e9fb9 | 15 | #include "fatal.h" |
c4ad1349 | 16 | #include "fd.h" |
82b7abe3 AJ |
17 | #include "log/File.h" |
18 | #include "log/ModUdp.h" | |
19 | #include "Parsing.h" | |
4d5904f7 | 20 | #include "SquidConfig.h" |
82b7abe3 | 21 | |
1a30fdf5 | 22 | #include <cerrno> |
21d845b1 | 23 | |
82b7abe3 AJ |
24 | /* |
25 | * This logfile UDP module is mostly inspired by a patch by Tim Starling | |
26 | * from Wikimedia. | |
27 | * | |
28 | * It doesn't do any UDP buffering - it'd be quite a bit of work for | |
29 | * something which the kernel could be doing for you! | |
30 | */ | |
31 | ||
32 | typedef struct { | |
33 | int fd; | |
34 | char *buf; | |
35 | size_t bufsz; | |
36 | int offset; | |
37 | } l_udp_t; | |
38 | ||
39 | static void | |
40 | logfile_mod_udp_write(Logfile * lf, const char *buf, size_t len) | |
41 | { | |
42 | l_udp_t *ll = (l_udp_t *) lf->data; | |
43 | ssize_t s; | |
44 | s = write(ll->fd, (char const *) buf, len); | |
45 | fd_bytes(ll->fd, s, FD_WRITE); | |
46 | #if 0 | |
47 | if (s < 0) { | |
e0236918 | 48 | debugs(1, DBG_IMPORTANT, "logfile (udp): got errno (" << errno << "):" << xstrerror()); |
82b7abe3 AJ |
49 | } |
50 | if (s != len) { | |
e0236918 | 51 | debugs(1, DBG_IMPORTANT, "logfile (udp): len=" << len << ", wrote=" << s); |
82b7abe3 AJ |
52 | } |
53 | #endif | |
54 | ||
55 | /* We don't worry about network errors for now */ | |
56 | } | |
57 | ||
58 | static void | |
59 | logfile_mod_udp_flush(Logfile * lf) | |
60 | { | |
61 | l_udp_t *ll = (l_udp_t *) lf->data; | |
62 | if (0 == ll->offset) | |
9d65168e | 63 | return; |
82b7abe3 AJ |
64 | logfile_mod_udp_write(lf, ll->buf, (size_t) ll->offset); |
65 | ll->offset = 0; | |
66 | } | |
67 | ||
68 | static void | |
69 | logfile_mod_udp_writeline(Logfile * lf, const char *buf, size_t len) | |
70 | { | |
71 | l_udp_t *ll = (l_udp_t *) lf->data; | |
72 | ||
73 | if (0 == ll->bufsz) { | |
9d65168e A |
74 | /* buffering disabled */ |
75 | logfile_mod_udp_write(lf, buf, len); | |
76 | return; | |
82b7abe3 AJ |
77 | } |
78 | if (ll->offset > 0 && (ll->offset + len + 4) > ll->bufsz) | |
9d65168e | 79 | logfile_mod_udp_flush(lf); |
82b7abe3 AJ |
80 | |
81 | if (len > ll->bufsz) { | |
9d65168e A |
82 | /* too big to fit in buffer */ |
83 | logfile_mod_udp_write(lf, buf, len); | |
84 | return; | |
82b7abe3 AJ |
85 | } |
86 | /* buffer it */ | |
41d00cd3 | 87 | memcpy(ll->buf + ll->offset, buf, len); |
82b7abe3 AJ |
88 | |
89 | ll->offset += len; | |
90 | ||
91 | assert(ll->offset >= 0); | |
92 | ||
93 | assert((size_t) ll->offset <= ll->bufsz); | |
94 | } | |
95 | ||
96 | static void | |
ced8def3 | 97 | logfile_mod_udp_linestart(Logfile *) |
82b7abe3 AJ |
98 | { |
99 | } | |
100 | ||
101 | static void | |
ced8def3 | 102 | logfile_mod_udp_lineend(Logfile *) |
82b7abe3 AJ |
103 | { |
104 | } | |
105 | ||
106 | static void | |
ced8def3 | 107 | logfile_mod_udp_rotate(Logfile *) |
82b7abe3 | 108 | { |
82b7abe3 AJ |
109 | } |
110 | ||
111 | static void | |
112 | logfile_mod_udp_close(Logfile * lf) | |
113 | { | |
114 | l_udp_t *ll = (l_udp_t *) lf->data; | |
115 | lf->f_flush(lf); | |
116 | ||
117 | if (ll->fd >= 0) | |
9d65168e | 118 | file_close(ll->fd); |
82b7abe3 AJ |
119 | |
120 | if (ll->buf) | |
9d65168e | 121 | xfree(ll->buf); |
82b7abe3 AJ |
122 | |
123 | xfree(lf->data); | |
124 | lf->data = NULL; | |
125 | } | |
126 | ||
82b7abe3 AJ |
127 | /* |
128 | * This code expects the path to be //host:port | |
129 | */ | |
130 | int | |
131 | logfile_mod_udp_open(Logfile * lf, const char *path, size_t bufsz, int fatal_flag) | |
132 | { | |
b7ac5457 | 133 | Ip::Address addr; |
82b7abe3 AJ |
134 | char *strAddr; |
135 | ||
136 | lf->f_close = logfile_mod_udp_close; | |
137 | lf->f_linewrite = logfile_mod_udp_writeline; | |
138 | lf->f_linestart = logfile_mod_udp_linestart; | |
139 | lf->f_lineend = logfile_mod_udp_lineend; | |
140 | lf->f_flush = logfile_mod_udp_flush; | |
141 | lf->f_rotate = logfile_mod_udp_rotate; | |
142 | ||
143 | l_udp_t *ll = static_cast<l_udp_t*>(xcalloc(1, sizeof(*ll))); | |
144 | lf->data = ll; | |
145 | ||
146 | if (strncmp(path, "//", 2) == 0) { | |
9d65168e | 147 | path += 2; |
82b7abe3 AJ |
148 | } |
149 | strAddr = xstrdup(path); | |
150 | if (!GetHostWithPort(strAddr, &addr)) { | |
9d65168e A |
151 | if (lf->flags.fatal) { |
152 | fatalf("Invalid UDP logging address '%s'\n", lf->path); | |
153 | } else { | |
154 | debugs(50, DBG_IMPORTANT, "Invalid UDP logging address '" << lf->path << "'"); | |
155 | safe_free(strAddr); | |
156 | return FALSE; | |
157 | } | |
82b7abe3 AJ |
158 | } |
159 | safe_free(strAddr); | |
160 | ||
b7ac5457 | 161 | Ip::Address any_addr; |
4dd643d5 | 162 | any_addr.setAnyAddr(); |
82b7abe3 | 163 | |
82b7abe3 | 164 | // require the sending UDP port to be of the right family for the destination address. |
4dd643d5 AJ |
165 | if (addr.isIPv4()) |
166 | any_addr.setIPv4(); | |
82b7abe3 | 167 | |
d938215c | 168 | ll->fd = comm_open(SOCK_DGRAM, IPPROTO_UDP, any_addr, COMM_NONBLOCKING, "UDP log socket"); |
82b7abe3 | 169 | if (ll->fd < 0) { |
9d65168e A |
170 | if (lf->flags.fatal) { |
171 | fatalf("Unable to open UDP socket for logging\n"); | |
172 | } else { | |
173 | debugs(50, DBG_IMPORTANT, "Unable to open UDP socket for logging"); | |
174 | return FALSE; | |
175 | } | |
db772b66 | 176 | } else if (!comm_connect_addr(ll->fd, addr)) { |
9d65168e A |
177 | if (lf->flags.fatal) { |
178 | fatalf("Unable to connect to %s for UDP log: %s\n", lf->path, xstrerror()); | |
179 | } else { | |
180 | debugs(50, DBG_IMPORTANT, "Unable to connect to " << lf->path << " for UDP log: " << xstrerror()); | |
181 | return FALSE; | |
182 | } | |
82b7abe3 AJ |
183 | } |
184 | if (ll->fd == -1) { | |
9d65168e A |
185 | if (ENOENT == errno && fatal_flag) { |
186 | fatalf("Cannot open '%s' because\n" | |
187 | "\tthe parent directory does not exist.\n" | |
188 | "\tPlease create the directory.\n", path); | |
189 | } else if (EACCES == errno && fatal_flag) { | |
190 | fatalf("Cannot open '%s' for writing.\n" | |
191 | "\tThe parent directory must be writeable by the\n" | |
192 | "\tuser '%s', which is the cache_effective_user\n" | |
193 | "\tset in squid.conf.", path, Config.effectiveUser); | |
194 | } else { | |
195 | debugs(50, DBG_IMPORTANT, "logfileOpen (UDP): " << lf->path << ": " << xstrerror()); | |
196 | return 0; | |
197 | } | |
82b7abe3 AJ |
198 | } |
199 | /* Force buffer size to something roughly fitting inside an MTU */ | |
200 | /* | |
201 | * XXX note the receive side needs to receive the whole packet at once; | |
202 | * applications like netcat have a small default receive buffer and will | |
203 | * truncate! | |
204 | */ | |
205 | bufsz = 1400; | |
206 | if (bufsz > 0) { | |
9d65168e A |
207 | ll->buf = static_cast<char*>(xmalloc(bufsz)); |
208 | ll->bufsz = bufsz; | |
82b7abe3 AJ |
209 | } |
210 | ||
211 | return 1; | |
212 | } | |
f53969cc | 213 |