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