Skip to content

Commit 434dbf6

Browse files
committed
oauth: Fix postcondition for set_timer on macOS
On macOS, readding an EVFILT_TIMER to a kqueue does not appear to clear out previously queued timer events, so checks for timer expiration do not work correctly during token retrieval. Switching to IPv4-only communication exposes the problem, because libcurl is no longer clearing out other timeouts related to Happy Eyeballs dual-stack handling. Fully remove and re-register the kqueue timer events during each call to set_timer(), to clear out any stale expirations. Author: Jacob Champion <jacob.champion@enterprisedb.com> Discussion: https://postgr.es/m/CAOYmi%2Bn4EDOOUL27_OqYT2-F2rS6S%2B3mK-ppWb2Ec92UEoUbYA%40mail.gmail.com
1 parent 8d9d584 commit 434dbf6

File tree

1 file changed

+35
-13
lines changed

1 file changed

+35
-13
lines changed

src/interfaces/libpq/fe-auth-oauth-curl.c

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,6 +1326,10 @@ register_socket(CURL *curl, curl_socket_t socket, int what, void *ctx,
13261326
* in the set at all times and just disarm it when it's not needed. For kqueue,
13271327
* the timer is removed completely when disabled to prevent stale timeouts from
13281328
* remaining in the queue.
1329+
*
1330+
* To meet Curl requirements for the CURLMOPT_TIMERFUNCTION, implementations of
1331+
* set_timer must handle repeated calls by fully discarding any previous running
1332+
* or expired timer.
13291333
*/
13301334
static bool
13311335
set_timer(struct async_ctx *actx, long timeout)
@@ -1373,26 +1377,44 @@ set_timer(struct async_ctx *actx, long timeout)
13731377
timeout = 1;
13741378
#endif
13751379

1376-
/* Enable/disable the timer itself. */
1377-
EV_SET(&ev, 1, EVFILT_TIMER, timeout < 0 ? EV_DELETE : (EV_ADD | EV_ONESHOT),
1378-
0, timeout, 0);
1380+
/*
1381+
* Always disable the timer, and remove it from the multiplexer, to clear
1382+
* out any already-queued events. (On some BSDs, adding an EVFILT_TIMER to
1383+
* a kqueue that already has one will clear stale events, but not on
1384+
* macOS.)
1385+
*
1386+
* If there was no previous timer set, the kevent calls will result in
1387+
* ENOENT, which is fine.
1388+
*/
1389+
EV_SET(&ev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, 0);
13791390
if (kevent(actx->timerfd, &ev, 1, NULL, 0, NULL) < 0 && errno != ENOENT)
13801391
{
1381-
actx_error(actx, "setting kqueue timer to %ld: %m", timeout);
1392+
actx_error(actx, "deleting kqueue timer: %m", timeout);
13821393
return false;
13831394
}
13841395

1385-
/*
1386-
* Add/remove the timer to/from the mux. (In contrast with epoll, if we
1387-
* allowed the timer to remain registered here after being disabled, the
1388-
* mux queue would retain any previous stale timeout notifications and
1389-
* remain readable.)
1390-
*/
1391-
EV_SET(&ev, actx->timerfd, EVFILT_READ, timeout < 0 ? EV_DELETE : EV_ADD,
1392-
0, 0, 0);
1396+
EV_SET(&ev, actx->timerfd, EVFILT_READ, EV_DELETE, 0, 0, 0);
13931397
if (kevent(actx->mux, &ev, 1, NULL, 0, NULL) < 0 && errno != ENOENT)
13941398
{
1395-
actx_error(actx, "could not update timer on kqueue: %m");
1399+
actx_error(actx, "removing kqueue timer from multiplexer: %m");
1400+
return false;
1401+
}
1402+
1403+
/* If we're not adding a timer, we're done. */
1404+
if (timeout < 0)
1405+
return true;
1406+
1407+
EV_SET(&ev, 1, EVFILT_TIMER, (EV_ADD | EV_ONESHOT), 0, timeout, 0);
1408+
if (kevent(actx->timerfd, &ev, 1, NULL, 0, NULL) < 0)
1409+
{
1410+
actx_error(actx, "setting kqueue timer to %ld: %m", timeout);
1411+
return false;
1412+
}
1413+
1414+
EV_SET(&ev, actx->timerfd, EVFILT_READ, EV_ADD, 0, 0, 0);
1415+
if (kevent(actx->mux, &ev, 1, NULL, 0, NULL) < 0)
1416+
{
1417+
actx_error(actx, "adding kqueue timer to multiplexer: %m");
13961418
return false;
13971419
}
13981420

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy