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