listener.c revision 66494
164562Sgshapiro/* 264562Sgshapiro * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers. 364562Sgshapiro * All rights reserved. 464562Sgshapiro * 564562Sgshapiro * By using this file, you agree to the terms and conditions set 664562Sgshapiro * forth in the LICENSE file which can be found at the top level of 764562Sgshapiro * the sendmail distribution. 864562Sgshapiro * 964562Sgshapiro */ 1064562Sgshapiro 1164562Sgshapiro#ifndef lint 1266494Sgshapirostatic char id[] = "@(#)$Id: listener.c,v 8.38.2.1.2.11 2000/09/01 00:49:04 ca Exp $"; 1364562Sgshapiro#endif /* ! lint */ 1464562Sgshapiro 1564562Sgshapiro#if _FFR_MILTER 1664562Sgshapiro/* 1764562Sgshapiro** listener.c -- threaded network listener 1864562Sgshapiro*/ 1964562Sgshapiro 2064562Sgshapiro#include "libmilter.h" 2164562Sgshapiro 2264562Sgshapiro 2364562Sgshapiro# if NETINET || NETINET6 2464562Sgshapiro# include <arpa/inet.h> 2564562Sgshapiro# endif /* NETINET || NETINET6 */ 2664562Sgshapiro/* 2764562Sgshapiro** MI_MILTEROPEN -- setup socket to listen on 2864562Sgshapiro** 2964562Sgshapiro** Parameters: 3064562Sgshapiro** conn -- connection description 3164562Sgshapiro** backlog -- listen backlog 3264562Sgshapiro** socksize -- socksize of created socket 3364562Sgshapiro** 3464562Sgshapiro** Returns: 3564562Sgshapiro** socket upon success, error code otherwise. 3664562Sgshapiro*/ 3764562Sgshapiro 3866494Sgshapirostatic socket_t 3964562Sgshapiromi_milteropen(conn, backlog, socksize, name) 4064562Sgshapiro char *conn; 4164562Sgshapiro int backlog; 4264562Sgshapiro SOCKADDR_LEN_T *socksize; 4364562Sgshapiro char *name; 4464562Sgshapiro{ 4566494Sgshapiro socket_t sock; 4664562Sgshapiro int sockopt = 1; 4764562Sgshapiro char *p; 4864562Sgshapiro char *colon; 4964562Sgshapiro char *at; 5064562Sgshapiro struct hostent *hp = NULL; 5164562Sgshapiro SOCKADDR addr; 5264562Sgshapiro 5364562Sgshapiro if (conn == NULL || conn[0] == '\0') 5464562Sgshapiro { 5564562Sgshapiro smi_log(SMI_LOG_ERR, "%s: empty or missing socket information", 5664562Sgshapiro name); 5766494Sgshapiro return INVALID_SOCKET; 5864562Sgshapiro } 5964562Sgshapiro (void) memset(&addr, '\0', sizeof addr); 6064562Sgshapiro 6164562Sgshapiro /* protocol:filename or protocol:port@host */ 6264562Sgshapiro p = conn; 6364562Sgshapiro colon = strchr(p, ':'); 6464562Sgshapiro if (colon != NULL) 6564562Sgshapiro { 6664562Sgshapiro *colon = '\0'; 6764562Sgshapiro 6864562Sgshapiro if (*p == '\0') 6964562Sgshapiro { 7064562Sgshapiro#if NETUNIX 7164562Sgshapiro /* default to AF_UNIX */ 7264562Sgshapiro addr.sa.sa_family = AF_UNIX; 7364562Sgshapiro *socksize = sizeof (struct sockaddr_un); 7464562Sgshapiro#else /* NETUNIX */ 7564562Sgshapiro# if NETINET 7664562Sgshapiro /* default to AF_INET */ 7764562Sgshapiro addr.sa.sa_family = AF_INET; 7864562Sgshapiro *socksize = sizeof addr.sin; 7964562Sgshapiro# else /* NETINET */ 8064562Sgshapiro# if NETINET6 8164562Sgshapiro /* default to AF_INET6 */ 8264562Sgshapiro addr.sa.sa_family = AF_INET6; 8364562Sgshapiro *socksize = sizeof addr.sin6; 8464562Sgshapiro# else /* NETINET6 */ 8564562Sgshapiro /* no protocols available */ 8664562Sgshapiro smi_log(SMI_LOG_ERR, 8764562Sgshapiro "%s: no valid socket protocols available", 8864562Sgshapiro name); 8966494Sgshapiro return INVALID_SOCKET; 9064562Sgshapiro# endif /* NETINET6 */ 9164562Sgshapiro# endif /* NETINET */ 9264562Sgshapiro#endif /* NETUNIX */ 9364562Sgshapiro } 9464562Sgshapiro#if NETUNIX 9564562Sgshapiro else if (strcasecmp(p, "unix") == 0 || 9664562Sgshapiro strcasecmp(p, "local") == 0) 9764562Sgshapiro { 9864562Sgshapiro addr.sa.sa_family = AF_UNIX; 9964562Sgshapiro *socksize = sizeof (struct sockaddr_un); 10064562Sgshapiro } 10164562Sgshapiro#endif /* NETUNIX */ 10264562Sgshapiro#if NETINET 10364562Sgshapiro else if (strcasecmp(p, "inet") == 0) 10464562Sgshapiro { 10564562Sgshapiro addr.sa.sa_family = AF_INET; 10664562Sgshapiro *socksize = sizeof addr.sin; 10764562Sgshapiro } 10864562Sgshapiro#endif /* NETINET */ 10964562Sgshapiro#if NETINET6 11064562Sgshapiro else if (strcasecmp(p, "inet6") == 0) 11164562Sgshapiro { 11264562Sgshapiro addr.sa.sa_family = AF_INET6; 11364562Sgshapiro *socksize = sizeof addr.sin6; 11464562Sgshapiro } 11564562Sgshapiro#endif /* NETINET6 */ 11664562Sgshapiro else 11764562Sgshapiro { 11864562Sgshapiro smi_log(SMI_LOG_ERR, "%s: unknown socket type %s", 11964562Sgshapiro name, p); 12066494Sgshapiro return INVALID_SOCKET; 12164562Sgshapiro } 12264562Sgshapiro *colon++ = ':'; 12364562Sgshapiro } 12464562Sgshapiro else 12564562Sgshapiro { 12664562Sgshapiro colon = p; 12764562Sgshapiro#if NETUNIX 12864562Sgshapiro /* default to AF_UNIX */ 12964562Sgshapiro addr.sa.sa_family = AF_UNIX; 13064562Sgshapiro *socksize = sizeof (struct sockaddr_un); 13164562Sgshapiro#else /* NETUNIX */ 13264562Sgshapiro# if NETINET 13364562Sgshapiro /* default to AF_INET */ 13464562Sgshapiro addr.sa.sa_family = AF_INET; 13564562Sgshapiro *socksize = sizeof addr.sin; 13664562Sgshapiro# else /* NETINET */ 13764562Sgshapiro# if NETINET6 13864562Sgshapiro /* default to AF_INET6 */ 13964562Sgshapiro addr.sa.sa_family = AF_INET6; 14064562Sgshapiro *socksize = sizeof addr.sin6; 14164562Sgshapiro# else /* NETINET6 */ 14264562Sgshapiro smi_log(SMI_LOG_ERR, "%s: unknown socket type %s", 14364562Sgshapiro name, p); 14466494Sgshapiro return INVALID_SOCKET; 14564562Sgshapiro# endif /* NETINET6 */ 14664562Sgshapiro# endif /* NETINET */ 14764562Sgshapiro#endif /* NETUNIX */ 14864562Sgshapiro } 14964562Sgshapiro 15064562Sgshapiro#if NETUNIX 15164562Sgshapiro if (addr.sa.sa_family == AF_UNIX) 15264562Sgshapiro { 15364562Sgshapiro# if 0 15464562Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN; 15564562Sgshapiro# endif /* 0 */ 15664562Sgshapiro 15764562Sgshapiro at = colon; 15864562Sgshapiro if (strlcpy(addr.sunix.sun_path, colon, 15964562Sgshapiro sizeof addr.sunix.sun_path) >= 16064562Sgshapiro sizeof addr.sunix.sun_path) 16164562Sgshapiro { 16264562Sgshapiro errno = EINVAL; 16364562Sgshapiro smi_log(SMI_LOG_ERR, "%s: UNIX socket name %s too long", 16464562Sgshapiro name, colon); 16566494Sgshapiro return INVALID_SOCKET; 16664562Sgshapiro } 16764562Sgshapiro# if 0 16864562Sgshapiro errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff, 16964562Sgshapiro S_IRUSR|S_IWUSR, NULL); 17064562Sgshapiro 17164562Sgshapiro /* if not safe, don't create */ 17264562Sgshapiro if (errno != 0) 17364562Sgshapiro { 17464562Sgshapiro smi_log(SMI_LOG_ERR, 17564562Sgshapiro "%s: UNIX socket name %s unsafe", 17664562Sgshapiro name, colon); 17766494Sgshapiro return INVALID_SOCKET; 17864562Sgshapiro } 17964562Sgshapiro# endif /* 0 */ 18064562Sgshapiro 18164562Sgshapiro } 18264562Sgshapiro#endif /* NETUNIX */ 18364562Sgshapiro 18464562Sgshapiro#if NETINET || NETINET6 18564562Sgshapiro if ( 18664562Sgshapiro# if NETINET 18764562Sgshapiro addr.sa.sa_family == AF_INET 18864562Sgshapiro# endif /* NETINET */ 18964562Sgshapiro# if NETINET && NETINET6 19064562Sgshapiro || 19164562Sgshapiro# endif /* NETINET && NETINET6 */ 19264562Sgshapiro# if NETINET6 19364562Sgshapiro addr.sa.sa_family == AF_INET6 19464562Sgshapiro# endif /* NETINET6 */ 19564562Sgshapiro ) 19664562Sgshapiro { 19764562Sgshapiro u_short port; 19864562Sgshapiro 19964562Sgshapiro /* Parse port@host */ 20064562Sgshapiro at = strchr(colon, '@'); 20164562Sgshapiro if (at == NULL) 20264562Sgshapiro { 20364562Sgshapiro switch (addr.sa.sa_family) 20464562Sgshapiro { 20564562Sgshapiro# if NETINET 20664562Sgshapiro case AF_INET: 20764562Sgshapiro addr.sin.sin_addr.s_addr = INADDR_ANY; 20864562Sgshapiro break; 20964562Sgshapiro# endif /* NETINET */ 21064562Sgshapiro 21164562Sgshapiro# if NETINET6 21264562Sgshapiro case AF_INET6: 21364562Sgshapiro addr.sin6.sin6_addr = in6addr_any; 21464562Sgshapiro break; 21564562Sgshapiro# endif /* NETINET6 */ 21664562Sgshapiro } 21764562Sgshapiro } 21864562Sgshapiro else 21964562Sgshapiro *at = '\0'; 22064562Sgshapiro 22164562Sgshapiro if (isascii(*colon) && isdigit(*colon)) 22264562Sgshapiro port = htons((u_short) atoi(colon)); 22364562Sgshapiro else 22464562Sgshapiro { 22564562Sgshapiro# ifdef NO_GETSERVBYNAME 22664562Sgshapiro smi_log(SMI_LOG_ERR, "%s: invalid port number %s", 22764562Sgshapiro name, colon); 22866494Sgshapiro return INVALID_SOCKET; 22964562Sgshapiro# else /* NO_GETSERVBYNAME */ 23064562Sgshapiro register struct servent *sp; 23164562Sgshapiro 23264562Sgshapiro sp = getservbyname(colon, "tcp"); 23364562Sgshapiro if (sp == NULL) 23464562Sgshapiro { 23564562Sgshapiro smi_log(SMI_LOG_ERR, 23664562Sgshapiro "%s: unknown port name %s", 23764562Sgshapiro name, colon); 23866494Sgshapiro return INVALID_SOCKET; 23964562Sgshapiro } 24064562Sgshapiro port = sp->s_port; 24164562Sgshapiro# endif /* NO_GETSERVBYNAME */ 24264562Sgshapiro } 24364562Sgshapiro if (at != NULL) 24464562Sgshapiro { 24564562Sgshapiro *at++ = '@'; 24664562Sgshapiro if (*at == '[') 24764562Sgshapiro { 24864562Sgshapiro char *end; 24964562Sgshapiro 25064562Sgshapiro end = strchr(at, ']'); 25164562Sgshapiro if (end != NULL) 25264562Sgshapiro { 25364562Sgshapiro bool found = FALSE; 25464562Sgshapiro# if NETINET 25564562Sgshapiro unsigned long hid = INADDR_NONE; 25664562Sgshapiro# endif /* NETINET */ 25764562Sgshapiro# if NETINET6 25864562Sgshapiro struct sockaddr_in6 hid6; 25964562Sgshapiro# endif /* NETINET6 */ 26064562Sgshapiro 26164562Sgshapiro *end = '\0'; 26264562Sgshapiro# if NETINET 26364562Sgshapiro if (addr.sa.sa_family == AF_INET && 26464562Sgshapiro (hid = inet_addr(&at[1])) != 26564562Sgshapiro INADDR_NONE) 26664562Sgshapiro { 26764562Sgshapiro addr.sin.sin_addr.s_addr = hid; 26864562Sgshapiro addr.sin.sin_port = port; 26964562Sgshapiro found = TRUE; 27064562Sgshapiro } 27164562Sgshapiro# endif /* NETINET */ 27264562Sgshapiro# if NETINET6 27364562Sgshapiro (void) memset(&hid6, '\0', sizeof hid6); 27464562Sgshapiro if (addr.sa.sa_family == AF_INET6 && 27564562Sgshapiro inet_pton(AF_INET6, &at[1], 27664562Sgshapiro &hid6.sin6_addr) == 1) 27764562Sgshapiro { 27864562Sgshapiro addr.sin6.sin6_addr = hid6.sin6_addr; 27964562Sgshapiro addr.sin6.sin6_port = port; 28064562Sgshapiro found = TRUE; 28164562Sgshapiro } 28264562Sgshapiro# endif /* NETINET6 */ 28364562Sgshapiro *end = ']'; 28464562Sgshapiro if (!found) 28564562Sgshapiro { 28664562Sgshapiro smi_log(SMI_LOG_ERR, 28764562Sgshapiro "%s: Invalid numeric domain spec \"%s\"", 28864562Sgshapiro name, at); 28966494Sgshapiro return INVALID_SOCKET; 29064562Sgshapiro } 29164562Sgshapiro } 29264562Sgshapiro else 29364562Sgshapiro { 29464562Sgshapiro smi_log(SMI_LOG_ERR, 29564562Sgshapiro "%s: Invalid numeric domain spec \"%s\"", 29664562Sgshapiro name, at); 29766494Sgshapiro return INVALID_SOCKET; 29864562Sgshapiro } 29964562Sgshapiro } 30064562Sgshapiro else 30164562Sgshapiro { 30264562Sgshapiro hp = mi_gethostbyname(at, addr.sa.sa_family); 30364562Sgshapiro if (hp == NULL) 30464562Sgshapiro { 30564562Sgshapiro smi_log(SMI_LOG_ERR, 30664562Sgshapiro "%s: Unknown host name %s", 30764562Sgshapiro name, at); 30866494Sgshapiro return INVALID_SOCKET; 30964562Sgshapiro } 31064562Sgshapiro addr.sa.sa_family = hp->h_addrtype; 31164562Sgshapiro switch (hp->h_addrtype) 31264562Sgshapiro { 31364562Sgshapiro# if NETINET 31464562Sgshapiro case AF_INET: 31564562Sgshapiro memmove(&addr.sin.sin_addr, 31664562Sgshapiro hp->h_addr, 31764562Sgshapiro INADDRSZ); 31864562Sgshapiro addr.sin.sin_port = port; 31964562Sgshapiro break; 32064562Sgshapiro# endif /* NETINET */ 32164562Sgshapiro 32264562Sgshapiro# if NETINET6 32364562Sgshapiro case AF_INET6: 32464562Sgshapiro memmove(&addr.sin6.sin6_addr, 32564562Sgshapiro hp->h_addr, 32664562Sgshapiro IN6ADDRSZ); 32764562Sgshapiro addr.sin6.sin6_port = port; 32864562Sgshapiro break; 32964562Sgshapiro# endif /* NETINET6 */ 33064562Sgshapiro 33164562Sgshapiro default: 33264562Sgshapiro smi_log(SMI_LOG_ERR, 33364562Sgshapiro "%s: Unknown protocol for %s (%d)", 33464562Sgshapiro name, at, hp->h_addrtype); 33566494Sgshapiro return INVALID_SOCKET; 33664562Sgshapiro } 33764562Sgshapiro } 33864562Sgshapiro } 33964562Sgshapiro else 34064562Sgshapiro { 34164562Sgshapiro switch (addr.sa.sa_family) 34264562Sgshapiro { 34364562Sgshapiro# if NETINET 34464562Sgshapiro case AF_INET: 34564562Sgshapiro addr.sin.sin_port = port; 34664562Sgshapiro break; 34764562Sgshapiro# endif /* NETINET */ 34864562Sgshapiro# if NETINET6 34964562Sgshapiro case AF_INET6: 35064562Sgshapiro addr.sin6.sin6_port = port; 35164562Sgshapiro break; 35264562Sgshapiro# endif /* NETINET6 */ 35364562Sgshapiro } 35464562Sgshapiro } 35564562Sgshapiro } 35664562Sgshapiro#endif /* NETINET || NETINET6 */ 35764562Sgshapiro 35864562Sgshapiro sock = socket(addr.sa.sa_family, SOCK_STREAM, 0); 35964562Sgshapiro if (!ValidSocket(sock)) 36064562Sgshapiro { 36164562Sgshapiro smi_log(SMI_LOG_ERR, 36264562Sgshapiro "%s: Unable to create new socket: %s", 36364562Sgshapiro name, strerror(errno)); 36466494Sgshapiro return INVALID_SOCKET; 36564562Sgshapiro } 36664562Sgshapiro 36764562Sgshapiro if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &sockopt, 36864562Sgshapiro sizeof(sockopt)) == -1) 36964562Sgshapiro { 37064562Sgshapiro smi_log(SMI_LOG_ERR, 37164562Sgshapiro "%s: Unable to setsockopt: %s", name, strerror(errno)); 37264562Sgshapiro (void) close(sock); 37366494Sgshapiro return INVALID_SOCKET; 37464562Sgshapiro } 37564562Sgshapiro 37664562Sgshapiro if (bind(sock, &addr.sa, *socksize) < 0) 37764562Sgshapiro { 37864562Sgshapiro smi_log(SMI_LOG_ERR, 37964562Sgshapiro "%s: Unable to bind to port %s: %s", 38064562Sgshapiro name, conn, strerror(errno)); 38164562Sgshapiro (void) close(sock); 38266494Sgshapiro return INVALID_SOCKET; 38364562Sgshapiro } 38464562Sgshapiro 38564562Sgshapiro if (listen(sock, backlog) < 0) 38664562Sgshapiro { 38764562Sgshapiro smi_log(SMI_LOG_ERR, 38864562Sgshapiro "%s: listen call failed: %s", name, strerror(errno)); 38964562Sgshapiro (void) close(sock); 39066494Sgshapiro return INVALID_SOCKET; 39164562Sgshapiro } 39264562Sgshapiro 39364562Sgshapiro return sock; 39464562Sgshapiro} 39564562Sgshapiro/* 39664562Sgshapiro** MI_THREAD_HANDLE_WRAPPER -- small wrapper to handle session 39764562Sgshapiro** 39864562Sgshapiro** Parameters: 39964562Sgshapiro** arg -- argument to pass to mi_handle_session() 40064562Sgshapiro** 40164562Sgshapiro** Returns: 40264562Sgshapiro** results from mi_handle_session() 40364562Sgshapiro*/ 40464562Sgshapiro 40564562Sgshapirovoid * 40664562Sgshapiromi_thread_handle_wrapper(arg) 40764562Sgshapiro void *arg; 40864562Sgshapiro{ 40964562Sgshapiro return (void *) mi_handle_session(arg); 41064562Sgshapiro} 41164562Sgshapiro 41266494Sgshapirostatic socket_t listenfd = INVALID_SOCKET; 41366494Sgshapiro 41464562Sgshapiro/* 41566494Sgshapiro** MI_CLOSENER -- close listen socket 41664562Sgshapiro** 41766494Sgshapiro** Parameters: 41866494Sgshapiro** none. 41966494Sgshapiro** 42066494Sgshapiro** Returns: 42166494Sgshapiro** none. 42266494Sgshapiro*/ 42366494Sgshapiro 42466494Sgshapirovoid 42566494Sgshapiromi_closener() 42666494Sgshapiro{ 42766494Sgshapiro if (ValidSocket(listenfd)) 42866494Sgshapiro { 42966494Sgshapiro (void) close(listenfd); 43066494Sgshapiro listenfd = INVALID_SOCKET; 43166494Sgshapiro } 43266494Sgshapiro} 43366494Sgshapiro 43466494Sgshapiro/* 43566494Sgshapiro** MI_LISTENER -- Generic listener harness 43666494Sgshapiro** 43764562Sgshapiro** Open up listen port 43864562Sgshapiro** Wait for connections 43964562Sgshapiro** 44064562Sgshapiro** Parameters: 44164562Sgshapiro** conn -- connection description 44264562Sgshapiro** dbg -- debug level 44364562Sgshapiro** smfi -- filter structure to use 44464562Sgshapiro** timeout -- timeout for reads/writes 44564562Sgshapiro** 44664562Sgshapiro** Returns: 44764562Sgshapiro** MI_SUCCESS -- Exited normally 44864562Sgshapiro** (session finished or we were told to exit) 44964562Sgshapiro** MI_FAILURE -- Network initialization failed. 45064562Sgshapiro*/ 45164562Sgshapiro 45264562Sgshapiroint 45366494Sgshapiromi_listener(conn, dbg, smfi, timeout, backlog) 45464562Sgshapiro char *conn; 45564562Sgshapiro int dbg; 45664562Sgshapiro smfiDesc_ptr smfi; 45764562Sgshapiro time_t timeout; 45866494Sgshapiro int backlog; 45964562Sgshapiro{ 46066494Sgshapiro socket_t connfd = INVALID_SOCKET; 46164562Sgshapiro int sockopt = 1; 46264562Sgshapiro int r; 46364562Sgshapiro int ret = MI_SUCCESS; 46464562Sgshapiro int cnt_m = 0; 46564562Sgshapiro int cnt_t = 0; 46664562Sgshapiro sthread_t thread_id; 46764562Sgshapiro _SOCK_ADDR cliaddr; 46864562Sgshapiro SOCKADDR_LEN_T socksize; 46964562Sgshapiro SOCKADDR_LEN_T clilen; 47064562Sgshapiro SMFICTX_PTR ctx; 47164562Sgshapiro fd_set readset, excset; 47264562Sgshapiro struct timeval chktime; 47364562Sgshapiro 47464562Sgshapiro if (dbg > 0) 47564562Sgshapiro smi_log(SMI_LOG_DEBUG, 47664562Sgshapiro "%s: Opening listen socket on conn %s", 47764562Sgshapiro smfi->xxfi_name, conn); 47866494Sgshapiro listenfd = mi_milteropen(conn, backlog, &socksize, smfi->xxfi_name); 47966494Sgshapiro if (!ValidSocket(listenfd)) 48064562Sgshapiro { 48164562Sgshapiro smi_log(SMI_LOG_FATAL, 48264562Sgshapiro "%s: Unable to create listening socket on conn %s", 48364562Sgshapiro smfi->xxfi_name, conn); 48464562Sgshapiro return MI_FAILURE; 48564562Sgshapiro } 48664562Sgshapiro clilen = socksize; 48764562Sgshapiro if (listenfd >= FD_SETSIZE) 48864562Sgshapiro { 48964562Sgshapiro smi_log(SMI_LOG_ERR, "%s: fd %d is larger than FD_SETSIZE %d", 49064562Sgshapiro smfi->xxfi_name, listenfd, FD_SETSIZE); 49164562Sgshapiro return MI_FAILURE; 49264562Sgshapiro } 49364562Sgshapiro 49464562Sgshapiro while (mi_stop() == MILTER_CONT) 49564562Sgshapiro { 49664562Sgshapiro /* select on interface ports */ 49764562Sgshapiro FD_ZERO(&readset); 49864562Sgshapiro FD_SET((u_int) listenfd, &readset); 49964562Sgshapiro FD_ZERO(&excset); 50064562Sgshapiro FD_SET((u_int) listenfd, &excset); 50164562Sgshapiro chktime.tv_sec = MI_CHK_TIME; 50264562Sgshapiro chktime.tv_usec = 0; 50364562Sgshapiro r = select(listenfd + 1, &readset, NULL, &excset, &chktime); 50464562Sgshapiro if (r == 0) /* timeout */ 50564562Sgshapiro continue; /* just check mi_stop() */ 50664562Sgshapiro if (r < 0) 50764562Sgshapiro { 50864562Sgshapiro if (errno == EINTR) 50964562Sgshapiro continue; 51064562Sgshapiro ret = MI_FAILURE; 51164562Sgshapiro break; 51264562Sgshapiro } 51364562Sgshapiro if (!FD_ISSET(listenfd, &readset)) 51464562Sgshapiro { 51564562Sgshapiro /* some error: just stop for now... */ 51664562Sgshapiro ret = MI_FAILURE; 51764562Sgshapiro break; 51864562Sgshapiro } 51964562Sgshapiro 52064562Sgshapiro connfd = accept(listenfd, (struct sockaddr *) &cliaddr, 52164562Sgshapiro &clilen); 52264562Sgshapiro 52366494Sgshapiro if (!ValidSocket(connfd)) 52464562Sgshapiro { 52564562Sgshapiro smi_log(SMI_LOG_ERR, 52664562Sgshapiro "%s: accept() returned invalid socket", 52764562Sgshapiro smfi->xxfi_name); 52864562Sgshapiro continue; 52964562Sgshapiro } 53064562Sgshapiro 53164562Sgshapiro if (setsockopt(connfd, SOL_SOCKET, SO_KEEPALIVE, 53264562Sgshapiro (void *) &sockopt, sizeof sockopt) < 0) 53364562Sgshapiro { 53464562Sgshapiro smi_log(SMI_LOG_WARN, "%s: setsockopt() failed", 53564562Sgshapiro smfi->xxfi_name); 53664562Sgshapiro /* XXX: continue? */ 53764562Sgshapiro } 53864562Sgshapiro if ((ctx = (SMFICTX_PTR) malloc(sizeof *ctx)) == NULL) 53964562Sgshapiro { 54064562Sgshapiro (void) close(connfd); 54164562Sgshapiro smi_log(SMI_LOG_ERR, "%s: malloc(ctx) failed", 54264562Sgshapiro smfi->xxfi_name); 54364562Sgshapiro sleep(++cnt_m); 54464562Sgshapiro if (cnt_m >= MAX_FAILS_M) 54564562Sgshapiro { 54664562Sgshapiro ret = MI_FAILURE; 54764562Sgshapiro break; 54864562Sgshapiro } 54964562Sgshapiro continue; 55064562Sgshapiro } 55164562Sgshapiro cnt_m = 0; 55264562Sgshapiro memset(ctx, '\0', sizeof *ctx); 55364562Sgshapiro ctx->ctx_sd = connfd; 55464562Sgshapiro ctx->ctx_dbg = dbg; 55564562Sgshapiro ctx->ctx_timeout = timeout; 55664562Sgshapiro ctx->ctx_smfi = smfi; 55764562Sgshapiro#if 0 55864562Sgshapiro if (smfi->xxfi_eoh == NULL) 55964562Sgshapiro if (smfi->xxfi_eom == NULL) 56064562Sgshapiro if (smfi->xxfi_abort == NULL) 56164562Sgshapiro if (smfi->xxfi_close == NULL) 56264562Sgshapiro#endif /* 0 */ 56364562Sgshapiro if (smfi->xxfi_connect == NULL) 56464562Sgshapiro ctx->ctx_pflags |= SMFIP_NOCONNECT; 56564562Sgshapiro if (smfi->xxfi_helo == NULL) 56664562Sgshapiro ctx->ctx_pflags |= SMFIP_NOHELO; 56764562Sgshapiro if (smfi->xxfi_envfrom == NULL) 56864562Sgshapiro ctx->ctx_pflags |= SMFIP_NOMAIL; 56964562Sgshapiro if (smfi->xxfi_envrcpt == NULL) 57064562Sgshapiro ctx->ctx_pflags |= SMFIP_NORCPT; 57164562Sgshapiro if (smfi->xxfi_header == NULL) 57264562Sgshapiro ctx->ctx_pflags |= SMFIP_NOHDRS; 57364562Sgshapiro if (smfi->xxfi_eoh == NULL) 57464562Sgshapiro ctx->ctx_pflags |= SMFIP_NOEOH; 57564562Sgshapiro if (smfi->xxfi_body == NULL) 57664562Sgshapiro ctx->ctx_pflags |= SMFIP_NOBODY; 57764562Sgshapiro 57864562Sgshapiro if ((r = thread_create(&thread_id, 57964562Sgshapiro mi_thread_handle_wrapper, 58064562Sgshapiro (void *) ctx)) != MI_SUCCESS) 58164562Sgshapiro { 58264562Sgshapiro smi_log(SMI_LOG_ERR, 58364562Sgshapiro "%s: thread_create() failed: %d", 58464562Sgshapiro smfi->xxfi_name, r); 58564562Sgshapiro sleep(++cnt_t); 58664562Sgshapiro (void) close(connfd); 58764562Sgshapiro free(ctx); 58864562Sgshapiro if (cnt_t >= MAX_FAILS_T) 58964562Sgshapiro { 59064562Sgshapiro ret = MI_FAILURE; 59164562Sgshapiro break; 59264562Sgshapiro } 59364562Sgshapiro continue; 59464562Sgshapiro } 59564562Sgshapiro cnt_t = 0; 59664562Sgshapiro } 59764562Sgshapiro if (ret != MI_SUCCESS) 59864562Sgshapiro mi_stop_milters(MILTER_ABRT); 59964562Sgshapiro if (listenfd >= 0) 60064562Sgshapiro (void) close(listenfd); 60164562Sgshapiro return ret; 60264562Sgshapiro} 60364562Sgshapiro#endif /* _FFR_MILTER */ 604