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