xref: /original-bsd/usr.sbin/sendmail/src/daemon.c (revision 210215ea)
17aa493c5Seric # include <errno.h>
27fa39d90Seric # include "sendmail.h"
37fa39d90Seric 
4d0a9e852Seric #ifndef DAEMON
5*210215eaSeric SCCSID(@(#)daemon.c	3.16		06/26/82	(w/o daemon mode));
6d0a9e852Seric #else
7d0a9e852Seric 
8d0a9e852Seric # include <sys/socket.h>
9d0a9e852Seric # include <net/in.h>
102554d49fSeric # include <wait.h>
11d0a9e852Seric 
12*210215eaSeric SCCSID(@(#)daemon.c	3.16		06/26/82	(with daemon mode));
137fa39d90Seric 
147fa39d90Seric /*
157fa39d90Seric **  DAEMON.C -- routines to use when running as a daemon.
167fa39d90Seric */
177fa39d90Seric /*
187fa39d90Seric **  GETREQUESTS -- open mail IPC port and get requests.
197fa39d90Seric **
207fa39d90Seric **	Parameters:
217fa39d90Seric **		none.
227fa39d90Seric **
237fa39d90Seric **	Returns:
247fa39d90Seric **		none.
257fa39d90Seric **
267fa39d90Seric **	Side Effects:
277fa39d90Seric **		Waits until some interesting activity occurs.  When
287fa39d90Seric **		it does, a child is created to process it, and the
297fa39d90Seric **		parent waits for completion.  Return from this
307fa39d90Seric **		routine is always in the child.
317fa39d90Seric */
327fa39d90Seric 
332554d49fSeric # define MAXCONNS	4	/* maximum simultaneous sendmails */
342554d49fSeric 
357fa39d90Seric getrequests()
367fa39d90Seric {
372554d49fSeric 	union wait status;
382554d49fSeric 	int numconnections = 0;
392554d49fSeric 
40eb889047Seric 	for (;;)
41eb889047Seric 	{
42a8268164Seric 		register int pid;
43d0a9e852Seric 		register int port;
44eb889047Seric 
45a8268164Seric 		/*
46a8268164Seric 		**  Wait for a connection.
47eb889047Seric 		*/
48eb889047Seric 
49d0a9e852Seric 		while ((port = getconnection()) < 0)
50d0a9e852Seric 		{
51d0a9e852Seric 			syserr("getrequests: getconnection failed");
52d0a9e852Seric 			sleep(30);
53d0a9e852Seric 		}
54d0a9e852Seric 
55d0a9e852Seric 		/*
56d0a9e852Seric 		**  Create a subprocess to process the mail.
57d0a9e852Seric 		*/
58d0a9e852Seric 
59d0a9e852Seric # ifdef DEBUG
60d0a9e852Seric 		if (Debug > 1)
61d0a9e852Seric 			printf("getrequests: forking (port = %d)\n", port);
62d0a9e852Seric # endif DEBUG
63eb889047Seric 
64a8268164Seric 		pid = fork();
65a8268164Seric 		if (pid < 0)
66a8268164Seric 		{
67a8268164Seric 			syserr("daemon: cannot fork");
68a8268164Seric 			sleep(10);
69b7db1904Seric 			(void) close(port);
70a8268164Seric 			continue;
71a8268164Seric 		}
72a8268164Seric 
73a8268164Seric 		if (pid == 0)
74a8268164Seric 		{
75a8268164Seric 			/*
76a8268164Seric 			**  CHILD -- return to caller.
77a8268164Seric 			**	Verify calling user id if possible here.
78a8268164Seric 			*/
79a8268164Seric 
80d0a9e852Seric 			InChannel = fdopen(port, "r");
81d0a9e852Seric 			OutChannel = fdopen(port, "w");
82a8268164Seric 			initsys();
83d0a9e852Seric # ifdef DEBUG
84d0a9e852Seric 			if (Debug > 1)
85d0a9e852Seric 				printf("getreq: returning\n");
86d0a9e852Seric # endif DEBUG
87a8268164Seric 			return;
88a8268164Seric 		}
89a8268164Seric 
90a8268164Seric 		/*
91a8268164Seric 		**  PARENT -- wait for child to terminate.
92a8268164Seric 		**	Perhaps we should allow concurrent processing?
93a8268164Seric 		*/
94a8268164Seric 
95d0a9e852Seric # ifdef DEBUG
96d0a9e852Seric 		if (Debug > 1)
97d0a9e852Seric 		{
98d0a9e852Seric 			sleep(2);
99d0a9e852Seric 			printf("getreq: parent waiting\n");
100d0a9e852Seric 		}
101d0a9e852Seric # endif DEBUG
102d0a9e852Seric 
1032554d49fSeric 		/* close the port so that others will hang (for a while) */
104b7db1904Seric 		(void) close(port);
1052554d49fSeric 
1062554d49fSeric 		/* pick up old zombies; implement load limiting */
1072554d49fSeric 		numconnections++;
1082554d49fSeric 		while (wait3(&status, numconnections < MAXCONNS ? WNOHANG : 0, 0) > 0)
1092554d49fSeric 			numconnections--;
110a8268164Seric 	}
1117fa39d90Seric }
112d0a9e852Seric /*
113d0a9e852Seric **  GETCONNECTION -- make a connection with the outside world
114d0a9e852Seric **
115d0a9e852Seric **	Parameters:
116d0a9e852Seric **		none.
117d0a9e852Seric **
118d0a9e852Seric **	Returns:
119d0a9e852Seric **		The port for mail traffic.
120d0a9e852Seric **
121d0a9e852Seric **	Side Effects:
122d0a9e852Seric **		Waits for a connection.
123d0a9e852Seric */
124d0a9e852Seric 
1252554d49fSeric #define IPPORT_PLAYPORT	3055		/* random number */
1262554d49fSeric 
127038c4785Seric struct sockaddr_in SendmailAddress = { AF_INET, IPPORT_SMTP };
128d0a9e852Seric 
129d0a9e852Seric getconnection()
130d0a9e852Seric {
131d0a9e852Seric 	register int s;
132d0a9e852Seric 	struct sockaddr otherend;
133d0a9e852Seric 
134d0a9e852Seric 	/*
135d0a9e852Seric 	**  Set up the address for the mailer.
136d0a9e852Seric 	*/
137d0a9e852Seric 
13819cf7d27Seric 	SendmailAddress.sin_addr.s_addr = 0;
13948ff0a9dSeric 	SendmailAddress.sin_port = IPPORT_SMTP;
1402554d49fSeric # ifdef DEBUG
1412554d49fSeric 	if (Debug > 0)
1422554d49fSeric 		SendmailAddress.sin_port = IPPORT_PLAYPORT;
1432554d49fSeric # endif DEBUG
1442554d49fSeric 	SendmailAddress.sin_port = htons(SendmailAddress.sin_port);
145d0a9e852Seric 
146d0a9e852Seric 	/*
147d0a9e852Seric 	**  Try to actually open the connection.
148d0a9e852Seric 	*/
149d0a9e852Seric 
150d0a9e852Seric # ifdef DEBUG
151d0a9e852Seric 	if (Debug)
15219cf7d27Seric 		printf("getconnection\n");
153d0a9e852Seric # endif DEBUG
154d0a9e852Seric 
155d0a9e852Seric 	s = socket(SOCK_STREAM, 0, &SendmailAddress, SO_ACCEPTCONN);
1562554d49fSeric 	if (s < 0)
1572554d49fSeric 	{
1582554d49fSeric 		sleep(10);
1592554d49fSeric 		return (s);
1602554d49fSeric 	}
161d0a9e852Seric 
162d0a9e852Seric # ifdef DEBUG
163d0a9e852Seric 	if (Debug)
164d0a9e852Seric 		printf("getconnection: %d\n", s);
165d0a9e852Seric # endif DEBUG
1662554d49fSeric 	if (accept(s, &otherend) < 0)
1672554d49fSeric 	{
1682554d49fSeric 		syserr("accept");
169*210215eaSeric 		(void) close(s);
1702554d49fSeric 		return (-1);
1712554d49fSeric 	}
172d0a9e852Seric 
173d0a9e852Seric 	return (s);
174d0a9e852Seric }
1757aa493c5Seric /*
1767aa493c5Seric **  MAKECONNECTION -- make a connection to an SMTP socket on another machine.
1777aa493c5Seric **
1787aa493c5Seric **	Parameters:
1797aa493c5Seric **		host -- the name of the host.
18048ff0a9dSeric **		port -- the port number to connect to.
1817aa493c5Seric **		outfile -- a pointer to a place to put the outfile
1827aa493c5Seric **			descriptor.
1837aa493c5Seric **		infile -- ditto for infile.
1847aa493c5Seric **
1857aa493c5Seric **	Returns:
1867aa493c5Seric **		An exit code telling whether the connection could be
1877aa493c5Seric **			made and if not why not.
1887aa493c5Seric **
1897aa493c5Seric **	Side Effects:
1907aa493c5Seric **		none.
1917aa493c5Seric */
1927aa493c5Seric 
19348ff0a9dSeric makeconnection(host, port, outfile, infile)
1947aa493c5Seric 	char *host;
195*210215eaSeric 	u_short port;
1967aa493c5Seric 	FILE **outfile;
1977aa493c5Seric 	FILE **infile;
1987aa493c5Seric {
1997aa493c5Seric 	register int s;
2007aa493c5Seric 
2017aa493c5Seric 	/*
2027aa493c5Seric 	**  Set up the address for the mailer.
2037aa493c5Seric 	*/
2047aa493c5Seric 
2057aa493c5Seric 	if ((SendmailAddress.sin_addr.s_addr = rhost(&host)) == -1)
2067aa493c5Seric 		return (EX_NOHOST);
20748ff0a9dSeric 	if (port == 0)
20848ff0a9dSeric 		port = IPPORT_SMTP;
2092554d49fSeric 	SendmailAddress.sin_port = htons(port);
2107aa493c5Seric 
2117aa493c5Seric 	/*
2127aa493c5Seric 	**  Try to actually open the connection.
2137aa493c5Seric 	*/
2147aa493c5Seric 
2157aa493c5Seric # ifdef DEBUG
2167aa493c5Seric 	if (Debug)
2177aa493c5Seric 		printf("makeconnection (%s)\n", host);
2187aa493c5Seric # endif DEBUG
2197aa493c5Seric 
220b7db1904Seric 	s = socket(SOCK_STREAM, 0, (struct sockaddr_in *) 0, 0);
2217aa493c5Seric 	if (s < 0)
2227aa493c5Seric 	{
2237aa493c5Seric 		syserr("makeconnection: no socket");
2247aa493c5Seric 		goto failure;
2257aa493c5Seric 	}
2267aa493c5Seric 
2277aa493c5Seric # ifdef DEBUG
2287aa493c5Seric 	if (Debug)
2297aa493c5Seric 		printf("makeconnection: %d\n", s);
2307aa493c5Seric # endif DEBUG
2317aa493c5Seric 	if (connect(s, &SendmailAddress) < 0)
2327aa493c5Seric 	{
2337aa493c5Seric 		/* failure, decide if temporary or not */
2347aa493c5Seric 	failure:
2357aa493c5Seric 		switch (errno)
2367aa493c5Seric 		{
2377aa493c5Seric 		  case EISCONN:
2387aa493c5Seric 		  case ETIMEDOUT:
239292668b9Seric 		  case EINPROGRESS:
240292668b9Seric 		  case EALREADY:
241292668b9Seric 		  case EADDRINUSE:
242292668b9Seric 		  case ENETDOWN:
243292668b9Seric 		  case ENETRESET:
244292668b9Seric 		  case ENOBUFS:
245a1645df8Seric 		  case ECONNREFUSED:
2467aa493c5Seric 			/* there are others, I'm sure..... */
2477aa493c5Seric 			return (EX_TEMPFAIL);
2487aa493c5Seric 
2497aa493c5Seric 		  default:
2507aa493c5Seric 			return (EX_UNAVAILABLE);
2517aa493c5Seric 		}
2527aa493c5Seric 	}
2537aa493c5Seric 
2547aa493c5Seric 	/* connection ok, put it into canonical form */
2557aa493c5Seric 	*outfile = fdopen(s, "w");
2567aa493c5Seric 	*infile = fdopen(s, "r");
2577aa493c5Seric 
2587aa493c5Seric 	return (0);
2597aa493c5Seric }
260d0a9e852Seric 
261d0a9e852Seric #endif DAEMON
262