From: Pierce Lopez Date: Sun, 26 Jul 2020 01:17:21 +0000 (-0400) Subject: windows socketpair tmpfile: use random prefix X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=65199178c6ee124a695a14983879921cb073c2df;p=libevent windows socketpair tmpfile: use random prefix fixes #1058 GetTempFileNameA() takes an optional prefix, and a "unique" long value which can optionally be zero, which causes it to automatically increment until a not-yet-existing filename is found. When libevent creates many AF_UNIX socketpairs on windows, it slows down dramatically, due to always using the same blank prefix, and GetTempFileNameA() needing to iterate through all the existing socketpair filenames. With a present and varying prefix, it will have much less need to iterate. It was also possible for a race with other processes also using blank-prefix tmpfile names to result in both trying to start using the same name at the same time (because libevent deletes the file and then re-creates it as a unix socket), which should now be much less likely. Unfortuantely, "much" is just a factor of 32k, because the prefix is only 3 characters, and windows filesystems are case-insensitive, so doing better would require more sophisticated windows API usage and charset trickyness. --- diff --git a/evutil.c b/evutil.c index 93093b0e..a9207188 100644 --- a/evutil.c +++ b/evutil.c @@ -212,11 +212,21 @@ create_tmpfile(char tmpfile[MAX_PATH]) { char short_path[MAX_PATH] = {0}; char long_path[MAX_PATH] = {0}; - char *tmp_file = tmpfile; + char prefix[4] = {0}; + // GetTempFileNameA() uses up to the first three characters of the prefix + // and windows filesystems are case-insensitive + const char *base32set = "abcdefghijklmnopqrstuvwxyz012345"; + ev_uint16_t rnd; + + evutil_secure_rng_get_bytes(&rnd, sizeof(rnd)); + prefix[0] = base32set[(rnd ) & 31]; + prefix[1] = base32set[(rnd >> 5) & 31]; + prefix[2] = base32set[(rnd >> 10) & 31]; + prefix[3] = '\0'; GetTempPathA(MAX_PATH, short_path); GetLongPathNameA(short_path, long_path, MAX_PATH); - if (!GetTempFileNameA(long_path, NULL, 0, tmp_file)) { + if (!GetTempFileNameA(long_path, prefix, 0, tmpfile)) { event_warnx("GetTempFileName failed: %d", EVUTIL_SOCKET_ERROR()); return -1; }