Annotation of embedaddon/curl/tests/server/util.c, revision 1.1.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>