Import sendmail 8.13.7
[dragonfly.git] / contrib / sendmail-8.13.7 / libmilter / listener.c
blob4429edfbfbda58add17b58836dd5e11f65cf448a
1 /*
2 * Copyright (c) 1999-2006 Sendmail, Inc. and its suppliers.
3 * All rights reserved.
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.
9 */
11 #include <sm/gen.h>
12 SM_RCSID("@(#)$Id: listener.c,v 8.115 2006/01/24 00:48:39 ca Exp $")
15 ** listener.c -- threaded network listener
18 #include "libmilter.h"
19 #include <sm/errstring.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
25 # if NETINET || NETINET6
26 # include <arpa/inet.h>
27 # endif /* NETINET || NETINET6 */
29 static smutex_t L_Mutex;
30 static int L_family;
31 static SOCKADDR_LEN_T L_socksize;
32 static socket_t listenfd = INVALID_SOCKET;
34 static socket_t mi_milteropen __P((char *, int, bool, char *));
35 static void *mi_thread_handle_wrapper __P((void *));
38 ** MI_OPENSOCKET -- create the socket where this filter and the MTA will meet
40 ** Parameters:
41 ** conn -- connection description
42 ** backlog -- listen backlog
43 ** dbg -- debug level
44 ** rmsocket -- if true, try to unlink() the socket first
45 ** (UNIX domain sockets only)
46 ** smfi -- filter structure to use
48 ** Return value:
49 ** MI_SUCCESS/MI_FAILURE
52 int
53 mi_opensocket(conn, backlog, dbg, rmsocket, smfi)
54 char *conn;
55 int backlog;
56 int dbg;
57 bool rmsocket;
58 smfiDesc_ptr smfi;
60 if (smfi == NULL || conn == NULL)
61 return MI_FAILURE;
63 if (ValidSocket(listenfd))
64 return MI_SUCCESS;
66 if (dbg > 0)
68 smi_log(SMI_LOG_DEBUG,
69 "%s: Opening listen socket on conn %s",
70 smfi->xxfi_name, conn);
72 (void) smutex_init(&L_Mutex);
73 (void) smutex_lock(&L_Mutex);
74 listenfd = mi_milteropen(conn, backlog, rmsocket, smfi->xxfi_name);
75 if (!ValidSocket(listenfd))
77 smi_log(SMI_LOG_FATAL,
78 "%s: Unable to create listening socket on conn %s",
79 smfi->xxfi_name, conn);
80 (void) smutex_unlock(&L_Mutex);
81 return MI_FAILURE;
83 #if !SM_CONF_POLL
84 if (!SM_FD_OK_SELECT(listenfd))
86 smi_log(SMI_LOG_ERR, "%s: fd %d is larger than FD_SETSIZE %d",
87 smfi->xxfi_name, listenfd, FD_SETSIZE);
88 (void) smutex_unlock(&L_Mutex);
89 return MI_FAILURE;
91 #endif /* !SM_CONF_POLL */
92 (void) smutex_unlock(&L_Mutex);
93 return MI_SUCCESS;
97 ** MI_MILTEROPEN -- setup socket to listen on
99 ** Parameters:
100 ** conn -- connection description
101 ** backlog -- listen backlog
102 ** rmsocket -- if true, try to unlink() the socket first
103 ** (UNIX domain sockets only)
104 ** name -- name for logging
106 ** Returns:
107 ** socket upon success, error code otherwise.
109 ** Side effect:
110 ** sets sockpath if UNIX socket.
113 #if NETUNIX
114 static char *sockpath = NULL;
115 #endif /* NETUNIX */
117 static socket_t
118 mi_milteropen(conn, backlog, rmsocket, name)
119 char *conn;
120 int backlog;
121 bool rmsocket;
122 char *name;
124 socket_t sock;
125 int sockopt = 1;
126 int fdflags;
127 size_t len = 0;
128 char *p;
129 char *colon;
130 char *at;
131 SOCKADDR addr;
133 if (conn == NULL || conn[0] == '\0')
135 smi_log(SMI_LOG_ERR, "%s: empty or missing socket information",
136 name);
137 return INVALID_SOCKET;
139 (void) memset(&addr, '\0', sizeof addr);
141 /* protocol:filename or protocol:port@host */
142 p = conn;
143 colon = strchr(p, ':');
144 if (colon != NULL)
146 *colon = '\0';
148 if (*p == '\0')
150 #if NETUNIX
151 /* default to AF_UNIX */
152 addr.sa.sa_family = AF_UNIX;
153 L_socksize = sizeof (struct sockaddr_un);
154 #else /* NETUNIX */
155 # if NETINET
156 /* default to AF_INET */
157 addr.sa.sa_family = AF_INET;
158 L_socksize = sizeof addr.sin;
159 # else /* NETINET */
160 # if NETINET6
161 /* default to AF_INET6 */
162 addr.sa.sa_family = AF_INET6;
163 L_socksize = sizeof addr.sin6;
164 # else /* NETINET6 */
165 /* no protocols available */
166 smi_log(SMI_LOG_ERR,
167 "%s: no valid socket protocols available",
168 name);
169 return INVALID_SOCKET;
170 # endif /* NETINET6 */
171 # endif /* NETINET */
172 #endif /* NETUNIX */
174 #if NETUNIX
175 else if (strcasecmp(p, "unix") == 0 ||
176 strcasecmp(p, "local") == 0)
178 addr.sa.sa_family = AF_UNIX;
179 L_socksize = sizeof (struct sockaddr_un);
181 #endif /* NETUNIX */
182 #if NETINET
183 else if (strcasecmp(p, "inet") == 0)
185 addr.sa.sa_family = AF_INET;
186 L_socksize = sizeof addr.sin;
188 #endif /* NETINET */
189 #if NETINET6
190 else if (strcasecmp(p, "inet6") == 0)
192 addr.sa.sa_family = AF_INET6;
193 L_socksize = sizeof addr.sin6;
195 #endif /* NETINET6 */
196 else
198 smi_log(SMI_LOG_ERR, "%s: unknown socket type %s",
199 name, p);
200 return INVALID_SOCKET;
202 *colon++ = ':';
204 else
206 colon = p;
207 #if NETUNIX
208 /* default to AF_UNIX */
209 addr.sa.sa_family = AF_UNIX;
210 L_socksize = sizeof (struct sockaddr_un);
211 #else /* NETUNIX */
212 # if NETINET
213 /* default to AF_INET */
214 addr.sa.sa_family = AF_INET;
215 L_socksize = sizeof addr.sin;
216 # else /* NETINET */
217 # if NETINET6
218 /* default to AF_INET6 */
219 addr.sa.sa_family = AF_INET6;
220 L_socksize = sizeof addr.sin6;
221 # else /* NETINET6 */
222 smi_log(SMI_LOG_ERR, "%s: unknown socket type %s",
223 name, p);
224 return INVALID_SOCKET;
225 # endif /* NETINET6 */
226 # endif /* NETINET */
227 #endif /* NETUNIX */
230 #if NETUNIX
231 if (addr.sa.sa_family == AF_UNIX)
233 # if 0
234 long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN;
235 # endif /* 0 */
237 at = colon;
238 len = strlen(colon) + 1;
239 if (len >= sizeof addr.sunix.sun_path)
241 errno = EINVAL;
242 smi_log(SMI_LOG_ERR, "%s: UNIX socket name %s too long",
243 name, colon);
244 return INVALID_SOCKET;
246 (void) sm_strlcpy(addr.sunix.sun_path, colon,
247 sizeof addr.sunix.sun_path);
248 # if 0
249 errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff,
250 S_IRUSR|S_IWUSR, NULL);
252 /* if not safe, don't create */
253 if (errno != 0)
255 smi_log(SMI_LOG_ERR,
256 "%s: UNIX socket name %s unsafe",
257 name, colon);
258 return INVALID_SOCKET;
260 # endif /* 0 */
262 #endif /* NETUNIX */
264 #if NETINET || NETINET6
265 if (
266 # if NETINET
267 addr.sa.sa_family == AF_INET
268 # endif /* NETINET */
269 # if NETINET && NETINET6
271 # endif /* NETINET && NETINET6 */
272 # if NETINET6
273 addr.sa.sa_family == AF_INET6
274 # endif /* NETINET6 */
277 unsigned short port;
279 /* Parse port@host */
280 at = strchr(colon, '@');
281 if (at == NULL)
283 switch (addr.sa.sa_family)
285 # if NETINET
286 case AF_INET:
287 addr.sin.sin_addr.s_addr = INADDR_ANY;
288 break;
289 # endif /* NETINET */
291 # if NETINET6
292 case AF_INET6:
293 addr.sin6.sin6_addr = in6addr_any;
294 break;
295 # endif /* NETINET6 */
298 else
299 *at = '\0';
301 if (isascii(*colon) && isdigit(*colon))
302 port = htons((unsigned short) atoi(colon));
303 else
305 # ifdef NO_GETSERVBYNAME
306 smi_log(SMI_LOG_ERR, "%s: invalid port number %s",
307 name, colon);
308 return INVALID_SOCKET;
309 # else /* NO_GETSERVBYNAME */
310 register struct servent *sp;
312 sp = getservbyname(colon, "tcp");
313 if (sp == NULL)
315 smi_log(SMI_LOG_ERR,
316 "%s: unknown port name %s",
317 name, colon);
318 return INVALID_SOCKET;
320 port = sp->s_port;
321 # endif /* NO_GETSERVBYNAME */
323 if (at != NULL)
325 *at++ = '@';
326 if (*at == '[')
328 char *end;
330 end = strchr(at, ']');
331 if (end != NULL)
333 bool found = false;
334 # if NETINET
335 unsigned long hid = INADDR_NONE;
336 # endif /* NETINET */
337 # if NETINET6
338 struct sockaddr_in6 hid6;
339 # endif /* NETINET6 */
341 *end = '\0';
342 # if NETINET
343 if (addr.sa.sa_family == AF_INET &&
344 (hid = inet_addr(&at[1])) != INADDR_NONE)
346 addr.sin.sin_addr.s_addr = hid;
347 addr.sin.sin_port = port;
348 found = true;
350 # endif /* NETINET */
351 # if NETINET6
352 (void) memset(&hid6, '\0', sizeof hid6);
353 if (addr.sa.sa_family == AF_INET6 &&
354 mi_inet_pton(AF_INET6, &at[1],
355 &hid6.sin6_addr) == 1)
357 addr.sin6.sin6_addr = hid6.sin6_addr;
358 addr.sin6.sin6_port = port;
359 found = true;
361 # endif /* NETINET6 */
362 *end = ']';
363 if (!found)
365 smi_log(SMI_LOG_ERR,
366 "%s: Invalid numeric domain spec \"%s\"",
367 name, at);
368 return INVALID_SOCKET;
371 else
373 smi_log(SMI_LOG_ERR,
374 "%s: Invalid numeric domain spec \"%s\"",
375 name, at);
376 return INVALID_SOCKET;
379 else
381 struct hostent *hp = NULL;
383 hp = mi_gethostbyname(at, addr.sa.sa_family);
384 if (hp == NULL)
386 smi_log(SMI_LOG_ERR,
387 "%s: Unknown host name %s",
388 name, at);
389 return INVALID_SOCKET;
391 addr.sa.sa_family = hp->h_addrtype;
392 switch (hp->h_addrtype)
394 # if NETINET
395 case AF_INET:
396 (void) memmove(&addr.sin.sin_addr,
397 hp->h_addr,
398 INADDRSZ);
399 addr.sin.sin_port = port;
400 break;
401 # endif /* NETINET */
403 # if NETINET6
404 case AF_INET6:
405 (void) memmove(&addr.sin6.sin6_addr,
406 hp->h_addr,
407 IN6ADDRSZ);
408 addr.sin6.sin6_port = port;
409 break;
410 # endif /* NETINET6 */
412 default:
413 smi_log(SMI_LOG_ERR,
414 "%s: Unknown protocol for %s (%d)",
415 name, at, hp->h_addrtype);
416 return INVALID_SOCKET;
418 # if NETINET6
419 freehostent(hp);
420 # endif /* NETINET6 */
423 else
425 switch (addr.sa.sa_family)
427 # if NETINET
428 case AF_INET:
429 addr.sin.sin_port = port;
430 break;
431 # endif /* NETINET */
432 # if NETINET6
433 case AF_INET6:
434 addr.sin6.sin6_port = port;
435 break;
436 # endif /* NETINET6 */
440 #endif /* NETINET || NETINET6 */
442 sock = socket(addr.sa.sa_family, SOCK_STREAM, 0);
443 if (!ValidSocket(sock))
445 smi_log(SMI_LOG_ERR,
446 "%s: Unable to create new socket: %s",
447 name, sm_errstring(errno));
448 return INVALID_SOCKET;
451 if ((fdflags = fcntl(sock, F_GETFD, 0)) == -1 ||
452 fcntl(sock, F_SETFD, fdflags | FD_CLOEXEC) == -1)
454 smi_log(SMI_LOG_ERR,
455 "%s: Unable to set close-on-exec: %s", name,
456 sm_errstring(errno));
457 (void) closesocket(sock);
458 return INVALID_SOCKET;
461 if (
462 #if NETUNIX
463 addr.sa.sa_family != AF_UNIX &&
464 #endif /* NETUNIX */
465 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &sockopt,
466 sizeof(sockopt)) == -1)
468 smi_log(SMI_LOG_ERR,
469 "%s: set reuseaddr failed (%s)", name,
470 sm_errstring(errno));
471 (void) closesocket(sock);
472 return INVALID_SOCKET;
475 #if NETUNIX
476 if (addr.sa.sa_family == AF_UNIX && rmsocket)
478 struct stat s;
480 if (stat(colon, &s) != 0)
482 if (errno != ENOENT)
484 smi_log(SMI_LOG_ERR,
485 "%s: Unable to stat() %s: %s",
486 name, colon, sm_errstring(errno));
487 (void) closesocket(sock);
488 return INVALID_SOCKET;
491 else if (!S_ISSOCK(s.st_mode))
493 smi_log(SMI_LOG_ERR,
494 "%s: %s is not a UNIX domain socket",
495 name, colon);
496 (void) closesocket(sock);
497 return INVALID_SOCKET;
499 else if (unlink(colon) != 0)
501 smi_log(SMI_LOG_ERR,
502 "%s: Unable to remove %s: %s",
503 name, colon, sm_errstring(errno));
504 (void) closesocket(sock);
505 return INVALID_SOCKET;
508 #endif /* NETUNIX */
510 if (bind(sock, &addr.sa, L_socksize) < 0)
512 smi_log(SMI_LOG_ERR,
513 "%s: Unable to bind to port %s: %s",
514 name, conn, sm_errstring(errno));
515 (void) closesocket(sock);
516 return INVALID_SOCKET;
519 if (listen(sock, backlog) < 0)
521 smi_log(SMI_LOG_ERR,
522 "%s: listen call failed: %s", name,
523 sm_errstring(errno));
524 (void) closesocket(sock);
525 return INVALID_SOCKET;
528 #if NETUNIX
529 if (addr.sa.sa_family == AF_UNIX && len > 0)
532 ** Set global variable sockpath so the UNIX socket can be
533 ** unlink()ed at exit.
536 sockpath = (char *) malloc(len);
537 if (sockpath != NULL)
538 (void) sm_strlcpy(sockpath, colon, len);
539 else
541 smi_log(SMI_LOG_ERR,
542 "%s: can't malloc(%d) for sockpath: %s",
543 name, (int) len, sm_errstring(errno));
544 (void) closesocket(sock);
545 return INVALID_SOCKET;
548 #endif /* NETUNIX */
549 L_family = addr.sa.sa_family;
550 return sock;
553 ** MI_THREAD_HANDLE_WRAPPER -- small wrapper to handle session
555 ** Parameters:
556 ** arg -- argument to pass to mi_handle_session()
558 ** Returns:
559 ** results from mi_handle_session()
562 static void *
563 mi_thread_handle_wrapper(arg)
564 void *arg;
566 return (void *) mi_handle_session(arg);
570 ** MI_CLOSENER -- close listen socket
572 ** Parameters:
573 ** none.
575 ** Returns:
576 ** none.
579 void
580 mi_closener()
582 (void) smutex_lock(&L_Mutex);
583 if (ValidSocket(listenfd))
585 #if NETUNIX
586 bool removable;
587 struct stat sockinfo;
588 struct stat fileinfo;
590 removable = sockpath != NULL &&
591 geteuid() != 0 &&
592 fstat(listenfd, &sockinfo) == 0 &&
593 (S_ISFIFO(sockinfo.st_mode)
594 # ifdef S_ISSOCK
595 || S_ISSOCK(sockinfo.st_mode)
596 # endif /* S_ISSOCK */
598 #endif /* NETUNIX */
600 (void) closesocket(listenfd);
601 listenfd = INVALID_SOCKET;
603 #if NETUNIX
604 /* XXX sleep() some time before doing this? */
605 if (sockpath != NULL)
607 if (removable &&
608 stat(sockpath, &fileinfo) == 0 &&
609 ((fileinfo.st_dev == sockinfo.st_dev &&
610 fileinfo.st_ino == sockinfo.st_ino)
611 # ifdef S_ISSOCK
612 || S_ISSOCK(fileinfo.st_mode)
613 # endif /* S_ISSOCK */
616 (S_ISFIFO(fileinfo.st_mode)
617 # ifdef S_ISSOCK
618 || S_ISSOCK(fileinfo.st_mode)
619 # endif /* S_ISSOCK */
621 (void) unlink(sockpath);
622 free(sockpath);
623 sockpath = NULL;
625 #endif /* NETUNIX */
627 (void) smutex_unlock(&L_Mutex);
631 ** MI_LISTENER -- Generic listener harness
633 ** Open up listen port
634 ** Wait for connections
636 ** Parameters:
637 ** conn -- connection description
638 ** dbg -- debug level
639 ** smfi -- filter structure to use
640 ** timeout -- timeout for reads/writes
641 ** backlog -- listen queue backlog size
643 ** Returns:
644 ** MI_SUCCESS -- Exited normally
645 ** (session finished or we were told to exit)
646 ** MI_FAILURE -- Network initialization failed.
649 #if BROKEN_PTHREAD_SLEEP
652 ** Solaris 2.6, perhaps others, gets an internal threads library panic
653 ** when sleep() is used:
655 ** thread_create() failed, returned 11 (EINVAL)
656 ** co_enable, thr_create() returned error = 24
657 ** libthread panic: co_enable failed (PID: 17793 LWP 1)
658 ** stacktrace:
659 ** ef526b10
660 ** ef52646c
661 ** ef534cbc
662 ** 156a4
663 ** 14644
664 ** 1413c
665 ** 135e0
666 ** 0
669 # define MI_SLEEP(s) \
671 int rs = 0; \
672 struct timeval st; \
674 st.tv_sec = (s); \
675 st.tv_usec = 0; \
676 if (st.tv_sec > 0) \
678 for (;;) \
680 rs = select(0, NULL, NULL, NULL, &st); \
681 if (rs < 0 && errno == EINTR) \
682 continue; \
683 if (rs != 0) \
685 smi_log(SMI_LOG_ERR, \
686 "MI_SLEEP(): select() returned non-zero result %d, errno = %d", \
687 rs, errno); \
689 break; \
693 #else /* BROKEN_PTHREAD_SLEEP */
694 # define MI_SLEEP(s) sleep((s))
695 #endif /* BROKEN_PTHREAD_SLEEP */
698 mi_listener(conn, dbg, smfi, timeout, backlog)
699 char *conn;
700 int dbg;
701 smfiDesc_ptr smfi;
702 time_t timeout;
703 int backlog;
705 socket_t connfd = INVALID_SOCKET;
706 #if _FFR_DUP_FD
707 socket_t dupfd = INVALID_SOCKET;
708 #endif /* _FFR_DUP_FD */
709 int sockopt = 1;
710 int r, mistop;
711 int ret = MI_SUCCESS;
712 int mcnt = 0; /* error count for malloc() failures */
713 int tcnt = 0; /* error count for thread_create() failures */
714 int acnt = 0; /* error count for accept() failures */
715 int scnt = 0; /* error count for select() failures */
716 int save_errno = 0;
717 sthread_t thread_id;
718 _SOCK_ADDR cliaddr;
719 SOCKADDR_LEN_T clilen;
720 SMFICTX_PTR ctx;
721 FD_RD_VAR(rds, excs);
722 struct timeval chktime;
724 if (mi_opensocket(conn, backlog, dbg, false, smfi) == MI_FAILURE)
725 return MI_FAILURE;
727 clilen = L_socksize;
728 while ((mistop = mi_stop()) == MILTER_CONT)
730 (void) smutex_lock(&L_Mutex);
731 if (!ValidSocket(listenfd))
733 ret = MI_FAILURE;
734 smi_log(SMI_LOG_ERR,
735 "%s: listenfd=%d corrupted, terminating, errno=%d",
736 smfi->xxfi_name, listenfd, errno);
737 (void) smutex_unlock(&L_Mutex);
738 break;
741 /* select on interface ports */
742 FD_RD_INIT(listenfd, rds, excs);
743 chktime.tv_sec = MI_CHK_TIME;
744 chktime.tv_usec = 0;
745 r = FD_RD_READY(listenfd, rds, excs, &chktime);
746 if (r == 0) /* timeout */
748 (void) smutex_unlock(&L_Mutex);
749 continue; /* just check mi_stop() */
751 if (r < 0)
753 save_errno = errno;
754 (void) smutex_unlock(&L_Mutex);
755 if (save_errno == EINTR)
756 continue;
757 scnt++;
758 smi_log(SMI_LOG_ERR,
759 "%s: select() failed (%s), %s",
760 smfi->xxfi_name, sm_errstring(save_errno),
761 scnt >= MAX_FAILS_S ? "abort" : "try again");
762 MI_SLEEP(scnt);
763 if (scnt >= MAX_FAILS_S)
765 ret = MI_FAILURE;
766 break;
768 continue;
770 if (!FD_IS_RD_RDY(listenfd, rds, excs))
772 /* some error: just stop for now... */
773 ret = MI_FAILURE;
774 (void) smutex_unlock(&L_Mutex);
775 smi_log(SMI_LOG_ERR,
776 "%s: %s() returned exception for socket, abort",
777 smfi->xxfi_name, MI_POLLSELECT);
778 break;
780 scnt = 0; /* reset error counter for select() */
782 (void) memset(&cliaddr, '\0', sizeof cliaddr);
783 connfd = accept(listenfd, (struct sockaddr *) &cliaddr,
784 &clilen);
785 save_errno = errno;
786 (void) smutex_unlock(&L_Mutex);
789 ** If remote side closes before
790 ** accept() finishes, sockaddr
791 ** might not be fully filled in.
794 if (ValidSocket(connfd) &&
795 (clilen == 0 ||
796 # ifdef BSD4_4_SOCKADDR
797 cliaddr.sa.sa_len == 0 ||
798 # endif /* BSD4_4_SOCKADDR */
799 cliaddr.sa.sa_family != L_family))
801 (void) closesocket(connfd);
802 connfd = INVALID_SOCKET;
803 save_errno = EINVAL;
806 #if !SM_CONF_POLL
807 /* check if acceptable for select() */
808 if (ValidSocket(connfd) && !SM_FD_OK_SELECT(connfd))
810 (void) closesocket(connfd);
811 connfd = INVALID_SOCKET;
812 save_errno = ERANGE;
814 #endif /* !SM_CONF_POLL */
816 if (!ValidSocket(connfd))
818 if (save_errno == EINTR
819 #ifdef EAGAIN
820 || save_errno == EAGAIN
821 #endif /* EAGAIN */
822 #ifdef ECONNABORTED
823 || save_errno == ECONNABORTED
824 #endif /* ECONNABORTED */
825 #ifdef EMFILE
826 || save_errno == EMFILE
827 #endif /* EMFILE */
828 #ifdef ENFILE
829 || save_errno == ENFILE
830 #endif /* ENFILE */
831 #ifdef ENOBUFS
832 || save_errno == ENOBUFS
833 #endif /* ENOBUFS */
834 #ifdef ENOMEM
835 || save_errno == ENOMEM
836 #endif /* ENOMEM */
837 #ifdef ENOSR
838 || save_errno == ENOSR
839 #endif /* ENOSR */
840 #ifdef EWOULDBLOCK
841 || save_errno == EWOULDBLOCK
842 #endif /* EWOULDBLOCK */
844 continue;
845 acnt++;
846 smi_log(SMI_LOG_ERR,
847 "%s: accept() returned invalid socket (%s), %s",
848 smfi->xxfi_name, sm_errstring(save_errno),
849 acnt >= MAX_FAILS_A ? "abort" : "try again");
850 MI_SLEEP(acnt);
851 if (acnt >= MAX_FAILS_A)
853 ret = MI_FAILURE;
854 break;
856 continue;
858 acnt = 0; /* reset error counter for accept() */
859 #if _FFR_DUP_FD
860 dupfd = fcntl(connfd, F_DUPFD, 256);
861 if (ValidSocket(dupfd)
862 # if !SM_CONF_POLL
863 && SM_FD_OK_SELECT(dupfd)
864 # endif /* !SM_CONF_POLL */
867 close(connfd);
868 connfd = dupfd;
869 dupfd = INVALID_SOCKET;
871 #endif /* _FFR_DUP_FD */
873 if (setsockopt(connfd, SOL_SOCKET, SO_KEEPALIVE,
874 (void *) &sockopt, sizeof sockopt) < 0)
876 smi_log(SMI_LOG_WARN,
877 "%s: set keepalive failed (%s)",
878 smfi->xxfi_name, sm_errstring(errno));
879 /* XXX: continue? */
881 if ((ctx = (SMFICTX_PTR) malloc(sizeof *ctx)) == NULL)
883 (void) closesocket(connfd);
884 mcnt++;
885 smi_log(SMI_LOG_ERR, "%s: malloc(ctx) failed (%s), %s",
886 smfi->xxfi_name, sm_errstring(save_errno),
887 mcnt >= MAX_FAILS_M ? "abort" : "try again");
888 MI_SLEEP(mcnt);
889 if (mcnt >= MAX_FAILS_M)
891 ret = MI_FAILURE;
892 break;
894 continue;
896 mcnt = 0; /* reset error counter for malloc() */
897 (void) memset(ctx, '\0', sizeof *ctx);
898 ctx->ctx_sd = connfd;
899 ctx->ctx_dbg = dbg;
900 ctx->ctx_timeout = timeout;
901 ctx->ctx_smfi = smfi;
902 #if 0
903 if (smfi->xxfi_eoh == NULL)
904 if (smfi->xxfi_eom == NULL)
905 if (smfi->xxfi_abort == NULL)
906 if (smfi->xxfi_close == NULL)
907 #endif /* 0 */
908 if (smfi->xxfi_connect == NULL)
909 ctx->ctx_pflags |= SMFIP_NOCONNECT;
910 if (smfi->xxfi_helo == NULL)
911 ctx->ctx_pflags |= SMFIP_NOHELO;
912 if (smfi->xxfi_envfrom == NULL)
913 ctx->ctx_pflags |= SMFIP_NOMAIL;
914 if (smfi->xxfi_envrcpt == NULL)
915 ctx->ctx_pflags |= SMFIP_NORCPT;
916 if (smfi->xxfi_header == NULL)
917 ctx->ctx_pflags |= SMFIP_NOHDRS;
918 if (smfi->xxfi_eoh == NULL)
919 ctx->ctx_pflags |= SMFIP_NOEOH;
920 if (smfi->xxfi_body == NULL)
921 ctx->ctx_pflags |= SMFIP_NOBODY;
923 if ((r = thread_create(&thread_id,
924 mi_thread_handle_wrapper,
925 (void *) ctx)) != 0)
927 tcnt++;
928 smi_log(SMI_LOG_ERR,
929 "%s: thread_create() failed: %d, %s",
930 smfi->xxfi_name, r,
931 tcnt >= MAX_FAILS_T ? "abort" : "try again");
932 MI_SLEEP(tcnt);
933 (void) closesocket(connfd);
934 free(ctx);
935 if (tcnt >= MAX_FAILS_T)
937 ret = MI_FAILURE;
938 break;
940 continue;
942 tcnt = 0;
944 if (ret != MI_SUCCESS)
945 mi_stop_milters(MILTER_ABRT);
946 else
948 if (mistop != MILTER_CONT)
949 smi_log(SMI_LOG_INFO, "%s: mi_stop=%d",
950 smfi->xxfi_name, mistop);
951 mi_closener();
953 (void) smutex_destroy(&L_Mutex);
954 return ret;