Willy Tarreau | 81f38d6 | 2015-04-13 17:11:11 +0200 | [diff] [blame] | 1 | /* |
| 2 | * Functions managing applets |
| 3 | * |
| 4 | * Copyright 2000-2015 Willy Tarreau <w@1wt.eu> |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU General Public License |
| 8 | * as published by the Free Software Foundation; either version |
| 9 | * 2 of the License, or (at your option) any later version. |
| 10 | * |
| 11 | */ |
| 12 | |
| 13 | #include <stdio.h> |
| 14 | #include <stdlib.h> |
| 15 | |
Willy Tarreau | 4c7e4b7 | 2020-05-27 12:58:42 +0200 | [diff] [blame] | 16 | #include <haproxy/api.h> |
Willy Tarreau | b255105 | 2020-06-09 09:07:15 +0200 | [diff] [blame] | 17 | #include <haproxy/applet.h> |
Willy Tarreau | f1d32c4 | 2020-06-04 21:07:02 +0200 | [diff] [blame] | 18 | #include <haproxy/channel.h> |
Willy Tarreau | 853b297 | 2020-05-27 18:01:47 +0200 | [diff] [blame] | 19 | #include <haproxy/list.h> |
Willy Tarreau | 5edca2f | 2022-05-27 09:25:10 +0200 | [diff] [blame] | 20 | #include <haproxy/sc_strm.h> |
Willy Tarreau | cb086c6 | 2022-05-27 09:47:12 +0200 | [diff] [blame] | 21 | #include <haproxy/stconn.h> |
Willy Tarreau | dfd3de8 | 2020-06-04 23:46:14 +0200 | [diff] [blame] | 22 | #include <haproxy/stream.h> |
Willy Tarreau | cea0e1b | 2020-06-04 17:25:40 +0200 | [diff] [blame] | 23 | #include <haproxy/task.h> |
Willy Tarreau | 81f38d6 | 2015-04-13 17:11:11 +0200 | [diff] [blame] | 24 | |
Christopher Faulet | 1cbe74c | 2016-12-06 09:13:22 +0100 | [diff] [blame] | 25 | unsigned int nb_applets = 0; |
Emeric Brun | 1138fd0 | 2017-06-19 12:38:55 +0200 | [diff] [blame] | 26 | |
Willy Tarreau | 8280ea9 | 2019-07-18 10:41:36 +0200 | [diff] [blame] | 27 | DECLARE_POOL(pool_head_appctx, "appctx", sizeof(struct appctx)); |
| 28 | |
Willy Tarreau | 009e42b | 2022-05-05 19:55:03 +0200 | [diff] [blame] | 29 | /* Tries to allocate a new appctx and initialize all of its fields. The appctx |
Christopher Faulet | cb2fa36 | 2022-03-23 11:46:56 +0100 | [diff] [blame] | 30 | * is returned on success, NULL on failure. The appctx must be released using |
Willy Tarreau | cb85427 | 2022-06-15 16:35:51 +0200 | [diff] [blame] | 31 | * appctx_free(). <applet> is assigned as the applet, but it can be NULL. <thr> |
| 32 | * is the thread ID to start the applet on, and a negative value allows the |
| 33 | * applet to start anywhere. Backend applets may only be created on the current |
| 34 | * thread. |
Christopher Faulet | cb2fa36 | 2022-03-23 11:46:56 +0100 | [diff] [blame] | 35 | */ |
Willy Tarreau | cb85427 | 2022-06-15 16:35:51 +0200 | [diff] [blame] | 36 | struct appctx *appctx_new_on(struct applet *applet, struct sedesc *sedesc, int thr) |
Christopher Faulet | cb2fa36 | 2022-03-23 11:46:56 +0100 | [diff] [blame] | 37 | { |
| 38 | struct appctx *appctx; |
| 39 | |
Christopher Faulet | d9c1d33 | 2022-05-16 17:15:31 +0200 | [diff] [blame] | 40 | /* Backend appctx cannot be started on another thread than the local one */ |
Willy Tarreau | cb85427 | 2022-06-15 16:35:51 +0200 | [diff] [blame] | 41 | BUG_ON(thr != tid && sedesc); |
Christopher Faulet | 6095d57 | 2022-05-16 17:09:48 +0200 | [diff] [blame] | 42 | |
Willy Tarreau | 009e42b | 2022-05-05 19:55:03 +0200 | [diff] [blame] | 43 | appctx = pool_zalloc(pool_head_appctx); |
Christopher Faulet | 9ec2f4d | 2022-03-23 15:15:29 +0100 | [diff] [blame] | 44 | if (unlikely(!appctx)) |
| 45 | goto fail_appctx; |
| 46 | |
Willy Tarreau | 009e42b | 2022-05-05 19:55:03 +0200 | [diff] [blame] | 47 | LIST_INIT(&appctx->wait_entry); |
Christopher Faulet | 9ec2f4d | 2022-03-23 15:15:29 +0100 | [diff] [blame] | 48 | appctx->obj_type = OBJ_TYPE_APPCTX; |
| 49 | appctx->applet = applet; |
Christopher Faulet | ac57bb5 | 2022-05-09 08:08:26 +0200 | [diff] [blame] | 50 | appctx->sess = NULL; |
Aurelien DARRAGON | 821581c | 2023-03-24 10:01:19 +0100 | [diff] [blame] | 51 | |
| 52 | appctx->t = task_new_on(thr); |
| 53 | if (unlikely(!appctx->t)) |
| 54 | goto fail_task; |
| 55 | |
Willy Tarreau | d869e13 | 2022-05-17 18:05:31 +0200 | [diff] [blame] | 56 | if (!sedesc) { |
| 57 | sedesc = sedesc_new(); |
Aurelien DARRAGON | 821581c | 2023-03-24 10:01:19 +0100 | [diff] [blame] | 58 | if (unlikely(!sedesc)) |
Christopher Faulet | 9ec2f4d | 2022-03-23 15:15:29 +0100 | [diff] [blame] | 59 | goto fail_endp; |
Willy Tarreau | d869e13 | 2022-05-17 18:05:31 +0200 | [diff] [blame] | 60 | sedesc->se = appctx; |
| 61 | se_fl_set(sedesc, SE_FL_T_APPLET | SE_FL_ORPHAN); |
Christopher Faulet | cb2fa36 | 2022-03-23 11:46:56 +0100 | [diff] [blame] | 62 | } |
Christopher Faulet | 9ec2f4d | 2022-03-23 15:15:29 +0100 | [diff] [blame] | 63 | |
Willy Tarreau | 465a6c8 | 2023-03-21 10:50:51 +0100 | [diff] [blame] | 64 | appctx->sedesc = sedesc; |
Christopher Faulet | 9ec2f4d | 2022-03-23 15:15:29 +0100 | [diff] [blame] | 65 | appctx->t->process = task_run_applet; |
| 66 | appctx->t->context = appctx; |
| 67 | |
| 68 | LIST_INIT(&appctx->buffer_wait.list); |
| 69 | appctx->buffer_wait.target = appctx; |
| 70 | appctx->buffer_wait.wakeup_cb = appctx_buf_available; |
| 71 | |
| 72 | _HA_ATOMIC_INC(&nb_applets); |
Christopher Faulet | cb2fa36 | 2022-03-23 11:46:56 +0100 | [diff] [blame] | 73 | return appctx; |
Christopher Faulet | 9ec2f4d | 2022-03-23 15:15:29 +0100 | [diff] [blame] | 74 | |
Christopher Faulet | 9ec2f4d | 2022-03-23 15:15:29 +0100 | [diff] [blame] | 75 | fail_endp: |
Aurelien DARRAGON | 821581c | 2023-03-24 10:01:19 +0100 | [diff] [blame] | 76 | task_destroy(appctx->t); |
| 77 | fail_task: |
Christopher Faulet | 9ec2f4d | 2022-03-23 15:15:29 +0100 | [diff] [blame] | 78 | pool_free(pool_head_appctx, appctx); |
| 79 | fail_appctx: |
| 80 | return NULL; |
Christopher Faulet | cb2fa36 | 2022-03-23 11:46:56 +0100 | [diff] [blame] | 81 | } |
| 82 | |
Christopher Faulet | 8718c95 | 2022-05-12 15:15:53 +0200 | [diff] [blame] | 83 | /* Finalize the frontend appctx startup. It must not be called for a backend |
| 84 | * appctx. This function is responsible to create the appctx's session and the |
Willy Tarreau | 4596fe2 | 2022-05-17 19:07:51 +0200 | [diff] [blame] | 85 | * frontend stream connector. By transitivity, the stream is also created. |
Christopher Faulet | 8718c95 | 2022-05-12 15:15:53 +0200 | [diff] [blame] | 86 | * |
| 87 | * It returns 0 on success and -1 on error. In this case, it is the caller |
| 88 | * responsibility to release the appctx. However, the session is released if it |
| 89 | * was created. On success, if an error is encountered in the caller function, |
Christopher Faulet | d0c4ec0 | 2022-05-12 15:18:48 +0200 | [diff] [blame] | 90 | * the stream must be released instead of the appctx. To be sure, |
| 91 | * appctx_free_on_early_error() must be called in this case. |
Christopher Faulet | 8718c95 | 2022-05-12 15:15:53 +0200 | [diff] [blame] | 92 | */ |
| 93 | int appctx_finalize_startup(struct appctx *appctx, struct proxy *px, struct buffer *input) |
| 94 | { |
| 95 | struct session *sess; |
| 96 | |
Christopher Faulet | d9c1d33 | 2022-05-16 17:15:31 +0200 | [diff] [blame] | 97 | /* async startup is only possible for frontend appctx. Thus for orphan |
| 98 | * appctx. Because no backend appctx can be orphan. |
| 99 | */ |
Willy Tarreau | d869e13 | 2022-05-17 18:05:31 +0200 | [diff] [blame] | 100 | BUG_ON(!se_fl_test(appctx->sedesc, SE_FL_ORPHAN)); |
Christopher Faulet | 8718c95 | 2022-05-12 15:15:53 +0200 | [diff] [blame] | 101 | |
| 102 | sess = session_new(px, NULL, &appctx->obj_type); |
| 103 | if (!sess) |
| 104 | return -1; |
Willy Tarreau | a0b58b5 | 2022-05-27 08:33:53 +0200 | [diff] [blame] | 105 | if (!sc_new_from_endp(appctx->sedesc, sess, input)) { |
Christopher Faulet | 8718c95 | 2022-05-12 15:15:53 +0200 | [diff] [blame] | 106 | session_free(sess); |
| 107 | return -1; |
| 108 | } |
| 109 | appctx->sess = sess; |
| 110 | return 0; |
| 111 | } |
| 112 | |
Christopher Faulet | d0c4ec0 | 2022-05-12 15:18:48 +0200 | [diff] [blame] | 113 | /* Release function to call when an error occurred during init stage of a |
| 114 | * frontend appctx. For a backend appctx, it just calls appctx_free() |
| 115 | */ |
| 116 | void appctx_free_on_early_error(struct appctx *appctx) |
| 117 | { |
Willy Tarreau | 4596fe2 | 2022-05-17 19:07:51 +0200 | [diff] [blame] | 118 | /* If a frontend appctx is attached to a stream connector, release the stream |
Christopher Faulet | d0c4ec0 | 2022-05-12 15:18:48 +0200 | [diff] [blame] | 119 | * instead of the appctx. |
| 120 | */ |
Willy Tarreau | c12b321 | 2022-05-27 11:08:15 +0200 | [diff] [blame] | 121 | if (!se_fl_test(appctx->sedesc, SE_FL_ORPHAN) && !(appctx_sc(appctx)->flags & SC_FL_ISBACK)) { |
Christopher Faulet | d0c4ec0 | 2022-05-12 15:18:48 +0200 | [diff] [blame] | 122 | stream_free(appctx_strm(appctx)); |
| 123 | return; |
| 124 | } |
| 125 | appctx_free(appctx); |
| 126 | } |
| 127 | |
Willy Tarreau | f12f32a | 2022-05-02 14:57:03 +0200 | [diff] [blame] | 128 | /* reserves a command context of at least <size> bytes in the <appctx>, for |
| 129 | * use by a CLI command or any regular applet. The pointer to this context is |
| 130 | * stored in ctx.svcctx and is returned. The caller doesn't need to release |
| 131 | * it as it's allocated from reserved space. If the size is larger than |
| 132 | * APPLET_MAX_SVCCTX a crash will occur (hence that will never happen outside |
| 133 | * of development). |
| 134 | * |
| 135 | * Note that the command does *not* initialize the area, so that it can easily |
| 136 | * be used upon each entry in a function. It's left to the initialization code |
| 137 | * to do it if needed. The CLI will always zero the whole area before calling |
| 138 | * a keyword's ->parse() function. |
| 139 | */ |
| 140 | void *applet_reserve_svcctx(struct appctx *appctx, size_t size) |
| 141 | { |
| 142 | BUG_ON(size > APPLET_MAX_SVCCTX); |
| 143 | appctx->svcctx = &appctx->svc.storage; |
| 144 | return appctx->svcctx; |
| 145 | } |
| 146 | |
Willy Tarreau | 1cc08a3 | 2022-08-18 18:13:34 +0200 | [diff] [blame] | 147 | /* This is used to reset an svcctx and the svc.storage without releasing the |
| 148 | * appctx. In fact this is only used by the CLI applet between commands. |
| 149 | */ |
| 150 | void applet_reset_svcctx(struct appctx *appctx) |
| 151 | { |
| 152 | memset(&appctx->svc.storage, 0, APPLET_MAX_SVCCTX); |
| 153 | appctx->svcctx = NULL; |
| 154 | } |
| 155 | |
Willy Tarreau | d869e13 | 2022-05-17 18:05:31 +0200 | [diff] [blame] | 156 | /* call the applet's release() function if any, and marks the sedesc as shut. |
Willy Tarreau | 1c3ead4 | 2022-05-10 19:42:22 +0200 | [diff] [blame] | 157 | * Needs to be called upon close(). |
| 158 | */ |
| 159 | void appctx_shut(struct appctx *appctx) |
| 160 | { |
Willy Tarreau | d869e13 | 2022-05-17 18:05:31 +0200 | [diff] [blame] | 161 | if (se_fl_test(appctx->sedesc, SE_FL_SHR | SE_FL_SHW)) |
Willy Tarreau | 1c3ead4 | 2022-05-10 19:42:22 +0200 | [diff] [blame] | 162 | return; |
| 163 | |
| 164 | if (appctx->applet->release) |
| 165 | appctx->applet->release(appctx); |
| 166 | |
Willy Tarreau | d869e13 | 2022-05-17 18:05:31 +0200 | [diff] [blame] | 167 | se_fl_set(appctx->sedesc, SE_FL_SHRR | SE_FL_SHWN); |
Willy Tarreau | 1c3ead4 | 2022-05-10 19:42:22 +0200 | [diff] [blame] | 168 | } |
| 169 | |
Willy Tarreau | 21028b5 | 2018-11-06 17:32:37 +0100 | [diff] [blame] | 170 | /* Callback used to wake up an applet when a buffer is available. The applet |
| 171 | * <appctx> is woken up if an input buffer was requested for the associated |
Willy Tarreau | 4596fe2 | 2022-05-17 19:07:51 +0200 | [diff] [blame] | 172 | * stream connector. In this case the buffer is immediately allocated and the |
Willy Tarreau | 21028b5 | 2018-11-06 17:32:37 +0100 | [diff] [blame] | 173 | * function returns 1. Otherwise it returns 0. Note that this automatically |
| 174 | * covers multiple wake-up attempts by ensuring that the same buffer will not |
| 175 | * be accounted for multiple times. |
| 176 | */ |
| 177 | int appctx_buf_available(void *arg) |
| 178 | { |
| 179 | struct appctx *appctx = arg; |
Willy Tarreau | c12b321 | 2022-05-27 11:08:15 +0200 | [diff] [blame] | 180 | struct stconn *sc = appctx_sc(appctx); |
Willy Tarreau | 21028b5 | 2018-11-06 17:32:37 +0100 | [diff] [blame] | 181 | |
| 182 | /* allocation requested ? */ |
Willy Tarreau | 07ee044 | 2022-05-27 10:32:34 +0200 | [diff] [blame] | 183 | if (!(sc->flags & SC_FL_NEED_BUFF)) |
Willy Tarreau | 21028b5 | 2018-11-06 17:32:37 +0100 | [diff] [blame] | 184 | return 0; |
| 185 | |
Willy Tarreau | 07ee044 | 2022-05-27 10:32:34 +0200 | [diff] [blame] | 186 | sc_have_buff(sc); |
Willy Tarreau | 8be7cd7 | 2018-11-14 15:12:08 +0100 | [diff] [blame] | 187 | |
| 188 | /* was already allocated another way ? if so, don't take this one */ |
Willy Tarreau | 07ee044 | 2022-05-27 10:32:34 +0200 | [diff] [blame] | 189 | if (c_size(sc_ic(sc)) || sc_ic(sc)->pipe) |
Willy Tarreau | 8be7cd7 | 2018-11-14 15:12:08 +0100 | [diff] [blame] | 190 | return 0; |
| 191 | |
Willy Tarreau | 21028b5 | 2018-11-06 17:32:37 +0100 | [diff] [blame] | 192 | /* allocation possible now ? */ |
Willy Tarreau | 07ee044 | 2022-05-27 10:32:34 +0200 | [diff] [blame] | 193 | if (!b_alloc(&sc_ic(sc)->buf)) { |
| 194 | sc_need_buff(sc); |
Willy Tarreau | 21028b5 | 2018-11-06 17:32:37 +0100 | [diff] [blame] | 195 | return 0; |
Willy Tarreau | 8be7cd7 | 2018-11-14 15:12:08 +0100 | [diff] [blame] | 196 | } |
Willy Tarreau | 21028b5 | 2018-11-06 17:32:37 +0100 | [diff] [blame] | 197 | |
Willy Tarreau | 21028b5 | 2018-11-06 17:32:37 +0100 | [diff] [blame] | 198 | task_wakeup(appctx->t, TASK_WOKEN_RES); |
| 199 | return 1; |
| 200 | } |
| 201 | |
| 202 | /* Default applet handler */ |
Willy Tarreau | 144f84a | 2021-03-02 16:09:26 +0100 | [diff] [blame] | 203 | struct task *task_run_applet(struct task *t, void *context, unsigned int state) |
Willy Tarreau | 3c595ac | 2015-04-19 09:59:31 +0200 | [diff] [blame] | 204 | { |
Olivier Houchard | 673867c | 2018-05-25 16:58:52 +0200 | [diff] [blame] | 205 | struct appctx *app = context; |
Willy Tarreau | 07ee044 | 2022-05-27 10:32:34 +0200 | [diff] [blame] | 206 | struct stconn *sc; |
Willy Tarreau | dcb0e1d | 2019-04-25 19:12:26 +0200 | [diff] [blame] | 207 | unsigned int rate; |
Christopher Faulet | 1eedf9b | 2021-04-27 17:08:10 +0200 | [diff] [blame] | 208 | size_t count; |
Christopher Faulet | b4a4d9a | 2017-11-15 22:14:49 +0100 | [diff] [blame] | 209 | |
Olivier Houchard | 673867c | 2018-05-25 16:58:52 +0200 | [diff] [blame] | 210 | if (app->state & APPLET_WANT_DIE) { |
| 211 | __appctx_free(app); |
| 212 | return NULL; |
Christopher Faulet | 7163056 | 2017-11-14 11:30:47 +0100 | [diff] [blame] | 213 | } |
Emeric Brun | 1138fd0 | 2017-06-19 12:38:55 +0200 | [diff] [blame] | 214 | |
Willy Tarreau | d869e13 | 2022-05-17 18:05:31 +0200 | [diff] [blame] | 215 | if (se_fl_test(app->sedesc, SE_FL_ORPHAN)) { |
Christopher Faulet | d9c1d33 | 2022-05-16 17:15:31 +0200 | [diff] [blame] | 216 | /* Finalize init of orphan appctx. .init callback function must |
| 217 | * be defined and it must finalize appctx startup. |
| 218 | */ |
| 219 | BUG_ON(!app->applet->init); |
| 220 | |
| 221 | if (appctx_init(app) == -1) { |
| 222 | appctx_free_on_early_error(app); |
| 223 | return NULL; |
| 224 | } |
Willy Tarreau | c12b321 | 2022-05-27 11:08:15 +0200 | [diff] [blame] | 225 | BUG_ON(!app->sess || !appctx_sc(app) || !appctx_strm(app)); |
Christopher Faulet | d9c1d33 | 2022-05-16 17:15:31 +0200 | [diff] [blame] | 226 | } |
| 227 | |
Willy Tarreau | c12b321 | 2022-05-27 11:08:15 +0200 | [diff] [blame] | 228 | sc = appctx_sc(app); |
Christopher Faulet | d9c1d33 | 2022-05-16 17:15:31 +0200 | [diff] [blame] | 229 | |
Olivier Houchard | 673867c | 2018-05-25 16:58:52 +0200 | [diff] [blame] | 230 | /* We always pretend the applet can't get and doesn't want to |
| 231 | * put, it's up to it to change this if needed. This ensures |
| 232 | * that one applet which ignores any event will not spin. |
Willy Tarreau | 9994238 | 2015-09-25 17:56:16 +0200 | [diff] [blame] | 233 | */ |
Willy Tarreau | 90e8b45 | 2022-05-25 18:21:43 +0200 | [diff] [blame] | 234 | applet_need_more_data(app); |
Willy Tarreau | 4164eb9 | 2022-05-25 15:42:03 +0200 | [diff] [blame] | 235 | applet_have_no_more_data(app); |
Willy Tarreau | 3c595ac | 2015-04-19 09:59:31 +0200 | [diff] [blame] | 236 | |
Willy Tarreau | 8be7cd7 | 2018-11-14 15:12:08 +0100 | [diff] [blame] | 237 | /* Now we'll try to allocate the input buffer. We wake up the applet in |
| 238 | * all cases. So this is the applet's responsibility to check if this |
| 239 | * buffer was allocated or not. This leaves a chance for applets to do |
| 240 | * some other processing if needed. The applet doesn't have anything to |
| 241 | * do if it needs the buffer, it will be called again upon readiness. |
| 242 | */ |
Willy Tarreau | 07ee044 | 2022-05-27 10:32:34 +0200 | [diff] [blame] | 243 | if (!sc_alloc_ibuf(sc, &app->buffer_wait)) |
Willy Tarreau | 4164eb9 | 2022-05-25 15:42:03 +0200 | [diff] [blame] | 244 | applet_have_more_data(app); |
Willy Tarreau | 8be7cd7 | 2018-11-14 15:12:08 +0100 | [diff] [blame] | 245 | |
Willy Tarreau | 07ee044 | 2022-05-27 10:32:34 +0200 | [diff] [blame] | 246 | count = co_data(sc_oc(sc)); |
Olivier Houchard | 673867c | 2018-05-25 16:58:52 +0200 | [diff] [blame] | 247 | app->applet->fct(app); |
Willy Tarreau | 19920d6 | 2019-10-11 14:15:47 +0200 | [diff] [blame] | 248 | |
Christopher Faulet | 1eedf9b | 2021-04-27 17:08:10 +0200 | [diff] [blame] | 249 | /* now check if the applet has released some room and forgot to |
| 250 | * notify the other side about it. |
| 251 | */ |
Willy Tarreau | 07ee044 | 2022-05-27 10:32:34 +0200 | [diff] [blame] | 252 | if (count != co_data(sc_oc(sc))) { |
Christopher Faulet | d898841 | 2022-12-20 18:10:04 +0100 | [diff] [blame] | 253 | sc_oc(sc)->flags |= CF_WRITE_EVENT | CF_WROTE_DATA; |
Willy Tarreau | 07ee044 | 2022-05-27 10:32:34 +0200 | [diff] [blame] | 254 | sc_have_room(sc_opposite(sc)); |
Christopher Faulet | 1eedf9b | 2021-04-27 17:08:10 +0200 | [diff] [blame] | 255 | } |
| 256 | |
Christopher Faulet | 4c13568 | 2023-02-16 11:09:31 +0100 | [diff] [blame] | 257 | if (sc_ic(sc)->flags & CF_READ_EVENT) |
| 258 | sc_ep_report_read_activity(sc); |
| 259 | |
Christopher Faulet | 59b240c | 2023-02-27 16:38:12 +0100 | [diff] [blame] | 260 | if (channel_is_empty(sc_oc(sc))) |
| 261 | sc_ep_report_send_activity(sc); |
| 262 | else |
| 263 | sc_ep_report_blocked_send(sc); |
| 264 | |
Willy Tarreau | 19920d6 | 2019-10-11 14:15:47 +0200 | [diff] [blame] | 265 | /* measure the call rate and check for anomalies when too high */ |
Willy Tarreau | df3cab1 | 2022-07-19 20:36:15 +0200 | [diff] [blame] | 266 | if (((b_size(sc_ib(sc)) && sc->flags & SC_FL_NEED_BUFF) || // asks for a buffer which is present |
Willy Tarreau | 07ee044 | 2022-05-27 10:32:34 +0200 | [diff] [blame] | 267 | (b_size(sc_ib(sc)) && !b_data(sc_ib(sc)) && sc->flags & SC_FL_NEED_ROOM) || // asks for room in an empty buffer |
| 268 | (b_data(sc_ob(sc)) && sc_is_send_allowed(sc)) || // asks for data already present |
| 269 | (!b_data(sc_ib(sc)) && b_data(sc_ob(sc)) && // didn't return anything ... |
Christopher Faulet | d898841 | 2022-12-20 18:10:04 +0100 | [diff] [blame] | 270 | (sc_oc(sc)->flags & (CF_WRITE_EVENT|CF_SHUTW_NOW)) == CF_SHUTW_NOW))) { // ... and left data pending after a shut |
Willy Tarreau | df3cab1 | 2022-07-19 20:36:15 +0200 | [diff] [blame] | 271 | rate = update_freq_ctr(&app->call_rate, 1); |
| 272 | if (rate >= 100000 && app->call_rate.prev_ctr) // looped like this more than 100k times over last second |
| 273 | stream_dump_and_crash(&app->obj_type, read_freq_ctr(&app->call_rate)); |
Willy Tarreau | 19920d6 | 2019-10-11 14:15:47 +0200 | [diff] [blame] | 274 | } |
| 275 | |
Willy Tarreau | 07ee044 | 2022-05-27 10:32:34 +0200 | [diff] [blame] | 276 | sc->app_ops->wake(sc); |
| 277 | channel_release_buffer(sc_ic(sc), &app->buffer_wait); |
Olivier Houchard | 673867c | 2018-05-25 16:58:52 +0200 | [diff] [blame] | 278 | return t; |
Willy Tarreau | 3c595ac | 2015-04-19 09:59:31 +0200 | [diff] [blame] | 279 | } |