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