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