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