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