]>
Commit | Line | Data |
---|---|---|
82b7abe3 | 1 | /* |
bf95c10a | 2 | * Copyright (C) 1996-2022 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" |
ed6e9fb9 | 14 | #include "fatal.h" |
c4ad1349 | 15 | #include "fd.h" |
b3f7fd88 | 16 | #include "fs_io.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 | |
53521734 | 47 | // TODO: Enable after polishing to properly log these errors. |
82b7abe3 | 48 | if (s < 0) { |
b69e9ffa AJ |
49 | int xerrno = errno; |
50 | debugs(1, DBG_IMPORTANT, "logfile (udp): got errno (" << errno << "):" << xstrerr(xerrno)); | |
82b7abe3 AJ |
51 | } |
52 | if (s != len) { | |
e0236918 | 53 | debugs(1, DBG_IMPORTANT, "logfile (udp): len=" << len << ", wrote=" << s); |
82b7abe3 AJ |
54 | } |
55 | #endif | |
56 | ||
57 | /* We don't worry about network errors for now */ | |
58 | } | |
59 | ||
60 | static void | |
61 | logfile_mod_udp_flush(Logfile * lf) | |
62 | { | |
63 | l_udp_t *ll = (l_udp_t *) lf->data; | |
64 | if (0 == ll->offset) | |
9d65168e | 65 | return; |
82b7abe3 AJ |
66 | logfile_mod_udp_write(lf, ll->buf, (size_t) ll->offset); |
67 | ll->offset = 0; | |
68 | } | |
69 | ||
70 | static void | |
71 | logfile_mod_udp_writeline(Logfile * lf, const char *buf, size_t len) | |
72 | { | |
73 | l_udp_t *ll = (l_udp_t *) lf->data; | |
74 | ||
75 | if (0 == ll->bufsz) { | |
9d65168e A |
76 | /* buffering disabled */ |
77 | logfile_mod_udp_write(lf, buf, len); | |
78 | return; | |
82b7abe3 AJ |
79 | } |
80 | if (ll->offset > 0 && (ll->offset + len + 4) > ll->bufsz) | |
9d65168e | 81 | logfile_mod_udp_flush(lf); |
82b7abe3 AJ |
82 | |
83 | if (len > ll->bufsz) { | |
9d65168e A |
84 | /* too big to fit in buffer */ |
85 | logfile_mod_udp_write(lf, buf, len); | |
86 | return; | |
82b7abe3 AJ |
87 | } |
88 | /* buffer it */ | |
41d00cd3 | 89 | memcpy(ll->buf + ll->offset, buf, len); |
82b7abe3 AJ |
90 | |
91 | ll->offset += len; | |
92 | ||
93 | assert(ll->offset >= 0); | |
94 | ||
95 | assert((size_t) ll->offset <= ll->bufsz); | |
96 | } | |
97 | ||
98 | static void | |
ced8def3 | 99 | logfile_mod_udp_linestart(Logfile *) |
82b7abe3 AJ |
100 | { |
101 | } | |
102 | ||
103 | static void | |
ced8def3 | 104 | logfile_mod_udp_lineend(Logfile *) |
82b7abe3 AJ |
105 | { |
106 | } | |
107 | ||
108 | static void | |
efc23871 | 109 | logfile_mod_udp_rotate(Logfile *, const int16_t) |
82b7abe3 | 110 | { |
82b7abe3 AJ |
111 | } |
112 | ||
113 | static void | |
114 | logfile_mod_udp_close(Logfile * lf) | |
115 | { | |
116 | l_udp_t *ll = (l_udp_t *) lf->data; | |
117 | lf->f_flush(lf); | |
118 | ||
119 | if (ll->fd >= 0) | |
9d65168e | 120 | file_close(ll->fd); |
82b7abe3 AJ |
121 | |
122 | if (ll->buf) | |
9d65168e | 123 | xfree(ll->buf); |
82b7abe3 AJ |
124 | |
125 | xfree(lf->data); | |
aee3523a | 126 | lf->data = nullptr; |
82b7abe3 AJ |
127 | } |
128 | ||
82b7abe3 AJ |
129 | /* |
130 | * This code expects the path to be //host:port | |
131 | */ | |
132 | int | |
133 | logfile_mod_udp_open(Logfile * lf, const char *path, size_t bufsz, int fatal_flag) | |
134 | { | |
b7ac5457 | 135 | Ip::Address addr; |
82b7abe3 AJ |
136 | char *strAddr; |
137 | ||
138 | lf->f_close = logfile_mod_udp_close; | |
139 | lf->f_linewrite = logfile_mod_udp_writeline; | |
140 | lf->f_linestart = logfile_mod_udp_linestart; | |
141 | lf->f_lineend = logfile_mod_udp_lineend; | |
142 | lf->f_flush = logfile_mod_udp_flush; | |
143 | lf->f_rotate = logfile_mod_udp_rotate; | |
144 | ||
145 | l_udp_t *ll = static_cast<l_udp_t*>(xcalloc(1, sizeof(*ll))); | |
146 | lf->data = ll; | |
147 | ||
148 | if (strncmp(path, "//", 2) == 0) { | |
9d65168e | 149 | path += 2; |
82b7abe3 AJ |
150 | } |
151 | strAddr = xstrdup(path); | |
152 | if (!GetHostWithPort(strAddr, &addr)) { | |
9d65168e A |
153 | if (lf->flags.fatal) { |
154 | fatalf("Invalid UDP logging address '%s'\n", lf->path); | |
155 | } else { | |
d816f28d | 156 | debugs(50, DBG_IMPORTANT, "ERROR: Invalid UDP logging address '" << lf->path << "'"); |
9d65168e A |
157 | safe_free(strAddr); |
158 | return FALSE; | |
159 | } | |
82b7abe3 AJ |
160 | } |
161 | safe_free(strAddr); | |
162 | ||
b7ac5457 | 163 | Ip::Address any_addr; |
4dd643d5 | 164 | any_addr.setAnyAddr(); |
82b7abe3 | 165 | |
82b7abe3 | 166 | // require the sending UDP port to be of the right family for the destination address. |
4dd643d5 AJ |
167 | if (addr.isIPv4()) |
168 | any_addr.setIPv4(); | |
82b7abe3 | 169 | |
d938215c | 170 | ll->fd = comm_open(SOCK_DGRAM, IPPROTO_UDP, any_addr, COMM_NONBLOCKING, "UDP log socket"); |
b69e9ffa | 171 | int xerrno = errno; |
82b7abe3 | 172 | if (ll->fd < 0) { |
9d65168e A |
173 | if (lf->flags.fatal) { |
174 | fatalf("Unable to open UDP socket for logging\n"); | |
175 | } else { | |
d816f28d | 176 | debugs(50, DBG_IMPORTANT, "ERROR: Unable to open UDP socket for logging"); |
9d65168e A |
177 | return FALSE; |
178 | } | |
db772b66 | 179 | } else if (!comm_connect_addr(ll->fd, addr)) { |
b69e9ffa | 180 | xerrno = errno; |
9d65168e | 181 | if (lf->flags.fatal) { |
b69e9ffa | 182 | fatalf("Unable to connect to %s for UDP log: %s\n", lf->path, xstrerr(xerrno)); |
9d65168e | 183 | } else { |
d816f28d | 184 | debugs(50, DBG_IMPORTANT, "ERROR: Unable to connect to " << lf->path << " for UDP log: " << xstrerr(xerrno)); |
9d65168e A |
185 | return FALSE; |
186 | } | |
82b7abe3 AJ |
187 | } |
188 | if (ll->fd == -1) { | |
b69e9ffa | 189 | if (ENOENT == xerrno && fatal_flag) { |
9d65168e A |
190 | fatalf("Cannot open '%s' because\n" |
191 | "\tthe parent directory does not exist.\n" | |
192 | "\tPlease create the directory.\n", path); | |
b69e9ffa | 193 | } else if (EACCES == xerrno && fatal_flag) { |
9d65168e A |
194 | fatalf("Cannot open '%s' for writing.\n" |
195 | "\tThe parent directory must be writeable by the\n" | |
196 | "\tuser '%s', which is the cache_effective_user\n" | |
197 | "\tset in squid.conf.", path, Config.effectiveUser); | |
198 | } else { | |
b69e9ffa | 199 | debugs(50, DBG_IMPORTANT, "logfileOpen (UDP): " << lf->path << ": " << xstrerr(xerrno)); |
9d65168e A |
200 | return 0; |
201 | } | |
82b7abe3 AJ |
202 | } |
203 | /* Force buffer size to something roughly fitting inside an MTU */ | |
204 | /* | |
205 | * XXX note the receive side needs to receive the whole packet at once; | |
206 | * applications like netcat have a small default receive buffer and will | |
207 | * truncate! | |
208 | */ | |
07d4ea38 | 209 | if (bufsz > 1400) |
210 | bufsz = 1400; | |
82b7abe3 | 211 | if (bufsz > 0) { |
9d65168e A |
212 | ll->buf = static_cast<char*>(xmalloc(bufsz)); |
213 | ll->bufsz = bufsz; | |
82b7abe3 AJ |
214 | } |
215 | ||
216 | return 1; | |
217 | } | |
f53969cc | 218 |