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