util.c (26086B)
1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24 #include "first.h" 25 26 #ifdef HAVE_FCNTL_H 27 #include <fcntl.h> 28 #endif 29 30 /* This function returns a pointer to STATIC memory. It converts the given 31 * binary lump to a hex formatted string usable for output in logs or 32 * whatever. 33 */ 34 char *data_to_hex(char *data, size_t len) 35 { 36 static char buf[256*3]; 37 size_t i; 38 char *optr = buf; 39 char *iptr = data; 40 41 if(len > 255) 42 len = 255; 43 44 for(i = 0; i < len; i++) { 45 if((data[i] >= 0x20) && (data[i] < 0x7f)) 46 *optr++ = *iptr++; 47 else { 48 snprintf(optr, 4, "%%%02x", (unsigned char)*iptr++); 49 optr += 3; 50 } 51 } 52 *optr = 0; /* in case no sprintf was used */ 53 54 return buf; 55 } 56 57 void loghex(unsigned char *buffer, ssize_t len) 58 { 59 char data[12000]; 60 ssize_t i; 61 unsigned char *ptr = buffer; 62 char *optr = data; 63 ssize_t width = 0; 64 int left = sizeof(data); 65 66 for(i = 0; i < len && (left >= 0); i++) { 67 snprintf(optr, left, "%02x", ptr[i]); 68 width += 2; 69 optr += 2; 70 left -= 2; 71 } 72 if(width) 73 logmsg("'%s'", data); 74 } 75 76 void logmsg(const char *msg, ...) 77 { 78 va_list ap; 79 char buffer[2048 + 1]; 80 FILE *logfp; 81 struct curltime tv; 82 time_t sec; 83 struct tm *now; 84 char timebuf[50]; 85 static time_t epoch_offset; 86 static int known_offset; 87 88 if(!serverlogfile) { 89 fprintf(stderr, "Serverlogfile not set error\n"); 90 return; 91 } 92 93 tv = curlx_now(); 94 if(!known_offset) { 95 epoch_offset = time(NULL) - tv.tv_sec; 96 known_offset = 1; 97 } 98 sec = epoch_offset + tv.tv_sec; 99 /* !checksrc! disable BANNEDFUNC 1 */ 100 now = localtime(&sec); /* not thread safe but we don't care */ 101 102 snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld", 103 (int)now->tm_hour, (int)now->tm_min, (int)now->tm_sec, 104 (long)tv.tv_usec); 105 106 va_start(ap, msg); 107 #ifdef __clang__ 108 #pragma clang diagnostic push 109 #pragma clang diagnostic ignored "-Wformat-nonliteral" 110 #endif 111 vsnprintf(buffer, sizeof(buffer), msg, ap); 112 #ifdef __clang__ 113 #pragma clang diagnostic pop 114 #endif 115 va_end(ap); 116 117 do { 118 logfp = fopen(serverlogfile, "ab"); 119 /* !checksrc! disable ERRNOVAR 1 */ 120 } while(!logfp && (errno == EINTR)); 121 if(logfp) { 122 fprintf(logfp, "%s %s\n", timebuf, buffer); 123 fclose(logfp); 124 } 125 else { 126 int error = errno; 127 fprintf(stderr, "fopen() failed with error (%d) %s\n", 128 error, strerror(error)); 129 fprintf(stderr, "Error opening file '%s'\n", serverlogfile); 130 fprintf(stderr, "Msg not logged: %s %s\n", timebuf, buffer); 131 } 132 } 133 134 unsigned char byteval(char *value) 135 { 136 unsigned long num = strtoul(value, NULL, 10); 137 return num & 0xff; 138 } 139 140 #ifdef _WIN32 141 /* use instead of perror() on generic Windows */ 142 static void win32_perror(const char *msg) 143 { 144 char buf[512]; 145 int err = SOCKERRNO; 146 curlx_winapi_strerror(err, buf, sizeof(buf)); 147 if(msg) 148 fprintf(stderr, "%s: ", msg); 149 fprintf(stderr, "%s\n", buf); 150 } 151 152 static void win32_cleanup(void) 153 { 154 #ifdef USE_WINSOCK 155 WSACleanup(); 156 #endif /* USE_WINSOCK */ 157 158 /* flush buffers of all streams regardless of their mode */ 159 _flushall(); 160 } 161 162 int win32_init(void) 163 { 164 curlx_now_init(); 165 #ifdef USE_WINSOCK 166 { 167 WORD wVersionRequested; 168 WSADATA wsaData; 169 int err; 170 171 wVersionRequested = MAKEWORD(2, 2); 172 err = WSAStartup(wVersionRequested, &wsaData); 173 174 if(err) { 175 win32_perror("Winsock init failed"); 176 logmsg("Error initialising Winsock -- aborting"); 177 return 1; 178 } 179 180 if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) || 181 HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested) ) { 182 WSACleanup(); 183 win32_perror("Winsock init failed"); 184 logmsg("No suitable winsock.dll found -- aborting"); 185 return 1; 186 } 187 } 188 #endif /* USE_WINSOCK */ 189 atexit(win32_cleanup); 190 return 0; 191 } 192 193 /* socket-safe strerror (works on Winsock errors, too) */ 194 const char *sstrerror(int err) 195 { 196 static char buf[512]; 197 return curlx_winapi_strerror(err, buf, sizeof(buf)); 198 } 199 #else 200 #define sstrerror(e) strerror(e) 201 #endif /* _WIN32 */ 202 203 /* fopens the test case file */ 204 FILE *test2fopen(long testno, const char *logdir2) 205 { 206 FILE *stream; 207 char filename[256]; 208 /* first try the alternative, preprocessed, file */ 209 snprintf(filename, sizeof(filename), "%s/test%ld", logdir2, testno); 210 stream = fopen(filename, "rb"); 211 if(stream) 212 return stream; 213 214 /* then try the source version */ 215 snprintf(filename, sizeof(filename), "%s/data/test%ld", srcpath, testno); 216 stream = fopen(filename, "rb"); 217 218 return stream; 219 } 220 221 #ifdef _WIN32 222 #define t_getpid() GetCurrentProcessId() 223 #else 224 #define t_getpid() getpid() 225 #endif 226 227 curl_off_t our_getpid(void) 228 { 229 curl_off_t pid = (curl_off_t)t_getpid(); 230 #ifdef _WIN32 231 /* store pid + MAX_PID to avoid conflict with Cygwin/msys PIDs, see also: 232 * - 2019-01-31: https://cygwin.com/git/?p=newlib-cygwin.git;a=commit; 233 * h=b5e1003722cb14235c4f166be72c09acdffc62ea 234 * - 2019-02-02: https://cygwin.com/git/?p=newlib-cygwin.git;a=commit; 235 * h=448cf5aa4b429d5a9cebf92a0da4ab4b5b6d23fe 236 * - 2024-12-19: https://cygwin.com/git/?p=newlib-cygwin.git;a=commit; 237 * h=363357c023ce01e936bdaedf0f479292a8fa4e0f 238 */ 239 pid += 4194304; 240 #endif 241 return pid; 242 } 243 244 int write_pidfile(const char *filename) 245 { 246 FILE *pidfile; 247 curl_off_t pid; 248 249 pid = our_getpid(); 250 pidfile = fopen(filename, "wb"); 251 if(!pidfile) { 252 logmsg("Couldn't write pid file: %s %s", filename, strerror(errno)); 253 return 0; /* fail */ 254 } 255 fprintf(pidfile, "%ld\n", (long)pid); 256 fclose(pidfile); 257 logmsg("Wrote pid %ld to %s", (long)pid, filename); 258 return 1; /* success */ 259 } 260 261 /* store the used port number in a file */ 262 int write_portfile(const char *filename, int port) 263 { 264 FILE *portfile = fopen(filename, "wb"); 265 if(!portfile) { 266 logmsg("Couldn't write port file: %s %s", filename, strerror(errno)); 267 return 0; /* fail */ 268 } 269 fprintf(portfile, "%d\n", port); 270 fclose(portfile); 271 logmsg("Wrote port %d to %s", port, filename); 272 return 1; /* success */ 273 } 274 275 void set_advisor_read_lock(const char *filename) 276 { 277 FILE *lockfile; 278 int error = 0; 279 int res; 280 281 do { 282 lockfile = fopen(filename, "wb"); 283 /* !checksrc! disable ERRNOVAR 1 */ 284 } while(!lockfile && ((error = errno) == EINTR)); 285 if(!lockfile) { 286 logmsg("Error creating lock file %s error (%d) %s", 287 filename, error, strerror(error)); 288 return; 289 } 290 291 res = fclose(lockfile); 292 if(res) 293 logmsg("Error closing lock file %s error (%d) %s", 294 filename, errno, strerror(errno)); 295 } 296 297 void clear_advisor_read_lock(const char *filename) 298 { 299 int error = 0; 300 int res; 301 302 /* 303 ** Log all removal failures. Even those due to file not existing. 304 ** This allows to detect if unexpectedly the file has already been 305 ** removed by a process different than the one that should do this. 306 */ 307 308 do { 309 res = unlink(filename); 310 /* !checksrc! disable ERRNOVAR 1 */ 311 } while(res && ((error = errno) == EINTR)); 312 if(res) 313 logmsg("Error removing lock file %s error (%d) %s", 314 filename, error, strerror(error)); 315 } 316 317 /* vars used to keep around previous signal handlers */ 318 319 typedef void (*SIGHANDLER_T)(int); 320 321 #if defined(_MSC_VER) && (_MSC_VER <= 1700) 322 /* Workaround for warning C4306: 323 'type cast' : conversion from 'int' to 'void (__cdecl *)(int)' */ 324 #undef SIG_ERR 325 #define SIG_ERR ((SIGHANDLER_T)(size_t)-1) 326 #endif 327 328 #ifdef SIGHUP 329 static SIGHANDLER_T old_sighup_handler = SIG_ERR; 330 #endif 331 332 #ifdef SIGPIPE 333 static SIGHANDLER_T old_sigpipe_handler = SIG_ERR; 334 #endif 335 336 #ifdef SIGALRM 337 static SIGHANDLER_T old_sigalrm_handler = SIG_ERR; 338 #endif 339 340 #ifdef SIGINT 341 static SIGHANDLER_T old_sigint_handler = SIG_ERR; 342 #endif 343 344 #ifdef SIGTERM 345 static SIGHANDLER_T old_sigterm_handler = SIG_ERR; 346 #endif 347 348 #if defined(SIGBREAK) && defined(_WIN32) 349 static SIGHANDLER_T old_sigbreak_handler = SIG_ERR; 350 #endif 351 352 #if defined(_WIN32) && !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE) 353 static unsigned int thread_main_id = 0; 354 static HANDLE thread_main_window = NULL; 355 static HWND hidden_main_window = NULL; 356 #endif 357 358 /* signal handler that will be triggered to indicate that the program 359 * should finish its execution in a controlled manner as soon as possible. 360 * The first time this is called it will set got_exit_signal to one and 361 * store in exit_signal the signal that triggered its execution. 362 */ 363 #ifndef UNDER_CE 364 /* 365 * Only call signal-safe functions from the signal handler, as required by 366 * the POSIX specification: 367 * https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html 368 * Hence, do not call 'logmsg()', and instead use 'open/write/close' to 369 * log errors. 370 */ 371 static void exit_signal_handler(int signum) 372 { 373 int old_errno = errno; 374 if(!serverlogfile) { 375 static const char msg[] = "exit_signal_handler: serverlogfile not set\n"; 376 (void)!write(STDERR_FILENO, msg, sizeof(msg) - 1); 377 } 378 else { 379 #ifdef _WIN32 380 #define OPENMODE S_IREAD | S_IWRITE 381 #else 382 #define OPENMODE S_IRUSR | S_IWUSR 383 #endif 384 int fd = open(serverlogfile, O_WRONLY|O_CREAT|O_APPEND, OPENMODE); 385 if(fd != -1) { 386 static const char msg[] = "exit_signal_handler: called\n"; 387 (void)!write(fd, msg, sizeof(msg) - 1); 388 close(fd); 389 } 390 else { 391 static const char msg[] = "exit_signal_handler: failed opening "; 392 (void)!write(STDERR_FILENO, msg, sizeof(msg) - 1); 393 (void)!write(STDERR_FILENO, serverlogfile, strlen(serverlogfile)); 394 (void)!write(STDERR_FILENO, "\n", 1); 395 } 396 } 397 if(got_exit_signal == 0) { 398 got_exit_signal = 1; 399 exit_signal = signum; 400 #ifdef _WIN32 401 if(exit_event) 402 (void)SetEvent(exit_event); 403 #endif 404 } 405 (void)signal(signum, exit_signal_handler); 406 CURL_SETERRNO(old_errno); 407 } 408 #endif 409 410 #if defined(_WIN32) && !defined(UNDER_CE) 411 /* CTRL event handler for Windows Console applications to simulate 412 * SIGINT, SIGTERM and SIGBREAK on CTRL events and trigger signal handler. 413 * 414 * Background information from MSDN: 415 * SIGINT is not supported for any Win32 application. When a CTRL+C 416 * interrupt occurs, Win32 operating systems generate a new thread 417 * to specifically handle that interrupt. This can cause a single-thread 418 * application, such as one in UNIX, to become multithreaded and cause 419 * unexpected behavior. 420 * [...] 421 * The SIGKILL and SIGTERM signals are not generated under Windows. 422 * They are included for ANSI compatibility. Therefore, you can set 423 * signal handlers for these signals by using signal, and you can also 424 * explicitly generate these signals by calling raise. Source: 425 * https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/signal 426 */ 427 static BOOL WINAPI ctrl_event_handler(DWORD dwCtrlType) 428 { 429 int signum = 0; 430 logmsg("ctrl_event_handler: %lu", dwCtrlType); 431 switch(dwCtrlType) { 432 #ifdef SIGINT 433 case CTRL_C_EVENT: 434 signum = SIGINT; 435 break; 436 #endif 437 #ifdef SIGTERM 438 case CTRL_CLOSE_EVENT: 439 signum = SIGTERM; 440 break; 441 #endif 442 #ifdef SIGBREAK 443 case CTRL_BREAK_EVENT: 444 signum = SIGBREAK; 445 break; 446 #endif 447 default: 448 return FALSE; 449 } 450 if(signum) { 451 logmsg("ctrl_event_handler: %lu -> %d", dwCtrlType, signum); 452 raise(signum); 453 } 454 return TRUE; 455 } 456 #endif 457 458 #if defined(_WIN32) && !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE) 459 /* Window message handler for Windows applications to add support 460 * for graceful process termination via taskkill (without /f) which 461 * sends WM_CLOSE to all Windows of a process (even hidden ones). 462 * 463 * Therefore we create and run a hidden Window in a separate thread 464 * to receive and handle the WM_CLOSE message as SIGTERM signal. 465 */ 466 static LRESULT CALLBACK main_window_proc(HWND hwnd, UINT uMsg, 467 WPARAM wParam, LPARAM lParam) 468 { 469 int signum = 0; 470 if(hwnd == hidden_main_window) { 471 switch(uMsg) { 472 #ifdef SIGTERM 473 case WM_CLOSE: 474 signum = SIGTERM; 475 break; 476 #endif 477 case WM_DESTROY: 478 PostQuitMessage(0); 479 break; 480 } 481 if(signum) { 482 logmsg("main_window_proc: %d -> %d", uMsg, signum); 483 raise(signum); 484 } 485 } 486 return DefWindowProc(hwnd, uMsg, wParam, lParam); 487 } 488 /* Window message queue loop for hidden main window, details see above. 489 */ 490 #include <process.h> 491 static unsigned int WINAPI main_window_loop(void *lpParameter) 492 { 493 WNDCLASS wc; 494 BOOL ret; 495 MSG msg; 496 497 ZeroMemory(&wc, sizeof(wc)); 498 wc.lpfnWndProc = (WNDPROC)main_window_proc; 499 wc.hInstance = (HINSTANCE)lpParameter; 500 wc.lpszClassName = TEXT("MainWClass"); 501 if(!RegisterClass(&wc)) { 502 win32_perror("RegisterClass failed"); 503 return (DWORD)-1; 504 } 505 506 hidden_main_window = CreateWindowEx(0, TEXT("MainWClass"), 507 TEXT("Recv WM_CLOSE msg"), 508 WS_OVERLAPPEDWINDOW, 509 CW_USEDEFAULT, CW_USEDEFAULT, 510 CW_USEDEFAULT, CW_USEDEFAULT, 511 (HWND)NULL, (HMENU)NULL, 512 wc.hInstance, (LPVOID)NULL); 513 if(!hidden_main_window) { 514 win32_perror("CreateWindowEx failed"); 515 return (DWORD)-1; 516 } 517 518 do { 519 ret = GetMessage(&msg, NULL, 0, 0); 520 if(ret == -1) { 521 win32_perror("GetMessage failed"); 522 return (DWORD)-1; 523 } 524 else if(ret) { 525 if(msg.message == WM_APP) { 526 DestroyWindow(hidden_main_window); 527 } 528 else if(msg.hwnd && !TranslateMessage(&msg)) { 529 DispatchMessage(&msg); 530 } 531 } 532 } while(ret); 533 534 hidden_main_window = NULL; 535 return (DWORD)msg.wParam; 536 } 537 #endif 538 539 #ifndef UNDER_CE 540 static SIGHANDLER_T set_signal(int signum, SIGHANDLER_T handler, 541 bool restartable) 542 { 543 #if defined(HAVE_SIGACTION) && defined(SA_RESTART) 544 struct sigaction sa, oldsa; 545 546 memset(&sa, 0, sizeof(sa)); 547 sa.sa_handler = handler; 548 sigemptyset(&sa.sa_mask); 549 sigaddset(&sa.sa_mask, signum); 550 sa.sa_flags = restartable ? SA_RESTART : 0; 551 552 if(sigaction(signum, &sa, &oldsa)) 553 return SIG_ERR; 554 555 return oldsa.sa_handler; 556 #else 557 SIGHANDLER_T oldhdlr = signal(signum, handler); 558 559 #ifdef HAVE_SIGINTERRUPT 560 if(oldhdlr != SIG_ERR) 561 siginterrupt(signum, (int) restartable); 562 #else 563 (void) restartable; 564 #endif 565 566 return oldhdlr; 567 #endif 568 } 569 #endif 570 571 void install_signal_handlers(bool keep_sigalrm) 572 { 573 #ifdef _WIN32 574 /* setup Windows exit event before any signal can trigger */ 575 exit_event = CreateEvent(NULL, TRUE, FALSE, NULL); 576 if(!exit_event) 577 logmsg("cannot create exit event"); 578 #endif 579 #ifdef SIGHUP 580 /* ignore SIGHUP signal */ 581 old_sighup_handler = set_signal(SIGHUP, SIG_IGN, FALSE); 582 if(old_sighup_handler == SIG_ERR) 583 logmsg("cannot install SIGHUP handler: %s", strerror(errno)); 584 #endif 585 #ifdef SIGPIPE 586 /* ignore SIGPIPE signal */ 587 old_sigpipe_handler = set_signal(SIGPIPE, SIG_IGN, FALSE); 588 if(old_sigpipe_handler == SIG_ERR) 589 logmsg("cannot install SIGPIPE handler: %s", strerror(errno)); 590 #endif 591 #ifdef SIGALRM 592 if(!keep_sigalrm) { 593 /* ignore SIGALRM signal */ 594 old_sigalrm_handler = set_signal(SIGALRM, SIG_IGN, FALSE); 595 if(old_sigalrm_handler == SIG_ERR) 596 logmsg("cannot install SIGALRM handler: %s", strerror(errno)); 597 } 598 #else 599 (void)keep_sigalrm; 600 #endif 601 #ifdef SIGINT 602 /* handle SIGINT signal with our exit_signal_handler */ 603 old_sigint_handler = set_signal(SIGINT, exit_signal_handler, TRUE); 604 if(old_sigint_handler == SIG_ERR) 605 logmsg("cannot install SIGINT handler: %s", strerror(errno)); 606 #endif 607 #ifdef SIGTERM 608 /* handle SIGTERM signal with our exit_signal_handler */ 609 old_sigterm_handler = set_signal(SIGTERM, exit_signal_handler, TRUE); 610 if(old_sigterm_handler == SIG_ERR) 611 logmsg("cannot install SIGTERM handler: %s", strerror(errno)); 612 #endif 613 #if defined(SIGBREAK) && defined(_WIN32) 614 /* handle SIGBREAK signal with our exit_signal_handler */ 615 old_sigbreak_handler = set_signal(SIGBREAK, exit_signal_handler, TRUE); 616 if(old_sigbreak_handler == SIG_ERR) 617 logmsg("cannot install SIGBREAK handler: %s", strerror(errno)); 618 #endif 619 #ifdef _WIN32 620 #ifndef UNDER_CE 621 if(!SetConsoleCtrlHandler(ctrl_event_handler, TRUE)) 622 logmsg("cannot install CTRL event handler"); 623 #endif 624 625 #if !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE) 626 { 627 typedef uintptr_t curl_win_thread_handle_t; 628 curl_win_thread_handle_t thread; 629 thread = _beginthreadex(NULL, 0, &main_window_loop, 630 (void *)GetModuleHandle(NULL), 0, &thread_main_id); 631 thread_main_window = (HANDLE)thread; 632 if(!thread_main_window || !thread_main_id) 633 logmsg("cannot start main window loop"); 634 } 635 #endif 636 #endif 637 } 638 639 void restore_signal_handlers(bool keep_sigalrm) 640 { 641 #ifdef SIGHUP 642 if(SIG_ERR != old_sighup_handler) 643 (void) set_signal(SIGHUP, old_sighup_handler, FALSE); 644 #endif 645 #ifdef SIGPIPE 646 if(SIG_ERR != old_sigpipe_handler) 647 (void) set_signal(SIGPIPE, old_sigpipe_handler, FALSE); 648 #endif 649 #ifdef SIGALRM 650 if(!keep_sigalrm) { 651 if(SIG_ERR != old_sigalrm_handler) 652 (void) set_signal(SIGALRM, old_sigalrm_handler, FALSE); 653 } 654 #else 655 (void)keep_sigalrm; 656 #endif 657 #ifdef SIGINT 658 if(SIG_ERR != old_sigint_handler) 659 (void) set_signal(SIGINT, old_sigint_handler, FALSE); 660 #endif 661 #ifdef SIGTERM 662 if(SIG_ERR != old_sigterm_handler) 663 (void) set_signal(SIGTERM, old_sigterm_handler, FALSE); 664 #endif 665 #if defined(SIGBREAK) && defined(_WIN32) 666 if(SIG_ERR != old_sigbreak_handler) 667 (void) set_signal(SIGBREAK, old_sigbreak_handler, FALSE); 668 #endif 669 #ifdef _WIN32 670 #ifndef UNDER_CE 671 (void)SetConsoleCtrlHandler(ctrl_event_handler, FALSE); 672 #endif 673 #if !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE) 674 if(thread_main_window && thread_main_id) { 675 if(PostThreadMessage(thread_main_id, WM_APP, 0, 0)) { 676 if(WaitForSingleObjectEx(thread_main_window, INFINITE, TRUE)) { 677 if(CloseHandle(thread_main_window)) { 678 thread_main_window = NULL; 679 thread_main_id = 0; 680 } 681 } 682 } 683 } 684 if(exit_event) { 685 if(CloseHandle(exit_event)) { 686 exit_event = NULL; 687 } 688 } 689 #endif 690 #endif 691 } 692 693 #ifdef USE_UNIX_SOCKETS 694 695 int bind_unix_socket(curl_socket_t sock, const char *unix_socket, 696 struct sockaddr_un *sau) 697 { 698 int error; 699 int rc; 700 size_t len = strlen(unix_socket); 701 702 memset(sau, 0, sizeof(struct sockaddr_un)); 703 sau->sun_family = AF_UNIX; 704 if(len >= sizeof(sau->sun_path) - 1) { 705 logmsg("Too long unix socket domain path (%zd)", len); 706 return -1; 707 } 708 strcpy(sau->sun_path, unix_socket); 709 rc = bind(sock, (struct sockaddr*)sau, sizeof(struct sockaddr_un)); 710 if(rc && SOCKERRNO == SOCKEADDRINUSE) { 711 struct_stat statbuf; 712 /* socket already exists. Perhaps it is stale? */ 713 curl_socket_t unixfd = socket(AF_UNIX, SOCK_STREAM, 0); 714 if(CURL_SOCKET_BAD == unixfd) { 715 logmsg("Failed to create socket at %s (%d) %s", 716 unix_socket, SOCKERRNO, sstrerror(SOCKERRNO)); 717 return -1; 718 } 719 /* check whether the server is alive */ 720 rc = connect(unixfd, (struct sockaddr*)sau, sizeof(struct sockaddr_un)); 721 error = SOCKERRNO; 722 sclose(unixfd); 723 if(rc && error != SOCKECONNREFUSED) { 724 logmsg("Failed to connect to %s (%d) %s", 725 unix_socket, error, sstrerror(error)); 726 return rc; 727 } 728 /* socket server is not alive, now check if it was actually a socket. */ 729 #ifdef _WIN32 730 /* Windows does not have lstat function. */ 731 rc = curlx_win32_stat(unix_socket, &statbuf); 732 #else 733 rc = lstat(unix_socket, &statbuf); 734 #endif 735 if(rc) { 736 logmsg("Error binding socket, failed to stat %s (%d) %s", 737 unix_socket, errno, strerror(errno)); 738 return rc; 739 } 740 #ifdef S_IFSOCK 741 if((statbuf.st_mode & S_IFSOCK) != S_IFSOCK) { 742 logmsg("Error binding socket, failed to stat %s", unix_socket); 743 return -1; 744 } 745 #endif 746 /* dead socket, cleanup and retry bind */ 747 rc = unlink(unix_socket); 748 if(rc) { 749 logmsg("Error binding socket, failed to unlink %s (%d) %s", 750 unix_socket, errno, strerror(errno)); 751 return rc; 752 } 753 /* stale socket is gone, retry bind */ 754 rc = bind(sock, (struct sockaddr*)sau, sizeof(struct sockaddr_un)); 755 } 756 return rc; 757 } 758 #endif 759 760 /* 761 ** unsigned long to unsigned short 762 */ 763 #define CURL_MASK_USHORT ((unsigned short)~0) 764 #define CURL_MASK_SSHORT (CURL_MASK_USHORT >> 1) 765 766 unsigned short util_ultous(unsigned long ulnum) 767 { 768 #ifdef __INTEL_COMPILER 769 # pragma warning(push) 770 # pragma warning(disable:810) /* conversion may lose significant bits */ 771 #endif 772 773 DEBUGASSERT(ulnum <= (unsigned long) CURL_MASK_USHORT); 774 return (unsigned short)(ulnum & (unsigned long) CURL_MASK_USHORT); 775 776 #ifdef __INTEL_COMPILER 777 # pragma warning(pop) 778 #endif 779 } 780 781 curl_socket_t sockdaemon(curl_socket_t sock, 782 unsigned short *listenport, 783 const char *unix_socket, 784 bool bind_only) 785 { 786 /* passive daemon style */ 787 srvr_sockaddr_union_t listener; 788 int flag; 789 int rc; 790 int totdelay = 0; 791 int maxretr = 10; 792 int delay = 20; 793 int attempt = 0; 794 int error = 0; 795 796 #ifndef USE_UNIX_SOCKETS 797 (void)unix_socket; 798 #endif 799 800 do { 801 attempt++; 802 flag = 1; 803 rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 804 (void *)&flag, sizeof(flag)); 805 if(rc) { 806 error = SOCKERRNO; 807 logmsg("setsockopt(SO_REUSEADDR) failed with error (%d) %s", 808 error, sstrerror(error)); 809 if(maxretr) { 810 rc = curlx_wait_ms(delay); 811 if(rc) { 812 /* should not happen */ 813 error = SOCKERRNO; 814 logmsg("curlx_wait_ms() failed with error (%d) %s", 815 error, sstrerror(error)); 816 sclose(sock); 817 return CURL_SOCKET_BAD; 818 } 819 if(got_exit_signal) { 820 logmsg("signalled to die, exiting..."); 821 sclose(sock); 822 return CURL_SOCKET_BAD; 823 } 824 totdelay += delay; 825 delay *= 2; /* double the sleep for next attempt */ 826 } 827 } 828 } while(rc && maxretr--); 829 830 if(rc) { 831 logmsg("setsockopt(SO_REUSEADDR) failed %d times in %d ms. Error (%d) %s", 832 attempt, totdelay, error, strerror(error)); 833 logmsg("Continuing anyway..."); 834 } 835 836 /* When the specified listener port is zero, it is actually a 837 request to let the system choose a non-zero available port. */ 838 839 switch(socket_domain) { 840 case AF_INET: 841 memset(&listener.sa4, 0, sizeof(listener.sa4)); 842 listener.sa4.sin_family = AF_INET; 843 listener.sa4.sin_addr.s_addr = INADDR_ANY; 844 listener.sa4.sin_port = htons(*listenport); 845 rc = bind(sock, &listener.sa, sizeof(listener.sa4)); 846 break; 847 #ifdef USE_IPV6 848 case AF_INET6: 849 memset(&listener.sa6, 0, sizeof(listener.sa6)); 850 listener.sa6.sin6_family = AF_INET6; 851 listener.sa6.sin6_addr = in6addr_any; 852 listener.sa6.sin6_port = htons(*listenport); 853 rc = bind(sock, &listener.sa, sizeof(listener.sa6)); 854 break; 855 #endif /* USE_IPV6 */ 856 #ifdef USE_UNIX_SOCKETS 857 case AF_UNIX: 858 rc = bind_unix_socket(sock, unix_socket, &listener.sau); 859 break; 860 #endif 861 default: 862 rc = 1; 863 } 864 865 if(rc) { 866 error = SOCKERRNO; 867 #ifdef USE_UNIX_SOCKETS 868 if(socket_domain == AF_UNIX) 869 logmsg("Error binding socket on path %s (%d) %s", 870 unix_socket, error, sstrerror(error)); 871 else 872 #endif 873 logmsg("Error binding socket on port %hu (%d) %s", 874 *listenport, error, sstrerror(error)); 875 sclose(sock); 876 return CURL_SOCKET_BAD; 877 } 878 879 if(!*listenport 880 #ifdef USE_UNIX_SOCKETS 881 && !unix_socket 882 #endif 883 ) { 884 /* The system was supposed to choose a port number, figure out which 885 port we actually got and update the listener port value with it. */ 886 curl_socklen_t la_size; 887 srvr_sockaddr_union_t localaddr; 888 #ifdef USE_IPV6 889 if(socket_domain == AF_INET6) 890 la_size = sizeof(localaddr.sa6); 891 else 892 #endif 893 la_size = sizeof(localaddr.sa4); 894 memset(&localaddr.sa, 0, (size_t)la_size); 895 if(getsockname(sock, &localaddr.sa, &la_size) < 0) { 896 error = SOCKERRNO; 897 logmsg("getsockname() failed with error (%d) %s", 898 error, sstrerror(error)); 899 sclose(sock); 900 return CURL_SOCKET_BAD; 901 } 902 switch(localaddr.sa.sa_family) { 903 case AF_INET: 904 *listenport = ntohs(localaddr.sa4.sin_port); 905 break; 906 #ifdef USE_IPV6 907 case AF_INET6: 908 *listenport = ntohs(localaddr.sa6.sin6_port); 909 break; 910 #endif 911 default: 912 break; 913 } 914 if(!*listenport) { 915 /* Real failure, listener port shall not be zero beyond this point. */ 916 logmsg("Apparently getsockname() succeeded, with listener port zero."); 917 logmsg("A valid reason for this failure is a binary built without"); 918 logmsg("proper network library linkage. This might not be the only"); 919 logmsg("reason, but double check it before anything else."); 920 sclose(sock); 921 return CURL_SOCKET_BAD; 922 } 923 } 924 925 /* bindonly option forces no listening */ 926 if(bind_only) { 927 logmsg("instructed to bind port without listening"); 928 return sock; 929 } 930 931 /* start accepting connections */ 932 rc = listen(sock, 5); 933 if(rc) { 934 error = SOCKERRNO; 935 logmsg("listen(%ld, 5) failed with error (%d) %s", 936 (long)sock, error, sstrerror(error)); 937 sclose(sock); 938 return CURL_SOCKET_BAD; 939 } 940 941 return sock; 942 }