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