quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

util.c (26086B)


      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
      9  *
     10  * This software is licensed as described in the file COPYING, which
     11  * you should have received as part of this distribution. The terms
     12  * are also available at https://curl.se/docs/copyright.html.
     13  *
     14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15  * copies of the Software, and permit persons to whom the Software is
     16  * furnished to do so, under the terms of the COPYING file.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  * SPDX-License-Identifier: curl
     22  *
     23  ***************************************************************************/
     24 #include "first.h"
     25 
     26 #ifdef HAVE_FCNTL_H
     27 #include <fcntl.h>
     28 #endif
     29 
     30 /* This function returns a pointer to STATIC memory. It converts the given
     31  * binary lump to a hex formatted string usable for output in logs or
     32  * whatever.
     33  */
     34 char *data_to_hex(char *data, size_t len)
     35 {
     36   static char buf[256*3];
     37   size_t i;
     38   char *optr = buf;
     39   char *iptr = data;
     40 
     41   if(len > 255)
     42     len = 255;
     43 
     44   for(i = 0; i < len; i++) {
     45     if((data[i] >= 0x20) && (data[i] < 0x7f))
     46       *optr++ = *iptr++;
     47     else {
     48       snprintf(optr, 4, "%%%02x", (unsigned char)*iptr++);
     49       optr += 3;
     50     }
     51   }
     52   *optr = 0; /* in case no sprintf was used */
     53 
     54   return buf;
     55 }
     56 
     57 void loghex(unsigned char *buffer, ssize_t len)
     58 {
     59   char data[12000];
     60   ssize_t i;
     61   unsigned char *ptr = buffer;
     62   char *optr = data;
     63   ssize_t width = 0;
     64   int left = sizeof(data);
     65 
     66   for(i = 0; i < len && (left >= 0); i++) {
     67     snprintf(optr, left, "%02x", ptr[i]);
     68     width += 2;
     69     optr += 2;
     70     left -= 2;
     71   }
     72   if(width)
     73     logmsg("'%s'", data);
     74 }
     75 
     76 void logmsg(const char *msg, ...)
     77 {
     78   va_list ap;
     79   char buffer[2048 + 1];
     80   FILE *logfp;
     81   struct curltime tv;
     82   time_t sec;
     83   struct tm *now;
     84   char timebuf[50];
     85   static time_t epoch_offset;
     86   static int    known_offset;
     87 
     88   if(!serverlogfile) {
     89     fprintf(stderr, "Serverlogfile not set error\n");
     90     return;
     91   }
     92 
     93   tv = curlx_now();
     94   if(!known_offset) {
     95     epoch_offset = time(NULL) - tv.tv_sec;
     96     known_offset = 1;
     97   }
     98   sec = epoch_offset + tv.tv_sec;
     99   /* !checksrc! disable BANNEDFUNC 1 */
    100   now = localtime(&sec); /* not thread safe but we don't care */
    101 
    102   snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld",
    103            (int)now->tm_hour, (int)now->tm_min, (int)now->tm_sec,
    104            (long)tv.tv_usec);
    105 
    106   va_start(ap, msg);
    107 #ifdef __clang__
    108 #pragma clang diagnostic push
    109 #pragma clang diagnostic ignored "-Wformat-nonliteral"
    110 #endif
    111   vsnprintf(buffer, sizeof(buffer), msg, ap);
    112 #ifdef __clang__
    113 #pragma clang diagnostic pop
    114 #endif
    115   va_end(ap);
    116 
    117   do {
    118     logfp = fopen(serverlogfile, "ab");
    119     /* !checksrc! disable ERRNOVAR 1 */
    120   } while(!logfp && (errno == EINTR));
    121   if(logfp) {
    122     fprintf(logfp, "%s %s\n", timebuf, buffer);
    123     fclose(logfp);
    124   }
    125   else {
    126     int error = errno;
    127     fprintf(stderr, "fopen() failed with error (%d) %s\n",
    128             error, strerror(error));
    129     fprintf(stderr, "Error opening file '%s'\n", serverlogfile);
    130     fprintf(stderr, "Msg not logged: %s %s\n", timebuf, buffer);
    131   }
    132 }
    133 
    134 unsigned char byteval(char *value)
    135 {
    136   unsigned long num = strtoul(value, NULL, 10);
    137   return num & 0xff;
    138 }
    139 
    140 #ifdef _WIN32
    141 /* use instead of perror() on generic Windows */
    142 static void win32_perror(const char *msg)
    143 {
    144   char buf[512];
    145   int err = SOCKERRNO;
    146   curlx_winapi_strerror(err, buf, sizeof(buf));
    147   if(msg)
    148     fprintf(stderr, "%s: ", msg);
    149   fprintf(stderr, "%s\n", buf);
    150 }
    151 
    152 static void win32_cleanup(void)
    153 {
    154 #ifdef USE_WINSOCK
    155   WSACleanup();
    156 #endif  /* USE_WINSOCK */
    157 
    158   /* flush buffers of all streams regardless of their mode */
    159   _flushall();
    160 }
    161 
    162 int win32_init(void)
    163 {
    164   curlx_now_init();
    165 #ifdef USE_WINSOCK
    166   {
    167     WORD wVersionRequested;
    168     WSADATA wsaData;
    169     int err;
    170 
    171     wVersionRequested = MAKEWORD(2, 2);
    172     err = WSAStartup(wVersionRequested, &wsaData);
    173 
    174     if(err) {
    175       win32_perror("Winsock init failed");
    176       logmsg("Error initialising Winsock -- aborting");
    177       return 1;
    178     }
    179 
    180     if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
    181        HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested) ) {
    182       WSACleanup();
    183       win32_perror("Winsock init failed");
    184       logmsg("No suitable winsock.dll found -- aborting");
    185       return 1;
    186     }
    187   }
    188 #endif  /* USE_WINSOCK */
    189   atexit(win32_cleanup);
    190   return 0;
    191 }
    192 
    193 /* socket-safe strerror (works on Winsock errors, too) */
    194 const char *sstrerror(int err)
    195 {
    196   static char buf[512];
    197   return curlx_winapi_strerror(err, buf, sizeof(buf));
    198 }
    199 #else
    200 #define sstrerror(e) strerror(e)
    201 #endif  /* _WIN32 */
    202 
    203 /* fopens the test case file */
    204 FILE *test2fopen(long testno, const char *logdir2)
    205 {
    206   FILE *stream;
    207   char filename[256];
    208   /* first try the alternative, preprocessed, file */
    209   snprintf(filename, sizeof(filename), "%s/test%ld", logdir2, testno);
    210   stream = fopen(filename, "rb");
    211   if(stream)
    212     return stream;
    213 
    214   /* then try the source version */
    215   snprintf(filename, sizeof(filename), "%s/data/test%ld", srcpath, testno);
    216   stream = fopen(filename, "rb");
    217 
    218   return stream;
    219 }
    220 
    221 #ifdef _WIN32
    222 #define t_getpid() GetCurrentProcessId()
    223 #else
    224 #define t_getpid() getpid()
    225 #endif
    226 
    227 curl_off_t our_getpid(void)
    228 {
    229   curl_off_t pid = (curl_off_t)t_getpid();
    230 #ifdef _WIN32
    231   /* store pid + MAX_PID to avoid conflict with Cygwin/msys PIDs, see also:
    232    * - 2019-01-31: https://cygwin.com/git/?p=newlib-cygwin.git;a=commit;
    233    *               h=b5e1003722cb14235c4f166be72c09acdffc62ea
    234    * - 2019-02-02: https://cygwin.com/git/?p=newlib-cygwin.git;a=commit;
    235    *               h=448cf5aa4b429d5a9cebf92a0da4ab4b5b6d23fe
    236    * - 2024-12-19: https://cygwin.com/git/?p=newlib-cygwin.git;a=commit;
    237    *               h=363357c023ce01e936bdaedf0f479292a8fa4e0f
    238    */
    239   pid += 4194304;
    240 #endif
    241   return pid;
    242 }
    243 
    244 int write_pidfile(const char *filename)
    245 {
    246   FILE *pidfile;
    247   curl_off_t pid;
    248 
    249   pid = our_getpid();
    250   pidfile = fopen(filename, "wb");
    251   if(!pidfile) {
    252     logmsg("Couldn't write pid file: %s %s", filename, strerror(errno));
    253     return 0; /* fail */
    254   }
    255   fprintf(pidfile, "%ld\n", (long)pid);
    256   fclose(pidfile);
    257   logmsg("Wrote pid %ld to %s", (long)pid, filename);
    258   return 1; /* success */
    259 }
    260 
    261 /* store the used port number in a file */
    262 int write_portfile(const char *filename, int port)
    263 {
    264   FILE *portfile = fopen(filename, "wb");
    265   if(!portfile) {
    266     logmsg("Couldn't write port file: %s %s", filename, strerror(errno));
    267     return 0; /* fail */
    268   }
    269   fprintf(portfile, "%d\n", port);
    270   fclose(portfile);
    271   logmsg("Wrote port %d to %s", port, filename);
    272   return 1; /* success */
    273 }
    274 
    275 void set_advisor_read_lock(const char *filename)
    276 {
    277   FILE *lockfile;
    278   int error = 0;
    279   int res;
    280 
    281   do {
    282     lockfile = fopen(filename, "wb");
    283     /* !checksrc! disable ERRNOVAR 1 */
    284   } while(!lockfile && ((error = errno) == EINTR));
    285   if(!lockfile) {
    286     logmsg("Error creating lock file %s error (%d) %s",
    287            filename, error, strerror(error));
    288     return;
    289   }
    290 
    291   res = fclose(lockfile);
    292   if(res)
    293     logmsg("Error closing lock file %s error (%d) %s",
    294            filename, errno, strerror(errno));
    295 }
    296 
    297 void clear_advisor_read_lock(const char *filename)
    298 {
    299   int error = 0;
    300   int res;
    301 
    302   /*
    303   ** Log all removal failures. Even those due to file not existing.
    304   ** This allows to detect if unexpectedly the file has already been
    305   ** removed by a process different than the one that should do this.
    306   */
    307 
    308   do {
    309     res = unlink(filename);
    310     /* !checksrc! disable ERRNOVAR 1 */
    311   } while(res && ((error = errno) == EINTR));
    312   if(res)
    313     logmsg("Error removing lock file %s error (%d) %s",
    314            filename, error, strerror(error));
    315 }
    316 
    317 /* vars used to keep around previous signal handlers */
    318 
    319 typedef void (*SIGHANDLER_T)(int);
    320 
    321 #if defined(_MSC_VER) && (_MSC_VER <= 1700)
    322 /* Workaround for warning C4306:
    323    'type cast' : conversion from 'int' to 'void (__cdecl *)(int)' */
    324 #undef SIG_ERR
    325 #define SIG_ERR  ((SIGHANDLER_T)(size_t)-1)
    326 #endif
    327 
    328 #ifdef SIGHUP
    329 static SIGHANDLER_T old_sighup_handler  = SIG_ERR;
    330 #endif
    331 
    332 #ifdef SIGPIPE
    333 static SIGHANDLER_T old_sigpipe_handler = SIG_ERR;
    334 #endif
    335 
    336 #ifdef SIGALRM
    337 static SIGHANDLER_T old_sigalrm_handler = SIG_ERR;
    338 #endif
    339 
    340 #ifdef SIGINT
    341 static SIGHANDLER_T old_sigint_handler  = SIG_ERR;
    342 #endif
    343 
    344 #ifdef SIGTERM
    345 static SIGHANDLER_T old_sigterm_handler = SIG_ERR;
    346 #endif
    347 
    348 #if defined(SIGBREAK) && defined(_WIN32)
    349 static SIGHANDLER_T old_sigbreak_handler = SIG_ERR;
    350 #endif
    351 
    352 #if defined(_WIN32) && !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE)
    353 static unsigned int thread_main_id = 0;
    354 static HANDLE thread_main_window = NULL;
    355 static HWND hidden_main_window = NULL;
    356 #endif
    357 
    358 /* signal handler that will be triggered to indicate that the program
    359  * should finish its execution in a controlled manner as soon as possible.
    360  * The first time this is called it will set got_exit_signal to one and
    361  * store in exit_signal the signal that triggered its execution.
    362  */
    363 #ifndef UNDER_CE
    364 /*
    365  * Only call signal-safe functions from the signal handler, as required by
    366  * the POSIX specification:
    367  *   https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html
    368  * Hence, do not call 'logmsg()', and instead use 'open/write/close' to
    369  * log errors.
    370  */
    371 static void exit_signal_handler(int signum)
    372 {
    373   int old_errno = errno;
    374   if(!serverlogfile) {
    375     static const char msg[] = "exit_signal_handler: serverlogfile not set\n";
    376     (void)!write(STDERR_FILENO, msg, sizeof(msg) - 1);
    377   }
    378   else {
    379 #ifdef _WIN32
    380 #define OPENMODE S_IREAD | S_IWRITE
    381 #else
    382 #define OPENMODE S_IRUSR | S_IWUSR
    383 #endif
    384     int fd = open(serverlogfile, O_WRONLY|O_CREAT|O_APPEND, OPENMODE);
    385     if(fd != -1) {
    386       static const char msg[] = "exit_signal_handler: called\n";
    387       (void)!write(fd, msg, sizeof(msg) - 1);
    388       close(fd);
    389     }
    390     else {
    391       static const char msg[] = "exit_signal_handler: failed opening ";
    392       (void)!write(STDERR_FILENO, msg, sizeof(msg) - 1);
    393       (void)!write(STDERR_FILENO, serverlogfile, strlen(serverlogfile));
    394       (void)!write(STDERR_FILENO, "\n", 1);
    395     }
    396   }
    397   if(got_exit_signal == 0) {
    398     got_exit_signal = 1;
    399     exit_signal = signum;
    400 #ifdef _WIN32
    401     if(exit_event)
    402       (void)SetEvent(exit_event);
    403 #endif
    404   }
    405   (void)signal(signum, exit_signal_handler);
    406   CURL_SETERRNO(old_errno);
    407 }
    408 #endif
    409 
    410 #if defined(_WIN32) && !defined(UNDER_CE)
    411 /* CTRL event handler for Windows Console applications to simulate
    412  * SIGINT, SIGTERM and SIGBREAK on CTRL events and trigger signal handler.
    413  *
    414  * Background information from MSDN:
    415  * SIGINT is not supported for any Win32 application. When a CTRL+C
    416  * interrupt occurs, Win32 operating systems generate a new thread
    417  * to specifically handle that interrupt. This can cause a single-thread
    418  * application, such as one in UNIX, to become multithreaded and cause
    419  * unexpected behavior.
    420  * [...]
    421  * The SIGKILL and SIGTERM signals are not generated under Windows.
    422  * They are included for ANSI compatibility. Therefore, you can set
    423  * signal handlers for these signals by using signal, and you can also
    424  * explicitly generate these signals by calling raise. Source:
    425  * https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/signal
    426  */
    427 static BOOL WINAPI ctrl_event_handler(DWORD dwCtrlType)
    428 {
    429   int signum = 0;
    430   logmsg("ctrl_event_handler: %lu", dwCtrlType);
    431   switch(dwCtrlType) {
    432 #ifdef SIGINT
    433   case CTRL_C_EVENT:
    434     signum = SIGINT;
    435     break;
    436 #endif
    437 #ifdef SIGTERM
    438   case CTRL_CLOSE_EVENT:
    439     signum = SIGTERM;
    440     break;
    441 #endif
    442 #ifdef SIGBREAK
    443   case CTRL_BREAK_EVENT:
    444     signum = SIGBREAK;
    445     break;
    446 #endif
    447   default:
    448     return FALSE;
    449   }
    450   if(signum) {
    451     logmsg("ctrl_event_handler: %lu -> %d", dwCtrlType, signum);
    452     raise(signum);
    453   }
    454   return TRUE;
    455 }
    456 #endif
    457 
    458 #if defined(_WIN32) && !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE)
    459 /* Window message handler for Windows applications to add support
    460  * for graceful process termination via taskkill (without /f) which
    461  * sends WM_CLOSE to all Windows of a process (even hidden ones).
    462  *
    463  * Therefore we create and run a hidden Window in a separate thread
    464  * to receive and handle the WM_CLOSE message as SIGTERM signal.
    465  */
    466 static LRESULT CALLBACK main_window_proc(HWND hwnd, UINT uMsg,
    467                                          WPARAM wParam, LPARAM lParam)
    468 {
    469   int signum = 0;
    470   if(hwnd == hidden_main_window) {
    471     switch(uMsg) {
    472 #ifdef SIGTERM
    473     case WM_CLOSE:
    474       signum = SIGTERM;
    475       break;
    476 #endif
    477     case WM_DESTROY:
    478       PostQuitMessage(0);
    479       break;
    480     }
    481     if(signum) {
    482       logmsg("main_window_proc: %d -> %d", uMsg, signum);
    483       raise(signum);
    484     }
    485   }
    486   return DefWindowProc(hwnd, uMsg, wParam, lParam);
    487 }
    488 /* Window message queue loop for hidden main window, details see above.
    489  */
    490 #include <process.h>
    491 static unsigned int WINAPI main_window_loop(void *lpParameter)
    492 {
    493   WNDCLASS wc;
    494   BOOL ret;
    495   MSG msg;
    496 
    497   ZeroMemory(&wc, sizeof(wc));
    498   wc.lpfnWndProc = (WNDPROC)main_window_proc;
    499   wc.hInstance = (HINSTANCE)lpParameter;
    500   wc.lpszClassName = TEXT("MainWClass");
    501   if(!RegisterClass(&wc)) {
    502     win32_perror("RegisterClass failed");
    503     return (DWORD)-1;
    504   }
    505 
    506   hidden_main_window = CreateWindowEx(0, TEXT("MainWClass"),
    507                                       TEXT("Recv WM_CLOSE msg"),
    508                                       WS_OVERLAPPEDWINDOW,
    509                                       CW_USEDEFAULT, CW_USEDEFAULT,
    510                                       CW_USEDEFAULT, CW_USEDEFAULT,
    511                                       (HWND)NULL, (HMENU)NULL,
    512                                       wc.hInstance, (LPVOID)NULL);
    513   if(!hidden_main_window) {
    514     win32_perror("CreateWindowEx failed");
    515     return (DWORD)-1;
    516   }
    517 
    518   do {
    519     ret = GetMessage(&msg, NULL, 0, 0);
    520     if(ret == -1) {
    521       win32_perror("GetMessage failed");
    522       return (DWORD)-1;
    523     }
    524     else if(ret) {
    525       if(msg.message == WM_APP) {
    526         DestroyWindow(hidden_main_window);
    527       }
    528       else if(msg.hwnd && !TranslateMessage(&msg)) {
    529         DispatchMessage(&msg);
    530       }
    531     }
    532   } while(ret);
    533 
    534   hidden_main_window = NULL;
    535   return (DWORD)msg.wParam;
    536 }
    537 #endif
    538 
    539 #ifndef UNDER_CE
    540 static SIGHANDLER_T set_signal(int signum, SIGHANDLER_T handler,
    541                                bool restartable)
    542 {
    543 #if defined(HAVE_SIGACTION) && defined(SA_RESTART)
    544   struct sigaction sa, oldsa;
    545 
    546   memset(&sa, 0, sizeof(sa));
    547   sa.sa_handler = handler;
    548   sigemptyset(&sa.sa_mask);
    549   sigaddset(&sa.sa_mask, signum);
    550   sa.sa_flags = restartable ? SA_RESTART : 0;
    551 
    552   if(sigaction(signum, &sa, &oldsa))
    553     return SIG_ERR;
    554 
    555   return oldsa.sa_handler;
    556 #else
    557   SIGHANDLER_T oldhdlr = signal(signum, handler);
    558 
    559 #ifdef HAVE_SIGINTERRUPT
    560   if(oldhdlr != SIG_ERR)
    561     siginterrupt(signum, (int) restartable);
    562 #else
    563   (void) restartable;
    564 #endif
    565 
    566   return oldhdlr;
    567 #endif
    568 }
    569 #endif
    570 
    571 void install_signal_handlers(bool keep_sigalrm)
    572 {
    573 #ifdef _WIN32
    574   /* setup Windows exit event before any signal can trigger */
    575   exit_event = CreateEvent(NULL, TRUE, FALSE, NULL);
    576   if(!exit_event)
    577     logmsg("cannot create exit event");
    578 #endif
    579 #ifdef SIGHUP
    580   /* ignore SIGHUP signal */
    581   old_sighup_handler = set_signal(SIGHUP, SIG_IGN, FALSE);
    582   if(old_sighup_handler == SIG_ERR)
    583     logmsg("cannot install SIGHUP handler: %s", strerror(errno));
    584 #endif
    585 #ifdef SIGPIPE
    586   /* ignore SIGPIPE signal */
    587   old_sigpipe_handler = set_signal(SIGPIPE, SIG_IGN, FALSE);
    588   if(old_sigpipe_handler == SIG_ERR)
    589     logmsg("cannot install SIGPIPE handler: %s", strerror(errno));
    590 #endif
    591 #ifdef SIGALRM
    592   if(!keep_sigalrm) {
    593     /* ignore SIGALRM signal */
    594     old_sigalrm_handler = set_signal(SIGALRM, SIG_IGN, FALSE);
    595     if(old_sigalrm_handler == SIG_ERR)
    596       logmsg("cannot install SIGALRM handler: %s", strerror(errno));
    597   }
    598 #else
    599   (void)keep_sigalrm;
    600 #endif
    601 #ifdef SIGINT
    602   /* handle SIGINT signal with our exit_signal_handler */
    603   old_sigint_handler = set_signal(SIGINT, exit_signal_handler, TRUE);
    604   if(old_sigint_handler == SIG_ERR)
    605     logmsg("cannot install SIGINT handler: %s", strerror(errno));
    606 #endif
    607 #ifdef SIGTERM
    608   /* handle SIGTERM signal with our exit_signal_handler */
    609   old_sigterm_handler = set_signal(SIGTERM, exit_signal_handler, TRUE);
    610   if(old_sigterm_handler == SIG_ERR)
    611     logmsg("cannot install SIGTERM handler: %s", strerror(errno));
    612 #endif
    613 #if defined(SIGBREAK) && defined(_WIN32)
    614   /* handle SIGBREAK signal with our exit_signal_handler */
    615   old_sigbreak_handler = set_signal(SIGBREAK, exit_signal_handler, TRUE);
    616   if(old_sigbreak_handler == SIG_ERR)
    617     logmsg("cannot install SIGBREAK handler: %s", strerror(errno));
    618 #endif
    619 #ifdef _WIN32
    620 #ifndef UNDER_CE
    621   if(!SetConsoleCtrlHandler(ctrl_event_handler, TRUE))
    622     logmsg("cannot install CTRL event handler");
    623 #endif
    624 
    625 #if !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE)
    626   {
    627     typedef uintptr_t curl_win_thread_handle_t;
    628     curl_win_thread_handle_t thread;
    629     thread = _beginthreadex(NULL, 0, &main_window_loop,
    630                             (void *)GetModuleHandle(NULL), 0, &thread_main_id);
    631     thread_main_window = (HANDLE)thread;
    632     if(!thread_main_window || !thread_main_id)
    633       logmsg("cannot start main window loop");
    634   }
    635 #endif
    636 #endif
    637 }
    638 
    639 void restore_signal_handlers(bool keep_sigalrm)
    640 {
    641 #ifdef SIGHUP
    642   if(SIG_ERR != old_sighup_handler)
    643     (void) set_signal(SIGHUP, old_sighup_handler, FALSE);
    644 #endif
    645 #ifdef SIGPIPE
    646   if(SIG_ERR != old_sigpipe_handler)
    647     (void) set_signal(SIGPIPE, old_sigpipe_handler, FALSE);
    648 #endif
    649 #ifdef SIGALRM
    650   if(!keep_sigalrm) {
    651     if(SIG_ERR != old_sigalrm_handler)
    652       (void) set_signal(SIGALRM, old_sigalrm_handler, FALSE);
    653   }
    654 #else
    655   (void)keep_sigalrm;
    656 #endif
    657 #ifdef SIGINT
    658   if(SIG_ERR != old_sigint_handler)
    659     (void) set_signal(SIGINT, old_sigint_handler, FALSE);
    660 #endif
    661 #ifdef SIGTERM
    662   if(SIG_ERR != old_sigterm_handler)
    663     (void) set_signal(SIGTERM, old_sigterm_handler, FALSE);
    664 #endif
    665 #if defined(SIGBREAK) && defined(_WIN32)
    666   if(SIG_ERR != old_sigbreak_handler)
    667     (void) set_signal(SIGBREAK, old_sigbreak_handler, FALSE);
    668 #endif
    669 #ifdef _WIN32
    670 #ifndef UNDER_CE
    671   (void)SetConsoleCtrlHandler(ctrl_event_handler, FALSE);
    672 #endif
    673 #if !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE)
    674   if(thread_main_window && thread_main_id) {
    675     if(PostThreadMessage(thread_main_id, WM_APP, 0, 0)) {
    676       if(WaitForSingleObjectEx(thread_main_window, INFINITE, TRUE)) {
    677         if(CloseHandle(thread_main_window)) {
    678           thread_main_window = NULL;
    679           thread_main_id = 0;
    680         }
    681       }
    682     }
    683   }
    684   if(exit_event) {
    685     if(CloseHandle(exit_event)) {
    686       exit_event = NULL;
    687     }
    688   }
    689 #endif
    690 #endif
    691 }
    692 
    693 #ifdef USE_UNIX_SOCKETS
    694 
    695 int bind_unix_socket(curl_socket_t sock, const char *unix_socket,
    696                      struct sockaddr_un *sau)
    697 {
    698   int error;
    699   int rc;
    700   size_t len = strlen(unix_socket);
    701 
    702   memset(sau, 0, sizeof(struct sockaddr_un));
    703   sau->sun_family = AF_UNIX;
    704   if(len >= sizeof(sau->sun_path) - 1) {
    705     logmsg("Too long unix socket domain path (%zd)", len);
    706     return -1;
    707   }
    708   strcpy(sau->sun_path, unix_socket);
    709   rc = bind(sock, (struct sockaddr*)sau, sizeof(struct sockaddr_un));
    710   if(rc && SOCKERRNO == SOCKEADDRINUSE) {
    711     struct_stat statbuf;
    712     /* socket already exists. Perhaps it is stale? */
    713     curl_socket_t unixfd = socket(AF_UNIX, SOCK_STREAM, 0);
    714     if(CURL_SOCKET_BAD == unixfd) {
    715       logmsg("Failed to create socket at %s (%d) %s",
    716              unix_socket, SOCKERRNO, sstrerror(SOCKERRNO));
    717       return -1;
    718     }
    719     /* check whether the server is alive */
    720     rc = connect(unixfd, (struct sockaddr*)sau, sizeof(struct sockaddr_un));
    721     error = SOCKERRNO;
    722     sclose(unixfd);
    723     if(rc && error != SOCKECONNREFUSED) {
    724       logmsg("Failed to connect to %s (%d) %s",
    725              unix_socket, error, sstrerror(error));
    726       return rc;
    727     }
    728     /* socket server is not alive, now check if it was actually a socket. */
    729 #ifdef _WIN32
    730     /* Windows does not have lstat function. */
    731     rc = curlx_win32_stat(unix_socket, &statbuf);
    732 #else
    733     rc = lstat(unix_socket, &statbuf);
    734 #endif
    735     if(rc) {
    736       logmsg("Error binding socket, failed to stat %s (%d) %s",
    737              unix_socket, errno, strerror(errno));
    738       return rc;
    739     }
    740 #ifdef S_IFSOCK
    741     if((statbuf.st_mode & S_IFSOCK) != S_IFSOCK) {
    742       logmsg("Error binding socket, failed to stat %s", unix_socket);
    743       return -1;
    744     }
    745 #endif
    746     /* dead socket, cleanup and retry bind */
    747     rc = unlink(unix_socket);
    748     if(rc) {
    749       logmsg("Error binding socket, failed to unlink %s (%d) %s",
    750              unix_socket, errno, strerror(errno));
    751       return rc;
    752     }
    753     /* stale socket is gone, retry bind */
    754     rc = bind(sock, (struct sockaddr*)sau, sizeof(struct sockaddr_un));
    755   }
    756   return rc;
    757 }
    758 #endif
    759 
    760 /*
    761 ** unsigned long to unsigned short
    762 */
    763 #define CURL_MASK_USHORT  ((unsigned short)~0)
    764 #define CURL_MASK_SSHORT  (CURL_MASK_USHORT >> 1)
    765 
    766 unsigned short util_ultous(unsigned long ulnum)
    767 {
    768 #ifdef __INTEL_COMPILER
    769 #  pragma warning(push)
    770 #  pragma warning(disable:810) /* conversion may lose significant bits */
    771 #endif
    772 
    773   DEBUGASSERT(ulnum <= (unsigned long) CURL_MASK_USHORT);
    774   return (unsigned short)(ulnum & (unsigned long) CURL_MASK_USHORT);
    775 
    776 #ifdef __INTEL_COMPILER
    777 #  pragma warning(pop)
    778 #endif
    779 }
    780 
    781 curl_socket_t sockdaemon(curl_socket_t sock,
    782                          unsigned short *listenport,
    783                          const char *unix_socket,
    784                          bool bind_only)
    785 {
    786   /* passive daemon style */
    787   srvr_sockaddr_union_t listener;
    788   int flag;
    789   int rc;
    790   int totdelay = 0;
    791   int maxretr = 10;
    792   int delay = 20;
    793   int attempt = 0;
    794   int error = 0;
    795 
    796 #ifndef USE_UNIX_SOCKETS
    797   (void)unix_socket;
    798 #endif
    799 
    800   do {
    801     attempt++;
    802     flag = 1;
    803     rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
    804                     (void *)&flag, sizeof(flag));
    805     if(rc) {
    806       error = SOCKERRNO;
    807       logmsg("setsockopt(SO_REUSEADDR) failed with error (%d) %s",
    808              error, sstrerror(error));
    809       if(maxretr) {
    810         rc = curlx_wait_ms(delay);
    811         if(rc) {
    812           /* should not happen */
    813           error = SOCKERRNO;
    814           logmsg("curlx_wait_ms() failed with error (%d) %s",
    815                  error, sstrerror(error));
    816           sclose(sock);
    817           return CURL_SOCKET_BAD;
    818         }
    819         if(got_exit_signal) {
    820           logmsg("signalled to die, exiting...");
    821           sclose(sock);
    822           return CURL_SOCKET_BAD;
    823         }
    824         totdelay += delay;
    825         delay *= 2; /* double the sleep for next attempt */
    826       }
    827     }
    828   } while(rc && maxretr--);
    829 
    830   if(rc) {
    831     logmsg("setsockopt(SO_REUSEADDR) failed %d times in %d ms. Error (%d) %s",
    832            attempt, totdelay, error, strerror(error));
    833     logmsg("Continuing anyway...");
    834   }
    835 
    836   /* When the specified listener port is zero, it is actually a
    837      request to let the system choose a non-zero available port. */
    838 
    839   switch(socket_domain) {
    840     case AF_INET:
    841       memset(&listener.sa4, 0, sizeof(listener.sa4));
    842       listener.sa4.sin_family = AF_INET;
    843       listener.sa4.sin_addr.s_addr = INADDR_ANY;
    844       listener.sa4.sin_port = htons(*listenport);
    845       rc = bind(sock, &listener.sa, sizeof(listener.sa4));
    846       break;
    847 #ifdef USE_IPV6
    848     case AF_INET6:
    849       memset(&listener.sa6, 0, sizeof(listener.sa6));
    850       listener.sa6.sin6_family = AF_INET6;
    851       listener.sa6.sin6_addr = in6addr_any;
    852       listener.sa6.sin6_port = htons(*listenport);
    853       rc = bind(sock, &listener.sa, sizeof(listener.sa6));
    854       break;
    855 #endif /* USE_IPV6 */
    856 #ifdef USE_UNIX_SOCKETS
    857     case AF_UNIX:
    858       rc = bind_unix_socket(sock, unix_socket, &listener.sau);
    859       break;
    860 #endif
    861     default:
    862       rc = 1;
    863   }
    864 
    865   if(rc) {
    866     error = SOCKERRNO;
    867 #ifdef USE_UNIX_SOCKETS
    868     if(socket_domain == AF_UNIX)
    869       logmsg("Error binding socket on path %s (%d) %s",
    870              unix_socket, error, sstrerror(error));
    871     else
    872 #endif
    873       logmsg("Error binding socket on port %hu (%d) %s",
    874              *listenport, error, sstrerror(error));
    875     sclose(sock);
    876     return CURL_SOCKET_BAD;
    877   }
    878 
    879   if(!*listenport
    880 #ifdef USE_UNIX_SOCKETS
    881      && !unix_socket
    882 #endif
    883     ) {
    884     /* The system was supposed to choose a port number, figure out which
    885        port we actually got and update the listener port value with it. */
    886     curl_socklen_t la_size;
    887     srvr_sockaddr_union_t localaddr;
    888 #ifdef USE_IPV6
    889     if(socket_domain == AF_INET6)
    890       la_size = sizeof(localaddr.sa6);
    891     else
    892 #endif
    893       la_size = sizeof(localaddr.sa4);
    894     memset(&localaddr.sa, 0, (size_t)la_size);
    895     if(getsockname(sock, &localaddr.sa, &la_size) < 0) {
    896       error = SOCKERRNO;
    897       logmsg("getsockname() failed with error (%d) %s",
    898              error, sstrerror(error));
    899       sclose(sock);
    900       return CURL_SOCKET_BAD;
    901     }
    902     switch(localaddr.sa.sa_family) {
    903     case AF_INET:
    904       *listenport = ntohs(localaddr.sa4.sin_port);
    905       break;
    906 #ifdef USE_IPV6
    907     case AF_INET6:
    908       *listenport = ntohs(localaddr.sa6.sin6_port);
    909       break;
    910 #endif
    911     default:
    912       break;
    913     }
    914     if(!*listenport) {
    915       /* Real failure, listener port shall not be zero beyond this point. */
    916       logmsg("Apparently getsockname() succeeded, with listener port zero.");
    917       logmsg("A valid reason for this failure is a binary built without");
    918       logmsg("proper network library linkage. This might not be the only");
    919       logmsg("reason, but double check it before anything else.");
    920       sclose(sock);
    921       return CURL_SOCKET_BAD;
    922     }
    923   }
    924 
    925   /* bindonly option forces no listening */
    926   if(bind_only) {
    927     logmsg("instructed to bind port without listening");
    928     return sock;
    929   }
    930 
    931   /* start accepting connections */
    932   rc = listen(sock, 5);
    933   if(rc) {
    934     error = SOCKERRNO;
    935     logmsg("listen(%ld, 5) failed with error (%d) %s",
    936            (long)sock, error, sstrerror(error));
    937     sclose(sock);
    938     return CURL_SOCKET_BAD;
    939   }
    940 
    941   return sock;
    942 }