listener.c revision 94334
1/* 2 * Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * 5 * By using this file, you agree to the terms and conditions set 6 * forth in the LICENSE file which can be found at the top level of 7 * the sendmail distribution. 8 * 9 */ 10 11#include <sm/gen.h> 12SM_RCSID("@(#)$Id: listener.c,v 8.82 2002/01/22 18:46:47 ca Exp $") 13 14/* 15** listener.c -- threaded network listener 16*/ 17 18#include "libmilter.h" 19#include <sm/errstring.h> 20 21 22# if NETINET || NETINET6 23# include <arpa/inet.h> 24# endif /* NETINET || NETINET6 */ 25 26static smutex_t L_Mutex; 27 28/* 29** MI_MILTEROPEN -- setup socket to listen on 30** 31** Parameters: 32** conn -- connection description 33** backlog -- listen backlog 34** socksize -- socksize of created socket 35** family -- family of created socket 36** name -- name for logging 37** 38** Returns: 39** socket upon success, error code otherwise. 40** 41** Side effect: 42** sets sockpath if UNIX socket. 43*/ 44 45#if NETUNIX 46static char *sockpath = NULL; 47#endif /* NETUNIX */ 48 49static socket_t 50mi_milteropen(conn, backlog, socksize, family, name) 51 char *conn; 52 int backlog; 53 SOCKADDR_LEN_T *socksize; 54 int *family; 55 char *name; 56{ 57 socket_t sock; 58 int sockopt = 1; 59 size_t len = 0; 60 char *p; 61 char *colon; 62 char *at; 63 SOCKADDR addr; 64 65 if (conn == NULL || conn[0] == '\0') 66 { 67 smi_log(SMI_LOG_ERR, "%s: empty or missing socket information", 68 name); 69 return INVALID_SOCKET; 70 } 71 (void) memset(&addr, '\0', sizeof addr); 72 73 /* protocol:filename or protocol:port@host */ 74 p = conn; 75 colon = strchr(p, ':'); 76 if (colon != NULL) 77 { 78 *colon = '\0'; 79 80 if (*p == '\0') 81 { 82#if NETUNIX 83 /* default to AF_UNIX */ 84 addr.sa.sa_family = AF_UNIX; 85 *socksize = sizeof (struct sockaddr_un); 86#else /* NETUNIX */ 87# if NETINET 88 /* default to AF_INET */ 89 addr.sa.sa_family = AF_INET; 90 *socksize = sizeof addr.sin; 91# else /* NETINET */ 92# if NETINET6 93 /* default to AF_INET6 */ 94 addr.sa.sa_family = AF_INET6; 95 *socksize = sizeof addr.sin6; 96# else /* NETINET6 */ 97 /* no protocols available */ 98 smi_log(SMI_LOG_ERR, 99 "%s: no valid socket protocols available", 100 name); 101 return INVALID_SOCKET; 102# endif /* NETINET6 */ 103# endif /* NETINET */ 104#endif /* NETUNIX */ 105 } 106#if NETUNIX 107 else if (strcasecmp(p, "unix") == 0 || 108 strcasecmp(p, "local") == 0) 109 { 110 addr.sa.sa_family = AF_UNIX; 111 *socksize = sizeof (struct sockaddr_un); 112 } 113#endif /* NETUNIX */ 114#if NETINET 115 else if (strcasecmp(p, "inet") == 0) 116 { 117 addr.sa.sa_family = AF_INET; 118 *socksize = sizeof addr.sin; 119 } 120#endif /* NETINET */ 121#if NETINET6 122 else if (strcasecmp(p, "inet6") == 0) 123 { 124 addr.sa.sa_family = AF_INET6; 125 *socksize = sizeof addr.sin6; 126 } 127#endif /* NETINET6 */ 128 else 129 { 130 smi_log(SMI_LOG_ERR, "%s: unknown socket type %s", 131 name, p); 132 return INVALID_SOCKET; 133 } 134 *colon++ = ':'; 135 } 136 else 137 { 138 colon = p; 139#if NETUNIX 140 /* default to AF_UNIX */ 141 addr.sa.sa_family = AF_UNIX; 142 *socksize = sizeof (struct sockaddr_un); 143#else /* NETUNIX */ 144# if NETINET 145 /* default to AF_INET */ 146 addr.sa.sa_family = AF_INET; 147 *socksize = sizeof addr.sin; 148# else /* NETINET */ 149# if NETINET6 150 /* default to AF_INET6 */ 151 addr.sa.sa_family = AF_INET6; 152 *socksize = sizeof addr.sin6; 153# else /* NETINET6 */ 154 smi_log(SMI_LOG_ERR, "%s: unknown socket type %s", 155 name, p); 156 return INVALID_SOCKET; 157# endif /* NETINET6 */ 158# endif /* NETINET */ 159#endif /* NETUNIX */ 160 } 161 162#if NETUNIX 163 if (addr.sa.sa_family == AF_UNIX) 164 { 165# if 0 166 long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN; 167# endif /* 0 */ 168 169 at = colon; 170 len = strlen(colon) + 1; 171 if (len >= sizeof addr.sunix.sun_path) 172 { 173 errno = EINVAL; 174 smi_log(SMI_LOG_ERR, "%s: UNIX socket name %s too long", 175 name, colon); 176 return INVALID_SOCKET; 177 } 178 (void) sm_strlcpy(addr.sunix.sun_path, colon, 179 sizeof addr.sunix.sun_path); 180# if 0 181 errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff, 182 S_IRUSR|S_IWUSR, NULL); 183 184 /* if not safe, don't create */ 185 if (errno != 0) 186 { 187 smi_log(SMI_LOG_ERR, 188 "%s: UNIX socket name %s unsafe", 189 name, colon); 190 return INVALID_SOCKET; 191 } 192# endif /* 0 */ 193 } 194#endif /* NETUNIX */ 195 196#if NETINET || NETINET6 197 if ( 198# if NETINET 199 addr.sa.sa_family == AF_INET 200# endif /* NETINET */ 201# if NETINET && NETINET6 202 || 203# endif /* NETINET && NETINET6 */ 204# if NETINET6 205 addr.sa.sa_family == AF_INET6 206# endif /* NETINET6 */ 207 ) 208 { 209 unsigned short port; 210 211 /* Parse port@host */ 212 at = strchr(colon, '@'); 213 if (at == NULL) 214 { 215 switch (addr.sa.sa_family) 216 { 217# if NETINET 218 case AF_INET: 219 addr.sin.sin_addr.s_addr = INADDR_ANY; 220 break; 221# endif /* NETINET */ 222 223# if NETINET6 224 case AF_INET6: 225 addr.sin6.sin6_addr = in6addr_any; 226 break; 227# endif /* NETINET6 */ 228 } 229 } 230 else 231 *at = '\0'; 232 233 if (isascii(*colon) && isdigit(*colon)) 234 port = htons((unsigned short) atoi(colon)); 235 else 236 { 237# ifdef NO_GETSERVBYNAME 238 smi_log(SMI_LOG_ERR, "%s: invalid port number %s", 239 name, colon); 240 return INVALID_SOCKET; 241# else /* NO_GETSERVBYNAME */ 242 register struct servent *sp; 243 244 sp = getservbyname(colon, "tcp"); 245 if (sp == NULL) 246 { 247 smi_log(SMI_LOG_ERR, 248 "%s: unknown port name %s", 249 name, colon); 250 return INVALID_SOCKET; 251 } 252 port = sp->s_port; 253# endif /* NO_GETSERVBYNAME */ 254 } 255 if (at != NULL) 256 { 257 *at++ = '@'; 258 if (*at == '[') 259 { 260 char *end; 261 262 end = strchr(at, ']'); 263 if (end != NULL) 264 { 265 bool found = false; 266# if NETINET 267 unsigned long hid = INADDR_NONE; 268# endif /* NETINET */ 269# if NETINET6 270 struct sockaddr_in6 hid6; 271# endif /* NETINET6 */ 272 273 *end = '\0'; 274# if NETINET 275 if (addr.sa.sa_family == AF_INET && 276 (hid = inet_addr(&at[1])) != INADDR_NONE) 277 { 278 addr.sin.sin_addr.s_addr = hid; 279 addr.sin.sin_port = port; 280 found = true; 281 } 282# endif /* NETINET */ 283# if NETINET6 284 (void) memset(&hid6, '\0', sizeof hid6); 285 if (addr.sa.sa_family == AF_INET6 && 286 mi_inet_pton(AF_INET6, &at[1], 287 &hid6.sin6_addr) == 1) 288 { 289 addr.sin6.sin6_addr = hid6.sin6_addr; 290 addr.sin6.sin6_port = port; 291 found = true; 292 } 293# endif /* NETINET6 */ 294 *end = ']'; 295 if (!found) 296 { 297 smi_log(SMI_LOG_ERR, 298 "%s: Invalid numeric domain spec \"%s\"", 299 name, at); 300 return INVALID_SOCKET; 301 } 302 } 303 else 304 { 305 smi_log(SMI_LOG_ERR, 306 "%s: Invalid numeric domain spec \"%s\"", 307 name, at); 308 return INVALID_SOCKET; 309 } 310 } 311 else 312 { 313 struct hostent *hp = NULL; 314 315 hp = mi_gethostbyname(at, addr.sa.sa_family); 316 if (hp == NULL) 317 { 318 smi_log(SMI_LOG_ERR, 319 "%s: Unknown host name %s", 320 name, at); 321 return INVALID_SOCKET; 322 } 323 addr.sa.sa_family = hp->h_addrtype; 324 switch (hp->h_addrtype) 325 { 326# if NETINET 327 case AF_INET: 328 memmove(&addr.sin.sin_addr, 329 hp->h_addr, 330 INADDRSZ); 331 addr.sin.sin_port = port; 332 break; 333# endif /* NETINET */ 334 335# if NETINET6 336 case AF_INET6: 337 memmove(&addr.sin6.sin6_addr, 338 hp->h_addr, 339 IN6ADDRSZ); 340 addr.sin6.sin6_port = port; 341 break; 342# endif /* NETINET6 */ 343 344 default: 345 smi_log(SMI_LOG_ERR, 346 "%s: Unknown protocol for %s (%d)", 347 name, at, hp->h_addrtype); 348 return INVALID_SOCKET; 349 } 350# if NETINET6 351 freehostent(hp); 352# endif /* NETINET6 */ 353 } 354 } 355 else 356 { 357 switch (addr.sa.sa_family) 358 { 359# if NETINET 360 case AF_INET: 361 addr.sin.sin_port = port; 362 break; 363# endif /* NETINET */ 364# if NETINET6 365 case AF_INET6: 366 addr.sin6.sin6_port = port; 367 break; 368# endif /* NETINET6 */ 369 } 370 } 371 } 372#endif /* NETINET || NETINET6 */ 373 374 sock = socket(addr.sa.sa_family, SOCK_STREAM, 0); 375 if (!ValidSocket(sock)) 376 { 377 smi_log(SMI_LOG_ERR, 378 "%s: Unable to create new socket: %s", 379 name, sm_errstring(errno)); 380 return INVALID_SOCKET; 381 } 382 383 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &sockopt, 384 sizeof(sockopt)) == -1) 385 { 386 smi_log(SMI_LOG_ERR, 387 "%s: Unable to setsockopt: %s", name, 388 sm_errstring(errno)); 389 (void) closesocket(sock); 390 return INVALID_SOCKET; 391 } 392 393 if (bind(sock, &addr.sa, *socksize) < 0) 394 { 395 smi_log(SMI_LOG_ERR, 396 "%s: Unable to bind to port %s: %s", 397 name, conn, sm_errstring(errno)); 398 (void) closesocket(sock); 399 return INVALID_SOCKET; 400 } 401 402 if (listen(sock, backlog) < 0) 403 { 404 smi_log(SMI_LOG_ERR, 405 "%s: listen call failed: %s", name, 406 sm_errstring(errno)); 407 (void) closesocket(sock); 408 return INVALID_SOCKET; 409 } 410 411#if NETUNIX 412 if (addr.sa.sa_family == AF_UNIX && len > 0) 413 { 414 /* 415 ** Set global variable sockpath so the UNIX socket can be 416 ** unlink()ed at exit. 417 */ 418 419 sockpath = (char *) malloc(len); 420 if (sockpath != NULL) 421 (void) sm_strlcpy(sockpath, colon, len); 422 else 423 { 424 smi_log(SMI_LOG_ERR, 425 "%s: can't malloc(%d) for sockpath: %s", 426 name, len, sm_errstring(errno)); 427 (void) closesocket(sock); 428 return INVALID_SOCKET; 429 } 430 } 431#endif /* NETUNIX */ 432 *family = addr.sa.sa_family; 433 return sock; 434} 435/* 436** MI_THREAD_HANDLE_WRAPPER -- small wrapper to handle session 437** 438** Parameters: 439** arg -- argument to pass to mi_handle_session() 440** 441** Returns: 442** results from mi_handle_session() 443*/ 444 445void * 446mi_thread_handle_wrapper(arg) 447 void *arg; 448{ 449 return (void *) mi_handle_session(arg); 450} 451 452static socket_t listenfd = INVALID_SOCKET; 453 454/* 455** MI_CLOSENER -- close listen socket 456** 457** NOTE: It is assumed that this function is called from a 458** function that has a mutex lock (currently mi_stop_milters()). 459** 460** Parameters: 461** none. 462** 463** Returns: 464** none. 465*/ 466 467void 468mi_closener() 469{ 470 (void) smutex_lock(&L_Mutex); 471 if (ValidSocket(listenfd)) 472 { 473#if NETUNIX 474 bool removable; 475 struct stat sockinfo; 476 struct stat fileinfo; 477 478 removable = sockpath != NULL && 479#if _FFR_MILTER_ROOT_UNSAFE 480 geteuid() != 0 && 481#endif /* _FFR_MILTER_ROOT_UNSAFE */ 482 fstat(listenfd, &sockinfo) == 0 && 483 (S_ISFIFO(sockinfo.st_mode) 484# ifdef S_ISSOCK 485 || S_ISSOCK(sockinfo.st_mode) 486# endif /* S_ISSOCK */ 487 ); 488#endif /* NETUNIX */ 489 490 (void) closesocket(listenfd); 491 listenfd = INVALID_SOCKET; 492 493#if NETUNIX 494 /* XXX sleep() some time before doing this? */ 495 if (sockpath != NULL) 496 { 497 if (removable && 498 stat(sockpath, &fileinfo) == 0 && 499 ((fileinfo.st_dev == sockinfo.st_dev && 500 fileinfo.st_ino == sockinfo.st_ino) 501# ifdef S_ISSOCK 502 || S_ISSOCK(fileinfo.st_mode) 503# endif /* S_ISSOCK */ 504 ) 505 && 506 (S_ISFIFO(fileinfo.st_mode) 507# ifdef S_ISSOCK 508 || S_ISSOCK(fileinfo.st_mode) 509# endif /* S_ISSOCK */ 510 )) 511 (void) unlink(sockpath); 512 free(sockpath); 513 sockpath = NULL; 514 } 515#endif /* NETUNIX */ 516 } 517 (void) smutex_unlock(&L_Mutex); 518} 519 520/* 521** MI_LISTENER -- Generic listener harness 522** 523** Open up listen port 524** Wait for connections 525** 526** Parameters: 527** conn -- connection description 528** dbg -- debug level 529** smfi -- filter structure to use 530** timeout -- timeout for reads/writes 531** 532** Returns: 533** MI_SUCCESS -- Exited normally 534** (session finished or we were told to exit) 535** MI_FAILURE -- Network initialization failed. 536*/ 537 538#if BROKEN_PTHREAD_SLEEP 539 540/* 541** Solaris 2.6, perhaps others, gets an internal threads library panic 542** when sleep() is used: 543** 544** thread_create() failed, returned 11 (EINVAL) 545** co_enable, thr_create() returned error = 24 546** libthread panic: co_enable failed (PID: 17793 LWP 1) 547** stacktrace: 548** ef526b10 549** ef52646c 550** ef534cbc 551** 156a4 552** 14644 553** 1413c 554** 135e0 555** 0 556*/ 557 558# define MI_SLEEP(s) \ 559{ \ 560 int rs = 0; \ 561 struct timeval st; \ 562 \ 563 st.tv_sec = (s); \ 564 st.tv_usec = 0; \ 565 if (st.tv_sec > 0) \ 566 rs = select(0, NULL, NULL, NULL, &st); \ 567 if (rs != 0) \ 568 { \ 569 smi_log(SMI_LOG_ERR, \ 570 "MI_SLEEP(): select() returned non-zero result %d, errno = %d", \ 571 rs, errno); \ 572 } \ 573} 574#else /* BROKEN_PTHREAD_SLEEP */ 575# define MI_SLEEP(s) sleep((s)) 576#endif /* BROKEN_PTHREAD_SLEEP */ 577 578int 579mi_listener(conn, dbg, smfi, timeout, backlog) 580 char *conn; 581 int dbg; 582 smfiDesc_ptr smfi; 583 time_t timeout; 584 int backlog; 585{ 586 socket_t connfd = INVALID_SOCKET; 587 int family = AF_UNSPEC; 588 int sockopt = 1; 589 int r; 590 int ret = MI_SUCCESS; 591 int mcnt = 0; /* error count for malloc() failures */ 592 int tcnt = 0; /* error count for thread_create() failures */ 593 int acnt = 0; /* error count for accept() failures */ 594 int scnt = 0; /* error count for select() failures */ 595 int save_errno = 0; 596 sthread_t thread_id; 597 _SOCK_ADDR cliaddr; 598 SOCKADDR_LEN_T socksize; 599 SOCKADDR_LEN_T clilen; 600 SMFICTX_PTR ctx; 601 fd_set readset, excset; 602 struct timeval chktime; 603 604 if (dbg > 0) 605 smi_log(SMI_LOG_DEBUG, 606 "%s: Opening listen socket on conn %s", 607 smfi->xxfi_name, conn); 608 (void) smutex_init(&L_Mutex); 609 (void) smutex_lock(&L_Mutex); 610 listenfd = mi_milteropen(conn, backlog, &socksize, &family, 611 smfi->xxfi_name); 612 if (!ValidSocket(listenfd)) 613 { 614 smi_log(SMI_LOG_FATAL, 615 "%s: Unable to create listening socket on conn %s", 616 smfi->xxfi_name, conn); 617 (void) smutex_unlock(&L_Mutex); 618 return MI_FAILURE; 619 } 620 clilen = socksize; 621 622 if (listenfd >= FD_SETSIZE) 623 { 624 smi_log(SMI_LOG_ERR, "%s: fd %d is larger than FD_SETSIZE %d", 625 smfi->xxfi_name, listenfd, FD_SETSIZE); 626 (void) smutex_unlock(&L_Mutex); 627 return MI_FAILURE; 628 } 629 (void) smutex_unlock(&L_Mutex); 630 631 while (mi_stop() == MILTER_CONT) 632 { 633 (void) smutex_lock(&L_Mutex); 634 if (!ValidSocket(listenfd)) 635 { 636 (void) smutex_unlock(&L_Mutex); 637 break; 638 } 639 640 /* select on interface ports */ 641 FD_ZERO(&readset); 642 FD_ZERO(&excset); 643 FD_SET((unsigned int) listenfd, &readset); 644 FD_SET((unsigned int) listenfd, &excset); 645 chktime.tv_sec = MI_CHK_TIME; 646 chktime.tv_usec = 0; 647 r = select(listenfd + 1, &readset, NULL, &excset, &chktime); 648 if (r == 0) /* timeout */ 649 { 650 (void) smutex_unlock(&L_Mutex); 651 continue; /* just check mi_stop() */ 652 } 653 if (r < 0) 654 { 655 save_errno = errno; 656 (void) smutex_unlock(&L_Mutex); 657 if (save_errno == EINTR) 658 continue; 659 scnt++; 660 smi_log(SMI_LOG_ERR, 661 "%s: select() failed (%s), %s", 662 smfi->xxfi_name, sm_errstring(save_errno), 663 scnt >= MAX_FAILS_S ? "abort" : "try again"); 664 MI_SLEEP(scnt); 665 if (scnt >= MAX_FAILS_S) 666 { 667 ret = MI_FAILURE; 668 break; 669 } 670 continue; 671 } 672 if (!FD_ISSET(listenfd, &readset)) 673 { 674 /* some error: just stop for now... */ 675 ret = MI_FAILURE; 676 (void) smutex_unlock(&L_Mutex); 677 smi_log(SMI_LOG_ERR, 678 "%s: select() returned exception for socket, abort", 679 smfi->xxfi_name); 680 break; 681 } 682 scnt = 0; /* reset error counter for select() */ 683 684 memset(&cliaddr, '\0', sizeof cliaddr); 685 connfd = accept(listenfd, (struct sockaddr *) &cliaddr, 686 &clilen); 687 save_errno = errno; 688 (void) smutex_unlock(&L_Mutex); 689 690 /* 691 ** If remote side closes before 692 ** accept() finishes, sockaddr 693 ** might not be fully filled in. 694 */ 695 696 if (ValidSocket(connfd) && 697 (clilen == 0 || 698# ifdef BSD4_4_SOCKADDR 699 cliaddr.sa.sa_len == 0 || 700# endif /* BSD4_4_SOCKADDR */ 701 cliaddr.sa.sa_family != family)) 702 { 703 (void) closesocket(connfd); 704 connfd = INVALID_SOCKET; 705 save_errno = EINVAL; 706 } 707 708 if (!ValidSocket(connfd)) 709 { 710 if (save_errno == EINTR) 711 continue; 712 acnt++; 713 smi_log(SMI_LOG_ERR, 714 "%s: accept() returned invalid socket (%s), %s", 715 smfi->xxfi_name, sm_errstring(save_errno), 716 acnt >= MAX_FAILS_A ? "abort" : "try again"); 717 MI_SLEEP(acnt); 718 if (acnt >= MAX_FAILS_A) 719 { 720 ret = MI_FAILURE; 721 break; 722 } 723 continue; 724 } 725 acnt = 0; /* reset error counter for accept() */ 726 727 if (setsockopt(connfd, SOL_SOCKET, SO_KEEPALIVE, 728 (void *) &sockopt, sizeof sockopt) < 0) 729 { 730 smi_log(SMI_LOG_WARN, "%s: setsockopt() failed (%s)", 731 smfi->xxfi_name, sm_errstring(errno)); 732 /* XXX: continue? */ 733 } 734 if ((ctx = (SMFICTX_PTR) malloc(sizeof *ctx)) == NULL) 735 { 736 (void) closesocket(connfd); 737 mcnt++; 738 smi_log(SMI_LOG_ERR, "%s: malloc(ctx) failed (%s), %s", 739 smfi->xxfi_name, sm_errstring(save_errno), 740 mcnt >= MAX_FAILS_M ? "abort" : "try again"); 741 MI_SLEEP(mcnt); 742 if (mcnt >= MAX_FAILS_M) 743 { 744 ret = MI_FAILURE; 745 break; 746 } 747 continue; 748 } 749 mcnt = 0; /* reset error counter for malloc() */ 750 memset(ctx, '\0', sizeof *ctx); 751 ctx->ctx_sd = connfd; 752 ctx->ctx_dbg = dbg; 753 ctx->ctx_timeout = timeout; 754 ctx->ctx_smfi = smfi; 755#if 0 756 if (smfi->xxfi_eoh == NULL) 757 if (smfi->xxfi_eom == NULL) 758 if (smfi->xxfi_abort == NULL) 759 if (smfi->xxfi_close == NULL) 760#endif /* 0 */ 761 if (smfi->xxfi_connect == NULL) 762 ctx->ctx_pflags |= SMFIP_NOCONNECT; 763 if (smfi->xxfi_helo == NULL) 764 ctx->ctx_pflags |= SMFIP_NOHELO; 765 if (smfi->xxfi_envfrom == NULL) 766 ctx->ctx_pflags |= SMFIP_NOMAIL; 767 if (smfi->xxfi_envrcpt == NULL) 768 ctx->ctx_pflags |= SMFIP_NORCPT; 769 if (smfi->xxfi_header == NULL) 770 ctx->ctx_pflags |= SMFIP_NOHDRS; 771 if (smfi->xxfi_eoh == NULL) 772 ctx->ctx_pflags |= SMFIP_NOEOH; 773 if (smfi->xxfi_body == NULL) 774 ctx->ctx_pflags |= SMFIP_NOBODY; 775 776 if ((r = thread_create(&thread_id, 777 mi_thread_handle_wrapper, 778 (void *) ctx)) != 0) 779 { 780 tcnt++; 781 smi_log(SMI_LOG_ERR, 782 "%s: thread_create() failed: %d, %s", 783 smfi->xxfi_name, r, 784 tcnt >= MAX_FAILS_T ? "abort" : "try again"); 785 MI_SLEEP(tcnt); 786 (void) closesocket(connfd); 787 free(ctx); 788 if (tcnt >= MAX_FAILS_T) 789 { 790 ret = MI_FAILURE; 791 break; 792 } 793 continue; 794 } 795 tcnt = 0; 796 } 797 if (ret != MI_SUCCESS) 798 mi_stop_milters(MILTER_ABRT); 799 else 800 mi_closener(); 801 (void) smutex_destroy(&L_Mutex); 802 return ret; 803} 804