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