xref: /third_party/curl/tests/server/util.c (revision 13498266)
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 "server_setup.h"
25
26#include <signal.h>
27#ifdef HAVE_NETINET_IN_H
28#include <netinet/in.h>
29#endif
30#ifdef _XOPEN_SOURCE_EXTENDED
31/* This define is "almost" required to build on HPUX 11 */
32#include <arpa/inet.h>
33#endif
34#ifdef HAVE_NETDB_H
35#include <netdb.h>
36#endif
37#ifdef HAVE_POLL_H
38#include <poll.h>
39#elif defined(HAVE_SYS_POLL_H)
40#include <sys/poll.h>
41#endif
42
43#define ENABLE_CURLX_PRINTF
44/* make the curlx header define all printf() functions to use the curlx_*
45   versions instead */
46#include "curlx.h" /* from the private lib dir */
47#include "getpart.h"
48#include "util.h"
49#include "timeval.h"
50
51#ifdef USE_WINSOCK
52#undef  EINTR
53#define EINTR    4 /* errno.h value */
54#undef  EINVAL
55#define EINVAL  22 /* errno.h value */
56#endif
57
58static struct timeval tvnow(void);
59
60/* This function returns a pointer to STATIC memory. It converts the given
61 * binary lump to a hex formatted string usable for output in logs or
62 * whatever.
63 */
64char *data_to_hex(char *data, size_t len)
65{
66  static char buf[256*3];
67  size_t i;
68  char *optr = buf;
69  char *iptr = data;
70
71  if(len > 255)
72    len = 255;
73
74  for(i = 0; i < len; i++) {
75    if((data[i] >= 0x20) && (data[i] < 0x7f))
76      *optr++ = *iptr++;
77    else {
78      msnprintf(optr, 4, "%%%02x", *iptr++);
79      optr += 3;
80    }
81  }
82  *optr = 0; /* in case no sprintf was used */
83
84  return buf;
85}
86
87void logmsg(const char *msg, ...)
88{
89  va_list ap;
90  char buffer[2048 + 1];
91  FILE *logfp;
92  struct timeval tv;
93  time_t sec;
94  struct tm *now;
95  char timebuf[20];
96  static time_t epoch_offset;
97  static int    known_offset;
98
99  if(!serverlogfile) {
100    fprintf(stderr, "Error: serverlogfile not set\n");
101    return;
102  }
103
104  tv = tvnow();
105  if(!known_offset) {
106    epoch_offset = time(NULL) - tv.tv_sec;
107    known_offset = 1;
108  }
109  sec = epoch_offset + tv.tv_sec;
110  /* !checksrc! disable BANNEDFUNC 1 */
111  now = localtime(&sec); /* not thread safe but we don't care */
112
113  msnprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld",
114            (int)now->tm_hour, (int)now->tm_min, (int)now->tm_sec,
115            (long)tv.tv_usec);
116
117  va_start(ap, msg);
118  mvsnprintf(buffer, sizeof(buffer), msg, ap);
119  va_end(ap);
120
121  logfp = fopen(serverlogfile, "ab");
122  if(logfp) {
123    fprintf(logfp, "%s %s\n", timebuf, buffer);
124    fclose(logfp);
125  }
126  else {
127    int error = errno;
128    fprintf(stderr, "fopen() failed with error: %d %s\n",
129            error, strerror(error));
130    fprintf(stderr, "Error opening file: %s\n", serverlogfile);
131    fprintf(stderr, "Msg not logged: %s %s\n", timebuf, buffer);
132  }
133}
134
135#ifdef _WIN32
136/* use instead of strerror() on generic Windows */
137static const char *win32_strerror(int err, char *buf, size_t buflen)
138{
139  if(!FormatMessageA((FORMAT_MESSAGE_FROM_SYSTEM |
140                      FORMAT_MESSAGE_IGNORE_INSERTS), NULL, (DWORD)err,
141                     LANG_NEUTRAL, buf, (DWORD)buflen, NULL))
142    msnprintf(buf, buflen, "Unknown error %d (%#x)", err, err);
143  return buf;
144}
145
146/* use instead of perror() on generic windows */
147void win32_perror(const char *msg)
148{
149  char buf[512];
150  DWORD err = SOCKERRNO;
151  win32_strerror(err, buf, sizeof(buf));
152  if(msg)
153    fprintf(stderr, "%s: ", msg);
154  fprintf(stderr, "%s\n", buf);
155}
156
157void win32_init(void)
158{
159#ifdef USE_WINSOCK
160  WORD wVersionRequested;
161  WSADATA wsaData;
162  int err;
163
164  wVersionRequested = MAKEWORD(2, 2);
165  err = WSAStartup(wVersionRequested, &wsaData);
166
167  if(err) {
168    perror("Winsock init failed");
169    logmsg("Error initialising winsock -- aborting");
170    exit(1);
171  }
172
173  if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
174     HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested) ) {
175    WSACleanup();
176    perror("Winsock init failed");
177    logmsg("No suitable winsock.dll found -- aborting");
178    exit(1);
179  }
180#endif  /* USE_WINSOCK */
181}
182
183void win32_cleanup(void)
184{
185#ifdef USE_WINSOCK
186  WSACleanup();
187#endif  /* USE_WINSOCK */
188
189  /* flush buffers of all streams regardless of their mode */
190  _flushall();
191}
192
193/* socket-safe strerror (works on WinSock errors, too */
194const char *sstrerror(int err)
195{
196  static char buf[512];
197  return win32_strerror(err, buf, sizeof(buf));
198}
199#endif  /* _WIN32 */
200
201/* set by the main code to point to where the test dir is */
202const char *path = ".";
203
204FILE *test2fopen(long testno, const char *logdir)
205{
206  FILE *stream;
207  char filename[256];
208  /* first try the alternative, preprocessed, file */
209  msnprintf(filename, sizeof(filename), ALTTEST_DATA_PATH, logdir, testno);
210  stream = fopen(filename, "rb");
211  if(stream)
212    return stream;
213
214  /* then try the source version */
215  msnprintf(filename, sizeof(filename), TEST_DATA_PATH, path, testno);
216  stream = fopen(filename, "rb");
217
218  return stream;
219}
220
221/*
222 * Portable function used for waiting a specific amount of ms.
223 * Waiting indefinitely with this function is not allowed, a
224 * zero or negative timeout value will return immediately.
225 *
226 * Return values:
227 *   -1 = system call error, or invalid timeout value
228 *    0 = specified timeout has elapsed
229 */
230int wait_ms(int timeout_ms)
231{
232#if !defined(MSDOS) && !defined(USE_WINSOCK)
233#ifndef HAVE_POLL_FINE
234  struct timeval pending_tv;
235#endif
236  struct timeval initial_tv;
237  int pending_ms;
238#endif
239  int r = 0;
240
241  if(!timeout_ms)
242    return 0;
243  if(timeout_ms < 0) {
244    errno = EINVAL;
245    return -1;
246  }
247#if defined(MSDOS)
248  delay(timeout_ms);
249#elif defined(USE_WINSOCK)
250  Sleep((DWORD)timeout_ms);
251#else
252  pending_ms = timeout_ms;
253  initial_tv = tvnow();
254  do {
255    int error;
256#if defined(HAVE_POLL_FINE)
257    r = poll(NULL, 0, pending_ms);
258#else
259    pending_tv.tv_sec = pending_ms / 1000;
260    pending_tv.tv_usec = (pending_ms % 1000) * 1000;
261    r = select(0, NULL, NULL, NULL, &pending_tv);
262#endif /* HAVE_POLL_FINE */
263    if(r != -1)
264      break;
265    error = errno;
266    if(error && (error != EINTR))
267      break;
268    pending_ms = timeout_ms - (int)timediff(tvnow(), initial_tv);
269    if(pending_ms <= 0)
270      break;
271  } while(r == -1);
272#endif /* USE_WINSOCK */
273  if(r)
274    r = -1;
275  return r;
276}
277
278curl_off_t our_getpid(void)
279{
280  curl_off_t pid;
281
282  pid = (curl_off_t)getpid();
283#if defined(_WIN32) || defined(_WIN32)
284  /* store pid + 65536 to avoid conflict with Cygwin/msys PIDs, see also:
285   * - https://cygwin.com/git/?p=newlib-cygwin.git;a=commit; ↵
286   *   h=b5e1003722cb14235c4f166be72c09acdffc62ea
287   * - https://cygwin.com/git/?p=newlib-cygwin.git;a=commit; ↵
288   *   h=448cf5aa4b429d5a9cebf92a0da4ab4b5b6d23fe
289   */
290  pid += 65536;
291#endif
292  return pid;
293}
294
295int write_pidfile(const char *filename)
296{
297  FILE *pidfile;
298  curl_off_t pid;
299
300  pid = our_getpid();
301  pidfile = fopen(filename, "wb");
302  if(!pidfile) {
303    logmsg("Couldn't write pid file: %s %s", filename, strerror(errno));
304    return 0; /* fail */
305  }
306  fprintf(pidfile, "%" CURL_FORMAT_CURL_OFF_T "\n", pid);
307  fclose(pidfile);
308  logmsg("Wrote pid %" CURL_FORMAT_CURL_OFF_T " to %s", pid, filename);
309  return 1; /* success */
310}
311
312/* store the used port number in a file */
313int write_portfile(const char *filename, int port)
314{
315  FILE *portfile = fopen(filename, "wb");
316  if(!portfile) {
317    logmsg("Couldn't write port file: %s %s", filename, strerror(errno));
318    return 0; /* fail */
319  }
320  fprintf(portfile, "%d\n", port);
321  fclose(portfile);
322  logmsg("Wrote port %d to %s", port, filename);
323  return 1; /* success */
324}
325
326void set_advisor_read_lock(const char *filename)
327{
328  FILE *lockfile;
329  int error = 0;
330  int res;
331
332  do {
333    lockfile = fopen(filename, "wb");
334  } while(!lockfile && ((error = errno) == EINTR));
335  if(!lockfile) {
336    logmsg("Error creating lock file %s error: %d %s",
337           filename, error, strerror(error));
338    return;
339  }
340
341  do {
342    res = fclose(lockfile);
343  } while(res && ((error = errno) == EINTR));
344  if(res)
345    logmsg("Error closing lock file %s error: %d %s",
346           filename, error, strerror(error));
347}
348
349void clear_advisor_read_lock(const char *filename)
350{
351  int error = 0;
352  int res;
353
354  /*
355  ** Log all removal failures. Even those due to file not existing.
356  ** This allows to detect if unexpectedly the file has already been
357  ** removed by a process different than the one that should do this.
358  */
359
360  do {
361    res = unlink(filename);
362  } while(res && ((error = errno) == EINTR));
363  if(res)
364    logmsg("Error removing lock file %s error: %d %s",
365           filename, error, strerror(error));
366}
367
368
369#if defined(_WIN32) && !defined(MSDOS)
370
371static struct timeval tvnow(void)
372{
373  /*
374  ** GetTickCount() is available on _all_ Windows versions from W95 up
375  ** to nowadays. Returns milliseconds elapsed since last system boot,
376  ** increases monotonically and wraps once 49.7 days have elapsed.
377  **
378  ** GetTickCount64() is available on Windows version from Windows Vista
379  ** and Windows Server 2008 up to nowadays. The resolution of the
380  ** function is limited to the resolution of the system timer, which
381  ** is typically in the range of 10 milliseconds to 16 milliseconds.
382  */
383  struct timeval now;
384#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
385  ULONGLONG milliseconds = GetTickCount64();
386#else
387  DWORD milliseconds = GetTickCount();
388#endif
389  now.tv_sec = (long)(milliseconds / 1000);
390  now.tv_usec = (long)((milliseconds % 1000) * 1000);
391  return now;
392}
393
394#elif defined(HAVE_CLOCK_GETTIME_MONOTONIC)
395
396static struct timeval tvnow(void)
397{
398  /*
399  ** clock_gettime() is granted to be increased monotonically when the
400  ** monotonic clock is queried. Time starting point is unspecified, it
401  ** could be the system start-up time, the Epoch, or something else,
402  ** in any case the time starting point does not change once that the
403  ** system has started up.
404  */
405  struct timeval now;
406  struct timespec tsnow;
407  if(0 == clock_gettime(CLOCK_MONOTONIC, &tsnow)) {
408    now.tv_sec = tsnow.tv_sec;
409    now.tv_usec = (int)(tsnow.tv_nsec / 1000);
410  }
411  /*
412  ** Even when the configure process has truly detected monotonic clock
413  ** availability, it might happen that it is not actually available at
414  ** run-time. When this occurs simply fallback to other time source.
415  */
416#ifdef HAVE_GETTIMEOFDAY
417  else
418    (void)gettimeofday(&now, NULL);
419#else
420  else {
421    now.tv_sec = time(NULL);
422    now.tv_usec = 0;
423  }
424#endif
425  return now;
426}
427
428#elif defined(HAVE_GETTIMEOFDAY)
429
430static struct timeval tvnow(void)
431{
432  /*
433  ** gettimeofday() is not granted to be increased monotonically, due to
434  ** clock drifting and external source time synchronization it can jump
435  ** forward or backward in time.
436  */
437  struct timeval now;
438  (void)gettimeofday(&now, NULL);
439  return now;
440}
441
442#else
443
444static struct timeval tvnow(void)
445{
446  /*
447  ** time() returns the value of time in seconds since the Epoch.
448  */
449  struct timeval now;
450  now.tv_sec = time(NULL);
451  now.tv_usec = 0;
452  return now;
453}
454
455#endif
456
457long timediff(struct timeval newer, struct timeval older)
458{
459  timediff_t diff = newer.tv_sec-older.tv_sec;
460  if(diff >= (LONG_MAX/1000))
461    return LONG_MAX;
462  else if(diff <= (LONG_MIN/1000))
463    return LONG_MIN;
464  return (long)(newer.tv_sec-older.tv_sec)*1000+
465    (long)(newer.tv_usec-older.tv_usec)/1000;
466}
467
468/* vars used to keep around previous signal handlers */
469
470typedef void (*SIGHANDLER_T)(int);
471
472#ifdef SIGHUP
473static SIGHANDLER_T old_sighup_handler  = SIG_ERR;
474#endif
475
476#ifdef SIGPIPE
477static SIGHANDLER_T old_sigpipe_handler = SIG_ERR;
478#endif
479
480#ifdef SIGALRM
481static SIGHANDLER_T old_sigalrm_handler = SIG_ERR;
482#endif
483
484#ifdef SIGINT
485static SIGHANDLER_T old_sigint_handler  = SIG_ERR;
486#endif
487
488#ifdef SIGTERM
489static SIGHANDLER_T old_sigterm_handler = SIG_ERR;
490#endif
491
492#if defined(SIGBREAK) && defined(_WIN32)
493static SIGHANDLER_T old_sigbreak_handler = SIG_ERR;
494#endif
495
496#ifdef _WIN32
497#ifdef _WIN32_WCE
498static DWORD thread_main_id = 0;
499#else
500static unsigned int thread_main_id = 0;
501#endif
502static HANDLE thread_main_window = NULL;
503static HWND hidden_main_window = NULL;
504#endif
505
506/* var which if set indicates that the program should finish execution */
507volatile int got_exit_signal = 0;
508
509/* if next is set indicates the first signal handled in exit_signal_handler */
510volatile int exit_signal = 0;
511
512#ifdef _WIN32
513/* event which if set indicates that the program should finish */
514HANDLE exit_event = NULL;
515#endif
516
517/* signal handler that will be triggered to indicate that the program
518 * should finish its execution in a controlled manner as soon as possible.
519 * The first time this is called it will set got_exit_signal to one and
520 * store in exit_signal the signal that triggered its execution.
521 */
522static void exit_signal_handler(int signum)
523{
524  int old_errno = errno;
525  logmsg("exit_signal_handler: %d", signum);
526  if(got_exit_signal == 0) {
527    got_exit_signal = 1;
528    exit_signal = signum;
529#ifdef _WIN32
530    if(exit_event)
531      (void)SetEvent(exit_event);
532#endif
533  }
534  (void)signal(signum, exit_signal_handler);
535  errno = old_errno;
536}
537
538#ifdef _WIN32
539/* CTRL event handler for Windows Console applications to simulate
540 * SIGINT, SIGTERM and SIGBREAK on CTRL events and trigger signal handler.
541 *
542 * Background information from MSDN:
543 * SIGINT is not supported for any Win32 application. When a CTRL+C
544 * interrupt occurs, Win32 operating systems generate a new thread
545 * to specifically handle that interrupt. This can cause a single-thread
546 * application, such as one in UNIX, to become multithreaded and cause
547 * unexpected behavior.
548 * [...]
549 * The SIGILL and SIGTERM signals are not generated under Windows.
550 * They are included for ANSI compatibility. Therefore, you can set
551 * signal handlers for these signals by using signal, and you can also
552 * explicitly generate these signals by calling raise. Source:
553 * https://docs.microsoft.com/de-de/cpp/c-runtime-library/reference/signal
554 */
555static BOOL WINAPI ctrl_event_handler(DWORD dwCtrlType)
556{
557  int signum = 0;
558  logmsg("ctrl_event_handler: %lu", dwCtrlType);
559  switch(dwCtrlType) {
560#ifdef SIGINT
561    case CTRL_C_EVENT: signum = SIGINT; break;
562#endif
563#ifdef SIGTERM
564    case CTRL_CLOSE_EVENT: signum = SIGTERM; break;
565#endif
566#ifdef SIGBREAK
567    case CTRL_BREAK_EVENT: signum = SIGBREAK; break;
568#endif
569    default: return FALSE;
570  }
571  if(signum) {
572    logmsg("ctrl_event_handler: %lu -> %d", dwCtrlType, signum);
573    raise(signum);
574  }
575  return TRUE;
576}
577/* Window message handler for Windows applications to add support
578 * for graceful process termination via taskkill (without /f) which
579 * sends WM_CLOSE to all Windows of a process (even hidden ones).
580 *
581 * Therefore we create and run a hidden Window in a separate thread
582 * to receive and handle the WM_CLOSE message as SIGTERM signal.
583 */
584static LRESULT CALLBACK main_window_proc(HWND hwnd, UINT uMsg,
585                                         WPARAM wParam, LPARAM lParam)
586{
587  int signum = 0;
588  if(hwnd == hidden_main_window) {
589    switch(uMsg) {
590#ifdef SIGTERM
591      case WM_CLOSE: signum = SIGTERM; break;
592#endif
593      case WM_DESTROY: PostQuitMessage(0); break;
594    }
595    if(signum) {
596      logmsg("main_window_proc: %d -> %d", uMsg, signum);
597      raise(signum);
598    }
599  }
600  return DefWindowProc(hwnd, uMsg, wParam, lParam);
601}
602/* Window message queue loop for hidden main window, details see above.
603 */
604#ifdef _WIN32_WCE
605static DWORD WINAPI main_window_loop(LPVOID lpParameter)
606#else
607#include <process.h>
608static unsigned int WINAPI main_window_loop(void *lpParameter)
609#endif
610{
611  WNDCLASS wc;
612  BOOL ret;
613  MSG msg;
614
615  ZeroMemory(&wc, sizeof(wc));
616  wc.lpfnWndProc = (WNDPROC)main_window_proc;
617  wc.hInstance = (HINSTANCE)lpParameter;
618  wc.lpszClassName = TEXT("MainWClass");
619  if(!RegisterClass(&wc)) {
620    perror("RegisterClass failed");
621    return (DWORD)-1;
622  }
623
624  hidden_main_window = CreateWindowEx(0, TEXT("MainWClass"),
625                                      TEXT("Recv WM_CLOSE msg"),
626                                      WS_OVERLAPPEDWINDOW,
627                                      CW_USEDEFAULT, CW_USEDEFAULT,
628                                      CW_USEDEFAULT, CW_USEDEFAULT,
629                                      (HWND)NULL, (HMENU)NULL,
630                                      wc.hInstance, (LPVOID)NULL);
631  if(!hidden_main_window) {
632    perror("CreateWindowEx failed");
633    return (DWORD)-1;
634  }
635
636  do {
637    ret = GetMessage(&msg, NULL, 0, 0);
638    if(ret == -1) {
639      perror("GetMessage failed");
640      return (DWORD)-1;
641    }
642    else if(ret) {
643      if(msg.message == WM_APP) {
644        DestroyWindow(hidden_main_window);
645      }
646      else if(msg.hwnd && !TranslateMessage(&msg)) {
647        DispatchMessage(&msg);
648      }
649    }
650  } while(ret);
651
652  hidden_main_window = NULL;
653  return (DWORD)msg.wParam;
654}
655#endif
656
657static SIGHANDLER_T set_signal(int signum, SIGHANDLER_T handler,
658                               bool restartable)
659{
660#if defined(HAVE_SIGACTION) && defined(SA_RESTART)
661  struct sigaction sa, oldsa;
662
663  memset(&sa, 0, sizeof(sa));
664  sa.sa_handler = handler;
665  sigemptyset(&sa.sa_mask);
666  sigaddset(&sa.sa_mask, signum);
667  sa.sa_flags = restartable? SA_RESTART: 0;
668
669  if(sigaction(signum, &sa, &oldsa))
670    return SIG_ERR;
671
672  return oldsa.sa_handler;
673#else
674  SIGHANDLER_T oldhdlr = signal(signum, handler);
675
676#ifdef HAVE_SIGINTERRUPT
677  if(oldhdlr != SIG_ERR)
678    siginterrupt(signum, (int) restartable);
679#else
680  (void) restartable;
681#endif
682
683  return oldhdlr;
684#endif
685}
686
687void install_signal_handlers(bool keep_sigalrm)
688{
689#ifdef _WIN32
690#ifdef _WIN32_WCE
691  typedef HANDLE curl_win_thread_handle_t;
692#else
693  typedef uintptr_t curl_win_thread_handle_t;
694#endif
695  curl_win_thread_handle_t thread;
696  /* setup windows exit event before any signal can trigger */
697  exit_event = CreateEvent(NULL, TRUE, FALSE, NULL);
698  if(!exit_event)
699    logmsg("cannot create exit event");
700#endif
701#ifdef SIGHUP
702  /* ignore SIGHUP signal */
703  old_sighup_handler = set_signal(SIGHUP, SIG_IGN, FALSE);
704  if(old_sighup_handler == SIG_ERR)
705    logmsg("cannot install SIGHUP handler: %s", strerror(errno));
706#endif
707#ifdef SIGPIPE
708  /* ignore SIGPIPE signal */
709  old_sigpipe_handler = set_signal(SIGPIPE, SIG_IGN, FALSE);
710  if(old_sigpipe_handler == SIG_ERR)
711    logmsg("cannot install SIGPIPE handler: %s", strerror(errno));
712#endif
713#ifdef SIGALRM
714  if(!keep_sigalrm) {
715    /* ignore SIGALRM signal */
716    old_sigalrm_handler = set_signal(SIGALRM, SIG_IGN, FALSE);
717    if(old_sigalrm_handler == SIG_ERR)
718      logmsg("cannot install SIGALRM handler: %s", strerror(errno));
719  }
720#else
721  (void)keep_sigalrm;
722#endif
723#ifdef SIGINT
724  /* handle SIGINT signal with our exit_signal_handler */
725  old_sigint_handler = set_signal(SIGINT, exit_signal_handler, TRUE);
726  if(old_sigint_handler == SIG_ERR)
727    logmsg("cannot install SIGINT handler: %s", strerror(errno));
728#endif
729#ifdef SIGTERM
730  /* handle SIGTERM signal with our exit_signal_handler */
731  old_sigterm_handler = set_signal(SIGTERM, exit_signal_handler, TRUE);
732  if(old_sigterm_handler == SIG_ERR)
733    logmsg("cannot install SIGTERM handler: %s", strerror(errno));
734#endif
735#if defined(SIGBREAK) && defined(_WIN32)
736  /* handle SIGBREAK signal with our exit_signal_handler */
737  old_sigbreak_handler = set_signal(SIGBREAK, exit_signal_handler, TRUE);
738  if(old_sigbreak_handler == SIG_ERR)
739    logmsg("cannot install SIGBREAK handler: %s", strerror(errno));
740#endif
741#ifdef _WIN32
742  if(!SetConsoleCtrlHandler(ctrl_event_handler, TRUE))
743    logmsg("cannot install CTRL event handler");
744#ifdef _WIN32_WCE
745  thread = CreateThread(NULL, 0, &main_window_loop,
746                        (LPVOID)GetModuleHandle(NULL), 0, &thread_main_id);
747#else
748  thread = _beginthreadex(NULL, 0, &main_window_loop,
749                          (void *)GetModuleHandle(NULL), 0, &thread_main_id);
750#endif
751  thread_main_window = (HANDLE)thread;
752  if(!thread_main_window || !thread_main_id)
753    logmsg("cannot start main window loop");
754#endif
755}
756
757void restore_signal_handlers(bool keep_sigalrm)
758{
759#ifdef SIGHUP
760  if(SIG_ERR != old_sighup_handler)
761    (void) set_signal(SIGHUP, old_sighup_handler, FALSE);
762#endif
763#ifdef SIGPIPE
764  if(SIG_ERR != old_sigpipe_handler)
765    (void) set_signal(SIGPIPE, old_sigpipe_handler, FALSE);
766#endif
767#ifdef SIGALRM
768  if(!keep_sigalrm) {
769    if(SIG_ERR != old_sigalrm_handler)
770      (void) set_signal(SIGALRM, old_sigalrm_handler, FALSE);
771  }
772#else
773  (void)keep_sigalrm;
774#endif
775#ifdef SIGINT
776  if(SIG_ERR != old_sigint_handler)
777    (void) set_signal(SIGINT, old_sigint_handler, FALSE);
778#endif
779#ifdef SIGTERM
780  if(SIG_ERR != old_sigterm_handler)
781    (void) set_signal(SIGTERM, old_sigterm_handler, FALSE);
782#endif
783#if defined(SIGBREAK) && defined(_WIN32)
784  if(SIG_ERR != old_sigbreak_handler)
785    (void) set_signal(SIGBREAK, old_sigbreak_handler, FALSE);
786#endif
787#ifdef _WIN32
788  (void)SetConsoleCtrlHandler(ctrl_event_handler, FALSE);
789  if(thread_main_window && thread_main_id) {
790    if(PostThreadMessage(thread_main_id, WM_APP, 0, 0)) {
791      if(WaitForSingleObjectEx(thread_main_window, INFINITE, TRUE)) {
792        if(CloseHandle(thread_main_window)) {
793          thread_main_window = NULL;
794          thread_main_id = 0;
795        }
796      }
797    }
798  }
799  if(exit_event) {
800    if(CloseHandle(exit_event)) {
801      exit_event = NULL;
802    }
803  }
804#endif
805}
806
807#ifdef USE_UNIX_SOCKETS
808
809int bind_unix_socket(curl_socket_t sock, const char *unix_socket,
810        struct sockaddr_un *sau) {
811    int error;
812    int rc;
813
814    memset(sau, 0, sizeof(struct sockaddr_un));
815    sau->sun_family = AF_UNIX;
816    strncpy(sau->sun_path, unix_socket, sizeof(sau->sun_path) - 1);
817    rc = bind(sock, (struct sockaddr*)sau, sizeof(struct sockaddr_un));
818    if(0 != rc && SOCKERRNO == EADDRINUSE) {
819      struct_stat statbuf;
820      /* socket already exists. Perhaps it is stale? */
821      curl_socket_t unixfd = socket(AF_UNIX, SOCK_STREAM, 0);
822      if(CURL_SOCKET_BAD == unixfd) {
823        logmsg("Failed to create socket at %s: (%d) %s",
824               unix_socket, SOCKERRNO, sstrerror(SOCKERRNO));
825        return -1;
826      }
827      /* check whether the server is alive */
828      rc = connect(unixfd, (struct sockaddr*)sau, sizeof(struct sockaddr_un));
829      error = SOCKERRNO;
830      sclose(unixfd);
831      if(0 != rc && ECONNREFUSED != error) {
832        logmsg("Failed to connect to %s: (%d) %s",
833               unix_socket, error, sstrerror(error));
834        return rc;
835      }
836      /* socket server is not alive, now check if it was actually a socket. */
837#ifdef _WIN32
838      /* Windows does not have lstat function. */
839      rc = curlx_win32_stat(unix_socket, &statbuf);
840#else
841      rc = lstat(unix_socket, &statbuf);
842#endif
843      if(0 != rc) {
844        logmsg("Error binding socket, failed to stat %s: (%d) %s",
845               unix_socket, errno, strerror(errno));
846        return rc;
847      }
848#ifdef S_IFSOCK
849      if((statbuf.st_mode & S_IFSOCK) != S_IFSOCK) {
850        logmsg("Error binding socket, failed to stat %s", unix_socket);
851        return -1;
852      }
853#endif
854      /* dead socket, cleanup and retry bind */
855      rc = unlink(unix_socket);
856      if(0 != rc) {
857        logmsg("Error binding socket, failed to unlink %s: (%d) %s",
858               unix_socket, errno, strerror(errno));
859        return rc;
860      }
861      /* stale socket is gone, retry bind */
862      rc = bind(sock, (struct sockaddr*)sau, sizeof(struct sockaddr_un));
863    }
864    return rc;
865}
866#endif
867