blob: 36b917c107e72196aec7dfc01c5244c47ccd5690 [file] [log] [blame]
Willy Tarreau67b5a162019-08-11 16:38:56 +02001/*
2 * Event sink management
3 *
4 * Copyright (C) 2000-2019 Willy Tarreau - w@1wt.eu
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation, version 2.1
9 * exclusively.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
Willy Tarreau0b8e9ce2022-08-11 16:38:20 +020021#include <sys/mman.h>
22#include <errno.h>
23#include <fcntl.h>
24
Willy Tarreau36979d92020-06-05 17:27:29 +020025#include <import/ist.h>
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020026#include <haproxy/api.h>
Christopher Faulet6b0a0fb2022-04-04 11:29:28 +020027#include <haproxy/applet.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020028#include <haproxy/cfgparse.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020029#include <haproxy/cli.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020030#include <haproxy/errors.h>
Willy Tarreau853b2972020-05-27 18:01:47 +020031#include <haproxy/list.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +020032#include <haproxy/log.h>
Willy Tarreau817538e2021-05-08 20:20:21 +020033#include <haproxy/proxy.h>
Willy Tarreaud2ad57c2020-06-03 19:43:35 +020034#include <haproxy/ring.h>
Willy Tarreau5edca2f2022-05-27 09:25:10 +020035#include <haproxy/sc_strm.h>
Willy Tarreau3727a8a2020-06-04 17:37:26 +020036#include <haproxy/signal.h>
Willy Tarreauba2f73d2020-06-03 20:02:28 +020037#include <haproxy/sink.h>
Willy Tarreaucb086c62022-05-27 09:47:12 +020038#include <haproxy/stconn.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020039#include <haproxy/time.h>
Willy Tarreau4bad5e22021-05-08 13:05:30 +020040#include <haproxy/tools.h>
Willy Tarreau67b5a162019-08-11 16:38:56 +020041
42struct list sink_list = LIST_HEAD_INIT(sink_list);
43
Emeric Brund6e581d2022-09-13 16:16:30 +020044/* sink proxies list */
45struct proxy *sink_proxies_list;
46
Emeric Brun99c453d2020-05-25 15:01:04 +020047struct sink *cfg_sink;
48
Willy Tarreau67b5a162019-08-11 16:38:56 +020049struct sink *sink_find(const char *name)
50{
51 struct sink *sink;
52
53 list_for_each_entry(sink, &sink_list, sink_list)
54 if (strcmp(sink->name, name) == 0)
55 return sink;
56 return NULL;
57}
58
59/* creates a new sink and adds it to the list, it's still generic and not fully
60 * initialized. Returns NULL on allocation failure. If another one already
61 * exists with the same name, it will be returned. The caller can detect it as
62 * a newly created one has type SINK_TYPE_NEW.
63 */
Emeric Brun54648852020-07-06 15:54:06 +020064static struct sink *__sink_new(const char *name, const char *desc, int fmt)
Willy Tarreau67b5a162019-08-11 16:38:56 +020065{
66 struct sink *sink;
67
68 sink = sink_find(name);
69 if (sink)
70 goto end;
71
Emeric Brun494c5052020-05-28 11:13:15 +020072 sink = calloc(1, sizeof(*sink));
Willy Tarreau67b5a162019-08-11 16:38:56 +020073 if (!sink)
74 goto end;
75
Emeric Brun99c453d2020-05-25 15:01:04 +020076 sink->name = strdup(name);
Tim Duesterhusa7ebffe2021-01-03 19:54:11 +010077 if (!sink->name)
78 goto err;
79
Emeric Brun99c453d2020-05-25 15:01:04 +020080 sink->desc = strdup(desc);
Tim Duesterhusa7ebffe2021-01-03 19:54:11 +010081 if (!sink->desc)
82 goto err;
83
Willy Tarreau67b5a162019-08-11 16:38:56 +020084 sink->fmt = fmt;
85 sink->type = SINK_TYPE_NEW;
Christopher Fauleta63a5c22019-11-15 15:10:12 +010086 sink->maxlen = BUFSIZE;
Willy Tarreau67b5a162019-08-11 16:38:56 +020087 /* address will be filled by the caller if needed */
Willy Tarreau973e6622019-08-20 11:57:52 +020088 sink->ctx.fd = -1;
Willy Tarreau67b5a162019-08-11 16:38:56 +020089 sink->ctx.dropped = 0;
90 HA_RWLOCK_INIT(&sink->ctx.lock);
Willy Tarreau2b718102021-04-21 07:32:39 +020091 LIST_APPEND(&sink_list, &sink->sink_list);
Willy Tarreau67b5a162019-08-11 16:38:56 +020092 end:
93 return sink;
Tim Duesterhusa7ebffe2021-01-03 19:54:11 +010094
95 err:
Willy Tarreau61cfdf42021-02-20 10:46:51 +010096 ha_free(&sink->name);
97 ha_free(&sink->desc);
98 ha_free(&sink);
Tim Duesterhusa7ebffe2021-01-03 19:54:11 +010099
100 return NULL;
Willy Tarreau67b5a162019-08-11 16:38:56 +0200101}
102
Willy Tarreau973e6622019-08-20 11:57:52 +0200103/* creates a sink called <name> of type FD associated to fd <fd>, format <fmt>,
104 * and description <desc>. Returns NULL on allocation failure or conflict.
105 * Perfect duplicates are merged (same type, fd, and name).
106 */
Emeric Brun54648852020-07-06 15:54:06 +0200107struct sink *sink_new_fd(const char *name, const char *desc, enum log_fmt fmt, int fd)
Willy Tarreau973e6622019-08-20 11:57:52 +0200108{
109 struct sink *sink;
110
111 sink = __sink_new(name, desc, fmt);
112 if (!sink || (sink->type == SINK_TYPE_FD && sink->ctx.fd == fd))
113 goto end;
114
115 if (sink->type != SINK_TYPE_NEW) {
116 sink = NULL;
117 goto end;
118 }
119
120 sink->type = SINK_TYPE_FD;
121 sink->ctx.fd = fd;
122 end:
123 return sink;
124}
125
Willy Tarreau4ed23ca2019-08-23 15:47:49 +0200126/* creates a sink called <name> of type BUF of size <size>, format <fmt>,
127 * and description <desc>. Returns NULL on allocation failure or conflict.
128 * Perfect duplicates are merged (same type and name). If sizes differ, the
129 * largest one is kept.
130 */
Emeric Brun54648852020-07-06 15:54:06 +0200131struct sink *sink_new_buf(const char *name, const char *desc, enum log_fmt fmt, size_t size)
Willy Tarreau4ed23ca2019-08-23 15:47:49 +0200132{
133 struct sink *sink;
134
135 sink = __sink_new(name, desc, fmt);
136 if (!sink)
137 goto fail;
138
139 if (sink->type == SINK_TYPE_BUFFER) {
140 /* such a buffer already exists, we may have to resize it */
141 if (!ring_resize(sink->ctx.ring, size))
142 goto fail;
143 goto end;
144 }
145
146 if (sink->type != SINK_TYPE_NEW) {
147 /* already exists of another type */
148 goto fail;
149 }
150
151 sink->ctx.ring = ring_new(size);
152 if (!sink->ctx.ring) {
Willy Tarreau2b718102021-04-21 07:32:39 +0200153 LIST_DELETE(&sink->sink_list);
Emeric Brun99c453d2020-05-25 15:01:04 +0200154 free(sink->name);
155 free(sink->desc);
Willy Tarreau4ed23ca2019-08-23 15:47:49 +0200156 free(sink);
157 goto fail;
158 }
159
160 sink->type = SINK_TYPE_BUFFER;
161 end:
162 return sink;
163 fail:
164 return NULL;
165}
166
Willy Tarreau67b5a162019-08-11 16:38:56 +0200167/* tries to send <nmsg> message parts (up to 8, ignored above) from message
Ilya Shipitsin46a030c2020-07-05 16:36:08 +0500168 * array <msg> to sink <sink>. Formatting according to the sink's preference is
Willy Tarreau8f240232019-08-27 16:41:06 +0200169 * done here. Lost messages are NOT accounted for. It is preferable to call
170 * sink_write() instead which will also try to emit the number of dropped
Aurelien DARRAGON5bab37e2023-06-26 16:44:41 +0200171 * messages when there are any. It will stop writing at <maxlen> instead of
172 * sink->maxlen if <maxlen> is positive and inferior to sink->maxlen.
173 *
174 * It returns >0 if it could write anything, <=0 otherwise.
Willy Tarreau67b5a162019-08-11 16:38:56 +0200175 */
Aurelien DARRAGON5bab37e2023-06-26 16:44:41 +0200176 ssize_t __sink_write(struct sink *sink, size_t maxlen,
177 const struct ist msg[], size_t nmsg,
Emeric Brun54648852020-07-06 15:54:06 +0200178 int level, int facility, struct ist *metadata)
179 {
180 struct ist *pfx = NULL;
Willy Tarreaua1426de2019-08-27 14:21:02 +0200181 size_t npfx = 0;
Emeric Brunbd163812020-05-06 14:33:46 +0200182
Emeric Brun54648852020-07-06 15:54:06 +0200183 if (sink->fmt == LOG_FORMAT_RAW)
Emeric Brunbd163812020-05-06 14:33:46 +0200184 goto send;
Willy Tarreau67b5a162019-08-11 16:38:56 +0200185
Emeric Brun54648852020-07-06 15:54:06 +0200186 pfx = build_log_header(sink->fmt, level, facility, metadata, &npfx);
Emeric Brunbd163812020-05-06 14:33:46 +0200187
188send:
Aurelien DARRAGON5bab37e2023-06-26 16:44:41 +0200189 if (!maxlen)
190 maxlen = ~0;
Willy Tarreau973e6622019-08-20 11:57:52 +0200191 if (sink->type == SINK_TYPE_FD) {
Aurelien DARRAGON5bab37e2023-06-26 16:44:41 +0200192 return fd_write_frag_line(sink->ctx.fd, MIN(maxlen, sink->maxlen), pfx, npfx, msg, nmsg, 1);
Willy Tarreau4ed23ca2019-08-23 15:47:49 +0200193 }
194 else if (sink->type == SINK_TYPE_BUFFER) {
Aurelien DARRAGON5bab37e2023-06-26 16:44:41 +0200195 return ring_write(sink->ctx.ring, MIN(maxlen, sink->maxlen), pfx, npfx, msg, nmsg);
Willy Tarreau973e6622019-08-20 11:57:52 +0200196 }
Willy Tarreau8f240232019-08-27 16:41:06 +0200197 return 0;
198}
Willy Tarreau67b5a162019-08-11 16:38:56 +0200199
Willy Tarreau8f240232019-08-27 16:41:06 +0200200/* Tries to emit a message indicating the number of dropped events. In case of
201 * success, the amount of drops is reduced by as much. It's supposed to be
202 * called under an exclusive lock on the sink to avoid multiple produces doing
203 * the same. On success, >0 is returned, otherwise <=0 on failure.
204 */
Emeric Brun54648852020-07-06 15:54:06 +0200205int sink_announce_dropped(struct sink *sink, int facility)
Willy Tarreau8f240232019-08-27 16:41:06 +0200206{
Emeric Brun54648852020-07-06 15:54:06 +0200207 static THREAD_LOCAL struct ist metadata[LOG_META_FIELDS];
208 static THREAD_LOCAL pid_t curr_pid;
209 static THREAD_LOCAL char pidstr[16];
Willy Tarreau8f240232019-08-27 16:41:06 +0200210 unsigned int dropped;
211 struct buffer msg;
212 struct ist msgvec[1];
213 char logbuf[64];
214
215 while (unlikely((dropped = sink->ctx.dropped) > 0)) {
216 chunk_init(&msg, logbuf, sizeof(logbuf));
217 chunk_printf(&msg, "%u event%s dropped", dropped, dropped > 1 ? "s" : "");
218 msgvec[0] = ist2(msg.area, msg.data);
Emeric Brunbd163812020-05-06 14:33:46 +0200219
Emeric Brun54648852020-07-06 15:54:06 +0200220 if (!metadata[LOG_META_HOST].len) {
221 if (global.log_send_hostname)
Tim Duesterhus77508502022-03-15 13:11:06 +0100222 metadata[LOG_META_HOST] = ist(global.log_send_hostname);
Emeric Brun54648852020-07-06 15:54:06 +0200223 }
224
225 if (!metadata[LOG_META_TAG].len)
226 metadata[LOG_META_TAG] = ist2(global.log_tag.area, global.log_tag.data);
227
228 if (unlikely(curr_pid != getpid()))
229 metadata[LOG_META_PID].len = 0;
230
231 if (!metadata[LOG_META_PID].len) {
232 curr_pid = getpid();
233 ltoa_o(curr_pid, pidstr, sizeof(pidstr));
234 metadata[LOG_META_PID] = ist2(pidstr, strlen(pidstr));
235 }
236
Aurelien DARRAGON5bab37e2023-06-26 16:44:41 +0200237 if (__sink_write(sink, 0, msgvec, 1, LOG_NOTICE, facility, metadata) <= 0)
Willy Tarreau8f240232019-08-27 16:41:06 +0200238 return 0;
239 /* success! */
240 HA_ATOMIC_SUB(&sink->ctx.dropped, dropped);
241 }
242 return 1;
Willy Tarreau67b5a162019-08-11 16:38:56 +0200243}
244
Willy Tarreau9f830d72019-08-26 18:17:04 +0200245/* parse the "show events" command, returns 1 if a message is returned, otherwise zero */
246static int cli_parse_show_events(char **args, char *payload, struct appctx *appctx, void *private)
247{
248 struct sink *sink;
Willy Tarreaucba88382022-05-05 15:18:57 +0200249 uint ring_flags;
Willy Tarreau1d181e42019-08-30 11:17:01 +0200250 int arg;
Willy Tarreau9f830d72019-08-26 18:17:04 +0200251
252 args++; // make args[1] the 1st arg
253
254 if (!*args[1]) {
255 /* no arg => report the list of supported sink */
Willy Tarreau1d181e42019-08-30 11:17:01 +0200256 chunk_printf(&trash, "Supported events sinks are listed below. Add -w(wait), -n(new). Any key to stop\n");
Willy Tarreau9f830d72019-08-26 18:17:04 +0200257 list_for_each_entry(sink, &sink_list, sink_list) {
258 chunk_appendf(&trash, " %-10s : type=%s, %u dropped, %s\n",
259 sink->name,
260 sink->type == SINK_TYPE_NEW ? "init" :
261 sink->type == SINK_TYPE_FD ? "fd" :
262 sink->type == SINK_TYPE_BUFFER ? "buffer" : "?",
263 sink->ctx.dropped, sink->desc);
264 }
265
266 trash.area[trash.data] = 0;
267 return cli_msg(appctx, LOG_WARNING, trash.area);
268 }
269
270 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
271 return 1;
272
273 sink = sink_find(args[1]);
274 if (!sink)
275 return cli_err(appctx, "No such event sink");
276
277 if (sink->type != SINK_TYPE_BUFFER)
278 return cli_msg(appctx, LOG_NOTICE, "Nothing to report for this sink");
279
Willy Tarreaucba88382022-05-05 15:18:57 +0200280 ring_flags = 0;
Willy Tarreau1d181e42019-08-30 11:17:01 +0200281 for (arg = 2; *args[arg]; arg++) {
282 if (strcmp(args[arg], "-w") == 0)
Willy Tarreaucba88382022-05-05 15:18:57 +0200283 ring_flags |= RING_WF_WAIT_MODE;
Willy Tarreau1d181e42019-08-30 11:17:01 +0200284 else if (strcmp(args[arg], "-n") == 0)
Willy Tarreaucba88382022-05-05 15:18:57 +0200285 ring_flags |= RING_WF_SEEK_NEW;
Willy Tarreau1d181e42019-08-30 11:17:01 +0200286 else if (strcmp(args[arg], "-nw") == 0 || strcmp(args[arg], "-wn") == 0)
Willy Tarreaucba88382022-05-05 15:18:57 +0200287 ring_flags |= RING_WF_WAIT_MODE | RING_WF_SEEK_NEW;
Willy Tarreau1d181e42019-08-30 11:17:01 +0200288 else
289 return cli_err(appctx, "unknown option");
290 }
Willy Tarreaucba88382022-05-05 15:18:57 +0200291 return ring_attach_cli(sink->ctx.ring, appctx, ring_flags);
Willy Tarreau9f830d72019-08-26 18:17:04 +0200292}
293
Ilya Shipitsin47d17182020-06-21 21:42:57 +0500294/* Pre-configures a ring proxy to emit connections */
Emeric Brun494c5052020-05-28 11:13:15 +0200295void sink_setup_proxy(struct proxy *px)
296{
Willy Tarreau69530f52023-04-28 09:16:15 +0200297 px->last_change = ns_to_sec(now_ns);
Christopher Faulet11a707a2022-10-24 15:10:18 +0200298 px->cap = PR_CAP_BE;
Emeric Brun494c5052020-05-28 11:13:15 +0200299 px->maxconn = 0;
300 px->conn_retries = 1;
301 px->timeout.server = TICK_ETERNITY;
302 px->timeout.client = TICK_ETERNITY;
303 px->timeout.connect = TICK_ETERNITY;
304 px->accept = NULL;
305 px->options2 |= PR_O2_INDEPSTR | PR_O2_SMARTCON | PR_O2_SMARTACC;
Emeric Brund6e581d2022-09-13 16:16:30 +0200306 px->next = sink_proxies_list;
307 sink_proxies_list = px;
Emeric Brun494c5052020-05-28 11:13:15 +0200308}
309
310/*
Willy Tarreau42cc8312022-05-04 20:42:23 +0200311 * IO Handler to handle message push to syslog tcp server.
312 * It takes its context from appctx->svcctx.
Emeric Brun494c5052020-05-28 11:13:15 +0200313 */
314static void sink_forward_io_handler(struct appctx *appctx)
315{
Willy Tarreauc12b3212022-05-27 11:08:15 +0200316 struct stconn *sc = appctx_sc(appctx);
Willy Tarreau0eca5392022-05-27 10:44:25 +0200317 struct stream *s = __sc_strm(sc);
Emeric Brun494c5052020-05-28 11:13:15 +0200318 struct sink *sink = strm_fe(s)->parent;
Willy Tarreau42cc8312022-05-04 20:42:23 +0200319 struct sink_forward_target *sft = appctx->svcctx;
Emeric Brun494c5052020-05-28 11:13:15 +0200320 struct ring *ring = sink->ctx.ring;
321 struct buffer *buf = &ring->buf;
322 uint64_t msg_len;
Willy Tarreau53bfab02022-08-04 17:18:54 +0200323 size_t len, cnt, ofs, last_ofs;
Emeric Brun494c5052020-05-28 11:13:15 +0200324 int ret = 0;
325
Christopher Fauleta739dc22023-03-31 11:25:55 +0200326 if (unlikely(se_fl_test(appctx->sedesc, (SE_FL_EOS|SE_FL_ERROR|SE_FL_SHR|SE_FL_SHW))))
327 goto out;
328
Ilya Shipitsin47d17182020-06-21 21:42:57 +0500329 /* if stopping was requested, close immediately */
Emeric Brun494c5052020-05-28 11:13:15 +0200330 if (unlikely(stopping))
331 goto close;
332
Emeric Brun494c5052020-05-28 11:13:15 +0200333 /* if the connection is not established, inform the stream that we want
334 * to be notified whenever the connection completes.
335 */
Willy Tarreau0eca5392022-05-27 10:44:25 +0200336 if (sc_opposite(sc)->state < SC_ST_EST) {
Willy Tarreau90e8b452022-05-25 18:21:43 +0200337 applet_need_more_data(appctx);
Willy Tarreaub23edc82022-05-24 16:49:03 +0200338 se_need_remote_conn(appctx->sedesc);
Willy Tarreau4164eb92022-05-25 15:42:03 +0200339 applet_have_more_data(appctx);
Christopher Fauleta739dc22023-03-31 11:25:55 +0200340 goto out;
Emeric Brun494c5052020-05-28 11:13:15 +0200341 }
342
343 HA_SPIN_LOCK(SFT_LOCK, &sft->lock);
344 if (appctx != sft->appctx) {
345 HA_SPIN_UNLOCK(SFT_LOCK, &sft->lock);
346 goto close;
347 }
Emeric Brun494c5052020-05-28 11:13:15 +0200348
349 HA_RWLOCK_WRLOCK(LOGSRV_LOCK, &ring->lock);
350 LIST_DEL_INIT(&appctx->wait_entry);
351 HA_RWLOCK_WRUNLOCK(LOGSRV_LOCK, &ring->lock);
352
353 HA_RWLOCK_RDLOCK(LOGSRV_LOCK, &ring->lock);
354
355 /* explanation for the initialization below: it would be better to do
356 * this in the parsing function but this would occasionally result in
357 * dropped events because we'd take a reference on the oldest message
358 * and keep it while being scheduled. Thus instead let's take it the
359 * first time we enter here so that we have a chance to pass many
360 * existing messages before grabbing a reference to a location. This
361 * value cannot be produced after initialization.
362 */
Aurelien DARRAGON2c988672023-03-07 16:09:33 +0100363 if (unlikely(sft->ofs == ~0)) {
364 sft->ofs = b_peek_ofs(buf, 0);
365 HA_ATOMIC_INC(b_orig(buf) + sft->ofs);
Emeric Brun494c5052020-05-28 11:13:15 +0200366 }
367
Christopher Faulet4b866952023-03-31 11:24:48 +0200368 /* we were already there, adjust the offset to be relative to
369 * the buffer's head and remove us from the counter.
370 */
371 ofs = sft->ofs - b_head_ofs(buf);
372 if (sft->ofs < b_head_ofs(buf))
373 ofs += b_size(buf);
374 BUG_ON(ofs >= buf->size);
375 HA_ATOMIC_DEC(b_peek(buf, ofs));
376
Emeric Brun494c5052020-05-28 11:13:15 +0200377 /* in this loop, ofs always points to the counter byte that precedes
378 * the message so that we can take our reference there if we have to
379 * stop before the end (ret=0).
380 */
Christopher Faulet4b866952023-03-31 11:24:48 +0200381 ret = 1;
382 while (ofs + 1 < b_data(buf)) {
383 cnt = 1;
384 len = b_peek_varint(buf, ofs + cnt, &msg_len);
385 if (!len)
386 break;
387 cnt += len;
388 BUG_ON(msg_len + ofs + cnt + 1 > b_data(buf));
Emeric Brun494c5052020-05-28 11:13:15 +0200389
Christopher Faulet4b866952023-03-31 11:24:48 +0200390 if (unlikely(msg_len + 1 > b_size(&trash))) {
391 /* too large a message to ever fit, let's skip it */
Emeric Brun494c5052020-05-28 11:13:15 +0200392 ofs += cnt + msg_len;
Christopher Faulet4b866952023-03-31 11:24:48 +0200393 continue;
Emeric Brun494c5052020-05-28 11:13:15 +0200394 }
395
Christopher Faulet4b866952023-03-31 11:24:48 +0200396 chunk_reset(&trash);
397 len = b_getblk(buf, trash.area, msg_len, ofs + cnt);
398 trash.data += len;
399 trash.area[trash.data++] = '\n';
400
401 if (applet_putchk(appctx, &trash) == -1) {
402 ret = 0;
403 break;
404 }
405 ofs += cnt + msg_len;
Emeric Brun494c5052020-05-28 11:13:15 +0200406 }
Christopher Faulet4b866952023-03-31 11:24:48 +0200407
408 HA_ATOMIC_INC(b_peek(buf, ofs));
409 last_ofs = b_tail_ofs(buf);
410 sft->ofs = b_peek_ofs(buf, ofs);
411
Emeric Brun494c5052020-05-28 11:13:15 +0200412 HA_RWLOCK_RDUNLOCK(LOGSRV_LOCK, &ring->lock);
413
414 if (ret) {
415 /* let's be woken up once new data arrive */
416 HA_RWLOCK_WRLOCK(LOGSRV_LOCK, &ring->lock);
Willy Tarreau2b718102021-04-21 07:32:39 +0200417 LIST_APPEND(&ring->waiters, &appctx->wait_entry);
Willy Tarreaud9c71882023-02-22 14:50:14 +0100418 ofs = b_tail_ofs(buf);
Emeric Brun494c5052020-05-28 11:13:15 +0200419 HA_RWLOCK_WRUNLOCK(LOGSRV_LOCK, &ring->lock);
Willy Tarreau53bfab02022-08-04 17:18:54 +0200420 if (ofs != last_ofs) {
421 /* more data was added into the ring between the
422 * unlock and the lock, and the writer might not
423 * have seen us. We need to reschedule a read.
424 */
425 applet_have_more_data(appctx);
426 } else
427 applet_have_no_more_data(appctx);
Emeric Brun494c5052020-05-28 11:13:15 +0200428 }
429 HA_SPIN_UNLOCK(SFT_LOCK, &sft->lock);
430
Christopher Fauleta739dc22023-03-31 11:25:55 +0200431out:
Emeric Brun494c5052020-05-28 11:13:15 +0200432 /* always drain data from server */
Willy Tarreau0eca5392022-05-27 10:44:25 +0200433 co_skip(sc_oc(sc), sc_oc(sc)->output);
Emeric Brun494c5052020-05-28 11:13:15 +0200434 return;
435
436close:
Christopher Fauleta739dc22023-03-31 11:25:55 +0200437 se_fl_set(appctx->sedesc, SE_FL_EOS|SE_FL_EOI);
Emeric Brun494c5052020-05-28 11:13:15 +0200438}
439
Emeric Brun97556472020-05-30 01:42:45 +0200440/*
441 * IO Handler to handle message push to syslog tcp server
442 * using octet counting frames
Willy Tarreau42cc8312022-05-04 20:42:23 +0200443 * It takes its context from appctx->svcctx.
Emeric Brun97556472020-05-30 01:42:45 +0200444 */
445static void sink_forward_oc_io_handler(struct appctx *appctx)
446{
Willy Tarreauc12b3212022-05-27 11:08:15 +0200447 struct stconn *sc = appctx_sc(appctx);
Willy Tarreau0eca5392022-05-27 10:44:25 +0200448 struct stream *s = __sc_strm(sc);
Emeric Brun97556472020-05-30 01:42:45 +0200449 struct sink *sink = strm_fe(s)->parent;
Willy Tarreau42cc8312022-05-04 20:42:23 +0200450 struct sink_forward_target *sft = appctx->svcctx;
Emeric Brun97556472020-05-30 01:42:45 +0200451 struct ring *ring = sink->ctx.ring;
452 struct buffer *buf = &ring->buf;
453 uint64_t msg_len;
Willy Tarreau3b0510b2024-02-27 17:32:44 +0100454 size_t len, cnt, ofs, last_ofs;
Emeric Brun97556472020-05-30 01:42:45 +0200455 int ret = 0;
456 char *p;
457
Christopher Fauleta739dc22023-03-31 11:25:55 +0200458 if (unlikely(se_fl_test(appctx->sedesc, (SE_FL_EOS|SE_FL_ERROR|SE_FL_SHR|SE_FL_SHW))))
459 goto out;
460
Ilya Shipitsin47d17182020-06-21 21:42:57 +0500461 /* if stopping was requested, close immediately */
Emeric Brun97556472020-05-30 01:42:45 +0200462 if (unlikely(stopping))
463 goto close;
464
Emeric Brun97556472020-05-30 01:42:45 +0200465 /* if the connection is not established, inform the stream that we want
466 * to be notified whenever the connection completes.
467 */
Willy Tarreau0eca5392022-05-27 10:44:25 +0200468 if (sc_opposite(sc)->state < SC_ST_EST) {
Willy Tarreau90e8b452022-05-25 18:21:43 +0200469 applet_need_more_data(appctx);
Willy Tarreaub23edc82022-05-24 16:49:03 +0200470 se_need_remote_conn(appctx->sedesc);
Willy Tarreau4164eb92022-05-25 15:42:03 +0200471 applet_have_more_data(appctx);
Christopher Fauleta739dc22023-03-31 11:25:55 +0200472 goto out;
Emeric Brun97556472020-05-30 01:42:45 +0200473 }
474
475 HA_SPIN_LOCK(SFT_LOCK, &sft->lock);
476 if (appctx != sft->appctx) {
477 HA_SPIN_UNLOCK(SFT_LOCK, &sft->lock);
478 goto close;
479 }
Emeric Brun97556472020-05-30 01:42:45 +0200480
481 HA_RWLOCK_WRLOCK(LOGSRV_LOCK, &ring->lock);
482 LIST_DEL_INIT(&appctx->wait_entry);
483 HA_RWLOCK_WRUNLOCK(LOGSRV_LOCK, &ring->lock);
484
485 HA_RWLOCK_RDLOCK(LOGSRV_LOCK, &ring->lock);
486
487 /* explanation for the initialization below: it would be better to do
488 * this in the parsing function but this would occasionally result in
489 * dropped events because we'd take a reference on the oldest message
490 * and keep it while being scheduled. Thus instead let's take it the
491 * first time we enter here so that we have a chance to pass many
492 * existing messages before grabbing a reference to a location. This
493 * value cannot be produced after initialization.
494 */
Aurelien DARRAGON2c988672023-03-07 16:09:33 +0100495 if (unlikely(sft->ofs == ~0)) {
496 sft->ofs = b_peek_ofs(buf, 0);
497 HA_ATOMIC_INC(b_orig(buf) + sft->ofs);
Emeric Brun97556472020-05-30 01:42:45 +0200498 }
499
Christopher Faulet4b866952023-03-31 11:24:48 +0200500 /* we were already there, adjust the offset to be relative to
501 * the buffer's head and remove us from the counter.
502 */
503 ofs = sft->ofs - b_head_ofs(buf);
504 if (sft->ofs < b_head_ofs(buf))
505 ofs += b_size(buf);
506 BUG_ON(ofs >= buf->size);
507 HA_ATOMIC_DEC(b_peek(buf, ofs));
508
Emeric Brun97556472020-05-30 01:42:45 +0200509 /* in this loop, ofs always points to the counter byte that precedes
510 * the message so that we can take our reference there if we have to
511 * stop before the end (ret=0).
512 */
Christopher Faulet4b866952023-03-31 11:24:48 +0200513 ret = 1;
514 while (ofs + 1 < b_data(buf)) {
515 cnt = 1;
516 len = b_peek_varint(buf, ofs + cnt, &msg_len);
517 if (!len)
518 break;
519 cnt += len;
520 BUG_ON(msg_len + ofs + cnt + 1 > b_data(buf));
Emeric Brun97556472020-05-30 01:42:45 +0200521
Christopher Faulet4b866952023-03-31 11:24:48 +0200522 chunk_reset(&trash);
523 p = ulltoa(msg_len, trash.area, b_size(&trash));
524 if (p) {
525 trash.data = (p - trash.area) + 1;
526 *p = ' ';
527 }
Emeric Brun97556472020-05-30 01:42:45 +0200528
Christopher Faulet4b866952023-03-31 11:24:48 +0200529 if (!p || (trash.data + msg_len > b_size(&trash))) {
530 /* too large a message to ever fit, let's skip it */
Emeric Brun97556472020-05-30 01:42:45 +0200531 ofs += cnt + msg_len;
Christopher Faulet4b866952023-03-31 11:24:48 +0200532 continue;
Emeric Brun97556472020-05-30 01:42:45 +0200533 }
534
Christopher Faulet4b866952023-03-31 11:24:48 +0200535 trash.data += b_getblk(buf, p + 1, msg_len, ofs + cnt);
536
537 if (applet_putchk(appctx, &trash) == -1) {
538 ret = 0;
539 break;
540 }
541 ofs += cnt + msg_len;
Emeric Brun97556472020-05-30 01:42:45 +0200542 }
Christopher Faulet4b866952023-03-31 11:24:48 +0200543
544 HA_ATOMIC_INC(b_peek(buf, ofs));
Willy Tarreau3b0510b2024-02-27 17:32:44 +0100545 last_ofs = b_tail_ofs(buf);
Christopher Faulet4b866952023-03-31 11:24:48 +0200546 sft->ofs = b_peek_ofs(buf, ofs);
547
Emeric Brun97556472020-05-30 01:42:45 +0200548 HA_RWLOCK_RDUNLOCK(LOGSRV_LOCK, &ring->lock);
549
550 if (ret) {
551 /* let's be woken up once new data arrive */
552 HA_RWLOCK_WRLOCK(LOGSRV_LOCK, &ring->lock);
Willy Tarreau2b718102021-04-21 07:32:39 +0200553 LIST_APPEND(&ring->waiters, &appctx->wait_entry);
Willy Tarreau3b0510b2024-02-27 17:32:44 +0100554 ofs = b_tail_ofs(buf);
Emeric Brun97556472020-05-30 01:42:45 +0200555 HA_RWLOCK_WRUNLOCK(LOGSRV_LOCK, &ring->lock);
Willy Tarreau3b0510b2024-02-27 17:32:44 +0100556 if (ofs != last_ofs) {
557 /* more data was added into the ring between the
558 * unlock and the lock, and the writer might not
559 * have seen us. We need to reschedule a read.
560 */
561 applet_have_more_data(appctx);
562 } else
563 applet_have_no_more_data(appctx);
Emeric Brun97556472020-05-30 01:42:45 +0200564 }
565 HA_SPIN_UNLOCK(SFT_LOCK, &sft->lock);
566
Christopher Fauleta739dc22023-03-31 11:25:55 +0200567 out:
Emeric Brun97556472020-05-30 01:42:45 +0200568 /* always drain data from server */
Willy Tarreau0eca5392022-05-27 10:44:25 +0200569 co_skip(sc_oc(sc), sc_oc(sc)->output);
Emeric Brun97556472020-05-30 01:42:45 +0200570 return;
571
572close:
Christopher Fauleta739dc22023-03-31 11:25:55 +0200573 se_fl_set(appctx->sedesc, SE_FL_EOS|SE_FL_EOI);
574 goto out;
Emeric Brun97556472020-05-30 01:42:45 +0200575}
576
Emeric Brun494c5052020-05-28 11:13:15 +0200577void __sink_forward_session_deinit(struct sink_forward_target *sft)
578{
Willy Tarreau0698c802022-05-11 14:09:57 +0200579 struct stream *s = appctx_strm(sft->appctx);
Emeric Brun494c5052020-05-28 11:13:15 +0200580 struct sink *sink;
581
Emeric Brun494c5052020-05-28 11:13:15 +0200582 sink = strm_fe(s)->parent;
583 if (!sink)
584 return;
585
586 HA_RWLOCK_WRLOCK(LOGSRV_LOCK, &sink->ctx.ring->lock);
587 LIST_DEL_INIT(&sft->appctx->wait_entry);
588 HA_RWLOCK_WRUNLOCK(LOGSRV_LOCK, &sink->ctx.ring->lock);
589
590 sft->appctx = NULL;
591 task_wakeup(sink->forward_task, TASK_WOKEN_MSG);
592}
593
Christopher Fauletaee57fc2022-05-12 15:34:48 +0200594static int sink_forward_session_init(struct appctx *appctx)
595{
596 struct sink_forward_target *sft = appctx->svcctx;
597 struct stream *s;
598 struct sockaddr_storage *addr = NULL;
599
600 if (!sockaddr_alloc(&addr, &sft->srv->addr, sizeof(sft->srv->addr)))
601 goto out_error;
Aurelien DARRAGON12a9db52023-11-09 15:00:34 +0100602 /* srv port should be learned from srv->svc_port not from srv->addr */
603 set_host_port(addr, sft->srv->svc_port);
Christopher Fauletaee57fc2022-05-12 15:34:48 +0200604
605 if (appctx_finalize_startup(appctx, sft->sink->forward_px, &BUF_NULL) == -1)
606 goto out_free_addr;
607
608 s = appctx_strm(appctx);
Willy Tarreau7cb9e6c2022-05-17 19:40:40 +0200609 s->scb->dst = addr;
Christopher Faulet9a790f62023-03-16 14:40:03 +0100610 s->scb->flags |= (SC_FL_RCV_ONCE|SC_FL_NOLINGER);
Christopher Fauletaee57fc2022-05-12 15:34:48 +0200611
612 s->target = &sft->srv->obj_type;
613 s->flags = SF_ASSIGNED;
614
615 s->do_log = NULL;
616 s->uniq_id = 0;
617
Christopher Faulet2ca4cc12023-02-22 14:22:56 +0100618 applet_expect_no_data(appctx);
Christopher Fauletaee57fc2022-05-12 15:34:48 +0200619 sft->appctx = appctx;
620
621 return 0;
622
623 out_free_addr:
624 sockaddr_free(&addr);
625 out_error:
626 return -1;
627}
Emeric Brun494c5052020-05-28 11:13:15 +0200628
629static void sink_forward_session_release(struct appctx *appctx)
630{
Willy Tarreau42cc8312022-05-04 20:42:23 +0200631 struct sink_forward_target *sft = appctx->svcctx;
Emeric Brun494c5052020-05-28 11:13:15 +0200632
633 if (!sft)
634 return;
635
636 HA_SPIN_LOCK(SFT_LOCK, &sft->lock);
637 if (sft->appctx == appctx)
638 __sink_forward_session_deinit(sft);
639 HA_SPIN_UNLOCK(SFT_LOCK, &sft->lock);
640}
641
642static struct applet sink_forward_applet = {
643 .obj_type = OBJ_TYPE_APPLET,
644 .name = "<SINKFWD>", /* used for logging */
645 .fct = sink_forward_io_handler,
Christopher Fauletaee57fc2022-05-12 15:34:48 +0200646 .init = sink_forward_session_init,
Emeric Brun494c5052020-05-28 11:13:15 +0200647 .release = sink_forward_session_release,
648};
649
Emeric Brun97556472020-05-30 01:42:45 +0200650static struct applet sink_forward_oc_applet = {
651 .obj_type = OBJ_TYPE_APPLET,
652 .name = "<SINKFWDOC>", /* used for logging */
653 .fct = sink_forward_oc_io_handler,
Christopher Fauletaee57fc2022-05-12 15:34:48 +0200654 .init = sink_forward_session_init,
Emeric Brun97556472020-05-30 01:42:45 +0200655 .release = sink_forward_session_release,
656};
657
Emeric Brun494c5052020-05-28 11:13:15 +0200658/*
659 * Create a new peer session in assigned state (connect will start automatically)
Willy Tarreau42cc8312022-05-04 20:42:23 +0200660 * It sets its context into appctx->svcctx.
Emeric Brun494c5052020-05-28 11:13:15 +0200661 */
662static struct appctx *sink_forward_session_create(struct sink *sink, struct sink_forward_target *sft)
663{
Emeric Brun494c5052020-05-28 11:13:15 +0200664 struct appctx *appctx;
Emeric Brun97556472020-05-30 01:42:45 +0200665 struct applet *applet = &sink_forward_applet;
666
667 if (sft->srv->log_proto == SRV_LOG_PROTO_OCTET_COUNTING)
668 applet = &sink_forward_oc_applet;
Emeric Brun494c5052020-05-28 11:13:15 +0200669
Christopher Faulet6095d572022-05-16 17:09:48 +0200670 appctx = appctx_new_here(applet, NULL);
Christopher Faulet2479e5f2022-01-19 14:50:11 +0100671 if (!appctx)
Christopher Fauleta9e8b392022-03-23 11:01:09 +0100672 goto out_close;
Willy Tarreau42cc8312022-05-04 20:42:23 +0200673 appctx->svcctx = (void *)sft;
Emeric Brun494c5052020-05-28 11:13:15 +0200674
Christopher Fauletaee57fc2022-05-12 15:34:48 +0200675 if (appctx_init(appctx) == -1)
Christopher Faulet92202da2022-05-11 12:22:10 +0200676 goto out_free_appctx;
Christopher Faulet13a35e52021-12-20 15:34:16 +0100677
Emeric Brun494c5052020-05-28 11:13:15 +0200678 return appctx;
679
680 /* Error unrolling */
Emeric Brun494c5052020-05-28 11:13:15 +0200681 out_free_appctx:
Christopher Fauletaee57fc2022-05-12 15:34:48 +0200682 appctx_free_on_early_error(appctx);
Emeric Brun494c5052020-05-28 11:13:15 +0200683 out_close:
684 return NULL;
685}
686
687/*
688 * Task to handle connctions to forward servers
689 */
Willy Tarreau144f84a2021-03-02 16:09:26 +0100690static struct task *process_sink_forward(struct task * task, void *context, unsigned int state)
Emeric Brun494c5052020-05-28 11:13:15 +0200691{
692 struct sink *sink = (struct sink *)context;
693 struct sink_forward_target *sft = sink->sft;
694
695 task->expire = TICK_ETERNITY;
696
697 if (!stopping) {
698 while (sft) {
699 HA_SPIN_LOCK(SFT_LOCK, &sft->lock);
700 /* if appctx is NULL, start a new session */
701 if (!sft->appctx)
702 sft->appctx = sink_forward_session_create(sink, sft);
703 HA_SPIN_UNLOCK(SFT_LOCK, &sft->lock);
704 sft = sft->next;
705 }
706 }
707 else {
708 while (sft) {
709 HA_SPIN_LOCK(SFT_LOCK, &sft->lock);
710 /* awake applet to perform a clean close */
711 if (sft->appctx)
712 appctx_wakeup(sft->appctx);
713 HA_SPIN_UNLOCK(SFT_LOCK, &sft->lock);
714 sft = sft->next;
715 }
716 }
717
718 return task;
719}
720/*
721 * Init task to manage connctions to forward servers
722 *
723 * returns 0 in case of error.
724 */
725int sink_init_forward(struct sink *sink)
726{
Willy Tarreaubeeabf52021-10-01 18:23:30 +0200727 sink->forward_task = task_new_anywhere();
Emeric Brun494c5052020-05-28 11:13:15 +0200728 if (!sink->forward_task)
729 return 0;
730
731 sink->forward_task->process = process_sink_forward;
732 sink->forward_task->context = (void *)sink;
733 sink->forward_sighandler = signal_register_task(0, sink->forward_task, 0);
734 task_wakeup(sink->forward_task, TASK_WOKEN_INIT);
735 return 1;
736}
Willy Tarreau32872db2022-08-31 18:52:17 +0200737
738/* This tries to rotate a file-backed ring, but only if it contains contents.
739 * This way empty rings will not cause backups to be overwritten and it's safe
740 * to reload multiple times. That's only best effort, failures are silently
741 * ignored.
742 */
743void sink_rotate_file_backed_ring(const char *name)
744{
745 struct ring ring;
746 char *oldback;
747 int ret;
748 int fd;
749
750 fd = open(name, O_RDONLY);
751 if (fd < 0)
752 return;
753
754 /* check for contents validity */
755 ret = read(fd, &ring, sizeof(ring));
756 close(fd);
757
758 if (ret != sizeof(ring))
759 goto rotate;
760
761 /* contents are present, we want to keep them => rotate. Note that
762 * an empty ring buffer has one byte (the marker).
763 */
764 if (ring.buf.data > 1)
765 goto rotate;
766
767 /* nothing to keep, let's scratch the file and preserve the backup */
768 return;
769
770 rotate:
771 oldback = NULL;
772 memprintf(&oldback, "%s.bak", name);
773 if (oldback) {
774 /* try to rename any possibly existing ring file to
775 * ".bak" and delete remains of older ones. This will
776 * ensure we don't wipe useful debug info upon restart.
777 */
778 unlink(oldback);
779 if (rename(name, oldback) < 0)
780 unlink(oldback);
781 ha_free(&oldback);
782 }
783}
784
Emeric Brun99c453d2020-05-25 15:01:04 +0200785/*
786 * Parse "ring" section and create corresponding sink buffer.
787 *
788 * The function returns 0 in success case, otherwise, it returns error
789 * flags.
790 */
791int cfg_parse_ring(const char *file, int linenum, char **args, int kwm)
792{
793 int err_code = 0;
794 const char *inv;
795 size_t size = BUFSIZE;
Emeric Brun494c5052020-05-28 11:13:15 +0200796 struct proxy *p;
Emeric Brun99c453d2020-05-25 15:01:04 +0200797
Willy Tarreau18d13062022-08-11 16:12:11 +0200798 if (strcmp(args[0], "ring") == 0) { /* new ring section */
Emeric Brun99c453d2020-05-25 15:01:04 +0200799 if (!*args[1]) {
800 ha_alert("parsing [%s:%d] : missing ring name.\n", file, linenum);
801 err_code |= ERR_ALERT | ERR_FATAL;
802 goto err;
803 }
804
805 inv = invalid_char(args[1]);
806 if (inv) {
807 ha_alert("parsing [%s:%d] : invalid ring name '%s' (character '%c' is not permitted).\n", file, linenum, args[1], *inv);
808 err_code |= ERR_ALERT | ERR_FATAL;
809 goto err;
810 }
811
812 if (sink_find(args[1])) {
813 ha_alert("parsing [%s:%d] : sink named '%s' already exists.\n", file, linenum, args[1]);
814 err_code |= ERR_ALERT | ERR_FATAL;
815 goto err;
816 }
817
Emeric Brun54648852020-07-06 15:54:06 +0200818 cfg_sink = sink_new_buf(args[1], args[1], LOG_FORMAT_RAW, size);
Emeric Brun99c453d2020-05-25 15:01:04 +0200819 if (!cfg_sink || cfg_sink->type != SINK_TYPE_BUFFER) {
820 ha_alert("parsing [%s:%d] : unable to create a new sink buffer for ring '%s'.\n", file, linenum, args[1]);
821 err_code |= ERR_ALERT | ERR_FATAL;
822 goto err;
823 }
Emeric Brun494c5052020-05-28 11:13:15 +0200824
825 /* allocate new proxy to handle forwards */
826 p = calloc(1, sizeof *p);
827 if (!p) {
828 ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
829 err_code |= ERR_ALERT | ERR_FATAL;
830 goto err;
831 }
832
833 init_new_proxy(p);
834 sink_setup_proxy(p);
835 p->parent = cfg_sink;
836 p->id = strdup(args[1]);
837 p->conf.args.file = p->conf.file = strdup(file);
838 p->conf.args.line = p->conf.line = linenum;
839 cfg_sink->forward_px = p;
Emeric Brun99c453d2020-05-25 15:01:04 +0200840 }
841 else if (strcmp(args[0], "size") == 0) {
Willy Tarreau18d13062022-08-11 16:12:11 +0200842 if (!cfg_sink || (cfg_sink->type != SINK_TYPE_BUFFER)) {
843 ha_alert("parsing [%s:%d] : 'size' directive not usable with this type of sink.\n", file, linenum);
844 err_code |= ERR_ALERT | ERR_FATAL;
845 goto err;
846 }
847
Emeric Brun99c453d2020-05-25 15:01:04 +0200848 size = atol(args[1]);
849 if (!size) {
850 ha_alert("parsing [%s:%d] : invalid size '%s' for new sink buffer.\n", file, linenum, args[1]);
851 err_code |= ERR_ALERT | ERR_FATAL;
852 goto err;
853 }
854
Willy Tarreau0b8e9ce2022-08-11 16:38:20 +0200855 if (cfg_sink->store) {
856 ha_alert("parsing [%s:%d] : cannot resize an already mapped file, please specify 'size' before 'backing-file'.\n", file, linenum);
857 err_code |= ERR_ALERT | ERR_FATAL;
858 goto err;
859 }
860
Willy Tarreau18d13062022-08-11 16:12:11 +0200861 if (size < cfg_sink->ctx.ring->buf.size) {
862 ha_warning("parsing [%s:%d] : ignoring new size '%llu' that is smaller than current size '%llu' for ring '%s'.\n",
863 file, linenum, (ullong)size, (ullong)cfg_sink->ctx.ring->buf.size, cfg_sink->name);
Aurelien DARRAGONcad9ce52023-06-22 16:57:29 +0200864 err_code |= ERR_WARN;
Willy Tarreau18d13062022-08-11 16:12:11 +0200865 goto err;
866 }
867
868 if (!ring_resize(cfg_sink->ctx.ring, size)) {
869 ha_alert("parsing [%s:%d] : fail to set sink buffer size '%llu' for ring '%s'.\n", file, linenum,
870 (ullong)cfg_sink->ctx.ring->buf.size, cfg_sink->name);
Emeric Brun99c453d2020-05-25 15:01:04 +0200871 err_code |= ERR_ALERT | ERR_FATAL;
872 goto err;
873 }
Willy Tarreau0b8e9ce2022-08-11 16:38:20 +0200874 }
875 else if (strcmp(args[0], "backing-file") == 0) {
876 /* This tries to mmap file <file> for size <size> and to use it as a backing store
877 * for ring <ring>. Existing data are delete. NULL is returned on error.
878 */
879 const char *backing = args[1];
880 size_t size;
881 void *area;
882 int fd;
883
884 if (!cfg_sink || (cfg_sink->type != SINK_TYPE_BUFFER)) {
885 ha_alert("parsing [%s:%d] : 'backing-file' only usable with existing rings.\n", file, linenum);
886 err_code |= ERR_ALERT | ERR_FATAL;
887 goto err;
888 }
889
890 if (cfg_sink->store) {
891 ha_alert("parsing [%s:%d] : 'backing-file' already specified for ring '%s' (was '%s').\n", file, linenum, cfg_sink->name, cfg_sink->store);
892 err_code |= ERR_ALERT | ERR_FATAL;
893 goto err;
894 }
895
Willy Tarreau32872db2022-08-31 18:52:17 +0200896 /* let's check if the file exists and is not empty. That's the
897 * only condition under which we'll trigger a rotate, so that
898 * config checks, reloads, or restarts that don't emit anything
899 * do not rotate it again.
900 */
901 sink_rotate_file_backed_ring(backing);
Willy Tarreauded77cc2022-08-12 15:38:20 +0200902
Willy Tarreau8e877052022-08-12 15:03:12 +0200903 fd = open(backing, O_RDWR | O_CREAT, 0600);
Willy Tarreau0b8e9ce2022-08-11 16:38:20 +0200904 if (fd < 0) {
905 ha_alert("parsing [%s:%d] : cannot open backing-file '%s' for ring '%s': %s.\n", file, linenum, backing, cfg_sink->name, strerror(errno));
906 err_code |= ERR_ALERT | ERR_FATAL;
907 goto err;
908 }
909
910 size = (cfg_sink->ctx.ring->buf.size + 4095UL) & -4096UL;
911 if (ftruncate(fd, size) != 0) {
912 close(fd);
913 ha_alert("parsing [%s:%d] : could not adjust size of backing-file for ring '%s': %s.\n", file, linenum, cfg_sink->name, strerror(errno));
914 err_code |= ERR_ALERT | ERR_FATAL;
915 goto err;
916 }
917
918 area = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
919 if (area == MAP_FAILED) {
920 close(fd);
921 ha_alert("parsing [%s:%d] : failed to use '%s' as a backing file for ring '%s': %s.\n", file, linenum, backing, cfg_sink->name, strerror(errno));
922 err_code |= ERR_ALERT | ERR_FATAL;
923 goto err;
924 }
925
926 /* we don't need the file anymore */
927 close(fd);
928 cfg_sink->store = strdup(backing);
929
930 /* never fails */
931 ring_free(cfg_sink->ctx.ring);
932 cfg_sink->ctx.ring = ring_make_from_area(area, size);
Emeric Brun99c453d2020-05-25 15:01:04 +0200933 }
Emeric Brun494c5052020-05-28 11:13:15 +0200934 else if (strcmp(args[0],"server") == 0) {
Willy Tarreau1b662aa2022-11-16 18:56:34 +0100935 if (!cfg_sink || (cfg_sink->type != SINK_TYPE_BUFFER)) {
936 ha_alert("parsing [%s:%d] : unable to create server '%s'.\n", file, linenum, args[1]);
937 err_code |= ERR_ALERT | ERR_FATAL;
938 goto err;
939 }
940
Amaury Denoyelle30c05372021-03-08 16:36:46 +0100941 err_code |= parse_server(file, linenum, args, cfg_sink->forward_px, NULL,
942 SRV_PARSE_PARSE_ADDR|SRV_PARSE_INITIAL_RESOLVE);
Emeric Brun494c5052020-05-28 11:13:15 +0200943 }
944 else if (strcmp(args[0],"timeout") == 0) {
945 if (!cfg_sink || !cfg_sink->forward_px) {
946 ha_alert("parsing [%s:%d] : unable to set timeout '%s'.\n", file, linenum, args[1]);
947 err_code |= ERR_ALERT | ERR_FATAL;
948 goto err;
949 }
950
951 if (strcmp(args[1], "connect") == 0 ||
952 strcmp(args[1], "server") == 0) {
953 const char *res;
954 unsigned int tout;
955
956 if (!*args[2]) {
957 ha_alert("parsing [%s:%d] : '%s %s' expects <time> as argument.\n",
958 file, linenum, args[0], args[1]);
959 err_code |= ERR_ALERT | ERR_FATAL;
960 goto err;
961 }
962 res = parse_time_err(args[2], &tout, TIME_UNIT_MS);
963 if (res == PARSE_TIME_OVER) {
964 ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to <%s %s>, maximum value is 2147483647 ms (~24.8 days).\n",
965 file, linenum, args[2], args[0], args[1]);
966 err_code |= ERR_ALERT | ERR_FATAL;
967 goto err;
968 }
969 else if (res == PARSE_TIME_UNDER) {
970 ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to <%s %s>, minimum non-null value is 1 ms.\n",
971 file, linenum, args[2], args[0], args[1]);
972 err_code |= ERR_ALERT | ERR_FATAL;
973 goto err;
974 }
975 else if (res) {
976 ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to <%s %s>.\n",
977 file, linenum, *res, args[0], args[1]);
978 err_code |= ERR_ALERT | ERR_FATAL;
979 goto err;
980 }
Christopher Faulet321d1002022-10-19 16:26:21 +0200981 if (args[1][0] == 'c')
Emeric Brun494c5052020-05-28 11:13:15 +0200982 cfg_sink->forward_px->timeout.connect = tout;
983 else
984 cfg_sink->forward_px->timeout.server = tout;
985 }
986 }
Emeric Brun99c453d2020-05-25 15:01:04 +0200987 else if (strcmp(args[0],"format") == 0) {
988 if (!cfg_sink) {
989 ha_alert("parsing [%s:%d] : unable to set format '%s'.\n", file, linenum, args[1]);
990 err_code |= ERR_ALERT | ERR_FATAL;
991 goto err;
992 }
993
Emeric Brun54648852020-07-06 15:54:06 +0200994 cfg_sink->fmt = get_log_format(args[1]);
995 if (cfg_sink->fmt == LOG_FORMAT_UNSPEC) {
Emeric Brun99c453d2020-05-25 15:01:04 +0200996 ha_alert("parsing [%s:%d] : unknown format '%s'.\n", file, linenum, args[1]);
997 err_code |= ERR_ALERT | ERR_FATAL;
998 goto err;
999 }
1000 }
1001 else if (strcmp(args[0],"maxlen") == 0) {
1002 if (!cfg_sink) {
1003 ha_alert("parsing [%s:%d] : unable to set event max length '%s'.\n", file, linenum, args[1]);
1004 err_code |= ERR_ALERT | ERR_FATAL;
1005 goto err;
1006 }
1007
1008 cfg_sink->maxlen = atol(args[1]);
1009 if (!cfg_sink->maxlen) {
1010 ha_alert("parsing [%s:%d] : invalid size '%s' for new sink buffer.\n", file, linenum, args[1]);
1011 err_code |= ERR_ALERT | ERR_FATAL;
1012 goto err;
1013 }
1014 }
1015 else if (strcmp(args[0],"description") == 0) {
1016 if (!cfg_sink) {
1017 ha_alert("parsing [%s:%d] : unable to set description '%s'.\n", file, linenum, args[1]);
1018 err_code |= ERR_ALERT | ERR_FATAL;
1019 goto err;
1020 }
1021
1022 if (!*args[1]) {
1023 ha_alert("parsing [%s:%d] : missing ring description text.\n", file, linenum);
1024 err_code |= ERR_ALERT | ERR_FATAL;
1025 goto err;
1026 }
1027
1028 free(cfg_sink->desc);
1029
1030 cfg_sink->desc = strdup(args[1]);
1031 if (!cfg_sink->desc) {
1032 ha_alert("parsing [%s:%d] : fail to set description '%s'.\n", file, linenum, args[1]);
1033 err_code |= ERR_ALERT | ERR_FATAL;
1034 goto err;
1035 }
1036 }
Emeric Brun9f2ff3a2020-05-29 15:47:52 +02001037 else {
1038 ha_alert("parsing [%s:%d] : unknown statement '%s'.\n", file, linenum, args[0]);
1039 err_code |= ERR_ALERT | ERR_FATAL;
1040 goto err;
1041 }
Emeric Brun99c453d2020-05-25 15:01:04 +02001042
1043err:
1044 return err_code;
1045}
1046
Emeric Brun94aab062021-04-02 10:41:36 +02001047/* Creates an new sink buffer from a log server.
1048 *
1049 * It uses the logsrvaddress to declare a forward
1050 * server for this buffer. And it initializes the
1051 * forwarding.
1052 *
1053 * The function returns a pointer on the
1054 * allocated struct sink if allocate
1055 * and initialize succeed, else if it fails
1056 * it returns NULL.
1057 *
1058 * Note: the sink is created using the name
Ilya Shipitsinb2be9a12021-04-24 13:25:42 +05001059 * specified into logsrv->ring_name
Emeric Brun94aab062021-04-02 10:41:36 +02001060 */
1061struct sink *sink_new_from_logsrv(struct logsrv *logsrv)
1062{
1063 struct proxy *p = NULL;
1064 struct sink *sink = NULL;
1065 struct server *srv = NULL;
1066 struct sink_forward_target *sft = NULL;
Emeric Brun94aab062021-04-02 10:41:36 +02001067
1068 /* allocate new proxy to handle
1069 * forward to a stream server
1070 */
1071 p = calloc(1, sizeof *p);
1072 if (!p) {
1073 goto error;
1074 }
1075
1076 init_new_proxy(p);
1077 sink_setup_proxy(p);
1078 p->id = strdup(logsrv->ring_name);
1079 p->conf.args.file = p->conf.file = strdup(logsrv->conf.file);
1080 p->conf.args.line = p->conf.line = logsrv->conf.line;
1081
Christopher Fauletd08a25b2022-10-24 15:53:01 +02001082 /* Set default connect and server timeout */
1083 p->timeout.connect = MS_TO_TICKS(1000);
1084 p->timeout.server = MS_TO_TICKS(5000);
1085
Emeric Brun94aab062021-04-02 10:41:36 +02001086 /* allocate a new server to forward messages
1087 * from ring buffer
1088 */
1089 srv = new_server(p);
1090 if (!srv)
1091 goto error;
1092
1093 /* init server */
1094 srv->id = strdup(logsrv->ring_name);
1095 srv->conf.file = strdup(logsrv->conf.file);
1096 srv->conf.line = logsrv->conf.line;
1097 srv->addr = logsrv->addr;
1098 srv->svc_port = get_host_port(&logsrv->addr);
1099 HA_SPIN_INIT(&srv->lock);
1100
1101 /* process per thread init */
Miroslav Zagorac8a8f2702021-06-15 15:33:20 +02001102 if (srv_init_per_thr(srv) == -1)
Emeric Brun94aab062021-04-02 10:41:36 +02001103 goto error;
1104
Emeric Brun94aab062021-04-02 10:41:36 +02001105 /* the servers are linked backwards
1106 * first into proxy
1107 */
Emeric Brun94aab062021-04-02 10:41:36 +02001108 srv->next = p->srv;
Aurelien DARRAGONaff4ac22023-07-06 14:57:32 +02001109 p->srv = srv;
Emeric Brun94aab062021-04-02 10:41:36 +02001110
1111 /* allocate sink_forward_target descriptor */
1112 sft = calloc(1, sizeof(*sft));
1113 if (!sft)
1114 goto error;
1115
1116 /* init sink_forward_target offset */
1117 sft->srv = srv;
1118 sft->appctx = NULL;
1119 sft->ofs = ~0;
1120 HA_SPIN_INIT(&sft->lock);
1121
Ilya Shipitsinb2be9a12021-04-24 13:25:42 +05001122 /* prepare description for the sink */
Emeric Brun94aab062021-04-02 10:41:36 +02001123 chunk_reset(&trash);
1124 chunk_printf(&trash, "created from logserver declared into '%s' at line %d", logsrv->conf.file, logsrv->conf.line);
1125
1126 /* allocate a new sink buffer */
1127 sink = sink_new_buf(logsrv->ring_name, trash.area, logsrv->format, BUFSIZE);
1128 if (!sink || sink->type != SINK_TYPE_BUFFER) {
1129 goto error;
1130 }
1131
1132 /* link sink_forward_target to proxy */
1133 sink->forward_px = p;
1134 p->parent = sink;
1135
1136 /* insert into sink_forward_targets
1137 * list into sink
1138 */
Christopher Faulet2ae25ea2022-05-12 14:50:09 +02001139 sft->sink = sink;
Emeric Brun94aab062021-04-02 10:41:36 +02001140 sft->next = sink->sft;
1141 sink->sft = sft;
1142
1143 /* mark server as an attached reader to the ring */
1144 if (!ring_attach(sink->ctx.ring)) {
1145 /* should never fail since there is
1146 * only one reader
1147 */
1148 goto error;
1149 }
1150
1151 /* initialize sink buffer forwarding */
1152 if (!sink_init_forward(sink))
1153 goto error;
1154
1155 /* reset familyt of logsrv to consider the ring buffer target */
1156 logsrv->addr.ss_family = AF_UNSPEC;
1157
1158 return sink;
1159error:
Aurelien DARRAGON9da1f952023-07-11 09:31:06 +02001160 if (srv)
1161 srv_drop(srv);
1162
Emeric Brun94aab062021-04-02 10:41:36 +02001163 if (p) {
1164 if (p->id)
1165 free(p->id);
1166 if (p->conf.file)
1167 free(p->conf.file);
1168
1169 free(p);
1170 }
1171
Emeric Brun94aab062021-04-02 10:41:36 +02001172 if (sft)
1173 free(sft);
1174
1175 if (sink) {
Tim Duesterhus1307cd42023-04-22 17:47:35 +02001176 ring_free(sink->ctx.ring);
Emeric Brun94aab062021-04-02 10:41:36 +02001177
Willy Tarreau2b718102021-04-21 07:32:39 +02001178 LIST_DELETE(&sink->sink_list);
Emeric Brun94aab062021-04-02 10:41:36 +02001179 free(sink->name);
1180 free(sink->desc);
1181 free(sink);
1182 }
1183
1184 return NULL;
1185}
1186
Emeric Brun99c453d2020-05-25 15:01:04 +02001187/*
1188 * Post parsing "ring" section.
1189 *
1190 * The function returns 0 in success case, otherwise, it returns error
1191 * flags.
1192 */
1193int cfg_post_parse_ring()
1194{
1195 int err_code = 0;
Emeric Brun494c5052020-05-28 11:13:15 +02001196 struct server *srv;
Emeric Brun99c453d2020-05-25 15:01:04 +02001197
1198 if (cfg_sink && (cfg_sink->type == SINK_TYPE_BUFFER)) {
1199 if (cfg_sink->maxlen > b_size(&cfg_sink->ctx.ring->buf)) {
1200 ha_warning("ring '%s' event max length '%u' exceeds size, forced to size '%lu'.\n",
Willy Tarreau570a22b2020-06-02 12:00:46 +02001201 cfg_sink->name, cfg_sink->maxlen, (unsigned long)b_size(&cfg_sink->ctx.ring->buf));
Emeric Brun99c453d2020-05-25 15:01:04 +02001202 cfg_sink->maxlen = b_size(&cfg_sink->ctx.ring->buf);
Aurelien DARRAGON79504b92023-06-26 14:22:12 +02001203 err_code |= ERR_WARN;
Emeric Brun99c453d2020-05-25 15:01:04 +02001204 }
Emeric Brun494c5052020-05-28 11:13:15 +02001205
1206 /* prepare forward server descriptors */
1207 if (cfg_sink->forward_px) {
1208 srv = cfg_sink->forward_px->srv;
1209 while (srv) {
1210 struct sink_forward_target *sft;
Emeric Brun99c453d2020-05-25 15:01:04 +02001211
Emeric Brun494c5052020-05-28 11:13:15 +02001212 /* allocate sink_forward_target descriptor */
1213 sft = calloc(1, sizeof(*sft));
1214 if (!sft) {
1215 ha_alert("memory allocation error initializing server '%s' in ring '%s'.\n",srv->id, cfg_sink->name);
1216 err_code |= ERR_ALERT | ERR_FATAL;
1217 break;
1218 }
1219 sft->srv = srv;
1220 sft->appctx = NULL;
1221 sft->ofs = ~0; /* init ring offset */
Christopher Faulet96417f32022-08-04 16:00:13 +02001222 sft->sink = cfg_sink;
Emeric Brun494c5052020-05-28 11:13:15 +02001223 sft->next = cfg_sink->sft;
1224 HA_SPIN_INIT(&sft->lock);
1225
1226 /* mark server attached to the ring */
1227 if (!ring_attach(cfg_sink->ctx.ring)) {
1228 ha_alert("server '%s' sets too many watchers > 255 on ring '%s'.\n", srv->id, cfg_sink->name);
1229 err_code |= ERR_ALERT | ERR_FATAL;
Aurelien DARRAGON727e3962023-07-10 16:26:08 +02001230 ha_free(&sft);
1231 break;
Emeric Brun494c5052020-05-28 11:13:15 +02001232 }
1233 cfg_sink->sft = sft;
1234 srv = srv->next;
1235 }
Aurelien DARRAGON727e3962023-07-10 16:26:08 +02001236 if (sink_init_forward(cfg_sink) == 0) {
1237 ha_alert("error when trying to initialize sink buffer forwarding.\n");
1238 err_code |= ERR_ALERT | ERR_FATAL;
1239 }
Emeric Brun494c5052020-05-28 11:13:15 +02001240 }
1241 }
Emeric Brun99c453d2020-05-25 15:01:04 +02001242 cfg_sink = NULL;
1243
1244 return err_code;
1245}
1246
1247/* resolve sink names at end of config. Returns 0 on success otherwise error
1248 * flags.
1249*/
1250int post_sink_resolve()
1251{
Christopher Fauletfc633b62020-11-06 15:24:23 +01001252 int err_code = ERR_NONE;
Emeric Brun99c453d2020-05-25 15:01:04 +02001253 struct logsrv *logsrv, *logb;
1254 struct sink *sink;
1255 struct proxy *px;
1256
1257 list_for_each_entry_safe(logsrv, logb, &global.logsrvs, list) {
1258 if (logsrv->type == LOG_TARGET_BUFFER) {
1259 sink = sink_find(logsrv->ring_name);
Emeric Brun94aab062021-04-02 10:41:36 +02001260 if (!sink) {
1261 /* LOG_TARGET_BUFFER but !AF_UNSPEC
1262 * means we must allocate a sink
1263 * buffer to send messages to this logsrv
1264 */
1265 if (logsrv->addr.ss_family != AF_UNSPEC) {
1266 sink = sink_new_from_logsrv(logsrv);
1267 if (!sink) {
1268 ha_alert("global stream log server declared in file '%s' at line %d cannot be initialized'.\n",
1269 logsrv->conf.file, logsrv->conf.line);
1270 err_code |= ERR_ALERT | ERR_FATAL;
1271 }
1272 }
1273 else {
1274 ha_alert("global log server declared in file '%s' at line %d uses unknown ring named '%s'.\n",
1275 logsrv->conf.file, logsrv->conf.line, logsrv->ring_name);
1276 err_code |= ERR_ALERT | ERR_FATAL;
1277 }
1278 }
1279 else if (sink->type != SINK_TYPE_BUFFER) {
1280 ha_alert("global log server declared in file '%s' at line %d uses incompatible ring '%s'.\n",
1281 logsrv->conf.file, logsrv->conf.line, logsrv->ring_name);
Emeric Brun99c453d2020-05-25 15:01:04 +02001282 err_code |= ERR_ALERT | ERR_FATAL;
1283 }
1284 logsrv->sink = sink;
1285 }
Emeric Brun94aab062021-04-02 10:41:36 +02001286
Emeric Brun99c453d2020-05-25 15:01:04 +02001287 }
1288
1289 for (px = proxies_list; px; px = px->next) {
1290 list_for_each_entry_safe(logsrv, logb, &px->logsrvs, list) {
1291 if (logsrv->type == LOG_TARGET_BUFFER) {
1292 sink = sink_find(logsrv->ring_name);
Emeric Brun94aab062021-04-02 10:41:36 +02001293 if (!sink) {
1294 /* LOG_TARGET_BUFFER but !AF_UNSPEC
1295 * means we must allocate a sink
1296 * buffer to send messages to this logsrv
1297 */
1298 if (logsrv->addr.ss_family != AF_UNSPEC) {
1299 sink = sink_new_from_logsrv(logsrv);
1300 if (!sink) {
1301 ha_alert("log server declared in proxy section '%s' file '%s' at line %d cannot be initialized'.\n",
1302 px->id, logsrv->conf.file, logsrv->conf.line);
1303 err_code |= ERR_ALERT | ERR_FATAL;
1304 }
1305 }
1306 else {
1307 ha_alert("log server declared in proxy section '%s' in file '%s' at line %d uses unknown ring named '%s'.\n",
1308 px->id, logsrv->conf.file, logsrv->conf.line, logsrv->ring_name);
1309 err_code |= ERR_ALERT | ERR_FATAL;
1310 }
1311 }
1312 else if (sink->type != SINK_TYPE_BUFFER) {
1313 ha_alert("log server declared in proxy section '%s' in file '%s' at line %d uses incomatible ring named '%s'.\n",
1314 px->id, logsrv->conf.file, logsrv->conf.line, logsrv->ring_name);
Emeric Brun99c453d2020-05-25 15:01:04 +02001315 err_code |= ERR_ALERT | ERR_FATAL;
1316 }
1317 logsrv->sink = sink;
1318 }
1319 }
1320 }
Emeric Brun12941c82020-07-07 14:19:42 +02001321
1322 for (px = cfg_log_forward; px; px = px->next) {
1323 list_for_each_entry_safe(logsrv, logb, &px->logsrvs, list) {
1324 if (logsrv->type == LOG_TARGET_BUFFER) {
1325 sink = sink_find(logsrv->ring_name);
Emeric Brun94aab062021-04-02 10:41:36 +02001326 if (!sink) {
1327 /* LOG_TARGET_BUFFER but !AF_UNSPEC
1328 * means we must allocate a sink
1329 * buffer to send messages to this logsrv
1330 */
1331 if (logsrv->addr.ss_family != AF_UNSPEC) {
1332 sink = sink_new_from_logsrv(logsrv);
1333 if (!sink) {
1334 ha_alert("log server declared in log-forward section '%s' file '%s' at line %d cannot be initialized'.\n",
1335 px->id, logsrv->conf.file, logsrv->conf.line);
1336 err_code |= ERR_ALERT | ERR_FATAL;
1337 }
1338 }
1339 else {
1340 ha_alert("log server declared in log-forward section '%s' in file '%s' at line %d uses unknown ring named '%s'.\n",
1341 px->id, logsrv->conf.file, logsrv->conf.line, logsrv->ring_name);
1342 err_code |= ERR_ALERT | ERR_FATAL;
1343 }
1344 }
1345 else if (sink->type != SINK_TYPE_BUFFER) {
1346 ha_alert("log server declared in log-forward section '%s' in file '%s' at line %d uses unknown ring named '%s'.\n",
1347 px->id, logsrv->conf.file, logsrv->conf.line, logsrv->ring_name);
Emeric Brun12941c82020-07-07 14:19:42 +02001348 err_code |= ERR_ALERT | ERR_FATAL;
1349 }
1350 logsrv->sink = sink;
1351 }
1352 }
1353 }
Emeric Brun99c453d2020-05-25 15:01:04 +02001354 return err_code;
1355}
1356
1357
Willy Tarreau973e6622019-08-20 11:57:52 +02001358static void sink_init()
1359{
Emeric Brun54648852020-07-06 15:54:06 +02001360 sink_new_fd("stdout", "standard output (fd#1)", LOG_FORMAT_RAW, 1);
1361 sink_new_fd("stderr", "standard output (fd#2)", LOG_FORMAT_RAW, 2);
1362 sink_new_buf("buf0", "in-memory ring buffer", LOG_FORMAT_TIMED, 1048576);
Willy Tarreau4ed23ca2019-08-23 15:47:49 +02001363}
1364
1365static void sink_deinit()
1366{
1367 struct sink *sink, *sb;
Aurelien DARRAGON6a366ea2023-07-10 15:17:12 +02001368 struct sink_forward_target *sft_next;
Willy Tarreau4ed23ca2019-08-23 15:47:49 +02001369
1370 list_for_each_entry_safe(sink, sb, &sink_list, sink_list) {
Willy Tarreau0b8e9ce2022-08-11 16:38:20 +02001371 if (sink->type == SINK_TYPE_BUFFER) {
Willy Tarreaufb9a4762023-01-24 12:11:41 +01001372 if (sink->store) {
1373 size_t size = (sink->ctx.ring->buf.size + 4095UL) & -4096UL;
1374 void *area = (sink->ctx.ring->buf.area - sizeof(*sink->ctx.ring));
1375
1376 msync(area, size, MS_SYNC);
1377 munmap(area, size);
Willy Tarreaub9191092023-01-26 15:34:31 +01001378 ha_free(&sink->store);
Willy Tarreaufb9a4762023-01-24 12:11:41 +01001379 }
Willy Tarreau0b8e9ce2022-08-11 16:38:20 +02001380 else
1381 ring_free(sink->ctx.ring);
1382 }
Willy Tarreau2b718102021-04-21 07:32:39 +02001383 LIST_DELETE(&sink->sink_list);
Willy Tarreau09727ee2023-01-26 15:46:08 +01001384 task_destroy(sink->forward_task);
Aurelien DARRAGON9b1d15f2023-03-09 12:07:09 +01001385 free_proxy(sink->forward_px);
Emeric Brun99c453d2020-05-25 15:01:04 +02001386 free(sink->name);
1387 free(sink->desc);
Aurelien DARRAGON6a366ea2023-07-10 15:17:12 +02001388 while (sink->sft) {
1389 sft_next = sink->sft->next;
1390 free(sink->sft);
1391 sink->sft = sft_next;
1392 }
Willy Tarreau4ed23ca2019-08-23 15:47:49 +02001393 free(sink);
1394 }
Willy Tarreau973e6622019-08-20 11:57:52 +02001395}
1396
1397INITCALL0(STG_REGISTER, sink_init);
Willy Tarreau4ed23ca2019-08-23 15:47:49 +02001398REGISTER_POST_DEINIT(sink_deinit);
Willy Tarreau973e6622019-08-20 11:57:52 +02001399
Willy Tarreau9f830d72019-08-26 18:17:04 +02001400static struct cli_kw_list cli_kws = {{ },{
Willy Tarreaub205bfd2021-05-07 11:38:37 +02001401 { { "show", "events", NULL }, "show events [<sink>] [-w] [-n] : show event sink state", cli_parse_show_events, NULL, NULL },
Willy Tarreau9f830d72019-08-26 18:17:04 +02001402 {{},}
1403}};
1404
1405INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
1406
Emeric Brun99c453d2020-05-25 15:01:04 +02001407/* config parsers for this section */
1408REGISTER_CONFIG_SECTION("ring", cfg_parse_ring, cfg_post_parse_ring);
1409REGISTER_POST_CHECK(post_sink_resolve);
1410
Willy Tarreau67b5a162019-08-11 16:38:56 +02001411/*
1412 * Local variables:
1413 * c-indent-level: 8
1414 * c-basic-offset: 8
1415 * End:
1416 */