Annotation of embedaddon/curl/tests/server/util.c, revision 1.1
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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>