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