1 # include <errno.h>
2 # include "sendmail.h"
3 
4 #ifndef DAEMON
5 SCCSID(@(#)daemon.c	3.10		03/22/82	(w/o daemon mode));
6 #else
7 
8 # include <sys/socket.h>
9 # include <net/in.h>
10 
11 SCCSID(@(#)daemon.c	3.10		03/22/82	(with daemon mode));
12 
13 /*
14 **  DAEMON.C -- routines to use when running as a daemon.
15 */
16 /*
17 **  GETREQUESTS -- open mail IPC port and get requests.
18 **
19 **	Parameters:
20 **		none.
21 **
22 **	Returns:
23 **		none.
24 **
25 **	Side Effects:
26 **		Waits until some interesting activity occurs.  When
27 **		it does, a child is created to process it, and the
28 **		parent waits for completion.  Return from this
29 **		routine is always in the child.
30 */
31 
32 getrequests()
33 {
34 	for (;;)
35 	{
36 		register int pid;
37 		auto int st;
38 		register int port;
39 
40 		/*
41 		**  Wait for a connection.
42 		*/
43 
44 		while ((port = getconnection()) < 0)
45 		{
46 			syserr("getrequests: getconnection failed");
47 			sleep(30);
48 		}
49 
50 		/*
51 		**  Create a subprocess to process the mail.
52 		*/
53 
54 # ifdef DEBUG
55 		if (Debug > 1)
56 			printf("getrequests: forking (port = %d)\n", port);
57 # endif DEBUG
58 
59 		pid = fork();
60 		if (pid < 0)
61 		{
62 			syserr("daemon: cannot fork");
63 			sleep(10);
64 			close(port);
65 			continue;
66 		}
67 
68 		if (pid == 0)
69 		{
70 			/*
71 			**  CHILD -- return to caller.
72 			**	Verify calling user id if possible here.
73 			*/
74 
75 			InChannel = fdopen(port, "r");
76 			OutChannel = fdopen(port, "w");
77 			initsys();
78 # ifdef DEBUG
79 			if (Debug > 1)
80 				printf("getreq: returning\n");
81 # endif DEBUG
82 			return;
83 		}
84 
85 		/*
86 		**  PARENT -- wait for child to terminate.
87 		**	Perhaps we should allow concurrent processing?
88 		*/
89 
90 # ifdef DEBUG
91 		if (Debug > 1)
92 		{
93 			sleep(2);
94 			printf("getreq: parent waiting\n");
95 		}
96 # endif DEBUG
97 
98 		(void) wait(&st);
99 		close(port);
100 	}
101 }
102 /*
103 **  GETCONNECTION -- make a connection with the outside world
104 **
105 **	Parameters:
106 **		none.
107 **
108 **	Returns:
109 **		The port for mail traffic.
110 **
111 **	Side Effects:
112 **		Waits for a connection.
113 */
114 
115 struct sockaddr_in SendmailAddress = { AF_INET, IPPORT_SMTP };
116 
117 getconnection()
118 {
119 	register int s;
120 	struct sockaddr otherend;
121 
122 	/*
123 	**  Set up the address for the mailer.
124 	*/
125 
126 	SendmailAddress.sin_addr.s_addr = 0;
127 
128 	/*
129 	**  Try to actually open the connection.
130 	*/
131 
132 # ifdef DEBUG
133 	if (Debug)
134 		printf("getconnection\n");
135 # endif DEBUG
136 
137 	s = socket(SOCK_STREAM, 0, &SendmailAddress, SO_ACCEPTCONN);
138 
139 # ifdef DEBUG
140 	if (Debug)
141 		printf("getconnection: %d\n", s);
142 # endif DEBUG
143 	accept(s, &otherend);
144 
145 	return (s);
146 }
147 /*
148 **  MAKECONNECTION -- make a connection to an SMTP socket on another machine.
149 **
150 **	Parameters:
151 **		host -- the name of the host.
152 **		outfile -- a pointer to a place to put the outfile
153 **			descriptor.
154 **		infile -- ditto for infile.
155 **
156 **	Returns:
157 **		An exit code telling whether the connection could be
158 **			made and if not why not.
159 **
160 **	Side Effects:
161 **		none.
162 */
163 
164 makeconnection(host, outfile, infile)
165 	char *host;
166 	FILE **outfile;
167 	FILE **infile;
168 {
169 	register int s;
170 
171 	/*
172 	**  Set up the address for the mailer.
173 	*/
174 
175 	if ((SendmailAddress.sin_addr.s_addr = rhost(&host)) == -1)
176 		return (EX_NOHOST);
177 
178 	/*
179 	**  Try to actually open the connection.
180 	*/
181 
182 # ifdef DEBUG
183 	if (Debug)
184 		printf("makeconnection (%s)\n", host);
185 # endif DEBUG
186 
187 	s = socket(SOCK_STREAM, 0, 0, 0);
188 	if (s < 0)
189 	{
190 		syserr("makeconnection: no socket");
191 		goto failure;
192 	}
193 
194 # ifdef DEBUG
195 	if (Debug)
196 		printf("makeconnection: %d\n", s);
197 # endif DEBUG
198 	if (connect(s, &SendmailAddress) < 0)
199 	{
200 		/* failure, decide if temporary or not */
201 	failure:
202 		switch (errno)
203 		{
204 		  case EISCONN:
205 		  case ETIMEDOUT:
206 			/* there are others, I'm sure..... */
207 			return (EX_TEMPFAIL);
208 
209 		  default:
210 			return (EX_UNAVAILABLE);
211 		}
212 	}
213 
214 	/* connection ok, put it into canonical form */
215 	*outfile = fdopen(s, "w");
216 	*infile = fdopen(s, "r");
217 
218 	return (0);
219 }
220 
221 #endif DAEMON
222